integrations: rewrote usage of pylons components inside integrations.

- added better auth decorators as used in other parts of the app
- fixed tests
- refactored the code to match other parts better (repo_route/repo_group_route)
This commit is contained in:
Marcin Kuzminski 2017-08-01 23:11:49 +02:00
parent 2c11516c9b
commit 17359c262c
10 changed files with 471 additions and 382 deletions

View file

@ -21,6 +21,7 @@
import logging
from rhodecode.apps._base import ADMIN_PREFIX, add_route_requirements
from rhodecode.lib.utils2 import safe_int
from rhodecode.model.db import Repository, Integration, RepoGroup
from rhodecode.integrations import integration_type_registry
@ -30,7 +31,6 @@ log = logging.getLogger(__name__)
def includeme(config):
# global integrations
config.add_route('global_integrations_new',
ADMIN_PREFIX + '/integrations/new')
config.add_view('rhodecode.integrations.views.GlobalIntegrationsView',
@ -45,7 +45,7 @@ def includeme(config):
ADMIN_PREFIX + '/integrations/{integration}')
for route_name in ['global_integrations_home', 'global_integrations_list']:
config.add_view('rhodecode.integrations.views.GlobalIntegrationsView',
attr='index',
attr='integration_list',
renderer='rhodecode:templates/admin/integrations/list.mako',
request_method='GET',
route_name=route_name)
@ -57,7 +57,6 @@ def includeme(config):
ADMIN_PREFIX + '/integrations/{integration}/{integration_id}',
custom_predicates=(valid_integration,))
for route_name in ['global_integrations_create', 'global_integrations_edit']:
config.add_view('rhodecode.integrations.views.GlobalIntegrationsView',
attr='settings_get',
@ -70,154 +69,159 @@ def includeme(config):
request_method='POST',
route_name=route_name)
# repo group integrations
config.add_route('repo_group_integrations_home',
add_route_requirements(
'{repo_group_name}/settings/integrations',
),
custom_predicates=(valid_repo_group,)
)
config.add_route('repo_group_integrations_list',
add_route_requirements(
'{repo_group_name}/settings/integrations/{integration}',
),
custom_predicates=(valid_repo_group, valid_integration))
for route_name in ['repo_group_integrations_home', 'repo_group_integrations_list']:
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='index',
renderer='rhodecode:templates/admin/integrations/list.mako',
request_method='GET',
route_name=route_name)
add_route_requirements('/{repo_group_name}/settings/integrations'),
repo_group_route=True)
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='integration_list',
renderer='rhodecode:templates/admin/integrations/list.mako',
request_method='GET',
route_name='repo_group_integrations_home')
config.add_route('repo_group_integrations_new',
add_route_requirements(
'{repo_group_name}/settings/integrations/new',
),
custom_predicates=(valid_repo_group,))
add_route_requirements('/{repo_group_name}/settings/integrations/new'),
repo_group_route=True)
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='new_integration',
renderer='rhodecode:templates/admin/integrations/new.mako',
request_method='GET',
route_name='repo_group_integrations_new')
config.add_route('repo_group_integrations_create',
add_route_requirements(
'{repo_group_name}/settings/integrations/{integration}/new',
),
custom_predicates=(valid_repo_group, valid_integration))
config.add_route('repo_group_integrations_edit',
add_route_requirements(
'{repo_group_name}/settings/integrations/{integration}/{integration_id}',
),
custom_predicates=(valid_repo_group, valid_integration))
for route_name in ['repo_group_integrations_edit', 'repo_group_integrations_create']:
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='settings_get',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='GET',
route_name=route_name)
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='settings_post',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='POST',
route_name=route_name)
config.add_route('repo_group_integrations_list',
add_route_requirements('/{repo_group_name}/settings/integrations/{integration}'),
repo_group_route=True,
custom_predicates=(valid_integration,))
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='integration_list',
renderer='rhodecode:templates/admin/integrations/list.mako',
request_method='GET',
route_name='repo_group_integrations_list')
config.add_route('repo_group_integrations_create',
add_route_requirements('/{repo_group_name}/settings/integrations/{integration}/new'),
repo_group_route=True,
custom_predicates=(valid_integration,))
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='settings_get',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='GET',
route_name='repo_group_integrations_create')
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='settings_post',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='POST',
route_name='repo_group_integrations_create')
config.add_route('repo_group_integrations_edit',
add_route_requirements('/{repo_group_name}/settings/integrations/{integration}/{integration_id}'),
repo_group_route=True,
custom_predicates=(valid_integration,))
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='settings_get',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='GET',
route_name='repo_group_integrations_edit')
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='settings_post',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='POST',
route_name='repo_group_integrations_edit')
# repo integrations
config.add_route('repo_integrations_home',
add_route_requirements(
'{repo_name}/settings/integrations',
),
custom_predicates=(valid_repo,))
config.add_route('repo_integrations_list',
add_route_requirements(
'{repo_name}/settings/integrations/{integration}',
),
custom_predicates=(valid_repo, valid_integration))
for route_name in ['repo_integrations_home', 'repo_integrations_list']:
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='index',
request_method='GET',
renderer='rhodecode:templates/admin/integrations/list.mako',
route_name=route_name)
add_route_requirements('/{repo_name}/settings/integrations'),
repo_route=True)
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='integration_list',
request_method='GET',
renderer='rhodecode:templates/admin/integrations/list.mako',
route_name='repo_integrations_home')
config.add_route('repo_integrations_new',
add_route_requirements(
'{repo_name}/settings/integrations/new',
),
custom_predicates=(valid_repo,))
add_route_requirements('/{repo_name}/settings/integrations/new'),
repo_route=True)
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='new_integration',
renderer='rhodecode:templates/admin/integrations/new.mako',
request_method='GET',
route_name='repo_integrations_new')
config.add_route('repo_integrations_list',
add_route_requirements('/{repo_name}/settings/integrations/{integration}'),
repo_route=True,
custom_predicates=(valid_integration,))
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='integration_list',
request_method='GET',
renderer='rhodecode:templates/admin/integrations/list.mako',
route_name='repo_integrations_list')
config.add_route('repo_integrations_create',
add_route_requirements(
'{repo_name}/settings/integrations/{integration}/new',
),
custom_predicates=(valid_repo, valid_integration))
add_route_requirements('/{repo_name}/settings/integrations/{integration}/new'),
repo_route=True,
custom_predicates=(valid_integration,))
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='settings_get',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='GET',
route_name='repo_integrations_create')
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='settings_post',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='POST',
route_name='repo_integrations_create')
config.add_route('repo_integrations_edit',
add_route_requirements(
'{repo_name}/settings/integrations/{integration}/{integration_id}',
),
custom_predicates=(valid_repo, valid_integration))
for route_name in ['repo_integrations_edit', 'repo_integrations_create']:
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='settings_get',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='GET',
route_name=route_name)
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='settings_post',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='POST',
route_name=route_name)
add_route_requirements('/{repo_name}/settings/integrations/{integration}/{integration_id}'),
repo_route=True,
custom_predicates=(valid_integration,))
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='settings_get',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='GET',
route_name='repo_integrations_edit')
config.add_view('rhodecode.integrations.views.RepoIntegrationsView',
attr='settings_post',
renderer='rhodecode:templates/admin/integrations/form.mako',
request_method='POST',
route_name='repo_integrations_edit')
def valid_repo(info, request):
repo = Repository.get_by_repo_name(info['match']['repo_name'])
if repo:
return True
def valid_repo_group(info, request):
repo_group = RepoGroup.get_by_group_name(info['match']['repo_group_name'])
if repo_group:
return True
return False
def valid_integration(info, request):
integration_type = info['match']['integration']
integration_id = info['match'].get('integration_id')
repo_name = info['match'].get('repo_name')
repo_group_name = info['match'].get('repo_group_name')
if integration_type not in integration_type_registry:
return False
repo, repo_group = None, None
if repo_name:
repo = Repository.get_by_repo_name(repo_name)
if not repo:
return False
if repo_group_name:
repo_group = RepoGroup.get_by_group_name(repo_group_name)
if not repo_group:
return False
if repo_name and repo_group:
raise Exception('Either repo or repo_group can be set, not both')
if integration_id:
if not safe_int(integration_id):
return False
integration = Integration.get(integration_id)
if not integration:
return False
if integration.integration_type != integration_type:
return False
# match types to repo or repo group
repo_name = info['match'].get('repo_name')
repo_group_name = info['match'].get('repo_group_name')
repo, repo_group = None, None
if repo_name:
repo = Repository.get_by_repo_name(repo_name)
if not repo:
return False
if repo_group_name:
repo_group = RepoGroup.get_by_group_name(repo_group_name)
if not repo_group:
return False
if repo and repo.repo_id != integration.repo_id:
return False
if repo_group and repo_group.group_id != integration.repo_group_id:

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016-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 <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/

View file

@ -20,10 +20,16 @@
import pytest
from rhodecode.apps._base import ADMIN_PREFIX
from rhodecode.model.db import Integration
from rhodecode.model.meta import Session
from rhodecode.integrations import integration_type_registry
from rhodecode.config.routing import ADMIN_PREFIX
def route_path(name, **kwargs):
return {
'home': '/',
}[name].format(**kwargs)
@pytest.mark.usefixtures('app', 'autologin_user')
@ -32,86 +38,141 @@ class TestIntegrationsView(object):
class TestGlobalIntegrationsView(TestIntegrationsView):
def test_index_no_integrations(self, app):
def test_index_no_integrations(self):
url = ADMIN_PREFIX + '/integrations'
response = app.get(url)
response = self.app.get(url)
assert response.status_code == 200
assert 'exist yet' in response.body
def test_index_with_integrations(self, app, global_integration_stub):
def test_index_with_integrations(self, global_integration_stub):
url = ADMIN_PREFIX + '/integrations'
response = app.get(url)
response = self.app.get(url)
assert response.status_code == 200
assert 'exist yet' not in response.body
assert global_integration_stub.name in response.body
def test_new_integration_page(self, app):
@pytest.mark.parametrize(
'IntegrationType', integration_type_registry.values())
def test_new_integration_page(self, IntegrationType):
url = ADMIN_PREFIX + '/integrations/new'
response = app.get(url)
response = self.app.get(url, status=200)
assert response.status_code == 200
for integration_key in integration_type_registry:
nurl = (ADMIN_PREFIX + '/integrations/{integration}/new').format(
integration=integration_key)
assert nurl in response.body
url = (ADMIN_PREFIX + '/integrations/{integration}/new').format(
integration=IntegrationType.key)
assert url in response.body
@pytest.mark.parametrize(
'IntegrationType', integration_type_registry.values())
def test_get_create_integration_page(self, app, IntegrationType):
def test_get_create_integration_page(self, IntegrationType):
url = ADMIN_PREFIX + '/integrations/{integration_key}/new'.format(
integration_key=IntegrationType.key)
response = app.get(url)
response = self.app.get(url, status=200)
assert response.status_code == 200
assert IntegrationType.display_name in response.body
def test_post_integration_page(self, app, StubIntegrationType, csrf_token,
def test_post_integration_page(self, StubIntegrationType, csrf_token,
test_repo_group, backend_random):
url = ADMIN_PREFIX + '/integrations/{integration_key}/new'.format(
integration_key=StubIntegrationType.key)
_post_integration_test_helper(app, url, csrf_token, admin_view=True,
_post_integration_test_helper(self.app, url, csrf_token, admin_view=True,
repo=backend_random.repo, repo_group=test_repo_group)
class TestRepoGroupIntegrationsView(TestIntegrationsView):
def test_index_no_integrations(self, app, test_repo_group):
url = '/{repo_group_name}/settings/integrations'.format(
repo_group_name=test_repo_group.group_name)
response = app.get(url)
class TestRepoIntegrationsView(TestIntegrationsView):
def test_index_no_integrations(self, backend_random):
url = '/{repo_name}/settings/integrations'.format(
repo_name=backend_random.repo.repo_name)
response = self.app.get(url)
assert response.status_code == 200
assert 'exist yet' in response.body
def test_index_with_integrations(self, app, test_repo_group,
repogroup_integration_stub):
def test_index_with_integrations(self, repo_integration_stub):
url = '/{repo_name}/settings/integrations'.format(
repo_name=repo_integration_stub.repo.repo_name)
stub_name = repo_integration_stub.name
response = self.app.get(url)
assert response.status_code == 200
assert stub_name in response.body
assert 'exist yet' not in response.body
@pytest.mark.parametrize(
'IntegrationType', integration_type_registry.values())
def test_new_integration_page(self, backend_random, IntegrationType):
repo_name = backend_random.repo.repo_name
url = '/{repo_name}/settings/integrations/new'.format(
repo_name=repo_name)
response = self.app.get(url, status=200)
url = '/{repo_name}/settings/integrations/{integration}/new'.format(
repo_name=repo_name,
integration=IntegrationType.key)
assert url in response.body
@pytest.mark.parametrize(
'IntegrationType', integration_type_registry.values())
def test_get_create_integration_page(self, backend_random, IntegrationType):
repo_name = backend_random.repo.repo_name
url = '/{repo_name}/settings/integrations/{integration_key}/new'.format(
repo_name=repo_name, integration_key=IntegrationType.key)
response = self.app.get(url, status=200)
assert IntegrationType.display_name in response.body
def test_post_integration_page(self, backend_random, test_repo_group,
StubIntegrationType, csrf_token):
repo_name = backend_random.repo.repo_name
url = '/{repo_name}/settings/integrations/{integration_key}/new'.format(
repo_name=repo_name, integration_key=StubIntegrationType.key)
_post_integration_test_helper(
self.app, url, csrf_token, admin_view=False,
repo=backend_random.repo, repo_group=test_repo_group)
class TestRepoGroupIntegrationsView(TestIntegrationsView):
def test_index_no_integrations(self, test_repo_group):
url = '/{repo_group_name}/settings/integrations'.format(
repo_group_name=test_repo_group.group_name)
response = self.app.get(url)
assert response.status_code == 200
assert 'exist yet' in response.body
def test_index_with_integrations(
self, test_repo_group, repogroup_integration_stub):
url = '/{repo_group_name}/settings/integrations'.format(
repo_group_name=test_repo_group.group_name)
stub_name = repogroup_integration_stub.name
response = app.get(url)
response = self.app.get(url)
assert response.status_code == 200
assert 'exist yet' not in response.body
assert stub_name in response.body
def test_new_integration_page(self, app, test_repo_group):
def test_new_integration_page(self, test_repo_group):
repo_group_name = test_repo_group.group_name
url = '/{repo_group_name}/settings/integrations/new'.format(
repo_group_name=test_repo_group.group_name)
response = app.get(url)
response = self.app.get(url)
assert response.status_code == 200
for integration_key in integration_type_registry:
nurl = ('/{repo_group_name}/settings/integrations'
'/{integration}/new').format(
nurl = ('/{repo_group_name}/settings/integrations/{integration}/new').format(
repo_group_name=repo_group_name,
integration=integration_key)
@ -119,86 +180,29 @@ class TestRepoGroupIntegrationsView(TestIntegrationsView):
@pytest.mark.parametrize(
'IntegrationType', integration_type_registry.values())
def test_get_create_integration_page(self, app, test_repo_group,
IntegrationType):
def test_get_create_integration_page(
self, test_repo_group, IntegrationType):
repo_group_name = test_repo_group.group_name
url = ('/{repo_group_name}/settings/integrations/{integration_key}/new'
).format(repo_group_name=repo_group_name,
integration_key=IntegrationType.key)
response = app.get(url)
response = self.app.get(url)
assert response.status_code == 200
assert IntegrationType.display_name in response.body
def test_post_integration_page(self, app, test_repo_group, backend_random,
def test_post_integration_page(self, test_repo_group, backend_random,
StubIntegrationType, csrf_token):
repo_group_name = test_repo_group.group_name
url = ('/{repo_group_name}/settings/integrations/{integration_key}/new'
).format(repo_group_name=repo_group_name,
integration_key=StubIntegrationType.key)
_post_integration_test_helper(app, url, csrf_token, admin_view=False,
repo=backend_random.repo, repo_group=test_repo_group)
class TestRepoIntegrationsView(TestIntegrationsView):
def test_index_no_integrations(self, app, backend_random):
url = '/{repo_name}/settings/integrations'.format(
repo_name=backend_random.repo.repo_name)
response = app.get(url)
assert response.status_code == 200
assert 'exist yet' in response.body
def test_index_with_integrations(self, app, repo_integration_stub):
url = '/{repo_name}/settings/integrations'.format(
repo_name=repo_integration_stub.repo.repo_name)
stub_name = repo_integration_stub.name
response = app.get(url)
assert response.status_code == 200
assert stub_name in response.body
assert 'exist yet' not in response.body
def test_new_integration_page(self, app, backend_random):
repo_name = backend_random.repo.repo_name
url = '/{repo_name}/settings/integrations/new'.format(
repo_name=repo_name)
response = app.get(url)
assert response.status_code == 200
for integration_key in integration_type_registry:
nurl = ('/{repo_name}/settings/integrations'
'/{integration}/new').format(
repo_name=repo_name,
integration=integration_key)
assert nurl in response.body
@pytest.mark.parametrize(
'IntegrationType', integration_type_registry.values())
def test_get_create_integration_page(self, app, backend_random,
IntegrationType):
repo_name = backend_random.repo.repo_name
url = '/{repo_name}/settings/integrations/{integration_key}/new'.format(
repo_name=repo_name, integration_key=IntegrationType.key)
response = app.get(url)
assert response.status_code == 200
assert IntegrationType.display_name in response.body
def test_post_integration_page(self, app, backend_random, test_repo_group,
StubIntegrationType, csrf_token):
repo_name = backend_random.repo.repo_name
url = '/{repo_name}/settings/integrations/{integration_key}/new'.format(
repo_name=repo_name, integration_key=StubIntegrationType.key)
_post_integration_test_helper(app, url, csrf_token, admin_view=False,
_post_integration_test_helper(
self.app, url, csrf_token, admin_view=False,
repo=backend_random.repo, repo_group=test_repo_group)
@ -208,7 +212,8 @@ def _post_integration_test_helper(app, url, csrf_token, repo, repo_group,
Posts form data to create integration at the url given then deletes it and
checks if the redirect url is correct.
"""
repo_name = repo.repo_name
repo_group_name = repo_group.group_name
app.post(url, params={}, status=403) # missing csrf check
response = app.post(url, params={'csrf_token': csrf_token})
assert response.status_code == 200
@ -216,15 +221,15 @@ def _post_integration_test_helper(app, url, csrf_token, repo, repo_group,
scopes_destinations = [
('global',
ADMIN_PREFIX + '/integrations'),
ADMIN_PREFIX + '/integrations'),
('root-repos',
ADMIN_PREFIX + '/integrations'),
('repo:%s' % repo.repo_name,
'/%s/settings/integrations' % repo.repo_name),
('repogroup:%s' % repo_group.group_name,
'/%s/settings/integrations' % repo_group.group_name),
('repogroup-recursive:%s' % repo_group.group_name,
'/%s/settings/integrations' % repo_group.group_name),
('repo:%s' % repo_name,
'/%s/settings/integrations' % repo_name),
('repogroup:%s' % repo_group_name,
'/%s/settings/integrations' % repo_group_name),
('repogroup-recursive:%s' % repo_group_name,
'/%s/settings/integrations' % repo_group_name),
]
for scope, destination in scopes_destinations:

View file

@ -18,45 +18,40 @@
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import pylons
import deform
import logging
import colander
import peppercorn
import webhelpers.paginate
from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest
from pyramid.renderers import render
from pyramid.response import Response
from pyramid.httpexceptions import HTTPFound, HTTPForbidden
from rhodecode.apps._base import BaseAppView
from rhodecode.integrations import integration_type_registry
from rhodecode.apps.admin.navigation import navigation_list
from rhodecode.lib import auth
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
from rhodecode.lib.auth import (
LoginRequired, CSRFRequired, HasPermissionAnyDecorator,
HasRepoPermissionAnyDecorator, HasRepoGroupPermissionAnyDecorator)
from rhodecode.lib.utils2 import safe_int
from rhodecode.lib.helpers import Page
from rhodecode.model.db import Repository, RepoGroup, Session, Integration
from rhodecode.model.scm import ScmModel
from rhodecode.model.integration import IntegrationModel
from rhodecode.translation import _
from rhodecode.integrations import integration_type_registry
from rhodecode.model.validation_schema.schemas.integration_schema import (
make_integration_schema, IntegrationScopeType)
log = logging.getLogger(__name__)
class IntegrationSettingsViewBase(object):
""" Base Integration settings view used by both repo / global settings """
class IntegrationSettingsViewBase(BaseAppView):
"""
Base Integration settings view used by both repo / global settings
"""
def __init__(self, context, request):
self.context = context
self.request = request
self._load_general_context()
super(IntegrationSettingsViewBase, self).__init__(context, request)
self._load_view_context()
if not self.perm_check(request.user):
raise HTTPForbidden()
def _load_general_context(self):
def _load_view_context(self):
"""
This avoids boilerplate for repo/global+list/edit+views/templates
by doing all possible contexts at the same time however it should
@ -110,25 +105,12 @@ class IntegrationSettingsViewBase(object):
return False
def _template_c_context(self):
# TODO: dan: this is a stopgap in order to inherit from current pylons
# based admin/repo settings templates - this should be removed entirely
# after port to pyramid
def _get_local_tmpl_context(self, include_app_defaults=False):
_ = self.request.translate
c = super(IntegrationSettingsViewBase, self)._get_local_tmpl_context(
include_app_defaults=include_app_defaults)
c = pylons.tmpl_context
c.active = 'integrations'
c.rhodecode_user = self.request.user
c.repo = self.repo
c.repo_group = self.repo_group
c.repo_name = self.repo and self.repo.repo_name or None
c.repo_group_name = self.repo_group and self.repo_group.group_name or None
if self.repo:
c.repo_info = self.repo
c.rhodecode_db_repo = self.repo
c.repository_pull_requests = ScmModel().get_pull_requests(self.repo)
else:
c.navlist = navigation_list(self.request)
return c
@ -142,6 +124,7 @@ class IntegrationSettingsViewBase(object):
no_scope=not self.admin_view)
def _form_defaults(self):
_ = self.request.translate
defaults = {}
if self.integration:
@ -178,28 +161,79 @@ class IntegrationSettingsViewBase(object):
return defaults
def _delete_integration(self, integration):
Session().delete(self.integration)
_ = self.request.translate
Session().delete(integration)
Session().commit()
self.request.session.flash(
_('Integration {integration_name} deleted successfully.').format(
integration_name=self.integration.name),
integration_name=integration.name),
queue='success')
if self.repo:
redirect_to = self.request.route_url(
redirect_to = self.request.route_path(
'repo_integrations_home', repo_name=self.repo.repo_name)
elif self.repo_group:
redirect_to = self.request.route_url(
redirect_to = self.request.route_path(
'repo_group_integrations_home',
repo_group_name=self.repo_group.group_name)
else:
redirect_to = self.request.route_url('global_integrations_home')
redirect_to = self.request.route_path('global_integrations_home')
raise HTTPFound(redirect_to)
def settings_get(self, defaults=None, form=None):
def _integration_list(self):
""" List integrations """
c = self.load_default_context()
if self.repo:
scope = self.repo
elif self.repo_group:
scope = self.repo_group
else:
scope = 'all'
integrations = []
for IntType, integration in IntegrationModel().get_integrations(
scope=scope, IntegrationType=self.IntegrationType):
# extra permissions check *just in case*
if not self._has_perms_for_integration(integration):
continue
integrations.append((IntType, integration))
sort_arg = self.request.GET.get('sort', 'name:asc')
if ':' in sort_arg:
sort_field, sort_dir = sort_arg.split(':')
else:
sort_field = sort_arg, 'asc'
assert sort_field in ('name', 'integration_type', 'enabled', 'scope')
integrations.sort(
key=lambda x: getattr(x[1], sort_field),
reverse=(sort_dir == 'desc'))
page_url = webhelpers.paginate.PageURL(
self.request.path, self.request.GET)
page = safe_int(self.request.GET.get('page', 1), 1)
integrations = Page(
integrations, page=page, items_per_page=10, url=page_url)
c.rev_sort_dir = sort_dir != 'desc' and 'desc' or 'asc'
c.current_IntegrationType = self.IntegrationType
c.integrations_list = integrations
c.available_integrations = integration_type_registry
return self._get_template_context(c)
def _settings_get(self, defaults=None, form=None):
"""
View that displays the integration settings as a form.
"""
c = self.load_default_context()
defaults = defaults or self._form_defaults()
schema = self._form_schema()
@ -211,20 +245,18 @@ class IntegrationSettingsViewBase(object):
form = form or deform.Form(schema, appstruct=defaults, buttons=buttons)
template_context = {
'form': form,
'current_IntegrationType': self.IntegrationType,
'integration': self.integration,
'c': self._template_c_context(),
}
c.form = form
c.current_IntegrationType = self.IntegrationType
c.integration = self.integration
return template_context
return self._get_template_context(c)
@auth.CSRFRequired()
def settings_post(self):
def _settings_post(self):
"""
View that validates and stores the integration settings.
"""
_ = self.request.translate
controls = self.request.POST.items()
pstruct = peppercorn.parse(controls)
@ -264,7 +296,7 @@ class IntegrationSettingsViewBase(object):
_('Errors exist when saving integration settings. '
'Please check the form inputs.'),
queue='error')
return self.settings_get(form=e)
return self._settings_get(form=e)
if not self.integration:
self.integration = Integration()
@ -314,77 +346,110 @@ class IntegrationSettingsViewBase(object):
return HTTPFound(redirect_to)
def index(self):
""" List integrations """
if self.repo:
scope = self.repo
elif self.repo_group:
scope = self.repo_group
else:
scope = 'all'
def _new_integration(self):
c = self.load_default_context()
c.available_integrations = integration_type_registry
return self._get_template_context(c)
integrations = []
for IntType, integration in IntegrationModel().get_integrations(
scope=scope, IntegrationType=self.IntegrationType):
# extra permissions check *just in case*
if not self._has_perms_for_integration(integration):
continue
integrations.append((IntType, integration))
sort_arg = self.request.GET.get('sort', 'name:asc')
if ':' in sort_arg:
sort_field, sort_dir = sort_arg.split(':')
else:
sort_field = sort_arg, 'asc'
assert sort_field in ('name', 'integration_type', 'enabled', 'scope')
integrations.sort(
key=lambda x: getattr(x[1], sort_field),
reverse=(sort_dir == 'desc'))
page_url = webhelpers.paginate.PageURL(
self.request.path, self.request.GET)
page = safe_int(self.request.GET.get('page', 1), 1)
integrations = Page(integrations, page=page, items_per_page=10,
url=page_url)
template_context = {
'sort_field': sort_field,
'rev_sort_dir': sort_dir != 'desc' and 'desc' or 'asc',
'current_IntegrationType': self.IntegrationType,
'integrations_list': integrations,
'available_integrations': integration_type_registry,
'c': self._template_c_context(),
'request': self.request,
}
return template_context
def new_integration(self):
template_context = {
'available_integrations': integration_type_registry,
'c': self._template_c_context(),
}
return template_context
def load_default_context(self):
raise NotImplementedError()
class GlobalIntegrationsView(IntegrationSettingsViewBase):
def perm_check(self, user):
return auth.HasPermissionAll('hg.admin').check_permissions(user=user)
def load_default_context(self):
c = self._get_local_tmpl_context()
c.repo = self.repo
c.repo_group = self.repo_group
c.navlist = navigation_list(self.request)
self._register_global_c(c)
return c
@LoginRequired()
@HasPermissionAnyDecorator('hg.admin')
def integration_list(self):
return self._integration_list()
@LoginRequired()
@HasPermissionAnyDecorator('hg.admin')
def settings_get(self):
return self._settings_get()
@LoginRequired()
@HasPermissionAnyDecorator('hg.admin')
@CSRFRequired()
def settings_post(self):
return self._settings_post()
@LoginRequired()
@HasPermissionAnyDecorator('hg.admin')
def new_integration(self):
return self._new_integration()
class RepoIntegrationsView(IntegrationSettingsViewBase):
def perm_check(self, user):
return auth.HasRepoPermissionAll('repository.admin')(
repo_name=self.repo.repo_name, user=user)
def load_default_context(self):
c = self._get_local_tmpl_context()
c.repo = self.repo
c.repo_group = self.repo_group
# TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
c.repo_info = self.db_repo = self.repo
c.rhodecode_db_repo = self.repo
c.repo_name = self.db_repo.repo_name
c.repository_pull_requests = ScmModel().get_pull_requests(self.repo)
self._register_global_c(c)
return c
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.admin')
def integration_list(self):
return self._integration_list()
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.admin')
def settings_get(self):
return self._settings_get()
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.admin')
@CSRFRequired()
def settings_post(self):
return self._settings_post()
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.admin')
def new_integration(self):
return self._new_integration()
class RepoGroupIntegrationsView(IntegrationSettingsViewBase):
def perm_check(self, user):
return auth.HasRepoGroupPermissionAll('group.admin')(
group_name=self.repo_group.group_name, user=user)
def load_default_context(self):
c = self._get_local_tmpl_context()
c.repo = self.repo
c.repo_group = self.repo_group
c.navlist = navigation_list(self.request)
self._register_global_c(c)
return c
@LoginRequired()
@HasRepoGroupPermissionAnyDecorator('group.admin')
def integration_list(self):
return self._integration_list()
@LoginRequired()
@HasRepoGroupPermissionAnyDecorator('group.admin')
def settings_get(self):
return self._settings_get()
@LoginRequired()
@HasRepoGroupPermissionAnyDecorator('group.admin')
@CSRFRequired()
def settings_post(self):
return self._settings_post()
@LoginRequired()
@HasRepoGroupPermissionAnyDecorator('group.admin')
def new_integration(self):
return self._new_integration()

View file

@ -23,13 +23,13 @@ function registerRCRoutes() {
pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/settings/integrations', ['repo_group_name']);
pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
pyroutes.register('ops_ping', '/_admin/ops/ping', []);

View file

@ -7,10 +7,10 @@
&raquo;
${h.link_to(_('Integrations'),request.route_url(route_name='repo_integrations_home', repo_name=c.repo.repo_name))}
&raquo;
${h.link_to(current_IntegrationType.display_name,
${h.link_to(c.current_IntegrationType.display_name,
request.route_url(route_name='repo_integrations_list',
repo_name=c.repo.repo_name,
integration=current_IntegrationType.key))}
integration=c.current_IntegrationType.key))}
%elif c.repo_group:
${h.link_to(_('Admin'),h.route_path('admin_home'))}
&raquo;
@ -20,10 +20,10 @@
&raquo;
${h.link_to(_('Integrations'),request.route_url(route_name='repo_group_integrations_home', repo_group_name=c.repo_group.group_name))}
&raquo;
${h.link_to(current_IntegrationType.display_name,
${h.link_to(c.current_IntegrationType.display_name,
request.route_url(route_name='repo_group_integrations_list',
repo_group_name=c.repo_group.group_name,
integration=current_IntegrationType.key))}
integration=c.current_IntegrationType.key))}
%else:
${h.link_to(_('Admin'),h.route_path('admin_home'))}
&raquo;
@ -31,17 +31,17 @@
&raquo;
${h.link_to(_('Integrations'),request.route_url(route_name='global_integrations_home'))}
&raquo;
${h.link_to(current_IntegrationType.display_name,
${h.link_to(c.current_IntegrationType.display_name,
request.route_url(route_name='global_integrations_list',
integration=current_IntegrationType.key))}
integration=c.current_IntegrationType.key))}
%endif
%if integration:
%if c.integration:
&raquo;
${integration.name}
%elif current_IntegrationType:
${c.integration.name}
%elif c.current_IntegrationType:
&raquo;
${current_IntegrationType.display_name}
${c.current_IntegrationType.display_name}
%endif
</%def>
@ -54,16 +54,16 @@
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">
%if integration:
${current_IntegrationType.display_name} - ${integration.name}
%if c.integration:
${c.current_IntegrationType.display_name} - ${c.integration.name}
%else:
${_('Create New %(integration_type)s Integration') % {
'integration_type': current_IntegrationType.display_name
'integration_type': c.current_IntegrationType.display_name
}}
%endif
</h2>
</div>
<div class="panel-body">
${form.render() | n}
${c.form.render() | n}
</div>
</div>

View file

@ -15,22 +15,22 @@
&raquo;
${h.link_to(_('Settings'),h.url('admin_settings'))}
%endif
%if current_IntegrationType:
%if c.current_IntegrationType:
&raquo;
%if c.repo:
${h.link_to(_('Integrations'),
request.route_url(route_name='repo_integrations_home',
repo_name=c.repo.repo_name))}
request.route_path(route_name='repo_integrations_home',
repo_name=c.repo.repo_name))}
%elif c.repo_group:
${h.link_to(_('Integrations'),
request.route_url(route_name='repo_group_integrations_home',
repo_group_name=c.repo_group.group_name))}
request.route_path(route_name='repo_group_integrations_home',
repo_group_name=c.repo_group.group_name))}
%else:
${h.link_to(_('Integrations'),
request.route_url(route_name='global_integrations_home'))}
request.route_path(route_name='global_integrations_home'))}
%endif
&raquo;
${current_IntegrationType.display_name}
${c.current_IntegrationType.display_name}
%else:
&raquo;
${_('Integrations')}
@ -61,9 +61,9 @@
home_url = request.route_path('global_integrations_home')
%>
<a href="${home_url}" class="btn ${not current_IntegrationType and 'btn-primary' or ''}">${_('All')}</a>
<a href="${home_url}" class="btn ${not c.current_IntegrationType and 'btn-primary' or ''}">${_('All')}</a>
%for integration_key, IntegrationType in available_integrations.items():
%for integration_key, IntegrationType in c.available_integrations.items():
<%
if c.repo:
list_url = request.route_path('repo_integrations_list',
@ -78,12 +78,14 @@
integration=integration_key)
%>
<a href="${list_url}"
class="btn ${current_IntegrationType and integration_key == current_IntegrationType.key and 'btn-primary' or ''}">
class="btn ${c.current_IntegrationType and integration_key == c.current_IntegrationType.key and 'btn-primary' or ''}">
${IntegrationType.display_name}
</a>
%endfor
<%
integration_type = c.current_IntegrationType and c.current_IntegrationType.display_name or ''
if c.repo:
create_url = h.route_path('repo_integrations_new', repo_name=c.repo.repo_name)
elif c.repo_group:
@ -98,19 +100,19 @@
<table class="rctable integrations">
<thead>
<tr>
<th><a href="?sort=enabled:${rev_sort_dir}">${_('Enabled')}</a></th>
<th><a href="?sort=name:${rev_sort_dir}">${_('Name')}</a></th>
<th colspan="2"><a href="?sort=integration_type:${rev_sort_dir}">${_('Type')}</a></th>
<th><a href="?sort=scope:${rev_sort_dir}">${_('Scope')}</a></th>
<th><a href="?sort=enabled:${c.rev_sort_dir}">${_('Enabled')}</a></th>
<th><a href="?sort=name:${c.rev_sort_dir}">${_('Name')}</a></th>
<th colspan="2"><a href="?sort=integration_type:${c.rev_sort_dir}">${_('Type')}</a></th>
<th><a href="?sort=scope:${c.rev_sort_dir}">${_('Scope')}</a></th>
<th>${_('Actions')}</th>
<th></th>
</tr>
</thead>
<tbody>
%if not integrations_list:
%if not c.integrations_list:
<tr>
<td colspan="7">
<% integration_type = current_IntegrationType and current_IntegrationType.display_name or '' %>
%if c.repo:
${_('No {type} integrations for repo {repo} exist yet.').format(type=integration_type, repo=c.repo.repo_name)}
%elif c.repo_group:
@ -119,14 +121,14 @@
${_('No {type} integrations exist yet.').format(type=integration_type)}
%endif
%if current_IntegrationType:
%if c.current_IntegrationType:
<%
if c.repo:
create_url = h.route_path('repo_integrations_create', repo_name=c.repo.repo_name, integration=current_IntegrationType.key)
create_url = h.route_path('repo_integrations_create', repo_name=c.repo.repo_name, integration=c.current_IntegrationType.key)
elif c.repo_group:
create_url = h.route_path('repo_group_integrations_create', repo_group_name=c.repo_group.group_name, integration=current_IntegrationType.key)
create_url = h.route_path('repo_group_integrations_create', repo_group_name=c.repo_group.group_name, integration=c.current_IntegrationType.key)
else:
create_url = h.route_path('global_integrations_create', integration=current_IntegrationType.key)
create_url = h.route_path('global_integrations_create', integration=c.current_IntegrationType.key)
%>
%endif
@ -134,7 +136,7 @@
</td>
</tr>
%endif
%for IntegrationType, integration in integrations_list:
%for IntegrationType, integration in c.integrations_list:
<tr id="integration_${integration.integration_id}">
<td class="td-enabled">
%if integration.enabled:
@ -147,9 +149,9 @@
${integration.name}
</td>
<td class="td-icon">
%if integration.integration_type in available_integrations:
%if integration.integration_type in c.available_integrations:
<div class="integration-icon">
${available_integrations[integration.integration_type].icon|n}
${c.available_integrations[integration.integration_type].icon|n}
</div>
%else:
?
@ -220,7 +222,7 @@
</table>
<div class="integrations-paginator">
<div class="pagination-wh pagination-left">
${integrations_list.pager('$link_previous ~2~ $link_next')}
${c.integrations_list.pager('$link_previous ~2~ $link_next')}
</div>
</div>
</div>

View file

@ -36,7 +36,7 @@
%endif
</%def>
%for integration, IntegrationType in available_integrations.items():
%for integration, IntegrationType in c.available_integrations.items():
<%
if c.repo:
create_url = request.route_path('repo_integrations_create',

View file

@ -25,21 +25,21 @@ from rhodecode import events
from rhodecode.tests.fixture import Fixture
from rhodecode.model.db import Session, Integration
from rhodecode.model.integration import IntegrationModel
from rhodecode.integrations.types.base import IntegrationTypeBase
class TestDeleteScopesDeletesIntegrations(object):
def test_delete_repo_with_integration_deletes_integration(self,
repo_integration_stub):
def test_delete_repo_with_integration_deletes_integration(
self, repo_integration_stub):
Session().delete(repo_integration_stub.repo)
Session().commit()
Session().expire_all()
integration = Integration.get(repo_integration_stub.integration_id)
assert integration is None
def test_delete_repo_group_with_integration_deletes_integration(
self, repogroup_integration_stub):
def test_delete_repo_group_with_integration_deletes_integration(self,
repogroup_integration_stub):
Session().delete(repogroup_integration_stub.repo_group)
Session().commit()
Session().expire_all()
@ -146,7 +146,6 @@ def test_enabled_integration_repo_scopes(integration_repos):
integrations['root_repo'],
]
triggered_integrations = IntegrationModel().get_for_event(
events.RepoEvent(repos['other_repo']))
@ -157,7 +156,6 @@ def test_enabled_integration_repo_scopes(integration_repos):
integrations['other_group_recursive'],
]
triggered_integrations = IntegrationModel().get_for_event(
events.RepoEvent(repos['parent_repo']))
@ -193,26 +191,22 @@ def test_disabled_integration_repo_scopes(integration_repos):
assert triggered_integrations == []
triggered_integrations = IntegrationModel().get_for_event(
events.RepoEvent(repos['parent_repo']))
assert triggered_integrations == []
triggered_integrations = IntegrationModel().get_for_event(
events.RepoEvent(repos['child_repo']))
assert triggered_integrations == []
triggered_integrations = IntegrationModel().get_for_event(
events.RepoEvent(repos['other_repo']))
assert triggered_integrations == []
def test_enabled_non_repo_integrations(integration_repos):
integrations = integration_repos['integrations']

View file

@ -336,7 +336,7 @@ def test_repo_group(request):
usage automatically
"""
fixture = Fixture()
repogroupid = 'test_repo_group_%s' % int(time.time())
repogroupid = 'test_repo_group_%s' % str(time.time()).replace('.', '')
repo_group = fixture.create_repo_group(repogroupid)
def _cleanup():
@ -353,7 +353,7 @@ def test_user_group(request):
usage automatically
"""
fixture = Fixture()
usergroupid = 'test_user_group_%s' % int(time.time())
usergroupid = 'test_user_group_%s' % str(time.time()).replace('.', '')
user_group = fixture.create_user_group(usergroupid)
def _cleanup():