##// END OF EJS Templates
user group: sort lists of current and available members by username...
user group: sort lists of current and available members by username It was hard to navigate lists with 200 users in "random" (user_id?) order.

File last commit:

r3565:a8f2d78d beta
r3624:4dddb7ee beta
Show More
repos_groups.py
392 lines | 16.2 KiB | text/x-python | PythonLexer
2012 copyrights
r1824 # -*- coding: utf-8 -*-
"""
rhodecode.controllers.admin.repos_groups
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mads Kiilerich
"Users groups" is grammatically incorrect English - rename to "user groups"...
r3410 Repository groups controller for RhodeCode
2012 copyrights
r1824
:created_on: Mar 23, 2010
:author: marcink
:copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
:license: GPLv3, see COPYING for more details.
"""
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
changes for #56
r1171 import logging
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 import traceback
import formencode
from formencode import htmlfill
changes for #56
r1171
#227 Initial version of repository groups permissions system...
r1982 from pylons import request, tmpl_context as c, url
Group management delegation:...
r3222 from pylons.controllers.util import abort, redirect
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 from pylons.i18n.translation import _
changes for #56
r1171
Added friendly message about removing a group that still contains subgroups....
r1543 from sqlalchemy.exc import IntegrityError
lightweight dashboard fix for repos group
r2945 import rhodecode
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 from rhodecode.lib import helpers as h
lightweight dashboard fix for repos group
r2945 from rhodecode.lib.ext_json import json
#227 Initial version of repository groups permissions system...
r1982 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
Group management delegation:...
r3222 HasReposGroupPermissionAnyDecorator, HasReposGroupPermissionAll,\
HasPermissionAll
changes for #56
r1171 from rhodecode.lib.base import BaseController, render
lightweight dashboard fix for repos group
r2945 from rhodecode.model.db import RepoGroup, Repository
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 from rhodecode.model.repos_group import ReposGroupModel
from rhodecode.model.forms import ReposGroupForm
another major refactoring with session management
r1734 from rhodecode.model.meta import Session
#227 Initial version of repository groups permissions system...
r1982 from rhodecode.model.repo import RepoModel
Fixed bug in repos group discovery, when inner folder of bare git repos were detected as a group
r2497 from webob.exc import HTTPInternalServerError, HTTPNotFound
Group management delegation:...
r3222 from rhodecode.lib.utils2 import str2bool, safe_int
lightweight dashboard fix for repos group
r2945 from sqlalchemy.sql.expression import func
Group management delegation:...
r3222 from rhodecode.model.scm import GroupList
changes for #56
r1171
log = logging.getLogger(__name__)
PEP8ify - controllers
r1245
changes for #56
r1171 class ReposGroupsController(BaseController):
"""REST Controller styled on the Atom Publishing Protocol"""
# To properly map this controller, ensure your config/routing.py
# file has a resource setup:
# map.resource('repos_group', 'repos_groups')
#47 implemented basic edition of groups
r1347 @LoginRequired()
def __before__(self):
super(ReposGroupsController, self).__before__()
Group management delegation:...
r3222 def __load_defaults(self, allow_empty_group=False, exclude_group_ids=[]):
if HasPermissionAll('hg.admin')('group edit'):
#we're global admin, we're ok and we can create TOP level groups
allow_empty_group = True
#override the choices for this form, we need to filter choices
#and display only those we have ADMIN right
groups_with_admin_rights = GroupList(RepoGroup.query().all(),
perm_set=['group.admin'])
c.repo_groups = RepoGroup.groups_choices(groups=groups_with_admin_rights,
show_empty_group=allow_empty_group)
# exclude filtered ids
c.repo_groups = filter(lambda x: x[0] not in exclude_group_ids,
c.repo_groups)
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
#227 Initial version of repository groups permissions system...
r1982 repo_model = RepoModel()
c.users_array = repo_model.get_users_js()
c.users_groups_array = repo_model.get_users_groups_js()
#47 implemented basic edition of groups
r1347 def __load_data(self, group_id):
"""
Load defaults settings for edit, and update
:param group_id:
"""
use get_or_404 where possible
r2496 repo_group = RepoGroup.get_or_404(group_id)
#47 added editing of groups, and moving them between. Added check constraint for groups...
r1349 data = repo_group.get_dict()
implements #226 repo groups available by path...
r1538 data['group_name'] = repo_group.name
#227 Initial version of repository groups permissions system...
r1982 # fill repository users
for p in repo_group.repo_group_to_perm:
data.update({'u_perm_%s' % p.user.username:
p.permission.permission_name})
# fill repository groups
for p in repo_group.users_group_to_perm:
data.update({'g_perm_%s' % p.users_group.users_group_name:
p.permission.permission_name})
#47 added editing of groups, and moving them between. Added check constraint for groups...
r1349 return data
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345
forbid removing yourself as beeing an admin of a group
r3332 def _revoke_perms_on_yourself(self, form_result):
_up = filter(lambda u: c.rhodecode_user.username == u[0],
form_result['perms_updates'])
_new = filter(lambda u: c.rhodecode_user.username == u[0],
form_result['perms_new'])
if _new and _new[0][1] != 'group.admin' or _up and _up[0][1] != 'group.admin':
return True
return False
changes for #56
r1171 def index(self, format='html'):
"""GET /repos_groups: All items in the collection"""
# url('repos_groups')
Group management delegation:...
r3222 group_iter = GroupList(RepoGroup.query().all(), perm_set=['group.admin'])
added validation to repo groups to check for conflicting repository name fixes #337
r1898 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
Group management delegation:...
r3222 c.groups = sorted(group_iter, key=sk)
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 return render('admin/repos_groups/repos_groups_show.html')
changes for #56
r1171 def create(self):
"""POST /repos_groups: Create a new item"""
# url('repos_groups')
Group management delegation:...
r3222
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 self.__load_defaults()
Group management delegation:...
r3222
# permissions for can create group based on parent_id are checked
# here in the Form
repos_group_form = ReposGroupForm(available_groups=
map(lambda k: unicode(k[0]), c.repo_groups))()
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 try:
form_result = repos_group_form.to_python(dict(request.POST))
#227 Initial version of repository groups permissions system...
r1982 ReposGroupModel().create(
group_name=form_result['group_name'],
group_description=form_result['group_description'],
Group management delegation:...
r3222 parent=form_result['group_parent_id'],
owner=self.rhodecode_user.user_id
#227 Initial version of repository groups permissions system...
r1982 )
sqlalchemy sessions cleanup in admin...
r2662 Session().commit()
Mads Kiilerich
consistently capitalize initial letter in flash messages
r3565 h.flash(_('Created repos group %s') \
#47 implemented basic edition of groups
r1347 % form_result['group_name'], category='success')
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 #TODO: in futureaction_logger(, '', '', '', self.sa)
except formencode.Invalid, errors:
return htmlfill.render(
render('admin/repos_groups/repos_groups_add.html'),
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8")
except Exception:
log.error(traceback.format_exc())
Mads Kiilerich
consistently capitalize initial letter in flash messages
r3565 h.flash(_('Error occurred during creation of repos group %s') \
#47 implemented basic edition of groups
r1347 % request.POST.get('group_name'), category='error')
Group management delegation:...
r3222 parent_group_id = form_result['group_parent_id']
#TODO: maybe we should get back to the main view, not the admin one
return redirect(url('repos_groups', parent_group=parent_group_id))
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345
changes for #56
r1171 def new(self, format='html'):
"""GET /repos_groups/new: Form to create a new item"""
# url('new_repos_group')
Group management delegation:...
r3222 if HasPermissionAll('hg.admin')('group create'):
#we're global admin, we're ok and we can create TOP level groups
pass
else:
# we pass in parent group into creation form, thus we know
# what would be the group, we can check perms here !
group_id = safe_int(request.GET.get('parent_group'))
group = RepoGroup.get(group_id) if group_id else None
group_name = group.group_name if group else None
if HasReposGroupPermissionAll('group.admin')(group_name, 'group create'):
pass
else:
return abort(403)
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
r1345 self.__load_defaults()
return render('admin/repos_groups/repos_groups_add.html')
changes for #56
r1171
Group management delegation:...
r3222 @HasReposGroupPermissionAnyDecorator('group.admin')
def update(self, group_name):
"""PUT /repos_groups/group_name: Update an existing item"""
changes for #56
r1171 # Forms posted to this method should contain a hidden field:
# <input type="hidden" name="_method" value="PUT" />
# Or using helpers:
Group management delegation:...
r3222 # h.form(url('repos_group', group_name=GROUP_NAME),
changes for #56
r1171 # method='put')
Group management delegation:...
r3222 # url('repos_group', group_name=GROUP_NAME)
changes for #56
r1171
Group management delegation:...
r3222 c.repos_group = ReposGroupModel()._get_repos_group(group_name)
if HasPermissionAll('hg.admin')('group edit'):
#we're global admin, we're ok and we can create TOP level groups
allow_empty_group = True
elif not c.repos_group.parent_group:
allow_empty_group = True
else:
allow_empty_group = False
self.__load_defaults(allow_empty_group=allow_empty_group,
exclude_group_ids=[c.repos_group.group_id])
#47 implemented basic edition of groups
r1347
#227 Initial version of repository groups permissions system...
r1982 repos_group_form = ReposGroupForm(
edit=True,
old_data=c.repos_group.get_dict(),
Group management delegation:...
r3222 available_groups=c.repo_groups_choices,
can_create_in_root=allow_empty_group,
#227 Initial version of repository groups permissions system...
r1982 )()
#47 implemented basic edition of groups
r1347 try:
form_result = repos_group_form.to_python(dict(request.POST))
forbid removing yourself as beeing an admin of a group
r3332 if not c.rhodecode_user.is_admin:
if self._revoke_perms_on_yourself(form_result):
msg = _('Cannot revoke permission for yourself as admin')
h.flash(msg, category='warning')
raise Exception('revoke admin permission on self')
Group management delegation:...
r3222 new_gr = ReposGroupModel().update(group_name, form_result)
sqlalchemy sessions cleanup in admin...
r2662 Session().commit()
Mads Kiilerich
consistently capitalize initial letter in flash messages
r3565 h.flash(_('Updated repos group %s') \
#47 implemented basic edition of groups
r1347 % form_result['group_name'], category='success')
Group management delegation:...
r3222 # we now have new name !
group_name = new_gr.group_name
Permissions on group can be set in recursive mode setting defined permission to all children...
r2820 #TODO: in future action_logger(, '', '', '', self.sa)
#47 implemented basic edition of groups
r1347 except formencode.Invalid, errors:
return htmlfill.render(
render('admin/repos_groups/repos_groups_edit.html'),
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8")
except Exception:
log.error(traceback.format_exc())
Mads Kiilerich
consistently capitalize initial letter in flash messages
r3565 h.flash(_('Error occurred during update of repos group %s') \
#47 implemented basic edition of groups
r1347 % request.POST.get('group_name'), category='error')
Group management delegation:...
r3222 return redirect(url('edit_repos_group', group_name=group_name))
#47 implemented basic edition of groups
r1347
Group management delegation:...
r3222 @HasReposGroupPermissionAnyDecorator('group.admin')
def delete(self, group_name):
"""DELETE /repos_groups/group_name: Delete an existing item"""
changes for #56
r1171 # Forms posted to this method should contain a hidden field:
# <input type="hidden" name="_method" value="DELETE" />
# Or using helpers:
Group management delegation:...
r3222 # h.form(url('repos_group', group_name=GROUP_NAME),
changes for #56
r1171 # method='delete')
Group management delegation:...
r3222 # url('repos_group', group_name=GROUP_NAME)
changes for #56
r1171
Group management delegation:...
r3222 gr = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
#47 implemented deleting of empty groups. Fixed problem with full paths on nested groups
r1346 repos = gr.repositories.all()
if repos:
h.flash(_('This group contains %s repositores and cannot be '
better detection of deleting groups with subgroups inside....
r3458 'deleted') % len(repos), category='warning')
return redirect(url('repos_groups'))
children = gr.children.all()
if children:
h.flash(_('This group contains %s subgroups and cannot be deleted'
% (len(children))), category='warning')
#47 implemented deleting of empty groups. Fixed problem with full paths on nested groups
r1346 return redirect(url('repos_groups'))
try:
Group management delegation:...
r3222 ReposGroupModel().delete(group_name)
sqlalchemy sessions cleanup in admin...
r2662 Session().commit()
Mads Kiilerich
consistently capitalize initial letter in flash messages
r3565 h.flash(_('Removed repos group %s') % group_name,
Recursive set locking on all children of a group.
r2749 category='success')
removed obsolete sort code
r1482 #TODO: in future action_logger(, '', '', '', self.sa)
#47 implemented deleting of empty groups. Fixed problem with full paths on nested groups
r1346 except Exception:
log.error(traceback.format_exc())
Mads Kiilerich
consistently capitalize initial letter in flash messages
r3565 h.flash(_('Error occurred during deletion of repos '
better detection of deleting groups with subgroups inside....
r3458 'group %s') % group_name, category='error')
#47 implemented deleting of empty groups. Fixed problem with full paths on nested groups
r1346
return redirect(url('repos_groups'))
#227 Initial version of repository groups permissions system...
r1982 @HasReposGroupPermissionAnyDecorator('group.admin')
def delete_repos_group_user_perm(self, group_name):
"""
Mads Kiilerich
"Users groups" is grammatically incorrect English - rename to "user groups"...
r3410 DELETE an existing repository group permission user
#227 Initial version of repository groups permissions system...
r1982
:param group_name:
"""
try:
forbid removing yourself as beeing an admin of a group
r3332 if not c.rhodecode_user.is_admin:
if c.rhodecode_user.user_id == safe_int(request.POST['user_id']):
msg = _('Cannot revoke permission for yourself as admin')
h.flash(msg, category='warning')
raise Exception('revoke admin permission on self')
Permissions on group can be set in recursive mode setting defined permission to all children...
r2820 recursive = str2bool(request.POST.get('recursive', False))
ReposGroupModel().delete_permission(
repos_group=group_name, obj=request.POST['user_id'],
obj_type='user', recursive=recursive
#227 Initial version of repository groups permissions system...
r1982 )
sqlalchemy sessions cleanup in admin...
r2662 Session().commit()
#227 Initial version of repository groups permissions system...
r1982 except Exception:
log.error(traceback.format_exc())
h.flash(_('An error occurred during deletion of group user'),
category='error')
raise HTTPInternalServerError()
@HasReposGroupPermissionAnyDecorator('group.admin')
def delete_repos_group_users_group_perm(self, group_name):
"""
Mads Kiilerich
"Users groups" is grammatically incorrect English - rename to "user groups"...
r3410 DELETE an existing repository group permission user group
#227 Initial version of repository groups permissions system...
r1982
:param group_name:
"""
try:
Permissions on group can be set in recursive mode setting defined permission to all children...
r2820 recursive = str2bool(request.POST.get('recursive', False))
ReposGroupModel().delete_permission(
repos_group=group_name, obj=request.POST['users_group_id'],
obj_type='users_group', recursive=recursive
#227 Initial version of repository groups permissions system...
r1982 )
sqlalchemy sessions cleanup in admin...
r2662 Session().commit()
#227 Initial version of repository groups permissions system...
r1982 except Exception:
log.error(traceback.format_exc())
h.flash(_('An error occurred during deletion of group'
Mads Kiilerich
"Users groups" is grammatically incorrect English - rename to "user groups"...
r3410 ' user groups'),
#227 Initial version of repository groups permissions system...
r1982 category='error')
raise HTTPInternalServerError()
implements #226 repo groups available by path...
r1538 def show_by_name(self, group_name):
fixed issue #370
r2055 """
This is a proxy that does a lookup group_name -> id, and shows
the group by id view instead
"""
group_name = group_name.rstrip('/')
Fixed bug in repos group discovery, when inner folder of bare git repos were detected as a group
r2497 id_ = RepoGroup.get_by_group_name(group_name)
if id_:
return self.show(id_.group_id)
raise HTTPNotFound
implements #226 repo groups available by path...
r1538
#227 Initial version of repository groups permissions system...
r1982 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
'group.admin')
Group management delegation:...
r3222 def show(self, group_name, format='html'):
"""GET /repos_groups/group_name: Show a specific item"""
# url('repos_group', group_name=GROUP_NAME)
changes for #56
r1171
Group management delegation:...
r3222 c.group = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
use get_or_404 where possible
r2496 c.group_repos = c.group.repositories.all()
Added repo group page showing what reposiories are inside a group
r1193
#overwrite our cached list with current filter
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 gr_filter = c.group_repos
c.repo_cnt = 0
#47 implemented basic gui for browsing repo groups
r1343
Wraps group listing with permissions check so they don't get displayed
r2831 groups = RepoGroup.query().order_by(RepoGroup.group_name)\
Group management delegation:...
r3222 .filter(RepoGroup.group_parent_id == c.group.group_id).all()
Wraps group listing with permissions check so they don't get displayed
r2831 c.groups = self.scm_model.get_repos_groups(groups)
lightweight dashboard fix for repos group
r2945
if c.visual.lightweight_dashboard is False:
fixed issue with displaying repos in groups view (without lightweight dashboard), added tests for this case
r3167 c.repos_list = self.scm_model.get_repos(all_repos=gr_filter)
lightweight dashboard fix for repos group
r2945 ## lightweight version of dashboard
else:
c.repos_list = Repository.query()\
Group management delegation:...
r3222 .filter(Repository.group_id == c.group.group_id)\
lightweight dashboard fix for repos group
r2945 .order_by(func.lower(Repository.repo_name))\
.all()
fixed issue with displaying repos in groups view (without lightweight dashboard), added tests for this case
r3167 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
admin=False)
#json used to render the grid
c.data = json.dumps(repos_data)
whitespace cleanup
r2973
Added repo group page showing what reposiories are inside a group
r1193 return render('admin/repos_groups/repos_groups.html')
Group management delegation:...
r3222 @HasReposGroupPermissionAnyDecorator('group.admin')
def edit(self, group_name, format='html'):
"""GET /repos_groups/group_name/edit: Form to edit an existing item"""
# url('edit_repos_group', group_name=GROUP_NAME)
#47 added editing of groups, and moving them between. Added check constraint for groups...
r1349
Group management delegation:...
r3222 c.repos_group = ReposGroupModel()._get_repos_group(group_name)
#we can only allow moving empty group if it's already a top-level
#group, ie has no parents, or we're admin
if HasPermissionAll('hg.admin')('group edit'):
#we're global admin, we're ok and we can create TOP level groups
allow_empty_group = True
elif not c.repos_group.parent_group:
allow_empty_group = True
else:
allow_empty_group = False
#47 implemented basic edition of groups
r1347
Group management delegation:...
r3222 self.__load_defaults(allow_empty_group=allow_empty_group,
exclude_group_ids=[c.repos_group.group_id])
defaults = self.__load_data(c.repos_group.group_id)
#47 added editing of groups, and moving them between. Added check constraint for groups...
r1349
#47 implemented basic edition of groups
r1347 return htmlfill.render(
render('admin/repos_groups/repos_groups_edit.html'),
defaults=defaults,
encoding="UTF-8",
force_defaults=False
)