##// END OF EJS Templates
Merge with upstream
Nicolas VINOT -
r1591:0b63a0d2 merge beta
parent child Browse files
Show More
@@ -0,0 +1,63 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.model.users_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 repository permission model for RhodeCode
7
8 :created_on: Oct 1, 2011
9 :author: nvinot
10 :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26 import logging
27 from rhodecode.model.db import BaseModel, RepoToPerm, Permission
28 from rhodecode.model.meta import Session
29
30 log = logging.getLogger( __name__ )
31
32 class RepositoryPermissionModel( BaseModel ):
33 def getUserPermission( self, repository, user ):
34 return RepoToPerm.query() \
35 .filter( RepoToPerm.user == user ) \
36 .filter( RepoToPerm.repository == repository ) \
37 .scalar()
38
39 def updateUserPermission( self, repository, user, permission ):
40 permission = Permission.get_by_key( permission )
41 current = self.getUserPermission( repository, user )
42 if current:
43 if not current.permission is permission:
44 current.permission = permission
45 else:
46 p = RepoToPerm()
47 p.user = user
48 p.repository = repository
49 p.permission = permission
50 Session.add( p )
51 Session.commit()
52
53 def deleteUserPermission( self, repository, user ):
54 current = self.getUserPermission( repository, user )
55 if current:
56 Session.delete( current )
57 Session.commit()
58
59 def updateOrDeleteUserPermission( self, repository, user, permission ):
60 if permission:
61 self.updateUserPermission( repository, user, permission )
62 else:
63 self.deleteUserPermission( repository, user )
@@ -0,0 +1,89 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.model.users_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 users group model for RhodeCode
7
8 :created_on: Oct 1, 2011
9 :author: nvinot
10 :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26 import logging
27 import traceback
28
29 from rhodecode.model import BaseModel
30 from rhodecode.model.caching_query import FromCache
31 from rhodecode.model.db import UsersGroupMember, UsersGroup
32
33 log = logging.getLogger( __name__ )
34
35 class UsersGroupModel( BaseModel ):
36
37 def get( self, users_group_id, cache = False ):
38 users_group = UsersGroup.query()
39 if cache:
40 users_group = users_group.options( FromCache( "sql_cache_short",
41 "get_users_group_%s" % users_group_id ) )
42 return users_group.get( users_group_id )
43
44 def get_by_name( self, name, cache = False, case_insensitive = False ):
45 users_group = UsersGroup.query()
46 if case_insensitive:
47 users_group = users_group.filter( UsersGroup.users_group_name.ilike( name ) )
48 else:
49 users_group = users_group.filter( UsersGroup.users_group_name == name )
50 if cache:
51 users_group = users_group.options( FromCache( "sql_cache_short",
52 "get_users_group_%s" % name ) )
53 return users_group.scalar()
54
55 def create( self, form_data ):
56 try:
57 new_users_group = UsersGroup()
58 for k, v in form_data.items():
59 setattr( new_users_group, k, v )
60
61 self.sa.add( new_users_group )
62 self.sa.commit()
63 return new_users_group
64 except:
65 log.error( traceback.format_exc() )
66 self.sa.rollback()
67 raise
68
69 def add_user_to_group( self, users_group, user ):
70 for m in users_group.members:
71 u = m.user
72 if u.user_id == user.user_id:
73 return m
74
75 try:
76 users_group_member = UsersGroupMember()
77 users_group_member.user = user
78 users_group_member.users_group = users_group
79
80 users_group.members.append( users_group_member )
81 user.group_member.append( users_group_member )
82
83 self.sa.add( users_group_member )
84 self.sa.commit()
85 return users_group_member
86 except:
87 log.error( traceback.format_exc() )
88 self.sa.rollback()
89 raise
@@ -1,98 +1,372 b''
1 1 import traceback
2 2 import logging
3 3
4 4 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
5 from rhodecode.lib.auth import HasPermissionAllDecorator
5 from rhodecode.lib.auth import HasPermissionAllDecorator, HasPermissionAnyDecorator
6 6 from rhodecode.model.scm import ScmModel
7 7
8 from rhodecode.model.db import User, UsersGroup, Repository
8 from rhodecode.model.db import User, UsersGroup, Group, Repository
9 from rhodecode.model.repo import RepoModel
10 from rhodecode.model.user import UserModel
11 from rhodecode.model.repo_permission import RepositoryPermissionModel
12 from rhodecode.model.users_group import UsersGroupModel
13 from rhodecode.model import users_group
14 from rhodecode.model.repos_group import ReposGroupModel
15 from sqlalchemy.orm.exc import NoResultFound
9 16
10 log = logging.getLogger(__name__)
17 log = logging.getLogger( __name__ )
11 18
12 19
13 class ApiController(JSONRPCController):
20 class ApiController( JSONRPCController ):
14 21 """
15 22 API Controller
16
17
23
24
18 25 Each method needs to have USER as argument this is then based on given
19 26 API_KEY propagated as instance of user object
20
27
21 28 Preferably this should be first argument also
22
23
24 Each function should also **raise** JSONRPCError for any
29
30
31 Each function should also **raise** JSONRPCError for any
25 32 errors that happens
26
33
27 34 """
28 35
29 @HasPermissionAllDecorator('hg.admin')
30 def pull(self, apiuser, repo):
36 @HasPermissionAllDecorator( 'hg.admin' )
37 def pull( self, apiuser, repo ):
31 38 """
32 39 Dispatch pull action on given repo
33
34
40
41
35 42 :param user:
36 43 :param repo:
37 44 """
38 45
39 if Repository.is_valid(repo) is False:
40 raise JSONRPCError('Unknown repo "%s"' % repo)
41
46 if Repository.is_valid( repo ) is False:
47 raise JSONRPCError( 'Unknown repo "%s"' % repo )
48
42 49 try:
43 ScmModel().pull_changes(repo, self.rhodecode_user.username)
50 ScmModel().pull_changes( repo, self.rhodecode_user.username )
44 51 return 'Pulled from %s' % repo
45 52 except Exception:
46 raise JSONRPCError('Unable to pull changes from "%s"' % repo)
53 raise JSONRPCError( 'Unable to pull changes from "%s"' % repo )
54
55 @HasPermissionAllDecorator( 'hg.admin' )
56 def get_user( self, apiuser, username ):
57 """"
58 Get a user by username
59
60 :param apiuser
61 :param username
62 """
47 63
64 user = User.get_by_username( username )
65 if not user:
66 return None
67
68 return dict( id = user.user_id,
69 username = user.username,
70 firstname = user.name,
71 lastname = user.lastname,
72 email = user.email,
73 active = user.active,
74 admin = user.admin,
75 ldap = user.ldap_dn )
48 76
49 @HasPermissionAllDecorator('hg.admin')
50 def create_user(self, apiuser, username, password, active, admin, name,
51 lastname, email):
77 @HasPermissionAllDecorator( 'hg.admin' )
78 def get_users( self, apiuser ):
79 """"
80 Get all users
81
82 :param apiuser
52 83 """
53 Creates new user
54
84
85 result = []
86 for user in User.getAll():
87 result.append( dict( id = user.user_id,
88 username = user.username,
89 firstname = user.name,
90 lastname = user.lastname,
91 email = user.email,
92 active = user.active,
93 admin = user.admin,
94 ldap = user.ldap_dn ) )
95 return result
96
97 @HasPermissionAllDecorator( 'hg.admin' )
98 def create_user( self, apiuser, username, password, firstname,
99 lastname, email, active = True, admin = False, ldap_dn = None ):
100 """
101 Create new user
102
55 103 :param apiuser:
56 104 :param username:
57 105 :param password:
58 :param active:
59 :param admin:
60 106 :param name:
61 107 :param lastname:
62 108 :param email:
109 :param active:
110 :param admin:
111 :param ldap_dn:
63 112 """
64
65 form_data = dict(username=username,
66 password=password,
67 active=active,
68 admin=admin,
69 name=name,
70 lastname=lastname,
71 email=email)
113
114 if self.get_user( apiuser, username ):
115 raise JSONRPCError( "user %s already exist" % username )
116
72 117 try:
73 u = User.create(form_data)
74 return {'id':u.user_id,
75 'msg':'created new user %s' % name}
118 form_data = dict( username = username,
119 password = password,
120 active = active,
121 admin = admin,
122 name = firstname,
123 lastname = lastname,
124 email = email,
125 ldap_dn = ldap_dn )
126 UserModel().create_ldap( username, password, ldap_dn, form_data )
127 return dict( msg = 'created new user %s' % username )
76 128 except Exception:
77 log.error(traceback.format_exc())
78 raise JSONRPCError('failed to create user %s' % name)
129 log.error( traceback.format_exc() )
130 raise JSONRPCError( 'failed to create user %s' % username )
131
132 @HasPermissionAllDecorator( 'hg.admin' )
133 def get_users_group( self, apiuser, group_name ):
134 """"
135 Get users group by name
136
137 :param apiuser
138 :param group_name
139 """
140
141 users_group = UsersGroup.get_by_group_name( group_name )
142 if not users_group:
143 return None
144
145 members = []
146 for user in users_group.members:
147 user = user.user
148 members.append( dict( id = user.user_id,
149 username = user.username,
150 firstname = user.name,
151 lastname = user.lastname,
152 email = user.email,
153 active = user.active,
154 admin = user.admin,
155 ldap = user.ldap_dn ) )
79 156
157 return dict( id = users_group.users_group_id,
158 name = users_group.users_group_name,
159 active = users_group.users_group_active,
160 members = members )
80 161
81 @HasPermissionAllDecorator('hg.admin')
82 def create_users_group(self, apiuser, name, active):
162 @HasPermissionAllDecorator( 'hg.admin' )
163 def get_users_groups( self, apiuser ):
164 """"
165 Get all users groups
166
167 :param apiuser
168 """
169
170 result = []
171 for users_group in UsersGroup.getAll():
172 members = []
173 for user in users_group.members:
174 user = user.user
175 members.append( dict( id = user.user_id,
176 username = user.username,
177 firstname = user.name,
178 lastname = user.lastname,
179 email = user.email,
180 active = user.active,
181 admin = user.admin,
182 ldap = user.ldap_dn ) )
183
184 result.append( dict( id = users_group.users_group_id,
185 name = users_group.users_group_name,
186 active = users_group.users_group_active,
187 members = members ) )
188 return result
189
190 @HasPermissionAllDecorator( 'hg.admin' )
191 def create_users_group( self, apiuser, name, active = True ):
83 192 """
84 193 Creates an new usergroup
85
194
86 195 :param name:
87 196 :param active:
88 197 """
89 form_data = {'users_group_name':name,
90 'users_group_active':active}
198
199 if self.get_users_group( apiuser, name ):
200 raise JSONRPCError( "users group %s already exist" % name )
201
202 try:
203 form_data = dict( users_group_name = name,
204 users_group_active = active )
205 ug = UsersGroup.create( form_data )
206 return dict( id = ug.users_group_id,
207 msg = 'created new users group %s' % name )
208 except Exception:
209 log.error( traceback.format_exc() )
210 raise JSONRPCError( 'failed to create group %s' % name )
211
212 @HasPermissionAllDecorator( 'hg.admin' )
213 def add_user_to_users_group( self, apiuser, group_name, user_name ):
214 """"
215 Add a user to a group
216
217 :param apiuser
218 :param group_name
219 :param user_name
220 """
221
222 try:
223 users_group = UsersGroup.get_by_group_name( group_name )
224 if not users_group:
225 raise JSONRPCError( 'unknown users group %s' % group_name )
226
227 try:
228 user = User.get_by_username( user_name )
229 except NoResultFound:
230 raise JSONRPCError( 'unknown user %s' % user_name )
231
232 ugm = UsersGroupModel().add_user_to_group( users_group, user )
233
234 return dict( id = ugm.users_group_member_id,
235 msg = 'created new users group member' )
236 except Exception:
237 log.error( traceback.format_exc() )
238 raise JSONRPCError( 'failed to create users group member' )
239
240 @HasPermissionAnyDecorator( 'hg.admin' )
241 def get_repo( self, apiuser, repo_name ):
242 """"
243 Get repository by name
244
245 :param apiuser
246 :param repo_name
247 """
248
91 249 try:
92 ug = UsersGroup.create(form_data)
93 return {'id':ug.users_group_id,
94 'msg':'created new users group %s' % name}
250 repo = Repository.get_by_repo_name( repo_name )
251 except NoResultFound:
252 return None
253
254 members = []
255 for user in repo.repo_to_perm:
256 perm = user.permission.permission_name
257 user = user.user
258 members.append( dict( type_ = "user",
259 id = user.user_id,
260 username = user.username,
261 firstname = user.name,
262 lastname = user.lastname,
263 email = user.email,
264 active = user.active,
265 admin = user.admin,
266 ldap = user.ldap_dn,
267 permission = perm ) )
268 for users_group in repo.users_group_to_perm:
269 perm = users_group.permission.permission_name
270 users_group = users_group.users_group
271 members.append( dict( type_ = "users_group",
272 id = users_group.users_group_id,
273 name = users_group.users_group_name,
274 active = users_group.users_group_active,
275 permission = perm ) )
276
277 return dict( id = repo.repo_id,
278 name = repo.repo_name,
279 type = repo.repo_type,
280 description = repo.description,
281 members = members )
282
283 @HasPermissionAnyDecorator( 'hg.admin' )
284 def get_repos( self, apiuser ):
285 """"
286 Get all repositories
287
288 :param apiuser
289 """
290
291 result = []
292 for repository in Repository.getAll():
293 result.append( dict( id = repository.repo_id,
294 name = repository.repo_name,
295 type = repository.repo_type,
296 description = repository.description ) )
297 return result
298
299 @HasPermissionAnyDecorator( 'hg.admin', 'hg.create.repository' )
300 def create_repo( self, apiuser, name, owner_name, description = '', repo_type = 'hg', \
301 private = False ):
302 """
303 Create a repository
304
305 :param apiuser
306 :param name
307 :param description
308 :param type
309 :param private
310 :param owner_name
311 """
312
313 try:
314 try:
315 owner = User.get_by_username( owner_name )
316 except NoResultFound:
317 raise JSONRPCError( 'unknown user %s' % owner )
318
319 if self.get_repo( apiuser, name ):
320 raise JSONRPCError( "repo %s already exist" % name )
321
322 groups = name.split( '/' )
323 real_name = groups[-1]
324 groups = groups[:-1]
325 parent_id = None
326 for g in groups:
327 group = Group.get_by_group_name( g )
328 if not group:
329 group = ReposGroupModel().create( dict( group_name = g,
330 group_description = '',
331 group_parent_id = parent_id ) )
332 parent_id = group.group_id
333
334 RepoModel().create( dict( repo_name = real_name,
335 repo_name_full = name,
336 description = description,
337 private = private,
338 repo_type = repo_type,
339 repo_group = parent_id,
340 clone_uri = None ), owner )
95 341 except Exception:
96 log.error(traceback.format_exc())
97 raise JSONRPCError('failed to create group %s' % name)
98 No newline at end of file
342 log.error( traceback.format_exc() )
343 raise JSONRPCError( 'failed to create repository %s' % name )
344
345 @HasPermissionAnyDecorator( 'hg.admin' )
346 def add_user_to_repo( self, apiuser, repo_name, user_name, perm ):
347 """
348 Add permission for a user to a repository
349
350 :param apiuser
351 :param repo_name
352 :param user_name
353 :param perm
354 """
355
356 try:
357 try:
358 repo = Repository.get_by_repo_name( repo_name )
359 except NoResultFound:
360 raise JSONRPCError( 'unknown repository %s' % repo )
361
362 try:
363 user = User.get_by_username( user_name )
364 except NoResultFound:
365 raise JSONRPCError( 'unknown user %s' % user )
366
367 RepositoryPermissionModel().updateOrDeleteUserPermission( repo, user, perm )
368 except Exception:
369 log.error( traceback.format_exc() )
370 raise JSONRPCError( 'failed to edit permission %(repo)s for %(user)s'
371 % dict( user = user_name, repo = repo_name ) )
372
This diff has been collapsed as it changes many lines, (903 lines changed) Show them Hide them
@@ -1,1050 +1,1069 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.db
4 4 ~~~~~~~~~~~~~~~~~~
5 5
6 6 Database Models for RhodeCode
7 7
8 8 :created_on: Apr 08, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import datetime
29 29 import traceback
30 30 from datetime import date
31 31
32 32 from sqlalchemy import *
33 33 from sqlalchemy.exc import DatabaseError
34 34 from sqlalchemy.ext.hybrid import hybrid_property
35 35 from sqlalchemy.orm import relationship, backref, joinedload, class_mapper, \
36 36 validates
37 37 from sqlalchemy.orm.interfaces import MapperExtension
38 38 from beaker.cache import cache_region, region_invalidate
39 39
40 40 from vcs import get_backend
41 41 from vcs.utils.helpers import get_scm
42 42 from vcs.exceptions import VCSError
43 43 from vcs.utils.lazy import LazyProperty
44 44
45 45 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, \
46 46 generate_api_key, safe_unicode
47 47 from rhodecode.lib.exceptions import UsersGroupsAssignedException
48 48 from rhodecode.lib.compat import json
49 49
50 50 from rhodecode.model.meta import Base, Session
51 51 from rhodecode.model.caching_query import FromCache
52 52
53 53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger( __name__ )
55 55
56 56 #==============================================================================
57 57 # BASE CLASSES
58 58 #==============================================================================
59 59
60 class ModelSerializer(json.JSONEncoder):
60 class ModelSerializer( json.JSONEncoder ):
61 61 """
62 62 Simple Serializer for JSON,
63
63
64 64 usage::
65
65
66 66 to make object customized for serialization implement a __json__
67 67 method that will return a dict for serialization into json
68
68
69 69 example::
70
70
71 71 class Task(object):
72
72
73 73 def __init__(self, name, value):
74 74 self.name = name
75 75 self.value = value
76
76
77 77 def __json__(self):
78 78 return dict(name=self.name,
79 value=self.value)
80
79 value=self.value)
80
81 81 """
82 82
83 def default(self, obj):
83 def default( self, obj ):
84 84
85 if hasattr(obj, '__json__'):
85 if hasattr( obj, '__json__' ):
86 86 return obj.__json__()
87 87 else:
88 return json.JSONEncoder.default(self, obj)
88 return json.JSONEncoder.default( self, obj )
89 89
90 class BaseModel(object):
90 class BaseModel( object ):
91 91 """Base Model for all classess
92 92
93 93 """
94 94
95 95 @classmethod
96 def _get_keys(cls):
96 def _get_keys( cls ):
97 97 """return column names for this model """
98 return class_mapper(cls).c.keys()
98 return class_mapper( cls ).c.keys()
99 99
100 def get_dict(self):
100 def get_dict( self ):
101 101 """return dict with keys and values corresponding
102 102 to this model data """
103 103
104 104 d = {}
105 105 for k in self._get_keys():
106 d[k] = getattr(self, k)
106 d[k] = getattr( self, k )
107 107 return d
108 108
109 def get_appstruct(self):
109 def get_appstruct( self ):
110 110 """return list with keys and values tupples corresponding
111 111 to this model data """
112 112
113 113 l = []
114 114 for k in self._get_keys():
115 l.append((k, getattr(self, k),))
115 l.append( ( k, getattr( self, k ), ) )
116 116 return l
117 117
118 def populate_obj(self, populate_dict):
118 def populate_obj( self, populate_dict ):
119 119 """populate model with data from given populate_dict"""
120 120
121 121 for k in self._get_keys():
122 122 if k in populate_dict:
123 setattr(self, k, populate_dict[k])
123 setattr( self, k, populate_dict[k] )
124 124
125 125 @classmethod
126 def query(cls):
127 return Session.query(cls)
126 def query( cls ):
127 return Session.query( cls )
128 128
129 129 @classmethod
130 def get(cls, id_):
131 if id_:
132 return Session.query(cls).get(id_)
130 def get( cls, id_ ):
131 return cls.query().get( id_ )
133 132
134 133 @classmethod
135 def delete(cls, id_):
136 obj = Session.query(cls).get(id_)
137 Session.delete(obj)
134 def getAll( cls ):
135 return cls.query().all()
136
137 @classmethod
138 def delete( cls, id_ ):
139 obj = cls.query().get( id_ )
140 Session.delete( obj )
138 141 Session.commit()
139 142
140 143
141 class RhodeCodeSettings(Base, BaseModel):
144 class RhodeCodeSettings( Base, BaseModel ):
142 145 __tablename__ = 'rhodecode_settings'
143 __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True})
144 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
145 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
146 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
146 __table_args__ = ( UniqueConstraint( 'app_settings_name' ), {'extend_existing':True} )
147 app_settings_id = Column( "app_settings_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
148 app_settings_name = Column( "app_settings_name", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
149 _app_settings_value = Column( "app_settings_value", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
147 150
148 def __init__(self, k='', v=''):
151 def __init__( self, k = '', v = '' ):
149 152 self.app_settings_name = k
150 153 self.app_settings_value = v
151 154
152 155
153 @validates('_app_settings_value')
154 def validate_settings_value(self, key, val):
155 assert type(val) == unicode
156 @validates( '_app_settings_value' )
157 def validate_settings_value( self, key, val ):
158 assert type( val ) == unicode
156 159 return val
157 160
158 161 @hybrid_property
159 def app_settings_value(self):
162 def app_settings_value( self ):
160 163 v = self._app_settings_value
161 164 if v == 'ldap_active':
162 v = str2bool(v)
163 return v
165 v = str2bool( v )
166 return v
164 167
165 168 @app_settings_value.setter
166 def app_settings_value(self,val):
169 def app_settings_value( self, val ):
167 170 """
168 171 Setter that will always make sure we use unicode in app_settings_value
169
172
170 173 :param val:
171 174 """
172 self._app_settings_value = safe_unicode(val)
175 self._app_settings_value = safe_unicode( val )
173 176
174 def __repr__(self):
175 return "<%s('%s:%s')>" % (self.__class__.__name__,
176 self.app_settings_name, self.app_settings_value)
177 def __repr__( self ):
178 return "<%s('%s:%s')>" % ( self.__class__.__name__,
179 self.app_settings_name, self.app_settings_value )
177 180
178 181
179 182 @classmethod
180 def get_by_name(cls, ldap_key):
181 return Session.query(cls)\
182 .filter(cls.app_settings_name == ldap_key).scalar()
183 def get_by_name( cls, ldap_key ):
184 return cls.query()\
185 .filter( cls.app_settings_name == ldap_key ).scalar()
183 186
184 187 @classmethod
185 def get_app_settings(cls, cache=False):
188 def get_app_settings( cls, cache = False ):
186 189
187 ret = Session.query(cls)
190 ret = cls.query()
188 191
189 192 if cache:
190 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
193 ret = ret.options( FromCache( "sql_cache_short", "get_hg_settings" ) )
191 194
192 195 if not ret:
193 raise Exception('Could not get application settings !')
196 raise Exception( 'Could not get application settings !' )
194 197 settings = {}
195 198 for each in ret:
196 199 settings['rhodecode_' + each.app_settings_name] = \
197 200 each.app_settings_value
198 201
199 202 return settings
200 203
201 204 @classmethod
202 def get_ldap_settings(cls, cache=False):
203 ret = Session.query(cls)\
204 .filter(cls.app_settings_name.startswith('ldap_')).all()
205 def get_ldap_settings( cls, cache = False ):
206 ret = cls.query()\
207 .filter( cls.app_settings_name.startswith( 'ldap_' ) ).all()
205 208 fd = {}
206 209 for row in ret:
207 fd.update({row.app_settings_name:row.app_settings_value})
210 fd.update( {row.app_settings_name:row.app_settings_value} )
208 211
209 212 return fd
210 213
211 214
212 class RhodeCodeUi(Base, BaseModel):
215 class RhodeCodeUi( Base, BaseModel ):
213 216 __tablename__ = 'rhodecode_ui'
214 __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True})
217 __table_args__ = ( UniqueConstraint( 'ui_key' ), {'extend_existing':True} )
215 218
216 219 HOOK_UPDATE = 'changegroup.update'
217 220 HOOK_REPO_SIZE = 'changegroup.repo_size'
218 221 HOOK_PUSH = 'pretxnchangegroup.push_logger'
219 222 HOOK_PULL = 'preoutgoing.pull_logger'
220 223
221 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
222 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
223 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
224 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
225 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
224 ui_id = Column( "ui_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
225 ui_section = Column( "ui_section", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
226 ui_key = Column( "ui_key", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
227 ui_value = Column( "ui_value", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
228 ui_active = Column( "ui_active", Boolean(), nullable = True, unique = None, default = True )
226 229
227 230
228 231 @classmethod
229 def get_by_key(cls, key):
230 return Session.query(cls).filter(cls.ui_key == key)
232 def get_by_key( cls, key ):
233 return cls.query().filter( cls.ui_key == key )
231 234
232 235
233 236 @classmethod
234 def get_builtin_hooks(cls):
237 def get_builtin_hooks( cls ):
235 238 q = cls.query()
236 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
239 q = q.filter( cls.ui_key.in_( [cls.HOOK_UPDATE,
237 240 cls.HOOK_REPO_SIZE,
238 cls.HOOK_PUSH, cls.HOOK_PULL]))
241 cls.HOOK_PUSH, cls.HOOK_PULL] ) )
239 242 return q.all()
240 243
241 244 @classmethod
242 def get_custom_hooks(cls):
245 def get_custom_hooks( cls ):
243 246 q = cls.query()
244 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
247 q = q.filter( ~cls.ui_key.in_( [cls.HOOK_UPDATE,
245 248 cls.HOOK_REPO_SIZE,
246 cls.HOOK_PUSH, cls.HOOK_PULL]))
247 q = q.filter(cls.ui_section == 'hooks')
249 cls.HOOK_PUSH, cls.HOOK_PULL] ) )
250 q = q.filter( cls.ui_section == 'hooks' )
248 251 return q.all()
249 252
250 253 @classmethod
251 def create_or_update_hook(cls, key, val):
252 new_ui = cls.get_by_key(key).scalar() or cls()
254 def create_or_update_hook( cls, key, val ):
255 new_ui = cls.get_by_key( key ).scalar() or cls()
253 256 new_ui.ui_section = 'hooks'
254 257 new_ui.ui_active = True
255 258 new_ui.ui_key = key
256 259 new_ui.ui_value = val
257 260
258 Session.add(new_ui)
261 Session.add( new_ui )
259 262 Session.commit()
260 263
261 264
262 class User(Base, BaseModel):
265 class User( Base, BaseModel ):
263 266 __tablename__ = 'users'
264 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True})
265 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
266 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
267 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
268 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
269 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
270 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
271 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
272 email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
273 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
274 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
275 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
267 __table_args__ = ( UniqueConstraint( 'username' ), UniqueConstraint( 'email' ), {'extend_existing':True} )
268 user_id = Column( "user_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
269 username = Column( "username", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
270 password = Column( "password", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
271 active = Column( "active", Boolean(), nullable = True, unique = None, default = None )
272 admin = Column( "admin", Boolean(), nullable = True, unique = None, default = False )
273 name = Column( "name", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
274 lastname = Column( "lastname", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
275 email = Column( "email", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
276 last_login = Column( "last_login", DateTime( timezone = False ), nullable = True, unique = None, default = None )
277 ldap_dn = Column( "ldap_dn", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
278 api_key = Column( "api_key", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
276 279
277 user_log = relationship('UserLog', cascade='all')
278 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
280 user_log = relationship( 'UserLog', cascade = 'all' )
281 user_perms = relationship( 'UserToPerm', primaryjoin = "User.user_id==UserToPerm.user_id", cascade = 'all' )
279 282
280 repositories = relationship('Repository')
281 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
282 repo_to_perm = relationship('RepoToPerm', primaryjoin='RepoToPerm.user_id==User.user_id', cascade='all')
283 repositories = relationship( 'Repository' )
284 user_followers = relationship( 'UserFollowing', primaryjoin = 'UserFollowing.follows_user_id==User.user_id', cascade = 'all' )
285 repo_to_perm = relationship( 'RepoToPerm', primaryjoin = 'RepoToPerm.user_id==User.user_id', cascade = 'all' )
283 286
284 group_member = relationship('UsersGroupMember', cascade='all')
287 group_member = relationship( 'UsersGroupMember', cascade = 'all' )
285 288
286 289 @property
287 def full_contact(self):
288 return '%s %s <%s>' % (self.name, self.lastname, self.email)
290 def full_contact( self ):
291 return '%s %s <%s>' % ( self.name, self.lastname, self.email )
289 292
290 293 @property
291 def short_contact(self):
292 return '%s %s' % (self.name, self.lastname)
294 def short_contact( self ):
295 return '%s %s' % ( self.name, self.lastname )
293 296
294 297 @property
295 def is_admin(self):
298 def is_admin( self ):
296 299 return self.admin
297 300
298 def __repr__(self):
301 def __repr__( self ):
299 302 try:
300 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
301 self.user_id, self.username)
303 return "<%s('id:%s:%s')>" % ( self.__class__.__name__,
304 self.user_id, self.username )
302 305 except:
303 306 return self.__class__.__name__
304 307
305 308 @classmethod
306 def get_by_username(cls, username, case_insensitive=False):
309 def get_by_username( cls, username, case_insensitive = False ):
307 310 if case_insensitive:
308 return Session.query(cls).filter(cls.username.ilike(username)).scalar()
311 return Session.query( cls ).filter( cls.username.ilike( username ) ).scalar()
309 312 else:
310 return Session.query(cls).filter(cls.username == username).scalar()
313 return Session.query( cls ).filter( cls.username == username ).scalar()
311 314
312 315 @classmethod
313 def get_by_api_key(cls, api_key):
314 return Session.query(cls).filter(cls.api_key == api_key).one()
316 def get_by_api_key( cls, api_key ):
317 return cls.query().filter( cls.api_key == api_key ).one()
315 318
316 def update_lastlogin(self):
319 def update_lastlogin( self ):
317 320 """Update user lastlogin"""
318 321
319 322 self.last_login = datetime.datetime.now()
320 Session.add(self)
323 Session.add( self )
321 324 Session.commit()
322 log.debug('updated user %s lastlogin', self.username)
325 log.debug( 'updated user %s lastlogin', self.username )
323 326
324 327 @classmethod
325 def create(cls, form_data):
328 def create( cls, form_data ):
326 329 from rhodecode.lib.auth import get_crypt_password
327 330
328 331 try:
329 332 new_user = cls()
330 333 for k, v in form_data.items():
331 334 if k == 'password':
332 v = get_crypt_password(v)
333 setattr(new_user, k, v)
335 v = get_crypt_password( v )
336 setattr( new_user, k, v )
334 337
335 new_user.api_key = generate_api_key(form_data['username'])
336 Session.add(new_user)
338 new_user.api_key = generate_api_key( form_data['username'] )
339 Session.add( new_user )
337 340 Session.commit()
338 341 return new_user
339 342 except:
340 log.error(traceback.format_exc())
343 log.error( traceback.format_exc() )
341 344 Session.rollback()
342 345 raise
343 346
344 class UserLog(Base, BaseModel):
347 class UserLog( Base, BaseModel ):
345 348 __tablename__ = 'user_logs'
346 349 __table_args__ = {'extend_existing':True}
347 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
348 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
349 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
350 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
351 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
352 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
353 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
350 user_log_id = Column( "user_log_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
351 user_id = Column( "user_id", Integer(), ForeignKey( 'users.user_id' ), nullable = False, unique = None, default = None )
352 repository_id = Column( "repository_id", Integer(), ForeignKey( 'repositories.repo_id' ), nullable = False, unique = None, default = None )
353 repository_name = Column( "repository_name", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
354 user_ip = Column( "user_ip", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
355 action = Column( "action", UnicodeText( length = 1200000, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
356 action_date = Column( "action_date", DateTime( timezone = False ), nullable = True, unique = None, default = None )
354 357
355 358 @property
356 def action_as_day(self):
357 return date(*self.action_date.timetuple()[:3])
359 def action_as_day( self ):
360 return date( *self.action_date.timetuple()[:3] )
358 361
359 user = relationship('User')
360 repository = relationship('Repository')
362 user = relationship( 'User' )
363 repository = relationship( 'Repository' )
361 364
362 365
363 class UsersGroup(Base, BaseModel):
366 class UsersGroup( Base, BaseModel ):
364 367 __tablename__ = 'users_groups'
365 368 __table_args__ = {'extend_existing':True}
366 369
367 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
368 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
369 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
370 users_group_id = Column( "users_group_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
371 users_group_name = Column( "users_group_name", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = False, unique = True, default = None )
372 users_group_active = Column( "users_group_active", Boolean(), nullable = True, unique = None, default = None )
370 373
371 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
374 members = relationship( 'UsersGroupMember', cascade = "all, delete, delete-orphan", lazy = "joined" )
372 375
373 def __repr__(self):
374 return '<userGroup(%s)>' % (self.users_group_name)
376 def __repr__( self ):
377 return '<userGroup(%s)>' % ( self.users_group_name )
375 378
376 379 @classmethod
377 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
380 def get_by_group_name( cls, group_name, cache = False, case_insensitive = False ):
378 381 if case_insensitive:
379 gr = Session.query(cls)\
380 .filter(cls.users_group_name.ilike(group_name))
382 gr = cls.query()\
383 .filter( cls.users_group_name.ilike( group_name ) )
381 384 else:
382 gr = Session.query(UsersGroup)\
383 .filter(UsersGroup.users_group_name == group_name)
385 gr = cls.query()\
386 .filter( cls.users_group_name == group_name )
384 387 if cache:
385 gr = gr.options(FromCache("sql_cache_short",
386 "get_user_%s" % group_name))
388 gr = gr.options( FromCache( "sql_cache_short",
389 "get_user_%s" % group_name ) )
387 390 return gr.scalar()
388 391
389 392
390 393 @classmethod
391 def get(cls, users_group_id, cache=False):
392 users_group = Session.query(cls)
394 def get( cls, users_group_id, cache = False ):
395 users_group = cls.query()
393 396 if cache:
394 users_group = users_group.options(FromCache("sql_cache_short",
395 "get_users_group_%s" % users_group_id))
396 return users_group.get(users_group_id)
397 users_group = users_group.options( FromCache( "sql_cache_short",
398 "get_users_group_%s" % users_group_id ) )
399 return users_group.get( users_group_id )
397 400
398 401 @classmethod
399 def create(cls, form_data):
402 def create( cls, form_data ):
400 403 try:
401 404 new_users_group = cls()
402 405 for k, v in form_data.items():
403 setattr(new_users_group, k, v)
406 setattr( new_users_group, k, v )
404 407
405 Session.add(new_users_group)
408 Session.add( new_users_group )
406 409 Session.commit()
407 410 return new_users_group
408 411 except:
409 log.error(traceback.format_exc())
412 log.error( traceback.format_exc() )
410 413 Session.rollback()
411 414 raise
412 415
413 416 @classmethod
414 def update(cls, users_group_id, form_data):
417 def update( cls, users_group_id, form_data ):
415 418
416 419 try:
417 users_group = cls.get(users_group_id, cache=False)
420 users_group = cls.get( users_group_id, cache = False )
418 421
419 422 for k, v in form_data.items():
420 423 if k == 'users_group_members':
421 424 users_group.members = []
422 425 Session.flush()
423 426 members_list = []
424 427 if v:
425 for u_id in set(list(v)):
426 member = UsersGroupMember(users_group_id,u_id)
427 members_list.append(member)
428 setattr(users_group, 'members', members_list)
429 setattr(users_group, k, v)
428 for u_id in set( list( v ) ):
429 member = UsersGroupMember( users_group_id, u_id )
430 members_list.append( member )
431 setattr( users_group, 'members', members_list )
432 setattr( users_group, k, v )
430 433
431 Session.add(users_group)
434 Session.add( users_group )
432 435 Session.commit()
433 436 except:
434 log.error(traceback.format_exc())
437 log.error( traceback.format_exc() )
435 438 Session.rollback()
436 439 raise
437 440
438 441 @classmethod
439 def delete(cls, users_group_id):
442 def delete( cls, users_group_id ):
440 443 try:
441 444
442 445 # check if this group is not assigned to repo
443 446 assigned_groups = UsersGroupRepoToPerm.query()\
444 .filter(UsersGroupRepoToPerm.users_group_id ==
445 users_group_id).all()
447 .filter( UsersGroupRepoToPerm.users_group_id ==
448 users_group_id ).all()
446 449
447 450 if assigned_groups:
448 raise UsersGroupsAssignedException('Group assigned to %s' %
449 assigned_groups)
451 raise UsersGroupsAssignedException( 'Group assigned to %s' %
452 assigned_groups )
450 453
451 users_group = cls.get(users_group_id, cache=False)
452 Session.delete(users_group)
454 users_group = cls.get( users_group_id, cache = False )
455 Session.delete( users_group )
453 456 Session.commit()
454 457 except:
455 log.error(traceback.format_exc())
458 log.error( traceback.format_exc() )
456 459 Session.rollback()
457 460 raise
458 461
459
460 class UsersGroupMember(Base, BaseModel):
462 class UsersGroupMember( Base, BaseModel ):
461 463 __tablename__ = 'users_groups_members'
462 464 __table_args__ = {'extend_existing':True}
463 465
464 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
465 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
466 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
466 users_group_member_id = Column( "users_group_member_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
467 users_group_id = Column( "users_group_id", Integer(), ForeignKey( 'users_groups.users_group_id' ), nullable = False, unique = None, default = None )
468 user_id = Column( "user_id", Integer(), ForeignKey( 'users.user_id' ), nullable = False, unique = None, default = None )
467 469
468 user = relationship('User', lazy='joined')
469 users_group = relationship('UsersGroup')
470 user = relationship( 'User', lazy = 'joined' )
471 users_group = relationship( 'UsersGroup' )
470 472
471 def __init__(self, gr_id='', u_id=''):
473 def __init__( self, gr_id = '', u_id = '' ):
472 474 self.users_group_id = gr_id
473 475 self.user_id = u_id
474 476
475 class Repository(Base, BaseModel):
477 @staticmethod
478 def add_user_to_group( group, user ):
479 ugm = UsersGroupMember()
480 ugm.users_group = group
481 ugm.user = user
482 Session.add( ugm )
483 Session.commit()
484 return ugm
485
486 class Repository( Base, BaseModel ):
476 487 __tablename__ = 'repositories'
477 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
488 __table_args__ = ( UniqueConstraint( 'repo_name' ), {'extend_existing':True}, )
478 489
479 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
480 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
481 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
482 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
483 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
484 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
485 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
486 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
487 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
488 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
490 repo_id = Column( "repo_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
491 repo_name = Column( "repo_name", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = False, unique = True, default = None )
492 clone_uri = Column( "clone_uri", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = False, default = None )
493 repo_type = Column( "repo_type", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = False, unique = False, default = 'hg' )
494 user_id = Column( "user_id", Integer(), ForeignKey( 'users.user_id' ), nullable = False, unique = False, default = None )
495 private = Column( "private", Boolean(), nullable = True, unique = None, default = None )
496 enable_statistics = Column( "statistics", Boolean(), nullable = True, unique = None, default = True )
497 enable_downloads = Column( "downloads", Boolean(), nullable = True, unique = None, default = True )
498 description = Column( "description", String( length = 10000, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
499 created_on = Column( 'created_on', DateTime( timezone = False ), nullable = True, unique = None, default = datetime.datetime.now )
489 500
490 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
491 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
501 fork_id = Column( "fork_id", Integer(), ForeignKey( 'repositories.repo_id' ), nullable = True, unique = False, default = None )
502 group_id = Column( "group_id", Integer(), ForeignKey( 'groups.group_id' ), nullable = True, unique = False, default = None )
492 503
493 504
494 user = relationship('User')
495 fork = relationship('Repository', remote_side=repo_id)
496 group = relationship('Group')
497 repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
498 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
499 stats = relationship('Statistics', cascade='all', uselist=False)
505 user = relationship( 'User' )
506 fork = relationship( 'Repository', remote_side = repo_id )
507 group = relationship( 'Group' )
508 repo_to_perm = relationship( 'RepoToPerm', cascade = 'all', order_by = 'RepoToPerm.repo_to_perm_id' )
509 users_group_to_perm = relationship( 'UsersGroupRepoToPerm', cascade = 'all' )
510 stats = relationship( 'Statistics', cascade = 'all', uselist = False )
500 511
501 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
512 followers = relationship( 'UserFollowing', primaryjoin = 'UserFollowing.follows_repo_id==Repository.repo_id', cascade = 'all' )
502 513
503 logs = relationship('UserLog', cascade='all')
514 logs = relationship( 'UserLog', cascade = 'all' )
504 515
505 def __repr__(self):
506 return "<%s('%s:%s')>" % (self.__class__.__name__,
507 self.repo_id, self.repo_name)
516 def __repr__( self ):
517 return "<%s('%s:%s')>" % ( self.__class__.__name__,
518 self.repo_id, self.repo_name )
508 519
509 520 @classmethod
510 def url_sep(cls):
521 def url_sep( cls ):
511 522 return '/'
512
523
513 524 @classmethod
514 def get_by_repo_name(cls, repo_name):
515 q = Session.query(cls).filter(cls.repo_name == repo_name)
516
517 q = q.options(joinedload(Repository.fork))\
518 .options(joinedload(Repository.user))\
519 .options(joinedload(Repository.group))\
520
525 def get_by_repo_name( cls, repo_name ):
526 q = Session.query( cls ).filter( cls.repo_name == repo_name )
527 q = q.options( joinedload( Repository.fork ) )\
528 .options( joinedload( Repository.user ) )\
529 .options( joinedload( Repository.group ) )
521 530 return q.one()
522 531
523 532 @classmethod
524 def get_repo_forks(cls, repo_id):
525 return Session.query(cls).filter(Repository.fork_id == repo_id)
533 def get_repo_forks( cls, repo_id ):
534 return cls.query().filter( Repository.fork_id == repo_id )
526 535
527 536 @classmethod
528 def base_path(cls):
537 def base_path( cls ):
529 538 """
530 539 Returns base path when all repos are stored
531
540
532 541 :param cls:
533 542 """
534 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
535 cls.url_sep())
536 q.options(FromCache("sql_cache_short", "repository_repo_path"))
543 q = Session.query( RhodeCodeUi ).filter( RhodeCodeUi.ui_key ==
544 cls.url_sep() )
545 q.options( FromCache( "sql_cache_short", "repository_repo_path" ) )
537 546 return q.one().ui_value
538 547
539 548 @property
540 def just_name(self):
541 return self.repo_name.split(Repository.url_sep())[-1]
549 def just_name( self ):
550 return self.repo_name.split( Repository.url_sep() )[-1]
542 551
543 552 @property
544 def groups_with_parents(self):
553 def groups_with_parents( self ):
545 554 groups = []
546 555 if self.group is None:
547 556 return groups
548 557
549 558 cur_gr = self.group
550 groups.insert(0, cur_gr)
559 groups.insert( 0, cur_gr )
551 560 while 1:
552 gr = getattr(cur_gr, 'parent_group', None)
561 gr = getattr( cur_gr, 'parent_group', None )
553 562 cur_gr = cur_gr.parent_group
554 563 if gr is None:
555 564 break
556 groups.insert(0, gr)
565 groups.insert( 0, gr )
557 566
558 567 return groups
559 568
560 569 @property
561 def groups_and_repo(self):
570 def groups_and_repo( self ):
562 571 return self.groups_with_parents, self.just_name
563 572
564 573 @LazyProperty
565 def repo_path(self):
574 def repo_path( self ):
566 575 """
567 576 Returns base full path for that repository means where it actually
568 577 exists on a filesystem
569 578 """
570 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
571 Repository.url_sep())
572 q.options(FromCache("sql_cache_short", "repository_repo_path"))
579 q = Session.query( RhodeCodeUi ).filter( RhodeCodeUi.ui_key ==
580 Repository.url_sep() )
581 q.options( FromCache( "sql_cache_short", "repository_repo_path" ) )
573 582 return q.one().ui_value
574 583
575 584 @property
576 def repo_full_path(self):
585 def repo_full_path( self ):
577 586 p = [self.repo_path]
578 587 # we need to split the name by / since this is how we store the
579 588 # names in the database, but that eventually needs to be converted
580 589 # into a valid system path
581 p += self.repo_name.split(Repository.url_sep())
582 return os.path.join(*p)
590 p += self.repo_name.split( Repository.url_sep() )
591 return os.path.join( *p )
583 592
584 def get_new_name(self, repo_name):
593 def get_new_name( self, repo_name ):
585 594 """
586 595 returns new full repository name based on assigned group and new new
587
596
588 597 :param group_name:
589 598 """
590 599 path_prefix = self.group.full_path_splitted if self.group else []
591 return Repository.url_sep().join(path_prefix + [repo_name])
600 return Repository.url_sep().join( path_prefix + [repo_name] )
592 601
593 602 @property
594 def _ui(self):
603 def _ui( self ):
595 604 """
596 605 Creates an db based ui object for this repository
597 606 """
598 607 from mercurial import ui
599 608 from mercurial import config
600 609 baseui = ui.ui()
601 610
602 611 #clean the baseui object
603 612 baseui._ocfg = config.config()
604 613 baseui._ucfg = config.config()
605 614 baseui._tcfg = config.config()
606 615
607 616
608 ret = Session.query(RhodeCodeUi)\
609 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
617 ret = RhodeCodeUi.query()\
618 .options( FromCache( "sql_cache_short", "repository_repo_ui" ) ).all()
610 619
611 620 hg_ui = ret
612 621 for ui_ in hg_ui:
613 622 if ui_.ui_active:
614 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
615 ui_.ui_key, ui_.ui_value)
616 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
623 log.debug( 'settings ui from db[%s]%s:%s', ui_.ui_section,
624 ui_.ui_key, ui_.ui_value )
625 baseui.setconfig( ui_.ui_section, ui_.ui_key, ui_.ui_value )
617 626
618 627 return baseui
619 628
620 629 @classmethod
621 def is_valid(cls, repo_name):
630 def is_valid( cls, repo_name ):
622 631 """
623 632 returns True if given repo name is a valid filesystem repository
624
633
625 634 @param cls:
626 635 @param repo_name:
627 636 """
628 637 from rhodecode.lib.utils import is_valid_repo
629 638
630 return is_valid_repo(repo_name, cls.base_path())
639 return is_valid_repo( repo_name, cls.base_path() )
631 640
632 641
633 642 #==========================================================================
634 643 # SCM PROPERTIES
635 644 #==========================================================================
636 645
637 def get_changeset(self, rev):
638 return get_changeset_safe(self.scm_instance, rev)
646 def get_changeset( self, rev ):
647 return get_changeset_safe( self.scm_instance, rev )
639 648
640 649 @property
641 def tip(self):
642 return self.get_changeset('tip')
650 def tip( self ):
651 return self.get_changeset( 'tip' )
643 652
644 653 @property
645 def author(self):
654 def author( self ):
646 655 return self.tip.author
647 656
648 657 @property
649 def last_change(self):
658 def last_change( self ):
650 659 return self.scm_instance.last_change
651 660
652 661 #==========================================================================
653 662 # SCM CACHE INSTANCE
654 663 #==========================================================================
655 664
656 665 @property
657 def invalidate(self):
666 def invalidate( self ):
658 667 """
659 668 Returns Invalidation object if this repo should be invalidated
660 669 None otherwise. `cache_active = False` means that this cache
661 670 state is not valid and needs to be invalidated
662 671 """
663 return Session.query(CacheInvalidation)\
664 .filter(CacheInvalidation.cache_key == self.repo_name)\
665 .filter(CacheInvalidation.cache_active == False)\
672 return CacheInvalidation.query()\
673 .filter( CacheInvalidation.cache_key == self.repo_name )\
674 .filter( CacheInvalidation.cache_active == False )\
666 675 .scalar()
667 676
668 def set_invalidate(self):
677 def set_invalidate( self ):
669 678 """
670 679 set a cache for invalidation for this instance
671 680 """
672 inv = Session.query(CacheInvalidation)\
673 .filter(CacheInvalidation.cache_key == self.repo_name)\
681 inv = CacheInvalidation.query()\
682 .filter( CacheInvalidation.cache_key == self.repo_name )\
674 683 .scalar()
675 684
676 685 if inv is None:
677 inv = CacheInvalidation(self.repo_name)
686 inv = CacheInvalidation( self.repo_name )
678 687 inv.cache_active = True
679 Session.add(inv)
688 Session.add( inv )
680 689 Session.commit()
681 690
682 691 @LazyProperty
683 def scm_instance(self):
692 def scm_instance( self ):
684 693 return self.__get_instance()
685 694
686 695 @property
687 def scm_instance_cached(self):
688 @cache_region('long_term')
689 def _c(repo_name):
696 def scm_instance_cached( self ):
697 @cache_region( 'long_term' )
698 def _c( repo_name ):
690 699 return self.__get_instance()
691 700
692 701 # TODO: remove this trick when beaker 1.6 is released
693 702 # and have fixed this issue with not supporting unicode keys
694 rn = safe_str(self.repo_name)
703 rn = safe_str( self.repo_name )
695 704
696 705 inv = self.invalidate
697 706 if inv is not None:
698 region_invalidate(_c, None, rn)
707 region_invalidate( _c, None, rn )
699 708 # update our cache
700 709 inv.cache_active = True
701 Session.add(inv)
710 Session.add( inv )
702 711 Session.commit()
703 712
704 return _c(rn)
713 return _c( rn )
705 714
706 def __get_instance(self):
715 def __get_instance( self ):
707 716
708 717 repo_full_path = self.repo_full_path
709 718
710 719 try:
711 alias = get_scm(repo_full_path)[0]
712 log.debug('Creating instance of %s repository', alias)
713 backend = get_backend(alias)
720 alias = get_scm( repo_full_path )[0]
721 log.debug( 'Creating instance of %s repository', alias )
722 backend = get_backend( alias )
714 723 except VCSError:
715 log.error(traceback.format_exc())
716 log.error('Perhaps this repository is in db and not in '
724 log.error( traceback.format_exc() )
725 log.error( 'Perhaps this repository is in db and not in '
717 726 'filesystem run rescan repositories with '
718 '"destroy old data " option from admin panel')
727 '"destroy old data " option from admin panel' )
719 728 return
720 729
721 730 if alias == 'hg':
722 731
723 repo = backend(safe_str(repo_full_path), create=False,
724 baseui=self._ui)
732 repo = backend( safe_str( repo_full_path ), create = False,
733 baseui = self._ui )
725 734 #skip hidden web repository
726 735 if repo._get_hidden():
727 736 return
728 737 else:
729 repo = backend(repo_full_path, create=False)
738 repo = backend( repo_full_path, create = False )
730 739
731 740 return repo
732 741
733 742
734 class Group(Base, BaseModel):
743 class Group( Base, BaseModel ):
735 744 __tablename__ = 'groups'
736 __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'),
737 CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},)
745 __table_args__ = ( UniqueConstraint( 'group_name', 'group_parent_id' ),
746 CheckConstraint( 'group_id != group_parent_id' ), {'extend_existing':True}, )
738 747 __mapper_args__ = {'order_by':'group_name'}
739 748
740 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
741 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
742 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
743 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
749 group_id = Column( "group_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
750 group_name = Column( "group_name", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = False, unique = True, default = None )
751 group_parent_id = Column( "group_parent_id", Integer(), ForeignKey( 'groups.group_id' ), nullable = True, unique = None, default = None )
752 group_description = Column( "group_description", String( length = 10000, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
744 753
745 parent_group = relationship('Group', remote_side=group_id)
754 parent_group = relationship( 'Group', remote_side = group_id )
746 755
747 756
748 def __init__(self, group_name='', parent_group=None):
757 def __init__( self, group_name = '', parent_group = None ):
749 758 self.group_name = group_name
750 759 self.parent_group = parent_group
751 760
752 def __repr__(self):
753 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
754 self.group_name)
761 def __repr__( self ):
762 return "<%s('%s:%s')>" % ( self.__class__.__name__, self.group_id,
763 self.group_name )
755 764
756 765 @classmethod
757 def groups_choices(cls):
766 def groups_choices( cls ):
758 767 from webhelpers.html import literal as _literal
759 repo_groups = [('', '')]
768 repo_groups = [( '', '' )]
760 769 sep = ' &raquo; '
761 _name = lambda k: _literal(sep.join(k))
770 _name = lambda k: _literal( sep.join( k ) )
762 771
763 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
764 for x in cls.query().all()])
765
766 repo_groups = sorted(repo_groups,key=lambda t: t[1].split(sep)[0])
772 repo_groups.extend( [( x.group_id, _name( x.full_path_splitted ) )
773 for x in cls.query().all()] )
774
775 repo_groups = sorted( repo_groups, key = lambda t: t[1].split( sep )[0] )
767 776 return repo_groups
768
777
769 778 @classmethod
770 def url_sep(cls):
779 def url_sep( cls ):
771 780 return '/'
772 781
773 782 @classmethod
774 def get_by_group_name(cls, group_name):
775 return cls.query().filter(cls.group_name == group_name).scalar()
783 def get_by_group_name( cls, group_name, cache = False, case_insensitive = False ):
784 if case_insensitive:
785 gr = cls.query()\
786 .filter( cls.group_name.ilike( group_name ) )
787 else:
788 gr = cls.query()\
789 .filter( cls.group_name == group_name )
790 if cache:
791 gr = gr.options( FromCache( "sql_cache_short",
792 "get_group_%s" % group_name ) )
793 return gr.scalar()
776 794
777 795 @property
778 def parents(self):
796 def parents( self ):
779 797 parents_recursion_limit = 5
780 798 groups = []
781 799 if self.parent_group is None:
782 800 return groups
783 801 cur_gr = self.parent_group
784 groups.insert(0, cur_gr)
802 groups.insert( 0, cur_gr )
785 803 cnt = 0
786 804 while 1:
787 805 cnt += 1
788 gr = getattr(cur_gr, 'parent_group', None)
806 gr = getattr( cur_gr, 'parent_group', None )
789 807 cur_gr = cur_gr.parent_group
790 808 if gr is None:
791 809 break
792 810 if cnt == parents_recursion_limit:
793 811 # this will prevent accidental infinit loops
794 log.error('group nested more than %s' %
795 parents_recursion_limit)
812 log.error( 'group nested more than %s' %
813 parents_recursion_limit )
796 814 break
797 815
798 groups.insert(0, gr)
816 groups.insert( 0, gr )
799 817 return groups
800 818
801 819 @property
802 def children(self):
803 return Session.query(Group).filter(Group.parent_group == self)
820 def children( self ):
821 return Group.query().filter( Group.parent_group == self )
804 822
805 823 @property
806 def name(self):
807 return self.group_name.split(Group.url_sep())[-1]
824 def name( self ):
825 return self.group_name.split( Group.url_sep() )[-1]
808 826
809 827 @property
810 def full_path(self):
811 return self.group_name
828 def full_path( self ):
829 return Group.url_sep().join( [g.group_name for g in self.parents] +
830 [self.group_name] )
812 831
813 832 @property
814 def full_path_splitted(self):
815 return self.group_name.split(Group.url_sep())
833 def full_path_splitted( self ):
834 return self.group_name.split( Group.url_sep() )
816 835
817 836 @property
818 def repositories(self):
819 return Session.query(Repository).filter(Repository.group == self)
837 def repositories( self ):
838 return Repository.query().filter( Repository.group == self )
820 839
821 840 @property
822 def repositories_recursive_count(self):
841 def repositories_recursive_count( self ):
823 842 cnt = self.repositories.count()
824 843
825 def children_count(group):
844 def children_count( group ):
826 845 cnt = 0
827 846 for child in group.children:
828 847 cnt += child.repositories.count()
829 cnt += children_count(child)
848 cnt += children_count( child )
830 849 return cnt
831 850
832 return cnt + children_count(self)
851 return cnt + children_count( self )
833 852
834 853
835 def get_new_name(self, group_name):
854 def get_new_name( self, group_name ):
836 855 """
837 856 returns new full group name based on parent and new name
838
857
839 858 :param group_name:
840 859 """
841 860 path_prefix = self.parent_group.full_path_splitted if self.parent_group else []
842 return Group.url_sep().join(path_prefix + [group_name])
861 return Group.url_sep().join( path_prefix + [group_name] )
843 862
844 863
845 class Permission(Base, BaseModel):
864 class Permission( Base, BaseModel ):
846 865 __tablename__ = 'permissions'
847 866 __table_args__ = {'extend_existing':True}
848 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
849 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
850 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
867 permission_id = Column( "permission_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
868 permission_name = Column( "permission_name", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
869 permission_longname = Column( "permission_longname", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
851 870
852 def __repr__(self):
853 return "<%s('%s:%s')>" % (self.__class__.__name__,
854 self.permission_id, self.permission_name)
871 def __repr__( self ):
872 return "<%s('%s:%s')>" % ( self.__class__.__name__,
873 self.permission_id, self.permission_name )
855 874
856 875 @classmethod
857 def get_by_key(cls, key):
858 return Session.query(cls).filter(cls.permission_name == key).scalar()
876 def get_by_key( cls, key ):
877 return cls.query().filter( cls.permission_name == key ).scalar()
859 878
860 class RepoToPerm(Base, BaseModel):
879 class RepoToPerm( Base, BaseModel ):
861 880 __tablename__ = 'repo_to_perm'
862 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True})
863 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
864 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
865 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
866 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
881 __table_args__ = ( UniqueConstraint( 'user_id', 'repository_id' ), {'extend_existing':True} )
882 repo_to_perm_id = Column( "repo_to_perm_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
883 user_id = Column( "user_id", Integer(), ForeignKey( 'users.user_id' ), nullable = False, unique = None, default = None )
884 permission_id = Column( "permission_id", Integer(), ForeignKey( 'permissions.permission_id' ), nullable = False, unique = None, default = None )
885 repository_id = Column( "repository_id", Integer(), ForeignKey( 'repositories.repo_id' ), nullable = False, unique = None, default = None )
867 886
868 user = relationship('User')
869 permission = relationship('Permission')
870 repository = relationship('Repository')
887 user = relationship( 'User' )
888 permission = relationship( 'Permission' )
889 repository = relationship( 'Repository' )
871 890
872 class UserToPerm(Base, BaseModel):
891 class UserToPerm( Base, BaseModel ):
873 892 __tablename__ = 'user_to_perm'
874 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True})
875 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
876 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
877 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
893 __table_args__ = ( UniqueConstraint( 'user_id', 'permission_id' ), {'extend_existing':True} )
894 user_to_perm_id = Column( "user_to_perm_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
895 user_id = Column( "user_id", Integer(), ForeignKey( 'users.user_id' ), nullable = False, unique = None, default = None )
896 permission_id = Column( "permission_id", Integer(), ForeignKey( 'permissions.permission_id' ), nullable = False, unique = None, default = None )
878 897
879 user = relationship('User')
880 permission = relationship('Permission')
898 user = relationship( 'User' )
899 permission = relationship( 'Permission' )
881 900
882 901 @classmethod
883 def has_perm(cls, user_id, perm):
884 if not isinstance(perm, Permission):
885 raise Exception('perm needs to be an instance of Permission class')
902 def has_perm( cls, user_id, perm ):
903 if not isinstance( perm, Permission ):
904 raise Exception( 'perm needs to be an instance of Permission class' )
886 905
887 return Session.query(cls).filter(cls.user_id == user_id)\
888 .filter(cls.permission == perm).scalar() is not None
906 return cls.query().filter( cls.user_id == user_id )\
907 .filter( cls.permission == perm ).scalar() is not None
889 908
890 909 @classmethod
891 def grant_perm(cls, user_id, perm):
892 if not isinstance(perm, Permission):
893 raise Exception('perm needs to be an instance of Permission class')
910 def grant_perm( cls, user_id, perm ):
911 if not isinstance( perm, Permission ):
912 raise Exception( 'perm needs to be an instance of Permission class' )
894 913
895 914 new = cls()
896 915 new.user_id = user_id
897 916 new.permission = perm
898 917 try:
899 Session.add(new)
918 Session.add( new )
900 919 Session.commit()
901 920 except:
902 921 Session.rollback()
903 922
904 923
905 924 @classmethod
906 def revoke_perm(cls, user_id, perm):
907 if not isinstance(perm, Permission):
908 raise Exception('perm needs to be an instance of Permission class')
925 def revoke_perm( cls, user_id, perm ):
926 if not isinstance( perm, Permission ):
927 raise Exception( 'perm needs to be an instance of Permission class' )
909 928
910 929 try:
911 Session.query(cls).filter(cls.user_id == user_id)\
912 .filter(cls.permission == perm).delete()
930 cls.query().filter( cls.user_id == user_id )\
931 .filter( cls.permission == perm ).delete()
913 932 Session.commit()
914 933 except:
915 934 Session.rollback()
916 935
917 class UsersGroupRepoToPerm(Base, BaseModel):
936 class UsersGroupRepoToPerm( Base, BaseModel ):
918 937 __tablename__ = 'users_group_repo_to_perm'
919 __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True})
920 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
921 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
922 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
923 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
938 __table_args__ = ( UniqueConstraint( 'repository_id', 'users_group_id', 'permission_id' ), {'extend_existing':True} )
939 users_group_to_perm_id = Column( "users_group_to_perm_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
940 users_group_id = Column( "users_group_id", Integer(), ForeignKey( 'users_groups.users_group_id' ), nullable = False, unique = None, default = None )
941 permission_id = Column( "permission_id", Integer(), ForeignKey( 'permissions.permission_id' ), nullable = False, unique = None, default = None )
942 repository_id = Column( "repository_id", Integer(), ForeignKey( 'repositories.repo_id' ), nullable = False, unique = None, default = None )
924 943
925 users_group = relationship('UsersGroup')
926 permission = relationship('Permission')
927 repository = relationship('Repository')
944 users_group = relationship( 'UsersGroup' )
945 permission = relationship( 'Permission' )
946 repository = relationship( 'Repository' )
928 947
929 def __repr__(self):
930 return '<userGroup:%s => %s >' % (self.users_group, self.repository)
948 def __repr__( self ):
949 return '<userGroup:%s => %s >' % ( self.users_group, self.repository )
931 950
932 class UsersGroupToPerm(Base, BaseModel):
951 class UsersGroupToPerm( Base, BaseModel ):
933 952 __tablename__ = 'users_group_to_perm'
934 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
935 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
936 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
953 users_group_to_perm_id = Column( "users_group_to_perm_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
954 users_group_id = Column( "users_group_id", Integer(), ForeignKey( 'users_groups.users_group_id' ), nullable = False, unique = None, default = None )
955 permission_id = Column( "permission_id", Integer(), ForeignKey( 'permissions.permission_id' ), nullable = False, unique = None, default = None )
937 956
938 users_group = relationship('UsersGroup')
939 permission = relationship('Permission')
957 users_group = relationship( 'UsersGroup' )
958 permission = relationship( 'Permission' )
940 959
941 960
942 961 @classmethod
943 def has_perm(cls, users_group_id, perm):
944 if not isinstance(perm, Permission):
945 raise Exception('perm needs to be an instance of Permission class')
962 def has_perm( cls, users_group_id, perm ):
963 if not isinstance( perm, Permission ):
964 raise Exception( 'perm needs to be an instance of Permission class' )
946 965
947 return Session.query(cls).filter(cls.users_group_id ==
948 users_group_id)\
949 .filter(cls.permission == perm)\
966 return cls.query().filter( cls.users_group_id ==
967 users_group_id )\
968 .filter( cls.permission == perm )\
950 969 .scalar() is not None
951 970
952 971 @classmethod
953 def grant_perm(cls, users_group_id, perm):
954 if not isinstance(perm, Permission):
955 raise Exception('perm needs to be an instance of Permission class')
972 def grant_perm( cls, users_group_id, perm ):
973 if not isinstance( perm, Permission ):
974 raise Exception( 'perm needs to be an instance of Permission class' )
956 975
957 976 new = cls()
958 977 new.users_group_id = users_group_id
959 978 new.permission = perm
960 979 try:
961 Session.add(new)
980 Session.add( new )
962 981 Session.commit()
963 982 except:
964 983 Session.rollback()
965 984
966 985
967 986 @classmethod
968 def revoke_perm(cls, users_group_id, perm):
969 if not isinstance(perm, Permission):
970 raise Exception('perm needs to be an instance of Permission class')
987 def revoke_perm( cls, users_group_id, perm ):
988 if not isinstance( perm, Permission ):
989 raise Exception( 'perm needs to be an instance of Permission class' )
971 990
972 991 try:
973 Session.query(cls).filter(cls.users_group_id == users_group_id)\
974 .filter(cls.permission == perm).delete()
992 cls.query().filter( cls.users_group_id == users_group_id )\
993 .filter( cls.permission == perm ).delete()
975 994 Session.commit()
976 995 except:
977 996 Session.rollback()
978 997
979 998
980 class GroupToPerm(Base, BaseModel):
999 class GroupToPerm( Base, BaseModel ):
981 1000 __tablename__ = 'group_to_perm'
982 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
1001 __table_args__ = ( UniqueConstraint( 'group_id', 'permission_id' ), {'extend_existing':True} )
983 1002
984 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
985 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
986 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
987 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1003 group_to_perm_id = Column( "group_to_perm_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
1004 user_id = Column( "user_id", Integer(), ForeignKey( 'users.user_id' ), nullable = False, unique = None, default = None )
1005 permission_id = Column( "permission_id", Integer(), ForeignKey( 'permissions.permission_id' ), nullable = False, unique = None, default = None )
1006 group_id = Column( "group_id", Integer(), ForeignKey( 'groups.group_id' ), nullable = False, unique = None, default = None )
988 1007
989 user = relationship('User')
990 permission = relationship('Permission')
991 group = relationship('Group')
1008 user = relationship( 'User' )
1009 permission = relationship( 'Permission' )
1010 group = relationship( 'Group' )
992 1011
993 class Statistics(Base, BaseModel):
1012 class Statistics( Base, BaseModel ):
994 1013 __tablename__ = 'statistics'
995 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True})
996 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
997 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
998 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
999 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1000 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1001 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1014 __table_args__ = ( UniqueConstraint( 'repository_id' ), {'extend_existing':True} )
1015 stat_id = Column( "stat_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
1016 repository_id = Column( "repository_id", Integer(), ForeignKey( 'repositories.repo_id' ), nullable = False, unique = True, default = None )
1017 stat_on_revision = Column( "stat_on_revision", Integer(), nullable = False )
1018 commit_activity = Column( "commit_activity", LargeBinary( 1000000 ), nullable = False )#JSON data
1019 commit_activity_combined = Column( "commit_activity_combined", LargeBinary(), nullable = False )#JSON data
1020 languages = Column( "languages", LargeBinary( 1000000 ), nullable = False )#JSON data
1002 1021
1003 repository = relationship('Repository', single_parent=True)
1022 repository = relationship( 'Repository', single_parent = True )
1004 1023
1005 class UserFollowing(Base, BaseModel):
1024 class UserFollowing( Base, BaseModel ):
1006 1025 __tablename__ = 'user_followings'
1007 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
1008 UniqueConstraint('user_id', 'follows_user_id')
1009 , {'extend_existing':True})
1026 __table_args__ = ( UniqueConstraint( 'user_id', 'follows_repository_id' ),
1027 UniqueConstraint( 'user_id', 'follows_user_id' )
1028 , {'extend_existing':True} )
1010 1029
1011 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1012 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1013 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1014 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1015 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1030 user_following_id = Column( "user_following_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
1031 user_id = Column( "user_id", Integer(), ForeignKey( 'users.user_id' ), nullable = False, unique = None, default = None )
1032 follows_repo_id = Column( "follows_repository_id", Integer(), ForeignKey( 'repositories.repo_id' ), nullable = True, unique = None, default = None )
1033 follows_user_id = Column( "follows_user_id", Integer(), ForeignKey( 'users.user_id' ), nullable = True, unique = None, default = None )
1034 follows_from = Column( 'follows_from', DateTime( timezone = False ), nullable = True, unique = None, default = datetime.datetime.now )
1016 1035
1017 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1036 user = relationship( 'User', primaryjoin = 'User.user_id==UserFollowing.user_id' )
1018 1037
1019 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1020 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1038 follows_user = relationship( 'User', primaryjoin = 'User.user_id==UserFollowing.follows_user_id' )
1039 follows_repository = relationship( 'Repository', order_by = 'Repository.repo_name' )
1021 1040
1022 1041
1023 1042 @classmethod
1024 def get_repo_followers(cls, repo_id):
1025 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
1043 def get_repo_followers( cls, repo_id ):
1044 return cls.query().filter( cls.follows_repo_id == repo_id )
1026 1045
1027 class CacheInvalidation(Base, BaseModel):
1046 class CacheInvalidation( Base, BaseModel ):
1028 1047 __tablename__ = 'cache_invalidation'
1029 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True})
1030 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1031 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1032 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1033 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1048 __table_args__ = ( UniqueConstraint( 'cache_key' ), {'extend_existing':True} )
1049 cache_id = Column( "cache_id", Integer(), nullable = False, unique = True, default = None, primary_key = True )
1050 cache_key = Column( "cache_key", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
1051 cache_args = Column( "cache_args", String( length = 255, convert_unicode = False, assert_unicode = None ), nullable = True, unique = None, default = None )
1052 cache_active = Column( "cache_active", Boolean(), nullable = True, unique = None, default = False )
1034 1053
1035 1054
1036 def __init__(self, cache_key, cache_args=''):
1055 def __init__( self, cache_key, cache_args = '' ):
1037 1056 self.cache_key = cache_key
1038 1057 self.cache_args = cache_args
1039 1058 self.cache_active = False
1040 1059
1041 def __repr__(self):
1042 return "<%s('%s:%s')>" % (self.__class__.__name__,
1043 self.cache_id, self.cache_key)
1060 def __repr__( self ):
1061 return "<%s('%s:%s')>" % ( self.__class__.__name__,
1062 self.cache_id, self.cache_key )
1044 1063
1045 class DbMigrateVersion(Base, BaseModel):
1064 class DbMigrateVersion( Base, BaseModel ):
1046 1065 __tablename__ = 'db_migrate_version'
1047 1066 __table_args__ = {'extend_existing':True}
1048 repository_id = Column('repository_id', String(250), primary_key=True)
1049 repository_path = Column('repository_path', Text)
1050 version = Column('version', Integer)
1067 repository_id = Column( 'repository_id', String( 250 ), primary_key = True )
1068 repository_path = Column( 'repository_path', Text )
1069 version = Column( 'version', Integer )
@@ -1,164 +1,174 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.user_group
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users groups model for RhodeCode
7 7
8 8 :created_on: Jan 25, 2011
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import traceback
29 29 import shutil
30 30
31 31 from pylons.i18n.translation import _
32 32
33 33 from vcs.utils.lazy import LazyProperty
34 34
35 35 from rhodecode.model import BaseModel
36 36 from rhodecode.model.caching_query import FromCache
37 37 from rhodecode.model.db import Group, RhodeCodeUi
38 38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger( __name__ )
40 40
41 41
42 class ReposGroupModel(BaseModel):
42 class ReposGroupModel( BaseModel ):
43 43
44 44 @LazyProperty
45 def repos_path(self):
45 def repos_path( self ):
46 46 """
47 47 Get's the repositories root path from database
48 48 """
49 49
50 q = RhodeCodeUi.get_by_key('/').one()
50 q = RhodeCodeUi.get_by_key( '/' ).one()
51 51 return q.ui_value
52 52
53 def __create_group(self, group_name):
53 def __create_group( self, group_name, parent_id ):
54 54 """
55 55 makes repositories group on filesystem
56 56
57 57 :param repo_name:
58 58 :param parent_id:
59 59 """
60 60
61 create_path = os.path.join(self.repos_path, group_name)
62 log.debug('creating new group in %s', create_path)
61 if parent_id:
62 paths = Group.get( parent_id ).full_path.split( Group.url_sep() )
63 parent_path = os.sep.join( paths )
64 else:
65 parent_path = ''
66
67 create_path = os.path.join( self.repos_path, parent_path, group_name )
68 log.debug( 'creating new group in %s', create_path )
63 69
64 if os.path.isdir(create_path):
65 raise Exception('That directory already exists !')
70 if os.path.isdir( create_path ):
71 raise Exception( 'That directory already exists !' )
72
66 73
67 os.makedirs(create_path)
74 os.makedirs( create_path )
68 75
69 def __rename_group(self, old, new):
76
77 def __rename_group( self, old, old_parent_id, new, new_parent_id ):
70 78 """
71 79 Renames a group on filesystem
72 80
73 81 :param group_name:
74 82 """
83 log.debug( 'renaming repos group from %s to %s', old, new )
75 84
76 if old == new:
77 log.debug('skipping group rename')
78 return
79
80 log.debug('renaming repos group from %s to %s', old, new)
81
85 if new_parent_id:
86 paths = Group.get( new_parent_id ).full_path.split( Group.url_sep() )
87 new_parent_path = os.sep.join( paths )
88 else:
89 new_parent_path = ''
82 90
83 old_path = os.path.join(self.repos_path, old)
84 new_path = os.path.join(self.repos_path, new)
91 if old_parent_id:
92 paths = Group.get( old_parent_id ).full_path.split( Group.url_sep() )
93 old_parent_path = os.sep.join( paths )
94 else:
95 old_parent_path = ''
85 96
86 log.debug('renaming repos paths from %s to %s', old_path, new_path)
97 old_path = os.path.join( self.repos_path, old_parent_path, old )
98 new_path = os.path.join( self.repos_path, new_parent_path, new )
87 99
88 if os.path.isdir(new_path):
89 raise Exception('Was trying to rename to already '
90 'existing dir %s' % new_path)
91 shutil.move(old_path, new_path)
100 log.debug( 'renaming repos paths from %s to %s', old_path, new_path )
92 101
93 def __delete_group(self, group):
102 if os.path.isdir( new_path ):
103 raise Exception( 'Was trying to rename to already '
104 'existing dir %s' % new_path )
105 shutil.move( old_path, new_path )
106
107 def __delete_group( self, group ):
94 108 """
95 109 Deletes a group from a filesystem
96 110
97 111 :param group: instance of group from database
98 112 """
99 paths = group.full_path.split(Group.url_sep())
100 paths = os.sep.join(paths)
113 paths = group.full_path.split( Group.url_sep() )
114 paths = os.sep.join( paths )
101 115
102 rm_path = os.path.join(self.repos_path, paths)
103 if os.path.isdir(rm_path):
104 # delete only if that path really exists
105 os.rmdir(rm_path)
116 rm_path = os.path.join( self.repos_path, paths )
117 os.rmdir( rm_path )
106 118
107 def create(self, form_data):
119 def create( self, form_data ):
108 120 try:
109 121 new_repos_group = Group()
110 new_repos_group.group_description = form_data['group_description']
111 new_repos_group.parent_group = Group.get(form_data['group_parent_id'])
112 new_repos_group.group_name = new_repos_group.get_new_name(form_data['group_name'])
122 new_repos_group.group_name = form_data['group_name']
123 new_repos_group.group_description = \
124 form_data['group_description']
125 new_repos_group.group_parent_id = form_data['group_parent_id']
113 126
114 self.sa.add(new_repos_group)
127 self.sa.add( new_repos_group )
115 128
116 self.__create_group(new_repos_group.group_name)
129 self.__create_group( form_data['group_name'],
130 form_data['group_parent_id'] )
117 131
118 132 self.sa.commit()
119 133 return new_repos_group
120 134 except:
121 log.error(traceback.format_exc())
135 log.error( traceback.format_exc() )
122 136 self.sa.rollback()
123 137 raise
124 138
125 def update(self, repos_group_id, form_data):
139 def update( self, repos_group_id, form_data ):
126 140
127 141 try:
128 repos_group = Group.get(repos_group_id)
129 old_path = repos_group.full_path
130
131 #change properties
132 repos_group.group_description = form_data['group_description']
133 repos_group.parent_group = Group.get(form_data['group_parent_id'])
134 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
135
136 new_path = repos_group.full_path
142 repos_group = Group.get( repos_group_id )
143 old_name = repos_group.group_name
144 old_parent_id = repos_group.group_parent_id
137 145
138 self.sa.add(repos_group)
139
140 self.__rename_group(old_path, new_path)
146 repos_group.group_name = form_data['group_name']
147 repos_group.group_description = \
148 form_data['group_description']
149 repos_group.group_parent_id = form_data['group_parent_id']
141 150
142 # we need to get all repositories from this new group and
143 # rename them accordingly to new group path
144 for r in repos_group.repositories:
145 r.repo_name = r.get_new_name(r.just_name)
146 self.sa.add(r)
151 self.sa.add( repos_group )
152
153 if old_name != form_data['group_name'] or ( old_parent_id !=
154 form_data['group_parent_id'] ):
155 self.__rename_group( old = old_name, old_parent_id = old_parent_id,
156 new = form_data['group_name'],
157 new_parent_id = form_data['group_parent_id'] )
147 158
148 159 self.sa.commit()
149 return repos_group
150 160 except:
151 log.error(traceback.format_exc())
161 log.error( traceback.format_exc() )
152 162 self.sa.rollback()
153 163 raise
154 164
155 def delete(self, users_group_id):
165 def delete( self, users_group_id ):
156 166 try:
157 users_group = Group.get(users_group_id)
158 self.sa.delete(users_group)
159 self.__delete_group(users_group)
167 users_group = Group.get( users_group_id )
168 self.sa.delete( users_group )
169 self.__delete_group( users_group )
160 170 self.sa.commit()
161 171 except:
162 log.error(traceback.format_exc())
172 log.error( traceback.format_exc() )
163 173 self.sa.rollback()
164 174 raise
@@ -1,388 +1,388 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.user
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users model for RhodeCode
7 7
8 8 :created_on: Apr 9, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28
29 29 from pylons.i18n.translation import _
30 30
31 31 from rhodecode.lib import safe_unicode
32 32 from rhodecode.model import BaseModel
33 33 from rhodecode.model.caching_query import FromCache
34 34 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
35 35 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember
36 36 from rhodecode.lib.exceptions import DefaultUserException, \
37 37 UserOwnsReposException
38 38
39 39 from sqlalchemy.exc import DatabaseError
40 40 from rhodecode.lib import generate_api_key
41 41 from sqlalchemy.orm import joinedload
42 42
43 43 log = logging.getLogger(__name__)
44 44
45 45 PERM_WEIGHTS = {'repository.none': 0,
46 46 'repository.read': 1,
47 47 'repository.write': 3,
48 48 'repository.admin': 3}
49 49
50 50
51 51 class UserModel(BaseModel):
52
53 52 def get(self, user_id, cache=False):
54 53 user = self.sa.query(User)
55 54 if cache:
56 55 user = user.options(FromCache("sql_cache_short",
57 56 "get_user_%s" % user_id))
58 57 return user.get(user_id)
59 58
60 59 def get_by_username(self, username, cache=False, case_insensitive=False):
61 60
62 61 if case_insensitive:
63 62 user = self.sa.query(User).filter(User.username.ilike(username))
64 63 else:
65 64 user = self.sa.query(User)\
66 65 .filter(User.username == username)
67 66 if cache:
68 67 user = user.options(FromCache("sql_cache_short",
69 68 "get_user_%s" % username))
70 69 return user.scalar()
71 70
72 71 def get_by_api_key(self, api_key, cache=False):
73 72
74 73 user = self.sa.query(User)\
75 74 .filter(User.api_key == api_key)
76 75 if cache:
77 76 user = user.options(FromCache("sql_cache_short",
78 77 "get_user_%s" % api_key))
79 78 return user.scalar()
80 79
81 80 def create(self, form_data):
82 81 try:
83 82 new_user = User()
84 83 for k, v in form_data.items():
85 84 setattr(new_user, k, v)
86 85
87 86 new_user.api_key = generate_api_key(form_data['username'])
88 87 self.sa.add(new_user)
89 88 self.sa.commit()
89 return new_user
90 90 except:
91 91 log.error(traceback.format_exc())
92 92 self.sa.rollback()
93 93 raise
94 94
95 95 def create_ldap(self, username, password, user_dn, attrs):
96 96 """
97 97 Checks if user is in database, if not creates this user marked
98 98 as ldap user
99 99 :param username:
100 100 :param password:
101 101 :param user_dn:
102 102 :param attrs:
103 103 """
104 104 from rhodecode.lib.auth import get_crypt_password
105 105 log.debug('Checking for such ldap account in RhodeCode database')
106 106 if self.get_by_username(username, case_insensitive=True) is None:
107 107 try:
108 108 new_user = User()
109 109 # add ldap account always lowercase
110 110 new_user.username = username.lower()
111 111 new_user.password = get_crypt_password(password)
112 112 new_user.api_key = generate_api_key(username)
113 113 new_user.email = attrs['email']
114 114 new_user.active = True
115 115 new_user.ldap_dn = safe_unicode(user_dn)
116 116 new_user.name = attrs['name']
117 117 new_user.lastname = attrs['lastname']
118 118
119 119 self.sa.add(new_user)
120 120 self.sa.commit()
121 121 return True
122 122 except (DatabaseError,):
123 123 log.error(traceback.format_exc())
124 124 self.sa.rollback()
125 125 raise
126 126 log.debug('this %s user exists skipping creation of ldap account',
127 127 username)
128 128 return False
129 129
130 130 def create_registration(self, form_data):
131 131 from rhodecode.lib.celerylib import tasks, run_task
132 132 try:
133 133 new_user = User()
134 134 for k, v in form_data.items():
135 135 if k != 'admin':
136 136 setattr(new_user, k, v)
137 137
138 138 self.sa.add(new_user)
139 139 self.sa.commit()
140 140 body = ('New user registration\n'
141 141 'username: %s\n'
142 142 'email: %s\n')
143 143 body = body % (form_data['username'], form_data['email'])
144 144
145 145 run_task(tasks.send_email, None,
146 146 _('[RhodeCode] New User registration'),
147 147 body)
148 148 except:
149 149 log.error(traceback.format_exc())
150 150 self.sa.rollback()
151 151 raise
152 152
153 153 def update(self, user_id, form_data):
154 154 try:
155 155 user = self.get(user_id, cache=False)
156 156 if user.username == 'default':
157 157 raise DefaultUserException(
158 158 _("You can't Edit this user since it's"
159 159 " crucial for entire application"))
160 160
161 161 for k, v in form_data.items():
162 162 if k == 'new_password' and v != '':
163 163 user.password = v
164 164 user.api_key = generate_api_key(user.username)
165 165 else:
166 166 setattr(user, k, v)
167 167
168 168 self.sa.add(user)
169 169 self.sa.commit()
170 170 except:
171 171 log.error(traceback.format_exc())
172 172 self.sa.rollback()
173 173 raise
174 174
175 175 def update_my_account(self, user_id, form_data):
176 176 try:
177 177 user = self.get(user_id, cache=False)
178 178 if user.username == 'default':
179 179 raise DefaultUserException(
180 180 _("You can't Edit this user since it's"
181 181 " crucial for entire application"))
182 182 for k, v in form_data.items():
183 183 if k == 'new_password' and v != '':
184 184 user.password = v
185 185 user.api_key = generate_api_key(user.username)
186 186 else:
187 187 if k not in ['admin', 'active']:
188 188 setattr(user, k, v)
189 189
190 190 self.sa.add(user)
191 191 self.sa.commit()
192 192 except:
193 193 log.error(traceback.format_exc())
194 194 self.sa.rollback()
195 195 raise
196 196
197 197 def delete(self, user_id):
198 198 try:
199 199 user = self.get(user_id, cache=False)
200 200 if user.username == 'default':
201 201 raise DefaultUserException(
202 202 _("You can't remove this user since it's"
203 203 " crucial for entire application"))
204 204 if user.repositories:
205 205 raise UserOwnsReposException(_('This user still owns %s '
206 206 'repositories and cannot be '
207 207 'removed. Switch owners or '
208 208 'remove those repositories') \
209 209 % user.repositories)
210 210 self.sa.delete(user)
211 211 self.sa.commit()
212 212 except:
213 213 log.error(traceback.format_exc())
214 214 self.sa.rollback()
215 215 raise
216 216
217 217 def reset_password_link(self, data):
218 218 from rhodecode.lib.celerylib import tasks, run_task
219 219 run_task(tasks.send_password_link, data['email'])
220 220
221 221 def reset_password(self, data):
222 222 from rhodecode.lib.celerylib import tasks, run_task
223 223 run_task(tasks.reset_user_password, data['email'])
224 224
225 225 def fill_data(self, auth_user, user_id=None, api_key=None):
226 226 """
227 227 Fetches auth_user by user_id,or api_key if present.
228 228 Fills auth_user attributes with those taken from database.
229 229 Additionally set's is_authenitated if lookup fails
230 230 present in database
231 231
232 232 :param auth_user: instance of user to set attributes
233 233 :param user_id: user id to fetch by
234 234 :param api_key: api key to fetch by
235 235 """
236 236 if user_id is None and api_key is None:
237 237 raise Exception('You need to pass user_id or api_key')
238 238
239 239 try:
240 240 if api_key:
241 241 dbuser = self.get_by_api_key(api_key)
242 242 else:
243 243 dbuser = self.get(user_id)
244 244
245 245 if dbuser is not None:
246 246 log.debug('filling %s data', dbuser)
247 247 for k, v in dbuser.get_dict().items():
248 248 setattr(auth_user, k, v)
249 249
250 250 except:
251 251 log.error(traceback.format_exc())
252 252 auth_user.is_authenticated = False
253 253
254 254 return auth_user
255 255
256 256 def fill_perms(self, user):
257 257 """
258 258 Fills user permission attribute with permissions taken from database
259 259 works for permissions given for repositories, and for permissions that
260 260 are granted to groups
261 261
262 262 :param user: user instance to fill his perms
263 263 """
264 264
265 265 user.permissions['repositories'] = {}
266 266 user.permissions['global'] = set()
267 267
268 268 #======================================================================
269 269 # fetch default permissions
270 270 #======================================================================
271 271 default_user = self.get_by_username('default', cache=True)
272 272
273 273 default_perms = self.sa.query(RepoToPerm, Repository, Permission)\
274 274 .join((Repository, RepoToPerm.repository_id ==
275 275 Repository.repo_id))\
276 276 .join((Permission, RepoToPerm.permission_id ==
277 277 Permission.permission_id))\
278 278 .filter(RepoToPerm.user == default_user).all()
279 279
280 280 if user.is_admin:
281 281 #==================================================================
282 282 # #admin have all default rights set to admin
283 283 #==================================================================
284 284 user.permissions['global'].add('hg.admin')
285 285
286 286 for perm in default_perms:
287 287 p = 'repository.admin'
288 288 user.permissions['repositories'][perm.RepoToPerm.
289 289 repository.repo_name] = p
290 290
291 291 else:
292 292 #==================================================================
293 293 # set default permissions
294 294 #==================================================================
295 295 uid = user.user_id
296 296
297 297 #default global
298 298 default_global_perms = self.sa.query(UserToPerm)\
299 299 .filter(UserToPerm.user == default_user)
300 300
301 301 for perm in default_global_perms:
302 302 user.permissions['global'].add(perm.permission.permission_name)
303 303
304 304 #default for repositories
305 305 for perm in default_perms:
306 306 if perm.Repository.private and not (perm.Repository.user_id ==
307 307 uid):
308 308 #diself.sable defaults for private repos,
309 309 p = 'repository.none'
310 310 elif perm.Repository.user_id == uid:
311 311 #set admin if owner
312 312 p = 'repository.admin'
313 313 else:
314 314 p = perm.Permission.permission_name
315 315
316 316 user.permissions['repositories'][perm.RepoToPerm.
317 317 repository.repo_name] = p
318 318
319 319 #==================================================================
320 320 # overwrite default with user permissions if any
321 321 #==================================================================
322 322
323 323 #user global
324 324 user_perms = self.sa.query(UserToPerm)\
325 325 .options(joinedload(UserToPerm.permission))\
326 326 .filter(UserToPerm.user_id == uid).all()
327 327
328 328 for perm in user_perms:
329 329 user.permissions['global'].add(perm.permission.
330 330 permission_name)
331 331
332 332 #user repositories
333 333 user_repo_perms = self.sa.query(RepoToPerm, Permission,
334 334 Repository)\
335 335 .join((Repository, RepoToPerm.repository_id ==
336 336 Repository.repo_id))\
337 337 .join((Permission, RepoToPerm.permission_id ==
338 338 Permission.permission_id))\
339 339 .filter(RepoToPerm.user_id == uid).all()
340 340
341 341 for perm in user_repo_perms:
342 342 # set admin if owner
343 343 if perm.Repository.user_id == uid:
344 344 p = 'repository.admin'
345 345 else:
346 346 p = perm.Permission.permission_name
347 347 user.permissions['repositories'][perm.RepoToPerm.
348 348 repository.repo_name] = p
349 349
350 350 #==================================================================
351 351 # check if user is part of groups for this repository and fill in
352 352 # (or replace with higher) permissions
353 353 #==================================================================
354 354
355 355 #users group global
356 356 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
357 357 .options(joinedload(UsersGroupToPerm.permission))\
358 358 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
359 359 UsersGroupMember.users_group_id))\
360 360 .filter(UsersGroupMember.user_id == uid).all()
361 361
362 362 for perm in user_perms_from_users_groups:
363 363 user.permissions['global'].add(perm.permission.permission_name)
364 364
365 365 #users group repositories
366 366 user_repo_perms_from_users_groups = self.sa.query(
367 367 UsersGroupRepoToPerm,
368 368 Permission, Repository,)\
369 369 .join((Repository, UsersGroupRepoToPerm.repository_id ==
370 370 Repository.repo_id))\
371 371 .join((Permission, UsersGroupRepoToPerm.permission_id ==
372 372 Permission.permission_id))\
373 373 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
374 374 UsersGroupMember.users_group_id))\
375 375 .filter(UsersGroupMember.user_id == uid).all()
376 376
377 377 for perm in user_repo_perms_from_users_groups:
378 378 p = perm.Permission.permission_name
379 379 cur_perm = user.permissions['repositories'][perm.
380 380 UsersGroupRepoToPerm.
381 381 repository.repo_name]
382 382 #overwrite permission only if it's greater than permission
383 383 # given from other sources
384 384 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
385 385 user.permissions['repositories'][perm.UsersGroupRepoToPerm.
386 386 repository.repo_name] = p
387 387
388 388 return user
General Comments 0
You need to be logged in to leave comments. Login now