##// END OF EJS Templates
repo group: drop pointless double handling of parent_group_id updates
Mads Kiilerich -
r8731:6d773118 stable
parent child Browse files
Show More
@@ -1,534 +1,531 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 151 # create an ADMIN permission for owner except if we're super admin,
152 152 # later owner should go into the owner field of groups
153 153 if not owner.is_admin:
154 154 self.grant_user_permission(repo_group=new_repo_group,
155 155 user=owner, perm='group.admin')
156 156
157 157 if parent_group and copy_permissions:
158 158 # copy permissions from parent
159 159 user_perms = db.UserRepoGroupToPerm.query() \
160 160 .filter(db.UserRepoGroupToPerm.group == parent_group).all()
161 161
162 162 group_perms = db.UserGroupRepoGroupToPerm.query() \
163 163 .filter(db.UserGroupRepoGroupToPerm.group == parent_group).all()
164 164
165 165 for perm in user_perms:
166 166 # don't copy over the permission for user who is creating
167 167 # this group, if he is not super admin he get's admin
168 168 # permission set above
169 169 if perm.user != owner or owner.is_admin:
170 170 db.UserRepoGroupToPerm.create(perm.user, new_repo_group, perm.permission)
171 171
172 172 for perm in group_perms:
173 173 db.UserGroupRepoGroupToPerm.create(perm.users_group, new_repo_group, perm.permission)
174 174 else:
175 175 self._create_default_perms(new_repo_group)
176 176
177 177 if not just_db:
178 178 # we need to flush here, in order to check if database won't
179 179 # throw any exceptions, create filesystem dirs at the very end
180 180 meta.Session().flush()
181 181 self._create_group(new_repo_group.group_name)
182 182
183 183 return new_repo_group
184 184 except Exception:
185 185 log.error(traceback.format_exc())
186 186 raise
187 187
188 188 def _update_permissions(self, repo_group, perms_new=None,
189 189 perms_updates=None, recursive=None,
190 190 check_perms=True):
191 191 from kallithea.lib.auth import HasUserGroupPermissionLevel
192 192
193 193 if not perms_new:
194 194 perms_new = []
195 195 if not perms_updates:
196 196 perms_updates = []
197 197
198 198 def _set_perm_user(obj, user, perm):
199 199 if isinstance(obj, db.RepoGroup):
200 200 self.grant_user_permission(repo_group=obj, user=user, perm=perm)
201 201 elif isinstance(obj, db.Repository):
202 202 user = db.User.guess_instance(user)
203 203
204 204 # private repos will not allow to change the default permissions
205 205 # using recursive mode
206 206 if obj.private and user.is_default_user:
207 207 return
208 208
209 209 # we set group permission but we have to switch to repo
210 210 # permission
211 211 perm = perm.replace('group.', 'repository.')
212 212 repo.RepoModel().grant_user_permission(
213 213 repo=obj, user=user, perm=perm
214 214 )
215 215
216 216 def _set_perm_group(obj, users_group, perm):
217 217 if isinstance(obj, db.RepoGroup):
218 218 self.grant_user_group_permission(repo_group=obj,
219 219 group_name=users_group,
220 220 perm=perm)
221 221 elif isinstance(obj, db.Repository):
222 222 # we set group permission but we have to switch to repo
223 223 # permission
224 224 perm = perm.replace('group.', 'repository.')
225 225 repo.RepoModel().grant_user_group_permission(
226 226 repo=obj, group_name=users_group, perm=perm
227 227 )
228 228
229 229 # start updates
230 230 updates = []
231 231 log.debug('Now updating permissions for %s in recursive mode:%s',
232 232 repo_group, recursive)
233 233
234 234 for obj in repo_group.recursive_groups_and_repos():
235 235 # iterated obj is an instance of a repos group or repository in
236 236 # that group, recursive option can be: none, repos, groups, all
237 237 if recursive == 'all':
238 238 pass
239 239 elif recursive == 'repos':
240 240 # skip groups, other than this one
241 241 if isinstance(obj, db.RepoGroup) and not obj == repo_group:
242 242 continue
243 243 elif recursive == 'groups':
244 244 # skip repos
245 245 if isinstance(obj, db.Repository):
246 246 continue
247 247 else: # recursive == 'none': # DEFAULT don't apply to iterated objects
248 248 obj = repo_group
249 249 # also we do a break at the end of this loop.
250 250
251 251 # update permissions
252 252 for member, perm, member_type in perms_updates:
253 253 ## set for user
254 254 if member_type == 'user':
255 255 # this updates also current one if found
256 256 _set_perm_user(obj, user=member, perm=perm)
257 257 ## set for user group
258 258 else:
259 259 # check if we have permissions to alter this usergroup's access
260 260 if not check_perms or HasUserGroupPermissionLevel('read')(member):
261 261 _set_perm_group(obj, users_group=member, perm=perm)
262 262 # set new permissions
263 263 for member, perm, member_type in perms_new:
264 264 if member_type == 'user':
265 265 _set_perm_user(obj, user=member, perm=perm)
266 266 else:
267 267 # check if we have permissions to alter this usergroup's access
268 268 if not check_perms or HasUserGroupPermissionLevel('read')(member):
269 269 _set_perm_group(obj, users_group=member, perm=perm)
270 270 updates.append(obj)
271 271 # if it's not recursive call for all,repos,groups
272 272 # break the loop and don't proceed with other changes
273 273 if recursive not in ['all', 'repos', 'groups']:
274 274 break
275 275
276 276 return updates
277 277
278 278 def update(self, repo_group, repo_group_args):
279 279 try:
280 280 repo_group = db.RepoGroup.guess_instance(repo_group)
281 281 old_path = repo_group.full_path
282 282
283 283 # change properties
284 284 if 'group_description' in repo_group_args:
285 285 repo_group.group_description = repo_group_args['group_description']
286 286 if 'parent_group_id' in repo_group_args:
287 repo_group.parent_group_id = repo_group_args['parent_group_id']
288
289 if 'parent_group_id' in repo_group_args:
290 287 assert repo_group_args['parent_group_id'] != '-1', repo_group_args # RepoGroupForm should have converted to None
291 288 repo_group.parent_group = db.RepoGroup.get(repo_group_args['parent_group_id'])
292 289 if 'group_name' in repo_group_args:
293 290 group_name = repo_group_args['group_name']
294 291 if kallithea.lib.utils2.repo_name_slug(group_name) != group_name:
295 292 raise Exception('invalid repo group name %s' % group_name)
296 293 repo_group.group_name = repo_group.get_new_name(group_name)
297 294 new_path = repo_group.full_path
298 295 meta.Session().add(repo_group)
299 296
300 297 # iterate over all members of this groups and do fixes
301 298 # if obj is a repoGroup also fix the name of the group according
302 299 # to the parent
303 300 # if obj is a Repo fix it's name
304 301 # this can be potentially heavy operation
305 302 for obj in repo_group.recursive_groups_and_repos():
306 303 # set the value from it's parent
307 304 if isinstance(obj, db.RepoGroup):
308 305 new_name = obj.get_new_name(obj.name)
309 306 log.debug('Fixing group %s to new name %s'
310 307 % (obj.group_name, new_name))
311 308 obj.group_name = new_name
312 309 elif isinstance(obj, db.Repository):
313 310 # we need to get all repositories from this new group and
314 311 # rename them accordingly to new group path
315 312 new_name = obj.get_new_name(obj.just_name)
316 313 log.debug('Fixing repo %s to new name %s'
317 314 % (obj.repo_name, new_name))
318 315 obj.repo_name = new_name
319 316
320 317 self._rename_group(old_path, new_path)
321 318
322 319 return repo_group
323 320 except Exception:
324 321 log.error(traceback.format_exc())
325 322 raise
326 323
327 324 def delete(self, repo_group, force_delete=False):
328 325 repo_group = db.RepoGroup.guess_instance(repo_group)
329 326 try:
330 327 meta.Session().delete(repo_group)
331 328 self._delete_group(repo_group, force_delete)
332 329 except Exception:
333 330 log.error('Error removing repo_group %s', repo_group)
334 331 raise
335 332
336 333 def add_permission(self, repo_group, obj, obj_type, perm, recursive):
337 334 repo_group = db.RepoGroup.guess_instance(repo_group)
338 335 perm = db.Permission.guess_instance(perm)
339 336
340 337 for el in repo_group.recursive_groups_and_repos():
341 338 # iterated obj is an instance of a repos group or repository in
342 339 # that group, recursive option can be: none, repos, groups, all
343 340 if recursive == 'all':
344 341 pass
345 342 elif recursive == 'repos':
346 343 # skip groups, other than this one
347 344 if isinstance(el, db.RepoGroup) and not el == repo_group:
348 345 continue
349 346 elif recursive == 'groups':
350 347 # skip repos
351 348 if isinstance(el, db.Repository):
352 349 continue
353 350 else: # recursive == 'none': # DEFAULT don't apply to iterated objects
354 351 el = repo_group
355 352 # also we do a break at the end of this loop.
356 353
357 354 if isinstance(el, db.RepoGroup):
358 355 if obj_type == 'user':
359 356 RepoGroupModel().grant_user_permission(el, user=obj, perm=perm)
360 357 elif obj_type == 'user_group':
361 358 RepoGroupModel().grant_user_group_permission(el, group_name=obj, perm=perm)
362 359 else:
363 360 raise Exception('undefined object type %s' % obj_type)
364 361 elif isinstance(el, db.Repository):
365 362 # for repos we need to hotfix the name of permission
366 363 _perm = perm.permission_name.replace('group.', 'repository.')
367 364 if obj_type == 'user':
368 365 repo.RepoModel().grant_user_permission(el, user=obj, perm=_perm)
369 366 elif obj_type == 'user_group':
370 367 repo.RepoModel().grant_user_group_permission(el, group_name=obj, perm=_perm)
371 368 else:
372 369 raise Exception('undefined object type %s' % obj_type)
373 370 else:
374 371 raise Exception('el should be instance of Repository or '
375 372 'RepositoryGroup got %s instead' % type(el))
376 373
377 374 # if it's not recursive call for all,repos,groups
378 375 # break the loop and don't proceed with other changes
379 376 if recursive not in ['all', 'repos', 'groups']:
380 377 break
381 378
382 379 def delete_permission(self, repo_group, obj, obj_type, recursive):
383 380 """
384 381 Revokes permission for repo_group for given obj(user or users_group),
385 382 obj_type can be user or user group
386 383
387 384 :param repo_group:
388 385 :param obj: user or user group id
389 386 :param obj_type: user or user group type
390 387 :param recursive: recurse to all children of group
391 388 """
392 389 repo_group = db.RepoGroup.guess_instance(repo_group)
393 390
394 391 for el in repo_group.recursive_groups_and_repos():
395 392 # iterated obj is an instance of a repos group or repository in
396 393 # that group, recursive option can be: none, repos, groups, all
397 394 if recursive == 'all':
398 395 pass
399 396 elif recursive == 'repos':
400 397 # skip groups, other than this one
401 398 if isinstance(el, db.RepoGroup) and not el == repo_group:
402 399 continue
403 400 elif recursive == 'groups':
404 401 # skip repos
405 402 if isinstance(el, db.Repository):
406 403 continue
407 404 else: # recursive == 'none': # DEFAULT don't apply to iterated objects
408 405 el = repo_group
409 406 # also we do a break at the end of this loop.
410 407
411 408 if isinstance(el, db.RepoGroup):
412 409 if obj_type == 'user':
413 410 RepoGroupModel().revoke_user_permission(el, user=obj)
414 411 elif obj_type == 'user_group':
415 412 RepoGroupModel().revoke_user_group_permission(el, group_name=obj)
416 413 else:
417 414 raise Exception('undefined object type %s' % obj_type)
418 415 elif isinstance(el, db.Repository):
419 416 if obj_type == 'user':
420 417 repo.RepoModel().revoke_user_permission(el, user=obj)
421 418 elif obj_type == 'user_group':
422 419 repo.RepoModel().revoke_user_group_permission(el, group_name=obj)
423 420 else:
424 421 raise Exception('undefined object type %s' % obj_type)
425 422 else:
426 423 raise Exception('el should be instance of Repository or '
427 424 'RepositoryGroup got %s instead' % type(el))
428 425
429 426 # if it's not recursive call for all,repos,groups
430 427 # break the loop and don't proceed with other changes
431 428 if recursive not in ['all', 'repos', 'groups']:
432 429 break
433 430
434 431 def grant_user_permission(self, repo_group, user, perm):
435 432 """
436 433 Grant permission for user on given repository group, or update
437 434 existing one if found
438 435
439 436 :param repo_group: Instance of RepoGroup, repositories_group_id,
440 437 or repositories_group name
441 438 :param user: Instance of User, user_id or username
442 439 :param perm: Instance of Permission, or permission_name
443 440 """
444 441
445 442 repo_group = db.RepoGroup.guess_instance(repo_group)
446 443 user = db.User.guess_instance(user)
447 444 permission = db.Permission.guess_instance(perm)
448 445
449 446 # check if we have that permission already
450 447 obj = db.UserRepoGroupToPerm.query() \
451 448 .filter(db.UserRepoGroupToPerm.user == user) \
452 449 .filter(db.UserRepoGroupToPerm.group == repo_group) \
453 450 .scalar()
454 451 if obj is None:
455 452 # create new !
456 453 obj = db.UserRepoGroupToPerm()
457 454 meta.Session().add(obj)
458 455 obj.group = repo_group
459 456 obj.user = user
460 457 obj.permission = permission
461 458 log.debug('Granted perm %s to %s on %s', perm, user, repo_group)
462 459 return obj
463 460
464 461 def revoke_user_permission(self, repo_group, user):
465 462 """
466 463 Revoke permission for user on given repository group
467 464
468 465 :param repo_group: Instance of RepoGroup, repositories_group_id,
469 466 or repositories_group name
470 467 :param user: Instance of User, user_id or username
471 468 """
472 469
473 470 repo_group = db.RepoGroup.guess_instance(repo_group)
474 471 user = db.User.guess_instance(user)
475 472
476 473 obj = db.UserRepoGroupToPerm.query() \
477 474 .filter(db.UserRepoGroupToPerm.user == user) \
478 475 .filter(db.UserRepoGroupToPerm.group == repo_group) \
479 476 .scalar()
480 477 if obj is not None:
481 478 meta.Session().delete(obj)
482 479 log.debug('Revoked perm on %s on %s', repo_group, user)
483 480
484 481 def grant_user_group_permission(self, repo_group, group_name, perm):
485 482 """
486 483 Grant permission for user group on given repository group, or update
487 484 existing one if found
488 485
489 486 :param repo_group: Instance of RepoGroup, repositories_group_id,
490 487 or repositories_group name
491 488 :param group_name: Instance of UserGroup, users_group_id,
492 489 or user group name
493 490 :param perm: Instance of Permission, or permission_name
494 491 """
495 492 repo_group = db.RepoGroup.guess_instance(repo_group)
496 493 group_name = db.UserGroup.guess_instance(group_name)
497 494 permission = db.Permission.guess_instance(perm)
498 495
499 496 # check if we have that permission already
500 497 obj = db.UserGroupRepoGroupToPerm.query() \
501 498 .filter(db.UserGroupRepoGroupToPerm.group == repo_group) \
502 499 .filter(db.UserGroupRepoGroupToPerm.users_group == group_name) \
503 500 .scalar()
504 501
505 502 if obj is None:
506 503 # create new
507 504 obj = db.UserGroupRepoGroupToPerm()
508 505 meta.Session().add(obj)
509 506
510 507 obj.group = repo_group
511 508 obj.users_group = group_name
512 509 obj.permission = permission
513 510 log.debug('Granted perm %s to %s on %s', perm, group_name, repo_group)
514 511 return obj
515 512
516 513 def revoke_user_group_permission(self, repo_group, group_name):
517 514 """
518 515 Revoke permission for user group on given repository group
519 516
520 517 :param repo_group: Instance of RepoGroup, repositories_group_id,
521 518 or repositories_group name
522 519 :param group_name: Instance of UserGroup, users_group_id,
523 520 or user group name
524 521 """
525 522 repo_group = db.RepoGroup.guess_instance(repo_group)
526 523 group_name = db.UserGroup.guess_instance(group_name)
527 524
528 525 obj = db.UserGroupRepoGroupToPerm.query() \
529 526 .filter(db.UserGroupRepoGroupToPerm.group == repo_group) \
530 527 .filter(db.UserGroupRepoGroupToPerm.users_group == group_name) \
531 528 .scalar()
532 529 if obj is not None:
533 530 meta.Session().delete(obj)
534 531 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