##// END OF EJS Templates
logging: improve how we log user lookup
marcink -
r76:f8fd77bc default
parent child Browse files
Show More
@@ -1,1076 +1,1075 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 Set of generic validators
22 Set of generic validators
23 """
23 """
24
24
25 import logging
25 import logging
26 import os
26 import os
27 import re
27 import re
28 from collections import defaultdict
28 from collections import defaultdict
29
29
30 import formencode
30 import formencode
31 import ipaddress
31 import ipaddress
32 from formencode.validators import (
32 from formencode.validators import (
33 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
33 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
34 NotEmpty, IPAddress, CIDR, String, FancyValidator
34 NotEmpty, IPAddress, CIDR, String, FancyValidator
35 )
35 )
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37 from sqlalchemy.sql.expression import true
37 from sqlalchemy.sql.expression import true
38 from sqlalchemy.util import OrderedSet
38 from sqlalchemy.util import OrderedSet
39 from webhelpers.pylonslib.secure_form import authentication_token
39 from webhelpers.pylonslib.secure_form import authentication_token
40
40
41 from rhodecode.config.routing import ADMIN_PREFIX
41 from rhodecode.config.routing import ADMIN_PREFIX
42 from rhodecode.lib.auth import HasRepoGroupPermissionAny, HasPermissionAny
42 from rhodecode.lib.auth import HasRepoGroupPermissionAny, HasPermissionAny
43 from rhodecode.lib.exceptions import LdapImportError
43 from rhodecode.lib.exceptions import LdapImportError
44 from rhodecode.lib.utils import repo_name_slug, make_db_config
44 from rhodecode.lib.utils import repo_name_slug, make_db_config
45 from rhodecode.lib.utils2 import safe_int, str2bool, aslist, md5
45 from rhodecode.lib.utils2 import safe_int, str2bool, aslist, md5
46 from rhodecode.lib.vcs.backends.git.repository import GitRepository
46 from rhodecode.lib.vcs.backends.git.repository import GitRepository
47 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
47 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
48 from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository
48 from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository
49 from rhodecode.model.db import (
49 from rhodecode.model.db import (
50 RepoGroup, Repository, UserGroup, User, ChangesetStatus, Gist)
50 RepoGroup, Repository, UserGroup, User, ChangesetStatus, Gist)
51 from rhodecode.model.settings import VcsSettingsModel
51 from rhodecode.model.settings import VcsSettingsModel
52
52
53 # silence warnings and pylint
53 # silence warnings and pylint
54 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
54 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
55 NotEmpty, IPAddress, CIDR, String, FancyValidator
55 NotEmpty, IPAddress, CIDR, String, FancyValidator
56
56
57 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
58
58
59
59
60 class _Missing(object):
60 class _Missing(object):
61 pass
61 pass
62
62
63 Missing = _Missing()
63 Missing = _Missing()
64
64
65
65
66 class StateObj(object):
66 class StateObj(object):
67 """
67 """
68 this is needed to translate the messages using _() in validators
68 this is needed to translate the messages using _() in validators
69 """
69 """
70 _ = staticmethod(_)
70 _ = staticmethod(_)
71
71
72
72
73 def M(self, key, state=None, **kwargs):
73 def M(self, key, state=None, **kwargs):
74 """
74 """
75 returns string from self.message based on given key,
75 returns string from self.message based on given key,
76 passed kw params are used to substitute %(named)s params inside
76 passed kw params are used to substitute %(named)s params inside
77 translated strings
77 translated strings
78
78
79 :param msg:
79 :param msg:
80 :param state:
80 :param state:
81 """
81 """
82 if state is None:
82 if state is None:
83 state = StateObj()
83 state = StateObj()
84 else:
84 else:
85 state._ = staticmethod(_)
85 state._ = staticmethod(_)
86 # inject validator into state object
86 # inject validator into state object
87 return self.message(key, state, **kwargs)
87 return self.message(key, state, **kwargs)
88
88
89
89
90 def UniqueList(convert=None):
90 def UniqueList(convert=None):
91 class _UniqueList(formencode.FancyValidator):
91 class _UniqueList(formencode.FancyValidator):
92 """
92 """
93 Unique List !
93 Unique List !
94 """
94 """
95 messages = {
95 messages = {
96 'empty': _(u'Value cannot be an empty list'),
96 'empty': _(u'Value cannot be an empty list'),
97 'missing_value': _(u'Value cannot be an empty list'),
97 'missing_value': _(u'Value cannot be an empty list'),
98 }
98 }
99
99
100 def _to_python(self, value, state):
100 def _to_python(self, value, state):
101 ret_val = []
101 ret_val = []
102
102
103 def make_unique(value):
103 def make_unique(value):
104 seen = []
104 seen = []
105 return [c for c in value if not (c in seen or seen.append(c))]
105 return [c for c in value if not (c in seen or seen.append(c))]
106
106
107 if isinstance(value, list):
107 if isinstance(value, list):
108 ret_val = make_unique(value)
108 ret_val = make_unique(value)
109 elif isinstance(value, set):
109 elif isinstance(value, set):
110 ret_val = make_unique(list(value))
110 ret_val = make_unique(list(value))
111 elif isinstance(value, tuple):
111 elif isinstance(value, tuple):
112 ret_val = make_unique(list(value))
112 ret_val = make_unique(list(value))
113 elif value is None:
113 elif value is None:
114 ret_val = []
114 ret_val = []
115 else:
115 else:
116 ret_val = [value]
116 ret_val = [value]
117
117
118 if convert:
118 if convert:
119 ret_val = map(convert, ret_val)
119 ret_val = map(convert, ret_val)
120 return ret_val
120 return ret_val
121
121
122 def empty_value(self, value):
122 def empty_value(self, value):
123 return []
123 return []
124
124
125 return _UniqueList
125 return _UniqueList
126
126
127
127
128 def UniqueListFromString():
128 def UniqueListFromString():
129 class _UniqueListFromString(UniqueList()):
129 class _UniqueListFromString(UniqueList()):
130 def _to_python(self, value, state):
130 def _to_python(self, value, state):
131 if isinstance(value, basestring):
131 if isinstance(value, basestring):
132 value = aslist(value, ',')
132 value = aslist(value, ',')
133 return super(_UniqueListFromString, self)._to_python(value, state)
133 return super(_UniqueListFromString, self)._to_python(value, state)
134 return _UniqueListFromString
134 return _UniqueListFromString
135
135
136
136
137 def ValidSvnPattern(section, repo_name=None):
137 def ValidSvnPattern(section, repo_name=None):
138 class _validator(formencode.validators.FancyValidator):
138 class _validator(formencode.validators.FancyValidator):
139 messages = {
139 messages = {
140 'pattern_exists': _(u'Pattern already exists'),
140 'pattern_exists': _(u'Pattern already exists'),
141 }
141 }
142
142
143 def validate_python(self, value, state):
143 def validate_python(self, value, state):
144 if not value:
144 if not value:
145 return
145 return
146 model = VcsSettingsModel(repo=repo_name)
146 model = VcsSettingsModel(repo=repo_name)
147 ui_settings = model.get_svn_patterns(section=section)
147 ui_settings = model.get_svn_patterns(section=section)
148 for entry in ui_settings:
148 for entry in ui_settings:
149 if value == entry.value:
149 if value == entry.value:
150 msg = M(self, 'pattern_exists', state)
150 msg = M(self, 'pattern_exists', state)
151 raise formencode.Invalid(msg, value, state)
151 raise formencode.Invalid(msg, value, state)
152 return _validator
152 return _validator
153
153
154
154
155 def ValidUsername(edit=False, old_data={}):
155 def ValidUsername(edit=False, old_data={}):
156 class _validator(formencode.validators.FancyValidator):
156 class _validator(formencode.validators.FancyValidator):
157 messages = {
157 messages = {
158 'username_exists': _(u'Username "%(username)s" already exists'),
158 'username_exists': _(u'Username "%(username)s" already exists'),
159 'system_invalid_username':
159 'system_invalid_username':
160 _(u'Username "%(username)s" is forbidden'),
160 _(u'Username "%(username)s" is forbidden'),
161 'invalid_username':
161 'invalid_username':
162 _(u'Username may only contain alphanumeric characters '
162 _(u'Username may only contain alphanumeric characters '
163 u'underscores, periods or dashes and must begin with '
163 u'underscores, periods or dashes and must begin with '
164 u'alphanumeric character or underscore')
164 u'alphanumeric character or underscore')
165 }
165 }
166
166
167 def validate_python(self, value, state):
167 def validate_python(self, value, state):
168 if value in ['default', 'new_user']:
168 if value in ['default', 'new_user']:
169 msg = M(self, 'system_invalid_username', state, username=value)
169 msg = M(self, 'system_invalid_username', state, username=value)
170 raise formencode.Invalid(msg, value, state)
170 raise formencode.Invalid(msg, value, state)
171 # check if user is unique
171 # check if user is unique
172 old_un = None
172 old_un = None
173 if edit:
173 if edit:
174 old_un = User.get(old_data.get('user_id')).username
174 old_un = User.get(old_data.get('user_id')).username
175
175
176 if old_un != value or not edit:
176 if old_un != value or not edit:
177 if User.get_by_username(value, case_insensitive=True):
177 if User.get_by_username(value, case_insensitive=True):
178 msg = M(self, 'username_exists', state, username=value)
178 msg = M(self, 'username_exists', state, username=value)
179 raise formencode.Invalid(msg, value, state)
179 raise formencode.Invalid(msg, value, state)
180
180
181 if (re.match(r'^[\w]{1}[\w\-\.]{0,254}$', value)
181 if (re.match(r'^[\w]{1}[\w\-\.]{0,254}$', value)
182 is None):
182 is None):
183 msg = M(self, 'invalid_username', state)
183 msg = M(self, 'invalid_username', state)
184 raise formencode.Invalid(msg, value, state)
184 raise formencode.Invalid(msg, value, state)
185 return _validator
185 return _validator
186
186
187
187
188 def ValidRegex(msg=None):
188 def ValidRegex(msg=None):
189 class _validator(formencode.validators.Regex):
189 class _validator(formencode.validators.Regex):
190 messages = {'invalid': msg or _(u'The input is not valid')}
190 messages = {'invalid': msg or _(u'The input is not valid')}
191 return _validator
191 return _validator
192
192
193
193
194 def ValidRepoUser():
194 def ValidRepoUser():
195 class _validator(formencode.validators.FancyValidator):
195 class _validator(formencode.validators.FancyValidator):
196 messages = {
196 messages = {
197 'invalid_username': _(u'Username %(username)s is not valid')
197 'invalid_username': _(u'Username %(username)s is not valid')
198 }
198 }
199
199
200 def validate_python(self, value, state):
200 def validate_python(self, value, state):
201 try:
201 try:
202 User.query().filter(User.active == true())\
202 User.query().filter(User.active == true())\
203 .filter(User.username == value).one()
203 .filter(User.username == value).one()
204 except Exception:
204 except Exception:
205 msg = M(self, 'invalid_username', state, username=value)
205 msg = M(self, 'invalid_username', state, username=value)
206 raise formencode.Invalid(
206 raise formencode.Invalid(
207 msg, value, state, error_dict={'username': msg}
207 msg, value, state, error_dict={'username': msg}
208 )
208 )
209
209
210 return _validator
210 return _validator
211
211
212
212
213 def ValidUserGroup(edit=False, old_data={}):
213 def ValidUserGroup(edit=False, old_data={}):
214 class _validator(formencode.validators.FancyValidator):
214 class _validator(formencode.validators.FancyValidator):
215 messages = {
215 messages = {
216 'invalid_group': _(u'Invalid user group name'),
216 'invalid_group': _(u'Invalid user group name'),
217 'group_exist': _(u'User group "%(usergroup)s" already exists'),
217 'group_exist': _(u'User group "%(usergroup)s" already exists'),
218 'invalid_usergroup_name':
218 'invalid_usergroup_name':
219 _(u'user group name may only contain alphanumeric '
219 _(u'user group name may only contain alphanumeric '
220 u'characters underscores, periods or dashes and must begin '
220 u'characters underscores, periods or dashes and must begin '
221 u'with alphanumeric character')
221 u'with alphanumeric character')
222 }
222 }
223
223
224 def validate_python(self, value, state):
224 def validate_python(self, value, state):
225 if value in ['default']:
225 if value in ['default']:
226 msg = M(self, 'invalid_group', state)
226 msg = M(self, 'invalid_group', state)
227 raise formencode.Invalid(
227 raise formencode.Invalid(
228 msg, value, state, error_dict={'users_group_name': msg}
228 msg, value, state, error_dict={'users_group_name': msg}
229 )
229 )
230 # check if group is unique
230 # check if group is unique
231 old_ugname = None
231 old_ugname = None
232 if edit:
232 if edit:
233 old_id = old_data.get('users_group_id')
233 old_id = old_data.get('users_group_id')
234 old_ugname = UserGroup.get(old_id).users_group_name
234 old_ugname = UserGroup.get(old_id).users_group_name
235
235
236 if old_ugname != value or not edit:
236 if old_ugname != value or not edit:
237 is_existing_group = UserGroup.get_by_group_name(
237 is_existing_group = UserGroup.get_by_group_name(
238 value, case_insensitive=True)
238 value, case_insensitive=True)
239 if is_existing_group:
239 if is_existing_group:
240 msg = M(self, 'group_exist', state, usergroup=value)
240 msg = M(self, 'group_exist', state, usergroup=value)
241 raise formencode.Invalid(
241 raise formencode.Invalid(
242 msg, value, state, error_dict={'users_group_name': msg}
242 msg, value, state, error_dict={'users_group_name': msg}
243 )
243 )
244
244
245 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
245 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
246 msg = M(self, 'invalid_usergroup_name', state)
246 msg = M(self, 'invalid_usergroup_name', state)
247 raise formencode.Invalid(
247 raise formencode.Invalid(
248 msg, value, state, error_dict={'users_group_name': msg}
248 msg, value, state, error_dict={'users_group_name': msg}
249 )
249 )
250
250
251 return _validator
251 return _validator
252
252
253
253
254 def ValidRepoGroup(edit=False, old_data={}, can_create_in_root=False):
254 def ValidRepoGroup(edit=False, old_data={}, can_create_in_root=False):
255 class _validator(formencode.validators.FancyValidator):
255 class _validator(formencode.validators.FancyValidator):
256 messages = {
256 messages = {
257 'group_parent_id': _(u'Cannot assign this group as parent'),
257 'group_parent_id': _(u'Cannot assign this group as parent'),
258 'group_exists': _(u'Group "%(group_name)s" already exists'),
258 'group_exists': _(u'Group "%(group_name)s" already exists'),
259 'repo_exists': _(u'Repository with name "%(group_name)s" '
259 'repo_exists': _(u'Repository with name "%(group_name)s" '
260 u'already exists'),
260 u'already exists'),
261 'permission_denied': _(u"no permission to store repository group"
261 'permission_denied': _(u"no permission to store repository group"
262 u"in this location"),
262 u"in this location"),
263 'permission_denied_root': _(
263 'permission_denied_root': _(
264 u"no permission to store repository group "
264 u"no permission to store repository group "
265 u"in root location")
265 u"in root location")
266 }
266 }
267
267
268 def _to_python(self, value, state):
268 def _to_python(self, value, state):
269 group_name = repo_name_slug(value.get('group_name', ''))
269 group_name = repo_name_slug(value.get('group_name', ''))
270 group_parent_id = safe_int(value.get('group_parent_id'))
270 group_parent_id = safe_int(value.get('group_parent_id'))
271 gr = RepoGroup.get(group_parent_id)
271 gr = RepoGroup.get(group_parent_id)
272 if gr:
272 if gr:
273 parent_group_path = gr.full_path
273 parent_group_path = gr.full_path
274 # value needs to be aware of group name in order to check
274 # value needs to be aware of group name in order to check
275 # db key This is an actual just the name to store in the
275 # db key This is an actual just the name to store in the
276 # database
276 # database
277 group_name_full = (
277 group_name_full = (
278 parent_group_path + RepoGroup.url_sep() + group_name)
278 parent_group_path + RepoGroup.url_sep() + group_name)
279 else:
279 else:
280 group_name_full = group_name
280 group_name_full = group_name
281
281
282 value['group_name'] = group_name
282 value['group_name'] = group_name
283 value['group_name_full'] = group_name_full
283 value['group_name_full'] = group_name_full
284 value['group_parent_id'] = group_parent_id
284 value['group_parent_id'] = group_parent_id
285 return value
285 return value
286
286
287 def validate_python(self, value, state):
287 def validate_python(self, value, state):
288
288
289 old_group_name = None
289 old_group_name = None
290 group_name = value.get('group_name')
290 group_name = value.get('group_name')
291 group_name_full = value.get('group_name_full')
291 group_name_full = value.get('group_name_full')
292 group_parent_id = safe_int(value.get('group_parent_id'))
292 group_parent_id = safe_int(value.get('group_parent_id'))
293 if group_parent_id == -1:
293 if group_parent_id == -1:
294 group_parent_id = None
294 group_parent_id = None
295
295
296 group_obj = RepoGroup.get(old_data.get('group_id'))
296 group_obj = RepoGroup.get(old_data.get('group_id'))
297 parent_group_changed = False
297 parent_group_changed = False
298 if edit:
298 if edit:
299 old_group_name = group_obj.group_name
299 old_group_name = group_obj.group_name
300 old_group_parent_id = group_obj.group_parent_id
300 old_group_parent_id = group_obj.group_parent_id
301
301
302 if group_parent_id != old_group_parent_id:
302 if group_parent_id != old_group_parent_id:
303 parent_group_changed = True
303 parent_group_changed = True
304
304
305 # TODO: mikhail: the following if statement is not reached
305 # TODO: mikhail: the following if statement is not reached
306 # since group_parent_id's OneOf validation fails before.
306 # since group_parent_id's OneOf validation fails before.
307 # Can be removed.
307 # Can be removed.
308
308
309 # check against setting a parent of self
309 # check against setting a parent of self
310 parent_of_self = (
310 parent_of_self = (
311 old_data['group_id'] == group_parent_id
311 old_data['group_id'] == group_parent_id
312 if group_parent_id else False
312 if group_parent_id else False
313 )
313 )
314 if parent_of_self:
314 if parent_of_self:
315 msg = M(self, 'group_parent_id', state)
315 msg = M(self, 'group_parent_id', state)
316 raise formencode.Invalid(
316 raise formencode.Invalid(
317 msg, value, state, error_dict={'group_parent_id': msg}
317 msg, value, state, error_dict={'group_parent_id': msg}
318 )
318 )
319
319
320 # group we're moving current group inside
320 # group we're moving current group inside
321 child_group = None
321 child_group = None
322 if group_parent_id:
322 if group_parent_id:
323 child_group = RepoGroup.query().filter(
323 child_group = RepoGroup.query().filter(
324 RepoGroup.group_id == group_parent_id).scalar()
324 RepoGroup.group_id == group_parent_id).scalar()
325
325
326 # do a special check that we cannot move a group to one of
326 # do a special check that we cannot move a group to one of
327 # it's children
327 # it's children
328 if edit and child_group:
328 if edit and child_group:
329 parents = [x.group_id for x in child_group.parents]
329 parents = [x.group_id for x in child_group.parents]
330 move_to_children = old_data['group_id'] in parents
330 move_to_children = old_data['group_id'] in parents
331 if move_to_children:
331 if move_to_children:
332 msg = M(self, 'group_parent_id', state)
332 msg = M(self, 'group_parent_id', state)
333 raise formencode.Invalid(
333 raise formencode.Invalid(
334 msg, value, state, error_dict={'group_parent_id': msg})
334 msg, value, state, error_dict={'group_parent_id': msg})
335
335
336 # Check if we have permission to store in the parent.
336 # Check if we have permission to store in the parent.
337 # Only check if the parent group changed.
337 # Only check if the parent group changed.
338 if parent_group_changed:
338 if parent_group_changed:
339 if child_group is None:
339 if child_group is None:
340 if not can_create_in_root:
340 if not can_create_in_root:
341 msg = M(self, 'permission_denied_root', state)
341 msg = M(self, 'permission_denied_root', state)
342 raise formencode.Invalid(
342 raise formencode.Invalid(
343 msg, value, state,
343 msg, value, state,
344 error_dict={'group_parent_id': msg})
344 error_dict={'group_parent_id': msg})
345 else:
345 else:
346 valid = HasRepoGroupPermissionAny('group.admin')
346 valid = HasRepoGroupPermissionAny('group.admin')
347 forbidden = not valid(
347 forbidden = not valid(
348 child_group.group_name, 'can create group validator')
348 child_group.group_name, 'can create group validator')
349 if forbidden:
349 if forbidden:
350 msg = M(self, 'permission_denied', state)
350 msg = M(self, 'permission_denied', state)
351 raise formencode.Invalid(
351 raise formencode.Invalid(
352 msg, value, state,
352 msg, value, state,
353 error_dict={'group_parent_id': msg})
353 error_dict={'group_parent_id': msg})
354
354
355 # if we change the name or it's new group, check for existing names
355 # if we change the name or it's new group, check for existing names
356 # or repositories with the same name
356 # or repositories with the same name
357 if old_group_name != group_name_full or not edit:
357 if old_group_name != group_name_full or not edit:
358 # check group
358 # check group
359 gr = RepoGroup.get_by_group_name(group_name_full)
359 gr = RepoGroup.get_by_group_name(group_name_full)
360 if gr:
360 if gr:
361 msg = M(self, 'group_exists', state, group_name=group_name)
361 msg = M(self, 'group_exists', state, group_name=group_name)
362 raise formencode.Invalid(
362 raise formencode.Invalid(
363 msg, value, state, error_dict={'group_name': msg})
363 msg, value, state, error_dict={'group_name': msg})
364
364
365 # check for same repo
365 # check for same repo
366 repo = Repository.get_by_repo_name(group_name_full)
366 repo = Repository.get_by_repo_name(group_name_full)
367 if repo:
367 if repo:
368 msg = M(self, 'repo_exists', state, group_name=group_name)
368 msg = M(self, 'repo_exists', state, group_name=group_name)
369 raise formencode.Invalid(
369 raise formencode.Invalid(
370 msg, value, state, error_dict={'group_name': msg})
370 msg, value, state, error_dict={'group_name': msg})
371
371
372 return _validator
372 return _validator
373
373
374
374
375 def ValidPassword():
375 def ValidPassword():
376 class _validator(formencode.validators.FancyValidator):
376 class _validator(formencode.validators.FancyValidator):
377 messages = {
377 messages = {
378 'invalid_password':
378 'invalid_password':
379 _(u'Invalid characters (non-ascii) in password')
379 _(u'Invalid characters (non-ascii) in password')
380 }
380 }
381
381
382 def validate_python(self, value, state):
382 def validate_python(self, value, state):
383 try:
383 try:
384 (value or '').decode('ascii')
384 (value or '').decode('ascii')
385 except UnicodeError:
385 except UnicodeError:
386 msg = M(self, 'invalid_password', state)
386 msg = M(self, 'invalid_password', state)
387 raise formencode.Invalid(msg, value, state,)
387 raise formencode.Invalid(msg, value, state,)
388 return _validator
388 return _validator
389
389
390
390
391 def ValidOldPassword(username):
391 def ValidOldPassword(username):
392 class _validator(formencode.validators.FancyValidator):
392 class _validator(formencode.validators.FancyValidator):
393 messages = {
393 messages = {
394 'invalid_password': _(u'Invalid old password')
394 'invalid_password': _(u'Invalid old password')
395 }
395 }
396
396
397 def validate_python(self, value, state):
397 def validate_python(self, value, state):
398 from rhodecode.authentication.base import authenticate, HTTP_TYPE
398 from rhodecode.authentication.base import authenticate, HTTP_TYPE
399 if not authenticate(username, value, '', HTTP_TYPE):
399 if not authenticate(username, value, '', HTTP_TYPE):
400 msg = M(self, 'invalid_password', state)
400 msg = M(self, 'invalid_password', state)
401 raise formencode.Invalid(
401 raise formencode.Invalid(
402 msg, value, state, error_dict={'current_password': msg}
402 msg, value, state, error_dict={'current_password': msg}
403 )
403 )
404 return _validator
404 return _validator
405
405
406
406
407 def ValidPasswordsMatch(
407 def ValidPasswordsMatch(
408 passwd='new_password', passwd_confirmation='password_confirmation'):
408 passwd='new_password', passwd_confirmation='password_confirmation'):
409 class _validator(formencode.validators.FancyValidator):
409 class _validator(formencode.validators.FancyValidator):
410 messages = {
410 messages = {
411 'password_mismatch': _(u'Passwords do not match'),
411 'password_mismatch': _(u'Passwords do not match'),
412 }
412 }
413
413
414 def validate_python(self, value, state):
414 def validate_python(self, value, state):
415
415
416 pass_val = value.get('password') or value.get(passwd)
416 pass_val = value.get('password') or value.get(passwd)
417 if pass_val != value[passwd_confirmation]:
417 if pass_val != value[passwd_confirmation]:
418 msg = M(self, 'password_mismatch', state)
418 msg = M(self, 'password_mismatch', state)
419 raise formencode.Invalid(
419 raise formencode.Invalid(
420 msg, value, state,
420 msg, value, state,
421 error_dict={passwd: msg, passwd_confirmation: msg}
421 error_dict={passwd: msg, passwd_confirmation: msg}
422 )
422 )
423 return _validator
423 return _validator
424
424
425
425
426 def ValidAuth():
426 def ValidAuth():
427 class _validator(formencode.validators.FancyValidator):
427 class _validator(formencode.validators.FancyValidator):
428 messages = {
428 messages = {
429 'invalid_password': _(u'invalid password'),
429 'invalid_password': _(u'invalid password'),
430 'invalid_username': _(u'invalid user name'),
430 'invalid_username': _(u'invalid user name'),
431 'disabled_account': _(u'Your account is disabled')
431 'disabled_account': _(u'Your account is disabled')
432 }
432 }
433
433
434 def validate_python(self, value, state):
434 def validate_python(self, value, state):
435 from rhodecode.authentication.base import authenticate, HTTP_TYPE
435 from rhodecode.authentication.base import authenticate, HTTP_TYPE
436
436
437 password = value['password']
437 password = value['password']
438 username = value['username']
438 username = value['username']
439
439
440 if not authenticate(username, password, '',
440 if not authenticate(username, password, '', HTTP_TYPE,
441 HTTP_TYPE,
442 skip_missing=True):
441 skip_missing=True):
443 user = User.get_by_username(username)
442 user = User.get_by_username(username)
444 if user and not user.active:
443 if user and not user.active:
445 log.warning('user %s is disabled', username)
444 log.warning('user %s is disabled', username)
446 msg = M(self, 'disabled_account', state)
445 msg = M(self, 'disabled_account', state)
447 raise formencode.Invalid(
446 raise formencode.Invalid(
448 msg, value, state, error_dict={'username': msg}
447 msg, value, state, error_dict={'username': msg}
449 )
448 )
450 else:
449 else:
451 log.warning('user %s failed to authenticate', username)
450 log.warning('user `%s` failed to authenticate', username)
452 msg = M(self, 'invalid_username', state)
451 msg = M(self, 'invalid_username', state)
453 msg2 = M(self, 'invalid_password', state)
452 msg2 = M(self, 'invalid_password', state)
454 raise formencode.Invalid(
453 raise formencode.Invalid(
455 msg, value, state,
454 msg, value, state,
456 error_dict={'username': msg, 'password': msg2}
455 error_dict={'username': msg, 'password': msg2}
457 )
456 )
458 return _validator
457 return _validator
459
458
460
459
461 def ValidAuthToken():
460 def ValidAuthToken():
462 class _validator(formencode.validators.FancyValidator):
461 class _validator(formencode.validators.FancyValidator):
463 messages = {
462 messages = {
464 'invalid_token': _(u'Token mismatch')
463 'invalid_token': _(u'Token mismatch')
465 }
464 }
466
465
467 def validate_python(self, value, state):
466 def validate_python(self, value, state):
468 if value != authentication_token():
467 if value != authentication_token():
469 msg = M(self, 'invalid_token', state)
468 msg = M(self, 'invalid_token', state)
470 raise formencode.Invalid(msg, value, state)
469 raise formencode.Invalid(msg, value, state)
471 return _validator
470 return _validator
472
471
473
472
474 def ValidRepoName(edit=False, old_data={}):
473 def ValidRepoName(edit=False, old_data={}):
475 class _validator(formencode.validators.FancyValidator):
474 class _validator(formencode.validators.FancyValidator):
476 messages = {
475 messages = {
477 'invalid_repo_name':
476 'invalid_repo_name':
478 _(u'Repository name %(repo)s is disallowed'),
477 _(u'Repository name %(repo)s is disallowed'),
479 # top level
478 # top level
480 'repository_exists': _(u'Repository with name %(repo)s '
479 'repository_exists': _(u'Repository with name %(repo)s '
481 u'already exists'),
480 u'already exists'),
482 'group_exists': _(u'Repository group with name "%(repo)s" '
481 'group_exists': _(u'Repository group with name "%(repo)s" '
483 u'already exists'),
482 u'already exists'),
484 # inside a group
483 # inside a group
485 'repository_in_group_exists': _(u'Repository with name %(repo)s '
484 'repository_in_group_exists': _(u'Repository with name %(repo)s '
486 u'exists in group "%(group)s"'),
485 u'exists in group "%(group)s"'),
487 'group_in_group_exists': _(
486 'group_in_group_exists': _(
488 u'Repository group with name "%(repo)s" '
487 u'Repository group with name "%(repo)s" '
489 u'exists in group "%(group)s"'),
488 u'exists in group "%(group)s"'),
490 }
489 }
491
490
492 def _to_python(self, value, state):
491 def _to_python(self, value, state):
493 repo_name = repo_name_slug(value.get('repo_name', ''))
492 repo_name = repo_name_slug(value.get('repo_name', ''))
494 repo_group = value.get('repo_group')
493 repo_group = value.get('repo_group')
495 if repo_group:
494 if repo_group:
496 gr = RepoGroup.get(repo_group)
495 gr = RepoGroup.get(repo_group)
497 group_path = gr.full_path
496 group_path = gr.full_path
498 group_name = gr.group_name
497 group_name = gr.group_name
499 # value needs to be aware of group name in order to check
498 # value needs to be aware of group name in order to check
500 # db key This is an actual just the name to store in the
499 # db key This is an actual just the name to store in the
501 # database
500 # database
502 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
501 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
503 else:
502 else:
504 group_name = group_path = ''
503 group_name = group_path = ''
505 repo_name_full = repo_name
504 repo_name_full = repo_name
506
505
507 value['repo_name'] = repo_name
506 value['repo_name'] = repo_name
508 value['repo_name_full'] = repo_name_full
507 value['repo_name_full'] = repo_name_full
509 value['group_path'] = group_path
508 value['group_path'] = group_path
510 value['group_name'] = group_name
509 value['group_name'] = group_name
511 return value
510 return value
512
511
513 def validate_python(self, value, state):
512 def validate_python(self, value, state):
514
513
515 repo_name = value.get('repo_name')
514 repo_name = value.get('repo_name')
516 repo_name_full = value.get('repo_name_full')
515 repo_name_full = value.get('repo_name_full')
517 group_path = value.get('group_path')
516 group_path = value.get('group_path')
518 group_name = value.get('group_name')
517 group_name = value.get('group_name')
519
518
520 if repo_name in [ADMIN_PREFIX, '']:
519 if repo_name in [ADMIN_PREFIX, '']:
521 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
520 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
522 raise formencode.Invalid(
521 raise formencode.Invalid(
523 msg, value, state, error_dict={'repo_name': msg})
522 msg, value, state, error_dict={'repo_name': msg})
524
523
525 rename = old_data.get('repo_name') != repo_name_full
524 rename = old_data.get('repo_name') != repo_name_full
526 create = not edit
525 create = not edit
527 if rename or create:
526 if rename or create:
528
527
529 if group_path:
528 if group_path:
530 if Repository.get_by_repo_name(repo_name_full):
529 if Repository.get_by_repo_name(repo_name_full):
531 msg = M(self, 'repository_in_group_exists', state,
530 msg = M(self, 'repository_in_group_exists', state,
532 repo=repo_name, group=group_name)
531 repo=repo_name, group=group_name)
533 raise formencode.Invalid(
532 raise formencode.Invalid(
534 msg, value, state, error_dict={'repo_name': msg})
533 msg, value, state, error_dict={'repo_name': msg})
535 if RepoGroup.get_by_group_name(repo_name_full):
534 if RepoGroup.get_by_group_name(repo_name_full):
536 msg = M(self, 'group_in_group_exists', state,
535 msg = M(self, 'group_in_group_exists', state,
537 repo=repo_name, group=group_name)
536 repo=repo_name, group=group_name)
538 raise formencode.Invalid(
537 raise formencode.Invalid(
539 msg, value, state, error_dict={'repo_name': msg})
538 msg, value, state, error_dict={'repo_name': msg})
540 else:
539 else:
541 if RepoGroup.get_by_group_name(repo_name_full):
540 if RepoGroup.get_by_group_name(repo_name_full):
542 msg = M(self, 'group_exists', state, repo=repo_name)
541 msg = M(self, 'group_exists', state, repo=repo_name)
543 raise formencode.Invalid(
542 raise formencode.Invalid(
544 msg, value, state, error_dict={'repo_name': msg})
543 msg, value, state, error_dict={'repo_name': msg})
545
544
546 if Repository.get_by_repo_name(repo_name_full):
545 if Repository.get_by_repo_name(repo_name_full):
547 msg = M(
546 msg = M(
548 self, 'repository_exists', state, repo=repo_name)
547 self, 'repository_exists', state, repo=repo_name)
549 raise formencode.Invalid(
548 raise formencode.Invalid(
550 msg, value, state, error_dict={'repo_name': msg})
549 msg, value, state, error_dict={'repo_name': msg})
551 return value
550 return value
552 return _validator
551 return _validator
553
552
554
553
555 def ValidForkName(*args, **kwargs):
554 def ValidForkName(*args, **kwargs):
556 return ValidRepoName(*args, **kwargs)
555 return ValidRepoName(*args, **kwargs)
557
556
558
557
559 def SlugifyName():
558 def SlugifyName():
560 class _validator(formencode.validators.FancyValidator):
559 class _validator(formencode.validators.FancyValidator):
561
560
562 def _to_python(self, value, state):
561 def _to_python(self, value, state):
563 return repo_name_slug(value)
562 return repo_name_slug(value)
564
563
565 def validate_python(self, value, state):
564 def validate_python(self, value, state):
566 pass
565 pass
567
566
568 return _validator
567 return _validator
569
568
570
569
571 def ValidCloneUri():
570 def ValidCloneUri():
572 class InvalidCloneUrl(Exception):
571 class InvalidCloneUrl(Exception):
573 allowed_prefixes = ()
572 allowed_prefixes = ()
574
573
575 def url_handler(repo_type, url):
574 def url_handler(repo_type, url):
576 config = make_db_config(clear_session=False)
575 config = make_db_config(clear_session=False)
577 if repo_type == 'hg':
576 if repo_type == 'hg':
578 allowed_prefixes = ('http', 'svn+http', 'git+http')
577 allowed_prefixes = ('http', 'svn+http', 'git+http')
579
578
580 if 'http' in url[:4]:
579 if 'http' in url[:4]:
581 # initially check if it's at least the proper URL
580 # initially check if it's at least the proper URL
582 # or does it pass basic auth
581 # or does it pass basic auth
583 MercurialRepository.check_url(url, config)
582 MercurialRepository.check_url(url, config)
584 elif 'svn+http' in url[:8]: # svn->hg import
583 elif 'svn+http' in url[:8]: # svn->hg import
585 SubversionRepository.check_url(url, config)
584 SubversionRepository.check_url(url, config)
586 elif 'git+http' in url[:8]: # git->hg import
585 elif 'git+http' in url[:8]: # git->hg import
587 raise NotImplementedError()
586 raise NotImplementedError()
588 else:
587 else:
589 exc = InvalidCloneUrl('Clone from URI %s not allowed. '
588 exc = InvalidCloneUrl('Clone from URI %s not allowed. '
590 'Allowed url must start with one of %s'
589 'Allowed url must start with one of %s'
591 % (url, ','.join(allowed_prefixes)))
590 % (url, ','.join(allowed_prefixes)))
592 exc.allowed_prefixes = allowed_prefixes
591 exc.allowed_prefixes = allowed_prefixes
593 raise exc
592 raise exc
594
593
595 elif repo_type == 'git':
594 elif repo_type == 'git':
596 allowed_prefixes = ('http', 'svn+http', 'hg+http')
595 allowed_prefixes = ('http', 'svn+http', 'hg+http')
597 if 'http' in url[:4]:
596 if 'http' in url[:4]:
598 # initially check if it's at least the proper URL
597 # initially check if it's at least the proper URL
599 # or does it pass basic auth
598 # or does it pass basic auth
600 GitRepository.check_url(url, config)
599 GitRepository.check_url(url, config)
601 elif 'svn+http' in url[:8]: # svn->git import
600 elif 'svn+http' in url[:8]: # svn->git import
602 raise NotImplementedError()
601 raise NotImplementedError()
603 elif 'hg+http' in url[:8]: # hg->git import
602 elif 'hg+http' in url[:8]: # hg->git import
604 raise NotImplementedError()
603 raise NotImplementedError()
605 else:
604 else:
606 exc = InvalidCloneUrl('Clone from URI %s not allowed. '
605 exc = InvalidCloneUrl('Clone from URI %s not allowed. '
607 'Allowed url must start with one of %s'
606 'Allowed url must start with one of %s'
608 % (url, ','.join(allowed_prefixes)))
607 % (url, ','.join(allowed_prefixes)))
609 exc.allowed_prefixes = allowed_prefixes
608 exc.allowed_prefixes = allowed_prefixes
610 raise exc
609 raise exc
611
610
612 class _validator(formencode.validators.FancyValidator):
611 class _validator(formencode.validators.FancyValidator):
613 messages = {
612 messages = {
614 'clone_uri': _(u'invalid clone url for %(rtype)s repository'),
613 'clone_uri': _(u'invalid clone url for %(rtype)s repository'),
615 'invalid_clone_uri': _(
614 'invalid_clone_uri': _(
616 u'Invalid clone url, provide a valid clone '
615 u'Invalid clone url, provide a valid clone '
617 u'url starting with one of %(allowed_prefixes)s')
616 u'url starting with one of %(allowed_prefixes)s')
618 }
617 }
619
618
620 def validate_python(self, value, state):
619 def validate_python(self, value, state):
621 repo_type = value.get('repo_type')
620 repo_type = value.get('repo_type')
622 url = value.get('clone_uri')
621 url = value.get('clone_uri')
623
622
624 if url:
623 if url:
625 try:
624 try:
626 url_handler(repo_type, url)
625 url_handler(repo_type, url)
627 except InvalidCloneUrl as e:
626 except InvalidCloneUrl as e:
628 log.warning(e)
627 log.warning(e)
629 msg = M(self, 'invalid_clone_uri', rtype=repo_type,
628 msg = M(self, 'invalid_clone_uri', rtype=repo_type,
630 allowed_prefixes=','.join(e.allowed_prefixes))
629 allowed_prefixes=','.join(e.allowed_prefixes))
631 raise formencode.Invalid(msg, value, state,
630 raise formencode.Invalid(msg, value, state,
632 error_dict={'clone_uri': msg})
631 error_dict={'clone_uri': msg})
633 except Exception:
632 except Exception:
634 log.exception('Url validation failed')
633 log.exception('Url validation failed')
635 msg = M(self, 'clone_uri', rtype=repo_type)
634 msg = M(self, 'clone_uri', rtype=repo_type)
636 raise formencode.Invalid(msg, value, state,
635 raise formencode.Invalid(msg, value, state,
637 error_dict={'clone_uri': msg})
636 error_dict={'clone_uri': msg})
638 return _validator
637 return _validator
639
638
640
639
641 def ValidForkType(old_data={}):
640 def ValidForkType(old_data={}):
642 class _validator(formencode.validators.FancyValidator):
641 class _validator(formencode.validators.FancyValidator):
643 messages = {
642 messages = {
644 'invalid_fork_type': _(u'Fork have to be the same type as parent')
643 'invalid_fork_type': _(u'Fork have to be the same type as parent')
645 }
644 }
646
645
647 def validate_python(self, value, state):
646 def validate_python(self, value, state):
648 if old_data['repo_type'] != value:
647 if old_data['repo_type'] != value:
649 msg = M(self, 'invalid_fork_type', state)
648 msg = M(self, 'invalid_fork_type', state)
650 raise formencode.Invalid(
649 raise formencode.Invalid(
651 msg, value, state, error_dict={'repo_type': msg}
650 msg, value, state, error_dict={'repo_type': msg}
652 )
651 )
653 return _validator
652 return _validator
654
653
655
654
656 def CanWriteGroup(old_data=None):
655 def CanWriteGroup(old_data=None):
657 class _validator(formencode.validators.FancyValidator):
656 class _validator(formencode.validators.FancyValidator):
658 messages = {
657 messages = {
659 'permission_denied': _(
658 'permission_denied': _(
660 u"You do not have the permission "
659 u"You do not have the permission "
661 u"to create repositories in this group."),
660 u"to create repositories in this group."),
662 'permission_denied_root': _(
661 'permission_denied_root': _(
663 u"You do not have the permission to store repositories in "
662 u"You do not have the permission to store repositories in "
664 u"the root location.")
663 u"the root location.")
665 }
664 }
666
665
667 def _to_python(self, value, state):
666 def _to_python(self, value, state):
668 # root location
667 # root location
669 if value in [-1, "-1"]:
668 if value in [-1, "-1"]:
670 return None
669 return None
671 return value
670 return value
672
671
673 def validate_python(self, value, state):
672 def validate_python(self, value, state):
674 gr = RepoGroup.get(value)
673 gr = RepoGroup.get(value)
675 gr_name = gr.group_name if gr else None # None means ROOT location
674 gr_name = gr.group_name if gr else None # None means ROOT location
676 # create repositories with write permission on group is set to true
675 # create repositories with write permission on group is set to true
677 create_on_write = HasPermissionAny(
676 create_on_write = HasPermissionAny(
678 'hg.create.write_on_repogroup.true')()
677 'hg.create.write_on_repogroup.true')()
679 group_admin = HasRepoGroupPermissionAny('group.admin')(
678 group_admin = HasRepoGroupPermissionAny('group.admin')(
680 gr_name, 'can write into group validator')
679 gr_name, 'can write into group validator')
681 group_write = HasRepoGroupPermissionAny('group.write')(
680 group_write = HasRepoGroupPermissionAny('group.write')(
682 gr_name, 'can write into group validator')
681 gr_name, 'can write into group validator')
683 forbidden = not (group_admin or (group_write and create_on_write))
682 forbidden = not (group_admin or (group_write and create_on_write))
684 can_create_repos = HasPermissionAny(
683 can_create_repos = HasPermissionAny(
685 'hg.admin', 'hg.create.repository')
684 'hg.admin', 'hg.create.repository')
686 gid = (old_data['repo_group'].get('group_id')
685 gid = (old_data['repo_group'].get('group_id')
687 if (old_data and 'repo_group' in old_data) else None)
686 if (old_data and 'repo_group' in old_data) else None)
688 value_changed = gid != safe_int(value)
687 value_changed = gid != safe_int(value)
689 new = not old_data
688 new = not old_data
690 # do check if we changed the value, there's a case that someone got
689 # do check if we changed the value, there's a case that someone got
691 # revoked write permissions to a repository, he still created, we
690 # revoked write permissions to a repository, he still created, we
692 # don't need to check permission if he didn't change the value of
691 # don't need to check permission if he didn't change the value of
693 # groups in form box
692 # groups in form box
694 if value_changed or new:
693 if value_changed or new:
695 # parent group need to be existing
694 # parent group need to be existing
696 if gr and forbidden:
695 if gr and forbidden:
697 msg = M(self, 'permission_denied', state)
696 msg = M(self, 'permission_denied', state)
698 raise formencode.Invalid(
697 raise formencode.Invalid(
699 msg, value, state, error_dict={'repo_type': msg}
698 msg, value, state, error_dict={'repo_type': msg}
700 )
699 )
701 # check if we can write to root location !
700 # check if we can write to root location !
702 elif gr is None and not can_create_repos():
701 elif gr is None and not can_create_repos():
703 msg = M(self, 'permission_denied_root', state)
702 msg = M(self, 'permission_denied_root', state)
704 raise formencode.Invalid(
703 raise formencode.Invalid(
705 msg, value, state, error_dict={'repo_type': msg}
704 msg, value, state, error_dict={'repo_type': msg}
706 )
705 )
707
706
708 return _validator
707 return _validator
709
708
710
709
711 def ValidPerms(type_='repo'):
710 def ValidPerms(type_='repo'):
712 if type_ == 'repo_group':
711 if type_ == 'repo_group':
713 EMPTY_PERM = 'group.none'
712 EMPTY_PERM = 'group.none'
714 elif type_ == 'repo':
713 elif type_ == 'repo':
715 EMPTY_PERM = 'repository.none'
714 EMPTY_PERM = 'repository.none'
716 elif type_ == 'user_group':
715 elif type_ == 'user_group':
717 EMPTY_PERM = 'usergroup.none'
716 EMPTY_PERM = 'usergroup.none'
718
717
719 class _validator(formencode.validators.FancyValidator):
718 class _validator(formencode.validators.FancyValidator):
720 messages = {
719 messages = {
721 'perm_new_member_name':
720 'perm_new_member_name':
722 _(u'This username or user group name is not valid')
721 _(u'This username or user group name is not valid')
723 }
722 }
724
723
725 def _to_python(self, value, state):
724 def _to_python(self, value, state):
726 perm_updates = OrderedSet()
725 perm_updates = OrderedSet()
727 perm_additions = OrderedSet()
726 perm_additions = OrderedSet()
728 perm_deletions = OrderedSet()
727 perm_deletions = OrderedSet()
729 # build a list of permission to update/delete and new permission
728 # build a list of permission to update/delete and new permission
730
729
731 # Read the perm_new_member/perm_del_member attributes and group
730 # Read the perm_new_member/perm_del_member attributes and group
732 # them by they IDs
731 # them by they IDs
733 new_perms_group = defaultdict(dict)
732 new_perms_group = defaultdict(dict)
734 del_perms_group = defaultdict(dict)
733 del_perms_group = defaultdict(dict)
735 for k, v in value.copy().iteritems():
734 for k, v in value.copy().iteritems():
736 if k.startswith('perm_del_member'):
735 if k.startswith('perm_del_member'):
737 # delete from org storage so we don't process that later
736 # delete from org storage so we don't process that later
738 del value[k]
737 del value[k]
739 # part is `id`, `type`
738 # part is `id`, `type`
740 _type, part = k.split('perm_del_member_')
739 _type, part = k.split('perm_del_member_')
741 args = part.split('_')
740 args = part.split('_')
742 if len(args) == 2:
741 if len(args) == 2:
743 _key, pos = args
742 _key, pos = args
744 del_perms_group[pos][_key] = v
743 del_perms_group[pos][_key] = v
745 if k.startswith('perm_new_member'):
744 if k.startswith('perm_new_member'):
746 # delete from org storage so we don't process that later
745 # delete from org storage so we don't process that later
747 del value[k]
746 del value[k]
748 # part is `id`, `type`, `perm`
747 # part is `id`, `type`, `perm`
749 _type, part = k.split('perm_new_member_')
748 _type, part = k.split('perm_new_member_')
750 args = part.split('_')
749 args = part.split('_')
751 if len(args) == 2:
750 if len(args) == 2:
752 _key, pos = args
751 _key, pos = args
753 new_perms_group[pos][_key] = v
752 new_perms_group[pos][_key] = v
754
753
755 # store the deletes
754 # store the deletes
756 for k in sorted(del_perms_group.keys()):
755 for k in sorted(del_perms_group.keys()):
757 perm_dict = del_perms_group[k]
756 perm_dict = del_perms_group[k]
758 del_member = perm_dict.get('id')
757 del_member = perm_dict.get('id')
759 del_type = perm_dict.get('type')
758 del_type = perm_dict.get('type')
760 if del_member and del_type:
759 if del_member and del_type:
761 perm_deletions.add((del_member, None, del_type))
760 perm_deletions.add((del_member, None, del_type))
762
761
763 # store additions in order of how they were added in web form
762 # store additions in order of how they were added in web form
764 for k in sorted(new_perms_group.keys()):
763 for k in sorted(new_perms_group.keys()):
765 perm_dict = new_perms_group[k]
764 perm_dict = new_perms_group[k]
766 new_member = perm_dict.get('id')
765 new_member = perm_dict.get('id')
767 new_type = perm_dict.get('type')
766 new_type = perm_dict.get('type')
768 new_perm = perm_dict.get('perm')
767 new_perm = perm_dict.get('perm')
769 if new_member and new_perm and new_type:
768 if new_member and new_perm and new_type:
770 perm_additions.add((new_member, new_perm, new_type))
769 perm_additions.add((new_member, new_perm, new_type))
771
770
772 # get updates of permissions
771 # get updates of permissions
773 # (read the existing radio button states)
772 # (read the existing radio button states)
774 for k, update_value in value.iteritems():
773 for k, update_value in value.iteritems():
775 if k.startswith('u_perm_') or k.startswith('g_perm_'):
774 if k.startswith('u_perm_') or k.startswith('g_perm_'):
776 member = k[7:]
775 member = k[7:]
777 update_type = {'u': 'user',
776 update_type = {'u': 'user',
778 'g': 'users_group'}[k[0]]
777 'g': 'users_group'}[k[0]]
779 if member == User.DEFAULT_USER:
778 if member == User.DEFAULT_USER:
780 if str2bool(value.get('repo_private')):
779 if str2bool(value.get('repo_private')):
781 # set none for default when updating to
780 # set none for default when updating to
782 # private repo protects agains form manipulation
781 # private repo protects agains form manipulation
783 update_value = EMPTY_PERM
782 update_value = EMPTY_PERM
784 perm_updates.add((member, update_value, update_type))
783 perm_updates.add((member, update_value, update_type))
785 # check the deletes
784 # check the deletes
786
785
787 value['perm_additions'] = list(perm_additions)
786 value['perm_additions'] = list(perm_additions)
788 value['perm_updates'] = list(perm_updates)
787 value['perm_updates'] = list(perm_updates)
789 value['perm_deletions'] = list(perm_deletions)
788 value['perm_deletions'] = list(perm_deletions)
790
789
791 # validate users they exist and they are active !
790 # validate users they exist and they are active !
792 for member_id, _perm, member_type in perm_additions:
791 for member_id, _perm, member_type in perm_additions:
793 try:
792 try:
794 if member_type == 'user':
793 if member_type == 'user':
795 self.user_db = User.query()\
794 self.user_db = User.query()\
796 .filter(User.active == true())\
795 .filter(User.active == true())\
797 .filter(User.user_id == member_id).one()
796 .filter(User.user_id == member_id).one()
798 if member_type == 'users_group':
797 if member_type == 'users_group':
799 self.user_db = UserGroup.query()\
798 self.user_db = UserGroup.query()\
800 .filter(UserGroup.users_group_active == true())\
799 .filter(UserGroup.users_group_active == true())\
801 .filter(UserGroup.users_group_id == member_id)\
800 .filter(UserGroup.users_group_id == member_id)\
802 .one()
801 .one()
803
802
804 except Exception:
803 except Exception:
805 log.exception('Updated permission failed: org_exc:')
804 log.exception('Updated permission failed: org_exc:')
806 msg = M(self, 'perm_new_member_type', state)
805 msg = M(self, 'perm_new_member_type', state)
807 raise formencode.Invalid(
806 raise formencode.Invalid(
808 msg, value, state, error_dict={
807 msg, value, state, error_dict={
809 'perm_new_member_name': msg}
808 'perm_new_member_name': msg}
810 )
809 )
811 return value
810 return value
812 return _validator
811 return _validator
813
812
814
813
815 def ValidSettings():
814 def ValidSettings():
816 class _validator(formencode.validators.FancyValidator):
815 class _validator(formencode.validators.FancyValidator):
817 def _to_python(self, value, state):
816 def _to_python(self, value, state):
818 # settings form for users that are not admin
817 # settings form for users that are not admin
819 # can't edit certain parameters, it's extra backup if they mangle
818 # can't edit certain parameters, it's extra backup if they mangle
820 # with forms
819 # with forms
821
820
822 forbidden_params = [
821 forbidden_params = [
823 'user', 'repo_type', 'repo_enable_locking',
822 'user', 'repo_type', 'repo_enable_locking',
824 'repo_enable_downloads', 'repo_enable_statistics'
823 'repo_enable_downloads', 'repo_enable_statistics'
825 ]
824 ]
826
825
827 for param in forbidden_params:
826 for param in forbidden_params:
828 if param in value:
827 if param in value:
829 del value[param]
828 del value[param]
830 return value
829 return value
831
830
832 def validate_python(self, value, state):
831 def validate_python(self, value, state):
833 pass
832 pass
834 return _validator
833 return _validator
835
834
836
835
837 def ValidPath():
836 def ValidPath():
838 class _validator(formencode.validators.FancyValidator):
837 class _validator(formencode.validators.FancyValidator):
839 messages = {
838 messages = {
840 'invalid_path': _(u'This is not a valid path')
839 'invalid_path': _(u'This is not a valid path')
841 }
840 }
842
841
843 def validate_python(self, value, state):
842 def validate_python(self, value, state):
844 if not os.path.isdir(value):
843 if not os.path.isdir(value):
845 msg = M(self, 'invalid_path', state)
844 msg = M(self, 'invalid_path', state)
846 raise formencode.Invalid(
845 raise formencode.Invalid(
847 msg, value, state, error_dict={'paths_root_path': msg}
846 msg, value, state, error_dict={'paths_root_path': msg}
848 )
847 )
849 return _validator
848 return _validator
850
849
851
850
852 def UniqSystemEmail(old_data={}):
851 def UniqSystemEmail(old_data={}):
853 class _validator(formencode.validators.FancyValidator):
852 class _validator(formencode.validators.FancyValidator):
854 messages = {
853 messages = {
855 'email_taken': _(u'This e-mail address is already taken')
854 'email_taken': _(u'This e-mail address is already taken')
856 }
855 }
857
856
858 def _to_python(self, value, state):
857 def _to_python(self, value, state):
859 return value.lower()
858 return value.lower()
860
859
861 def validate_python(self, value, state):
860 def validate_python(self, value, state):
862 if (old_data.get('email') or '').lower() != value:
861 if (old_data.get('email') or '').lower() != value:
863 user = User.get_by_email(value, case_insensitive=True)
862 user = User.get_by_email(value, case_insensitive=True)
864 if user:
863 if user:
865 msg = M(self, 'email_taken', state)
864 msg = M(self, 'email_taken', state)
866 raise formencode.Invalid(
865 raise formencode.Invalid(
867 msg, value, state, error_dict={'email': msg}
866 msg, value, state, error_dict={'email': msg}
868 )
867 )
869 return _validator
868 return _validator
870
869
871
870
872 def ValidSystemEmail():
871 def ValidSystemEmail():
873 class _validator(formencode.validators.FancyValidator):
872 class _validator(formencode.validators.FancyValidator):
874 messages = {
873 messages = {
875 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
874 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
876 }
875 }
877
876
878 def _to_python(self, value, state):
877 def _to_python(self, value, state):
879 return value.lower()
878 return value.lower()
880
879
881 def validate_python(self, value, state):
880 def validate_python(self, value, state):
882 user = User.get_by_email(value, case_insensitive=True)
881 user = User.get_by_email(value, case_insensitive=True)
883 if user is None:
882 if user is None:
884 msg = M(self, 'non_existing_email', state, email=value)
883 msg = M(self, 'non_existing_email', state, email=value)
885 raise formencode.Invalid(
884 raise formencode.Invalid(
886 msg, value, state, error_dict={'email': msg}
885 msg, value, state, error_dict={'email': msg}
887 )
886 )
888
887
889 return _validator
888 return _validator
890
889
891
890
892 def NotReviewedRevisions(repo_id):
891 def NotReviewedRevisions(repo_id):
893 class _validator(formencode.validators.FancyValidator):
892 class _validator(formencode.validators.FancyValidator):
894 messages = {
893 messages = {
895 'rev_already_reviewed':
894 'rev_already_reviewed':
896 _(u'Revisions %(revs)s are already part of pull request '
895 _(u'Revisions %(revs)s are already part of pull request '
897 u'or have set status'),
896 u'or have set status'),
898 }
897 }
899
898
900 def validate_python(self, value, state):
899 def validate_python(self, value, state):
901 # check revisions if they are not reviewed, or a part of another
900 # check revisions if they are not reviewed, or a part of another
902 # pull request
901 # pull request
903 statuses = ChangesetStatus.query()\
902 statuses = ChangesetStatus.query()\
904 .filter(ChangesetStatus.revision.in_(value))\
903 .filter(ChangesetStatus.revision.in_(value))\
905 .filter(ChangesetStatus.repo_id == repo_id)\
904 .filter(ChangesetStatus.repo_id == repo_id)\
906 .all()
905 .all()
907
906
908 errors = []
907 errors = []
909 for status in statuses:
908 for status in statuses:
910 if status.pull_request_id:
909 if status.pull_request_id:
911 errors.append(['pull_req', status.revision[:12]])
910 errors.append(['pull_req', status.revision[:12]])
912 elif status.status:
911 elif status.status:
913 errors.append(['status', status.revision[:12]])
912 errors.append(['status', status.revision[:12]])
914
913
915 if errors:
914 if errors:
916 revs = ','.join([x[1] for x in errors])
915 revs = ','.join([x[1] for x in errors])
917 msg = M(self, 'rev_already_reviewed', state, revs=revs)
916 msg = M(self, 'rev_already_reviewed', state, revs=revs)
918 raise formencode.Invalid(
917 raise formencode.Invalid(
919 msg, value, state, error_dict={'revisions': revs})
918 msg, value, state, error_dict={'revisions': revs})
920
919
921 return _validator
920 return _validator
922
921
923
922
924 def ValidIp():
923 def ValidIp():
925 class _validator(CIDR):
924 class _validator(CIDR):
926 messages = {
925 messages = {
927 'badFormat': _(u'Please enter a valid IPv4 or IpV6 address'),
926 'badFormat': _(u'Please enter a valid IPv4 or IpV6 address'),
928 'illegalBits': _(
927 'illegalBits': _(
929 u'The network size (bits) must be within the range '
928 u'The network size (bits) must be within the range '
930 u'of 0-32 (not %(bits)r)'),
929 u'of 0-32 (not %(bits)r)'),
931 }
930 }
932
931
933 # we ovveride the default to_python() call
932 # we ovveride the default to_python() call
934 def to_python(self, value, state):
933 def to_python(self, value, state):
935 v = super(_validator, self).to_python(value, state)
934 v = super(_validator, self).to_python(value, state)
936 v = v.strip()
935 v = v.strip()
937 net = ipaddress.ip_network(address=v, strict=False)
936 net = ipaddress.ip_network(address=v, strict=False)
938 return str(net)
937 return str(net)
939
938
940 def validate_python(self, value, state):
939 def validate_python(self, value, state):
941 try:
940 try:
942 addr = value.strip()
941 addr = value.strip()
943 # this raises an ValueError if address is not IpV4 or IpV6
942 # this raises an ValueError if address is not IpV4 or IpV6
944 ipaddress.ip_network(addr, strict=False)
943 ipaddress.ip_network(addr, strict=False)
945 except ValueError:
944 except ValueError:
946 raise formencode.Invalid(self.message('badFormat', state),
945 raise formencode.Invalid(self.message('badFormat', state),
947 value, state)
946 value, state)
948
947
949 return _validator
948 return _validator
950
949
951
950
952 def FieldKey():
951 def FieldKey():
953 class _validator(formencode.validators.FancyValidator):
952 class _validator(formencode.validators.FancyValidator):
954 messages = {
953 messages = {
955 'badFormat': _(
954 'badFormat': _(
956 u'Key name can only consist of letters, '
955 u'Key name can only consist of letters, '
957 u'underscore, dash or numbers'),
956 u'underscore, dash or numbers'),
958 }
957 }
959
958
960 def validate_python(self, value, state):
959 def validate_python(self, value, state):
961 if not re.match('[a-zA-Z0-9_-]+$', value):
960 if not re.match('[a-zA-Z0-9_-]+$', value):
962 raise formencode.Invalid(self.message('badFormat', state),
961 raise formencode.Invalid(self.message('badFormat', state),
963 value, state)
962 value, state)
964 return _validator
963 return _validator
965
964
966
965
967 def BasePath():
966 def BasePath():
968 class _validator(formencode.validators.FancyValidator):
967 class _validator(formencode.validators.FancyValidator):
969 messages = {
968 messages = {
970 'badPath': _(u'Filename cannot be inside a directory'),
969 'badPath': _(u'Filename cannot be inside a directory'),
971 }
970 }
972
971
973 def _to_python(self, value, state):
972 def _to_python(self, value, state):
974 return value
973 return value
975
974
976 def validate_python(self, value, state):
975 def validate_python(self, value, state):
977 if value != os.path.basename(value):
976 if value != os.path.basename(value):
978 raise formencode.Invalid(self.message('badPath', state),
977 raise formencode.Invalid(self.message('badPath', state),
979 value, state)
978 value, state)
980 return _validator
979 return _validator
981
980
982
981
983 def ValidAuthPlugins():
982 def ValidAuthPlugins():
984 class _validator(formencode.validators.FancyValidator):
983 class _validator(formencode.validators.FancyValidator):
985 messages = {
984 messages = {
986 'import_duplicate': _(
985 'import_duplicate': _(
987 u'Plugins %(loaded)s and %(next_to_load)s '
986 u'Plugins %(loaded)s and %(next_to_load)s '
988 u'both export the same name'),
987 u'both export the same name'),
989 }
988 }
990
989
991 def _to_python(self, value, state):
990 def _to_python(self, value, state):
992 # filter empty values
991 # filter empty values
993 return filter(lambda s: s not in [None, ''], value)
992 return filter(lambda s: s not in [None, ''], value)
994
993
995 def validate_python(self, value, state):
994 def validate_python(self, value, state):
996 from rhodecode.authentication.base import loadplugin
995 from rhodecode.authentication.base import loadplugin
997 module_list = value
996 module_list = value
998 unique_names = {}
997 unique_names = {}
999 try:
998 try:
1000 for module in module_list:
999 for module in module_list:
1001 plugin = loadplugin(module)
1000 plugin = loadplugin(module)
1002 plugin_name = plugin.name
1001 plugin_name = plugin.name
1003 if plugin_name in unique_names:
1002 if plugin_name in unique_names:
1004 msg = M(self, 'import_duplicate', state,
1003 msg = M(self, 'import_duplicate', state,
1005 loaded=unique_names[plugin_name],
1004 loaded=unique_names[plugin_name],
1006 next_to_load=plugin_name)
1005 next_to_load=plugin_name)
1007 raise formencode.Invalid(msg, value, state)
1006 raise formencode.Invalid(msg, value, state)
1008 unique_names[plugin_name] = plugin
1007 unique_names[plugin_name] = plugin
1009 except (KeyError, AttributeError, TypeError) as e:
1008 except (KeyError, AttributeError, TypeError) as e:
1010 raise formencode.Invalid(str(e), value, state)
1009 raise formencode.Invalid(str(e), value, state)
1011
1010
1012 return _validator
1011 return _validator
1013
1012
1014
1013
1015 def UniqGistId():
1014 def UniqGistId():
1016 class _validator(formencode.validators.FancyValidator):
1015 class _validator(formencode.validators.FancyValidator):
1017 messages = {
1016 messages = {
1018 'gistid_taken': _(u'This gistid is already in use')
1017 'gistid_taken': _(u'This gistid is already in use')
1019 }
1018 }
1020
1019
1021 def _to_python(self, value, state):
1020 def _to_python(self, value, state):
1022 return repo_name_slug(value.lower())
1021 return repo_name_slug(value.lower())
1023
1022
1024 def validate_python(self, value, state):
1023 def validate_python(self, value, state):
1025 existing = Gist.get_by_access_id(value)
1024 existing = Gist.get_by_access_id(value)
1026 if existing:
1025 if existing:
1027 msg = M(self, 'gistid_taken', state)
1026 msg = M(self, 'gistid_taken', state)
1028 raise formencode.Invalid(
1027 raise formencode.Invalid(
1029 msg, value, state, error_dict={'gistid': msg}
1028 msg, value, state, error_dict={'gistid': msg}
1030 )
1029 )
1031
1030
1032 return _validator
1031 return _validator
1033
1032
1034
1033
1035 def ValidPattern():
1034 def ValidPattern():
1036
1035
1037 class _Validator(formencode.validators.FancyValidator):
1036 class _Validator(formencode.validators.FancyValidator):
1038
1037
1039 def _to_python(self, value, state):
1038 def _to_python(self, value, state):
1040 patterns = []
1039 patterns = []
1041
1040
1042 prefix = 'new_pattern'
1041 prefix = 'new_pattern'
1043 for name, v in value.iteritems():
1042 for name, v in value.iteritems():
1044 pattern_name = '_'.join((prefix, 'pattern'))
1043 pattern_name = '_'.join((prefix, 'pattern'))
1045 if name.startswith(pattern_name):
1044 if name.startswith(pattern_name):
1046 new_item_id = name[len(pattern_name)+1:]
1045 new_item_id = name[len(pattern_name)+1:]
1047
1046
1048 def _field(name):
1047 def _field(name):
1049 return '%s_%s_%s' % (prefix, name, new_item_id)
1048 return '%s_%s_%s' % (prefix, name, new_item_id)
1050
1049
1051 values = {
1050 values = {
1052 'issuetracker_pat': value.get(_field('pattern')),
1051 'issuetracker_pat': value.get(_field('pattern')),
1053 'issuetracker_pat': value.get(_field('pattern')),
1052 'issuetracker_pat': value.get(_field('pattern')),
1054 'issuetracker_url': value.get(_field('url')),
1053 'issuetracker_url': value.get(_field('url')),
1055 'issuetracker_pref': value.get(_field('prefix')),
1054 'issuetracker_pref': value.get(_field('prefix')),
1056 'issuetracker_desc': value.get(_field('description'))
1055 'issuetracker_desc': value.get(_field('description'))
1057 }
1056 }
1058 new_uid = md5(values['issuetracker_pat'])
1057 new_uid = md5(values['issuetracker_pat'])
1059
1058
1060 has_required_fields = (
1059 has_required_fields = (
1061 values['issuetracker_pat']
1060 values['issuetracker_pat']
1062 and values['issuetracker_url'])
1061 and values['issuetracker_url'])
1063
1062
1064 if has_required_fields:
1063 if has_required_fields:
1065 settings = [
1064 settings = [
1066 ('_'.join((key, new_uid)), values[key], 'unicode')
1065 ('_'.join((key, new_uid)), values[key], 'unicode')
1067 for key in values]
1066 for key in values]
1068 patterns.append(settings)
1067 patterns.append(settings)
1069
1068
1070 value['patterns'] = patterns
1069 value['patterns'] = patterns
1071 delete_patterns = value.get('uid') or []
1070 delete_patterns = value.get('uid') or []
1072 if not isinstance(delete_patterns, (list, tuple)):
1071 if not isinstance(delete_patterns, (list, tuple)):
1073 delete_patterns = [delete_patterns]
1072 delete_patterns = [delete_patterns]
1074 value['delete_patterns'] = delete_patterns
1073 value['delete_patterns'] = delete_patterns
1075 return value
1074 return value
1076 return _Validator
1075 return _Validator
General Comments 0
You need to be logged in to leave comments. Login now