##// END OF EJS Templates
Migration upgrades cache for lightweight dashboard...
marcink -
r3148:b3198497 beta
parent child Browse files
Show More
@@ -0,0 +1,28 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.model.db_1_4_0
4 ~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Database Models for RhodeCode <=1.5.X
7
8 :created_on: Apr 08, 2010
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26 #TODO: replace that will db.py content after 1.6 Release
27
28 from rhodecode.model.db import *
@@ -164,8 +164,8 b' class DbManage(object):'
164 164
165 165 def step_0(self):
166 166 # step 0 is the schema upgrade, and than follow proper upgrades
167 notify('attempting to do database upgrade to version %s' \
168 % __dbversion__)
167 notify('attempting to do database upgrade from '
168 'version %s to version %s' %(curr_version, __dbversion__))
169 169 api.upgrade(db_uri, repository_path, __dbversion__)
170 170 notify('Schema upgrade completed')
171 171
This diff has been collapsed as it changes many lines, (1814 lines changed) Show them Hide them
@@ -1,9 +1,9 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 rhodecode.model.db_1_4_0
3 rhodecode.model.db_1_5_0
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 Database Models for RhodeCode <=1.5.X
6 Database Models for RhodeCode <=1.5.2
7 7
8 8 :created_on: Apr 08, 2010
9 9 :author: marcink
@@ -23,6 +23,1812 b''
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 #TODO: replace that will db.py content after 1.6 Release
26 import os
27 import logging
28 import datetime
29 import traceback
30 import hashlib
31 import time
32 from collections import defaultdict
33
34 from sqlalchemy import *
35 from sqlalchemy.ext.hybrid import hybrid_property
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
37 from sqlalchemy.exc import DatabaseError
38 from beaker.cache import cache_region, region_invalidate
39 from webob.exc import HTTPNotFound
40
41 from pylons.i18n.translation import lazy_ugettext as _
42
43 from rhodecode.lib.vcs import get_backend
44 from rhodecode.lib.vcs.utils.helpers import get_scm
45 from rhodecode.lib.vcs.exceptions import VCSError
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47
48 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
49 safe_unicode, remove_suffix, remove_prefix
50 from rhodecode.lib.compat import json
51 from rhodecode.lib.caching_query import FromCache
52
53 from rhodecode.model.meta import Base, Session
54
55 URL_SEP = '/'
56 log = logging.getLogger(__name__)
57
58 #==============================================================================
59 # BASE CLASSES
60 #==============================================================================
61
62 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
63
64
65 class BaseModel(object):
66 """
67 Base Model for all classess
68 """
69
70 @classmethod
71 def _get_keys(cls):
72 """return column names for this model """
73 return class_mapper(cls).c.keys()
74
75 def get_dict(self):
76 """
77 return dict with keys and values corresponding
78 to this model data """
79
80 d = {}
81 for k in self._get_keys():
82 d[k] = getattr(self, k)
83
84 # also use __json__() if present to get additional fields
85 _json_attr = getattr(self, '__json__', None)
86 if _json_attr:
87 # update with attributes from __json__
88 if callable(_json_attr):
89 _json_attr = _json_attr()
90 for k, val in _json_attr.iteritems():
91 d[k] = val
92 return d
93
94 def get_appstruct(self):
95 """return list with keys and values tupples corresponding
96 to this model data """
97
98 l = []
99 for k in self._get_keys():
100 l.append((k, getattr(self, k),))
101 return l
102
103 def populate_obj(self, populate_dict):
104 """populate model with data from given populate_dict"""
105
106 for k in self._get_keys():
107 if k in populate_dict:
108 setattr(self, k, populate_dict[k])
109
110 @classmethod
111 def query(cls):
112 return Session().query(cls)
113
114 @classmethod
115 def get(cls, id_):
116 if id_:
117 return cls.query().get(id_)
118
119 @classmethod
120 def get_or_404(cls, id_):
121 try:
122 id_ = int(id_)
123 except (TypeError, ValueError):
124 raise HTTPNotFound
125
126 res = cls.query().get(id_)
127 if not res:
128 raise HTTPNotFound
129 return res
130
131 @classmethod
132 def getAll(cls):
133 return cls.query().all()
134
135 @classmethod
136 def delete(cls, id_):
137 obj = cls.query().get(id_)
138 Session().delete(obj)
139
140 def __repr__(self):
141 if hasattr(self, '__unicode__'):
142 # python repr needs to return str
143 return safe_str(self.__unicode__())
144 return '<DB:%s>' % (self.__class__.__name__)
145
146
147 class RhodeCodeSetting(Base, BaseModel):
148 __tablename__ = 'rhodecode_settings'
149 __table_args__ = (
150 UniqueConstraint('app_settings_name'),
151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 'mysql_charset': 'utf8'}
153 )
154 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
156 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
157
158 def __init__(self, k='', v=''):
159 self.app_settings_name = k
160 self.app_settings_value = v
161
162 @validates('_app_settings_value')
163 def validate_settings_value(self, key, val):
164 assert type(val) == unicode
165 return val
166
167 @hybrid_property
168 def app_settings_value(self):
169 v = self._app_settings_value
170 if self.app_settings_name in ["ldap_active",
171 "default_repo_enable_statistics",
172 "default_repo_enable_locking",
173 "default_repo_private",
174 "default_repo_enable_downloads"]:
175 v = str2bool(v)
176 return v
177
178 @app_settings_value.setter
179 def app_settings_value(self, val):
180 """
181 Setter that will always make sure we use unicode in app_settings_value
182
183 :param val:
184 """
185 self._app_settings_value = safe_unicode(val)
186
187 def __unicode__(self):
188 return u"<%s('%s:%s')>" % (
189 self.__class__.__name__,
190 self.app_settings_name, self.app_settings_value
191 )
192
193 @classmethod
194 def get_by_name(cls, key):
195 return cls.query()\
196 .filter(cls.app_settings_name == key).scalar()
197
198 @classmethod
199 def get_by_name_or_create(cls, key):
200 res = cls.get_by_name(key)
201 if not res:
202 res = cls(key)
203 return res
204
205 @classmethod
206 def get_app_settings(cls, cache=False):
207
208 ret = cls.query()
209
210 if cache:
211 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
212
213 if not ret:
214 raise Exception('Could not get application settings !')
215 settings = {}
216 for each in ret:
217 settings['rhodecode_' + each.app_settings_name] = \
218 each.app_settings_value
219
220 return settings
221
222 @classmethod
223 def get_ldap_settings(cls, cache=False):
224 ret = cls.query()\
225 .filter(cls.app_settings_name.startswith('ldap_')).all()
226 fd = {}
227 for row in ret:
228 fd.update({row.app_settings_name: row.app_settings_value})
229
230 return fd
231
232 @classmethod
233 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
234 ret = cls.query()\
235 .filter(cls.app_settings_name.startswith('default_')).all()
236 fd = {}
237 for row in ret:
238 key = row.app_settings_name
239 if strip_prefix:
240 key = remove_prefix(key, prefix='default_')
241 fd.update({key: row.app_settings_value})
242
243 return fd
244
245
246 class RhodeCodeUi(Base, BaseModel):
247 __tablename__ = 'rhodecode_ui'
248 __table_args__ = (
249 UniqueConstraint('ui_key'),
250 {'extend_existing': True, 'mysql_engine': 'InnoDB',
251 'mysql_charset': 'utf8'}
252 )
253
254 HOOK_UPDATE = 'changegroup.update'
255 HOOK_REPO_SIZE = 'changegroup.repo_size'
256 HOOK_PUSH = 'changegroup.push_logger'
257 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
258 HOOK_PULL = 'outgoing.pull_logger'
259 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
260
261 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
262 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
263 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
264 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
265 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
266
267 @classmethod
268 def get_by_key(cls, key):
269 return cls.query().filter(cls.ui_key == key).scalar()
270
271 @classmethod
272 def get_builtin_hooks(cls):
273 q = cls.query()
274 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
275 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
276 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
277 return q.all()
278
279 @classmethod
280 def get_custom_hooks(cls):
281 q = cls.query()
282 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
283 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
284 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
285 q = q.filter(cls.ui_section == 'hooks')
286 return q.all()
287
288 @classmethod
289 def get_repos_location(cls):
290 return cls.get_by_key('/').ui_value
291
292 @classmethod
293 def create_or_update_hook(cls, key, val):
294 new_ui = cls.get_by_key(key) or cls()
295 new_ui.ui_section = 'hooks'
296 new_ui.ui_active = True
297 new_ui.ui_key = key
298 new_ui.ui_value = val
299
300 Session().add(new_ui)
301
302 def __repr__(self):
303 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
304 self.ui_value)
305
306
307 class User(Base, BaseModel):
308 __tablename__ = 'users'
309 __table_args__ = (
310 UniqueConstraint('username'), UniqueConstraint('email'),
311 Index('u_username_idx', 'username'),
312 Index('u_email_idx', 'email'),
313 {'extend_existing': True, 'mysql_engine': 'InnoDB',
314 'mysql_charset': 'utf8'}
315 )
316 DEFAULT_USER = 'default'
317 DEFAULT_PERMISSIONS = [
318 'hg.register.manual_activate', 'hg.create.repository',
319 'hg.fork.repository', 'repository.read', 'group.read'
320 ]
321 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
322 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
323 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
324 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
325 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
326 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
328 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
329 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
330 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
332 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
333
334 user_log = relationship('UserLog')
335 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
336
337 repositories = relationship('Repository')
338 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
339 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
340
341 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
342 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
343
344 group_member = relationship('UsersGroupMember', cascade='all')
345
346 notifications = relationship('UserNotification', cascade='all')
347 # notifications assigned to this user
348 user_created_notifications = relationship('Notification', cascade='all')
349 # comments created by this user
350 user_comments = relationship('ChangesetComment', cascade='all')
351 #extra emails for this user
352 user_emails = relationship('UserEmailMap', cascade='all')
353
354 @hybrid_property
355 def email(self):
356 return self._email
357
358 @email.setter
359 def email(self, val):
360 self._email = val.lower() if val else None
361
362 @property
363 def firstname(self):
364 # alias for future
365 return self.name
366
367 @property
368 def emails(self):
369 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
370 return [self.email] + [x.email for x in other]
371
372 @property
373 def username_and_name(self):
374 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
375
376 @property
377 def full_name(self):
378 return '%s %s' % (self.firstname, self.lastname)
379
380 @property
381 def full_name_or_username(self):
382 return ('%s %s' % (self.firstname, self.lastname)
383 if (self.firstname and self.lastname) else self.username)
384
385 @property
386 def full_contact(self):
387 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
388
389 @property
390 def short_contact(self):
391 return '%s %s' % (self.firstname, self.lastname)
392
393 @property
394 def is_admin(self):
395 return self.admin
396
397 def __unicode__(self):
398 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
399 self.user_id, self.username)
400
401 @classmethod
402 def get_by_username(cls, username, case_insensitive=False, cache=False):
403 if case_insensitive:
404 q = cls.query().filter(cls.username.ilike(username))
405 else:
406 q = cls.query().filter(cls.username == username)
407
408 if cache:
409 q = q.options(FromCache(
410 "sql_cache_short",
411 "get_user_%s" % _hash_key(username)
412 )
413 )
414 return q.scalar()
415
416 @classmethod
417 def get_by_api_key(cls, api_key, cache=False):
418 q = cls.query().filter(cls.api_key == api_key)
419
420 if cache:
421 q = q.options(FromCache("sql_cache_short",
422 "get_api_key_%s" % api_key))
423 return q.scalar()
424
425 @classmethod
426 def get_by_email(cls, email, case_insensitive=False, cache=False):
427 if case_insensitive:
428 q = cls.query().filter(cls.email.ilike(email))
429 else:
430 q = cls.query().filter(cls.email == email)
431
432 if cache:
433 q = q.options(FromCache("sql_cache_short",
434 "get_email_key_%s" % email))
435
436 ret = q.scalar()
437 if ret is None:
438 q = UserEmailMap.query()
439 # try fetching in alternate email map
440 if case_insensitive:
441 q = q.filter(UserEmailMap.email.ilike(email))
442 else:
443 q = q.filter(UserEmailMap.email == email)
444 q = q.options(joinedload(UserEmailMap.user))
445 if cache:
446 q = q.options(FromCache("sql_cache_short",
447 "get_email_map_key_%s" % email))
448 ret = getattr(q.scalar(), 'user', None)
449
450 return ret
451
452 def update_lastlogin(self):
453 """Update user lastlogin"""
454 self.last_login = datetime.datetime.now()
455 Session().add(self)
456 log.debug('updated user %s lastlogin' % self.username)
457
458 def get_api_data(self):
459 """
460 Common function for generating user related data for API
461 """
462 user = self
463 data = dict(
464 user_id=user.user_id,
465 username=user.username,
466 firstname=user.name,
467 lastname=user.lastname,
468 email=user.email,
469 emails=user.emails,
470 api_key=user.api_key,
471 active=user.active,
472 admin=user.admin,
473 ldap_dn=user.ldap_dn,
474 last_login=user.last_login,
475 )
476 return data
477
478 def __json__(self):
479 data = dict(
480 full_name=self.full_name,
481 full_name_or_username=self.full_name_or_username,
482 short_contact=self.short_contact,
483 full_contact=self.full_contact
484 )
485 data.update(self.get_api_data())
486 return data
487
488
489 class UserEmailMap(Base, BaseModel):
490 __tablename__ = 'user_email_map'
491 __table_args__ = (
492 Index('uem_email_idx', 'email'),
493 UniqueConstraint('email'),
494 {'extend_existing': True, 'mysql_engine': 'InnoDB',
495 'mysql_charset': 'utf8'}
496 )
497 __mapper_args__ = {}
498
499 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
500 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
501 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
502 user = relationship('User', lazy='joined')
503
504 @validates('_email')
505 def validate_email(self, key, email):
506 # check if this email is not main one
507 main_email = Session().query(User).filter(User.email == email).scalar()
508 if main_email is not None:
509 raise AttributeError('email %s is present is user table' % email)
510 return email
511
512 @hybrid_property
513 def email(self):
514 return self._email
515
516 @email.setter
517 def email(self, val):
518 self._email = val.lower() if val else None
519
520
521 class UserLog(Base, BaseModel):
522 __tablename__ = 'user_logs'
523 __table_args__ = (
524 {'extend_existing': True, 'mysql_engine': 'InnoDB',
525 'mysql_charset': 'utf8'},
526 )
527 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
528 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
529 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
530 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
531 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
532 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
533 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
534 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
535
536 @property
537 def action_as_day(self):
538 return datetime.date(*self.action_date.timetuple()[:3])
539
540 user = relationship('User')
541 repository = relationship('Repository', cascade='')
542
543
544 class UsersGroup(Base, BaseModel):
545 __tablename__ = 'users_groups'
546 __table_args__ = (
547 {'extend_existing': True, 'mysql_engine': 'InnoDB',
548 'mysql_charset': 'utf8'},
549 )
550
551 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
552 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
553 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
554 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
555
556 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
557 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
558 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
559
560 def __unicode__(self):
561 return u'<userGroup(%s)>' % (self.users_group_name)
562
563 @classmethod
564 def get_by_group_name(cls, group_name, cache=False,
565 case_insensitive=False):
566 if case_insensitive:
567 q = cls.query().filter(cls.users_group_name.ilike(group_name))
568 else:
569 q = cls.query().filter(cls.users_group_name == group_name)
570 if cache:
571 q = q.options(FromCache(
572 "sql_cache_short",
573 "get_user_%s" % _hash_key(group_name)
574 )
575 )
576 return q.scalar()
577
578 @classmethod
579 def get(cls, users_group_id, cache=False):
580 users_group = cls.query()
581 if cache:
582 users_group = users_group.options(FromCache("sql_cache_short",
583 "get_users_group_%s" % users_group_id))
584 return users_group.get(users_group_id)
585
586 def get_api_data(self):
587 users_group = self
588
589 data = dict(
590 users_group_id=users_group.users_group_id,
591 group_name=users_group.users_group_name,
592 active=users_group.users_group_active,
593 )
594
595 return data
596
597
598 class UsersGroupMember(Base, BaseModel):
599 __tablename__ = 'users_groups_members'
600 __table_args__ = (
601 {'extend_existing': True, 'mysql_engine': 'InnoDB',
602 'mysql_charset': 'utf8'},
603 )
604
605 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
606 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
607 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
608
609 user = relationship('User', lazy='joined')
610 users_group = relationship('UsersGroup')
611
612 def __init__(self, gr_id='', u_id=''):
613 self.users_group_id = gr_id
614 self.user_id = u_id
615
616
617 class Repository(Base, BaseModel):
618 __tablename__ = 'repositories'
619 __table_args__ = (
620 UniqueConstraint('repo_name'),
621 Index('r_repo_name_idx', 'repo_name'),
622 {'extend_existing': True, 'mysql_engine': 'InnoDB',
623 'mysql_charset': 'utf8'},
624 )
625
626 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
627 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
628 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
629 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
630 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
631 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
632 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
633 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
634 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
635 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
636 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
637 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
638 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
639 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
640
641 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
642 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
643
644 user = relationship('User')
645 fork = relationship('Repository', remote_side=repo_id)
646 group = relationship('RepoGroup')
647 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
648 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
649 stats = relationship('Statistics', cascade='all', uselist=False)
650
651 followers = relationship('UserFollowing',
652 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
653 cascade='all')
654
655 logs = relationship('UserLog')
656 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
657
658 pull_requests_org = relationship('PullRequest',
659 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
660 cascade="all, delete, delete-orphan")
661
662 pull_requests_other = relationship('PullRequest',
663 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
664 cascade="all, delete, delete-orphan")
665
666 def __unicode__(self):
667 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
668 self.repo_name)
669
670 @hybrid_property
671 def locked(self):
672 # always should return [user_id, timelocked]
673 if self._locked:
674 _lock_info = self._locked.split(':')
675 return int(_lock_info[0]), _lock_info[1]
676 return [None, None]
677
678 @locked.setter
679 def locked(self, val):
680 if val and isinstance(val, (list, tuple)):
681 self._locked = ':'.join(map(str, val))
682 else:
683 self._locked = None
684
685 @classmethod
686 def url_sep(cls):
687 return URL_SEP
688
689 @classmethod
690 def get_by_repo_name(cls, repo_name):
691 q = Session().query(cls).filter(cls.repo_name == repo_name)
692 q = q.options(joinedload(Repository.fork))\
693 .options(joinedload(Repository.user))\
694 .options(joinedload(Repository.group))
695 return q.scalar()
696
697 @classmethod
698 def get_by_full_path(cls, repo_full_path):
699 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
700 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
701
702 @classmethod
703 def get_repo_forks(cls, repo_id):
704 return cls.query().filter(Repository.fork_id == repo_id)
705
706 @classmethod
707 def base_path(cls):
708 """
709 Returns base path when all repos are stored
710
711 :param cls:
712 """
713 q = Session().query(RhodeCodeUi)\
714 .filter(RhodeCodeUi.ui_key == cls.url_sep())
715 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
716 return q.one().ui_value
717
718 @property
719 def forks(self):
720 """
721 Return forks of this repo
722 """
723 return Repository.get_repo_forks(self.repo_id)
724
725 @property
726 def parent(self):
727 """
728 Returns fork parent
729 """
730 return self.fork
731
732 @property
733 def just_name(self):
734 return self.repo_name.split(Repository.url_sep())[-1]
735
736 @property
737 def groups_with_parents(self):
738 groups = []
739 if self.group is None:
740 return groups
741
742 cur_gr = self.group
743 groups.insert(0, cur_gr)
744 while 1:
745 gr = getattr(cur_gr, 'parent_group', None)
746 cur_gr = cur_gr.parent_group
747 if gr is None:
748 break
749 groups.insert(0, gr)
750
751 return groups
752
753 @property
754 def groups_and_repo(self):
755 return self.groups_with_parents, self.just_name
756
757 @LazyProperty
758 def repo_path(self):
759 """
760 Returns base full path for that repository means where it actually
761 exists on a filesystem
762 """
763 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
764 Repository.url_sep())
765 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
766 return q.one().ui_value
767
768 @property
769 def repo_full_path(self):
770 p = [self.repo_path]
771 # we need to split the name by / since this is how we store the
772 # names in the database, but that eventually needs to be converted
773 # into a valid system path
774 p += self.repo_name.split(Repository.url_sep())
775 return os.path.join(*p)
776
777 @property
778 def cache_keys(self):
779 """
780 Returns associated cache keys for that repo
781 """
782 return CacheInvalidation.query()\
783 .filter(CacheInvalidation.cache_args == self.repo_name)\
784 .order_by(CacheInvalidation.cache_key)\
785 .all()
786
787 def get_new_name(self, repo_name):
788 """
789 returns new full repository name based on assigned group and new new
790
791 :param group_name:
792 """
793 path_prefix = self.group.full_path_splitted if self.group else []
794 return Repository.url_sep().join(path_prefix + [repo_name])
795
796 @property
797 def _ui(self):
798 """
799 Creates an db based ui object for this repository
800 """
801 from rhodecode.lib.utils import make_ui
802 return make_ui('db', clear_session=False)
803
804 @classmethod
805 def inject_ui(cls, repo, extras={}):
806 from rhodecode.lib.vcs.backends.hg import MercurialRepository
807 from rhodecode.lib.vcs.backends.git import GitRepository
808 required = (MercurialRepository, GitRepository)
809 if not isinstance(repo, required):
810 raise Exception('repo must be instance of %s' % required)
811
812 # inject ui extra param to log this action via push logger
813 for k, v in extras.items():
814 repo._repo.ui.setconfig('rhodecode_extras', k, v)
815
816 @classmethod
817 def is_valid(cls, repo_name):
818 """
819 returns True if given repo name is a valid filesystem repository
820
821 :param cls:
822 :param repo_name:
823 """
824 from rhodecode.lib.utils import is_valid_repo
825
826 return is_valid_repo(repo_name, cls.base_path())
827
828 def get_api_data(self):
829 """
830 Common function for generating repo api data
831
832 """
833 repo = self
834 data = dict(
835 repo_id=repo.repo_id,
836 repo_name=repo.repo_name,
837 repo_type=repo.repo_type,
838 clone_uri=repo.clone_uri,
839 private=repo.private,
840 created_on=repo.created_on,
841 description=repo.description,
842 landing_rev=repo.landing_rev,
843 owner=repo.user.username,
844 fork_of=repo.fork.repo_name if repo.fork else None
845 )
846
847 return data
848
849 @classmethod
850 def lock(cls, repo, user_id):
851 repo.locked = [user_id, time.time()]
852 Session().add(repo)
853 Session().commit()
854
855 @classmethod
856 def unlock(cls, repo):
857 repo.locked = None
858 Session().add(repo)
859 Session().commit()
860
861 @property
862 def last_db_change(self):
863 return self.updated_on
864
865 #==========================================================================
866 # SCM PROPERTIES
867 #==========================================================================
868
869 def get_changeset(self, rev=None):
870 return get_changeset_safe(self.scm_instance, rev)
871
872 def get_landing_changeset(self):
873 """
874 Returns landing changeset, or if that doesn't exist returns the tip
875 """
876 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
877 return cs
878
879 def update_last_change(self, last_change=None):
880 if last_change is None:
881 last_change = datetime.datetime.now()
882 if self.updated_on is None or self.updated_on != last_change:
883 log.debug('updated repo %s with new date %s' % (self, last_change))
884 self.updated_on = last_change
885 Session().add(self)
886 Session().commit()
887
888 @property
889 def tip(self):
890 return self.get_changeset('tip')
891
892 @property
893 def author(self):
894 return self.tip.author
895
896 @property
897 def last_change(self):
898 return self.scm_instance.last_change
899
900 def get_comments(self, revisions=None):
901 """
902 Returns comments for this repository grouped by revisions
903
904 :param revisions: filter query by revisions only
905 """
906 cmts = ChangesetComment.query()\
907 .filter(ChangesetComment.repo == self)
908 if revisions:
909 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
910 grouped = defaultdict(list)
911 for cmt in cmts.all():
912 grouped[cmt.revision].append(cmt)
913 return grouped
914
915 def statuses(self, revisions=None):
916 """
917 Returns statuses for this repository
918
919 :param revisions: list of revisions to get statuses for
920 :type revisions: list
921 """
922
923 statuses = ChangesetStatus.query()\
924 .filter(ChangesetStatus.repo == self)\
925 .filter(ChangesetStatus.version == 0)
926 if revisions:
927 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
928 grouped = {}
27 929
28 from rhodecode.model.db import *
930 #maybe we have open new pullrequest without a status ?
931 stat = ChangesetStatus.STATUS_UNDER_REVIEW
932 status_lbl = ChangesetStatus.get_status_lbl(stat)
933 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
934 for rev in pr.revisions:
935 pr_id = pr.pull_request_id
936 pr_repo = pr.other_repo.repo_name
937 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
938
939 for stat in statuses.all():
940 pr_id = pr_repo = None
941 if stat.pull_request:
942 pr_id = stat.pull_request.pull_request_id
943 pr_repo = stat.pull_request.other_repo.repo_name
944 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
945 pr_id, pr_repo]
946 return grouped
947
948 #==========================================================================
949 # SCM CACHE INSTANCE
950 #==========================================================================
951
952 @property
953 def invalidate(self):
954 return CacheInvalidation.invalidate(self.repo_name)
955
956 def set_invalidate(self):
957 """
958 set a cache for invalidation for this instance
959 """
960 CacheInvalidation.set_invalidate(repo_name=self.repo_name)
961
962 @LazyProperty
963 def scm_instance(self):
964 import rhodecode
965 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
966 if full_cache:
967 return self.scm_instance_cached()
968 return self.__get_instance()
969
970 def scm_instance_cached(self, cache_map=None):
971 @cache_region('long_term')
972 def _c(repo_name):
973 return self.__get_instance()
974 rn = self.repo_name
975 log.debug('Getting cached instance of repo')
976
977 if cache_map:
978 # get using prefilled cache_map
979 invalidate_repo = cache_map[self.repo_name]
980 if invalidate_repo:
981 invalidate_repo = (None if invalidate_repo.cache_active
982 else invalidate_repo)
983 else:
984 # get from invalidate
985 invalidate_repo = self.invalidate
986
987 if invalidate_repo is not None:
988 region_invalidate(_c, None, rn)
989 # update our cache
990 CacheInvalidation.set_valid(invalidate_repo.cache_key)
991 return _c(rn)
992
993 def __get_instance(self):
994 repo_full_path = self.repo_full_path
995 try:
996 alias = get_scm(repo_full_path)[0]
997 log.debug('Creating instance of %s repository' % alias)
998 backend = get_backend(alias)
999 except VCSError:
1000 log.error(traceback.format_exc())
1001 log.error('Perhaps this repository is in db and not in '
1002 'filesystem run rescan repositories with '
1003 '"destroy old data " option from admin panel')
1004 return
1005
1006 if alias == 'hg':
1007
1008 repo = backend(safe_str(repo_full_path), create=False,
1009 baseui=self._ui)
1010 # skip hidden web repository
1011 if repo._get_hidden():
1012 return
1013 else:
1014 repo = backend(repo_full_path, create=False)
1015
1016 return repo
1017
1018
1019 class RepoGroup(Base, BaseModel):
1020 __tablename__ = 'groups'
1021 __table_args__ = (
1022 UniqueConstraint('group_name', 'group_parent_id'),
1023 CheckConstraint('group_id != group_parent_id'),
1024 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1025 'mysql_charset': 'utf8'},
1026 )
1027 __mapper_args__ = {'order_by': 'group_name'}
1028
1029 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1030 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1031 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1032 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1033 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1034
1035 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1036 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
1037
1038 parent_group = relationship('RepoGroup', remote_side=group_id)
1039
1040 def __init__(self, group_name='', parent_group=None):
1041 self.group_name = group_name
1042 self.parent_group = parent_group
1043
1044 def __unicode__(self):
1045 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
1046 self.group_name)
1047
1048 @classmethod
1049 def groups_choices(cls, check_perms=False):
1050 from webhelpers.html import literal as _literal
1051 from rhodecode.model.scm import ScmModel
1052 groups = cls.query().all()
1053 if check_perms:
1054 #filter group user have access to, it's done
1055 #magically inside ScmModel based on current user
1056 groups = ScmModel().get_repos_groups(groups)
1057 repo_groups = [('', '')]
1058 sep = ' &raquo; '
1059 _name = lambda k: _literal(sep.join(k))
1060
1061 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1062 for x in groups])
1063
1064 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1065 return repo_groups
1066
1067 @classmethod
1068 def url_sep(cls):
1069 return URL_SEP
1070
1071 @classmethod
1072 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1073 if case_insensitive:
1074 gr = cls.query()\
1075 .filter(cls.group_name.ilike(group_name))
1076 else:
1077 gr = cls.query()\
1078 .filter(cls.group_name == group_name)
1079 if cache:
1080 gr = gr.options(FromCache(
1081 "sql_cache_short",
1082 "get_group_%s" % _hash_key(group_name)
1083 )
1084 )
1085 return gr.scalar()
1086
1087 @property
1088 def parents(self):
1089 parents_recursion_limit = 5
1090 groups = []
1091 if self.parent_group is None:
1092 return groups
1093 cur_gr = self.parent_group
1094 groups.insert(0, cur_gr)
1095 cnt = 0
1096 while 1:
1097 cnt += 1
1098 gr = getattr(cur_gr, 'parent_group', None)
1099 cur_gr = cur_gr.parent_group
1100 if gr is None:
1101 break
1102 if cnt == parents_recursion_limit:
1103 # this will prevent accidental infinit loops
1104 log.error('group nested more than %s' %
1105 parents_recursion_limit)
1106 break
1107
1108 groups.insert(0, gr)
1109 return groups
1110
1111 @property
1112 def children(self):
1113 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1114
1115 @property
1116 def name(self):
1117 return self.group_name.split(RepoGroup.url_sep())[-1]
1118
1119 @property
1120 def full_path(self):
1121 return self.group_name
1122
1123 @property
1124 def full_path_splitted(self):
1125 return self.group_name.split(RepoGroup.url_sep())
1126
1127 @property
1128 def repositories(self):
1129 return Repository.query()\
1130 .filter(Repository.group == self)\
1131 .order_by(Repository.repo_name)
1132
1133 @property
1134 def repositories_recursive_count(self):
1135 cnt = self.repositories.count()
1136
1137 def children_count(group):
1138 cnt = 0
1139 for child in group.children:
1140 cnt += child.repositories.count()
1141 cnt += children_count(child)
1142 return cnt
1143
1144 return cnt + children_count(self)
1145
1146 def recursive_groups_and_repos(self):
1147 """
1148 Recursive return all groups, with repositories in those groups
1149 """
1150 all_ = []
1151
1152 def _get_members(root_gr):
1153 for r in root_gr.repositories:
1154 all_.append(r)
1155 childs = root_gr.children.all()
1156 if childs:
1157 for gr in childs:
1158 all_.append(gr)
1159 _get_members(gr)
1160
1161 _get_members(self)
1162 return [self] + all_
1163
1164 def get_new_name(self, group_name):
1165 """
1166 returns new full group name based on parent and new name
1167
1168 :param group_name:
1169 """
1170 path_prefix = (self.parent_group.full_path_splitted if
1171 self.parent_group else [])
1172 return RepoGroup.url_sep().join(path_prefix + [group_name])
1173
1174
1175 class Permission(Base, BaseModel):
1176 __tablename__ = 'permissions'
1177 __table_args__ = (
1178 Index('p_perm_name_idx', 'permission_name'),
1179 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1180 'mysql_charset': 'utf8'},
1181 )
1182 PERMS = [
1183 ('repository.none', _('Repository no access')),
1184 ('repository.read', _('Repository read access')),
1185 ('repository.write', _('Repository write access')),
1186 ('repository.admin', _('Repository admin access')),
1187
1188 ('group.none', _('Repositories Group no access')),
1189 ('group.read', _('Repositories Group read access')),
1190 ('group.write', _('Repositories Group write access')),
1191 ('group.admin', _('Repositories Group admin access')),
1192
1193 ('hg.admin', _('RhodeCode Administrator')),
1194 ('hg.create.none', _('Repository creation disabled')),
1195 ('hg.create.repository', _('Repository creation enabled')),
1196 ('hg.fork.none', _('Repository forking disabled')),
1197 ('hg.fork.repository', _('Repository forking enabled')),
1198 ('hg.register.none', _('Register disabled')),
1199 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1200 'with manual activation')),
1201
1202 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1203 'with auto activation')),
1204 ]
1205
1206 # defines which permissions are more important higher the more important
1207 PERM_WEIGHTS = {
1208 'repository.none': 0,
1209 'repository.read': 1,
1210 'repository.write': 3,
1211 'repository.admin': 4,
1212
1213 'group.none': 0,
1214 'group.read': 1,
1215 'group.write': 3,
1216 'group.admin': 4,
1217
1218 'hg.fork.none': 0,
1219 'hg.fork.repository': 1,
1220 'hg.create.none': 0,
1221 'hg.create.repository':1
1222 }
1223
1224 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1225 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1226 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1227
1228 def __unicode__(self):
1229 return u"<%s('%s:%s')>" % (
1230 self.__class__.__name__, self.permission_id, self.permission_name
1231 )
1232
1233 @classmethod
1234 def get_by_key(cls, key):
1235 return cls.query().filter(cls.permission_name == key).scalar()
1236
1237 @classmethod
1238 def get_default_perms(cls, default_user_id):
1239 q = Session().query(UserRepoToPerm, Repository, cls)\
1240 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1241 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1242 .filter(UserRepoToPerm.user_id == default_user_id)
1243
1244 return q.all()
1245
1246 @classmethod
1247 def get_default_group_perms(cls, default_user_id):
1248 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1249 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1250 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1251 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1252
1253 return q.all()
1254
1255
1256 class UserRepoToPerm(Base, BaseModel):
1257 __tablename__ = 'repo_to_perm'
1258 __table_args__ = (
1259 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1260 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1261 'mysql_charset': 'utf8'}
1262 )
1263 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1264 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1265 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1266 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1267
1268 user = relationship('User')
1269 repository = relationship('Repository')
1270 permission = relationship('Permission')
1271
1272 @classmethod
1273 def create(cls, user, repository, permission):
1274 n = cls()
1275 n.user = user
1276 n.repository = repository
1277 n.permission = permission
1278 Session().add(n)
1279 return n
1280
1281 def __unicode__(self):
1282 return u'<user:%s => %s >' % (self.user, self.repository)
1283
1284
1285 class UserToPerm(Base, BaseModel):
1286 __tablename__ = 'user_to_perm'
1287 __table_args__ = (
1288 UniqueConstraint('user_id', 'permission_id'),
1289 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1290 'mysql_charset': 'utf8'}
1291 )
1292 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1293 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1294 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1295
1296 user = relationship('User')
1297 permission = relationship('Permission', lazy='joined')
1298
1299
1300 class UsersGroupRepoToPerm(Base, BaseModel):
1301 __tablename__ = 'users_group_repo_to_perm'
1302 __table_args__ = (
1303 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1304 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1305 'mysql_charset': 'utf8'}
1306 )
1307 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1308 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1309 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1310 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1311
1312 users_group = relationship('UsersGroup')
1313 permission = relationship('Permission')
1314 repository = relationship('Repository')
1315
1316 @classmethod
1317 def create(cls, users_group, repository, permission):
1318 n = cls()
1319 n.users_group = users_group
1320 n.repository = repository
1321 n.permission = permission
1322 Session().add(n)
1323 return n
1324
1325 def __unicode__(self):
1326 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1327
1328
1329 class UsersGroupToPerm(Base, BaseModel):
1330 __tablename__ = 'users_group_to_perm'
1331 __table_args__ = (
1332 UniqueConstraint('users_group_id', 'permission_id',),
1333 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1334 'mysql_charset': 'utf8'}
1335 )
1336 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1337 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1338 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1339
1340 users_group = relationship('UsersGroup')
1341 permission = relationship('Permission')
1342
1343
1344 class UserRepoGroupToPerm(Base, BaseModel):
1345 __tablename__ = 'user_repo_group_to_perm'
1346 __table_args__ = (
1347 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1348 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1349 'mysql_charset': 'utf8'}
1350 )
1351
1352 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1353 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1354 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1355 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1356
1357 user = relationship('User')
1358 group = relationship('RepoGroup')
1359 permission = relationship('Permission')
1360
1361
1362 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1363 __tablename__ = 'users_group_repo_group_to_perm'
1364 __table_args__ = (
1365 UniqueConstraint('users_group_id', 'group_id'),
1366 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1367 'mysql_charset': 'utf8'}
1368 )
1369
1370 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)
1371 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1372 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1373 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1374
1375 users_group = relationship('UsersGroup')
1376 permission = relationship('Permission')
1377 group = relationship('RepoGroup')
1378
1379
1380 class Statistics(Base, BaseModel):
1381 __tablename__ = 'statistics'
1382 __table_args__ = (
1383 UniqueConstraint('repository_id'),
1384 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1385 'mysql_charset': 'utf8'}
1386 )
1387 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1388 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1389 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1390 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1391 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1392 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1393
1394 repository = relationship('Repository', single_parent=True)
1395
1396
1397 class UserFollowing(Base, BaseModel):
1398 __tablename__ = 'user_followings'
1399 __table_args__ = (
1400 UniqueConstraint('user_id', 'follows_repository_id'),
1401 UniqueConstraint('user_id', 'follows_user_id'),
1402 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1403 'mysql_charset': 'utf8'}
1404 )
1405
1406 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1407 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1408 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1409 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1410 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1411
1412 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1413
1414 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1415 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1416
1417 @classmethod
1418 def get_repo_followers(cls, repo_id):
1419 return cls.query().filter(cls.follows_repo_id == repo_id)
1420
1421
1422 class CacheInvalidation(Base, BaseModel):
1423 __tablename__ = 'cache_invalidation'
1424 __table_args__ = (
1425 UniqueConstraint('cache_key'),
1426 Index('key_idx', 'cache_key'),
1427 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1428 'mysql_charset': 'utf8'},
1429 )
1430 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1431 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1432 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1433 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1434
1435 def __init__(self, cache_key, cache_args=''):
1436 self.cache_key = cache_key
1437 self.cache_args = cache_args
1438 self.cache_active = False
1439
1440 def __unicode__(self):
1441 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1442 self.cache_id, self.cache_key)
1443
1444 @property
1445 def prefix(self):
1446 _split = self.cache_key.split(self.cache_args, 1)
1447 if _split and len(_split) == 2:
1448 return _split[0]
1449 return ''
1450
1451 @classmethod
1452 def clear_cache(cls):
1453 cls.query().delete()
1454
1455 @classmethod
1456 def _get_key(cls, key):
1457 """
1458 Wrapper for generating a key, together with a prefix
1459
1460 :param key:
1461 """
1462 import rhodecode
1463 prefix = ''
1464 org_key = key
1465 iid = rhodecode.CONFIG.get('instance_id')
1466 if iid:
1467 prefix = iid
1468
1469 return "%s%s" % (prefix, key), prefix, org_key
1470
1471 @classmethod
1472 def get_by_key(cls, key):
1473 return cls.query().filter(cls.cache_key == key).scalar()
1474
1475 @classmethod
1476 def get_by_repo_name(cls, repo_name):
1477 return cls.query().filter(cls.cache_args == repo_name).all()
1478
1479 @classmethod
1480 def _get_or_create_key(cls, key, repo_name, commit=True):
1481 inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
1482 if not inv_obj:
1483 try:
1484 inv_obj = CacheInvalidation(key, repo_name)
1485 Session().add(inv_obj)
1486 if commit:
1487 Session().commit()
1488 except Exception:
1489 log.error(traceback.format_exc())
1490 Session().rollback()
1491 return inv_obj
1492
1493 @classmethod
1494 def invalidate(cls, key):
1495 """
1496 Returns Invalidation object if this given key should be invalidated
1497 None otherwise. `cache_active = False` means that this cache
1498 state is not valid and needs to be invalidated
1499
1500 :param key:
1501 """
1502 repo_name = key
1503 repo_name = remove_suffix(repo_name, '_README')
1504 repo_name = remove_suffix(repo_name, '_RSS')
1505 repo_name = remove_suffix(repo_name, '_ATOM')
1506
1507 # adds instance prefix
1508 key, _prefix, _org_key = cls._get_key(key)
1509 inv = cls._get_or_create_key(key, repo_name)
1510
1511 if inv and inv.cache_active is False:
1512 return inv
1513
1514 @classmethod
1515 def set_invalidate(cls, key=None, repo_name=None):
1516 """
1517 Mark this Cache key for invalidation, either by key or whole
1518 cache sets based on repo_name
1519
1520 :param key:
1521 """
1522 if key:
1523 key, _prefix, _org_key = cls._get_key(key)
1524 inv_objs = Session().query(cls).filter(cls.cache_key == key).all()
1525 elif repo_name:
1526 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1527
1528 log.debug('marking %s key[s] for invalidation based on key=%s,repo_name=%s'
1529 % (len(inv_objs), key, repo_name))
1530 try:
1531 for inv_obj in inv_objs:
1532 inv_obj.cache_active = False
1533 Session().add(inv_obj)
1534 Session().commit()
1535 except Exception:
1536 log.error(traceback.format_exc())
1537 Session().rollback()
1538
1539 @classmethod
1540 def set_valid(cls, key):
1541 """
1542 Mark this cache key as active and currently cached
1543
1544 :param key:
1545 """
1546 inv_obj = cls.get_by_key(key)
1547 inv_obj.cache_active = True
1548 Session().add(inv_obj)
1549 Session().commit()
1550
1551 @classmethod
1552 def get_cache_map(cls):
1553
1554 class cachemapdict(dict):
1555
1556 def __init__(self, *args, **kwargs):
1557 fixkey = kwargs.get('fixkey')
1558 if fixkey:
1559 del kwargs['fixkey']
1560 self.fixkey = fixkey
1561 super(cachemapdict, self).__init__(*args, **kwargs)
1562
1563 def __getattr__(self, name):
1564 key = name
1565 if self.fixkey:
1566 key, _prefix, _org_key = cls._get_key(key)
1567 if key in self.__dict__:
1568 return self.__dict__[key]
1569 else:
1570 return self[key]
1571
1572 def __getitem__(self, key):
1573 if self.fixkey:
1574 key, _prefix, _org_key = cls._get_key(key)
1575 try:
1576 return super(cachemapdict, self).__getitem__(key)
1577 except KeyError:
1578 return
1579
1580 cache_map = cachemapdict(fixkey=True)
1581 for obj in cls.query().all():
1582 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1583 return cache_map
1584
1585
1586 class ChangesetComment(Base, BaseModel):
1587 __tablename__ = 'changeset_comments'
1588 __table_args__ = (
1589 Index('cc_revision_idx', 'revision'),
1590 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1591 'mysql_charset': 'utf8'},
1592 )
1593 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1594 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1595 revision = Column('revision', String(40), nullable=True)
1596 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1597 line_no = Column('line_no', Unicode(10), nullable=True)
1598 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1599 f_path = Column('f_path', Unicode(1000), nullable=True)
1600 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1601 text = Column('text', UnicodeText(25000), nullable=False)
1602 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1603 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1604
1605 author = relationship('User', lazy='joined')
1606 repo = relationship('Repository')
1607 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1608 pull_request = relationship('PullRequest', lazy='joined')
1609
1610 @classmethod
1611 def get_users(cls, revision=None, pull_request_id=None):
1612 """
1613 Returns user associated with this ChangesetComment. ie those
1614 who actually commented
1615
1616 :param cls:
1617 :param revision:
1618 """
1619 q = Session().query(User)\
1620 .join(ChangesetComment.author)
1621 if revision:
1622 q = q.filter(cls.revision == revision)
1623 elif pull_request_id:
1624 q = q.filter(cls.pull_request_id == pull_request_id)
1625 return q.all()
1626
1627
1628 class ChangesetStatus(Base, BaseModel):
1629 __tablename__ = 'changeset_statuses'
1630 __table_args__ = (
1631 Index('cs_revision_idx', 'revision'),
1632 Index('cs_version_idx', 'version'),
1633 UniqueConstraint('repo_id', 'revision', 'version'),
1634 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1635 'mysql_charset': 'utf8'}
1636 )
1637 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1638 STATUS_APPROVED = 'approved'
1639 STATUS_REJECTED = 'rejected'
1640 STATUS_UNDER_REVIEW = 'under_review'
1641
1642 STATUSES = [
1643 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1644 (STATUS_APPROVED, _("Approved")),
1645 (STATUS_REJECTED, _("Rejected")),
1646 (STATUS_UNDER_REVIEW, _("Under Review")),
1647 ]
1648
1649 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1650 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1651 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1652 revision = Column('revision', String(40), nullable=False)
1653 status = Column('status', String(128), nullable=False, default=DEFAULT)
1654 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1655 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1656 version = Column('version', Integer(), nullable=False, default=0)
1657 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1658
1659 author = relationship('User', lazy='joined')
1660 repo = relationship('Repository')
1661 comment = relationship('ChangesetComment', lazy='joined')
1662 pull_request = relationship('PullRequest', lazy='joined')
1663
1664 def __unicode__(self):
1665 return u"<%s('%s:%s')>" % (
1666 self.__class__.__name__,
1667 self.status, self.author
1668 )
1669
1670 @classmethod
1671 def get_status_lbl(cls, value):
1672 return dict(cls.STATUSES).get(value)
1673
1674 @property
1675 def status_lbl(self):
1676 return ChangesetStatus.get_status_lbl(self.status)
1677
1678
1679 class PullRequest(Base, BaseModel):
1680 __tablename__ = 'pull_requests'
1681 __table_args__ = (
1682 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1683 'mysql_charset': 'utf8'},
1684 )
1685
1686 STATUS_NEW = u'new'
1687 STATUS_OPEN = u'open'
1688 STATUS_CLOSED = u'closed'
1689
1690 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1691 title = Column('title', Unicode(256), nullable=True)
1692 description = Column('description', UnicodeText(10240), nullable=True)
1693 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1694 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1695 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1696 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1697 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1698 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1699 org_ref = Column('org_ref', Unicode(256), nullable=False)
1700 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1701 other_ref = Column('other_ref', Unicode(256), nullable=False)
1702
1703 @hybrid_property
1704 def revisions(self):
1705 return self._revisions.split(':')
1706
1707 @revisions.setter
1708 def revisions(self, val):
1709 self._revisions = ':'.join(val)
1710
1711 author = relationship('User', lazy='joined')
1712 reviewers = relationship('PullRequestReviewers',
1713 cascade="all, delete, delete-orphan")
1714 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1715 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1716 statuses = relationship('ChangesetStatus')
1717 comments = relationship('ChangesetComment',
1718 cascade="all, delete, delete-orphan")
1719
1720 def is_closed(self):
1721 return self.status == self.STATUS_CLOSED
1722
1723 def __json__(self):
1724 return dict(
1725 revisions=self.revisions
1726 )
1727
1728
1729 class PullRequestReviewers(Base, BaseModel):
1730 __tablename__ = 'pull_request_reviewers'
1731 __table_args__ = (
1732 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1733 'mysql_charset': 'utf8'},
1734 )
1735
1736 def __init__(self, user=None, pull_request=None):
1737 self.user = user
1738 self.pull_request = pull_request
1739
1740 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1741 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1742 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1743
1744 user = relationship('User')
1745 pull_request = relationship('PullRequest')
1746
1747
1748 class Notification(Base, BaseModel):
1749 __tablename__ = 'notifications'
1750 __table_args__ = (
1751 Index('notification_type_idx', 'type'),
1752 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1753 'mysql_charset': 'utf8'},
1754 )
1755
1756 TYPE_CHANGESET_COMMENT = u'cs_comment'
1757 TYPE_MESSAGE = u'message'
1758 TYPE_MENTION = u'mention'
1759 TYPE_REGISTRATION = u'registration'
1760 TYPE_PULL_REQUEST = u'pull_request'
1761 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1762
1763 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1764 subject = Column('subject', Unicode(512), nullable=True)
1765 body = Column('body', UnicodeText(50000), nullable=True)
1766 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1767 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1768 type_ = Column('type', Unicode(256))
1769
1770 created_by_user = relationship('User')
1771 notifications_to_users = relationship('UserNotification', lazy='joined',
1772 cascade="all, delete, delete-orphan")
1773
1774 @property
1775 def recipients(self):
1776 return [x.user for x in UserNotification.query()\
1777 .filter(UserNotification.notification == self)\
1778 .order_by(UserNotification.user_id.asc()).all()]
1779
1780 @classmethod
1781 def create(cls, created_by, subject, body, recipients, type_=None):
1782 if type_ is None:
1783 type_ = Notification.TYPE_MESSAGE
1784
1785 notification = cls()
1786 notification.created_by_user = created_by
1787 notification.subject = subject
1788 notification.body = body
1789 notification.type_ = type_
1790 notification.created_on = datetime.datetime.now()
1791
1792 for u in recipients:
1793 assoc = UserNotification()
1794 assoc.notification = notification
1795 u.notifications.append(assoc)
1796 Session().add(notification)
1797 return notification
1798
1799 @property
1800 def description(self):
1801 from rhodecode.model.notification import NotificationModel
1802 return NotificationModel().make_description(self)
1803
1804
1805 class UserNotification(Base, BaseModel):
1806 __tablename__ = 'user_to_notification'
1807 __table_args__ = (
1808 UniqueConstraint('user_id', 'notification_id'),
1809 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1810 'mysql_charset': 'utf8'}
1811 )
1812 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1813 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1814 read = Column('read', Boolean, default=False)
1815 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1816
1817 user = relationship('User', lazy="joined")
1818 notification = relationship('Notification', lazy="joined",
1819 order_by=lambda: Notification.created_on.desc(),)
1820
1821 def mark_as_read(self):
1822 self.read = True
1823 Session().add(self)
1824
1825
1826 class DbMigrateVersion(Base, BaseModel):
1827 __tablename__ = 'db_migrate_version'
1828 __table_args__ = (
1829 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1830 'mysql_charset': 'utf8'},
1831 )
1832 repository_id = Column('repository_id', String(250), primary_key=True)
1833 repository_path = Column('repository_path', Text)
1834 version = Column('version', Integer)
@@ -12,6 +12,7 b' from rhodecode.lib.dbmigrate.migrate.cha'
12 12
13 13 from rhodecode.model.meta import Base
14 14 from rhodecode.model import meta
15 from rhodecode.lib.dbmigrate.versions import _reset_base
15 16
16 17 log = logging.getLogger(__name__)
17 18
@@ -49,12 +50,7 b' def upgrade(migrate_engine):'
49 50 tbl = ChangesetStatus.__table__
50 51 tbl.create()
51 52
52 ## RESET COMPLETLY THE metadata for sqlalchemy to use the 1_3_0 Base
53 Base = declarative_base()
54 Base.metadata.clear()
55 Base.metadata = MetaData()
56 Base.metadata.bind = migrate_engine
57 meta.Base = Base
53 _reset_base(migrate_engine)
58 54
59 55 #==========================================================================
60 56 # USERS TABLE
@@ -173,12 +169,7 b' def upgrade(migrate_engine):'
173 169 ForeignKey('pull_requests.pull_request_id'),
174 170 nullable=True)
175 171 pull_request_id.create(table=tbl)
176 ## RESET COMPLETLY THE metadata for sqlalchemy back after using 1_3_0
177 Base = declarative_base()
178 Base.metadata.clear()
179 Base.metadata = MetaData()
180 Base.metadata.bind = migrate_engine
181 meta.Base = Base
172 _reset_base(migrate_engine)
182 173
183 174
184 175 def downgrade(migrate_engine):
@@ -12,6 +12,7 b' from rhodecode.lib.dbmigrate.migrate.cha'
12 12
13 13 from rhodecode.model.meta import Base
14 14 from rhodecode.model import meta
15 from rhodecode.lib.dbmigrate.versions import _reset_base
15 16
16 17 log = logging.getLogger(__name__)
17 18
@@ -24,6 +25,7 b' def upgrade(migrate_engine):'
24 25 #==========================================================================
25 26 # USER LOGS
26 27 #==========================================================================
28 _reset_base(migrate_engine)
27 29 from rhodecode.lib.dbmigrate.schema.db_1_5_0 import UserLog
28 30 tbl = UserLog.__table__
29 31 username = Column("username", String(255, convert_unicode=False,
@@ -12,6 +12,7 b' from rhodecode.lib.dbmigrate.migrate.cha'
12 12
13 13 from rhodecode.model.meta import Base
14 14 from rhodecode.model import meta
15 from rhodecode.lib.dbmigrate.versions import _reset_base
15 16
16 17 log = logging.getLogger(__name__)
17 18
@@ -21,29 +22,27 b' def upgrade(migrate_engine):'
21 22 Upgrade operations go here.
22 23 Don't create your own engine; bind migrate_engine to your metadata
23 24 """
25 _reset_base(migrate_engine)
24 26 #==========================================================================
25 27 # USER LOGS
26 28 #==========================================================================
27 from rhodecode.lib.dbmigrate.schema.db_1_5_0 import UserIpMap
29 from rhodecode.lib.dbmigrate.schema.db_1_5_2 import UserIpMap
28 30 tbl = UserIpMap.__table__
29 31 tbl.create()
30 32
31 33 #==========================================================================
32 34 # REPOSITORIES
33 35 #==========================================================================
34 from rhodecode.lib.dbmigrate.schema.db_1_5_0 import Repository
36 from rhodecode.lib.dbmigrate.schema.db_1_5_2 import Repository
35 37 tbl = Repository.__table__
36 38 changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True)
37 39 # create username column
38 40 changeset_cache.create(table=tbl)
39 41
40 42 #fix cache data
41 _Session = Session()
42 ## after adding that column fix all usernames
43 repositories = _Session.query(Repository).all()
43 repositories = Repository.getAll()
44 44 for entry in repositories:
45 45 entry.update_changeset_cache()
46 _Session.commit()
47 46
48 47
49 48 def downgrade(migrate_engine):
@@ -22,3 +22,23 b''
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 from sqlalchemy import *
26 from sqlalchemy.exc import DatabaseError
27 from sqlalchemy.orm import relation, backref, class_mapper, joinedload
28 from sqlalchemy.orm.session import Session
29 from sqlalchemy.ext.declarative import declarative_base
30
31 from rhodecode.lib.dbmigrate.migrate import *
32 from rhodecode.lib.dbmigrate.migrate.changeset import *
33
34 from rhodecode.model.meta import Base
35 from rhodecode.model import meta
36
37
38 def _reset_base(migrate_engine):
39 ## RESET COMPLETLY THE metadata for sqlalchemy to use previous declared Base
40 Base = declarative_base()
41 Base.metadata.clear()
42 Base.metadata = MetaData()
43 Base.metadata.bind = migrate_engine
44 meta.Base = Base
General Comments 0
You need to be logged in to leave comments. Login now