Mercurial > kallithea
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)) |