##// END OF EJS Templates
implements #237 added password confirmation for my account and admin edit user.
marcink -
r1597:019026a8 beta
parent child Browse files
Show More
@@ -1,692 +1,694 b''
1 1 """ this is forms validation classes
2 2 http://formencode.org/module-formencode.validators.html
3 3 for list off all availible validators
4 4
5 5 we can create our own validators
6 6
7 7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 8 pre_validators [] These validators will be applied before the schema
9 9 chained_validators [] These validators will be applied after the schema
10 10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14 14
15 15
16 16 <name> = formencode.validators.<name of validator>
17 17 <name> must equal form name
18 18 list=[1,2,3,4,5]
19 19 for SELECT use formencode.All(OneOf(list), Int())
20 20
21 21 """
22 22 import os
23 23 import re
24 24 import logging
25 25 import traceback
26 26
27 27 import formencode
28 28 from formencode import All
29 29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
30 30 Email, Bool, StringBoolean, Set
31 31
32 32 from pylons.i18n.translation import _
33 33 from webhelpers.pylonslib.secure_form import authentication_token
34 34
35 35 from rhodecode.config.routing import ADMIN_PREFIX
36 36 from rhodecode.lib.utils import repo_name_slug
37 37 from rhodecode.lib.auth import authenticate, get_crypt_password
38 38 from rhodecode.lib.exceptions import LdapImportError
39 39 from rhodecode.model.user import UserModel
40 40 from rhodecode.model.repo import RepoModel
41 41 from rhodecode.model.db import User, UsersGroup, Group
42 42 from rhodecode import BACKENDS
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46 #this is needed to translate the messages using _() in validators
47 47 class State_obj(object):
48 48 _ = staticmethod(_)
49 49
50 50 #==============================================================================
51 51 # VALIDATORS
52 52 #==============================================================================
53 53 class ValidAuthToken(formencode.validators.FancyValidator):
54 54 messages = {'invalid_token':_('Token mismatch')}
55 55
56 56 def validate_python(self, value, state):
57 57
58 58 if value != authentication_token():
59 59 raise formencode.Invalid(self.message('invalid_token', state,
60 60 search_number=value), value, state)
61 61
62 62 def ValidUsername(edit, old_data):
63 63 class _ValidUsername(formencode.validators.FancyValidator):
64 64
65 65 def validate_python(self, value, state):
66 66 if value in ['default', 'new_user']:
67 67 raise formencode.Invalid(_('Invalid username'), value, state)
68 68 #check if user is unique
69 69 old_un = None
70 70 if edit:
71 71 old_un = UserModel().get(old_data.get('user_id')).username
72 72
73 73 if old_un != value or not edit:
74 74 if User.get_by_username(value, case_insensitive=True):
75 75 raise formencode.Invalid(_('This username already '
76 76 'exists') , value, state)
77 77
78 78 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
79 79 raise formencode.Invalid(_('Username may only contain '
80 80 'alphanumeric characters '
81 81 'underscores, periods or dashes '
82 82 'and must begin with alphanumeric '
83 83 'character'), value, state)
84 84
85 85 return _ValidUsername
86 86
87 87
88 88 def ValidUsersGroup(edit, old_data):
89 89
90 90 class _ValidUsersGroup(formencode.validators.FancyValidator):
91 91
92 92 def validate_python(self, value, state):
93 93 if value in ['default']:
94 94 raise formencode.Invalid(_('Invalid group name'), value, state)
95 95 #check if group is unique
96 96 old_ugname = None
97 97 if edit:
98 98 old_ugname = UsersGroup.get(
99 99 old_data.get('users_group_id')).users_group_name
100 100
101 101 if old_ugname != value or not edit:
102 102 if UsersGroup.get_by_group_name(value, cache=False,
103 103 case_insensitive=True):
104 104 raise formencode.Invalid(_('This users group '
105 105 'already exists') , value,
106 106 state)
107 107
108 108
109 109 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
110 110 raise formencode.Invalid(_('Group name may only contain '
111 111 'alphanumeric characters '
112 112 'underscores, periods or dashes '
113 113 'and must begin with alphanumeric '
114 114 'character'), value, state)
115 115
116 116 return _ValidUsersGroup
117 117
118 118
119 119 def ValidReposGroup(edit, old_data):
120 120 class _ValidReposGroup(formencode.validators.FancyValidator):
121 121
122 122 def validate_python(self, value, state):
123 123 #TODO WRITE VALIDATIONS
124 124 group_name = value.get('group_name')
125 125 group_parent_id = int(value.get('group_parent_id') or -1)
126 126
127 127 # slugify repo group just in case :)
128 128 slug = repo_name_slug(group_name)
129 129
130 130 # check for parent of self
131 131 if edit and old_data['group_id'] == group_parent_id:
132 132 e_dict = {'group_parent_id':_('Cannot assign this group '
133 133 'as parent')}
134 134 raise formencode.Invalid('', value, state,
135 135 error_dict=e_dict)
136 136
137 137 old_gname = None
138 138 if edit:
139 139 old_gname = Group.get(
140 140 old_data.get('group_id')).group_name
141 141
142 142 if old_gname != group_name or not edit:
143 143 # check filesystem
144 144 gr = Group.query().filter(Group.group_name == slug)\
145 145 .filter(Group.group_parent_id == group_parent_id).scalar()
146 146
147 147 if gr:
148 148 e_dict = {'group_name':_('This group already exists')}
149 149 raise formencode.Invalid('', value, state,
150 150 error_dict=e_dict)
151 151
152 152 return _ValidReposGroup
153 153
154 154 class ValidPassword(formencode.validators.FancyValidator):
155 155
156 156 def to_python(self, value, state):
157 157
158 158 if value:
159 159
160 160 if value.get('password'):
161 161 try:
162 162 value['password'] = get_crypt_password(value['password'])
163 163 except UnicodeEncodeError:
164 164 e_dict = {'password':_('Invalid characters in password')}
165 165 raise formencode.Invalid('', value, state, error_dict=e_dict)
166 166
167 167 if value.get('password_confirmation'):
168 168 try:
169 169 value['password_confirmation'] = \
170 170 get_crypt_password(value['password_confirmation'])
171 171 except UnicodeEncodeError:
172 172 e_dict = {'password_confirmation':_('Invalid characters in password')}
173 173 raise formencode.Invalid('', value, state, error_dict=e_dict)
174 174
175 175 if value.get('new_password'):
176 176 try:
177 177 value['new_password'] = \
178 178 get_crypt_password(value['new_password'])
179 179 except UnicodeEncodeError:
180 180 e_dict = {'new_password':_('Invalid characters in password')}
181 181 raise formencode.Invalid('', value, state, error_dict=e_dict)
182 182
183 183 return value
184 184
185 185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
186 186
187 187 def validate_python(self, value, state):
188 188
189 if value['password'] != value['password_confirmation']:
189 pass_val = value.get('password') or value.get('new_password')
190 if pass_val != value['password_confirmation']:
190 191 e_dict = {'password_confirmation':
191 192 _('Passwords do not match')}
192 193 raise formencode.Invalid('', value, state, error_dict=e_dict)
193 194
194 195 class ValidAuth(formencode.validators.FancyValidator):
195 196 messages = {
196 197 'invalid_password':_('invalid password'),
197 198 'invalid_login':_('invalid user name'),
198 199 'disabled_account':_('Your account is disabled')
199 200 }
200 201
201 202 # error mapping
202 203 e_dict = {'username':messages['invalid_login'],
203 204 'password':messages['invalid_password']}
204 205 e_dict_disable = {'username':messages['disabled_account']}
205 206
206 207 def validate_python(self, value, state):
207 208 password = value['password']
208 209 username = value['username']
209 210 user = User.get_by_username(username)
210 211
211 212 if authenticate(username, password):
212 213 return value
213 214 else:
214 215 if user and user.active is False:
215 216 log.warning('user %s is disabled', username)
216 217 raise formencode.Invalid(self.message('disabled_account',
217 218 state=State_obj),
218 219 value, state,
219 220 error_dict=self.e_dict_disable)
220 221 else:
221 222 log.warning('user %s not authenticated', username)
222 223 raise formencode.Invalid(self.message('invalid_password',
223 224 state=State_obj), value, state,
224 225 error_dict=self.e_dict)
225 226
226 227 class ValidRepoUser(formencode.validators.FancyValidator):
227 228
228 229 def to_python(self, value, state):
229 230 try:
230 231 User.query().filter(User.active == True)\
231 232 .filter(User.username == value).one()
232 233 except Exception:
233 234 raise formencode.Invalid(_('This username is not valid'),
234 235 value, state)
235 236 return value
236 237
237 238 def ValidRepoName(edit, old_data):
238 239 class _ValidRepoName(formencode.validators.FancyValidator):
239 240 def to_python(self, value, state):
240 241
241 242 repo_name = value.get('repo_name')
242 243
243 244 slug = repo_name_slug(repo_name)
244 245 if slug in [ADMIN_PREFIX, '']:
245 246 e_dict = {'repo_name': _('This repository name is disallowed')}
246 247 raise formencode.Invalid('', value, state, error_dict=e_dict)
247 248
248 249
249 250 if value.get('repo_group'):
250 251 gr = Group.get(value.get('repo_group'))
251 252 group_path = gr.full_path
252 253 # value needs to be aware of group name in order to check
253 254 # db key This is an actual just the name to store in the
254 255 # database
255 256 repo_name_full = group_path + Group.url_sep() + repo_name
256 257
257 258 else:
258 259 group_path = ''
259 260 repo_name_full = repo_name
260 261
261 262
262 263 value['repo_name_full'] = repo_name_full
263 264 rename = old_data.get('repo_name') != repo_name_full
264 265 create = not edit
265 266 if rename or create:
266 267
267 268 if group_path != '':
268 269 if RepoModel().get_by_repo_name(repo_name_full,):
269 270 e_dict = {'repo_name':_('This repository already '
270 271 'exists in a group "%s"') %
271 272 gr.group_name}
272 273 raise formencode.Invalid('', value, state,
273 274 error_dict=e_dict)
274 275 elif Group.get_by_group_name(repo_name_full):
275 276 e_dict = {'repo_name':_('There is a group with this'
276 277 ' name already "%s"') %
277 278 repo_name_full}
278 279 raise formencode.Invalid('', value, state,
279 280 error_dict=e_dict)
280 281
281 282 elif RepoModel().get_by_repo_name(repo_name_full):
282 283 e_dict = {'repo_name':_('This repository '
283 284 'already exists')}
284 285 raise formencode.Invalid('', value, state,
285 286 error_dict=e_dict)
286 287
287 288 return value
288 289
289 290 return _ValidRepoName
290 291
291 292 def ValidForkName():
292 293 class _ValidForkName(formencode.validators.FancyValidator):
293 294 def to_python(self, value, state):
294 295
295 296 repo_name = value.get('fork_name')
296 297
297 298 slug = repo_name_slug(repo_name)
298 299 if slug in [ADMIN_PREFIX, '']:
299 300 e_dict = {'repo_name': _('This repository name is disallowed')}
300 301 raise formencode.Invalid('', value, state, error_dict=e_dict)
301 302
302 303 if RepoModel().get_by_repo_name(repo_name):
303 304 e_dict = {'fork_name':_('This repository '
304 305 'already exists')}
305 306 raise formencode.Invalid('', value, state,
306 307 error_dict=e_dict)
307 308 return value
308 309 return _ValidForkName
309 310
310 311
311 312 def SlugifyName():
312 313 class _SlugifyName(formencode.validators.FancyValidator):
313 314
314 315 def to_python(self, value, state):
315 316 return repo_name_slug(value)
316 317
317 318 return _SlugifyName
318 319
319 320 def ValidCloneUri():
320 321 from mercurial.httprepo import httprepository, httpsrepository
321 322 from rhodecode.lib.utils import make_ui
322 323
323 324 class _ValidCloneUri(formencode.validators.FancyValidator):
324 325
325 326 def to_python(self, value, state):
326 327 if not value:
327 328 pass
328 329 elif value.startswith('https'):
329 330 try:
330 331 httpsrepository(make_ui('db'), value).capabilities
331 332 except Exception, e:
332 333 log.error(traceback.format_exc())
333 334 raise formencode.Invalid(_('invalid clone url'), value,
334 335 state)
335 336 elif value.startswith('http'):
336 337 try:
337 338 httprepository(make_ui('db'), value).capabilities
338 339 except Exception, e:
339 340 log.error(traceback.format_exc())
340 341 raise formencode.Invalid(_('invalid clone url'), value,
341 342 state)
342 343 else:
343 344 raise formencode.Invalid(_('Invalid clone url, provide a '
344 345 'valid clone http\s url'), value,
345 346 state)
346 347 return value
347 348
348 349 return _ValidCloneUri
349 350
350 351 def ValidForkType(old_data):
351 352 class _ValidForkType(formencode.validators.FancyValidator):
352 353
353 354 def to_python(self, value, state):
354 355 if old_data['repo_type'] != value:
355 356 raise formencode.Invalid(_('Fork have to be the same '
356 357 'type as original'), value, state)
357 358
358 359 return value
359 360 return _ValidForkType
360 361
361 362 class ValidPerms(formencode.validators.FancyValidator):
362 363 messages = {'perm_new_member_name':_('This username or users group name'
363 364 ' is not valid')}
364 365
365 366 def to_python(self, value, state):
366 367 perms_update = []
367 368 perms_new = []
368 369 #build a list of permission to update and new permission to create
369 370 for k, v in value.items():
370 371 #means new added member to permissions
371 372 if k.startswith('perm_new_member'):
372 373 new_perm = value.get('perm_new_member', False)
373 374 new_member = value.get('perm_new_member_name', False)
374 375 new_type = value.get('perm_new_member_type')
375 376
376 377 if new_member and new_perm:
377 378 if (new_member, new_perm, new_type) not in perms_new:
378 379 perms_new.append((new_member, new_perm, new_type))
379 380 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
380 381 member = k[7:]
381 382 t = {'u':'user',
382 383 'g':'users_group'}[k[0]]
383 384 if member == 'default':
384 385 if value['private']:
385 386 #set none for default when updating to private repo
386 387 v = 'repository.none'
387 388 perms_update.append((member, v, t))
388 389
389 390 value['perms_updates'] = perms_update
390 391 value['perms_new'] = perms_new
391 392
392 393 #update permissions
393 394 for k, v, t in perms_new:
394 395 try:
395 396 if t is 'user':
396 397 self.user_db = User.query()\
397 398 .filter(User.active == True)\
398 399 .filter(User.username == k).one()
399 400 if t is 'users_group':
400 401 self.user_db = UsersGroup.query()\
401 402 .filter(UsersGroup.users_group_active == True)\
402 403 .filter(UsersGroup.users_group_name == k).one()
403 404
404 405 except Exception:
405 406 msg = self.message('perm_new_member_name',
406 407 state=State_obj)
407 408 raise formencode.Invalid(msg, value, state,
408 409 error_dict={'perm_new_member_name':msg})
409 410 return value
410 411
411 412 class ValidSettings(formencode.validators.FancyValidator):
412 413
413 414 def to_python(self, value, state):
414 415 #settings form can't edit user
415 416 if value.has_key('user'):
416 417 del['value']['user']
417 418
418 419 return value
419 420
420 421 class ValidPath(formencode.validators.FancyValidator):
421 422 def to_python(self, value, state):
422 423
423 424 if not os.path.isdir(value):
424 425 msg = _('This is not a valid path')
425 426 raise formencode.Invalid(msg, value, state,
426 427 error_dict={'paths_root_path':msg})
427 428 return value
428 429
429 430 def UniqSystemEmail(old_data):
430 431 class _UniqSystemEmail(formencode.validators.FancyValidator):
431 432 def to_python(self, value, state):
432 433 value = value.lower()
433 434 if old_data.get('email') != value:
434 435 user = User.query().filter(User.email == value).scalar()
435 436 if user:
436 437 raise formencode.Invalid(
437 438 _("This e-mail address is already taken"),
438 439 value, state)
439 440 return value
440 441
441 442 return _UniqSystemEmail
442 443
443 444 class ValidSystemEmail(formencode.validators.FancyValidator):
444 445 def to_python(self, value, state):
445 446 value = value.lower()
446 447 user = User.query().filter(User.email == value).scalar()
447 448 if user is None:
448 449 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
449 450 value, state)
450 451
451 452 return value
452 453
453 454 class LdapLibValidator(formencode.validators.FancyValidator):
454 455
455 456 def to_python(self, value, state):
456 457
457 458 try:
458 459 import ldap
459 460 except ImportError:
460 461 raise LdapImportError
461 462 return value
462 463
463 464 class AttrLoginValidator(formencode.validators.FancyValidator):
464 465
465 466 def to_python(self, value, state):
466 467
467 468 if not value or not isinstance(value, (str, unicode)):
468 469 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
469 470 "must be specified - this is the name "
470 471 "of the attribute that is equivalent "
471 472 "to 'username'"),
472 473 value, state)
473 474
474 475 return value
475 476
476 477 #===============================================================================
477 478 # FORMS
478 479 #===============================================================================
479 480 class LoginForm(formencode.Schema):
480 481 allow_extra_fields = True
481 482 filter_extra_fields = True
482 483 username = UnicodeString(
483 484 strip=True,
484 485 min=1,
485 486 not_empty=True,
486 487 messages={
487 488 'empty':_('Please enter a login'),
488 489 'tooShort':_('Enter a value %(min)i characters long or more')}
489 490 )
490 491
491 492 password = UnicodeString(
492 493 strip=True,
493 494 min=3,
494 495 not_empty=True,
495 496 messages={
496 497 'empty':_('Please enter a password'),
497 498 'tooShort':_('Enter %(min)i characters or more')}
498 499 )
499 500
500
501 #chained validators have access to all data
502 501 chained_validators = [ValidAuth]
503 502
504 503 def UserForm(edit=False, old_data={}):
505 504 class _UserForm(formencode.Schema):
506 505 allow_extra_fields = True
507 506 filter_extra_fields = True
508 507 username = All(UnicodeString(strip=True, min=1, not_empty=True),
509 508 ValidUsername(edit, old_data))
510 509 if edit:
511 510 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
511 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
512 512 admin = StringBoolean(if_missing=False)
513 513 else:
514 514 password = All(UnicodeString(strip=True, min=6, not_empty=True))
515 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
516
515 517 active = StringBoolean(if_missing=False)
516 518 name = UnicodeString(strip=True, min=1, not_empty=True)
517 519 lastname = UnicodeString(strip=True, min=1, not_empty=True)
518 520 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
519 521
520 chained_validators = [ValidPassword]
522 chained_validators = [ValidPasswordsMatch, ValidPassword]
521 523
522 524 return _UserForm
523 525
524 526
525 527 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
526 528 class _UsersGroupForm(formencode.Schema):
527 529 allow_extra_fields = True
528 530 filter_extra_fields = True
529 531
530 532 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
531 533 ValidUsersGroup(edit, old_data))
532 534
533 535 users_group_active = StringBoolean(if_missing=False)
534 536
535 537 if edit:
536 538 users_group_members = OneOf(available_members, hideList=False,
537 539 testValueList=True,
538 540 if_missing=None, not_empty=False)
539 541
540 542 return _UsersGroupForm
541 543
542 544 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
543 545 class _ReposGroupForm(formencode.Schema):
544 546 allow_extra_fields = True
545 547 filter_extra_fields = True
546 548
547 549 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
548 550 SlugifyName())
549 551 group_description = UnicodeString(strip=True, min=1,
550 552 not_empty=True)
551 553 group_parent_id = OneOf(available_groups, hideList=False,
552 554 testValueList=True,
553 555 if_missing=None, not_empty=False)
554 556
555 557 chained_validators = [ValidReposGroup(edit, old_data)]
556 558
557 559 return _ReposGroupForm
558 560
559 561 def RegisterForm(edit=False, old_data={}):
560 562 class _RegisterForm(formencode.Schema):
561 563 allow_extra_fields = True
562 564 filter_extra_fields = True
563 565 username = All(ValidUsername(edit, old_data),
564 566 UnicodeString(strip=True, min=1, not_empty=True))
565 567 password = All(UnicodeString(strip=True, min=6, not_empty=True))
566 568 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
567 569 active = StringBoolean(if_missing=False)
568 570 name = UnicodeString(strip=True, min=1, not_empty=True)
569 571 lastname = UnicodeString(strip=True, min=1, not_empty=True)
570 572 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
571 573
572 574 chained_validators = [ValidPasswordsMatch, ValidPassword]
573 575
574 576 return _RegisterForm
575 577
576 578 def PasswordResetForm():
577 579 class _PasswordResetForm(formencode.Schema):
578 580 allow_extra_fields = True
579 581 filter_extra_fields = True
580 582 email = All(ValidSystemEmail(), Email(not_empty=True))
581 583 return _PasswordResetForm
582 584
583 585 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
584 586 repo_groups=[]):
585 587 class _RepoForm(formencode.Schema):
586 588 allow_extra_fields = True
587 589 filter_extra_fields = False
588 590 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
589 591 SlugifyName())
590 592 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
591 593 ValidCloneUri()())
592 594 repo_group = OneOf(repo_groups, hideList=True)
593 595 repo_type = OneOf(supported_backends)
594 596 description = UnicodeString(strip=True, min=1, not_empty=True)
595 597 private = StringBoolean(if_missing=False)
596 598 enable_statistics = StringBoolean(if_missing=False)
597 599 enable_downloads = StringBoolean(if_missing=False)
598 600
599 601 if edit:
600 602 #this is repo owner
601 603 user = All(UnicodeString(not_empty=True), ValidRepoUser)
602 604
603 605 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
604 606 return _RepoForm
605 607
606 608 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
607 609 class _RepoForkForm(formencode.Schema):
608 610 allow_extra_fields = True
609 611 filter_extra_fields = False
610 612 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
611 613 SlugifyName())
612 614 description = UnicodeString(strip=True, min=1, not_empty=True)
613 615 private = StringBoolean(if_missing=False)
614 616 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
615 617
616 618 chained_validators = [ValidForkName()]
617 619
618 620 return _RepoForkForm
619 621
620 622 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
621 623 repo_groups=[]):
622 624 class _RepoForm(formencode.Schema):
623 625 allow_extra_fields = True
624 626 filter_extra_fields = False
625 627 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
626 628 SlugifyName())
627 629 description = UnicodeString(strip=True, min=1, not_empty=True)
628 630 repo_group = OneOf(repo_groups, hideList=True)
629 631 private = StringBoolean(if_missing=False)
630 632
631 633 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
632 634 ValidSettings]
633 635 return _RepoForm
634 636
635 637
636 638 def ApplicationSettingsForm():
637 639 class _ApplicationSettingsForm(formencode.Schema):
638 640 allow_extra_fields = True
639 641 filter_extra_fields = False
640 642 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
641 643 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
642 644 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
643 645
644 646 return _ApplicationSettingsForm
645 647
646 648 def ApplicationUiSettingsForm():
647 649 class _ApplicationUiSettingsForm(formencode.Schema):
648 650 allow_extra_fields = True
649 651 filter_extra_fields = False
650 652 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
651 653 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
652 654 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
653 655 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
654 656 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
655 657 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
656 658
657 659 return _ApplicationUiSettingsForm
658 660
659 661 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
660 662 class _DefaultPermissionsForm(formencode.Schema):
661 663 allow_extra_fields = True
662 664 filter_extra_fields = True
663 665 overwrite_default = StringBoolean(if_missing=False)
664 666 anonymous = OneOf(['True', 'False'], if_missing=False)
665 667 default_perm = OneOf(perms_choices)
666 668 default_register = OneOf(register_choices)
667 669 default_create = OneOf(create_choices)
668 670
669 671 return _DefaultPermissionsForm
670 672
671 673
672 674 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
673 675 class _LdapSettingsForm(formencode.Schema):
674 676 allow_extra_fields = True
675 677 filter_extra_fields = True
676 678 pre_validators = [LdapLibValidator]
677 679 ldap_active = StringBoolean(if_missing=False)
678 680 ldap_host = UnicodeString(strip=True,)
679 681 ldap_port = Number(strip=True,)
680 682 ldap_tls_kind = OneOf(tls_kind_choices)
681 683 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
682 684 ldap_dn_user = UnicodeString(strip=True,)
683 685 ldap_dn_pass = UnicodeString(strip=True,)
684 686 ldap_base_dn = UnicodeString(strip=True,)
685 687 ldap_filter = UnicodeString(strip=True,)
686 688 ldap_search_scope = OneOf(search_scope_choices)
687 689 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
688 690 ldap_attr_firstname = UnicodeString(strip=True,)
689 691 ldap_attr_lastname = UnicodeString(strip=True,)
690 692 ldap_attr_email = UnicodeString(strip=True,)
691 693
692 694 return _LdapSettingsForm
@@ -1,91 +1,100 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Add user')} - ${c.rhodecode_name}
6 6 </%def>
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 9 &raquo;
10 10 ${h.link_to(_('Users'),h.url('users'))}
11 11 &raquo;
12 12 ${_('add new user')}
13 13 </%def>
14 14
15 15 <%def name="page_nav()">
16 16 ${self.menu('admin')}
17 17 </%def>
18 18
19 19 <%def name="main()">
20 20 <div class="box">
21 21 <!-- box / title -->
22 22 <div class="title">
23 23 ${self.breadcrumbs()}
24 24 </div>
25 25 <!-- end box / title -->
26 26 ${h.form(url('users'))}
27 27 <div class="form">
28 28 <!-- fields -->
29 29 <div class="fields">
30 30 <div class="field">
31 31 <div class="label">
32 32 <label for="username">${_('Username')}:</label>
33 33 </div>
34 34 <div class="input">
35 35 ${h.text('username',class_='small')}
36 36 </div>
37 37 </div>
38 38
39 39 <div class="field">
40 40 <div class="label">
41 41 <label for="password">${_('Password')}:</label>
42 42 </div>
43 43 <div class="input">
44 44 ${h.password('password',class_='small')}
45 45 </div>
46 46 </div>
47 47
48 48 <div class="field">
49 49 <div class="label">
50 <label for="password_confirmation">${_('Password confirmation')}:</label>
51 </div>
52 <div class="input">
53 ${h.password('password_confirmation',class_="small",autocomplete="off")}
54 </div>
55 </div>
56
57 <div class="field">
58 <div class="label">
50 59 <label for="name">${_('First Name')}:</label>
51 60 </div>
52 61 <div class="input">
53 62 ${h.text('name',class_='small')}
54 63 </div>
55 64 </div>
56 65
57 66 <div class="field">
58 67 <div class="label">
59 68 <label for="lastname">${_('Last Name')}:</label>
60 69 </div>
61 70 <div class="input">
62 71 ${h.text('lastname',class_='small')}
63 72 </div>
64 73 </div>
65 74
66 75 <div class="field">
67 76 <div class="label">
68 77 <label for="email">${_('Email')}:</label>
69 78 </div>
70 79 <div class="input">
71 80 ${h.text('email',class_='small')}
72 81 </div>
73 82 </div>
74 83
75 84 <div class="field">
76 85 <div class="label label-checkbox">
77 86 <label for="active">${_('Active')}:</label>
78 87 </div>
79 88 <div class="checkboxes">
80 89 ${h.checkbox('active',value=True)}
81 90 </div>
82 91 </div>
83 92
84 93 <div class="buttons">
85 94 ${h.submit('save',_('save'),class_="ui-button")}
86 95 </div>
87 96 </div>
88 97 </div>
89 98 ${h.end_form()}
90 99 </div>
91 100 </%def>
@@ -1,149 +1,158 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 10 &raquo;
11 11 ${h.link_to(_('Users'),h.url('users'))}
12 12 &raquo;
13 13 ${_('edit')} "${c.user.username}"
14 14 </%def>
15 15
16 16 <%def name="page_nav()">
17 17 ${self.menu('admin')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21 <div class="box box-left">
22 22 <!-- box / title -->
23 23 <div class="title">
24 24 ${self.breadcrumbs()}
25 25 </div>
26 26 <!-- end box / title -->
27 27 ${h.form(url('update_user', id=c.user.user_id),method='put')}
28 28 <div class="form">
29 29 <div class="field">
30 30 <div class="gravatar_box">
31 31 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
32 32 <p>
33 33 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong><br/>
34 34 ${_('Using')} ${c.user.email}
35 35 </p>
36 36 </div>
37 37 </div>
38 38 <div class="field">
39 39 <div class="label">
40 40 <label>${_('API key')}</label> ${c.user.api_key}
41 41 </div>
42 42 </div>
43 43
44 44 <div class="fields">
45 45 <div class="field">
46 46 <div class="label">
47 47 <label for="username">${_('Username')}:</label>
48 48 </div>
49 49 <div class="input">
50 50 ${h.text('username',class_='medium')}
51 51 </div>
52 52 </div>
53 53
54 54 <div class="field">
55 55 <div class="label">
56 56 <label for="ldap_dn">${_('LDAP DN')}:</label>
57 57 </div>
58 58 <div class="input">
59 59 ${h.text('ldap_dn',class_='medium')}
60 60 </div>
61 61 </div>
62 62
63 63 <div class="field">
64 64 <div class="label">
65 65 <label for="new_password">${_('New password')}:</label>
66 66 </div>
67 67 <div class="input">
68 68 ${h.password('new_password',class_='medium',autocomplete="off")}
69 69 </div>
70 70 </div>
71 71
72 72 <div class="field">
73 73 <div class="label">
74 <label for="password_confirmation">${_('New password confirmation')}:</label>
75 </div>
76 <div class="input">
77 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
78 </div>
79 </div>
80
81 <div class="field">
82 <div class="label">
74 83 <label for="name">${_('First Name')}:</label>
75 84 </div>
76 85 <div class="input">
77 86 ${h.text('name',class_='medium')}
78 87 </div>
79 88 </div>
80 89
81 90 <div class="field">
82 91 <div class="label">
83 92 <label for="lastname">${_('Last Name')}:</label>
84 93 </div>
85 94 <div class="input">
86 95 ${h.text('lastname',class_='medium')}
87 96 </div>
88 97 </div>
89 98
90 99 <div class="field">
91 100 <div class="label">
92 101 <label for="email">${_('Email')}:</label>
93 102 </div>
94 103 <div class="input">
95 104 ${h.text('email',class_='medium')}
96 105 </div>
97 106 </div>
98 107
99 108 <div class="field">
100 109 <div class="label label-checkbox">
101 110 <label for="active">${_('Active')}:</label>
102 111 </div>
103 112 <div class="checkboxes">
104 113 ${h.checkbox('active',value=True)}
105 114 </div>
106 115 </div>
107 116
108 117 <div class="field">
109 118 <div class="label label-checkbox">
110 119 <label for="admin">${_('Admin')}:</label>
111 120 </div>
112 121 <div class="checkboxes">
113 122 ${h.checkbox('admin',value=True)}
114 123 </div>
115 124 </div>
116 125 <div class="buttons">
117 126 ${h.submit('save',_('Save'),class_="ui-button")}
118 127 ${h.reset('reset',_('Reset'),class_="ui-button")}
119 128 </div>
120 129 </div>
121 130 </div>
122 131 ${h.end_form()}
123 132 </div>
124 133 <div class="box box-right">
125 134 <!-- box / title -->
126 135 <div class="title">
127 136 <h5>${_('Permissions')}</h5>
128 137 </div>
129 138 ${h.form(url('user_perm', id=c.user.user_id),method='put')}
130 139 <div class="form">
131 140 <!-- fields -->
132 141 <div class="fields">
133 142 <div class="field">
134 143 <div class="label label-checkbox">
135 144 <label for="create_repo_perm">${_('Create repositories')}:</label>
136 145 </div>
137 146 <div class="checkboxes">
138 147 ${h.checkbox('create_repo_perm',value=True)}
139 148 </div>
140 149 </div>
141 150 <div class="buttons">
142 151 ${h.submit('save',_('Save'),class_="ui-button")}
143 152 ${h.reset('reset',_('Reset'),class_="ui-button")}
144 153 </div>
145 154 </div>
146 155 </div>
147 156 ${h.end_form()}
148 157 </div>
149 158 </%def>
@@ -1,211 +1,222 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${_('My Account')}
10 10 </%def>
11 11
12 12 <%def name="page_nav()">
13 13 ${self.menu('admin')}
14 14 </%def>
15 15
16 16 <%def name="main()">
17 17
18 18 <div class="box box-left">
19 19 <!-- box / title -->
20 20 <div class="title">
21 21 ${self.breadcrumbs()}
22 22 </div>
23 23 <!-- end box / title -->
24 24 <div>
25 25 ${h.form(url('admin_settings_my_account_update'),method='put')}
26 26 <div class="form">
27 27
28 28 <div class="field">
29 29 <div class="gravatar_box">
30 30 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
31 31 <p>
32 32 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong><br/>
33 33 ${_('Using')} ${c.user.email}
34 34 </p>
35 35 </div>
36 36 </div>
37 37 <div class="field">
38 38 <div class="label">
39 39 <label>${_('API key')}</label> ${c.user.api_key}
40 40 </div>
41 41 </div>
42 42 <div class="fields">
43 43 <div class="field">
44 44 <div class="label">
45 45 <label for="username">${_('Username')}:</label>
46 46 </div>
47 47 <div class="input">
48 48 ${h.text('username',class_="medium")}
49 49 </div>
50 50 </div>
51 51
52 52 <div class="field">
53 53 <div class="label">
54 54 <label for="new_password">${_('New password')}:</label>
55 55 </div>
56 56 <div class="input">
57 57 ${h.password('new_password',class_="medium",autocomplete="off")}
58 58 </div>
59 59 </div>
60 60
61 61 <div class="field">
62 62 <div class="label">
63 <label for="password_confirmation">${_('New password confirmation')}:</label>
64 </div>
65 <div class="input">
66 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
67 </div>
68 </div>
69
70 <div class="field">
71 <div class="label">
63 72 <label for="name">${_('First Name')}:</label>
64 73 </div>
65 74 <div class="input">
66 75 ${h.text('name',class_="medium")}
67 76 </div>
68 77 </div>
69 78
70 79 <div class="field">
71 80 <div class="label">
72 81 <label for="lastname">${_('Last Name')}:</label>
73 82 </div>
74 83 <div class="input">
75 84 ${h.text('lastname',class_="medium")}
76 85 </div>
77 86 </div>
78 87
79 88 <div class="field">
80 89 <div class="label">
81 90 <label for="email">${_('Email')}:</label>
82 91 </div>
83 92 <div class="input">
84 93 ${h.text('email',class_="medium")}
85 94 </div>
86 95 </div>
87 96
88 97 <div class="buttons">
89 98 ${h.submit('save',_('Save'),class_="ui-button")}
90 99 ${h.reset('reset',_('Reset'),class_="ui-button")}
91 100 </div>
92 101 </div>
93 102 </div>
94 103 ${h.end_form()}
95 104 </div>
96 105 </div>
97 106
98 107 <div class="box box-right">
99 108 <!-- box / title -->
100 109 <div class="title">
101 110 <h5>${_('My repositories')}
102 111 <input class="top-right-rounded-corner top-left-rounded-corner bottom-left-rounded-corner bottom-right-rounded-corner" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
103 112 </h5>
104 113 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
105 114 <ul class="links">
106 115 <li>
107 116 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
108 117 </li>
109 118 </ul>
110 119 %endif
111 120 </div>
112 121 <!-- end box / title -->
113 122 <div class="table">
114 123 <table>
115 124 <thead>
116 125 <tr>
117 126 <th class="left">${_('Name')}</th>
118 127 <th class="left">${_('revision')}</th>
119 128 <th colspan="2" class="left">${_('action')}</th>
120 129 </thead>
121 130 <tbody>
122 131 %if c.user_repos:
123 132 %for repo in c.user_repos:
124 133 <tr>
125 134 <td>
126 135 %if repo['dbrepo']['repo_type'] =='hg':
127 136 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
128 137 %elif repo['dbrepo']['repo_type'] =='git':
129 138 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
130 139 %else:
131 140
132 141 %endif
133 142 %if repo['dbrepo']['private']:
134 143 <img class="icon" alt="${_('private')}" src="${h.url("/images/icons/lock.png")}"/>
135 144 %else:
136 145 <img class="icon" alt="${_('public')}" src="${h.url("/images/icons/lock_open.png")}"/>
137 146 %endif
138 147
139 148 ${h.link_to(repo['name'], h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
140 149 %if repo['dbrepo_fork']:
141 150 <a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
142 151 <img class="icon" alt="${_('public')}"
143 152 title="${_('Fork of')} ${repo['dbrepo_fork']['repo_name']}"
144 153 src="${h.url('/images/icons/arrow_divide.png')}"/></a>
145 154 %endif
146 155 </td>
147 156 <td><span class="tooltip" title="${repo['last_change']}">${("r%s:%s") % (repo['rev'],h.short_id(repo['tip']))}</span></td>
148 157 <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td>
149 158 <td>
150 159 ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
151 160 ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
152 161 ${h.end_form()}
153 162 </td>
154 163 </tr>
155 164 %endfor
156 165 %else:
166 <div style="padding:5px 0px 10px 0px;">
157 167 ${_('No repositories yet')}
158 168 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
159 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'))}
169 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-button-small")}
160 170 %endif
171 </div>
161 172 %endif
162 173 </tbody>
163 174 </table>
164 175 </div>
165 176
166 177 </div>
167 178 <script type="text/javascript">
168 179 var D = YAHOO.util.Dom;
169 180 var E = YAHOO.util.Event;
170 181 var S = YAHOO.util.Selector;
171 182
172 183 var q_filter = D.get('q_filter');
173 184 var F = YAHOO.namespace('q_filter');
174 185
175 186 E.on(q_filter,'click',function(){
176 187 q_filter.value = '';
177 188 });
178 189
179 190 F.filterTimeout = null;
180 191
181 192 F.updateFilter = function() {
182 193 // Reset timeout
183 194 F.filterTimeout = null;
184 195
185 196 var obsolete = [];
186 197 var nodes = S.query('div.table tr td a.repo_name');
187 198 var req = q_filter.value.toLowerCase();
188 199 for (n in nodes){
189 200 D.setStyle(nodes[n].parentNode.parentNode,'display','')
190 201 }
191 202 if (req){
192 203 for (n in nodes){
193 204 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
194 205 obsolete.push(nodes[n]);
195 206 }
196 207 }
197 208 if(obsolete){
198 209 for (n in obsolete){
199 210 D.setStyle(obsolete[n].parentNode.parentNode,'display','none');
200 211 }
201 212 }
202 213 }
203 214 }
204 215
205 216 E.on(q_filter,'keyup',function(e){
206 217 clearTimeout(F.filterTimeout);
207 218 F.filterTimeout = setTimeout(F.updateFilter,600);
208 219 });
209 220
210 221 </script>
211 222 </%def>
@@ -1,208 +1,212 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 from rhodecode.lib.auth import get_crypt_password, check_password
4 4 from rhodecode.model.db import User, RhodeCodeSettings
5 5 from rhodecode.tests import *
6 6
7 7 class TestAdminSettingsController(TestController):
8 8
9 9 def test_index(self):
10 10 response = self.app.get(url('admin_settings'))
11 11 # Test response...
12 12
13 13 def test_index_as_xml(self):
14 14 response = self.app.get(url('formatted_admin_settings', format='xml'))
15 15
16 16 def test_create(self):
17 17 response = self.app.post(url('admin_settings'))
18 18
19 19 def test_new(self):
20 20 response = self.app.get(url('admin_new_setting'))
21 21
22 22 def test_new_as_xml(self):
23 23 response = self.app.get(url('formatted_admin_new_setting', format='xml'))
24 24
25 25 def test_update(self):
26 26 response = self.app.put(url('admin_setting', setting_id=1))
27 27
28 28 def test_update_browser_fakeout(self):
29 29 response = self.app.post(url('admin_setting', setting_id=1), params=dict(_method='put'))
30 30
31 31 def test_delete(self):
32 32 response = self.app.delete(url('admin_setting', setting_id=1))
33 33
34 34 def test_delete_browser_fakeout(self):
35 35 response = self.app.post(url('admin_setting', setting_id=1), params=dict(_method='delete'))
36 36
37 37 def test_show(self):
38 38 response = self.app.get(url('admin_setting', setting_id=1))
39 39
40 40 def test_show_as_xml(self):
41 41 response = self.app.get(url('formatted_admin_setting', setting_id=1, format='xml'))
42 42
43 43 def test_edit(self):
44 44 response = self.app.get(url('admin_edit_setting', setting_id=1))
45 45
46 46 def test_edit_as_xml(self):
47 47 response = self.app.get(url('formatted_admin_edit_setting',
48 48 setting_id=1, format='xml'))
49 49
50 50
51 51 def test_ga_code_active(self):
52 52 self.log_user()
53 53 old_title = 'RhodeCode'
54 54 old_realm = 'RhodeCode authentication'
55 55 new_ga_code = 'ga-test-123456789'
56 56 response = self.app.post(url('admin_setting', setting_id='global'),
57 57 params=dict(
58 58 _method='put',
59 59 rhodecode_title=old_title,
60 60 rhodecode_realm=old_realm,
61 61 rhodecode_ga_code=new_ga_code
62 62 ))
63 63
64 64 self.checkSessionFlash(response, 'Updated application settings')
65 65
66 66 self.assertEqual(RhodeCodeSettings
67 67 .get_app_settings()['rhodecode_ga_code'], new_ga_code)
68 68
69 69 response = response.follow()
70 70 self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
71 71 in response.body)
72 72
73 73 def test_ga_code_inactive(self):
74 74 self.log_user()
75 75 old_title = 'RhodeCode'
76 76 old_realm = 'RhodeCode authentication'
77 77 new_ga_code = ''
78 78 response = self.app.post(url('admin_setting', setting_id='global'),
79 79 params=dict(
80 80 _method='put',
81 81 rhodecode_title=old_title,
82 82 rhodecode_realm=old_realm,
83 83 rhodecode_ga_code=new_ga_code
84 84 ))
85 85
86 86 self.assertTrue('Updated application settings' in
87 87 response.session['flash'][0][1])
88 88 self.assertEqual(RhodeCodeSettings
89 89 .get_app_settings()['rhodecode_ga_code'], new_ga_code)
90 90
91 91 response = response.follow()
92 92 self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
93 93 not in response.body)
94 94
95 95
96 96 def test_title_change(self):
97 97 self.log_user()
98 98 old_title = 'RhodeCode'
99 99 new_title = old_title + '_changed'
100 100 old_realm = 'RhodeCode authentication'
101 101
102 102 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
103 103 response = self.app.post(url('admin_setting', setting_id='global'),
104 104 params=dict(
105 105 _method='put',
106 106 rhodecode_title=new_title,
107 107 rhodecode_realm=old_realm,
108 108 rhodecode_ga_code=''
109 109 ))
110 110
111 111 self.checkSessionFlash(response, 'Updated application settings')
112 112 self.assertEqual(RhodeCodeSettings
113 113 .get_app_settings()['rhodecode_title'],
114 114 new_title.decode('utf-8'))
115 115
116 116 response = response.follow()
117 117 self.assertTrue("""<h1><a href="/">%s</a></h1>""" % new_title
118 118 in response.body)
119 119
120 120
121 121 def test_my_account(self):
122 122 self.log_user()
123 123 response = self.app.get(url('admin_settings_my_account'))
124 124
125 125 self.assertTrue('value="test_admin' in response.body)
126 126
127 127 def test_my_account_update(self):
128 128 self.log_user()
129 129
130 130 new_email = 'new@mail.pl'
131 131 new_name = 'NewName'
132 132 new_lastname = 'NewLastname'
133 133 new_password = 'test123'
134 134
135 135
136 136 response = self.app.post(url('admin_settings_my_account_update'),
137 137 params=dict(_method='put',
138 138 username='test_admin',
139 139 new_password=new_password,
140 password_confirmation = new_password,
140 141 password='',
141 142 name=new_name,
142 143 lastname=new_lastname,
143 144 email=new_email,))
144 145 response.follow()
145 146
146 147 assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change'
147 148 user = self.sa.query(User).filter(User.username == 'test_admin').one()
148 149 assert user.email == new_email , 'incorrect user email after update got %s vs %s' % (user.email, new_email)
149 150 assert user.name == new_name, 'updated field mismatch %s vs %s' % (user.name, new_name)
150 151 assert user.lastname == new_lastname, 'updated field mismatch %s vs %s' % (user.lastname, new_lastname)
151 152 assert check_password(new_password, user.password) is True, 'password field mismatch %s vs %s' % (user.password, new_password)
152 153
153 154 #bring back the admin settings
154 155 old_email = 'test_admin@mail.com'
155 156 old_name = 'RhodeCode'
156 157 old_lastname = 'Admin'
157 158 old_password = 'test12'
158 159
159 160 response = self.app.post(url('admin_settings_my_account_update'), params=dict(
160 161 _method='put',
161 162 username='test_admin',
162 163 new_password=old_password,
164 password_confirmation = old_password,
163 165 password='',
164 166 name=old_name,
165 167 lastname=old_lastname,
166 168 email=old_email,))
167 169
168 170 response.follow()
169 171 self.checkSessionFlash(response,
170 172 'Your account was updated successfully')
171 173
172 174 user = self.sa.query(User).filter(User.username == 'test_admin').one()
173 175 assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
174 176
175 177 assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
176 178 assert user.name == old_name, 'updated field mismatch %s vs %s' % (user.name, old_name)
177 179 assert user.lastname == old_lastname, 'updated field mismatch %s vs %s' % (user.lastname, old_lastname)
178 180 assert check_password(old_password, user.password) is True , 'password updated field mismatch %s vs %s' % (user.password, old_password)
179 181
180 182
181 183 def test_my_account_update_err_email_exists(self):
182 184 self.log_user()
183 185
184 186 new_email = 'test_regular@mail.com'#already exisitn email
185 187 response = self.app.post(url('admin_settings_my_account_update'), params=dict(
186 188 _method='put',
187 189 username='test_admin',
188 190 new_password='test12',
191 password_confirmation = 'test122',
189 192 name='NewName',
190 193 lastname='NewLastname',
191 194 email=new_email,))
192 195
193 196 assert 'This e-mail address is already taken' in response.body, 'Missing error message about existing email'
194 197
195 198
196 199 def test_my_account_update_err(self):
197 200 self.log_user('test_regular2', 'test12')
198 201
199 202 new_email = 'newmail.pl'
200 203 response = self.app.post(url('admin_settings_my_account_update'), params=dict(
201 204 _method='put',
202 205 username='test_admin',
203 206 new_password='test12',
207 password_confirmation = 'test122',
204 208 name='NewName',
205 209 lastname='NewLastname',
206 210 email=new_email,))
207 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'
@@ -1,119 +1,122 b''
1 1 from rhodecode.tests import *
2 2 from rhodecode.model.db import User
3 3 from rhodecode.lib.auth import check_password
4 4 from sqlalchemy.orm.exc import NoResultFound
5 5
6 6 class TestAdminUsersController(TestController):
7 7
8 8 def test_index(self):
9 9 response = self.app.get(url('users'))
10 10 # Test response...
11 11
12 12 def test_index_as_xml(self):
13 13 response = self.app.get(url('formatted_users', format='xml'))
14 14
15 15 def test_create(self):
16 16 self.log_user()
17 17 username = 'newtestuser'
18 18 password = 'test12'
19 password_confirmation = password
19 20 name = 'name'
20 21 lastname = 'lastname'
21 22 email = 'mail@mail.com'
22 23
23 24 response = self.app.post(url('users'), {'username':username,
24 25 'password':password,
26 'password_confirmation':password_confirmation,
25 27 'name':name,
26 28 'active':True,
27 29 'lastname':lastname,
28 30 'email':email})
29 31
30 32
31 33 assert '''created user %s''' % (username) in response.session['flash'][0], 'No flash message about new user'
32 34
33 35 new_user = self.sa.query(User).filter(User.username == username).one()
34 36
35 37
36 38 assert new_user.username == username, 'wrong info about username'
37 39 assert check_password(password, new_user.password) == True , 'wrong info about password'
38 40 assert new_user.name == name, 'wrong info about name'
39 41 assert new_user.lastname == lastname, 'wrong info about lastname'
40 42 assert new_user.email == email, 'wrong info about email'
41 43
42 44
43 45 response.follow()
44 46 response = response.follow()
45 47 assert """edit">newtestuser</a>""" in response.body
46 48
47 49 def test_create_err(self):
48 50 self.log_user()
49 51 username = 'new_user'
50 52 password = ''
51 53 name = 'name'
52 54 lastname = 'lastname'
53 55 email = 'errmail.com'
54 56
55 57 response = self.app.post(url('users'), {'username':username,
56 58 'password':password,
57 59 'name':name,
58 60 'active':False,
59 61 'lastname':lastname,
60 62 'email':email})
61 63
62 64 assert """<span class="error-message">Invalid username</span>""" in response.body
63 65 assert """<span class="error-message">Please enter a value</span>""" in response.body
64 66 assert """<span class="error-message">An email address must contain a single @</span>""" in response.body
65 67
66 68 def get_user():
67 69 self.sa.query(User).filter(User.username == username).one()
68 70
69 71 self.assertRaises(NoResultFound, get_user), 'found user in database'
70 72
71 73 def test_new(self):
72 74 response = self.app.get(url('new_user'))
73 75
74 76 def test_new_as_xml(self):
75 77 response = self.app.get(url('formatted_new_user', format='xml'))
76 78
77 79 def test_update(self):
78 80 response = self.app.put(url('user', id=1))
79 81
80 82 def test_update_browser_fakeout(self):
81 83 response = self.app.post(url('user', id=1), params=dict(_method='put'))
82 84
83 85 def test_delete(self):
84 86 self.log_user()
85 87 username = 'newtestuserdeleteme'
86 88 password = 'test12'
87 89 name = 'name'
88 90 lastname = 'lastname'
89 91 email = 'todeletemail@mail.com'
90 92
91 93 response = self.app.post(url('users'), {'username':username,
92 94 'password':password,
95 'password_confirmation':password,
93 96 'name':name,
94 97 'active':True,
95 98 'lastname':lastname,
96 99 'email':email})
97 100
98 101 response = response.follow()
99 102
100 103 new_user = self.sa.query(User).filter(User.username == username).one()
101 104 response = self.app.delete(url('user', id=new_user.user_id))
102 105
103 106 assert """successfully deleted user""" in response.session['flash'][0], 'No info about user deletion'
104 107
105 108
106 109 def test_delete_browser_fakeout(self):
107 110 response = self.app.post(url('user', id=1), params=dict(_method='delete'))
108 111
109 112 def test_show(self):
110 113 response = self.app.get(url('user', id=1))
111 114
112 115 def test_show_as_xml(self):
113 116 response = self.app.get(url('formatted_user', id=1, format='xml'))
114 117
115 118 def test_edit(self):
116 119 response = self.app.get(url('edit_user', id=1))
117 120
118 121 def test_edit_as_xml(self):
119 122 response = self.app.get(url('formatted_edit_user', id=1, format='xml'))
General Comments 0
You need to be logged in to leave comments. Login now