##// END OF EJS Templates
merge beta fixes into stable
marcink -
r1518:55856097 merge default
parent child Browse files
Show More
@@ -1,358 +1,361 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.repo
3 rhodecode.model.repo
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Repository model for rhodecode
6 Repository model for rhodecode
7
7
8 :created_on: Jun 5, 2010
8 :created_on: Jun 5, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import os
25 import os
26 import shutil
26 import shutil
27 import logging
27 import logging
28 import traceback
28 import traceback
29 from datetime import datetime
29 from datetime import datetime
30
30
31 from sqlalchemy.orm import joinedload, make_transient
31 from sqlalchemy.orm import joinedload, make_transient
32
32
33 from vcs.utils.lazy import LazyProperty
33 from vcs.utils.lazy import LazyProperty
34 from vcs.backends import get_backend
34 from vcs.backends import get_backend
35
35
36 from rhodecode.lib import safe_str
36 from rhodecode.lib import safe_str
37
37
38 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
39 from rhodecode.model.caching_query import FromCache
39 from rhodecode.model.caching_query import FromCache
40 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
40 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
41 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, Group
41 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, Group
42 from rhodecode.model.user import UserModel
42 from rhodecode.model.user import UserModel
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46
47 class RepoModel(BaseModel):
47 class RepoModel(BaseModel):
48
48
49 @LazyProperty
49 @LazyProperty
50 def repos_path(self):
50 def repos_path(self):
51 """Get's the repositories root path from database
51 """Get's the repositories root path from database
52 """
52 """
53
53
54 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
54 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
55 return q.ui_value
55 return q.ui_value
56
56
57 def get(self, repo_id, cache=False):
57 def get(self, repo_id, cache=False):
58 repo = self.sa.query(Repository)\
58 repo = self.sa.query(Repository)\
59 .filter(Repository.repo_id == repo_id)
59 .filter(Repository.repo_id == repo_id)
60
60
61 if cache:
61 if cache:
62 repo = repo.options(FromCache("sql_cache_short",
62 repo = repo.options(FromCache("sql_cache_short",
63 "get_repo_%s" % repo_id))
63 "get_repo_%s" % repo_id))
64 return repo.scalar()
64 return repo.scalar()
65
65
66 def get_by_repo_name(self, repo_name, cache=False):
66 def get_by_repo_name(self, repo_name, cache=False):
67 repo = self.sa.query(Repository)\
67 repo = self.sa.query(Repository)\
68 .filter(Repository.repo_name == repo_name)
68 .filter(Repository.repo_name == repo_name)
69
69
70 if cache:
70 if cache:
71 repo = repo.options(FromCache("sql_cache_short",
71 repo = repo.options(FromCache("sql_cache_short",
72 "get_repo_%s" % repo_name))
72 "get_repo_%s" % repo_name))
73 return repo.scalar()
73 return repo.scalar()
74
74
75
75
76 def get_users_js(self):
76 def get_users_js(self):
77
77
78 users = self.sa.query(User).filter(User.active == True).all()
78 users = self.sa.query(User).filter(User.active == True).all()
79 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
79 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
80 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
80 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
81 u.lastname, u.username)
81 u.lastname, u.username)
82 for u in users])
82 for u in users])
83 return users_array
83 return users_array
84
84
85 def get_users_groups_js(self):
85 def get_users_groups_js(self):
86 users_groups = self.sa.query(UsersGroup)\
86 users_groups = self.sa.query(UsersGroup)\
87 .filter(UsersGroup.users_group_active == True).all()
87 .filter(UsersGroup.users_group_active == True).all()
88
88
89 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
89 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
90
90
91 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
91 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
92 (gr.users_group_id, gr.users_group_name,
92 (gr.users_group_id, gr.users_group_name,
93 len(gr.members))
93 len(gr.members))
94 for gr in users_groups])
94 for gr in users_groups])
95 return users_groups_array
95 return users_groups_array
96
96
97 def update(self, repo_name, form_data):
97 def update(self, repo_name, form_data):
98 try:
98 try:
99 cur_repo = self.get_by_repo_name(repo_name, cache=False)
99 cur_repo = self.get_by_repo_name(repo_name, cache=False)
100
100
101 #update permissions
101 #update permissions
102 for member, perm, member_type in form_data['perms_updates']:
102 for member, perm, member_type in form_data['perms_updates']:
103 if member_type == 'user':
103 if member_type == 'user':
104 r2p = self.sa.query(RepoToPerm)\
104 r2p = self.sa.query(RepoToPerm)\
105 .filter(RepoToPerm.user == User.by_username(member))\
105 .filter(RepoToPerm.user == User.by_username(member))\
106 .filter(RepoToPerm.repository == cur_repo)\
106 .filter(RepoToPerm.repository == cur_repo)\
107 .one()
107 .one()
108
108
109 r2p.permission = self.sa.query(Permission)\
109 r2p.permission = self.sa.query(Permission)\
110 .filter(Permission.permission_name ==
110 .filter(Permission.permission_name ==
111 perm).scalar()
111 perm).scalar()
112 self.sa.add(r2p)
112 self.sa.add(r2p)
113 else:
113 else:
114 g2p = self.sa.query(UsersGroupRepoToPerm)\
114 g2p = self.sa.query(UsersGroupRepoToPerm)\
115 .filter(UsersGroupRepoToPerm.users_group ==
115 .filter(UsersGroupRepoToPerm.users_group ==
116 UsersGroup.get_by_group_name(member))\
116 UsersGroup.get_by_group_name(member))\
117 .filter(UsersGroupRepoToPerm.repository ==
117 .filter(UsersGroupRepoToPerm.repository ==
118 cur_repo).one()
118 cur_repo).one()
119
119
120 g2p.permission = self.sa.query(Permission)\
120 g2p.permission = self.sa.query(Permission)\
121 .filter(Permission.permission_name ==
121 .filter(Permission.permission_name ==
122 perm).scalar()
122 perm).scalar()
123 self.sa.add(g2p)
123 self.sa.add(g2p)
124
124
125 #set new permissions
125 #set new permissions
126 for member, perm, member_type in form_data['perms_new']:
126 for member, perm, member_type in form_data['perms_new']:
127 if member_type == 'user':
127 if member_type == 'user':
128 r2p = RepoToPerm()
128 r2p = RepoToPerm()
129 r2p.repository = cur_repo
129 r2p.repository = cur_repo
130 r2p.user = User.by_username(member)
130 r2p.user = User.by_username(member)
131
131
132 r2p.permission = self.sa.query(Permission)\
132 r2p.permission = self.sa.query(Permission)\
133 .filter(Permission.
133 .filter(Permission.
134 permission_name == perm)\
134 permission_name == perm)\
135 .scalar()
135 .scalar()
136 self.sa.add(r2p)
136 self.sa.add(r2p)
137 else:
137 else:
138 g2p = UsersGroupRepoToPerm()
138 g2p = UsersGroupRepoToPerm()
139 g2p.repository = cur_repo
139 g2p.repository = cur_repo
140 g2p.users_group = UsersGroup.get_by_group_name(member)
140 g2p.users_group = UsersGroup.get_by_group_name(member)
141 g2p.permission = self.sa.query(Permission)\
141 g2p.permission = self.sa.query(Permission)\
142 .filter(Permission.
142 .filter(Permission.
143 permission_name == perm)\
143 permission_name == perm)\
144 .scalar()
144 .scalar()
145 self.sa.add(g2p)
145 self.sa.add(g2p)
146
146
147 #update current repo
147 #update current repo
148 for k, v in form_data.items():
148 for k, v in form_data.items():
149 if k == 'user':
149 if k == 'user':
150 cur_repo.user = User.by_username(v)
150 cur_repo.user = User.by_username(v)
151 elif k == 'repo_name':
151 elif k == 'repo_name':
152 cur_repo.repo_name = form_data['repo_name_full']
152 cur_repo.repo_name = form_data['repo_name_full']
153 elif k == 'repo_group':
153 elif k == 'repo_group':
154 cur_repo.group_id = v
154 cur_repo.group_id = v
155
155
156 else:
156 else:
157 setattr(cur_repo, k, v)
157 setattr(cur_repo, k, v)
158
158
159 self.sa.add(cur_repo)
159 self.sa.add(cur_repo)
160
160
161 if repo_name != form_data['repo_name_full']:
161 if repo_name != form_data['repo_name_full']:
162 # rename repository
162 # rename repository
163 self.__rename_repo(old=repo_name,
163 self.__rename_repo(old=repo_name,
164 new=form_data['repo_name_full'])
164 new=form_data['repo_name_full'])
165
165
166 self.sa.commit()
166 self.sa.commit()
167 except:
167 except:
168 log.error(traceback.format_exc())
168 log.error(traceback.format_exc())
169 self.sa.rollback()
169 self.sa.rollback()
170 raise
170 raise
171
171
172 def create(self, form_data, cur_user, just_db=False, fork=False):
172 def create(self, form_data, cur_user, just_db=False, fork=False):
173
173
174 try:
174 try:
175 if fork:
175 if fork:
176 repo_name = form_data['fork_name']
176 repo_name = form_data['fork_name']
177 org_name = form_data['repo_name']
177 org_name = form_data['repo_name']
178 org_full_name = org_name
178 org_full_name = org_name
179
179
180 else:
180 else:
181 org_name = repo_name = form_data['repo_name']
181 org_name = repo_name = form_data['repo_name']
182 repo_name_full = form_data['repo_name_full']
182 repo_name_full = form_data['repo_name_full']
183
183
184 new_repo = Repository()
184 new_repo = Repository()
185 new_repo.enable_statistics = False
185 new_repo.enable_statistics = False
186 for k, v in form_data.items():
186 for k, v in form_data.items():
187 if k == 'repo_name':
187 if k == 'repo_name':
188 if fork:
188 if fork:
189 v = repo_name
189 v = repo_name
190 else:
190 else:
191 v = repo_name_full
191 v = repo_name_full
192 if k == 'repo_group':
192 if k == 'repo_group':
193 k = 'group_id'
193 k = 'group_id'
194
194
195 if k == 'description':
196 v = v or repo_name
197
195 setattr(new_repo, k, v)
198 setattr(new_repo, k, v)
196
199
197 if fork:
200 if fork:
198 parent_repo = self.sa.query(Repository)\
201 parent_repo = self.sa.query(Repository)\
199 .filter(Repository.repo_name == org_full_name).one()
202 .filter(Repository.repo_name == org_full_name).one()
200 new_repo.fork = parent_repo
203 new_repo.fork = parent_repo
201
204
202 new_repo.user_id = cur_user.user_id
205 new_repo.user_id = cur_user.user_id
203 self.sa.add(new_repo)
206 self.sa.add(new_repo)
204
207
205 #create default permission
208 #create default permission
206 repo_to_perm = RepoToPerm()
209 repo_to_perm = RepoToPerm()
207 default = 'repository.read'
210 default = 'repository.read'
208 for p in UserModel(self.sa).get_by_username('default',
211 for p in UserModel(self.sa).get_by_username('default',
209 cache=False).user_perms:
212 cache=False).user_perms:
210 if p.permission.permission_name.startswith('repository.'):
213 if p.permission.permission_name.startswith('repository.'):
211 default = p.permission.permission_name
214 default = p.permission.permission_name
212 break
215 break
213
216
214 default_perm = 'repository.none' if form_data['private'] else default
217 default_perm = 'repository.none' if form_data['private'] else default
215
218
216 repo_to_perm.permission_id = self.sa.query(Permission)\
219 repo_to_perm.permission_id = self.sa.query(Permission)\
217 .filter(Permission.permission_name == default_perm)\
220 .filter(Permission.permission_name == default_perm)\
218 .one().permission_id
221 .one().permission_id
219
222
220 repo_to_perm.repository = new_repo
223 repo_to_perm.repository = new_repo
221 repo_to_perm.user_id = UserModel(self.sa)\
224 repo_to_perm.user_id = UserModel(self.sa)\
222 .get_by_username('default', cache=False).user_id
225 .get_by_username('default', cache=False).user_id
223
226
224 self.sa.add(repo_to_perm)
227 self.sa.add(repo_to_perm)
225
228
226 if not just_db:
229 if not just_db:
227 self.__create_repo(repo_name, form_data['repo_type'],
230 self.__create_repo(repo_name, form_data['repo_type'],
228 form_data['repo_group'],
231 form_data['repo_group'],
229 form_data['clone_uri'])
232 form_data['clone_uri'])
230
233
231 self.sa.commit()
234 self.sa.commit()
232
235
233 #now automatically start following this repository as owner
236 #now automatically start following this repository as owner
234 from rhodecode.model.scm import ScmModel
237 from rhodecode.model.scm import ScmModel
235 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
238 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
236 cur_user.user_id)
239 cur_user.user_id)
237
240
238 except:
241 except:
239 log.error(traceback.format_exc())
242 log.error(traceback.format_exc())
240 self.sa.rollback()
243 self.sa.rollback()
241 raise
244 raise
242
245
243 def create_fork(self, form_data, cur_user):
246 def create_fork(self, form_data, cur_user):
244 from rhodecode.lib.celerylib import tasks, run_task
247 from rhodecode.lib.celerylib import tasks, run_task
245 run_task(tasks.create_repo_fork, form_data, cur_user)
248 run_task(tasks.create_repo_fork, form_data, cur_user)
246
249
247 def delete(self, repo):
250 def delete(self, repo):
248 try:
251 try:
249 self.sa.delete(repo)
252 self.sa.delete(repo)
250 self.__delete_repo(repo)
253 self.__delete_repo(repo)
251 self.sa.commit()
254 self.sa.commit()
252 except:
255 except:
253 log.error(traceback.format_exc())
256 log.error(traceback.format_exc())
254 self.sa.rollback()
257 self.sa.rollback()
255 raise
258 raise
256
259
257 def delete_perm_user(self, form_data, repo_name):
260 def delete_perm_user(self, form_data, repo_name):
258 try:
261 try:
259 self.sa.query(RepoToPerm)\
262 self.sa.query(RepoToPerm)\
260 .filter(RepoToPerm.repository \
263 .filter(RepoToPerm.repository \
261 == self.get_by_repo_name(repo_name))\
264 == self.get_by_repo_name(repo_name))\
262 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
265 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
263 self.sa.commit()
266 self.sa.commit()
264 except:
267 except:
265 log.error(traceback.format_exc())
268 log.error(traceback.format_exc())
266 self.sa.rollback()
269 self.sa.rollback()
267 raise
270 raise
268
271
269 def delete_perm_users_group(self, form_data, repo_name):
272 def delete_perm_users_group(self, form_data, repo_name):
270 try:
273 try:
271 self.sa.query(UsersGroupRepoToPerm)\
274 self.sa.query(UsersGroupRepoToPerm)\
272 .filter(UsersGroupRepoToPerm.repository \
275 .filter(UsersGroupRepoToPerm.repository \
273 == self.get_by_repo_name(repo_name))\
276 == self.get_by_repo_name(repo_name))\
274 .filter(UsersGroupRepoToPerm.users_group_id \
277 .filter(UsersGroupRepoToPerm.users_group_id \
275 == form_data['users_group_id']).delete()
278 == form_data['users_group_id']).delete()
276 self.sa.commit()
279 self.sa.commit()
277 except:
280 except:
278 log.error(traceback.format_exc())
281 log.error(traceback.format_exc())
279 self.sa.rollback()
282 self.sa.rollback()
280 raise
283 raise
281
284
282 def delete_stats(self, repo_name):
285 def delete_stats(self, repo_name):
283 try:
286 try:
284 self.sa.query(Statistics)\
287 self.sa.query(Statistics)\
285 .filter(Statistics.repository == \
288 .filter(Statistics.repository == \
286 self.get_by_repo_name(repo_name)).delete()
289 self.get_by_repo_name(repo_name)).delete()
287 self.sa.commit()
290 self.sa.commit()
288 except:
291 except:
289 log.error(traceback.format_exc())
292 log.error(traceback.format_exc())
290 self.sa.rollback()
293 self.sa.rollback()
291 raise
294 raise
292
295
293 def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
296 def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
294 """
297 """
295 makes repository on filesystem. It's group aware means it'll create
298 makes repository on filesystem. It's group aware means it'll create
296 a repository within a group, and alter the paths accordingly of
299 a repository within a group, and alter the paths accordingly of
297 group location
300 group location
298
301
299 :param repo_name:
302 :param repo_name:
300 :param alias:
303 :param alias:
301 :param parent_id:
304 :param parent_id:
302 :param clone_uri:
305 :param clone_uri:
303 """
306 """
304 from rhodecode.lib.utils import is_valid_repo
307 from rhodecode.lib.utils import is_valid_repo
305
308
306 if new_parent_id:
309 if new_parent_id:
307 paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
310 paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
308 new_parent_path = os.sep.join(paths)
311 new_parent_path = os.sep.join(paths)
309 else:
312 else:
310 new_parent_path = ''
313 new_parent_path = ''
311
314
312 repo_path = os.path.join(*map(lambda x:safe_str(x),
315 repo_path = os.path.join(*map(lambda x:safe_str(x),
313 [self.repos_path, new_parent_path, repo_name]))
316 [self.repos_path, new_parent_path, repo_name]))
314
317
315 if is_valid_repo(repo_path, self.repos_path) is False:
318 if is_valid_repo(repo_path, self.repos_path) is False:
316 log.info('creating repo %s in %s @ %s', repo_name, repo_path,
319 log.info('creating repo %s in %s @ %s', repo_name, repo_path,
317 clone_uri)
320 clone_uri)
318 backend = get_backend(alias)
321 backend = get_backend(alias)
319
322
320 backend(repo_path, create=True, src_url=clone_uri)
323 backend(repo_path, create=True, src_url=clone_uri)
321
324
322
325
323 def __rename_repo(self, old, new):
326 def __rename_repo(self, old, new):
324 """
327 """
325 renames repository on filesystem
328 renames repository on filesystem
326
329
327 :param old: old name
330 :param old: old name
328 :param new: new name
331 :param new: new name
329 """
332 """
330 log.info('renaming repo from %s to %s', old, new)
333 log.info('renaming repo from %s to %s', old, new)
331
334
332 old_path = os.path.join(self.repos_path, old)
335 old_path = os.path.join(self.repos_path, old)
333 new_path = os.path.join(self.repos_path, new)
336 new_path = os.path.join(self.repos_path, new)
334 if os.path.isdir(new_path):
337 if os.path.isdir(new_path):
335 raise Exception('Was trying to rename to already existing dir %s' \
338 raise Exception('Was trying to rename to already existing dir %s' \
336 % new_path)
339 % new_path)
337 shutil.move(old_path, new_path)
340 shutil.move(old_path, new_path)
338
341
339 def __delete_repo(self, repo):
342 def __delete_repo(self, repo):
340 """
343 """
341 removes repo from filesystem, the removal is acctually made by
344 removes repo from filesystem, the removal is acctually made by
342 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
345 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
343 repository is no longer valid for rhodecode, can be undeleted later on
346 repository is no longer valid for rhodecode, can be undeleted later on
344 by reverting the renames on this repository
347 by reverting the renames on this repository
345
348
346 :param repo: repo object
349 :param repo: repo object
347 """
350 """
348 rm_path = os.path.join(self.repos_path, repo.repo_name)
351 rm_path = os.path.join(self.repos_path, repo.repo_name)
349 log.info("Removing %s", rm_path)
352 log.info("Removing %s", rm_path)
350 #disable hg/git
353 #disable hg/git
351 alias = repo.repo_type
354 alias = repo.repo_type
352 shutil.move(os.path.join(rm_path, '.%s' % alias),
355 shutil.move(os.path.join(rm_path, '.%s' % alias),
353 os.path.join(rm_path, 'rm__.%s' % alias))
356 os.path.join(rm_path, 'rm__.%s' % alias))
354 #disable repo
357 #disable repo
355 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
358 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
356 % (datetime.today()\
359 % (datetime.today()\
357 .strftime('%Y%m%d_%H%M%S_%f'),
360 .strftime('%Y%m%d_%H%M%S_%f'),
358 repo.repo_name)))
361 repo.repo_name)))
@@ -1,387 +1,388 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
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
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30
30
31 from rhodecode.lib import safe_unicode
31 from rhodecode.model import BaseModel
32 from rhodecode.model import BaseModel
32 from rhodecode.model.caching_query import FromCache
33 from rhodecode.model.caching_query import FromCache
33 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
34 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
34 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember
35 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember
35 from rhodecode.lib.exceptions import DefaultUserException, \
36 from rhodecode.lib.exceptions import DefaultUserException, \
36 UserOwnsReposException
37 UserOwnsReposException
37
38
38 from sqlalchemy.exc import DatabaseError
39 from sqlalchemy.exc import DatabaseError
39 from rhodecode.lib import generate_api_key
40 from rhodecode.lib import generate_api_key
40 from sqlalchemy.orm import joinedload
41 from sqlalchemy.orm import joinedload
41
42
42 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
43
44
44 PERM_WEIGHTS = {'repository.none': 0,
45 PERM_WEIGHTS = {'repository.none': 0,
45 'repository.read': 1,
46 'repository.read': 1,
46 'repository.write': 3,
47 'repository.write': 3,
47 'repository.admin': 3}
48 'repository.admin': 3}
48
49
49
50
50 class UserModel(BaseModel):
51 class UserModel(BaseModel):
51
52
52 def get(self, user_id, cache=False):
53 def get(self, user_id, cache=False):
53 user = self.sa.query(User)
54 user = self.sa.query(User)
54 if cache:
55 if cache:
55 user = user.options(FromCache("sql_cache_short",
56 user = user.options(FromCache("sql_cache_short",
56 "get_user_%s" % user_id))
57 "get_user_%s" % user_id))
57 return user.get(user_id)
58 return user.get(user_id)
58
59
59 def get_by_username(self, username, cache=False, case_insensitive=False):
60 def get_by_username(self, username, cache=False, case_insensitive=False):
60
61
61 if case_insensitive:
62 if case_insensitive:
62 user = self.sa.query(User).filter(User.username.ilike(username))
63 user = self.sa.query(User).filter(User.username.ilike(username))
63 else:
64 else:
64 user = self.sa.query(User)\
65 user = self.sa.query(User)\
65 .filter(User.username == username)
66 .filter(User.username == username)
66 if cache:
67 if cache:
67 user = user.options(FromCache("sql_cache_short",
68 user = user.options(FromCache("sql_cache_short",
68 "get_user_%s" % username))
69 "get_user_%s" % username))
69 return user.scalar()
70 return user.scalar()
70
71
71 def get_by_api_key(self, api_key, cache=False):
72 def get_by_api_key(self, api_key, cache=False):
72
73
73 user = self.sa.query(User)\
74 user = self.sa.query(User)\
74 .filter(User.api_key == api_key)
75 .filter(User.api_key == api_key)
75 if cache:
76 if cache:
76 user = user.options(FromCache("sql_cache_short",
77 user = user.options(FromCache("sql_cache_short",
77 "get_user_%s" % api_key))
78 "get_user_%s" % api_key))
78 return user.scalar()
79 return user.scalar()
79
80
80 def create(self, form_data):
81 def create(self, form_data):
81 try:
82 try:
82 new_user = User()
83 new_user = User()
83 for k, v in form_data.items():
84 for k, v in form_data.items():
84 setattr(new_user, k, v)
85 setattr(new_user, k, v)
85
86
86 new_user.api_key = generate_api_key(form_data['username'])
87 new_user.api_key = generate_api_key(form_data['username'])
87 self.sa.add(new_user)
88 self.sa.add(new_user)
88 self.sa.commit()
89 self.sa.commit()
89 except:
90 except:
90 log.error(traceback.format_exc())
91 log.error(traceback.format_exc())
91 self.sa.rollback()
92 self.sa.rollback()
92 raise
93 raise
93
94
94 def create_ldap(self, username, password, user_dn, attrs):
95 def create_ldap(self, username, password, user_dn, attrs):
95 """
96 """
96 Checks if user is in database, if not creates this user marked
97 Checks if user is in database, if not creates this user marked
97 as ldap user
98 as ldap user
98 :param username:
99 :param username:
99 :param password:
100 :param password:
100 :param user_dn:
101 :param user_dn:
101 :param attrs:
102 :param attrs:
102 """
103 """
103 from rhodecode.lib.auth import get_crypt_password
104 from rhodecode.lib.auth import get_crypt_password
104 log.debug('Checking for such ldap account in RhodeCode database')
105 log.debug('Checking for such ldap account in RhodeCode database')
105 if self.get_by_username(username, case_insensitive=True) is None:
106 if self.get_by_username(username, case_insensitive=True) is None:
106 try:
107 try:
107 new_user = User()
108 new_user = User()
108 # add ldap account always lowercase
109 # add ldap account always lowercase
109 new_user.username = username.lower()
110 new_user.username = username.lower()
110 new_user.password = get_crypt_password(password)
111 new_user.password = get_crypt_password(password)
111 new_user.api_key = generate_api_key(username)
112 new_user.api_key = generate_api_key(username)
112 new_user.email = attrs['email']
113 new_user.email = attrs['email']
113 new_user.active = True
114 new_user.active = True
114 new_user.ldap_dn = user_dn
115 new_user.ldap_dn = safe_unicode(user_dn)
115 new_user.name = attrs['name']
116 new_user.name = attrs['name']
116 new_user.lastname = attrs['lastname']
117 new_user.lastname = attrs['lastname']
117
118
118 self.sa.add(new_user)
119 self.sa.add(new_user)
119 self.sa.commit()
120 self.sa.commit()
120 return True
121 return True
121 except (DatabaseError,):
122 except (DatabaseError,):
122 log.error(traceback.format_exc())
123 log.error(traceback.format_exc())
123 self.sa.rollback()
124 self.sa.rollback()
124 raise
125 raise
125 log.debug('this %s user exists skipping creation of ldap account',
126 log.debug('this %s user exists skipping creation of ldap account',
126 username)
127 username)
127 return False
128 return False
128
129
129 def create_registration(self, form_data):
130 def create_registration(self, form_data):
130 from rhodecode.lib.celerylib import tasks, run_task
131 from rhodecode.lib.celerylib import tasks, run_task
131 try:
132 try:
132 new_user = User()
133 new_user = User()
133 for k, v in form_data.items():
134 for k, v in form_data.items():
134 if k != 'admin':
135 if k != 'admin':
135 setattr(new_user, k, v)
136 setattr(new_user, k, v)
136
137
137 self.sa.add(new_user)
138 self.sa.add(new_user)
138 self.sa.commit()
139 self.sa.commit()
139 body = ('New user registration\n'
140 body = ('New user registration\n'
140 'username: %s\n'
141 'username: %s\n'
141 'email: %s\n')
142 'email: %s\n')
142 body = body % (form_data['username'], form_data['email'])
143 body = body % (form_data['username'], form_data['email'])
143
144
144 run_task(tasks.send_email, None,
145 run_task(tasks.send_email, None,
145 _('[RhodeCode] New User registration'),
146 _('[RhodeCode] New User registration'),
146 body)
147 body)
147 except:
148 except:
148 log.error(traceback.format_exc())
149 log.error(traceback.format_exc())
149 self.sa.rollback()
150 self.sa.rollback()
150 raise
151 raise
151
152
152 def update(self, user_id, form_data):
153 def update(self, user_id, form_data):
153 try:
154 try:
154 user = self.get(user_id, cache=False)
155 user = self.get(user_id, cache=False)
155 if user.username == 'default':
156 if user.username == 'default':
156 raise DefaultUserException(
157 raise DefaultUserException(
157 _("You can't Edit this user since it's"
158 _("You can't Edit this user since it's"
158 " crucial for entire application"))
159 " crucial for entire application"))
159
160
160 for k, v in form_data.items():
161 for k, v in form_data.items():
161 if k == 'new_password' and v != '':
162 if k == 'new_password' and v != '':
162 user.password = v
163 user.password = v
163 user.api_key = generate_api_key(user.username)
164 user.api_key = generate_api_key(user.username)
164 else:
165 else:
165 setattr(user, k, v)
166 setattr(user, k, v)
166
167
167 self.sa.add(user)
168 self.sa.add(user)
168 self.sa.commit()
169 self.sa.commit()
169 except:
170 except:
170 log.error(traceback.format_exc())
171 log.error(traceback.format_exc())
171 self.sa.rollback()
172 self.sa.rollback()
172 raise
173 raise
173
174
174 def update_my_account(self, user_id, form_data):
175 def update_my_account(self, user_id, form_data):
175 try:
176 try:
176 user = self.get(user_id, cache=False)
177 user = self.get(user_id, cache=False)
177 if user.username == 'default':
178 if user.username == 'default':
178 raise DefaultUserException(
179 raise DefaultUserException(
179 _("You can't Edit this user since it's"
180 _("You can't Edit this user since it's"
180 " crucial for entire application"))
181 " crucial for entire application"))
181 for k, v in form_data.items():
182 for k, v in form_data.items():
182 if k == 'new_password' and v != '':
183 if k == 'new_password' and v != '':
183 user.password = v
184 user.password = v
184 user.api_key = generate_api_key(user.username)
185 user.api_key = generate_api_key(user.username)
185 else:
186 else:
186 if k not in ['admin', 'active']:
187 if k not in ['admin', 'active']:
187 setattr(user, k, v)
188 setattr(user, k, v)
188
189
189 self.sa.add(user)
190 self.sa.add(user)
190 self.sa.commit()
191 self.sa.commit()
191 except:
192 except:
192 log.error(traceback.format_exc())
193 log.error(traceback.format_exc())
193 self.sa.rollback()
194 self.sa.rollback()
194 raise
195 raise
195
196
196 def delete(self, user_id):
197 def delete(self, user_id):
197 try:
198 try:
198 user = self.get(user_id, cache=False)
199 user = self.get(user_id, cache=False)
199 if user.username == 'default':
200 if user.username == 'default':
200 raise DefaultUserException(
201 raise DefaultUserException(
201 _("You can't remove this user since it's"
202 _("You can't remove this user since it's"
202 " crucial for entire application"))
203 " crucial for entire application"))
203 if user.repositories:
204 if user.repositories:
204 raise UserOwnsReposException(_('This user still owns %s '
205 raise UserOwnsReposException(_('This user still owns %s '
205 'repositories and cannot be '
206 'repositories and cannot be '
206 'removed. Switch owners or '
207 'removed. Switch owners or '
207 'remove those repositories') \
208 'remove those repositories') \
208 % user.repositories)
209 % user.repositories)
209 self.sa.delete(user)
210 self.sa.delete(user)
210 self.sa.commit()
211 self.sa.commit()
211 except:
212 except:
212 log.error(traceback.format_exc())
213 log.error(traceback.format_exc())
213 self.sa.rollback()
214 self.sa.rollback()
214 raise
215 raise
215
216
216 def reset_password_link(self, data):
217 def reset_password_link(self, data):
217 from rhodecode.lib.celerylib import tasks, run_task
218 from rhodecode.lib.celerylib import tasks, run_task
218 run_task(tasks.send_password_link, data['email'])
219 run_task(tasks.send_password_link, data['email'])
219
220
220 def reset_password(self, data):
221 def reset_password(self, data):
221 from rhodecode.lib.celerylib import tasks, run_task
222 from rhodecode.lib.celerylib import tasks, run_task
222 run_task(tasks.reset_user_password, data['email'])
223 run_task(tasks.reset_user_password, data['email'])
223
224
224 def fill_data(self, auth_user, user_id=None, api_key=None):
225 def fill_data(self, auth_user, user_id=None, api_key=None):
225 """
226 """
226 Fetches auth_user by user_id,or api_key if present.
227 Fetches auth_user by user_id,or api_key if present.
227 Fills auth_user attributes with those taken from database.
228 Fills auth_user attributes with those taken from database.
228 Additionally set's is_authenitated if lookup fails
229 Additionally set's is_authenitated if lookup fails
229 present in database
230 present in database
230
231
231 :param auth_user: instance of user to set attributes
232 :param auth_user: instance of user to set attributes
232 :param user_id: user id to fetch by
233 :param user_id: user id to fetch by
233 :param api_key: api key to fetch by
234 :param api_key: api key to fetch by
234 """
235 """
235 if user_id is None and api_key is None:
236 if user_id is None and api_key is None:
236 raise Exception('You need to pass user_id or api_key')
237 raise Exception('You need to pass user_id or api_key')
237
238
238 try:
239 try:
239 if api_key:
240 if api_key:
240 dbuser = self.get_by_api_key(api_key)
241 dbuser = self.get_by_api_key(api_key)
241 else:
242 else:
242 dbuser = self.get(user_id)
243 dbuser = self.get(user_id)
243
244
244 if dbuser is not None:
245 if dbuser is not None:
245 log.debug('filling %s data', dbuser)
246 log.debug('filling %s data', dbuser)
246 for k, v in dbuser.get_dict().items():
247 for k, v in dbuser.get_dict().items():
247 setattr(auth_user, k, v)
248 setattr(auth_user, k, v)
248
249
249 except:
250 except:
250 log.error(traceback.format_exc())
251 log.error(traceback.format_exc())
251 auth_user.is_authenticated = False
252 auth_user.is_authenticated = False
252
253
253 return auth_user
254 return auth_user
254
255
255 def fill_perms(self, user):
256 def fill_perms(self, user):
256 """
257 """
257 Fills user permission attribute with permissions taken from database
258 Fills user permission attribute with permissions taken from database
258 works for permissions given for repositories, and for permissions that
259 works for permissions given for repositories, and for permissions that
259 are granted to groups
260 are granted to groups
260
261
261 :param user: user instance to fill his perms
262 :param user: user instance to fill his perms
262 """
263 """
263
264
264 user.permissions['repositories'] = {}
265 user.permissions['repositories'] = {}
265 user.permissions['global'] = set()
266 user.permissions['global'] = set()
266
267
267 #======================================================================
268 #======================================================================
268 # fetch default permissions
269 # fetch default permissions
269 #======================================================================
270 #======================================================================
270 default_user = self.get_by_username('default', cache=True)
271 default_user = self.get_by_username('default', cache=True)
271
272
272 default_perms = self.sa.query(RepoToPerm, Repository, Permission)\
273 default_perms = self.sa.query(RepoToPerm, Repository, Permission)\
273 .join((Repository, RepoToPerm.repository_id ==
274 .join((Repository, RepoToPerm.repository_id ==
274 Repository.repo_id))\
275 Repository.repo_id))\
275 .join((Permission, RepoToPerm.permission_id ==
276 .join((Permission, RepoToPerm.permission_id ==
276 Permission.permission_id))\
277 Permission.permission_id))\
277 .filter(RepoToPerm.user == default_user).all()
278 .filter(RepoToPerm.user == default_user).all()
278
279
279 if user.is_admin:
280 if user.is_admin:
280 #==================================================================
281 #==================================================================
281 # #admin have all default rights set to admin
282 # #admin have all default rights set to admin
282 #==================================================================
283 #==================================================================
283 user.permissions['global'].add('hg.admin')
284 user.permissions['global'].add('hg.admin')
284
285
285 for perm in default_perms:
286 for perm in default_perms:
286 p = 'repository.admin'
287 p = 'repository.admin'
287 user.permissions['repositories'][perm.RepoToPerm.
288 user.permissions['repositories'][perm.RepoToPerm.
288 repository.repo_name] = p
289 repository.repo_name] = p
289
290
290 else:
291 else:
291 #==================================================================
292 #==================================================================
292 # set default permissions
293 # set default permissions
293 #==================================================================
294 #==================================================================
294 uid = user.user_id
295 uid = user.user_id
295
296
296 #default global
297 #default global
297 default_global_perms = self.sa.query(UserToPerm)\
298 default_global_perms = self.sa.query(UserToPerm)\
298 .filter(UserToPerm.user == default_user)
299 .filter(UserToPerm.user == default_user)
299
300
300 for perm in default_global_perms:
301 for perm in default_global_perms:
301 user.permissions['global'].add(perm.permission.permission_name)
302 user.permissions['global'].add(perm.permission.permission_name)
302
303
303 #default for repositories
304 #default for repositories
304 for perm in default_perms:
305 for perm in default_perms:
305 if perm.Repository.private and not (perm.Repository.user_id ==
306 if perm.Repository.private and not (perm.Repository.user_id ==
306 uid):
307 uid):
307 #diself.sable defaults for private repos,
308 #diself.sable defaults for private repos,
308 p = 'repository.none'
309 p = 'repository.none'
309 elif perm.Repository.user_id == uid:
310 elif perm.Repository.user_id == uid:
310 #set admin if owner
311 #set admin if owner
311 p = 'repository.admin'
312 p = 'repository.admin'
312 else:
313 else:
313 p = perm.Permission.permission_name
314 p = perm.Permission.permission_name
314
315
315 user.permissions['repositories'][perm.RepoToPerm.
316 user.permissions['repositories'][perm.RepoToPerm.
316 repository.repo_name] = p
317 repository.repo_name] = p
317
318
318 #==================================================================
319 #==================================================================
319 # overwrite default with user permissions if any
320 # overwrite default with user permissions if any
320 #==================================================================
321 #==================================================================
321
322
322 #user global
323 #user global
323 user_perms = self.sa.query(UserToPerm)\
324 user_perms = self.sa.query(UserToPerm)\
324 .options(joinedload(UserToPerm.permission))\
325 .options(joinedload(UserToPerm.permission))\
325 .filter(UserToPerm.user_id == uid).all()
326 .filter(UserToPerm.user_id == uid).all()
326
327
327 for perm in user_perms:
328 for perm in user_perms:
328 user.permissions['global'].add(perm.permission.
329 user.permissions['global'].add(perm.permission.
329 permission_name)
330 permission_name)
330
331
331 #user repositories
332 #user repositories
332 user_repo_perms = self.sa.query(RepoToPerm, Permission,
333 user_repo_perms = self.sa.query(RepoToPerm, Permission,
333 Repository)\
334 Repository)\
334 .join((Repository, RepoToPerm.repository_id ==
335 .join((Repository, RepoToPerm.repository_id ==
335 Repository.repo_id))\
336 Repository.repo_id))\
336 .join((Permission, RepoToPerm.permission_id ==
337 .join((Permission, RepoToPerm.permission_id ==
337 Permission.permission_id))\
338 Permission.permission_id))\
338 .filter(RepoToPerm.user_id == uid).all()
339 .filter(RepoToPerm.user_id == uid).all()
339
340
340 for perm in user_repo_perms:
341 for perm in user_repo_perms:
341 # set admin if owner
342 # set admin if owner
342 if perm.Repository.user_id == uid:
343 if perm.Repository.user_id == uid:
343 p = 'repository.admin'
344 p = 'repository.admin'
344 else:
345 else:
345 p = perm.Permission.permission_name
346 p = perm.Permission.permission_name
346 user.permissions['repositories'][perm.RepoToPerm.
347 user.permissions['repositories'][perm.RepoToPerm.
347 repository.repo_name] = p
348 repository.repo_name] = p
348
349
349 #==================================================================
350 #==================================================================
350 # check if user is part of groups for this repository and fill in
351 # check if user is part of groups for this repository and fill in
351 # (or replace with higher) permissions
352 # (or replace with higher) permissions
352 #==================================================================
353 #==================================================================
353
354
354 #users group global
355 #users group global
355 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
356 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
356 .options(joinedload(UsersGroupToPerm.permission))\
357 .options(joinedload(UsersGroupToPerm.permission))\
357 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
358 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
358 UsersGroupMember.users_group_id))\
359 UsersGroupMember.users_group_id))\
359 .filter(UsersGroupMember.user_id == uid).all()
360 .filter(UsersGroupMember.user_id == uid).all()
360
361
361 for perm in user_perms_from_users_groups:
362 for perm in user_perms_from_users_groups:
362 user.permissions['global'].add(perm.permission.permission_name)
363 user.permissions['global'].add(perm.permission.permission_name)
363
364
364 #users group repositories
365 #users group repositories
365 user_repo_perms_from_users_groups = self.sa.query(
366 user_repo_perms_from_users_groups = self.sa.query(
366 UsersGroupRepoToPerm,
367 UsersGroupRepoToPerm,
367 Permission, Repository,)\
368 Permission, Repository,)\
368 .join((Repository, UsersGroupRepoToPerm.repository_id ==
369 .join((Repository, UsersGroupRepoToPerm.repository_id ==
369 Repository.repo_id))\
370 Repository.repo_id))\
370 .join((Permission, UsersGroupRepoToPerm.permission_id ==
371 .join((Permission, UsersGroupRepoToPerm.permission_id ==
371 Permission.permission_id))\
372 Permission.permission_id))\
372 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
373 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
373 UsersGroupMember.users_group_id))\
374 UsersGroupMember.users_group_id))\
374 .filter(UsersGroupMember.user_id == uid).all()
375 .filter(UsersGroupMember.user_id == uid).all()
375
376
376 for perm in user_repo_perms_from_users_groups:
377 for perm in user_repo_perms_from_users_groups:
377 p = perm.Permission.permission_name
378 p = perm.Permission.permission_name
378 cur_perm = user.permissions['repositories'][perm.
379 cur_perm = user.permissions['repositories'][perm.
379 UsersGroupRepoToPerm.
380 UsersGroupRepoToPerm.
380 repository.repo_name]
381 repository.repo_name]
381 #overwrite permission only if it's greater than permission
382 #overwrite permission only if it's greater than permission
382 # given from other sources
383 # given from other sources
383 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
384 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
384 user.permissions['repositories'][perm.UsersGroupRepoToPerm.
385 user.permissions['repositories'][perm.UsersGroupRepoToPerm.
385 repository.repo_name] = p
386 repository.repo_name] = p
386
387
387 return user
388 return user
General Comments 0
You need to be logged in to leave comments. Login now