##// END OF EJS Templates
repo group: always update fullpath group_name when changing parent...
Mads Kiilerich -
r8732:03d51a2a stable
parent child Browse files
Show More
@@ -1,531 +1,532 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 287 assert repo_group_args['parent_group_id'] != '-1', repo_group_args # RepoGroupForm should have converted to None
288 288 repo_group.parent_group = db.RepoGroup.get(repo_group_args['parent_group_id'])
289 repo_group.group_name = repo_group.get_new_name(repo_group.name)
289 290 if 'group_name' in repo_group_args:
290 291 group_name = repo_group_args['group_name']
291 292 if kallithea.lib.utils2.repo_name_slug(group_name) != group_name:
292 293 raise Exception('invalid repo group name %s' % group_name)
293 294 repo_group.group_name = repo_group.get_new_name(group_name)
294 295 new_path = repo_group.full_path
295 296 meta.Session().add(repo_group)
296 297
297 298 # iterate over all members of this groups and do fixes
298 299 # if obj is a repoGroup also fix the name of the group according
299 300 # to the parent
300 301 # if obj is a Repo fix it's name
301 302 # this can be potentially heavy operation
302 303 for obj in repo_group.recursive_groups_and_repos():
303 304 # set the value from it's parent
304 305 if isinstance(obj, db.RepoGroup):
305 306 new_name = obj.get_new_name(obj.name)
306 307 log.debug('Fixing group %s to new name %s'
307 308 % (obj.group_name, new_name))
308 309 obj.group_name = new_name
309 310 elif isinstance(obj, db.Repository):
310 311 # we need to get all repositories from this new group and
311 312 # rename them accordingly to new group path
312 313 new_name = obj.get_new_name(obj.just_name)
313 314 log.debug('Fixing repo %s to new name %s'
314 315 % (obj.repo_name, new_name))
315 316 obj.repo_name = new_name
316 317
317 318 self._rename_group(old_path, new_path)
318 319
319 320 return repo_group
320 321 except Exception:
321 322 log.error(traceback.format_exc())
322 323 raise
323 324
324 325 def delete(self, repo_group, force_delete=False):
325 326 repo_group = db.RepoGroup.guess_instance(repo_group)
326 327 try:
327 328 meta.Session().delete(repo_group)
328 329 self._delete_group(repo_group, force_delete)
329 330 except Exception:
330 331 log.error('Error removing repo_group %s', repo_group)
331 332 raise
332 333
333 334 def add_permission(self, repo_group, obj, obj_type, perm, recursive):
334 335 repo_group = db.RepoGroup.guess_instance(repo_group)
335 336 perm = db.Permission.guess_instance(perm)
336 337
337 338 for el in repo_group.recursive_groups_and_repos():
338 339 # iterated obj is an instance of a repos group or repository in
339 340 # that group, recursive option can be: none, repos, groups, all
340 341 if recursive == 'all':
341 342 pass
342 343 elif recursive == 'repos':
343 344 # skip groups, other than this one
344 345 if isinstance(el, db.RepoGroup) and not el == repo_group:
345 346 continue
346 347 elif recursive == 'groups':
347 348 # skip repos
348 349 if isinstance(el, db.Repository):
349 350 continue
350 351 else: # recursive == 'none': # DEFAULT don't apply to iterated objects
351 352 el = repo_group
352 353 # also we do a break at the end of this loop.
353 354
354 355 if isinstance(el, db.RepoGroup):
355 356 if obj_type == 'user':
356 357 RepoGroupModel().grant_user_permission(el, user=obj, perm=perm)
357 358 elif obj_type == 'user_group':
358 359 RepoGroupModel().grant_user_group_permission(el, group_name=obj, perm=perm)
359 360 else:
360 361 raise Exception('undefined object type %s' % obj_type)
361 362 elif isinstance(el, db.Repository):
362 363 # for repos we need to hotfix the name of permission
363 364 _perm = perm.permission_name.replace('group.', 'repository.')
364 365 if obj_type == 'user':
365 366 repo.RepoModel().grant_user_permission(el, user=obj, perm=_perm)
366 367 elif obj_type == 'user_group':
367 368 repo.RepoModel().grant_user_group_permission(el, group_name=obj, perm=_perm)
368 369 else:
369 370 raise Exception('undefined object type %s' % obj_type)
370 371 else:
371 372 raise Exception('el should be instance of Repository or '
372 373 'RepositoryGroup got %s instead' % type(el))
373 374
374 375 # if it's not recursive call for all,repos,groups
375 376 # break the loop and don't proceed with other changes
376 377 if recursive not in ['all', 'repos', 'groups']:
377 378 break
378 379
379 380 def delete_permission(self, repo_group, obj, obj_type, recursive):
380 381 """
381 382 Revokes permission for repo_group for given obj(user or users_group),
382 383 obj_type can be user or user group
383 384
384 385 :param repo_group:
385 386 :param obj: user or user group id
386 387 :param obj_type: user or user group type
387 388 :param recursive: recurse to all children of group
388 389 """
389 390 repo_group = db.RepoGroup.guess_instance(repo_group)
390 391
391 392 for el in repo_group.recursive_groups_and_repos():
392 393 # iterated obj is an instance of a repos group or repository in
393 394 # that group, recursive option can be: none, repos, groups, all
394 395 if recursive == 'all':
395 396 pass
396 397 elif recursive == 'repos':
397 398 # skip groups, other than this one
398 399 if isinstance(el, db.RepoGroup) and not el == repo_group:
399 400 continue
400 401 elif recursive == 'groups':
401 402 # skip repos
402 403 if isinstance(el, db.Repository):
403 404 continue
404 405 else: # recursive == 'none': # DEFAULT don't apply to iterated objects
405 406 el = repo_group
406 407 # also we do a break at the end of this loop.
407 408
408 409 if isinstance(el, db.RepoGroup):
409 410 if obj_type == 'user':
410 411 RepoGroupModel().revoke_user_permission(el, user=obj)
411 412 elif obj_type == 'user_group':
412 413 RepoGroupModel().revoke_user_group_permission(el, group_name=obj)
413 414 else:
414 415 raise Exception('undefined object type %s' % obj_type)
415 416 elif isinstance(el, db.Repository):
416 417 if obj_type == 'user':
417 418 repo.RepoModel().revoke_user_permission(el, user=obj)
418 419 elif obj_type == 'user_group':
419 420 repo.RepoModel().revoke_user_group_permission(el, group_name=obj)
420 421 else:
421 422 raise Exception('undefined object type %s' % obj_type)
422 423 else:
423 424 raise Exception('el should be instance of Repository or '
424 425 'RepositoryGroup got %s instead' % type(el))
425 426
426 427 # if it's not recursive call for all,repos,groups
427 428 # break the loop and don't proceed with other changes
428 429 if recursive not in ['all', 'repos', 'groups']:
429 430 break
430 431
431 432 def grant_user_permission(self, repo_group, user, perm):
432 433 """
433 434 Grant permission for user on given repository group, or update
434 435 existing one if found
435 436
436 437 :param repo_group: Instance of RepoGroup, repositories_group_id,
437 438 or repositories_group name
438 439 :param user: Instance of User, user_id or username
439 440 :param perm: Instance of Permission, or permission_name
440 441 """
441 442
442 443 repo_group = db.RepoGroup.guess_instance(repo_group)
443 444 user = db.User.guess_instance(user)
444 445 permission = db.Permission.guess_instance(perm)
445 446
446 447 # check if we have that permission already
447 448 obj = db.UserRepoGroupToPerm.query() \
448 449 .filter(db.UserRepoGroupToPerm.user == user) \
449 450 .filter(db.UserRepoGroupToPerm.group == repo_group) \
450 451 .scalar()
451 452 if obj is None:
452 453 # create new !
453 454 obj = db.UserRepoGroupToPerm()
454 455 meta.Session().add(obj)
455 456 obj.group = repo_group
456 457 obj.user = user
457 458 obj.permission = permission
458 459 log.debug('Granted perm %s to %s on %s', perm, user, repo_group)
459 460 return obj
460 461
461 462 def revoke_user_permission(self, repo_group, user):
462 463 """
463 464 Revoke permission for user on given repository group
464 465
465 466 :param repo_group: Instance of RepoGroup, repositories_group_id,
466 467 or repositories_group name
467 468 :param user: Instance of User, user_id or username
468 469 """
469 470
470 471 repo_group = db.RepoGroup.guess_instance(repo_group)
471 472 user = db.User.guess_instance(user)
472 473
473 474 obj = db.UserRepoGroupToPerm.query() \
474 475 .filter(db.UserRepoGroupToPerm.user == user) \
475 476 .filter(db.UserRepoGroupToPerm.group == repo_group) \
476 477 .scalar()
477 478 if obj is not None:
478 479 meta.Session().delete(obj)
479 480 log.debug('Revoked perm on %s on %s', repo_group, user)
480 481
481 482 def grant_user_group_permission(self, repo_group, group_name, perm):
482 483 """
483 484 Grant permission for user group on given repository group, or update
484 485 existing one if found
485 486
486 487 :param repo_group: Instance of RepoGroup, repositories_group_id,
487 488 or repositories_group name
488 489 :param group_name: Instance of UserGroup, users_group_id,
489 490 or user group name
490 491 :param perm: Instance of Permission, or permission_name
491 492 """
492 493 repo_group = db.RepoGroup.guess_instance(repo_group)
493 494 group_name = db.UserGroup.guess_instance(group_name)
494 495 permission = db.Permission.guess_instance(perm)
495 496
496 497 # check if we have that permission already
497 498 obj = db.UserGroupRepoGroupToPerm.query() \
498 499 .filter(db.UserGroupRepoGroupToPerm.group == repo_group) \
499 500 .filter(db.UserGroupRepoGroupToPerm.users_group == group_name) \
500 501 .scalar()
501 502
502 503 if obj is None:
503 504 # create new
504 505 obj = db.UserGroupRepoGroupToPerm()
505 506 meta.Session().add(obj)
506 507
507 508 obj.group = repo_group
508 509 obj.users_group = group_name
509 510 obj.permission = permission
510 511 log.debug('Granted perm %s to %s on %s', perm, group_name, repo_group)
511 512 return obj
512 513
513 514 def revoke_user_group_permission(self, repo_group, group_name):
514 515 """
515 516 Revoke permission for user group on given repository group
516 517
517 518 :param repo_group: Instance of RepoGroup, repositories_group_id,
518 519 or repositories_group name
519 520 :param group_name: Instance of UserGroup, users_group_id,
520 521 or user group name
521 522 """
522 523 repo_group = db.RepoGroup.guess_instance(repo_group)
523 524 group_name = db.UserGroup.guess_instance(group_name)
524 525
525 526 obj = db.UserGroupRepoGroupToPerm.query() \
526 527 .filter(db.UserGroupRepoGroupToPerm.group == repo_group) \
527 528 .filter(db.UserGroupRepoGroupToPerm.users_group == group_name) \
528 529 .scalar()
529 530 if obj is not None:
530 531 meta.Session().delete(obj)
531 532 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