Mercurial > kallithea
comparison rhodecode/model/db.py @ 2031:82a88013a3fd
merge 1.3 into stable
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Sun, 26 Feb 2012 17:25:09 +0200 |
parents | a1b8bd86c488 6020e3884a58 |
children | 9ab21c5ddb84 |
comparison
equal
deleted
inserted
replaced
2005:ab0e122b38a7 | 2031:82a88013a3fd |
---|---|
5 | 5 |
6 Database Models for RhodeCode | 6 Database Models for RhodeCode |
7 | 7 |
8 :created_on: Apr 08, 2010 | 8 :created_on: Apr 08, 2010 |
9 :author: marcink | 9 :author: marcink |
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> |
11 :license: GPLv3, see COPYING for more details. | 11 :license: GPLv3, see COPYING for more details. |
12 """ | 12 """ |
13 # This program is free software: you can redistribute it and/or modify | 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 | 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 | 15 # the Free Software Foundation, either version 3 of the License, or |
25 | 25 |
26 import os | 26 import os |
27 import logging | 27 import logging |
28 import datetime | 28 import datetime |
29 import traceback | 29 import traceback |
30 from datetime import date | 30 from collections import defaultdict |
31 | 31 |
32 from sqlalchemy import * | 32 from sqlalchemy import * |
33 from sqlalchemy.ext.hybrid import hybrid_property | 33 from sqlalchemy.ext.hybrid import hybrid_property |
34 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates | 34 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates |
35 from beaker.cache import cache_region, region_invalidate | 35 from beaker.cache import cache_region, region_invalidate |
36 | 36 |
37 from vcs import get_backend | 37 from rhodecode.lib.vcs import get_backend |
38 from vcs.utils.helpers import get_scm | 38 from rhodecode.lib.vcs.utils.helpers import get_scm |
39 from vcs.exceptions import VCSError | 39 from rhodecode.lib.vcs.exceptions import VCSError |
40 from vcs.utils.lazy import LazyProperty | 40 from rhodecode.lib.vcs.utils.lazy import LazyProperty |
41 | 41 |
42 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, \ | 42 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, safe_unicode |
43 generate_api_key, safe_unicode | |
44 from rhodecode.lib.exceptions import UsersGroupsAssignedException | |
45 from rhodecode.lib.compat import json | 43 from rhodecode.lib.compat import json |
44 from rhodecode.lib.caching_query import FromCache | |
46 | 45 |
47 from rhodecode.model.meta import Base, Session | 46 from rhodecode.model.meta import Base, Session |
48 from rhodecode.model.caching_query import FromCache | |
49 | 47 |
50 | 48 |
51 log = logging.getLogger(__name__) | 49 log = logging.getLogger(__name__) |
52 | 50 |
53 #============================================================================== | 51 #============================================================================== |
85 else: | 83 else: |
86 return json.JSONEncoder.default(self, obj) | 84 return json.JSONEncoder.default(self, obj) |
87 | 85 |
88 | 86 |
89 class BaseModel(object): | 87 class BaseModel(object): |
90 """Base Model for all classess | 88 """ |
91 | 89 Base Model for all classess |
92 """ | 90 """ |
93 | 91 |
94 @classmethod | 92 @classmethod |
95 def _get_keys(cls): | 93 def _get_keys(cls): |
96 """return column names for this model """ | 94 """return column names for this model """ |
97 return class_mapper(cls).c.keys() | 95 return class_mapper(cls).c.keys() |
98 | 96 |
99 def get_dict(self): | 97 def get_dict(self): |
100 """return dict with keys and values corresponding | 98 """ |
99 return dict with keys and values corresponding | |
101 to this model data """ | 100 to this model data """ |
102 | 101 |
103 d = {} | 102 d = {} |
104 for k in self._get_keys(): | 103 for k in self._get_keys(): |
105 d[k] = getattr(self, k) | 104 d[k] = getattr(self, k) |
140 | 139 |
141 @classmethod | 140 @classmethod |
142 def delete(cls, id_): | 141 def delete(cls, id_): |
143 obj = cls.query().get(id_) | 142 obj = cls.query().get(id_) |
144 Session.delete(obj) | 143 Session.delete(obj) |
145 Session.commit() | 144 |
146 | 145 |
147 | 146 class RhodeCodeSetting(Base, BaseModel): |
148 class RhodeCodeSettings(Base, BaseModel): | |
149 __tablename__ = 'rhodecode_settings' | 147 __tablename__ = 'rhodecode_settings' |
150 __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True}) | 148 __table_args__ = ( |
149 UniqueConstraint('app_settings_name'), | |
150 {'extend_existing': True} | |
151 ) | |
151 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 152 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
152 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 153 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
153 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 154 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
154 | 155 |
155 def __init__(self, k='', v=''): | 156 def __init__(self, k='', v=''): |
156 self.app_settings_name = k | 157 self.app_settings_name = k |
157 self.app_settings_value = v | 158 self.app_settings_value = v |
158 | |
159 | 159 |
160 @validates('_app_settings_value') | 160 @validates('_app_settings_value') |
161 def validate_settings_value(self, key, val): | 161 def validate_settings_value(self, key, val): |
162 assert type(val) == unicode | 162 assert type(val) == unicode |
163 return val | 163 return val |
164 | 164 |
165 @hybrid_property | 165 @hybrid_property |
166 def app_settings_value(self): | 166 def app_settings_value(self): |
167 v = self._app_settings_value | 167 v = self._app_settings_value |
168 if v == 'ldap_active': | 168 if self.app_settings_name == 'ldap_active': |
169 v = str2bool(v) | 169 v = str2bool(v) |
170 return v | 170 return v |
171 | 171 |
172 @app_settings_value.setter | 172 @app_settings_value.setter |
173 def app_settings_value(self, val): | 173 def app_settings_value(self, val): |
177 :param val: | 177 :param val: |
178 """ | 178 """ |
179 self._app_settings_value = safe_unicode(val) | 179 self._app_settings_value = safe_unicode(val) |
180 | 180 |
181 def __repr__(self): | 181 def __repr__(self): |
182 return "<%s('%s:%s')>" % (self.__class__.__name__, | 182 return "<%s('%s:%s')>" % ( |
183 self.app_settings_name, self.app_settings_value) | 183 self.__class__.__name__, |
184 | 184 self.app_settings_name, self.app_settings_value |
185 ) | |
185 | 186 |
186 @classmethod | 187 @classmethod |
187 def get_by_name(cls, ldap_key): | 188 def get_by_name(cls, ldap_key): |
188 return cls.query()\ | 189 return cls.query()\ |
189 .filter(cls.app_settings_name == ldap_key).scalar() | 190 .filter(cls.app_settings_name == ldap_key).scalar() |
216 return fd | 217 return fd |
217 | 218 |
218 | 219 |
219 class RhodeCodeUi(Base, BaseModel): | 220 class RhodeCodeUi(Base, BaseModel): |
220 __tablename__ = 'rhodecode_ui' | 221 __tablename__ = 'rhodecode_ui' |
221 __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True}) | 222 __table_args__ = ( |
223 UniqueConstraint('ui_key'), | |
224 {'extend_existing': True} | |
225 ) | |
222 | 226 |
223 HOOK_UPDATE = 'changegroup.update' | 227 HOOK_UPDATE = 'changegroup.update' |
224 HOOK_REPO_SIZE = 'changegroup.repo_size' | 228 HOOK_REPO_SIZE = 'changegroup.repo_size' |
225 HOOK_PUSH = 'pretxnchangegroup.push_logger' | 229 HOOK_PUSH = 'pretxnchangegroup.push_logger' |
226 HOOK_PULL = 'preoutgoing.pull_logger' | 230 HOOK_PULL = 'preoutgoing.pull_logger' |
229 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 233 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
230 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 234 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
231 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 235 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
232 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) | 236 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) |
233 | 237 |
234 | |
235 @classmethod | 238 @classmethod |
236 def get_by_key(cls, key): | 239 def get_by_key(cls, key): |
237 return cls.query().filter(cls.ui_key == key) | 240 return cls.query().filter(cls.ui_key == key) |
238 | |
239 | 241 |
240 @classmethod | 242 @classmethod |
241 def get_builtin_hooks(cls): | 243 def get_builtin_hooks(cls): |
242 q = cls.query() | 244 q = cls.query() |
243 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, | 245 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, |
261 new_ui.ui_active = True | 263 new_ui.ui_active = True |
262 new_ui.ui_key = key | 264 new_ui.ui_key = key |
263 new_ui.ui_value = val | 265 new_ui.ui_value = val |
264 | 266 |
265 Session.add(new_ui) | 267 Session.add(new_ui) |
266 Session.commit() | |
267 | 268 |
268 | 269 |
269 class User(Base, BaseModel): | 270 class User(Base, BaseModel): |
270 __tablename__ = 'users' | 271 __tablename__ = 'users' |
271 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True}) | 272 __table_args__ = ( |
273 UniqueConstraint('username'), UniqueConstraint('email'), | |
274 {'extend_existing': True} | |
275 ) | |
272 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 276 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
273 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 277 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
274 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 278 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
275 active = Column("active", Boolean(), nullable=True, unique=None, default=None) | 279 active = Column("active", Boolean(), nullable=True, unique=None, default=None) |
276 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) | 280 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) |
284 user_log = relationship('UserLog', cascade='all') | 288 user_log = relationship('UserLog', cascade='all') |
285 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') | 289 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all') |
286 | 290 |
287 repositories = relationship('Repository') | 291 repositories = relationship('Repository') |
288 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') | 292 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all') |
289 repo_to_perm = relationship('RepoToPerm', primaryjoin='RepoToPerm.user_id==User.user_id', cascade='all') | 293 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all') |
290 | 294 |
291 group_member = relationship('UsersGroupMember', cascade='all') | 295 group_member = relationship('UsersGroupMember', cascade='all') |
296 | |
297 notifications = relationship('UserNotification',) | |
292 | 298 |
293 @hybrid_property | 299 @hybrid_property |
294 def email(self): | 300 def email(self): |
295 return self._email | 301 return self._email |
296 | 302 |
301 @property | 307 @property |
302 def full_name(self): | 308 def full_name(self): |
303 return '%s %s' % (self.name, self.lastname) | 309 return '%s %s' % (self.name, self.lastname) |
304 | 310 |
305 @property | 311 @property |
312 def full_name_or_username(self): | |
313 return ('%s %s' % (self.name, self.lastname) | |
314 if (self.name and self.lastname) else self.username) | |
315 | |
316 @property | |
306 def full_contact(self): | 317 def full_contact(self): |
307 return '%s %s <%s>' % (self.name, self.lastname, self.email) | 318 return '%s %s <%s>' % (self.name, self.lastname, self.email) |
308 | 319 |
309 @property | 320 @property |
310 def short_contact(self): | 321 def short_contact(self): |
313 @property | 324 @property |
314 def is_admin(self): | 325 def is_admin(self): |
315 return self.admin | 326 return self.admin |
316 | 327 |
317 def __repr__(self): | 328 def __repr__(self): |
318 try: | 329 return "<%s('id:%s:%s')>" % (self.__class__.__name__, |
319 return "<%s('id:%s:%s')>" % (self.__class__.__name__, | 330 self.user_id, self.username) |
320 self.user_id, self.username) | 331 |
321 except: | 332 @classmethod |
322 return self.__class__.__name__ | 333 def get_by_username(cls, username, case_insensitive=False, cache=False): |
323 | |
324 def __json__(self): | |
325 return {'email': self.email} | |
326 | |
327 @classmethod | |
328 def get_by_username(cls, username, case_insensitive=False): | |
329 if case_insensitive: | 334 if case_insensitive: |
330 return Session.query(cls).filter(cls.username.ilike(username)).scalar() | 335 q = cls.query().filter(cls.username.ilike(username)) |
331 else: | 336 else: |
332 return Session.query(cls).filter(cls.username == username).scalar() | 337 q = cls.query().filter(cls.username == username) |
333 | 338 |
334 @classmethod | 339 if cache: |
335 def get_by_api_key(cls, api_key): | 340 q = q.options(FromCache("sql_cache_short", |
336 return cls.query().filter(cls.api_key == api_key).one() | 341 "get_user_%s" % username)) |
342 return q.scalar() | |
343 | |
344 @classmethod | |
345 def get_by_api_key(cls, api_key, cache=False): | |
346 q = cls.query().filter(cls.api_key == api_key) | |
347 | |
348 if cache: | |
349 q = q.options(FromCache("sql_cache_short", | |
350 "get_api_key_%s" % api_key)) | |
351 return q.scalar() | |
352 | |
353 @classmethod | |
354 def get_by_email(cls, email, case_insensitive=False, cache=False): | |
355 if case_insensitive: | |
356 q = cls.query().filter(cls.email.ilike(email)) | |
357 else: | |
358 q = cls.query().filter(cls.email == email) | |
359 | |
360 if cache: | |
361 q = q.options(FromCache("sql_cache_short", | |
362 "get_api_key_%s" % email)) | |
363 return q.scalar() | |
337 | 364 |
338 def update_lastlogin(self): | 365 def update_lastlogin(self): |
339 """Update user lastlogin""" | 366 """Update user lastlogin""" |
340 | |
341 self.last_login = datetime.datetime.now() | 367 self.last_login = datetime.datetime.now() |
342 Session.add(self) | 368 Session.add(self) |
343 Session.commit() | 369 log.debug('updated user %s lastlogin' % self.username) |
344 log.debug('updated user %s lastlogin', self.username) | 370 |
345 | 371 def __json__(self): |
346 @classmethod | 372 return dict( |
347 def create(cls, form_data): | 373 email=self.email, |
348 from rhodecode.lib.auth import get_crypt_password | 374 full_name=self.full_name, |
349 | 375 full_name_or_username=self.full_name_or_username, |
350 try: | 376 short_contact=self.short_contact, |
351 new_user = cls() | 377 full_contact=self.full_contact |
352 for k, v in form_data.items(): | 378 ) |
353 if k == 'password': | 379 |
354 v = get_crypt_password(v) | |
355 setattr(new_user, k, v) | |
356 | |
357 new_user.api_key = generate_api_key(form_data['username']) | |
358 Session.add(new_user) | |
359 Session.commit() | |
360 return new_user | |
361 except: | |
362 log.error(traceback.format_exc()) | |
363 Session.rollback() | |
364 raise | |
365 | 380 |
366 class UserLog(Base, BaseModel): | 381 class UserLog(Base, BaseModel): |
367 __tablename__ = 'user_logs' | 382 __tablename__ = 'user_logs' |
368 __table_args__ = {'extend_existing':True} | 383 __table_args__ = {'extend_existing': True} |
369 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 384 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
370 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) | 385 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) |
371 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) | 386 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True) |
372 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 387 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
373 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 388 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
374 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 389 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
375 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) | 390 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) |
376 | 391 |
377 @property | 392 @property |
378 def action_as_day(self): | 393 def action_as_day(self): |
379 return date(*self.action_date.timetuple()[:3]) | 394 return datetime.date(*self.action_date.timetuple()[:3]) |
380 | 395 |
381 user = relationship('User') | 396 user = relationship('User') |
382 repository = relationship('Repository') | 397 repository = relationship('Repository',cascade='') |
383 | 398 |
384 | 399 |
385 class UsersGroup(Base, BaseModel): | 400 class UsersGroup(Base, BaseModel): |
386 __tablename__ = 'users_groups' | 401 __tablename__ = 'users_groups' |
387 __table_args__ = {'extend_existing':True} | 402 __table_args__ = {'extend_existing': True} |
388 | 403 |
389 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 404 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
390 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) | 405 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) |
391 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) | 406 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) |
392 | 407 |
394 | 409 |
395 def __repr__(self): | 410 def __repr__(self): |
396 return '<userGroup(%s)>' % (self.users_group_name) | 411 return '<userGroup(%s)>' % (self.users_group_name) |
397 | 412 |
398 @classmethod | 413 @classmethod |
399 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False): | 414 def get_by_group_name(cls, group_name, cache=False, |
415 case_insensitive=False): | |
400 if case_insensitive: | 416 if case_insensitive: |
401 gr = cls.query()\ | 417 q = cls.query().filter(cls.users_group_name.ilike(group_name)) |
402 .filter(cls.users_group_name.ilike(group_name)) | |
403 else: | 418 else: |
404 gr = cls.query()\ | 419 q = cls.query().filter(cls.users_group_name == group_name) |
405 .filter(cls.users_group_name == group_name) | |
406 if cache: | 420 if cache: |
407 gr = gr.options(FromCache("sql_cache_short", | 421 q = q.options(FromCache("sql_cache_short", |
408 "get_user_%s" % group_name)) | 422 "get_user_%s" % group_name)) |
409 return gr.scalar() | 423 return q.scalar() |
410 | |
411 | 424 |
412 @classmethod | 425 @classmethod |
413 def get(cls, users_group_id, cache=False): | 426 def get(cls, users_group_id, cache=False): |
414 users_group = cls.query() | 427 users_group = cls.query() |
415 if cache: | 428 if cache: |
416 users_group = users_group.options(FromCache("sql_cache_short", | 429 users_group = users_group.options(FromCache("sql_cache_short", |
417 "get_users_group_%s" % users_group_id)) | 430 "get_users_group_%s" % users_group_id)) |
418 return users_group.get(users_group_id) | 431 return users_group.get(users_group_id) |
419 | 432 |
420 @classmethod | |
421 def create(cls, form_data): | |
422 try: | |
423 new_users_group = cls() | |
424 for k, v in form_data.items(): | |
425 setattr(new_users_group, k, v) | |
426 | |
427 Session.add(new_users_group) | |
428 Session.commit() | |
429 return new_users_group | |
430 except: | |
431 log.error(traceback.format_exc()) | |
432 Session.rollback() | |
433 raise | |
434 | |
435 @classmethod | |
436 def update(cls, users_group_id, form_data): | |
437 | |
438 try: | |
439 users_group = cls.get(users_group_id, cache=False) | |
440 | |
441 for k, v in form_data.items(): | |
442 if k == 'users_group_members': | |
443 users_group.members = [] | |
444 Session.flush() | |
445 members_list = [] | |
446 if v: | |
447 v = [v] if isinstance(v, basestring) else v | |
448 for u_id in set(v): | |
449 member = UsersGroupMember(users_group_id, u_id) | |
450 members_list.append(member) | |
451 setattr(users_group, 'members', members_list) | |
452 setattr(users_group, k, v) | |
453 | |
454 Session.add(users_group) | |
455 Session.commit() | |
456 except: | |
457 log.error(traceback.format_exc()) | |
458 Session.rollback() | |
459 raise | |
460 | |
461 @classmethod | |
462 def delete(cls, users_group_id): | |
463 try: | |
464 | |
465 # check if this group is not assigned to repo | |
466 assigned_groups = UsersGroupRepoToPerm.query()\ | |
467 .filter(UsersGroupRepoToPerm.users_group_id == | |
468 users_group_id).all() | |
469 | |
470 if assigned_groups: | |
471 raise UsersGroupsAssignedException('Group assigned to %s' % | |
472 assigned_groups) | |
473 | |
474 users_group = cls.get(users_group_id, cache=False) | |
475 Session.delete(users_group) | |
476 Session.commit() | |
477 except: | |
478 log.error(traceback.format_exc()) | |
479 Session.rollback() | |
480 raise | |
481 | 433 |
482 class UsersGroupMember(Base, BaseModel): | 434 class UsersGroupMember(Base, BaseModel): |
483 __tablename__ = 'users_groups_members' | 435 __tablename__ = 'users_groups_members' |
484 __table_args__ = {'extend_existing':True} | 436 __table_args__ = {'extend_existing': True} |
485 | 437 |
486 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 438 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
487 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) | 439 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) |
488 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) | 440 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) |
489 | 441 |
492 | 444 |
493 def __init__(self, gr_id='', u_id=''): | 445 def __init__(self, gr_id='', u_id=''): |
494 self.users_group_id = gr_id | 446 self.users_group_id = gr_id |
495 self.user_id = u_id | 447 self.user_id = u_id |
496 | 448 |
497 @staticmethod | |
498 def add_user_to_group(group, user): | |
499 ugm = UsersGroupMember() | |
500 ugm.users_group = group | |
501 ugm.user = user | |
502 Session.add(ugm) | |
503 Session.commit() | |
504 return ugm | |
505 | 449 |
506 class Repository(Base, BaseModel): | 450 class Repository(Base, BaseModel): |
507 __tablename__ = 'repositories' | 451 __tablename__ = 'repositories' |
508 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},) | 452 __table_args__ = ( |
453 UniqueConstraint('repo_name'), | |
454 {'extend_existing': True}, | |
455 ) | |
509 | 456 |
510 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 457 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
511 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) | 458 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) |
512 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None) | 459 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None) |
513 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg') | 460 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg') |
519 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) | 466 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) |
520 | 467 |
521 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) | 468 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) |
522 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) | 469 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) |
523 | 470 |
524 | |
525 user = relationship('User') | 471 user = relationship('User') |
526 fork = relationship('Repository', remote_side=repo_id) | 472 fork = relationship('Repository', remote_side=repo_id) |
527 group = relationship('Group') | 473 group = relationship('RepoGroup') |
528 repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id') | 474 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id') |
529 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all') | 475 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all') |
530 stats = relationship('Statistics', cascade='all', uselist=False) | 476 stats = relationship('Statistics', cascade='all', uselist=False) |
531 | 477 |
532 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all') | 478 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all') |
533 | 479 |
534 logs = relationship('UserLog', cascade='all') | 480 logs = relationship('UserLog') |
535 | 481 |
536 def __repr__(self): | 482 def __repr__(self): |
537 return "<%s('%s:%s')>" % (self.__class__.__name__, | 483 return "<%s('%s:%s')>" % (self.__class__.__name__, |
538 self.repo_id, self.repo_name) | 484 self.repo_id, self.repo_name) |
539 | 485 |
545 def get_by_repo_name(cls, repo_name): | 491 def get_by_repo_name(cls, repo_name): |
546 q = Session.query(cls).filter(cls.repo_name == repo_name) | 492 q = Session.query(cls).filter(cls.repo_name == repo_name) |
547 q = q.options(joinedload(Repository.fork))\ | 493 q = q.options(joinedload(Repository.fork))\ |
548 .options(joinedload(Repository.user))\ | 494 .options(joinedload(Repository.user))\ |
549 .options(joinedload(Repository.group)) | 495 .options(joinedload(Repository.group)) |
550 return q.one() | 496 return q.scalar() |
551 | 497 |
552 @classmethod | 498 @classmethod |
553 def get_repo_forks(cls, repo_id): | 499 def get_repo_forks(cls, repo_id): |
554 return cls.query().filter(Repository.fork_id == repo_id) | 500 return cls.query().filter(Repository.fork_id == repo_id) |
555 | 501 |
558 """ | 504 """ |
559 Returns base path when all repos are stored | 505 Returns base path when all repos are stored |
560 | 506 |
561 :param cls: | 507 :param cls: |
562 """ | 508 """ |
563 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == | 509 q = Session.query(RhodeCodeUi)\ |
564 cls.url_sep()) | 510 .filter(RhodeCodeUi.ui_key == cls.url_sep()) |
565 q.options(FromCache("sql_cache_short", "repository_repo_path")) | 511 q = q.options(FromCache("sql_cache_short", "repository_repo_path")) |
566 return q.one().ui_value | 512 return q.one().ui_value |
567 | 513 |
568 @property | 514 @property |
569 def just_name(self): | 515 def just_name(self): |
570 return self.repo_name.split(Repository.url_sep())[-1] | 516 return self.repo_name.split(Repository.url_sep())[-1] |
596 Returns base full path for that repository means where it actually | 542 Returns base full path for that repository means where it actually |
597 exists on a filesystem | 543 exists on a filesystem |
598 """ | 544 """ |
599 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == | 545 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == |
600 Repository.url_sep()) | 546 Repository.url_sep()) |
601 q.options(FromCache("sql_cache_short", "repository_repo_path")) | 547 q = q.options(FromCache("sql_cache_short", "repository_repo_path")) |
602 return q.one().ui_value | 548 return q.one().ui_value |
603 | 549 |
604 @property | 550 @property |
605 def repo_full_path(self): | 551 def repo_full_path(self): |
606 p = [self.repo_path] | 552 p = [self.repo_path] |
631 #clean the baseui object | 577 #clean the baseui object |
632 baseui._ocfg = config.config() | 578 baseui._ocfg = config.config() |
633 baseui._ucfg = config.config() | 579 baseui._ucfg = config.config() |
634 baseui._tcfg = config.config() | 580 baseui._tcfg = config.config() |
635 | 581 |
636 | |
637 ret = RhodeCodeUi.query()\ | 582 ret = RhodeCodeUi.query()\ |
638 .options(FromCache("sql_cache_short", "repository_repo_ui")).all() | 583 .options(FromCache("sql_cache_short", "repository_repo_ui")).all() |
639 | 584 |
640 hg_ui = ret | 585 hg_ui = ret |
641 for ui_ in hg_ui: | 586 for ui_ in hg_ui: |
649 @classmethod | 594 @classmethod |
650 def is_valid(cls, repo_name): | 595 def is_valid(cls, repo_name): |
651 """ | 596 """ |
652 returns True if given repo name is a valid filesystem repository | 597 returns True if given repo name is a valid filesystem repository |
653 | 598 |
654 @param cls: | 599 :param cls: |
655 @param repo_name: | 600 :param repo_name: |
656 """ | 601 """ |
657 from rhodecode.lib.utils import is_valid_repo | 602 from rhodecode.lib.utils import is_valid_repo |
658 | 603 |
659 return is_valid_repo(repo_name, cls.base_path()) | 604 return is_valid_repo(repo_name, cls.base_path()) |
660 | |
661 | 605 |
662 #========================================================================== | 606 #========================================================================== |
663 # SCM PROPERTIES | 607 # SCM PROPERTIES |
664 #========================================================================== | 608 #========================================================================== |
665 | 609 |
676 | 620 |
677 @property | 621 @property |
678 def last_change(self): | 622 def last_change(self): |
679 return self.scm_instance.last_change | 623 return self.scm_instance.last_change |
680 | 624 |
625 def comments(self, revisions=None): | |
626 """ | |
627 Returns comments for this repository grouped by revisions | |
628 | |
629 :param revisions: filter query by revisions only | |
630 """ | |
631 cmts = ChangesetComment.query()\ | |
632 .filter(ChangesetComment.repo == self) | |
633 if revisions: | |
634 cmts = cmts.filter(ChangesetComment.revision.in_(revisions)) | |
635 grouped = defaultdict(list) | |
636 for cmt in cmts.all(): | |
637 grouped[cmt.revision].append(cmt) | |
638 return grouped | |
639 | |
681 #========================================================================== | 640 #========================================================================== |
682 # SCM CACHE INSTANCE | 641 # SCM CACHE INSTANCE |
683 #========================================================================== | 642 #========================================================================== |
684 | 643 |
685 @property | 644 @property |
686 def invalidate(self): | 645 def invalidate(self): |
687 """ | 646 return CacheInvalidation.invalidate(self.repo_name) |
688 Returns Invalidation object if this repo should be invalidated | |
689 None otherwise. `cache_active = False` means that this cache | |
690 state is not valid and needs to be invalidated | |
691 """ | |
692 return CacheInvalidation.query()\ | |
693 .filter(CacheInvalidation.cache_key == self.repo_name)\ | |
694 .filter(CacheInvalidation.cache_active == False)\ | |
695 .scalar() | |
696 | 647 |
697 def set_invalidate(self): | 648 def set_invalidate(self): |
698 """ | 649 """ |
699 set a cache for invalidation for this instance | 650 set a cache for invalidation for this instance |
700 """ | 651 """ |
701 inv = CacheInvalidation.query()\ | 652 CacheInvalidation.set_invalidate(self.repo_name) |
702 .filter(CacheInvalidation.cache_key == self.repo_name)\ | |
703 .scalar() | |
704 | |
705 if inv is None: | |
706 inv = CacheInvalidation(self.repo_name) | |
707 inv.cache_active = True | |
708 Session.add(inv) | |
709 Session.commit() | |
710 | 653 |
711 @LazyProperty | 654 @LazyProperty |
712 def scm_instance(self): | 655 def scm_instance(self): |
713 return self.__get_instance() | 656 return self.__get_instance() |
714 | 657 |
715 @property | 658 @property |
716 def scm_instance_cached(self): | 659 def scm_instance_cached(self): |
717 @cache_region('long_term') | 660 @cache_region('long_term') |
718 def _c(repo_name): | 661 def _c(repo_name): |
719 return self.__get_instance() | 662 return self.__get_instance() |
720 | 663 rn = self.repo_name |
721 # TODO: remove this trick when beaker 1.6 is released | 664 log.debug('Getting cached instance of repo') |
722 # and have fixed this issue with not supporting unicode keys | |
723 rn = safe_str(self.repo_name) | |
724 | |
725 inv = self.invalidate | 665 inv = self.invalidate |
726 if inv is not None: | 666 if inv is not None: |
727 region_invalidate(_c, None, rn) | 667 region_invalidate(_c, None, rn) |
728 # update our cache | 668 # update our cache |
729 inv.cache_active = True | 669 CacheInvalidation.set_valid(inv.cache_key) |
730 Session.add(inv) | |
731 Session.commit() | |
732 | |
733 return _c(rn) | 670 return _c(rn) |
734 | 671 |
735 def __get_instance(self): | 672 def __get_instance(self): |
736 | |
737 repo_full_path = self.repo_full_path | 673 repo_full_path = self.repo_full_path |
738 | |
739 try: | 674 try: |
740 alias = get_scm(repo_full_path)[0] | 675 alias = get_scm(repo_full_path)[0] |
741 log.debug('Creating instance of %s repository', alias) | 676 log.debug('Creating instance of %s repository' % alias) |
742 backend = get_backend(alias) | 677 backend = get_backend(alias) |
743 except VCSError: | 678 except VCSError: |
744 log.error(traceback.format_exc()) | 679 log.error(traceback.format_exc()) |
745 log.error('Perhaps this repository is in db and not in ' | 680 log.error('Perhaps this repository is in db and not in ' |
746 'filesystem run rescan repositories with ' | 681 'filesystem run rescan repositories with ' |
749 | 684 |
750 if alias == 'hg': | 685 if alias == 'hg': |
751 | 686 |
752 repo = backend(safe_str(repo_full_path), create=False, | 687 repo = backend(safe_str(repo_full_path), create=False, |
753 baseui=self._ui) | 688 baseui=self._ui) |
754 #skip hidden web repository | 689 # skip hidden web repository |
755 if repo._get_hidden(): | 690 if repo._get_hidden(): |
756 return | 691 return |
757 else: | 692 else: |
758 repo = backend(repo_full_path, create=False) | 693 repo = backend(repo_full_path, create=False) |
759 | 694 |
760 return repo | 695 return repo |
761 | 696 |
762 | 697 |
763 class Group(Base, BaseModel): | 698 class RepoGroup(Base, BaseModel): |
764 __tablename__ = 'groups' | 699 __tablename__ = 'groups' |
765 __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'), | 700 __table_args__ = ( |
766 CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},) | 701 UniqueConstraint('group_name', 'group_parent_id'), |
767 __mapper_args__ = {'order_by':'group_name'} | 702 CheckConstraint('group_id != group_parent_id'), |
703 {'extend_existing': True}, | |
704 ) | |
705 __mapper_args__ = {'order_by': 'group_name'} | |
768 | 706 |
769 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 707 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
770 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) | 708 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) |
771 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) | 709 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) |
772 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 710 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
773 | 711 |
774 parent_group = relationship('Group', remote_side=group_id) | 712 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') |
775 | 713 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all') |
714 | |
715 parent_group = relationship('RepoGroup', remote_side=group_id) | |
776 | 716 |
777 def __init__(self, group_name='', parent_group=None): | 717 def __init__(self, group_name='', parent_group=None): |
778 self.group_name = group_name | 718 self.group_name = group_name |
779 self.parent_group = parent_group | 719 self.parent_group = parent_group |
780 | 720 |
836 groups.insert(0, gr) | 776 groups.insert(0, gr) |
837 return groups | 777 return groups |
838 | 778 |
839 @property | 779 @property |
840 def children(self): | 780 def children(self): |
841 return Group.query().filter(Group.parent_group == self) | 781 return RepoGroup.query().filter(RepoGroup.parent_group == self) |
842 | 782 |
843 @property | 783 @property |
844 def name(self): | 784 def name(self): |
845 return self.group_name.split(Group.url_sep())[-1] | 785 return self.group_name.split(RepoGroup.url_sep())[-1] |
846 | 786 |
847 @property | 787 @property |
848 def full_path(self): | 788 def full_path(self): |
849 return self.group_name | 789 return self.group_name |
850 | 790 |
851 @property | 791 @property |
852 def full_path_splitted(self): | 792 def full_path_splitted(self): |
853 return self.group_name.split(Group.url_sep()) | 793 return self.group_name.split(RepoGroup.url_sep()) |
854 | 794 |
855 @property | 795 @property |
856 def repositories(self): | 796 def repositories(self): |
857 return Repository.query().filter(Repository.group == self) | 797 return Repository.query().filter(Repository.group == self) |
858 | 798 |
867 cnt += children_count(child) | 807 cnt += children_count(child) |
868 return cnt | 808 return cnt |
869 | 809 |
870 return cnt + children_count(self) | 810 return cnt + children_count(self) |
871 | 811 |
872 | |
873 def get_new_name(self, group_name): | 812 def get_new_name(self, group_name): |
874 """ | 813 """ |
875 returns new full group name based on parent and new name | 814 returns new full group name based on parent and new name |
876 | 815 |
877 :param group_name: | 816 :param group_name: |
878 """ | 817 """ |
879 path_prefix = (self.parent_group.full_path_splitted if | 818 path_prefix = (self.parent_group.full_path_splitted if |
880 self.parent_group else []) | 819 self.parent_group else []) |
881 return Group.url_sep().join(path_prefix + [group_name]) | 820 return RepoGroup.url_sep().join(path_prefix + [group_name]) |
882 | 821 |
883 | 822 |
884 class Permission(Base, BaseModel): | 823 class Permission(Base, BaseModel): |
885 __tablename__ = 'permissions' | 824 __tablename__ = 'permissions' |
886 __table_args__ = {'extend_existing':True} | 825 __table_args__ = {'extend_existing': True} |
887 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 826 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
888 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 827 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
889 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 828 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
890 | 829 |
891 def __repr__(self): | 830 def __repr__(self): |
892 return "<%s('%s:%s')>" % (self.__class__.__name__, | 831 return "<%s('%s:%s')>" % ( |
893 self.permission_id, self.permission_name) | 832 self.__class__.__name__, self.permission_id, self.permission_name |
833 ) | |
894 | 834 |
895 @classmethod | 835 @classmethod |
896 def get_by_key(cls, key): | 836 def get_by_key(cls, key): |
897 return cls.query().filter(cls.permission_name == key).scalar() | 837 return cls.query().filter(cls.permission_name == key).scalar() |
898 | 838 |
899 class RepoToPerm(Base, BaseModel): | 839 @classmethod |
840 def get_default_perms(cls, default_user_id): | |
841 q = Session.query(UserRepoToPerm, Repository, cls)\ | |
842 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\ | |
843 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\ | |
844 .filter(UserRepoToPerm.user_id == default_user_id) | |
845 | |
846 return q.all() | |
847 | |
848 @classmethod | |
849 def get_default_group_perms(cls, default_user_id): | |
850 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\ | |
851 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\ | |
852 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\ | |
853 .filter(UserRepoGroupToPerm.user_id == default_user_id) | |
854 | |
855 return q.all() | |
856 | |
857 | |
858 class UserRepoToPerm(Base, BaseModel): | |
900 __tablename__ = 'repo_to_perm' | 859 __tablename__ = 'repo_to_perm' |
901 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True}) | 860 __table_args__ = ( |
861 UniqueConstraint('user_id', 'repository_id', 'permission_id'), | |
862 {'extend_existing': True} | |
863 ) | |
902 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 864 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
903 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) | 865 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) |
904 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) | 866 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) |
905 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) | 867 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) |
906 | 868 |
907 user = relationship('User') | 869 user = relationship('User') |
870 repository = relationship('Repository') | |
908 permission = relationship('Permission') | 871 permission = relationship('Permission') |
909 repository = relationship('Repository') | 872 |
873 @classmethod | |
874 def create(cls, user, repository, permission): | |
875 n = cls() | |
876 n.user = user | |
877 n.repository = repository | |
878 n.permission = permission | |
879 Session.add(n) | |
880 return n | |
881 | |
882 def __repr__(self): | |
883 return '<user:%s => %s >' % (self.user, self.repository) | |
884 | |
910 | 885 |
911 class UserToPerm(Base, BaseModel): | 886 class UserToPerm(Base, BaseModel): |
912 __tablename__ = 'user_to_perm' | 887 __tablename__ = 'user_to_perm' |
913 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True}) | 888 __table_args__ = ( |
889 UniqueConstraint('user_id', 'permission_id'), | |
890 {'extend_existing': True} | |
891 ) | |
914 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 892 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
915 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) | 893 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) |
916 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) | 894 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) |
917 | 895 |
918 user = relationship('User') | 896 user = relationship('User') |
919 permission = relationship('Permission') | 897 permission = relationship('Permission', lazy='joined') |
920 | 898 |
921 @classmethod | |
922 def has_perm(cls, user_id, perm): | |
923 if not isinstance(perm, Permission): | |
924 raise Exception('perm needs to be an instance of Permission class') | |
925 | |
926 return cls.query().filter(cls.user_id == user_id)\ | |
927 .filter(cls.permission == perm).scalar() is not None | |
928 | |
929 @classmethod | |
930 def grant_perm(cls, user_id, perm): | |
931 if not isinstance(perm, Permission): | |
932 raise Exception('perm needs to be an instance of Permission class') | |
933 | |
934 new = cls() | |
935 new.user_id = user_id | |
936 new.permission = perm | |
937 try: | |
938 Session.add(new) | |
939 Session.commit() | |
940 except: | |
941 Session.rollback() | |
942 | |
943 | |
944 @classmethod | |
945 def revoke_perm(cls, user_id, perm): | |
946 if not isinstance(perm, Permission): | |
947 raise Exception('perm needs to be an instance of Permission class') | |
948 | |
949 try: | |
950 cls.query().filter(cls.user_id == user_id)\ | |
951 .filter(cls.permission == perm).delete() | |
952 Session.commit() | |
953 except: | |
954 Session.rollback() | |
955 | 899 |
956 class UsersGroupRepoToPerm(Base, BaseModel): | 900 class UsersGroupRepoToPerm(Base, BaseModel): |
957 __tablename__ = 'users_group_repo_to_perm' | 901 __tablename__ = 'users_group_repo_to_perm' |
958 __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True}) | 902 __table_args__ = ( |
903 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), | |
904 {'extend_existing': True} | |
905 ) | |
959 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 906 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
960 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) | 907 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) |
961 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) | 908 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) |
962 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) | 909 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) |
963 | 910 |
964 users_group = relationship('UsersGroup') | 911 users_group = relationship('UsersGroup') |
965 permission = relationship('Permission') | 912 permission = relationship('Permission') |
966 repository = relationship('Repository') | 913 repository = relationship('Repository') |
967 | 914 |
915 @classmethod | |
916 def create(cls, users_group, repository, permission): | |
917 n = cls() | |
918 n.users_group = users_group | |
919 n.repository = repository | |
920 n.permission = permission | |
921 Session.add(n) | |
922 return n | |
923 | |
968 def __repr__(self): | 924 def __repr__(self): |
969 return '<userGroup:%s => %s >' % (self.users_group, self.repository) | 925 return '<userGroup:%s => %s >' % (self.users_group, self.repository) |
970 | 926 |
927 | |
971 class UsersGroupToPerm(Base, BaseModel): | 928 class UsersGroupToPerm(Base, BaseModel): |
972 __tablename__ = 'users_group_to_perm' | 929 __tablename__ = 'users_group_to_perm' |
930 __table_args__ = ( | |
931 UniqueConstraint('users_group_id', 'permission_id',), | |
932 {'extend_existing': True} | |
933 ) | |
973 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 934 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
974 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) | 935 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) |
975 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) | 936 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) |
976 | 937 |
977 users_group = relationship('UsersGroup') | 938 users_group = relationship('UsersGroup') |
978 permission = relationship('Permission') | 939 permission = relationship('Permission') |
979 | 940 |
980 | 941 |
981 @classmethod | 942 class UserRepoGroupToPerm(Base, BaseModel): |
982 def has_perm(cls, users_group_id, perm): | 943 __tablename__ = 'user_repo_group_to_perm' |
983 if not isinstance(perm, Permission): | 944 __table_args__ = ( |
984 raise Exception('perm needs to be an instance of Permission class') | 945 UniqueConstraint('user_id', 'group_id', 'permission_id'), |
985 | 946 {'extend_existing': True} |
986 return cls.query().filter(cls.users_group_id == | 947 ) |
987 users_group_id)\ | |
988 .filter(cls.permission == perm)\ | |
989 .scalar() is not None | |
990 | |
991 @classmethod | |
992 def grant_perm(cls, users_group_id, perm): | |
993 if not isinstance(perm, Permission): | |
994 raise Exception('perm needs to be an instance of Permission class') | |
995 | |
996 new = cls() | |
997 new.users_group_id = users_group_id | |
998 new.permission = perm | |
999 try: | |
1000 Session.add(new) | |
1001 Session.commit() | |
1002 except: | |
1003 Session.rollback() | |
1004 | |
1005 | |
1006 @classmethod | |
1007 def revoke_perm(cls, users_group_id, perm): | |
1008 if not isinstance(perm, Permission): | |
1009 raise Exception('perm needs to be an instance of Permission class') | |
1010 | |
1011 try: | |
1012 cls.query().filter(cls.users_group_id == users_group_id)\ | |
1013 .filter(cls.permission == perm).delete() | |
1014 Session.commit() | |
1015 except: | |
1016 Session.rollback() | |
1017 | |
1018 | |
1019 class GroupToPerm(Base, BaseModel): | |
1020 __tablename__ = 'group_to_perm' | |
1021 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True}) | |
1022 | 948 |
1023 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 949 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
1024 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) | 950 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) |
951 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) | |
1025 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) | 952 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) |
953 | |
954 user = relationship('User') | |
955 group = relationship('RepoGroup') | |
956 permission = relationship('Permission') | |
957 | |
958 | |
959 class UsersGroupRepoGroupToPerm(Base, BaseModel): | |
960 __tablename__ = 'users_group_repo_group_to_perm' | |
961 __table_args__ = ( | |
962 UniqueConstraint('users_group_id', 'group_id'), | |
963 {'extend_existing': True} | |
964 ) | |
965 | |
966 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) | |
967 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None) | |
1026 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) | 968 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None) |
1027 | 969 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None) |
1028 user = relationship('User') | 970 |
971 users_group = relationship('UsersGroup') | |
1029 permission = relationship('Permission') | 972 permission = relationship('Permission') |
1030 group = relationship('Group') | 973 group = relationship('RepoGroup') |
974 | |
1031 | 975 |
1032 class Statistics(Base, BaseModel): | 976 class Statistics(Base, BaseModel): |
1033 __tablename__ = 'statistics' | 977 __tablename__ = 'statistics' |
1034 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True}) | 978 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing': True}) |
1035 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 979 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
1036 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) | 980 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) |
1037 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) | 981 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) |
1038 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data | 982 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data |
1039 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data | 983 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data |
1040 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data | 984 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data |
1041 | 985 |
1042 repository = relationship('Repository', single_parent=True) | 986 repository = relationship('Repository', single_parent=True) |
1043 | 987 |
988 | |
1044 class UserFollowing(Base, BaseModel): | 989 class UserFollowing(Base, BaseModel): |
1045 __tablename__ = 'user_followings' | 990 __tablename__ = 'user_followings' |
1046 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'), | 991 __table_args__ = ( |
1047 UniqueConstraint('user_id', 'follows_user_id') | 992 UniqueConstraint('user_id', 'follows_repository_id'), |
1048 , {'extend_existing':True}) | 993 UniqueConstraint('user_id', 'follows_user_id'), |
994 {'extend_existing': True} | |
995 ) | |
1049 | 996 |
1050 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 997 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
1051 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) | 998 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) |
1052 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) | 999 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) |
1053 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) | 1000 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) |
1056 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') | 1003 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') |
1057 | 1004 |
1058 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') | 1005 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') |
1059 follows_repository = relationship('Repository', order_by='Repository.repo_name') | 1006 follows_repository = relationship('Repository', order_by='Repository.repo_name') |
1060 | 1007 |
1061 | |
1062 @classmethod | 1008 @classmethod |
1063 def get_repo_followers(cls, repo_id): | 1009 def get_repo_followers(cls, repo_id): |
1064 return cls.query().filter(cls.follows_repo_id == repo_id) | 1010 return cls.query().filter(cls.follows_repo_id == repo_id) |
1065 | 1011 |
1012 | |
1066 class CacheInvalidation(Base, BaseModel): | 1013 class CacheInvalidation(Base, BaseModel): |
1067 __tablename__ = 'cache_invalidation' | 1014 __tablename__ = 'cache_invalidation' |
1068 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True}) | 1015 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing': True}) |
1069 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | 1016 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
1070 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 1017 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
1071 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | 1018 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
1072 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) | 1019 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) |
1073 | 1020 |
1074 | |
1075 def __init__(self, cache_key, cache_args=''): | 1021 def __init__(self, cache_key, cache_args=''): |
1076 self.cache_key = cache_key | 1022 self.cache_key = cache_key |
1077 self.cache_args = cache_args | 1023 self.cache_args = cache_args |
1078 self.cache_active = False | 1024 self.cache_active = False |
1079 | 1025 |
1080 def __repr__(self): | 1026 def __repr__(self): |
1081 return "<%s('%s:%s')>" % (self.__class__.__name__, | 1027 return "<%s('%s:%s')>" % (self.__class__.__name__, |
1082 self.cache_id, self.cache_key) | 1028 self.cache_id, self.cache_key) |
1083 | 1029 |
1030 @classmethod | |
1031 def _get_key(cls, key): | |
1032 """ | |
1033 Wrapper for generating a key | |
1034 | |
1035 :param key: | |
1036 """ | |
1037 import rhodecode | |
1038 prefix = '' | |
1039 iid = rhodecode.CONFIG.get('instance_id') | |
1040 if iid: | |
1041 prefix = iid | |
1042 return "%s%s" % (prefix, key) | |
1043 | |
1044 @classmethod | |
1045 def get_by_key(cls, key): | |
1046 return cls.query().filter(cls.cache_key == key).scalar() | |
1047 | |
1048 @classmethod | |
1049 def invalidate(cls, key): | |
1050 """ | |
1051 Returns Invalidation object if this given key should be invalidated | |
1052 None otherwise. `cache_active = False` means that this cache | |
1053 state is not valid and needs to be invalidated | |
1054 | |
1055 :param key: | |
1056 """ | |
1057 return cls.query()\ | |
1058 .filter(CacheInvalidation.cache_key == key)\ | |
1059 .filter(CacheInvalidation.cache_active == False)\ | |
1060 .scalar() | |
1061 | |
1062 @classmethod | |
1063 def set_invalidate(cls, key): | |
1064 """ | |
1065 Mark this Cache key for invalidation | |
1066 | |
1067 :param key: | |
1068 """ | |
1069 | |
1070 log.debug('marking %s for invalidation' % key) | |
1071 inv_obj = Session.query(cls)\ | |
1072 .filter(cls.cache_key == key).scalar() | |
1073 if inv_obj: | |
1074 inv_obj.cache_active = False | |
1075 else: | |
1076 log.debug('cache key not found in invalidation db -> creating one') | |
1077 inv_obj = CacheInvalidation(key) | |
1078 | |
1079 try: | |
1080 Session.add(inv_obj) | |
1081 Session.commit() | |
1082 except Exception: | |
1083 log.error(traceback.format_exc()) | |
1084 Session.rollback() | |
1085 | |
1086 @classmethod | |
1087 def set_valid(cls, key): | |
1088 """ | |
1089 Mark this cache key as active and currently cached | |
1090 | |
1091 :param key: | |
1092 """ | |
1093 inv_obj = cls.get_by_key(key) | |
1094 inv_obj.cache_active = True | |
1095 Session.add(inv_obj) | |
1096 Session.commit() | |
1097 | |
1098 | |
1099 class ChangesetComment(Base, BaseModel): | |
1100 __tablename__ = 'changeset_comments' | |
1101 __table_args__ = ({'extend_existing': True},) | |
1102 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) | |
1103 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) | |
1104 revision = Column('revision', String(40), nullable=False) | |
1105 line_no = Column('line_no', Unicode(10), nullable=True) | |
1106 f_path = Column('f_path', Unicode(1000), nullable=True) | |
1107 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) | |
1108 text = Column('text', Unicode(25000), nullable=False) | |
1109 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) | |
1110 | |
1111 author = relationship('User', lazy='joined') | |
1112 repo = relationship('Repository') | |
1113 | |
1114 @classmethod | |
1115 def get_users(cls, revision): | |
1116 """ | |
1117 Returns user associated with this changesetComment. ie those | |
1118 who actually commented | |
1119 | |
1120 :param cls: | |
1121 :param revision: | |
1122 """ | |
1123 return Session.query(User)\ | |
1124 .filter(cls.revision == revision)\ | |
1125 .join(ChangesetComment.author).all() | |
1126 | |
1127 | |
1128 class Notification(Base, BaseModel): | |
1129 __tablename__ = 'notifications' | |
1130 __table_args__ = ({'extend_existing': True},) | |
1131 | |
1132 TYPE_CHANGESET_COMMENT = u'cs_comment' | |
1133 TYPE_MESSAGE = u'message' | |
1134 TYPE_MENTION = u'mention' | |
1135 TYPE_REGISTRATION = u'registration' | |
1136 | |
1137 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) | |
1138 subject = Column('subject', Unicode(512), nullable=True) | |
1139 body = Column('body', Unicode(50000), nullable=True) | |
1140 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) | |
1141 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) | |
1142 type_ = Column('type', Unicode(256)) | |
1143 | |
1144 created_by_user = relationship('User') | |
1145 notifications_to_users = relationship('UserNotification', lazy='joined', | |
1146 cascade="all, delete, delete-orphan") | |
1147 | |
1148 @property | |
1149 def recipients(self): | |
1150 return [x.user for x in UserNotification.query()\ | |
1151 .filter(UserNotification.notification == self).all()] | |
1152 | |
1153 @classmethod | |
1154 def create(cls, created_by, subject, body, recipients, type_=None): | |
1155 if type_ is None: | |
1156 type_ = Notification.TYPE_MESSAGE | |
1157 | |
1158 notification = cls() | |
1159 notification.created_by_user = created_by | |
1160 notification.subject = subject | |
1161 notification.body = body | |
1162 notification.type_ = type_ | |
1163 notification.created_on = datetime.datetime.now() | |
1164 | |
1165 for u in recipients: | |
1166 assoc = UserNotification() | |
1167 assoc.notification = notification | |
1168 u.notifications.append(assoc) | |
1169 Session.add(notification) | |
1170 return notification | |
1171 | |
1172 @property | |
1173 def description(self): | |
1174 from rhodecode.model.notification import NotificationModel | |
1175 return NotificationModel().make_description(self) | |
1176 | |
1177 | |
1178 class UserNotification(Base, BaseModel): | |
1179 __tablename__ = 'user_to_notification' | |
1180 __table_args__ = ( | |
1181 UniqueConstraint('user_id', 'notification_id'), | |
1182 {'extend_existing': True} | |
1183 ) | |
1184 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True) | |
1185 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True) | |
1186 read = Column('read', Boolean, default=False) | |
1187 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) | |
1188 | |
1189 user = relationship('User', lazy="joined") | |
1190 notification = relationship('Notification', lazy="joined", | |
1191 order_by=lambda: Notification.created_on.desc(),) | |
1192 | |
1193 def mark_as_read(self): | |
1194 self.read = True | |
1195 Session.add(self) | |
1196 | |
1197 | |
1084 class DbMigrateVersion(Base, BaseModel): | 1198 class DbMigrateVersion(Base, BaseModel): |
1085 __tablename__ = 'db_migrate_version' | 1199 __tablename__ = 'db_migrate_version' |
1086 __table_args__ = {'extend_existing':True} | 1200 __table_args__ = {'extend_existing': True} |
1087 repository_id = Column('repository_id', String(250), primary_key=True) | 1201 repository_id = Column('repository_id', String(250), primary_key=True) |
1088 repository_path = Column('repository_path', Text) | 1202 repository_path = Column('repository_path', Text) |
1089 version = Column('version', Integer) | 1203 version = Column('version', Integer) |
1090 |