user_groups.py
250 lines
| 9.6 KiB
| text/x-python
|
PythonLexer
r5608 | # Copyright (C) 2016-2024 RhodeCode GmbH | |||
r1980 | # | |||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU Affero General Public License, version 3 | ||||
# (only), as published by the Free Software Foundation. | ||||
# | ||||
# 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 Affero General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
# | ||||
# This program is dual-licensed. If you wish to learn more about the | ||||
# RhodeCode Enterprise Edition, including its added features, Support services, | ||||
# and proprietary license terms, please see https://rhodecode.com/licenses/ | ||||
import logging | ||||
r2068 | import formencode | |||
import formencode.htmlfill | ||||
r1980 | from pyramid.httpexceptions import HTTPFound | |||
r4610 | ||||
r2068 | from pyramid.response import Response | |||
from pyramid.renderers import render | ||||
r1980 | ||||
r2852 | from rhodecode import events | |||
r1980 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |||
from rhodecode.lib.auth import ( | ||||
r2068 | LoginRequired, NotAnonymous, CSRFRequired, HasPermissionAnyDecorator) | |||
from rhodecode.lib import helpers as h, audit_logger | ||||
r5065 | from rhodecode.lib.str_utils import safe_str | |||
r2068 | ||||
from rhodecode.model.forms import UserGroupForm | ||||
from rhodecode.model.permission import PermissionModel | ||||
r1998 | from rhodecode.model.db import ( | |||
r3624 | or_, count, User, UserGroup, UserGroupMember, in_filter_generator) | |||
r1980 | from rhodecode.model.meta import Session | |||
r2068 | from rhodecode.model.user_group import UserGroupModel | |||
Bartłomiej Wołyńczyk
|
r2727 | from rhodecode.model.db import true | ||
r1980 | ||||
log = logging.getLogger(__name__) | ||||
class AdminUserGroupsView(BaseAppView, DataGridAppView): | ||||
def load_default_context(self): | ||||
c = self._get_local_tmpl_context() | ||||
r2068 | PermissionModel().set_global_permission_choices( | |||
c, gettext_translator=self.request.translate) | ||||
r1980 | return c | |||
# permission check in data loading of | ||||
# `user_groups_list_data` via UserGroupList | ||||
r2001 | @LoginRequired() | |||
r1980 | @NotAnonymous() | |||
def user_groups_list(self): | ||||
c = self.load_default_context() | ||||
return self._get_template_context(c) | ||||
# permission check inside | ||||
r2001 | @LoginRequired() | |||
r1980 | @NotAnonymous() | |||
def user_groups_list_data(self): | ||||
r2308 | self.load_default_context() | |||
r1980 | column_map = { | |||
'active': 'users_group_active', | ||||
'description': 'user_group_description', | ||||
'members': 'members_total', | ||||
'owner': 'user_username', | ||||
'sync': 'group_data' | ||||
} | ||||
draw, start, limit = self._extract_chunk(self.request) | ||||
search_q, order_by, order_dir = self._extract_ordering( | ||||
self.request, column_map=column_map) | ||||
r2109 | _render = self.request.get_partial_renderer( | |||
r2313 | 'rhodecode:templates/data_table/_dt_elements.mako') | |||
r1980 | ||||
r2639 | def user_group_name(user_group_name): | |||
return _render("user_group_name", user_group_name) | ||||
r1980 | ||||
def user_group_actions(user_group_id, user_group_name): | ||||
return _render("user_group_actions", user_group_id, user_group_name) | ||||
def user_profile(username): | ||||
return _render('user_profile', username) | ||||
r4146 | _perms = ['usergroup.admin'] | |||
allowed_ids = [-1] + self._rhodecode_user.user_group_acl_ids_from_stack(_perms) | ||||
r1986 | ||||
user_groups_data_total_count = UserGroup.query()\ | ||||
r3624 | .filter(or_( | |||
# generate multiple IN to fix limitation problems | ||||
*in_filter_generator(UserGroup.users_group_id, allowed_ids) | ||||
))\ | ||||
r1986 | .count() | |||
r1980 | ||||
Bartłomiej Wołyńczyk
|
r2727 | user_groups_data_total_inactive_count = UserGroup.query()\ | ||
r3624 | .filter(or_( | |||
# generate multiple IN to fix limitation problems | ||||
*in_filter_generator(UserGroup.users_group_id, allowed_ids) | ||||
))\ | ||||
Bartłomiej Wołyńczyk
|
r2727 | .filter(UserGroup.users_group_active != true()).count() | ||
r1980 | member_count = count(UserGroupMember.user_id) | |||
base_q = Session.query( | ||||
UserGroup.users_group_name, | ||||
UserGroup.user_group_description, | ||||
UserGroup.users_group_active, | ||||
UserGroup.users_group_id, | ||||
UserGroup.group_data, | ||||
User, | ||||
member_count.label('member_count') | ||||
r3624 | ) \ | |||
.filter(or_( | ||||
# generate multiple IN to fix limitation problems | ||||
*in_filter_generator(UserGroup.users_group_id, allowed_ids) | ||||
)) \ | ||||
r3949 | .outerjoin(UserGroupMember, UserGroupMember.users_group_id == UserGroup.users_group_id) \ | |||
r3624 | .join(User, User.user_id == UserGroup.user_id) \ | |||
.group_by(UserGroup, User) | ||||
r1980 | ||||
Bartłomiej Wołyńczyk
|
r2727 | base_q_inactive = base_q.filter(UserGroup.users_group_active != true()) | ||
r1980 | if search_q: | |||
r5065 | like_expression = u'%{}%'.format(safe_str(search_q)) | |||
r1980 | base_q = base_q.filter(or_( | |||
UserGroup.users_group_name.ilike(like_expression), | ||||
)) | ||||
Bartłomiej Wołyńczyk
|
r2727 | base_q_inactive = base_q.filter(UserGroup.users_group_active != true()) | ||
r1980 | ||||
user_groups_data_total_filtered_count = base_q.count() | ||||
Bartłomiej Wołyńczyk
|
r2727 | user_groups_data_total_filtered_inactive_count = base_q_inactive.count() | ||
r1980 | ||||
r3624 | sort_defined = False | |||
r1980 | if order_by == 'members_total': | |||
sort_col = member_count | ||||
r3624 | sort_defined = True | |||
r1980 | elif order_by == 'user_username': | |||
sort_col = User.username | ||||
else: | ||||
sort_col = getattr(UserGroup, order_by, None) | ||||
r3624 | if sort_defined or sort_col: | |||
r1980 | if order_dir == 'asc': | |||
sort_col = sort_col.asc() | ||||
else: | ||||
sort_col = sort_col.desc() | ||||
base_q = base_q.order_by(sort_col) | ||||
base_q = base_q.offset(start).limit(limit) | ||||
# authenticated access to user groups | ||||
r1986 | auth_user_group_list = base_q.all() | |||
r1980 | ||||
user_groups_data = [] | ||||
for user_gr in auth_user_group_list: | ||||
r3624 | row = { | |||
r2639 | "users_group_name": user_group_name(user_gr.users_group_name), | |||
r1980 | "description": h.escape(user_gr.user_group_description), | |||
"members": user_gr.member_count, | ||||
# NOTE(marcink): because of advanced query we | ||||
# need to load it like that | ||||
r2672 | "sync": UserGroup._load_sync( | |||
UserGroup._load_group_data(user_gr.group_data)), | ||||
r1980 | "active": h.bool2icon(user_gr.users_group_active), | |||
"owner": user_profile(user_gr.User.username), | ||||
"action": user_group_actions( | ||||
user_gr.users_group_id, user_gr.users_group_name) | ||||
r3624 | } | |||
user_groups_data.append(row) | ||||
r1980 | ||||
data = ({ | ||||
'draw': draw, | ||||
'data': user_groups_data, | ||||
'recordsTotal': user_groups_data_total_count, | ||||
Bartłomiej Wołyńczyk
|
r2727 | 'recordsTotalInactive': user_groups_data_total_inactive_count, | ||
r1980 | 'recordsFiltered': user_groups_data_total_filtered_count, | |||
Bartłomiej Wołyńczyk
|
r2727 | 'recordsFilteredInactive': user_groups_data_total_filtered_inactive_count, | ||
r1980 | }) | |||
return data | ||||
@LoginRequired() | ||||
r2068 | @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') | |||
def user_groups_new(self): | ||||
r1998 | c = self.load_default_context() | |||
return self._get_template_context(c) | ||||
@LoginRequired() | ||||
r2068 | @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') | |||
@CSRFRequired() | ||||
def user_groups_create(self): | ||||
_ = self.request.translate | ||||
c = self.load_default_context() | ||||
r2351 | users_group_form = UserGroupForm(self.request.translate)() | |||
r2068 | ||||
user_group_name = self.request.POST.get('users_group_name') | ||||
try: | ||||
form_result = users_group_form.to_python(dict(self.request.POST)) | ||||
user_group = UserGroupModel().create( | ||||
name=form_result['users_group_name'], | ||||
description=form_result['user_group_description'], | ||||
owner=self._rhodecode_user.user_id, | ||||
active=form_result['users_group_active']) | ||||
Session().flush() | ||||
creation_data = user_group.get_api_data() | ||||
user_group_name = form_result['users_group_name'] | ||||
audit_logger.store_web( | ||||
'user_group.create', action_data={'data': creation_data}, | ||||
user=self._rhodecode_user) | ||||
r1998 | ||||
r2068 | user_group_link = h.link_to( | |||
h.escape(user_group_name), | ||||
h.route_path( | ||||
'edit_user_group', user_group_id=user_group.users_group_id)) | ||||
h.flash(h.literal(_('Created user group %(user_group_link)s') | ||||
% {'user_group_link': user_group_link}), | ||||
category='success') | ||||
Session().commit() | ||||
user_group_id = user_group.users_group_id | ||||
except formencode.Invalid as errors: | ||||
r1998 | ||||
r2068 | data = render( | |||
'rhodecode:templates/admin/user_groups/user_group_add.mako', | ||||
self._get_template_context(c), self.request) | ||||
html = formencode.htmlfill.render( | ||||
data, | ||||
defaults=errors.value, | ||||
r5018 | errors=errors.unpack_errors() or {}, | |||
r2068 | prefix_error=False, | |||
encoding="UTF-8", | ||||
force_defaults=False | ||||
) | ||||
return Response(html) | ||||
except Exception: | ||||
log.exception("Exception creating user group") | ||||
h.flash(_('Error occurred during creation of user group %s') \ | ||||
% user_group_name, category='error') | ||||
raise HTTPFound(h.route_path('user_groups_new')) | ||||
r4727 | PermissionModel().trigger_permission_flush() | |||
r3824 | ||||
r2068 | raise HTTPFound( | |||
h.route_path('edit_user_group', user_group_id=user_group_id)) | ||||