Show More
@@ -220,7 +220,7 b' class UsersController(BaseController):' | |||||
220 | return redirect(url('edit_user', id=id)) |
|
220 | return redirect(url('edit_user', id=id)) | |
221 |
|
221 | |||
222 | def add_email(self, id): |
|
222 | def add_email(self, id): | |
223 |
"""P |
|
223 | """POST /user_emails:Add an existing item""" | |
224 | # url('user_emails', id=ID, method='put') |
|
224 | # url('user_emails', id=ID, method='put') | |
225 |
|
225 | |||
226 | #TODO: validation and form !!! |
|
226 | #TODO: validation and form !!! |
This diff has been collapsed as it changes many lines, (753 lines changed) Show them Hide them | |||||
@@ -19,573 +19,76 b' list=[1,2,3,4,5]' | |||||
19 | for SELECT use formencode.All(OneOf(list), Int()) |
|
19 | for SELECT use formencode.All(OneOf(list), Int()) | |
20 |
|
20 | |||
21 | """ |
|
21 | """ | |
22 | import os |
|
|||
23 | import re |
|
|||
24 | import logging |
|
22 | import logging | |
25 | import traceback |
|
|||
26 |
|
23 | |||
27 | import formencode |
|
24 | import formencode | |
28 | from formencode import All |
|
25 | from formencode import All | |
29 | from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \ |
|
|||
30 | Email, Bool, StringBoolean, Set |
|
|||
31 |
|
26 | |||
32 | from pylons.i18n.translation import _ |
|
27 | from pylons.i18n.translation import _ | |
33 | from webhelpers.pylonslib.secure_form import authentication_token |
|
|||
34 |
|
28 | |||
35 | from rhodecode.config.routing import ADMIN_PREFIX |
|
29 | from rhodecode.model import validators as v | |
36 | from rhodecode.lib.utils import repo_name_slug |
|
|||
37 | from rhodecode.lib.auth import authenticate, get_crypt_password |
|
|||
38 | from rhodecode.lib.exceptions import LdapImportError |
|
|||
39 | from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository |
|
|||
40 | from rhodecode import BACKENDS |
|
30 | from rhodecode import BACKENDS | |
41 |
|
31 | |||
42 | log = logging.getLogger(__name__) |
|
32 | log = logging.getLogger(__name__) | |
43 |
|
33 | |||
44 |
|
34 | |||
45 | #this is needed to translate the messages using _() in validators |
|
|||
46 | class State_obj(object): |
|
|||
47 | _ = staticmethod(_) |
|
|||
48 |
|
||||
49 |
|
||||
50 | #============================================================================== |
|
|||
51 | # VALIDATORS |
|
|||
52 | #============================================================================== |
|
|||
53 | class ValidAuthToken(formencode.validators.FancyValidator): |
|
|||
54 | messages = {'invalid_token': _('Token mismatch')} |
|
|||
55 |
|
||||
56 | def validate_python(self, value, state): |
|
|||
57 |
|
||||
58 | if value != authentication_token(): |
|
|||
59 | raise formencode.Invalid( |
|
|||
60 | self.message('invalid_token', |
|
|||
61 | state, search_number=value), |
|
|||
62 | value, |
|
|||
63 | state |
|
|||
64 | ) |
|
|||
65 |
|
||||
66 |
|
||||
67 | def ValidUsername(edit, old_data): |
|
|||
68 | class _ValidUsername(formencode.validators.FancyValidator): |
|
|||
69 |
|
||||
70 | def validate_python(self, value, state): |
|
|||
71 | if value in ['default', 'new_user']: |
|
|||
72 | raise formencode.Invalid(_('Invalid username'), value, state) |
|
|||
73 | #check if user is unique |
|
|||
74 | old_un = None |
|
|||
75 | if edit: |
|
|||
76 | old_un = User.get(old_data.get('user_id')).username |
|
|||
77 |
|
||||
78 | if old_un != value or not edit: |
|
|||
79 | if User.get_by_username(value, case_insensitive=True): |
|
|||
80 | raise formencode.Invalid(_('This username already ' |
|
|||
81 | 'exists') , value, state) |
|
|||
82 |
|
||||
83 | if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None: |
|
|||
84 | raise formencode.Invalid( |
|
|||
85 | _('Username may only contain alphanumeric characters ' |
|
|||
86 | 'underscores, periods or dashes and must begin with ' |
|
|||
87 | 'alphanumeric character'), |
|
|||
88 | value, |
|
|||
89 | state |
|
|||
90 | ) |
|
|||
91 |
|
||||
92 | return _ValidUsername |
|
|||
93 |
|
||||
94 |
|
||||
95 | def ValidUsersGroup(edit, old_data): |
|
|||
96 |
|
||||
97 | class _ValidUsersGroup(formencode.validators.FancyValidator): |
|
|||
98 |
|
||||
99 | def validate_python(self, value, state): |
|
|||
100 | if value in ['default']: |
|
|||
101 | raise formencode.Invalid(_('Invalid group name'), value, state) |
|
|||
102 | #check if group is unique |
|
|||
103 | old_ugname = None |
|
|||
104 | if edit: |
|
|||
105 | old_ugname = UsersGroup.get( |
|
|||
106 | old_data.get('users_group_id')).users_group_name |
|
|||
107 |
|
||||
108 | if old_ugname != value or not edit: |
|
|||
109 | if UsersGroup.get_by_group_name(value, cache=False, |
|
|||
110 | case_insensitive=True): |
|
|||
111 | raise formencode.Invalid(_('This users group ' |
|
|||
112 | 'already exists'), value, |
|
|||
113 | state) |
|
|||
114 |
|
||||
115 | if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None: |
|
|||
116 | raise formencode.Invalid( |
|
|||
117 | _('RepoGroup name may only contain alphanumeric characters ' |
|
|||
118 | 'underscores, periods or dashes and must begin with ' |
|
|||
119 | 'alphanumeric character'), |
|
|||
120 | value, |
|
|||
121 | state |
|
|||
122 | ) |
|
|||
123 |
|
||||
124 | return _ValidUsersGroup |
|
|||
125 |
|
||||
126 |
|
||||
127 | def ValidReposGroup(edit, old_data): |
|
|||
128 | class _ValidReposGroup(formencode.validators.FancyValidator): |
|
|||
129 |
|
||||
130 | def validate_python(self, value, state): |
|
|||
131 | # TODO WRITE VALIDATIONS |
|
|||
132 | group_name = value.get('group_name') |
|
|||
133 | group_parent_id = value.get('group_parent_id') |
|
|||
134 |
|
||||
135 | # slugify repo group just in case :) |
|
|||
136 | slug = repo_name_slug(group_name) |
|
|||
137 |
|
||||
138 | # check for parent of self |
|
|||
139 | parent_of_self = lambda: ( |
|
|||
140 | old_data['group_id'] == int(group_parent_id) |
|
|||
141 | if group_parent_id else False |
|
|||
142 | ) |
|
|||
143 | if edit and parent_of_self(): |
|
|||
144 | e_dict = { |
|
|||
145 | 'group_parent_id': _('Cannot assign this group as parent') |
|
|||
146 | } |
|
|||
147 | raise formencode.Invalid('', value, state, |
|
|||
148 | error_dict=e_dict) |
|
|||
149 |
|
||||
150 | old_gname = None |
|
|||
151 | if edit: |
|
|||
152 | old_gname = RepoGroup.get(old_data.get('group_id')).group_name |
|
|||
153 |
|
||||
154 | if old_gname != group_name or not edit: |
|
|||
155 |
|
||||
156 | # check group |
|
|||
157 | gr = RepoGroup.query()\ |
|
|||
158 | .filter(RepoGroup.group_name == slug)\ |
|
|||
159 | .filter(RepoGroup.group_parent_id == group_parent_id)\ |
|
|||
160 | .scalar() |
|
|||
161 |
|
||||
162 | if gr: |
|
|||
163 | e_dict = { |
|
|||
164 | 'group_name': _('This group already exists') |
|
|||
165 | } |
|
|||
166 | raise formencode.Invalid('', value, state, |
|
|||
167 | error_dict=e_dict) |
|
|||
168 |
|
||||
169 | # check for same repo |
|
|||
170 | repo = Repository.query()\ |
|
|||
171 | .filter(Repository.repo_name == slug)\ |
|
|||
172 | .scalar() |
|
|||
173 |
|
||||
174 | if repo: |
|
|||
175 | e_dict = { |
|
|||
176 | 'group_name': _('Repository with this name already exists') |
|
|||
177 | } |
|
|||
178 | raise formencode.Invalid('', value, state, |
|
|||
179 | error_dict=e_dict) |
|
|||
180 |
|
||||
181 | return _ValidReposGroup |
|
|||
182 |
|
||||
183 |
|
||||
184 | class ValidPassword(formencode.validators.FancyValidator): |
|
|||
185 |
|
||||
186 | def to_python(self, value, state): |
|
|||
187 |
|
||||
188 | if not value: |
|
|||
189 | return |
|
|||
190 |
|
||||
191 | if value.get('password'): |
|
|||
192 | try: |
|
|||
193 | value['password'] = get_crypt_password(value['password']) |
|
|||
194 | except UnicodeEncodeError: |
|
|||
195 | e_dict = {'password': _('Invalid characters in password')} |
|
|||
196 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
|||
197 |
|
||||
198 | if value.get('password_confirmation'): |
|
|||
199 | try: |
|
|||
200 | value['password_confirmation'] = \ |
|
|||
201 | get_crypt_password(value['password_confirmation']) |
|
|||
202 | except UnicodeEncodeError: |
|
|||
203 | e_dict = { |
|
|||
204 | 'password_confirmation': _('Invalid characters in password') |
|
|||
205 | } |
|
|||
206 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
|||
207 |
|
||||
208 | if value.get('new_password'): |
|
|||
209 | try: |
|
|||
210 | value['new_password'] = \ |
|
|||
211 | get_crypt_password(value['new_password']) |
|
|||
212 | except UnicodeEncodeError: |
|
|||
213 | e_dict = {'new_password': _('Invalid characters in password')} |
|
|||
214 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
|||
215 |
|
||||
216 | return value |
|
|||
217 |
|
||||
218 |
|
||||
219 | class ValidPasswordsMatch(formencode.validators.FancyValidator): |
|
|||
220 |
|
||||
221 | def validate_python(self, value, state): |
|
|||
222 |
|
||||
223 | pass_val = value.get('password') or value.get('new_password') |
|
|||
224 | if pass_val != value['password_confirmation']: |
|
|||
225 | e_dict = {'password_confirmation': |
|
|||
226 | _('Passwords do not match')} |
|
|||
227 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
|||
228 |
|
||||
229 |
|
||||
230 | class ValidAuth(formencode.validators.FancyValidator): |
|
|||
231 | messages = { |
|
|||
232 | 'invalid_password':_('invalid password'), |
|
|||
233 | 'invalid_login':_('invalid user name'), |
|
|||
234 | 'disabled_account':_('Your account is disabled') |
|
|||
235 | } |
|
|||
236 |
|
||||
237 | # error mapping |
|
|||
238 | e_dict = {'username': messages['invalid_login'], |
|
|||
239 | 'password': messages['invalid_password']} |
|
|||
240 | e_dict_disable = {'username': messages['disabled_account']} |
|
|||
241 |
|
||||
242 | def validate_python(self, value, state): |
|
|||
243 | password = value['password'] |
|
|||
244 | username = value['username'] |
|
|||
245 | user = User.get_by_username(username) |
|
|||
246 |
|
||||
247 | if authenticate(username, password): |
|
|||
248 | return value |
|
|||
249 | else: |
|
|||
250 | if user and user.active is False: |
|
|||
251 | log.warning('user %s is disabled' % username) |
|
|||
252 | raise formencode.Invalid( |
|
|||
253 | self.message('disabled_account', |
|
|||
254 | state=State_obj), |
|
|||
255 | value, state, |
|
|||
256 | error_dict=self.e_dict_disable |
|
|||
257 | ) |
|
|||
258 | else: |
|
|||
259 | log.warning('user %s failed to authenticate' % username) |
|
|||
260 | raise formencode.Invalid( |
|
|||
261 | self.message('invalid_password', |
|
|||
262 | state=State_obj), value, state, |
|
|||
263 | error_dict=self.e_dict |
|
|||
264 | ) |
|
|||
265 |
|
||||
266 |
|
||||
267 | class ValidRepoUser(formencode.validators.FancyValidator): |
|
|||
268 |
|
||||
269 | def to_python(self, value, state): |
|
|||
270 | try: |
|
|||
271 | User.query().filter(User.active == True)\ |
|
|||
272 | .filter(User.username == value).one() |
|
|||
273 | except Exception: |
|
|||
274 | raise formencode.Invalid(_('This username is not valid'), |
|
|||
275 | value, state) |
|
|||
276 | return value |
|
|||
277 |
|
||||
278 |
|
||||
279 | def ValidRepoName(edit, old_data): |
|
|||
280 | class _ValidRepoName(formencode.validators.FancyValidator): |
|
|||
281 | def to_python(self, value, state): |
|
|||
282 |
|
||||
283 | repo_name = value.get('repo_name') |
|
|||
284 |
|
||||
285 | slug = repo_name_slug(repo_name) |
|
|||
286 | if slug in [ADMIN_PREFIX, '']: |
|
|||
287 | e_dict = {'repo_name': _('This repository name is disallowed')} |
|
|||
288 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
|||
289 |
|
||||
290 | if value.get('repo_group'): |
|
|||
291 | gr = RepoGroup.get(value.get('repo_group')) |
|
|||
292 | group_path = gr.full_path |
|
|||
293 | # value needs to be aware of group name in order to check |
|
|||
294 | # db key This is an actual just the name to store in the |
|
|||
295 | # database |
|
|||
296 | repo_name_full = group_path + RepoGroup.url_sep() + repo_name |
|
|||
297 |
|
||||
298 | else: |
|
|||
299 | group_path = '' |
|
|||
300 | repo_name_full = repo_name |
|
|||
301 |
|
||||
302 | value['repo_name_full'] = repo_name_full |
|
|||
303 | rename = old_data.get('repo_name') != repo_name_full |
|
|||
304 | create = not edit |
|
|||
305 | if rename or create: |
|
|||
306 |
|
||||
307 | if group_path != '': |
|
|||
308 | if Repository.get_by_repo_name(repo_name_full): |
|
|||
309 | e_dict = { |
|
|||
310 | 'repo_name': _('This repository already exists in ' |
|
|||
311 | 'a group "%s"') % gr.group_name |
|
|||
312 | } |
|
|||
313 | raise formencode.Invalid('', value, state, |
|
|||
314 | error_dict=e_dict) |
|
|||
315 | elif RepoGroup.get_by_group_name(repo_name_full): |
|
|||
316 | e_dict = { |
|
|||
317 | 'repo_name': _('There is a group with this name ' |
|
|||
318 | 'already "%s"') % repo_name_full |
|
|||
319 | } |
|
|||
320 | raise formencode.Invalid('', value, state, |
|
|||
321 | error_dict=e_dict) |
|
|||
322 |
|
||||
323 | elif Repository.get_by_repo_name(repo_name_full): |
|
|||
324 | e_dict = {'repo_name': _('This repository ' |
|
|||
325 | 'already exists')} |
|
|||
326 | raise formencode.Invalid('', value, state, |
|
|||
327 | error_dict=e_dict) |
|
|||
328 |
|
||||
329 | return value |
|
|||
330 |
|
||||
331 | return _ValidRepoName |
|
|||
332 |
|
||||
333 |
|
||||
334 | def ValidForkName(*args, **kwargs): |
|
|||
335 | return ValidRepoName(*args, **kwargs) |
|
|||
336 |
|
||||
337 |
|
||||
338 | def SlugifyName(): |
|
|||
339 | class _SlugifyName(formencode.validators.FancyValidator): |
|
|||
340 |
|
||||
341 | def to_python(self, value, state): |
|
|||
342 | return repo_name_slug(value) |
|
|||
343 |
|
||||
344 | return _SlugifyName |
|
|||
345 |
|
||||
346 |
|
||||
347 | def ValidCloneUri(): |
|
|||
348 | from rhodecode.lib.utils import make_ui |
|
|||
349 |
|
||||
350 | def url_handler(repo_type, url, proto, ui=None): |
|
|||
351 | if repo_type == 'hg': |
|
|||
352 | from mercurial.httprepo import httprepository, httpsrepository |
|
|||
353 | if proto == 'https': |
|
|||
354 | httpsrepository(make_ui('db'), url).capabilities |
|
|||
355 | elif proto == 'http': |
|
|||
356 | httprepository(make_ui('db'), url).capabilities |
|
|||
357 | elif repo_type == 'git': |
|
|||
358 | #TODO: write a git url validator |
|
|||
359 | pass |
|
|||
360 |
|
||||
361 | class _ValidCloneUri(formencode.validators.FancyValidator): |
|
|||
362 |
|
||||
363 | def to_python(self, value, state): |
|
|||
364 |
|
||||
365 | repo_type = value.get('repo_type') |
|
|||
366 | url = value.get('clone_uri') |
|
|||
367 | e_dict = {'clone_uri': _('invalid clone url')} |
|
|||
368 |
|
||||
369 | if not url: |
|
|||
370 | pass |
|
|||
371 | elif url.startswith('https'): |
|
|||
372 | try: |
|
|||
373 | url_handler(repo_type, url, 'https', make_ui('db')) |
|
|||
374 | except Exception: |
|
|||
375 | log.error(traceback.format_exc()) |
|
|||
376 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
|||
377 | elif url.startswith('http'): |
|
|||
378 | try: |
|
|||
379 | url_handler(repo_type, url, 'http', make_ui('db')) |
|
|||
380 | except Exception: |
|
|||
381 | log.error(traceback.format_exc()) |
|
|||
382 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
|||
383 | else: |
|
|||
384 | e_dict = {'clone_uri': _('Invalid clone url, provide a ' |
|
|||
385 | 'valid clone http\s url')} |
|
|||
386 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
|||
387 |
|
||||
388 | return value |
|
|||
389 |
|
||||
390 | return _ValidCloneUri |
|
|||
391 |
|
||||
392 |
|
||||
393 | def ValidForkType(old_data): |
|
|||
394 | class _ValidForkType(formencode.validators.FancyValidator): |
|
|||
395 |
|
||||
396 | def to_python(self, value, state): |
|
|||
397 | if old_data['repo_type'] != value: |
|
|||
398 | raise formencode.Invalid(_('Fork have to be the same ' |
|
|||
399 | 'type as original'), value, state) |
|
|||
400 |
|
||||
401 | return value |
|
|||
402 | return _ValidForkType |
|
|||
403 |
|
||||
404 |
|
||||
405 | def ValidPerms(type_='repo'): |
|
|||
406 | if type_ == 'group': |
|
|||
407 | EMPTY_PERM = 'group.none' |
|
|||
408 | elif type_ == 'repo': |
|
|||
409 | EMPTY_PERM = 'repository.none' |
|
|||
410 |
|
||||
411 | class _ValidPerms(formencode.validators.FancyValidator): |
|
|||
412 | messages = { |
|
|||
413 | 'perm_new_member_name': |
|
|||
414 | _('This username or users group name is not valid') |
|
|||
415 | } |
|
|||
416 |
|
||||
417 | def to_python(self, value, state): |
|
|||
418 | perms_update = [] |
|
|||
419 | perms_new = [] |
|
|||
420 | # build a list of permission to update and new permission to create |
|
|||
421 | for k, v in value.items(): |
|
|||
422 | # means new added member to permissions |
|
|||
423 | if k.startswith('perm_new_member'): |
|
|||
424 | new_perm = value.get('perm_new_member', False) |
|
|||
425 | new_member = value.get('perm_new_member_name', False) |
|
|||
426 | new_type = value.get('perm_new_member_type') |
|
|||
427 |
|
||||
428 | if new_member and new_perm: |
|
|||
429 | if (new_member, new_perm, new_type) not in perms_new: |
|
|||
430 | perms_new.append((new_member, new_perm, new_type)) |
|
|||
431 | elif k.startswith('u_perm_') or k.startswith('g_perm_'): |
|
|||
432 | member = k[7:] |
|
|||
433 | t = {'u': 'user', |
|
|||
434 | 'g': 'users_group' |
|
|||
435 | }[k[0]] |
|
|||
436 | if member == 'default': |
|
|||
437 | if value.get('private'): |
|
|||
438 | # set none for default when updating to private repo |
|
|||
439 | v = EMPTY_PERM |
|
|||
440 | perms_update.append((member, v, t)) |
|
|||
441 |
|
||||
442 | value['perms_updates'] = perms_update |
|
|||
443 | value['perms_new'] = perms_new |
|
|||
444 |
|
||||
445 | # update permissions |
|
|||
446 | for k, v, t in perms_new: |
|
|||
447 | try: |
|
|||
448 | if t is 'user': |
|
|||
449 | self.user_db = User.query()\ |
|
|||
450 | .filter(User.active == True)\ |
|
|||
451 | .filter(User.username == k).one() |
|
|||
452 | if t is 'users_group': |
|
|||
453 | self.user_db = UsersGroup.query()\ |
|
|||
454 | .filter(UsersGroup.users_group_active == True)\ |
|
|||
455 | .filter(UsersGroup.users_group_name == k).one() |
|
|||
456 |
|
||||
457 | except Exception: |
|
|||
458 | msg = self.message('perm_new_member_name', |
|
|||
459 | state=State_obj) |
|
|||
460 | raise formencode.Invalid( |
|
|||
461 | msg, value, state, error_dict={'perm_new_member_name': msg} |
|
|||
462 | ) |
|
|||
463 | return value |
|
|||
464 | return _ValidPerms |
|
|||
465 |
|
||||
466 |
|
||||
467 | class ValidSettings(formencode.validators.FancyValidator): |
|
|||
468 |
|
||||
469 | def to_python(self, value, state): |
|
|||
470 | # settings form can't edit user |
|
|||
471 | if 'user' in value: |
|
|||
472 | del['value']['user'] |
|
|||
473 | return value |
|
|||
474 |
|
||||
475 |
|
||||
476 | class ValidPath(formencode.validators.FancyValidator): |
|
|||
477 | def to_python(self, value, state): |
|
|||
478 |
|
||||
479 | if not os.path.isdir(value): |
|
|||
480 | msg = _('This is not a valid path') |
|
|||
481 | raise formencode.Invalid(msg, value, state, |
|
|||
482 | error_dict={'paths_root_path': msg}) |
|
|||
483 | return value |
|
|||
484 |
|
||||
485 |
|
||||
486 | def UniqSystemEmail(old_data): |
|
|||
487 | class _UniqSystemEmail(formencode.validators.FancyValidator): |
|
|||
488 | def to_python(self, value, state): |
|
|||
489 | value = value.lower() |
|
|||
490 | if (old_data.get('email') or '').lower() != value: |
|
|||
491 | user = User.get_by_email(value, case_insensitive=True) |
|
|||
492 | if user: |
|
|||
493 | raise formencode.Invalid( |
|
|||
494 | _("This e-mail address is already taken"), value, state |
|
|||
495 | ) |
|
|||
496 | return value |
|
|||
497 |
|
||||
498 | return _UniqSystemEmail |
|
|||
499 |
|
||||
500 |
|
||||
501 | class ValidSystemEmail(formencode.validators.FancyValidator): |
|
|||
502 | def to_python(self, value, state): |
|
|||
503 | value = value.lower() |
|
|||
504 | user = User.get_by_email(value, case_insensitive=True) |
|
|||
505 | if user is None: |
|
|||
506 | raise formencode.Invalid( |
|
|||
507 | _("This e-mail address doesn't exist."), value, state |
|
|||
508 | ) |
|
|||
509 |
|
||||
510 | return value |
|
|||
511 |
|
||||
512 |
|
||||
513 | class LdapLibValidator(formencode.validators.FancyValidator): |
|
|||
514 |
|
||||
515 | def to_python(self, value, state): |
|
|||
516 |
|
||||
517 | try: |
|
|||
518 | import ldap |
|
|||
519 | except ImportError: |
|
|||
520 | raise LdapImportError |
|
|||
521 | return value |
|
|||
522 |
|
||||
523 |
|
||||
524 | class AttrLoginValidator(formencode.validators.FancyValidator): |
|
|||
525 |
|
||||
526 | def to_python(self, value, state): |
|
|||
527 |
|
||||
528 | if not value or not isinstance(value, (str, unicode)): |
|
|||
529 | raise formencode.Invalid( |
|
|||
530 | _("The LDAP Login attribute of the CN must be specified - " |
|
|||
531 | "this is the name of the attribute that is equivalent " |
|
|||
532 | "to 'username'"), value, state |
|
|||
533 | ) |
|
|||
534 |
|
||||
535 | return value |
|
|||
536 |
|
||||
537 |
|
||||
538 | #============================================================================== |
|
|||
539 | # FORMS |
|
|||
540 | #============================================================================== |
|
|||
541 | class LoginForm(formencode.Schema): |
|
35 | class LoginForm(formencode.Schema): | |
542 | allow_extra_fields = True |
|
36 | allow_extra_fields = True | |
543 | filter_extra_fields = True |
|
37 | filter_extra_fields = True | |
544 | username = UnicodeString( |
|
38 | username = v.UnicodeString( | |
545 | strip=True, |
|
39 | strip=True, | |
546 | min=1, |
|
40 | min=1, | |
547 | not_empty=True, |
|
41 | not_empty=True, | |
548 | messages={ |
|
42 | messages={ | |
549 | 'empty': _('Please enter a login'), |
|
43 | 'empty': _(u'Please enter a login'), | |
550 | 'tooShort': _('Enter a value %(min)i characters long or more')} |
|
44 | 'tooShort': _(u'Enter a value %(min)i characters long or more')} | |
551 | ) |
|
45 | ) | |
552 |
|
46 | |||
553 | password = UnicodeString( |
|
47 | password = v.UnicodeString( | |
554 | strip=False, |
|
48 | strip=False, | |
555 | min=3, |
|
49 | min=3, | |
556 | not_empty=True, |
|
50 | not_empty=True, | |
557 | messages={ |
|
51 | messages={ | |
558 | 'empty': _('Please enter a password'), |
|
52 | 'empty': _(u'Please enter a password'), | |
559 | 'tooShort': _('Enter %(min)i characters or more')} |
|
53 | 'tooShort': _(u'Enter %(min)i characters or more')} | |
560 | ) |
|
54 | ) | |
561 |
|
55 | |||
562 | remember = StringBoolean(if_missing=False) |
|
56 | remember = v.StringBoolean(if_missing=False) | |
563 |
|
57 | |||
564 | chained_validators = [ValidAuth] |
|
58 | chained_validators = [v.ValidAuth()] | |
565 |
|
59 | |||
566 |
|
60 | |||
567 | def UserForm(edit=False, old_data={}): |
|
61 | def UserForm(edit=False, old_data={}): | |
568 | class _UserForm(formencode.Schema): |
|
62 | class _UserForm(formencode.Schema): | |
569 | allow_extra_fields = True |
|
63 | allow_extra_fields = True | |
570 | filter_extra_fields = True |
|
64 | filter_extra_fields = True | |
571 | username = All(UnicodeString(strip=True, min=1, not_empty=True), |
|
65 | username = All(v.UnicodeString(strip=True, min=1, not_empty=True), | |
572 | ValidUsername(edit, old_data)) |
|
66 | v.ValidUsername(edit, old_data)) | |
573 | if edit: |
|
67 | if edit: | |
574 | new_password = All(UnicodeString(strip=False, min=6, not_empty=False)) |
|
68 | new_password = All( | |
575 |
|
|
69 | v.UnicodeString(strip=False, min=6, not_empty=False) | |
576 | not_empty=False)) |
|
70 | ) | |
577 | admin = StringBoolean(if_missing=False) |
|
71 | password_confirmation = All( | |
|
72 | v.ValidPassword(), | |||
|
73 | v.UnicodeString(strip=False, min=6, not_empty=False), | |||
|
74 | ) | |||
|
75 | admin = v.StringBoolean(if_missing=False) | |||
578 | else: |
|
76 | else: | |
579 | password = All(UnicodeString(strip=False, min=6, not_empty=True)) |
|
77 | password = All( | |
580 | password_confirmation = All(UnicodeString(strip=False, min=6, |
|
78 | v.ValidPassword(), | |
581 | not_empty=False)) |
|
79 | v.UnicodeString(strip=False, min=6, not_empty=True) | |
|
80 | ) | |||
|
81 | password_confirmation = All( | |||
|
82 | v.ValidPassword(), | |||
|
83 | v.UnicodeString(strip=False, min=6, not_empty=False) | |||
|
84 | ) | |||
582 |
|
85 | |||
583 | active = StringBoolean(if_missing=False) |
|
86 | active = v.StringBoolean(if_missing=False) | |
584 | name = UnicodeString(strip=True, min=1, not_empty=False) |
|
87 | name = v.UnicodeString(strip=True, min=1, not_empty=False) | |
585 | lastname = UnicodeString(strip=True, min=1, not_empty=False) |
|
88 | lastname = v.UnicodeString(strip=True, min=1, not_empty=False) | |
586 | email = All(Email(not_empty=True), UniqSystemEmail(old_data)) |
|
89 | email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data)) | |
587 |
|
90 | |||
588 |
chained_validators = [ValidPasswordsMatch |
|
91 | chained_validators = [v.ValidPasswordsMatch()] | |
589 |
|
92 | |||
590 | return _UserForm |
|
93 | return _UserForm | |
591 |
|
94 | |||
@@ -595,15 +98,18 b' def UsersGroupForm(edit=False, old_data=' | |||||
595 | allow_extra_fields = True |
|
98 | allow_extra_fields = True | |
596 | filter_extra_fields = True |
|
99 | filter_extra_fields = True | |
597 |
|
100 | |||
598 | users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True), |
|
101 | users_group_name = All( | |
599 | ValidUsersGroup(edit, old_data)) |
|
102 | v.UnicodeString(strip=True, min=1, not_empty=True), | |
|
103 | v.ValidUsersGroup(edit, old_data) | |||
|
104 | ) | |||
600 |
|
105 | |||
601 | users_group_active = StringBoolean(if_missing=False) |
|
106 | users_group_active = v.StringBoolean(if_missing=False) | |
602 |
|
107 | |||
603 | if edit: |
|
108 | if edit: | |
604 |
users_group_members = OneOf( |
|
109 | users_group_members = v.OneOf( | |
605 | testValueList=True, |
|
110 | available_members, hideList=False, testValueList=True, | |
606 |
|
|
111 | if_missing=None, not_empty=False | |
|
112 | ) | |||
607 |
|
113 | |||
608 | return _UsersGroupForm |
|
114 | return _UsersGroupForm | |
609 |
|
115 | |||
@@ -613,15 +119,16 b' def ReposGroupForm(edit=False, old_data=' | |||||
613 | allow_extra_fields = True |
|
119 | allow_extra_fields = True | |
614 | filter_extra_fields = False |
|
120 | filter_extra_fields = False | |
615 |
|
121 | |||
616 | group_name = All(UnicodeString(strip=True, min=1, not_empty=True), |
|
122 | group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True), | |
617 | SlugifyName()) |
|
123 | v.SlugifyName()) | |
618 | group_description = UnicodeString(strip=True, min=1, |
|
124 | group_description = v.UnicodeString(strip=True, min=1, | |
619 | not_empty=True) |
|
125 | not_empty=True) | |
620 | group_parent_id = OneOf(available_groups, hideList=False, |
|
126 | group_parent_id = v.OneOf(available_groups, hideList=False, | |
621 | testValueList=True, |
|
127 | testValueList=True, | |
622 | if_missing=None, not_empty=False) |
|
128 | if_missing=None, not_empty=False) | |
623 |
|
129 | |||
624 |
chained_validators = [ValidReposGroup(edit, old_data), |
|
130 | chained_validators = [v.ValidReposGroup(edit, old_data), | |
|
131 | v.ValidPerms('group')] | |||
625 |
|
132 | |||
626 | return _ReposGroupForm |
|
133 | return _ReposGroupForm | |
627 |
|
134 | |||
@@ -630,16 +137,24 b' def RegisterForm(edit=False, old_data={}' | |||||
630 | class _RegisterForm(formencode.Schema): |
|
137 | class _RegisterForm(formencode.Schema): | |
631 | allow_extra_fields = True |
|
138 | allow_extra_fields = True | |
632 | filter_extra_fields = True |
|
139 | filter_extra_fields = True | |
633 |
username = All( |
|
140 | username = All( | |
634 | UnicodeString(strip=True, min=1, not_empty=True)) |
|
141 | v.ValidUsername(edit, old_data), | |
635 |
|
|
142 | v.UnicodeString(strip=True, min=1, not_empty=True) | |
636 | password_confirmation = All(UnicodeString(strip=False, min=6, not_empty=True)) |
|
143 | ) | |
637 | active = StringBoolean(if_missing=False) |
|
144 | password = All( | |
638 | name = UnicodeString(strip=True, min=1, not_empty=False) |
|
145 | v.ValidPassword(), | |
639 |
|
|
146 | v.UnicodeString(strip=False, min=6, not_empty=True) | |
640 | email = All(Email(not_empty=True), UniqSystemEmail(old_data)) |
|
147 | ) | |
|
148 | password_confirmation = All( | |||
|
149 | v.ValidPassword(), | |||
|
150 | v.UnicodeString(strip=False, min=6, not_empty=True) | |||
|
151 | ) | |||
|
152 | active = v.StringBoolean(if_missing=False) | |||
|
153 | name = v.UnicodeString(strip=True, min=1, not_empty=False) | |||
|
154 | lastname = v.UnicodeString(strip=True, min=1, not_empty=False) | |||
|
155 | email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data)) | |||
641 |
|
156 | |||
642 |
chained_validators = [ValidPasswordsMatch |
|
157 | chained_validators = [v.ValidPasswordsMatch()] | |
643 |
|
158 | |||
644 | return _RegisterForm |
|
159 | return _RegisterForm | |
645 |
|
160 | |||
@@ -648,7 +163,7 b' def PasswordResetForm():' | |||||
648 | class _PasswordResetForm(formencode.Schema): |
|
163 | class _PasswordResetForm(formencode.Schema): | |
649 | allow_extra_fields = True |
|
164 | allow_extra_fields = True | |
650 | filter_extra_fields = True |
|
165 | filter_extra_fields = True | |
651 | email = All(ValidSystemEmail(), Email(not_empty=True)) |
|
166 | email = All(v.ValidSystemEmail(), v.Email(not_empty=True)) | |
652 | return _PasswordResetForm |
|
167 | return _PasswordResetForm | |
653 |
|
168 | |||
654 |
|
169 | |||
@@ -657,24 +172,24 b' def RepoForm(edit=False, old_data={}, su' | |||||
657 | class _RepoForm(formencode.Schema): |
|
172 | class _RepoForm(formencode.Schema): | |
658 | allow_extra_fields = True |
|
173 | allow_extra_fields = True | |
659 | filter_extra_fields = False |
|
174 | filter_extra_fields = False | |
660 | repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), |
|
175 | repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True), | |
661 | SlugifyName()) |
|
176 | v.SlugifyName()) | |
662 | clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False)) |
|
177 | clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False)) | |
663 | repo_group = OneOf(repo_groups, hideList=True) |
|
178 | repo_group = v.OneOf(repo_groups, hideList=True) | |
664 | repo_type = OneOf(supported_backends) |
|
179 | repo_type = v.OneOf(supported_backends) | |
665 | description = UnicodeString(strip=True, min=1, not_empty=False) |
|
180 | description = v.UnicodeString(strip=True, min=1, not_empty=False) | |
666 | private = StringBoolean(if_missing=False) |
|
181 | private = v.StringBoolean(if_missing=False) | |
667 | enable_statistics = StringBoolean(if_missing=False) |
|
182 | enable_statistics = v.StringBoolean(if_missing=False) | |
668 | enable_downloads = StringBoolean(if_missing=False) |
|
183 | enable_downloads = v.StringBoolean(if_missing=False) | |
669 | landing_rev = OneOf(landing_revs, hideList=True) |
|
184 | landing_rev = v.OneOf(landing_revs, hideList=True) | |
670 |
|
185 | |||
671 | if edit: |
|
186 | if edit: | |
672 | #this is repo owner |
|
187 | #this is repo owner | |
673 | user = All(UnicodeString(not_empty=True), ValidRepoUser) |
|
188 | user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) | |
674 |
|
189 | |||
675 |
chained_validators = [ValidCloneUri |
|
190 | chained_validators = [v.ValidCloneUri(), | |
676 | ValidRepoName(edit, old_data), |
|
191 | v.ValidRepoName(edit, old_data), | |
677 | ValidPerms()] |
|
192 | v.ValidPerms()] | |
678 | return _RepoForm |
|
193 | return _RepoForm | |
679 |
|
194 | |||
680 |
|
195 | |||
@@ -683,33 +198,34 b' def RepoForkForm(edit=False, old_data={}' | |||||
683 | class _RepoForkForm(formencode.Schema): |
|
198 | class _RepoForkForm(formencode.Schema): | |
684 | allow_extra_fields = True |
|
199 | allow_extra_fields = True | |
685 | filter_extra_fields = False |
|
200 | filter_extra_fields = False | |
686 | repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), |
|
201 | repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True), | |
687 | SlugifyName()) |
|
202 | v.SlugifyName()) | |
688 | repo_group = OneOf(repo_groups, hideList=True) |
|
203 | repo_group = v.OneOf(repo_groups, hideList=True) | |
689 | repo_type = All(ValidForkType(old_data), OneOf(supported_backends)) |
|
204 | repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends)) | |
690 | description = UnicodeString(strip=True, min=1, not_empty=True) |
|
205 | description = v.UnicodeString(strip=True, min=1, not_empty=True) | |
691 | private = StringBoolean(if_missing=False) |
|
206 | private = v.StringBoolean(if_missing=False) | |
692 | copy_permissions = StringBoolean(if_missing=False) |
|
207 | copy_permissions = v.StringBoolean(if_missing=False) | |
693 | update_after_clone = StringBoolean(if_missing=False) |
|
208 | update_after_clone = v.StringBoolean(if_missing=False) | |
694 | fork_parent_id = UnicodeString() |
|
209 | fork_parent_id = v.UnicodeString() | |
695 | chained_validators = [ValidForkName(edit, old_data)] |
|
210 | chained_validators = [v.ValidForkName(edit, old_data)] | |
696 |
|
211 | |||
697 | return _RepoForkForm |
|
212 | return _RepoForkForm | |
698 |
|
213 | |||
699 |
|
214 | |||
700 |
def RepoSettingsForm(edit=False, old_data={}, |
|
215 | def RepoSettingsForm(edit=False, old_data={}, | |
701 | repo_groups=[], landing_revs=[]): |
|
216 | supported_backends=BACKENDS.keys(), repo_groups=[], | |
|
217 | landing_revs=[]): | |||
702 | class _RepoForm(formencode.Schema): |
|
218 | class _RepoForm(formencode.Schema): | |
703 | allow_extra_fields = True |
|
219 | allow_extra_fields = True | |
704 | filter_extra_fields = False |
|
220 | filter_extra_fields = False | |
705 | repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), |
|
221 | repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True), | |
706 | SlugifyName()) |
|
222 | v.SlugifyName()) | |
707 | description = UnicodeString(strip=True, min=1, not_empty=True) |
|
223 | description = v.UnicodeString(strip=True, min=1, not_empty=True) | |
708 | repo_group = OneOf(repo_groups, hideList=True) |
|
224 | repo_group = v.OneOf(repo_groups, hideList=True) | |
709 | private = StringBoolean(if_missing=False) |
|
225 | private = v.StringBoolean(if_missing=False) | |
710 | landing_rev = OneOf(landing_revs, hideList=True) |
|
226 | landing_rev = v.OneOf(landing_revs, hideList=True) | |
711 | chained_validators = [ValidRepoName(edit, old_data), ValidPerms(), |
|
227 | chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(), | |
712 | ValidSettings] |
|
228 | v.ValidSettings()] | |
713 | return _RepoForm |
|
229 | return _RepoForm | |
714 |
|
230 | |||
715 |
|
231 | |||
@@ -717,9 +233,9 b' def ApplicationSettingsForm():' | |||||
717 | class _ApplicationSettingsForm(formencode.Schema): |
|
233 | class _ApplicationSettingsForm(formencode.Schema): | |
718 | allow_extra_fields = True |
|
234 | allow_extra_fields = True | |
719 | filter_extra_fields = False |
|
235 | filter_extra_fields = False | |
720 | rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True) |
|
236 | rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True) | |
721 | rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True) |
|
237 | rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True) | |
722 | rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False) |
|
238 | rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False) | |
723 |
|
239 | |||
724 | return _ApplicationSettingsForm |
|
240 | return _ApplicationSettingsForm | |
725 |
|
241 | |||
@@ -728,12 +244,19 b' def ApplicationUiSettingsForm():' | |||||
728 | class _ApplicationUiSettingsForm(formencode.Schema): |
|
244 | class _ApplicationUiSettingsForm(formencode.Schema): | |
729 | allow_extra_fields = True |
|
245 | allow_extra_fields = True | |
730 | filter_extra_fields = False |
|
246 | filter_extra_fields = False | |
731 | web_push_ssl = OneOf(['true', 'false'], if_missing='false') |
|
247 | web_push_ssl = v.OneOf(['true', 'false'], if_missing='false') | |
732 | paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True)) |
|
248 | paths_root_path = All( | |
733 | hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False) |
|
249 | v.ValidPath(), | |
734 | hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False) |
|
250 | v.UnicodeString(strip=True, min=1, not_empty=True) | |
735 | hooks_changegroup_push_logger = OneOf(['True', 'False'], if_missing=False) |
|
251 | ) | |
736 |
hooks_ |
|
252 | hooks_changegroup_update = v.OneOf(['True', 'False'], | |
|
253 | if_missing=False) | |||
|
254 | hooks_changegroup_repo_size = v.OneOf(['True', 'False'], | |||
|
255 | if_missing=False) | |||
|
256 | hooks_changegroup_push_logger = v.OneOf(['True', 'False'], | |||
|
257 | if_missing=False) | |||
|
258 | hooks_preoutgoing_pull_logger = v.OneOf(['True', 'False'], | |||
|
259 | if_missing=False) | |||
737 |
|
260 | |||
738 | return _ApplicationUiSettingsForm |
|
261 | return _ApplicationUiSettingsForm | |
739 |
|
262 | |||
@@ -742,33 +265,37 b' def DefaultPermissionsForm(perms_choices' | |||||
742 | class _DefaultPermissionsForm(formencode.Schema): |
|
265 | class _DefaultPermissionsForm(formencode.Schema): | |
743 | allow_extra_fields = True |
|
266 | allow_extra_fields = True | |
744 | filter_extra_fields = True |
|
267 | filter_extra_fields = True | |
745 | overwrite_default = StringBoolean(if_missing=False) |
|
268 | overwrite_default = v.StringBoolean(if_missing=False) | |
746 | anonymous = OneOf(['True', 'False'], if_missing=False) |
|
269 | anonymous = v.OneOf(['True', 'False'], if_missing=False) | |
747 | default_perm = OneOf(perms_choices) |
|
270 | default_perm = v.OneOf(perms_choices) | |
748 | default_register = OneOf(register_choices) |
|
271 | default_register = v.OneOf(register_choices) | |
749 | default_create = OneOf(create_choices) |
|
272 | default_create = v.OneOf(create_choices) | |
750 |
|
273 | |||
751 | return _DefaultPermissionsForm |
|
274 | return _DefaultPermissionsForm | |
752 |
|
275 | |||
753 |
|
276 | |||
754 |
def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, |
|
277 | def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, | |
|
278 | tls_kind_choices): | |||
755 | class _LdapSettingsForm(formencode.Schema): |
|
279 | class _LdapSettingsForm(formencode.Schema): | |
756 | allow_extra_fields = True |
|
280 | allow_extra_fields = True | |
757 | filter_extra_fields = True |
|
281 | filter_extra_fields = True | |
758 | #pre_validators = [LdapLibValidator] |
|
282 | #pre_validators = [LdapLibValidator] | |
759 | ldap_active = StringBoolean(if_missing=False) |
|
283 | ldap_active = v.StringBoolean(if_missing=False) | |
760 | ldap_host = UnicodeString(strip=True,) |
|
284 | ldap_host = v.UnicodeString(strip=True,) | |
761 | ldap_port = Number(strip=True,) |
|
285 | ldap_port = v.Number(strip=True,) | |
762 | ldap_tls_kind = OneOf(tls_kind_choices) |
|
286 | ldap_tls_kind = v.OneOf(tls_kind_choices) | |
763 | ldap_tls_reqcert = OneOf(tls_reqcert_choices) |
|
287 | ldap_tls_reqcert = v.OneOf(tls_reqcert_choices) | |
764 | ldap_dn_user = UnicodeString(strip=True,) |
|
288 | ldap_dn_user = v.UnicodeString(strip=True,) | |
765 | ldap_dn_pass = UnicodeString(strip=True,) |
|
289 | ldap_dn_pass = v.UnicodeString(strip=True,) | |
766 | ldap_base_dn = UnicodeString(strip=True,) |
|
290 | ldap_base_dn = v.UnicodeString(strip=True,) | |
767 | ldap_filter = UnicodeString(strip=True,) |
|
291 | ldap_filter = v.UnicodeString(strip=True,) | |
768 | ldap_search_scope = OneOf(search_scope_choices) |
|
292 | ldap_search_scope = v.OneOf(search_scope_choices) | |
769 | ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,)) |
|
293 | ldap_attr_login = All( | |
770 | ldap_attr_firstname = UnicodeString(strip=True,) |
|
294 | v.AttrLoginValidator(), | |
771 |
|
|
295 | v.UnicodeString(strip=True,) | |
772 | ldap_attr_email = UnicodeString(strip=True,) |
|
296 | ) | |
|
297 | ldap_attr_firstname = v.UnicodeString(strip=True,) | |||
|
298 | ldap_attr_lastname = v.UnicodeString(strip=True,) | |||
|
299 | ldap_attr_email = v.UnicodeString(strip=True,) | |||
773 |
|
300 | |||
774 | return _LdapSettingsForm |
|
301 | return _LdapSettingsForm |
@@ -199,13 +199,13 b' class ReposGroupModel(BaseModel):' | |||||
199 | log.error(traceback.format_exc()) |
|
199 | log.error(traceback.format_exc()) | |
200 | raise |
|
200 | raise | |
201 |
|
201 | |||
202 |
def delete(self, |
|
202 | def delete(self, repos_group): | |
|
203 | repos_group = self.__get_repos_group(repos_group) | |||
203 | try: |
|
204 | try: | |
204 | users_group = RepoGroup.get(users_group_id) |
|
205 | self.sa.delete(repos_group) | |
205 |
self. |
|
206 | self.__delete_group(repos_group) | |
206 | self.__delete_group(users_group) |
|
|||
207 | except: |
|
207 | except: | |
208 | log.error(traceback.format_exc()) |
|
208 | log.exception('Error removing repos_group %s' % repos_group) | |
209 | raise |
|
209 | raise | |
210 |
|
210 | |||
211 | def grant_user_permission(self, repos_group, user, perm): |
|
211 | def grant_user_permission(self, repos_group, user, perm): |
@@ -87,9 +87,12 b' class UserModel(BaseModel):' | |||||
87 | return User.get_by_api_key(api_key, cache) |
|
87 | return User.get_by_api_key(api_key, cache) | |
88 |
|
88 | |||
89 | def create(self, form_data): |
|
89 | def create(self, form_data): | |
|
90 | from rhodecode.lib.auth import get_crypt_password | |||
90 | try: |
|
91 | try: | |
91 | new_user = User() |
|
92 | new_user = User() | |
92 | for k, v in form_data.items(): |
|
93 | for k, v in form_data.items(): | |
|
94 | if k == 'password': | |||
|
95 | v = get_crypt_password(v) | |||
93 | setattr(new_user, k, v) |
|
96 | setattr(new_user, k, v) | |
94 |
|
97 | |||
95 | new_user.api_key = generate_api_key(form_data['username']) |
|
98 | new_user.api_key = generate_api_key(form_data['username']) | |
@@ -265,15 +268,17 b' class UserModel(BaseModel):' | |||||
265 | raise |
|
268 | raise | |
266 |
|
269 | |||
267 | def update_my_account(self, user_id, form_data): |
|
270 | def update_my_account(self, user_id, form_data): | |
|
271 | from rhodecode.lib.auth import get_crypt_password | |||
268 | try: |
|
272 | try: | |
269 | user = self.get(user_id, cache=False) |
|
273 | user = self.get(user_id, cache=False) | |
270 | if user.username == 'default': |
|
274 | if user.username == 'default': | |
271 | raise DefaultUserException( |
|
275 | raise DefaultUserException( | |
272 |
|
|
276 | _("You can't Edit this user since it's" | |
273 |
|
|
277 | " crucial for entire application") | |
|
278 | ) | |||
274 | for k, v in form_data.items(): |
|
279 | for k, v in form_data.items(): | |
275 | if k == 'new_password' and v != '': |
|
280 | if k == 'new_password' and v != '': | |
276 | user.password = v |
|
281 | user.password = get_crypt_password(v) | |
277 | user.api_key = generate_api_key(user.username) |
|
282 | user.api_key = generate_api_key(user.username) | |
278 | else: |
|
283 | else: | |
279 | if k not in ['admin', 'active']: |
|
284 | if k not in ['admin', 'active']: |
@@ -3,6 +3,8 b'' | |||||
3 | from rhodecode.lib.auth import get_crypt_password, check_password |
|
3 | from rhodecode.lib.auth import get_crypt_password, check_password | |
4 | from rhodecode.model.db import User, RhodeCodeSetting |
|
4 | from rhodecode.model.db import User, RhodeCodeSetting | |
5 | from rhodecode.tests import * |
|
5 | from rhodecode.tests import * | |
|
6 | from rhodecode.lib import helpers as h | |||
|
7 | ||||
6 |
|
8 | |||
7 | class TestAdminSettingsController(TestController): |
|
9 | class TestAdminSettingsController(TestController): | |
8 |
|
10 | |||
@@ -47,7 +49,6 b' class TestAdminSettingsController(TestCo' | |||||
47 | response = self.app.get(url('formatted_admin_edit_setting', |
|
49 | response = self.app.get(url('formatted_admin_edit_setting', | |
48 | setting_id=1, format='xml')) |
|
50 | setting_id=1, format='xml')) | |
49 |
|
51 | |||
50 |
|
||||
51 | def test_ga_code_active(self): |
|
52 | def test_ga_code_active(self): | |
52 | self.log_user() |
|
53 | self.log_user() | |
53 | old_title = 'RhodeCode' |
|
54 | old_title = 'RhodeCode' | |
@@ -92,7 +93,6 b' class TestAdminSettingsController(TestCo' | |||||
92 | self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code |
|
93 | self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code | |
93 | not in response.body) |
|
94 | not in response.body) | |
94 |
|
95 | |||
95 |
|
||||
96 | def test_title_change(self): |
|
96 | def test_title_change(self): | |
97 | self.log_user() |
|
97 | self.log_user() | |
98 | old_title = 'RhodeCode' |
|
98 | old_title = 'RhodeCode' | |
@@ -117,7 +117,6 b' class TestAdminSettingsController(TestCo' | |||||
117 | self.assertTrue("""<h1><a href="/">%s</a></h1>""" % new_title |
|
117 | self.assertTrue("""<h1><a href="/">%s</a></h1>""" % new_title | |
118 | in response.body) |
|
118 | in response.body) | |
119 |
|
119 | |||
120 |
|
||||
121 | def test_my_account(self): |
|
120 | def test_my_account(self): | |
122 | self.log_user() |
|
121 | self.log_user() | |
123 | response = self.app.get(url('admin_settings_my_account')) |
|
122 | response = self.app.get(url('admin_settings_my_account')) | |
@@ -132,7 +131,6 b' class TestAdminSettingsController(TestCo' | |||||
132 | new_lastname = 'NewLastname' |
|
131 | new_lastname = 'NewLastname' | |
133 | new_password = 'test123' |
|
132 | new_password = 'test123' | |
134 |
|
133 | |||
135 |
|
||||
136 | response = self.app.post(url('admin_settings_my_account_update'), |
|
134 | response = self.app.post(url('admin_settings_my_account_update'), | |
137 | params=dict(_method='put', |
|
135 | params=dict(_method='put', | |
138 | username='test_admin', |
|
136 | username='test_admin', | |
@@ -179,7 +177,6 b' class TestAdminSettingsController(TestCo' | |||||
179 | assert user.lastname == old_lastname, 'updated field mismatch %s vs %s' % (user.lastname, old_lastname) |
|
177 | assert user.lastname == old_lastname, 'updated field mismatch %s vs %s' % (user.lastname, old_lastname) | |
180 |
assert check_password(old_password, user.password) is True |
|
178 | assert check_password(old_password, user.password) is True, 'password updated field mismatch %s vs %s' % (user.password, old_password) | |
181 |
|
179 | |||
182 |
|
||||
183 | def test_my_account_update_err_email_exists(self): |
|
180 | def test_my_account_update_err_email_exists(self): | |
184 | self.log_user() |
|
181 | self.log_user() | |
185 |
|
182 | |||
@@ -195,18 +192,24 b' class TestAdminSettingsController(TestCo' | |||||
195 |
|
192 | |||
196 | assert 'This e-mail address is already taken' in response.body, 'Missing error message about existing email' |
|
193 | assert 'This e-mail address is already taken' in response.body, 'Missing error message about existing email' | |
197 |
|
194 | |||
198 |
|
||||
199 | def test_my_account_update_err(self): |
|
195 | def test_my_account_update_err(self): | |
200 | self.log_user('test_regular2', 'test12') |
|
196 | self.log_user('test_regular2', 'test12') | |
201 |
|
197 | |||
202 | new_email = 'newmail.pl' |
|
198 | new_email = 'newmail.pl' | |
203 |
response = self.app.post(url('admin_settings_my_account_update'), |
|
199 | response = self.app.post(url('admin_settings_my_account_update'), | |
|
200 | params=dict( | |||
204 |
|
|
201 | _method='put', | |
205 |
|
|
202 | username='test_admin', | |
206 |
|
|
203 | new_password='test12', | |
207 |
|
|
204 | password_confirmation='test122', | |
208 |
|
|
205 | name='NewName', | |
209 |
|
|
206 | lastname='NewLastname', | |
210 |
|
|
207 | email=new_email,) | |
211 | assert 'An email address must contain a single @' in response.body, 'Missing error message about wrong email' |
|
208 | ) | |
212 | assert 'This username already exists' in response.body, 'Missing error message about existing user' |
|
209 | ||
|
210 | response.mustcontain('An email address must contain a single @') | |||
|
211 | from rhodecode.model import validators | |||
|
212 | msg = validators.ValidUsername(edit=False, | |||
|
213 | old_data={})._messages['username_exists'] | |||
|
214 | msg = h.html_escape(msg % {'username': 'test_admin'}) | |||
|
215 | response.mustcontain(u"%s" % msg) |
@@ -1,8 +1,12 b'' | |||||
|
1 | from sqlalchemy.orm.exc import NoResultFound | |||
|
2 | ||||
1 | from rhodecode.tests import * |
|
3 | from rhodecode.tests import * | |
2 | from rhodecode.model.db import User, Permission |
|
4 | from rhodecode.model.db import User, Permission | |
3 | from rhodecode.lib.auth import check_password |
|
5 | from rhodecode.lib.auth import check_password | |
4 | from sqlalchemy.orm.exc import NoResultFound |
|
|||
5 | from rhodecode.model.user import UserModel |
|
6 | from rhodecode.model.user import UserModel | |
|
7 | from rhodecode.model import validators | |||
|
8 | from rhodecode.lib import helpers as h | |||
|
9 | ||||
6 |
|
10 | |||
7 | class TestAdminUsersController(TestController): |
|
11 | class TestAdminUsersController(TestController): | |
8 |
|
12 | |||
@@ -32,9 +36,8 b' class TestAdminUsersController(TestContr' | |||||
32 |
|
|
36 | 'lastname': lastname, | |
33 |
|
|
37 | 'email': email}) | |
34 |
|
38 | |||
|
39 | self.checkSessionFlash(response, '''created user %s''' % (username)) | |||
35 |
|
40 | |||
36 | self.assertTrue('''created user %s''' % (username) in |
|
|||
37 | response.session['flash'][0]) |
|
|||
38 |
|
41 | |||
39 | new_user = self.Session.query(User).\ |
|
42 | new_user = self.Session.query(User).\ | |
40 | filter(User.username == username).one() |
|
43 | filter(User.username == username).one() | |
@@ -64,9 +67,11 b' class TestAdminUsersController(TestContr' | |||||
64 | 'lastname':lastname, |
|
67 | 'lastname': lastname, | |
65 | 'email':email}) |
|
68 | 'email': email}) | |
66 |
|
69 | |||
67 | self.assertTrue("""<span class="error-message">Invalid username</span>""" in response.body) |
|
70 | msg = validators.ValidUsername(False, {})._messages['system_invalid_username'] | |
68 | self.assertTrue("""<span class="error-message">Please enter a value</span>""" in response.body) |
|
71 | msg = h.html_escape(msg % {'username': 'new_user'}) | |
69 | self.assertTrue("""<span class="error-message">An email address must contain a single @</span>""" in response.body) |
|
72 | response.mustcontain("""<span class="error-message">%s</span>""" % msg) | |
|
73 | response.mustcontain("""<span class="error-message">Please enter a value</span>""") | |||
|
74 | response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""") | |||
70 |
|
75 | |||
71 | def get_user(): |
|
76 | def get_user(): | |
72 | self.Session.query(User).filter(User.username == username).one() |
|
77 | self.Session.query(User).filter(User.username == username).one() | |
@@ -111,7 +116,6 b' class TestAdminUsersController(TestContr' | |||||
111 | self.assertTrue("""successfully deleted user""" in |
|
116 | self.assertTrue("""successfully deleted user""" in | |
112 | response.session['flash'][0]) |
|
117 | response.session['flash'][0]) | |
113 |
|
118 | |||
114 |
|
||||
115 | def test_delete_browser_fakeout(self): |
|
119 | def test_delete_browser_fakeout(self): | |
116 | response = self.app.post(url('user', id=1), |
|
120 | response = self.app.post(url('user', id=1), | |
117 | params=dict(_method='delete')) |
|
121 | params=dict(_method='delete')) | |
@@ -127,7 +131,6 b' class TestAdminUsersController(TestContr' | |||||
127 | user = User.get_by_username(TEST_USER_ADMIN_LOGIN) |
|
131 | user = User.get_by_username(TEST_USER_ADMIN_LOGIN) | |
128 | response = self.app.get(url('edit_user', id=user.user_id)) |
|
132 | response = self.app.get(url('edit_user', id=user.user_id)) | |
129 |
|
133 | |||
130 |
|
||||
131 | def test_add_perm_create_repo(self): |
|
134 | def test_add_perm_create_repo(self): | |
132 | self.log_user() |
|
135 | self.log_user() | |
133 | perm_none = Permission.get_by_key('hg.create.none') |
|
136 | perm_none = Permission.get_by_key('hg.create.none') | |
@@ -135,7 +138,6 b' class TestAdminUsersController(TestContr' | |||||
135 |
|
138 | |||
136 | user = User.get_by_username(TEST_USER_REGULAR_LOGIN) |
|
139 | user = User.get_by_username(TEST_USER_REGULAR_LOGIN) | |
137 |
|
140 | |||
138 |
|
||||
139 | #User should have None permission on creation repository |
|
141 | #User should have None permission on creation repository | |
140 | self.assertEqual(UserModel().has_perm(user, perm_none), False) |
|
142 | self.assertEqual(UserModel().has_perm(user, perm_none), False) | |
141 | self.assertEqual(UserModel().has_perm(user, perm_create), False) |
|
143 | self.assertEqual(UserModel().has_perm(user, perm_create), False) | |
@@ -159,7 +161,6 b' class TestAdminUsersController(TestContr' | |||||
159 |
|
161 | |||
160 | user = User.get_by_username(TEST_USER_REGULAR2_LOGIN) |
|
162 | user = User.get_by_username(TEST_USER_REGULAR2_LOGIN) | |
161 |
|
163 | |||
162 |
|
||||
163 | #User should have None permission on creation repository |
|
164 | #User should have None permission on creation repository | |
164 | self.assertEqual(UserModel().has_perm(user, perm_none), False) |
|
165 | self.assertEqual(UserModel().has_perm(user, perm_none), False) | |
165 | self.assertEqual(UserModel().has_perm(user, perm_create), False) |
|
166 | self.assertEqual(UserModel().has_perm(user, perm_create), False) |
@@ -4,6 +4,8 b' from rhodecode.model.db import User, Not' | |||||
4 | from rhodecode.lib.utils2 import generate_api_key |
|
4 | from rhodecode.lib.utils2 import generate_api_key | |
5 | from rhodecode.lib.auth import check_password |
|
5 | from rhodecode.lib.auth import check_password | |
6 | from rhodecode.model.meta import Session |
|
6 | from rhodecode.model.meta import Session | |
|
7 | from rhodecode.lib import helpers as h | |||
|
8 | from rhodecode.model import validators | |||
7 |
|
9 | |||
8 |
|
10 | |||
9 | class TestLoginController(TestController): |
|
11 | class TestLoginController(TestController): | |
@@ -66,7 +68,6 b' class TestLoginController(TestController' | |||||
66 | response = self.app.post(url(controller='login', action='index'), |
|
68 | response = self.app.post(url(controller='login', action='index'), | |
67 | {'username':'error', |
|
69 | {'username': 'error', | |
68 | 'password':'test12'}) |
|
70 | 'password': 'test12'}) | |
69 | self.assertEqual(response.status , '200 OK') |
|
|||
70 |
|
71 | |||
71 | self.assertTrue('invalid user name' in response.body) |
|
72 | self.assertTrue('invalid user name' in response.body) | |
72 | self.assertTrue('invalid password' in response.body) |
|
73 | self.assertTrue('invalid password' in response.body) | |
@@ -79,16 +80,18 b' class TestLoginController(TestController' | |||||
79 | self.assertTrue('Sign Up to RhodeCode' in response.body) |
|
80 | self.assertTrue('Sign Up to RhodeCode' in response.body) | |
80 |
|
81 | |||
81 | def test_register_err_same_username(self): |
|
82 | def test_register_err_same_username(self): | |
|
83 | uname = 'test_admin' | |||
82 | response = self.app.post(url(controller='login', action='register'), |
|
84 | response = self.app.post(url(controller='login', action='register'), | |
83 |
{'username': |
|
85 | {'username': uname, | |
84 | 'password':'test12', |
|
86 | 'password': 'test12', | |
85 | 'password_confirmation':'test12', |
|
87 | 'password_confirmation': 'test12', | |
86 | 'email':'goodmail@domain.com', |
|
88 | 'email': 'goodmail@domain.com', | |
87 | 'name':'test', |
|
89 | 'name': 'test', | |
88 | 'lastname':'test'}) |
|
90 | 'lastname': 'test'}) | |
89 |
|
91 | |||
90 | self.assertEqual(response.status , '200 OK') |
|
92 | msg = validators.ValidUsername()._messages['username_exists'] | |
91 | self.assertTrue('This username already exists' in response.body) |
|
93 | msg = h.html_escape(msg % {'username': uname}) | |
|
94 | response.mustcontain(msg) | |||
92 |
|
95 | |||
93 | def test_register_err_same_email(self): |
|
96 | def test_register_err_same_email(self): | |
94 | response = self.app.post(url(controller='login', action='register'), |
|
97 | response = self.app.post(url(controller='login', action='register'), | |
@@ -99,8 +102,8 b' class TestLoginController(TestController' | |||||
99 | 'name':'test', |
|
102 | 'name': 'test', | |
100 | 'lastname':'test'}) |
|
103 | 'lastname': 'test'}) | |
101 |
|
104 | |||
102 | self.assertEqual(response.status , '200 OK') |
|
105 | msg = validators.UniqSystemEmail()()._messages['email_taken'] | |
103 |
response.mustcontain( |
|
106 | response.mustcontain(msg) | |
104 |
|
107 | |||
105 | def test_register_err_same_email_case_sensitive(self): |
|
108 | def test_register_err_same_email_case_sensitive(self): | |
106 | response = self.app.post(url(controller='login', action='register'), |
|
109 | response = self.app.post(url(controller='login', action='register'), | |
@@ -110,8 +113,8 b' class TestLoginController(TestController' | |||||
110 | 'email':'TesT_Admin@mail.COM', |
|
113 | 'email': 'TesT_Admin@mail.COM', | |
111 | 'name':'test', |
|
114 | 'name': 'test', | |
112 | 'lastname':'test'}) |
|
115 | 'lastname': 'test'}) | |
113 | self.assertEqual(response.status , '200 OK') |
|
116 | msg = validators.UniqSystemEmail()()._messages['email_taken'] | |
114 |
response.mustcontain( |
|
117 | response.mustcontain(msg) | |
115 |
|
118 | |||
116 | def test_register_err_wrong_data(self): |
|
119 | def test_register_err_wrong_data(self): | |
117 | response = self.app.post(url(controller='login', action='register'), |
|
120 | response = self.app.post(url(controller='login', action='register'), | |
@@ -134,7 +137,6 b' class TestLoginController(TestController' | |||||
134 | 'name':'test', |
|
137 | 'name': 'test', | |
135 | 'lastname':'test'}) |
|
138 | 'lastname': 'test'}) | |
136 |
|
139 | |||
137 | self.assertEqual(response.status , '200 OK') |
|
|||
138 | response.mustcontain('An email address must contain a single @') |
|
140 | response.mustcontain('An email address must contain a single @') | |
139 | response.mustcontain('Username may only contain ' |
|
141 | response.mustcontain('Username may only contain ' | |
140 | 'alphanumeric characters underscores, ' |
|
142 | 'alphanumeric characters underscores, ' | |
@@ -142,17 +144,19 b' class TestLoginController(TestController' | |||||
142 | 'alphanumeric character') |
|
144 | 'alphanumeric character') | |
143 |
|
145 | |||
144 | def test_register_err_case_sensitive(self): |
|
146 | def test_register_err_case_sensitive(self): | |
|
147 | usr = 'Test_Admin' | |||
145 | response = self.app.post(url(controller='login', action='register'), |
|
148 | response = self.app.post(url(controller='login', action='register'), | |
146 |
{'username': |
|
149 | {'username': usr, | |
147 | 'password':'test12', |
|
150 | 'password': 'test12', | |
148 | 'password_confirmation':'test12', |
|
151 | 'password_confirmation': 'test12', | |
149 | 'email':'goodmailm', |
|
152 | 'email': 'goodmailm', | |
150 | 'name':'test', |
|
153 | 'name': 'test', | |
151 | 'lastname':'test'}) |
|
154 | 'lastname': 'test'}) | |
152 |
|
155 | |||
153 | self.assertEqual(response.status , '200 OK') |
|
156 | response.mustcontain('An email address must contain a single @') | |
154 | self.assertTrue('An email address must contain a single @' in response.body) |
|
157 | msg = validators.ValidUsername()._messages['username_exists'] | |
155 | self.assertTrue('This username already exists' in response.body) |
|
158 | msg = h.html_escape(msg % {'username': usr}) | |
|
159 | response.mustcontain(msg) | |||
156 |
|
160 | |||
157 | def test_register_special_chars(self): |
|
161 | def test_register_special_chars(self): | |
158 | response = self.app.post(url(controller='login', action='register'), |
|
162 | response = self.app.post(url(controller='login', action='register'), | |
@@ -163,8 +167,8 b' class TestLoginController(TestController' | |||||
163 |
|
|
167 | 'name': 'test', | |
164 |
|
|
168 | 'lastname': 'test'}) | |
165 |
|
169 | |||
166 | self.assertEqual(response.status , '200 OK') |
|
170 | msg = validators.ValidPassword()._messages['invalid_password'] | |
167 | self.assertTrue('Invalid characters in password' in response.body) |
|
171 | response.mustcontain(msg) | |
168 |
|
172 | |||
169 | def test_register_password_mismatch(self): |
|
173 | def test_register_password_mismatch(self): | |
170 | response = self.app.post(url(controller='login', action='register'), |
|
174 | response = self.app.post(url(controller='login', action='register'), | |
@@ -174,9 +178,8 b' class TestLoginController(TestController' | |||||
174 | 'email':'goodmailm@test.plxa', |
|
178 | 'email': 'goodmailm@test.plxa', | |
175 | 'name':'test', |
|
179 | 'name': 'test', | |
176 | 'lastname':'test'}) |
|
180 | 'lastname': 'test'}) | |
177 |
|
181 | msg = validators.ValidPasswordsMatch()._messages['password_mismatch'] | ||
178 | self.assertEqual(response.status, '200 OK') |
|
182 | response.mustcontain(msg) | |
179 | response.mustcontain('Passwords do not match') |
|
|||
180 |
|
183 | |||
181 | def test_register_ok(self): |
|
184 | def test_register_ok(self): | |
182 | username = 'test_regular4' |
|
185 | username = 'test_regular4' | |
@@ -206,12 +209,15 b' class TestLoginController(TestController' | |||||
206 | self.assertEqual(ret.admin, False) |
|
209 | self.assertEqual(ret.admin, False) | |
207 |
|
210 | |||
208 | def test_forgot_password_wrong_mail(self): |
|
211 | def test_forgot_password_wrong_mail(self): | |
|
212 | bad_email = 'marcin@wrongmail.org' | |||
209 | response = self.app.post( |
|
213 | response = self.app.post( | |
210 | url(controller='login', action='password_reset'), |
|
214 | url(controller='login', action='password_reset'), | |
211 |
{'email': |
|
215 | {'email': bad_email, } | |
212 | ) |
|
216 | ) | |
213 |
|
217 | |||
214 | response.mustcontain("This e-mail address doesn't exist") |
|
218 | msg = validators.ValidSystemEmail()._messages['non_existing_email'] | |
|
219 | msg = h.html_escape(msg % {'email': bad_email}) | |||
|
220 | response.mustcontain() | |||
215 |
|
221 | |||
216 | def test_forgot_password(self): |
|
222 | def test_forgot_password(self): | |
217 | response = self.app.get(url(controller='login', |
|
223 | response = self.app.get(url(controller='login', |
General Comments 0
You need to be logged in to leave comments.
Login now