##// END OF EJS Templates
integrations: add repo group integrations, fixes #4175
dan -
r667:b9ef2c10 default
parent child Browse files
Show More
@@ -20,7 +20,7 b''
20
20
21 import logging
21 import logging
22
22
23 from rhodecode.model.db import Repository, Integration
23 from rhodecode.model.db import Repository, Integration, RepoGroup
24 from rhodecode.config.routing import (
24 from rhodecode.config.routing import (
25 ADMIN_PREFIX, add_route_requirements, URL_NAME_REQUIREMENTS)
25 ADMIN_PREFIX, add_route_requirements, URL_NAME_REQUIREMENTS)
26 from rhodecode.integrations import integration_type_registry
26 from rhodecode.integrations import integration_type_registry
@@ -29,6 +29,8 b' log = logging.getLogger(__name__)'
29
29
30
30
31 def includeme(config):
31 def includeme(config):
32
33 # global integrations
32 config.add_route('global_integrations_home',
34 config.add_route('global_integrations_home',
33 ADMIN_PREFIX + '/integrations')
35 ADMIN_PREFIX + '/integrations')
34 config.add_route('global_integrations_list',
36 config.add_route('global_integrations_list',
@@ -58,6 +60,8 b' def includeme(config):'
58 request_method='POST',
60 request_method='POST',
59 route_name=route_name)
61 route_name=route_name)
60
62
63
64 # repo integrations
61 config.add_route('repo_integrations_home',
65 config.add_route('repo_integrations_home',
62 add_route_requirements(
66 add_route_requirements(
63 '{repo_name}/settings/integrations',
67 '{repo_name}/settings/integrations',
@@ -101,26 +105,87 b' def includeme(config):'
101 route_name=route_name)
105 route_name=route_name)
102
106
103
107
108 # repo group integrations
109 config.add_route('repo_group_integrations_home',
110 add_route_requirements(
111 '{repo_group_name}/settings/integrations',
112 URL_NAME_REQUIREMENTS
113 ),
114 custom_predicates=(valid_repo_group,))
115 config.add_route('repo_group_integrations_list',
116 add_route_requirements(
117 '{repo_group_name}/settings/integrations/{integration}',
118 URL_NAME_REQUIREMENTS
119 ),
120 custom_predicates=(valid_repo_group, valid_integration))
121 for route_name in ['repo_group_integrations_home', 'repo_group_integrations_list']:
122 config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
123 attr='index',
124 request_method='GET',
125 route_name=route_name)
126
127 config.add_route('repo_group_integrations_create',
128 add_route_requirements(
129 '{repo_group_name}/settings/integrations/{integration}/new',
130 URL_NAME_REQUIREMENTS
131 ),
132 custom_predicates=(valid_repo_group, valid_integration))
133 config.add_route('repo_group_integrations_edit',
134 add_route_requirements(
135 '{repo_group_name}/settings/integrations/{integration}/{integration_id}',
136 URL_NAME_REQUIREMENTS
137 ),
138 custom_predicates=(valid_repo_group, valid_integration))
139 for route_name in ['repo_group_integrations_edit', 'repo_group_integrations_create']:
140 config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
141 attr='settings_get',
142 renderer='rhodecode:templates/admin/integrations/edit.html',
143 request_method='GET',
144 route_name=route_name)
145 config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
146 attr='settings_post',
147 renderer='rhodecode:templates/admin/integrations/edit.html',
148 request_method='POST',
149 route_name=route_name)
150
151
104 def valid_repo(info, request):
152 def valid_repo(info, request):
105 repo = Repository.get_by_repo_name(info['match']['repo_name'])
153 repo = Repository.get_by_repo_name(info['match']['repo_name'])
106 if repo:
154 if repo:
107 return True
155 return True
108
156
109
157
158 def valid_repo_group(info, request):
159 repo_group = RepoGroup.get_by_group_name(info['match']['repo_group_name'])
160 if repo_group:
161 return True
162 return False
163
164
110 def valid_integration(info, request):
165 def valid_integration(info, request):
111 integration_type = info['match']['integration']
166 integration_type = info['match']['integration']
112 integration_id = info['match'].get('integration_id')
167 integration_id = info['match'].get('integration_id')
113 repo_name = info['match'].get('repo_name')
168 repo_name = info['match'].get('repo_name')
169 repo_group_name = info['match'].get('repo_group_name')
114
170
115 if integration_type not in integration_type_registry:
171 if integration_type not in integration_type_registry:
116 return False
172 return False
117
173
118 repo = None
174 repo, repo_group = None, None
119 if repo_name:
175 if repo_name:
120 repo = Repository.get_by_repo_name(info['match']['repo_name'])
176 repo = Repository.get_by_repo_name(repo_name)
121 if not repo:
177 if not repo:
122 return False
178 return False
123
179
180 if repo_group_name:
181 repo_group = RepoGroup.get_by_group_name(repo_group_name)
182 if not repo_group:
183 return False
184
185 if repo_name and repo_group:
186 raise Exception('Either repo or repo_group can be set, not both')
187
188
124 if integration_id:
189 if integration_id:
125 integration = Integration.get(integration_id)
190 integration = Integration.get(integration_id)
126 if not integration:
191 if not integration:
@@ -129,5 +194,7 b' def valid_integration(info, request):'
129 return False
194 return False
130 if repo and repo.repo_id != integration.repo_id:
195 if repo and repo.repo_id != integration.repo_id:
131 return False
196 return False
197 if repo_group and repo_group.repo_group_id != integration.repo_group_id:
198 return False
132
199
133 return True
200 return True
@@ -29,7 +29,7 b' from pyramid.response import Response'
29
29
30 from rhodecode.lib import auth
30 from rhodecode.lib import auth
31 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
31 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
32 from rhodecode.model.db import Repository, Session, Integration
32 from rhodecode.model.db import Repository, RepoGroup, Session, Integration
33 from rhodecode.model.scm import ScmModel
33 from rhodecode.model.scm import ScmModel
34 from rhodecode.model.integration import IntegrationModel
34 from rhodecode.model.integration import IntegrationModel
35 from rhodecode.admin.navigation import navigation_list
35 from rhodecode.admin.navigation import navigation_list
@@ -59,6 +59,7 b' class IntegrationSettingsViewBase(object'
59
59
60 self.IntegrationType = None
60 self.IntegrationType = None
61 self.repo = None
61 self.repo = None
62 self.repo_group = None
62 self.integration = None
63 self.integration = None
63 self.integrations = {}
64 self.integrations = {}
64
65
@@ -68,6 +69,10 b' class IntegrationSettingsViewBase(object'
68 repo_name = request.matchdict['repo_name']
69 repo_name = request.matchdict['repo_name']
69 self.repo = Repository.get_by_repo_name(repo_name)
70 self.repo = Repository.get_by_repo_name(repo_name)
70
71
72 if 'repo_group_name' in request.matchdict: # we're in repo_group context
73 repo_group_name = request.matchdict['repo_group_name']
74 self.repo_group = RepoGroup.get_by_group_name(repo_group_name)
75
71 if 'integration' in request.matchdict: # we're in integration context
76 if 'integration' in request.matchdict: # we're in integration context
72 integration_type = request.matchdict['integration']
77 integration_type = request.matchdict['integration']
73 self.IntegrationType = integration_type_registry[integration_type]
78 self.IntegrationType = integration_type_registry[integration_type]
@@ -76,7 +81,10 b' class IntegrationSettingsViewBase(object'
76 integration_id = request.matchdict['integration_id']
81 integration_id = request.matchdict['integration_id']
77 self.integration = Integration.get(integration_id)
82 self.integration = Integration.get(integration_id)
78 else: # list integrations context
83 else: # list integrations context
79 for integration in IntegrationModel().get_integrations(self.repo):
84 integrations = IntegrationModel().get_integrations(
85 repo=self.repo, repo_group=self.repo_group)
86
87 for integration in integrations:
80 self.integrations.setdefault(integration.integration_type, []
88 self.integrations.setdefault(integration.integration_type, []
81 ).append(integration)
89 ).append(integration)
82
90
@@ -91,7 +99,9 b' class IntegrationSettingsViewBase(object'
91 c.active = 'integrations'
99 c.active = 'integrations'
92 c.rhodecode_user = self.request.user
100 c.rhodecode_user = self.request.user
93 c.repo = self.repo
101 c.repo = self.repo
102 c.repo_group = self.repo_group
94 c.repo_name = self.repo and self.repo.repo_name or None
103 c.repo_name = self.repo and self.repo.repo_name or None
104 c.repo_group_name = self.repo_group and self.repo_group.group_name or None
95 if self.repo:
105 if self.repo:
96 c.repo_info = self.repo
106 c.repo_info = self.repo
97 c.rhodecode_db_repo = self.repo
107 c.rhodecode_db_repo = self.repo
@@ -121,7 +131,11 b' class IntegrationSettingsViewBase(object'
121 defaults['enabled'] = self.integration.enabled
131 defaults['enabled'] = self.integration.enabled
122 else:
132 else:
123 if self.repo:
133 if self.repo:
124 scope = self.repo.repo_name
134 scope = _('{repo_name} repository').format(
135 repo_name=self.repo.repo_name)
136 elif self.repo_group:
137 scope = _('{repo_group_name} repo group').format(
138 repo_group_name=self.repo_group.group_name)
125 else:
139 else:
126 scope = _('Global')
140 scope = _('Global')
127
141
@@ -207,6 +221,8 b' class IntegrationSettingsViewBase(object'
207 self.integration.integration_type = self.IntegrationType.key
221 self.integration.integration_type = self.IntegrationType.key
208 if self.repo:
222 if self.repo:
209 self.integration.repo = self.repo
223 self.integration.repo = self.repo
224 elif self.repo_group:
225 self.integration.repo_group = self.repo_group
210 Session().add(self.integration)
226 Session().add(self.integration)
211
227
212 self.integration.enabled = valid_data.pop('enabled', False)
228 self.integration.enabled = valid_data.pop('enabled', False)
@@ -226,6 +242,12 b' class IntegrationSettingsViewBase(object'
226 'repo_integrations_edit', repo_name=self.repo.repo_name,
242 'repo_integrations_edit', repo_name=self.repo.repo_name,
227 integration=self.integration.integration_type,
243 integration=self.integration.integration_type,
228 integration_id=self.integration.integration_id)
244 integration_id=self.integration.integration_id)
245 elif self.repo:
246 redirect_to = self.request.route_url(
247 'repo_group_integrations_edit',
248 repo_group_name=self.repo_group.group_name,
249 integration=self.integration.integration_type,
250 integration_id=self.integration.integration_id)
229 else:
251 else:
230 redirect_to = self.request.route_url(
252 redirect_to = self.request.route_url(
231 'global_integrations_edit',
253 'global_integrations_edit',
@@ -270,3 +292,8 b' class RepoIntegrationsView(IntegrationSe'
270 def perm_check(self, user):
292 def perm_check(self, user):
271 return auth.HasRepoPermissionAll('repository.admin'
293 return auth.HasRepoPermissionAll('repository.admin'
272 )(repo_name=self.repo.repo_name, user=user)
294 )(repo_name=self.repo.repo_name, user=user)
295
296 class RepoGroupIntegrationsView(IntegrationSettingsViewBase):
297 def perm_check(self, user):
298 return auth.HasRepoGroupPermissionAll('group.admin'
299 )(group_name=self.repo_group.group_name, user=user)
@@ -3490,9 +3490,16 b' class Integration(Base, BaseModel):'
3490 nullable=True, unique=None, default=None)
3490 nullable=True, unique=None, default=None)
3491 repo = relationship('Repository', lazy='joined')
3491 repo = relationship('Repository', lazy='joined')
3492
3492
3493 repo_group_id = Column(
3494 'repo_group_id', Integer(), ForeignKey('groups.group_id'),
3495 nullable=True, unique=None, default=None)
3496 repo_group = relationship('RepoGroup', lazy='joined')
3497
3493 def __repr__(self):
3498 def __repr__(self):
3494 if self.repo:
3499 if self.repo:
3495 scope = 'repo=%r' % self.repo
3500 scope = 'repo=%r' % self.repo
3501 elif self.repo_group:
3502 scope = 'repo_group=%r' % self.repo_group
3496 else:
3503 else:
3497 scope = 'global'
3504 scope = 'global'
3498
3505
@@ -100,10 +100,13 b' class IntegrationModel(BaseModel):'
100 if handler:
100 if handler:
101 handler.send_event(event)
101 handler.send_event(event)
102
102
103 def get_integrations(self, repo=None):
103 def get_integrations(self, repo=None, repo_group=None):
104 if repo:
104 if repo:
105 return self.sa.query(Integration).filter(
105 return self.sa.query(Integration).filter(
106 Integration.repo_id==repo.repo_id).all()
106 Integration.repo_id==repo.repo_id).all()
107 elif repo_group:
108 return self.sa.query(Integration).filter(
109 Integration.repo_group_id==repo_group.group_id).all()
107
110
108 # global integrations
111 # global integrations
109 return self.sa.query(Integration).filter(
112 return self.sa.query(Integration).filter(
@@ -116,9 +119,14 b' class IntegrationModel(BaseModel):'
116 query = self.sa.query(Integration).filter(Integration.enabled==True)
119 query = self.sa.query(Integration).filter(Integration.enabled==True)
117
120
118 if isinstance(event, events.RepoEvent): # global + repo integrations
121 if isinstance(event, events.RepoEvent): # global + repo integrations
122 # + repo_group integrations
123 parent_groups = event.repo.groups_with_parents
119 query = query.filter(
124 query = query.filter(
120 or_(Integration.repo_id==None,
125 or_(Integration.repo_id==None,
121 Integration.repo_id==event.repo.repo_id))
126 Integration.repo_id==event.repo.repo_id,
127 Integration.repo_group_id.in_(
128 [group.group_id for group in parent_groups]
129 )))
122 if cache:
130 if cache:
123 query = query.options(FromCache(
131 query = query.options(FromCache(
124 "sql_cache_short",
132 "sql_cache_short",
@@ -3,6 +3,8 b''
3 def inherit(context):
3 def inherit(context):
4 if context['c'].repo:
4 if context['c'].repo:
5 return "/admin/repos/repo_edit.html"
5 return "/admin/repos/repo_edit.html"
6 elif context['c'].repo_group:
7 return "/admin/repo_groups/repo_group_edit.html"
6 else:
8 else:
7 return "/admin/settings/settings.html"
9 return "/admin/settings/settings.html"
8 %>
10 %>
@@ -37,11 +37,15 b''
37 %for integration in available_integrations:
37 %for integration in available_integrations:
38 <%
38 <%
39 if c.repo:
39 if c.repo:
40 create_url = request.route_url('repo_integrations_create',
40 create_url = request.route_path('repo_integrations_create',
41 repo_name=c.repo.repo_name,
41 repo_name=c.repo.repo_name,
42 integration=integration)
42 integration=integration)
43 elif c.repo_group:
44 create_url = request.route_path('repo_group_integrations_create',
45 repo_group_name=c.repo_group.group_name,
46 integration=integration)
43 else:
47 else:
44 create_url = request.route_url('global_integrations_create',
48 create_url = request.route_path('global_integrations_create',
45 integration=integration)
49 integration=integration)
46 %>
50 %>
47 <a href="${create_url}" class="btn">
51 <a href="${create_url}" class="btn">
@@ -90,12 +94,17 b''
90 %else:
94 %else:
91 <%
95 <%
92 if c.repo:
96 if c.repo:
93 edit_url = request.route_url('repo_integrations_edit',
97 edit_url = request.route_path('repo_integrations_edit',
94 repo_name=c.repo.repo_name,
98 repo_name=c.repo.repo_name,
95 integration=integration.integration_type,
99 integration=integration.integration_type,
96 integration_id=integration.integration_id)
100 integration_id=integration.integration_id)
101 elif c.repo_group:
102 edit_url = request.route_path('repo_group_integrations_edit',
103 repo_group_name=c.repo_group.group_name,
104 integration=integration.integration_type,
105 integration_id=integration.integration_id)
97 else:
106 else:
98 edit_url = request.route_url('global_integrations_edit',
107 edit_url = request.route_path('global_integrations_edit',
99 integration=integration.integration_type,
108 integration=integration.integration_type,
100 integration_id=integration.integration_id)
109 integration_id=integration.integration_id)
101 %>
110 %>
@@ -30,6 +30,10 b''
30 ${self.menu_items(active='admin')}
30 ${self.menu_items(active='admin')}
31 </%def>
31 </%def>
32
32
33 <%def name="main_content()">
34 <%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/>
35 </%def>
36
33 <%def name="main()">
37 <%def name="main()">
34 <div class="box">
38 <div class="box">
35 <div class="title">
39 <div class="title">
@@ -44,11 +48,12 b''
44 <li class="${'active' if c.active=='settings' else ''}"><a href="${h.url('edit_repo_group', group_name=c.repo_group.group_name)}">${_('Settings')}</a></li>
48 <li class="${'active' if c.active=='settings' else ''}"><a href="${h.url('edit_repo_group', group_name=c.repo_group.group_name)}">${_('Settings')}</a></li>
45 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_repo_group_perms', group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li>
49 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_repo_group_perms', group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li>
46 <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_repo_group_advanced', group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li>
50 <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_repo_group_advanced', group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li>
51 <li class="${'active' if c.active=='integrations' else ''}"><a href="${h.route_path('repo_group_integrations_home', repo_group_name=c.repo_group.group_name)}">${_('Integrations')}</a></li>
47 </ul>
52 </ul>
48 </div>
53 </div>
49
54
50 <div class="main-content-full-width">
55 <div class="main-content-full-width">
51 <%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/>
56 ${self.main_content()}
52 </div>
57 </div>
53
58
54 </div>
59 </div>
General Comments 0
You need to be logged in to leave comments. Login now