##// END OF EJS Templates
fixes #298, ldap email addresses created by rhodecode automatically during first login didn't get converted to lower case, which lead to lookup failures and than wrong checks for uniqueness. Fixed that by putting a setter on db model column that will enforce converting to lowercase.
marcink -
r1757:2aa7f454 beta
parent child Browse files
Show More
@@ -1,1097 +1,1108 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) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 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
30
31 from sqlalchemy import *
31 from sqlalchemy import *
32 from sqlalchemy.ext.hybrid import hybrid_property
32 from sqlalchemy.ext.hybrid import hybrid_property
33 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
33 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
34 from beaker.cache import cache_region, region_invalidate
34 from beaker.cache import cache_region, region_invalidate
35
35
36 from vcs import get_backend
36 from vcs import get_backend
37 from vcs.utils.helpers import get_scm
37 from vcs.utils.helpers import get_scm
38 from vcs.exceptions import VCSError
38 from vcs.exceptions import VCSError
39 from vcs.utils.lazy import LazyProperty
39 from vcs.utils.lazy import LazyProperty
40
40
41 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, safe_unicode
41 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, safe_unicode
42 from rhodecode.lib.exceptions import UsersGroupsAssignedException
42 from rhodecode.lib.exceptions import UsersGroupsAssignedException
43 from rhodecode.lib.compat import json
43 from rhodecode.lib.compat import json
44 from rhodecode.lib.caching_query import FromCache
44 from rhodecode.lib.caching_query import FromCache
45
45
46 from rhodecode.model.meta import Base, Session
46 from rhodecode.model.meta import Base, Session
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50 #==============================================================================
50 #==============================================================================
51 # BASE CLASSES
51 # BASE CLASSES
52 #==============================================================================
52 #==============================================================================
53
53
54 class ModelSerializer(json.JSONEncoder):
54 class ModelSerializer(json.JSONEncoder):
55 """
55 """
56 Simple Serializer for JSON,
56 Simple Serializer for JSON,
57
57
58 usage::
58 usage::
59
59
60 to make object customized for serialization implement a __json__
60 to make object customized for serialization implement a __json__
61 method that will return a dict for serialization into json
61 method that will return a dict for serialization into json
62
62
63 example::
63 example::
64
64
65 class Task(object):
65 class Task(object):
66
66
67 def __init__(self, name, value):
67 def __init__(self, name, value):
68 self.name = name
68 self.name = name
69 self.value = value
69 self.value = value
70
70
71 def __json__(self):
71 def __json__(self):
72 return dict(name=self.name,
72 return dict(name=self.name,
73 value=self.value)
73 value=self.value)
74
74
75 """
75 """
76
76
77 def default(self, obj):
77 def default(self, obj):
78
78
79 if hasattr(obj, '__json__'):
79 if hasattr(obj, '__json__'):
80 return obj.__json__()
80 return obj.__json__()
81 else:
81 else:
82 return json.JSONEncoder.default(self, obj)
82 return json.JSONEncoder.default(self, obj)
83
83
84 class BaseModel(object):
84 class BaseModel(object):
85 """Base Model for all classess
85 """Base Model for all classess
86
86
87 """
87 """
88
88
89 @classmethod
89 @classmethod
90 def _get_keys(cls):
90 def _get_keys(cls):
91 """return column names for this model """
91 """return column names for this model """
92 return class_mapper(cls).c.keys()
92 return class_mapper(cls).c.keys()
93
93
94 def get_dict(self):
94 def get_dict(self):
95 """return dict with keys and values corresponding
95 """return dict with keys and values corresponding
96 to this model data """
96 to this model data """
97
97
98 d = {}
98 d = {}
99 for k in self._get_keys():
99 for k in self._get_keys():
100 d[k] = getattr(self, k)
100 d[k] = getattr(self, k)
101 return d
101 return d
102
102
103 def get_appstruct(self):
103 def get_appstruct(self):
104 """return list with keys and values tupples corresponding
104 """return list with keys and values tupples corresponding
105 to this model data """
105 to this model data """
106
106
107 l = []
107 l = []
108 for k in self._get_keys():
108 for k in self._get_keys():
109 l.append((k, getattr(self, k),))
109 l.append((k, getattr(self, k),))
110 return l
110 return l
111
111
112 def populate_obj(self, populate_dict):
112 def populate_obj(self, populate_dict):
113 """populate model with data from given populate_dict"""
113 """populate model with data from given populate_dict"""
114
114
115 for k in self._get_keys():
115 for k in self._get_keys():
116 if k in populate_dict:
116 if k in populate_dict:
117 setattr(self, k, populate_dict[k])
117 setattr(self, k, populate_dict[k])
118
118
119 @classmethod
119 @classmethod
120 def query(cls):
120 def query(cls):
121 return Session.query(cls)
121 return Session.query(cls)
122
122
123 @classmethod
123 @classmethod
124 def get(cls, id_):
124 def get(cls, id_):
125 if id_:
125 if id_:
126 return cls.query().get(id_)
126 return cls.query().get(id_)
127
127
128 @classmethod
128 @classmethod
129 def getAll(cls):
129 def getAll(cls):
130 return cls.query().all()
130 return cls.query().all()
131
131
132 @classmethod
132 @classmethod
133 def delete(cls, id_):
133 def delete(cls, id_):
134 obj = cls.query().get(id_)
134 obj = cls.query().get(id_)
135 Session.delete(obj)
135 Session.delete(obj)
136
136
137
137
138 class RhodeCodeSetting(Base, BaseModel):
138 class RhodeCodeSetting(Base, BaseModel):
139 __tablename__ = 'rhodecode_settings'
139 __tablename__ = 'rhodecode_settings'
140 __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True})
140 __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True})
141 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
141 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
142 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
142 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
143 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
143 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
144
144
145 def __init__(self, k='', v=''):
145 def __init__(self, k='', v=''):
146 self.app_settings_name = k
146 self.app_settings_name = k
147 self.app_settings_value = v
147 self.app_settings_value = v
148
148
149
149
150 @validates('_app_settings_value')
150 @validates('_app_settings_value')
151 def validate_settings_value(self, key, val):
151 def validate_settings_value(self, key, val):
152 assert type(val) == unicode
152 assert type(val) == unicode
153 return val
153 return val
154
154
155 @hybrid_property
155 @hybrid_property
156 def app_settings_value(self):
156 def app_settings_value(self):
157 v = self._app_settings_value
157 v = self._app_settings_value
158 if v == 'ldap_active':
158 if v == 'ldap_active':
159 v = str2bool(v)
159 v = str2bool(v)
160 return v
160 return v
161
161
162 @app_settings_value.setter
162 @app_settings_value.setter
163 def app_settings_value(self, val):
163 def app_settings_value(self, val):
164 """
164 """
165 Setter that will always make sure we use unicode in app_settings_value
165 Setter that will always make sure we use unicode in app_settings_value
166
166
167 :param val:
167 :param val:
168 """
168 """
169 self._app_settings_value = safe_unicode(val)
169 self._app_settings_value = safe_unicode(val)
170
170
171 def __repr__(self):
171 def __repr__(self):
172 return "<%s('%s:%s')>" % (self.__class__.__name__,
172 return "<%s('%s:%s')>" % (self.__class__.__name__,
173 self.app_settings_name, self.app_settings_value)
173 self.app_settings_name, self.app_settings_value)
174
174
175
175
176 @classmethod
176 @classmethod
177 def get_by_name(cls, ldap_key):
177 def get_by_name(cls, ldap_key):
178 return cls.query()\
178 return cls.query()\
179 .filter(cls.app_settings_name == ldap_key).scalar()
179 .filter(cls.app_settings_name == ldap_key).scalar()
180
180
181 @classmethod
181 @classmethod
182 def get_app_settings(cls, cache=False):
182 def get_app_settings(cls, cache=False):
183
183
184 ret = cls.query()
184 ret = cls.query()
185
185
186 if cache:
186 if cache:
187 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
187 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
188
188
189 if not ret:
189 if not ret:
190 raise Exception('Could not get application settings !')
190 raise Exception('Could not get application settings !')
191 settings = {}
191 settings = {}
192 for each in ret:
192 for each in ret:
193 settings['rhodecode_' + each.app_settings_name] = \
193 settings['rhodecode_' + each.app_settings_name] = \
194 each.app_settings_value
194 each.app_settings_value
195
195
196 return settings
196 return settings
197
197
198 @classmethod
198 @classmethod
199 def get_ldap_settings(cls, cache=False):
199 def get_ldap_settings(cls, cache=False):
200 ret = cls.query()\
200 ret = cls.query()\
201 .filter(cls.app_settings_name.startswith('ldap_')).all()
201 .filter(cls.app_settings_name.startswith('ldap_')).all()
202 fd = {}
202 fd = {}
203 for row in ret:
203 for row in ret:
204 fd.update({row.app_settings_name:row.app_settings_value})
204 fd.update({row.app_settings_name:row.app_settings_value})
205
205
206 return fd
206 return fd
207
207
208
208
209 class RhodeCodeUi(Base, BaseModel):
209 class RhodeCodeUi(Base, BaseModel):
210 __tablename__ = 'rhodecode_ui'
210 __tablename__ = 'rhodecode_ui'
211 __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True})
211 __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True})
212
212
213 HOOK_UPDATE = 'changegroup.update'
213 HOOK_UPDATE = 'changegroup.update'
214 HOOK_REPO_SIZE = 'changegroup.repo_size'
214 HOOK_REPO_SIZE = 'changegroup.repo_size'
215 HOOK_PUSH = 'pretxnchangegroup.push_logger'
215 HOOK_PUSH = 'pretxnchangegroup.push_logger'
216 HOOK_PULL = 'preoutgoing.pull_logger'
216 HOOK_PULL = 'preoutgoing.pull_logger'
217
217
218 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
218 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
219 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
219 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
220 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
220 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
221 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
221 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
222 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
222 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
223
223
224
224
225 @classmethod
225 @classmethod
226 def get_by_key(cls, key):
226 def get_by_key(cls, key):
227 return cls.query().filter(cls.ui_key == key)
227 return cls.query().filter(cls.ui_key == key)
228
228
229
229
230 @classmethod
230 @classmethod
231 def get_builtin_hooks(cls):
231 def get_builtin_hooks(cls):
232 q = cls.query()
232 q = cls.query()
233 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
233 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
234 cls.HOOK_REPO_SIZE,
234 cls.HOOK_REPO_SIZE,
235 cls.HOOK_PUSH, cls.HOOK_PULL]))
235 cls.HOOK_PUSH, cls.HOOK_PULL]))
236 return q.all()
236 return q.all()
237
237
238 @classmethod
238 @classmethod
239 def get_custom_hooks(cls):
239 def get_custom_hooks(cls):
240 q = cls.query()
240 q = cls.query()
241 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
241 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
242 cls.HOOK_REPO_SIZE,
242 cls.HOOK_REPO_SIZE,
243 cls.HOOK_PUSH, cls.HOOK_PULL]))
243 cls.HOOK_PUSH, cls.HOOK_PULL]))
244 q = q.filter(cls.ui_section == 'hooks')
244 q = q.filter(cls.ui_section == 'hooks')
245 return q.all()
245 return q.all()
246
246
247 @classmethod
247 @classmethod
248 def create_or_update_hook(cls, key, val):
248 def create_or_update_hook(cls, key, val):
249 new_ui = cls.get_by_key(key).scalar() or cls()
249 new_ui = cls.get_by_key(key).scalar() or cls()
250 new_ui.ui_section = 'hooks'
250 new_ui.ui_section = 'hooks'
251 new_ui.ui_active = True
251 new_ui.ui_active = True
252 new_ui.ui_key = key
252 new_ui.ui_key = key
253 new_ui.ui_value = val
253 new_ui.ui_value = val
254
254
255 Session.add(new_ui)
255 Session.add(new_ui)
256
256
257
257
258 class User(Base, BaseModel):
258 class User(Base, BaseModel):
259 __tablename__ = 'users'
259 __tablename__ = 'users'
260 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True})
260 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True})
261 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
261 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
262 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
262 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
263 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
263 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
264 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
264 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
265 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
265 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
266 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
266 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
267 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
267 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
268 email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
268 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
269 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
269 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
270 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
270 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
271 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
271 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
272
272
273 user_log = relationship('UserLog', cascade='all')
273 user_log = relationship('UserLog', cascade='all')
274 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
274 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
275
275
276 repositories = relationship('Repository')
276 repositories = relationship('Repository')
277 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
277 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
278 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
278 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
279
279
280 group_member = relationship('UsersGroupMember', cascade='all')
280 group_member = relationship('UsersGroupMember', cascade='all')
281
281
282 notifications = relationship('UserNotification',)
282 notifications = relationship('UserNotification',)
283
283
284 @hybrid_property
285 def email(self):
286 return self._email
287
288 @email.setter
289 def email(self, val):
290 self._email = val.lower() if val else None
291
284 @property
292 @property
285 def full_name(self):
293 def full_name(self):
286 return '%s %s' % (self.name, self.lastname)
294 return '%s %s' % (self.name, self.lastname)
287
295
288 @property
296 @property
289 def full_contact(self):
297 def full_contact(self):
290 return '%s %s <%s>' % (self.name, self.lastname, self.email)
298 return '%s %s <%s>' % (self.name, self.lastname, self.email)
291
299
292 @property
300 @property
293 def short_contact(self):
301 def short_contact(self):
294 return '%s %s' % (self.name, self.lastname)
302 return '%s %s' % (self.name, self.lastname)
295
303
296 @property
304 @property
297 def is_admin(self):
305 def is_admin(self):
298 return self.admin
306 return self.admin
299
307
300 def __repr__(self):
308 def __repr__(self):
301 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
309 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
302 self.user_id, self.username)
310 self.user_id, self.username)
303
311
304
312
305 @classmethod
313 @classmethod
306 def get_by_username(cls, username, case_insensitive=False, cache=False):
314 def get_by_username(cls, username, case_insensitive=False, cache=False):
307 if case_insensitive:
315 if case_insensitive:
308 q = cls.query().filter(cls.username.ilike(username))
316 q = cls.query().filter(cls.username.ilike(username))
309 else:
317 else:
310 q = cls.query().filter(cls.username == username)
318 q = cls.query().filter(cls.username == username)
311
319
312 if cache:
320 if cache:
313 q = q.options(FromCache("sql_cache_short",
321 q = q.options(FromCache("sql_cache_short",
314 "get_user_%s" % username))
322 "get_user_%s" % username))
315 return q.scalar()
323 return q.scalar()
316
324
317 @classmethod
325 @classmethod
318 def get_by_api_key(cls, api_key, cache=False):
326 def get_by_api_key(cls, api_key, cache=False):
319 q = cls.query().filter(cls.api_key == api_key)
327 q = cls.query().filter(cls.api_key == api_key)
320
328
321 if cache:
329 if cache:
322 q = q.options(FromCache("sql_cache_short",
330 q = q.options(FromCache("sql_cache_short",
323 "get_api_key_%s" % api_key))
331 "get_api_key_%s" % api_key))
324 return q.scalar()
332 return q.scalar()
325
333
326 @classmethod
334 @classmethod
327 def get_by_email(cls, email, cache=False):
335 def get_by_email(cls, email, case_insensitive=False, cache=False):
336 if case_insensitive:
337 q = cls.query().filter(cls.email.ilike(email))
338 else:
328 q = cls.query().filter(cls.email == email)
339 q = cls.query().filter(cls.email == email)
329
340
330 if cache:
341 if cache:
331 q = q.options(FromCache("sql_cache_short",
342 q = q.options(FromCache("sql_cache_short",
332 "get_api_key_%s" % email))
343 "get_api_key_%s" % email))
333 return q.scalar()
344 return q.scalar()
334
345
335 def update_lastlogin(self):
346 def update_lastlogin(self):
336 """Update user lastlogin"""
347 """Update user lastlogin"""
337 self.last_login = datetime.datetime.now()
348 self.last_login = datetime.datetime.now()
338 Session.add(self)
349 Session.add(self)
339 log.debug('updated user %s lastlogin', self.username)
350 log.debug('updated user %s lastlogin', self.username)
340
351
341
352
342 class UserLog(Base, BaseModel):
353 class UserLog(Base, BaseModel):
343 __tablename__ = 'user_logs'
354 __tablename__ = 'user_logs'
344 __table_args__ = {'extend_existing':True}
355 __table_args__ = {'extend_existing':True}
345 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
356 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
346 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
357 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
347 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
358 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
348 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
359 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
349 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
360 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
350 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
361 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
351 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
362 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
352
363
353 @property
364 @property
354 def action_as_day(self):
365 def action_as_day(self):
355 return datetime.date(*self.action_date.timetuple()[:3])
366 return datetime.date(*self.action_date.timetuple()[:3])
356
367
357 user = relationship('User')
368 user = relationship('User')
358 repository = relationship('Repository',cascade='')
369 repository = relationship('Repository',cascade='')
359
370
360
371
361 class UsersGroup(Base, BaseModel):
372 class UsersGroup(Base, BaseModel):
362 __tablename__ = 'users_groups'
373 __tablename__ = 'users_groups'
363 __table_args__ = {'extend_existing':True}
374 __table_args__ = {'extend_existing':True}
364
375
365 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
376 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
366 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
377 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
367 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
378 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
368
379
369 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
380 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
370
381
371 def __repr__(self):
382 def __repr__(self):
372 return '<userGroup(%s)>' % (self.users_group_name)
383 return '<userGroup(%s)>' % (self.users_group_name)
373
384
374 @classmethod
385 @classmethod
375 def get_by_group_name(cls, group_name, cache=False,
386 def get_by_group_name(cls, group_name, cache=False,
376 case_insensitive=False):
387 case_insensitive=False):
377 if case_insensitive:
388 if case_insensitive:
378 q = cls.query().filter(cls.users_group_name.ilike(group_name))
389 q = cls.query().filter(cls.users_group_name.ilike(group_name))
379 else:
390 else:
380 q = cls.query().filter(cls.users_group_name == group_name)
391 q = cls.query().filter(cls.users_group_name == group_name)
381 if cache:
392 if cache:
382 q = q.options(FromCache("sql_cache_short",
393 q = q.options(FromCache("sql_cache_short",
383 "get_user_%s" % group_name))
394 "get_user_%s" % group_name))
384 return q.scalar()
395 return q.scalar()
385
396
386 @classmethod
397 @classmethod
387 def get(cls, users_group_id, cache=False):
398 def get(cls, users_group_id, cache=False):
388 users_group = cls.query()
399 users_group = cls.query()
389 if cache:
400 if cache:
390 users_group = users_group.options(FromCache("sql_cache_short",
401 users_group = users_group.options(FromCache("sql_cache_short",
391 "get_users_group_%s" % users_group_id))
402 "get_users_group_%s" % users_group_id))
392 return users_group.get(users_group_id)
403 return users_group.get(users_group_id)
393
404
394 class UsersGroupMember(Base, BaseModel):
405 class UsersGroupMember(Base, BaseModel):
395 __tablename__ = 'users_groups_members'
406 __tablename__ = 'users_groups_members'
396 __table_args__ = {'extend_existing':True}
407 __table_args__ = {'extend_existing':True}
397
408
398 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
409 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
399 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
410 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
400 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
411 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
401
412
402 user = relationship('User', lazy='joined')
413 user = relationship('User', lazy='joined')
403 users_group = relationship('UsersGroup')
414 users_group = relationship('UsersGroup')
404
415
405 def __init__(self, gr_id='', u_id=''):
416 def __init__(self, gr_id='', u_id=''):
406 self.users_group_id = gr_id
417 self.users_group_id = gr_id
407 self.user_id = u_id
418 self.user_id = u_id
408
419
409 @staticmethod
420 @staticmethod
410 def add_user_to_group(group, user):
421 def add_user_to_group(group, user):
411 ugm = UsersGroupMember()
422 ugm = UsersGroupMember()
412 ugm.users_group = group
423 ugm.users_group = group
413 ugm.user = user
424 ugm.user = user
414 Session.add(ugm)
425 Session.add(ugm)
415 Session.commit()
426 Session.commit()
416 return ugm
427 return ugm
417
428
418 class Repository(Base, BaseModel):
429 class Repository(Base, BaseModel):
419 __tablename__ = 'repositories'
430 __tablename__ = 'repositories'
420 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
431 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
421
432
422 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
433 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
423 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
434 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
424 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
435 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
425 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
436 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
426 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
437 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
427 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
438 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
428 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
439 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
429 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
440 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
430 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
441 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
431 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
442 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
432
443
433 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
444 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
434 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
445 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
435
446
436
447
437 user = relationship('User')
448 user = relationship('User')
438 fork = relationship('Repository', remote_side=repo_id)
449 fork = relationship('Repository', remote_side=repo_id)
439 group = relationship('RepoGroup')
450 group = relationship('RepoGroup')
440 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
451 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
441 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
452 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
442 stats = relationship('Statistics', cascade='all', uselist=False)
453 stats = relationship('Statistics', cascade='all', uselist=False)
443
454
444 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
455 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
445
456
446 logs = relationship('UserLog')
457 logs = relationship('UserLog')
447
458
448 def __repr__(self):
459 def __repr__(self):
449 return "<%s('%s:%s')>" % (self.__class__.__name__,
460 return "<%s('%s:%s')>" % (self.__class__.__name__,
450 self.repo_id, self.repo_name)
461 self.repo_id, self.repo_name)
451
462
452 @classmethod
463 @classmethod
453 def url_sep(cls):
464 def url_sep(cls):
454 return '/'
465 return '/'
455
466
456 @classmethod
467 @classmethod
457 def get_by_repo_name(cls, repo_name):
468 def get_by_repo_name(cls, repo_name):
458 q = Session.query(cls).filter(cls.repo_name == repo_name)
469 q = Session.query(cls).filter(cls.repo_name == repo_name)
459 q = q.options(joinedload(Repository.fork))\
470 q = q.options(joinedload(Repository.fork))\
460 .options(joinedload(Repository.user))\
471 .options(joinedload(Repository.user))\
461 .options(joinedload(Repository.group))
472 .options(joinedload(Repository.group))
462 return q.scalar()
473 return q.scalar()
463
474
464 @classmethod
475 @classmethod
465 def get_repo_forks(cls, repo_id):
476 def get_repo_forks(cls, repo_id):
466 return cls.query().filter(Repository.fork_id == repo_id)
477 return cls.query().filter(Repository.fork_id == repo_id)
467
478
468 @classmethod
479 @classmethod
469 def base_path(cls):
480 def base_path(cls):
470 """
481 """
471 Returns base path when all repos are stored
482 Returns base path when all repos are stored
472
483
473 :param cls:
484 :param cls:
474 """
485 """
475 q = Session.query(RhodeCodeUi)\
486 q = Session.query(RhodeCodeUi)\
476 .filter(RhodeCodeUi.ui_key == cls.url_sep())
487 .filter(RhodeCodeUi.ui_key == cls.url_sep())
477 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
488 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
478 return q.one().ui_value
489 return q.one().ui_value
479
490
480 @property
491 @property
481 def just_name(self):
492 def just_name(self):
482 return self.repo_name.split(Repository.url_sep())[-1]
493 return self.repo_name.split(Repository.url_sep())[-1]
483
494
484 @property
495 @property
485 def groups_with_parents(self):
496 def groups_with_parents(self):
486 groups = []
497 groups = []
487 if self.group is None:
498 if self.group is None:
488 return groups
499 return groups
489
500
490 cur_gr = self.group
501 cur_gr = self.group
491 groups.insert(0, cur_gr)
502 groups.insert(0, cur_gr)
492 while 1:
503 while 1:
493 gr = getattr(cur_gr, 'parent_group', None)
504 gr = getattr(cur_gr, 'parent_group', None)
494 cur_gr = cur_gr.parent_group
505 cur_gr = cur_gr.parent_group
495 if gr is None:
506 if gr is None:
496 break
507 break
497 groups.insert(0, gr)
508 groups.insert(0, gr)
498
509
499 return groups
510 return groups
500
511
501 @property
512 @property
502 def groups_and_repo(self):
513 def groups_and_repo(self):
503 return self.groups_with_parents, self.just_name
514 return self.groups_with_parents, self.just_name
504
515
505 @LazyProperty
516 @LazyProperty
506 def repo_path(self):
517 def repo_path(self):
507 """
518 """
508 Returns base full path for that repository means where it actually
519 Returns base full path for that repository means where it actually
509 exists on a filesystem
520 exists on a filesystem
510 """
521 """
511 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
522 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
512 Repository.url_sep())
523 Repository.url_sep())
513 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
524 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
514 return q.one().ui_value
525 return q.one().ui_value
515
526
516 @property
527 @property
517 def repo_full_path(self):
528 def repo_full_path(self):
518 p = [self.repo_path]
529 p = [self.repo_path]
519 # we need to split the name by / since this is how we store the
530 # we need to split the name by / since this is how we store the
520 # names in the database, but that eventually needs to be converted
531 # names in the database, but that eventually needs to be converted
521 # into a valid system path
532 # into a valid system path
522 p += self.repo_name.split(Repository.url_sep())
533 p += self.repo_name.split(Repository.url_sep())
523 return os.path.join(*p)
534 return os.path.join(*p)
524
535
525 def get_new_name(self, repo_name):
536 def get_new_name(self, repo_name):
526 """
537 """
527 returns new full repository name based on assigned group and new new
538 returns new full repository name based on assigned group and new new
528
539
529 :param group_name:
540 :param group_name:
530 """
541 """
531 path_prefix = self.group.full_path_splitted if self.group else []
542 path_prefix = self.group.full_path_splitted if self.group else []
532 return Repository.url_sep().join(path_prefix + [repo_name])
543 return Repository.url_sep().join(path_prefix + [repo_name])
533
544
534 @property
545 @property
535 def _ui(self):
546 def _ui(self):
536 """
547 """
537 Creates an db based ui object for this repository
548 Creates an db based ui object for this repository
538 """
549 """
539 from mercurial import ui
550 from mercurial import ui
540 from mercurial import config
551 from mercurial import config
541 baseui = ui.ui()
552 baseui = ui.ui()
542
553
543 #clean the baseui object
554 #clean the baseui object
544 baseui._ocfg = config.config()
555 baseui._ocfg = config.config()
545 baseui._ucfg = config.config()
556 baseui._ucfg = config.config()
546 baseui._tcfg = config.config()
557 baseui._tcfg = config.config()
547
558
548
559
549 ret = RhodeCodeUi.query()\
560 ret = RhodeCodeUi.query()\
550 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
561 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
551
562
552 hg_ui = ret
563 hg_ui = ret
553 for ui_ in hg_ui:
564 for ui_ in hg_ui:
554 if ui_.ui_active:
565 if ui_.ui_active:
555 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
566 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
556 ui_.ui_key, ui_.ui_value)
567 ui_.ui_key, ui_.ui_value)
557 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
568 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
558
569
559 return baseui
570 return baseui
560
571
561 @classmethod
572 @classmethod
562 def is_valid(cls, repo_name):
573 def is_valid(cls, repo_name):
563 """
574 """
564 returns True if given repo name is a valid filesystem repository
575 returns True if given repo name is a valid filesystem repository
565
576
566 @param cls:
577 @param cls:
567 @param repo_name:
578 @param repo_name:
568 """
579 """
569 from rhodecode.lib.utils import is_valid_repo
580 from rhodecode.lib.utils import is_valid_repo
570
581
571 return is_valid_repo(repo_name, cls.base_path())
582 return is_valid_repo(repo_name, cls.base_path())
572
583
573
584
574 #==========================================================================
585 #==========================================================================
575 # SCM PROPERTIES
586 # SCM PROPERTIES
576 #==========================================================================
587 #==========================================================================
577
588
578 def get_changeset(self, rev):
589 def get_changeset(self, rev):
579 return get_changeset_safe(self.scm_instance, rev)
590 return get_changeset_safe(self.scm_instance, rev)
580
591
581 @property
592 @property
582 def tip(self):
593 def tip(self):
583 return self.get_changeset('tip')
594 return self.get_changeset('tip')
584
595
585 @property
596 @property
586 def author(self):
597 def author(self):
587 return self.tip.author
598 return self.tip.author
588
599
589 @property
600 @property
590 def last_change(self):
601 def last_change(self):
591 return self.scm_instance.last_change
602 return self.scm_instance.last_change
592
603
593 #==========================================================================
604 #==========================================================================
594 # SCM CACHE INSTANCE
605 # SCM CACHE INSTANCE
595 #==========================================================================
606 #==========================================================================
596
607
597 @property
608 @property
598 def invalidate(self):
609 def invalidate(self):
599 return CacheInvalidation.invalidate(self.repo_name)
610 return CacheInvalidation.invalidate(self.repo_name)
600
611
601 def set_invalidate(self):
612 def set_invalidate(self):
602 """
613 """
603 set a cache for invalidation for this instance
614 set a cache for invalidation for this instance
604 """
615 """
605 CacheInvalidation.set_invalidate(self.repo_name)
616 CacheInvalidation.set_invalidate(self.repo_name)
606
617
607 @LazyProperty
618 @LazyProperty
608 def scm_instance(self):
619 def scm_instance(self):
609 return self.__get_instance()
620 return self.__get_instance()
610
621
611 @property
622 @property
612 def scm_instance_cached(self):
623 def scm_instance_cached(self):
613 @cache_region('long_term')
624 @cache_region('long_term')
614 def _c(repo_name):
625 def _c(repo_name):
615 return self.__get_instance()
626 return self.__get_instance()
616 rn = self.repo_name
627 rn = self.repo_name
617 log.debug('Getting cached instance of repo')
628 log.debug('Getting cached instance of repo')
618 inv = self.invalidate
629 inv = self.invalidate
619 if inv is not None:
630 if inv is not None:
620 region_invalidate(_c, None, rn)
631 region_invalidate(_c, None, rn)
621 # update our cache
632 # update our cache
622 CacheInvalidation.set_valid(inv.cache_key)
633 CacheInvalidation.set_valid(inv.cache_key)
623 return _c(rn)
634 return _c(rn)
624
635
625 def __get_instance(self):
636 def __get_instance(self):
626 repo_full_path = self.repo_full_path
637 repo_full_path = self.repo_full_path
627 try:
638 try:
628 alias = get_scm(repo_full_path)[0]
639 alias = get_scm(repo_full_path)[0]
629 log.debug('Creating instance of %s repository', alias)
640 log.debug('Creating instance of %s repository', alias)
630 backend = get_backend(alias)
641 backend = get_backend(alias)
631 except VCSError:
642 except VCSError:
632 log.error(traceback.format_exc())
643 log.error(traceback.format_exc())
633 log.error('Perhaps this repository is in db and not in '
644 log.error('Perhaps this repository is in db and not in '
634 'filesystem run rescan repositories with '
645 'filesystem run rescan repositories with '
635 '"destroy old data " option from admin panel')
646 '"destroy old data " option from admin panel')
636 return
647 return
637
648
638 if alias == 'hg':
649 if alias == 'hg':
639 repo = backend(safe_str(repo_full_path), create=False,
650 repo = backend(safe_str(repo_full_path), create=False,
640 baseui=self._ui)
651 baseui=self._ui)
641 # skip hidden web repository
652 # skip hidden web repository
642 if repo._get_hidden():
653 if repo._get_hidden():
643 return
654 return
644 else:
655 else:
645 repo = backend(repo_full_path, create=False)
656 repo = backend(repo_full_path, create=False)
646
657
647 return repo
658 return repo
648
659
649
660
650 class RepoGroup(Base, BaseModel):
661 class RepoGroup(Base, BaseModel):
651 __tablename__ = 'groups'
662 __tablename__ = 'groups'
652 __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'),
663 __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'),
653 CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},)
664 CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},)
654 __mapper_args__ = {'order_by':'group_name'}
665 __mapper_args__ = {'order_by':'group_name'}
655
666
656 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
667 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
657 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
668 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
658 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
669 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
659 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
670 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
660
671
661 parent_group = relationship('RepoGroup', remote_side=group_id)
672 parent_group = relationship('RepoGroup', remote_side=group_id)
662
673
663
674
664 def __init__(self, group_name='', parent_group=None):
675 def __init__(self, group_name='', parent_group=None):
665 self.group_name = group_name
676 self.group_name = group_name
666 self.parent_group = parent_group
677 self.parent_group = parent_group
667
678
668 def __repr__(self):
679 def __repr__(self):
669 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
680 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
670 self.group_name)
681 self.group_name)
671
682
672 @classmethod
683 @classmethod
673 def groups_choices(cls):
684 def groups_choices(cls):
674 from webhelpers.html import literal as _literal
685 from webhelpers.html import literal as _literal
675 repo_groups = [('', '')]
686 repo_groups = [('', '')]
676 sep = ' &raquo; '
687 sep = ' &raquo; '
677 _name = lambda k: _literal(sep.join(k))
688 _name = lambda k: _literal(sep.join(k))
678
689
679 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
690 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
680 for x in cls.query().all()])
691 for x in cls.query().all()])
681
692
682 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
693 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
683 return repo_groups
694 return repo_groups
684
695
685 @classmethod
696 @classmethod
686 def url_sep(cls):
697 def url_sep(cls):
687 return '/'
698 return '/'
688
699
689 @classmethod
700 @classmethod
690 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
701 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
691 if case_insensitive:
702 if case_insensitive:
692 gr = cls.query()\
703 gr = cls.query()\
693 .filter(cls.group_name.ilike(group_name))
704 .filter(cls.group_name.ilike(group_name))
694 else:
705 else:
695 gr = cls.query()\
706 gr = cls.query()\
696 .filter(cls.group_name == group_name)
707 .filter(cls.group_name == group_name)
697 if cache:
708 if cache:
698 gr = gr.options(FromCache("sql_cache_short",
709 gr = gr.options(FromCache("sql_cache_short",
699 "get_group_%s" % group_name))
710 "get_group_%s" % group_name))
700 return gr.scalar()
711 return gr.scalar()
701
712
702 @property
713 @property
703 def parents(self):
714 def parents(self):
704 parents_recursion_limit = 5
715 parents_recursion_limit = 5
705 groups = []
716 groups = []
706 if self.parent_group is None:
717 if self.parent_group is None:
707 return groups
718 return groups
708 cur_gr = self.parent_group
719 cur_gr = self.parent_group
709 groups.insert(0, cur_gr)
720 groups.insert(0, cur_gr)
710 cnt = 0
721 cnt = 0
711 while 1:
722 while 1:
712 cnt += 1
723 cnt += 1
713 gr = getattr(cur_gr, 'parent_group', None)
724 gr = getattr(cur_gr, 'parent_group', None)
714 cur_gr = cur_gr.parent_group
725 cur_gr = cur_gr.parent_group
715 if gr is None:
726 if gr is None:
716 break
727 break
717 if cnt == parents_recursion_limit:
728 if cnt == parents_recursion_limit:
718 # this will prevent accidental infinit loops
729 # this will prevent accidental infinit loops
719 log.error('group nested more than %s' %
730 log.error('group nested more than %s' %
720 parents_recursion_limit)
731 parents_recursion_limit)
721 break
732 break
722
733
723 groups.insert(0, gr)
734 groups.insert(0, gr)
724 return groups
735 return groups
725
736
726 @property
737 @property
727 def children(self):
738 def children(self):
728 return RepoGroup.query().filter(RepoGroup.parent_group == self)
739 return RepoGroup.query().filter(RepoGroup.parent_group == self)
729
740
730 @property
741 @property
731 def name(self):
742 def name(self):
732 return self.group_name.split(RepoGroup.url_sep())[-1]
743 return self.group_name.split(RepoGroup.url_sep())[-1]
733
744
734 @property
745 @property
735 def full_path(self):
746 def full_path(self):
736 return self.group_name
747 return self.group_name
737
748
738 @property
749 @property
739 def full_path_splitted(self):
750 def full_path_splitted(self):
740 return self.group_name.split(RepoGroup.url_sep())
751 return self.group_name.split(RepoGroup.url_sep())
741
752
742 @property
753 @property
743 def repositories(self):
754 def repositories(self):
744 return Repository.query().filter(Repository.group == self)
755 return Repository.query().filter(Repository.group == self)
745
756
746 @property
757 @property
747 def repositories_recursive_count(self):
758 def repositories_recursive_count(self):
748 cnt = self.repositories.count()
759 cnt = self.repositories.count()
749
760
750 def children_count(group):
761 def children_count(group):
751 cnt = 0
762 cnt = 0
752 for child in group.children:
763 for child in group.children:
753 cnt += child.repositories.count()
764 cnt += child.repositories.count()
754 cnt += children_count(child)
765 cnt += children_count(child)
755 return cnt
766 return cnt
756
767
757 return cnt + children_count(self)
768 return cnt + children_count(self)
758
769
759
770
760 def get_new_name(self, group_name):
771 def get_new_name(self, group_name):
761 """
772 """
762 returns new full group name based on parent and new name
773 returns new full group name based on parent and new name
763
774
764 :param group_name:
775 :param group_name:
765 """
776 """
766 path_prefix = (self.parent_group.full_path_splitted if
777 path_prefix = (self.parent_group.full_path_splitted if
767 self.parent_group else [])
778 self.parent_group else [])
768 return RepoGroup.url_sep().join(path_prefix + [group_name])
779 return RepoGroup.url_sep().join(path_prefix + [group_name])
769
780
770
781
771 class Permission(Base, BaseModel):
782 class Permission(Base, BaseModel):
772 __tablename__ = 'permissions'
783 __tablename__ = 'permissions'
773 __table_args__ = {'extend_existing':True}
784 __table_args__ = {'extend_existing':True}
774 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
785 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
775 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
786 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
776 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
787 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
777
788
778 def __repr__(self):
789 def __repr__(self):
779 return "<%s('%s:%s')>" % (self.__class__.__name__,
790 return "<%s('%s:%s')>" % (self.__class__.__name__,
780 self.permission_id, self.permission_name)
791 self.permission_id, self.permission_name)
781
792
782 @classmethod
793 @classmethod
783 def get_by_key(cls, key):
794 def get_by_key(cls, key):
784 return cls.query().filter(cls.permission_name == key).scalar()
795 return cls.query().filter(cls.permission_name == key).scalar()
785
796
786 @classmethod
797 @classmethod
787 def get_default_perms(cls, default_user_id):
798 def get_default_perms(cls, default_user_id):
788 q = Session.query(UserRepoToPerm, Repository, cls)\
799 q = Session.query(UserRepoToPerm, Repository, cls)\
789 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
800 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
790 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
801 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
791 .filter(UserRepoToPerm.user_id == default_user_id)
802 .filter(UserRepoToPerm.user_id == default_user_id)
792
803
793 return q.all()
804 return q.all()
794
805
795
806
796 class UserRepoToPerm(Base, BaseModel):
807 class UserRepoToPerm(Base, BaseModel):
797 __tablename__ = 'repo_to_perm'
808 __tablename__ = 'repo_to_perm'
798 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True})
809 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True})
799 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
810 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
800 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
811 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
801 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
812 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
802 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
813 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
803
814
804 user = relationship('User')
815 user = relationship('User')
805 permission = relationship('Permission')
816 permission = relationship('Permission')
806 repository = relationship('Repository')
817 repository = relationship('Repository')
807
818
808 @classmethod
819 @classmethod
809 def create(cls, user, repository, permission):
820 def create(cls, user, repository, permission):
810 n = cls()
821 n = cls()
811 n.user = user
822 n.user = user
812 n.repository = repository
823 n.repository = repository
813 n.permission = permission
824 n.permission = permission
814 Session.add(n)
825 Session.add(n)
815 return n
826 return n
816
827
817 def __repr__(self):
828 def __repr__(self):
818 return '<user:%s => %s >' % (self.user, self.repository)
829 return '<user:%s => %s >' % (self.user, self.repository)
819
830
820 class UserToPerm(Base, BaseModel):
831 class UserToPerm(Base, BaseModel):
821 __tablename__ = 'user_to_perm'
832 __tablename__ = 'user_to_perm'
822 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True})
833 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True})
823 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
834 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
824 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
835 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
825 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
836 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
826
837
827 user = relationship('User')
838 user = relationship('User')
828 permission = relationship('Permission', lazy='joined')
839 permission = relationship('Permission', lazy='joined')
829
840
830
841
831 class UsersGroupRepoToPerm(Base, BaseModel):
842 class UsersGroupRepoToPerm(Base, BaseModel):
832 __tablename__ = 'users_group_repo_to_perm'
843 __tablename__ = 'users_group_repo_to_perm'
833 __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True})
844 __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True})
834 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
845 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
835 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
846 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
836 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
847 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
837 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
848 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
838
849
839 users_group = relationship('UsersGroup')
850 users_group = relationship('UsersGroup')
840 permission = relationship('Permission')
851 permission = relationship('Permission')
841 repository = relationship('Repository')
852 repository = relationship('Repository')
842
853
843 @classmethod
854 @classmethod
844 def create(cls, users_group, repository, permission):
855 def create(cls, users_group, repository, permission):
845 n = cls()
856 n = cls()
846 n.users_group = users_group
857 n.users_group = users_group
847 n.repository = repository
858 n.repository = repository
848 n.permission = permission
859 n.permission = permission
849 Session.add(n)
860 Session.add(n)
850 return n
861 return n
851
862
852 def __repr__(self):
863 def __repr__(self):
853 return '<userGroup:%s => %s >' % (self.users_group, self.repository)
864 return '<userGroup:%s => %s >' % (self.users_group, self.repository)
854
865
855 class UsersGroupToPerm(Base, BaseModel):
866 class UsersGroupToPerm(Base, BaseModel):
856 __tablename__ = 'users_group_to_perm'
867 __tablename__ = 'users_group_to_perm'
857 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
868 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
858 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
869 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
859 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
870 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
860
871
861 users_group = relationship('UsersGroup')
872 users_group = relationship('UsersGroup')
862 permission = relationship('Permission')
873 permission = relationship('Permission')
863
874
864
875
865 class UserRepoGroupToPerm(Base, BaseModel):
876 class UserRepoGroupToPerm(Base, BaseModel):
866 __tablename__ = 'group_to_perm'
877 __tablename__ = 'group_to_perm'
867 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
878 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
868
879
869 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
880 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
870 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
881 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
871 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
882 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
872 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
883 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
873
884
874 user = relationship('User')
885 user = relationship('User')
875 permission = relationship('Permission')
886 permission = relationship('Permission')
876 group = relationship('RepoGroup')
887 group = relationship('RepoGroup')
877
888
878 class UsersGroupRepoGroupToPerm(Base, BaseModel):
889 class UsersGroupRepoGroupToPerm(Base, BaseModel):
879 __tablename__ = 'users_group_repo_group_to_perm'
890 __tablename__ = 'users_group_repo_group_to_perm'
880 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
891 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
881
892
882 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)
893 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)
883 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
894 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
884 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
895 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
885 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
896 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
886
897
887 users_group = relationship('UsersGroup')
898 users_group = relationship('UsersGroup')
888 permission = relationship('Permission')
899 permission = relationship('Permission')
889 group = relationship('RepoGroup')
900 group = relationship('RepoGroup')
890
901
891 class Statistics(Base, BaseModel):
902 class Statistics(Base, BaseModel):
892 __tablename__ = 'statistics'
903 __tablename__ = 'statistics'
893 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True})
904 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True})
894 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
905 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
895 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
906 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
896 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
907 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
897 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
908 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
898 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
909 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
899 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
910 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
900
911
901 repository = relationship('Repository', single_parent=True)
912 repository = relationship('Repository', single_parent=True)
902
913
903 class UserFollowing(Base, BaseModel):
914 class UserFollowing(Base, BaseModel):
904 __tablename__ = 'user_followings'
915 __tablename__ = 'user_followings'
905 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
916 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
906 UniqueConstraint('user_id', 'follows_user_id')
917 UniqueConstraint('user_id', 'follows_user_id')
907 , {'extend_existing':True})
918 , {'extend_existing':True})
908
919
909 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
920 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
910 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
921 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
911 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
922 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
912 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
923 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
913 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
924 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
914
925
915 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
926 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
916
927
917 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
928 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
918 follows_repository = relationship('Repository', order_by='Repository.repo_name')
929 follows_repository = relationship('Repository', order_by='Repository.repo_name')
919
930
920
931
921 @classmethod
932 @classmethod
922 def get_repo_followers(cls, repo_id):
933 def get_repo_followers(cls, repo_id):
923 return cls.query().filter(cls.follows_repo_id == repo_id)
934 return cls.query().filter(cls.follows_repo_id == repo_id)
924
935
925 class CacheInvalidation(Base, BaseModel):
936 class CacheInvalidation(Base, BaseModel):
926 __tablename__ = 'cache_invalidation'
937 __tablename__ = 'cache_invalidation'
927 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True})
938 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True})
928 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
939 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
929 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
940 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
930 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
941 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
931 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
942 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
932
943
933
944
934 def __init__(self, cache_key, cache_args=''):
945 def __init__(self, cache_key, cache_args=''):
935 self.cache_key = cache_key
946 self.cache_key = cache_key
936 self.cache_args = cache_args
947 self.cache_args = cache_args
937 self.cache_active = False
948 self.cache_active = False
938
949
939 def __repr__(self):
950 def __repr__(self):
940 return "<%s('%s:%s')>" % (self.__class__.__name__,
951 return "<%s('%s:%s')>" % (self.__class__.__name__,
941 self.cache_id, self.cache_key)
952 self.cache_id, self.cache_key)
942
953
943 @classmethod
954 @classmethod
944 def invalidate(cls, key):
955 def invalidate(cls, key):
945 """
956 """
946 Returns Invalidation object if this given key should be invalidated
957 Returns Invalidation object if this given key should be invalidated
947 None otherwise. `cache_active = False` means that this cache
958 None otherwise. `cache_active = False` means that this cache
948 state is not valid and needs to be invalidated
959 state is not valid and needs to be invalidated
949
960
950 :param key:
961 :param key:
951 """
962 """
952 return cls.query()\
963 return cls.query()\
953 .filter(CacheInvalidation.cache_key == key)\
964 .filter(CacheInvalidation.cache_key == key)\
954 .filter(CacheInvalidation.cache_active == False)\
965 .filter(CacheInvalidation.cache_active == False)\
955 .scalar()
966 .scalar()
956
967
957 @classmethod
968 @classmethod
958 def set_invalidate(cls, key):
969 def set_invalidate(cls, key):
959 """
970 """
960 Mark this Cache key for invalidation
971 Mark this Cache key for invalidation
961
972
962 :param key:
973 :param key:
963 """
974 """
964
975
965 log.debug('marking %s for invalidation' % key)
976 log.debug('marking %s for invalidation' % key)
966 inv_obj = Session.query(cls)\
977 inv_obj = Session.query(cls)\
967 .filter(cls.cache_key == key).scalar()
978 .filter(cls.cache_key == key).scalar()
968 if inv_obj:
979 if inv_obj:
969 inv_obj.cache_active = False
980 inv_obj.cache_active = False
970 else:
981 else:
971 log.debug('cache key not found in invalidation db -> creating one')
982 log.debug('cache key not found in invalidation db -> creating one')
972 inv_obj = CacheInvalidation(key)
983 inv_obj = CacheInvalidation(key)
973
984
974 try:
985 try:
975 Session.add(inv_obj)
986 Session.add(inv_obj)
976 Session.commit()
987 Session.commit()
977 except Exception:
988 except Exception:
978 log.error(traceback.format_exc())
989 log.error(traceback.format_exc())
979 Session.rollback()
990 Session.rollback()
980
991
981 @classmethod
992 @classmethod
982 def set_valid(cls, key):
993 def set_valid(cls, key):
983 """
994 """
984 Mark this cache key as active and currently cached
995 Mark this cache key as active and currently cached
985
996
986 :param key:
997 :param key:
987 """
998 """
988 inv_obj = CacheInvalidation.query()\
999 inv_obj = CacheInvalidation.query()\
989 .filter(CacheInvalidation.cache_key == key).scalar()
1000 .filter(CacheInvalidation.cache_key == key).scalar()
990 inv_obj.cache_active = True
1001 inv_obj.cache_active = True
991 Session.add(inv_obj)
1002 Session.add(inv_obj)
992 Session.commit()
1003 Session.commit()
993
1004
994
1005
995 class ChangesetComment(Base, BaseModel):
1006 class ChangesetComment(Base, BaseModel):
996 __tablename__ = 'changeset_comments'
1007 __tablename__ = 'changeset_comments'
997 __table_args__ = ({'extend_existing':True},)
1008 __table_args__ = ({'extend_existing':True},)
998 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1009 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
999 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1010 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1000 revision = Column('revision', String(40), nullable=False)
1011 revision = Column('revision', String(40), nullable=False)
1001 line_no = Column('line_no', Unicode(10), nullable=True)
1012 line_no = Column('line_no', Unicode(10), nullable=True)
1002 f_path = Column('f_path', Unicode(1000), nullable=True)
1013 f_path = Column('f_path', Unicode(1000), nullable=True)
1003 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1014 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1004 text = Column('text', Unicode(25000), nullable=False)
1015 text = Column('text', Unicode(25000), nullable=False)
1005 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1016 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1006
1017
1007 author = relationship('User', lazy='joined')
1018 author = relationship('User', lazy='joined')
1008 repo = relationship('Repository')
1019 repo = relationship('Repository')
1009
1020
1010
1021
1011 @classmethod
1022 @classmethod
1012 def get_users(cls, revision):
1023 def get_users(cls, revision):
1013 """
1024 """
1014 Returns user associated with this changesetComment. ie those
1025 Returns user associated with this changesetComment. ie those
1015 who actually commented
1026 who actually commented
1016
1027
1017 :param cls:
1028 :param cls:
1018 :param revision:
1029 :param revision:
1019 """
1030 """
1020 return Session.query(User)\
1031 return Session.query(User)\
1021 .filter(cls.revision == revision)\
1032 .filter(cls.revision == revision)\
1022 .join(ChangesetComment.author).all()
1033 .join(ChangesetComment.author).all()
1023
1034
1024
1035
1025 class Notification(Base, BaseModel):
1036 class Notification(Base, BaseModel):
1026 __tablename__ = 'notifications'
1037 __tablename__ = 'notifications'
1027 __table_args__ = ({'extend_existing':True})
1038 __table_args__ = ({'extend_existing':True})
1028
1039
1029 TYPE_CHANGESET_COMMENT = u'cs_comment'
1040 TYPE_CHANGESET_COMMENT = u'cs_comment'
1030 TYPE_MESSAGE = u'message'
1041 TYPE_MESSAGE = u'message'
1031 TYPE_MENTION = u'mention'
1042 TYPE_MENTION = u'mention'
1032 TYPE_REGISTRATION = u'registration'
1043 TYPE_REGISTRATION = u'registration'
1033
1044
1034 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1045 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1035 subject = Column('subject', Unicode(512), nullable=True)
1046 subject = Column('subject', Unicode(512), nullable=True)
1036 body = Column('body', Unicode(50000), nullable=True)
1047 body = Column('body', Unicode(50000), nullable=True)
1037 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1048 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1038 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1049 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1039 type_ = Column('type', Unicode(256))
1050 type_ = Column('type', Unicode(256))
1040
1051
1041 created_by_user = relationship('User')
1052 created_by_user = relationship('User')
1042 notifications_to_users = relationship('UserNotification', lazy='joined',
1053 notifications_to_users = relationship('UserNotification', lazy='joined',
1043 cascade="all, delete, delete-orphan")
1054 cascade="all, delete, delete-orphan")
1044
1055
1045 @property
1056 @property
1046 def recipients(self):
1057 def recipients(self):
1047 return [x.user for x in UserNotification.query()\
1058 return [x.user for x in UserNotification.query()\
1048 .filter(UserNotification.notification == self).all()]
1059 .filter(UserNotification.notification == self).all()]
1049
1060
1050 @classmethod
1061 @classmethod
1051 def create(cls, created_by, subject, body, recipients, type_=None):
1062 def create(cls, created_by, subject, body, recipients, type_=None):
1052 if type_ is None:
1063 if type_ is None:
1053 type_ = Notification.TYPE_MESSAGE
1064 type_ = Notification.TYPE_MESSAGE
1054
1065
1055 notification = cls()
1066 notification = cls()
1056 notification.created_by_user = created_by
1067 notification.created_by_user = created_by
1057 notification.subject = subject
1068 notification.subject = subject
1058 notification.body = body
1069 notification.body = body
1059 notification.type_ = type_
1070 notification.type_ = type_
1060 notification.created_on = datetime.datetime.now()
1071 notification.created_on = datetime.datetime.now()
1061
1072
1062 for u in recipients:
1073 for u in recipients:
1063 assoc = UserNotification()
1074 assoc = UserNotification()
1064 assoc.notification = notification
1075 assoc.notification = notification
1065 u.notifications.append(assoc)
1076 u.notifications.append(assoc)
1066 Session.add(notification)
1077 Session.add(notification)
1067 return notification
1078 return notification
1068
1079
1069 @property
1080 @property
1070 def description(self):
1081 def description(self):
1071 from rhodecode.model.notification import NotificationModel
1082 from rhodecode.model.notification import NotificationModel
1072 return NotificationModel().make_description(self)
1083 return NotificationModel().make_description(self)
1073
1084
1074 class UserNotification(Base, BaseModel):
1085 class UserNotification(Base, BaseModel):
1075 __tablename__ = 'user_to_notification'
1086 __tablename__ = 'user_to_notification'
1076 __table_args__ = (UniqueConstraint('user_id', 'notification_id'),
1087 __table_args__ = (UniqueConstraint('user_id', 'notification_id'),
1077 {'extend_existing':True})
1088 {'extend_existing':True})
1078 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), primary_key=True)
1089 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), primary_key=True)
1079 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1090 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1080 read = Column('read', Boolean, default=False)
1091 read = Column('read', Boolean, default=False)
1081 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1092 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1082
1093
1083 user = relationship('User', lazy="joined")
1094 user = relationship('User', lazy="joined")
1084 notification = relationship('Notification', lazy="joined",
1095 notification = relationship('Notification', lazy="joined",
1085 order_by=lambda:Notification.created_on.desc(),)
1096 order_by=lambda:Notification.created_on.desc(),)
1086
1097
1087 def mark_as_read(self):
1098 def mark_as_read(self):
1088 self.read = True
1099 self.read = True
1089 Session.add(self)
1100 Session.add(self)
1090
1101
1091 class DbMigrateVersion(Base, BaseModel):
1102 class DbMigrateVersion(Base, BaseModel):
1092 __tablename__ = 'db_migrate_version'
1103 __tablename__ = 'db_migrate_version'
1093 __table_args__ = {'extend_existing':True}
1104 __table_args__ = {'extend_existing':True}
1094 repository_id = Column('repository_id', String(250), primary_key=True)
1105 repository_id = Column('repository_id', String(250), primary_key=True)
1095 repository_path = Column('repository_path', Text)
1106 repository_path = Column('repository_path', Text)
1096 version = Column('version', Integer)
1107 version = Column('version', Integer)
1097
1108
@@ -1,682 +1,682 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import os
22 import os
23 import re
23 import re
24 import logging
24 import logging
25 import traceback
25 import traceback
26
26
27 import formencode
27 import formencode
28 from formencode import All
28 from formencode import All
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
30 Email, Bool, StringBoolean, Set
30 Email, Bool, StringBoolean, Set
31
31
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34
34
35 from rhodecode.config.routing import ADMIN_PREFIX
35 from rhodecode.config.routing import ADMIN_PREFIX
36 from rhodecode.lib.utils import repo_name_slug
36 from rhodecode.lib.utils import repo_name_slug
37 from rhodecode.lib.auth import authenticate, get_crypt_password
37 from rhodecode.lib.auth import authenticate, get_crypt_password
38 from rhodecode.lib.exceptions import LdapImportError
38 from rhodecode.lib.exceptions import LdapImportError
39 from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository
39 from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository
40 from rhodecode import BACKENDS
40 from rhodecode import BACKENDS
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44 #this is needed to translate the messages using _() in validators
44 #this is needed to translate the messages using _() in validators
45 class State_obj(object):
45 class State_obj(object):
46 _ = staticmethod(_)
46 _ = staticmethod(_)
47
47
48 #==============================================================================
48 #==============================================================================
49 # VALIDATORS
49 # VALIDATORS
50 #==============================================================================
50 #==============================================================================
51 class ValidAuthToken(formencode.validators.FancyValidator):
51 class ValidAuthToken(formencode.validators.FancyValidator):
52 messages = {'invalid_token':_('Token mismatch')}
52 messages = {'invalid_token':_('Token mismatch')}
53
53
54 def validate_python(self, value, state):
54 def validate_python(self, value, state):
55
55
56 if value != authentication_token():
56 if value != authentication_token():
57 raise formencode.Invalid(self.message('invalid_token', state,
57 raise formencode.Invalid(self.message('invalid_token', state,
58 search_number=value), value, state)
58 search_number=value), value, state)
59
59
60 def ValidUsername(edit, old_data):
60 def ValidUsername(edit, old_data):
61 class _ValidUsername(formencode.validators.FancyValidator):
61 class _ValidUsername(formencode.validators.FancyValidator):
62
62
63 def validate_python(self, value, state):
63 def validate_python(self, value, state):
64 if value in ['default', 'new_user']:
64 if value in ['default', 'new_user']:
65 raise formencode.Invalid(_('Invalid username'), value, state)
65 raise formencode.Invalid(_('Invalid username'), value, state)
66 #check if user is unique
66 #check if user is unique
67 old_un = None
67 old_un = None
68 if edit:
68 if edit:
69 old_un = User.get(old_data.get('user_id')).username
69 old_un = User.get(old_data.get('user_id')).username
70
70
71 if old_un != value or not edit:
71 if old_un != value or not edit:
72 if User.get_by_username(value, case_insensitive=True):
72 if User.get_by_username(value, case_insensitive=True):
73 raise formencode.Invalid(_('This username already '
73 raise formencode.Invalid(_('This username already '
74 'exists') , value, state)
74 'exists') , value, state)
75
75
76 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
76 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
77 raise formencode.Invalid(_('Username may only contain '
77 raise formencode.Invalid(_('Username may only contain '
78 'alphanumeric characters '
78 'alphanumeric characters '
79 'underscores, periods or dashes '
79 'underscores, periods or dashes '
80 'and must begin with alphanumeric '
80 'and must begin with alphanumeric '
81 'character'), value, state)
81 'character'), value, state)
82
82
83 return _ValidUsername
83 return _ValidUsername
84
84
85
85
86 def ValidUsersGroup(edit, old_data):
86 def ValidUsersGroup(edit, old_data):
87
87
88 class _ValidUsersGroup(formencode.validators.FancyValidator):
88 class _ValidUsersGroup(formencode.validators.FancyValidator):
89
89
90 def validate_python(self, value, state):
90 def validate_python(self, value, state):
91 if value in ['default']:
91 if value in ['default']:
92 raise formencode.Invalid(_('Invalid group name'), value, state)
92 raise formencode.Invalid(_('Invalid group name'), value, state)
93 #check if group is unique
93 #check if group is unique
94 old_ugname = None
94 old_ugname = None
95 if edit:
95 if edit:
96 old_ugname = UsersGroup.get(
96 old_ugname = UsersGroup.get(
97 old_data.get('users_group_id')).users_group_name
97 old_data.get('users_group_id')).users_group_name
98
98
99 if old_ugname != value or not edit:
99 if old_ugname != value or not edit:
100 if UsersGroup.get_by_group_name(value, cache=False,
100 if UsersGroup.get_by_group_name(value, cache=False,
101 case_insensitive=True):
101 case_insensitive=True):
102 raise formencode.Invalid(_('This users group '
102 raise formencode.Invalid(_('This users group '
103 'already exists') , value,
103 'already exists') , value,
104 state)
104 state)
105
105
106
106
107 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
107 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
108 raise formencode.Invalid(_('RepoGroup name may only contain '
108 raise formencode.Invalid(_('RepoGroup name may only contain '
109 'alphanumeric characters '
109 'alphanumeric characters '
110 'underscores, periods or dashes '
110 'underscores, periods or dashes '
111 'and must begin with alphanumeric '
111 'and must begin with alphanumeric '
112 'character'), value, state)
112 'character'), value, state)
113
113
114 return _ValidUsersGroup
114 return _ValidUsersGroup
115
115
116
116
117 def ValidReposGroup(edit, old_data):
117 def ValidReposGroup(edit, old_data):
118 class _ValidReposGroup(formencode.validators.FancyValidator):
118 class _ValidReposGroup(formencode.validators.FancyValidator):
119
119
120 def validate_python(self, value, state):
120 def validate_python(self, value, state):
121 # TODO WRITE VALIDATIONS
121 # TODO WRITE VALIDATIONS
122 group_name = value.get('group_name')
122 group_name = value.get('group_name')
123 group_parent_id = value.get('group_parent_id')
123 group_parent_id = value.get('group_parent_id')
124
124
125 # slugify repo group just in case :)
125 # slugify repo group just in case :)
126 slug = repo_name_slug(group_name)
126 slug = repo_name_slug(group_name)
127
127
128 # check for parent of self
128 # check for parent of self
129 parent_of_self = lambda:(old_data['group_id'] == int(group_parent_id)
129 parent_of_self = lambda:(old_data['group_id'] == int(group_parent_id)
130 if group_parent_id else False)
130 if group_parent_id else False)
131 if edit and parent_of_self():
131 if edit and parent_of_self():
132 e_dict = {'group_parent_id':_('Cannot assign this group '
132 e_dict = {'group_parent_id':_('Cannot assign this group '
133 'as parent')}
133 'as parent')}
134 raise formencode.Invalid('', value, state,
134 raise formencode.Invalid('', value, state,
135 error_dict=e_dict)
135 error_dict=e_dict)
136
136
137 old_gname = None
137 old_gname = None
138 if edit:
138 if edit:
139 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
139 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
140
140
141 if old_gname != group_name or not edit:
141 if old_gname != group_name or not edit:
142
142
143 # check filesystem
143 # check filesystem
144 gr = RepoGroup.query().filter(RepoGroup.group_name == slug)\
144 gr = RepoGroup.query().filter(RepoGroup.group_name == slug)\
145 .filter(RepoGroup.group_parent_id == group_parent_id).scalar()
145 .filter(RepoGroup.group_parent_id == group_parent_id).scalar()
146
146
147 if gr:
147 if gr:
148 e_dict = {'group_name':_('This group already exists')}
148 e_dict = {'group_name':_('This group already exists')}
149 raise formencode.Invalid('', value, state,
149 raise formencode.Invalid('', value, state,
150 error_dict=e_dict)
150 error_dict=e_dict)
151
151
152 return _ValidReposGroup
152 return _ValidReposGroup
153
153
154 class ValidPassword(formencode.validators.FancyValidator):
154 class ValidPassword(formencode.validators.FancyValidator):
155
155
156 def to_python(self, value, state):
156 def to_python(self, value, state):
157
157
158 if value:
158 if value:
159
159
160 if value.get('password'):
160 if value.get('password'):
161 try:
161 try:
162 value['password'] = get_crypt_password(value['password'])
162 value['password'] = get_crypt_password(value['password'])
163 except UnicodeEncodeError:
163 except UnicodeEncodeError:
164 e_dict = {'password':_('Invalid characters in password')}
164 e_dict = {'password':_('Invalid characters in password')}
165 raise formencode.Invalid('', value, state, error_dict=e_dict)
165 raise formencode.Invalid('', value, state, error_dict=e_dict)
166
166
167 if value.get('password_confirmation'):
167 if value.get('password_confirmation'):
168 try:
168 try:
169 value['password_confirmation'] = \
169 value['password_confirmation'] = \
170 get_crypt_password(value['password_confirmation'])
170 get_crypt_password(value['password_confirmation'])
171 except UnicodeEncodeError:
171 except UnicodeEncodeError:
172 e_dict = {'password_confirmation':_('Invalid characters in password')}
172 e_dict = {'password_confirmation':_('Invalid characters in password')}
173 raise formencode.Invalid('', value, state, error_dict=e_dict)
173 raise formencode.Invalid('', value, state, error_dict=e_dict)
174
174
175 if value.get('new_password'):
175 if value.get('new_password'):
176 try:
176 try:
177 value['new_password'] = \
177 value['new_password'] = \
178 get_crypt_password(value['new_password'])
178 get_crypt_password(value['new_password'])
179 except UnicodeEncodeError:
179 except UnicodeEncodeError:
180 e_dict = {'new_password':_('Invalid characters in password')}
180 e_dict = {'new_password':_('Invalid characters in password')}
181 raise formencode.Invalid('', value, state, error_dict=e_dict)
181 raise formencode.Invalid('', value, state, error_dict=e_dict)
182
182
183 return value
183 return value
184
184
185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
186
186
187 def validate_python(self, value, state):
187 def validate_python(self, value, state):
188
188
189 pass_val = value.get('password') or value.get('new_password')
189 pass_val = value.get('password') or value.get('new_password')
190 if pass_val != value['password_confirmation']:
190 if pass_val != value['password_confirmation']:
191 e_dict = {'password_confirmation':
191 e_dict = {'password_confirmation':
192 _('Passwords do not match')}
192 _('Passwords do not match')}
193 raise formencode.Invalid('', value, state, error_dict=e_dict)
193 raise formencode.Invalid('', value, state, error_dict=e_dict)
194
194
195 class ValidAuth(formencode.validators.FancyValidator):
195 class ValidAuth(formencode.validators.FancyValidator):
196 messages = {
196 messages = {
197 'invalid_password':_('invalid password'),
197 'invalid_password':_('invalid password'),
198 'invalid_login':_('invalid user name'),
198 'invalid_login':_('invalid user name'),
199 'disabled_account':_('Your account is disabled')
199 'disabled_account':_('Your account is disabled')
200 }
200 }
201
201
202 # error mapping
202 # error mapping
203 e_dict = {'username':messages['invalid_login'],
203 e_dict = {'username':messages['invalid_login'],
204 'password':messages['invalid_password']}
204 'password':messages['invalid_password']}
205 e_dict_disable = {'username':messages['disabled_account']}
205 e_dict_disable = {'username':messages['disabled_account']}
206
206
207 def validate_python(self, value, state):
207 def validate_python(self, value, state):
208 password = value['password']
208 password = value['password']
209 username = value['username']
209 username = value['username']
210 user = User.get_by_username(username)
210 user = User.get_by_username(username)
211
211
212 if authenticate(username, password):
212 if authenticate(username, password):
213 return value
213 return value
214 else:
214 else:
215 if user and user.active is False:
215 if user and user.active is False:
216 log.warning('user %s is disabled', username)
216 log.warning('user %s is disabled', username)
217 raise formencode.Invalid(self.message('disabled_account',
217 raise formencode.Invalid(self.message('disabled_account',
218 state=State_obj),
218 state=State_obj),
219 value, state,
219 value, state,
220 error_dict=self.e_dict_disable)
220 error_dict=self.e_dict_disable)
221 else:
221 else:
222 log.warning('user %s not authenticated', username)
222 log.warning('user %s not authenticated', username)
223 raise formencode.Invalid(self.message('invalid_password',
223 raise formencode.Invalid(self.message('invalid_password',
224 state=State_obj), value, state,
224 state=State_obj), value, state,
225 error_dict=self.e_dict)
225 error_dict=self.e_dict)
226
226
227 class ValidRepoUser(formencode.validators.FancyValidator):
227 class ValidRepoUser(formencode.validators.FancyValidator):
228
228
229 def to_python(self, value, state):
229 def to_python(self, value, state):
230 try:
230 try:
231 User.query().filter(User.active == True)\
231 User.query().filter(User.active == True)\
232 .filter(User.username == value).one()
232 .filter(User.username == value).one()
233 except Exception:
233 except Exception:
234 raise formencode.Invalid(_('This username is not valid'),
234 raise formencode.Invalid(_('This username is not valid'),
235 value, state)
235 value, state)
236 return value
236 return value
237
237
238 def ValidRepoName(edit, old_data):
238 def ValidRepoName(edit, old_data):
239 class _ValidRepoName(formencode.validators.FancyValidator):
239 class _ValidRepoName(formencode.validators.FancyValidator):
240 def to_python(self, value, state):
240 def to_python(self, value, state):
241
241
242 repo_name = value.get('repo_name')
242 repo_name = value.get('repo_name')
243
243
244 slug = repo_name_slug(repo_name)
244 slug = repo_name_slug(repo_name)
245 if slug in [ADMIN_PREFIX, '']:
245 if slug in [ADMIN_PREFIX, '']:
246 e_dict = {'repo_name': _('This repository name is disallowed')}
246 e_dict = {'repo_name': _('This repository name is disallowed')}
247 raise formencode.Invalid('', value, state, error_dict=e_dict)
247 raise formencode.Invalid('', value, state, error_dict=e_dict)
248
248
249
249
250 if value.get('repo_group'):
250 if value.get('repo_group'):
251 gr = RepoGroup.get(value.get('repo_group'))
251 gr = RepoGroup.get(value.get('repo_group'))
252 group_path = gr.full_path
252 group_path = gr.full_path
253 # value needs to be aware of group name in order to check
253 # value needs to be aware of group name in order to check
254 # db key This is an actual just the name to store in the
254 # db key This is an actual just the name to store in the
255 # database
255 # database
256 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
256 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
257
257
258 else:
258 else:
259 group_path = ''
259 group_path = ''
260 repo_name_full = repo_name
260 repo_name_full = repo_name
261
261
262
262
263 value['repo_name_full'] = repo_name_full
263 value['repo_name_full'] = repo_name_full
264 rename = old_data.get('repo_name') != repo_name_full
264 rename = old_data.get('repo_name') != repo_name_full
265 create = not edit
265 create = not edit
266 if rename or create:
266 if rename or create:
267
267
268 if group_path != '':
268 if group_path != '':
269 if Repository.get_by_repo_name(repo_name_full):
269 if Repository.get_by_repo_name(repo_name_full):
270 e_dict = {'repo_name':_('This repository already '
270 e_dict = {'repo_name':_('This repository already '
271 'exists in a group "%s"') %
271 'exists in a group "%s"') %
272 gr.group_name}
272 gr.group_name}
273 raise formencode.Invalid('', value, state,
273 raise formencode.Invalid('', value, state,
274 error_dict=e_dict)
274 error_dict=e_dict)
275 elif RepoGroup.get_by_group_name(repo_name_full):
275 elif RepoGroup.get_by_group_name(repo_name_full):
276 e_dict = {'repo_name':_('There is a group with this'
276 e_dict = {'repo_name':_('There is a group with this'
277 ' name already "%s"') %
277 ' name already "%s"') %
278 repo_name_full}
278 repo_name_full}
279 raise formencode.Invalid('', value, state,
279 raise formencode.Invalid('', value, state,
280 error_dict=e_dict)
280 error_dict=e_dict)
281
281
282 elif Repository.get_by_repo_name(repo_name_full):
282 elif Repository.get_by_repo_name(repo_name_full):
283 e_dict = {'repo_name':_('This repository '
283 e_dict = {'repo_name':_('This repository '
284 'already exists')}
284 'already exists')}
285 raise formencode.Invalid('', value, state,
285 raise formencode.Invalid('', value, state,
286 error_dict=e_dict)
286 error_dict=e_dict)
287
287
288 return value
288 return value
289
289
290 return _ValidRepoName
290 return _ValidRepoName
291
291
292 def ValidForkName(*args, **kwargs):
292 def ValidForkName(*args, **kwargs):
293 return ValidRepoName(*args, **kwargs)
293 return ValidRepoName(*args, **kwargs)
294
294
295
295
296 def SlugifyName():
296 def SlugifyName():
297 class _SlugifyName(formencode.validators.FancyValidator):
297 class _SlugifyName(formencode.validators.FancyValidator):
298
298
299 def to_python(self, value, state):
299 def to_python(self, value, state):
300 return repo_name_slug(value)
300 return repo_name_slug(value)
301
301
302 return _SlugifyName
302 return _SlugifyName
303
303
304 def ValidCloneUri():
304 def ValidCloneUri():
305 from mercurial.httprepo import httprepository, httpsrepository
305 from mercurial.httprepo import httprepository, httpsrepository
306 from rhodecode.lib.utils import make_ui
306 from rhodecode.lib.utils import make_ui
307
307
308 class _ValidCloneUri(formencode.validators.FancyValidator):
308 class _ValidCloneUri(formencode.validators.FancyValidator):
309
309
310 def to_python(self, value, state):
310 def to_python(self, value, state):
311 if not value:
311 if not value:
312 pass
312 pass
313 elif value.startswith('https'):
313 elif value.startswith('https'):
314 try:
314 try:
315 httpsrepository(make_ui('db'), value).capabilities
315 httpsrepository(make_ui('db'), value).capabilities
316 except Exception, e:
316 except Exception, e:
317 log.error(traceback.format_exc())
317 log.error(traceback.format_exc())
318 raise formencode.Invalid(_('invalid clone url'), value,
318 raise formencode.Invalid(_('invalid clone url'), value,
319 state)
319 state)
320 elif value.startswith('http'):
320 elif value.startswith('http'):
321 try:
321 try:
322 httprepository(make_ui('db'), value).capabilities
322 httprepository(make_ui('db'), value).capabilities
323 except Exception, e:
323 except Exception, e:
324 log.error(traceback.format_exc())
324 log.error(traceback.format_exc())
325 raise formencode.Invalid(_('invalid clone url'), value,
325 raise formencode.Invalid(_('invalid clone url'), value,
326 state)
326 state)
327 else:
327 else:
328 raise formencode.Invalid(_('Invalid clone url, provide a '
328 raise formencode.Invalid(_('Invalid clone url, provide a '
329 'valid clone http\s url'), value,
329 'valid clone http\s url'), value,
330 state)
330 state)
331 return value
331 return value
332
332
333 return _ValidCloneUri
333 return _ValidCloneUri
334
334
335 def ValidForkType(old_data):
335 def ValidForkType(old_data):
336 class _ValidForkType(formencode.validators.FancyValidator):
336 class _ValidForkType(formencode.validators.FancyValidator):
337
337
338 def to_python(self, value, state):
338 def to_python(self, value, state):
339 if old_data['repo_type'] != value:
339 if old_data['repo_type'] != value:
340 raise formencode.Invalid(_('Fork have to be the same '
340 raise formencode.Invalid(_('Fork have to be the same '
341 'type as original'), value, state)
341 'type as original'), value, state)
342
342
343 return value
343 return value
344 return _ValidForkType
344 return _ValidForkType
345
345
346 class ValidPerms(formencode.validators.FancyValidator):
346 class ValidPerms(formencode.validators.FancyValidator):
347 messages = {'perm_new_member_name':_('This username or users group name'
347 messages = {'perm_new_member_name':_('This username or users group name'
348 ' is not valid')}
348 ' is not valid')}
349
349
350 def to_python(self, value, state):
350 def to_python(self, value, state):
351 perms_update = []
351 perms_update = []
352 perms_new = []
352 perms_new = []
353 #build a list of permission to update and new permission to create
353 #build a list of permission to update and new permission to create
354 for k, v in value.items():
354 for k, v in value.items():
355 #means new added member to permissions
355 #means new added member to permissions
356 if k.startswith('perm_new_member'):
356 if k.startswith('perm_new_member'):
357 new_perm = value.get('perm_new_member', False)
357 new_perm = value.get('perm_new_member', False)
358 new_member = value.get('perm_new_member_name', False)
358 new_member = value.get('perm_new_member_name', False)
359 new_type = value.get('perm_new_member_type')
359 new_type = value.get('perm_new_member_type')
360
360
361 if new_member and new_perm:
361 if new_member and new_perm:
362 if (new_member, new_perm, new_type) not in perms_new:
362 if (new_member, new_perm, new_type) not in perms_new:
363 perms_new.append((new_member, new_perm, new_type))
363 perms_new.append((new_member, new_perm, new_type))
364 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
364 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
365 member = k[7:]
365 member = k[7:]
366 t = {'u':'user',
366 t = {'u':'user',
367 'g':'users_group'}[k[0]]
367 'g':'users_group'}[k[0]]
368 if member == 'default':
368 if member == 'default':
369 if value['private']:
369 if value['private']:
370 #set none for default when updating to private repo
370 #set none for default when updating to private repo
371 v = 'repository.none'
371 v = 'repository.none'
372 perms_update.append((member, v, t))
372 perms_update.append((member, v, t))
373
373
374 value['perms_updates'] = perms_update
374 value['perms_updates'] = perms_update
375 value['perms_new'] = perms_new
375 value['perms_new'] = perms_new
376
376
377 #update permissions
377 #update permissions
378 for k, v, t in perms_new:
378 for k, v, t in perms_new:
379 try:
379 try:
380 if t is 'user':
380 if t is 'user':
381 self.user_db = User.query()\
381 self.user_db = User.query()\
382 .filter(User.active == True)\
382 .filter(User.active == True)\
383 .filter(User.username == k).one()
383 .filter(User.username == k).one()
384 if t is 'users_group':
384 if t is 'users_group':
385 self.user_db = UsersGroup.query()\
385 self.user_db = UsersGroup.query()\
386 .filter(UsersGroup.users_group_active == True)\
386 .filter(UsersGroup.users_group_active == True)\
387 .filter(UsersGroup.users_group_name == k).one()
387 .filter(UsersGroup.users_group_name == k).one()
388
388
389 except Exception:
389 except Exception:
390 msg = self.message('perm_new_member_name',
390 msg = self.message('perm_new_member_name',
391 state=State_obj)
391 state=State_obj)
392 raise formencode.Invalid(msg, value, state,
392 raise formencode.Invalid(msg, value, state,
393 error_dict={'perm_new_member_name':msg})
393 error_dict={'perm_new_member_name':msg})
394 return value
394 return value
395
395
396 class ValidSettings(formencode.validators.FancyValidator):
396 class ValidSettings(formencode.validators.FancyValidator):
397
397
398 def to_python(self, value, state):
398 def to_python(self, value, state):
399 #settings form can't edit user
399 # settings form can't edit user
400 if value.has_key('user'):
400 if value.has_key('user'):
401 del['value']['user']
401 del['value']['user']
402
402
403 return value
403 return value
404
404
405 class ValidPath(formencode.validators.FancyValidator):
405 class ValidPath(formencode.validators.FancyValidator):
406 def to_python(self, value, state):
406 def to_python(self, value, state):
407
407
408 if not os.path.isdir(value):
408 if not os.path.isdir(value):
409 msg = _('This is not a valid path')
409 msg = _('This is not a valid path')
410 raise formencode.Invalid(msg, value, state,
410 raise formencode.Invalid(msg, value, state,
411 error_dict={'paths_root_path':msg})
411 error_dict={'paths_root_path':msg})
412 return value
412 return value
413
413
414 def UniqSystemEmail(old_data):
414 def UniqSystemEmail(old_data):
415 class _UniqSystemEmail(formencode.validators.FancyValidator):
415 class _UniqSystemEmail(formencode.validators.FancyValidator):
416 def to_python(self, value, state):
416 def to_python(self, value, state):
417 value = value.lower()
417 value = value.lower()
418 if old_data.get('email') != value:
418 if old_data.get('email') != value:
419 user = User.query().filter(User.email == value).scalar()
419 user = User.get_by_email(value, case_insensitive=True)
420 if user:
420 if user:
421 raise formencode.Invalid(
421 raise formencode.Invalid(
422 _("This e-mail address is already taken"),
422 _("This e-mail address is already taken"),
423 value, state)
423 value, state)
424 return value
424 return value
425
425
426 return _UniqSystemEmail
426 return _UniqSystemEmail
427
427
428 class ValidSystemEmail(formencode.validators.FancyValidator):
428 class ValidSystemEmail(formencode.validators.FancyValidator):
429 def to_python(self, value, state):
429 def to_python(self, value, state):
430 value = value.lower()
430 value = value.lower()
431 user = User.query().filter(User.email == value).scalar()
431 user = User.get_by_email(value, case_insensitive=True)
432 if user is None:
432 if user is None:
433 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
433 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
434 value, state)
434 value, state)
435
435
436 return value
436 return value
437
437
438 class LdapLibValidator(formencode.validators.FancyValidator):
438 class LdapLibValidator(formencode.validators.FancyValidator):
439
439
440 def to_python(self, value, state):
440 def to_python(self, value, state):
441
441
442 try:
442 try:
443 import ldap
443 import ldap
444 except ImportError:
444 except ImportError:
445 raise LdapImportError
445 raise LdapImportError
446 return value
446 return value
447
447
448 class AttrLoginValidator(formencode.validators.FancyValidator):
448 class AttrLoginValidator(formencode.validators.FancyValidator):
449
449
450 def to_python(self, value, state):
450 def to_python(self, value, state):
451
451
452 if not value or not isinstance(value, (str, unicode)):
452 if not value or not isinstance(value, (str, unicode)):
453 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
453 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
454 "must be specified - this is the name "
454 "must be specified - this is the name "
455 "of the attribute that is equivalent "
455 "of the attribute that is equivalent "
456 "to 'username'"),
456 "to 'username'"),
457 value, state)
457 value, state)
458
458
459 return value
459 return value
460
460
461 #===============================================================================
461 #===============================================================================
462 # FORMS
462 # FORMS
463 #===============================================================================
463 #===============================================================================
464 class LoginForm(formencode.Schema):
464 class LoginForm(formencode.Schema):
465 allow_extra_fields = True
465 allow_extra_fields = True
466 filter_extra_fields = True
466 filter_extra_fields = True
467 username = UnicodeString(
467 username = UnicodeString(
468 strip=True,
468 strip=True,
469 min=1,
469 min=1,
470 not_empty=True,
470 not_empty=True,
471 messages={
471 messages={
472 'empty':_('Please enter a login'),
472 'empty':_('Please enter a login'),
473 'tooShort':_('Enter a value %(min)i characters long or more')}
473 'tooShort':_('Enter a value %(min)i characters long or more')}
474 )
474 )
475
475
476 password = UnicodeString(
476 password = UnicodeString(
477 strip=True,
477 strip=True,
478 min=3,
478 min=3,
479 not_empty=True,
479 not_empty=True,
480 messages={
480 messages={
481 'empty':_('Please enter a password'),
481 'empty':_('Please enter a password'),
482 'tooShort':_('Enter %(min)i characters or more')}
482 'tooShort':_('Enter %(min)i characters or more')}
483 )
483 )
484
484
485 chained_validators = [ValidAuth]
485 chained_validators = [ValidAuth]
486
486
487 def UserForm(edit=False, old_data={}):
487 def UserForm(edit=False, old_data={}):
488 class _UserForm(formencode.Schema):
488 class _UserForm(formencode.Schema):
489 allow_extra_fields = True
489 allow_extra_fields = True
490 filter_extra_fields = True
490 filter_extra_fields = True
491 username = All(UnicodeString(strip=True, min=1, not_empty=True),
491 username = All(UnicodeString(strip=True, min=1, not_empty=True),
492 ValidUsername(edit, old_data))
492 ValidUsername(edit, old_data))
493 if edit:
493 if edit:
494 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
494 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
495 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
495 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
496 admin = StringBoolean(if_missing=False)
496 admin = StringBoolean(if_missing=False)
497 else:
497 else:
498 password = All(UnicodeString(strip=True, min=6, not_empty=True))
498 password = All(UnicodeString(strip=True, min=6, not_empty=True))
499 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
499 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
500
500
501 active = StringBoolean(if_missing=False)
501 active = StringBoolean(if_missing=False)
502 name = UnicodeString(strip=True, min=1, not_empty=True)
502 name = UnicodeString(strip=True, min=1, not_empty=True)
503 lastname = UnicodeString(strip=True, min=1, not_empty=True)
503 lastname = UnicodeString(strip=True, min=1, not_empty=True)
504 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
504 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
505
505
506 chained_validators = [ValidPasswordsMatch, ValidPassword]
506 chained_validators = [ValidPasswordsMatch, ValidPassword]
507
507
508 return _UserForm
508 return _UserForm
509
509
510
510
511 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
511 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
512 class _UsersGroupForm(formencode.Schema):
512 class _UsersGroupForm(formencode.Schema):
513 allow_extra_fields = True
513 allow_extra_fields = True
514 filter_extra_fields = True
514 filter_extra_fields = True
515
515
516 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
516 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
517 ValidUsersGroup(edit, old_data))
517 ValidUsersGroup(edit, old_data))
518
518
519 users_group_active = StringBoolean(if_missing=False)
519 users_group_active = StringBoolean(if_missing=False)
520
520
521 if edit:
521 if edit:
522 users_group_members = OneOf(available_members, hideList=False,
522 users_group_members = OneOf(available_members, hideList=False,
523 testValueList=True,
523 testValueList=True,
524 if_missing=None, not_empty=False)
524 if_missing=None, not_empty=False)
525
525
526 return _UsersGroupForm
526 return _UsersGroupForm
527
527
528 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
528 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
529 class _ReposGroupForm(formencode.Schema):
529 class _ReposGroupForm(formencode.Schema):
530 allow_extra_fields = True
530 allow_extra_fields = True
531 filter_extra_fields = True
531 filter_extra_fields = True
532
532
533 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
533 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
534 SlugifyName())
534 SlugifyName())
535 group_description = UnicodeString(strip=True, min=1,
535 group_description = UnicodeString(strip=True, min=1,
536 not_empty=True)
536 not_empty=True)
537 group_parent_id = OneOf(available_groups, hideList=False,
537 group_parent_id = OneOf(available_groups, hideList=False,
538 testValueList=True,
538 testValueList=True,
539 if_missing=None, not_empty=False)
539 if_missing=None, not_empty=False)
540
540
541 chained_validators = [ValidReposGroup(edit, old_data)]
541 chained_validators = [ValidReposGroup(edit, old_data)]
542
542
543 return _ReposGroupForm
543 return _ReposGroupForm
544
544
545 def RegisterForm(edit=False, old_data={}):
545 def RegisterForm(edit=False, old_data={}):
546 class _RegisterForm(formencode.Schema):
546 class _RegisterForm(formencode.Schema):
547 allow_extra_fields = True
547 allow_extra_fields = True
548 filter_extra_fields = True
548 filter_extra_fields = True
549 username = All(ValidUsername(edit, old_data),
549 username = All(ValidUsername(edit, old_data),
550 UnicodeString(strip=True, min=1, not_empty=True))
550 UnicodeString(strip=True, min=1, not_empty=True))
551 password = All(UnicodeString(strip=True, min=6, not_empty=True))
551 password = All(UnicodeString(strip=True, min=6, not_empty=True))
552 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
552 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
553 active = StringBoolean(if_missing=False)
553 active = StringBoolean(if_missing=False)
554 name = UnicodeString(strip=True, min=1, not_empty=True)
554 name = UnicodeString(strip=True, min=1, not_empty=True)
555 lastname = UnicodeString(strip=True, min=1, not_empty=True)
555 lastname = UnicodeString(strip=True, min=1, not_empty=True)
556 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
556 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
557
557
558 chained_validators = [ValidPasswordsMatch, ValidPassword]
558 chained_validators = [ValidPasswordsMatch, ValidPassword]
559
559
560 return _RegisterForm
560 return _RegisterForm
561
561
562 def PasswordResetForm():
562 def PasswordResetForm():
563 class _PasswordResetForm(formencode.Schema):
563 class _PasswordResetForm(formencode.Schema):
564 allow_extra_fields = True
564 allow_extra_fields = True
565 filter_extra_fields = True
565 filter_extra_fields = True
566 email = All(ValidSystemEmail(), Email(not_empty=True))
566 email = All(ValidSystemEmail(), Email(not_empty=True))
567 return _PasswordResetForm
567 return _PasswordResetForm
568
568
569 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
569 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
570 repo_groups=[]):
570 repo_groups=[]):
571 class _RepoForm(formencode.Schema):
571 class _RepoForm(formencode.Schema):
572 allow_extra_fields = True
572 allow_extra_fields = True
573 filter_extra_fields = False
573 filter_extra_fields = False
574 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
574 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
575 SlugifyName())
575 SlugifyName())
576 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
576 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
577 ValidCloneUri()())
577 ValidCloneUri()())
578 repo_group = OneOf(repo_groups, hideList=True)
578 repo_group = OneOf(repo_groups, hideList=True)
579 repo_type = OneOf(supported_backends)
579 repo_type = OneOf(supported_backends)
580 description = UnicodeString(strip=True, min=1, not_empty=True)
580 description = UnicodeString(strip=True, min=1, not_empty=True)
581 private = StringBoolean(if_missing=False)
581 private = StringBoolean(if_missing=False)
582 enable_statistics = StringBoolean(if_missing=False)
582 enable_statistics = StringBoolean(if_missing=False)
583 enable_downloads = StringBoolean(if_missing=False)
583 enable_downloads = StringBoolean(if_missing=False)
584
584
585 if edit:
585 if edit:
586 #this is repo owner
586 #this is repo owner
587 user = All(UnicodeString(not_empty=True), ValidRepoUser)
587 user = All(UnicodeString(not_empty=True), ValidRepoUser)
588
588
589 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
589 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
590 return _RepoForm
590 return _RepoForm
591
591
592 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
592 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
593 repo_groups=[]):
593 repo_groups=[]):
594 class _RepoForkForm(formencode.Schema):
594 class _RepoForkForm(formencode.Schema):
595 allow_extra_fields = True
595 allow_extra_fields = True
596 filter_extra_fields = False
596 filter_extra_fields = False
597 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
597 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
598 SlugifyName())
598 SlugifyName())
599 repo_group = OneOf(repo_groups, hideList=True)
599 repo_group = OneOf(repo_groups, hideList=True)
600 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
600 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
601 description = UnicodeString(strip=True, min=1, not_empty=True)
601 description = UnicodeString(strip=True, min=1, not_empty=True)
602 private = StringBoolean(if_missing=False)
602 private = StringBoolean(if_missing=False)
603 copy_permissions = StringBoolean(if_missing=False)
603 copy_permissions = StringBoolean(if_missing=False)
604 update_after_clone = StringBoolean(if_missing=False)
604 update_after_clone = StringBoolean(if_missing=False)
605 fork_parent_id = UnicodeString()
605 fork_parent_id = UnicodeString()
606 chained_validators = [ValidForkName(edit, old_data)]
606 chained_validators = [ValidForkName(edit, old_data)]
607
607
608 return _RepoForkForm
608 return _RepoForkForm
609
609
610 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
610 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
611 repo_groups=[]):
611 repo_groups=[]):
612 class _RepoForm(formencode.Schema):
612 class _RepoForm(formencode.Schema):
613 allow_extra_fields = True
613 allow_extra_fields = True
614 filter_extra_fields = False
614 filter_extra_fields = False
615 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
615 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
616 SlugifyName())
616 SlugifyName())
617 description = UnicodeString(strip=True, min=1, not_empty=True)
617 description = UnicodeString(strip=True, min=1, not_empty=True)
618 repo_group = OneOf(repo_groups, hideList=True)
618 repo_group = OneOf(repo_groups, hideList=True)
619 private = StringBoolean(if_missing=False)
619 private = StringBoolean(if_missing=False)
620
620
621 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
621 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
622 ValidSettings]
622 ValidSettings]
623 return _RepoForm
623 return _RepoForm
624
624
625
625
626 def ApplicationSettingsForm():
626 def ApplicationSettingsForm():
627 class _ApplicationSettingsForm(formencode.Schema):
627 class _ApplicationSettingsForm(formencode.Schema):
628 allow_extra_fields = True
628 allow_extra_fields = True
629 filter_extra_fields = False
629 filter_extra_fields = False
630 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
630 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
631 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
631 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
632 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
632 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
633
633
634 return _ApplicationSettingsForm
634 return _ApplicationSettingsForm
635
635
636 def ApplicationUiSettingsForm():
636 def ApplicationUiSettingsForm():
637 class _ApplicationUiSettingsForm(formencode.Schema):
637 class _ApplicationUiSettingsForm(formencode.Schema):
638 allow_extra_fields = True
638 allow_extra_fields = True
639 filter_extra_fields = False
639 filter_extra_fields = False
640 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
640 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
641 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
641 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
642 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
642 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
643 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
643 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
644 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
644 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
645 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
645 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
646
646
647 return _ApplicationUiSettingsForm
647 return _ApplicationUiSettingsForm
648
648
649 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
649 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
650 class _DefaultPermissionsForm(formencode.Schema):
650 class _DefaultPermissionsForm(formencode.Schema):
651 allow_extra_fields = True
651 allow_extra_fields = True
652 filter_extra_fields = True
652 filter_extra_fields = True
653 overwrite_default = StringBoolean(if_missing=False)
653 overwrite_default = StringBoolean(if_missing=False)
654 anonymous = OneOf(['True', 'False'], if_missing=False)
654 anonymous = OneOf(['True', 'False'], if_missing=False)
655 default_perm = OneOf(perms_choices)
655 default_perm = OneOf(perms_choices)
656 default_register = OneOf(register_choices)
656 default_register = OneOf(register_choices)
657 default_create = OneOf(create_choices)
657 default_create = OneOf(create_choices)
658
658
659 return _DefaultPermissionsForm
659 return _DefaultPermissionsForm
660
660
661
661
662 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
662 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
663 class _LdapSettingsForm(formencode.Schema):
663 class _LdapSettingsForm(formencode.Schema):
664 allow_extra_fields = True
664 allow_extra_fields = True
665 filter_extra_fields = True
665 filter_extra_fields = True
666 pre_validators = [LdapLibValidator]
666 pre_validators = [LdapLibValidator]
667 ldap_active = StringBoolean(if_missing=False)
667 ldap_active = StringBoolean(if_missing=False)
668 ldap_host = UnicodeString(strip=True,)
668 ldap_host = UnicodeString(strip=True,)
669 ldap_port = Number(strip=True,)
669 ldap_port = Number(strip=True,)
670 ldap_tls_kind = OneOf(tls_kind_choices)
670 ldap_tls_kind = OneOf(tls_kind_choices)
671 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
671 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
672 ldap_dn_user = UnicodeString(strip=True,)
672 ldap_dn_user = UnicodeString(strip=True,)
673 ldap_dn_pass = UnicodeString(strip=True,)
673 ldap_dn_pass = UnicodeString(strip=True,)
674 ldap_base_dn = UnicodeString(strip=True,)
674 ldap_base_dn = UnicodeString(strip=True,)
675 ldap_filter = UnicodeString(strip=True,)
675 ldap_filter = UnicodeString(strip=True,)
676 ldap_search_scope = OneOf(search_scope_choices)
676 ldap_search_scope = OneOf(search_scope_choices)
677 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
677 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
678 ldap_attr_firstname = UnicodeString(strip=True,)
678 ldap_attr_firstname = UnicodeString(strip=True,)
679 ldap_attr_lastname = UnicodeString(strip=True,)
679 ldap_attr_lastname = UnicodeString(strip=True,)
680 ldap_attr_email = UnicodeString(strip=True,)
680 ldap_attr_email = UnicodeString(strip=True,)
681
681
682 return _LdapSettingsForm
682 return _LdapSettingsForm
General Comments 0
You need to be logged in to leave comments. Login now