##// END OF EJS Templates
chore(configs): remove is_test flag which is deprecated
chore(configs): remove is_test flag which is deprecated

File last commit:

r5096:a0018795 default
r5346:eaae1e84 default
Show More
repo_group.py
895 lines | 35.1 KiB | text/x-python | PythonLexer
copyrights: updated for 2023
r5088 # Copyright (C) 2011-2023 RhodeCode GmbH
project: added all source files and assets
r1 #
# 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/
"""
repo group model for RhodeCode
"""
repo-groups: implemented default personal repo groups logic....
r1094 import os
project: added all source files and assets
r1 import datetime
import itertools
import logging
import shutil
admin: fixed problems with generating last change in admin panels....
r4000 import time
project: added all source files and assets
r1 import traceback
repo-groups: implemented default personal repo groups logic....
r1094 import string
project: added all source files and assets
r1
from zope.cachedescriptors.property import Lazy as LazyProperty
Martin Bornhold
events: Trigger repository group events (create/update/delete)
r557 from rhodecode import events
project: added all source files and assets
r1 from rhodecode.model import BaseModel
exported get_repos_as_dict for new grids
r4147 from rhodecode.model.db import (_hash_key, func, or_, in_filter_generator,
Session, RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm,
project: added all source files and assets
r1 UserGroup, Repository)
permissions: flush permissions on owner changes for repo and repo groups.
r4662 from rhodecode.model.permission import PermissionModel
repo-groups: implemented default personal repo groups logic....
r1094 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
project: added all source files and assets
r1 from rhodecode.lib.caching_query import FromCache
descriptions: fixed rendering problem with certain meta-tags....
r4223 from rhodecode.lib.utils2 import action_logger_generic
project: added all source files and assets
r1
log = logging.getLogger(__name__)
class RepoGroupModel(BaseModel):
cls = RepoGroup
meta-tags: fixes #4305, metatags are not taken into account when truncating output....
r1102 PERSONAL_GROUP_DESC = 'personal repo group of user `%(username)s`'
repo-groups: implemented default personal repo groups logic....
r1094 PERSONAL_GROUP_PATTERN = '${username}' # default
project: added all source files and assets
r1
def _get_user_group(self, users_group):
return self._get_instance(UserGroup, users_group,
callback=UserGroup.get_by_group_name)
def _get_repo_group(self, repo_group):
return self._get_instance(RepoGroup, repo_group,
callback=RepoGroup.get_by_group_name)
file-store: changed for stream upload endpoint.
r4611 def get_repo_group(self, repo_group):
return self._get_repo_group(repo_group)
project: added all source files and assets
r1 @LazyProperty
def repos_path(self):
"""
Gets the repositories root path from database
"""
settings_model = VcsSettingsModel(sa=self.sa)
return settings_model.get_repos_location()
def get_by_group_name(self, repo_group_name, cache=None):
repo = self.sa.query(RepoGroup) \
.filter(RepoGroup.group_name == repo_group_name)
if cache:
caches: ensure we don't use non-ascii characters in cache keys....
r1749 name_key = _hash_key(repo_group_name)
repo = repo.options(
caches: cleanup code...
r5009 FromCache("sql_cache_short", f"get_repo_group_{name_key}"))
project: added all source files and assets
r1 return repo.scalar()
repo-groups: implemented default personal repo groups logic....
r1094 def get_default_create_personal_repo_group(self):
value = SettingsModel().get_setting_by_name(
'create_personal_repo_group')
return value.app_settings_value if value else None or False
def get_personal_group_name_pattern(self):
value = SettingsModel().get_setting_by_name(
'personal_repo_group_pattern')
val = value.app_settings_value if value else None
group_template = val or self.PERSONAL_GROUP_PATTERN
group_template = group_template.lstrip('/')
return group_template
def get_personal_group_name(self, user):
template = self.get_personal_group_name_pattern()
return string.Template(template).safe_substitute(
username=user.username,
user_id=user.user_id,
users: personal repo group template also can use first/last names for an user
r3659 first_name=user.first_name,
last_name=user.last_name,
repo-groups: implemented default personal repo groups logic....
r1094 )
def create_personal_repo_group(self, user, commit_early=True):
desc = self.PERSONAL_GROUP_DESC % {'username': user.username}
personal_repo_group_name = self.get_personal_group_name(user)
# create a new one
RepoGroupModel().create(
group_name=personal_repo_group_name,
group_description=desc,
owner=user.username,
personal=True,
commit_early=commit_early)
project: added all source files and assets
r1 def _create_default_perms(self, new_group):
# create default permission
default_perm = 'group.read'
def_user = User.get_default_user()
for p in def_user.user_perms:
if p.permission.permission_name.startswith('group.'):
default_perm = p.permission.permission_name
break
repo_group_to_perm = UserRepoGroupToPerm()
repo_group_to_perm.permission = Permission.get_by_key(default_perm)
repo_group_to_perm.group = new_group
models: major update for python3,...
r5070 repo_group_to_perm.user = def_user
project: added all source files and assets
r1 return repo_group_to_perm
repo-group-model: add flag to return proper object along the exported names.
r1151 def _get_group_name_and_parent(self, group_name_full, repo_in_path=False,
get_object=False):
project: added all source files and assets
r1 """
Get's the group name and a parent group name from given group name.
If repo_in_path is set to truth, we asume the full path also includes
repo name, in such case we clean the last element.
:param group_name_full:
"""
split_paths = 1
if repo_in_path:
split_paths = 2
_parts = group_name_full.rsplit(RepoGroup.url_sep(), split_paths)
if repo_in_path and len(_parts) > 1:
# such case last element is the repo_name
_parts.pop(-1)
group_name_cleaned = _parts[-1] # just the group name
parent_repo_group_name = None
if len(_parts) > 1:
parent_repo_group_name = _parts[0]
repo-group-model: add flag to return proper object along the exported names.
r1151 parent_group = None
project: added all source files and assets
r1 if parent_repo_group_name:
parent_group = RepoGroup.get_by_group_name(parent_repo_group_name)
repo-group-model: add flag to return proper object along the exported names.
r1151 if get_object:
return group_name_cleaned, parent_repo_group_name, parent_group
project: added all source files and assets
r1 return group_name_cleaned, parent_repo_group_name
def check_exist_filesystem(self, group_name, exc_on_failure=True):
create_path = os.path.join(self.repos_path, group_name)
log.debug('creating new group in %s', create_path)
if os.path.isdir(create_path):
if exc_on_failure:
repo-group: add path to exception when directory under which repo group should be created already exists.
r1152 abs_create_path = os.path.abspath(create_path)
modernize: python3 updates
r5096 raise Exception(f'Directory `{abs_create_path}` already exists !')
project: added all source files and assets
r1 return False
return True
def _create_group(self, group_name):
"""
makes repository group on filesystem
:param repo_name:
:param parent_id:
"""
self.check_exist_filesystem(group_name)
create_path = os.path.join(self.repos_path, group_name)
log.debug('creating new group in %s', create_path)
code: fixed deprecated octal calls for py3 compat.
r3268 os.makedirs(create_path, mode=0o755)
project: added all source files and assets
r1 log.debug('created group in %s', create_path)
def _rename_group(self, old, new):
"""
Renames a group on filesystem
:param group_name:
"""
if old == new:
log.debug('skipping group rename')
return
log.debug('renaming repository group from %s to %s', old, new)
old_path = os.path.join(self.repos_path, old)
new_path = os.path.join(self.repos_path, new)
log.debug('renaming repos paths from %s to %s', old_path, new_path)
if os.path.isdir(new_path):
raise Exception('Was trying to rename to already '
'existing dir %s' % new_path)
shutil.move(old_path, new_path)
def _delete_filesystem_group(self, group, force_delete=False):
"""
Deletes a group from a filesystem
:param group: instance of group from database
:param force_delete: use shutil rmtree to remove all objects
"""
paths = group.full_path.split(RepoGroup.url_sep())
paths = os.sep.join(paths)
rm_path = os.path.join(self.repos_path, paths)
log.info("Removing group %s", rm_path)
# delete only if that path really exists
if os.path.isdir(rm_path):
if force_delete:
shutil.rmtree(rm_path)
else:
# archive that group`
_now = datetime.datetime.now()
_ms = str(_now.microsecond).rjust(6, '0')
modernize: python3 updates
r5096 _d = 'rm__{}_GROUP_{}'.format(
project: added all source files and assets
r1 _now.strftime('%Y%m%d_%H%M%S_' + _ms), group.name)
shutil.move(rm_path, os.path.join(self.repos_path, _d))
def create(self, group_name, group_description, owner, just_db=False,
repo-groups: implemented default personal repo groups logic....
r1094 copy_permissions=False, personal=None, commit_early=True):
project: added all source files and assets
r1
(group_name_cleaned,
parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name)
parent_group = None
if parent_group_name:
parent_group = self._get_repo_group(parent_group_name)
repo-groups: implemented default personal repo groups logic....
r1094 if not parent_group:
# we tried to create a nested group, but the parent is not
# existing
raise ValueError(
'Parent group `%s` given in `%s` group name '
'is not yet existing.' % (parent_group_name, group_name))
project: added all source files and assets
r1
repo-groups: implemented default personal repo groups logic....
r1094 # because we are doing a cleanup, we need to check if such directory
# already exists. If we don't do that we can accidentally delete
# existing directory via cleanup that can cause data issues, since
# delete does a folder rename to special syntax later cleanup
# functions can delete this
project: added all source files and assets
r1 cleanup_group = self.check_exist_filesystem(group_name,
exc_on_failure=False)
repo-groups: moved to pyramid
r2175 user = self._get_user(owner)
if not user:
raise ValueError('Owner %s not found as rhodecode user', owner)
project: added all source files and assets
r1 try:
new_repo_group = RepoGroup()
new_repo_group.user = user
new_repo_group.group_description = group_description or group_name
new_repo_group.parent_group = parent_group
new_repo_group.group_name = group_name
repo-groups: implemented default personal repo groups logic....
r1094 new_repo_group.personal = personal
project: added all source files and assets
r1
self.sa.add(new_repo_group)
# create an ADMIN permission for owner except if we're super admin,
# later owner should go into the owner field of groups
if not user.is_admin:
self.grant_user_permission(repo_group=new_repo_group,
user=owner, perm='group.admin')
if parent_group and copy_permissions:
# copy permissions from parent
user_perms = UserRepoGroupToPerm.query() \
.filter(UserRepoGroupToPerm.group == parent_group).all()
group_perms = UserGroupRepoGroupToPerm.query() \
.filter(UserGroupRepoGroupToPerm.group == parent_group).all()
for perm in user_perms:
# don't copy over the permission for user who is creating
# this group, if he is not super admin he get's admin
# permission set above
if perm.user != user or user.is_admin:
UserRepoGroupToPerm.create(
perm.user, new_repo_group, perm.permission)
for perm in group_perms:
UserGroupRepoGroupToPerm.create(
perm.users_group, new_repo_group, perm.permission)
else:
perm_obj = self._create_default_perms(new_repo_group)
self.sa.add(perm_obj)
# now commit the changes, earlier so we are sure everything is in
# the database.
if commit_early:
self.sa.commit()
if not just_db:
self._create_group(new_repo_group.group_name)
# trigger the post hook
comments: added rcextensions hoooks for comment editing, and renamed methods to remove odd log_ prefix which...
r4445 from rhodecode.lib import hooks_base
project: added all source files and assets
r1 repo_group = RepoGroup.get_by_group_name(group_name)
feat: changed last change of repo group to be commit of a latest repository.
r3689
# update repo group commit caches initially
repo_group.update_commit_cache()
comments: added rcextensions hoooks for comment editing, and renamed methods to remove odd log_ prefix which...
r4445 hooks_base.create_repository_group(
project: added all source files and assets
r1 created_by=user.username, **repo_group.get_dict())
Martin Bornhold
events: Trigger repository group events (create/update/delete)
r557 # Trigger create event.
events.trigger(events.RepoGroupCreateEvent(repo_group))
project: added all source files and assets
r1 return new_repo_group
except Exception:
self.sa.rollback()
log.exception('Exception occurred when creating repository group, '
'doing cleanup...')
# rollback things manually !
repo_group = RepoGroup.get_by_group_name(group_name)
if repo_group:
RepoGroup.delete(repo_group.group_id)
self.sa.commit()
if cleanup_group:
RepoGroupModel()._delete_filesystem_group(repo_group)
raise
def update_permissions(
self, repo_group, perm_additions=None, perm_updates=None,
perm_deletions=None, recursive=None, check_perms=True,
cur_user=None):
from rhodecode.model.repo import RepoModel
from rhodecode.lib.auth import HasUserGroupPermissionAny
if not perm_additions:
perm_additions = []
if not perm_updates:
perm_updates = []
if not perm_deletions:
perm_deletions = []
req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
audit-logs: added action logs for repository groups.
r1799 changes = {
'added': [],
'updated': [],
dan
permissions: flush all user permissions in case of default user permission changes....
r4187 'deleted': [],
'default_user_changed': None
audit-logs: added action logs for repository groups.
r1799 }
project: added all source files and assets
r1 def _set_perm_user(obj, user, perm):
if isinstance(obj, RepoGroup):
self.grant_user_permission(
repo_group=obj, user=user, perm=perm)
elif isinstance(obj, Repository):
# private repos will not allow to change the default
# permissions using recursive mode
if obj.private and user == User.DEFAULT_USER:
return
# we set group permission but we have to switch to repo
# permission
perm = perm.replace('group.', 'repository.')
RepoModel().grant_user_permission(
repo=obj, user=user, perm=perm)
def _set_perm_group(obj, users_group, perm):
if isinstance(obj, RepoGroup):
self.grant_user_group_permission(
repo_group=obj, group_name=users_group, perm=perm)
elif isinstance(obj, Repository):
# we set group permission but we have to switch to repo
# permission
perm = perm.replace('group.', 'repository.')
RepoModel().grant_user_group_permission(
repo=obj, group_name=users_group, perm=perm)
def _revoke_perm_user(obj, user):
if isinstance(obj, RepoGroup):
self.revoke_user_permission(repo_group=obj, user=user)
elif isinstance(obj, Repository):
RepoModel().revoke_user_permission(repo=obj, user=user)
def _revoke_perm_group(obj, user_group):
if isinstance(obj, RepoGroup):
self.revoke_user_group_permission(
repo_group=obj, group_name=user_group)
elif isinstance(obj, Repository):
RepoModel().revoke_user_group_permission(
repo=obj, group_name=user_group)
# start updates
log.debug('Now updating permissions for %s in recursive mode:%s',
repo_group, recursive)
# initialize check function, we'll call that multiple times
has_group_perm = HasUserGroupPermissionAny(*req_perms)
for obj in repo_group.recursive_groups_and_repos():
# iterated obj is an instance of a repos group or repository in
# that group, recursive option can be: none, repos, groups, all
if recursive == 'all':
obj = obj
elif recursive == 'repos':
# skip groups, other than this one
if isinstance(obj, RepoGroup) and not obj == repo_group:
continue
elif recursive == 'groups':
# skip repos
if isinstance(obj, Repository):
continue
else: # recursive == 'none':
# DEFAULT option - don't apply to iterated objects
# also we do a break at the end of this loop. if we are not
# in recursive mode
obj = repo_group
audit-logs: added action logs for repository groups.
r1799 change_obj = obj.get_api_data()
project: added all source files and assets
r1 # update permissions
for member_id, perm, member_type in perm_updates:
member_id = int(member_id)
if member_type == 'user':
audit-logs: added action logs for repository groups.
r1799 member_name = User.get(member_id).username
dan
permissions: flush all user permissions in case of default user permission changes....
r4187 if isinstance(obj, RepoGroup) and obj == repo_group and member_name == User.DEFAULT_USER:
# NOTE(dan): detect if we changed permissions for default user
perm_obj = self.sa.query(UserRepoGroupToPerm) \
.filter(UserRepoGroupToPerm.user_id == member_id) \
.filter(UserRepoGroupToPerm.group == repo_group) \
.scalar()
if perm_obj and perm_obj.permission.permission_name != perm:
changes['default_user_changed'] = True
project: added all source files and assets
r1 # this updates also current one if found
_set_perm_user(obj, user=member_id, perm=perm)
tests: added tests for permission update views to catch obvious form errors.
r2827 elif member_type == 'user_group':
project: added all source files and assets
r1 member_name = UserGroup.get(member_id).users_group_name
if not check_perms or has_group_perm(member_name,
user=cur_user):
_set_perm_group(obj, users_group=member_id, perm=perm)
tests: added tests for permission update views to catch obvious form errors.
r2827 else:
raise ValueError("member_type must be 'user' or 'user_group' "
"got {} instead".format(member_type))
project: added all source files and assets
r1
audit-logs: added action logs for repository groups.
r1799 changes['updated'].append(
{'change_obj': change_obj, 'type': member_type,
'id': member_id, 'name': member_name, 'new_perm': perm})
project: added all source files and assets
r1 # set new permissions
for member_id, perm, member_type in perm_additions:
member_id = int(member_id)
if member_type == 'user':
audit-logs: added action logs for repository groups.
r1799 member_name = User.get(member_id).username
project: added all source files and assets
r1 _set_perm_user(obj, user=member_id, perm=perm)
tests: added tests for permission update views to catch obvious form errors.
r2827 elif member_type == 'user_group':
project: added all source files and assets
r1 # check if we have permissions to alter this usergroup
member_name = UserGroup.get(member_id).users_group_name
if not check_perms or has_group_perm(member_name,
user=cur_user):
_set_perm_group(obj, users_group=member_id, perm=perm)
tests: added tests for permission update views to catch obvious form errors.
r2827 else:
raise ValueError("member_type must be 'user' or 'user_group' "
"got {} instead".format(member_type))
project: added all source files and assets
r1
audit-logs: added action logs for repository groups.
r1799 changes['added'].append(
{'change_obj': change_obj, 'type': member_type,
'id': member_id, 'name': member_name, 'new_perm': perm})
project: added all source files and assets
r1 # delete permissions
for member_id, perm, member_type in perm_deletions:
member_id = int(member_id)
if member_type == 'user':
audit-logs: added action logs for repository groups.
r1799 member_name = User.get(member_id).username
project: added all source files and assets
r1 _revoke_perm_user(obj, user=member_id)
tests: added tests for permission update views to catch obvious form errors.
r2827 elif member_type == 'user_group':
project: added all source files and assets
r1 # check if we have permissions to alter this usergroup
member_name = UserGroup.get(member_id).users_group_name
if not check_perms or has_group_perm(member_name,
user=cur_user):
_revoke_perm_group(obj, user_group=member_id)
tests: added tests for permission update views to catch obvious form errors.
r2827 else:
raise ValueError("member_type must be 'user' or 'user_group' "
"got {} instead".format(member_type))
project: added all source files and assets
r1
audit-logs: added action logs for repository groups.
r1799 changes['deleted'].append(
{'change_obj': change_obj, 'type': member_type,
'id': member_id, 'name': member_name, 'new_perm': perm})
project: added all source files and assets
r1 # if it's not recursive call for all,repos,groups
# break the loop and don't proceed with other changes
if recursive not in ['all', 'repos', 'groups']:
break
audit-logs: added action logs for repository groups.
r1799 return changes
project: added all source files and assets
r1
def update(self, repo_group, form_data):
try:
repo_group = self._get_repo_group(repo_group)
old_path = repo_group.full_path
# change properties
if 'group_description' in form_data:
repo_group.group_description = form_data['group_description']
if 'enable_locking' in form_data:
repo_group.enable_locking = form_data['enable_locking']
if 'group_parent_id' in form_data:
parent_group = (
self._get_repo_group(form_data['group_parent_id']))
repo_group.group_parent_id = (
parent_group.group_id if parent_group else None)
repo_group.parent_group = parent_group
# mikhail: to update the full_path, we have to explicitly
# update group_name
group_name = form_data.get('group_name', repo_group.name)
repo_group.group_name = repo_group.get_new_name(group_name)
new_path = repo_group.full_path
permissions: flush permissions on owner changes for repo and repo groups.
r4662 affected_user_ids = []
project: added all source files and assets
r1 if 'user' in form_data:
permissions: flush permissions on owner changes for repo and repo groups.
r4662 old_owner_id = repo_group.user.user_id
new_owner = User.get_by_username(form_data['user'])
repo_group.user = new_owner
if old_owner_id != new_owner.user_id:
affected_user_ids = [new_owner.user_id, old_owner_id]
admin: fixed problems with generating last change in admin panels....
r4000
project: added all source files and assets
r1 self.sa.add(repo_group)
# iterate over all members of this groups and do fixes
# set locking if given
# if obj is a repoGroup also fix the name of the group according
# to the parent
# if obj is a Repo fix it's name
# this can be potentially heavy operation
for obj in repo_group.recursive_groups_and_repos():
# set the value from it's parent
obj.enable_locking = repo_group.enable_locking
if isinstance(obj, RepoGroup):
new_name = obj.get_new_name(obj.name)
log.debug('Fixing group %s to new name %s',
obj.group_name, new_name)
obj.group_name = new_name
admin: fixed problems with generating last change in admin panels....
r4000
project: added all source files and assets
r1 elif isinstance(obj, Repository):
# we need to get all repositories from this new group and
# rename them accordingly to new group path
new_name = obj.get_new_name(obj.just_name)
log.debug('Fixing repo %s to new name %s',
obj.repo_name, new_name)
obj.repo_name = new_name
admin: fixed problems with generating last change in admin panels....
r4000
project: added all source files and assets
r1 self.sa.add(obj)
self._rename_group(old_path, new_path)
Martin Bornhold
events: Trigger repository group events (create/update/delete)
r557 # Trigger update event.
events.trigger(events.RepoGroupUpdateEvent(repo_group))
permissions: flush permissions on owner changes for repo and repo groups.
r4662 if affected_user_ids:
PermissionModel().trigger_permission_flush(affected_user_ids)
project: added all source files and assets
r1 return repo_group
except Exception:
log.error(traceback.format_exc())
raise
def delete(self, repo_group, force_delete=False, fs_remove=True):
repo_group = self._get_repo_group(repo_group)
dan
integrations: refactor/cleanup + features, fixes #4181...
r731 if not repo_group:
return False
project: added all source files and assets
r1 try:
self.sa.delete(repo_group)
if fs_remove:
self._delete_filesystem_group(repo_group, force_delete)
else:
log.debug('skipping removal from filesystem')
Martin Bornhold
events: Trigger repository group events (create/update/delete)
r557 # Trigger delete event.
events.trigger(events.RepoGroupDeleteEvent(repo_group))
dan
integrations: refactor/cleanup + features, fixes #4181...
r731 return True
Martin Bornhold
events: Trigger repository group events (create/update/delete)
r557
project: added all source files and assets
r1 except Exception:
log.error('Error removing repo_group %s', repo_group)
raise
def grant_user_permission(self, repo_group, user, perm):
"""
Grant permission for user on given repository group, or update
existing one if found
:param repo_group: Instance of RepoGroup, repositories_group_id,
or repositories_group name
:param user: Instance of User, user_id or username
:param perm: Instance of Permission, or permission_name
"""
repo_group = self._get_repo_group(repo_group)
user = self._get_user(user)
permission = self._get_perm(perm)
# check if we have that permission already
obj = self.sa.query(UserRepoGroupToPerm)\
.filter(UserRepoGroupToPerm.user == user)\
.filter(UserRepoGroupToPerm.group == repo_group)\
.scalar()
if obj is None:
# create new !
obj = UserRepoGroupToPerm()
obj.group = repo_group
obj.user = user
obj.permission = permission
self.sa.add(obj)
log.debug('Granted perm %s to %s on %s', perm, user, repo_group)
action_logger_generic(
'granted permission: {} to user: {} on repogroup: {}'.format(
perm, user, repo_group), namespace='security.repogroup')
return obj
def revoke_user_permission(self, repo_group, user):
"""
Revoke permission for user on given repository group
:param repo_group: Instance of RepoGroup, repositories_group_id,
or repositories_group name
:param user: Instance of User, user_id or username
"""
repo_group = self._get_repo_group(repo_group)
user = self._get_user(user)
obj = self.sa.query(UserRepoGroupToPerm)\
.filter(UserRepoGroupToPerm.user == user)\
.filter(UserRepoGroupToPerm.group == repo_group)\
.scalar()
if obj:
self.sa.delete(obj)
log.debug('Revoked perm on %s on %s', repo_group, user)
action_logger_generic(
'revoked permission from user: {} on repogroup: {}'.format(
user, repo_group), namespace='security.repogroup')
def grant_user_group_permission(self, repo_group, group_name, perm):
"""
Grant permission for user group on given repository group, or update
existing one if found
:param repo_group: Instance of RepoGroup, repositories_group_id,
or repositories_group name
:param group_name: Instance of UserGroup, users_group_id,
or user group name
:param perm: Instance of Permission, or permission_name
"""
repo_group = self._get_repo_group(repo_group)
group_name = self._get_user_group(group_name)
permission = self._get_perm(perm)
# check if we have that permission already
obj = self.sa.query(UserGroupRepoGroupToPerm)\
.filter(UserGroupRepoGroupToPerm.group == repo_group)\
.filter(UserGroupRepoGroupToPerm.users_group == group_name)\
.scalar()
if obj is None:
# create new
obj = UserGroupRepoGroupToPerm()
obj.group = repo_group
obj.users_group = group_name
obj.permission = permission
self.sa.add(obj)
log.debug('Granted perm %s to %s on %s', perm, group_name, repo_group)
action_logger_generic(
'granted permission: {} to usergroup: {} on repogroup: {}'.format(
perm, group_name, repo_group), namespace='security.repogroup')
return obj
def revoke_user_group_permission(self, repo_group, group_name):
"""
Revoke permission for user group on given repository group
:param repo_group: Instance of RepoGroup, repositories_group_id,
or repositories_group name
:param group_name: Instance of UserGroup, users_group_id,
or user group name
"""
repo_group = self._get_repo_group(repo_group)
group_name = self._get_user_group(group_name)
obj = self.sa.query(UserGroupRepoGroupToPerm)\
.filter(UserGroupRepoGroupToPerm.group == repo_group)\
.filter(UserGroupRepoGroupToPerm.users_group == group_name)\
.scalar()
if obj:
self.sa.delete(obj)
log.debug('Revoked perm to %s on %s', repo_group, group_name)
action_logger_generic(
'revoked permission from usergroup: {} on repogroup: {}'.format(
group_name, repo_group), namespace='security.repogroup')
feat: changed last change of repo group to be commit of a latest repository.
r3689 @classmethod
def update_commit_cache(cls, repo_groups=None):
if not repo_groups:
repo_groups = RepoGroup.getAll()
for repo_group in repo_groups:
repo_group.update_commit_cache()
project: added all source files and assets
r1 def get_repo_groups_as_dict(self, repo_group_list=None, admin=False,
super_user_actions=False):
core: use new style pyramid partial renderer where possible.
r1897 from pyramid.threadlocal import get_current_request
_render = get_current_request().get_partial_renderer(
partial-renderer: use package resource format for templates....
r2313 'rhodecode:templates/data_table/_dt_elements.mako')
core: use new style pyramid partial renderer where possible.
r1897 c = _render.get_call_context()
h = _render.get_helpers()
project: added all source files and assets
r1
def quick_menu(repo_group_name):
return _render('quick_repo_group_menu', repo_group_name)
def repo_group_lnk(repo_group_name):
return _render('repo_group_name', repo_group_name)
repository-groups: introduce last change for repository groups.
r1940 def last_change(last_change):
if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
admin: fixed problems with generating last change in admin panels....
r4000 ts = time.time()
utc_offset = (datetime.datetime.fromtimestamp(ts)
- datetime.datetime.utcfromtimestamp(ts)).total_seconds()
last_change = last_change + datetime.timedelta(seconds=utc_offset)
repository-groups: introduce last change for repository groups.
r1940 return _render("last_change", last_change)
meta-tags: fixes #4305, metatags are not taken into account when truncating output....
r1102 def desc(desc, personal):
meta-tags: cleanup support for metatags....
r2091 return _render(
'repo_group_desc', desc, personal, c.visual.stylify_metatags)
project: added all source files and assets
r1
def repo_group_actions(repo_group_id, repo_group_name, gr_count):
return _render(
'repo_group_actions', repo_group_id, repo_group_name, gr_count)
def repo_group_name(repo_group_name, children_groups):
return _render("repo_group_name", repo_group_name, children_groups)
def user_profile(username):
return _render('user_profile', username)
repo_group_data = []
for group in repo_group_list:
exported get_repos_as_dict for new grids
r4147 # NOTE(marcink): because we use only raw column we need to load it like that
changeset_cache = RepoGroup._load_changeset_cache(
'', group._changeset_cache)
last_commit_change = RepoGroup._load_commit_change(changeset_cache)
project: added all source files and assets
r1 row = {
"menu": quick_menu(group.group_name),
"name": repo_group_lnk(group.group_name),
"name_raw": group.group_name,
exported get_repos_as_dict for new grids
r4147
"last_change": last_change(last_commit_change),
ui: normalize main grid sizes and columns
r3557
"last_changeset": "",
"last_changeset_raw": "",
descriptions: fixed rendering problem with certain meta-tags....
r4223 "desc": desc(h.escape(group.group_description), group.personal),
project: added all source files and assets
r1 "top_level_repos": 0,
exported get_repos_as_dict for new grids
r4147 "owner": user_profile(group.User.username)
project: added all source files and assets
r1 }
if admin:
repo_count = group.repositories.count()
models: major update for python3,...
r5070 children_groups = list(map(
h.safe_str,
project: added all source files and assets
r1 itertools.chain((g.name for g in group.parents),
models: major update for python3,...
r5070 (x.name for x in [group]))))
project: added all source files and assets
r1 row.update({
"action": repo_group_actions(
group.group_id, group.group_name, repo_count),
"top_level_repos": repo_count,
"name": repo_group_name(group.group_name, children_groups),
})
repo_group_data.append(row)
return repo_group_data
repo-groups: moved to pyramid
r2175
dashboard: main page grids async load....
r4148 def get_repo_groups_data_table(
self, draw, start, limit,
search_q, order_by, order_dir,
auth_user, repo_group_id):
from rhodecode.model.scm import RepoGroupList
_perms = ['group.read', 'group.write', 'group.admin']
repo_groups = RepoGroup.query() \
.filter(RepoGroup.group_parent_id == repo_group_id) \
.all()
auth_repo_group_list = RepoGroupList(
repo_groups, perm_set=_perms,
extra_kwargs=dict(user=auth_user))
allowed_ids = [-1]
for repo_group in auth_repo_group_list:
allowed_ids.append(repo_group.group_id)
repo_groups_data_total_count = RepoGroup.query() \
.filter(RepoGroup.group_parent_id == repo_group_id) \
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(RepoGroup.group_id, allowed_ids))
) \
.count()
base_q = Session.query(
RepoGroup.group_name,
RepoGroup.group_name_hash,
RepoGroup.group_description,
RepoGroup.group_id,
RepoGroup.personal,
RepoGroup.updated_on,
RepoGroup._changeset_cache,
User,
) \
.filter(RepoGroup.group_parent_id == repo_group_id) \
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(RepoGroup.group_id, allowed_ids))
) \
.join(User, User.user_id == RepoGroup.user_id) \
.group_by(RepoGroup, User)
repo_groups_data_total_filtered_count = base_q.count()
sort_defined = False
if order_by == 'group_name':
sort_col = func.lower(RepoGroup.group_name)
sort_defined = True
elif order_by == 'user_username':
sort_col = User.username
else:
sort_col = getattr(RepoGroup, order_by, None)
if sort_defined or sort_col:
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)
repo_group_list = base_q.all()
repo_groups_data = RepoGroupModel().get_repo_groups_as_dict(
repo_group_list=repo_group_list, admin=False)
data = ({
'draw': draw,
'data': repo_groups_data,
'recordsTotal': repo_groups_data_total_count,
'recordsFiltered': repo_groups_data_total_filtered_count,
})
return data
repo-groups: moved to pyramid
r2175 def _get_defaults(self, repo_group_name):
repo_group = RepoGroup.get_by_group_name(repo_group_name)
if repo_group is None:
return None
defaults = repo_group.get_dict()
defaults['repo_group_name'] = repo_group.name
defaults['repo_group_description'] = repo_group.group_description
defaults['repo_group_enable_locking'] = repo_group.enable_locking
# we use -1 as this is how in HTML, we mark an empty group
defaults['repo_group'] = defaults['group_parent_id'] or -1
# fill owner
if repo_group.user:
defaults.update({'user': repo_group.user.username})
else:
replacement_user = User.get_first_super_admin().username
defaults.update({'user': replacement_user})
return defaults