@@ -1378,388 +1378,385 @@ class ApiController(JSONRPCController):
flat=False)
_map = {
'all': _d + _f,
'files': _f,
'dirs': _d,
}
return _map[ret_type]
except KeyError:
raise JSONRPCError('ret_type must be one of %s'
% (','.join(_map.keys())))
except Exception:
log.error(traceback.format_exc())
raise JSONRPCError(
'failed to get repo: `%s` nodes' % repo.repo_name
)
@HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')),
repo_type=Optional('hg'), description=Optional(''),
private=Optional(False), clone_uri=Optional(None),
landing_rev=Optional('rev:tip'),
enable_statistics=Optional(False),
enable_locking=Optional(False),
enable_downloads=Optional(False),
copy_permissions=Optional(False)):
"""
Creates a repository. If repository name contains "/", all needed repository
groups will be created. For example "foo/bar/baz" will create groups
"foo", "bar" (with "foo" as parent), and create "baz" repository with
"bar" as group. This command can be executed only using api_key
belonging to user with admin rights or regular user that have create
repository permission. Regular users cannot specify owner parameter
:param apiuser: filled automatically from apikey
:type apiuser: AuthUser
:param repo_name: repository name
:type repo_name: str
:param owner: user_id or username
:type owner: Optional(str)
:param repo_type: 'hg' or 'git'
:type repo_type: Optional(str)
:param description: repository description
:type description: Optional(str)
:param private:
:type private: bool
:param clone_uri:
:type clone_uri: str
:param landing_rev: <rev_type>:<rev>
:type landing_rev: str
:param enable_locking:
:type enable_locking: bool
:param enable_downloads:
:type enable_downloads: bool
:param enable_statistics:
:type enable_statistics: bool
:param copy_permissions: Copy permission from group that repository is
being created.
:type copy_permissions: bool
OUTPUT::
id : <id_given_in_input>
result: {
"msg": "Created new repository `<reponame>`",
"success": true,
"task": "<celery task id or None if done sync>"
error: null
ERROR OUTPUT::
result : null
error : {
'failed to create repository `<repo_name>`
if not HasPermissionAnyApi('hg.admin')(user=apiuser):
if not isinstance(owner, Optional):
#forbid setting owner for non-admins
'Only Kallithea admin can specify `owner` param'
if isinstance(owner, Optional):
owner = apiuser.user_id
owner = get_user_or_error(owner)
if RepoModel().get_by_repo_name(repo_name):
raise JSONRPCError("repo `%s` already exist" % repo_name)
defs = Setting.get_default_repo_settings(strip_prefix=True)
if isinstance(private, Optional):
private = defs.get('repo_private') or Optional.extract(private)
if isinstance(repo_type, Optional):
repo_type = defs.get('repo_type')
if isinstance(enable_statistics, Optional):
enable_statistics = defs.get('repo_enable_statistics')
if isinstance(enable_locking, Optional):
enable_locking = defs.get('repo_enable_locking')
if isinstance(enable_downloads, Optional):
enable_downloads = defs.get('repo_enable_downloads')
clone_uri = Optional.extract(clone_uri)
description = Optional.extract(description)
landing_rev = Optional.extract(landing_rev)
copy_permissions = Optional.extract(copy_permissions)
try:
repo_name_cleaned = repo_name.split('/')[-1]
# create structure of groups and return the last group
repo_group = map_groups(repo_name)
data = dict(
repo_name=repo_name_cleaned,
repo_name_full=repo_name,
repo_type=repo_type,
repo_description=description,
owner=owner,
repo_private=private,
clone_uri=clone_uri,
repo_group=repo_group,
repo_landing_rev=landing_rev,
enable_statistics=enable_statistics,
enable_locking=enable_locking,
enable_downloads=enable_downloads,
repo_copy_permissions=copy_permissions,
task = RepoModel().create(form_data=data, cur_user=owner)
from celery.result import BaseAsyncResult
task_id = None
if isinstance(task, BaseAsyncResult):
task_id = task.task_id
# no commit, it's done in RepoModel, or async via celery
return dict(
msg="Created new repository `%s`" % (repo_name,),
success=True, # cannot return the repo data here since fork
# can be done async
task=task_id
'failed to create repository `%s`' % (repo_name,))
# permission check inside
def update_repo(self, apiuser, repoid, name=Optional(None),
owner=Optional(OAttr('apiuser')),
group=Optional(None),
description=Optional(''), private=Optional(False),
clone_uri=Optional(None), landing_rev=Optional('rev:tip'),
enable_downloads=Optional(False)):
Updates repo
:param repoid: repository name or repository id
:type repoid: str or int
:param name:
:param owner:
:param group:
:param description:
:param landing_rev:
repo = get_repo_or_error(repoid)
# check if we have admin permission for this repo !
if not HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
repo_name=repo.repo_name):
raise JSONRPCError('repository `%s` does not exist' % (repoid,))
if (name != repo.repo_name and
not HasPermissionAnyApi('hg.create.repository')(user=apiuser)
):
raise JSONRPCError('no permission to create (or move) repositories')
updates = {
# update function requires this.
'repo_name': repo.repo_name
updates = {}
repo_group = group
if not isinstance(repo_group, Optional):
repo_group = get_repo_group_or_error(repo_group)
repo_group = repo_group.group_id
store_update(updates, name, 'repo_name')
store_update(updates, repo_group, 'repo_group')
store_update(updates, owner, 'user')
store_update(updates, description, 'repo_description')
store_update(updates, private, 'repo_private')
store_update(updates, clone_uri, 'clone_uri')
store_update(updates, landing_rev, 'repo_landing_rev')
store_update(updates, enable_statistics, 'repo_enable_statistics')
store_update(updates, enable_locking, 'repo_enable_locking')
store_update(updates, enable_downloads, 'repo_enable_downloads')
RepoModel().update(repo, **updates)
Session().commit()
msg='updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
repository=repo.get_api_data()
raise JSONRPCError('failed to update repo `%s`' % repoid)
@HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
def fork_repo(self, apiuser, repoid, fork_name,
description=Optional(''), copy_permissions=Optional(False),
private=Optional(False), landing_rev=Optional('rev:tip')):
Creates a fork of given repo. In case of using celery this will
immediately return success message, while fork is going to be created
asynchronous. This command can be executed only using api_key belonging to
user with admin rights or regular user that have fork permission, and at least
read access to forking repository. Regular users cannot specify owner parameter.
:param fork_name:
:param copy_permissions:
INPUT::
id : <id_for_response>
api_key : "<api_key>"
args: {
"repoid" : "<reponame or repo_id>",
"fork_name": "<forkname>",
"owner": "<username or user_id = Optional(=apiuser)>",
"description": "<description>",
"copy_permissions": "<bool>",
"private": "<bool>",
"landing_rev": "<landing_rev>"
"msg": "Created fork of `<reponame>` as `<forkname>`",
repo_name = repo.repo_name
_repo = RepoModel().get_by_repo_name(fork_name)
if _repo:
type_ = 'fork' if _repo.fork else 'repo'
raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
if HasPermissionAnyApi('hg.admin')(user=apiuser):
pass
elif HasRepoPermissionAnyApi('repository.admin',
'repository.write',
'repository.read')(user=apiuser,
if not HasPermissionAnyApi('hg.create.repository')(user=apiuser):
raise JSONRPCError('no permission to create repositories')
else:
group = map_groups(fork_name)
form_data = dict(
repo_name=fork_name,
repo_name_full=fork_name,
repo_group=group,
repo_type=repo.repo_type,
description=Optional.extract(description),
private=Optional.extract(private),
copy_permissions=Optional.extract(copy_permissions),
landing_rev=Optional.extract(landing_rev),
update_after_clone=False,
fork_parent_id=repo.repo_id,
task = RepoModel().create_fork(form_data, cur_user=owner)
msg='Created fork of `%s` as `%s`' % (repo.repo_name,
fork_name),
'failed to fork repository `%s` as `%s`' % (repo_name,
fork_name)
def delete_repo(self, apiuser, repoid, forks=Optional('')):
Deletes a repository. This command can be executed only using api_key belonging
to user with admin rights or regular user that have admin access to repository.
When `forks` param is set it's possible to detach or delete forks of deleting
repository
:param forks: `detach` or `delete`, what do do with attached forks for repo
:type forks: Optional(str)
"msg": "Deleted repository `<reponame>`",
"success": true
handle_forks = Optional.extract(forks)
_forks_msg = ''
_forks = [f for f in repo.forks]
if handle_forks == 'detach':
_forks_msg = ' ' + 'Detached %s forks' % len(_forks)
elif handle_forks == 'delete':
_forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
elif _forks:
'Cannot delete `%s` it still contains attached forks' %
(repo.repo_name,)
RepoModel().delete(repo, forks=forks)
msg='Deleted repository `%s`%s' % (repo.repo_name, _forks_msg),
success=True
@@ -133,420 +133,421 @@ class RepoModel(BaseModel):
def get_users_js(self):
users = self.sa.query(User).filter(User.active == True).all()
return json.dumps([
{
'id': u.user_id,
'fname': h.escape(u.name),
'lname': h.escape(u.lastname),
'nname': u.username,
'gravatar_lnk': h.gravatar_url(u.email, size=28),
'gravatar_size': 14,
} for u in users]
def get_user_groups_js(self):
user_groups = self.sa.query(UserGroup) \
.filter(UserGroup.users_group_active == True) \
.options(subqueryload(UserGroup.members)) \
.all()
user_groups = UserGroupList(user_groups, perm_set=['usergroup.read',
'usergroup.write',
'usergroup.admin'])
'id': gr.users_group_id,
'grname': gr.users_group_name,
'grmembers': len(gr.members),
} for gr in user_groups]
@classmethod
def _render_datatable(cls, tmpl, *args, **kwargs):
import kallithea
from pylons import tmpl_context as c
from pylons.i18n.translation import _
_tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
tmpl = template.get_def(tmpl)
kwargs.update(dict(_=_, h=h, c=c))
return tmpl.render(*args, **kwargs)
def update_repoinfo(cls, repositories=None):
if repositories is None:
repositories = Repository.getAll()
for repo in repositories:
repo.update_changeset_cache()
def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True,
super_user_actions=False):
_render = self._render_datatable
def quick_menu(repo_name):
return _render('quick_menu', repo_name)
def repo_lnk(name, rtype, rstate, private, fork_of):
return _render('repo_name', name, rtype, rstate, private, fork_of,
short_name=not admin, admin=False)
def last_change(last_change):
return _render("last_change", last_change)
def rss_lnk(repo_name):
return _render("rss", repo_name)
def atom_lnk(repo_name):
return _render("atom", repo_name)
def last_rev(repo_name, cs_cache):
return _render('revision', repo_name, cs_cache.get('revision'),
cs_cache.get('raw_id'), cs_cache.get('author'),
cs_cache.get('message'))
def desc(desc):
return h.urlify_text(desc, truncate=60, stylize=c.visual.stylify_metatags)
def state(repo_state):
return _render("repo_state", repo_state)
def repo_actions(repo_name):
return _render('repo_actions', repo_name, super_user_actions)
def owner_actions(user_id, username):
return _render('user_name', user_id, username)
repos_data = []
for repo in repos_list:
if perm_check:
# check permission at this level
if not HasRepoPermissionAny(
'repository.read', 'repository.write',
'repository.admin'
)(repo.repo_name, 'get_repos_as_dict check'):
continue
cs_cache = repo.changeset_cache
row = {
"menu": quick_menu(repo.repo_name),
"raw_name": repo.repo_name.lower(),
"name": repo_lnk(repo.repo_name, repo.repo_type,
repo.repo_state, repo.private, repo.fork),
"last_change": last_change(repo.last_db_change),
"last_changeset": last_rev(repo.repo_name, cs_cache),
"last_rev_raw": cs_cache.get('revision'),
"desc": desc(repo.description),
"owner": h.person(repo.user),
"state": state(repo.repo_state),
"rss": rss_lnk(repo.repo_name),
"atom": atom_lnk(repo.repo_name),
if admin:
row.update({
"action": repo_actions(repo.repo_name),
"owner": owner_actions(repo.user.user_id,
h.person(repo.user))
})
repos_data.append(row)
return {
"totalRecords": len(repos_list),
"startIndex": 0,
"sort": "name",
"dir": "asc",
"records": repos_data
def _get_defaults(self, repo_name):
Gets information about repository, and returns a dict for
usage in forms
:param repo_name:
repo_info = Repository.get_by_repo_name(repo_name)
if repo_info is None:
return None
defaults = repo_info.get_dict()
group, repo_name, repo_name_full = repo_info.groups_and_repo
defaults['repo_name'] = repo_name
defaults['repo_group'] = getattr(group[-1] if group else None,
'group_id', None)
for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
(1, 'repo_description'), (1, 'repo_enable_locking'),
(1, 'repo_landing_rev'), (0, 'clone_uri'),
(1, 'repo_private'), (1, 'repo_enable_statistics')]:
attr = k
if strip:
attr = remove_prefix(k, 'repo_')
val = defaults[attr]
if k == 'repo_landing_rev':
val = ':'.join(defaults[attr])
defaults[k] = val
if k == 'clone_uri':
defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
# fill owner
if repo_info.user:
defaults.update({'user': repo_info.user.username})
replacement_user = User.query().filter(User.admin ==
True).first().username
defaults.update({'user': replacement_user})
# fill repository users
for p in repo_info.repo_to_perm:
defaults.update({'u_perm_%s' % p.user.username:
p.permission.permission_name})
# fill repository groups
for p in repo_info.users_group_to_perm:
defaults.update({'g_perm_%s' % p.users_group.users_group_name:
return defaults
def update(self, repo, **kwargs):
cur_repo = self._get_repo(repo)
org_repo_name = cur_repo.repo_name
if 'user' in kwargs:
cur_repo.user = User.get_by_username(kwargs['user'])
if 'repo_group' in kwargs:
cur_repo.group = RepoGroup.get(kwargs['repo_group'])
cur_repo.repo_name = cur_repo.get_new_name(cur_repo.just_name)
log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
for k in ['repo_enable_downloads',
'repo_description',
'repo_enable_locking',
'repo_landing_rev',
'repo_private',
'repo_enable_statistics',
]:
if k in kwargs:
setattr(cur_repo, remove_prefix(k, 'repo_'), kwargs[k])
clone_uri = kwargs.get('clone_uri')
if clone_uri is not None and clone_uri != cur_repo.clone_uri_hidden:
cur_repo.clone_uri = clone_uri
new_name = cur_repo.get_new_name(kwargs['repo_name'])
cur_repo.repo_name = new_name
if 'repo_name' in kwargs:
cur_repo.repo_name = cur_repo.get_new_name(kwargs['repo_name'])
#if private flag is set, reset default permission to NONE
if kwargs.get('repo_private'):
EMPTY_PERM = 'repository.none'
RepoModel().grant_user_permission(
repo=cur_repo, user='default', perm=EMPTY_PERM
#handle extra fields
for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
kwargs):
k = RepositoryField.un_prefix_key(field)
ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo)
if ex_field:
ex_field.field_value = kwargs[field]
self.sa.add(ex_field)
self.sa.add(cur_repo)
if org_repo_name != new_name:
if org_repo_name != cur_repo.repo_name:
# rename repository
self._rename_filesystem_repo(old=org_repo_name, new=new_name)
self._rename_filesystem_repo(old=org_repo_name, new=cur_repo.repo_name)
return cur_repo
raise
def _create_repo(self, repo_name, repo_type, description, owner,
private=False, clone_uri=None, repo_group=None,
landing_rev='rev:tip', fork_of=None,
copy_fork_permissions=False, enable_statistics=False,
enable_locking=False, enable_downloads=False,
copy_group_permissions=False, state=Repository.STATE_PENDING):
Create repository inside database with PENDING state. This should only be
executed by create() repo, with exception of importing existing repos.
from kallithea.model.scm import ScmModel
owner = self._get_user(owner)
fork_of = self._get_repo(fork_of)
repo_group = self._get_repo_group(repo_group)
repo_name = safe_unicode(repo_name)
description = safe_unicode(description)
# repo name is just a name of repository
# while repo_name_full is a full qualified name that is combined
# with name and path of group
repo_name_full = repo_name
repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
new_repo = Repository()
new_repo.repo_state = state
new_repo.enable_statistics = False
new_repo.repo_name = repo_name_full
new_repo.repo_type = repo_type
new_repo.user = owner
new_repo.group = repo_group
new_repo.description = description or repo_name
new_repo.private = private
new_repo.clone_uri = clone_uri
new_repo.landing_rev = landing_rev
new_repo.enable_statistics = enable_statistics
new_repo.enable_locking = enable_locking
new_repo.enable_downloads = enable_downloads
if repo_group:
new_repo.enable_locking = repo_group.enable_locking
if fork_of:
parent_repo = fork_of
new_repo.fork = parent_repo
self.sa.add(new_repo)
if fork_of and copy_fork_permissions:
repo = fork_of
user_perms = UserRepoToPerm.query() \
.filter(UserRepoToPerm.repository == repo).all()
group_perms = UserGroupRepoToPerm.query() \
.filter(UserGroupRepoToPerm.repository == repo).all()
for perm in user_perms:
UserRepoToPerm.create(perm.user, new_repo, perm.permission)
for perm in group_perms:
UserGroupRepoToPerm.create(perm.users_group, new_repo,
perm.permission)
elif repo_group and copy_group_permissions:
user_perms = UserRepoGroupToPerm.query() \
.filter(UserRepoGroupToPerm.group == repo_group).all()
group_perms = UserGroupRepoGroupToPerm.query() \
.filter(UserGroupRepoGroupToPerm.group == repo_group).all()
perm_name = perm.permission.permission_name.replace('group.', 'repository.')
perm_obj = Permission.get_by_key(perm_name)
UserRepoToPerm.create(perm.user, new_repo, perm_obj)
UserGroupRepoToPerm.create(perm.users_group, new_repo, perm_obj)
perm_obj = self._create_default_perms(new_repo, private)
self.sa.add(perm_obj)
# now automatically start following this repository as owner
ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
owner.user_id)
# we need to flush here, in order to check if database won't
# throw any exceptions, create filesystem dirs at the very end
self.sa.flush()
return new_repo
def create(self, form_data, cur_user):
Create repository using celery tasks
:param form_data:
:param cur_user:
from kallithea.lib.celerylib import tasks, run_task
return run_task(tasks.create_repo, form_data, cur_user)
def _update_permissions(self, repo, perms_new=None, perms_updates=None,
check_perms=True):
if not perms_new:
perms_new = []
if not perms_updates:
perms_updates = []
# update permissions
for member, perm, member_type in perms_updates:
if member_type == 'user':
# this updates existing one
self.grant_user_permission(
repo=repo, user=member, perm=perm
#check if we have permissions to alter this usergroup
req_perms = (
'usergroup.read', 'usergroup.write', 'usergroup.admin')
if not check_perms or HasUserGroupPermissionAny(*req_perms)(
member):
self.grant_user_group_permission(
repo=repo, group_name=member, perm=perm
# set new permissions
for member, perm, member_type in perms_new:
def create_fork(self, form_data, cur_user):
Simple wrapper into executing celery task for fork creation
return run_task(tasks.create_repo_fork, form_data, cur_user)
def delete(self, repo, forks=None, fs_remove=True, cur_user=None):
Delete given repository, forks parameter defines what do do with
attached forks. Throws AttachedForksError if deleted repo has attached
forks
:param repo:
:param forks: str 'delete' or 'detach'
:param fs_remove: remove(archive) repo from filesystem
if not cur_user:
cur_user = getattr(get_current_authuser(), 'username', None)
repo = self._get_repo(repo)
if repo is not None:
if forks == 'detach':
for r in repo.forks:
r.fork = None
self.sa.add(r)
elif forks == 'delete':
self.delete(r, forks='delete')
elif [f for f in repo.forks]:
raise AttachedForksError()
old_repo_dict = repo.get_dict()
self.sa.delete(repo)
if fs_remove:
self._delete_filesystem_repo(repo)
@@ -982,384 +982,425 @@ class _BaseTestApi(object):
repo_type=self.REPO_TYPE,
response = api_call(self, params)
repo = RepoModel().get_by_repo_name(repo_name)
self.assertNotEqual(repo, None)
ret = {
'msg': 'Created new repository `%s`' % repo_name,
'success': True,
'task': None,
expected = ret
self._compare_ok(id_, expected, given=response.body)
fixture.destroy_repo(repo_name)
def test_api_create_repo_and_repo_group(self):
repo_name = 'my_gr/api-repo'
id_, params = _build_data(self.apikey, 'create_repo',
repo_name=repo_name,
owner=TEST_USER_ADMIN_LOGIN,
repo_type=self.REPO_TYPE,)
print params
fixture.destroy_repo_group('my_gr')
def test_api_create_repo_in_repo_group_without_permission(self):
repo_group_name = '%s/api-repo-repo' % TEST_REPO_GROUP
repo_name = '%s/api-repo' % repo_group_name
rg = fixture.create_repo_group(repo_group_name)
RepoGroupModel().grant_user_permission(repo_group_name,
self.TEST_USER_LOGIN,
'group.none')
id_, params = _build_data(self.apikey_regular, 'create_repo',
# Current result when API access control is different from Web:
# Expected and arguably more correct result:
#expected = 'failed to create repository `%s`' % repo_name
#self._compare_error(id_, expected, given=response.body)
fixture.destroy_repo_group(repo_group_name)
def test_api_create_repo_unknown_owner(self):
repo_name = 'api-repo'
owner = 'i-dont-exist'
expected = 'user `%s` does not exist' % owner
self._compare_error(id_, expected, given=response.body)
def test_api_create_repo_dont_specify_owner(self):
def test_api_create_repo_by_non_admin(self):
def test_api_create_repo_by_non_admin_specify_owner(self):
owner=owner)
expected = 'Only Kallithea admin can specify `owner` param'
def test_api_create_repo_exists(self):
repo_name = self.REPO
expected = "repo `%s` already exist" % repo_name
@mock.patch.object(RepoModel, 'create', crash)
def test_api_create_repo_exception_occurred(self):
expected = 'failed to create repository `%s`' % repo_name
@parameterized.expand([
('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
('description', {'description': 'new description'}),
('active', {'active': True}),
('active', {'active': False}),
('clone_uri', {'clone_uri': 'http://example.com/repo'}),
('clone_uri', {'clone_uri': None}),
('landing_rev', {'landing_rev': 'branch:master'}),
('enable_statistics', {'enable_statistics': True}),
('enable_locking', {'enable_locking': True}),
('enable_downloads', {'enable_downloads': True}),
('name', {'name': 'new_repo_name'}),
('repo_group', {'group': 'test_group_for_update'}),
])
def test_api_update_repo(self, changing_attr, updates):
repo_name = 'api_update_me'
repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
if changing_attr == 'repo_group':
fixture.create_repo_group(updates['group'])
id_, params = _build_data(self.apikey, 'update_repo',
repoid=repo_name, **updates)
if changing_attr == 'name':
repo_name = updates['name']
repo_name = '/'.join([updates['group'], repo_name])
expected = {
'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
'repository': repo.get_api_data()
finally:
fixture.destroy_repo_group(updates['group'])
('description', {'description': u'new description'}),
('name', {'name': u'new_repo_name'}),
('repo_group', {'group': u'test_group_for_update'}),
def test_api_update_group_repo(self, changing_attr, updates):
group_name = u'lololo'
fixture.create_repo_group(group_name)
repo_name = u'%s/api_update_me' % group_name
repo = fixture.create_repo(repo_name, repo_group=group_name, repo_type=self.REPO_TYPE)
repo_name = u'%s/%s' % (group_name, updates['name'])
repo_name = u'/'.join([updates['group'], repo_name.rsplit('/', 1)[-1]])
fixture.destroy_repo_group(group_name)
def test_api_update_repo_repo_group_does_not_exist(self):
repo_name = 'admin_owned'
fixture.create_repo(repo_name)
updates = {'group': 'test_group_for_update'}
expected = 'repository group `%s` does not exist' % updates['group']
def test_api_update_repo_regular_user_not_allowed(self):
updates = {'active': False}
id_, params = _build_data(self.apikey_regular, 'update_repo',
expected = 'repository `%s` does not exist' % repo_name
@mock.patch.object(RepoModel, 'update', crash)
def test_api_update_repo_exception_occurred(self):
fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
repoid=repo_name, owner=TEST_USER_ADMIN_LOGIN,)
expected = 'failed to update repo `%s`' % repo_name
def test_api_update_repo_regular_user_change_repo_name(self):
new_repo_name = 'new_repo_name'
RepoModel().grant_user_permission(repo=repo_name,
user=self.TEST_USER_LOGIN,
perm='repository.admin')
UserModel().revoke_perm('default', 'hg.create.repository')
UserModel().grant_perm('default', 'hg.create.none')
updates = {'name': new_repo_name}
expected = 'no permission to create (or move) repositories'
fixture.destroy_repo(new_repo_name)
def test_api_update_repo_regular_user_change_repo_name_allowed(self):
UserModel().revoke_perm('default', 'hg.create.none')
UserModel().grant_perm('default', 'hg.create.repository')
'msg': 'updated repo ID:%s %s' % (repo.repo_id, new_repo_name),
def test_api_update_repo_regular_user_change_owner(self):
updates = {'owner': TEST_USER_ADMIN_LOGIN}
def test_api_delete_repo(self):
repo_name = 'api_delete_me'
id_, params = _build_data(self.apikey, 'delete_repo',
repoid=repo_name, )
'msg': 'Deleted repository `%s`' % repo_name,
'success': True
def test_api_delete_repo_by_non_admin(self):
fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
cur_user=self.TEST_USER_LOGIN)
id_, params = _build_data(self.apikey_regular, 'delete_repo',
def test_api_delete_repo_by_non_admin_no_permission(self):
expected = 'repository `%s` does not exist' % (repo_name)
def test_api_delete_repo_exception_occurred(self):
with mock.patch.object(RepoModel, 'delete', crash):
expected = 'failed to delete repository `%s`' % repo_name
def test_api_fork_repo(self):
fork_name = 'api-repo-fork'
id_, params = _build_data(self.apikey, 'fork_repo',
repoid=self.REPO,
fork_name=fork_name,
'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
fixture.destroy_repo(fork_name)
def test_api_fork_repo_non_admin(self):
id_, params = _build_data(self.apikey_regular, 'fork_repo',
Status change: