comparison rhodecode/model/user.py @ 1512:bf263968da47

merge beta in stable branch
author Marcin Kuzminski <marcin@python-works.com>
date Fri, 07 Oct 2011 01:08:50 +0200
parents a3b2b4b4e440 5875955def39
children 5585609772d0
comparison
equal deleted inserted replaced
1329:e058df3ff2b4 1512:bf263968da47
2 """ 2 """
3 rhodecode.model.user 3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~ 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 users model for RhodeCode 6 users model for RhodeCode
7 7
8 :created_on: Apr 9, 2010 8 :created_on: Apr 9, 2010
9 :author: marcink 9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details. 11 :license: GPLv3, see COPYING for more details.
12 """ 12 """
13 # This program is free software: you can redistribute it and/or modify 13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by 14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or 15 # the Free Software Foundation, either version 3 of the License, or
28 28
29 from pylons.i18n.translation import _ 29 from pylons.i18n.translation import _
30 30
31 from rhodecode.model import BaseModel 31 from rhodecode.model import BaseModel
32 from rhodecode.model.caching_query import FromCache 32 from rhodecode.model.caching_query import FromCache
33 from rhodecode.model.db import User 33 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
34 34 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember
35 from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException 35 from rhodecode.lib.exceptions import DefaultUserException, \
36 UserOwnsReposException
36 37
37 from sqlalchemy.exc import DatabaseError 38 from sqlalchemy.exc import DatabaseError
39 from rhodecode.lib import generate_api_key
40 from sqlalchemy.orm import joinedload
38 41
39 log = logging.getLogger(__name__) 42 log = logging.getLogger(__name__)
43
44 PERM_WEIGHTS = {'repository.none': 0,
45 'repository.read': 1,
46 'repository.write': 3,
47 'repository.admin': 3}
48
40 49
41 class UserModel(BaseModel): 50 class UserModel(BaseModel):
42 51
43 def get(self, user_id, cache=False): 52 def get(self, user_id, cache=False):
44 user = self.sa.query(User) 53 user = self.sa.query(User)
45 if cache: 54 if cache:
46 user = user.options(FromCache("sql_cache_short", 55 user = user.options(FromCache("sql_cache_short",
47 "get_user_%s" % user_id)) 56 "get_user_%s" % user_id))
48 return user.get(user_id) 57 return user.get(user_id)
49
50 58
51 def get_by_username(self, username, cache=False, case_insensitive=False): 59 def get_by_username(self, username, cache=False, case_insensitive=False):
52 60
53 if case_insensitive: 61 if case_insensitive:
54 user = self.sa.query(User).filter(User.username.ilike(username)) 62 user = self.sa.query(User).filter(User.username.ilike(username))
58 if cache: 66 if cache:
59 user = user.options(FromCache("sql_cache_short", 67 user = user.options(FromCache("sql_cache_short",
60 "get_user_%s" % username)) 68 "get_user_%s" % username))
61 return user.scalar() 69 return user.scalar()
62 70
71 def get_by_api_key(self, api_key, cache=False):
72
73 user = self.sa.query(User)\
74 .filter(User.api_key == api_key)
75 if cache:
76 user = user.options(FromCache("sql_cache_short",
77 "get_user_%s" % api_key))
78 return user.scalar()
79
63 def create(self, form_data): 80 def create(self, form_data):
64 try: 81 try:
65 new_user = User() 82 new_user = User()
66 for k, v in form_data.items(): 83 for k, v in form_data.items():
67 setattr(new_user, k, v) 84 setattr(new_user, k, v)
68 85
86 new_user.api_key = generate_api_key(form_data['username'])
69 self.sa.add(new_user) 87 self.sa.add(new_user)
70 self.sa.commit() 88 self.sa.commit()
71 except: 89 except:
72 log.error(traceback.format_exc()) 90 log.error(traceback.format_exc())
73 self.sa.rollback() 91 self.sa.rollback()
74 raise 92 raise
75 93
76 def create_ldap(self, username, password): 94 def create_ldap(self, username, password, user_dn, attrs):
77 """ 95 """
78 Checks if user is in database, if not creates this user marked 96 Checks if user is in database, if not creates this user marked
79 as ldap user 97 as ldap user
80 :param username: 98 :param username:
81 :param password: 99 :param password:
100 :param user_dn:
101 :param attrs:
82 """ 102 """
83 from rhodecode.lib.auth import get_crypt_password 103 from rhodecode.lib.auth import get_crypt_password
84 log.debug('Checking for such ldap account in RhodeCode database') 104 log.debug('Checking for such ldap account in RhodeCode database')
85 if self.get_by_username(username, case_insensitive=True) is None: 105 if self.get_by_username(username, case_insensitive=True) is None:
86 try: 106 try:
87 new_user = User() 107 new_user = User()
88 new_user.username = username.lower()#add ldap account always lowercase 108 # add ldap account always lowercase
109 new_user.username = username.lower()
89 new_user.password = get_crypt_password(password) 110 new_user.password = get_crypt_password(password)
90 new_user.email = '%s@ldap.server' % username 111 new_user.api_key = generate_api_key(username)
112 new_user.email = attrs['email']
91 new_user.active = True 113 new_user.active = True
92 new_user.is_ldap = True 114 new_user.ldap_dn = user_dn
93 new_user.name = '%s@ldap' % username 115 new_user.name = attrs['name']
94 new_user.lastname = '' 116 new_user.lastname = attrs['lastname']
95
96 117
97 self.sa.add(new_user) 118 self.sa.add(new_user)
98 self.sa.commit() 119 self.sa.commit()
99 return True 120 return True
100 except (DatabaseError,): 121 except (DatabaseError,):
128 self.sa.rollback() 149 self.sa.rollback()
129 raise 150 raise
130 151
131 def update(self, user_id, form_data): 152 def update(self, user_id, form_data):
132 try: 153 try:
133 new_user = self.get(user_id, cache=False) 154 user = self.get(user_id, cache=False)
134 if new_user.username == 'default': 155 if user.username == 'default':
135 raise DefaultUserException( 156 raise DefaultUserException(
136 _("You can't Edit this user since it's" 157 _("You can't Edit this user since it's"
137 " crucial for entire application")) 158 " crucial for entire application"))
138 159
139 for k, v in form_data.items(): 160 for k, v in form_data.items():
140 if k == 'new_password' and v != '': 161 if k == 'new_password' and v != '':
141 new_user.password = v 162 user.password = v
163 user.api_key = generate_api_key(user.username)
142 else: 164 else:
143 setattr(new_user, k, v) 165 setattr(user, k, v)
144 166
145 self.sa.add(new_user) 167 self.sa.add(user)
146 self.sa.commit() 168 self.sa.commit()
147 except: 169 except:
148 log.error(traceback.format_exc()) 170 log.error(traceback.format_exc())
149 self.sa.rollback() 171 self.sa.rollback()
150 raise 172 raise
151 173
152 def update_my_account(self, user_id, form_data): 174 def update_my_account(self, user_id, form_data):
153 try: 175 try:
154 new_user = self.get(user_id, cache=False) 176 user = self.get(user_id, cache=False)
155 if new_user.username == 'default': 177 if user.username == 'default':
156 raise DefaultUserException( 178 raise DefaultUserException(
157 _("You can't Edit this user since it's" 179 _("You can't Edit this user since it's"
158 " crucial for entire application")) 180 " crucial for entire application"))
159 for k, v in form_data.items(): 181 for k, v in form_data.items():
160 if k == 'new_password' and v != '': 182 if k == 'new_password' and v != '':
161 new_user.password = v 183 user.password = v
184 user.api_key = generate_api_key(user.username)
162 else: 185 else:
163 if k not in ['admin', 'active']: 186 if k not in ['admin', 'active']:
164 setattr(new_user, k, v) 187 setattr(user, k, v)
165 188
166 self.sa.add(new_user) 189 self.sa.add(user)
167 self.sa.commit() 190 self.sa.commit()
168 except: 191 except:
169 log.error(traceback.format_exc()) 192 log.error(traceback.format_exc())
170 self.sa.rollback() 193 self.sa.rollback()
171 raise 194 raise
188 except: 211 except:
189 log.error(traceback.format_exc()) 212 log.error(traceback.format_exc())
190 self.sa.rollback() 213 self.sa.rollback()
191 raise 214 raise
192 215
216 def reset_password_link(self, data):
217 from rhodecode.lib.celerylib import tasks, run_task
218 run_task(tasks.send_password_link, data['email'])
219
193 def reset_password(self, data): 220 def reset_password(self, data):
194 from rhodecode.lib.celerylib import tasks, run_task 221 from rhodecode.lib.celerylib import tasks, run_task
195 run_task(tasks.reset_user_password, data['email']) 222 run_task(tasks.reset_user_password, data['email'])
196 223
197 224 def fill_data(self, auth_user, user_id=None, api_key=None):
198 def fill_data(self, user): 225 """
199 """ 226 Fetches auth_user by user_id,or api_key if present.
200 Fills user data with those from database and log out user if not 227 Fills auth_user attributes with those taken from database.
228 Additionally set's is_authenitated if lookup fails
201 present in database 229 present in database
202 :param user: 230
203 """ 231 :param auth_user: instance of user to set attributes
204 232 :param user_id: user id to fetch by
205 if not hasattr(user, 'user_id') or user.user_id is None: 233 :param api_key: api key to fetch by
206 raise Exception('passed in user has to have the user_id attribute') 234 """
207 235 if user_id is None and api_key is None:
208 236 raise Exception('You need to pass user_id or api_key')
209 log.debug('filling auth user data') 237
210 try: 238 try:
211 dbuser = self.get(user.user_id) 239 if api_key:
212 user.username = dbuser.username 240 dbuser = self.get_by_api_key(api_key)
213 user.is_admin = dbuser.admin 241 else:
214 user.name = dbuser.name 242 dbuser = self.get(user_id)
215 user.lastname = dbuser.lastname 243
216 user.email = dbuser.email 244 if dbuser is not None:
217 except: 245 log.debug('filling %s data', dbuser)
218 log.error(traceback.format_exc()) 246 for k, v in dbuser.get_dict().items():
219 user.is_authenticated = False 247 setattr(auth_user, k, v)
248
249 except:
250 log.error(traceback.format_exc())
251 auth_user.is_authenticated = False
252
253 return auth_user
254
255 def fill_perms(self, user):
256 """
257 Fills user permission attribute with permissions taken from database
258 works for permissions given for repositories, and for permissions that
259 are granted to groups
260
261 :param user: user instance to fill his perms
262 """
263
264 user.permissions['repositories'] = {}
265 user.permissions['global'] = set()
266
267 #======================================================================
268 # fetch default permissions
269 #======================================================================
270 default_user = self.get_by_username('default', cache=True)
271
272 default_perms = self.sa.query(RepoToPerm, Repository, Permission)\
273 .join((Repository, RepoToPerm.repository_id ==
274 Repository.repo_id))\
275 .join((Permission, RepoToPerm.permission_id ==
276 Permission.permission_id))\
277 .filter(RepoToPerm.user == default_user).all()
278
279 if user.is_admin:
280 #==================================================================
281 # #admin have all default rights set to admin
282 #==================================================================
283 user.permissions['global'].add('hg.admin')
284
285 for perm in default_perms:
286 p = 'repository.admin'
287 user.permissions['repositories'][perm.RepoToPerm.
288 repository.repo_name] = p
289
290 else:
291 #==================================================================
292 # set default permissions
293 #==================================================================
294 uid = user.user_id
295
296 #default global
297 default_global_perms = self.sa.query(UserToPerm)\
298 .filter(UserToPerm.user == default_user)
299
300 for perm in default_global_perms:
301 user.permissions['global'].add(perm.permission.permission_name)
302
303 #default for repositories
304 for perm in default_perms:
305 if perm.Repository.private and not (perm.Repository.user_id ==
306 uid):
307 #diself.sable defaults for private repos,
308 p = 'repository.none'
309 elif perm.Repository.user_id == uid:
310 #set admin if owner
311 p = 'repository.admin'
312 else:
313 p = perm.Permission.permission_name
314
315 user.permissions['repositories'][perm.RepoToPerm.
316 repository.repo_name] = p
317
318 #==================================================================
319 # overwrite default with user permissions if any
320 #==================================================================
321
322 #user global
323 user_perms = self.sa.query(UserToPerm)\
324 .options(joinedload(UserToPerm.permission))\
325 .filter(UserToPerm.user_id == uid).all()
326
327 for perm in user_perms:
328 user.permissions['global'].add(perm.permission.
329 permission_name)
330
331 #user repositories
332 user_repo_perms = self.sa.query(RepoToPerm, Permission,
333 Repository)\
334 .join((Repository, RepoToPerm.repository_id ==
335 Repository.repo_id))\
336 .join((Permission, RepoToPerm.permission_id ==
337 Permission.permission_id))\
338 .filter(RepoToPerm.user_id == uid).all()
339
340 for perm in user_repo_perms:
341 # set admin if owner
342 if perm.Repository.user_id == uid:
343 p = 'repository.admin'
344 else:
345 p = perm.Permission.permission_name
346 user.permissions['repositories'][perm.RepoToPerm.
347 repository.repo_name] = p
348
349 #==================================================================
350 # check if user is part of groups for this repository and fill in
351 # (or replace with higher) permissions
352 #==================================================================
353
354 #users group global
355 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
356 .options(joinedload(UsersGroupToPerm.permission))\
357 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
358 UsersGroupMember.users_group_id))\
359 .filter(UsersGroupMember.user_id == uid).all()
360
361 for perm in user_perms_from_users_groups:
362 user.permissions['global'].add(perm.permission.permission_name)
363
364 #users group repositories
365 user_repo_perms_from_users_groups = self.sa.query(
366 UsersGroupRepoToPerm,
367 Permission, Repository,)\
368 .join((Repository, UsersGroupRepoToPerm.repository_id ==
369 Repository.repo_id))\
370 .join((Permission, UsersGroupRepoToPerm.permission_id ==
371 Permission.permission_id))\
372 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
373 UsersGroupMember.users_group_id))\
374 .filter(UsersGroupMember.user_id == uid).all()
375
376 for perm in user_repo_perms_from_users_groups:
377 p = perm.Permission.permission_name
378 cur_perm = user.permissions['repositories'][perm.
379 UsersGroupRepoToPerm.
380 repository.repo_name]
381 #overwrite permission only if it's greater than permission
382 # given from other sources
383 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
384 user.permissions['repositories'][perm.UsersGroupRepoToPerm.
385 repository.repo_name] = p
220 386
221 return user 387 return user