##// END OF EJS Templates
settings: fix #3944 add password reset permission
lisaq -
r1034:d1b70f85 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,42 b''
1 import logging
2 import datetime
3
4 from sqlalchemy import *
5 from sqlalchemy.exc import DatabaseError
6 from sqlalchemy.orm import relation, backref, class_mapper, joinedload
7 from sqlalchemy.orm.session import Session
8 from sqlalchemy.ext.declarative import declarative_base
9
10 from rhodecode.lib.dbmigrate.migrate import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
12 from rhodecode.lib.utils2 import str2bool
13
14 from rhodecode.model.meta import Base
15 from rhodecode.model import meta
16 from rhodecode.lib.dbmigrate.versions import _reset_base, notify
17
18 log = logging.getLogger(__name__)
19
20
21 def upgrade(migrate_engine):
22 """
23 Upgrade operations go here.
24 Don't create your own engine; bind migrate_engine to your metadata
25 """
26 _reset_base(migrate_engine)
27 from rhodecode.lib.dbmigrate.schema import db_4_5_0_0
28
29 fixups(db_4_5_0_0, meta.Session)
30
31 def downgrade(migrate_engine):
32 meta = MetaData()
33 meta.bind = migrate_engine
34
35 def fixups(models, _SESSION):
36 # ** create default permissions ** #
37 from rhodecode.model.permission import PermissionModel
38 PermissionModel(_SESSION()).create_permissions()
39
40 res = PermissionModel(_SESSION()).create_default_user_permissions(
41 models.User.DEFAULT_USER)
42 _SESSION().commit()
@@ -1,63 +1,63 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22
22
23 RhodeCode, a web based repository management software
23 RhodeCode, a web based repository management software
24 versioning implementation: http://www.python.org/dev/peps/pep-0386/
24 versioning implementation: http://www.python.org/dev/peps/pep-0386/
25 """
25 """
26
26
27 import os
27 import os
28 import sys
28 import sys
29 import platform
29 import platform
30
30
31 VERSION = tuple(open(os.path.join(
31 VERSION = tuple(open(os.path.join(
32 os.path.dirname(__file__), 'VERSION')).read().split('.'))
32 os.path.dirname(__file__), 'VERSION')).read().split('.'))
33
33
34 BACKENDS = {
34 BACKENDS = {
35 'hg': 'Mercurial repository',
35 'hg': 'Mercurial repository',
36 'git': 'Git repository',
36 'git': 'Git repository',
37 'svn': 'Subversion repository',
37 'svn': 'Subversion repository',
38 }
38 }
39
39
40 CELERY_ENABLED = False
40 CELERY_ENABLED = False
41 CELERY_EAGER = False
41 CELERY_EAGER = False
42
42
43 # link to config for pylons
43 # link to config for pylons
44 CONFIG = {}
44 CONFIG = {}
45
45
46 # Populated with the settings dictionary from application init in
46 # Populated with the settings dictionary from application init in
47 # rhodecode.conf.environment.load_pyramid_environment
47 # rhodecode.conf.environment.load_pyramid_environment
48 PYRAMID_SETTINGS = {}
48 PYRAMID_SETTINGS = {}
49
49
50 # Linked module for extensions
50 # Linked module for extensions
51 EXTENSIONS = {}
51 EXTENSIONS = {}
52
52
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
54 __dbversion__ = 60 # defines current db version for migrations
54 __dbversion__ = 61 # defines current db version for migrations
55 __platform__ = platform.system()
55 __platform__ = platform.system()
56 __license__ = 'AGPLv3, and Commercial License'
56 __license__ = 'AGPLv3, and Commercial License'
57 __author__ = 'RhodeCode GmbH'
57 __author__ = 'RhodeCode GmbH'
58 __url__ = 'http://rhodecode.com'
58 __url__ = 'http://rhodecode.com'
59
59
60 is_windows = __platform__ in ['Windows']
60 is_windows = __platform__ in ['Windows']
61 is_unix = not is_windows
61 is_unix = not is_windows
62 is_test = False
62 is_test = False
63 disable_error_handler = False
63 disable_error_handler = False
@@ -1,465 +1,466 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden
23 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden
24 from rhodecode.api.utils import (
24 from rhodecode.api.utils import (
25 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
25 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
26 from rhodecode.lib.auth import AuthUser, PasswordGenerator
26 from rhodecode.lib.auth import AuthUser, PasswordGenerator
27 from rhodecode.lib.exceptions import DefaultUserException
27 from rhodecode.lib.exceptions import DefaultUserException
28 from rhodecode.lib.utils2 import safe_int
28 from rhodecode.lib.utils2 import safe_int
29 from rhodecode.model.db import Session, User, Repository
29 from rhodecode.model.db import Session, User, Repository
30 from rhodecode.model.user import UserModel
30 from rhodecode.model.user import UserModel
31
31
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
35
35
36 @jsonrpc_method()
36 @jsonrpc_method()
37 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
37 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
38 """
38 """
39 Returns the information associated with a username or userid.
39 Returns the information associated with a username or userid.
40
40
41 * If the ``userid`` is not set, this command returns the information
41 * If the ``userid`` is not set, this command returns the information
42 for the ``userid`` calling the method.
42 for the ``userid`` calling the method.
43
43
44 .. note::
44 .. note::
45
45
46 Normal users may only run this command against their ``userid``. For
46 Normal users may only run this command against their ``userid``. For
47 full privileges you must run this command using an |authtoken| with
47 full privileges you must run this command using an |authtoken| with
48 admin rights.
48 admin rights.
49
49
50 :param apiuser: This is filled automatically from the |authtoken|.
50 :param apiuser: This is filled automatically from the |authtoken|.
51 :type apiuser: AuthUser
51 :type apiuser: AuthUser
52 :param userid: Sets the userid for which data will be returned.
52 :param userid: Sets the userid for which data will be returned.
53 :type userid: Optional(str or int)
53 :type userid: Optional(str or int)
54
54
55 Example output:
55 Example output:
56
56
57 .. code-block:: bash
57 .. code-block:: bash
58
58
59 {
59 {
60 "error": null,
60 "error": null,
61 "id": <id>,
61 "id": <id>,
62 "result": {
62 "result": {
63 "active": true,
63 "active": true,
64 "admin": false,
64 "admin": false,
65 "api_key": "api-key",
65 "api_key": "api-key",
66 "api_keys": [ list of keys ],
66 "api_keys": [ list of keys ],
67 "email": "user@example.com",
67 "email": "user@example.com",
68 "emails": [
68 "emails": [
69 "user@example.com"
69 "user@example.com"
70 ],
70 ],
71 "extern_name": "rhodecode",
71 "extern_name": "rhodecode",
72 "extern_type": "rhodecode",
72 "extern_type": "rhodecode",
73 "firstname": "username",
73 "firstname": "username",
74 "ip_addresses": [],
74 "ip_addresses": [],
75 "language": null,
75 "language": null,
76 "last_login": "Timestamp",
76 "last_login": "Timestamp",
77 "lastname": "surnae",
77 "lastname": "surnae",
78 "permissions": {
78 "permissions": {
79 "global": [
79 "global": [
80 "hg.inherit_default_perms.true",
80 "hg.inherit_default_perms.true",
81 "usergroup.read",
81 "usergroup.read",
82 "hg.repogroup.create.false",
82 "hg.repogroup.create.false",
83 "hg.create.none",
83 "hg.create.none",
84 "hg.password_reset.enabled",
84 "hg.extern_activate.manual",
85 "hg.extern_activate.manual",
85 "hg.create.write_on_repogroup.false",
86 "hg.create.write_on_repogroup.false",
86 "hg.usergroup.create.false",
87 "hg.usergroup.create.false",
87 "group.none",
88 "group.none",
88 "repository.none",
89 "repository.none",
89 "hg.register.none",
90 "hg.register.none",
90 "hg.fork.repository"
91 "hg.fork.repository"
91 ],
92 ],
92 "repositories": { "username/example": "repository.write"},
93 "repositories": { "username/example": "repository.write"},
93 "repositories_groups": { "user-group/repo": "group.none" },
94 "repositories_groups": { "user-group/repo": "group.none" },
94 "user_groups": { "user_group_name": "usergroup.read" }
95 "user_groups": { "user_group_name": "usergroup.read" }
95 },
96 },
96 "user_id": 32,
97 "user_id": 32,
97 "username": "username"
98 "username": "username"
98 }
99 }
99 }
100 }
100 """
101 """
101
102
102 if not has_superadmin_permission(apiuser):
103 if not has_superadmin_permission(apiuser):
103 # make sure normal user does not pass someone else userid,
104 # make sure normal user does not pass someone else userid,
104 # he is not allowed to do that
105 # he is not allowed to do that
105 if not isinstance(userid, Optional) and userid != apiuser.user_id:
106 if not isinstance(userid, Optional) and userid != apiuser.user_id:
106 raise JSONRPCError('userid is not the same as your user')
107 raise JSONRPCError('userid is not the same as your user')
107
108
108 userid = Optional.extract(userid, evaluate_locals=locals())
109 userid = Optional.extract(userid, evaluate_locals=locals())
109 userid = getattr(userid, 'user_id', userid)
110 userid = getattr(userid, 'user_id', userid)
110
111
111 user = get_user_or_error(userid)
112 user = get_user_or_error(userid)
112 data = user.get_api_data(include_secrets=True)
113 data = user.get_api_data(include_secrets=True)
113 data['permissions'] = AuthUser(user_id=user.user_id).permissions
114 data['permissions'] = AuthUser(user_id=user.user_id).permissions
114 return data
115 return data
115
116
116
117
117 @jsonrpc_method()
118 @jsonrpc_method()
118 def get_users(request, apiuser):
119 def get_users(request, apiuser):
119 """
120 """
120 Lists all users in the |RCE| user database.
121 Lists all users in the |RCE| user database.
121
122
122 This command can only be run using an |authtoken| with admin rights to
123 This command can only be run using an |authtoken| with admin rights to
123 the specified repository.
124 the specified repository.
124
125
125 This command takes the following options:
126 This command takes the following options:
126
127
127 :param apiuser: This is filled automatically from the |authtoken|.
128 :param apiuser: This is filled automatically from the |authtoken|.
128 :type apiuser: AuthUser
129 :type apiuser: AuthUser
129
130
130 Example output:
131 Example output:
131
132
132 .. code-block:: bash
133 .. code-block:: bash
133
134
134 id : <id_given_in_input>
135 id : <id_given_in_input>
135 result: [<user_object>, ...]
136 result: [<user_object>, ...]
136 error: null
137 error: null
137 """
138 """
138
139
139 if not has_superadmin_permission(apiuser):
140 if not has_superadmin_permission(apiuser):
140 raise JSONRPCForbidden()
141 raise JSONRPCForbidden()
141
142
142 result = []
143 result = []
143 users_list = User.query().order_by(User.username) \
144 users_list = User.query().order_by(User.username) \
144 .filter(User.username != User.DEFAULT_USER) \
145 .filter(User.username != User.DEFAULT_USER) \
145 .all()
146 .all()
146 for user in users_list:
147 for user in users_list:
147 result.append(user.get_api_data(include_secrets=True))
148 result.append(user.get_api_data(include_secrets=True))
148 return result
149 return result
149
150
150
151
151 @jsonrpc_method()
152 @jsonrpc_method()
152 def create_user(request, apiuser, username, email, password=Optional(''),
153 def create_user(request, apiuser, username, email, password=Optional(''),
153 firstname=Optional(''), lastname=Optional(''),
154 firstname=Optional(''), lastname=Optional(''),
154 active=Optional(True), admin=Optional(False),
155 active=Optional(True), admin=Optional(False),
155 extern_name=Optional('rhodecode'),
156 extern_name=Optional('rhodecode'),
156 extern_type=Optional('rhodecode'),
157 extern_type=Optional('rhodecode'),
157 force_password_change=Optional(False)):
158 force_password_change=Optional(False)):
158 """
159 """
159 Creates a new user and returns the new user object.
160 Creates a new user and returns the new user object.
160
161
161 This command can only be run using an |authtoken| with admin rights to
162 This command can only be run using an |authtoken| with admin rights to
162 the specified repository.
163 the specified repository.
163
164
164 This command takes the following options:
165 This command takes the following options:
165
166
166 :param apiuser: This is filled automatically from the |authtoken|.
167 :param apiuser: This is filled automatically from the |authtoken|.
167 :type apiuser: AuthUser
168 :type apiuser: AuthUser
168 :param username: Set the new username.
169 :param username: Set the new username.
169 :type username: str or int
170 :type username: str or int
170 :param email: Set the user email address.
171 :param email: Set the user email address.
171 :type email: str
172 :type email: str
172 :param password: Set the new user password.
173 :param password: Set the new user password.
173 :type password: Optional(str)
174 :type password: Optional(str)
174 :param firstname: Set the new user firstname.
175 :param firstname: Set the new user firstname.
175 :type firstname: Optional(str)
176 :type firstname: Optional(str)
176 :param lastname: Set the new user surname.
177 :param lastname: Set the new user surname.
177 :type lastname: Optional(str)
178 :type lastname: Optional(str)
178 :param active: Set the user as active.
179 :param active: Set the user as active.
179 :type active: Optional(``True`` | ``False``)
180 :type active: Optional(``True`` | ``False``)
180 :param admin: Give the new user admin rights.
181 :param admin: Give the new user admin rights.
181 :type admin: Optional(``True`` | ``False``)
182 :type admin: Optional(``True`` | ``False``)
182 :param extern_name: Set the authentication plugin name.
183 :param extern_name: Set the authentication plugin name.
183 Using LDAP this is filled with LDAP UID.
184 Using LDAP this is filled with LDAP UID.
184 :type extern_name: Optional(str)
185 :type extern_name: Optional(str)
185 :param extern_type: Set the new user authentication plugin.
186 :param extern_type: Set the new user authentication plugin.
186 :type extern_type: Optional(str)
187 :type extern_type: Optional(str)
187 :param force_password_change: Force the new user to change password
188 :param force_password_change: Force the new user to change password
188 on next login.
189 on next login.
189 :type force_password_change: Optional(``True`` | ``False``)
190 :type force_password_change: Optional(``True`` | ``False``)
190
191
191 Example output:
192 Example output:
192
193
193 .. code-block:: bash
194 .. code-block:: bash
194
195
195 id : <id_given_in_input>
196 id : <id_given_in_input>
196 result: {
197 result: {
197 "msg" : "created new user `<username>`",
198 "msg" : "created new user `<username>`",
198 "user": <user_obj>
199 "user": <user_obj>
199 }
200 }
200 error: null
201 error: null
201
202
202 Example error output:
203 Example error output:
203
204
204 .. code-block:: bash
205 .. code-block:: bash
205
206
206 id : <id_given_in_input>
207 id : <id_given_in_input>
207 result : null
208 result : null
208 error : {
209 error : {
209 "user `<username>` already exist"
210 "user `<username>` already exist"
210 or
211 or
211 "email `<email>` already exist"
212 "email `<email>` already exist"
212 or
213 or
213 "failed to create user `<username>`"
214 "failed to create user `<username>`"
214 }
215 }
215
216
216 """
217 """
217 if not has_superadmin_permission(apiuser):
218 if not has_superadmin_permission(apiuser):
218 raise JSONRPCForbidden()
219 raise JSONRPCForbidden()
219
220
220 if UserModel().get_by_username(username):
221 if UserModel().get_by_username(username):
221 raise JSONRPCError("user `%s` already exist" % (username,))
222 raise JSONRPCError("user `%s` already exist" % (username,))
222
223
223 if UserModel().get_by_email(email, case_insensitive=True):
224 if UserModel().get_by_email(email, case_insensitive=True):
224 raise JSONRPCError("email `%s` already exist" % (email,))
225 raise JSONRPCError("email `%s` already exist" % (email,))
225
226
226 # generate random password if we actually given the
227 # generate random password if we actually given the
227 # extern_name and it's not rhodecode
228 # extern_name and it's not rhodecode
228 if (not isinstance(extern_name, Optional) and
229 if (not isinstance(extern_name, Optional) and
229 Optional.extract(extern_name) != 'rhodecode'):
230 Optional.extract(extern_name) != 'rhodecode'):
230 # generate temporary password if user is external
231 # generate temporary password if user is external
231 password = PasswordGenerator().gen_password(length=16)
232 password = PasswordGenerator().gen_password(length=16)
232
233
233 try:
234 try:
234 user = UserModel().create_or_update(
235 user = UserModel().create_or_update(
235 username=Optional.extract(username),
236 username=Optional.extract(username),
236 password=Optional.extract(password),
237 password=Optional.extract(password),
237 email=Optional.extract(email),
238 email=Optional.extract(email),
238 firstname=Optional.extract(firstname),
239 firstname=Optional.extract(firstname),
239 lastname=Optional.extract(lastname),
240 lastname=Optional.extract(lastname),
240 active=Optional.extract(active),
241 active=Optional.extract(active),
241 admin=Optional.extract(admin),
242 admin=Optional.extract(admin),
242 extern_type=Optional.extract(extern_type),
243 extern_type=Optional.extract(extern_type),
243 extern_name=Optional.extract(extern_name),
244 extern_name=Optional.extract(extern_name),
244 force_password_change=Optional.extract(force_password_change),
245 force_password_change=Optional.extract(force_password_change),
245 )
246 )
246 Session().commit()
247 Session().commit()
247 return {
248 return {
248 'msg': 'created new user `%s`' % username,
249 'msg': 'created new user `%s`' % username,
249 'user': user.get_api_data(include_secrets=True)
250 'user': user.get_api_data(include_secrets=True)
250 }
251 }
251 except Exception:
252 except Exception:
252 log.exception('Error occurred during creation of user')
253 log.exception('Error occurred during creation of user')
253 raise JSONRPCError('failed to create user `%s`' % (username,))
254 raise JSONRPCError('failed to create user `%s`' % (username,))
254
255
255
256
256 @jsonrpc_method()
257 @jsonrpc_method()
257 def update_user(request, apiuser, userid, username=Optional(None),
258 def update_user(request, apiuser, userid, username=Optional(None),
258 email=Optional(None), password=Optional(None),
259 email=Optional(None), password=Optional(None),
259 firstname=Optional(None), lastname=Optional(None),
260 firstname=Optional(None), lastname=Optional(None),
260 active=Optional(None), admin=Optional(None),
261 active=Optional(None), admin=Optional(None),
261 extern_type=Optional(None), extern_name=Optional(None), ):
262 extern_type=Optional(None), extern_name=Optional(None), ):
262 """
263 """
263 Updates the details for the specified user, if that user exists.
264 Updates the details for the specified user, if that user exists.
264
265
265 This command can only be run using an |authtoken| with admin rights to
266 This command can only be run using an |authtoken| with admin rights to
266 the specified repository.
267 the specified repository.
267
268
268 This command takes the following options:
269 This command takes the following options:
269
270
270 :param apiuser: This is filled automatically from |authtoken|.
271 :param apiuser: This is filled automatically from |authtoken|.
271 :type apiuser: AuthUser
272 :type apiuser: AuthUser
272 :param userid: Set the ``userid`` to update.
273 :param userid: Set the ``userid`` to update.
273 :type userid: str or int
274 :type userid: str or int
274 :param username: Set the new username.
275 :param username: Set the new username.
275 :type username: str or int
276 :type username: str or int
276 :param email: Set the new email.
277 :param email: Set the new email.
277 :type email: str
278 :type email: str
278 :param password: Set the new password.
279 :param password: Set the new password.
279 :type password: Optional(str)
280 :type password: Optional(str)
280 :param firstname: Set the new first name.
281 :param firstname: Set the new first name.
281 :type firstname: Optional(str)
282 :type firstname: Optional(str)
282 :param lastname: Set the new surname.
283 :param lastname: Set the new surname.
283 :type lastname: Optional(str)
284 :type lastname: Optional(str)
284 :param active: Set the new user as active.
285 :param active: Set the new user as active.
285 :type active: Optional(``True`` | ``False``)
286 :type active: Optional(``True`` | ``False``)
286 :param admin: Give the user admin rights.
287 :param admin: Give the user admin rights.
287 :type admin: Optional(``True`` | ``False``)
288 :type admin: Optional(``True`` | ``False``)
288 :param extern_name: Set the authentication plugin user name.
289 :param extern_name: Set the authentication plugin user name.
289 Using LDAP this is filled with LDAP UID.
290 Using LDAP this is filled with LDAP UID.
290 :type extern_name: Optional(str)
291 :type extern_name: Optional(str)
291 :param extern_type: Set the authentication plugin type.
292 :param extern_type: Set the authentication plugin type.
292 :type extern_type: Optional(str)
293 :type extern_type: Optional(str)
293
294
294
295
295 Example output:
296 Example output:
296
297
297 .. code-block:: bash
298 .. code-block:: bash
298
299
299 id : <id_given_in_input>
300 id : <id_given_in_input>
300 result: {
301 result: {
301 "msg" : "updated user ID:<userid> <username>",
302 "msg" : "updated user ID:<userid> <username>",
302 "user": <user_object>,
303 "user": <user_object>,
303 }
304 }
304 error: null
305 error: null
305
306
306 Example error output:
307 Example error output:
307
308
308 .. code-block:: bash
309 .. code-block:: bash
309
310
310 id : <id_given_in_input>
311 id : <id_given_in_input>
311 result : null
312 result : null
312 error : {
313 error : {
313 "failed to update user `<username>`"
314 "failed to update user `<username>`"
314 }
315 }
315
316
316 """
317 """
317 if not has_superadmin_permission(apiuser):
318 if not has_superadmin_permission(apiuser):
318 raise JSONRPCForbidden()
319 raise JSONRPCForbidden()
319
320
320 user = get_user_or_error(userid)
321 user = get_user_or_error(userid)
321
322
322 # only non optional arguments will be stored in updates
323 # only non optional arguments will be stored in updates
323 updates = {}
324 updates = {}
324
325
325 try:
326 try:
326
327
327 store_update(updates, username, 'username')
328 store_update(updates, username, 'username')
328 store_update(updates, password, 'password')
329 store_update(updates, password, 'password')
329 store_update(updates, email, 'email')
330 store_update(updates, email, 'email')
330 store_update(updates, firstname, 'name')
331 store_update(updates, firstname, 'name')
331 store_update(updates, lastname, 'lastname')
332 store_update(updates, lastname, 'lastname')
332 store_update(updates, active, 'active')
333 store_update(updates, active, 'active')
333 store_update(updates, admin, 'admin')
334 store_update(updates, admin, 'admin')
334 store_update(updates, extern_name, 'extern_name')
335 store_update(updates, extern_name, 'extern_name')
335 store_update(updates, extern_type, 'extern_type')
336 store_update(updates, extern_type, 'extern_type')
336
337
337 user = UserModel().update_user(user, **updates)
338 user = UserModel().update_user(user, **updates)
338 Session().commit()
339 Session().commit()
339 return {
340 return {
340 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
341 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
341 'user': user.get_api_data(include_secrets=True)
342 'user': user.get_api_data(include_secrets=True)
342 }
343 }
343 except DefaultUserException:
344 except DefaultUserException:
344 log.exception("Default user edit exception")
345 log.exception("Default user edit exception")
345 raise JSONRPCError('editing default user is forbidden')
346 raise JSONRPCError('editing default user is forbidden')
346 except Exception:
347 except Exception:
347 log.exception("Error occurred during update of user")
348 log.exception("Error occurred during update of user")
348 raise JSONRPCError('failed to update user `%s`' % (userid,))
349 raise JSONRPCError('failed to update user `%s`' % (userid,))
349
350
350
351
351 @jsonrpc_method()
352 @jsonrpc_method()
352 def delete_user(request, apiuser, userid):
353 def delete_user(request, apiuser, userid):
353 """
354 """
354 Deletes the specified user from the |RCE| user database.
355 Deletes the specified user from the |RCE| user database.
355
356
356 This command can only be run using an |authtoken| with admin rights to
357 This command can only be run using an |authtoken| with admin rights to
357 the specified repository.
358 the specified repository.
358
359
359 .. important::
360 .. important::
360
361
361 Ensure all open pull requests and open code review
362 Ensure all open pull requests and open code review
362 requests to this user are close.
363 requests to this user are close.
363
364
364 Also ensure all repositories, or repository groups owned by this
365 Also ensure all repositories, or repository groups owned by this
365 user are reassigned before deletion.
366 user are reassigned before deletion.
366
367
367 This command takes the following options:
368 This command takes the following options:
368
369
369 :param apiuser: This is filled automatically from the |authtoken|.
370 :param apiuser: This is filled automatically from the |authtoken|.
370 :type apiuser: AuthUser
371 :type apiuser: AuthUser
371 :param userid: Set the user to delete.
372 :param userid: Set the user to delete.
372 :type userid: str or int
373 :type userid: str or int
373
374
374 Example output:
375 Example output:
375
376
376 .. code-block:: bash
377 .. code-block:: bash
377
378
378 id : <id_given_in_input>
379 id : <id_given_in_input>
379 result: {
380 result: {
380 "msg" : "deleted user ID:<userid> <username>",
381 "msg" : "deleted user ID:<userid> <username>",
381 "user": null
382 "user": null
382 }
383 }
383 error: null
384 error: null
384
385
385 Example error output:
386 Example error output:
386
387
387 .. code-block:: bash
388 .. code-block:: bash
388
389
389 id : <id_given_in_input>
390 id : <id_given_in_input>
390 result : null
391 result : null
391 error : {
392 error : {
392 "failed to delete user ID:<userid> <username>"
393 "failed to delete user ID:<userid> <username>"
393 }
394 }
394
395
395 """
396 """
396 if not has_superadmin_permission(apiuser):
397 if not has_superadmin_permission(apiuser):
397 raise JSONRPCForbidden()
398 raise JSONRPCForbidden()
398
399
399 user = get_user_or_error(userid)
400 user = get_user_or_error(userid)
400
401
401 try:
402 try:
402 UserModel().delete(userid)
403 UserModel().delete(userid)
403 Session().commit()
404 Session().commit()
404 return {
405 return {
405 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
406 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
406 'user': None
407 'user': None
407 }
408 }
408 except Exception:
409 except Exception:
409 log.exception("Error occurred during deleting of user")
410 log.exception("Error occurred during deleting of user")
410 raise JSONRPCError(
411 raise JSONRPCError(
411 'failed to delete user ID:%s %s' % (user.user_id, user.username))
412 'failed to delete user ID:%s %s' % (user.user_id, user.username))
412
413
413
414
414 @jsonrpc_method()
415 @jsonrpc_method()
415 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
416 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
416 """
417 """
417 Displays all repositories locked by the specified user.
418 Displays all repositories locked by the specified user.
418
419
419 * If this command is run by a non-admin user, it returns
420 * If this command is run by a non-admin user, it returns
420 a list of |repos| locked by that user.
421 a list of |repos| locked by that user.
421
422
422 This command takes the following options:
423 This command takes the following options:
423
424
424 :param apiuser: This is filled automatically from the |authtoken|.
425 :param apiuser: This is filled automatically from the |authtoken|.
425 :type apiuser: AuthUser
426 :type apiuser: AuthUser
426 :param userid: Sets the userid whose list of locked |repos| will be
427 :param userid: Sets the userid whose list of locked |repos| will be
427 displayed.
428 displayed.
428 :type userid: Optional(str or int)
429 :type userid: Optional(str or int)
429
430
430 Example output:
431 Example output:
431
432
432 .. code-block:: bash
433 .. code-block:: bash
433
434
434 id : <id_given_in_input>
435 id : <id_given_in_input>
435 result : {
436 result : {
436 [repo_object, repo_object,...]
437 [repo_object, repo_object,...]
437 }
438 }
438 error : null
439 error : null
439 """
440 """
440
441
441 include_secrets = False
442 include_secrets = False
442 if not has_superadmin_permission(apiuser):
443 if not has_superadmin_permission(apiuser):
443 # make sure normal user does not pass someone else userid,
444 # make sure normal user does not pass someone else userid,
444 # he is not allowed to do that
445 # he is not allowed to do that
445 if not isinstance(userid, Optional) and userid != apiuser.user_id:
446 if not isinstance(userid, Optional) and userid != apiuser.user_id:
446 raise JSONRPCError('userid is not the same as your user')
447 raise JSONRPCError('userid is not the same as your user')
447 else:
448 else:
448 include_secrets = True
449 include_secrets = True
449
450
450 userid = Optional.extract(userid, evaluate_locals=locals())
451 userid = Optional.extract(userid, evaluate_locals=locals())
451 userid = getattr(userid, 'user_id', userid)
452 userid = getattr(userid, 'user_id', userid)
452 user = get_user_or_error(userid)
453 user = get_user_or_error(userid)
453
454
454 ret = []
455 ret = []
455
456
456 # show all locks
457 # show all locks
457 for r in Repository.getAll():
458 for r in Repository.getAll():
458 _user_id, _time, _reason = r.locked
459 _user_id, _time, _reason = r.locked
459 if _user_id and _time:
460 if _user_id and _time:
460 _api_data = r.get_api_data(include_secrets=include_secrets)
461 _api_data = r.get_api_data(include_secrets=include_secrets)
461 # if we use user filter just show the locks for this user
462 # if we use user filter just show the locks for this user
462 if safe_int(_user_id) == user.user_id:
463 if safe_int(_user_id) == user.user_id:
463 ret.append(_api_data)
464 ret.append(_api_data)
464
465
465 return ret
466 return ret
@@ -1,248 +1,249 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 """
22 """
23 permissions controller for RhodeCode Enterprise
23 permissions controller for RhodeCode Enterprise
24 """
24 """
25
25
26
26
27 import logging
27 import logging
28
28
29 import formencode
29 import formencode
30 from formencode import htmlfill
30 from formencode import htmlfill
31 from pylons import request, tmpl_context as c, url
31 from pylons import request, tmpl_context as c, url
32 from pylons.controllers.util import redirect
32 from pylons.controllers.util import redirect
33 from pylons.i18n.translation import _
33 from pylons.i18n.translation import _
34
34
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
36 from rhodecode.lib import auth
36 from rhodecode.lib import auth
37 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
37 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
38 from rhodecode.lib.base import BaseController, render
38 from rhodecode.lib.base import BaseController, render
39 from rhodecode.model.db import User, UserIpMap
39 from rhodecode.model.db import User, UserIpMap
40 from rhodecode.model.forms import (
40 from rhodecode.model.forms import (
41 ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
41 ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
42 from rhodecode.model.meta import Session
42 from rhodecode.model.meta import Session
43 from rhodecode.model.permission import PermissionModel
43 from rhodecode.model.permission import PermissionModel
44 from rhodecode.model.settings import SettingsModel
44 from rhodecode.model.settings import SettingsModel
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class PermissionsController(BaseController):
49 class PermissionsController(BaseController):
50 """REST Controller styled on the Atom Publishing Protocol"""
50 """REST Controller styled on the Atom Publishing Protocol"""
51 # To properly map this controller, ensure your config/routing.py
51 # To properly map this controller, ensure your config/routing.py
52 # file has a resource setup:
52 # file has a resource setup:
53 # map.resource('permission', 'permissions')
53 # map.resource('permission', 'permissions')
54
54
55 @LoginRequired()
55 @LoginRequired()
56 def __before__(self):
56 def __before__(self):
57 super(PermissionsController, self).__before__()
57 super(PermissionsController, self).__before__()
58
58
59 def __load_data(self):
59 def __load_data(self):
60 PermissionModel().set_global_permission_choices(c, translator=_)
60 PermissionModel().set_global_permission_choices(c, translator=_)
61
61
62 @HasPermissionAllDecorator('hg.admin')
62 @HasPermissionAllDecorator('hg.admin')
63 def permission_application(self):
63 def permission_application(self):
64 c.active = 'application'
64 c.active = 'application'
65 self.__load_data()
65 self.__load_data()
66
66
67 c.user = User.get_default_user()
67 c.user = User.get_default_user()
68
68
69 # TODO: johbo: The default user might be based on outdated state which
69 # TODO: johbo: The default user might be based on outdated state which
70 # has been loaded from the cache. A call to refresh() ensures that the
70 # has been loaded from the cache. A call to refresh() ensures that the
71 # latest state from the database is used.
71 # latest state from the database is used.
72 Session().refresh(c.user)
72 Session().refresh(c.user)
73
73
74 app_settings = SettingsModel().get_all_settings()
74 app_settings = SettingsModel().get_all_settings()
75 defaults = {
75 defaults = {
76 'anonymous': c.user.active,
76 'anonymous': c.user.active,
77 'default_register_message': app_settings.get(
77 'default_register_message': app_settings.get(
78 'rhodecode_register_message')
78 'rhodecode_register_message')
79 }
79 }
80 defaults.update(c.user.get_default_perms())
80 defaults.update(c.user.get_default_perms())
81
81
82 return htmlfill.render(
82 return htmlfill.render(
83 render('admin/permissions/permissions.html'),
83 render('admin/permissions/permissions.html'),
84 defaults=defaults,
84 defaults=defaults,
85 encoding="UTF-8",
85 encoding="UTF-8",
86 force_defaults=False)
86 force_defaults=False)
87
87
88 @HasPermissionAllDecorator('hg.admin')
88 @HasPermissionAllDecorator('hg.admin')
89 @auth.CSRFRequired()
89 @auth.CSRFRequired()
90 def permission_application_update(self):
90 def permission_application_update(self):
91 c.active = 'application'
91 c.active = 'application'
92 self.__load_data()
92 self.__load_data()
93 _form = ApplicationPermissionsForm(
93 _form = ApplicationPermissionsForm(
94 [x[0] for x in c.register_choices],
94 [x[0] for x in c.register_choices],
95 [x[0] for x in c.password_reset_choices],
95 [x[0] for x in c.extern_activate_choices])()
96 [x[0] for x in c.extern_activate_choices])()
96
97
97 try:
98 try:
98 form_result = _form.to_python(dict(request.POST))
99 form_result = _form.to_python(dict(request.POST))
99 form_result.update({'perm_user_name': User.DEFAULT_USER})
100 form_result.update({'perm_user_name': User.DEFAULT_USER})
100 PermissionModel().update_application_permissions(form_result)
101 PermissionModel().update_application_permissions(form_result)
101
102
102 settings = [
103 settings = [
103 ('register_message', 'default_register_message'),
104 ('register_message', 'default_register_message'),
104 ]
105 ]
105 for setting, form_key in settings:
106 for setting, form_key in settings:
106 sett = SettingsModel().create_or_update_setting(
107 sett = SettingsModel().create_or_update_setting(
107 setting, form_result[form_key])
108 setting, form_result[form_key])
108 Session().add(sett)
109 Session().add(sett)
109
110
110 Session().commit()
111 Session().commit()
111 h.flash(_('Application permissions updated successfully'),
112 h.flash(_('Application permissions updated successfully'),
112 category='success')
113 category='success')
113
114
114 except formencode.Invalid as errors:
115 except formencode.Invalid as errors:
115 defaults = errors.value
116 defaults = errors.value
116
117
117 return htmlfill.render(
118 return htmlfill.render(
118 render('admin/permissions/permissions.html'),
119 render('admin/permissions/permissions.html'),
119 defaults=defaults,
120 defaults=defaults,
120 errors=errors.error_dict or {},
121 errors=errors.error_dict or {},
121 prefix_error=False,
122 prefix_error=False,
122 encoding="UTF-8",
123 encoding="UTF-8",
123 force_defaults=False)
124 force_defaults=False)
124 except Exception:
125 except Exception:
125 log.exception("Exception during update of permissions")
126 log.exception("Exception during update of permissions")
126 h.flash(_('Error occurred during update of permissions'),
127 h.flash(_('Error occurred during update of permissions'),
127 category='error')
128 category='error')
128
129
129 return redirect(url('admin_permissions_application'))
130 return redirect(url('admin_permissions_application'))
130
131
131 @HasPermissionAllDecorator('hg.admin')
132 @HasPermissionAllDecorator('hg.admin')
132 def permission_objects(self):
133 def permission_objects(self):
133 c.active = 'objects'
134 c.active = 'objects'
134 self.__load_data()
135 self.__load_data()
135 c.user = User.get_default_user()
136 c.user = User.get_default_user()
136 defaults = {}
137 defaults = {}
137 defaults.update(c.user.get_default_perms())
138 defaults.update(c.user.get_default_perms())
138 return htmlfill.render(
139 return htmlfill.render(
139 render('admin/permissions/permissions.html'),
140 render('admin/permissions/permissions.html'),
140 defaults=defaults,
141 defaults=defaults,
141 encoding="UTF-8",
142 encoding="UTF-8",
142 force_defaults=False)
143 force_defaults=False)
143
144
144 @HasPermissionAllDecorator('hg.admin')
145 @HasPermissionAllDecorator('hg.admin')
145 @auth.CSRFRequired()
146 @auth.CSRFRequired()
146 def permission_objects_update(self):
147 def permission_objects_update(self):
147 c.active = 'objects'
148 c.active = 'objects'
148 self.__load_data()
149 self.__load_data()
149 _form = ObjectPermissionsForm(
150 _form = ObjectPermissionsForm(
150 [x[0] for x in c.repo_perms_choices],
151 [x[0] for x in c.repo_perms_choices],
151 [x[0] for x in c.group_perms_choices],
152 [x[0] for x in c.group_perms_choices],
152 [x[0] for x in c.user_group_perms_choices])()
153 [x[0] for x in c.user_group_perms_choices])()
153
154
154 try:
155 try:
155 form_result = _form.to_python(dict(request.POST))
156 form_result = _form.to_python(dict(request.POST))
156 form_result.update({'perm_user_name': User.DEFAULT_USER})
157 form_result.update({'perm_user_name': User.DEFAULT_USER})
157 PermissionModel().update_object_permissions(form_result)
158 PermissionModel().update_object_permissions(form_result)
158
159
159 Session().commit()
160 Session().commit()
160 h.flash(_('Object permissions updated successfully'),
161 h.flash(_('Object permissions updated successfully'),
161 category='success')
162 category='success')
162
163
163 except formencode.Invalid as errors:
164 except formencode.Invalid as errors:
164 defaults = errors.value
165 defaults = errors.value
165
166
166 return htmlfill.render(
167 return htmlfill.render(
167 render('admin/permissions/permissions.html'),
168 render('admin/permissions/permissions.html'),
168 defaults=defaults,
169 defaults=defaults,
169 errors=errors.error_dict or {},
170 errors=errors.error_dict or {},
170 prefix_error=False,
171 prefix_error=False,
171 encoding="UTF-8",
172 encoding="UTF-8",
172 force_defaults=False)
173 force_defaults=False)
173 except Exception:
174 except Exception:
174 log.exception("Exception during update of permissions")
175 log.exception("Exception during update of permissions")
175 h.flash(_('Error occurred during update of permissions'),
176 h.flash(_('Error occurred during update of permissions'),
176 category='error')
177 category='error')
177
178
178 return redirect(url('admin_permissions_object'))
179 return redirect(url('admin_permissions_object'))
179
180
180 @HasPermissionAllDecorator('hg.admin')
181 @HasPermissionAllDecorator('hg.admin')
181 def permission_global(self):
182 def permission_global(self):
182 c.active = 'global'
183 c.active = 'global'
183 self.__load_data()
184 self.__load_data()
184
185
185 c.user = User.get_default_user()
186 c.user = User.get_default_user()
186 defaults = {}
187 defaults = {}
187 defaults.update(c.user.get_default_perms())
188 defaults.update(c.user.get_default_perms())
188
189
189 return htmlfill.render(
190 return htmlfill.render(
190 render('admin/permissions/permissions.html'),
191 render('admin/permissions/permissions.html'),
191 defaults=defaults,
192 defaults=defaults,
192 encoding="UTF-8",
193 encoding="UTF-8",
193 force_defaults=False)
194 force_defaults=False)
194
195
195 @HasPermissionAllDecorator('hg.admin')
196 @HasPermissionAllDecorator('hg.admin')
196 @auth.CSRFRequired()
197 @auth.CSRFRequired()
197 def permission_global_update(self):
198 def permission_global_update(self):
198 c.active = 'global'
199 c.active = 'global'
199 self.__load_data()
200 self.__load_data()
200 _form = UserPermissionsForm(
201 _form = UserPermissionsForm(
201 [x[0] for x in c.repo_create_choices],
202 [x[0] for x in c.repo_create_choices],
202 [x[0] for x in c.repo_create_on_write_choices],
203 [x[0] for x in c.repo_create_on_write_choices],
203 [x[0] for x in c.repo_group_create_choices],
204 [x[0] for x in c.repo_group_create_choices],
204 [x[0] for x in c.user_group_create_choices],
205 [x[0] for x in c.user_group_create_choices],
205 [x[0] for x in c.fork_choices],
206 [x[0] for x in c.fork_choices],
206 [x[0] for x in c.inherit_default_permission_choices])()
207 [x[0] for x in c.inherit_default_permission_choices])()
207
208
208 try:
209 try:
209 form_result = _form.to_python(dict(request.POST))
210 form_result = _form.to_python(dict(request.POST))
210 form_result.update({'perm_user_name': User.DEFAULT_USER})
211 form_result.update({'perm_user_name': User.DEFAULT_USER})
211 PermissionModel().update_user_permissions(form_result)
212 PermissionModel().update_user_permissions(form_result)
212
213
213 Session().commit()
214 Session().commit()
214 h.flash(_('Global permissions updated successfully'),
215 h.flash(_('Global permissions updated successfully'),
215 category='success')
216 category='success')
216
217
217 except formencode.Invalid as errors:
218 except formencode.Invalid as errors:
218 defaults = errors.value
219 defaults = errors.value
219
220
220 return htmlfill.render(
221 return htmlfill.render(
221 render('admin/permissions/permissions.html'),
222 render('admin/permissions/permissions.html'),
222 defaults=defaults,
223 defaults=defaults,
223 errors=errors.error_dict or {},
224 errors=errors.error_dict or {},
224 prefix_error=False,
225 prefix_error=False,
225 encoding="UTF-8",
226 encoding="UTF-8",
226 force_defaults=False)
227 force_defaults=False)
227 except Exception:
228 except Exception:
228 log.exception("Exception during update of permissions")
229 log.exception("Exception during update of permissions")
229 h.flash(_('Error occurred during update of permissions'),
230 h.flash(_('Error occurred during update of permissions'),
230 category='error')
231 category='error')
231
232
232 return redirect(url('admin_permissions_global'))
233 return redirect(url('admin_permissions_global'))
233
234
234 @HasPermissionAllDecorator('hg.admin')
235 @HasPermissionAllDecorator('hg.admin')
235 def permission_ips(self):
236 def permission_ips(self):
236 c.active = 'ips'
237 c.active = 'ips'
237 c.user = User.get_default_user()
238 c.user = User.get_default_user()
238 c.user_ip_map = (
239 c.user_ip_map = (
239 UserIpMap.query().filter(UserIpMap.user == c.user).all())
240 UserIpMap.query().filter(UserIpMap.user == c.user).all())
240
241
241 return render('admin/permissions/permissions.html')
242 return render('admin/permissions/permissions.html')
242
243
243 @HasPermissionAllDecorator('hg.admin')
244 @HasPermissionAllDecorator('hg.admin')
244 def permission_perms(self):
245 def permission_perms(self):
245 c.active = 'perms'
246 c.active = 'perms'
246 c.user = User.get_default_user()
247 c.user = User.get_default_user()
247 c.perm_user = c.user.AuthUser
248 c.perm_user = c.user.AuthUser
248 return render('admin/permissions/permissions.html')
249 return render('admin/permissions/permissions.html')
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,551 +1,553 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 this is forms validation classes
22 this is forms validation classes
23 http://formencode.org/module-formencode.validators.html
23 http://formencode.org/module-formencode.validators.html
24 for list off all availible validators
24 for list off all availible validators
25
25
26 we can create our own validators
26 we can create our own validators
27
27
28 The table below outlines the options which can be used in a schema in addition to the validators themselves
28 The table below outlines the options which can be used in a schema in addition to the validators themselves
29 pre_validators [] These validators will be applied before the schema
29 pre_validators [] These validators will be applied before the schema
30 chained_validators [] These validators will be applied after the schema
30 chained_validators [] These validators will be applied after the schema
31 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
31 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
32 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
32 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
33 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
33 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
34 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
34 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
35
35
36
36
37 <name> = formencode.validators.<name of validator>
37 <name> = formencode.validators.<name of validator>
38 <name> must equal form name
38 <name> must equal form name
39 list=[1,2,3,4,5]
39 list=[1,2,3,4,5]
40 for SELECT use formencode.All(OneOf(list), Int())
40 for SELECT use formencode.All(OneOf(list), Int())
41
41
42 """
42 """
43
43
44 import deform
44 import deform
45 import logging
45 import logging
46 import formencode
46 import formencode
47
47
48 from pkg_resources import resource_filename
48 from pkg_resources import resource_filename
49 from formencode import All, Pipe
49 from formencode import All, Pipe
50
50
51 from pylons.i18n.translation import _
51 from pylons.i18n.translation import _
52
52
53 from rhodecode import BACKENDS
53 from rhodecode import BACKENDS
54 from rhodecode.lib import helpers
54 from rhodecode.lib import helpers
55 from rhodecode.model import validators as v
55 from rhodecode.model import validators as v
56
56
57 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
58
58
59
59
60 deform_templates = resource_filename('deform', 'templates')
60 deform_templates = resource_filename('deform', 'templates')
61 rhodecode_templates = resource_filename('rhodecode', 'templates/forms')
61 rhodecode_templates = resource_filename('rhodecode', 'templates/forms')
62 search_path = (rhodecode_templates, deform_templates)
62 search_path = (rhodecode_templates, deform_templates)
63
63
64
64
65 class RhodecodeFormZPTRendererFactory(deform.ZPTRendererFactory):
65 class RhodecodeFormZPTRendererFactory(deform.ZPTRendererFactory):
66 """ Subclass of ZPTRendererFactory to add rhodecode context variables """
66 """ Subclass of ZPTRendererFactory to add rhodecode context variables """
67 def __call__(self, template_name, **kw):
67 def __call__(self, template_name, **kw):
68 kw['h'] = helpers
68 kw['h'] = helpers
69 return self.load(template_name)(**kw)
69 return self.load(template_name)(**kw)
70
70
71
71
72 form_renderer = RhodecodeFormZPTRendererFactory(search_path)
72 form_renderer = RhodecodeFormZPTRendererFactory(search_path)
73 deform.Form.set_default_renderer(form_renderer)
73 deform.Form.set_default_renderer(form_renderer)
74
74
75
75
76 def LoginForm():
76 def LoginForm():
77 class _LoginForm(formencode.Schema):
77 class _LoginForm(formencode.Schema):
78 allow_extra_fields = True
78 allow_extra_fields = True
79 filter_extra_fields = True
79 filter_extra_fields = True
80 username = v.UnicodeString(
80 username = v.UnicodeString(
81 strip=True,
81 strip=True,
82 min=1,
82 min=1,
83 not_empty=True,
83 not_empty=True,
84 messages={
84 messages={
85 'empty': _(u'Please enter a login'),
85 'empty': _(u'Please enter a login'),
86 'tooShort': _(u'Enter a value %(min)i characters long or more')
86 'tooShort': _(u'Enter a value %(min)i characters long or more')
87 }
87 }
88 )
88 )
89
89
90 password = v.UnicodeString(
90 password = v.UnicodeString(
91 strip=False,
91 strip=False,
92 min=3,
92 min=3,
93 not_empty=True,
93 not_empty=True,
94 messages={
94 messages={
95 'empty': _(u'Please enter a password'),
95 'empty': _(u'Please enter a password'),
96 'tooShort': _(u'Enter %(min)i characters or more')}
96 'tooShort': _(u'Enter %(min)i characters or more')}
97 )
97 )
98
98
99 remember = v.StringBoolean(if_missing=False)
99 remember = v.StringBoolean(if_missing=False)
100
100
101 chained_validators = [v.ValidAuth()]
101 chained_validators = [v.ValidAuth()]
102 return _LoginForm
102 return _LoginForm
103
103
104
104
105 def UserForm(edit=False, available_languages=[], old_data={}):
105 def UserForm(edit=False, available_languages=[], old_data={}):
106 class _UserForm(formencode.Schema):
106 class _UserForm(formencode.Schema):
107 allow_extra_fields = True
107 allow_extra_fields = True
108 filter_extra_fields = True
108 filter_extra_fields = True
109 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
109 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
110 v.ValidUsername(edit, old_data))
110 v.ValidUsername(edit, old_data))
111 if edit:
111 if edit:
112 new_password = All(
112 new_password = All(
113 v.ValidPassword(),
113 v.ValidPassword(),
114 v.UnicodeString(strip=False, min=6, not_empty=False)
114 v.UnicodeString(strip=False, min=6, not_empty=False)
115 )
115 )
116 password_confirmation = All(
116 password_confirmation = All(
117 v.ValidPassword(),
117 v.ValidPassword(),
118 v.UnicodeString(strip=False, min=6, not_empty=False),
118 v.UnicodeString(strip=False, min=6, not_empty=False),
119 )
119 )
120 admin = v.StringBoolean(if_missing=False)
120 admin = v.StringBoolean(if_missing=False)
121 else:
121 else:
122 password = All(
122 password = All(
123 v.ValidPassword(),
123 v.ValidPassword(),
124 v.UnicodeString(strip=False, min=6, not_empty=True)
124 v.UnicodeString(strip=False, min=6, not_empty=True)
125 )
125 )
126 password_confirmation = All(
126 password_confirmation = All(
127 v.ValidPassword(),
127 v.ValidPassword(),
128 v.UnicodeString(strip=False, min=6, not_empty=False)
128 v.UnicodeString(strip=False, min=6, not_empty=False)
129 )
129 )
130
130
131 password_change = v.StringBoolean(if_missing=False)
131 password_change = v.StringBoolean(if_missing=False)
132 create_repo_group = v.StringBoolean(if_missing=False)
132 create_repo_group = v.StringBoolean(if_missing=False)
133
133
134 active = v.StringBoolean(if_missing=False)
134 active = v.StringBoolean(if_missing=False)
135 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
135 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
136 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
136 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
137 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
137 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
138 extern_name = v.UnicodeString(strip=True)
138 extern_name = v.UnicodeString(strip=True)
139 extern_type = v.UnicodeString(strip=True)
139 extern_type = v.UnicodeString(strip=True)
140 language = v.OneOf(available_languages, hideList=False,
140 language = v.OneOf(available_languages, hideList=False,
141 testValueList=True, if_missing=None)
141 testValueList=True, if_missing=None)
142 chained_validators = [v.ValidPasswordsMatch()]
142 chained_validators = [v.ValidPasswordsMatch()]
143 return _UserForm
143 return _UserForm
144
144
145
145
146 def UserGroupForm(edit=False, old_data=None, available_members=None,
146 def UserGroupForm(edit=False, old_data=None, available_members=None,
147 allow_disabled=False):
147 allow_disabled=False):
148 old_data = old_data or {}
148 old_data = old_data or {}
149 available_members = available_members or []
149 available_members = available_members or []
150
150
151 class _UserGroupForm(formencode.Schema):
151 class _UserGroupForm(formencode.Schema):
152 allow_extra_fields = True
152 allow_extra_fields = True
153 filter_extra_fields = True
153 filter_extra_fields = True
154
154
155 users_group_name = All(
155 users_group_name = All(
156 v.UnicodeString(strip=True, min=1, not_empty=True),
156 v.UnicodeString(strip=True, min=1, not_empty=True),
157 v.ValidUserGroup(edit, old_data)
157 v.ValidUserGroup(edit, old_data)
158 )
158 )
159 user_group_description = v.UnicodeString(strip=True, min=1,
159 user_group_description = v.UnicodeString(strip=True, min=1,
160 not_empty=False)
160 not_empty=False)
161
161
162 users_group_active = v.StringBoolean(if_missing=False)
162 users_group_active = v.StringBoolean(if_missing=False)
163
163
164 if edit:
164 if edit:
165 users_group_members = v.OneOf(
165 users_group_members = v.OneOf(
166 available_members, hideList=False, testValueList=True,
166 available_members, hideList=False, testValueList=True,
167 if_missing=None, not_empty=False
167 if_missing=None, not_empty=False
168 )
168 )
169 # this is user group owner
169 # this is user group owner
170 user = All(
170 user = All(
171 v.UnicodeString(not_empty=True),
171 v.UnicodeString(not_empty=True),
172 v.ValidRepoUser(allow_disabled))
172 v.ValidRepoUser(allow_disabled))
173 return _UserGroupForm
173 return _UserGroupForm
174
174
175
175
176 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
176 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
177 can_create_in_root=False, allow_disabled=False):
177 can_create_in_root=False, allow_disabled=False):
178 old_data = old_data or {}
178 old_data = old_data or {}
179 available_groups = available_groups or []
179 available_groups = available_groups or []
180
180
181 class _RepoGroupForm(formencode.Schema):
181 class _RepoGroupForm(formencode.Schema):
182 allow_extra_fields = True
182 allow_extra_fields = True
183 filter_extra_fields = False
183 filter_extra_fields = False
184
184
185 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
185 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
186 v.SlugifyName(),)
186 v.SlugifyName(),)
187 group_description = v.UnicodeString(strip=True, min=1,
187 group_description = v.UnicodeString(strip=True, min=1,
188 not_empty=False)
188 not_empty=False)
189 group_copy_permissions = v.StringBoolean(if_missing=False)
189 group_copy_permissions = v.StringBoolean(if_missing=False)
190
190
191 group_parent_id = v.OneOf(available_groups, hideList=False,
191 group_parent_id = v.OneOf(available_groups, hideList=False,
192 testValueList=True, not_empty=True)
192 testValueList=True, not_empty=True)
193 enable_locking = v.StringBoolean(if_missing=False)
193 enable_locking = v.StringBoolean(if_missing=False)
194 chained_validators = [
194 chained_validators = [
195 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
195 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
196
196
197 if edit:
197 if edit:
198 # this is repo group owner
198 # this is repo group owner
199 user = All(
199 user = All(
200 v.UnicodeString(not_empty=True),
200 v.UnicodeString(not_empty=True),
201 v.ValidRepoUser(allow_disabled))
201 v.ValidRepoUser(allow_disabled))
202
202
203 return _RepoGroupForm
203 return _RepoGroupForm
204
204
205
205
206 def RegisterForm(edit=False, old_data={}):
206 def RegisterForm(edit=False, old_data={}):
207 class _RegisterForm(formencode.Schema):
207 class _RegisterForm(formencode.Schema):
208 allow_extra_fields = True
208 allow_extra_fields = True
209 filter_extra_fields = True
209 filter_extra_fields = True
210 username = All(
210 username = All(
211 v.ValidUsername(edit, old_data),
211 v.ValidUsername(edit, old_data),
212 v.UnicodeString(strip=True, min=1, not_empty=True)
212 v.UnicodeString(strip=True, min=1, not_empty=True)
213 )
213 )
214 password = All(
214 password = All(
215 v.ValidPassword(),
215 v.ValidPassword(),
216 v.UnicodeString(strip=False, min=6, not_empty=True)
216 v.UnicodeString(strip=False, min=6, not_empty=True)
217 )
217 )
218 password_confirmation = All(
218 password_confirmation = All(
219 v.ValidPassword(),
219 v.ValidPassword(),
220 v.UnicodeString(strip=False, min=6, not_empty=True)
220 v.UnicodeString(strip=False, min=6, not_empty=True)
221 )
221 )
222 active = v.StringBoolean(if_missing=False)
222 active = v.StringBoolean(if_missing=False)
223 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
223 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
224 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
224 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
225 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
225 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
226
226
227 chained_validators = [v.ValidPasswordsMatch()]
227 chained_validators = [v.ValidPasswordsMatch()]
228
228
229 return _RegisterForm
229 return _RegisterForm
230
230
231
231
232 def PasswordResetForm():
232 def PasswordResetForm():
233 class _PasswordResetForm(formencode.Schema):
233 class _PasswordResetForm(formencode.Schema):
234 allow_extra_fields = True
234 allow_extra_fields = True
235 filter_extra_fields = True
235 filter_extra_fields = True
236 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
236 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
237 return _PasswordResetForm
237 return _PasswordResetForm
238
238
239
239
240 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
240 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
241 allow_disabled=False):
241 allow_disabled=False):
242 old_data = old_data or {}
242 old_data = old_data or {}
243 repo_groups = repo_groups or []
243 repo_groups = repo_groups or []
244 landing_revs = landing_revs or []
244 landing_revs = landing_revs or []
245 supported_backends = BACKENDS.keys()
245 supported_backends = BACKENDS.keys()
246
246
247 class _RepoForm(formencode.Schema):
247 class _RepoForm(formencode.Schema):
248 allow_extra_fields = True
248 allow_extra_fields = True
249 filter_extra_fields = False
249 filter_extra_fields = False
250 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
250 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
251 v.SlugifyName())
251 v.SlugifyName())
252 repo_group = All(v.CanWriteGroup(old_data),
252 repo_group = All(v.CanWriteGroup(old_data),
253 v.OneOf(repo_groups, hideList=True))
253 v.OneOf(repo_groups, hideList=True))
254 repo_type = v.OneOf(supported_backends, required=False,
254 repo_type = v.OneOf(supported_backends, required=False,
255 if_missing=old_data.get('repo_type'))
255 if_missing=old_data.get('repo_type'))
256 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
256 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
257 repo_private = v.StringBoolean(if_missing=False)
257 repo_private = v.StringBoolean(if_missing=False)
258 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
258 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
259 repo_copy_permissions = v.StringBoolean(if_missing=False)
259 repo_copy_permissions = v.StringBoolean(if_missing=False)
260 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
260 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
261
261
262 repo_enable_statistics = v.StringBoolean(if_missing=False)
262 repo_enable_statistics = v.StringBoolean(if_missing=False)
263 repo_enable_downloads = v.StringBoolean(if_missing=False)
263 repo_enable_downloads = v.StringBoolean(if_missing=False)
264 repo_enable_locking = v.StringBoolean(if_missing=False)
264 repo_enable_locking = v.StringBoolean(if_missing=False)
265
265
266 if edit:
266 if edit:
267 # this is repo owner
267 # this is repo owner
268 user = All(
268 user = All(
269 v.UnicodeString(not_empty=True),
269 v.UnicodeString(not_empty=True),
270 v.ValidRepoUser(allow_disabled))
270 v.ValidRepoUser(allow_disabled))
271 clone_uri_change = v.UnicodeString(
271 clone_uri_change = v.UnicodeString(
272 not_empty=False, if_missing=v.Missing)
272 not_empty=False, if_missing=v.Missing)
273
273
274 chained_validators = [v.ValidCloneUri(),
274 chained_validators = [v.ValidCloneUri(),
275 v.ValidRepoName(edit, old_data)]
275 v.ValidRepoName(edit, old_data)]
276 return _RepoForm
276 return _RepoForm
277
277
278
278
279 def RepoPermsForm():
279 def RepoPermsForm():
280 class _RepoPermsForm(formencode.Schema):
280 class _RepoPermsForm(formencode.Schema):
281 allow_extra_fields = True
281 allow_extra_fields = True
282 filter_extra_fields = False
282 filter_extra_fields = False
283 chained_validators = [v.ValidPerms(type_='repo')]
283 chained_validators = [v.ValidPerms(type_='repo')]
284 return _RepoPermsForm
284 return _RepoPermsForm
285
285
286
286
287 def RepoGroupPermsForm(valid_recursive_choices):
287 def RepoGroupPermsForm(valid_recursive_choices):
288 class _RepoGroupPermsForm(formencode.Schema):
288 class _RepoGroupPermsForm(formencode.Schema):
289 allow_extra_fields = True
289 allow_extra_fields = True
290 filter_extra_fields = False
290 filter_extra_fields = False
291 recursive = v.OneOf(valid_recursive_choices)
291 recursive = v.OneOf(valid_recursive_choices)
292 chained_validators = [v.ValidPerms(type_='repo_group')]
292 chained_validators = [v.ValidPerms(type_='repo_group')]
293 return _RepoGroupPermsForm
293 return _RepoGroupPermsForm
294
294
295
295
296 def UserGroupPermsForm():
296 def UserGroupPermsForm():
297 class _UserPermsForm(formencode.Schema):
297 class _UserPermsForm(formencode.Schema):
298 allow_extra_fields = True
298 allow_extra_fields = True
299 filter_extra_fields = False
299 filter_extra_fields = False
300 chained_validators = [v.ValidPerms(type_='user_group')]
300 chained_validators = [v.ValidPerms(type_='user_group')]
301 return _UserPermsForm
301 return _UserPermsForm
302
302
303
303
304 def RepoFieldForm():
304 def RepoFieldForm():
305 class _RepoFieldForm(formencode.Schema):
305 class _RepoFieldForm(formencode.Schema):
306 filter_extra_fields = True
306 filter_extra_fields = True
307 allow_extra_fields = True
307 allow_extra_fields = True
308
308
309 new_field_key = All(v.FieldKey(),
309 new_field_key = All(v.FieldKey(),
310 v.UnicodeString(strip=True, min=3, not_empty=True))
310 v.UnicodeString(strip=True, min=3, not_empty=True))
311 new_field_value = v.UnicodeString(not_empty=False, if_missing=u'')
311 new_field_value = v.UnicodeString(not_empty=False, if_missing=u'')
312 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
312 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
313 if_missing='str')
313 if_missing='str')
314 new_field_label = v.UnicodeString(not_empty=False)
314 new_field_label = v.UnicodeString(not_empty=False)
315 new_field_desc = v.UnicodeString(not_empty=False)
315 new_field_desc = v.UnicodeString(not_empty=False)
316
316
317 return _RepoFieldForm
317 return _RepoFieldForm
318
318
319
319
320 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
320 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
321 repo_groups=[], landing_revs=[]):
321 repo_groups=[], landing_revs=[]):
322 class _RepoForkForm(formencode.Schema):
322 class _RepoForkForm(formencode.Schema):
323 allow_extra_fields = True
323 allow_extra_fields = True
324 filter_extra_fields = False
324 filter_extra_fields = False
325 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
325 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
326 v.SlugifyName())
326 v.SlugifyName())
327 repo_group = All(v.CanWriteGroup(),
327 repo_group = All(v.CanWriteGroup(),
328 v.OneOf(repo_groups, hideList=True))
328 v.OneOf(repo_groups, hideList=True))
329 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
329 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
330 description = v.UnicodeString(strip=True, min=1, not_empty=True)
330 description = v.UnicodeString(strip=True, min=1, not_empty=True)
331 private = v.StringBoolean(if_missing=False)
331 private = v.StringBoolean(if_missing=False)
332 copy_permissions = v.StringBoolean(if_missing=False)
332 copy_permissions = v.StringBoolean(if_missing=False)
333 fork_parent_id = v.UnicodeString()
333 fork_parent_id = v.UnicodeString()
334 chained_validators = [v.ValidForkName(edit, old_data)]
334 chained_validators = [v.ValidForkName(edit, old_data)]
335 landing_rev = v.OneOf(landing_revs, hideList=True)
335 landing_rev = v.OneOf(landing_revs, hideList=True)
336
336
337 return _RepoForkForm
337 return _RepoForkForm
338
338
339
339
340 def ApplicationSettingsForm():
340 def ApplicationSettingsForm():
341 class _ApplicationSettingsForm(formencode.Schema):
341 class _ApplicationSettingsForm(formencode.Schema):
342 allow_extra_fields = True
342 allow_extra_fields = True
343 filter_extra_fields = False
343 filter_extra_fields = False
344 rhodecode_title = v.UnicodeString(strip=True, max=40, not_empty=False)
344 rhodecode_title = v.UnicodeString(strip=True, max=40, not_empty=False)
345 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
345 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
346 rhodecode_pre_code = v.UnicodeString(strip=True, min=1, not_empty=False)
346 rhodecode_pre_code = v.UnicodeString(strip=True, min=1, not_empty=False)
347 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
347 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
348 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
348 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
349 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
349 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
350
350
351 return _ApplicationSettingsForm
351 return _ApplicationSettingsForm
352
352
353
353
354 def ApplicationVisualisationForm():
354 def ApplicationVisualisationForm():
355 class _ApplicationVisualisationForm(formencode.Schema):
355 class _ApplicationVisualisationForm(formencode.Schema):
356 allow_extra_fields = True
356 allow_extra_fields = True
357 filter_extra_fields = False
357 filter_extra_fields = False
358 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
358 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
359 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
359 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
360 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
360 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
361
361
362 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
362 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
363 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
363 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
364 rhodecode_dashboard_items = v.Int(min=5, not_empty=True)
364 rhodecode_dashboard_items = v.Int(min=5, not_empty=True)
365 rhodecode_admin_grid_items = v.Int(min=5, not_empty=True)
365 rhodecode_admin_grid_items = v.Int(min=5, not_empty=True)
366 rhodecode_show_version = v.StringBoolean(if_missing=False)
366 rhodecode_show_version = v.StringBoolean(if_missing=False)
367 rhodecode_use_gravatar = v.StringBoolean(if_missing=False)
367 rhodecode_use_gravatar = v.StringBoolean(if_missing=False)
368 rhodecode_markup_renderer = v.OneOf(['markdown', 'rst'])
368 rhodecode_markup_renderer = v.OneOf(['markdown', 'rst'])
369 rhodecode_gravatar_url = v.UnicodeString(min=3)
369 rhodecode_gravatar_url = v.UnicodeString(min=3)
370 rhodecode_clone_uri_tmpl = v.UnicodeString(min=3)
370 rhodecode_clone_uri_tmpl = v.UnicodeString(min=3)
371 rhodecode_support_url = v.UnicodeString()
371 rhodecode_support_url = v.UnicodeString()
372 rhodecode_show_revision_number = v.StringBoolean(if_missing=False)
372 rhodecode_show_revision_number = v.StringBoolean(if_missing=False)
373 rhodecode_show_sha_length = v.Int(min=4, not_empty=True)
373 rhodecode_show_sha_length = v.Int(min=4, not_empty=True)
374
374
375 return _ApplicationVisualisationForm
375 return _ApplicationVisualisationForm
376
376
377
377
378 class _BaseVcsSettingsForm(formencode.Schema):
378 class _BaseVcsSettingsForm(formencode.Schema):
379 allow_extra_fields = True
379 allow_extra_fields = True
380 filter_extra_fields = False
380 filter_extra_fields = False
381 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
381 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
382 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
382 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
383 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
383 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
384
384
385 extensions_largefiles = v.StringBoolean(if_missing=False)
385 extensions_largefiles = v.StringBoolean(if_missing=False)
386 phases_publish = v.StringBoolean(if_missing=False)
386 phases_publish = v.StringBoolean(if_missing=False)
387
387
388 rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False)
388 rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False)
389 rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False)
389 rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False)
390 rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False)
390 rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False)
391
391
392 vcs_svn_proxy_http_requests_enabled = v.StringBoolean(if_missing=False)
392 vcs_svn_proxy_http_requests_enabled = v.StringBoolean(if_missing=False)
393 vcs_svn_proxy_http_server_url = v.UnicodeString(strip=True, if_missing=None)
393 vcs_svn_proxy_http_server_url = v.UnicodeString(strip=True, if_missing=None)
394
394
395
395
396 def ApplicationUiSettingsForm():
396 def ApplicationUiSettingsForm():
397 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
397 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
398 web_push_ssl = v.StringBoolean(if_missing=False)
398 web_push_ssl = v.StringBoolean(if_missing=False)
399 paths_root_path = All(
399 paths_root_path = All(
400 v.ValidPath(),
400 v.ValidPath(),
401 v.UnicodeString(strip=True, min=1, not_empty=True)
401 v.UnicodeString(strip=True, min=1, not_empty=True)
402 )
402 )
403 extensions_hgsubversion = v.StringBoolean(if_missing=False)
403 extensions_hgsubversion = v.StringBoolean(if_missing=False)
404 extensions_hggit = v.StringBoolean(if_missing=False)
404 extensions_hggit = v.StringBoolean(if_missing=False)
405 new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch')
405 new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch')
406 new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag')
406 new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag')
407
407
408 return _ApplicationUiSettingsForm
408 return _ApplicationUiSettingsForm
409
409
410
410
411 def RepoVcsSettingsForm(repo_name):
411 def RepoVcsSettingsForm(repo_name):
412 class _RepoVcsSettingsForm(_BaseVcsSettingsForm):
412 class _RepoVcsSettingsForm(_BaseVcsSettingsForm):
413 inherit_global_settings = v.StringBoolean(if_missing=False)
413 inherit_global_settings = v.StringBoolean(if_missing=False)
414 new_svn_branch = v.ValidSvnPattern(
414 new_svn_branch = v.ValidSvnPattern(
415 section='vcs_svn_branch', repo_name=repo_name)
415 section='vcs_svn_branch', repo_name=repo_name)
416 new_svn_tag = v.ValidSvnPattern(
416 new_svn_tag = v.ValidSvnPattern(
417 section='vcs_svn_tag', repo_name=repo_name)
417 section='vcs_svn_tag', repo_name=repo_name)
418
418
419 return _RepoVcsSettingsForm
419 return _RepoVcsSettingsForm
420
420
421
421
422 def LabsSettingsForm():
422 def LabsSettingsForm():
423 class _LabSettingsForm(formencode.Schema):
423 class _LabSettingsForm(formencode.Schema):
424 allow_extra_fields = True
424 allow_extra_fields = True
425 filter_extra_fields = False
425 filter_extra_fields = False
426
426
427 return _LabSettingsForm
427 return _LabSettingsForm
428
428
429
429
430 def ApplicationPermissionsForm(register_choices, extern_activate_choices):
430 def ApplicationPermissionsForm(
431 register_choices, password_reset_choices, extern_activate_choices):
431 class _DefaultPermissionsForm(formencode.Schema):
432 class _DefaultPermissionsForm(formencode.Schema):
432 allow_extra_fields = True
433 allow_extra_fields = True
433 filter_extra_fields = True
434 filter_extra_fields = True
434
435
435 anonymous = v.StringBoolean(if_missing=False)
436 anonymous = v.StringBoolean(if_missing=False)
436 default_register = v.OneOf(register_choices)
437 default_register = v.OneOf(register_choices)
437 default_register_message = v.UnicodeString()
438 default_register_message = v.UnicodeString()
439 default_password_reset = v.OneOf(password_reset_choices)
438 default_extern_activate = v.OneOf(extern_activate_choices)
440 default_extern_activate = v.OneOf(extern_activate_choices)
439
441
440 return _DefaultPermissionsForm
442 return _DefaultPermissionsForm
441
443
442
444
443 def ObjectPermissionsForm(repo_perms_choices, group_perms_choices,
445 def ObjectPermissionsForm(repo_perms_choices, group_perms_choices,
444 user_group_perms_choices):
446 user_group_perms_choices):
445 class _ObjectPermissionsForm(formencode.Schema):
447 class _ObjectPermissionsForm(formencode.Schema):
446 allow_extra_fields = True
448 allow_extra_fields = True
447 filter_extra_fields = True
449 filter_extra_fields = True
448 overwrite_default_repo = v.StringBoolean(if_missing=False)
450 overwrite_default_repo = v.StringBoolean(if_missing=False)
449 overwrite_default_group = v.StringBoolean(if_missing=False)
451 overwrite_default_group = v.StringBoolean(if_missing=False)
450 overwrite_default_user_group = v.StringBoolean(if_missing=False)
452 overwrite_default_user_group = v.StringBoolean(if_missing=False)
451 default_repo_perm = v.OneOf(repo_perms_choices)
453 default_repo_perm = v.OneOf(repo_perms_choices)
452 default_group_perm = v.OneOf(group_perms_choices)
454 default_group_perm = v.OneOf(group_perms_choices)
453 default_user_group_perm = v.OneOf(user_group_perms_choices)
455 default_user_group_perm = v.OneOf(user_group_perms_choices)
454
456
455 return _ObjectPermissionsForm
457 return _ObjectPermissionsForm
456
458
457
459
458 def UserPermissionsForm(create_choices, create_on_write_choices,
460 def UserPermissionsForm(create_choices, create_on_write_choices,
459 repo_group_create_choices, user_group_create_choices,
461 repo_group_create_choices, user_group_create_choices,
460 fork_choices, inherit_default_permissions_choices):
462 fork_choices, inherit_default_permissions_choices):
461 class _DefaultPermissionsForm(formencode.Schema):
463 class _DefaultPermissionsForm(formencode.Schema):
462 allow_extra_fields = True
464 allow_extra_fields = True
463 filter_extra_fields = True
465 filter_extra_fields = True
464
466
465 anonymous = v.StringBoolean(if_missing=False)
467 anonymous = v.StringBoolean(if_missing=False)
466
468
467 default_repo_create = v.OneOf(create_choices)
469 default_repo_create = v.OneOf(create_choices)
468 default_repo_create_on_write = v.OneOf(create_on_write_choices)
470 default_repo_create_on_write = v.OneOf(create_on_write_choices)
469 default_user_group_create = v.OneOf(user_group_create_choices)
471 default_user_group_create = v.OneOf(user_group_create_choices)
470 default_repo_group_create = v.OneOf(repo_group_create_choices)
472 default_repo_group_create = v.OneOf(repo_group_create_choices)
471 default_fork_create = v.OneOf(fork_choices)
473 default_fork_create = v.OneOf(fork_choices)
472 default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices)
474 default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices)
473
475
474 return _DefaultPermissionsForm
476 return _DefaultPermissionsForm
475
477
476
478
477 def UserIndividualPermissionsForm():
479 def UserIndividualPermissionsForm():
478 class _DefaultPermissionsForm(formencode.Schema):
480 class _DefaultPermissionsForm(formencode.Schema):
479 allow_extra_fields = True
481 allow_extra_fields = True
480 filter_extra_fields = True
482 filter_extra_fields = True
481
483
482 inherit_default_permissions = v.StringBoolean(if_missing=False)
484 inherit_default_permissions = v.StringBoolean(if_missing=False)
483
485
484 return _DefaultPermissionsForm
486 return _DefaultPermissionsForm
485
487
486
488
487 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
489 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
488 class _DefaultsForm(formencode.Schema):
490 class _DefaultsForm(formencode.Schema):
489 allow_extra_fields = True
491 allow_extra_fields = True
490 filter_extra_fields = True
492 filter_extra_fields = True
491 default_repo_type = v.OneOf(supported_backends)
493 default_repo_type = v.OneOf(supported_backends)
492 default_repo_private = v.StringBoolean(if_missing=False)
494 default_repo_private = v.StringBoolean(if_missing=False)
493 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
495 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
494 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
496 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
495 default_repo_enable_locking = v.StringBoolean(if_missing=False)
497 default_repo_enable_locking = v.StringBoolean(if_missing=False)
496
498
497 return _DefaultsForm
499 return _DefaultsForm
498
500
499
501
500 def AuthSettingsForm():
502 def AuthSettingsForm():
501 class _AuthSettingsForm(formencode.Schema):
503 class _AuthSettingsForm(formencode.Schema):
502 allow_extra_fields = True
504 allow_extra_fields = True
503 filter_extra_fields = True
505 filter_extra_fields = True
504 auth_plugins = All(v.ValidAuthPlugins(),
506 auth_plugins = All(v.ValidAuthPlugins(),
505 v.UniqueListFromString()(not_empty=True))
507 v.UniqueListFromString()(not_empty=True))
506
508
507 return _AuthSettingsForm
509 return _AuthSettingsForm
508
510
509
511
510 def UserExtraEmailForm():
512 def UserExtraEmailForm():
511 class _UserExtraEmailForm(formencode.Schema):
513 class _UserExtraEmailForm(formencode.Schema):
512 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
514 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
513 return _UserExtraEmailForm
515 return _UserExtraEmailForm
514
516
515
517
516 def UserExtraIpForm():
518 def UserExtraIpForm():
517 class _UserExtraIpForm(formencode.Schema):
519 class _UserExtraIpForm(formencode.Schema):
518 ip = v.ValidIp()(not_empty=True)
520 ip = v.ValidIp()(not_empty=True)
519 return _UserExtraIpForm
521 return _UserExtraIpForm
520
522
521
523
522
524
523 def PullRequestForm(repo_id):
525 def PullRequestForm(repo_id):
524 class ReviewerForm(formencode.Schema):
526 class ReviewerForm(formencode.Schema):
525 user_id = v.Int(not_empty=True)
527 user_id = v.Int(not_empty=True)
526 reasons = All()
528 reasons = All()
527
529
528 class _PullRequestForm(formencode.Schema):
530 class _PullRequestForm(formencode.Schema):
529 allow_extra_fields = True
531 allow_extra_fields = True
530 filter_extra_fields = True
532 filter_extra_fields = True
531
533
532 user = v.UnicodeString(strip=True, required=True)
534 user = v.UnicodeString(strip=True, required=True)
533 source_repo = v.UnicodeString(strip=True, required=True)
535 source_repo = v.UnicodeString(strip=True, required=True)
534 source_ref = v.UnicodeString(strip=True, required=True)
536 source_ref = v.UnicodeString(strip=True, required=True)
535 target_repo = v.UnicodeString(strip=True, required=True)
537 target_repo = v.UnicodeString(strip=True, required=True)
536 target_ref = v.UnicodeString(strip=True, required=True)
538 target_ref = v.UnicodeString(strip=True, required=True)
537 revisions = All(#v.NotReviewedRevisions(repo_id)(),
539 revisions = All(#v.NotReviewedRevisions(repo_id)(),
538 v.UniqueList()(not_empty=True))
540 v.UniqueList()(not_empty=True))
539 review_members = formencode.ForEach(ReviewerForm())
541 review_members = formencode.ForEach(ReviewerForm())
540 pullrequest_title = v.UnicodeString(strip=True, required=True)
542 pullrequest_title = v.UnicodeString(strip=True, required=True)
541 pullrequest_desc = v.UnicodeString(strip=True, required=False)
543 pullrequest_desc = v.UnicodeString(strip=True, required=False)
542
544
543 return _PullRequestForm
545 return _PullRequestForm
544
546
545
547
546 def IssueTrackerPatternsForm():
548 def IssueTrackerPatternsForm():
547 class _IssueTrackerPatternsForm(formencode.Schema):
549 class _IssueTrackerPatternsForm(formencode.Schema):
548 allow_extra_fields = True
550 allow_extra_fields = True
549 filter_extra_fields = False
551 filter_extra_fields = False
550 chained_validators = [v.ValidPattern()]
552 chained_validators = [v.ValidPattern()]
551 return _IssueTrackerPatternsForm
553 return _IssueTrackerPatternsForm
@@ -1,470 +1,482 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 permissions model for RhodeCode
22 permissions model for RhodeCode
23 """
23 """
24
24
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from sqlalchemy.exc import DatabaseError
29 from sqlalchemy.exc import DatabaseError
30
30
31 from rhodecode.model import BaseModel
31 from rhodecode.model import BaseModel
32 from rhodecode.model.db import (
32 from rhodecode.model.db import (
33 User, Permission, UserToPerm, UserRepoToPerm, UserRepoGroupToPerm,
33 User, Permission, UserToPerm, UserRepoToPerm, UserRepoGroupToPerm,
34 UserUserGroupToPerm, UserGroup, UserGroupToPerm)
34 UserUserGroupToPerm, UserGroup, UserGroupToPerm)
35 from rhodecode.lib.utils2 import str2bool, safe_int
35 from rhodecode.lib.utils2 import str2bool, safe_int
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 class PermissionModel(BaseModel):
40 class PermissionModel(BaseModel):
41 """
41 """
42 Permissions model for RhodeCode
42 Permissions model for RhodeCode
43 """
43 """
44
44
45 cls = Permission
45 cls = Permission
46 global_perms = {
46 global_perms = {
47 'default_repo_create': None,
47 'default_repo_create': None,
48 # special case for create repos on write access to group
48 # special case for create repos on write access to group
49 'default_repo_create_on_write': None,
49 'default_repo_create_on_write': None,
50 'default_repo_group_create': None,
50 'default_repo_group_create': None,
51 'default_user_group_create': None,
51 'default_user_group_create': None,
52 'default_fork_create': None,
52 'default_fork_create': None,
53 'default_inherit_default_permissions': None,
53 'default_inherit_default_permissions': None,
54
55 'default_register': None,
54 'default_register': None,
55 'default_password_reset': None,
56 'default_extern_activate': None,
56 'default_extern_activate': None,
57
57
58 # object permissions below
58 # object permissions below
59 'default_repo_perm': None,
59 'default_repo_perm': None,
60 'default_group_perm': None,
60 'default_group_perm': None,
61 'default_user_group_perm': None,
61 'default_user_group_perm': None,
62 }
62 }
63
63
64 def set_global_permission_choices(self, c_obj, translator):
64 def set_global_permission_choices(self, c_obj, translator):
65 c_obj.repo_perms_choices = [
65 c_obj.repo_perms_choices = [
66 ('repository.none', translator('None'),),
66 ('repository.none', translator('None'),),
67 ('repository.read', translator('Read'),),
67 ('repository.read', translator('Read'),),
68 ('repository.write', translator('Write'),),
68 ('repository.write', translator('Write'),),
69 ('repository.admin', translator('Admin'),)]
69 ('repository.admin', translator('Admin'),)]
70
70
71 c_obj.group_perms_choices = [
71 c_obj.group_perms_choices = [
72 ('group.none', translator('None'),),
72 ('group.none', translator('None'),),
73 ('group.read', translator('Read'),),
73 ('group.read', translator('Read'),),
74 ('group.write', translator('Write'),),
74 ('group.write', translator('Write'),),
75 ('group.admin', translator('Admin'),)]
75 ('group.admin', translator('Admin'),)]
76
76
77 c_obj.user_group_perms_choices = [
77 c_obj.user_group_perms_choices = [
78 ('usergroup.none', translator('None'),),
78 ('usergroup.none', translator('None'),),
79 ('usergroup.read', translator('Read'),),
79 ('usergroup.read', translator('Read'),),
80 ('usergroup.write', translator('Write'),),
80 ('usergroup.write', translator('Write'),),
81 ('usergroup.admin', translator('Admin'),)]
81 ('usergroup.admin', translator('Admin'),)]
82
82
83 c_obj.register_choices = [
83 c_obj.register_choices = [
84 ('hg.register.none', translator('Disabled')),
84 ('hg.register.none', translator('Disabled')),
85 ('hg.register.manual_activate', translator('Allowed with manual account activation')),
85 ('hg.register.manual_activate', translator('Allowed with manual account activation')),
86 ('hg.register.auto_activate', translator('Allowed with automatic account activation')),]
86 ('hg.register.auto_activate', translator('Allowed with automatic account activation')),]
87
87
88 c_obj.password_reset_choices = [
89 ('hg.password_reset.enabled', translator('Allow password recovery')),
90 ('hg.password_reset.hidden', translator('Hide password recovery link')),
91 ('hg.password_reset.disabled', translator('Disable password recovery')),]
92
88 c_obj.extern_activate_choices = [
93 c_obj.extern_activate_choices = [
89 ('hg.extern_activate.manual', translator('Manual activation of external account')),
94 ('hg.extern_activate.manual', translator('Manual activation of external account')),
90 ('hg.extern_activate.auto', translator('Automatic activation of external account')),]
95 ('hg.extern_activate.auto', translator('Automatic activation of external account')),]
91
96
92 c_obj.repo_create_choices = [
97 c_obj.repo_create_choices = [
93 ('hg.create.none', translator('Disabled')),
98 ('hg.create.none', translator('Disabled')),
94 ('hg.create.repository', translator('Enabled'))]
99 ('hg.create.repository', translator('Enabled'))]
95
100
96 c_obj.repo_create_on_write_choices = [
101 c_obj.repo_create_on_write_choices = [
97 ('hg.create.write_on_repogroup.false', translator('Disabled')),
102 ('hg.create.write_on_repogroup.false', translator('Disabled')),
98 ('hg.create.write_on_repogroup.true', translator('Enabled'))]
103 ('hg.create.write_on_repogroup.true', translator('Enabled'))]
99
104
100 c_obj.user_group_create_choices = [
105 c_obj.user_group_create_choices = [
101 ('hg.usergroup.create.false', translator('Disabled')),
106 ('hg.usergroup.create.false', translator('Disabled')),
102 ('hg.usergroup.create.true', translator('Enabled'))]
107 ('hg.usergroup.create.true', translator('Enabled'))]
103
108
104 c_obj.repo_group_create_choices = [
109 c_obj.repo_group_create_choices = [
105 ('hg.repogroup.create.false', translator('Disabled')),
110 ('hg.repogroup.create.false', translator('Disabled')),
106 ('hg.repogroup.create.true', translator('Enabled'))]
111 ('hg.repogroup.create.true', translator('Enabled'))]
107
112
108 c_obj.fork_choices = [
113 c_obj.fork_choices = [
109 ('hg.fork.none', translator('Disabled')),
114 ('hg.fork.none', translator('Disabled')),
110 ('hg.fork.repository', translator('Enabled'))]
115 ('hg.fork.repository', translator('Enabled'))]
111
116
112 c_obj.inherit_default_permission_choices = [
117 c_obj.inherit_default_permission_choices = [
113 ('hg.inherit_default_perms.false', translator('Disabled')),
118 ('hg.inherit_default_perms.false', translator('Disabled')),
114 ('hg.inherit_default_perms.true', translator('Enabled'))]
119 ('hg.inherit_default_perms.true', translator('Enabled'))]
115
120
116 def get_default_perms(self, object_perms, suffix):
121 def get_default_perms(self, object_perms, suffix):
117 defaults = {}
122 defaults = {}
118 for perm in object_perms:
123 for perm in object_perms:
119 # perms
124 # perms
120 if perm.permission.permission_name.startswith('repository.'):
125 if perm.permission.permission_name.startswith('repository.'):
121 defaults['default_repo_perm' + suffix] = perm.permission.permission_name
126 defaults['default_repo_perm' + suffix] = perm.permission.permission_name
122
127
123 if perm.permission.permission_name.startswith('group.'):
128 if perm.permission.permission_name.startswith('group.'):
124 defaults['default_group_perm' + suffix] = perm.permission.permission_name
129 defaults['default_group_perm' + suffix] = perm.permission.permission_name
125
130
126 if perm.permission.permission_name.startswith('usergroup.'):
131 if perm.permission.permission_name.startswith('usergroup.'):
127 defaults['default_user_group_perm' + suffix] = perm.permission.permission_name
132 defaults['default_user_group_perm' + suffix] = perm.permission.permission_name
128
133
129 # creation of objects
134 # creation of objects
130 if perm.permission.permission_name.startswith('hg.create.write_on_repogroup'):
135 if perm.permission.permission_name.startswith('hg.create.write_on_repogroup'):
131 defaults['default_repo_create_on_write' + suffix] = perm.permission.permission_name
136 defaults['default_repo_create_on_write' + suffix] = perm.permission.permission_name
132
137
133 elif perm.permission.permission_name.startswith('hg.create.'):
138 elif perm.permission.permission_name.startswith('hg.create.'):
134 defaults['default_repo_create' + suffix] = perm.permission.permission_name
139 defaults['default_repo_create' + suffix] = perm.permission.permission_name
135
140
136 if perm.permission.permission_name.startswith('hg.fork.'):
141 if perm.permission.permission_name.startswith('hg.fork.'):
137 defaults['default_fork_create' + suffix] = perm.permission.permission_name
142 defaults['default_fork_create' + suffix] = perm.permission.permission_name
138
143
139 if perm.permission.permission_name.startswith('hg.inherit_default_perms.'):
144 if perm.permission.permission_name.startswith('hg.inherit_default_perms.'):
140 defaults['default_inherit_default_permissions' + suffix] = perm.permission.permission_name
145 defaults['default_inherit_default_permissions' + suffix] = perm.permission.permission_name
141
146
142 if perm.permission.permission_name.startswith('hg.repogroup.'):
147 if perm.permission.permission_name.startswith('hg.repogroup.'):
143 defaults['default_repo_group_create' + suffix] = perm.permission.permission_name
148 defaults['default_repo_group_create' + suffix] = perm.permission.permission_name
144
149
145 if perm.permission.permission_name.startswith('hg.usergroup.'):
150 if perm.permission.permission_name.startswith('hg.usergroup.'):
146 defaults['default_user_group_create' + suffix] = perm.permission.permission_name
151 defaults['default_user_group_create' + suffix] = perm.permission.permission_name
147
152
148 # registration and external account activation
153 # registration and external account activation
149 if perm.permission.permission_name.startswith('hg.register.'):
154 if perm.permission.permission_name.startswith('hg.register.'):
150 defaults['default_register' + suffix] = perm.permission.permission_name
155 defaults['default_register' + suffix] = perm.permission.permission_name
151
156
157 if perm.permission.permission_name.startswith('hg.password_reset.'):
158 defaults['default_password_reset' + suffix] = perm.permission.permission_name
159
152 if perm.permission.permission_name.startswith('hg.extern_activate.'):
160 if perm.permission.permission_name.startswith('hg.extern_activate.'):
153 defaults['default_extern_activate' + suffix] = perm.permission.permission_name
161 defaults['default_extern_activate' + suffix] = perm.permission.permission_name
154
162
155 return defaults
163 return defaults
156
164
157 def _make_new_user_perm(self, user, perm_name):
165 def _make_new_user_perm(self, user, perm_name):
158 log.debug('Creating new user permission:%s', perm_name)
166 log.debug('Creating new user permission:%s', perm_name)
159 new = UserToPerm()
167 new = UserToPerm()
160 new.user = user
168 new.user = user
161 new.permission = Permission.get_by_key(perm_name)
169 new.permission = Permission.get_by_key(perm_name)
162 return new
170 return new
163
171
164 def _make_new_user_group_perm(self, user_group, perm_name):
172 def _make_new_user_group_perm(self, user_group, perm_name):
165 log.debug('Creating new user group permission:%s', perm_name)
173 log.debug('Creating new user group permission:%s', perm_name)
166 new = UserGroupToPerm()
174 new = UserGroupToPerm()
167 new.users_group = user_group
175 new.users_group = user_group
168 new.permission = Permission.get_by_key(perm_name)
176 new.permission = Permission.get_by_key(perm_name)
169 return new
177 return new
170
178
171 def _keep_perm(self, perm_name, keep_fields):
179 def _keep_perm(self, perm_name, keep_fields):
172 def get_pat(field_name):
180 def get_pat(field_name):
173 return {
181 return {
174 # global perms
182 # global perms
175 'default_repo_create': 'hg.create.',
183 'default_repo_create': 'hg.create.',
176 # special case for create repos on write access to group
184 # special case for create repos on write access to group
177 'default_repo_create_on_write': 'hg.create.write_on_repogroup.',
185 'default_repo_create_on_write': 'hg.create.write_on_repogroup.',
178 'default_repo_group_create': 'hg.repogroup.create.',
186 'default_repo_group_create': 'hg.repogroup.create.',
179 'default_user_group_create': 'hg.usergroup.create.',
187 'default_user_group_create': 'hg.usergroup.create.',
180 'default_fork_create': 'hg.fork.',
188 'default_fork_create': 'hg.fork.',
181 'default_inherit_default_permissions': 'hg.inherit_default_perms.',
189 'default_inherit_default_permissions': 'hg.inherit_default_perms.',
182
190
183 # application perms
191 # application perms
184 'default_register': 'hg.register.',
192 'default_register': 'hg.register.',
193 'default_password_reset': 'hg.password_reset.',
185 'default_extern_activate': 'hg.extern_activate.',
194 'default_extern_activate': 'hg.extern_activate.',
186
195
187 # object permissions below
196 # object permissions below
188 'default_repo_perm': 'repository.',
197 'default_repo_perm': 'repository.',
189 'default_group_perm': 'group.',
198 'default_group_perm': 'group.',
190 'default_user_group_perm': 'usergroup.',
199 'default_user_group_perm': 'usergroup.',
191 }[field_name]
200 }[field_name]
192 for field in keep_fields:
201 for field in keep_fields:
193 pat = get_pat(field)
202 pat = get_pat(field)
194 if perm_name.startswith(pat):
203 if perm_name.startswith(pat):
195 return True
204 return True
196 return False
205 return False
197
206
198 def _clear_object_perm(self, object_perms, preserve=None):
207 def _clear_object_perm(self, object_perms, preserve=None):
199 preserve = preserve or []
208 preserve = preserve or []
200 _deleted = []
209 _deleted = []
201 for perm in object_perms:
210 for perm in object_perms:
202 perm_name = perm.permission.permission_name
211 perm_name = perm.permission.permission_name
203 if not self._keep_perm(perm_name, keep_fields=preserve):
212 if not self._keep_perm(perm_name, keep_fields=preserve):
204 _deleted.append(perm_name)
213 _deleted.append(perm_name)
205 self.sa.delete(perm)
214 self.sa.delete(perm)
206 return _deleted
215 return _deleted
207
216
208 def _clear_user_perms(self, user_id, preserve=None):
217 def _clear_user_perms(self, user_id, preserve=None):
209 perms = self.sa.query(UserToPerm)\
218 perms = self.sa.query(UserToPerm)\
210 .filter(UserToPerm.user_id == user_id)\
219 .filter(UserToPerm.user_id == user_id)\
211 .all()
220 .all()
212 return self._clear_object_perm(perms, preserve=preserve)
221 return self._clear_object_perm(perms, preserve=preserve)
213
222
214 def _clear_user_group_perms(self, user_group_id, preserve=None):
223 def _clear_user_group_perms(self, user_group_id, preserve=None):
215 perms = self.sa.query(UserGroupToPerm)\
224 perms = self.sa.query(UserGroupToPerm)\
216 .filter(UserGroupToPerm.users_group_id == user_group_id)\
225 .filter(UserGroupToPerm.users_group_id == user_group_id)\
217 .all()
226 .all()
218 return self._clear_object_perm(perms, preserve=preserve)
227 return self._clear_object_perm(perms, preserve=preserve)
219
228
220 def _set_new_object_perms(self, obj_type, object, form_result, preserve=None):
229 def _set_new_object_perms(self, obj_type, object, form_result, preserve=None):
221 # clear current entries, to make this function idempotent
230 # clear current entries, to make this function idempotent
222 # it will fix even if we define more permissions or permissions
231 # it will fix even if we define more permissions or permissions
223 # are somehow missing
232 # are somehow missing
224 preserve = preserve or []
233 preserve = preserve or []
225 _global_perms = self.global_perms.copy()
234 _global_perms = self.global_perms.copy()
226 if obj_type not in ['user', 'user_group']:
235 if obj_type not in ['user', 'user_group']:
227 raise ValueError("obj_type must be on of 'user' or 'user_group'")
236 raise ValueError("obj_type must be on of 'user' or 'user_group'")
228 if len(_global_perms) != len(Permission.DEFAULT_USER_PERMISSIONS):
237 if len(_global_perms) != len(Permission.DEFAULT_USER_PERMISSIONS):
229 raise Exception('Inconsistent permissions definition')
238 raise Exception('Inconsistent permissions definition')
230
239
231 if obj_type == 'user':
240 if obj_type == 'user':
232 self._clear_user_perms(object.user_id, preserve)
241 self._clear_user_perms(object.user_id, preserve)
233 if obj_type == 'user_group':
242 if obj_type == 'user_group':
234 self._clear_user_group_perms(object.users_group_id, preserve)
243 self._clear_user_group_perms(object.users_group_id, preserve)
235
244
236 # now kill the keys that we want to preserve from the form.
245 # now kill the keys that we want to preserve from the form.
237 for key in preserve:
246 for key in preserve:
238 del _global_perms[key]
247 del _global_perms[key]
239
248
240 for k in _global_perms.copy():
249 for k in _global_perms.copy():
241 _global_perms[k] = form_result[k]
250 _global_perms[k] = form_result[k]
242
251
243 # at that stage we validate all are passed inside form_result
252 # at that stage we validate all are passed inside form_result
244 for _perm_key, perm_value in _global_perms.items():
253 for _perm_key, perm_value in _global_perms.items():
245 if perm_value is None:
254 if perm_value is None:
246 raise ValueError('Missing permission for %s' % (_perm_key,))
255 raise ValueError('Missing permission for %s' % (_perm_key,))
247
256
248 if obj_type == 'user':
257 if obj_type == 'user':
249 p = self._make_new_user_perm(object, perm_value)
258 p = self._make_new_user_perm(object, perm_value)
250 self.sa.add(p)
259 self.sa.add(p)
251 if obj_type == 'user_group':
260 if obj_type == 'user_group':
252 p = self._make_new_user_group_perm(object, perm_value)
261 p = self._make_new_user_group_perm(object, perm_value)
253 self.sa.add(p)
262 self.sa.add(p)
254
263
255 def _set_new_user_perms(self, user, form_result, preserve=None):
264 def _set_new_user_perms(self, user, form_result, preserve=None):
256 return self._set_new_object_perms(
265 return self._set_new_object_perms(
257 'user', user, form_result, preserve)
266 'user', user, form_result, preserve)
258
267
259 def _set_new_user_group_perms(self, user_group, form_result, preserve=None):
268 def _set_new_user_group_perms(self, user_group, form_result, preserve=None):
260 return self._set_new_object_perms(
269 return self._set_new_object_perms(
261 'user_group', user_group, form_result, preserve)
270 'user_group', user_group, form_result, preserve)
262
271
263 def set_new_user_perms(self, user, form_result):
272 def set_new_user_perms(self, user, form_result):
264 # calculate what to preserve from what is given in form_result
273 # calculate what to preserve from what is given in form_result
265 preserve = set(self.global_perms.keys()).difference(set(form_result.keys()))
274 preserve = set(self.global_perms.keys()).difference(set(form_result.keys()))
266 return self._set_new_user_perms(user, form_result, preserve)
275 return self._set_new_user_perms(user, form_result, preserve)
267
276
268 def set_new_user_group_perms(self, user_group, form_result):
277 def set_new_user_group_perms(self, user_group, form_result):
269 # calculate what to preserve from what is given in form_result
278 # calculate what to preserve from what is given in form_result
270 preserve = set(self.global_perms.keys()).difference(set(form_result.keys()))
279 preserve = set(self.global_perms.keys()).difference(set(form_result.keys()))
271 return self._set_new_user_group_perms(user_group, form_result, preserve)
280 return self._set_new_user_group_perms(user_group, form_result, preserve)
272
281
273 def create_permissions(self):
282 def create_permissions(self):
274 """
283 """
275 Create permissions for whole system
284 Create permissions for whole system
276 """
285 """
277 for p in Permission.PERMS:
286 for p in Permission.PERMS:
278 if not Permission.get_by_key(p[0]):
287 if not Permission.get_by_key(p[0]):
279 new_perm = Permission()
288 new_perm = Permission()
280 new_perm.permission_name = p[0]
289 new_perm.permission_name = p[0]
281 new_perm.permission_longname = p[0] # translation err with p[1]
290 new_perm.permission_longname = p[0] # translation err with p[1]
282 self.sa.add(new_perm)
291 self.sa.add(new_perm)
283
292
284 def _create_default_object_permission(self, obj_type, obj, obj_perms,
293 def _create_default_object_permission(self, obj_type, obj, obj_perms,
285 force=False):
294 force=False):
286 if obj_type not in ['user', 'user_group']:
295 if obj_type not in ['user', 'user_group']:
287 raise ValueError("obj_type must be on of 'user' or 'user_group'")
296 raise ValueError("obj_type must be on of 'user' or 'user_group'")
288
297
289 def _get_group(perm_name):
298 def _get_group(perm_name):
290 return '.'.join(perm_name.split('.')[:1])
299 return '.'.join(perm_name.split('.')[:1])
291
300
292 defined_perms_groups = map(
301 defined_perms_groups = map(
293 _get_group, (x.permission.permission_name for x in obj_perms))
302 _get_group, (x.permission.permission_name for x in obj_perms))
294 log.debug('GOT ALREADY DEFINED:%s', obj_perms)
303 log.debug('GOT ALREADY DEFINED:%s', obj_perms)
295
304
296 if force:
305 if force:
297 self._clear_object_perm(obj_perms)
306 self._clear_object_perm(obj_perms)
298 self.sa.commit()
307 self.sa.commit()
299 defined_perms_groups = []
308 defined_perms_groups = []
300 # for every default permission that needs to be created, we check if
309 # for every default permission that needs to be created, we check if
301 # it's group is already defined, if it's not we create default perm
310 # it's group is already defined, if it's not we create default perm
302 for perm_name in Permission.DEFAULT_USER_PERMISSIONS:
311 for perm_name in Permission.DEFAULT_USER_PERMISSIONS:
303 gr = _get_group(perm_name)
312 gr = _get_group(perm_name)
304 if gr not in defined_perms_groups:
313 if gr not in defined_perms_groups:
305 log.debug('GR:%s not found, creating permission %s',
314 log.debug('GR:%s not found, creating permission %s',
306 gr, perm_name)
315 gr, perm_name)
307 if obj_type == 'user':
316 if obj_type == 'user':
308 new_perm = self._make_new_user_perm(obj, perm_name)
317 new_perm = self._make_new_user_perm(obj, perm_name)
309 self.sa.add(new_perm)
318 self.sa.add(new_perm)
310 if obj_type == 'user_group':
319 if obj_type == 'user_group':
311 new_perm = self._make_new_user_group_perm(obj, perm_name)
320 new_perm = self._make_new_user_group_perm(obj, perm_name)
312 self.sa.add(new_perm)
321 self.sa.add(new_perm)
313
322
314 def create_default_user_permissions(self, user, force=False):
323 def create_default_user_permissions(self, user, force=False):
315 """
324 """
316 Creates only missing default permissions for user, if force is set it
325 Creates only missing default permissions for user, if force is set it
317 resets the default permissions for that user
326 resets the default permissions for that user
318
327
319 :param user:
328 :param user:
320 :param force:
329 :param force:
321 """
330 """
322 user = self._get_user(user)
331 user = self._get_user(user)
323 obj_perms = UserToPerm.query().filter(UserToPerm.user == user).all()
332 obj_perms = UserToPerm.query().filter(UserToPerm.user == user).all()
324 return self._create_default_object_permission(
333 return self._create_default_object_permission(
325 'user', user, obj_perms, force)
334 'user', user, obj_perms, force)
326
335
327 def create_default_user_group_permissions(self, user_group, force=False):
336 def create_default_user_group_permissions(self, user_group, force=False):
328 """
337 """
329 Creates only missing default permissions for user group, if force is set it
338 Creates only missing default permissions for user group, if force is set it
330 resets the default permissions for that user group
339 resets the default permissions for that user group
331
340
332 :param user_group:
341 :param user_group:
333 :param force:
342 :param force:
334 """
343 """
335 user_group = self._get_user_group(user_group)
344 user_group = self._get_user_group(user_group)
336 obj_perms = UserToPerm.query().filter(UserGroupToPerm.users_group == user_group).all()
345 obj_perms = UserToPerm.query().filter(UserGroupToPerm.users_group == user_group).all()
337 return self._create_default_object_permission(
346 return self._create_default_object_permission(
338 'user_group', user_group, obj_perms, force)
347 'user_group', user_group, obj_perms, force)
339
348
340 def update_application_permissions(self, form_result):
349 def update_application_permissions(self, form_result):
341 if 'perm_user_id' in form_result:
350 if 'perm_user_id' in form_result:
342 perm_user = User.get(safe_int(form_result['perm_user_id']))
351 perm_user = User.get(safe_int(form_result['perm_user_id']))
343 else:
352 else:
344 # used mostly to do lookup for default user
353 # used mostly to do lookup for default user
345 perm_user = User.get_by_username(form_result['perm_user_name'])
354 perm_user = User.get_by_username(form_result['perm_user_name'])
346
355
347 try:
356 try:
348 # stage 1 set anonymous access
357 # stage 1 set anonymous access
349 if perm_user.username == User.DEFAULT_USER:
358 if perm_user.username == User.DEFAULT_USER:
350 perm_user.active = str2bool(form_result['anonymous'])
359 perm_user.active = str2bool(form_result['anonymous'])
351 self.sa.add(perm_user)
360 self.sa.add(perm_user)
352
361
353 # stage 2 reset defaults and set them from form data
362 # stage 2 reset defaults and set them from form data
354 self._set_new_user_perms(perm_user, form_result, preserve=[
363 self._set_new_user_perms(perm_user, form_result, preserve=[
355 'default_repo_perm',
364 'default_repo_perm',
356 'default_group_perm',
365 'default_group_perm',
357 'default_user_group_perm',
366 'default_user_group_perm',
358
367
359 'default_repo_group_create',
368 'default_repo_group_create',
360 'default_user_group_create',
369 'default_user_group_create',
361 'default_repo_create_on_write',
370 'default_repo_create_on_write',
362 'default_repo_create',
371 'default_repo_create',
363 'default_fork_create',
372 'default_fork_create',
364 'default_inherit_default_permissions',])
373 'default_inherit_default_permissions',])
365
374
366 self.sa.commit()
375 self.sa.commit()
367 except (DatabaseError,):
376 except (DatabaseError,):
368 log.error(traceback.format_exc())
377 log.error(traceback.format_exc())
369 self.sa.rollback()
378 self.sa.rollback()
370 raise
379 raise
371
380
372 def update_user_permissions(self, form_result):
381 def update_user_permissions(self, form_result):
373 if 'perm_user_id' in form_result:
382 if 'perm_user_id' in form_result:
374 perm_user = User.get(safe_int(form_result['perm_user_id']))
383 perm_user = User.get(safe_int(form_result['perm_user_id']))
375 else:
384 else:
376 # used mostly to do lookup for default user
385 # used mostly to do lookup for default user
377 perm_user = User.get_by_username(form_result['perm_user_name'])
386 perm_user = User.get_by_username(form_result['perm_user_name'])
378 try:
387 try:
379 # stage 2 reset defaults and set them from form data
388 # stage 2 reset defaults and set them from form data
380 self._set_new_user_perms(perm_user, form_result, preserve=[
389 self._set_new_user_perms(perm_user, form_result, preserve=[
381 'default_repo_perm',
390 'default_repo_perm',
382 'default_group_perm',
391 'default_group_perm',
383 'default_user_group_perm',
392 'default_user_group_perm',
384
393
385 'default_register',
394 'default_register',
395 'default_password_reset',
386 'default_extern_activate'])
396 'default_extern_activate'])
387 self.sa.commit()
397 self.sa.commit()
388 except (DatabaseError,):
398 except (DatabaseError,):
389 log.error(traceback.format_exc())
399 log.error(traceback.format_exc())
390 self.sa.rollback()
400 self.sa.rollback()
391 raise
401 raise
392
402
393 def update_user_group_permissions(self, form_result):
403 def update_user_group_permissions(self, form_result):
394 if 'perm_user_group_id' in form_result:
404 if 'perm_user_group_id' in form_result:
395 perm_user_group = UserGroup.get(safe_int(form_result['perm_user_group_id']))
405 perm_user_group = UserGroup.get(safe_int(form_result['perm_user_group_id']))
396 else:
406 else:
397 # used mostly to do lookup for default user
407 # used mostly to do lookup for default user
398 perm_user_group = UserGroup.get_by_group_name(form_result['perm_user_group_name'])
408 perm_user_group = UserGroup.get_by_group_name(form_result['perm_user_group_name'])
399 try:
409 try:
400 # stage 2 reset defaults and set them from form data
410 # stage 2 reset defaults and set them from form data
401 self._set_new_user_group_perms(perm_user_group, form_result, preserve=[
411 self._set_new_user_group_perms(perm_user_group, form_result, preserve=[
402 'default_repo_perm',
412 'default_repo_perm',
403 'default_group_perm',
413 'default_group_perm',
404 'default_user_group_perm',
414 'default_user_group_perm',
405
415
406 'default_register',
416 'default_register',
417 'default_password_reset',
407 'default_extern_activate'])
418 'default_extern_activate'])
408 self.sa.commit()
419 self.sa.commit()
409 except (DatabaseError,):
420 except (DatabaseError,):
410 log.error(traceback.format_exc())
421 log.error(traceback.format_exc())
411 self.sa.rollback()
422 self.sa.rollback()
412 raise
423 raise
413
424
414 def update_object_permissions(self, form_result):
425 def update_object_permissions(self, form_result):
415 if 'perm_user_id' in form_result:
426 if 'perm_user_id' in form_result:
416 perm_user = User.get(safe_int(form_result['perm_user_id']))
427 perm_user = User.get(safe_int(form_result['perm_user_id']))
417 else:
428 else:
418 # used mostly to do lookup for default user
429 # used mostly to do lookup for default user
419 perm_user = User.get_by_username(form_result['perm_user_name'])
430 perm_user = User.get_by_username(form_result['perm_user_name'])
420 try:
431 try:
421
432
422 # stage 2 reset defaults and set them from form data
433 # stage 2 reset defaults and set them from form data
423 self._set_new_user_perms(perm_user, form_result, preserve=[
434 self._set_new_user_perms(perm_user, form_result, preserve=[
424 'default_repo_group_create',
435 'default_repo_group_create',
425 'default_user_group_create',
436 'default_user_group_create',
426 'default_repo_create_on_write',
437 'default_repo_create_on_write',
427 'default_repo_create',
438 'default_repo_create',
428 'default_fork_create',
439 'default_fork_create',
429 'default_inherit_default_permissions',
440 'default_inherit_default_permissions',
430
441
431 'default_register',
442 'default_register',
443 'default_password_reset',
432 'default_extern_activate'])
444 'default_extern_activate'])
433
445
434 # overwrite default repo permissions
446 # overwrite default repo permissions
435 if form_result['overwrite_default_repo']:
447 if form_result['overwrite_default_repo']:
436 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
448 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
437 _def = Permission.get_by_key('repository.' + _def_name)
449 _def = Permission.get_by_key('repository.' + _def_name)
438 for r2p in self.sa.query(UserRepoToPerm)\
450 for r2p in self.sa.query(UserRepoToPerm)\
439 .filter(UserRepoToPerm.user == perm_user)\
451 .filter(UserRepoToPerm.user == perm_user)\
440 .all():
452 .all():
441 # don't reset PRIVATE repositories
453 # don't reset PRIVATE repositories
442 if not r2p.repository.private:
454 if not r2p.repository.private:
443 r2p.permission = _def
455 r2p.permission = _def
444 self.sa.add(r2p)
456 self.sa.add(r2p)
445
457
446 # overwrite default repo group permissions
458 # overwrite default repo group permissions
447 if form_result['overwrite_default_group']:
459 if form_result['overwrite_default_group']:
448 _def_name = form_result['default_group_perm'].split('group.')[-1]
460 _def_name = form_result['default_group_perm'].split('group.')[-1]
449 _def = Permission.get_by_key('group.' + _def_name)
461 _def = Permission.get_by_key('group.' + _def_name)
450 for g2p in self.sa.query(UserRepoGroupToPerm)\
462 for g2p in self.sa.query(UserRepoGroupToPerm)\
451 .filter(UserRepoGroupToPerm.user == perm_user)\
463 .filter(UserRepoGroupToPerm.user == perm_user)\
452 .all():
464 .all():
453 g2p.permission = _def
465 g2p.permission = _def
454 self.sa.add(g2p)
466 self.sa.add(g2p)
455
467
456 # overwrite default user group permissions
468 # overwrite default user group permissions
457 if form_result['overwrite_default_user_group']:
469 if form_result['overwrite_default_user_group']:
458 _def_name = form_result['default_user_group_perm'].split('usergroup.')[-1]
470 _def_name = form_result['default_user_group_perm'].split('usergroup.')[-1]
459 # user groups
471 # user groups
460 _def = Permission.get_by_key('usergroup.' + _def_name)
472 _def = Permission.get_by_key('usergroup.' + _def_name)
461 for g2p in self.sa.query(UserUserGroupToPerm)\
473 for g2p in self.sa.query(UserUserGroupToPerm)\
462 .filter(UserUserGroupToPerm.user == perm_user)\
474 .filter(UserUserGroupToPerm.user == perm_user)\
463 .all():
475 .all():
464 g2p.permission = _def
476 g2p.permission = _def
465 self.sa.add(g2p)
477 self.sa.add(g2p)
466 self.sa.commit()
478 self.sa.commit()
467 except (DatabaseError,):
479 except (DatabaseError,):
468 log.exception('Failed to set default object permissions')
480 log.exception('Failed to set default object permissions')
469 self.sa.rollback()
481 self.sa.rollback()
470 raise
482 raise
@@ -1,297 +1,301 b''
1 //LOGIN
1 //LOGIN
2
2
3
3
4 .loginbox {
4 .loginbox {
5 max-width: 65%;
5 max-width: 65%;
6 margin: @pagepadding auto;
6 margin: @pagepadding auto;
7 font-family: @text-light;
7 font-family: @text-light;
8 border: @border-thickness solid @grey5;
8 border: @border-thickness solid @grey5;
9 box-sizing: border-box;
9 box-sizing: border-box;
10
10
11 @media (max-width:1200px) {
11 @media (max-width:1200px) {
12 max-width: 85%;
12 max-width: 85%;
13 }
13 }
14
14
15 @media (max-width:768px) {
15 @media (max-width:768px) {
16 max-width: 100%;
16 max-width: 100%;
17 width: 100%;
17 width: 100%;
18 margin: 0;
18 margin: 0;
19 }
19 }
20
20
21 .title {
21 .title {
22 float: none;
22 float: none;
23 }
23 }
24
24
25 .header {
25 .header {
26 width: 100%;
26 width: 100%;
27 padding: 0 35px;
27 padding: 0 35px;
28 box-sizing: border-box;
28 box-sizing: border-box;
29
29
30 .title {
30 .title {
31 padding: 0;
31 padding: 0;
32 }
32 }
33 }
33 }
34
34
35 .loginwrapper {
35 .loginwrapper {
36 float: left;
36 float: left;
37 height: 100%;
37 height: 100%;
38 width: 100%;
38 width: 100%;
39 padding: 35px 55px 35px 0;
39 padding: 35px 55px 35px 0;
40 background-color: white;
40 background-color: white;
41 box-sizing: border-box;
41 box-sizing: border-box;
42
42
43 @media (max-width:414px) {
43 @media (max-width:414px) {
44 padding: 35px;
44 padding: 35px;
45 }
45 }
46 }
46 }
47
47
48 .left-column {
48 .left-column {
49 float: left;
49 float: left;
50 position: relative;
50 position: relative;
51 width: 50%;
51 width: 50%;
52 height: 100%;
52 height: 100%;
53
53
54 @media (max-width:414px) {
54 @media (max-width:414px) {
55 display:none;
55 display:none;
56 }
56 }
57 }
57 }
58
58
59 .right-column {
59 .right-column {
60 float: right;
60 float: right;
61 position: relative;
61 position: relative;
62 width: 50%;
62 width: 50%;
63
63
64 @media (max-width:414px) {
64 @media (max-width:414px) {
65 width: 100%;
65 width: 100%;
66 }
66 }
67 }
67 }
68
68
69 .sign-in-image {
69 .sign-in-image {
70 display: block;
70 display: block;
71 width: 65%;
71 width: 65%;
72 margin: 5% auto;
72 margin: 5% auto;
73 }
73 }
74
74
75 .sign-in-title {
75 .sign-in-title {
76 h1 {
76 h1 {
77 margin: 0;
77 margin: 0;
78 }
78 }
79
79
80 h4 {
80 h4 {
81 margin: @padding*2 0;
81 margin: @padding*2 0;
82 }
82 }
83 }
83 }
84
84
85 .form {
85 .form {
86 label {
86 label {
87 display: block;
87 display: block;
88 }
88 }
89
89
90 input {
90 input {
91 width: 100%;
91 width: 100%;
92 margin: 0 10% @padding 0;
92 margin: 0 10% @padding 0;
93 .box-sizing(border-box) ;
93 .box-sizing(border-box) ;
94
94
95 &[type="checkbox"] {
95 &[type="checkbox"] {
96 clear: both;
96 clear: both;
97 width: auto;
97 width: auto;
98 margin: 0 1em @padding 0;
98 margin: 0 1em @padding 0;
99 }
99 }
100 }
100 }
101
101
102 .checkbox {
102 .checkbox {
103 display: inline;
103 display: inline;
104 width: auto;
104 width: auto;
105 }
105 }
106
106
107 .sign-in {
107 .sign-in {
108 clear: both;
108 clear: both;
109 width: 100%;
109 width: 100%;
110 margin: @padding 0;
110 margin: @padding 0;
111 }
111 }
112 }
112 }
113 .register_message,
113 .register_message,
114 .activation_msg {
114 .activation_msg {
115 padding: 0 0 @padding;
115 padding: 0 0 @padding;
116 }
116 }
117
117
118 .buttons,
118 .buttons,
119 .links {
119 .links {
120 padding: 0;
120 padding: 0;
121 }
121 }
122
122
123 .buttons {
123 .buttons {
124 input {
124 input {
125 margin-right: 0;
125 margin-right: 0;
126 .box-sizing(border-box);
126 .box-sizing(border-box);
127 }
127 }
128
128
129 #sign_up, #send {
129 #sign_up, #send {
130 width: 100%;
130 width: 100%;
131 }
131 }
132 }
132 }
133
133
134 .fields {
134 .fields {
135 .field.field-compact {
135 .field.field-compact {
136 margin-bottom: 0px;
136 margin-bottom: 0px;
137 }
137 }
138
138
139 .buttons {
139 .buttons {
140 margin: 0;
140 margin: 0;
141 }
141 }
142
142
143 .field {
143 .field {
144 margin-bottom: 15px;
144 margin-bottom: 15px;
145
145
146 input {
146 input {
147 width: 100%;
147 width: 100%;
148 .box-sizing(border-box);
148 .box-sizing(border-box);
149 }
149 }
150
150
151 .input {
151 .input {
152 margin-left: 0;
152 margin-left: 0;
153 }
153 }
154
154
155 .label {
155 .label {
156 padding-top: 0;
156 padding-top: 0;
157 }
157 }
158 }
158 }
159 }
159 }
160
160
161 .checkbox {
161 .checkbox {
162 margin: 0 0 @textmargin 0;
162 margin: 0 0 @textmargin 0;
163
163
164 input[type="checkbox"] {
164 input[type="checkbox"] {
165 width: auto;
165 width: auto;
166 }
166 }
167
167
168 label {
168 label {
169 padding: 0;
169 padding: 0;
170 min-height: 0;
170 min-height: 0;
171 }
171 }
172 }
172 }
173
173
174 .activation_msg {
174 .activation_msg {
175 padding: @padding 0 0;
175 padding: @padding 0 0;
176 color: @grey4;
176 color: @grey4;
177 }
177 }
178
178
179 .links {
179 .links {
180 float: right;
180 float: right;
181 margin: 0;
181 margin: 0;
182 padding: 0;
182 padding: 0;
183 line-height: 1;
183 line-height: 1;
184
184
185 p {
185 p {
186 float: right;
186 float: right;
187 margin: 0;
187 margin: 0;
188 line-height: 1.5em;
188 line-height: 1.5em;
189 }
189 }
190 }
190 }
191
192 p.help-block {
193 margin-left: 0;
194 }
191 }
195 }
192
196
193 .user-menu.submenu {
197 .user-menu.submenu {
194 right: 0;
198 right: 0;
195 left: auto;
199 left: auto;
196 }
200 }
197 #quick_login {
201 #quick_login {
198 left: auto;
202 left: auto;
199 right: 0;
203 right: 0;
200 padding: @menupadding;
204 padding: @menupadding;
201 z-index: 999;
205 z-index: 999;
202 overflow: hidden;
206 overflow: hidden;
203 background-color: @grey6;
207 background-color: @grey6;
204 color: @grey2;
208 color: @grey2;
205
209
206 h4 {
210 h4 {
207 margin-bottom: 12px;
211 margin-bottom: 12px;
208 }
212 }
209
213
210 .form {
214 .form {
211 width: auto;
215 width: auto;
212 }
216 }
213
217
214 label, .field {
218 label, .field {
215 margin-bottom: 0;
219 margin-bottom: 0;
216 }
220 }
217
221
218 .label {
222 .label {
219 padding-top: 0;
223 padding-top: 0;
220 }
224 }
221
225
222 input {
226 input {
223 min-width: 215px;
227 min-width: 215px;
224 margin: 8px 0 @padding;
228 margin: 8px 0 @padding;
225 }
229 }
226
230
227 input[type="submit"] {
231 input[type="submit"] {
228 &:extend(.btn-primary);
232 &:extend(.btn-primary);
229 width:100%;
233 width:100%;
230 min-width: 0;
234 min-width: 0;
231 }
235 }
232
236
233 .forgot_password,
237 .forgot_password,
234 .buttons .register {
238 .buttons .register {
235 a {
239 a {
236 color: @rcblue;
240 color: @rcblue;
237
241
238 &:hover {
242 &:hover {
239 color: @rcdarkblue;
243 color: @rcdarkblue;
240 }
244 }
241 }
245 }
242 }
246 }
243
247
244 .buttons {
248 .buttons {
245 margin: 0;
249 margin: 0;
246 }
250 }
247
251
248 .buttons a {
252 .buttons a {
249 padding: 8px 0;
253 padding: 8px 0;
250 line-height: 1.4em;
254 line-height: 1.4em;
251 color: @grey4;
255 color: @grey4;
252
256
253 &:hover {
257 &:hover {
254 color: @grey2;
258 color: @grey2;
255 }
259 }
256 }
260 }
257
261
258 #sign_in {
262 #sign_in {
259 margin-bottom: 0
263 margin-bottom: 0
260 }
264 }
261
265
262 .big_gravatar {
266 .big_gravatar {
263 float: left;
267 float: left;
264 display: block;
268 display: block;
265 margin-top: .5em;
269 margin-top: .5em;
266 }
270 }
267
271
268 .full_name,
272 .full_name,
269 .email {
273 .email {
270 margin: 0 0 0 65px;
274 margin: 0 0 0 65px;
271 }
275 }
272
276
273 .email {
277 .email {
274 font-family: @text-light;
278 font-family: @text-light;
275 }
279 }
276
280
277 ol.links {
281 ol.links {
278 clear:both;
282 clear:both;
279 margin: 0;
283 margin: 0;
280 padding: @padding 0 0 0;
284 padding: @padding 0 0 0;
281
285
282 li {
286 li {
283 border-top: @border-thickness solid @grey5;
287 border-top: @border-thickness solid @grey5;
284
288
285 input {
289 input {
286 margin: @padding 0 0 0;
290 margin: @padding 0 0 0;
287 }
291 }
288 }
292 }
289 }
293 }
290 }
294 }
291 .submenu #quick_login li:hover {
295 .submenu #quick_login li:hover {
292 background-color: transparent;
296 background-color: transparent;
293 }
297 }
294
298
295 #quick_login_link:hover + #quick_login {
299 #quick_login_link:hover + #quick_login {
296 display: block;
300 display: block;
297 }
301 }
@@ -1,71 +1,81 b''
1 <div class="panel panel-default">
1 <div class="panel panel-default">
2 <div class="panel-heading">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('System Wide Application Permissions')}</h3>
3 <h3 class="panel-title">${_('System Wide Application Permissions')}</h3>
4 </div>
4 </div>
5 <div class="panel-body">
5 <div class="panel-body">
6 ${h.secure_form(url('admin_permissions_application'), method='post')}
6 ${h.secure_form(url('admin_permissions_application'), method='post')}
7 <div class="form">
7 <div class="form">
8 <!-- fields -->
8 <!-- fields -->
9 <div class="fields">
9 <div class="fields">
10 <div class="field">
10 <div class="field">
11 <div class="label label-checkbox">
11 <div class="label label-checkbox">
12 <label for="anonymous">${_('Anonymous Access')}:</label>
12 <label for="anonymous">${_('Anonymous Access')}:</label>
13 </div>
13 </div>
14 <div class="checkboxes">
14 <div class="checkboxes">
15 <div class="checkbox">
15 <div class="checkbox">
16 ${h.checkbox('anonymous',True)} Allow Anonymous Access
16 ${h.checkbox('anonymous',True)} Allow Anonymous Access
17 </div>
17 </div>
18 <span class="help-block">${h.literal(_('Allow access to RhodeCode Enterprise without requiring users to login. Anonymous users get the %s permission settings.' % (h.link_to('"default user"',h.url('admin_permissions_object')))))}</span>
18 <span class="help-block">${h.literal(_('Allow access to RhodeCode Enterprise without requiring users to login. Anonymous users get the %s permission settings.' % (h.link_to('"default user"',h.url('admin_permissions_object')))))}</span>
19 </div>
19 </div>
20 </div>
20 </div>
21
21
22 <div class="field">
22 <div class="field">
23 <div class="label label-select">
23 <div class="label label-select">
24 <label for="default_register">${_('Registration')}:</label>
24 <label for="default_register">${_('Registration')}:</label>
25 </div>
25 </div>
26 <div class="select">
26 <div class="select">
27 ${h.select('default_register','',c.register_choices)}
27 ${h.select('default_register','',c.register_choices)}
28 </div>
28 </div>
29 </div>
29 </div>
30
30
31 <div class="field">
31 <div class="field">
32 <div class="label label-select">
33 <label for="default_password_reset">${_('Password Reset')}:</label>
34 </div>
35 <div class="select">
36 ${h.select('default_password_reset','',c.password_reset_choices)}
37 </div>
38 </div>
39
40 <div class="field">
32 <div class="label label-textarea">
41 <div class="label label-textarea">
33 <label for="default_register_message">${_('Registration Page Message')}:</label>
42 <label for="default_register_message">${_('Registration Page Message')}:</label>
34 </div>
43 </div>
35 <div class="textarea text-area editor" >
44 <div class="textarea text-area editor" >
36 ${h.textarea('default_register_message', class_="medium", )}
45 ${h.textarea('default_register_message', class_="medium", )}
37 <span class="help-block">${_('Custom message to be displayed on the registration page. HTML syntax is supported.')}</span>
46 <span class="help-block">${_('Custom message to be displayed on the registration page. HTML syntax is supported.')}</span>
38 </div>
47 </div>
39 </div>
48 </div>
40
49
41 <div class="field">
50 <div class="field">
42 <div class="label">
51 <div class="label">
43 <label for="default_extern_activate">${_('External Authentication Account Activation')}:</label>
52 <label for="default_extern_activate">${_('External Authentication Account Activation')}:</label>
44 </div>
53 </div>
45 <div class="select">
54 <div class="select">
46 ${h.select('default_extern_activate','',c.extern_activate_choices)}
55 ${h.select('default_extern_activate','',c.extern_activate_choices)}
47 </div>
56 </div>
48 </div>
57 </div>
49 <div class="buttons">
58 <div class="buttons">
50 ${h.submit('save',_('Save'),class_="btn")}
59 ${h.submit('save',_('Save'),class_="btn")}
51 ${h.reset('reset',_('Reset'),class_="btn")}
60 ${h.reset('reset',_('Reset'),class_="btn")}
52 </div>
61 </div>
53 </div>
62 </div>
54 </div>
63 </div>
55 ${h.end_form()}
64 ${h.end_form()}
56 </div>
65 </div>
57 </div>
66 </div>
58
67
59 <script>
68 <script>
60 $(document).ready(function(){
69 $(document).ready(function(){
61 var select2Options = {
70 var select2Options = {
62 containerCssClass: 'drop-menu',
71 containerCssClass: 'drop-menu',
63 dropdownCssClass: 'drop-menu-dropdown',
72 dropdownCssClass: 'drop-menu-dropdown',
64 dropdownAutoWidth: true,
73 dropdownAutoWidth: true,
65 minimumResultsForSearch: -1
74 minimumResultsForSearch: -1
66 };
75 };
67
76
68 $("#default_register").select2(select2Options);
77 $("#default_register").select2(select2Options);
78 $("#default_password_reset").select2(select2Options);
69 $("#default_extern_activate").select2(select2Options);
79 $("#default_extern_activate").select2(select2Options);
70 });
80 });
71 </script>
81 </script>
@@ -1,651 +1,653 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.html"/>
2 <%inherit file="root.html"/>
3
3
4 <div class="outerwrapper">
4 <div class="outerwrapper">
5 <!-- HEADER -->
5 <!-- HEADER -->
6 <div class="header">
6 <div class="header">
7 <div id="header-inner" class="wrapper">
7 <div id="header-inner" class="wrapper">
8 <div id="logo">
8 <div id="logo">
9 <div class="logo-wrapper">
9 <div class="logo-wrapper">
10 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
10 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
11 </div>
11 </div>
12 %if c.rhodecode_name:
12 %if c.rhodecode_name:
13 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
13 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
14 %endif
14 %endif
15 </div>
15 </div>
16 <!-- MENU BAR NAV -->
16 <!-- MENU BAR NAV -->
17 ${self.menu_bar_nav()}
17 ${self.menu_bar_nav()}
18 <!-- END MENU BAR NAV -->
18 <!-- END MENU BAR NAV -->
19 </div>
19 </div>
20 </div>
20 </div>
21 ${self.menu_bar_subnav()}
21 ${self.menu_bar_subnav()}
22 <!-- END HEADER -->
22 <!-- END HEADER -->
23
23
24 <!-- CONTENT -->
24 <!-- CONTENT -->
25 <div id="content" class="wrapper">
25 <div id="content" class="wrapper">
26 <div class="main">
26 <div class="main">
27 ${next.main()}
27 ${next.main()}
28 </div>
28 </div>
29 </div>
29 </div>
30 <!-- END CONTENT -->
30 <!-- END CONTENT -->
31
31
32 </div>
32 </div>
33 <!-- FOOTER -->
33 <!-- FOOTER -->
34 <div id="footer">
34 <div id="footer">
35 <div id="footer-inner" class="title wrapper">
35 <div id="footer-inner" class="title wrapper">
36 <div>
36 <div>
37 <p class="footer-link-right">
37 <p class="footer-link-right">
38 % if c.visual.show_version:
38 % if c.visual.show_version:
39 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
39 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
40 % endif
40 % endif
41 &copy; 2010-${h.datetime.today().year}, <a href="${h.url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
41 &copy; 2010-${h.datetime.today().year}, <a href="${h.url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
42 % if c.visual.rhodecode_support_url:
42 % if c.visual.rhodecode_support_url:
43 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
43 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
44 % endif
44 % endif
45 </p>
45 </p>
46 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
46 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
47 <p class="server-instance" style="display:${sid}">
47 <p class="server-instance" style="display:${sid}">
48 ## display hidden instance ID if specially defined
48 ## display hidden instance ID if specially defined
49 % if c.rhodecode_instanceid:
49 % if c.rhodecode_instanceid:
50 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
50 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
51 % endif
51 % endif
52 </p>
52 </p>
53 </div>
53 </div>
54 </div>
54 </div>
55 </div>
55 </div>
56
56
57 <!-- END FOOTER -->
57 <!-- END FOOTER -->
58
58
59 ### MAKO DEFS ###
59 ### MAKO DEFS ###
60
60
61 <%def name="menu_bar_subnav()">
61 <%def name="menu_bar_subnav()">
62 </%def>
62 </%def>
63
63
64 <%def name="breadcrumbs(class_='breadcrumbs')">
64 <%def name="breadcrumbs(class_='breadcrumbs')">
65 <div class="${class_}">
65 <div class="${class_}">
66 ${self.breadcrumbs_links()}
66 ${self.breadcrumbs_links()}
67 </div>
67 </div>
68 </%def>
68 </%def>
69
69
70 <%def name="admin_menu()">
70 <%def name="admin_menu()">
71 <ul class="admin_menu submenu">
71 <ul class="admin_menu submenu">
72 <li><a href="${h.url('admin_home')}">${_('Admin journal')}</a></li>
72 <li><a href="${h.url('admin_home')}">${_('Admin journal')}</a></li>
73 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
73 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
74 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
74 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
75 <li><a href="${h.url('users')}">${_('Users')}</a></li>
75 <li><a href="${h.url('users')}">${_('Users')}</a></li>
76 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
76 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
77 <li><a href="${h.url('admin_permissions_application')}">${_('Permissions')}</a></li>
77 <li><a href="${h.url('admin_permissions_application')}">${_('Permissions')}</a></li>
78 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
78 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
79 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
79 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
80 <li><a href="${h.url('admin_defaults_repositories')}">${_('Defaults')}</a></li>
80 <li><a href="${h.url('admin_defaults_repositories')}">${_('Defaults')}</a></li>
81 <li class="last"><a href="${h.url('admin_settings')}">${_('Settings')}</a></li>
81 <li class="last"><a href="${h.url('admin_settings')}">${_('Settings')}</a></li>
82 </ul>
82 </ul>
83 </%def>
83 </%def>
84
84
85
85
86 <%def name="dt_info_panel(elements)">
86 <%def name="dt_info_panel(elements)">
87 <dl class="dl-horizontal">
87 <dl class="dl-horizontal">
88 %for dt, dd, title, show_items in elements:
88 %for dt, dd, title, show_items in elements:
89 <dt>${dt}:</dt>
89 <dt>${dt}:</dt>
90 <dd title="${title}">
90 <dd title="${title}">
91 %if callable(dd):
91 %if callable(dd):
92 ## allow lazy evaluation of elements
92 ## allow lazy evaluation of elements
93 ${dd()}
93 ${dd()}
94 %else:
94 %else:
95 ${dd}
95 ${dd}
96 %endif
96 %endif
97 %if show_items:
97 %if show_items:
98 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
98 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
99 %endif
99 %endif
100 </dd>
100 </dd>
101
101
102 %if show_items:
102 %if show_items:
103 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
103 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
104 %for item in show_items:
104 %for item in show_items:
105 <dt></dt>
105 <dt></dt>
106 <dd>${item}</dd>
106 <dd>${item}</dd>
107 %endfor
107 %endfor
108 </div>
108 </div>
109 %endif
109 %endif
110
110
111 %endfor
111 %endfor
112 </dl>
112 </dl>
113 </%def>
113 </%def>
114
114
115
115
116 <%def name="gravatar(email, size=16)">
116 <%def name="gravatar(email, size=16)">
117 <%
117 <%
118 if (size > 16):
118 if (size > 16):
119 gravatar_class = 'gravatar gravatar-large'
119 gravatar_class = 'gravatar gravatar-large'
120 else:
120 else:
121 gravatar_class = 'gravatar'
121 gravatar_class = 'gravatar'
122 %>
122 %>
123 <%doc>
123 <%doc>
124 TODO: johbo: For now we serve double size images to make it smooth
124 TODO: johbo: For now we serve double size images to make it smooth
125 for retina. This is how it worked until now. Should be replaced
125 for retina. This is how it worked until now. Should be replaced
126 with a better solution at some point.
126 with a better solution at some point.
127 </%doc>
127 </%doc>
128 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
128 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
129 </%def>
129 </%def>
130
130
131
131
132 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
132 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
133 <% email = h.email_or_none(contact) %>
133 <% email = h.email_or_none(contact) %>
134 <div class="rc-user tooltip" title="${h.author_string(email)}">
134 <div class="rc-user tooltip" title="${h.author_string(email)}">
135 ${self.gravatar(email, size)}
135 ${self.gravatar(email, size)}
136 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
136 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
137 </div>
137 </div>
138 </%def>
138 </%def>
139
139
140
140
141 ## admin menu used for people that have some admin resources
141 ## admin menu used for people that have some admin resources
142 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
142 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
143 <ul class="submenu">
143 <ul class="submenu">
144 %if repositories:
144 %if repositories:
145 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
145 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
146 %endif
146 %endif
147 %if repository_groups:
147 %if repository_groups:
148 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
148 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
149 %endif
149 %endif
150 %if user_groups:
150 %if user_groups:
151 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
151 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
152 %endif
152 %endif
153 </ul>
153 </ul>
154 </%def>
154 </%def>
155
155
156 <%def name="repo_page_title(repo_instance)">
156 <%def name="repo_page_title(repo_instance)">
157 <div class="title-content">
157 <div class="title-content">
158 <div class="title-main">
158 <div class="title-main">
159 ## SVN/HG/GIT icons
159 ## SVN/HG/GIT icons
160 %if h.is_hg(repo_instance):
160 %if h.is_hg(repo_instance):
161 <i class="icon-hg"></i>
161 <i class="icon-hg"></i>
162 %endif
162 %endif
163 %if h.is_git(repo_instance):
163 %if h.is_git(repo_instance):
164 <i class="icon-git"></i>
164 <i class="icon-git"></i>
165 %endif
165 %endif
166 %if h.is_svn(repo_instance):
166 %if h.is_svn(repo_instance):
167 <i class="icon-svn"></i>
167 <i class="icon-svn"></i>
168 %endif
168 %endif
169
169
170 ## public/private
170 ## public/private
171 %if repo_instance.private:
171 %if repo_instance.private:
172 <i class="icon-repo-private"></i>
172 <i class="icon-repo-private"></i>
173 %else:
173 %else:
174 <i class="icon-repo-public"></i>
174 <i class="icon-repo-public"></i>
175 %endif
175 %endif
176
176
177 ## repo name with group name
177 ## repo name with group name
178 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
178 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
179
179
180 </div>
180 </div>
181
181
182 ## FORKED
182 ## FORKED
183 %if repo_instance.fork:
183 %if repo_instance.fork:
184 <p>
184 <p>
185 <i class="icon-code-fork"></i> ${_('Fork of')}
185 <i class="icon-code-fork"></i> ${_('Fork of')}
186 <a href="${h.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
186 <a href="${h.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
187 </p>
187 </p>
188 %endif
188 %endif
189
189
190 ## IMPORTED FROM REMOTE
190 ## IMPORTED FROM REMOTE
191 %if repo_instance.clone_uri:
191 %if repo_instance.clone_uri:
192 <p>
192 <p>
193 <i class="icon-code-fork"></i> ${_('Clone from')}
193 <i class="icon-code-fork"></i> ${_('Clone from')}
194 <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
194 <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
195 </p>
195 </p>
196 %endif
196 %endif
197
197
198 ## LOCKING STATUS
198 ## LOCKING STATUS
199 %if repo_instance.locked[0]:
199 %if repo_instance.locked[0]:
200 <p class="locking_locked">
200 <p class="locking_locked">
201 <i class="icon-repo-lock"></i>
201 <i class="icon-repo-lock"></i>
202 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
202 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
203 </p>
203 </p>
204 %elif repo_instance.enable_locking:
204 %elif repo_instance.enable_locking:
205 <p class="locking_unlocked">
205 <p class="locking_unlocked">
206 <i class="icon-repo-unlock"></i>
206 <i class="icon-repo-unlock"></i>
207 ${_('Repository not locked. Pull repository to lock it.')}
207 ${_('Repository not locked. Pull repository to lock it.')}
208 </p>
208 </p>
209 %endif
209 %endif
210
210
211 </div>
211 </div>
212 </%def>
212 </%def>
213
213
214 <%def name="repo_menu(active=None)">
214 <%def name="repo_menu(active=None)">
215 <%
215 <%
216 def is_active(selected):
216 def is_active(selected):
217 if selected == active:
217 if selected == active:
218 return "active"
218 return "active"
219 %>
219 %>
220
220
221 <!--- CONTEXT BAR -->
221 <!--- CONTEXT BAR -->
222 <div id="context-bar">
222 <div id="context-bar">
223 <div class="wrapper">
223 <div class="wrapper">
224 <ul id="context-pages" class="horizontal-list navigation">
224 <ul id="context-pages" class="horizontal-list navigation">
225 <li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
225 <li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
226 <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
226 <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
227 <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
227 <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
228 <li class="${is_active('compare')}">
228 <li class="${is_active('compare')}">
229 <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a>
229 <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a>
230 </li>
230 </li>
231 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
231 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
232 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
232 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
233 <li class="${is_active('showpullrequest')}">
233 <li class="${is_active('showpullrequest')}">
234 <a class="menulink" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}">
234 <a class="menulink" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}">
235 %if c.repository_pull_requests:
235 %if c.repository_pull_requests:
236 <span class="pr_notifications">${c.repository_pull_requests}</span>
236 <span class="pr_notifications">${c.repository_pull_requests}</span>
237 %endif
237 %endif
238 <div class="menulabel">${_('Pull Requests')}</div>
238 <div class="menulabel">${_('Pull Requests')}</div>
239 </a>
239 </a>
240 </li>
240 </li>
241 %endif
241 %endif
242 <li class="${is_active('options')}">
242 <li class="${is_active('options')}">
243 <a class="menulink" href="#" class="dropdown"><div class="menulabel">${_('Options')} <div class="show_more"></div></div></a>
243 <a class="menulink" href="#" class="dropdown"><div class="menulabel">${_('Options')} <div class="show_more"></div></div></a>
244 <ul class="submenu">
244 <ul class="submenu">
245 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
245 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
246 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
246 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
247 %endif
247 %endif
248 %if c.rhodecode_db_repo.fork:
248 %if c.rhodecode_db_repo.fork:
249 <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}">
249 <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}">
250 ${_('Compare fork')}</a></li>
250 ${_('Compare fork')}</a></li>
251 %endif
251 %endif
252
252
253 <li><a href="${h.url('search_repo_home',repo_name=c.repo_name)}">${_('Search')}</a></li>
253 <li><a href="${h.url('search_repo_home',repo_name=c.repo_name)}">${_('Search')}</a></li>
254
254
255 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
255 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
256 %if c.rhodecode_db_repo.locked[0]:
256 %if c.rhodecode_db_repo.locked[0]:
257 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
257 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
258 %else:
258 %else:
259 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
259 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
260 %endif
260 %endif
261 %endif
261 %endif
262 %if c.rhodecode_user.username != h.DEFAULT_USER:
262 %if c.rhodecode_user.username != h.DEFAULT_USER:
263 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
263 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
264 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
264 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
265 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
265 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
266 %endif
266 %endif
267 %endif
267 %endif
268 </ul>
268 </ul>
269 </li>
269 </li>
270 </ul>
270 </ul>
271 </div>
271 </div>
272 <div class="clear"></div>
272 <div class="clear"></div>
273 </div>
273 </div>
274 <!--- END CONTEXT BAR -->
274 <!--- END CONTEXT BAR -->
275
275
276 </%def>
276 </%def>
277
277
278 <%def name="usermenu()">
278 <%def name="usermenu()">
279 ## USER MENU
279 ## USER MENU
280 <li id="quick_login_li">
280 <li id="quick_login_li">
281 <a id="quick_login_link" class="menulink childs">
281 <a id="quick_login_link" class="menulink childs">
282 ${gravatar(c.rhodecode_user.email, 20)}
282 ${gravatar(c.rhodecode_user.email, 20)}
283 <span class="user">
283 <span class="user">
284 %if c.rhodecode_user.username != h.DEFAULT_USER:
284 %if c.rhodecode_user.username != h.DEFAULT_USER:
285 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
285 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
286 %else:
286 %else:
287 <span>${_('Sign in')}</span>
287 <span>${_('Sign in')}</span>
288 %endif
288 %endif
289 </span>
289 </span>
290 </a>
290 </a>
291
291
292 <div class="user-menu submenu">
292 <div class="user-menu submenu">
293 <div id="quick_login">
293 <div id="quick_login">
294 %if c.rhodecode_user.username == h.DEFAULT_USER:
294 %if c.rhodecode_user.username == h.DEFAULT_USER:
295 <h4>${_('Sign in to your account')}</h4>
295 <h4>${_('Sign in to your account')}</h4>
296 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
296 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
297 <div class="form form-vertical">
297 <div class="form form-vertical">
298 <div class="fields">
298 <div class="fields">
299 <div class="field">
299 <div class="field">
300 <div class="label">
300 <div class="label">
301 <label for="username">${_('Username')}:</label>
301 <label for="username">${_('Username')}:</label>
302 </div>
302 </div>
303 <div class="input">
303 <div class="input">
304 ${h.text('username',class_='focus',tabindex=1)}
304 ${h.text('username',class_='focus',tabindex=1)}
305 </div>
305 </div>
306
306
307 </div>
307 </div>
308 <div class="field">
308 <div class="field">
309 <div class="label">
309 <div class="label">
310 <label for="password">${_('Password')}:</label>
310 <label for="password">${_('Password')}:</label>
311 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'))}</span>
311 %if h.HasPermissionAny('hg.password_reset.enabled')():
312 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'))}</span>
313 %endif
312 </div>
314 </div>
313 <div class="input">
315 <div class="input">
314 ${h.password('password',class_='focus',tabindex=2)}
316 ${h.password('password',class_='focus',tabindex=2)}
315 </div>
317 </div>
316 </div>
318 </div>
317 <div class="buttons">
319 <div class="buttons">
318 <div class="register">
320 <div class="register">
319 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
321 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
320 ${h.link_to(_("Don't have an account ?"),h.route_path('register'))}
322 ${h.link_to(_("Don't have an account ?"),h.route_path('register'))}
321 %endif
323 %endif
322 </div>
324 </div>
323 <div class="submit">
325 <div class="submit">
324 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
326 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
325 </div>
327 </div>
326 </div>
328 </div>
327 </div>
329 </div>
328 </div>
330 </div>
329 ${h.end_form()}
331 ${h.end_form()}
330 %else:
332 %else:
331 <div class="">
333 <div class="">
332 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
334 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
333 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
335 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
334 <div class="email">${c.rhodecode_user.email}</div>
336 <div class="email">${c.rhodecode_user.email}</div>
335 </div>
337 </div>
336 <div class="">
338 <div class="">
337 <ol class="links">
339 <ol class="links">
338 <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li>
340 <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li>
339 <li class="logout">
341 <li class="logout">
340 ${h.secure_form(h.route_path('logout'))}
342 ${h.secure_form(h.route_path('logout'))}
341 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
343 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
342 ${h.end_form()}
344 ${h.end_form()}
343 </li>
345 </li>
344 </ol>
346 </ol>
345 </div>
347 </div>
346 %endif
348 %endif
347 </div>
349 </div>
348 </div>
350 </div>
349 %if c.rhodecode_user.username != h.DEFAULT_USER:
351 %if c.rhodecode_user.username != h.DEFAULT_USER:
350 <div class="pill_container">
352 <div class="pill_container">
351 % if c.unread_notifications == 0:
353 % if c.unread_notifications == 0:
352 <a class="menu_link_notifications empty" href="${h.url('notifications')}">${c.unread_notifications}</a>
354 <a class="menu_link_notifications empty" href="${h.url('notifications')}">${c.unread_notifications}</a>
353 % else:
355 % else:
354 <a class="menu_link_notifications" href="${h.url('notifications')}">${c.unread_notifications}</a>
356 <a class="menu_link_notifications" href="${h.url('notifications')}">${c.unread_notifications}</a>
355 % endif
357 % endif
356 </div>
358 </div>
357 % endif
359 % endif
358 </li>
360 </li>
359 </%def>
361 </%def>
360
362
361 <%def name="menu_items(active=None)">
363 <%def name="menu_items(active=None)">
362 <%
364 <%
363 def is_active(selected):
365 def is_active(selected):
364 if selected == active:
366 if selected == active:
365 return "active"
367 return "active"
366 return ""
368 return ""
367 %>
369 %>
368 <ul id="quick" class="main_nav navigation horizontal-list">
370 <ul id="quick" class="main_nav navigation horizontal-list">
369 <!-- repo switcher -->
371 <!-- repo switcher -->
370 <li class="${is_active('repositories')} repo_switcher_li has_select2">
372 <li class="${is_active('repositories')} repo_switcher_li has_select2">
371 <input id="repo_switcher" name="repo_switcher" type="hidden">
373 <input id="repo_switcher" name="repo_switcher" type="hidden">
372 </li>
374 </li>
373
375
374 ## ROOT MENU
376 ## ROOT MENU
375 %if c.rhodecode_user.username != h.DEFAULT_USER:
377 %if c.rhodecode_user.username != h.DEFAULT_USER:
376 <li class="${is_active('journal')}">
378 <li class="${is_active('journal')}">
377 <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}">
379 <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}">
378 <div class="menulabel">${_('Journal')}</div>
380 <div class="menulabel">${_('Journal')}</div>
379 </a>
381 </a>
380 </li>
382 </li>
381 %else:
383 %else:
382 <li class="${is_active('journal')}">
384 <li class="${is_active('journal')}">
383 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}">
385 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}">
384 <div class="menulabel">${_('Public journal')}</div>
386 <div class="menulabel">${_('Public journal')}</div>
385 </a>
387 </a>
386 </li>
388 </li>
387 %endif
389 %endif
388 <li class="${is_active('gists')}">
390 <li class="${is_active('gists')}">
389 <a class="menulink childs" title="${_('Show Gists')}" href="${h.url('gists')}">
391 <a class="menulink childs" title="${_('Show Gists')}" href="${h.url('gists')}">
390 <div class="menulabel">${_('Gists')}</div>
392 <div class="menulabel">${_('Gists')}</div>
391 </a>
393 </a>
392 </li>
394 </li>
393 <li class="${is_active('search')}">
395 <li class="${is_active('search')}">
394 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.url('search')}">
396 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.url('search')}">
395 <div class="menulabel">${_('Search')}</div>
397 <div class="menulabel">${_('Search')}</div>
396 </a>
398 </a>
397 </li>
399 </li>
398 % if h.HasPermissionAll('hg.admin')('access admin main page'):
400 % if h.HasPermissionAll('hg.admin')('access admin main page'):
399 <li class="${is_active('admin')}">
401 <li class="${is_active('admin')}">
400 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
402 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
401 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
403 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
402 </a>
404 </a>
403 ${admin_menu()}
405 ${admin_menu()}
404 </li>
406 </li>
405 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
407 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
406 <li class="${is_active('admin')}">
408 <li class="${is_active('admin')}">
407 <a class="menulink childs" title="${_('Delegated Admin settings')}">
409 <a class="menulink childs" title="${_('Delegated Admin settings')}">
408 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
410 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
409 </a>
411 </a>
410 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
412 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
411 c.rhodecode_user.repository_groups_admin,
413 c.rhodecode_user.repository_groups_admin,
412 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
414 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
413 </li>
415 </li>
414 % endif
416 % endif
415 % if c.debug_style:
417 % if c.debug_style:
416 <li class="${is_active('debug_style')}">
418 <li class="${is_active('debug_style')}">
417 <a class="menulink" title="${_('Style')}" href="${h.url('debug_style_home')}">
419 <a class="menulink" title="${_('Style')}" href="${h.url('debug_style_home')}">
418 <div class="menulabel">${_('Style')}</div>
420 <div class="menulabel">${_('Style')}</div>
419 </a>
421 </a>
420 </li>
422 </li>
421 % endif
423 % endif
422 ## render extra user menu
424 ## render extra user menu
423 ${usermenu()}
425 ${usermenu()}
424 </ul>
426 </ul>
425
427
426 <script type="text/javascript">
428 <script type="text/javascript">
427 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
429 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
428
430
429 /*format the look of items in the list*/
431 /*format the look of items in the list*/
430 var format = function(state, escapeMarkup){
432 var format = function(state, escapeMarkup){
431 if (!state.id){
433 if (!state.id){
432 return state.text; // optgroup
434 return state.text; // optgroup
433 }
435 }
434 var obj_dict = state.obj;
436 var obj_dict = state.obj;
435 var tmpl = '';
437 var tmpl = '';
436
438
437 if(obj_dict && state.type == 'repo'){
439 if(obj_dict && state.type == 'repo'){
438 if(obj_dict['repo_type'] === 'hg'){
440 if(obj_dict['repo_type'] === 'hg'){
439 tmpl += '<i class="icon-hg"></i> ';
441 tmpl += '<i class="icon-hg"></i> ';
440 }
442 }
441 else if(obj_dict['repo_type'] === 'git'){
443 else if(obj_dict['repo_type'] === 'git'){
442 tmpl += '<i class="icon-git"></i> ';
444 tmpl += '<i class="icon-git"></i> ';
443 }
445 }
444 else if(obj_dict['repo_type'] === 'svn'){
446 else if(obj_dict['repo_type'] === 'svn'){
445 tmpl += '<i class="icon-svn"></i> ';
447 tmpl += '<i class="icon-svn"></i> ';
446 }
448 }
447 if(obj_dict['private']){
449 if(obj_dict['private']){
448 tmpl += '<i class="icon-lock" ></i> ';
450 tmpl += '<i class="icon-lock" ></i> ';
449 }
451 }
450 else if(visual_show_public_icon){
452 else if(visual_show_public_icon){
451 tmpl += '<i class="icon-unlock-alt"></i> ';
453 tmpl += '<i class="icon-unlock-alt"></i> ';
452 }
454 }
453 }
455 }
454 if(obj_dict && state.type == 'commit') {
456 if(obj_dict && state.type == 'commit') {
455 tmpl += '<i class="icon-tag"></i>';
457 tmpl += '<i class="icon-tag"></i>';
456 }
458 }
457 if(obj_dict && state.type == 'group'){
459 if(obj_dict && state.type == 'group'){
458 tmpl += '<i class="icon-folder-close"></i> ';
460 tmpl += '<i class="icon-folder-close"></i> ';
459 }
461 }
460 tmpl += escapeMarkup(state.text);
462 tmpl += escapeMarkup(state.text);
461 return tmpl;
463 return tmpl;
462 };
464 };
463
465
464 var formatResult = function(result, container, query, escapeMarkup) {
466 var formatResult = function(result, container, query, escapeMarkup) {
465 return format(result, escapeMarkup);
467 return format(result, escapeMarkup);
466 };
468 };
467
469
468 var formatSelection = function(data, container, escapeMarkup) {
470 var formatSelection = function(data, container, escapeMarkup) {
469 return format(data, escapeMarkup);
471 return format(data, escapeMarkup);
470 };
472 };
471
473
472 $("#repo_switcher").select2({
474 $("#repo_switcher").select2({
473 cachedDataSource: {},
475 cachedDataSource: {},
474 minimumInputLength: 2,
476 minimumInputLength: 2,
475 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
477 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
476 dropdownAutoWidth: true,
478 dropdownAutoWidth: true,
477 formatResult: formatResult,
479 formatResult: formatResult,
478 formatSelection: formatSelection,
480 formatSelection: formatSelection,
479 containerCssClass: "repo-switcher",
481 containerCssClass: "repo-switcher",
480 dropdownCssClass: "repo-switcher-dropdown",
482 dropdownCssClass: "repo-switcher-dropdown",
481 escapeMarkup: function(m){
483 escapeMarkup: function(m){
482 // don't escape our custom placeholder
484 // don't escape our custom placeholder
483 if(m.substr(0,23) == '<div class="menulabel">'){
485 if(m.substr(0,23) == '<div class="menulabel">'){
484 return m;
486 return m;
485 }
487 }
486
488
487 return Select2.util.escapeMarkup(m);
489 return Select2.util.escapeMarkup(m);
488 },
490 },
489 query: $.debounce(250, function(query){
491 query: $.debounce(250, function(query){
490 self = this;
492 self = this;
491 var cacheKey = query.term;
493 var cacheKey = query.term;
492 var cachedData = self.cachedDataSource[cacheKey];
494 var cachedData = self.cachedDataSource[cacheKey];
493
495
494 if (cachedData) {
496 if (cachedData) {
495 query.callback({results: cachedData.results});
497 query.callback({results: cachedData.results});
496 } else {
498 } else {
497 $.ajax({
499 $.ajax({
498 url: "${h.url('goto_switcher_data')}",
500 url: "${h.url('goto_switcher_data')}",
499 data: {'query': query.term},
501 data: {'query': query.term},
500 dataType: 'json',
502 dataType: 'json',
501 type: 'GET',
503 type: 'GET',
502 success: function(data) {
504 success: function(data) {
503 self.cachedDataSource[cacheKey] = data;
505 self.cachedDataSource[cacheKey] = data;
504 query.callback({results: data.results});
506 query.callback({results: data.results});
505 },
507 },
506 error: function(data, textStatus, errorThrown) {
508 error: function(data, textStatus, errorThrown) {
507 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
509 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
508 }
510 }
509 })
511 })
510 }
512 }
511 })
513 })
512 });
514 });
513
515
514 $("#repo_switcher").on('select2-selecting', function(e){
516 $("#repo_switcher").on('select2-selecting', function(e){
515 e.preventDefault();
517 e.preventDefault();
516 window.location = e.choice.url;
518 window.location = e.choice.url;
517 });
519 });
518
520
519 ## Global mouse bindings ##
521 ## Global mouse bindings ##
520
522
521 // general help "?"
523 // general help "?"
522 Mousetrap.bind(['?'], function(e) {
524 Mousetrap.bind(['?'], function(e) {
523 $('#help_kb').modal({})
525 $('#help_kb').modal({})
524 });
526 });
525
527
526 // / open the quick filter
528 // / open the quick filter
527 Mousetrap.bind(['/'], function(e) {
529 Mousetrap.bind(['/'], function(e) {
528 $("#repo_switcher").select2("open");
530 $("#repo_switcher").select2("open");
529
531
530 // return false to prevent default browser behavior
532 // return false to prevent default browser behavior
531 // and stop event from bubbling
533 // and stop event from bubbling
532 return false;
534 return false;
533 });
535 });
534
536
535 // general nav g + action
537 // general nav g + action
536 Mousetrap.bind(['g h'], function(e) {
538 Mousetrap.bind(['g h'], function(e) {
537 window.location = pyroutes.url('home');
539 window.location = pyroutes.url('home');
538 });
540 });
539 Mousetrap.bind(['g g'], function(e) {
541 Mousetrap.bind(['g g'], function(e) {
540 window.location = pyroutes.url('gists', {'private':1});
542 window.location = pyroutes.url('gists', {'private':1});
541 });
543 });
542 Mousetrap.bind(['g G'], function(e) {
544 Mousetrap.bind(['g G'], function(e) {
543 window.location = pyroutes.url('gists', {'public':1});
545 window.location = pyroutes.url('gists', {'public':1});
544 });
546 });
545 Mousetrap.bind(['n g'], function(e) {
547 Mousetrap.bind(['n g'], function(e) {
546 window.location = pyroutes.url('new_gist');
548 window.location = pyroutes.url('new_gist');
547 });
549 });
548 Mousetrap.bind(['n r'], function(e) {
550 Mousetrap.bind(['n r'], function(e) {
549 window.location = pyroutes.url('new_repo');
551 window.location = pyroutes.url('new_repo');
550 });
552 });
551
553
552 % if hasattr(c, 'repo_name') and hasattr(c, 'rhodecode_db_repo'):
554 % if hasattr(c, 'repo_name') and hasattr(c, 'rhodecode_db_repo'):
553 // nav in repo context
555 // nav in repo context
554 Mousetrap.bind(['g s'], function(e) {
556 Mousetrap.bind(['g s'], function(e) {
555 window.location = pyroutes.url('summary_home', {'repo_name': REPO_NAME});
557 window.location = pyroutes.url('summary_home', {'repo_name': REPO_NAME});
556 });
558 });
557 Mousetrap.bind(['g c'], function(e) {
559 Mousetrap.bind(['g c'], function(e) {
558 window.location = pyroutes.url('changelog_home', {'repo_name': REPO_NAME});
560 window.location = pyroutes.url('changelog_home', {'repo_name': REPO_NAME});
559 });
561 });
560 Mousetrap.bind(['g F'], function(e) {
562 Mousetrap.bind(['g F'], function(e) {
561 window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.rhodecode_db_repo.landing_rev[1]}', 'f_path': '', 'search': '1'});
563 window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.rhodecode_db_repo.landing_rev[1]}', 'f_path': '', 'search': '1'});
562 });
564 });
563 Mousetrap.bind(['g f'], function(e) {
565 Mousetrap.bind(['g f'], function(e) {
564 window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.rhodecode_db_repo.landing_rev[1]}', 'f_path': ''});
566 window.location = pyroutes.url('files_home', {'repo_name': REPO_NAME, 'revision': '${c.rhodecode_db_repo.landing_rev[1]}', 'f_path': ''});
565 });
567 });
566 Mousetrap.bind(['g p'], function(e) {
568 Mousetrap.bind(['g p'], function(e) {
567 window.location = pyroutes.url('pullrequest_show_all', {'repo_name': REPO_NAME});
569 window.location = pyroutes.url('pullrequest_show_all', {'repo_name': REPO_NAME});
568 });
570 });
569 Mousetrap.bind(['g o'], function(e) {
571 Mousetrap.bind(['g o'], function(e) {
570 window.location = pyroutes.url('edit_repo', {'repo_name': REPO_NAME});
572 window.location = pyroutes.url('edit_repo', {'repo_name': REPO_NAME});
571 });
573 });
572 Mousetrap.bind(['g O'], function(e) {
574 Mousetrap.bind(['g O'], function(e) {
573 window.location = pyroutes.url('edit_repo_perms', {'repo_name': REPO_NAME});
575 window.location = pyroutes.url('edit_repo_perms', {'repo_name': REPO_NAME});
574 });
576 });
575 % endif
577 % endif
576
578
577 </script>
579 </script>
578 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
580 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
579 </%def>
581 </%def>
580
582
581 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
583 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
582 <div class="modal-dialog">
584 <div class="modal-dialog">
583 <div class="modal-content">
585 <div class="modal-content">
584 <div class="modal-header">
586 <div class="modal-header">
585 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
587 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
586 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
588 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
587 </div>
589 </div>
588 <div class="modal-body">
590 <div class="modal-body">
589 <div class="block-left">
591 <div class="block-left">
590 <table class="keyboard-mappings">
592 <table class="keyboard-mappings">
591 <tbody>
593 <tbody>
592 <tr>
594 <tr>
593 <th></th>
595 <th></th>
594 <th>${_('Site-wide shortcuts')}</th>
596 <th>${_('Site-wide shortcuts')}</th>
595 </tr>
597 </tr>
596 <%
598 <%
597 elems = [
599 elems = [
598 ('/', 'Open quick search box'),
600 ('/', 'Open quick search box'),
599 ('g h', 'Goto home page'),
601 ('g h', 'Goto home page'),
600 ('g g', 'Goto my private gists page'),
602 ('g g', 'Goto my private gists page'),
601 ('g G', 'Goto my public gists page'),
603 ('g G', 'Goto my public gists page'),
602 ('n r', 'New repository page'),
604 ('n r', 'New repository page'),
603 ('n g', 'New gist page'),
605 ('n g', 'New gist page'),
604 ]
606 ]
605 %>
607 %>
606 %for key, desc in elems:
608 %for key, desc in elems:
607 <tr>
609 <tr>
608 <td class="keys">
610 <td class="keys">
609 <span class="key tag">${key}</span>
611 <span class="key tag">${key}</span>
610 </td>
612 </td>
611 <td>${desc}</td>
613 <td>${desc}</td>
612 </tr>
614 </tr>
613 %endfor
615 %endfor
614 </tbody>
616 </tbody>
615 </table>
617 </table>
616 </div>
618 </div>
617 <div class="block-left">
619 <div class="block-left">
618 <table class="keyboard-mappings">
620 <table class="keyboard-mappings">
619 <tbody>
621 <tbody>
620 <tr>
622 <tr>
621 <th></th>
623 <th></th>
622 <th>${_('Repositories')}</th>
624 <th>${_('Repositories')}</th>
623 </tr>
625 </tr>
624 <%
626 <%
625 elems = [
627 elems = [
626 ('g s', 'Goto summary page'),
628 ('g s', 'Goto summary page'),
627 ('g c', 'Goto changelog page'),
629 ('g c', 'Goto changelog page'),
628 ('g f', 'Goto files page'),
630 ('g f', 'Goto files page'),
629 ('g F', 'Goto files page with file search activated'),
631 ('g F', 'Goto files page with file search activated'),
630 ('g p', 'Goto pull requests page'),
632 ('g p', 'Goto pull requests page'),
631 ('g o', 'Goto repository settings'),
633 ('g o', 'Goto repository settings'),
632 ('g O', 'Goto repository permissions settings'),
634 ('g O', 'Goto repository permissions settings'),
633 ]
635 ]
634 %>
636 %>
635 %for key, desc in elems:
637 %for key, desc in elems:
636 <tr>
638 <tr>
637 <td class="keys">
639 <td class="keys">
638 <span class="key tag">${key}</span>
640 <span class="key tag">${key}</span>
639 </td>
641 </td>
640 <td>${desc}</td>
642 <td>${desc}</td>
641 </tr>
643 </tr>
642 %endfor
644 %endfor
643 </tbody>
645 </tbody>
644 </table>
646 </table>
645 </div>
647 </div>
646 </div>
648 </div>
647 <div class="modal-footer">
649 <div class="modal-footer">
648 </div>
650 </div>
649 </div><!-- /.modal-content -->
651 </div><!-- /.modal-content -->
650 </div><!-- /.modal-dialog -->
652 </div><!-- /.modal-dialog -->
651 </div><!-- /.modal -->
653 </div><!-- /.modal -->
@@ -1,76 +1,84 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/root.html"/>
2 <%inherit file="base/root.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Sign In')}
5 ${_('Sign In')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <style>body{background-color:#eeeeee;}</style>
11 <style>body{background-color:#eeeeee;}</style>
12 <div class="loginbox">
12 <div class="loginbox">
13 <div class="header">
13 <div class="header">
14 <div id="header-inner" class="title">
14 <div id="header-inner" class="title">
15 <div id="logo">
15 <div id="logo">
16 <div class="logo-wrapper">
16 <div class="logo-wrapper">
17 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
17 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
18 </div>
18 </div>
19 %if c.rhodecode_name:
19 %if c.rhodecode_name:
20 <div class="branding"> ${h.branding(c.rhodecode_name)}</div>
20 <div class="branding"> ${h.branding(c.rhodecode_name)}</div>
21 %endif
21 %endif
22 </div>
22 </div>
23 </div>
23 </div>
24 </div>
24 </div>
25
25
26 <div class="loginwrapper">
26 <div class="loginwrapper">
27 <div class="left-column">
27 <div class="left-column">
28 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
28 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
29 </div>
29 </div>
30 <%block name="above_login_button" />
30 <%block name="above_login_button" />
31 <div id="login" class="right-column">
31 <div id="login" class="right-column">
32 <!-- login -->
32 <!-- login -->
33 <div class="sign-in-title">
33 <div class="sign-in-title">
34 <h1>${_('Sign In')}</h1>
34 <h1>${_('Sign In')}</h1>
35 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
35 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
36 <h4>${h.link_to(_("Go to the registration page to create a new account."), request.route_path('register'))}</h4>
36 <h4>${h.link_to(_("Go to the registration page to create a new account."), request.route_path('register'))}</h4>
37 %endif
37 %endif
38 </div>
38 </div>
39 <div class="inner form">
39 <div class="inner form">
40 ${h.form(request.route_path('login', _query={'came_from': came_from}), needs_csrf_token=False)}
40 ${h.form(request.route_path('login', _query={'came_from': came_from}), needs_csrf_token=False)}
41
41
42 <label for="username">${_('Username')}:</label>
42 <label for="username">${_('Username')}:</label>
43 ${h.text('username', class_='focus', value=defaults.get('username'))}
43 ${h.text('username', class_='focus', value=defaults.get('username'))}
44 %if 'username' in errors:
44 %if 'username' in errors:
45 <span class="error-message">${errors.get('username')}</span>
45 <span class="error-message">${errors.get('username')}</span>
46 <br />
46 <br />
47 %endif
47 %endif
48
48
49 <label for="password">${_('Password')}:</label>
49 <label for="password">${_('Password')}:</label>
50 ${h.password('password', class_='focus')}
50 ${h.password('password', class_='focus')}
51 %if 'password' in errors:
51 %if 'password' in errors:
52 <span class="error-message">${errors.get('password')}</span>
52 <span class="error-message">${errors.get('password')}</span>
53 <br />
53 <br />
54 %endif
54 %endif
55
55
56 ${h.checkbox('remember', value=True, checked=defaults.get('remember'))}
56 ${h.checkbox('remember', value=True, checked=defaults.get('remember'))}
57 <label class="checkbox" for="remember">${_('Remember me')}</label>
57 <label class="checkbox" for="remember">${_('Remember me')}</label>
58
58
59 <p class="links">
59
60 ${h.link_to(_('Forgot your password?'), h.route_path('reset_password'))}
60 %if h.HasPermissionAny('hg.password_reset.enable')():
61 </p>
61 <p class="links">
62 ${h.link_to(_('Forgot your password?'), h.route_path('reset_password'))}
63 </p>
64 %elif h.HasPermissionAny('hg.password_reset.hidden')():
65 <p class="help-block">
66 ${_('Contact an administrator if you have forgotten your password.')}
67 </p>
68 %endif
69
62
70
63 ${h.submit('sign_in', _('Sign In'), class_="btn sign-in")}
71 ${h.submit('sign_in', _('Sign In'), class_="btn sign-in")}
64
72
65 ${h.end_form()}
73 ${h.end_form()}
66 <script type="text/javascript">
74 <script type="text/javascript">
67 $(document).ready(function(){
75 $(document).ready(function(){
68 $('#username').focus();
76 $('#username').focus();
69 })
77 })
70 </script>
78 </script>
71 </div>
79 </div>
72 <!-- end login -->
80 <!-- end login -->
73 <%block name="below_login_button" />
81 <%block name="below_login_button" />
74 </div>
82 </div>
75 </div>
83 </div>
76 </div>
84 </div>
@@ -1,77 +1,83 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/root.html"/>
2 <%inherit file="base/root.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Create an Account')}
5 ${_('Create an Account')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10 <style>body{background-color:#eeeeee;}</style>
10 <style>body{background-color:#eeeeee;}</style>
11
11
12 <div class="loginbox">
12 <div class="loginbox">
13 <div class="header">
13 <div class="header">
14 <div id="header-inner" class="title">
14 <div id="header-inner" class="title">
15 <div id="logo">
15 <div id="logo">
16 <div class="logo-wrapper">
16 <div class="logo-wrapper">
17 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
17 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
18 </div>
18 </div>
19 %if c.rhodecode_name:
19 %if c.rhodecode_name:
20 <div class="branding"> ${h.branding(c.rhodecode_name)}</div>
20 <div class="branding"> ${h.branding(c.rhodecode_name)}</div>
21 %endif
21 %endif
22 </div>
22 </div>
23 </div>
23 </div>
24 </div>
24 </div>
25
25
26 <div class="loginwrapper">
26 <div class="loginwrapper">
27 <div class="left-column">
27 <div class="left-column">
28 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
28 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
29 </div>
29 </div>
30
30
31 <div id="register" class="right-column">
31 %if h.HasPermissionAny('hg.password_reset.disabled')():
32 <!-- login -->
32 <div class="right-column">
33 <div class="sign-in-title">
33 <p>${_('Password reset has been disabled.')}</p>
34 <h1>${_('Reset your Password')}</h1>
35 <h4>${h.link_to(_("Go to the login page to sign in."), request.route_path('login'))}</h4>
36 </div>
34 </div>
37 <div class="inner form">
35 %else:
38 ${h.form(request.route_path('reset_password'), needs_csrf_token=False)}
36 <div id="register" class="right-column">
39 <label for="email">${_('Email Address')}:</label>
37 <!-- login -->
40 ${h.text('email', defaults.get('email'))}
38 <div class="sign-in-title">
41 %if 'email' in errors:
39 <h1>${_('Reset your Password')}</h1>
42 <span class="error-message">${errors.get('email')}</span>
40 <h4>${h.link_to(_("Go to the login page to sign in."), request.route_path('login'))}</h4>
43 <br />
41 </div>
44 %endif
42 <div class="inner form">
45
43 ${h.form(request.route_path('reset_password'), needs_csrf_token=False)}
46 %if captcha_active:
44 <label for="email">${_('Email Address')}:</label>
47 <div class="login-captcha"
45 ${h.text('email', defaults.get('email'))}
48 <label for="email">${_('Captcha')}:</label>
46 %if 'email' in errors:
49 ${h.hidden('recaptcha_field')}
47 <span class="error-message">${errors.get('email')}</span>
50 <div id="recaptcha"></div>
51 %if 'recaptcha_field' in errors:
52 <span class="error-message">${errors.get('recaptcha_field')}</span>
53 <br />
48 <br />
54 %endif
49 %endif
55 </div>
50
56 %endif
51 %if captcha_active:
57
52 <div class="login-captcha"
58 ${h.submit('send', _('Send password reset email'), class_="btn sign-in")}
53 <label for="email">${_('Captcha')}:</label>
59 <div class="activation_msg">${_('Password reset link will be sent to matching email address')}</div>
54 ${h.hidden('recaptcha_field')}
60
55 <div id="recaptcha"></div>
61 ${h.end_form()}
56 %if 'recaptcha_field' in errors:
57 <span class="error-message">${errors.get('recaptcha_field')}</span>
58 <br />
59 %endif
60 </div>
61 %endif
62
63 ${h.submit('send', _('Send password reset email'), class_="btn sign-in")}
64 <div class="activation_msg">${_('Password reset link will be sent to matching email address')}</div>
65
66 ${h.end_form()}
67 </div>
62 </div>
68 </div>
63 </div>
69 %endif
64 </div>
70 </div>
65 </div>
71 </div>
66
72
67 %if captcha_active:
73 %if captcha_active:
68 <script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
74 <script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
69 %endif
75 %endif
70 <script type="text/javascript">
76 <script type="text/javascript">
71 $(document).ready(function(){
77 $(document).ready(function(){
72 $('#email').focus();
78 $('#email').focus();
73 %if captcha_active:
79 %if captcha_active:
74 Recaptcha.create("${captcha_public_key}", "recaptcha", {theme: "white"});
80 Recaptcha.create("${captcha_public_key}", "recaptcha", {theme: "white"});
75 %endif
81 %endif
76 });
82 });
77 </script>
83 </script>
General Comments 0
You need to be logged in to leave comments. Login now