diff --git a/rhodecode/apps/repository/__init__.py b/rhodecode/apps/repository/__init__.py --- a/rhodecode/apps/repository/__init__.py +++ b/rhodecode/apps/repository/__init__.py @@ -21,6 +21,11 @@ def includeme(config): + # Settings + config.add_route( + name='edit_repo', + pattern='/{repo_name:.*?[^/]}/settings', repo_route=True) + config.add_route( name='repo_maintenance', pattern='/{repo_name:.*?[^/]}/maintenance', repo_route=True) @@ -29,7 +34,6 @@ def includeme(config): name='repo_maintenance_execute', pattern='/{repo_name:.*?[^/]}/maintenance/execute', repo_route=True) - # Strip config.add_route( name='strip', diff --git a/rhodecode/apps/repository/views/repo_settings.py b/rhodecode/apps/repository/views/repo_settings.py new file mode 100644 --- /dev/null +++ b/rhodecode/apps/repository/views/repo_settings.py @@ -0,0 +1,178 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2017 RhodeCode GmbH +# +# 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 . +# +# 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 + +import deform +from pyramid.httpexceptions import HTTPFound +from pyramid.view import view_config + +from rhodecode.apps._base import RepoAppView +from rhodecode.forms import RcForm +from rhodecode.lib import helpers as h +from rhodecode.lib import audit_logger +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator, + HasRepoPermissionAllDecorator, CSRFRequired) +from rhodecode.model.db import RepositoryField, RepoGroup +from rhodecode.model.meta import Session +from rhodecode.model.repo import RepoModel +from rhodecode.model.scm import RepoGroupList, ScmModel +from rhodecode.model.validation_schema.schemas import repo_schema + +log = logging.getLogger(__name__) + + +class RepoSettingsView(RepoAppView): + + def load_default_context(self): + c = self._get_local_tmpl_context() + + # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead + c.repo_info = self.db_repo + + acl_groups = RepoGroupList( + RepoGroup.query().all(), + perm_set=['group.write', 'group.admin']) + c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) + c.repo_groups_choices = map(lambda k: k[0], c.repo_groups) + + # in case someone no longer have a group.write access to a repository + # pre fill the list with this entry, we don't care if this is the same + # but it will allow saving repo data properly. + repo_group = self.db_repo.group + if repo_group and repo_group.group_id not in c.repo_groups_choices: + c.repo_groups_choices.append(repo_group.group_id) + c.repo_groups.append(RepoGroup._generate_choice(repo_group)) + + if c.repository_requirements_missing or self.rhodecode_vcs_repo is None: + # we might be in missing requirement state, so we load things + # without touching scm_instance() + c.landing_revs_choices, c.landing_revs = \ + ScmModel().get_repo_landing_revs() + else: + c.landing_revs_choices, c.landing_revs = \ + ScmModel().get_repo_landing_revs(self.db_repo) + + c.personal_repo_group = c.auth_user.personal_repo_group + c.repo_fields = RepositoryField.query()\ + .filter(RepositoryField.repository == self.db_repo).all() + + self._register_global_c(c) + return c + + def _get_schema(self, c, old_values=None): + return repo_schema.RepoSettingsSchema().bind( + repo_type_options=[self.db_repo.repo_type], + repo_ref_options=c.landing_revs_choices, + repo_ref_items=c.landing_revs, + repo_repo_group_options=c.repo_groups_choices, + repo_repo_group_items=c.repo_groups, + # user caller + user=self._rhodecode_user, + old_values=old_values + ) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.admin') + @view_config( + route_name='edit_repo', request_method='GET', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def edit_settings(self): + c = self.load_default_context() + c.active = 'settings' + + defaults = RepoModel()._get_defaults(self.db_repo_name) + defaults['repo_owner'] = defaults['user'] + defaults['repo_landing_commit_ref'] = defaults['repo_landing_rev'] + + schema = self._get_schema(c) + c.form = RcForm(schema, appstruct=defaults) + return self._get_template_context(c) + + @LoginRequired() + @HasRepoPermissionAllDecorator('repository.admin') + @CSRFRequired() + @view_config( + route_name='edit_repo', request_method='POST', + renderer='rhodecode:templates/admin/repos/repo_edit.mako') + def edit_settings_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'settings' + old_repo_name = self.db_repo_name + + old_values = self.db_repo.get_api_data() + schema = self._get_schema(c, old_values=old_values) + + c.form = RcForm(schema) + pstruct = self.request.POST.items() + pstruct.append(('repo_type', self.db_repo.repo_type)) + try: + schema_data = c.form.validate(pstruct) + except deform.ValidationFailure as err_form: + return self._get_template_context(c) + + # data is now VALID, proceed with updates + # save validated data back into the updates dict + validated_updates = dict( + repo_name=schema_data['repo_group']['repo_name_without_group'], + repo_group=schema_data['repo_group']['repo_group_id'], + + user=schema_data['repo_owner'], + repo_description=schema_data['repo_description'], + repo_private=schema_data['repo_private'], + clone_uri=schema_data['repo_clone_uri'], + repo_landing_rev=schema_data['repo_landing_commit_ref'], + repo_enable_statistics=schema_data['repo_enable_statistics'], + repo_enable_locking=schema_data['repo_enable_locking'], + repo_enable_downloads=schema_data['repo_enable_downloads'], + ) + # detect if CLONE URI changed, if we get OLD means we keep old values + if schema_data['repo_clone_uri_change'] == 'OLD': + validated_updates['clone_uri'] = self.db_repo.clone_uri + + # use the new full name for redirect + new_repo_name = schema_data['repo_group']['repo_name_with_group'] + + # save extra fields into our validated data + for key, value in pstruct: + if key.startswith(RepositoryField.PREFIX): + validated_updates[key] = value + + try: + RepoModel().update(self.db_repo, **validated_updates) + ScmModel().mark_for_invalidation(new_repo_name) + + audit_logger.store( + 'repo.edit', action_data={'old_data': old_values}, + user=self._rhodecode_user, repo=self.db_repo) + + Session().commit() + + h.flash(_('Repository {} updated successfully').format( + old_repo_name), category='success') + except Exception: + log.exception("Exception during update of repository") + h.flash(_('Error occurred during update of repository {}').format( + old_repo_name), category='error') + + raise HTTPFound( + self.request.route_path('edit_repo', repo_name=new_repo_name)) diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py --- a/rhodecode/config/routing.py +++ b/rhodecode/config/routing.py @@ -200,10 +200,6 @@ def make_map(config): action='index', conditions={'method': ['GET']}) m.connect('new_repo', '/create_repository', jsroute=True, action='create_repository', conditions={'method': ['GET']}) - m.connect('/repos/{repo_name}', - action='update', conditions={'method': ['PUT'], - 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) m.connect('delete_repo', '/repos/{repo_name}', action='delete', conditions={'method': ['DELETE']}, requirements=URL_NAME_REQUIREMENTS) @@ -665,11 +661,6 @@ def make_map(config): requirements=URL_NAME_REQUIREMENTS) # repo edit options - rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True, - controller='admin/repos', action='edit', - conditions={'method': ['GET'], 'function': check_repo}, - requirements=URL_NAME_REQUIREMENTS) - rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions', jsroute=True, controller='admin/repos', action='edit_permissions', diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py --- a/rhodecode/controllers/admin/repos.py +++ b/rhodecode/controllers/admin/repos.py @@ -290,65 +290,6 @@ class ReposController(BaseRepoController @HasRepoPermissionAllDecorator('repository.admin') @auth.CSRFRequired() - def update(self, repo_name): - """ - PUT /repos/repo_name: Update an existing item""" - # Forms posted to this method should contain a hidden field: - # - # Or using helpers: - # h.form(url('repo', repo_name=ID), - # method='put') - # url('repo', repo_name=ID) - - self.__load_data(repo_name) - c.active = 'settings' - c.repo_fields = RepositoryField.query()\ - .filter(RepositoryField.repository == c.repo_info).all() - - repo_model = RepoModel() - changed_name = repo_name - - c.personal_repo_group = c.rhodecode_user.personal_repo_group - # override the choices with extracted revisions ! - repo = Repository.get_by_repo_name(repo_name) - old_data = { - 'repo_name': repo_name, - 'repo_group': repo.group.get_dict() if repo.group else {}, - 'repo_type': repo.repo_type, - } - _form = RepoForm( - edit=True, old_data=old_data, repo_groups=c.repo_groups_choices, - landing_revs=c.landing_revs_choices, allow_disabled=True)() - - try: - form_result = _form.to_python(dict(request.POST)) - repo = repo_model.update(repo_name, **form_result) - ScmModel().mark_for_invalidation(repo_name) - h.flash(_('Repository %s updated successfully') % repo_name, - category='success') - changed_name = repo.repo_name - action_logger(c.rhodecode_user, 'admin_updated_repo', - changed_name, self.ip_addr, self.sa) - Session().commit() - except formencode.Invalid as errors: - defaults = self.__load_data(repo_name) - defaults.update(errors.value) - return htmlfill.render( - render('admin/repos/repo_edit.mako'), - defaults=defaults, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False) - - except Exception: - log.exception("Exception during update of repository") - h.flash(_('Error occurred during update of repository %s') \ - % repo_name, category='error') - return redirect(url('edit_repo', repo_name=changed_name)) - - @HasRepoPermissionAllDecorator('repository.admin') - @auth.CSRFRequired() def delete(self, repo_name): """ DELETE /repos/repo_name: Delete an existing item""" @@ -398,27 +339,8 @@ class ReposController(BaseRepoController # url('repo', repo_name=ID) @HasRepoPermissionAllDecorator('repository.admin') - def edit(self, repo_name): - """GET /repo_name/settings: Form to edit an existing item""" - # url('edit_repo', repo_name=ID) - defaults = self.__load_data(repo_name) - if 'clone_uri' in defaults: - del defaults['clone_uri'] - - c.repo_fields = RepositoryField.query()\ - .filter(RepositoryField.repository == c.repo_info).all() - c.personal_repo_group = c.rhodecode_user.personal_repo_group - c.active = 'settings' - return htmlfill.render( - render('admin/repos/repo_edit.mako'), - defaults=defaults, - encoding="UTF-8", - force_defaults=False) - - @HasRepoPermissionAllDecorator('repository.admin') def edit_permissions(self, repo_name): """GET /repo_name/settings: Form to edit an existing item""" - # url('edit_repo', repo_name=ID) c.repo_info = self._load_repo(repo_name) c.active = 'permissions' defaults = RepoModel()._get_defaults(repo_name) @@ -446,7 +368,6 @@ class ReposController(BaseRepoController @HasRepoPermissionAllDecorator('repository.admin') def edit_fields(self, repo_name): """GET /repo_name/settings: Form to edit an existing item""" - # url('edit_repo', repo_name=ID) c.repo_info = self._load_repo(repo_name) c.repo_fields = RepositoryField.query()\ .filter(RepositoryField.repository == c.repo_info).all() @@ -493,7 +414,6 @@ class ReposController(BaseRepoController @HasRepoPermissionAllDecorator('repository.admin') def edit_advanced(self, repo_name): """GET /repo_name/settings: Form to edit an existing item""" - # url('edit_repo', repo_name=ID) c.repo_info = self._load_repo(repo_name) c.default_user_id = User.get_default_user().user_id c.in_public_journal = UserFollowing.query()\ @@ -638,7 +558,6 @@ class ReposController(BaseRepoController @HasRepoPermissionAllDecorator('repository.admin') def edit_caches_form(self, repo_name): """GET /repo_name/settings: Form to edit an existing item""" - # url('edit_repo', repo_name=ID) c.repo_info = self._load_repo(repo_name) c.active = 'caches' @@ -660,7 +579,6 @@ class ReposController(BaseRepoController @HasRepoPermissionAllDecorator('repository.admin') def edit_remote_form(self, repo_name): """GET /repo_name/settings: Form to edit an existing item""" - # url('edit_repo', repo_name=ID) c.repo_info = self._load_repo(repo_name) c.active = 'remote' @@ -682,7 +600,6 @@ class ReposController(BaseRepoController @HasRepoPermissionAllDecorator('repository.admin') def edit_statistics_form(self, repo_name): """GET /repo_name/settings: Form to edit an existing item""" - # url('edit_repo', repo_name=ID) c.repo_info = self._load_repo(repo_name) repo = c.repo_info.scm_instance() diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -2184,7 +2184,7 @@ class RepoGroup(Base, BaseModel): repo_groups = [] if show_empty_group: - repo_groups = [('-1', u'-- %s --' % _('No parent'))] + repo_groups = [(-1, u'-- %s --' % _('No parent'))] repo_groups.extend([cls._generate_choice(x) for x in groups]) diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py --- a/rhodecode/model/repo.py +++ b/rhodecode/model/repo.py @@ -333,12 +333,6 @@ class RepoModel(BaseModel): val = kwargs[k] if strip: k = remove_prefix(k, 'repo_') - if k == 'clone_uri': - from rhodecode.model.validators import Missing - _change = kwargs.get('clone_uri_change') - if _change in [Missing, 'OLD']: - # we don't change the value, so use original one - val = cur_repo.clone_uri setattr(cur_repo, k, val) diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -24,7 +24,6 @@ function registerRCRoutes() { pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']); pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']); - pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']); pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']); @@ -98,6 +97,7 @@ function registerRCRoutes() { pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); pyroutes.register('repo_list_data', '/_repos', []); pyroutes.register('goto_switcher_data', '/_goto_data', []); + pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']); pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']); pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']); diff --git a/rhodecode/templates/admin/integrations/form.mako b/rhodecode/templates/admin/integrations/form.mako --- a/rhodecode/templates/admin/integrations/form.mako +++ b/rhodecode/templates/admin/integrations/form.mako @@ -3,7 +3,7 @@ <%def name="breadcrumbs_links()"> %if c.repo: - ${h.link_to('Settings',h.url('edit_repo', repo_name=c.repo.repo_name))} + ${h.link_to('Settings',h.route_path('edit_repo', repo_name=c.repo.repo_name))} » ${h.link_to(_('Integrations'),request.route_url(route_name='repo_integrations_home', repo_name=c.repo.repo_name))} » diff --git a/rhodecode/templates/admin/integrations/list.mako b/rhodecode/templates/admin/integrations/list.mako --- a/rhodecode/templates/admin/integrations/list.mako +++ b/rhodecode/templates/admin/integrations/list.mako @@ -3,7 +3,7 @@ <%def name="breadcrumbs_links()"> %if c.repo: - ${h.link_to('Settings',h.url('edit_repo', repo_name=c.repo.repo_name))} + ${h.link_to('Settings',h.route_path('edit_repo', repo_name=c.repo.repo_name))} %elif c.repo_group: ${h.link_to(_('Admin'),h.url('admin_home'))} » diff --git a/rhodecode/templates/admin/integrations/new.mako b/rhodecode/templates/admin/integrations/new.mako --- a/rhodecode/templates/admin/integrations/new.mako +++ b/rhodecode/templates/admin/integrations/new.mako @@ -4,7 +4,7 @@ <%def name="breadcrumbs_links()"> %if c.repo: - ${h.link_to('Settings',h.url('edit_repo', repo_name=c.repo.repo_name))} + ${h.link_to('Settings',h.route_path('edit_repo', repo_name=c.repo.repo_name))} » ${h.link_to(_('Integrations'),request.route_url(route_name='repo_integrations_home', repo_name=c.repo.repo_name))} %elif c.repo_group: diff --git a/rhodecode/templates/admin/repos/repo_edit.mako b/rhodecode/templates/admin/repos/repo_edit.mako --- a/rhodecode/templates/admin/repos/repo_edit.mako +++ b/rhodecode/templates/admin/repos/repo_edit.mako @@ -40,7 +40,7 @@