comparison rhodecode/model/repo_group.py @ 4116:ffd45b185016 rhodecode-2.2.5-gpl

Imported some of the GPLv3'd changes from RhodeCode v2.2.5. This imports changes between changesets 21af6c4eab3d and 6177597791c2 in RhodeCode's original repository, including only changes to Python files and HTML. RhodeCode clearly licensed its changes to these files under GPLv3 in their /LICENSE file, which states the following: The Python code and integrated HTML are licensed under the GPLv3 license. (See: https://code.rhodecode.com/rhodecode/files/v2.2.5/LICENSE or http://web.archive.org/web/20140512193334/https://code.rhodecode.com/rhodecode/files/f3b123159901f15426d18e3dc395e8369f70ebe0/LICENSE for an online copy of that LICENSE file) Conservancy reviewed these changes and confirmed that they can be licensed as a whole to the Kallithea project under GPLv3-only. While some of the contents committed herein are clearly licensed GPLv3-or-later, on the whole we must assume the are GPLv3-only, since the statement above from RhodeCode indicates that they intend GPLv3-only as their license, per GPLv3ยง14 and other relevant sections of GPLv3.
author Bradley M. Kuhn <bkuhn@sfconservancy.org>
date Wed, 02 Jul 2014 19:03:13 -0400
parents
children 7e5f8c12a3fc
comparison
equal deleted inserted replaced
4115:8b7294a804a0 4116:ffd45b185016
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
15 rhodecode.model.user_group
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~
17
18 repo group model for RhodeCode
19
20 :created_on: Jan 25, 2011
21 :author: marcink
22 :copyright: (c) 2013 RhodeCode GmbH.
23 :license: GPLv3, see LICENSE for more details.
24 """
25
26
27 import os
28 import logging
29 import traceback
30 import shutil
31 import datetime
32
33 from rhodecode.lib.utils2 import LazyProperty
34
35 from rhodecode.model import BaseModel
36 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
37 User, Permission, UserGroupRepoGroupToPerm, UserGroup, Repository
38
39 log = logging.getLogger(__name__)
40
41
42 class RepoGroupModel(BaseModel):
43
44 cls = RepoGroup
45
46 def _get_user_group(self, users_group):
47 return self._get_instance(UserGroup, users_group,
48 callback=UserGroup.get_by_group_name)
49
50 def _get_repo_group(self, repo_group):
51 return self._get_instance(RepoGroup, repo_group,
52 callback=RepoGroup.get_by_group_name)
53
54 @LazyProperty
55 def repos_path(self):
56 """
57 Gets the repositories root path from database
58 """
59
60 q = RhodeCodeUi.get_by_key('/')
61 return q.ui_value
62
63 def _create_default_perms(self, new_group):
64 # create default permission
65 default_perm = 'group.read'
66 def_user = User.get_default_user()
67 for p in def_user.user_perms:
68 if p.permission.permission_name.startswith('group.'):
69 default_perm = p.permission.permission_name
70 break
71
72 repo_group_to_perm = UserRepoGroupToPerm()
73 repo_group_to_perm.permission = Permission.get_by_key(default_perm)
74
75 repo_group_to_perm.group = new_group
76 repo_group_to_perm.user_id = def_user.user_id
77 return repo_group_to_perm
78
79 def _create_group(self, group_name):
80 """
81 makes repository group on filesystem
82
83 :param repo_name:
84 :param parent_id:
85 """
86
87 create_path = os.path.join(self.repos_path, group_name)
88 log.debug('creating new group in %s' % create_path)
89
90 if os.path.isdir(create_path):
91 raise Exception('That directory already exists !')
92
93 os.makedirs(create_path)
94 log.debug('Created group in %s' % create_path)
95
96 def _rename_group(self, old, new):
97 """
98 Renames a group on filesystem
99
100 :param group_name:
101 """
102
103 if old == new:
104 log.debug('skipping group rename')
105 return
106
107 log.debug('renaming repository group from %s to %s' % (old, new))
108
109 old_path = os.path.join(self.repos_path, old)
110 new_path = os.path.join(self.repos_path, new)
111
112 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
113
114 if os.path.isdir(new_path):
115 raise Exception('Was trying to rename to already '
116 'existing dir %s' % new_path)
117 shutil.move(old_path, new_path)
118
119 def _delete_group(self, group, force_delete=False):
120 """
121 Deletes a group from a filesystem
122
123 :param group: instance of group from database
124 :param force_delete: use shutil rmtree to remove all objects
125 """
126 paths = group.full_path.split(RepoGroup.url_sep())
127 paths = os.sep.join(paths)
128
129 rm_path = os.path.join(self.repos_path, paths)
130 log.info("Removing group %s" % (rm_path))
131 # delete only if that path really exists
132 if os.path.isdir(rm_path):
133 if force_delete:
134 shutil.rmtree(rm_path)
135 else:
136 #archive that group`
137 _now = datetime.datetime.now()
138 _ms = str(_now.microsecond).rjust(6, '0')
139 _d = 'rm__%s_GROUP_%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
140 group.name)
141 shutil.move(rm_path, os.path.join(self.repos_path, _d))
142
143 def create(self, group_name, group_description, owner, parent=None,
144 just_db=False, copy_permissions=False):
145 try:
146 user = self._get_user(owner)
147 parent_group = self._get_repo_group(parent)
148 new_repo_group = RepoGroup()
149 new_repo_group.user = user
150 new_repo_group.group_description = group_description or group_name
151 new_repo_group.parent_group = parent_group
152 new_repo_group.group_name = new_repo_group.get_new_name(group_name)
153
154 self.sa.add(new_repo_group)
155
156 # create an ADMIN permission for owner except if we're super admin,
157 # later owner should go into the owner field of groups
158 if not user.is_admin:
159 self.grant_user_permission(repo_group=new_repo_group,
160 user=owner, perm='group.admin')
161
162 if parent_group and copy_permissions:
163 # copy permissions from parent
164 user_perms = UserRepoGroupToPerm.query() \
165 .filter(UserRepoGroupToPerm.group == parent_group).all()
166
167 group_perms = UserGroupRepoGroupToPerm.query() \
168 .filter(UserGroupRepoGroupToPerm.group == parent_group).all()
169
170 for perm in user_perms:
171 # don't copy over the permission for user who is creating
172 # this group, if he is not super admin he get's admin
173 # permission set above
174 if perm.user != user or user.is_admin:
175 UserRepoGroupToPerm.create(perm.user, new_repo_group, perm.permission)
176
177 for perm in group_perms:
178 UserGroupRepoGroupToPerm.create(perm.users_group, new_repo_group, perm.permission)
179 else:
180 perm_obj = self._create_default_perms(new_repo_group)
181 self.sa.add(perm_obj)
182
183 if not just_db:
184 # we need to flush here, in order to check if database won't
185 # throw any exceptions, create filesystem dirs at the very end
186 self.sa.flush()
187 self._create_group(new_repo_group.group_name)
188
189 return new_repo_group
190 except Exception:
191 log.error(traceback.format_exc())
192 raise
193
194 def _update_permissions(self, repo_group, perms_new=None,
195 perms_updates=None, recursive=None,
196 check_perms=True):
197 from rhodecode.model.repo import RepoModel
198 from rhodecode.lib.auth import HasUserGroupPermissionAny
199
200 if not perms_new:
201 perms_new = []
202 if not perms_updates:
203 perms_updates = []
204
205 def _set_perm_user(obj, user, perm):
206 if isinstance(obj, RepoGroup):
207 self.grant_user_permission(repo_group=obj, user=user, perm=perm)
208 elif isinstance(obj, Repository):
209 # private repos will not allow to change the default permissions
210 # using recursive mode
211 if obj.private and user == User.DEFAULT_USER:
212 return
213
214 # we set group permission but we have to switch to repo
215 # permission
216 perm = perm.replace('group.', 'repository.')
217 RepoModel().grant_user_permission(
218 repo=obj, user=user, perm=perm
219 )
220
221 def _set_perm_group(obj, users_group, perm):
222 if isinstance(obj, RepoGroup):
223 self.grant_user_group_permission(repo_group=obj,
224 group_name=users_group,
225 perm=perm)
226 elif isinstance(obj, Repository):
227 # we set group permission but we have to switch to repo
228 # permission
229 perm = perm.replace('group.', 'repository.')
230 RepoModel().grant_user_group_permission(
231 repo=obj, group_name=users_group, perm=perm
232 )
233
234 # start updates
235 updates = []
236 log.debug('Now updating permissions for %s in recursive mode:%s'
237 % (repo_group, recursive))
238
239 for obj in repo_group.recursive_groups_and_repos():
240 # iterated obj is an instance of a repos group or repository in
241 # that group, recursive option can be: none, repos, groups, all
242 if recursive == 'all':
243 obj = obj
244 elif recursive == 'repos':
245 # skip groups, other than this one
246 if isinstance(obj, RepoGroup) and not obj == repo_group:
247 continue
248 elif recursive == 'groups':
249 # skip repos
250 if isinstance(obj, Repository):
251 continue
252 else: # recursive == 'none': # DEFAULT don't apply to iterated objects
253 obj = repo_group
254 # also we do a break at the end of this loop.
255
256 # update permissions
257 for member, perm, member_type in perms_updates:
258 ## set for user
259 if member_type == 'user':
260 # this updates also current one if found
261 _set_perm_user(obj, user=member, perm=perm)
262 ## set for user group
263 else:
264 #check if we have permissions to alter this usergroup
265 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
266 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member):
267 _set_perm_group(obj, users_group=member, perm=perm)
268 # set new permissions
269 for member, perm, member_type in perms_new:
270 if member_type == 'user':
271 _set_perm_user(obj, user=member, perm=perm)
272 else:
273 #check if we have permissions to alter this usergroup
274 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
275 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member):
276 _set_perm_group(obj, users_group=member, perm=perm)
277 updates.append(obj)
278 # if it's not recursive call for all,repos,groups
279 # break the loop and don't proceed with other changes
280 if recursive not in ['all', 'repos', 'groups']:
281 break
282
283 return updates
284
285 def update(self, repo_group, form_data):
286
287 try:
288 repo_group = self._get_repo_group(repo_group)
289 old_path = repo_group.full_path
290
291 # change properties
292 repo_group.group_description = form_data['group_description']
293 repo_group.group_parent_id = form_data['group_parent_id']
294 repo_group.enable_locking = form_data['enable_locking']
295
296 repo_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
297 repo_group.group_name = repo_group.get_new_name(form_data['group_name'])
298 new_path = repo_group.full_path
299 self.sa.add(repo_group)
300
301 # iterate over all members of this groups and do fixes
302 # set locking if given
303 # if obj is a repoGroup also fix the name of the group according
304 # to the parent
305 # if obj is a Repo fix it's name
306 # this can be potentially heavy operation
307 for obj in repo_group.recursive_groups_and_repos():
308 #set the value from it's parent
309 obj.enable_locking = repo_group.enable_locking
310 if isinstance(obj, RepoGroup):
311 new_name = obj.get_new_name(obj.name)
312 log.debug('Fixing group %s to new name %s' \
313 % (obj.group_name, new_name))
314 obj.group_name = new_name
315 elif isinstance(obj, Repository):
316 # we need to get all repositories from this new group and
317 # rename them accordingly to new group path
318 new_name = obj.get_new_name(obj.just_name)
319 log.debug('Fixing repo %s to new name %s' \
320 % (obj.repo_name, new_name))
321 obj.repo_name = new_name
322 self.sa.add(obj)
323
324 self._rename_group(old_path, new_path)
325
326 return repo_group
327 except Exception:
328 log.error(traceback.format_exc())
329 raise
330
331 def delete(self, repo_group, force_delete=False):
332 repo_group = self._get_repo_group(repo_group)
333 try:
334 self.sa.delete(repo_group)
335 self._delete_group(repo_group, force_delete)
336 except Exception:
337 log.error('Error removing repo_group %s' % repo_group)
338 raise
339
340 def add_permission(self, repo_group, obj, obj_type, perm, recursive):
341 from rhodecode.model.repo import RepoModel
342 repo_group = self._get_repo_group(repo_group)
343 perm = self._get_perm(perm)
344
345 for el in repo_group.recursive_groups_and_repos():
346 # iterated obj is an instance of a repos group or repository in
347 # that group, recursive option can be: none, repos, groups, all
348 if recursive == 'all':
349 el = el
350 elif recursive == 'repos':
351 # skip groups, other than this one
352 if isinstance(el, RepoGroup) and not el == repo_group:
353 continue
354 elif recursive == 'groups':
355 # skip repos
356 if isinstance(el, Repository):
357 continue
358 else: # recursive == 'none': # DEFAULT don't apply to iterated objects
359 el = repo_group
360 # also we do a break at the end of this loop.
361
362 if isinstance(el, RepoGroup):
363 if obj_type == 'user':
364 RepoGroupModel().grant_user_permission(el, user=obj, perm=perm)
365 elif obj_type == 'user_group':
366 RepoGroupModel().grant_user_group_permission(el, group_name=obj, perm=perm)
367 else:
368 raise Exception('undefined object type %s' % obj_type)
369 elif isinstance(el, Repository):
370 # for repos we need to hotfix the name of permission
371 _perm = perm.permission_name.replace('group.', 'repository.')
372 if obj_type == 'user':
373 RepoModel().grant_user_permission(el, user=obj, perm=_perm)
374 elif obj_type == 'user_group':
375 RepoModel().grant_user_group_permission(el, group_name=obj, perm=_perm)
376 else:
377 raise Exception('undefined object type %s' % obj_type)
378 else:
379 raise Exception('el should be instance of Repository or '
380 'RepositoryGroup got %s instead' % type(el))
381
382 # if it's not recursive call for all,repos,groups
383 # break the loop and don't proceed with other changes
384 if recursive not in ['all', 'repos', 'groups']:
385 break
386
387 def delete_permission(self, repo_group, obj, obj_type, recursive):
388 """
389 Revokes permission for repo_group for given obj(user or users_group),
390 obj_type can be user or user group
391
392 :param repo_group:
393 :param obj: user or user group id
394 :param obj_type: user or user group type
395 :param recursive: recurse to all children of group
396 """
397 from rhodecode.model.repo import RepoModel
398 repo_group = self._get_repo_group(repo_group)
399
400 for el in repo_group.recursive_groups_and_repos():
401 # iterated obj is an instance of a repos group or repository in
402 # that group, recursive option can be: none, repos, groups, all
403 if recursive == 'all':
404 el = el
405 elif recursive == 'repos':
406 # skip groups, other than this one
407 if isinstance(el, RepoGroup) and not el == repo_group:
408 continue
409 elif recursive == 'groups':
410 # skip repos
411 if isinstance(el, Repository):
412 continue
413 else: # recursive == 'none': # DEFAULT don't apply to iterated objects
414 el = repo_group
415 # also we do a break at the end of this loop.
416
417 if isinstance(el, RepoGroup):
418 if obj_type == 'user':
419 RepoGroupModel().revoke_user_permission(el, user=obj)
420 elif obj_type == 'user_group':
421 RepoGroupModel().revoke_user_group_permission(el, group_name=obj)
422 else:
423 raise Exception('undefined object type %s' % obj_type)
424 elif isinstance(el, Repository):
425 if obj_type == 'user':
426 RepoModel().revoke_user_permission(el, user=obj)
427 elif obj_type == 'user_group':
428 RepoModel().revoke_user_group_permission(el, group_name=obj)
429 else:
430 raise Exception('undefined object type %s' % obj_type)
431 else:
432 raise Exception('el should be instance of Repository or '
433 'RepositoryGroup got %s instead' % type(el))
434
435 # if it's not recursive call for all,repos,groups
436 # break the loop and don't proceed with other changes
437 if recursive not in ['all', 'repos', 'groups']:
438 break
439
440 def grant_user_permission(self, repo_group, user, perm):
441 """
442 Grant permission for user on given repository group, or update
443 existing one if found
444
445 :param repo_group: Instance of RepoGroup, repositories_group_id,
446 or repositories_group name
447 :param user: Instance of User, user_id or username
448 :param perm: Instance of Permission, or permission_name
449 """
450
451 repo_group = self._get_repo_group(repo_group)
452 user = self._get_user(user)
453 permission = self._get_perm(perm)
454
455 # check if we have that permission already
456 obj = self.sa.query(UserRepoGroupToPerm)\
457 .filter(UserRepoGroupToPerm.user == user)\
458 .filter(UserRepoGroupToPerm.group == repo_group)\
459 .scalar()
460 if obj is None:
461 # create new !
462 obj = UserRepoGroupToPerm()
463 obj.group = repo_group
464 obj.user = user
465 obj.permission = permission
466 self.sa.add(obj)
467 log.debug('Granted perm %s to %s on %s' % (perm, user, repo_group))
468 return obj
469
470 def revoke_user_permission(self, repo_group, user):
471 """
472 Revoke permission for user on given repository group
473
474 :param repo_group: Instance of RepoGroup, repositories_group_id,
475 or repositories_group name
476 :param user: Instance of User, user_id or username
477 """
478
479 repo_group = self._get_repo_group(repo_group)
480 user = self._get_user(user)
481
482 obj = self.sa.query(UserRepoGroupToPerm)\
483 .filter(UserRepoGroupToPerm.user == user)\
484 .filter(UserRepoGroupToPerm.group == repo_group)\
485 .scalar()
486 if obj:
487 self.sa.delete(obj)
488 log.debug('Revoked perm on %s on %s' % (repo_group, user))
489
490 def grant_user_group_permission(self, repo_group, group_name, perm):
491 """
492 Grant permission for user group on given repository group, or update
493 existing one if found
494
495 :param repo_group: Instance of RepoGroup, repositories_group_id,
496 or repositories_group name
497 :param group_name: Instance of UserGroup, users_group_id,
498 or user group name
499 :param perm: Instance of Permission, or permission_name
500 """
501 repo_group = self._get_repo_group(repo_group)
502 group_name = self._get_user_group(group_name)
503 permission = self._get_perm(perm)
504
505 # check if we have that permission already
506 obj = self.sa.query(UserGroupRepoGroupToPerm)\
507 .filter(UserGroupRepoGroupToPerm.group == repo_group)\
508 .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
509 .scalar()
510
511 if obj is None:
512 # create new
513 obj = UserGroupRepoGroupToPerm()
514
515 obj.group = repo_group
516 obj.users_group = group_name
517 obj.permission = permission
518 self.sa.add(obj)
519 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo_group))
520 return obj
521
522 def revoke_user_group_permission(self, repo_group, group_name):
523 """
524 Revoke permission for user group on given repository group
525
526 :param repo_group: Instance of RepoGroup, repositories_group_id,
527 or repositories_group name
528 :param group_name: Instance of UserGroup, users_group_id,
529 or user group name
530 """
531 repo_group = self._get_repo_group(repo_group)
532 group_name = self._get_user_group(group_name)
533
534 obj = self.sa.query(UserGroupRepoGroupToPerm)\
535 .filter(UserGroupRepoGroupToPerm.group == repo_group)\
536 .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
537 .scalar()
538 if obj:
539 self.sa.delete(obj)
540 log.debug('Revoked perm to %s on %s' % (repo_group, group_name))