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