diff --git a/rhodecode/integrations/routes.py b/rhodecode/integrations/routes.py --- a/rhodecode/integrations/routes.py +++ b/rhodecode/integrations/routes.py @@ -20,7 +20,7 @@ import logging -from rhodecode.model.db import Repository, Integration +from rhodecode.model.db import Repository, Integration, RepoGroup from rhodecode.config.routing import ( ADMIN_PREFIX, add_route_requirements, URL_NAME_REQUIREMENTS) from rhodecode.integrations import integration_type_registry @@ -29,6 +29,8 @@ log = logging.getLogger(__name__) def includeme(config): + + # global integrations config.add_route('global_integrations_home', ADMIN_PREFIX + '/integrations') config.add_route('global_integrations_list', @@ -58,6 +60,8 @@ def includeme(config): request_method='POST', route_name=route_name) + + # repo integrations config.add_route('repo_integrations_home', add_route_requirements( '{repo_name}/settings/integrations', @@ -101,26 +105,87 @@ def includeme(config): route_name=route_name) + # repo group integrations + config.add_route('repo_group_integrations_home', + add_route_requirements( + '{repo_group_name}/settings/integrations', + URL_NAME_REQUIREMENTS + ), + custom_predicates=(valid_repo_group,)) + config.add_route('repo_group_integrations_list', + add_route_requirements( + '{repo_group_name}/settings/integrations/{integration}', + URL_NAME_REQUIREMENTS + ), + 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', + request_method='GET', + route_name=route_name) + + config.add_route('repo_group_integrations_create', + add_route_requirements( + '{repo_group_name}/settings/integrations/{integration}/new', + URL_NAME_REQUIREMENTS + ), + 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}', + URL_NAME_REQUIREMENTS + ), + 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/edit.html', + request_method='GET', + route_name=route_name) + config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView', + attr='settings_post', + renderer='rhodecode:templates/admin/integrations/edit.html', + request_method='POST', + route_name=route_name) + + 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 = None + repo, repo_group = None, None if repo_name: - repo = Repository.get_by_repo_name(info['match']['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: integration = Integration.get(integration_id) if not integration: @@ -129,5 +194,7 @@ def valid_integration(info, request): return False if repo and repo.repo_id != integration.repo_id: return False + if repo_group and repo_group.repo_group_id != integration.repo_group_id: + return False return True diff --git a/rhodecode/integrations/views.py b/rhodecode/integrations/views.py --- a/rhodecode/integrations/views.py +++ b/rhodecode/integrations/views.py @@ -29,7 +29,7 @@ from pyramid.response import Response from rhodecode.lib import auth from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator -from rhodecode.model.db import Repository, Session, Integration +from rhodecode.model.db import Repository, RepoGroup, Session, Integration from rhodecode.model.scm import ScmModel from rhodecode.model.integration import IntegrationModel from rhodecode.admin.navigation import navigation_list @@ -59,6 +59,7 @@ class IntegrationSettingsViewBase(object self.IntegrationType = None self.repo = None + self.repo_group = None self.integration = None self.integrations = {} @@ -68,6 +69,10 @@ class IntegrationSettingsViewBase(object repo_name = request.matchdict['repo_name'] self.repo = Repository.get_by_repo_name(repo_name) + if 'repo_group_name' in request.matchdict: # we're in repo_group context + repo_group_name = request.matchdict['repo_group_name'] + self.repo_group = RepoGroup.get_by_group_name(repo_group_name) + if 'integration' in request.matchdict: # we're in integration context integration_type = request.matchdict['integration'] self.IntegrationType = integration_type_registry[integration_type] @@ -76,7 +81,10 @@ class IntegrationSettingsViewBase(object integration_id = request.matchdict['integration_id'] self.integration = Integration.get(integration_id) else: # list integrations context - for integration in IntegrationModel().get_integrations(self.repo): + integrations = IntegrationModel().get_integrations( + repo=self.repo, repo_group=self.repo_group) + + for integration in integrations: self.integrations.setdefault(integration.integration_type, [] ).append(integration) @@ -91,7 +99,9 @@ class IntegrationSettingsViewBase(object 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 @@ -121,7 +131,11 @@ class IntegrationSettingsViewBase(object defaults['enabled'] = self.integration.enabled else: if self.repo: - scope = self.repo.repo_name + scope = _('{repo_name} repository').format( + repo_name=self.repo.repo_name) + elif self.repo_group: + scope = _('{repo_group_name} repo group').format( + repo_group_name=self.repo_group.group_name) else: scope = _('Global') @@ -207,6 +221,8 @@ class IntegrationSettingsViewBase(object self.integration.integration_type = self.IntegrationType.key if self.repo: self.integration.repo = self.repo + elif self.repo_group: + self.integration.repo_group = self.repo_group Session().add(self.integration) self.integration.enabled = valid_data.pop('enabled', False) @@ -226,6 +242,12 @@ class IntegrationSettingsViewBase(object 'repo_integrations_edit', repo_name=self.repo.repo_name, integration=self.integration.integration_type, integration_id=self.integration.integration_id) + elif self.repo: + redirect_to = self.request.route_url( + 'repo_group_integrations_edit', + repo_group_name=self.repo_group.group_name, + integration=self.integration.integration_type, + integration_id=self.integration.integration_id) else: redirect_to = self.request.route_url( 'global_integrations_edit', @@ -270,3 +292,8 @@ class RepoIntegrationsView(IntegrationSe def perm_check(self, user): return auth.HasRepoPermissionAll('repository.admin' )(repo_name=self.repo.repo_name, user=user) + +class RepoGroupIntegrationsView(IntegrationSettingsViewBase): + def perm_check(self, user): + return auth.HasRepoGroupPermissionAll('group.admin' + )(group_name=self.repo_group.group_name, user=user) diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -3490,9 +3490,16 @@ class Integration(Base, BaseModel): nullable=True, unique=None, default=None) repo = relationship('Repository', lazy='joined') + repo_group_id = Column( + 'repo_group_id', Integer(), ForeignKey('groups.group_id'), + nullable=True, unique=None, default=None) + repo_group = relationship('RepoGroup', lazy='joined') + def __repr__(self): if self.repo: scope = 'repo=%r' % self.repo + elif self.repo_group: + scope = 'repo_group=%r' % self.repo_group else: scope = 'global' diff --git a/rhodecode/model/integration.py b/rhodecode/model/integration.py --- a/rhodecode/model/integration.py +++ b/rhodecode/model/integration.py @@ -100,10 +100,13 @@ class IntegrationModel(BaseModel): if handler: handler.send_event(event) - def get_integrations(self, repo=None): + def get_integrations(self, repo=None, repo_group=None): if repo: return self.sa.query(Integration).filter( Integration.repo_id==repo.repo_id).all() + elif repo_group: + return self.sa.query(Integration).filter( + Integration.repo_group_id==repo_group.group_id).all() # global integrations return self.sa.query(Integration).filter( @@ -116,9 +119,14 @@ class IntegrationModel(BaseModel): query = self.sa.query(Integration).filter(Integration.enabled==True) if isinstance(event, events.RepoEvent): # global + repo integrations + # + repo_group integrations + parent_groups = event.repo.groups_with_parents query = query.filter( or_(Integration.repo_id==None, - Integration.repo_id==event.repo.repo_id)) + Integration.repo_id==event.repo.repo_id, + Integration.repo_group_id.in_( + [group.group_id for group in parent_groups] + ))) if cache: query = query.options(FromCache( "sql_cache_short", diff --git a/rhodecode/templates/admin/integrations/base.html b/rhodecode/templates/admin/integrations/base.html --- a/rhodecode/templates/admin/integrations/base.html +++ b/rhodecode/templates/admin/integrations/base.html @@ -3,6 +3,8 @@ def inherit(context): if context['c'].repo: return "/admin/repos/repo_edit.html" + elif context['c'].repo_group: + return "/admin/repo_groups/repo_group_edit.html" else: return "/admin/settings/settings.html" %> diff --git a/rhodecode/templates/admin/integrations/list.html b/rhodecode/templates/admin/integrations/list.html --- a/rhodecode/templates/admin/integrations/list.html +++ b/rhodecode/templates/admin/integrations/list.html @@ -37,11 +37,15 @@ %for integration in available_integrations: <% if c.repo: - create_url = request.route_url('repo_integrations_create', + create_url = request.route_path('repo_integrations_create', repo_name=c.repo.repo_name, integration=integration) + elif c.repo_group: + create_url = request.route_path('repo_group_integrations_create', + repo_group_name=c.repo_group.group_name, + integration=integration) else: - create_url = request.route_url('global_integrations_create', + create_url = request.route_path('global_integrations_create', integration=integration) %> @@ -90,12 +94,17 @@ %else: <% if c.repo: - edit_url = request.route_url('repo_integrations_edit', + edit_url = request.route_path('repo_integrations_edit', repo_name=c.repo.repo_name, integration=integration.integration_type, integration_id=integration.integration_id) + elif c.repo_group: + edit_url = request.route_path('repo_group_integrations_edit', + repo_group_name=c.repo_group.group_name, + integration=integration.integration_type, + integration_id=integration.integration_id) else: - edit_url = request.route_url('global_integrations_edit', + edit_url = request.route_path('global_integrations_edit', integration=integration.integration_type, integration_id=integration.integration_id) %> diff --git a/rhodecode/templates/admin/repo_groups/repo_group_edit.html b/rhodecode/templates/admin/repo_groups/repo_group_edit.html --- a/rhodecode/templates/admin/repo_groups/repo_group_edit.html +++ b/rhodecode/templates/admin/repo_groups/repo_group_edit.html @@ -30,6 +30,10 @@ ${self.menu_items(active='admin')} +<%def name="main_content()"> + <%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/> + + <%def name="main()">
@@ -44,11 +48,12 @@
  • ${_('Settings')}
  • ${_('Permissions')}
  • ${_('Advanced')}
  • +
  • ${_('Integrations')}
  • - <%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/> + ${self.main_content()}