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