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