##// END OF EJS Templates
User active flag should be default to True
marcink -
r2480:cb9e73b2 beta
parent child Browse files
Show More
@@ -1,1549 +1,1549 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.db
4 4 ~~~~~~~~~~~~~~~~~~
5 5
6 6 Database Models for RhodeCode
7 7
8 8 :created_on: Apr 08, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import datetime
29 29 import traceback
30 30 import hashlib
31 31 from collections import defaultdict
32 32
33 33 from sqlalchemy import *
34 34 from sqlalchemy.ext.hybrid import hybrid_property
35 35 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
36 36 from sqlalchemy.exc import DatabaseError
37 37 from beaker.cache import cache_region, region_invalidate
38 38
39 39 from pylons.i18n.translation import lazy_ugettext as _
40 40
41 41 from rhodecode.lib.vcs import get_backend
42 42 from rhodecode.lib.vcs.utils.helpers import get_scm
43 43 from rhodecode.lib.vcs.exceptions import VCSError
44 44 from rhodecode.lib.vcs.utils.lazy import LazyProperty
45 45
46 46 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
47 47 safe_unicode
48 48 from rhodecode.lib.compat import json
49 49 from rhodecode.lib.caching_query import FromCache
50 50
51 51 from rhodecode.model.meta import Base, Session
52 52
53 53
54 54 URL_SEP = '/'
55 55 log = logging.getLogger(__name__)
56 56
57 57 #==============================================================================
58 58 # BASE CLASSES
59 59 #==============================================================================
60 60
61 61 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
62 62
63 63
64 64 class ModelSerializer(json.JSONEncoder):
65 65 """
66 66 Simple Serializer for JSON,
67 67
68 68 usage::
69 69
70 70 to make object customized for serialization implement a __json__
71 71 method that will return a dict for serialization into json
72 72
73 73 example::
74 74
75 75 class Task(object):
76 76
77 77 def __init__(self, name, value):
78 78 self.name = name
79 79 self.value = value
80 80
81 81 def __json__(self):
82 82 return dict(name=self.name,
83 83 value=self.value)
84 84
85 85 """
86 86
87 87 def default(self, obj):
88 88
89 89 if hasattr(obj, '__json__'):
90 90 return obj.__json__()
91 91 else:
92 92 return json.JSONEncoder.default(self, obj)
93 93
94 94
95 95 class BaseModel(object):
96 96 """
97 97 Base Model for all classess
98 98 """
99 99
100 100 @classmethod
101 101 def _get_keys(cls):
102 102 """return column names for this model """
103 103 return class_mapper(cls).c.keys()
104 104
105 105 def get_dict(self):
106 106 """
107 107 return dict with keys and values corresponding
108 108 to this model data """
109 109
110 110 d = {}
111 111 for k in self._get_keys():
112 112 d[k] = getattr(self, k)
113 113
114 114 # also use __json__() if present to get additional fields
115 115 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
116 116 d[k] = val
117 117 return d
118 118
119 119 def get_appstruct(self):
120 120 """return list with keys and values tupples corresponding
121 121 to this model data """
122 122
123 123 l = []
124 124 for k in self._get_keys():
125 125 l.append((k, getattr(self, k),))
126 126 return l
127 127
128 128 def populate_obj(self, populate_dict):
129 129 """populate model with data from given populate_dict"""
130 130
131 131 for k in self._get_keys():
132 132 if k in populate_dict:
133 133 setattr(self, k, populate_dict[k])
134 134
135 135 @classmethod
136 136 def query(cls):
137 137 return Session.query(cls)
138 138
139 139 @classmethod
140 140 def get(cls, id_):
141 141 if id_:
142 142 return cls.query().get(id_)
143 143
144 144 @classmethod
145 145 def getAll(cls):
146 146 return cls.query().all()
147 147
148 148 @classmethod
149 149 def delete(cls, id_):
150 150 obj = cls.query().get(id_)
151 151 Session.delete(obj)
152 152
153 153 def __repr__(self):
154 154 if hasattr(self, '__unicode__'):
155 155 # python repr needs to return str
156 156 return safe_str(self.__unicode__())
157 157 return '<DB:%s>' % (self.__class__.__name__)
158 158
159 159
160 160 class RhodeCodeSetting(Base, BaseModel):
161 161 __tablename__ = 'rhodecode_settings'
162 162 __table_args__ = (
163 163 UniqueConstraint('app_settings_name'),
164 164 {'extend_existing': True, 'mysql_engine': 'InnoDB',
165 165 'mysql_charset': 'utf8'}
166 166 )
167 167 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
168 168 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
169 169 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
170 170
171 171 def __init__(self, k='', v=''):
172 172 self.app_settings_name = k
173 173 self.app_settings_value = v
174 174
175 175 @validates('_app_settings_value')
176 176 def validate_settings_value(self, key, val):
177 177 assert type(val) == unicode
178 178 return val
179 179
180 180 @hybrid_property
181 181 def app_settings_value(self):
182 182 v = self._app_settings_value
183 183 if self.app_settings_name == 'ldap_active':
184 184 v = str2bool(v)
185 185 return v
186 186
187 187 @app_settings_value.setter
188 188 def app_settings_value(self, val):
189 189 """
190 190 Setter that will always make sure we use unicode in app_settings_value
191 191
192 192 :param val:
193 193 """
194 194 self._app_settings_value = safe_unicode(val)
195 195
196 196 def __unicode__(self):
197 197 return u"<%s('%s:%s')>" % (
198 198 self.__class__.__name__,
199 199 self.app_settings_name, self.app_settings_value
200 200 )
201 201
202 202 @classmethod
203 203 def get_by_name(cls, ldap_key):
204 204 return cls.query()\
205 205 .filter(cls.app_settings_name == ldap_key).scalar()
206 206
207 207 @classmethod
208 208 def get_app_settings(cls, cache=False):
209 209
210 210 ret = cls.query()
211 211
212 212 if cache:
213 213 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
214 214
215 215 if not ret:
216 216 raise Exception('Could not get application settings !')
217 217 settings = {}
218 218 for each in ret:
219 219 settings['rhodecode_' + each.app_settings_name] = \
220 220 each.app_settings_value
221 221
222 222 return settings
223 223
224 224 @classmethod
225 225 def get_ldap_settings(cls, cache=False):
226 226 ret = cls.query()\
227 227 .filter(cls.app_settings_name.startswith('ldap_')).all()
228 228 fd = {}
229 229 for row in ret:
230 230 fd.update({row.app_settings_name: row.app_settings_value})
231 231
232 232 return fd
233 233
234 234
235 235 class RhodeCodeUi(Base, BaseModel):
236 236 __tablename__ = 'rhodecode_ui'
237 237 __table_args__ = (
238 238 UniqueConstraint('ui_key'),
239 239 {'extend_existing': True, 'mysql_engine': 'InnoDB',
240 240 'mysql_charset': 'utf8'}
241 241 )
242 242
243 243 HOOK_UPDATE = 'changegroup.update'
244 244 HOOK_REPO_SIZE = 'changegroup.repo_size'
245 245 HOOK_PUSH = 'changegroup.push_logger'
246 246 HOOK_PULL = 'preoutgoing.pull_logger'
247 247
248 248 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
249 249 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
250 250 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
251 251 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
252 252 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
253 253
254 254 @classmethod
255 255 def get_by_key(cls, key):
256 256 return cls.query().filter(cls.ui_key == key)
257 257
258 258 @classmethod
259 259 def get_builtin_hooks(cls):
260 260 q = cls.query()
261 261 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
262 262 cls.HOOK_REPO_SIZE,
263 263 cls.HOOK_PUSH, cls.HOOK_PULL]))
264 264 return q.all()
265 265
266 266 @classmethod
267 267 def get_custom_hooks(cls):
268 268 q = cls.query()
269 269 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
270 270 cls.HOOK_REPO_SIZE,
271 271 cls.HOOK_PUSH, cls.HOOK_PULL]))
272 272 q = q.filter(cls.ui_section == 'hooks')
273 273 return q.all()
274 274
275 275 @classmethod
276 276 def get_repos_location(cls):
277 277 return cls.get_by_key('/').one().ui_value
278 278
279 279 @classmethod
280 280 def create_or_update_hook(cls, key, val):
281 281 new_ui = cls.get_by_key(key).scalar() or cls()
282 282 new_ui.ui_section = 'hooks'
283 283 new_ui.ui_active = True
284 284 new_ui.ui_key = key
285 285 new_ui.ui_value = val
286 286
287 287 Session.add(new_ui)
288 288
289 289
290 290 class User(Base, BaseModel):
291 291 __tablename__ = 'users'
292 292 __table_args__ = (
293 293 UniqueConstraint('username'), UniqueConstraint('email'),
294 294 {'extend_existing': True, 'mysql_engine': 'InnoDB',
295 295 'mysql_charset': 'utf8'}
296 296 )
297 297 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
298 298 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
299 299 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
300 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
300 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
301 301 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
302 302 name = Column("firstname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
303 303 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
304 304 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
305 305 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
306 306 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
307 307 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
308 308
309 309 user_log = relationship('UserLog', cascade='all')
310 310 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
311 311
312 312 repositories = relationship('Repository')
313 313 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
314 314 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
315 315 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
316 316
317 317 group_member = relationship('UsersGroupMember', cascade='all')
318 318
319 319 notifications = relationship('UserNotification', cascade='all')
320 320 # notifications assigned to this user
321 321 user_created_notifications = relationship('Notification', cascade='all')
322 322 # comments created by this user
323 323 user_comments = relationship('ChangesetComment', cascade='all')
324 324
325 325 @hybrid_property
326 326 def email(self):
327 327 return self._email
328 328
329 329 @email.setter
330 330 def email(self, val):
331 331 self._email = val.lower() if val else None
332 332
333 333 @property
334 334 def full_name(self):
335 335 return '%s %s' % (self.name, self.lastname)
336 336
337 337 @property
338 338 def full_name_or_username(self):
339 339 return ('%s %s' % (self.name, self.lastname)
340 340 if (self.name and self.lastname) else self.username)
341 341
342 342 @property
343 343 def full_contact(self):
344 344 return '%s %s <%s>' % (self.name, self.lastname, self.email)
345 345
346 346 @property
347 347 def short_contact(self):
348 348 return '%s %s' % (self.name, self.lastname)
349 349
350 350 @property
351 351 def is_admin(self):
352 352 return self.admin
353 353
354 354 def __unicode__(self):
355 355 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
356 356 self.user_id, self.username)
357 357
358 358 @classmethod
359 359 def get_by_username(cls, username, case_insensitive=False, cache=False):
360 360 if case_insensitive:
361 361 q = cls.query().filter(cls.username.ilike(username))
362 362 else:
363 363 q = cls.query().filter(cls.username == username)
364 364
365 365 if cache:
366 366 q = q.options(FromCache(
367 367 "sql_cache_short",
368 368 "get_user_%s" % _hash_key(username)
369 369 )
370 370 )
371 371 return q.scalar()
372 372
373 373 @classmethod
374 374 def get_by_api_key(cls, api_key, cache=False):
375 375 q = cls.query().filter(cls.api_key == api_key)
376 376
377 377 if cache:
378 378 q = q.options(FromCache("sql_cache_short",
379 379 "get_api_key_%s" % api_key))
380 380 return q.scalar()
381 381
382 382 @classmethod
383 383 def get_by_email(cls, email, case_insensitive=False, cache=False):
384 384 if case_insensitive:
385 385 q = cls.query().filter(cls.email.ilike(email))
386 386 else:
387 387 q = cls.query().filter(cls.email == email)
388 388
389 389 if cache:
390 390 q = q.options(FromCache("sql_cache_short",
391 391 "get_email_key_%s" % email))
392 392
393 393 ret = q.scalar()
394 394 if ret is None:
395 395 q = UserEmailMap.query()
396 396 # try fetching in alternate email map
397 397 if case_insensitive:
398 398 q = q.filter(UserEmailMap.email.ilike(email))
399 399 else:
400 400 q = q.filter(UserEmailMap.email == email)
401 401 q = q.options(joinedload(UserEmailMap.user))
402 402 if cache:
403 403 q = q.options(FromCache("sql_cache_short",
404 404 "get_email_map_key_%s" % email))
405 405 ret = getattr(q.scalar(), 'user', None)
406 406
407 407 return ret
408 408
409 409 def update_lastlogin(self):
410 410 """Update user lastlogin"""
411 411 self.last_login = datetime.datetime.now()
412 412 Session.add(self)
413 413 log.debug('updated user %s lastlogin' % self.username)
414 414
415 415 def __json__(self):
416 416 return dict(
417 417 user_id=self.user_id,
418 418 first_name=self.name,
419 419 last_name=self.lastname,
420 420 email=self.email,
421 421 full_name=self.full_name,
422 422 full_name_or_username=self.full_name_or_username,
423 423 short_contact=self.short_contact,
424 424 full_contact=self.full_contact
425 425 )
426 426
427 427
428 428 class UserEmailMap(Base, BaseModel):
429 429 __tablename__ = 'user_email_map'
430 430 __table_args__ = (
431 431 Index('uem_email_idx', 'email'),
432 432 UniqueConstraint('email'),
433 433 {'extend_existing': True, 'mysql_engine': 'InnoDB',
434 434 'mysql_charset': 'utf8'}
435 435 )
436 436 __mapper_args__ = {}
437 437
438 438 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
439 439 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
440 440 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
441 441
442 442 user = relationship('User', lazy='joined')
443 443
444 444 @validates('_email')
445 445 def validate_email(self, key, email):
446 446 # check if this email is not main one
447 447 main_email = Session.query(User).filter(User.email == email).scalar()
448 448 if main_email is not None:
449 449 raise AttributeError('email %s is present is user table' % email)
450 450 return email
451 451
452 452 @hybrid_property
453 453 def email(self):
454 454 return self._email
455 455
456 456 @email.setter
457 457 def email(self, val):
458 458 self._email = val.lower() if val else None
459 459
460 460
461 461 class UserLog(Base, BaseModel):
462 462 __tablename__ = 'user_logs'
463 463 __table_args__ = (
464 464 {'extend_existing': True, 'mysql_engine': 'InnoDB',
465 465 'mysql_charset': 'utf8'},
466 466 )
467 467 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
468 468 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
469 469 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
470 470 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
471 471 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
472 472 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
473 473 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
474 474
475 475 @property
476 476 def action_as_day(self):
477 477 return datetime.date(*self.action_date.timetuple()[:3])
478 478
479 479 user = relationship('User')
480 480 repository = relationship('Repository', cascade='')
481 481
482 482
483 483 class UsersGroup(Base, BaseModel):
484 484 __tablename__ = 'users_groups'
485 485 __table_args__ = (
486 486 {'extend_existing': True, 'mysql_engine': 'InnoDB',
487 487 'mysql_charset': 'utf8'},
488 488 )
489 489
490 490 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
491 491 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
492 492 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
493 493
494 494 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
495 495 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
496 496 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
497 497
498 498 def __unicode__(self):
499 499 return u'<userGroup(%s)>' % (self.users_group_name)
500 500
501 501 @classmethod
502 502 def get_by_group_name(cls, group_name, cache=False,
503 503 case_insensitive=False):
504 504 if case_insensitive:
505 505 q = cls.query().filter(cls.users_group_name.ilike(group_name))
506 506 else:
507 507 q = cls.query().filter(cls.users_group_name == group_name)
508 508 if cache:
509 509 q = q.options(FromCache(
510 510 "sql_cache_short",
511 511 "get_user_%s" % _hash_key(group_name)
512 512 )
513 513 )
514 514 return q.scalar()
515 515
516 516 @classmethod
517 517 def get(cls, users_group_id, cache=False):
518 518 users_group = cls.query()
519 519 if cache:
520 520 users_group = users_group.options(FromCache("sql_cache_short",
521 521 "get_users_group_%s" % users_group_id))
522 522 return users_group.get(users_group_id)
523 523
524 524
525 525 class UsersGroupMember(Base, BaseModel):
526 526 __tablename__ = 'users_groups_members'
527 527 __table_args__ = (
528 528 {'extend_existing': True, 'mysql_engine': 'InnoDB',
529 529 'mysql_charset': 'utf8'},
530 530 )
531 531
532 532 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
533 533 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
534 534 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
535 535
536 536 user = relationship('User', lazy='joined')
537 537 users_group = relationship('UsersGroup')
538 538
539 539 def __init__(self, gr_id='', u_id=''):
540 540 self.users_group_id = gr_id
541 541 self.user_id = u_id
542 542
543 543
544 544 class Repository(Base, BaseModel):
545 545 __tablename__ = 'repositories'
546 546 __table_args__ = (
547 547 UniqueConstraint('repo_name'),
548 548 {'extend_existing': True, 'mysql_engine': 'InnoDB',
549 549 'mysql_charset': 'utf8'},
550 550 )
551 551
552 552 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
553 553 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
554 554 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
555 555 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
556 556 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
557 557 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
558 558 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
559 559 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
560 560 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
561 561 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
562 562 landing_rev = Column("landing_revision", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
563 563
564 564 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
565 565 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
566 566
567 567 user = relationship('User')
568 568 fork = relationship('Repository', remote_side=repo_id)
569 569 group = relationship('RepoGroup')
570 570 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
571 571 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
572 572 stats = relationship('Statistics', cascade='all', uselist=False)
573 573
574 574 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
575 575
576 576 logs = relationship('UserLog')
577 577 comments = relationship('ChangesetComment')
578 578
579 579 def __unicode__(self):
580 580 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
581 581 self.repo_name)
582 582
583 583 @classmethod
584 584 def url_sep(cls):
585 585 return URL_SEP
586 586
587 587 @classmethod
588 588 def get_by_repo_name(cls, repo_name):
589 589 q = Session.query(cls).filter(cls.repo_name == repo_name)
590 590 q = q.options(joinedload(Repository.fork))\
591 591 .options(joinedload(Repository.user))\
592 592 .options(joinedload(Repository.group))
593 593 return q.scalar()
594 594
595 595 @classmethod
596 596 def get_by_full_path(cls, repo_full_path):
597 597 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
598 598 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
599 599
600 600 @classmethod
601 601 def get_repo_forks(cls, repo_id):
602 602 return cls.query().filter(Repository.fork_id == repo_id)
603 603
604 604 @classmethod
605 605 def base_path(cls):
606 606 """
607 607 Returns base path when all repos are stored
608 608
609 609 :param cls:
610 610 """
611 611 q = Session.query(RhodeCodeUi)\
612 612 .filter(RhodeCodeUi.ui_key == cls.url_sep())
613 613 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
614 614 return q.one().ui_value
615 615
616 616 @property
617 617 def forks(self):
618 618 """
619 619 Return forks of this repo
620 620 """
621 621 return Repository.get_repo_forks(self.repo_id)
622 622
623 623 @property
624 624 def parent(self):
625 625 """
626 626 Returns fork parent
627 627 """
628 628 return self.fork
629 629
630 630 @property
631 631 def just_name(self):
632 632 return self.repo_name.split(Repository.url_sep())[-1]
633 633
634 634 @property
635 635 def groups_with_parents(self):
636 636 groups = []
637 637 if self.group is None:
638 638 return groups
639 639
640 640 cur_gr = self.group
641 641 groups.insert(0, cur_gr)
642 642 while 1:
643 643 gr = getattr(cur_gr, 'parent_group', None)
644 644 cur_gr = cur_gr.parent_group
645 645 if gr is None:
646 646 break
647 647 groups.insert(0, gr)
648 648
649 649 return groups
650 650
651 651 @property
652 652 def groups_and_repo(self):
653 653 return self.groups_with_parents, self.just_name
654 654
655 655 @LazyProperty
656 656 def repo_path(self):
657 657 """
658 658 Returns base full path for that repository means where it actually
659 659 exists on a filesystem
660 660 """
661 661 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
662 662 Repository.url_sep())
663 663 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
664 664 return q.one().ui_value
665 665
666 666 @property
667 667 def repo_full_path(self):
668 668 p = [self.repo_path]
669 669 # we need to split the name by / since this is how we store the
670 670 # names in the database, but that eventually needs to be converted
671 671 # into a valid system path
672 672 p += self.repo_name.split(Repository.url_sep())
673 673 return os.path.join(*p)
674 674
675 675 def get_new_name(self, repo_name):
676 676 """
677 677 returns new full repository name based on assigned group and new new
678 678
679 679 :param group_name:
680 680 """
681 681 path_prefix = self.group.full_path_splitted if self.group else []
682 682 return Repository.url_sep().join(path_prefix + [repo_name])
683 683
684 684 @property
685 685 def _ui(self):
686 686 """
687 687 Creates an db based ui object for this repository
688 688 """
689 689 from mercurial import ui
690 690 from mercurial import config
691 691 baseui = ui.ui()
692 692
693 693 #clean the baseui object
694 694 baseui._ocfg = config.config()
695 695 baseui._ucfg = config.config()
696 696 baseui._tcfg = config.config()
697 697
698 698 ret = RhodeCodeUi.query()\
699 699 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
700 700
701 701 hg_ui = ret
702 702 for ui_ in hg_ui:
703 703 if ui_.ui_active:
704 704 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
705 705 ui_.ui_key, ui_.ui_value)
706 706 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
707 707
708 708 return baseui
709 709
710 710 @classmethod
711 711 def is_valid(cls, repo_name):
712 712 """
713 713 returns True if given repo name is a valid filesystem repository
714 714
715 715 :param cls:
716 716 :param repo_name:
717 717 """
718 718 from rhodecode.lib.utils import is_valid_repo
719 719
720 720 return is_valid_repo(repo_name, cls.base_path())
721 721
722 722 #==========================================================================
723 723 # SCM PROPERTIES
724 724 #==========================================================================
725 725
726 726 def get_changeset(self, rev=None):
727 727 return get_changeset_safe(self.scm_instance, rev)
728 728
729 729 @property
730 730 def tip(self):
731 731 return self.get_changeset('tip')
732 732
733 733 @property
734 734 def author(self):
735 735 return self.tip.author
736 736
737 737 @property
738 738 def last_change(self):
739 739 return self.scm_instance.last_change
740 740
741 741 def comments(self, revisions=None):
742 742 """
743 743 Returns comments for this repository grouped by revisions
744 744
745 745 :param revisions: filter query by revisions only
746 746 """
747 747 cmts = ChangesetComment.query()\
748 748 .filter(ChangesetComment.repo == self)
749 749 if revisions:
750 750 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
751 751 grouped = defaultdict(list)
752 752 for cmt in cmts.all():
753 753 grouped[cmt.revision].append(cmt)
754 754 return grouped
755 755
756 756 def statuses(self, revisions=None):
757 757 """
758 758 Returns statuses for this repository
759 759
760 760 :param revisions: list of revisions to get statuses for
761 761 :type revisions: list
762 762 """
763 763
764 764 statuses = ChangesetStatus.query()\
765 765 .filter(ChangesetStatus.repo == self)\
766 766 .filter(ChangesetStatus.version == 0)
767 767 if revisions:
768 768 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
769 769 grouped = {}
770 770 for stat in statuses.all():
771 771 pr_id = pr_repo = None
772 772 if stat.pull_request:
773 773 pr_id = stat.pull_request.pull_request_id
774 774 pr_repo = stat.pull_request.other_repo.repo_name
775 775 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
776 776 pr_id, pr_repo]
777 777 return grouped
778 778
779 779 #==========================================================================
780 780 # SCM CACHE INSTANCE
781 781 #==========================================================================
782 782
783 783 @property
784 784 def invalidate(self):
785 785 return CacheInvalidation.invalidate(self.repo_name)
786 786
787 787 def set_invalidate(self):
788 788 """
789 789 set a cache for invalidation for this instance
790 790 """
791 791 CacheInvalidation.set_invalidate(self.repo_name)
792 792
793 793 @LazyProperty
794 794 def scm_instance(self):
795 795 return self.__get_instance()
796 796
797 797 def scm_instance_cached(self, cache_map=None):
798 798 @cache_region('long_term')
799 799 def _c(repo_name):
800 800 return self.__get_instance()
801 801 rn = self.repo_name
802 802 log.debug('Getting cached instance of repo')
803 803
804 804 if cache_map:
805 805 # get using prefilled cache_map
806 806 invalidate_repo = cache_map[self.repo_name]
807 807 if invalidate_repo:
808 808 invalidate_repo = (None if invalidate_repo.cache_active
809 809 else invalidate_repo)
810 810 else:
811 811 # get from invalidate
812 812 invalidate_repo = self.invalidate
813 813
814 814 if invalidate_repo is not None:
815 815 region_invalidate(_c, None, rn)
816 816 # update our cache
817 817 CacheInvalidation.set_valid(invalidate_repo.cache_key)
818 818 return _c(rn)
819 819
820 820 def __get_instance(self):
821 821 repo_full_path = self.repo_full_path
822 822 try:
823 823 alias = get_scm(repo_full_path)[0]
824 824 log.debug('Creating instance of %s repository' % alias)
825 825 backend = get_backend(alias)
826 826 except VCSError:
827 827 log.error(traceback.format_exc())
828 828 log.error('Perhaps this repository is in db and not in '
829 829 'filesystem run rescan repositories with '
830 830 '"destroy old data " option from admin panel')
831 831 return
832 832
833 833 if alias == 'hg':
834 834
835 835 repo = backend(safe_str(repo_full_path), create=False,
836 836 baseui=self._ui)
837 837 # skip hidden web repository
838 838 if repo._get_hidden():
839 839 return
840 840 else:
841 841 repo = backend(repo_full_path, create=False)
842 842
843 843 return repo
844 844
845 845
846 846 class RepoGroup(Base, BaseModel):
847 847 __tablename__ = 'groups'
848 848 __table_args__ = (
849 849 UniqueConstraint('group_name', 'group_parent_id'),
850 850 CheckConstraint('group_id != group_parent_id'),
851 851 {'extend_existing': True, 'mysql_engine': 'InnoDB',
852 852 'mysql_charset': 'utf8'},
853 853 )
854 854 __mapper_args__ = {'order_by': 'group_name'}
855 855
856 856 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
857 857 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
858 858 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
859 859 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
860 860
861 861 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
862 862 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
863 863
864 864 parent_group = relationship('RepoGroup', remote_side=group_id)
865 865
866 866 def __init__(self, group_name='', parent_group=None):
867 867 self.group_name = group_name
868 868 self.parent_group = parent_group
869 869
870 870 def __unicode__(self):
871 871 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
872 872 self.group_name)
873 873
874 874 @classmethod
875 875 def groups_choices(cls):
876 876 from webhelpers.html import literal as _literal
877 877 repo_groups = [('', '')]
878 878 sep = ' &raquo; '
879 879 _name = lambda k: _literal(sep.join(k))
880 880
881 881 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
882 882 for x in cls.query().all()])
883 883
884 884 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
885 885 return repo_groups
886 886
887 887 @classmethod
888 888 def url_sep(cls):
889 889 return URL_SEP
890 890
891 891 @classmethod
892 892 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
893 893 if case_insensitive:
894 894 gr = cls.query()\
895 895 .filter(cls.group_name.ilike(group_name))
896 896 else:
897 897 gr = cls.query()\
898 898 .filter(cls.group_name == group_name)
899 899 if cache:
900 900 gr = gr.options(FromCache(
901 901 "sql_cache_short",
902 902 "get_group_%s" % _hash_key(group_name)
903 903 )
904 904 )
905 905 return gr.scalar()
906 906
907 907 @property
908 908 def parents(self):
909 909 parents_recursion_limit = 5
910 910 groups = []
911 911 if self.parent_group is None:
912 912 return groups
913 913 cur_gr = self.parent_group
914 914 groups.insert(0, cur_gr)
915 915 cnt = 0
916 916 while 1:
917 917 cnt += 1
918 918 gr = getattr(cur_gr, 'parent_group', None)
919 919 cur_gr = cur_gr.parent_group
920 920 if gr is None:
921 921 break
922 922 if cnt == parents_recursion_limit:
923 923 # this will prevent accidental infinit loops
924 924 log.error('group nested more than %s' %
925 925 parents_recursion_limit)
926 926 break
927 927
928 928 groups.insert(0, gr)
929 929 return groups
930 930
931 931 @property
932 932 def children(self):
933 933 return RepoGroup.query().filter(RepoGroup.parent_group == self)
934 934
935 935 @property
936 936 def name(self):
937 937 return self.group_name.split(RepoGroup.url_sep())[-1]
938 938
939 939 @property
940 940 def full_path(self):
941 941 return self.group_name
942 942
943 943 @property
944 944 def full_path_splitted(self):
945 945 return self.group_name.split(RepoGroup.url_sep())
946 946
947 947 @property
948 948 def repositories(self):
949 949 return Repository.query()\
950 950 .filter(Repository.group == self)\
951 951 .order_by(Repository.repo_name)
952 952
953 953 @property
954 954 def repositories_recursive_count(self):
955 955 cnt = self.repositories.count()
956 956
957 957 def children_count(group):
958 958 cnt = 0
959 959 for child in group.children:
960 960 cnt += child.repositories.count()
961 961 cnt += children_count(child)
962 962 return cnt
963 963
964 964 return cnt + children_count(self)
965 965
966 966 def get_new_name(self, group_name):
967 967 """
968 968 returns new full group name based on parent and new name
969 969
970 970 :param group_name:
971 971 """
972 972 path_prefix = (self.parent_group.full_path_splitted if
973 973 self.parent_group else [])
974 974 return RepoGroup.url_sep().join(path_prefix + [group_name])
975 975
976 976
977 977 class Permission(Base, BaseModel):
978 978 __tablename__ = 'permissions'
979 979 __table_args__ = (
980 980 Index('p_perm_name_idx', 'permission_name'),
981 981 {'extend_existing': True, 'mysql_engine': 'InnoDB',
982 982 'mysql_charset': 'utf8'},
983 983 )
984 984 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
985 985 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
986 986 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
987 987
988 988 def __unicode__(self):
989 989 return u"<%s('%s:%s')>" % (
990 990 self.__class__.__name__, self.permission_id, self.permission_name
991 991 )
992 992
993 993 @classmethod
994 994 def get_by_key(cls, key):
995 995 return cls.query().filter(cls.permission_name == key).scalar()
996 996
997 997 @classmethod
998 998 def get_default_perms(cls, default_user_id):
999 999 q = Session.query(UserRepoToPerm, Repository, cls)\
1000 1000 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1001 1001 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1002 1002 .filter(UserRepoToPerm.user_id == default_user_id)
1003 1003
1004 1004 return q.all()
1005 1005
1006 1006 @classmethod
1007 1007 def get_default_group_perms(cls, default_user_id):
1008 1008 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
1009 1009 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1010 1010 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1011 1011 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1012 1012
1013 1013 return q.all()
1014 1014
1015 1015
1016 1016 class UserRepoToPerm(Base, BaseModel):
1017 1017 __tablename__ = 'repo_to_perm'
1018 1018 __table_args__ = (
1019 1019 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1020 1020 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1021 1021 'mysql_charset': 'utf8'}
1022 1022 )
1023 1023 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1024 1024 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1025 1025 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1026 1026 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1027 1027
1028 1028 user = relationship('User')
1029 1029 repository = relationship('Repository')
1030 1030 permission = relationship('Permission')
1031 1031
1032 1032 @classmethod
1033 1033 def create(cls, user, repository, permission):
1034 1034 n = cls()
1035 1035 n.user = user
1036 1036 n.repository = repository
1037 1037 n.permission = permission
1038 1038 Session.add(n)
1039 1039 return n
1040 1040
1041 1041 def __unicode__(self):
1042 1042 return u'<user:%s => %s >' % (self.user, self.repository)
1043 1043
1044 1044
1045 1045 class UserToPerm(Base, BaseModel):
1046 1046 __tablename__ = 'user_to_perm'
1047 1047 __table_args__ = (
1048 1048 UniqueConstraint('user_id', 'permission_id'),
1049 1049 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1050 1050 'mysql_charset': 'utf8'}
1051 1051 )
1052 1052 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1053 1053 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1054 1054 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1055 1055
1056 1056 user = relationship('User')
1057 1057 permission = relationship('Permission', lazy='joined')
1058 1058
1059 1059
1060 1060 class UsersGroupRepoToPerm(Base, BaseModel):
1061 1061 __tablename__ = 'users_group_repo_to_perm'
1062 1062 __table_args__ = (
1063 1063 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1064 1064 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1065 1065 'mysql_charset': 'utf8'}
1066 1066 )
1067 1067 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1068 1068 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1069 1069 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1070 1070 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1071 1071
1072 1072 users_group = relationship('UsersGroup')
1073 1073 permission = relationship('Permission')
1074 1074 repository = relationship('Repository')
1075 1075
1076 1076 @classmethod
1077 1077 def create(cls, users_group, repository, permission):
1078 1078 n = cls()
1079 1079 n.users_group = users_group
1080 1080 n.repository = repository
1081 1081 n.permission = permission
1082 1082 Session.add(n)
1083 1083 return n
1084 1084
1085 1085 def __unicode__(self):
1086 1086 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1087 1087
1088 1088
1089 1089 class UsersGroupToPerm(Base, BaseModel):
1090 1090 __tablename__ = 'users_group_to_perm'
1091 1091 __table_args__ = (
1092 1092 UniqueConstraint('users_group_id', 'permission_id',),
1093 1093 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1094 1094 'mysql_charset': 'utf8'}
1095 1095 )
1096 1096 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1097 1097 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1098 1098 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1099 1099
1100 1100 users_group = relationship('UsersGroup')
1101 1101 permission = relationship('Permission')
1102 1102
1103 1103
1104 1104 class UserRepoGroupToPerm(Base, BaseModel):
1105 1105 __tablename__ = 'user_repo_group_to_perm'
1106 1106 __table_args__ = (
1107 1107 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1108 1108 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1109 1109 'mysql_charset': 'utf8'}
1110 1110 )
1111 1111
1112 1112 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1113 1113 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1114 1114 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1115 1115 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1116 1116
1117 1117 user = relationship('User')
1118 1118 group = relationship('RepoGroup')
1119 1119 permission = relationship('Permission')
1120 1120
1121 1121
1122 1122 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1123 1123 __tablename__ = 'users_group_repo_group_to_perm'
1124 1124 __table_args__ = (
1125 1125 UniqueConstraint('users_group_id', 'group_id'),
1126 1126 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1127 1127 'mysql_charset': 'utf8'}
1128 1128 )
1129 1129
1130 1130 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1131 1131 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1132 1132 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1133 1133 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1134 1134
1135 1135 users_group = relationship('UsersGroup')
1136 1136 permission = relationship('Permission')
1137 1137 group = relationship('RepoGroup')
1138 1138
1139 1139
1140 1140 class Statistics(Base, BaseModel):
1141 1141 __tablename__ = 'statistics'
1142 1142 __table_args__ = (
1143 1143 UniqueConstraint('repository_id'),
1144 1144 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1145 1145 'mysql_charset': 'utf8'}
1146 1146 )
1147 1147 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1148 1148 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1149 1149 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1150 1150 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1151 1151 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1152 1152 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1153 1153
1154 1154 repository = relationship('Repository', single_parent=True)
1155 1155
1156 1156
1157 1157 class UserFollowing(Base, BaseModel):
1158 1158 __tablename__ = 'user_followings'
1159 1159 __table_args__ = (
1160 1160 UniqueConstraint('user_id', 'follows_repository_id'),
1161 1161 UniqueConstraint('user_id', 'follows_user_id'),
1162 1162 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1163 1163 'mysql_charset': 'utf8'}
1164 1164 )
1165 1165
1166 1166 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1167 1167 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1168 1168 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1169 1169 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1170 1170 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1171 1171
1172 1172 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1173 1173
1174 1174 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1175 1175 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1176 1176
1177 1177 @classmethod
1178 1178 def get_repo_followers(cls, repo_id):
1179 1179 return cls.query().filter(cls.follows_repo_id == repo_id)
1180 1180
1181 1181
1182 1182 class CacheInvalidation(Base, BaseModel):
1183 1183 __tablename__ = 'cache_invalidation'
1184 1184 __table_args__ = (
1185 1185 UniqueConstraint('cache_key'),
1186 1186 Index('key_idx', 'cache_key'),
1187 1187 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1188 1188 'mysql_charset': 'utf8'},
1189 1189 )
1190 1190 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1191 1191 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1192 1192 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1193 1193 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1194 1194
1195 1195 def __init__(self, cache_key, cache_args=''):
1196 1196 self.cache_key = cache_key
1197 1197 self.cache_args = cache_args
1198 1198 self.cache_active = False
1199 1199
1200 1200 def __unicode__(self):
1201 1201 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1202 1202 self.cache_id, self.cache_key)
1203 1203
1204 1204 @classmethod
1205 1205 def clear_cache(cls):
1206 1206 cls.query().delete()
1207 1207
1208 1208 @classmethod
1209 1209 def _get_key(cls, key):
1210 1210 """
1211 1211 Wrapper for generating a key, together with a prefix
1212 1212
1213 1213 :param key:
1214 1214 """
1215 1215 import rhodecode
1216 1216 prefix = ''
1217 1217 iid = rhodecode.CONFIG.get('instance_id')
1218 1218 if iid:
1219 1219 prefix = iid
1220 1220 return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
1221 1221
1222 1222 @classmethod
1223 1223 def get_by_key(cls, key):
1224 1224 return cls.query().filter(cls.cache_key == key).scalar()
1225 1225
1226 1226 @classmethod
1227 1227 def _get_or_create_key(cls, key, prefix, org_key):
1228 1228 inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
1229 1229 if not inv_obj:
1230 1230 try:
1231 1231 inv_obj = CacheInvalidation(key, org_key)
1232 1232 Session.add(inv_obj)
1233 1233 Session.commit()
1234 1234 except Exception:
1235 1235 log.error(traceback.format_exc())
1236 1236 Session.rollback()
1237 1237 return inv_obj
1238 1238
1239 1239 @classmethod
1240 1240 def invalidate(cls, key):
1241 1241 """
1242 1242 Returns Invalidation object if this given key should be invalidated
1243 1243 None otherwise. `cache_active = False` means that this cache
1244 1244 state is not valid and needs to be invalidated
1245 1245
1246 1246 :param key:
1247 1247 """
1248 1248
1249 1249 key, _prefix, _org_key = cls._get_key(key)
1250 1250 inv = cls._get_or_create_key(key, _prefix, _org_key)
1251 1251
1252 1252 if inv and inv.cache_active is False:
1253 1253 return inv
1254 1254
1255 1255 @classmethod
1256 1256 def set_invalidate(cls, key):
1257 1257 """
1258 1258 Mark this Cache key for invalidation
1259 1259
1260 1260 :param key:
1261 1261 """
1262 1262
1263 1263 key, _prefix, _org_key = cls._get_key(key)
1264 1264 inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
1265 1265 log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs),
1266 1266 _org_key))
1267 1267 try:
1268 1268 for inv_obj in inv_objs:
1269 1269 if inv_obj:
1270 1270 inv_obj.cache_active = False
1271 1271
1272 1272 Session.add(inv_obj)
1273 1273 Session.commit()
1274 1274 except Exception:
1275 1275 log.error(traceback.format_exc())
1276 1276 Session.rollback()
1277 1277
1278 1278 @classmethod
1279 1279 def set_valid(cls, key):
1280 1280 """
1281 1281 Mark this cache key as active and currently cached
1282 1282
1283 1283 :param key:
1284 1284 """
1285 1285 inv_obj = cls.get_by_key(key)
1286 1286 inv_obj.cache_active = True
1287 1287 Session.add(inv_obj)
1288 1288 Session.commit()
1289 1289
1290 1290 @classmethod
1291 1291 def get_cache_map(cls):
1292 1292
1293 1293 class cachemapdict(dict):
1294 1294
1295 1295 def __init__(self, *args, **kwargs):
1296 1296 fixkey = kwargs.get('fixkey')
1297 1297 if fixkey:
1298 1298 del kwargs['fixkey']
1299 1299 self.fixkey = fixkey
1300 1300 super(cachemapdict, self).__init__(*args, **kwargs)
1301 1301
1302 1302 def __getattr__(self, name):
1303 1303 key = name
1304 1304 if self.fixkey:
1305 1305 key, _prefix, _org_key = cls._get_key(key)
1306 1306 if key in self.__dict__:
1307 1307 return self.__dict__[key]
1308 1308 else:
1309 1309 return self[key]
1310 1310
1311 1311 def __getitem__(self, key):
1312 1312 if self.fixkey:
1313 1313 key, _prefix, _org_key = cls._get_key(key)
1314 1314 try:
1315 1315 return super(cachemapdict, self).__getitem__(key)
1316 1316 except KeyError:
1317 1317 return
1318 1318
1319 1319 cache_map = cachemapdict(fixkey=True)
1320 1320 for obj in cls.query().all():
1321 1321 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1322 1322 return cache_map
1323 1323
1324 1324
1325 1325 class ChangesetComment(Base, BaseModel):
1326 1326 __tablename__ = 'changeset_comments'
1327 1327 __table_args__ = (
1328 1328 Index('cc_revision_idx', 'revision'),
1329 1329 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1330 1330 'mysql_charset': 'utf8'},
1331 1331 )
1332 1332 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1333 1333 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1334 1334 revision = Column('revision', String(40), nullable=True)
1335 1335 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1336 1336 line_no = Column('line_no', Unicode(10), nullable=True)
1337 1337 f_path = Column('f_path', Unicode(1000), nullable=True)
1338 1338 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1339 1339 text = Column('text', Unicode(25000), nullable=False)
1340 1340 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1341 1341
1342 1342 author = relationship('User', lazy='joined')
1343 1343 repo = relationship('Repository')
1344 1344 status_change = relationship('ChangesetStatus', uselist=False)
1345 1345 pull_request = relationship('PullRequest', lazy='joined')
1346 1346
1347 1347 @classmethod
1348 1348 def get_users(cls, revision=None, pull_request_id=None):
1349 1349 """
1350 1350 Returns user associated with this ChangesetComment. ie those
1351 1351 who actually commented
1352 1352
1353 1353 :param cls:
1354 1354 :param revision:
1355 1355 """
1356 1356 q = Session.query(User)\
1357 1357 .join(ChangesetComment.author)
1358 1358 if revision:
1359 1359 q = q.filter(cls.revision == revision)
1360 1360 elif pull_request_id:
1361 1361 q = q.filter(cls.pull_request_id == pull_request_id)
1362 1362 return q.all()
1363 1363
1364 1364
1365 1365 class ChangesetStatus(Base, BaseModel):
1366 1366 __tablename__ = 'changeset_statuses'
1367 1367 __table_args__ = (
1368 1368 Index('cs_revision_idx', 'revision'),
1369 1369 Index('cs_version_idx', 'version'),
1370 1370 UniqueConstraint('repo_id', 'revision', 'version'),
1371 1371 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1372 1372 'mysql_charset': 'utf8'}
1373 1373 )
1374 1374
1375 1375 STATUSES = [
1376 1376 ('not_reviewed', _("Not Reviewed")), # (no icon) and default
1377 1377 ('approved', _("Approved")),
1378 1378 ('rejected', _("Rejected")),
1379 1379 ('under_review', _("Under Review")),
1380 1380 ]
1381 1381 DEFAULT = STATUSES[0][0]
1382 1382
1383 1383 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1384 1384 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1385 1385 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1386 1386 revision = Column('revision', String(40), nullable=False)
1387 1387 status = Column('status', String(128), nullable=False, default=DEFAULT)
1388 1388 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1389 1389 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1390 1390 version = Column('version', Integer(), nullable=False, default=0)
1391 1391 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1392 1392
1393 1393 author = relationship('User', lazy='joined')
1394 1394 repo = relationship('Repository')
1395 1395 comment = relationship('ChangesetComment', lazy='joined')
1396 1396 pull_request = relationship('PullRequest', lazy='joined')
1397 1397
1398 1398 @classmethod
1399 1399 def get_status_lbl(cls, value):
1400 1400 return dict(cls.STATUSES).get(value)
1401 1401
1402 1402 @property
1403 1403 def status_lbl(self):
1404 1404 return ChangesetStatus.get_status_lbl(self.status)
1405 1405
1406 1406
1407 1407 class PullRequest(Base, BaseModel):
1408 1408 __tablename__ = 'pull_requests'
1409 1409 __table_args__ = (
1410 1410 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1411 1411 'mysql_charset': 'utf8'},
1412 1412 )
1413 1413
1414 1414 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1415 1415 title = Column('title', Unicode(256), nullable=True)
1416 1416 description = Column('description', Unicode(10240), nullable=True)
1417 1417 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1418 1418 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1419 1419 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1420 1420 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1421 1421 org_ref = Column('org_ref', Unicode(256), nullable=False)
1422 1422 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1423 1423 other_ref = Column('other_ref', Unicode(256), nullable=False)
1424 1424
1425 1425 @hybrid_property
1426 1426 def revisions(self):
1427 1427 return self._revisions.split(':')
1428 1428
1429 1429 @revisions.setter
1430 1430 def revisions(self, val):
1431 1431 self._revisions = ':'.join(val)
1432 1432
1433 1433 author = relationship('User', lazy='joined')
1434 1434 reviewers = relationship('PullRequestReviewers')
1435 1435 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1436 1436 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1437 1437
1438 1438 def __json__(self):
1439 1439 return dict(
1440 1440 revisions=self.revisions
1441 1441 )
1442 1442
1443 1443
1444 1444 class PullRequestReviewers(Base, BaseModel):
1445 1445 __tablename__ = 'pull_request_reviewers'
1446 1446 __table_args__ = (
1447 1447 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1448 1448 'mysql_charset': 'utf8'},
1449 1449 )
1450 1450
1451 1451 def __init__(self, user=None, pull_request=None):
1452 1452 self.user = user
1453 1453 self.pull_request = pull_request
1454 1454
1455 1455 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1456 1456 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1457 1457 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1458 1458
1459 1459 user = relationship('User')
1460 1460 pull_request = relationship('PullRequest')
1461 1461
1462 1462
1463 1463 class Notification(Base, BaseModel):
1464 1464 __tablename__ = 'notifications'
1465 1465 __table_args__ = (
1466 1466 Index('notification_type_idx', 'type'),
1467 1467 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1468 1468 'mysql_charset': 'utf8'},
1469 1469 )
1470 1470
1471 1471 TYPE_CHANGESET_COMMENT = u'cs_comment'
1472 1472 TYPE_MESSAGE = u'message'
1473 1473 TYPE_MENTION = u'mention'
1474 1474 TYPE_REGISTRATION = u'registration'
1475 1475 TYPE_PULL_REQUEST = u'pull_request'
1476 1476 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1477 1477
1478 1478 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1479 1479 subject = Column('subject', Unicode(512), nullable=True)
1480 1480 body = Column('body', Unicode(50000), nullable=True)
1481 1481 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1482 1482 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1483 1483 type_ = Column('type', Unicode(256))
1484 1484
1485 1485 created_by_user = relationship('User')
1486 1486 notifications_to_users = relationship('UserNotification', lazy='joined',
1487 1487 cascade="all, delete, delete-orphan")
1488 1488
1489 1489 @property
1490 1490 def recipients(self):
1491 1491 return [x.user for x in UserNotification.query()\
1492 1492 .filter(UserNotification.notification == self)\
1493 1493 .order_by(UserNotification.user).all()]
1494 1494
1495 1495 @classmethod
1496 1496 def create(cls, created_by, subject, body, recipients, type_=None):
1497 1497 if type_ is None:
1498 1498 type_ = Notification.TYPE_MESSAGE
1499 1499
1500 1500 notification = cls()
1501 1501 notification.created_by_user = created_by
1502 1502 notification.subject = subject
1503 1503 notification.body = body
1504 1504 notification.type_ = type_
1505 1505 notification.created_on = datetime.datetime.now()
1506 1506
1507 1507 for u in recipients:
1508 1508 assoc = UserNotification()
1509 1509 assoc.notification = notification
1510 1510 u.notifications.append(assoc)
1511 1511 Session.add(notification)
1512 1512 return notification
1513 1513
1514 1514 @property
1515 1515 def description(self):
1516 1516 from rhodecode.model.notification import NotificationModel
1517 1517 return NotificationModel().make_description(self)
1518 1518
1519 1519
1520 1520 class UserNotification(Base, BaseModel):
1521 1521 __tablename__ = 'user_to_notification'
1522 1522 __table_args__ = (
1523 1523 UniqueConstraint('user_id', 'notification_id'),
1524 1524 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1525 1525 'mysql_charset': 'utf8'}
1526 1526 )
1527 1527 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1528 1528 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1529 1529 read = Column('read', Boolean, default=False)
1530 1530 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1531 1531
1532 1532 user = relationship('User', lazy="joined")
1533 1533 notification = relationship('Notification', lazy="joined",
1534 1534 order_by=lambda: Notification.created_on.desc(),)
1535 1535
1536 1536 def mark_as_read(self):
1537 1537 self.read = True
1538 1538 Session.add(self)
1539 1539
1540 1540
1541 1541 class DbMigrateVersion(Base, BaseModel):
1542 1542 __tablename__ = 'db_migrate_version'
1543 1543 __table_args__ = (
1544 1544 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1545 1545 'mysql_charset': 'utf8'},
1546 1546 )
1547 1547 repository_id = Column('repository_id', String(250), primary_key=True)
1548 1548 repository_path = Column('repository_path', Text)
1549 1549 version = Column('version', Integer)
@@ -1,308 +1,308 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 logging
23 23
24 24 import formencode
25 25 from formencode import All
26 26
27 27 from pylons.i18n.translation import _
28 28
29 29 from rhodecode.model import validators as v
30 30 from rhodecode import BACKENDS
31 31
32 32 log = logging.getLogger(__name__)
33 33
34 34
35 35 class LoginForm(formencode.Schema):
36 36 allow_extra_fields = True
37 37 filter_extra_fields = True
38 38 username = v.UnicodeString(
39 39 strip=True,
40 40 min=1,
41 41 not_empty=True,
42 42 messages={
43 43 'empty': _(u'Please enter a login'),
44 44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 45 )
46 46
47 47 password = v.UnicodeString(
48 48 strip=False,
49 49 min=3,
50 50 not_empty=True,
51 51 messages={
52 52 'empty': _(u'Please enter a password'),
53 53 'tooShort': _(u'Enter %(min)i characters or more')}
54 54 )
55 55
56 56 remember = v.StringBoolean(if_missing=False)
57 57
58 58 chained_validators = [v.ValidAuth()]
59 59
60 60
61 61 def UserForm(edit=False, old_data={}):
62 62 class _UserForm(formencode.Schema):
63 63 allow_extra_fields = True
64 64 filter_extra_fields = True
65 65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 66 v.ValidUsername(edit, old_data))
67 67 if edit:
68 68 new_password = All(
69 69 v.UnicodeString(strip=False, min=6, not_empty=False)
70 70 )
71 71 password_confirmation = All(
72 72 v.ValidPassword(),
73 73 v.UnicodeString(strip=False, min=6, not_empty=False),
74 74 )
75 75 admin = v.StringBoolean(if_missing=False)
76 76 else:
77 77 password = All(
78 78 v.ValidPassword(),
79 79 v.UnicodeString(strip=False, min=6, not_empty=True)
80 80 )
81 81 password_confirmation = All(
82 82 v.ValidPassword(),
83 83 v.UnicodeString(strip=False, min=6, not_empty=False)
84 84 )
85 85
86 86 active = v.StringBoolean(if_missing=False)
87 87 name = v.UnicodeString(strip=True, min=1, not_empty=False)
88 88 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 89 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
90 90
91 91 chained_validators = [v.ValidPasswordsMatch()]
92 92
93 93 return _UserForm
94 94
95 95
96 96 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
97 97 class _UsersGroupForm(formencode.Schema):
98 98 allow_extra_fields = True
99 99 filter_extra_fields = True
100 100
101 101 users_group_name = All(
102 102 v.UnicodeString(strip=True, min=1, not_empty=True),
103 103 v.ValidUsersGroup(edit, old_data)
104 104 )
105 105
106 106 users_group_active = v.StringBoolean(if_missing=False)
107 107
108 108 if edit:
109 109 users_group_members = v.OneOf(
110 110 available_members, hideList=False, testValueList=True,
111 111 if_missing=None, not_empty=False
112 112 )
113 113
114 114 return _UsersGroupForm
115 115
116 116
117 117 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
118 118 class _ReposGroupForm(formencode.Schema):
119 119 allow_extra_fields = True
120 120 filter_extra_fields = False
121 121
122 122 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
123 123 v.SlugifyName())
124 124 group_description = v.UnicodeString(strip=True, min=1,
125 125 not_empty=True)
126 126 group_parent_id = v.OneOf(available_groups, hideList=False,
127 127 testValueList=True,
128 128 if_missing=None, not_empty=False)
129 129
130 130 chained_validators = [v.ValidReposGroup(edit, old_data),
131 131 v.ValidPerms('group')]
132 132
133 133 return _ReposGroupForm
134 134
135 135
136 136 def RegisterForm(edit=False, old_data={}):
137 137 class _RegisterForm(formencode.Schema):
138 138 allow_extra_fields = True
139 139 filter_extra_fields = True
140 140 username = All(
141 141 v.ValidUsername(edit, old_data),
142 142 v.UnicodeString(strip=True, min=1, not_empty=True)
143 143 )
144 144 password = All(
145 145 v.ValidPassword(),
146 146 v.UnicodeString(strip=False, min=6, not_empty=True)
147 147 )
148 148 password_confirmation = All(
149 149 v.ValidPassword(),
150 150 v.UnicodeString(strip=False, min=6, not_empty=True)
151 151 )
152 152 active = v.StringBoolean(if_missing=False)
153 153 name = v.UnicodeString(strip=True, min=1, not_empty=False)
154 154 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
155 155 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
156 156
157 157 chained_validators = [v.ValidPasswordsMatch()]
158 158
159 159 return _RegisterForm
160 160
161 161
162 162 def PasswordResetForm():
163 163 class _PasswordResetForm(formencode.Schema):
164 164 allow_extra_fields = True
165 165 filter_extra_fields = True
166 166 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
167 167 return _PasswordResetForm
168 168
169 169
170 170 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
171 171 repo_groups=[], landing_revs=[]):
172 172 class _RepoForm(formencode.Schema):
173 173 allow_extra_fields = True
174 174 filter_extra_fields = False
175 175 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
176 176 v.SlugifyName())
177 177 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
178 178 repo_group = v.OneOf(repo_groups, hideList=True)
179 179 repo_type = v.OneOf(supported_backends)
180 180 description = v.UnicodeString(strip=True, min=1, not_empty=False)
181 181 private = v.StringBoolean(if_missing=False)
182 182 enable_statistics = v.StringBoolean(if_missing=False)
183 183 enable_downloads = v.StringBoolean(if_missing=False)
184 184 landing_rev = v.OneOf(landing_revs, hideList=True)
185 185
186 186 if edit:
187 187 #this is repo owner
188 188 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
189 189
190 190 chained_validators = [v.ValidCloneUri(),
191 191 v.ValidRepoName(edit, old_data),
192 192 v.ValidPerms()]
193 193 return _RepoForm
194 194
195 195
196 196 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
197 197 repo_groups=[]):
198 198 class _RepoForkForm(formencode.Schema):
199 199 allow_extra_fields = True
200 200 filter_extra_fields = False
201 201 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
202 202 v.SlugifyName())
203 203 repo_group = v.OneOf(repo_groups, hideList=True)
204 204 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
205 205 description = v.UnicodeString(strip=True, min=1, not_empty=True)
206 206 private = v.StringBoolean(if_missing=False)
207 207 copy_permissions = v.StringBoolean(if_missing=False)
208 208 update_after_clone = v.StringBoolean(if_missing=False)
209 209 fork_parent_id = v.UnicodeString()
210 210 chained_validators = [v.ValidForkName(edit, old_data)]
211 211
212 212 return _RepoForkForm
213 213
214 214
215 215 def RepoSettingsForm(edit=False, old_data={},
216 216 supported_backends=BACKENDS.keys(), repo_groups=[],
217 217 landing_revs=[]):
218 218 class _RepoForm(formencode.Schema):
219 219 allow_extra_fields = True
220 220 filter_extra_fields = False
221 221 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
222 222 v.SlugifyName())
223 223 description = v.UnicodeString(strip=True, min=1, not_empty=True)
224 224 repo_group = v.OneOf(repo_groups, hideList=True)
225 225 private = v.StringBoolean(if_missing=False)
226 226 landing_rev = v.OneOf(landing_revs, hideList=True)
227 227 chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
228 228 v.ValidSettings()]
229 229 return _RepoForm
230 230
231 231
232 232 def ApplicationSettingsForm():
233 233 class _ApplicationSettingsForm(formencode.Schema):
234 234 allow_extra_fields = True
235 235 filter_extra_fields = False
236 236 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
237 237 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
238 238 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
239 239
240 240 return _ApplicationSettingsForm
241 241
242 242
243 243 def ApplicationUiSettingsForm():
244 244 class _ApplicationUiSettingsForm(formencode.Schema):
245 245 allow_extra_fields = True
246 246 filter_extra_fields = False
247 247 web_push_ssl = v.OneOf(['true', 'false'], if_missing='false')
248 248 paths_root_path = All(
249 249 v.ValidPath(),
250 250 v.UnicodeString(strip=True, min=1, not_empty=True)
251 251 )
252 252 hooks_changegroup_update = v.OneOf(['True', 'False'],
253 253 if_missing=False)
254 254 hooks_changegroup_repo_size = v.OneOf(['True', 'False'],
255 255 if_missing=False)
256 256 hooks_changegroup_push_logger = v.OneOf(['True', 'False'],
257 257 if_missing=False)
258 258 hooks_preoutgoing_pull_logger = v.OneOf(['True', 'False'],
259 259 if_missing=False)
260 260
261 261 return _ApplicationUiSettingsForm
262 262
263 263
264 264 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
265 265 class _DefaultPermissionsForm(formencode.Schema):
266 266 allow_extra_fields = True
267 267 filter_extra_fields = True
268 268 overwrite_default = v.StringBoolean(if_missing=False)
269 269 anonymous = v.OneOf(['True', 'False'], if_missing=False)
270 270 default_perm = v.OneOf(perms_choices)
271 271 default_register = v.OneOf(register_choices)
272 272 default_create = v.OneOf(create_choices)
273 273
274 274 return _DefaultPermissionsForm
275 275
276 276
277 277 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
278 278 tls_kind_choices):
279 279 class _LdapSettingsForm(formencode.Schema):
280 280 allow_extra_fields = True
281 281 filter_extra_fields = True
282 282 #pre_validators = [LdapLibValidator]
283 283 ldap_active = v.StringBoolean(if_missing=False)
284 284 ldap_host = v.UnicodeString(strip=True,)
285 285 ldap_port = v.Number(strip=True,)
286 286 ldap_tls_kind = v.OneOf(tls_kind_choices)
287 287 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
288 288 ldap_dn_user = v.UnicodeString(strip=True,)
289 289 ldap_dn_pass = v.UnicodeString(strip=True,)
290 290 ldap_base_dn = v.UnicodeString(strip=True,)
291 291 ldap_filter = v.UnicodeString(strip=True,)
292 292 ldap_search_scope = v.OneOf(search_scope_choices)
293 293 ldap_attr_login = All(
294 294 v.AttrLoginValidator(),
295 295 v.UnicodeString(strip=True,)
296 296 )
297 297 ldap_attr_firstname = v.UnicodeString(strip=True,)
298 298 ldap_attr_lastname = v.UnicodeString(strip=True,)
299 299 ldap_attr_email = v.UnicodeString(strip=True,)
300 300
301 301 return _LdapSettingsForm
302 302
303 303
304 304 def UserExtraEmailForm():
305 305 class _UserExtraEmailForm(formencode.Schema):
306 306 email = All(v.UniqSystemEmail(), v.Email)
307 307
308 return _UserExtraEmailForm No newline at end of file
308 return _UserExtraEmailForm
General Comments 0
You need to be logged in to leave comments. Login now