##// END OF EJS Templates
#56 hacking on forms, and model for users groups
marcink -
r1013:d2a840b2 beta
parent child Browse files
Show More
@@ -1,535 +1,546 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
26 26 import formencode
27 27 from formencode import All
28 28 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 29 Email, Bool, StringBoolean, Set
30 30
31 31 from pylons.i18n.translation import _
32 32
33 33 import rhodecode.lib.helpers as h
34 34 from rhodecode.lib.auth import authenticate, get_crypt_password
35 35 from rhodecode.lib.exceptions import LdapImportError
36 36 from rhodecode.model import meta
37 37 from rhodecode.model.user import UserModel
38 38 from rhodecode.model.repo import RepoModel
39 39 from rhodecode.model.users_group import UsersGroupModel
40 from rhodecode.model.db import User
40 from rhodecode.model.db import User, UsersGroup
41 41 from rhodecode import BACKENDS
42 42
43 43 from webhelpers.pylonslib.secure_form import authentication_token
44 44
45 45 log = logging.getLogger(__name__)
46 46
47 47 #this is needed to translate the messages using _() in validators
48 48 class State_obj(object):
49 49 _ = staticmethod(_)
50 50
51 51 #===============================================================================
52 52 # VALIDATORS
53 53 #===============================================================================
54 54 class ValidAuthToken(formencode.validators.FancyValidator):
55 55 messages = {'invalid_token':_('Token mismatch')}
56 56
57 57 def validate_python(self, value, state):
58 58
59 59 if value != authentication_token():
60 60 raise formencode.Invalid(self.message('invalid_token', state,
61 61 search_number=value), value, state)
62 62
63 63 def ValidUsername(edit, old_data):
64 64 class _ValidUsername(formencode.validators.FancyValidator):
65 65
66 66 def validate_python(self, value, state):
67 67 if value in ['default', 'new_user']:
68 68 raise formencode.Invalid(_('Invalid username'), value, state)
69 69 #check if user is unique
70 70 old_un = None
71 71 if edit:
72 72 old_un = UserModel().get(old_data.get('user_id')).username
73 73
74 74 if old_un != value or not edit:
75 75 if UserModel().get_by_username(value, cache=False,
76 76 case_insensitive=True):
77 77 raise formencode.Invalid(_('This username already exists') ,
78 78 value, state)
79 79
80 80
81 81 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
82 82 raise formencode.Invalid(_('Username may only contain '
83 83 'alphanumeric characters underscores, '
84 84 'periods or dashes and must begin with '
85 85 'alphanumeric character'),
86 86 value, state)
87 87
88 88
89 89
90 90 return _ValidUsername
91 91
92 92
93 93
94 94 def ValidUsersGroup(edit, old_data):
95 95
96 96 class _ValidUsersGroup(formencode.validators.FancyValidator):
97 97
98 98 def validate_python(self, value, state):
99 99 if value in ['default']:
100 100 raise formencode.Invalid(_('Invalid group name'), value, state)
101 101 #check if group is unique
102 102 old_ugname = None
103 103 if edit:
104 104 old_ugname = UsersGroupModel()\
105 105 .get(old_data.get('users_group_id')).users_group_name
106 106
107 107 if old_ugname != value or not edit:
108 108 if UsersGroupModel().get_by_groupname(value, cache=False,
109 109 case_insensitive=True):
110 110 raise formencode.Invalid(_('This users group already exists') ,
111 111 value, state)
112 112
113 113
114 114 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
115 115 raise formencode.Invalid(_('Group name may only contain '
116 116 'alphanumeric characters underscores, '
117 117 'periods or dashes and must begin with '
118 118 'alphanumeric character'),
119 119 value, state)
120 120
121 121 return _ValidUsersGroup
122 122
123 123
124 124
125 125 class ValidPassword(formencode.validators.FancyValidator):
126 126
127 127 def to_python(self, value, state):
128 128
129 129 if value:
130 130
131 131 if value.get('password'):
132 132 try:
133 133 value['password'] = get_crypt_password(value['password'])
134 134 except UnicodeEncodeError:
135 135 e_dict = {'password':_('Invalid characters in password')}
136 136 raise formencode.Invalid('', value, state, error_dict=e_dict)
137 137
138 138 if value.get('password_confirmation'):
139 139 try:
140 140 value['password_confirmation'] = \
141 141 get_crypt_password(value['password_confirmation'])
142 142 except UnicodeEncodeError:
143 143 e_dict = {'password_confirmation':_('Invalid characters in password')}
144 144 raise formencode.Invalid('', value, state, error_dict=e_dict)
145 145
146 146 if value.get('new_password'):
147 147 try:
148 148 value['new_password'] = \
149 149 get_crypt_password(value['new_password'])
150 150 except UnicodeEncodeError:
151 151 e_dict = {'new_password':_('Invalid characters in password')}
152 152 raise formencode.Invalid('', value, state, error_dict=e_dict)
153 153
154 154 return value
155 155
156 156 class ValidPasswordsMatch(formencode.validators.FancyValidator):
157 157
158 158 def validate_python(self, value, state):
159 159
160 160 if value['password'] != value['password_confirmation']:
161 161 e_dict = {'password_confirmation':
162 162 _('Password do not match')}
163 163 raise formencode.Invalid('', value, state, error_dict=e_dict)
164 164
165 165 class ValidAuth(formencode.validators.FancyValidator):
166 166 messages = {
167 167 'invalid_password':_('invalid password'),
168 168 'invalid_login':_('invalid user name'),
169 169 'disabled_account':_('Your account is disabled')
170 170
171 171 }
172 172 #error mapping
173 173 e_dict = {'username':messages['invalid_login'],
174 174 'password':messages['invalid_password']}
175 175 e_dict_disable = {'username':messages['disabled_account']}
176 176
177 177 def validate_python(self, value, state):
178 178 password = value['password']
179 179 username = value['username']
180 180 user = UserModel().get_by_username(username)
181 181
182 182 if authenticate(username, password):
183 183 return value
184 184 else:
185 185 if user and user.active is False:
186 186 log.warning('user %s is disabled', username)
187 187 raise formencode.Invalid(self.message('disabled_account',
188 188 state=State_obj),
189 189 value, state,
190 190 error_dict=self.e_dict_disable)
191 191 else:
192 192 log.warning('user %s not authenticated', username)
193 193 raise formencode.Invalid(self.message('invalid_password',
194 194 state=State_obj), value, state,
195 195 error_dict=self.e_dict)
196 196
197 197 class ValidRepoUser(formencode.validators.FancyValidator):
198 198
199 199 def to_python(self, value, state):
200 200 sa = meta.Session()
201 201 try:
202 202 self.user_db = sa.query(User)\
203 203 .filter(User.active == True)\
204 204 .filter(User.username == value).one()
205 205 except Exception:
206 206 raise formencode.Invalid(_('This username is not valid'),
207 207 value, state)
208 208 finally:
209 209 meta.Session.remove()
210 210
211 211 return self.user_db.user_id
212 212
213 213 def ValidRepoName(edit, old_data):
214 214 class _ValidRepoName(formencode.validators.FancyValidator):
215 215
216 216 def to_python(self, value, state):
217 217 slug = h.repo_name_slug(value)
218 218 if slug in ['_admin']:
219 219 raise formencode.Invalid(_('This repository name is disallowed'),
220 220 value, state)
221 221 if old_data.get('repo_name') != value or not edit:
222 222 if RepoModel().get_by_repo_name(slug, cache=False):
223 223 raise formencode.Invalid(_('This repository already exists') ,
224 224 value, state)
225 225 return slug
226 226
227 227
228 228 return _ValidRepoName
229 229
230 230 def ValidForkType(old_data):
231 231 class _ValidForkType(formencode.validators.FancyValidator):
232 232
233 233 def to_python(self, value, state):
234 234 if old_data['repo_type'] != value:
235 235 raise formencode.Invalid(_('Fork have to be the same type as original'),
236 236 value, state)
237 237 return value
238 238 return _ValidForkType
239 239
240 240 class ValidPerms(formencode.validators.FancyValidator):
241 messages = {'perm_new_user_name':_('This username is not valid')}
241 messages = {'perm_new_member_name':_('This username or users group name'
242 ' is not valid')}
242 243
243 244 def to_python(self, value, state):
244 245 perms_update = []
245 246 perms_new = []
246 247 #build a list of permission to update and new permission to create
247 248 for k, v in value.items():
248 249 if k.startswith('perm_'):
249 if k.startswith('perm_new_user'):
250 new_perm = value.get('perm_new_user', False)
251 new_user = value.get('perm_new_user_name', False)
252 if new_user and new_perm:
253 if (new_user, new_perm) not in perms_new:
254 perms_new.append((new_user, new_perm))
250 if k.startswith('perm_new_member'):
251 #means new added member to permissions
252 new_perm = value.get('perm_new_member', False)
253 new_member = value.get('perm_new_member_name', False)
254 new_type = value.get('perm_new_member_type')
255
256 if new_member and new_perm:
257 if (new_member, new_perm) not in perms_new:
258 perms_new.append((new_member, new_perm, new_type))
255 259 else:
256 260 usr = k[5:]
261 t = 'user'
257 262 if usr == 'default':
258 263 if value['private']:
259 264 #set none for default when updating to private repo
260 265 v = 'repository.none'
261 perms_update.append((usr, v))
266 perms_update.append((usr, v, t))
262 267 value['perms_updates'] = perms_update
263 268 value['perms_new'] = perms_new
264 269 sa = meta.Session
265 for k, v in perms_new:
270 for k, v, t in perms_new:
266 271 try:
272 if t is 'user':
267 273 self.user_db = sa.query(User)\
268 274 .filter(User.active == True)\
269 275 .filter(User.username == k).one()
276 if t is 'users_group':
277 self.user_db = sa.query(UsersGroup)\
278 .filter(UsersGroup.users_group_active == True)\
279 .filter(UsersGroup.users_group_name == k).one()
280
270 281 except Exception:
271 msg = self.message('perm_new_user_name',
282 msg = self.message('perm_new_member_name',
272 283 state=State_obj)
273 284 raise formencode.Invalid(msg, value, state,
274 error_dict={'perm_new_user_name':msg})
285 error_dict={'perm_new_member_name':msg})
275 286 return value
276 287
277 288 class ValidSettings(formencode.validators.FancyValidator):
278 289
279 290 def to_python(self, value, state):
280 291 #settings form can't edit user
281 292 if value.has_key('user'):
282 293 del['value']['user']
283 294
284 295 return value
285 296
286 297 class ValidPath(formencode.validators.FancyValidator):
287 298 def to_python(self, value, state):
288 299
289 300 if not os.path.isdir(value):
290 301 msg = _('This is not a valid path')
291 302 raise formencode.Invalid(msg, value, state,
292 303 error_dict={'paths_root_path':msg})
293 304 return value
294 305
295 306 def UniqSystemEmail(old_data):
296 307 class _UniqSystemEmail(formencode.validators.FancyValidator):
297 308 def to_python(self, value, state):
298 309 value = value.lower()
299 310 if old_data.get('email') != value:
300 311 sa = meta.Session()
301 312 try:
302 313 user = sa.query(User).filter(User.email == value).scalar()
303 314 if user:
304 315 raise formencode.Invalid(_("This e-mail address is already taken") ,
305 316 value, state)
306 317 finally:
307 318 meta.Session.remove()
308 319
309 320 return value
310 321
311 322 return _UniqSystemEmail
312 323
313 324 class ValidSystemEmail(formencode.validators.FancyValidator):
314 325 def to_python(self, value, state):
315 326 value = value.lower()
316 327 sa = meta.Session
317 328 try:
318 329 user = sa.query(User).filter(User.email == value).scalar()
319 330 if user is None:
320 331 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
321 332 value, state)
322 333 finally:
323 334 meta.Session.remove()
324 335
325 336 return value
326 337
327 338 class LdapLibValidator(formencode.validators.FancyValidator):
328 339
329 340 def to_python(self, value, state):
330 341
331 342 try:
332 343 import ldap
333 344 except ImportError:
334 345 raise LdapImportError
335 346 return value
336 347
337 348 class AttrLoginValidator(formencode.validators.FancyValidator):
338 349
339 350 def to_python(self, value, state):
340 351
341 352 if not value or not isinstance(value, (str, unicode)):
342 353 raise formencode.Invalid(_("The LDAP Login attribute of the CN must be specified "
343 354 "- this is the name of the attribute that is equivalent to 'username'"),
344 355 value, state)
345 356
346 357 return value
347 358
348 359 #===============================================================================
349 360 # FORMS
350 361 #===============================================================================
351 362 class LoginForm(formencode.Schema):
352 363 allow_extra_fields = True
353 364 filter_extra_fields = True
354 365 username = UnicodeString(
355 366 strip=True,
356 367 min=1,
357 368 not_empty=True,
358 369 messages={
359 370 'empty':_('Please enter a login'),
360 371 'tooShort':_('Enter a value %(min)i characters long or more')}
361 372 )
362 373
363 374 password = UnicodeString(
364 375 strip=True,
365 376 min=6,
366 377 not_empty=True,
367 378 messages={
368 379 'empty':_('Please enter a password'),
369 380 'tooShort':_('Enter %(min)i characters or more')}
370 381 )
371 382
372 383
373 384 #chained validators have access to all data
374 385 chained_validators = [ValidAuth]
375 386
376 387 def UserForm(edit=False, old_data={}):
377 388 class _UserForm(formencode.Schema):
378 389 allow_extra_fields = True
379 390 filter_extra_fields = True
380 391 username = All(UnicodeString(strip=True, min=1, not_empty=True),
381 392 ValidUsername(edit, old_data))
382 393 if edit:
383 394 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
384 395 admin = StringBoolean(if_missing=False)
385 396 else:
386 397 password = All(UnicodeString(strip=True, min=6, not_empty=True))
387 398 active = StringBoolean(if_missing=False)
388 399 name = UnicodeString(strip=True, min=1, not_empty=True)
389 400 lastname = UnicodeString(strip=True, min=1, not_empty=True)
390 401 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
391 402
392 403 chained_validators = [ValidPassword]
393 404
394 405 return _UserForm
395 406
396 407
397 408 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
398 409 class _UsersGroupForm(formencode.Schema):
399 410 allow_extra_fields = True
400 411 filter_extra_fields = True
401 412
402 413 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
403 414 ValidUsersGroup(edit, old_data))
404 415
405 416 users_group_active = StringBoolean(if_missing=False)
406 417
407 418 if edit:
408 419 users_group_members = OneOf(available_members, hideList=False,
409 420 testValueList=True,
410 421 if_missing=None, not_empty=False)
411 422
412 423 return _UsersGroupForm
413 424
414 425 def RegisterForm(edit=False, old_data={}):
415 426 class _RegisterForm(formencode.Schema):
416 427 allow_extra_fields = True
417 428 filter_extra_fields = True
418 429 username = All(ValidUsername(edit, old_data),
419 430 UnicodeString(strip=True, min=1, not_empty=True))
420 431 password = All(UnicodeString(strip=True, min=6, not_empty=True))
421 432 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
422 433 active = StringBoolean(if_missing=False)
423 434 name = UnicodeString(strip=True, min=1, not_empty=True)
424 435 lastname = UnicodeString(strip=True, min=1, not_empty=True)
425 436 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
426 437
427 438 chained_validators = [ValidPasswordsMatch, ValidPassword]
428 439
429 440 return _RegisterForm
430 441
431 442 def PasswordResetForm():
432 443 class _PasswordResetForm(formencode.Schema):
433 444 allow_extra_fields = True
434 445 filter_extra_fields = True
435 446 email = All(ValidSystemEmail(), Email(not_empty=True))
436 447 return _PasswordResetForm
437 448
438 449 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
439 450 class _RepoForm(formencode.Schema):
440 451 allow_extra_fields = True
441 452 filter_extra_fields = False
442 453 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
443 454 ValidRepoName(edit, old_data))
444 455 description = UnicodeString(strip=True, min=1, not_empty=True)
445 456 private = StringBoolean(if_missing=False)
446 457 enable_statistics = StringBoolean(if_missing=False)
447 458 enable_downloads = StringBoolean(if_missing=False)
448 459 repo_type = OneOf(supported_backends)
449 460 if edit:
450 461 user = All(Int(not_empty=True), ValidRepoUser)
451 462
452 463 chained_validators = [ValidPerms]
453 464 return _RepoForm
454 465
455 466 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
456 467 class _RepoForkForm(formencode.Schema):
457 468 allow_extra_fields = True
458 469 filter_extra_fields = False
459 470 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
460 471 ValidRepoName(edit, old_data))
461 472 description = UnicodeString(strip=True, min=1, not_empty=True)
462 473 private = StringBoolean(if_missing=False)
463 474 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
464 475 return _RepoForkForm
465 476
466 477 def RepoSettingsForm(edit=False, old_data={}):
467 478 class _RepoForm(formencode.Schema):
468 479 allow_extra_fields = True
469 480 filter_extra_fields = False
470 481 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
471 482 ValidRepoName(edit, old_data))
472 483 description = UnicodeString(strip=True, min=1, not_empty=True)
473 484 private = StringBoolean(if_missing=False)
474 485
475 486 chained_validators = [ValidPerms, ValidSettings]
476 487 return _RepoForm
477 488
478 489
479 490 def ApplicationSettingsForm():
480 491 class _ApplicationSettingsForm(formencode.Schema):
481 492 allow_extra_fields = True
482 493 filter_extra_fields = False
483 494 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
484 495 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
485 496 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
486 497
487 498 return _ApplicationSettingsForm
488 499
489 500 def ApplicationUiSettingsForm():
490 501 class _ApplicationUiSettingsForm(formencode.Schema):
491 502 allow_extra_fields = True
492 503 filter_extra_fields = False
493 504 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
494 505 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
495 506 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
496 507 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
497 508 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
498 509 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
499 510
500 511 return _ApplicationUiSettingsForm
501 512
502 513 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
503 514 class _DefaultPermissionsForm(formencode.Schema):
504 515 allow_extra_fields = True
505 516 filter_extra_fields = True
506 517 overwrite_default = StringBoolean(if_missing=False)
507 518 anonymous = OneOf(['True', 'False'], if_missing=False)
508 519 default_perm = OneOf(perms_choices)
509 520 default_register = OneOf(register_choices)
510 521 default_create = OneOf(create_choices)
511 522
512 523 return _DefaultPermissionsForm
513 524
514 525
515 526 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices):
516 527 class _LdapSettingsForm(formencode.Schema):
517 528 allow_extra_fields = True
518 529 filter_extra_fields = True
519 530 pre_validators = [LdapLibValidator]
520 531 ldap_active = StringBoolean(if_missing=False)
521 532 ldap_host = UnicodeString(strip=True,)
522 533 ldap_port = Number(strip=True,)
523 534 ldap_ldaps = StringBoolean(if_missing=False)
524 535 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
525 536 ldap_dn_user = UnicodeString(strip=True,)
526 537 ldap_dn_pass = UnicodeString(strip=True,)
527 538 ldap_base_dn = UnicodeString(strip=True,)
528 539 ldap_filter = UnicodeString(strip=True,)
529 540 ldap_search_scope = OneOf(search_scope_choices)
530 541 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
531 542 ldap_attr_firstname = UnicodeString(strip=True,)
532 543 ldap_attr_lastname = UnicodeString(strip=True,)
533 544 ldap_attr_email = UnicodeString(strip=True,)
534 545
535 546 return _LdapSettingsForm
@@ -1,263 +1,291 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.repo
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repository model for rhodecode
7 7
8 8 :created_on: Jun 5, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27 import os
28 28 import shutil
29 29 import logging
30 30 import traceback
31 31 from datetime import datetime
32 32
33 from pylons import app_globals as g
34
35 33 from rhodecode.model import BaseModel
36 34 from rhodecode.model.caching_query import FromCache
37 35 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
38 Statistics
36 Statistics, UsersGroup
39 37 from rhodecode.model.user import UserModel
40 38
41 39 from vcs.backends import get_backend
42 40
43 41 log = logging.getLogger(__name__)
44 42
45 43 class RepoModel(BaseModel):
46 44
45 def __init__(self, sa=None):
46 try:
47 from pylons import app_globals
48 self._base_path = app_globals.base_path
49 except:
50 self._base_path = None
51
52 @property
53 def base_path():
54 if self._base_path is None:
55 raise Exception('Base Path is empty, try set this after'
56 'class initialization when not having '
57 'app_globals available')
58 return self._base_path
59
60 super(RepoModel, self).__init__()
61
62
47 63 def get(self, repo_id, cache=False):
48 64 repo = self.sa.query(Repository)\
49 65 .filter(Repository.repo_id == repo_id)
50 66
51 67 if cache:
52 68 repo = repo.options(FromCache("sql_cache_short",
53 69 "get_repo_%s" % repo_id))
54 70 return repo.scalar()
55 71
56 72
57 73 def get_by_repo_name(self, repo_name, cache=False):
58 74 repo = self.sa.query(Repository)\
59 75 .filter(Repository.repo_name == repo_name)
60 76
61 77 if cache:
62 78 repo = repo.options(FromCache("sql_cache_short",
63 79 "get_repo_%s" % repo_name))
64 80 return repo.scalar()
65 81
66 82 def get_users_js(self):
67 83
68 84 users = self.sa.query(User).filter(User.active == True).all()
69 85 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
70 users_array = '[%s];' % '\n'.join([u_tmpl % (u.user_id, u.name,
86 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
71 87 u.lastname, u.username)
72 88 for u in users])
73 89 return users_array
74 90
75 91
92 def get_users_groups_js(self):
93 users_groups = self.sa.query(UsersGroup)\
94 .filter(UsersGroup.users_group_active == True).all()
95
96 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
97
98 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
99 (gr.users_group_id, gr.users_group_name,
100 len(gr.members))
101 for gr in users_groups])
102 return users_groups_array
103
76 104 def update(self, repo_name, form_data):
77 105 try:
78 106 cur_repo = self.get_by_repo_name(repo_name, cache=False)
79 107 user_model = UserModel(self.sa)
80 108
81 109 #update permissions
82 for username, perm in form_data['perms_updates']:
110 for username, perm, member_type in form_data['perms_updates']:
83 111 r2p = self.sa.query(RepoToPerm)\
84 112 .filter(RepoToPerm.user == user_model.get_by_username(username))\
85 113 .filter(RepoToPerm.repository == cur_repo)\
86 114 .one()
87 115
88 116 r2p.permission = self.sa.query(Permission)\
89 117 .filter(Permission.permission_name == perm)\
90 118 .scalar()
91 119 self.sa.add(r2p)
92 120
93 121 #set new permissions
94 for username, perm in form_data['perms_new']:
122 for username, perm, member_type in form_data['perms_new']:
95 123 r2p = RepoToPerm()
96 124 r2p.repository = cur_repo
97 125 r2p.user = user_model.get_by_username(username, cache=False)
98 126
99 127 r2p.permission = self.sa.query(Permission)\
100 128 .filter(Permission.permission_name == perm)\
101 129 .scalar()
102 130 self.sa.add(r2p)
103 131
104 132 #update current repo
105 133 for k, v in form_data.items():
106 134 if k == 'user':
107 135 cur_repo.user = user_model.get(v)
108 136 else:
109 137 setattr(cur_repo, k, v)
110 138
111 139 self.sa.add(cur_repo)
112 140
113 141 if repo_name != form_data['repo_name']:
114 142 #rename our data
115 143 self.__rename_repo(repo_name, form_data['repo_name'])
116 144
117 145 self.sa.commit()
118 146 except:
119 147 log.error(traceback.format_exc())
120 148 self.sa.rollback()
121 149 raise
122 150
123 151 def create(self, form_data, cur_user, just_db=False, fork=False):
124 152 try:
125 153 if fork:
126 154 #force str since hg doesn't go with unicode
127 155 repo_name = str(form_data['fork_name'])
128 156 org_name = str(form_data['repo_name'])
129 157
130 158 else:
131 159 org_name = repo_name = str(form_data['repo_name'])
132 160 new_repo = Repository()
133 161 new_repo.enable_statistics = True
134 162 for k, v in form_data.items():
135 163 if k == 'repo_name':
136 164 v = repo_name
137 165 setattr(new_repo, k, v)
138 166
139 167 if fork:
140 168 parent_repo = self.sa.query(Repository)\
141 169 .filter(Repository.repo_name == org_name).scalar()
142 170 new_repo.fork = parent_repo
143 171
144 172 new_repo.user_id = cur_user.user_id
145 173 self.sa.add(new_repo)
146 174
147 175 #create default permission
148 176 repo_to_perm = RepoToPerm()
149 177 default = 'repository.read'
150 178 for p in UserModel(self.sa).get_by_username('default', cache=False).user_perms:
151 179 if p.permission.permission_name.startswith('repository.'):
152 180 default = p.permission.permission_name
153 181 break
154 182
155 183 default_perm = 'repository.none' if form_data['private'] else default
156 184
157 185 repo_to_perm.permission_id = self.sa.query(Permission)\
158 186 .filter(Permission.permission_name == default_perm)\
159 187 .one().permission_id
160 188
161 189 repo_to_perm.repository_id = new_repo.repo_id
162 190 repo_to_perm.user_id = UserModel(self.sa)\
163 191 .get_by_username('default', cache=False).user_id
164 192
165 193 self.sa.add(repo_to_perm)
166 194 self.sa.commit()
167 195
168 196
169 197 #now automatically start following this repository as owner
170 198 from rhodecode.model.scm import ScmModel
171 199 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
172 200 cur_user.user_id)
173 201
174 202 if not just_db:
175 203 self.__create_repo(repo_name, form_data['repo_type'])
176 204 except:
177 205 log.error(traceback.format_exc())
178 206 self.sa.rollback()
179 207 raise
180 208
181 209 def create_fork(self, form_data, cur_user):
182 210 from rhodecode.lib.celerylib import tasks, run_task
183 211 run_task(tasks.create_repo_fork, form_data, cur_user)
184 212
185 213 def delete(self, repo):
186 214 try:
187 215 self.sa.delete(repo)
188 216 self.__delete_repo(repo)
189 217 self.sa.commit()
190 218 except:
191 219 log.error(traceback.format_exc())
192 220 self.sa.rollback()
193 221 raise
194 222
195 223 def delete_perm_user(self, form_data, repo_name):
196 224 try:
197 225 self.sa.query(RepoToPerm)\
198 226 .filter(RepoToPerm.repository \
199 227 == self.get_by_repo_name(repo_name))\
200 228 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
201 229 self.sa.commit()
202 230 except:
203 231 log.error(traceback.format_exc())
204 232 self.sa.rollback()
205 233 raise
206 234
207 235 def delete_stats(self, repo_name):
208 236 try:
209 237 self.sa.query(Statistics)\
210 238 .filter(Statistics.repository == \
211 239 self.get_by_repo_name(repo_name)).delete()
212 240 self.sa.commit()
213 241 except:
214 242 log.error(traceback.format_exc())
215 243 self.sa.rollback()
216 244 raise
217 245
218 246
219 247 def __create_repo(self, repo_name, alias):
220 248 """
221 249 makes repository on filesystem
222 250 :param repo_name:
223 251 :param alias:
224 252 """
225 253 from rhodecode.lib.utils import check_repo
226 repo_path = os.path.join(g.base_path, repo_name)
227 if check_repo(repo_name, g.base_path):
254 repo_path = os.path.join(self.base_path, repo_name)
255 if check_repo(repo_name, self.base_path):
228 256 log.info('creating repo %s in %s', repo_name, repo_path)
229 257 backend = get_backend(alias)
230 258 backend(repo_path, create=True)
231 259
232 260 def __rename_repo(self, old, new):
233 261 """
234 262 renames repository on filesystem
235 263 :param old: old name
236 264 :param new: new name
237 265 """
238 266 log.info('renaming repo from %s to %s', old, new)
239 267
240 old_path = os.path.join(g.base_path, old)
241 new_path = os.path.join(g.base_path, new)
268 old_path = os.path.join(self.base_path, old)
269 new_path = os.path.join(self.base_path, new)
242 270 if os.path.isdir(new_path):
243 271 raise Exception('Was trying to rename to already existing dir %s',
244 272 new_path)
245 273 shutil.move(old_path, new_path)
246 274
247 275 def __delete_repo(self, repo):
248 276 """
249 277 removes repo from filesystem, the removal is acctually made by
250 278 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
251 279 repository is no longer valid for rhodecode, can be undeleted later on
252 280 by reverting the renames on this repository
253 281 :param repo: repo object
254 282 """
255 rm_path = os.path.join(g.base_path, repo.repo_name)
283 rm_path = os.path.join(self.base_path, repo.repo_name)
256 284 log.info("Removing %s", rm_path)
257 285 #disable hg/git
258 286 alias = repo.repo_type
259 287 shutil.move(os.path.join(rm_path, '.%s' % alias),
260 288 os.path.join(rm_path, 'rm__.%s' % alias))
261 289 #disable repo
262 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
290 shutil.move(rm_path, os.path.join(self.base_path, 'rm__%s__%s' \
263 291 % (datetime.today(), repo.repo_name)))
General Comments 0
You need to be logged in to leave comments. Login now