Show More
@@ -0,0 +1,180 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | import formencode | |||
|
23 | ||||
|
24 | from pyramid.httpexceptions import HTTPFound, HTTPForbidden | |||
|
25 | from pyramid.view import view_config | |||
|
26 | from pyramid.renderers import render | |||
|
27 | from pyramid.response import Response | |||
|
28 | ||||
|
29 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |||
|
30 | ||||
|
31 | from rhodecode.lib.ext_json import json | |||
|
32 | from rhodecode.lib.auth import ( | |||
|
33 | LoginRequired, CSRFRequired, NotAnonymous, | |||
|
34 | HasPermissionAny, HasRepoGroupPermissionAny) | |||
|
35 | from rhodecode.lib import helpers as h | |||
|
36 | from rhodecode.lib.utils import repo_name_slug | |||
|
37 | from rhodecode.lib.utils2 import safe_int, safe_unicode | |||
|
38 | from rhodecode.model.forms import RepoForm | |||
|
39 | from rhodecode.model.repo import RepoModel | |||
|
40 | from rhodecode.model.scm import RepoList, RepoGroupList, ScmModel | |||
|
41 | from rhodecode.model.settings import SettingsModel | |||
|
42 | from rhodecode.model.db import Repository, RepoGroup | |||
|
43 | ||||
|
44 | log = logging.getLogger(__name__) | |||
|
45 | ||||
|
46 | ||||
|
47 | class AdminReposView(BaseAppView, DataGridAppView): | |||
|
48 | ||||
|
49 | def load_default_context(self): | |||
|
50 | c = self._get_local_tmpl_context() | |||
|
51 | self._register_global_c(c) | |||
|
52 | return c | |||
|
53 | ||||
|
54 | def _load_form_data(self, c): | |||
|
55 | acl_groups = RepoGroupList(RepoGroup.query().all(), | |||
|
56 | perm_set=['group.write', 'group.admin']) | |||
|
57 | c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) | |||
|
58 | c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups) | |||
|
59 | c.landing_revs_choices, c.landing_revs = \ | |||
|
60 | ScmModel().get_repo_landing_revs() | |||
|
61 | c.personal_repo_group = self._rhodecode_user.personal_repo_group | |||
|
62 | ||||
|
63 | @LoginRequired() | |||
|
64 | @NotAnonymous() | |||
|
65 | @view_config( | |||
|
66 | route_name='repos', request_method='GET', | |||
|
67 | renderer='rhodecode:templates/admin/repos/repos.mako') | |||
|
68 | def repository_list(self): | |||
|
69 | c = self.load_default_context() | |||
|
70 | ||||
|
71 | repo_list = Repository.get_all_repos() | |||
|
72 | c.repo_list = RepoList(repo_list, perm_set=['repository.admin']) | |||
|
73 | repos_data = RepoModel().get_repos_as_dict( | |||
|
74 | repo_list=c.repo_list, admin=True, super_user_actions=True) | |||
|
75 | # json used to render the grid | |||
|
76 | c.data = json.dumps(repos_data) | |||
|
77 | ||||
|
78 | return self._get_template_context(c) | |||
|
79 | ||||
|
80 | @LoginRequired() | |||
|
81 | @NotAnonymous() | |||
|
82 | # perms check inside | |||
|
83 | @view_config( | |||
|
84 | route_name='repo_new', request_method='GET', | |||
|
85 | renderer='rhodecode:templates/admin/repos/repo_add.mako') | |||
|
86 | def repository_new(self): | |||
|
87 | c = self.load_default_context() | |||
|
88 | ||||
|
89 | new_repo = self.request.GET.get('repo', '') | |||
|
90 | parent_group = safe_int(self.request.GET.get('parent_group')) | |||
|
91 | _gr = RepoGroup.get(parent_group) | |||
|
92 | ||||
|
93 | if not HasPermissionAny('hg.admin', 'hg.create.repository')(): | |||
|
94 | # you're not super admin nor have global create permissions, | |||
|
95 | # but maybe you have at least write permission to a parent group ? | |||
|
96 | ||||
|
97 | gr_name = _gr.group_name if _gr else None | |||
|
98 | # create repositories with write permission on group is set to true | |||
|
99 | create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')() | |||
|
100 | group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name) | |||
|
101 | group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name) | |||
|
102 | if not (group_admin or (group_write and create_on_write)): | |||
|
103 | raise HTTPForbidden() | |||
|
104 | ||||
|
105 | self._load_form_data(c) | |||
|
106 | c.new_repo = repo_name_slug(new_repo) | |||
|
107 | ||||
|
108 | # apply the defaults from defaults page | |||
|
109 | defaults = SettingsModel().get_default_repo_settings(strip_prefix=True) | |||
|
110 | # set checkbox to autochecked | |||
|
111 | defaults['repo_copy_permissions'] = True | |||
|
112 | ||||
|
113 | parent_group_choice = '-1' | |||
|
114 | if not self._rhodecode_user.is_admin and self._rhodecode_user.personal_repo_group: | |||
|
115 | parent_group_choice = self._rhodecode_user.personal_repo_group | |||
|
116 | ||||
|
117 | if parent_group and _gr: | |||
|
118 | if parent_group in [x[0] for x in c.repo_groups]: | |||
|
119 | parent_group_choice = safe_unicode(parent_group) | |||
|
120 | ||||
|
121 | defaults.update({'repo_group': parent_group_choice}) | |||
|
122 | ||||
|
123 | data = render('rhodecode:templates/admin/repos/repo_add.mako', | |||
|
124 | self._get_template_context(c), self.request) | |||
|
125 | html = formencode.htmlfill.render( | |||
|
126 | data, | |||
|
127 | defaults=defaults, | |||
|
128 | encoding="UTF-8", | |||
|
129 | force_defaults=False | |||
|
130 | ) | |||
|
131 | return Response(html) | |||
|
132 | ||||
|
133 | @LoginRequired() | |||
|
134 | @NotAnonymous() | |||
|
135 | @CSRFRequired() | |||
|
136 | # perms check inside | |||
|
137 | @view_config( | |||
|
138 | route_name='repo_create', request_method='POST', | |||
|
139 | renderer='rhodecode:templates/admin/repos/repos.mako') | |||
|
140 | def repository_create(self): | |||
|
141 | c = self.load_default_context() | |||
|
142 | ||||
|
143 | form_result = {} | |||
|
144 | task_id = None | |||
|
145 | self._load_form_data(c) | |||
|
146 | ||||
|
147 | try: | |||
|
148 | # CanWriteToGroup validators checks permissions of this POST | |||
|
149 | form_result = RepoForm(repo_groups=c.repo_groups_choices, | |||
|
150 | landing_revs=c.landing_revs_choices)()\ | |||
|
151 | .to_python(dict(self.request.POST)) | |||
|
152 | ||||
|
153 | # create is done sometimes async on celery, db transaction | |||
|
154 | # management is handled there. | |||
|
155 | task = RepoModel().create(form_result, self._rhodecode_user.user_id) | |||
|
156 | from celery.result import BaseAsyncResult | |||
|
157 | if isinstance(task, BaseAsyncResult): | |||
|
158 | task_id = task.task_id | |||
|
159 | except formencode.Invalid as errors: | |||
|
160 | data = render('rhodecode:templates/admin/repos/repo_add.mako', | |||
|
161 | self._get_template_context(c), self.request) | |||
|
162 | html = formencode.htmlfill.render( | |||
|
163 | data, | |||
|
164 | defaults=errors.value, | |||
|
165 | errors=errors.error_dict or {}, | |||
|
166 | prefix_error=False, | |||
|
167 | encoding="UTF-8", | |||
|
168 | force_defaults=False | |||
|
169 | ) | |||
|
170 | return Response(html) | |||
|
171 | ||||
|
172 | except Exception as e: | |||
|
173 | msg = self._log_creation_exception(e, form_result.get('repo_name')) | |||
|
174 | h.flash(msg, category='error') | |||
|
175 | raise HTTPFound(h.route_path('home')) | |||
|
176 | ||||
|
177 | raise HTTPFound( | |||
|
178 | h.route_path('repo_creating', | |||
|
179 | repo_name=form_result['repo_name_full'], | |||
|
180 | _query=dict(task_id=task_id))) |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
This diff has been collapsed as it changes many lines, (685 lines changed) Show them Hide them | |||||
@@ -0,0 +1,685 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2010-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import mock | |||
|
22 | import pytest | |||
|
23 | ||||
|
24 | from rhodecode.lib import auth | |||
|
25 | from rhodecode.lib.utils2 import str2bool | |||
|
26 | from rhodecode.model.db import ( | |||
|
27 | Repository, UserRepoToPerm, User) | |||
|
28 | from rhodecode.model.meta import Session | |||
|
29 | from rhodecode.model.settings import SettingsModel, VcsSettingsModel | |||
|
30 | from rhodecode.model.user import UserModel | |||
|
31 | from rhodecode.tests import ( | |||
|
32 | login_user_session, logout_user_session, | |||
|
33 | TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |||
|
34 | from rhodecode.tests.fixture import Fixture | |||
|
35 | from rhodecode.tests.utils import AssertResponse | |||
|
36 | ||||
|
37 | fixture = Fixture() | |||
|
38 | ||||
|
39 | ||||
|
40 | def route_path(name, params=None, **kwargs): | |||
|
41 | import urllib | |||
|
42 | ||||
|
43 | base_url = { | |||
|
44 | 'repo_summary': '/{repo_name}', | |||
|
45 | 'repo_creating_check': '/{repo_name}/repo_creating_check', | |||
|
46 | 'edit_repo': '/{repo_name}/settings', | |||
|
47 | 'edit_repo_vcs': '/{repo_name}/settings/vcs', | |||
|
48 | 'edit_repo_vcs_update': '/{repo_name}/settings/vcs/update', | |||
|
49 | 'edit_repo_vcs_svn_pattern_delete': '/{repo_name}/settings/vcs/svn_pattern/delete' | |||
|
50 | }[name].format(**kwargs) | |||
|
51 | ||||
|
52 | if params: | |||
|
53 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
54 | return base_url | |||
|
55 | ||||
|
56 | ||||
|
57 | @pytest.mark.usefixtures("app") | |||
|
58 | class TestVcsSettings(object): | |||
|
59 | FORM_DATA = { | |||
|
60 | 'inherit_global_settings': False, | |||
|
61 | 'hooks_changegroup_repo_size': False, | |||
|
62 | 'hooks_changegroup_push_logger': False, | |||
|
63 | 'hooks_outgoing_pull_logger': False, | |||
|
64 | 'extensions_largefiles': False, | |||
|
65 | 'extensions_evolve': False, | |||
|
66 | 'phases_publish': 'False', | |||
|
67 | 'rhodecode_pr_merge_enabled': False, | |||
|
68 | 'rhodecode_use_outdated_comments': False, | |||
|
69 | 'new_svn_branch': '', | |||
|
70 | 'new_svn_tag': '' | |||
|
71 | } | |||
|
72 | ||||
|
73 | @pytest.mark.skip_backends('svn') | |||
|
74 | def test_global_settings_initial_values(self, autologin_user, backend): | |||
|
75 | repo_name = backend.repo_name | |||
|
76 | response = self.app.get(route_path('edit_repo_vcs', repo_name=repo_name)) | |||
|
77 | ||||
|
78 | expected_settings = ( | |||
|
79 | 'rhodecode_use_outdated_comments', 'rhodecode_pr_merge_enabled', | |||
|
80 | 'hooks_changegroup_repo_size', 'hooks_changegroup_push_logger', | |||
|
81 | 'hooks_outgoing_pull_logger' | |||
|
82 | ) | |||
|
83 | for setting in expected_settings: | |||
|
84 | self.assert_repo_value_equals_global_value(response, setting) | |||
|
85 | ||||
|
86 | def test_show_settings_requires_repo_admin_permission( | |||
|
87 | self, backend, user_util, settings_util): | |||
|
88 | repo = backend.create_repo() | |||
|
89 | repo_name = repo.repo_name | |||
|
90 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) | |||
|
91 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') | |||
|
92 | login_user_session( | |||
|
93 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |||
|
94 | self.app.get(route_path('edit_repo_vcs', repo_name=repo_name), status=200) | |||
|
95 | ||||
|
96 | def test_inherit_global_settings_flag_is_true_by_default( | |||
|
97 | self, autologin_user, backend): | |||
|
98 | repo_name = backend.repo_name | |||
|
99 | response = self.app.get(route_path('edit_repo_vcs', repo_name=repo_name)) | |||
|
100 | ||||
|
101 | assert_response = AssertResponse(response) | |||
|
102 | element = assert_response.get_element('#inherit_global_settings') | |||
|
103 | assert element.checked | |||
|
104 | ||||
|
105 | @pytest.mark.parametrize('checked_value', [True, False]) | |||
|
106 | def test_inherit_global_settings_value( | |||
|
107 | self, autologin_user, backend, checked_value, settings_util): | |||
|
108 | repo = backend.create_repo() | |||
|
109 | repo_name = repo.repo_name | |||
|
110 | settings_util.create_repo_rhodecode_setting( | |||
|
111 | repo, 'inherit_vcs_settings', checked_value, 'bool') | |||
|
112 | response = self.app.get(route_path('edit_repo_vcs', repo_name=repo_name)) | |||
|
113 | ||||
|
114 | assert_response = AssertResponse(response) | |||
|
115 | element = assert_response.get_element('#inherit_global_settings') | |||
|
116 | assert element.checked == checked_value | |||
|
117 | ||||
|
118 | @pytest.mark.skip_backends('svn') | |||
|
119 | def test_hooks_settings_are_created( | |||
|
120 | self, autologin_user, backend, csrf_token): | |||
|
121 | repo_name = backend.repo_name | |||
|
122 | data = self.FORM_DATA.copy() | |||
|
123 | data['csrf_token'] = csrf_token | |||
|
124 | self.app.post( | |||
|
125 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
126 | settings = SettingsModel(repo=repo_name) | |||
|
127 | try: | |||
|
128 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: | |||
|
129 | ui = settings.get_ui_by_section_and_key(section, key) | |||
|
130 | assert ui.ui_active is False | |||
|
131 | finally: | |||
|
132 | self._cleanup_repo_settings(settings) | |||
|
133 | ||||
|
134 | def test_hooks_settings_are_not_created_for_svn( | |||
|
135 | self, autologin_user, backend_svn, csrf_token): | |||
|
136 | repo_name = backend_svn.repo_name | |||
|
137 | data = self.FORM_DATA.copy() | |||
|
138 | data['csrf_token'] = csrf_token | |||
|
139 | self.app.post( | |||
|
140 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
141 | settings = SettingsModel(repo=repo_name) | |||
|
142 | try: | |||
|
143 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: | |||
|
144 | ui = settings.get_ui_by_section_and_key(section, key) | |||
|
145 | assert ui is None | |||
|
146 | finally: | |||
|
147 | self._cleanup_repo_settings(settings) | |||
|
148 | ||||
|
149 | @pytest.mark.skip_backends('svn') | |||
|
150 | def test_hooks_settings_are_updated( | |||
|
151 | self, autologin_user, backend, csrf_token): | |||
|
152 | repo_name = backend.repo_name | |||
|
153 | settings = SettingsModel(repo=repo_name) | |||
|
154 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: | |||
|
155 | settings.create_ui_section_value(section, '', key=key, active=True) | |||
|
156 | ||||
|
157 | data = self.FORM_DATA.copy() | |||
|
158 | data['csrf_token'] = csrf_token | |||
|
159 | self.app.post( | |||
|
160 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
161 | try: | |||
|
162 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: | |||
|
163 | ui = settings.get_ui_by_section_and_key(section, key) | |||
|
164 | assert ui.ui_active is False | |||
|
165 | finally: | |||
|
166 | self._cleanup_repo_settings(settings) | |||
|
167 | ||||
|
168 | def test_hooks_settings_are_not_updated_for_svn( | |||
|
169 | self, autologin_user, backend_svn, csrf_token): | |||
|
170 | repo_name = backend_svn.repo_name | |||
|
171 | settings = SettingsModel(repo=repo_name) | |||
|
172 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: | |||
|
173 | settings.create_ui_section_value(section, '', key=key, active=True) | |||
|
174 | ||||
|
175 | data = self.FORM_DATA.copy() | |||
|
176 | data['csrf_token'] = csrf_token | |||
|
177 | self.app.post( | |||
|
178 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
179 | try: | |||
|
180 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: | |||
|
181 | ui = settings.get_ui_by_section_and_key(section, key) | |||
|
182 | assert ui.ui_active is True | |||
|
183 | finally: | |||
|
184 | self._cleanup_repo_settings(settings) | |||
|
185 | ||||
|
186 | @pytest.mark.skip_backends('svn') | |||
|
187 | def test_pr_settings_are_created( | |||
|
188 | self, autologin_user, backend, csrf_token): | |||
|
189 | repo_name = backend.repo_name | |||
|
190 | data = self.FORM_DATA.copy() | |||
|
191 | data['csrf_token'] = csrf_token | |||
|
192 | self.app.post( | |||
|
193 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
194 | settings = SettingsModel(repo=repo_name) | |||
|
195 | try: | |||
|
196 | for name in VcsSettingsModel.GENERAL_SETTINGS: | |||
|
197 | setting = settings.get_setting_by_name(name) | |||
|
198 | assert setting.app_settings_value is False | |||
|
199 | finally: | |||
|
200 | self._cleanup_repo_settings(settings) | |||
|
201 | ||||
|
202 | def test_pr_settings_are_not_created_for_svn( | |||
|
203 | self, autologin_user, backend_svn, csrf_token): | |||
|
204 | repo_name = backend_svn.repo_name | |||
|
205 | data = self.FORM_DATA.copy() | |||
|
206 | data['csrf_token'] = csrf_token | |||
|
207 | self.app.post( | |||
|
208 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
209 | settings = SettingsModel(repo=repo_name) | |||
|
210 | try: | |||
|
211 | for name in VcsSettingsModel.GENERAL_SETTINGS: | |||
|
212 | setting = settings.get_setting_by_name(name) | |||
|
213 | assert setting is None | |||
|
214 | finally: | |||
|
215 | self._cleanup_repo_settings(settings) | |||
|
216 | ||||
|
217 | def test_pr_settings_creation_requires_repo_admin_permission( | |||
|
218 | self, backend, user_util, settings_util, csrf_token): | |||
|
219 | repo = backend.create_repo() | |||
|
220 | repo_name = repo.repo_name | |||
|
221 | ||||
|
222 | logout_user_session(self.app, csrf_token) | |||
|
223 | session = login_user_session( | |||
|
224 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |||
|
225 | new_csrf_token = auth.get_csrf_token(session) | |||
|
226 | ||||
|
227 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) | |||
|
228 | repo = Repository.get_by_repo_name(repo_name) | |||
|
229 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') | |||
|
230 | data = self.FORM_DATA.copy() | |||
|
231 | data['csrf_token'] = new_csrf_token | |||
|
232 | settings = SettingsModel(repo=repo_name) | |||
|
233 | ||||
|
234 | try: | |||
|
235 | self.app.post( | |||
|
236 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, | |||
|
237 | status=302) | |||
|
238 | finally: | |||
|
239 | self._cleanup_repo_settings(settings) | |||
|
240 | ||||
|
241 | @pytest.mark.skip_backends('svn') | |||
|
242 | def test_pr_settings_are_updated( | |||
|
243 | self, autologin_user, backend, csrf_token): | |||
|
244 | repo_name = backend.repo_name | |||
|
245 | settings = SettingsModel(repo=repo_name) | |||
|
246 | for name in VcsSettingsModel.GENERAL_SETTINGS: | |||
|
247 | settings.create_or_update_setting(name, True, 'bool') | |||
|
248 | ||||
|
249 | data = self.FORM_DATA.copy() | |||
|
250 | data['csrf_token'] = csrf_token | |||
|
251 | self.app.post( | |||
|
252 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
253 | try: | |||
|
254 | for name in VcsSettingsModel.GENERAL_SETTINGS: | |||
|
255 | setting = settings.get_setting_by_name(name) | |||
|
256 | assert setting.app_settings_value is False | |||
|
257 | finally: | |||
|
258 | self._cleanup_repo_settings(settings) | |||
|
259 | ||||
|
260 | def test_pr_settings_are_not_updated_for_svn( | |||
|
261 | self, autologin_user, backend_svn, csrf_token): | |||
|
262 | repo_name = backend_svn.repo_name | |||
|
263 | settings = SettingsModel(repo=repo_name) | |||
|
264 | for name in VcsSettingsModel.GENERAL_SETTINGS: | |||
|
265 | settings.create_or_update_setting(name, True, 'bool') | |||
|
266 | ||||
|
267 | data = self.FORM_DATA.copy() | |||
|
268 | data['csrf_token'] = csrf_token | |||
|
269 | self.app.post( | |||
|
270 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
271 | try: | |||
|
272 | for name in VcsSettingsModel.GENERAL_SETTINGS: | |||
|
273 | setting = settings.get_setting_by_name(name) | |||
|
274 | assert setting.app_settings_value is True | |||
|
275 | finally: | |||
|
276 | self._cleanup_repo_settings(settings) | |||
|
277 | ||||
|
278 | def test_svn_settings_are_created( | |||
|
279 | self, autologin_user, backend_svn, csrf_token, settings_util): | |||
|
280 | repo_name = backend_svn.repo_name | |||
|
281 | data = self.FORM_DATA.copy() | |||
|
282 | data['new_svn_tag'] = 'svn-tag' | |||
|
283 | data['new_svn_branch'] = 'svn-branch' | |||
|
284 | data['csrf_token'] = csrf_token | |||
|
285 | ||||
|
286 | # Create few global settings to make sure that uniqueness validators | |||
|
287 | # are not triggered | |||
|
288 | settings_util.create_rhodecode_ui( | |||
|
289 | VcsSettingsModel.SVN_BRANCH_SECTION, 'svn-branch') | |||
|
290 | settings_util.create_rhodecode_ui( | |||
|
291 | VcsSettingsModel.SVN_TAG_SECTION, 'svn-tag') | |||
|
292 | ||||
|
293 | self.app.post( | |||
|
294 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
295 | settings = SettingsModel(repo=repo_name) | |||
|
296 | try: | |||
|
297 | svn_branches = settings.get_ui_by_section( | |||
|
298 | VcsSettingsModel.SVN_BRANCH_SECTION) | |||
|
299 | svn_branch_names = [b.ui_value for b in svn_branches] | |||
|
300 | svn_tags = settings.get_ui_by_section( | |||
|
301 | VcsSettingsModel.SVN_TAG_SECTION) | |||
|
302 | svn_tag_names = [b.ui_value for b in svn_tags] | |||
|
303 | assert 'svn-branch' in svn_branch_names | |||
|
304 | assert 'svn-tag' in svn_tag_names | |||
|
305 | finally: | |||
|
306 | self._cleanup_repo_settings(settings) | |||
|
307 | ||||
|
308 | def test_svn_settings_are_unique( | |||
|
309 | self, autologin_user, backend_svn, csrf_token, settings_util): | |||
|
310 | repo = backend_svn.repo | |||
|
311 | repo_name = repo.repo_name | |||
|
312 | data = self.FORM_DATA.copy() | |||
|
313 | data['new_svn_tag'] = 'test_tag' | |||
|
314 | data['new_svn_branch'] = 'test_branch' | |||
|
315 | data['csrf_token'] = csrf_token | |||
|
316 | settings_util.create_repo_rhodecode_ui( | |||
|
317 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch') | |||
|
318 | settings_util.create_repo_rhodecode_ui( | |||
|
319 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'test_tag') | |||
|
320 | ||||
|
321 | response = self.app.post( | |||
|
322 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=200) | |||
|
323 | response.mustcontain('Pattern already exists') | |||
|
324 | ||||
|
325 | def test_svn_settings_with_empty_values_are_not_created( | |||
|
326 | self, autologin_user, backend_svn, csrf_token): | |||
|
327 | repo_name = backend_svn.repo_name | |||
|
328 | data = self.FORM_DATA.copy() | |||
|
329 | data['csrf_token'] = csrf_token | |||
|
330 | self.app.post( | |||
|
331 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
332 | settings = SettingsModel(repo=repo_name) | |||
|
333 | try: | |||
|
334 | svn_branches = settings.get_ui_by_section( | |||
|
335 | VcsSettingsModel.SVN_BRANCH_SECTION) | |||
|
336 | svn_tags = settings.get_ui_by_section( | |||
|
337 | VcsSettingsModel.SVN_TAG_SECTION) | |||
|
338 | assert len(svn_branches) == 0 | |||
|
339 | assert len(svn_tags) == 0 | |||
|
340 | finally: | |||
|
341 | self._cleanup_repo_settings(settings) | |||
|
342 | ||||
|
343 | def test_svn_settings_are_shown_for_svn_repository( | |||
|
344 | self, autologin_user, backend_svn, csrf_token): | |||
|
345 | repo_name = backend_svn.repo_name | |||
|
346 | response = self.app.get( | |||
|
347 | route_path('edit_repo_vcs', repo_name=repo_name), status=200) | |||
|
348 | response.mustcontain('Subversion Settings') | |||
|
349 | ||||
|
350 | @pytest.mark.skip_backends('svn') | |||
|
351 | def test_svn_settings_are_not_created_for_not_svn_repository( | |||
|
352 | self, autologin_user, backend, csrf_token): | |||
|
353 | repo_name = backend.repo_name | |||
|
354 | data = self.FORM_DATA.copy() | |||
|
355 | data['csrf_token'] = csrf_token | |||
|
356 | self.app.post( | |||
|
357 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
358 | settings = SettingsModel(repo=repo_name) | |||
|
359 | try: | |||
|
360 | svn_branches = settings.get_ui_by_section( | |||
|
361 | VcsSettingsModel.SVN_BRANCH_SECTION) | |||
|
362 | svn_tags = settings.get_ui_by_section( | |||
|
363 | VcsSettingsModel.SVN_TAG_SECTION) | |||
|
364 | assert len(svn_branches) == 0 | |||
|
365 | assert len(svn_tags) == 0 | |||
|
366 | finally: | |||
|
367 | self._cleanup_repo_settings(settings) | |||
|
368 | ||||
|
369 | @pytest.mark.skip_backends('svn') | |||
|
370 | def test_svn_settings_are_shown_only_for_svn_repository( | |||
|
371 | self, autologin_user, backend, csrf_token): | |||
|
372 | repo_name = backend.repo_name | |||
|
373 | response = self.app.get( | |||
|
374 | route_path('edit_repo_vcs', repo_name=repo_name), status=200) | |||
|
375 | response.mustcontain(no='Subversion Settings') | |||
|
376 | ||||
|
377 | def test_hg_settings_are_created( | |||
|
378 | self, autologin_user, backend_hg, csrf_token): | |||
|
379 | repo_name = backend_hg.repo_name | |||
|
380 | data = self.FORM_DATA.copy() | |||
|
381 | data['new_svn_tag'] = 'svn-tag' | |||
|
382 | data['new_svn_branch'] = 'svn-branch' | |||
|
383 | data['csrf_token'] = csrf_token | |||
|
384 | self.app.post( | |||
|
385 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
386 | settings = SettingsModel(repo=repo_name) | |||
|
387 | try: | |||
|
388 | largefiles_ui = settings.get_ui_by_section_and_key( | |||
|
389 | 'extensions', 'largefiles') | |||
|
390 | assert largefiles_ui.ui_active is False | |||
|
391 | phases_ui = settings.get_ui_by_section_and_key( | |||
|
392 | 'phases', 'publish') | |||
|
393 | assert str2bool(phases_ui.ui_value) is False | |||
|
394 | finally: | |||
|
395 | self._cleanup_repo_settings(settings) | |||
|
396 | ||||
|
397 | def test_hg_settings_are_updated( | |||
|
398 | self, autologin_user, backend_hg, csrf_token): | |||
|
399 | repo_name = backend_hg.repo_name | |||
|
400 | settings = SettingsModel(repo=repo_name) | |||
|
401 | settings.create_ui_section_value( | |||
|
402 | 'extensions', '', key='largefiles', active=True) | |||
|
403 | settings.create_ui_section_value( | |||
|
404 | 'phases', '1', key='publish', active=True) | |||
|
405 | ||||
|
406 | data = self.FORM_DATA.copy() | |||
|
407 | data['csrf_token'] = csrf_token | |||
|
408 | self.app.post( | |||
|
409 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
410 | try: | |||
|
411 | largefiles_ui = settings.get_ui_by_section_and_key( | |||
|
412 | 'extensions', 'largefiles') | |||
|
413 | assert largefiles_ui.ui_active is False | |||
|
414 | phases_ui = settings.get_ui_by_section_and_key( | |||
|
415 | 'phases', 'publish') | |||
|
416 | assert str2bool(phases_ui.ui_value) is False | |||
|
417 | finally: | |||
|
418 | self._cleanup_repo_settings(settings) | |||
|
419 | ||||
|
420 | def test_hg_settings_are_shown_for_hg_repository( | |||
|
421 | self, autologin_user, backend_hg, csrf_token): | |||
|
422 | repo_name = backend_hg.repo_name | |||
|
423 | response = self.app.get( | |||
|
424 | route_path('edit_repo_vcs', repo_name=repo_name), status=200) | |||
|
425 | response.mustcontain('Mercurial Settings') | |||
|
426 | ||||
|
427 | @pytest.mark.skip_backends('hg') | |||
|
428 | def test_hg_settings_are_created_only_for_hg_repository( | |||
|
429 | self, autologin_user, backend, csrf_token): | |||
|
430 | repo_name = backend.repo_name | |||
|
431 | data = self.FORM_DATA.copy() | |||
|
432 | data['csrf_token'] = csrf_token | |||
|
433 | self.app.post( | |||
|
434 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
435 | settings = SettingsModel(repo=repo_name) | |||
|
436 | try: | |||
|
437 | largefiles_ui = settings.get_ui_by_section_and_key( | |||
|
438 | 'extensions', 'largefiles') | |||
|
439 | assert largefiles_ui is None | |||
|
440 | phases_ui = settings.get_ui_by_section_and_key( | |||
|
441 | 'phases', 'publish') | |||
|
442 | assert phases_ui is None | |||
|
443 | finally: | |||
|
444 | self._cleanup_repo_settings(settings) | |||
|
445 | ||||
|
446 | @pytest.mark.skip_backends('hg') | |||
|
447 | def test_hg_settings_are_shown_only_for_hg_repository( | |||
|
448 | self, autologin_user, backend, csrf_token): | |||
|
449 | repo_name = backend.repo_name | |||
|
450 | response = self.app.get( | |||
|
451 | route_path('edit_repo_vcs', repo_name=repo_name), status=200) | |||
|
452 | response.mustcontain(no='Mercurial Settings') | |||
|
453 | ||||
|
454 | @pytest.mark.skip_backends('hg') | |||
|
455 | def test_hg_settings_are_updated_only_for_hg_repository( | |||
|
456 | self, autologin_user, backend, csrf_token): | |||
|
457 | repo_name = backend.repo_name | |||
|
458 | settings = SettingsModel(repo=repo_name) | |||
|
459 | settings.create_ui_section_value( | |||
|
460 | 'extensions', '', key='largefiles', active=True) | |||
|
461 | settings.create_ui_section_value( | |||
|
462 | 'phases', '1', key='publish', active=True) | |||
|
463 | ||||
|
464 | data = self.FORM_DATA.copy() | |||
|
465 | data['csrf_token'] = csrf_token | |||
|
466 | self.app.post( | |||
|
467 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
468 | try: | |||
|
469 | largefiles_ui = settings.get_ui_by_section_and_key( | |||
|
470 | 'extensions', 'largefiles') | |||
|
471 | assert largefiles_ui.ui_active is True | |||
|
472 | phases_ui = settings.get_ui_by_section_and_key( | |||
|
473 | 'phases', 'publish') | |||
|
474 | assert phases_ui.ui_value == '1' | |||
|
475 | finally: | |||
|
476 | self._cleanup_repo_settings(settings) | |||
|
477 | ||||
|
478 | def test_per_repo_svn_settings_are_displayed( | |||
|
479 | self, autologin_user, backend_svn, settings_util): | |||
|
480 | repo = backend_svn.create_repo() | |||
|
481 | repo_name = repo.repo_name | |||
|
482 | branches = [ | |||
|
483 | settings_util.create_repo_rhodecode_ui( | |||
|
484 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, | |||
|
485 | 'branch_{}'.format(i)) | |||
|
486 | for i in range(10)] | |||
|
487 | tags = [ | |||
|
488 | settings_util.create_repo_rhodecode_ui( | |||
|
489 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'tag_{}'.format(i)) | |||
|
490 | for i in range(10)] | |||
|
491 | ||||
|
492 | response = self.app.get( | |||
|
493 | route_path('edit_repo_vcs', repo_name=repo_name), status=200) | |||
|
494 | assert_response = AssertResponse(response) | |||
|
495 | for branch in branches: | |||
|
496 | css_selector = '[name=branch_value_{}]'.format(branch.ui_id) | |||
|
497 | element = assert_response.get_element(css_selector) | |||
|
498 | assert element.value == branch.ui_value | |||
|
499 | for tag in tags: | |||
|
500 | css_selector = '[name=tag_ui_value_new_{}]'.format(tag.ui_id) | |||
|
501 | element = assert_response.get_element(css_selector) | |||
|
502 | assert element.value == tag.ui_value | |||
|
503 | ||||
|
504 | def test_per_repo_hg_and_pr_settings_are_not_displayed_for_svn( | |||
|
505 | self, autologin_user, backend_svn, settings_util): | |||
|
506 | repo = backend_svn.create_repo() | |||
|
507 | repo_name = repo.repo_name | |||
|
508 | response = self.app.get( | |||
|
509 | route_path('edit_repo_vcs', repo_name=repo_name), status=200) | |||
|
510 | response.mustcontain(no='<label>Hooks:</label>') | |||
|
511 | response.mustcontain(no='<label>Pull Request Settings:</label>') | |||
|
512 | ||||
|
513 | def test_inherit_global_settings_value_is_saved( | |||
|
514 | self, autologin_user, backend, csrf_token): | |||
|
515 | repo_name = backend.repo_name | |||
|
516 | data = self.FORM_DATA.copy() | |||
|
517 | data['csrf_token'] = csrf_token | |||
|
518 | data['inherit_global_settings'] = True | |||
|
519 | self.app.post( | |||
|
520 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
521 | ||||
|
522 | settings = SettingsModel(repo=repo_name) | |||
|
523 | vcs_settings = VcsSettingsModel(repo=repo_name) | |||
|
524 | try: | |||
|
525 | assert vcs_settings.inherit_global_settings is True | |||
|
526 | finally: | |||
|
527 | self._cleanup_repo_settings(settings) | |||
|
528 | ||||
|
529 | def test_repo_cache_is_invalidated_when_settings_are_updated( | |||
|
530 | self, autologin_user, backend, csrf_token): | |||
|
531 | repo_name = backend.repo_name | |||
|
532 | data = self.FORM_DATA.copy() | |||
|
533 | data['csrf_token'] = csrf_token | |||
|
534 | data['inherit_global_settings'] = True | |||
|
535 | settings = SettingsModel(repo=repo_name) | |||
|
536 | ||||
|
537 | invalidation_patcher = mock.patch( | |||
|
538 | 'rhodecode.model.scm.ScmModel.mark_for_invalidation') | |||
|
539 | with invalidation_patcher as invalidation_mock: | |||
|
540 | self.app.post( | |||
|
541 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, | |||
|
542 | status=302) | |||
|
543 | try: | |||
|
544 | invalidation_mock.assert_called_once_with(repo_name, delete=True) | |||
|
545 | finally: | |||
|
546 | self._cleanup_repo_settings(settings) | |||
|
547 | ||||
|
548 | def test_other_settings_not_saved_inherit_global_settings_is_true( | |||
|
549 | self, autologin_user, backend, csrf_token): | |||
|
550 | repo_name = backend.repo_name | |||
|
551 | data = self.FORM_DATA.copy() | |||
|
552 | data['csrf_token'] = csrf_token | |||
|
553 | data['inherit_global_settings'] = True | |||
|
554 | self.app.post( | |||
|
555 | route_path('edit_repo_vcs_update', repo_name=repo_name), data, status=302) | |||
|
556 | ||||
|
557 | settings = SettingsModel(repo=repo_name) | |||
|
558 | ui_settings = ( | |||
|
559 | VcsSettingsModel.HOOKS_SETTINGS + VcsSettingsModel.HG_SETTINGS) | |||
|
560 | ||||
|
561 | vcs_settings = [] | |||
|
562 | try: | |||
|
563 | for section, key in ui_settings: | |||
|
564 | ui = settings.get_ui_by_section_and_key(section, key) | |||
|
565 | if ui: | |||
|
566 | vcs_settings.append(ui) | |||
|
567 | vcs_settings.extend(settings.get_ui_by_section( | |||
|
568 | VcsSettingsModel.SVN_BRANCH_SECTION)) | |||
|
569 | vcs_settings.extend(settings.get_ui_by_section( | |||
|
570 | VcsSettingsModel.SVN_TAG_SECTION)) | |||
|
571 | for name in VcsSettingsModel.GENERAL_SETTINGS: | |||
|
572 | setting = settings.get_setting_by_name(name) | |||
|
573 | if setting: | |||
|
574 | vcs_settings.append(setting) | |||
|
575 | assert vcs_settings == [] | |||
|
576 | finally: | |||
|
577 | self._cleanup_repo_settings(settings) | |||
|
578 | ||||
|
579 | def test_delete_svn_branch_and_tag_patterns( | |||
|
580 | self, autologin_user, backend_svn, settings_util, csrf_token, xhr_header): | |||
|
581 | repo = backend_svn.create_repo() | |||
|
582 | repo_name = repo.repo_name | |||
|
583 | branch = settings_util.create_repo_rhodecode_ui( | |||
|
584 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch', | |||
|
585 | cleanup=False) | |||
|
586 | tag = settings_util.create_repo_rhodecode_ui( | |||
|
587 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'test_tag', cleanup=False) | |||
|
588 | data = { | |||
|
589 | 'csrf_token': csrf_token | |||
|
590 | } | |||
|
591 | for id_ in (branch.ui_id, tag.ui_id): | |||
|
592 | data['delete_svn_pattern'] = id_, | |||
|
593 | self.app.post( | |||
|
594 | route_path('edit_repo_vcs_svn_pattern_delete', repo_name=repo_name), | |||
|
595 | data, extra_environ=xhr_header, status=200) | |||
|
596 | settings = VcsSettingsModel(repo=repo_name) | |||
|
597 | assert settings.get_repo_svn_branch_patterns() == [] | |||
|
598 | ||||
|
599 | def test_delete_svn_branch_requires_repo_admin_permission( | |||
|
600 | self, backend_svn, user_util, settings_util, csrf_token, xhr_header): | |||
|
601 | repo = backend_svn.create_repo() | |||
|
602 | repo_name = repo.repo_name | |||
|
603 | ||||
|
604 | logout_user_session(self.app, csrf_token) | |||
|
605 | session = login_user_session( | |||
|
606 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |||
|
607 | csrf_token = auth.get_csrf_token(session) | |||
|
608 | ||||
|
609 | repo = Repository.get_by_repo_name(repo_name) | |||
|
610 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) | |||
|
611 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') | |||
|
612 | branch = settings_util.create_repo_rhodecode_ui( | |||
|
613 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch', | |||
|
614 | cleanup=False) | |||
|
615 | data = { | |||
|
616 | 'csrf_token': csrf_token, | |||
|
617 | 'delete_svn_pattern': branch.ui_id | |||
|
618 | } | |||
|
619 | self.app.post( | |||
|
620 | route_path('edit_repo_vcs_svn_pattern_delete', repo_name=repo_name), | |||
|
621 | data, extra_environ=xhr_header, status=200) | |||
|
622 | ||||
|
623 | def test_delete_svn_branch_raises_400_when_not_found( | |||
|
624 | self, autologin_user, backend_svn, settings_util, csrf_token, xhr_header): | |||
|
625 | repo_name = backend_svn.repo_name | |||
|
626 | data = { | |||
|
627 | 'delete_svn_pattern': 123, | |||
|
628 | 'csrf_token': csrf_token | |||
|
629 | } | |||
|
630 | self.app.post( | |||
|
631 | route_path('edit_repo_vcs_svn_pattern_delete', repo_name=repo_name), | |||
|
632 | data, extra_environ=xhr_header, status=400) | |||
|
633 | ||||
|
634 | def test_delete_svn_branch_raises_400_when_no_id_specified( | |||
|
635 | self, autologin_user, backend_svn, settings_util, csrf_token, xhr_header): | |||
|
636 | repo_name = backend_svn.repo_name | |||
|
637 | data = { | |||
|
638 | 'csrf_token': csrf_token | |||
|
639 | } | |||
|
640 | self.app.post( | |||
|
641 | route_path('edit_repo_vcs_svn_pattern_delete', repo_name=repo_name), | |||
|
642 | data, extra_environ=xhr_header, status=400) | |||
|
643 | ||||
|
644 | def _cleanup_repo_settings(self, settings_model): | |||
|
645 | cleanup = [] | |||
|
646 | ui_settings = ( | |||
|
647 | VcsSettingsModel.HOOKS_SETTINGS + VcsSettingsModel.HG_SETTINGS) | |||
|
648 | ||||
|
649 | for section, key in ui_settings: | |||
|
650 | ui = settings_model.get_ui_by_section_and_key(section, key) | |||
|
651 | if ui: | |||
|
652 | cleanup.append(ui) | |||
|
653 | ||||
|
654 | cleanup.extend(settings_model.get_ui_by_section( | |||
|
655 | VcsSettingsModel.INHERIT_SETTINGS)) | |||
|
656 | cleanup.extend(settings_model.get_ui_by_section( | |||
|
657 | VcsSettingsModel.SVN_BRANCH_SECTION)) | |||
|
658 | cleanup.extend(settings_model.get_ui_by_section( | |||
|
659 | VcsSettingsModel.SVN_TAG_SECTION)) | |||
|
660 | ||||
|
661 | for name in VcsSettingsModel.GENERAL_SETTINGS: | |||
|
662 | setting = settings_model.get_setting_by_name(name) | |||
|
663 | if setting: | |||
|
664 | cleanup.append(setting) | |||
|
665 | ||||
|
666 | for object_ in cleanup: | |||
|
667 | Session().delete(object_) | |||
|
668 | Session().commit() | |||
|
669 | ||||
|
670 | def assert_repo_value_equals_global_value(self, response, setting): | |||
|
671 | assert_response = AssertResponse(response) | |||
|
672 | global_css_selector = '[name={}_inherited]'.format(setting) | |||
|
673 | repo_css_selector = '[name={}]'.format(setting) | |||
|
674 | repo_element = assert_response.get_element(repo_css_selector) | |||
|
675 | global_element = assert_response.get_element(global_css_selector) | |||
|
676 | assert repo_element.value == global_element.value | |||
|
677 | ||||
|
678 | ||||
|
679 | def _get_permission_for_user(user, repo): | |||
|
680 | perm = UserRepoToPerm.query()\ | |||
|
681 | .filter(UserRepoToPerm.repository == | |||
|
682 | Repository.get_by_repo_name(repo))\ | |||
|
683 | .filter(UserRepoToPerm.user == User.get_by_username(user))\ | |||
|
684 | .all() | |||
|
685 | return perm |
@@ -0,0 +1,113 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2017-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | import formencode | |||
|
24 | ||||
|
25 | from pyramid.httpexceptions import HTTPFound | |||
|
26 | from pyramid.view import view_config | |||
|
27 | ||||
|
28 | from rhodecode.apps._base import RepoAppView | |||
|
29 | from rhodecode.lib import audit_logger | |||
|
30 | from rhodecode.lib import helpers as h | |||
|
31 | from rhodecode.lib.auth import ( | |||
|
32 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) | |||
|
33 | from rhodecode.model.db import RepositoryField | |||
|
34 | from rhodecode.model.forms import RepoFieldForm | |||
|
35 | from rhodecode.model.meta import Session | |||
|
36 | from rhodecode.model.repo import RepoModel | |||
|
37 | ||||
|
38 | log = logging.getLogger(__name__) | |||
|
39 | ||||
|
40 | ||||
|
41 | class RepoSettingsFieldsView(RepoAppView): | |||
|
42 | def load_default_context(self): | |||
|
43 | c = self._get_local_tmpl_context() | |||
|
44 | ||||
|
45 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead | |||
|
46 | c.repo_info = self.db_repo | |||
|
47 | ||||
|
48 | self._register_global_c(c) | |||
|
49 | return c | |||
|
50 | ||||
|
51 | @LoginRequired() | |||
|
52 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
53 | @view_config( | |||
|
54 | route_name='edit_repo_fields', request_method='GET', | |||
|
55 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
56 | def repo_field_edit(self): | |||
|
57 | c = self.load_default_context() | |||
|
58 | ||||
|
59 | c.active = 'fields' | |||
|
60 | c.repo_fields = RepositoryField.query() \ | |||
|
61 | .filter(RepositoryField.repository == self.db_repo).all() | |||
|
62 | ||||
|
63 | return self._get_template_context(c) | |||
|
64 | ||||
|
65 | @LoginRequired() | |||
|
66 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
67 | @CSRFRequired() | |||
|
68 | @view_config( | |||
|
69 | route_name='edit_repo_fields_create', request_method='POST', | |||
|
70 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
71 | def repo_field_create(self): | |||
|
72 | _ = self.request.translate | |||
|
73 | ||||
|
74 | try: | |||
|
75 | form_result = RepoFieldForm()().to_python(dict(self.request.POST)) | |||
|
76 | RepoModel().add_repo_field( | |||
|
77 | self.db_repo_name, | |||
|
78 | form_result['new_field_key'], | |||
|
79 | field_type=form_result['new_field_type'], | |||
|
80 | field_value=form_result['new_field_value'], | |||
|
81 | field_label=form_result['new_field_label'], | |||
|
82 | field_desc=form_result['new_field_desc']) | |||
|
83 | ||||
|
84 | Session().commit() | |||
|
85 | except Exception as e: | |||
|
86 | log.exception("Exception creating field") | |||
|
87 | msg = _('An error occurred during creation of field') | |||
|
88 | if isinstance(e, formencode.Invalid): | |||
|
89 | msg += ". " + e.msg | |||
|
90 | h.flash(msg, category='error') | |||
|
91 | ||||
|
92 | raise HTTPFound( | |||
|
93 | h.route_path('edit_repo_fields', repo_name=self.db_repo_name)) | |||
|
94 | ||||
|
95 | @LoginRequired() | |||
|
96 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
97 | @CSRFRequired() | |||
|
98 | @view_config( | |||
|
99 | route_name='edit_repo_fields_delete', request_method='POST', | |||
|
100 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
101 | def repo_field_delete(self): | |||
|
102 | _ = self.request.translate | |||
|
103 | field = RepositoryField.get_or_404(self.request.matchdict['field_id']) | |||
|
104 | try: | |||
|
105 | RepoModel().delete_repo_field(self.db_repo_name, field.field_key) | |||
|
106 | Session().commit() | |||
|
107 | except Exception: | |||
|
108 | log.exception('Exception during removal of field') | |||
|
109 | msg = _('An error occurred during removal of field') | |||
|
110 | h.flash(msg, category='error') | |||
|
111 | ||||
|
112 | raise HTTPFound( | |||
|
113 | h.route_path('edit_repo_fields', repo_name=self.db_repo_name)) |
@@ -0,0 +1,129 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2017-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | from pyramid.httpexceptions import HTTPFound | |||
|
24 | from pyramid.view import view_config | |||
|
25 | ||||
|
26 | from rhodecode.apps._base import RepoAppView | |||
|
27 | from rhodecode.lib import audit_logger | |||
|
28 | from rhodecode.lib import helpers as h | |||
|
29 | from rhodecode.lib.auth import ( | |||
|
30 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) | |||
|
31 | from rhodecode.model.forms import IssueTrackerPatternsForm | |||
|
32 | from rhodecode.model.meta import Session | |||
|
33 | from rhodecode.model.settings import IssueTrackerSettingsModel | |||
|
34 | ||||
|
35 | log = logging.getLogger(__name__) | |||
|
36 | ||||
|
37 | ||||
|
38 | class RepoSettingsIssueTrackersView(RepoAppView): | |||
|
39 | def load_default_context(self): | |||
|
40 | c = self._get_local_tmpl_context() | |||
|
41 | ||||
|
42 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead | |||
|
43 | c.repo_info = self.db_repo | |||
|
44 | ||||
|
45 | self._register_global_c(c) | |||
|
46 | return c | |||
|
47 | ||||
|
48 | @LoginRequired() | |||
|
49 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
50 | @view_config( | |||
|
51 | route_name='edit_repo_issuetracker', request_method='GET', | |||
|
52 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
53 | def repo_issuetracker(self): | |||
|
54 | c = self.load_default_context() | |||
|
55 | c.active = 'issuetracker' | |||
|
56 | c.data = 'data' | |||
|
57 | ||||
|
58 | c.settings_model = IssueTrackerSettingsModel(repo=self.db_repo) | |||
|
59 | c.global_patterns = c.settings_model.get_global_settings() | |||
|
60 | c.repo_patterns = c.settings_model.get_repo_settings() | |||
|
61 | ||||
|
62 | return self._get_template_context(c) | |||
|
63 | ||||
|
64 | @LoginRequired() | |||
|
65 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
66 | @CSRFRequired() | |||
|
67 | @view_config( | |||
|
68 | route_name='edit_repo_issuetracker_test', request_method='POST', | |||
|
69 | xhr=True, renderer='string') | |||
|
70 | def repo_issuetracker_test(self): | |||
|
71 | return h.urlify_commit_message( | |||
|
72 | self.request.POST.get('test_text', ''), | |||
|
73 | self.db_repo_name) | |||
|
74 | ||||
|
75 | @LoginRequired() | |||
|
76 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
77 | @CSRFRequired() | |||
|
78 | @view_config( | |||
|
79 | route_name='edit_repo_issuetracker_delete', request_method='POST', | |||
|
80 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
81 | def repo_issuetracker_delete(self): | |||
|
82 | _ = self.request.translate | |||
|
83 | uid = self.request.POST.get('uid') | |||
|
84 | repo_settings = IssueTrackerSettingsModel(repo=self.db_repo_name) | |||
|
85 | try: | |||
|
86 | repo_settings.delete_entries(uid) | |||
|
87 | except Exception: | |||
|
88 | h.flash(_('Error occurred during deleting issue tracker entry'), | |||
|
89 | category='error') | |||
|
90 | else: | |||
|
91 | h.flash(_('Removed issue tracker entry'), category='success') | |||
|
92 | raise HTTPFound( | |||
|
93 | h.route_path('edit_repo_issuetracker', repo_name=self.db_repo_name)) | |||
|
94 | ||||
|
95 | def _update_patterns(self, form, repo_settings): | |||
|
96 | for uid in form['delete_patterns']: | |||
|
97 | repo_settings.delete_entries(uid) | |||
|
98 | ||||
|
99 | for pattern_data in form['patterns']: | |||
|
100 | for setting_key, pattern, type_ in pattern_data: | |||
|
101 | sett = repo_settings.create_or_update_setting( | |||
|
102 | setting_key, pattern.strip(), type_) | |||
|
103 | Session().add(sett) | |||
|
104 | ||||
|
105 | Session().commit() | |||
|
106 | ||||
|
107 | @LoginRequired() | |||
|
108 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
109 | @CSRFRequired() | |||
|
110 | @view_config( | |||
|
111 | route_name='edit_repo_issuetracker_update', request_method='POST', | |||
|
112 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
113 | def repo_issuetracker_update(self): | |||
|
114 | _ = self.request.translate | |||
|
115 | # Save inheritance | |||
|
116 | repo_settings = IssueTrackerSettingsModel(repo=self.db_repo_name) | |||
|
117 | inherited = ( | |||
|
118 | self.request.POST.get('inherit_global_issuetracker') == "inherited") | |||
|
119 | repo_settings.inherit_global_settings = inherited | |||
|
120 | Session().commit() | |||
|
121 | ||||
|
122 | form = IssueTrackerPatternsForm()().to_python(self.request.POST) | |||
|
123 | if form: | |||
|
124 | self._update_patterns(form, repo_settings) | |||
|
125 | ||||
|
126 | h.flash(_('Updated issue tracker entries'), category='success') | |||
|
127 | raise HTTPFound( | |||
|
128 | h.route_path('edit_repo_issuetracker', repo_name=self.db_repo_name)) | |||
|
129 |
@@ -0,0 +1,75 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2017-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | from pyramid.httpexceptions import HTTPFound | |||
|
24 | from pyramid.view import view_config | |||
|
25 | ||||
|
26 | from rhodecode.apps._base import RepoAppView | |||
|
27 | from rhodecode.lib import helpers as h | |||
|
28 | from rhodecode.lib.auth import ( | |||
|
29 | LoginRequired, CSRFRequired, HasRepoPermissionAnyDecorator) | |||
|
30 | from rhodecode.model.scm import ScmModel | |||
|
31 | ||||
|
32 | log = logging.getLogger(__name__) | |||
|
33 | ||||
|
34 | ||||
|
35 | class RepoSettingsRemoteView(RepoAppView): | |||
|
36 | def load_default_context(self): | |||
|
37 | c = self._get_local_tmpl_context() | |||
|
38 | ||||
|
39 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead | |||
|
40 | c.repo_info = self.db_repo | |||
|
41 | ||||
|
42 | self._register_global_c(c) | |||
|
43 | return c | |||
|
44 | ||||
|
45 | @LoginRequired() | |||
|
46 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
47 | @view_config( | |||
|
48 | route_name='edit_repo_remote', request_method='GET', | |||
|
49 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
50 | def repo_remote_edit_form(self): | |||
|
51 | c = self.load_default_context() | |||
|
52 | c.active = 'remote' | |||
|
53 | ||||
|
54 | return self._get_template_context(c) | |||
|
55 | ||||
|
56 | @LoginRequired() | |||
|
57 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
58 | @CSRFRequired() | |||
|
59 | @view_config( | |||
|
60 | route_name='edit_repo_remote_pull', request_method='POST', | |||
|
61 | renderer=None) | |||
|
62 | def repo_remote_pull_changes(self): | |||
|
63 | _ = self.request.translate | |||
|
64 | self.load_default_context() | |||
|
65 | ||||
|
66 | try: | |||
|
67 | ScmModel().pull_changes( | |||
|
68 | self.db_repo_name, self._rhodecode_user.username) | |||
|
69 | h.flash(_('Pulled from remote location'), category='success') | |||
|
70 | except Exception: | |||
|
71 | log.exception("Exception during pull from remote") | |||
|
72 | h.flash(_('An error occurred during pull from remote location'), | |||
|
73 | category='error') | |||
|
74 | raise HTTPFound( | |||
|
75 | h.route_path('edit_repo_remote', repo_name=self.db_repo_name)) |
@@ -0,0 +1,172 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2017-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | import formencode | |||
|
24 | from pyramid.httpexceptions import HTTPFound, HTTPBadRequest | |||
|
25 | from pyramid.response import Response | |||
|
26 | from pyramid.renderers import render | |||
|
27 | from pyramid.view import view_config | |||
|
28 | ||||
|
29 | from rhodecode.apps._base import RepoAppView | |||
|
30 | from rhodecode.lib import audit_logger | |||
|
31 | from rhodecode.lib import helpers as h | |||
|
32 | from rhodecode.lib.auth import ( | |||
|
33 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) | |||
|
34 | from rhodecode.model.forms import RepoVcsSettingsForm | |||
|
35 | from rhodecode.model.meta import Session | |||
|
36 | from rhodecode.model.settings import VcsSettingsModel, SettingNotFound | |||
|
37 | ||||
|
38 | log = logging.getLogger(__name__) | |||
|
39 | ||||
|
40 | ||||
|
41 | class RepoSettingsVcsView(RepoAppView): | |||
|
42 | def load_default_context(self): | |||
|
43 | c = self._get_local_tmpl_context() | |||
|
44 | ||||
|
45 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead | |||
|
46 | c.repo_info = self.db_repo | |||
|
47 | ||||
|
48 | self._register_global_c(c) | |||
|
49 | return c | |||
|
50 | ||||
|
51 | def _vcs_form_defaults(self, repo_name): | |||
|
52 | model = VcsSettingsModel(repo=repo_name) | |||
|
53 | global_defaults = model.get_global_settings() | |||
|
54 | ||||
|
55 | repo_defaults = {} | |||
|
56 | repo_defaults.update(global_defaults) | |||
|
57 | repo_defaults.update(model.get_repo_settings()) | |||
|
58 | ||||
|
59 | global_defaults = { | |||
|
60 | '{}_inherited'.format(k): global_defaults[k] | |||
|
61 | for k in global_defaults} | |||
|
62 | ||||
|
63 | defaults = { | |||
|
64 | 'inherit_global_settings': model.inherit_global_settings | |||
|
65 | } | |||
|
66 | defaults.update(global_defaults) | |||
|
67 | defaults.update(repo_defaults) | |||
|
68 | defaults.update({ | |||
|
69 | 'new_svn_branch': '', | |||
|
70 | 'new_svn_tag': '', | |||
|
71 | }) | |||
|
72 | return defaults | |||
|
73 | ||||
|
74 | @LoginRequired() | |||
|
75 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
76 | @view_config( | |||
|
77 | route_name='edit_repo_vcs', request_method='GET', | |||
|
78 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
79 | def repo_vcs_settings(self): | |||
|
80 | c = self.load_default_context() | |||
|
81 | model = VcsSettingsModel(repo=self.db_repo_name) | |||
|
82 | ||||
|
83 | c.active = 'vcs' | |||
|
84 | c.global_svn_branch_patterns = model.get_global_svn_branch_patterns() | |||
|
85 | c.global_svn_tag_patterns = model.get_global_svn_tag_patterns() | |||
|
86 | c.svn_branch_patterns = model.get_repo_svn_branch_patterns() | |||
|
87 | c.svn_tag_patterns = model.get_repo_svn_tag_patterns() | |||
|
88 | ||||
|
89 | defaults = self._vcs_form_defaults(self.db_repo_name) | |||
|
90 | c.inherit_global_settings = defaults['inherit_global_settings'] | |||
|
91 | ||||
|
92 | data = render('rhodecode:templates/admin/repos/repo_edit.mako', | |||
|
93 | self._get_template_context(c), self.request) | |||
|
94 | html = formencode.htmlfill.render( | |||
|
95 | data, | |||
|
96 | defaults=defaults, | |||
|
97 | encoding="UTF-8", | |||
|
98 | force_defaults=False | |||
|
99 | ) | |||
|
100 | return Response(html) | |||
|
101 | ||||
|
102 | @LoginRequired() | |||
|
103 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
104 | @CSRFRequired() | |||
|
105 | @view_config( | |||
|
106 | route_name='edit_repo_vcs_update', request_method='POST', | |||
|
107 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
108 | def repo_settings_vcs_update(self): | |||
|
109 | _ = self.request.translate | |||
|
110 | c = self.load_default_context() | |||
|
111 | c.active = 'vcs' | |||
|
112 | ||||
|
113 | model = VcsSettingsModel(repo=self.db_repo_name) | |||
|
114 | c.global_svn_branch_patterns = model.get_global_svn_branch_patterns() | |||
|
115 | c.global_svn_tag_patterns = model.get_global_svn_tag_patterns() | |||
|
116 | c.svn_branch_patterns = model.get_repo_svn_branch_patterns() | |||
|
117 | c.svn_tag_patterns = model.get_repo_svn_tag_patterns() | |||
|
118 | ||||
|
119 | defaults = self._vcs_form_defaults(self.db_repo_name) | |||
|
120 | c.inherit_global_settings = defaults['inherit_global_settings'] | |||
|
121 | ||||
|
122 | application_form = RepoVcsSettingsForm(self.db_repo_name)() | |||
|
123 | try: | |||
|
124 | form_result = application_form.to_python(dict(self.request.POST)) | |||
|
125 | except formencode.Invalid as errors: | |||
|
126 | h.flash(_("Some form inputs contain invalid data."), | |||
|
127 | category='error') | |||
|
128 | ||||
|
129 | data = render('rhodecode:templates/admin/repos/repo_edit.mako', | |||
|
130 | self._get_template_context(c), self.request) | |||
|
131 | html = formencode.htmlfill.render( | |||
|
132 | data, | |||
|
133 | defaults=errors.value, | |||
|
134 | errors=errors.error_dict or {}, | |||
|
135 | encoding="UTF-8", | |||
|
136 | force_defaults=False | |||
|
137 | ) | |||
|
138 | return Response(html) | |||
|
139 | ||||
|
140 | try: | |||
|
141 | inherit_global_settings = form_result['inherit_global_settings'] | |||
|
142 | model.create_or_update_repo_settings( | |||
|
143 | form_result, inherit_global_settings=inherit_global_settings) | |||
|
144 | Session().commit() | |||
|
145 | h.flash(_('Updated VCS settings'), category='success') | |||
|
146 | except Exception: | |||
|
147 | log.exception("Exception while updating settings") | |||
|
148 | h.flash( | |||
|
149 | _('Error occurred during updating repository VCS settings'), | |||
|
150 | category='error') | |||
|
151 | ||||
|
152 | raise HTTPFound( | |||
|
153 | h.route_path('edit_repo_vcs', repo_name=self.db_repo_name)) | |||
|
154 | ||||
|
155 | @LoginRequired() | |||
|
156 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
157 | @CSRFRequired() | |||
|
158 | @view_config( | |||
|
159 | route_name='edit_repo_vcs_svn_pattern_delete', request_method='POST', | |||
|
160 | renderer='json_ext', xhr=True) | |||
|
161 | def repo_settings_delete_svn_pattern(self): | |||
|
162 | self.load_default_context() | |||
|
163 | delete_pattern_id = self.request.POST.get('delete_svn_pattern') | |||
|
164 | model = VcsSettingsModel(repo=self.db_repo_name) | |||
|
165 | try: | |||
|
166 | model.delete_repo_svn_pattern(delete_pattern_id) | |||
|
167 | except SettingNotFound: | |||
|
168 | log.exception('Failed to delete SVN pattern') | |||
|
169 | raise HTTPBadRequest() | |||
|
170 | ||||
|
171 | Session().commit() | |||
|
172 | return True |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -205,6 +205,19 b' def admin_routes(config):' | |||||
205 | name='edit_user_group_perms_summary_json', |
|
205 | name='edit_user_group_perms_summary_json', | |
206 | pattern='/user_groups/{user_group_id:\d+}/edit/permissions_summary/json') |
|
206 | pattern='/user_groups/{user_group_id:\d+}/edit/permissions_summary/json') | |
207 |
|
207 | |||
|
208 | # repos admin | |||
|
209 | config.add_route( | |||
|
210 | name='repos', | |||
|
211 | pattern='/repos') | |||
|
212 | ||||
|
213 | config.add_route( | |||
|
214 | name='repo_new', | |||
|
215 | pattern='/repos/new') | |||
|
216 | ||||
|
217 | config.add_route( | |||
|
218 | name='repo_create', | |||
|
219 | pattern='/repos/create') | |||
|
220 | ||||
208 |
|
221 | |||
209 | def includeme(config): |
|
222 | def includeme(config): | |
210 | settings = config.get_settings() |
|
223 | settings = config.get_settings() |
This diff has been collapsed as it changes many lines, (712 lines changed) Show them Hide them | |||||
@@ -23,19 +23,19 b' import urllib' | |||||
23 | import mock |
|
23 | import mock | |
24 | import pytest |
|
24 | import pytest | |
25 |
|
25 | |||
|
26 | from rhodecode.apps._base import ADMIN_PREFIX | |||
26 | from rhodecode.lib import auth |
|
27 | from rhodecode.lib import auth | |
27 |
from rhodecode.lib.utils2 import safe_str |
|
28 | from rhodecode.lib.utils2 import safe_str | |
28 | from rhodecode.lib import helpers as h |
|
29 | from rhodecode.lib import helpers as h | |
29 | from rhodecode.model.db import ( |
|
30 | from rhodecode.model.db import ( | |
30 | Repository, RepoGroup, UserRepoToPerm, User, Permission) |
|
31 | Repository, RepoGroup, UserRepoToPerm, User, Permission) | |
31 | from rhodecode.model.meta import Session |
|
32 | from rhodecode.model.meta import Session | |
32 | from rhodecode.model.repo import RepoModel |
|
33 | from rhodecode.model.repo import RepoModel | |
33 | from rhodecode.model.repo_group import RepoGroupModel |
|
34 | from rhodecode.model.repo_group import RepoGroupModel | |
34 | from rhodecode.model.settings import SettingsModel, VcsSettingsModel |
|
|||
35 | from rhodecode.model.user import UserModel |
|
35 | from rhodecode.model.user import UserModel | |
36 | from rhodecode.tests import ( |
|
36 | from rhodecode.tests import ( | |
37 |
login_user_session |
|
37 | login_user_session, assert_session_flash, TEST_USER_ADMIN_LOGIN, | |
38 |
TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS |
|
38 | TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
39 | from rhodecode.tests.fixture import Fixture, error_function |
|
39 | from rhodecode.tests.fixture import Fixture, error_function | |
40 | from rhodecode.tests.utils import AssertResponse, repo_on_filesystem |
|
40 | from rhodecode.tests.utils import AssertResponse, repo_on_filesystem | |
41 |
|
41 | |||
@@ -46,7 +46,10 b' def route_path(name, params=None, **kwar' | |||||
46 | import urllib |
|
46 | import urllib | |
47 |
|
47 | |||
48 | base_url = { |
|
48 | base_url = { | |
49 |
'repo |
|
49 | 'repos': ADMIN_PREFIX + '/repos', | |
|
50 | 'repo_new': ADMIN_PREFIX + '/repos/new', | |||
|
51 | 'repo_create': ADMIN_PREFIX + '/repos/create', | |||
|
52 | ||||
50 | 'repo_creating_check': '/{repo_name}/repo_creating_check', |
|
53 | 'repo_creating_check': '/{repo_name}/repo_creating_check', | |
51 | }[name].format(**kwargs) |
|
54 | }[name].format(**kwargs) | |
52 |
|
55 | |||
@@ -55,35 +58,48 b' def route_path(name, params=None, **kwar' | |||||
55 | return base_url |
|
58 | return base_url | |
56 |
|
59 | |||
57 |
|
60 | |||
|
61 | def _get_permission_for_user(user, repo): | |||
|
62 | perm = UserRepoToPerm.query()\ | |||
|
63 | .filter(UserRepoToPerm.repository == | |||
|
64 | Repository.get_by_repo_name(repo))\ | |||
|
65 | .filter(UserRepoToPerm.user == User.get_by_username(user))\ | |||
|
66 | .all() | |||
|
67 | return perm | |||
|
68 | ||||
|
69 | ||||
58 | @pytest.mark.usefixtures("app") |
|
70 | @pytest.mark.usefixtures("app") | |
59 | class TestAdminRepos(object): |
|
71 | class TestAdminRepos(object): | |
60 |
|
72 | |||
61 | def test_index(self): |
|
73 | def test_repo_list(self, autologin_user, user_util): | |
62 | self.app.get(url('repos')) |
|
74 | repo = user_util.create_repo() | |
|
75 | response = self.app.get( | |||
|
76 | route_path('repos'), status=200) | |||
63 |
|
77 | |||
64 | def test_create_page_restricted(self, autologin_user, backend): |
|
78 | response.mustcontain(repo.repo_name) | |
|
79 | ||||
|
80 | def test_create_page_restricted_to_single_backend(self, autologin_user, backend): | |||
65 | with mock.patch('rhodecode.BACKENDS', {'git': 'git'}): |
|
81 | with mock.patch('rhodecode.BACKENDS', {'git': 'git'}): | |
66 |
response = self.app.get( |
|
82 | response = self.app.get(route_path('repo_new'), status=200) | |
67 | assert_response = AssertResponse(response) |
|
83 | assert_response = AssertResponse(response) | |
68 | element = assert_response.get_element('#repo_type') |
|
84 | element = assert_response.get_element('#repo_type') | |
69 | assert element.text_content() == '\ngit\n' |
|
85 | assert element.text_content() == '\ngit\n' | |
70 |
|
86 | |||
71 | def test_create_page_non_restricted(self, autologin_user, backend): |
|
87 | def test_create_page_non_restricted_backends(self, autologin_user, backend): | |
72 |
response = self.app.get( |
|
88 | response = self.app.get(route_path('repo_new'), status=200) | |
73 | assert_response = AssertResponse(response) |
|
89 | assert_response = AssertResponse(response) | |
74 | assert_response.element_contains('#repo_type', 'git') |
|
90 | assert_response.element_contains('#repo_type', 'git') | |
75 | assert_response.element_contains('#repo_type', 'svn') |
|
91 | assert_response.element_contains('#repo_type', 'svn') | |
76 | assert_response.element_contains('#repo_type', 'hg') |
|
92 | assert_response.element_contains('#repo_type', 'hg') | |
77 |
|
93 | |||
78 |
@pytest.mark.parametrize( |
|
94 | @pytest.mark.parametrize( | |
79 |
|
|
95 | "suffix", [u'', u'xxa'], ids=['', 'non-ascii']) | |
80 | def test_create(self, autologin_user, backend, suffix, csrf_token): |
|
96 | def test_create(self, autologin_user, backend, suffix, csrf_token): | |
81 | repo_name_unicode = backend.new_repo_name(suffix=suffix) |
|
97 | repo_name_unicode = backend.new_repo_name(suffix=suffix) | |
82 | repo_name = repo_name_unicode.encode('utf8') |
|
98 | repo_name = repo_name_unicode.encode('utf8') | |
83 | description_unicode = u'description for newly created repo' + suffix |
|
99 | description_unicode = u'description for newly created repo' + suffix | |
84 | description = description_unicode.encode('utf8') |
|
100 | description = description_unicode.encode('utf8') | |
85 | response = self.app.post( |
|
101 | response = self.app.post( | |
86 |
|
|
102 | route_path('repo_create'), | |
87 | fixture._get_repo_create_params( |
|
103 | fixture._get_repo_create_params( | |
88 | repo_private=False, |
|
104 | repo_private=False, | |
89 | repo_name=repo_name, |
|
105 | repo_name=repo_name, | |
@@ -95,12 +111,12 b' class TestAdminRepos(object):' | |||||
95 | self.assert_repository_is_created_correctly( |
|
111 | self.assert_repository_is_created_correctly( | |
96 | repo_name, description, backend) |
|
112 | repo_name, description, backend) | |
97 |
|
113 | |||
98 | def test_create_numeric(self, autologin_user, backend, csrf_token): |
|
114 | def test_create_numeric_name(self, autologin_user, backend, csrf_token): | |
99 | numeric_repo = '1234' |
|
115 | numeric_repo = '1234' | |
100 | repo_name = numeric_repo |
|
116 | repo_name = numeric_repo | |
101 | description = 'description for newly created repo' + numeric_repo |
|
117 | description = 'description for newly created repo' + numeric_repo | |
102 | self.app.post( |
|
118 | self.app.post( | |
103 |
|
|
119 | route_path('repo_create'), | |
104 | fixture._get_repo_create_params( |
|
120 | fixture._get_repo_create_params( | |
105 | repo_private=False, |
|
121 | repo_private=False, | |
106 | repo_name=repo_name, |
|
122 | repo_name=repo_name, | |
@@ -126,7 +142,7 b' class TestAdminRepos(object):' | |||||
126 | [group_name, repo_name]) |
|
142 | [group_name, repo_name]) | |
127 | description = u'description for newly created repo' |
|
143 | description = u'description for newly created repo' | |
128 | self.app.post( |
|
144 | self.app.post( | |
129 |
|
|
145 | route_path('repo_create'), | |
130 | fixture._get_repo_create_params( |
|
146 | fixture._get_repo_create_params( | |
131 | repo_private=False, |
|
147 | repo_private=False, | |
132 | repo_name=safe_str(repo_name), |
|
148 | repo_name=safe_str(repo_name), | |
@@ -149,7 +165,7 b' class TestAdminRepos(object):' | |||||
149 | RepoGroupModel().delete(group_name) |
|
165 | RepoGroupModel().delete(group_name) | |
150 | Session().commit() |
|
166 | Session().commit() | |
151 |
|
167 | |||
152 | def test_create_in_group_numeric( |
|
168 | def test_create_in_group_numeric_name( | |
153 | self, autologin_user, backend, csrf_token): |
|
169 | self, autologin_user, backend, csrf_token): | |
154 | # create GROUP |
|
170 | # create GROUP | |
155 | group_name = 'sometest_%s' % backend.alias |
|
171 | group_name = 'sometest_%s' % backend.alias | |
@@ -162,7 +178,7 b' class TestAdminRepos(object):' | |||||
162 | repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) |
|
178 | repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) | |
163 | description = 'description for newly created repo' |
|
179 | description = 'description for newly created repo' | |
164 | self.app.post( |
|
180 | self.app.post( | |
165 |
|
|
181 | route_path('repo_create'), | |
166 | fixture._get_repo_create_params( |
|
182 | fixture._get_repo_create_params( | |
167 | repo_private=False, |
|
183 | repo_private=False, | |
168 | repo_name=repo_name, |
|
184 | repo_name=repo_name, | |
@@ -221,7 +237,7 b' class TestAdminRepos(object):' | |||||
221 | repo_name = 'ingroup' |
|
237 | repo_name = 'ingroup' | |
222 | description = 'description for newly created repo' |
|
238 | description = 'description for newly created repo' | |
223 | response = self.app.post( |
|
239 | response = self.app.post( | |
224 |
|
|
240 | route_path('repo_create'), | |
225 | fixture._get_repo_create_params( |
|
241 | fixture._get_repo_create_params( | |
226 | repo_private=False, |
|
242 | repo_private=False, | |
227 | repo_name=repo_name, |
|
243 | repo_name=repo_name, | |
@@ -238,7 +254,7 b' class TestAdminRepos(object):' | |||||
238 | [group_name_allowed, repo_name]) |
|
254 | [group_name_allowed, repo_name]) | |
239 | description = 'description for newly created repo' |
|
255 | description = 'description for newly created repo' | |
240 | response = self.app.post( |
|
256 | response = self.app.post( | |
241 |
|
|
257 | route_path('repo_create'), | |
242 | fixture._get_repo_create_params( |
|
258 | fixture._get_repo_create_params( | |
243 | repo_private=False, |
|
259 | repo_private=False, | |
244 | repo_name=repo_name, |
|
260 | repo_name=repo_name, | |
@@ -282,7 +298,7 b' class TestAdminRepos(object):' | |||||
282 | repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) |
|
298 | repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) | |
283 | description = 'description for newly created repo' |
|
299 | description = 'description for newly created repo' | |
284 | self.app.post( |
|
300 | self.app.post( | |
285 |
|
|
301 | route_path('repo_create'), | |
286 | fixture._get_repo_create_params( |
|
302 | fixture._get_repo_create_params( | |
287 | repo_private=False, |
|
303 | repo_private=False, | |
288 | repo_name=repo_name, |
|
304 | repo_name=repo_name, | |
@@ -326,7 +342,7 b' class TestAdminRepos(object):' | |||||
326 |
|
342 | |||
327 | repo_name = backend.new_repo_name() |
|
343 | repo_name = backend.new_repo_name() | |
328 | response = self.app.post( |
|
344 | response = self.app.post( | |
329 |
|
|
345 | route_path('repo_create'), | |
330 | fixture._get_repo_create_params( |
|
346 | fixture._get_repo_create_params( | |
331 | repo_private=False, |
|
347 | repo_private=False, | |
332 | repo_name=repo_name, |
|
348 | repo_name=repo_name, | |
@@ -354,7 +370,7 b' class TestAdminRepos(object):' | |||||
354 | repo_name = backend.new_repo_name() |
|
370 | repo_name = backend.new_repo_name() | |
355 | description = 'description for newly created repo' |
|
371 | description = 'description for newly created repo' | |
356 | response = self.app.post( |
|
372 | response = self.app.post( | |
357 |
|
|
373 | route_path('repo_create'), | |
358 | fixture._get_repo_create_params( |
|
374 | fixture._get_repo_create_params( | |
359 | repo_private=False, |
|
375 | repo_private=False, | |
360 | repo_name=repo_name, |
|
376 | repo_name=repo_name, | |
@@ -370,7 +386,7 b' class TestAdminRepos(object):' | |||||
370 | repo_name = backend.new_repo_name() |
|
386 | repo_name = backend.new_repo_name() | |
371 | description = 'description for newly created repo' |
|
387 | description = 'description for newly created repo' | |
372 | response = self.app.post( |
|
388 | response = self.app.post( | |
373 |
|
|
389 | route_path('repo_create'), | |
374 | fixture._get_repo_create_params( |
|
390 | fixture._get_repo_create_params( | |
375 | repo_private=False, |
|
391 | repo_private=False, | |
376 | repo_name=repo_name, |
|
392 | repo_name=repo_name, | |
@@ -385,7 +401,7 b' class TestAdminRepos(object):' | |||||
385 | repo_name = backend.new_repo_name() + ".git" |
|
401 | repo_name = backend.new_repo_name() + ".git" | |
386 | description = 'description for newly created repo' |
|
402 | description = 'description for newly created repo' | |
387 | response = self.app.post( |
|
403 | response = self.app.post( | |
388 |
|
|
404 | route_path('repo_create'), | |
389 | fixture._get_repo_create_params( |
|
405 | fixture._get_repo_create_params( | |
390 | repo_private=False, |
|
406 | repo_private=False, | |
391 | repo_name=repo_name, |
|
407 | repo_name=repo_name, | |
@@ -394,11 +410,8 b' class TestAdminRepos(object):' | |||||
394 | csrf_token=csrf_token)) |
|
410 | csrf_token=csrf_token)) | |
395 | response.mustcontain('Repository name cannot end with .git') |
|
411 | response.mustcontain('Repository name cannot end with .git') | |
396 |
|
412 | |||
397 | def test_show(self, autologin_user, backend): |
|
|||
398 | self.app.get(url('repo', repo_name=backend.repo_name)) |
|
|||
399 |
|
||||
400 | def test_default_user_cannot_access_private_repo_in_a_group( |
|
413 | def test_default_user_cannot_access_private_repo_in_a_group( | |
401 |
self, autologin_user, user_util, backend |
|
414 | self, autologin_user, user_util, backend): | |
402 |
|
415 | |||
403 | group = user_util.create_repo_group() |
|
416 | group = user_util.create_repo_group() | |
404 |
|
417 | |||
@@ -434,7 +447,7 b' class TestAdminRepos(object):' | |||||
434 | repo_name = backend.new_repo_name() |
|
447 | repo_name = backend.new_repo_name() | |
435 | description = 'description for newly created repo' |
|
448 | description = 'description for newly created repo' | |
436 | response = self.app.post( |
|
449 | response = self.app.post( | |
437 |
|
|
450 | route_path('repo_create'), | |
438 | fixture._get_repo_create_params( |
|
451 | fixture._get_repo_create_params( | |
439 | repo_private=False, |
|
452 | repo_private=False, | |
440 | repo_name=repo_name, |
|
453 | repo_name=repo_name, | |
@@ -453,7 +466,7 b' class TestAdminRepos(object):' | |||||
453 | description = 'description for newly created repo' |
|
466 | description = 'description for newly created repo' | |
454 |
|
467 | |||
455 | response = self.app.post( |
|
468 | response = self.app.post( | |
456 |
|
|
469 | route_path('repo_create'), | |
457 | fixture._get_repo_create_params( |
|
470 | fixture._get_repo_create_params( | |
458 | repo_private=False, |
|
471 | repo_private=False, | |
459 | repo_name=repo_name, |
|
472 | repo_name=repo_name, | |
@@ -494,638 +507,3 b' class TestAdminRepos(object):' | |||||
494 | response.mustcontain(backend.alias) |
|
507 | response.mustcontain(backend.alias) | |
495 |
|
508 | |||
496 | assert repo_on_filesystem(repo_name) |
|
509 | assert repo_on_filesystem(repo_name) | |
497 |
|
||||
498 |
|
||||
499 | @pytest.mark.usefixtures("app") |
|
|||
500 | class TestVcsSettings(object): |
|
|||
501 | FORM_DATA = { |
|
|||
502 | 'inherit_global_settings': False, |
|
|||
503 | 'hooks_changegroup_repo_size': False, |
|
|||
504 | 'hooks_changegroup_push_logger': False, |
|
|||
505 | 'hooks_outgoing_pull_logger': False, |
|
|||
506 | 'extensions_largefiles': False, |
|
|||
507 | 'extensions_evolve': False, |
|
|||
508 | 'phases_publish': 'False', |
|
|||
509 | 'rhodecode_pr_merge_enabled': False, |
|
|||
510 | 'rhodecode_use_outdated_comments': False, |
|
|||
511 | 'new_svn_branch': '', |
|
|||
512 | 'new_svn_tag': '' |
|
|||
513 | } |
|
|||
514 |
|
||||
515 | @pytest.mark.skip_backends('svn') |
|
|||
516 | def test_global_settings_initial_values(self, autologin_user, backend): |
|
|||
517 | repo_name = backend.repo_name |
|
|||
518 | response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) |
|
|||
519 |
|
||||
520 | expected_settings = ( |
|
|||
521 | 'rhodecode_use_outdated_comments', 'rhodecode_pr_merge_enabled', |
|
|||
522 | 'hooks_changegroup_repo_size', 'hooks_changegroup_push_logger', |
|
|||
523 | 'hooks_outgoing_pull_logger' |
|
|||
524 | ) |
|
|||
525 | for setting in expected_settings: |
|
|||
526 | self.assert_repo_value_equals_global_value(response, setting) |
|
|||
527 |
|
||||
528 | def test_show_settings_requires_repo_admin_permission( |
|
|||
529 | self, backend, user_util, settings_util): |
|
|||
530 | repo = backend.create_repo() |
|
|||
531 | repo_name = repo.repo_name |
|
|||
532 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) |
|
|||
533 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') |
|
|||
534 | login_user_session( |
|
|||
535 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
|||
536 | self.app.get(url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
537 |
|
||||
538 | def test_inherit_global_settings_flag_is_true_by_default( |
|
|||
539 | self, autologin_user, backend): |
|
|||
540 | repo_name = backend.repo_name |
|
|||
541 | response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) |
|
|||
542 |
|
||||
543 | assert_response = AssertResponse(response) |
|
|||
544 | element = assert_response.get_element('#inherit_global_settings') |
|
|||
545 | assert element.checked |
|
|||
546 |
|
||||
547 | @pytest.mark.parametrize('checked_value', [True, False]) |
|
|||
548 | def test_inherit_global_settings_value( |
|
|||
549 | self, autologin_user, backend, checked_value, settings_util): |
|
|||
550 | repo = backend.create_repo() |
|
|||
551 | repo_name = repo.repo_name |
|
|||
552 | settings_util.create_repo_rhodecode_setting( |
|
|||
553 | repo, 'inherit_vcs_settings', checked_value, 'bool') |
|
|||
554 | response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) |
|
|||
555 |
|
||||
556 | assert_response = AssertResponse(response) |
|
|||
557 | element = assert_response.get_element('#inherit_global_settings') |
|
|||
558 | assert element.checked == checked_value |
|
|||
559 |
|
||||
560 | @pytest.mark.skip_backends('svn') |
|
|||
561 | def test_hooks_settings_are_created( |
|
|||
562 | self, autologin_user, backend, csrf_token): |
|
|||
563 | repo_name = backend.repo_name |
|
|||
564 | data = self.FORM_DATA.copy() |
|
|||
565 | data['csrf_token'] = csrf_token |
|
|||
566 | self.app.post( |
|
|||
567 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
568 | settings = SettingsModel(repo=repo_name) |
|
|||
569 | try: |
|
|||
570 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
571 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
572 | assert ui.ui_active is False |
|
|||
573 | finally: |
|
|||
574 | self._cleanup_repo_settings(settings) |
|
|||
575 |
|
||||
576 | def test_hooks_settings_are_not_created_for_svn( |
|
|||
577 | self, autologin_user, backend_svn, csrf_token): |
|
|||
578 | repo_name = backend_svn.repo_name |
|
|||
579 | data = self.FORM_DATA.copy() |
|
|||
580 | data['csrf_token'] = csrf_token |
|
|||
581 | self.app.post( |
|
|||
582 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
583 | settings = SettingsModel(repo=repo_name) |
|
|||
584 | try: |
|
|||
585 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
586 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
587 | assert ui is None |
|
|||
588 | finally: |
|
|||
589 | self._cleanup_repo_settings(settings) |
|
|||
590 |
|
||||
591 | @pytest.mark.skip_backends('svn') |
|
|||
592 | def test_hooks_settings_are_updated( |
|
|||
593 | self, autologin_user, backend, csrf_token): |
|
|||
594 | repo_name = backend.repo_name |
|
|||
595 | settings = SettingsModel(repo=repo_name) |
|
|||
596 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
597 | settings.create_ui_section_value(section, '', key=key, active=True) |
|
|||
598 |
|
||||
599 | data = self.FORM_DATA.copy() |
|
|||
600 | data['csrf_token'] = csrf_token |
|
|||
601 | self.app.post( |
|
|||
602 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
603 | try: |
|
|||
604 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
605 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
606 | assert ui.ui_active is False |
|
|||
607 | finally: |
|
|||
608 | self._cleanup_repo_settings(settings) |
|
|||
609 |
|
||||
610 | def test_hooks_settings_are_not_updated_for_svn( |
|
|||
611 | self, autologin_user, backend_svn, csrf_token): |
|
|||
612 | repo_name = backend_svn.repo_name |
|
|||
613 | settings = SettingsModel(repo=repo_name) |
|
|||
614 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
615 | settings.create_ui_section_value(section, '', key=key, active=True) |
|
|||
616 |
|
||||
617 | data = self.FORM_DATA.copy() |
|
|||
618 | data['csrf_token'] = csrf_token |
|
|||
619 | self.app.post( |
|
|||
620 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
621 | try: |
|
|||
622 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
623 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
624 | assert ui.ui_active is True |
|
|||
625 | finally: |
|
|||
626 | self._cleanup_repo_settings(settings) |
|
|||
627 |
|
||||
628 | @pytest.mark.skip_backends('svn') |
|
|||
629 | def test_pr_settings_are_created( |
|
|||
630 | self, autologin_user, backend, csrf_token): |
|
|||
631 | repo_name = backend.repo_name |
|
|||
632 | data = self.FORM_DATA.copy() |
|
|||
633 | data['csrf_token'] = csrf_token |
|
|||
634 | self.app.post( |
|
|||
635 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
636 | settings = SettingsModel(repo=repo_name) |
|
|||
637 | try: |
|
|||
638 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
639 | setting = settings.get_setting_by_name(name) |
|
|||
640 | assert setting.app_settings_value is False |
|
|||
641 | finally: |
|
|||
642 | self._cleanup_repo_settings(settings) |
|
|||
643 |
|
||||
644 | def test_pr_settings_are_not_created_for_svn( |
|
|||
645 | self, autologin_user, backend_svn, csrf_token): |
|
|||
646 | repo_name = backend_svn.repo_name |
|
|||
647 | data = self.FORM_DATA.copy() |
|
|||
648 | data['csrf_token'] = csrf_token |
|
|||
649 | self.app.post( |
|
|||
650 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
651 | settings = SettingsModel(repo=repo_name) |
|
|||
652 | try: |
|
|||
653 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
654 | setting = settings.get_setting_by_name(name) |
|
|||
655 | assert setting is None |
|
|||
656 | finally: |
|
|||
657 | self._cleanup_repo_settings(settings) |
|
|||
658 |
|
||||
659 | def test_pr_settings_creation_requires_repo_admin_permission( |
|
|||
660 | self, backend, user_util, settings_util, csrf_token): |
|
|||
661 | repo = backend.create_repo() |
|
|||
662 | repo_name = repo.repo_name |
|
|||
663 |
|
||||
664 | logout_user_session(self.app, csrf_token) |
|
|||
665 | session = login_user_session( |
|
|||
666 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
|||
667 | new_csrf_token = auth.get_csrf_token(session) |
|
|||
668 |
|
||||
669 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) |
|
|||
670 | repo = Repository.get_by_repo_name(repo_name) |
|
|||
671 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') |
|
|||
672 | data = self.FORM_DATA.copy() |
|
|||
673 | data['csrf_token'] = new_csrf_token |
|
|||
674 | settings = SettingsModel(repo=repo_name) |
|
|||
675 |
|
||||
676 | try: |
|
|||
677 | self.app.post( |
|
|||
678 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
679 | status=302) |
|
|||
680 | finally: |
|
|||
681 | self._cleanup_repo_settings(settings) |
|
|||
682 |
|
||||
683 | @pytest.mark.skip_backends('svn') |
|
|||
684 | def test_pr_settings_are_updated( |
|
|||
685 | self, autologin_user, backend, csrf_token): |
|
|||
686 | repo_name = backend.repo_name |
|
|||
687 | settings = SettingsModel(repo=repo_name) |
|
|||
688 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
689 | settings.create_or_update_setting(name, True, 'bool') |
|
|||
690 |
|
||||
691 | data = self.FORM_DATA.copy() |
|
|||
692 | data['csrf_token'] = csrf_token |
|
|||
693 | self.app.post( |
|
|||
694 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
695 | try: |
|
|||
696 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
697 | setting = settings.get_setting_by_name(name) |
|
|||
698 | assert setting.app_settings_value is False |
|
|||
699 | finally: |
|
|||
700 | self._cleanup_repo_settings(settings) |
|
|||
701 |
|
||||
702 | def test_pr_settings_are_not_updated_for_svn( |
|
|||
703 | self, autologin_user, backend_svn, csrf_token): |
|
|||
704 | repo_name = backend_svn.repo_name |
|
|||
705 | settings = SettingsModel(repo=repo_name) |
|
|||
706 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
707 | settings.create_or_update_setting(name, True, 'bool') |
|
|||
708 |
|
||||
709 | data = self.FORM_DATA.copy() |
|
|||
710 | data['csrf_token'] = csrf_token |
|
|||
711 | self.app.post( |
|
|||
712 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
713 | try: |
|
|||
714 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
715 | setting = settings.get_setting_by_name(name) |
|
|||
716 | assert setting.app_settings_value is True |
|
|||
717 | finally: |
|
|||
718 | self._cleanup_repo_settings(settings) |
|
|||
719 |
|
||||
720 | def test_svn_settings_are_created( |
|
|||
721 | self, autologin_user, backend_svn, csrf_token, settings_util): |
|
|||
722 | repo_name = backend_svn.repo_name |
|
|||
723 | data = self.FORM_DATA.copy() |
|
|||
724 | data['new_svn_tag'] = 'svn-tag' |
|
|||
725 | data['new_svn_branch'] = 'svn-branch' |
|
|||
726 | data['csrf_token'] = csrf_token |
|
|||
727 |
|
||||
728 | # Create few global settings to make sure that uniqueness validators |
|
|||
729 | # are not triggered |
|
|||
730 | settings_util.create_rhodecode_ui( |
|
|||
731 | VcsSettingsModel.SVN_BRANCH_SECTION, 'svn-branch') |
|
|||
732 | settings_util.create_rhodecode_ui( |
|
|||
733 | VcsSettingsModel.SVN_TAG_SECTION, 'svn-tag') |
|
|||
734 |
|
||||
735 | self.app.post( |
|
|||
736 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
737 | settings = SettingsModel(repo=repo_name) |
|
|||
738 | try: |
|
|||
739 | svn_branches = settings.get_ui_by_section( |
|
|||
740 | VcsSettingsModel.SVN_BRANCH_SECTION) |
|
|||
741 | svn_branch_names = [b.ui_value for b in svn_branches] |
|
|||
742 | svn_tags = settings.get_ui_by_section( |
|
|||
743 | VcsSettingsModel.SVN_TAG_SECTION) |
|
|||
744 | svn_tag_names = [b.ui_value for b in svn_tags] |
|
|||
745 | assert 'svn-branch' in svn_branch_names |
|
|||
746 | assert 'svn-tag' in svn_tag_names |
|
|||
747 | finally: |
|
|||
748 | self._cleanup_repo_settings(settings) |
|
|||
749 |
|
||||
750 | def test_svn_settings_are_unique( |
|
|||
751 | self, autologin_user, backend_svn, csrf_token, settings_util): |
|
|||
752 | repo = backend_svn.repo |
|
|||
753 | repo_name = repo.repo_name |
|
|||
754 | data = self.FORM_DATA.copy() |
|
|||
755 | data['new_svn_tag'] = 'test_tag' |
|
|||
756 | data['new_svn_branch'] = 'test_branch' |
|
|||
757 | data['csrf_token'] = csrf_token |
|
|||
758 | settings_util.create_repo_rhodecode_ui( |
|
|||
759 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch') |
|
|||
760 | settings_util.create_repo_rhodecode_ui( |
|
|||
761 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'test_tag') |
|
|||
762 |
|
||||
763 | response = self.app.post( |
|
|||
764 | url('repo_vcs_settings', repo_name=repo_name), data, status=200) |
|
|||
765 | response.mustcontain('Pattern already exists') |
|
|||
766 |
|
||||
767 | def test_svn_settings_with_empty_values_are_not_created( |
|
|||
768 | self, autologin_user, backend_svn, csrf_token): |
|
|||
769 | repo_name = backend_svn.repo_name |
|
|||
770 | data = self.FORM_DATA.copy() |
|
|||
771 | data['csrf_token'] = csrf_token |
|
|||
772 | self.app.post( |
|
|||
773 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
774 | settings = SettingsModel(repo=repo_name) |
|
|||
775 | try: |
|
|||
776 | svn_branches = settings.get_ui_by_section( |
|
|||
777 | VcsSettingsModel.SVN_BRANCH_SECTION) |
|
|||
778 | svn_tags = settings.get_ui_by_section( |
|
|||
779 | VcsSettingsModel.SVN_TAG_SECTION) |
|
|||
780 | assert len(svn_branches) == 0 |
|
|||
781 | assert len(svn_tags) == 0 |
|
|||
782 | finally: |
|
|||
783 | self._cleanup_repo_settings(settings) |
|
|||
784 |
|
||||
785 | def test_svn_settings_are_shown_for_svn_repository( |
|
|||
786 | self, autologin_user, backend_svn, csrf_token): |
|
|||
787 | repo_name = backend_svn.repo_name |
|
|||
788 | response = self.app.get( |
|
|||
789 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
790 | response.mustcontain('Subversion Settings') |
|
|||
791 |
|
||||
792 | @pytest.mark.skip_backends('svn') |
|
|||
793 | def test_svn_settings_are_not_created_for_not_svn_repository( |
|
|||
794 | self, autologin_user, backend, csrf_token): |
|
|||
795 | repo_name = backend.repo_name |
|
|||
796 | data = self.FORM_DATA.copy() |
|
|||
797 | data['csrf_token'] = csrf_token |
|
|||
798 | self.app.post( |
|
|||
799 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
800 | settings = SettingsModel(repo=repo_name) |
|
|||
801 | try: |
|
|||
802 | svn_branches = settings.get_ui_by_section( |
|
|||
803 | VcsSettingsModel.SVN_BRANCH_SECTION) |
|
|||
804 | svn_tags = settings.get_ui_by_section( |
|
|||
805 | VcsSettingsModel.SVN_TAG_SECTION) |
|
|||
806 | assert len(svn_branches) == 0 |
|
|||
807 | assert len(svn_tags) == 0 |
|
|||
808 | finally: |
|
|||
809 | self._cleanup_repo_settings(settings) |
|
|||
810 |
|
||||
811 | @pytest.mark.skip_backends('svn') |
|
|||
812 | def test_svn_settings_are_shown_only_for_svn_repository( |
|
|||
813 | self, autologin_user, backend, csrf_token): |
|
|||
814 | repo_name = backend.repo_name |
|
|||
815 | response = self.app.get( |
|
|||
816 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
817 | response.mustcontain(no='Subversion Settings') |
|
|||
818 |
|
||||
819 | def test_hg_settings_are_created( |
|
|||
820 | self, autologin_user, backend_hg, csrf_token): |
|
|||
821 | repo_name = backend_hg.repo_name |
|
|||
822 | data = self.FORM_DATA.copy() |
|
|||
823 | data['new_svn_tag'] = 'svn-tag' |
|
|||
824 | data['new_svn_branch'] = 'svn-branch' |
|
|||
825 | data['csrf_token'] = csrf_token |
|
|||
826 | self.app.post( |
|
|||
827 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
828 | settings = SettingsModel(repo=repo_name) |
|
|||
829 | try: |
|
|||
830 | largefiles_ui = settings.get_ui_by_section_and_key( |
|
|||
831 | 'extensions', 'largefiles') |
|
|||
832 | assert largefiles_ui.ui_active is False |
|
|||
833 | phases_ui = settings.get_ui_by_section_and_key( |
|
|||
834 | 'phases', 'publish') |
|
|||
835 | assert str2bool(phases_ui.ui_value) is False |
|
|||
836 | finally: |
|
|||
837 | self._cleanup_repo_settings(settings) |
|
|||
838 |
|
||||
839 | def test_hg_settings_are_updated( |
|
|||
840 | self, autologin_user, backend_hg, csrf_token): |
|
|||
841 | repo_name = backend_hg.repo_name |
|
|||
842 | settings = SettingsModel(repo=repo_name) |
|
|||
843 | settings.create_ui_section_value( |
|
|||
844 | 'extensions', '', key='largefiles', active=True) |
|
|||
845 | settings.create_ui_section_value( |
|
|||
846 | 'phases', '1', key='publish', active=True) |
|
|||
847 |
|
||||
848 | data = self.FORM_DATA.copy() |
|
|||
849 | data['csrf_token'] = csrf_token |
|
|||
850 | self.app.post( |
|
|||
851 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
852 | try: |
|
|||
853 | largefiles_ui = settings.get_ui_by_section_and_key( |
|
|||
854 | 'extensions', 'largefiles') |
|
|||
855 | assert largefiles_ui.ui_active is False |
|
|||
856 | phases_ui = settings.get_ui_by_section_and_key( |
|
|||
857 | 'phases', 'publish') |
|
|||
858 | assert str2bool(phases_ui.ui_value) is False |
|
|||
859 | finally: |
|
|||
860 | self._cleanup_repo_settings(settings) |
|
|||
861 |
|
||||
862 | def test_hg_settings_are_shown_for_hg_repository( |
|
|||
863 | self, autologin_user, backend_hg, csrf_token): |
|
|||
864 | repo_name = backend_hg.repo_name |
|
|||
865 | response = self.app.get( |
|
|||
866 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
867 | response.mustcontain('Mercurial Settings') |
|
|||
868 |
|
||||
869 | @pytest.mark.skip_backends('hg') |
|
|||
870 | def test_hg_settings_are_created_only_for_hg_repository( |
|
|||
871 | self, autologin_user, backend, csrf_token): |
|
|||
872 | repo_name = backend.repo_name |
|
|||
873 | data = self.FORM_DATA.copy() |
|
|||
874 | data['csrf_token'] = csrf_token |
|
|||
875 | self.app.post( |
|
|||
876 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
877 | settings = SettingsModel(repo=repo_name) |
|
|||
878 | try: |
|
|||
879 | largefiles_ui = settings.get_ui_by_section_and_key( |
|
|||
880 | 'extensions', 'largefiles') |
|
|||
881 | assert largefiles_ui is None |
|
|||
882 | phases_ui = settings.get_ui_by_section_and_key( |
|
|||
883 | 'phases', 'publish') |
|
|||
884 | assert phases_ui is None |
|
|||
885 | finally: |
|
|||
886 | self._cleanup_repo_settings(settings) |
|
|||
887 |
|
||||
888 | @pytest.mark.skip_backends('hg') |
|
|||
889 | def test_hg_settings_are_shown_only_for_hg_repository( |
|
|||
890 | self, autologin_user, backend, csrf_token): |
|
|||
891 | repo_name = backend.repo_name |
|
|||
892 | response = self.app.get( |
|
|||
893 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
894 | response.mustcontain(no='Mercurial Settings') |
|
|||
895 |
|
||||
896 | @pytest.mark.skip_backends('hg') |
|
|||
897 | def test_hg_settings_are_updated_only_for_hg_repository( |
|
|||
898 | self, autologin_user, backend, csrf_token): |
|
|||
899 | repo_name = backend.repo_name |
|
|||
900 | settings = SettingsModel(repo=repo_name) |
|
|||
901 | settings.create_ui_section_value( |
|
|||
902 | 'extensions', '', key='largefiles', active=True) |
|
|||
903 | settings.create_ui_section_value( |
|
|||
904 | 'phases', '1', key='publish', active=True) |
|
|||
905 |
|
||||
906 | data = self.FORM_DATA.copy() |
|
|||
907 | data['csrf_token'] = csrf_token |
|
|||
908 | self.app.post( |
|
|||
909 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
910 | try: |
|
|||
911 | largefiles_ui = settings.get_ui_by_section_and_key( |
|
|||
912 | 'extensions', 'largefiles') |
|
|||
913 | assert largefiles_ui.ui_active is True |
|
|||
914 | phases_ui = settings.get_ui_by_section_and_key( |
|
|||
915 | 'phases', 'publish') |
|
|||
916 | assert phases_ui.ui_value == '1' |
|
|||
917 | finally: |
|
|||
918 | self._cleanup_repo_settings(settings) |
|
|||
919 |
|
||||
920 | def test_per_repo_svn_settings_are_displayed( |
|
|||
921 | self, autologin_user, backend_svn, settings_util): |
|
|||
922 | repo = backend_svn.create_repo() |
|
|||
923 | repo_name = repo.repo_name |
|
|||
924 | branches = [ |
|
|||
925 | settings_util.create_repo_rhodecode_ui( |
|
|||
926 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, |
|
|||
927 | 'branch_{}'.format(i)) |
|
|||
928 | for i in range(10)] |
|
|||
929 | tags = [ |
|
|||
930 | settings_util.create_repo_rhodecode_ui( |
|
|||
931 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'tag_{}'.format(i)) |
|
|||
932 | for i in range(10)] |
|
|||
933 |
|
||||
934 | response = self.app.get( |
|
|||
935 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
936 | assert_response = AssertResponse(response) |
|
|||
937 | for branch in branches: |
|
|||
938 | css_selector = '[name=branch_value_{}]'.format(branch.ui_id) |
|
|||
939 | element = assert_response.get_element(css_selector) |
|
|||
940 | assert element.value == branch.ui_value |
|
|||
941 | for tag in tags: |
|
|||
942 | css_selector = '[name=tag_ui_value_new_{}]'.format(tag.ui_id) |
|
|||
943 | element = assert_response.get_element(css_selector) |
|
|||
944 | assert element.value == tag.ui_value |
|
|||
945 |
|
||||
946 | def test_per_repo_hg_and_pr_settings_are_not_displayed_for_svn( |
|
|||
947 | self, autologin_user, backend_svn, settings_util): |
|
|||
948 | repo = backend_svn.create_repo() |
|
|||
949 | repo_name = repo.repo_name |
|
|||
950 | response = self.app.get( |
|
|||
951 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
952 | response.mustcontain(no='<label>Hooks:</label>') |
|
|||
953 | response.mustcontain(no='<label>Pull Request Settings:</label>') |
|
|||
954 |
|
||||
955 | def test_inherit_global_settings_value_is_saved( |
|
|||
956 | self, autologin_user, backend, csrf_token): |
|
|||
957 | repo_name = backend.repo_name |
|
|||
958 | data = self.FORM_DATA.copy() |
|
|||
959 | data['csrf_token'] = csrf_token |
|
|||
960 | data['inherit_global_settings'] = True |
|
|||
961 | self.app.post( |
|
|||
962 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
963 |
|
||||
964 | settings = SettingsModel(repo=repo_name) |
|
|||
965 | vcs_settings = VcsSettingsModel(repo=repo_name) |
|
|||
966 | try: |
|
|||
967 | assert vcs_settings.inherit_global_settings is True |
|
|||
968 | finally: |
|
|||
969 | self._cleanup_repo_settings(settings) |
|
|||
970 |
|
||||
971 | def test_repo_cache_is_invalidated_when_settings_are_updated( |
|
|||
972 | self, autologin_user, backend, csrf_token): |
|
|||
973 | repo_name = backend.repo_name |
|
|||
974 | data = self.FORM_DATA.copy() |
|
|||
975 | data['csrf_token'] = csrf_token |
|
|||
976 | data['inherit_global_settings'] = True |
|
|||
977 | settings = SettingsModel(repo=repo_name) |
|
|||
978 |
|
||||
979 | invalidation_patcher = mock.patch( |
|
|||
980 | 'rhodecode.controllers.admin.repos.ScmModel.mark_for_invalidation') |
|
|||
981 | with invalidation_patcher as invalidation_mock: |
|
|||
982 | self.app.post( |
|
|||
983 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
984 | status=302) |
|
|||
985 | try: |
|
|||
986 | invalidation_mock.assert_called_once_with(repo_name, delete=True) |
|
|||
987 | finally: |
|
|||
988 | self._cleanup_repo_settings(settings) |
|
|||
989 |
|
||||
990 | def test_other_settings_not_saved_inherit_global_settings_is_true( |
|
|||
991 | self, autologin_user, backend, csrf_token): |
|
|||
992 | repo_name = backend.repo_name |
|
|||
993 | data = self.FORM_DATA.copy() |
|
|||
994 | data['csrf_token'] = csrf_token |
|
|||
995 | data['inherit_global_settings'] = True |
|
|||
996 | self.app.post( |
|
|||
997 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
998 |
|
||||
999 | settings = SettingsModel(repo=repo_name) |
|
|||
1000 | ui_settings = ( |
|
|||
1001 | VcsSettingsModel.HOOKS_SETTINGS + VcsSettingsModel.HG_SETTINGS) |
|
|||
1002 |
|
||||
1003 | vcs_settings = [] |
|
|||
1004 | try: |
|
|||
1005 | for section, key in ui_settings: |
|
|||
1006 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
1007 | if ui: |
|
|||
1008 | vcs_settings.append(ui) |
|
|||
1009 | vcs_settings.extend(settings.get_ui_by_section( |
|
|||
1010 | VcsSettingsModel.SVN_BRANCH_SECTION)) |
|
|||
1011 | vcs_settings.extend(settings.get_ui_by_section( |
|
|||
1012 | VcsSettingsModel.SVN_TAG_SECTION)) |
|
|||
1013 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
1014 | setting = settings.get_setting_by_name(name) |
|
|||
1015 | if setting: |
|
|||
1016 | vcs_settings.append(setting) |
|
|||
1017 | assert vcs_settings == [] |
|
|||
1018 | finally: |
|
|||
1019 | self._cleanup_repo_settings(settings) |
|
|||
1020 |
|
||||
1021 | def test_delete_svn_branch_and_tag_patterns( |
|
|||
1022 | self, autologin_user, backend_svn, settings_util, csrf_token): |
|
|||
1023 | repo = backend_svn.create_repo() |
|
|||
1024 | repo_name = repo.repo_name |
|
|||
1025 | branch = settings_util.create_repo_rhodecode_ui( |
|
|||
1026 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch', |
|
|||
1027 | cleanup=False) |
|
|||
1028 | tag = settings_util.create_repo_rhodecode_ui( |
|
|||
1029 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'test_tag', cleanup=False) |
|
|||
1030 | data = { |
|
|||
1031 | '_method': 'delete', |
|
|||
1032 | 'csrf_token': csrf_token |
|
|||
1033 | } |
|
|||
1034 | for id_ in (branch.ui_id, tag.ui_id): |
|
|||
1035 | data['delete_svn_pattern'] = id_, |
|
|||
1036 | self.app.post( |
|
|||
1037 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
1038 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) |
|
|||
1039 | settings = VcsSettingsModel(repo=repo_name) |
|
|||
1040 | assert settings.get_repo_svn_branch_patterns() == [] |
|
|||
1041 |
|
||||
1042 | def test_delete_svn_branch_requires_repo_admin_permission( |
|
|||
1043 | self, backend_svn, user_util, settings_util, csrf_token): |
|
|||
1044 | repo = backend_svn.create_repo() |
|
|||
1045 | repo_name = repo.repo_name |
|
|||
1046 |
|
||||
1047 | logout_user_session(self.app, csrf_token) |
|
|||
1048 | session = login_user_session( |
|
|||
1049 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
|||
1050 | csrf_token = auth.get_csrf_token(session) |
|
|||
1051 |
|
||||
1052 | repo = Repository.get_by_repo_name(repo_name) |
|
|||
1053 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) |
|
|||
1054 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') |
|
|||
1055 | branch = settings_util.create_repo_rhodecode_ui( |
|
|||
1056 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch', |
|
|||
1057 | cleanup=False) |
|
|||
1058 | data = { |
|
|||
1059 | '_method': 'delete', |
|
|||
1060 | 'csrf_token': csrf_token, |
|
|||
1061 | 'delete_svn_pattern': branch.ui_id |
|
|||
1062 | } |
|
|||
1063 | self.app.post( |
|
|||
1064 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
1065 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) |
|
|||
1066 |
|
||||
1067 | def test_delete_svn_branch_raises_400_when_not_found( |
|
|||
1068 | self, autologin_user, backend_svn, settings_util, csrf_token): |
|
|||
1069 | repo_name = backend_svn.repo_name |
|
|||
1070 | data = { |
|
|||
1071 | '_method': 'delete', |
|
|||
1072 | 'delete_svn_pattern': 123, |
|
|||
1073 | 'csrf_token': csrf_token |
|
|||
1074 | } |
|
|||
1075 | self.app.post( |
|
|||
1076 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
1077 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=400) |
|
|||
1078 |
|
||||
1079 | def test_delete_svn_branch_raises_400_when_no_id_specified( |
|
|||
1080 | self, autologin_user, backend_svn, settings_util, csrf_token): |
|
|||
1081 | repo_name = backend_svn.repo_name |
|
|||
1082 | data = { |
|
|||
1083 | '_method': 'delete', |
|
|||
1084 | 'csrf_token': csrf_token |
|
|||
1085 | } |
|
|||
1086 | self.app.post( |
|
|||
1087 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
1088 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=400) |
|
|||
1089 |
|
||||
1090 | def _cleanup_repo_settings(self, settings_model): |
|
|||
1091 | cleanup = [] |
|
|||
1092 | ui_settings = ( |
|
|||
1093 | VcsSettingsModel.HOOKS_SETTINGS + VcsSettingsModel.HG_SETTINGS) |
|
|||
1094 |
|
||||
1095 | for section, key in ui_settings: |
|
|||
1096 | ui = settings_model.get_ui_by_section_and_key(section, key) |
|
|||
1097 | if ui: |
|
|||
1098 | cleanup.append(ui) |
|
|||
1099 |
|
||||
1100 | cleanup.extend(settings_model.get_ui_by_section( |
|
|||
1101 | VcsSettingsModel.INHERIT_SETTINGS)) |
|
|||
1102 | cleanup.extend(settings_model.get_ui_by_section( |
|
|||
1103 | VcsSettingsModel.SVN_BRANCH_SECTION)) |
|
|||
1104 | cleanup.extend(settings_model.get_ui_by_section( |
|
|||
1105 | VcsSettingsModel.SVN_TAG_SECTION)) |
|
|||
1106 |
|
||||
1107 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
1108 | setting = settings_model.get_setting_by_name(name) |
|
|||
1109 | if setting: |
|
|||
1110 | cleanup.append(setting) |
|
|||
1111 |
|
||||
1112 | for object_ in cleanup: |
|
|||
1113 | Session().delete(object_) |
|
|||
1114 | Session().commit() |
|
|||
1115 |
|
||||
1116 | def assert_repo_value_equals_global_value(self, response, setting): |
|
|||
1117 | assert_response = AssertResponse(response) |
|
|||
1118 | global_css_selector = '[name={}_inherited]'.format(setting) |
|
|||
1119 | repo_css_selector = '[name={}]'.format(setting) |
|
|||
1120 | repo_element = assert_response.get_element(repo_css_selector) |
|
|||
1121 | global_element = assert_response.get_element(global_css_selector) |
|
|||
1122 | assert repo_element.value == global_element.value |
|
|||
1123 |
|
||||
1124 |
|
||||
1125 | def _get_permission_for_user(user, repo): |
|
|||
1126 | perm = UserRepoToPerm.query()\ |
|
|||
1127 | .filter(UserRepoToPerm.repository == |
|
|||
1128 | Repository.get_by_repo_name(repo))\ |
|
|||
1129 | .filter(UserRepoToPerm.user == User.get_by_username(user))\ |
|
|||
1130 | .all() |
|
|||
1131 | return perm |
|
@@ -48,7 +48,7 b' class OpenSourceLicensesAdminSettingsVie' | |||||
48 | c = self.load_default_context() |
|
48 | c = self.load_default_context() | |
49 | c.active = 'open_source' |
|
49 | c.active = 'open_source' | |
50 | c.navlist = navigation_list(self.request) |
|
50 | c.navlist = navigation_list(self.request) | |
51 | c.opensource_licenses = collections.OrderedDict( |
|
51 | items = sorted(read_opensource_licenses().items(), key=lambda t: t[0]) | |
52 | sorted(read_opensource_licenses().items(), key=lambda t: t[0])) |
|
52 | c.opensource_licenses = collections.OrderedDict(items) | |
53 |
|
53 | |||
54 | return self._get_template_context(c) |
|
54 | return self._get_template_context(c) |
@@ -19,7 +19,6 b'' | |||||
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | import logging |
|
21 | import logging | |
22 | import datetime |
|
|||
23 |
|
22 | |||
24 | from pyramid.httpexceptions import HTTPFound |
|
23 | from pyramid.httpexceptions import HTTPFound | |
25 | from pyramid.view import view_config |
|
24 | from pyramid.view import view_config | |
@@ -28,12 +27,11 b' from rhodecode.model.scm import UserGrou' | |||||
28 |
|
27 | |||
29 | from rhodecode.apps._base import BaseAppView, DataGridAppView |
|
28 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |
30 | from rhodecode.lib.auth import ( |
|
29 | from rhodecode.lib.auth import ( | |
31 |
LoginRequired, |
|
30 | LoginRequired, NotAnonymous, | |
32 | HasUserGroupPermissionAnyDecorator) |
|
31 | HasUserGroupPermissionAnyDecorator) | |
33 | from rhodecode.lib import helpers as h |
|
32 | from rhodecode.lib import helpers as h | |
34 | from rhodecode.lib.utils import PartialRenderer |
|
33 | from rhodecode.lib.utils import PartialRenderer | |
35 |
from rhodecode.lib.utils2 import |
|
34 | from rhodecode.lib.utils2 import safe_unicode | |
36 | from rhodecode.model.user_group import UserGroupModel |
|
|||
37 | from rhodecode.model.db import ( |
|
35 | from rhodecode.model.db import ( | |
38 | joinedload, or_, count, User, UserGroup, UserGroupMember, |
|
36 | joinedload, or_, count, User, UserGroup, UserGroupMember, | |
39 | UserGroupRepoToPerm, UserGroupRepoGroupToPerm) |
|
37 | UserGroupRepoToPerm, UserGroupRepoGroupToPerm) |
@@ -337,7 +337,76 b' def includeme(config):' | |||||
337 | name='edit_repo_perms', |
|
337 | name='edit_repo_perms', | |
338 | pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True) |
|
338 | pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True) | |
339 |
|
339 | |||
340 | # Repo Review Rules |
|
340 | # Maintenance | |
|
341 | config.add_route( | |||
|
342 | name='edit_repo_maintenance', | |||
|
343 | pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True) | |||
|
344 | ||||
|
345 | config.add_route( | |||
|
346 | name='edit_repo_maintenance_execute', | |||
|
347 | pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True) | |||
|
348 | ||||
|
349 | # Fields | |||
|
350 | config.add_route( | |||
|
351 | name='edit_repo_fields', | |||
|
352 | pattern='/{repo_name:.*?[^/]}/settings/fields', repo_route=True) | |||
|
353 | config.add_route( | |||
|
354 | name='edit_repo_fields_create', | |||
|
355 | pattern='/{repo_name:.*?[^/]}/settings/fields/create', repo_route=True) | |||
|
356 | config.add_route( | |||
|
357 | name='edit_repo_fields_delete', | |||
|
358 | pattern='/{repo_name:.*?[^/]}/settings/fields/{field_id}/delete', repo_route=True) | |||
|
359 | ||||
|
360 | # Locking | |||
|
361 | config.add_route( | |||
|
362 | name='repo_edit_toggle_locking', | |||
|
363 | pattern='/{repo_name:.*?[^/]}/settings/toggle_locking', repo_route=True) | |||
|
364 | ||||
|
365 | # Remote | |||
|
366 | config.add_route( | |||
|
367 | name='edit_repo_remote', | |||
|
368 | pattern='/{repo_name:.*?[^/]}/settings/remote', repo_route=True) | |||
|
369 | config.add_route( | |||
|
370 | name='edit_repo_remote_pull', | |||
|
371 | pattern='/{repo_name:.*?[^/]}/settings/remote/pull', repo_route=True) | |||
|
372 | ||||
|
373 | ||||
|
374 | # Statistics | |||
|
375 | config.add_route( | |||
|
376 | name='edit_repo_statistics', | |||
|
377 | pattern='/{repo_name:.*?[^/]}/settings/statistics', repo_route=True) | |||
|
378 | config.add_route( | |||
|
379 | name='edit_repo_statistics_reset', | |||
|
380 | pattern='/{repo_name:.*?[^/]}/settings/statistics/update', repo_route=True) | |||
|
381 | ||||
|
382 | # Issue trackers | |||
|
383 | config.add_route( | |||
|
384 | name='edit_repo_issuetracker', | |||
|
385 | pattern='/{repo_name:.*?[^/]}/settings/issue_trackers', repo_route=True) | |||
|
386 | config.add_route( | |||
|
387 | name='edit_repo_issuetracker_test', | |||
|
388 | pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/test', repo_route=True) | |||
|
389 | config.add_route( | |||
|
390 | name='edit_repo_issuetracker_delete', | |||
|
391 | pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/delete', repo_route=True) | |||
|
392 | config.add_route( | |||
|
393 | name='edit_repo_issuetracker_update', | |||
|
394 | pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/update', repo_route=True) | |||
|
395 | ||||
|
396 | # VCS Settings | |||
|
397 | config.add_route( | |||
|
398 | name='edit_repo_vcs', | |||
|
399 | pattern='/{repo_name:.*?[^/]}/settings/vcs', repo_route=True) | |||
|
400 | config.add_route( | |||
|
401 | name='edit_repo_vcs_update', | |||
|
402 | pattern='/{repo_name:.*?[^/]}/settings/vcs/update', repo_route=True) | |||
|
403 | ||||
|
404 | # svn pattern | |||
|
405 | config.add_route( | |||
|
406 | name='edit_repo_vcs_svn_pattern_delete', | |||
|
407 | pattern='/{repo_name:.*?[^/]}/settings/vcs/svn_pattern/delete', repo_route=True) | |||
|
408 | ||||
|
409 | # Repo Review Rules (EE feature) | |||
341 | config.add_route( |
|
410 | config.add_route( | |
342 | name='repo_reviewers', |
|
411 | name='repo_reviewers', | |
343 | pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True) |
|
412 | pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True) | |
@@ -346,18 +415,9 b' def includeme(config):' | |||||
346 | name='repo_default_reviewers_data', |
|
415 | name='repo_default_reviewers_data', | |
347 | pattern='/{repo_name:.*?[^/]}/settings/review/default-reviewers', repo_route=True) |
|
416 | pattern='/{repo_name:.*?[^/]}/settings/review/default-reviewers', repo_route=True) | |
348 |
|
417 | |||
349 | # Maintenance |
|
|||
350 | config.add_route( |
|
|||
351 | name='repo_maintenance', |
|
|||
352 | pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True) |
|
|||
353 |
|
||||
354 | config.add_route( |
|
|||
355 | name='repo_maintenance_execute', |
|
|||
356 | pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True) |
|
|||
357 |
|
||||
358 | # Strip |
|
418 | # Strip | |
359 | config.add_route( |
|
419 | config.add_route( | |
360 | name='strip', |
|
420 | name='edit_repo_strip', | |
361 | pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True) |
|
421 | pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True) | |
362 |
|
422 | |||
363 | config.add_route( |
|
423 | config.add_route( |
@@ -24,23 +24,38 b' from rhodecode.lib.utils2 import md5' | |||||
24 | from rhodecode.model.db import Repository |
|
24 | from rhodecode.model.db import Repository | |
25 | from rhodecode.model.meta import Session |
|
25 | from rhodecode.model.meta import Session | |
26 | from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel |
|
26 | from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel | |
27 | from rhodecode.tests import url |
|
27 | ||
|
28 | ||||
|
29 | def route_path(name, params=None, **kwargs): | |||
|
30 | import urllib | |||
|
31 | ||||
|
32 | base_url = { | |||
|
33 | 'repo_summary': '/{repo_name}', | |||
|
34 | 'edit_repo_issuetracker': '/{repo_name}/settings/issue_trackers', | |||
|
35 | 'edit_repo_issuetracker_test': '/{repo_name}/settings/issue_trackers/test', | |||
|
36 | 'edit_repo_issuetracker_delete': '/{repo_name}/settings/issue_trackers/delete', | |||
|
37 | 'edit_repo_issuetracker_update': '/{repo_name}/settings/issue_trackers/update', | |||
|
38 | }[name].format(**kwargs) | |||
|
39 | ||||
|
40 | if params: | |||
|
41 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
42 | return base_url | |||
28 |
|
43 | |||
29 |
|
44 | |||
30 | @pytest.mark.usefixtures("app") |
|
45 | @pytest.mark.usefixtures("app") | |
31 | class TestAdminRepos: |
|
46 | class TestRepoIssueTracker(object): | |
32 | def test_issuetracker_index(self, autologin_user, backend): |
|
47 | def test_issuetracker_index(self, autologin_user, backend): | |
33 | repo = backend.create_repo() |
|
48 | repo = backend.create_repo() | |
34 |
response = self.app.get( |
|
49 | response = self.app.get(route_path('edit_repo_issuetracker', | |
35 | repo_name=repo.repo_name)) |
|
50 | repo_name=repo.repo_name)) | |
36 | assert response.status_code == 200 |
|
51 | assert response.status_code == 200 | |
37 |
|
52 | |||
38 | def test_add_issuetracker_patterns( |
|
53 | def test_add_and_test_issuetracker_patterns( | |
39 | self, autologin_user, backend, csrf_token, request): |
|
54 | self, autologin_user, backend, csrf_token, request, xhr_header): | |
40 | pattern = 'issuetracker_pat' |
|
55 | pattern = 'issuetracker_pat' | |
41 | another_pattern = pattern+'1' |
|
56 | another_pattern = pattern+'1' | |
42 | post_url = url('repo_issuetracker_save', |
|
57 | post_url = route_path( | |
43 |
|
|
58 | 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name) | |
44 | post_data = { |
|
59 | post_data = { | |
45 | 'new_pattern_pattern_0': pattern, |
|
60 | 'new_pattern_pattern_0': pattern, | |
46 | 'new_pattern_url_0': 'url', |
|
61 | 'new_pattern_url_0': 'url', | |
@@ -60,6 +75,17 b' class TestAdminRepos:' | |||||
60 | self.another_uid = md5(another_pattern) |
|
75 | self.another_uid = md5(another_pattern) | |
61 | assert settings[self.another_uid]['pat'] == another_pattern |
|
76 | assert settings[self.another_uid]['pat'] == another_pattern | |
62 |
|
77 | |||
|
78 | # test pattern | |||
|
79 | data = {'test_text': 'example of issuetracker_pat replacement', | |||
|
80 | 'csrf_token': csrf_token} | |||
|
81 | response = self.app.post( | |||
|
82 | route_path('edit_repo_issuetracker_test', | |||
|
83 | repo_name=backend.repo.repo_name), | |||
|
84 | extra_environ=xhr_header, params=data) | |||
|
85 | ||||
|
86 | assert response.body == \ | |||
|
87 | 'example of <a class="issue-tracker-link" href="url">prefix</a> replacement' | |||
|
88 | ||||
63 | @request.addfinalizer |
|
89 | @request.addfinalizer | |
64 | def cleanup(): |
|
90 | def cleanup(): | |
65 | self.settings_model.delete_entries(self.uid) |
|
91 | self.settings_model.delete_entries(self.uid) | |
@@ -76,8 +102,8 b' class TestAdminRepos:' | |||||
76 | entry_key+old_uid, old_pattern, 'unicode') |
|
102 | entry_key+old_uid, old_pattern, 'unicode') | |
77 | Session().add(sett) |
|
103 | Session().add(sett) | |
78 | Session().commit() |
|
104 | Session().commit() | |
79 | post_url = url('repo_issuetracker_save', |
|
105 | post_url = route_path( | |
80 |
|
|
106 | 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name) | |
81 | post_data = { |
|
107 | post_data = { | |
82 | 'new_pattern_pattern_0': pattern, |
|
108 | 'new_pattern_pattern_0': pattern, | |
83 | 'new_pattern_url_0': 'url', |
|
109 | 'new_pattern_url_0': 'url', | |
@@ -92,7 +118,7 b' class TestAdminRepos:' | |||||
92 | self.uid = md5(pattern) |
|
118 | self.uid = md5(pattern) | |
93 | assert settings[self.uid]['pat'] == pattern |
|
119 | assert settings[self.uid]['pat'] == pattern | |
94 | with pytest.raises(KeyError): |
|
120 | with pytest.raises(KeyError): | |
95 | settings[old_uid] |
|
121 | key = settings[old_uid] | |
96 |
|
122 | |||
97 | @request.addfinalizer |
|
123 | @request.addfinalizer | |
98 | def cleanup(): |
|
124 | def cleanup(): | |
@@ -110,10 +136,10 b' class TestAdminRepos:' | |||||
110 | value=entry_key, type_='unicode', cleanup=False) |
|
136 | value=entry_key, type_='unicode', cleanup=False) | |
111 |
|
137 | |||
112 | self.app.post( |
|
138 | self.app.post( | |
113 | url('repo_issuetracker_delete', |
|
139 | route_path( | |
|
140 | 'edit_repo_issuetracker_delete', | |||
114 | repo_name=backend.repo.repo_name), |
|
141 | repo_name=backend.repo.repo_name), | |
115 | { |
|
142 | { | |
116 | '_method': 'delete', |
|
|||
117 | 'uid': uid, |
|
143 | 'uid': uid, | |
118 | 'csrf_token': csrf_token |
|
144 | 'csrf_token': csrf_token | |
119 | }, status=302) |
|
145 | }, status=302) |
@@ -26,8 +26,7 b' from rhodecode.lib.vcs.exceptions import' | |||||
26 | from rhodecode.model.db import Repository, UserRepoToPerm, Permission, User |
|
26 | from rhodecode.model.db import Repository, UserRepoToPerm, Permission, User | |
27 | from rhodecode.model.meta import Session |
|
27 | from rhodecode.model.meta import Session | |
28 | from rhodecode.tests import ( |
|
28 | from rhodecode.tests import ( | |
29 |
|
|
29 | TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, assert_session_flash) | |
30 | assert_session_flash) |
|
|||
31 | from rhodecode.tests.fixture import Fixture |
|
30 | from rhodecode.tests.fixture import Fixture | |
32 |
|
31 | |||
33 | fixture = Fixture() |
|
32 | fixture = Fixture() | |
@@ -41,6 +40,11 b' def route_path(name, params=None, **kwar' | |||||
41 | 'edit_repo_advanced': '/{repo_name}/settings/advanced', |
|
40 | 'edit_repo_advanced': '/{repo_name}/settings/advanced', | |
42 | 'edit_repo_caches': '/{repo_name}/settings/caches', |
|
41 | 'edit_repo_caches': '/{repo_name}/settings/caches', | |
43 | 'edit_repo_perms': '/{repo_name}/settings/permissions', |
|
42 | 'edit_repo_perms': '/{repo_name}/settings/permissions', | |
|
43 | 'edit_repo_vcs': '/{repo_name}/settings/vcs', | |||
|
44 | 'edit_repo_issuetracker': '/{repo_name}/settings/issue_trackers', | |||
|
45 | 'edit_repo_fields': '/{repo_name}/settings/fields', | |||
|
46 | 'edit_repo_remote': '/{repo_name}/settings/remote', | |||
|
47 | 'edit_repo_statistics': '/{repo_name}/settings/statistics', | |||
44 | }[name].format(**kwargs) |
|
48 | }[name].format(**kwargs) | |
45 |
|
49 | |||
46 | if params: |
|
50 | if params: | |
@@ -64,6 +68,11 b' class TestAdminRepoSettings(object):' | |||||
64 | 'edit_repo_caches', |
|
68 | 'edit_repo_caches', | |
65 | 'edit_repo_perms', |
|
69 | 'edit_repo_perms', | |
66 | 'edit_repo_advanced', |
|
70 | 'edit_repo_advanced', | |
|
71 | 'edit_repo_vcs', | |||
|
72 | 'edit_repo_issuetracker', | |||
|
73 | 'edit_repo_fields', | |||
|
74 | 'edit_repo_remote', | |||
|
75 | 'edit_repo_statistics', | |||
67 | ]) |
|
76 | ]) | |
68 | def test_show_page(self, urlname, app, backend): |
|
77 | def test_show_page(self, urlname, app, backend): | |
69 | app.get(route_path(urlname, repo_name=backend.repo_name), status=200) |
|
78 | app.get(route_path(urlname, repo_name=backend.repo_name), status=200) | |
@@ -75,16 +84,6 b' class TestAdminRepoSettings(object):' | |||||
75 | with scm_patcher: |
|
84 | with scm_patcher: | |
76 | self.app.get(route_path('edit_repo', repo_name=backend_hg.repo_name)) |
|
85 | self.app.get(route_path('edit_repo', repo_name=backend_hg.repo_name)) | |
77 |
|
86 | |||
78 | @pytest.mark.parametrize('urlname', [ |
|
|||
79 | 'repo_vcs_settings', |
|
|||
80 | 'repo_settings_issuetracker', |
|
|||
81 | 'edit_repo_fields', |
|
|||
82 | 'edit_repo_remote', |
|
|||
83 | 'edit_repo_statistics', |
|
|||
84 | ]) |
|
|||
85 | def test_show_page_pylons(self, urlname, app): |
|
|||
86 | app.get(url(urlname, repo_name=HG_REPO)) |
|
|||
87 |
|
||||
88 | @pytest.mark.parametrize('update_settings', [ |
|
87 | @pytest.mark.parametrize('update_settings', [ | |
89 | {'repo_description': 'alter-desc'}, |
|
88 | {'repo_description': 'alter-desc'}, | |
90 | {'repo_owner': TEST_USER_REGULAR_LOGIN}, |
|
89 | {'repo_owner': TEST_USER_REGULAR_LOGIN}, |
@@ -24,7 +24,6 b' import pytest' | |||||
24 | import rhodecode |
|
24 | import rhodecode | |
25 | from rhodecode.model.db import Repository |
|
25 | from rhodecode.model.db import Repository | |
26 | from rhodecode.model.settings import SettingsModel |
|
26 | from rhodecode.model.settings import SettingsModel | |
27 | from rhodecode.tests import url |
|
|||
28 | from rhodecode.tests.utils import AssertResponse |
|
27 | from rhodecode.tests.utils import AssertResponse | |
29 |
|
28 | |||
30 |
|
29 | |||
@@ -33,6 +32,8 b' def route_path(name, params=None, **kwar' | |||||
33 |
|
32 | |||
34 | base_url = { |
|
33 | base_url = { | |
35 | 'edit_repo': '/{repo_name}/settings', |
|
34 | 'edit_repo': '/{repo_name}/settings', | |
|
35 | 'edit_repo_vcs': '/{repo_name}/settings/vcs', | |||
|
36 | 'edit_repo_vcs_update': '/{repo_name}/settings/vcs/update', | |||
36 | }[name].format(**kwargs) |
|
37 | }[name].format(**kwargs) | |
37 |
|
38 | |||
38 | if params: |
|
39 | if params: | |
@@ -51,8 +52,8 b' class TestAdminRepoVcsSettings(object):' | |||||
51 | if backend.alias not in setting_backends: |
|
52 | if backend.alias not in setting_backends: | |
52 | pytest.skip('Setting not available for backend {}'.format(backend)) |
|
53 | pytest.skip('Setting not available for backend {}'.format(backend)) | |
53 |
|
54 | |||
54 |
vcs_settings_url = |
|
55 | vcs_settings_url = route_path( | |
55 |
'repo_vcs |
|
56 | 'edit_repo_vcs', repo_name=backend.repo.repo_name) | |
56 |
|
57 | |||
57 | with mock.patch.dict( |
|
58 | with mock.patch.dict( | |
58 | rhodecode.CONFIG, {'labs_settings_active': 'true'}): |
|
59 | rhodecode.CONFIG, {'labs_settings_active': 'true'}): | |
@@ -64,24 +65,6 b' class TestAdminRepoVcsSettings(object):' | |||||
64 | @pytest.mark.parametrize('setting_name, setting_backends', [ |
|
65 | @pytest.mark.parametrize('setting_name, setting_backends', [ | |
65 | ('hg_use_rebase_for_merging', ['hg']), |
|
66 | ('hg_use_rebase_for_merging', ['hg']), | |
66 | ]) |
|
67 | ]) | |
67 | def test_labs_settings_not_visible_if_disabled( |
|
|||
68 | self, setting_name, setting_backends, backend): |
|
|||
69 | if backend.alias not in setting_backends: |
|
|||
70 | pytest.skip('Setting not available for backend {}'.format(backend)) |
|
|||
71 |
|
||||
72 | vcs_settings_url = url( |
|
|||
73 | 'repo_vcs_settings', repo_name=backend.repo.repo_name) |
|
|||
74 |
|
||||
75 | with mock.patch.dict( |
|
|||
76 | rhodecode.CONFIG, {'labs_settings_active': 'false'}): |
|
|||
77 | response = self.app.get(vcs_settings_url) |
|
|||
78 |
|
||||
79 | assertr = AssertResponse(response) |
|
|||
80 | assertr.no_element_exists('#rhodecode_{}'.format(setting_name)) |
|
|||
81 |
|
||||
82 | @pytest.mark.parametrize('setting_name, setting_backends', [ |
|
|||
83 | ('hg_use_rebase_for_merging', ['hg']), |
|
|||
84 | ]) |
|
|||
85 | def test_update_boolean_settings( |
|
68 | def test_update_boolean_settings( | |
86 | self, csrf_token, setting_name, setting_backends, backend): |
|
69 | self, csrf_token, setting_name, setting_backends, backend): | |
87 | if backend.alias not in setting_backends: |
|
70 | if backend.alias not in setting_backends: | |
@@ -91,8 +74,8 b' class TestAdminRepoVcsSettings(object):' | |||||
91 | repo_name = repo.repo_name |
|
74 | repo_name = repo.repo_name | |
92 |
|
75 | |||
93 | settings_model = SettingsModel(repo=repo) |
|
76 | settings_model = SettingsModel(repo=repo) | |
94 |
vcs_settings_url = |
|
77 | vcs_settings_url = route_path( | |
95 |
'repo_vcs_ |
|
78 | 'edit_repo_vcs_update', repo_name=repo_name) | |
96 |
|
79 | |||
97 | self.app.post( |
|
80 | self.app.post( | |
98 | vcs_settings_url, |
|
81 | vcs_settings_url, |
@@ -36,7 +36,7 b' from rhodecode.lib.auth import (' | |||||
36 | from rhodecode.lib.compat import OrderedDict |
|
36 | from rhodecode.lib.compat import OrderedDict | |
37 | from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError |
|
37 | from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError | |
38 | import rhodecode.lib.helpers as h |
|
38 | import rhodecode.lib.helpers as h | |
39 |
from rhodecode.lib.utils2 import safe_unicode |
|
39 | from rhodecode.lib.utils2 import safe_unicode | |
40 | from rhodecode.lib.vcs.backends.base import EmptyCommit |
|
40 | from rhodecode.lib.vcs.backends.base import EmptyCommit | |
41 | from rhodecode.lib.vcs.exceptions import ( |
|
41 | from rhodecode.lib.vcs.exceptions import ( | |
42 | RepositoryError, CommitDoesNotExistError, NodeDoesNotExistError) |
|
42 | RepositoryError, CommitDoesNotExistError, NodeDoesNotExistError) |
@@ -29,10 +29,9 b' from webhelpers.feedgenerator import Rss' | |||||
29 | from rhodecode.apps._base import RepoAppView |
|
29 | from rhodecode.apps._base import RepoAppView | |
30 | from rhodecode.lib import audit_logger |
|
30 | from rhodecode.lib import audit_logger | |
31 | from rhodecode.lib import helpers as h |
|
31 | from rhodecode.lib import helpers as h | |
32 | from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator, |
|
32 | from rhodecode.lib.auth import ( | |
33 | NotAnonymous, CSRFRequired) |
|
33 | LoginRequired, HasRepoPermissionAnyDecorator) | |
34 | from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer |
|
34 | from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer | |
35 | from rhodecode.lib.ext_json import json |
|
|||
36 | from rhodecode.lib.utils2 import str2bool, safe_int |
|
35 | from rhodecode.lib.utils2 import str2bool, safe_int | |
37 | from rhodecode.model.db import UserApiKeys, CacheKey |
|
36 | from rhodecode.model.db import UserApiKeys, CacheKey | |
38 |
|
37 |
@@ -23,8 +23,7 b' import logging' | |||||
23 | from pyramid.view import view_config |
|
23 | from pyramid.view import view_config | |
24 |
|
24 | |||
25 | from rhodecode.apps._base import RepoAppView |
|
25 | from rhodecode.apps._base import RepoAppView | |
26 |
from rhodecode.lib.auth import |
|
26 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
27 | NotAnonymous) |
|
|||
28 | from rhodecode.lib import repo_maintenance |
|
27 | from rhodecode.lib import repo_maintenance | |
29 |
|
28 | |||
30 | log = logging.getLogger(__name__) |
|
29 | log = logging.getLogger(__name__) | |
@@ -43,7 +42,7 b' class RepoMaintenanceView(RepoAppView):' | |||||
43 | @LoginRequired() |
|
42 | @LoginRequired() | |
44 | @HasRepoPermissionAnyDecorator('repository.admin') |
|
43 | @HasRepoPermissionAnyDecorator('repository.admin') | |
45 | @view_config( |
|
44 | @view_config( | |
46 | route_name='repo_maintenance', request_method='GET', |
|
45 | route_name='edit_repo_maintenance', request_method='GET', | |
47 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') |
|
46 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |
48 | def repo_maintenance(self): |
|
47 | def repo_maintenance(self): | |
49 | c = self.load_default_context() |
|
48 | c = self.load_default_context() | |
@@ -55,7 +54,7 b' class RepoMaintenanceView(RepoAppView):' | |||||
55 | @LoginRequired() |
|
54 | @LoginRequired() | |
56 | @HasRepoPermissionAnyDecorator('repository.admin') |
|
55 | @HasRepoPermissionAnyDecorator('repository.admin') | |
57 | @view_config( |
|
56 | @view_config( | |
58 | route_name='repo_maintenance_execute', request_method='GET', |
|
57 | route_name='edit_repo_maintenance_execute', request_method='GET', | |
59 | renderer='json', xhr=True) |
|
58 | renderer='json', xhr=True) | |
60 | def repo_maintenance_execute(self): |
|
59 | def repo_maintenance_execute(self): | |
61 | c = self.load_default_context() |
|
60 | c = self.load_default_context() |
@@ -20,23 +20,17 b'' | |||||
20 |
|
20 | |||
21 | import logging |
|
21 | import logging | |
22 |
|
22 | |||
23 | import deform |
|
|||
24 | from pyramid.httpexceptions import HTTPFound |
|
23 | from pyramid.httpexceptions import HTTPFound | |
25 | from pyramid.view import view_config |
|
24 | from pyramid.view import view_config | |
26 |
|
25 | |||
27 | from rhodecode.apps._base import RepoAppView |
|
26 | from rhodecode.apps._base import RepoAppView | |
28 | from rhodecode.forms import RcForm |
|
|||
29 | from rhodecode.lib import helpers as h |
|
27 | from rhodecode.lib import helpers as h | |
30 | from rhodecode.lib import audit_logger |
|
28 | from rhodecode.lib import audit_logger | |
31 | from rhodecode.lib.auth import ( |
|
29 | from rhodecode.lib.auth import ( | |
32 | LoginRequired, HasRepoPermissionAnyDecorator, |
|
30 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) | |
33 | HasRepoPermissionAllDecorator, CSRFRequired) |
|
|||
34 | from rhodecode.model.db import RepositoryField, RepoGroup |
|
|||
35 | from rhodecode.model.forms import RepoPermsForm |
|
31 | from rhodecode.model.forms import RepoPermsForm | |
36 | from rhodecode.model.meta import Session |
|
32 | from rhodecode.model.meta import Session | |
37 | from rhodecode.model.repo import RepoModel |
|
33 | from rhodecode.model.repo import RepoModel | |
38 | from rhodecode.model.scm import RepoGroupList, ScmModel |
|
|||
39 | from rhodecode.model.validation_schema.schemas import repo_schema |
|
|||
40 |
|
34 | |||
41 | log = logging.getLogger(__name__) |
|
35 | log = logging.getLogger(__name__) | |
42 |
|
36 | |||
@@ -63,7 +57,7 b' class RepoSettingsPermissionsView(RepoAp' | |||||
63 | return self._get_template_context(c) |
|
57 | return self._get_template_context(c) | |
64 |
|
58 | |||
65 | @LoginRequired() |
|
59 | @LoginRequired() | |
66 |
@HasRepoPermissionA |
|
60 | @HasRepoPermissionAnyDecorator('repository.admin') | |
67 | @CSRFRequired() |
|
61 | @CSRFRequired() | |
68 | @view_config( |
|
62 | @view_config( | |
69 | route_name='edit_repo_perms', request_method='POST', |
|
63 | route_name='edit_repo_perms', request_method='POST', | |
@@ -74,7 +68,7 b' class RepoSettingsPermissionsView(RepoAp' | |||||
74 | c.active = 'permissions' |
|
68 | c.active = 'permissions' | |
75 | data = self.request.POST |
|
69 | data = self.request.POST | |
76 | # store private flag outside of HTML to verify if we can modify |
|
70 | # store private flag outside of HTML to verify if we can modify | |
77 |
# default user permissions, prevents submi |
|
71 | # default user permissions, prevents submission of FAKE post data | |
78 | # into the form for private repos |
|
72 | # into the form for private repos | |
79 | data['repo_private'] = self.db_repo.private |
|
73 | data['repo_private'] = self.db_repo.private | |
80 | form = RepoPermsForm()().to_python(data) |
|
74 | form = RepoPermsForm()().to_python(data) | |
@@ -95,4 +89,4 b' class RepoSettingsPermissionsView(RepoAp' | |||||
95 | h.flash(_('Repository permissions updated'), category='success') |
|
89 | h.flash(_('Repository permissions updated'), category='success') | |
96 |
|
90 | |||
97 | raise HTTPFound( |
|
91 | raise HTTPFound( | |
98 |
|
|
92 | h.route_path('edit_repo_perms', repo_name=self.db_repo_name)) |
@@ -29,9 +29,8 b' from rhodecode.forms import RcForm' | |||||
29 | from rhodecode.lib import helpers as h |
|
29 | from rhodecode.lib import helpers as h | |
30 | from rhodecode.lib import audit_logger |
|
30 | from rhodecode.lib import audit_logger | |
31 | from rhodecode.lib.auth import ( |
|
31 | from rhodecode.lib.auth import ( | |
32 | LoginRequired, HasRepoPermissionAnyDecorator, |
|
32 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) | |
33 | HasRepoPermissionAllDecorator, CSRFRequired) |
|
33 | from rhodecode.model.db import RepositoryField, RepoGroup, Repository | |
34 | from rhodecode.model.db import RepositoryField, RepoGroup |
|
|||
35 | from rhodecode.model.meta import Session |
|
34 | from rhodecode.model.meta import Session | |
36 | from rhodecode.model.repo import RepoModel |
|
35 | from rhodecode.model.repo import RepoModel | |
37 | from rhodecode.model.scm import RepoGroupList, ScmModel |
|
36 | from rhodecode.model.scm import RepoGroupList, ScmModel | |
@@ -109,7 +108,7 b' class RepoSettingsView(RepoAppView):' | |||||
109 | return self._get_template_context(c) |
|
108 | return self._get_template_context(c) | |
110 |
|
109 | |||
111 | @LoginRequired() |
|
110 | @LoginRequired() | |
112 |
@HasRepoPermissionA |
|
111 | @HasRepoPermissionAnyDecorator('repository.admin') | |
113 | @CSRFRequired() |
|
112 | @CSRFRequired() | |
114 | @view_config( |
|
113 | @view_config( | |
115 | route_name='edit_repo', request_method='POST', |
|
114 | route_name='edit_repo', request_method='POST', | |
@@ -176,4 +175,80 b' class RepoSettingsView(RepoAppView):' | |||||
176 | old_repo_name), category='error') |
|
175 | old_repo_name), category='error') | |
177 |
|
176 | |||
178 | raise HTTPFound( |
|
177 | raise HTTPFound( | |
179 |
|
|
178 | h.route_path('edit_repo', repo_name=new_repo_name)) | |
|
179 | ||||
|
180 | @LoginRequired() | |||
|
181 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') | |||
|
182 | @view_config( | |||
|
183 | route_name='repo_edit_toggle_locking', request_method='GET', | |||
|
184 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
185 | def toggle_locking(self): | |||
|
186 | """ | |||
|
187 | Toggle locking of repository by simple GET call to url | |||
|
188 | """ | |||
|
189 | _ = self.request.translate | |||
|
190 | repo = self.db_repo | |||
|
191 | ||||
|
192 | try: | |||
|
193 | if repo.enable_locking: | |||
|
194 | if repo.locked[0]: | |||
|
195 | Repository.unlock(repo) | |||
|
196 | action = _('Unlocked') | |||
|
197 | else: | |||
|
198 | Repository.lock( | |||
|
199 | repo, self._rhodecode_user.user_id, | |||
|
200 | lock_reason=Repository.LOCK_WEB) | |||
|
201 | action = _('Locked') | |||
|
202 | ||||
|
203 | h.flash(_('Repository has been %s') % action, | |||
|
204 | category='success') | |||
|
205 | except Exception: | |||
|
206 | log.exception("Exception during unlocking") | |||
|
207 | h.flash(_('An error occurred during unlocking'), | |||
|
208 | category='error') | |||
|
209 | raise HTTPFound( | |||
|
210 | h.route_path('repo_summary', repo_name=self.db_repo_name)) | |||
|
211 | ||||
|
212 | @LoginRequired() | |||
|
213 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
214 | @view_config( | |||
|
215 | route_name='edit_repo_statistics', request_method='GET', | |||
|
216 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
217 | def edit_statistics_form(self): | |||
|
218 | c = self.load_default_context() | |||
|
219 | ||||
|
220 | if self.db_repo.stats: | |||
|
221 | # this is on what revision we ended up so we add +1 for count | |||
|
222 | last_rev = self.db_repo.stats.stat_on_revision + 1 | |||
|
223 | else: | |||
|
224 | last_rev = 0 | |||
|
225 | ||||
|
226 | c.active = 'statistics' | |||
|
227 | c.stats_revision = last_rev | |||
|
228 | c.repo_last_rev = self.rhodecode_vcs_repo.count() | |||
|
229 | ||||
|
230 | if last_rev == 0 or c.repo_last_rev == 0: | |||
|
231 | c.stats_percentage = 0 | |||
|
232 | else: | |||
|
233 | c.stats_percentage = '%.2f' % ( | |||
|
234 | (float((last_rev)) / c.repo_last_rev) * 100) | |||
|
235 | return self._get_template_context(c) | |||
|
236 | ||||
|
237 | @LoginRequired() | |||
|
238 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
239 | @CSRFRequired() | |||
|
240 | @view_config( | |||
|
241 | route_name='edit_repo_statistics_reset', request_method='POST', | |||
|
242 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
243 | def repo_statistics_reset(self): | |||
|
244 | _ = self.request.translate | |||
|
245 | ||||
|
246 | try: | |||
|
247 | RepoModel().delete_stats(self.db_repo_name) | |||
|
248 | Session().commit() | |||
|
249 | except Exception: | |||
|
250 | log.exception('Edit statistics failure') | |||
|
251 | h.flash(_('An error occurred during deletion of repository stats'), | |||
|
252 | category='error') | |||
|
253 | raise HTTPFound( | |||
|
254 | h.route_path('edit_repo_statistics', repo_name=self.db_repo_name)) |
@@ -61,7 +61,7 b' class RepoSettingsView(RepoAppView):' | |||||
61 | c.default_user_id = User.get_default_user().user_id |
|
61 | c.default_user_id = User.get_default_user().user_id | |
62 | c.in_public_journal = UserFollowing.query() \ |
|
62 | c.in_public_journal = UserFollowing.query() \ | |
63 | .filter(UserFollowing.user_id == c.default_user_id) \ |
|
63 | .filter(UserFollowing.user_id == c.default_user_id) \ | |
64 |
.filter(UserFollowing.follows_repository == |
|
64 | .filter(UserFollowing.follows_repository == self.db_repo).scalar() | |
65 |
|
65 | |||
66 | c.has_origin_repo_read_perm = False |
|
66 | c.has_origin_repo_read_perm = False | |
67 | if self.db_repo.fork: |
|
67 | if self.db_repo.fork: |
@@ -24,8 +24,8 b' from pyramid.view import view_config' | |||||
24 | from rhodecode.apps._base import RepoAppView |
|
24 | from rhodecode.apps._base import RepoAppView | |
25 | from rhodecode.lib import audit_logger |
|
25 | from rhodecode.lib import audit_logger | |
26 | from rhodecode.lib import helpers as h |
|
26 | from rhodecode.lib import helpers as h | |
27 | from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator, |
|
27 | from rhodecode.lib.auth import ( | |
28 | NotAnonymous, CSRFRequired) |
|
28 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) | |
29 | from rhodecode.lib.ext_json import json |
|
29 | from rhodecode.lib.ext_json import json | |
30 |
|
30 | |||
31 | log = logging.getLogger(__name__) |
|
31 | log = logging.getLogger(__name__) | |
@@ -44,7 +44,7 b' class StripView(RepoAppView):' | |||||
44 | @LoginRequired() |
|
44 | @LoginRequired() | |
45 | @HasRepoPermissionAnyDecorator('repository.admin') |
|
45 | @HasRepoPermissionAnyDecorator('repository.admin') | |
46 | @view_config( |
|
46 | @view_config( | |
47 | route_name='strip', request_method='GET', |
|
47 | route_name='edit_repo_strip', request_method='GET', | |
48 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') |
|
48 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |
49 | def strip(self): |
|
49 | def strip(self): | |
50 | c = self.load_default_context() |
|
50 | c = self.load_default_context() | |
@@ -99,10 +99,10 b' class StripView(RepoAppView):' | |||||
99 | continue |
|
99 | continue | |
100 | try: |
|
100 | try: | |
101 | ScmModel().strip( |
|
101 | ScmModel().strip( | |
102 |
repo= |
|
102 | repo=self.db_repo, | |
103 | commit_id=commit['rev'], branch=commit['branch']) |
|
103 | commit_id=commit['rev'], branch=commit['branch']) | |
104 | log.info('Stripped commit %s from repo `%s` by %s' % ( |
|
104 | log.info('Stripped commit %s from repo `%s` by %s' % ( | |
105 |
commit['rev'], |
|
105 | commit['rev'], self.db_repo_name, user)) | |
106 | data[commit['rev']] = True |
|
106 | data[commit['rev']] = True | |
107 |
|
107 | |||
108 | audit_logger.store_web( |
|
108 | audit_logger.store_web( |
@@ -22,12 +22,9 b' import logging' | |||||
22 | import string |
|
22 | import string | |
23 |
|
23 | |||
24 | from pyramid.view import view_config |
|
24 | from pyramid.view import view_config | |
25 |
|
||||
26 | from beaker.cache import cache_region |
|
25 | from beaker.cache import cache_region | |
27 |
|
26 | |||
28 |
|
||||
29 | from rhodecode.controllers import utils |
|
27 | from rhodecode.controllers import utils | |
30 |
|
||||
31 | from rhodecode.apps._base import RepoAppView |
|
28 | from rhodecode.apps._base import RepoAppView | |
32 | from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP) |
|
29 | from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP) | |
33 | from rhodecode.lib import caches, helpers as h |
|
30 | from rhodecode.lib import caches, helpers as h | |
@@ -74,11 +71,16 b' class RepoSummaryView(RepoAppView):' | |||||
74 | log.debug("Searching for a README file.") |
|
71 | log.debug("Searching for a README file.") | |
75 | readme_node = ReadmeFinder(default_renderer).search(commit) |
|
72 | readme_node = ReadmeFinder(default_renderer).search(commit) | |
76 | if readme_node: |
|
73 | if readme_node: | |
77 |
relative_url = |
|
74 | relative_urls = { | |
|
75 | 'raw': h.route_path( | |||
78 | 'repo_file_raw', repo_name=repo_name, |
|
76 | 'repo_file_raw', repo_name=repo_name, | |
79 | commit_id=commit.raw_id, f_path=readme_node.path) |
|
77 | commit_id=commit.raw_id, f_path=readme_node.path), | |
|
78 | 'standard': h.route_path( | |||
|
79 | 'repo_files', repo_name=repo_name, | |||
|
80 | commit_id=commit.raw_id, f_path=readme_node.path), | |||
|
81 | } | |||
80 | readme_data = self._render_readme_or_none( |
|
82 | readme_data = self._render_readme_or_none( | |
81 | commit, readme_node, relative_url) |
|
83 | commit, readme_node, relative_urls) | |
82 | readme_filename = readme_node.path |
|
84 | readme_filename = readme_node.path | |
83 | return readme_data, readme_filename |
|
85 | return readme_data, readme_filename | |
84 |
|
86 | |||
@@ -103,15 +105,15 b' class RepoSummaryView(RepoAppView):' | |||||
103 | log.exception( |
|
105 | log.exception( | |
104 | "Problem getting commit when trying to render the README.") |
|
106 | "Problem getting commit when trying to render the README.") | |
105 |
|
107 | |||
106 | def _render_readme_or_none(self, commit, readme_node, relative_url): |
|
108 | def _render_readme_or_none(self, commit, readme_node, relative_urls): | |
107 | log.debug( |
|
109 | log.debug( | |
108 | 'Found README file `%s` rendering...', readme_node.path) |
|
110 | 'Found README file `%s` rendering...', readme_node.path) | |
109 | renderer = MarkupRenderer() |
|
111 | renderer = MarkupRenderer() | |
110 | try: |
|
112 | try: | |
111 | html_source = renderer.render( |
|
113 | html_source = renderer.render( | |
112 | readme_node.content, filename=readme_node.path) |
|
114 | readme_node.content, filename=readme_node.path) | |
113 | if relative_url: |
|
115 | if relative_urls: | |
114 | return relative_links(html_source, relative_url) |
|
116 | return relative_links(html_source, relative_urls) | |
115 | return html_source |
|
117 | return html_source | |
116 | except Exception: |
|
118 | except Exception: | |
117 | log.exception( |
|
119 | log.exception( |
@@ -143,6 +143,8 b' def load_pyramid_environment(global_conf' | |||||
143 |
|
143 | |||
144 | # Store the settings to make them available to other modules. |
|
144 | # Store the settings to make them available to other modules. | |
145 | rhodecode.PYRAMID_SETTINGS = settings_merged |
|
145 | rhodecode.PYRAMID_SETTINGS = settings_merged | |
|
146 | # NOTE(marcink): needs to be enabled after full port to pyramid | |||
|
147 | # rhodecode.CONFIG = config | |||
146 |
|
148 | |||
147 | # If this is a test run we prepare the test environment like |
|
149 | # If this is a test run we prepare the test environment like | |
148 | # creating a test database, test search index and test repositories. |
|
150 | # creating a test database, test search index and test repositories. |
@@ -176,23 +176,6 b' def make_map(config):' | |||||
176 | rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping') |
|
176 | rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping') | |
177 | rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test') |
|
177 | rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test') | |
178 |
|
178 | |||
179 | # ADMIN REPOSITORY ROUTES |
|
|||
180 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
|||
181 | controller='admin/repos') as m: |
|
|||
182 | m.connect('repos', '/repos', |
|
|||
183 | action='create', conditions={'method': ['POST']}) |
|
|||
184 | m.connect('repos', '/repos', |
|
|||
185 | action='index', conditions={'method': ['GET']}) |
|
|||
186 | m.connect('new_repo', '/create_repository', jsroute=True, |
|
|||
187 | action='create_repository', conditions={'method': ['GET']}) |
|
|||
188 | m.connect('delete_repo', '/repos/{repo_name}', |
|
|||
189 | action='delete', conditions={'method': ['DELETE']}, |
|
|||
190 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
191 | m.connect('repo', '/repos/{repo_name}', |
|
|||
192 | action='show', conditions={'method': ['GET'], |
|
|||
193 | 'function': check_repo}, |
|
|||
194 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
195 |
|
||||
196 | # ADMIN REPOSITORY GROUPS ROUTES |
|
179 | # ADMIN REPOSITORY GROUPS ROUTES | |
197 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
180 | with rmap.submapper(path_prefix=ADMIN_PREFIX, | |
198 | controller='admin/repo_groups') as m: |
|
181 | controller='admin/repo_groups') as m: | |
@@ -406,81 +389,5 b' def make_map(config):' | |||||
406 | m.connect('my_account_password', '/my_account/password', |
|
389 | m.connect('my_account_password', '/my_account/password', | |
407 | action='my_account_password', conditions={'method': ['GET']}) |
|
390 | action='my_account_password', conditions={'method': ['GET']}) | |
408 |
|
391 | |||
409 | #========================================================================== |
|
|||
410 | # REPOSITORY ROUTES |
|
|||
411 | #========================================================================== |
|
|||
412 |
|
||||
413 | # repo edit options |
|
|||
414 | rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields', |
|
|||
415 | controller='admin/repos', action='edit_fields', |
|
|||
416 | conditions={'method': ['GET'], 'function': check_repo}, |
|
|||
417 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
418 | rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new', |
|
|||
419 | controller='admin/repos', action='create_repo_field', |
|
|||
420 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
|||
421 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
422 | rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}', |
|
|||
423 | controller='admin/repos', action='delete_repo_field', |
|
|||
424 | conditions={'method': ['DELETE'], 'function': check_repo}, |
|
|||
425 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
426 |
|
||||
427 | rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle', |
|
|||
428 | controller='admin/repos', action='toggle_locking', |
|
|||
429 | conditions={'method': ['GET'], 'function': check_repo}, |
|
|||
430 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
431 |
|
||||
432 | rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', |
|
|||
433 | controller='admin/repos', action='edit_remote_form', |
|
|||
434 | conditions={'method': ['GET'], 'function': check_repo}, |
|
|||
435 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
436 | rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', |
|
|||
437 | controller='admin/repos', action='edit_remote', |
|
|||
438 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
|||
439 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
440 |
|
||||
441 | rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics', |
|
|||
442 | controller='admin/repos', action='edit_statistics_form', |
|
|||
443 | conditions={'method': ['GET'], 'function': check_repo}, |
|
|||
444 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
445 | rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics', |
|
|||
446 | controller='admin/repos', action='edit_statistics', |
|
|||
447 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
|||
448 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
449 | rmap.connect('repo_settings_issuetracker', |
|
|||
450 | '/{repo_name}/settings/issue-tracker', |
|
|||
451 | controller='admin/repos', action='repo_issuetracker', |
|
|||
452 | conditions={'method': ['GET'], 'function': check_repo}, |
|
|||
453 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
454 | rmap.connect('repo_issuetracker_test', |
|
|||
455 | '/{repo_name}/settings/issue-tracker/test', |
|
|||
456 | controller='admin/repos', action='repo_issuetracker_test', |
|
|||
457 | conditions={'method': ['POST'], 'function': check_repo}, |
|
|||
458 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
459 | rmap.connect('repo_issuetracker_delete', |
|
|||
460 | '/{repo_name}/settings/issue-tracker/delete', |
|
|||
461 | controller='admin/repos', action='repo_issuetracker_delete', |
|
|||
462 | conditions={'method': ['DELETE'], 'function': check_repo}, |
|
|||
463 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
464 | rmap.connect('repo_issuetracker_save', |
|
|||
465 | '/{repo_name}/settings/issue-tracker/save', |
|
|||
466 | controller='admin/repos', action='repo_issuetracker_save', |
|
|||
467 | conditions={'method': ['POST'], 'function': check_repo}, |
|
|||
468 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
469 | rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', |
|
|||
470 | controller='admin/repos', action='repo_settings_vcs_update', |
|
|||
471 | conditions={'method': ['POST'], 'function': check_repo}, |
|
|||
472 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
473 | rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', |
|
|||
474 | controller='admin/repos', action='repo_settings_vcs', |
|
|||
475 | conditions={'method': ['GET'], 'function': check_repo}, |
|
|||
476 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
477 | rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', |
|
|||
478 | controller='admin/repos', action='repo_delete_svn_pattern', |
|
|||
479 | conditions={'method': ['DELETE'], 'function': check_repo}, |
|
|||
480 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
481 | rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest', |
|
|||
482 | controller='admin/repos', action='repo_settings_pullrequest', |
|
|||
483 | conditions={'method': ['GET', 'POST'], 'function': check_repo}, |
|
|||
484 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
485 |
|
392 | |||
486 | return rmap |
|
393 | return rmap |
@@ -32,6 +32,7 b' from formencode import htmlfill' | |||||
32 | from pylons import request, tmpl_context as c, url, config |
|
32 | from pylons import request, tmpl_context as c, url, config | |
33 | from pylons.controllers.util import redirect |
|
33 | from pylons.controllers.util import redirect | |
34 | from pylons.i18n.translation import _ |
|
34 | from pylons.i18n.translation import _ | |
|
35 | from pylons.decorators import jsonify | |||
35 | from pyramid.threadlocal import get_current_registry |
|
36 | from pyramid.threadlocal import get_current_registry | |
36 | from webob.exc import HTTPBadRequest |
|
37 | from webob.exc import HTTPBadRequest | |
37 |
|
38 | |||
@@ -47,7 +48,6 b' from rhodecode.lib.utils import repo2db_' | |||||
47 | from rhodecode.lib.utils2 import ( |
|
48 | from rhodecode.lib.utils2 import ( | |
48 | str2bool, safe_unicode, AttributeDict, safe_int) |
|
49 | str2bool, safe_unicode, AttributeDict, safe_int) | |
49 | from rhodecode.lib.compat import OrderedDict |
|
50 | from rhodecode.lib.compat import OrderedDict | |
50 | from rhodecode.lib.utils import jsonify |
|
|||
51 |
|
51 | |||
52 | from rhodecode.model.db import RhodeCodeUi, Repository |
|
52 | from rhodecode.model.db import RhodeCodeUi, Repository | |
53 | from rhodecode.model.forms import ApplicationSettingsForm, \ |
|
53 | from rhodecode.model.forms import ApplicationSettingsForm, \ |
@@ -31,25 +31,19 b' from pylons import request, tmpl_context' | |||||
31 | from pylons.controllers.util import redirect |
|
31 | from pylons.controllers.util import redirect | |
32 | from pylons.i18n.translation import _ |
|
32 | from pylons.i18n.translation import _ | |
33 |
|
33 | |||
34 | from sqlalchemy.orm import joinedload |
|
|||
35 |
|
||||
36 | from rhodecode.lib import auth |
|
34 | from rhodecode.lib import auth | |
37 | from rhodecode.lib import helpers as h |
|
35 | from rhodecode.lib import helpers as h | |
38 | from rhodecode.lib import audit_logger |
|
36 | from rhodecode.lib import audit_logger | |
39 | from rhodecode.lib.ext_json import json |
|
|||
40 | from rhodecode.lib.exceptions import UserGroupAssignedException,\ |
|
37 | from rhodecode.lib.exceptions import UserGroupAssignedException,\ | |
41 | RepoGroupAssignmentError |
|
38 | RepoGroupAssignmentError | |
42 | from rhodecode.lib.utils import jsonify |
|
|||
43 | from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int |
|
39 | from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int | |
44 | from rhodecode.lib.auth import ( |
|
40 | from rhodecode.lib.auth import ( | |
45 | LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator, |
|
41 | LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator, | |
46 | HasPermissionAnyDecorator) |
|
42 | HasPermissionAnyDecorator) | |
47 | from rhodecode.lib.base import BaseController, render |
|
43 | from rhodecode.lib.base import BaseController, render | |
48 | from rhodecode.model.permission import PermissionModel |
|
44 | from rhodecode.model.permission import PermissionModel | |
49 | from rhodecode.model.scm import UserGroupList |
|
|||
50 | from rhodecode.model.user_group import UserGroupModel |
|
45 | from rhodecode.model.user_group import UserGroupModel | |
51 |
from rhodecode.model.db import |
|
46 | from rhodecode.model.db import User, UserGroup | |
52 | User, UserGroup, UserGroupRepoToPerm, UserGroupRepoGroupToPerm) |
|
|||
53 | from rhodecode.model.forms import ( |
|
47 | from rhodecode.model.forms import ( | |
54 | UserGroupForm, UserGroupPermsForm, UserIndividualPermissionsForm, |
|
48 | UserGroupForm, UserGroupPermsForm, UserIndividualPermissionsForm, | |
55 | UserPermissionsForm) |
|
49 | UserPermissionsForm) |
@@ -34,15 +34,6 b' import pyramid.threadlocal' | |||||
34 | from paste.auth.basic import AuthBasicAuthenticator |
|
34 | from paste.auth.basic import AuthBasicAuthenticator | |
35 | from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception |
|
35 | from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception | |
36 | from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION |
|
36 | from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION | |
37 | from pylons import tmpl_context as c, request, url |
|
|||
38 | from pylons.controllers import WSGIController |
|
|||
39 | from pylons.controllers.util import redirect |
|
|||
40 | from pylons.i18n import translation |
|
|||
41 | # marcink: don't remove this import |
|
|||
42 | from pylons.templating import render_mako, pylons_globals, literal, cached_template |
|
|||
43 | from pylons.i18n.translation import _ |
|
|||
44 | from webob.exc import HTTPFound |
|
|||
45 |
|
||||
46 |
|
37 | |||
47 | import rhodecode |
|
38 | import rhodecode | |
48 | from rhodecode.authentication.base import VCS_TYPE |
|
39 | from rhodecode.authentication.base import VCS_TYPE | |
@@ -55,13 +46,15 b' from rhodecode.lib.utils import (' | |||||
55 | get_enabled_hook_classes) |
|
46 | get_enabled_hook_classes) | |
56 | from rhodecode.lib.utils2 import ( |
|
47 | from rhodecode.lib.utils2 import ( | |
57 | str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist) |
|
48 | str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist) | |
58 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
|||
59 | from rhodecode.model import meta |
|
49 | from rhodecode.model import meta | |
60 | from rhodecode.model.db import Repository, User, ChangesetComment |
|
50 | from rhodecode.model.db import Repository, User, ChangesetComment | |
61 | from rhodecode.model.notification import NotificationModel |
|
51 | from rhodecode.model.notification import NotificationModel | |
62 | from rhodecode.model.scm import ScmModel |
|
52 | from rhodecode.model.scm import ScmModel | |
63 | from rhodecode.model.settings import VcsSettingsModel, SettingsModel |
|
53 | from rhodecode.model.settings import VcsSettingsModel, SettingsModel | |
64 |
|
54 | |||
|
55 | # NOTE(marcink): remove after base controller is no longer required | |||
|
56 | from pylons.controllers import WSGIController | |||
|
57 | from pylons.i18n import translation | |||
65 |
|
58 | |||
66 | log = logging.getLogger(__name__) |
|
59 | log = logging.getLogger(__name__) | |
67 |
|
60 | |||
@@ -75,6 +68,9 b' def render(template_name, extra_vars=Non' | |||||
75 | ``cache_expire``. |
|
68 | ``cache_expire``. | |
76 |
|
69 | |||
77 | """ |
|
70 | """ | |
|
71 | from pylons.templating import literal | |||
|
72 | from pylons.templating import cached_template, pylons_globals | |||
|
73 | ||||
78 | # Create a render callable for the cache function |
|
74 | # Create a render callable for the cache function | |
79 | def render_template(): |
|
75 | def render_template(): | |
80 | # Pull in extra vars if needed |
|
76 | # Pull in extra vars if needed | |
@@ -411,10 +407,6 b' def attach_context_attributes(context, r' | |||||
411 | 'refresh_time': 120 * 1000, |
|
407 | 'refresh_time': 120 * 1000, | |
412 | 'cutoff_limit': 1000 * 60 * 60 * 24 * 7 |
|
408 | 'cutoff_limit': 1000 * 60 * 60 * 24 * 7 | |
413 | }, |
|
409 | }, | |
414 | 'pylons_dispatch': { |
|
|||
415 | # 'controller': request.environ['pylons.routes_dict']['controller'], |
|
|||
416 | # 'action': request.environ['pylons.routes_dict']['action'], |
|
|||
417 | }, |
|
|||
418 | 'pyramid_dispatch': { |
|
410 | 'pyramid_dispatch': { | |
419 |
|
411 | |||
420 | }, |
|
412 | }, | |
@@ -512,6 +504,7 b' class BaseController(WSGIController):' | |||||
512 | """ |
|
504 | """ | |
513 | # on each call propagate settings calls into global settings. |
|
505 | # on each call propagate settings calls into global settings. | |
514 | from pylons import config |
|
506 | from pylons import config | |
|
507 | from pylons import tmpl_context as c, request, url | |||
515 | set_rhodecode_config(config) |
|
508 | set_rhodecode_config(config) | |
516 | attach_context_attributes(c, request, self._rhodecode_user.user_id) |
|
509 | attach_context_attributes(c, request, self._rhodecode_user.user_id) | |
517 |
|
510 | |||
@@ -531,6 +524,7 b' class BaseController(WSGIController):' | |||||
531 | user_lang, self._rhodecode_user) |
|
524 | user_lang, self._rhodecode_user) | |
532 |
|
525 | |||
533 | def _dispatch_redirect(self, with_url, environ, start_response): |
|
526 | def _dispatch_redirect(self, with_url, environ, start_response): | |
|
527 | from webob.exc import HTTPFound | |||
534 | resp = HTTPFound(with_url) |
|
528 | resp = HTTPFound(with_url) | |
535 | environ['SCRIPT_NAME'] = '' # handle prefix middleware |
|
529 | environ['SCRIPT_NAME'] = '' # handle prefix middleware | |
536 | environ['PATH_INFO'] = with_url |
|
530 | environ['PATH_INFO'] = with_url | |
@@ -542,6 +536,7 b' class BaseController(WSGIController):' | |||||
542 | # the request is routed to. This routing information is |
|
536 | # the request is routed to. This routing information is | |
543 | # available in environ['pylons.routes_dict'] |
|
537 | # available in environ['pylons.routes_dict'] | |
544 | from rhodecode.lib import helpers as h |
|
538 | from rhodecode.lib import helpers as h | |
|
539 | from pylons import tmpl_context as c, request, url | |||
545 |
|
540 | |||
546 | # Provide the Pylons context to Pyramid's debugtoolbar if it asks |
|
541 | # Provide the Pylons context to Pyramid's debugtoolbar if it asks | |
547 | if environ.get('debugtoolbar.wants_pylons_context', False): |
|
542 | if environ.get('debugtoolbar.wants_pylons_context', False): | |
@@ -620,93 +615,3 b' def bootstrap_request(**kwargs):' | |||||
620 |
|
615 | |||
621 | config = pyramid.testing.setUp(request=request) |
|
616 | config = pyramid.testing.setUp(request=request) | |
622 | add_events_routes(config) |
|
617 | add_events_routes(config) | |
623 |
|
||||
624 |
|
||||
625 | class BaseRepoController(BaseController): |
|
|||
626 | """ |
|
|||
627 | Base class for controllers responsible for loading all needed data for |
|
|||
628 | repository loaded items are |
|
|||
629 |
|
||||
630 | c.rhodecode_repo: instance of scm repository |
|
|||
631 | c.rhodecode_db_repo: instance of db |
|
|||
632 | c.repository_requirements_missing: shows that repository specific data |
|
|||
633 | could not be displayed due to the missing requirements |
|
|||
634 | c.repository_pull_requests: show number of open pull requests |
|
|||
635 | """ |
|
|||
636 |
|
||||
637 | def __before__(self): |
|
|||
638 | super(BaseRepoController, self).__before__() |
|
|||
639 | if c.repo_name: # extracted from routes |
|
|||
640 | db_repo = Repository.get_by_repo_name(c.repo_name) |
|
|||
641 | if not db_repo: |
|
|||
642 | return |
|
|||
643 |
|
||||
644 | log.debug( |
|
|||
645 | 'Found repository in database %s with state `%s`', |
|
|||
646 | safe_unicode(db_repo), safe_unicode(db_repo.repo_state)) |
|
|||
647 | route = getattr(request.environ.get('routes.route'), 'name', '') |
|
|||
648 |
|
||||
649 | # allow to delete repos that are somehow damages in filesystem |
|
|||
650 | if route in ['delete_repo']: |
|
|||
651 | return |
|
|||
652 |
|
||||
653 | if db_repo.repo_state in [Repository.STATE_PENDING]: |
|
|||
654 | if route in ['repo_creating_home']: |
|
|||
655 | return |
|
|||
656 | check_url = url('repo_creating_home', repo_name=c.repo_name) |
|
|||
657 | return redirect(check_url) |
|
|||
658 |
|
||||
659 | self.rhodecode_db_repo = db_repo |
|
|||
660 |
|
||||
661 | missing_requirements = False |
|
|||
662 | try: |
|
|||
663 | self.rhodecode_repo = self.rhodecode_db_repo.scm_instance() |
|
|||
664 | except RepositoryRequirementError as e: |
|
|||
665 | missing_requirements = True |
|
|||
666 | self._handle_missing_requirements(e) |
|
|||
667 |
|
||||
668 | if self.rhodecode_repo is None and not missing_requirements: |
|
|||
669 | log.error('%s this repository is present in database but it ' |
|
|||
670 | 'cannot be created as an scm instance', c.repo_name) |
|
|||
671 |
|
||||
672 | h.flash(_( |
|
|||
673 | "The repository at %(repo_name)s cannot be located.") % |
|
|||
674 | {'repo_name': c.repo_name}, |
|
|||
675 | category='error', ignore_duplicate=True) |
|
|||
676 | redirect(h.route_path('home')) |
|
|||
677 |
|
||||
678 | # update last change according to VCS data |
|
|||
679 | if not missing_requirements: |
|
|||
680 | commit = db_repo.get_commit( |
|
|||
681 | pre_load=["author", "date", "message", "parents"]) |
|
|||
682 | db_repo.update_commit_cache(commit) |
|
|||
683 |
|
||||
684 | # Prepare context |
|
|||
685 | c.rhodecode_db_repo = db_repo |
|
|||
686 | c.rhodecode_repo = self.rhodecode_repo |
|
|||
687 | c.repository_requirements_missing = missing_requirements |
|
|||
688 |
|
||||
689 | self._update_global_counters(self.scm_model, db_repo) |
|
|||
690 |
|
||||
691 | def _update_global_counters(self, scm_model, db_repo): |
|
|||
692 | """ |
|
|||
693 | Base variables that are exposed to every page of repository |
|
|||
694 | """ |
|
|||
695 | c.repository_pull_requests = scm_model.get_pull_requests(db_repo) |
|
|||
696 |
|
||||
697 | def _handle_missing_requirements(self, error): |
|
|||
698 | self.rhodecode_repo = None |
|
|||
699 | log.error( |
|
|||
700 | 'Requirements are missing for repository %s: %s', |
|
|||
701 | c.repo_name, error.message) |
|
|||
702 |
|
||||
703 | summary_url = h.route_path('repo_summary', repo_name=c.repo_name) |
|
|||
704 | statistics_url = url('edit_repo_statistics', repo_name=c.repo_name) |
|
|||
705 | settings_update_url = url('repo', repo_name=c.repo_name) |
|
|||
706 | path = request.path |
|
|||
707 | should_redirect = ( |
|
|||
708 | path not in (summary_url, settings_update_url) |
|
|||
709 | and '/settings' not in path or path == statistics_url |
|
|||
710 | ) |
|
|||
711 | if should_redirect: |
|
|||
712 | redirect(summary_url) |
|
@@ -852,30 +852,6 b' class BasePasterCommand(Command):' | |||||
852 | initialize_database(config) |
|
852 | initialize_database(config) | |
853 |
|
853 | |||
854 |
|
854 | |||
855 | @decorator.decorator |
|
|||
856 | def jsonify(func, *args, **kwargs): |
|
|||
857 | """Action decorator that formats output for JSON |
|
|||
858 |
|
||||
859 | Given a function that will return content, this decorator will turn |
|
|||
860 | the result into JSON, with a content-type of 'application/json' and |
|
|||
861 | output it. |
|
|||
862 |
|
||||
863 | """ |
|
|||
864 | from pylons.decorators.util import get_pylons |
|
|||
865 | from rhodecode.lib.ext_json import json |
|
|||
866 | pylons = get_pylons(args) |
|
|||
867 | pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8' |
|
|||
868 | data = func(*args, **kwargs) |
|
|||
869 | if isinstance(data, (list, tuple)): |
|
|||
870 | msg = "JSON responses with Array envelopes are susceptible to " \ |
|
|||
871 | "cross-site data leak attacks, see " \ |
|
|||
872 | "http://wiki.pylonshq.com/display/pylonsfaq/Warnings" |
|
|||
873 | warnings.warn(msg, Warning, 2) |
|
|||
874 | log.warning(msg) |
|
|||
875 | log.debug("Returning JSON wrapped action output") |
|
|||
876 | return json.dumps(data, encoding='utf-8') |
|
|||
877 |
|
||||
878 |
|
||||
879 | class PartialRenderer(object): |
|
855 | class PartialRenderer(object): | |
880 | """ |
|
856 | """ | |
881 | Partial renderer used to render chunks of html used in datagrids |
|
857 | Partial renderer used to render chunks of html used in datagrids |
@@ -18,10 +18,6 b'' | |||||
18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | """ |
|
|||
22 | Repository model for rhodecode |
|
|||
23 | """ |
|
|||
24 |
|
||||
25 | import logging |
|
21 | import logging | |
26 | import os |
|
22 | import os | |
27 | import re |
|
23 | import re |
@@ -55,7 +55,7 b' function setRCMouseBindings(repoName, re' | |||||
55 | window.location = pyroutes.url('gists_new'); |
|
55 | window.location = pyroutes.url('gists_new'); | |
56 | }); |
|
56 | }); | |
57 | Mousetrap.bind(['n r'], function(e) { |
|
57 | Mousetrap.bind(['n r'], function(e) { | |
58 |
window.location = pyroutes.url(' |
|
58 | window.location = pyroutes.url('repo_new'); | |
59 | }); |
|
59 | }); | |
60 |
|
60 | |||
61 | if (repoName && repoName != '') { |
|
61 | if (repoName && repoName != '') { |
@@ -12,7 +12,6 b'' | |||||
12 | ******************************************************************************/ |
|
12 | ******************************************************************************/ | |
13 | function registerRCRoutes() { |
|
13 | function registerRCRoutes() { | |
14 | // routes registration |
|
14 | // routes registration | |
15 | pyroutes.register('new_repo', '/_admin/create_repository', []); |
|
|||
16 | pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']); |
|
15 | pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']); | |
17 | pyroutes.register('favicon', '/favicon.ico', []); |
|
16 | pyroutes.register('favicon', '/favicon.ico', []); | |
18 | pyroutes.register('robots', '/robots.txt', []); |
|
17 | pyroutes.register('robots', '/robots.txt', []); | |
@@ -82,6 +81,9 b' function registerRCRoutes() {' | |||||
82 | pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']); |
|
81 | pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']); | |
83 | pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']); |
|
82 | pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']); | |
84 | pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']); |
|
83 | pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']); | |
|
84 | pyroutes.register('repos', '/_admin/repos', []); | |||
|
85 | pyroutes.register('repo_new', '/_admin/repos/new', []); | |||
|
86 | pyroutes.register('repo_create', '/_admin/repos/create', []); | |||
85 | pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []); |
|
87 | pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []); | |
86 | pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []); |
|
88 | pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []); | |
87 | pyroutes.register('channelstream_proxy', '/_channelstream', []); |
|
89 | pyroutes.register('channelstream_proxy', '/_channelstream', []); | |
@@ -177,11 +179,26 b' function registerRCRoutes() {' | |||||
177 | pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']); |
|
179 | pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']); | |
178 | pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); |
|
180 | pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); | |
179 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); |
|
181 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); | |
|
182 | pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']); | |||
|
183 | pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']); | |||
|
184 | pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']); | |||
|
185 | pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']); | |||
|
186 | pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']); | |||
|
187 | pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']); | |||
|
188 | pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']); | |||
|
189 | pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']); | |||
|
190 | pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']); | |||
|
191 | pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']); | |||
|
192 | pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']); | |||
|
193 | pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']); | |||
|
194 | pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']); | |||
|
195 | pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']); | |||
|
196 | pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']); | |||
|
197 | pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']); | |||
|
198 | pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']); | |||
180 | pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']); |
|
199 | pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']); | |
181 | pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']); |
|
200 | pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']); | |
182 |
pyroutes.register(' |
|
201 | pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']); | |
183 | pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']); |
|
|||
184 | pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']); |
|
|||
185 | pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']); |
|
202 | pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']); | |
186 | pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']); |
|
203 | pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']); | |
187 | pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']); |
|
204 | pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']); |
@@ -12,7 +12,7 b'' | |||||
12 | %if c.rhodecode_user.is_admin: |
|
12 | %if c.rhodecode_user.is_admin: | |
13 | ${h.link_to(_('Admin'),h.route_path('admin_home'))} |
|
13 | ${h.link_to(_('Admin'), h.route_path('admin_home'))} | |
14 | » |
|
14 | » | |
15 |
${h.link_to(_('Repositories'),h. |
|
15 | ${h.link_to(_('Repositories'), h.route_path('repos'))} | |
16 | %else: |
|
16 | %else: | |
17 | ${_('Admin')} |
|
17 | ${_('Admin')} | |
18 | » |
|
18 | » |
@@ -1,6 +1,6 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
2 |
|
2 | |||
3 | ${h.secure_form(h.url('repos'))} |
|
3 | ${h.secure_form(h.route_path('repo_create'), method='POST', request=request)} | |
4 | <div class="form"> |
|
4 | <div class="form"> | |
5 | <!-- fields --> |
|
5 | <!-- fields --> | |
6 | <div class="fields"> |
|
6 | <div class="fields"> |
@@ -52,24 +52,24 b'' | |||||
52 | <a href="${h.route_path('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a> |
|
52 | <a href="${h.route_path('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a> | |
53 | </li> |
|
53 | </li> | |
54 | <li class="${'active' if c.active=='vcs' else ''}"> |
|
54 | <li class="${'active' if c.active=='vcs' else ''}"> | |
55 |
<a href="${h. |
|
55 | <a href="${h.route_path('edit_repo_vcs', repo_name=c.repo_name)}">${_('VCS')}</a> | |
56 | </li> |
|
56 | </li> | |
57 | <li class="${'active' if c.active=='fields' else ''}"> |
|
57 | <li class="${'active' if c.active=='fields' else ''}"> | |
58 |
<a href="${h. |
|
58 | <a href="${h.route_path('edit_repo_fields', repo_name=c.repo_name)}">${_('Extra Fields')}</a> | |
59 | </li> |
|
59 | </li> | |
60 | <li class="${'active' if c.active=='issuetracker' else ''}"> |
|
60 | <li class="${'active' if c.active=='issuetracker' else ''}"> | |
61 |
<a href="${h. |
|
61 | <a href="${h.route_path('edit_repo_issuetracker', repo_name=c.repo_name)}">${_('Issue Tracker')}</a> | |
62 | </li> |
|
62 | </li> | |
63 | <li class="${'active' if c.active=='caches' else ''}"> |
|
63 | <li class="${'active' if c.active=='caches' else ''}"> | |
64 | <a href="${h.route_path('edit_repo_caches', repo_name=c.repo_name)}">${_('Caches')}</a> |
|
64 | <a href="${h.route_path('edit_repo_caches', repo_name=c.repo_name)}">${_('Caches')}</a> | |
65 | </li> |
|
65 | </li> | |
66 | %if c.repo_info.repo_type != 'svn': |
|
66 | %if c.repo_info.repo_type != 'svn': | |
67 | <li class="${'active' if c.active=='remote' else ''}"> |
|
67 | <li class="${'active' if c.active=='remote' else ''}"> | |
68 |
<a href="${h. |
|
68 | <a href="${h.route_path('edit_repo_remote', repo_name=c.repo_name)}">${_('Remote')}</a> | |
69 | </li> |
|
69 | </li> | |
70 | %endif |
|
70 | %endif | |
71 | <li class="${'active' if c.active=='statistics' else ''}"> |
|
71 | <li class="${'active' if c.active=='statistics' else ''}"> | |
72 |
<a href="${h. |
|
72 | <a href="${h.route_path('edit_repo_statistics', repo_name=c.repo_name)}">${_('Statistics')}</a> | |
73 | </li> |
|
73 | </li> | |
74 | <li class="${'active' if c.active=='integrations' else ''}"> |
|
74 | <li class="${'active' if c.active=='integrations' else ''}"> | |
75 | <a href="${h.route_path('repo_integrations_home', repo_name=c.repo_name)}">${_('Integrations')}</a> |
|
75 | <a href="${h.route_path('repo_integrations_home', repo_name=c.repo_name)}">${_('Integrations')}</a> | |
@@ -80,10 +80,10 b'' | |||||
80 | </li> |
|
80 | </li> | |
81 | %endif |
|
81 | %endif | |
82 | <li class="${'active' if c.active=='maintenance' else ''}"> |
|
82 | <li class="${'active' if c.active=='maintenance' else ''}"> | |
83 | <a href="${h.route_path('repo_maintenance', repo_name=c.repo_name)}">${_('Maintenance')}</a> |
|
83 | <a href="${h.route_path('edit_repo_maintenance', repo_name=c.repo_name)}">${_('Maintenance')}</a> | |
84 | </li> |
|
84 | </li> | |
85 | <li class="${'active' if c.active=='strip' else ''}"> |
|
85 | <li class="${'active' if c.active=='strip' else ''}"> | |
86 | <a href="${h.route_path('strip', repo_name=c.repo_name)}">${_('Strip')}</a> |
|
86 | <a href="${h.route_path('edit_repo_strip', repo_name=c.repo_name)}">${_('Strip')}</a> | |
87 | </li> |
|
87 | </li> | |
88 |
|
88 | |||
89 | </ul> |
|
89 | </ul> |
@@ -18,7 +18,7 b'' | |||||
18 | <td class="td-hash">${field.field_key}</td> |
|
18 | <td class="td-hash">${field.field_key}</td> | |
19 | <td class="td-type">${field.field_type}</td> |
|
19 | <td class="td-type">${field.field_type}</td> | |
20 | <td class="td-action"> |
|
20 | <td class="td-action"> | |
21 |
${h.secure_form(h. |
|
21 | ${h.secure_form(h.route_path('edit_repo_fields_delete', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id), method='POST', request=request)} | |
22 | ${h.hidden('del_repo_field',field.repo_field_id)} |
|
22 | ${h.hidden('del_repo_field',field.repo_field_id)} | |
23 | <button class="btn btn-link btn-danger" type="submit" |
|
23 | <button class="btn btn-link btn-danger" type="submit" | |
24 | onclick="return confirm('${_('Confirm to delete this field: %s') % field.field_key}');"> |
|
24 | onclick="return confirm('${_('Confirm to delete this field: %s') % field.field_key}');"> | |
@@ -31,7 +31,7 b'' | |||||
31 | </table> |
|
31 | </table> | |
32 | </div> |
|
32 | </div> | |
33 | %endif |
|
33 | %endif | |
34 |
${h.secure_form(h. |
|
34 | ${h.secure_form(h.route_path('edit_repo_fields_create', repo_name=c.repo_name), method='POST', request=request)} | |
35 | <div class="form"> |
|
35 | <div class="form"> | |
36 | <!-- fields --> |
|
36 | <!-- fields --> | |
37 | <div class="fields"> |
|
37 | <div class="fields"> |
@@ -1,7 +1,7 b'' | |||||
1 | <%namespace name="its" file="/base/issue_tracker_settings.mako"/> |
|
1 | <%namespace name="its" file="/base/issue_tracker_settings.mako"/> | |
2 |
|
2 | |||
3 | <div id="repo_issue_tracker" class="${'inherited' if c.settings_model.inherit_global_settings else ''}"> |
|
3 | <div id="repo_issue_tracker" class="${'inherited' if c.settings_model.inherit_global_settings else ''}"> | |
4 |
${h.secure_form(h. |
|
4 | ${h.secure_form(h.route_path('edit_repo_issuetracker_update', repo_name=c.repo_name), id="inherit-form", method='POST', request=request)} | |
5 | <div class="panel panel-default panel-body"> |
|
5 | <div class="panel panel-default panel-body"> | |
6 | <div class="fields"> |
|
6 | <div class="fields"> | |
7 | <div class="field"> |
|
7 | <div class="field"> | |
@@ -72,8 +72,8 b'' | |||||
72 | <div class="panel-body"> |
|
72 | <div class="panel-body"> | |
73 | ${its.issue_tracker_settings_table( |
|
73 | ${its.issue_tracker_settings_table( | |
74 | patterns=c.repo_patterns.items(), |
|
74 | patterns=c.repo_patterns.items(), | |
75 |
form_url=h. |
|
75 | form_url=h.route_path('edit_repo_issuetracker', repo_name=c.repo_info.repo_name), | |
76 |
delete_url=h. |
|
76 | delete_url=h.route_path('edit_repo_issuetracker_delete', repo_name=c.repo_info.repo_name) | |
77 | )} |
|
77 | )} | |
78 | <div class="buttons"> |
|
78 | <div class="buttons"> | |
79 | <button type="submit" class="btn btn-primary save-inheritance" id="save">${_('Save')}</button> |
|
79 | <button type="submit" class="btn btn-primary save-inheritance" id="save">${_('Save')}</button> | |
@@ -92,7 +92,7 b'' | |||||
92 | </div> |
|
92 | </div> | |
93 | <div class="panel-body"> |
|
93 | <div class="panel-body"> | |
94 | ${its.issue_tracker_new_row()} |
|
94 | ${its.issue_tracker_new_row()} | |
95 |
${its.issue_tracker_settings_test(test_url=h. |
|
95 | ${its.issue_tracker_settings_test(test_url=h.route_path('edit_repo_issuetracker_test', repo_name=c.repo_info.repo_name))} | |
96 | </div> |
|
96 | </div> | |
97 | </div> |
|
97 | </div> | |
98 |
|
98 |
@@ -19,7 +19,7 b'' | |||||
19 | </code> |
|
19 | </code> | |
20 | </p> |
|
20 | </p> | |
21 |
|
21 | |||
22 |
${h.secure_form(h. |
|
22 | ${h.secure_form(h.route_path('edit_repo_remote_pull', repo_name=c.repo_name), method='POST', request=request)} | |
23 | <div class="form"> |
|
23 | <div class="form"> | |
24 | <div class="fields"> |
|
24 | <div class="fields"> | |
25 | ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")} |
|
25 | ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")} |
@@ -83,7 +83,7 b'' | |||||
83 | ${h.hidden('repo_clone_uri_change', 'NEW')} |
|
83 | ${h.hidden('repo_clone_uri_change', 'NEW')} | |
84 | %endif |
|
84 | %endif | |
85 | <p id="alter_clone_uri_help_block" class="help-block"> |
|
85 | <p id="alter_clone_uri_help_block" class="help-block"> | |
86 |
<% pull_link = h.literal(h.link_to('remote sync', h. |
|
86 | <% pull_link = h.literal(h.link_to('remote sync', h.route_path('edit_repo_remote', repo_name=c.repo_name))) %> | |
87 | ${_('http[s] url where from repository was imported, this field can used for doing {pull_link}.').format(pull_link=pull_link)|n} <br/> |
|
87 | ${_('http[s] url where from repository was imported, this field can used for doing {pull_link}.').format(pull_link=pull_link)|n} <br/> | |
88 | ${_('This field is stored encrypted inside Database, a format of http://user:password@server.com/repo_name can be used and will be hidden from display.')} |
|
88 | ${_('This field is stored encrypted inside Database, a format of http://user:password@server.com/repo_name can be used and will be hidden from display.')} | |
89 | </p> |
|
89 | </p> |
@@ -3,7 +3,7 b'' | |||||
3 | <h3 class="panel-title">${_('Repository statistics')}</h3> |
|
3 | <h3 class="panel-title">${_('Repository statistics')}</h3> | |
4 | </div> |
|
4 | </div> | |
5 | <div class="panel-body"> |
|
5 | <div class="panel-body"> | |
6 |
${h.secure_form(h. |
|
6 | ${h.secure_form(h.route_path('edit_repo_statistics_reset', repo_name=c.repo_info.repo_name), method='POST', request=request)} | |
7 | <div class="form"> |
|
7 | <div class="form"> | |
8 | <div class="fields"> |
|
8 | <div class="fields"> | |
9 | <div class="field" > |
|
9 | <div class="field" > |
@@ -1,7 +1,7 b'' | |||||
1 | <%namespace name="vcss" file="/base/vcs_settings.mako"/> |
|
1 | <%namespace name="vcss" file="/base/vcs_settings.mako"/> | |
2 |
|
2 | |||
3 | <div id="repo_vcs_settings" class="${'inherited' if c.inherit_global_settings else ''}"> |
|
3 | <div id="repo_vcs_settings" class="${'inherited' if c.inherit_global_settings else ''}"> | |
4 |
${h.secure_form(h. |
|
4 | ${h.secure_form(h.route_path('edit_repo_vcs_update', repo_name=c.repo_info.repo_name), method='POST', request=request)} | |
5 | <div class="form panel panel-default"> |
|
5 | <div class="form panel panel-default"> | |
6 | <div class="fields panel-body"> |
|
6 | <div class="fields panel-body"> | |
7 | <div class="field"> |
|
7 | <div class="field"> | |
@@ -50,13 +50,12 b'' | |||||
50 | <script type="text/javascript"> |
|
50 | <script type="text/javascript"> | |
51 |
|
51 | |||
52 | function ajaxDeletePattern(pattern_id, field_id) { |
|
52 | function ajaxDeletePattern(pattern_id, field_id) { | |
53 |
var sUrl = "${h. |
|
53 | var sUrl = "${h.route_path('edit_repo_vcs_svn_pattern_delete', repo_name=c.repo_info.repo_name)}"; | |
54 | var callback = function (o) { |
|
54 | var callback = function (o) { | |
55 | var elem = $("#"+field_id); |
|
55 | var elem = $("#"+field_id); | |
56 | elem.remove(); |
|
56 | elem.remove(); | |
57 | }; |
|
57 | }; | |
58 | var postData = { |
|
58 | var postData = { | |
59 | '_method': 'delete', |
|
|||
60 | 'delete_svn_pattern': pattern_id, |
|
59 | 'delete_svn_pattern': pattern_id, | |
61 | 'csrf_token': CSRF_TOKEN |
|
60 | 'csrf_token': CSRF_TOKEN | |
62 | }; |
|
61 | }; |
@@ -24,7 +24,7 b'' | |||||
24 | <ul class="links"> |
|
24 | <ul class="links"> | |
25 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): |
|
25 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): | |
26 | <li> |
|
26 | <li> | |
27 |
<a href="${h. |
|
27 | <a href="${h.route_path('repo_new')}" class="btn btn-small btn-success">${_(u'Add Repository')}</a> | |
28 | </li> |
|
28 | </li> | |
29 | %endif |
|
29 | %endif | |
30 | </ul> |
|
30 | </ul> |
@@ -73,7 +73,7 b'' | |||||
73 | <%def name="admin_menu()"> |
|
73 | <%def name="admin_menu()"> | |
74 | <ul class="admin_menu submenu"> |
|
74 | <ul class="admin_menu submenu"> | |
75 | <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li> |
|
75 | <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li> | |
76 |
<li><a href="${h. |
|
76 | <li><a href="${h.route_path('repos')}">${_('Repositories')}</a></li> | |
77 | <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li> |
|
77 | <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li> | |
78 | <li><a href="${h.route_path('users')}">${_('Users')}</a></li> |
|
78 | <li><a href="${h.route_path('users')}">${_('Users')}</a></li> | |
79 | <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li> |
|
79 | <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li> | |
@@ -145,7 +145,7 b'' | |||||
145 | <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)"> |
|
145 | <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)"> | |
146 | <ul class="submenu"> |
|
146 | <ul class="submenu"> | |
147 | %if repositories: |
|
147 | %if repositories: | |
148 |
<li class="local-admin-repos"><a href="${h. |
|
148 | <li class="local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li> | |
149 | %endif |
|
149 | %endif | |
150 | %if repository_groups: |
|
150 | %if repository_groups: | |
151 | <li class="local-admin-repo-groups"><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li> |
|
151 | <li class="local-admin-repo-groups"><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li> | |
@@ -268,9 +268,9 b'' | |||||
268 |
|
268 | |||
269 | %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking: |
|
269 | %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking: | |
270 | %if c.rhodecode_db_repo.locked[0]: |
|
270 | %if c.rhodecode_db_repo.locked[0]: | |
271 |
<li><a class="locking_del" href="${h. |
|
271 | <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li> | |
272 | %else: |
|
272 | %else: | |
273 |
<li><a class="locking_add" href="${h. |
|
273 | <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li> | |
274 | %endif |
|
274 | %endif | |
275 | %endif |
|
275 | %endif | |
276 | %if c.rhodecode_user.username != h.DEFAULT_USER: |
|
276 | %if c.rhodecode_user.username != h.DEFAULT_USER: |
@@ -108,8 +108,8 b'' | |||||
108 | alert("Error while deleting entry.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(entry)[0].url)); |
|
108 | alert("Error while deleting entry.\nError code {0} ({1}). URL: {2}".format(data.status,data.statusText,$(entry)[0].url)); | |
109 | } |
|
109 | } | |
110 | }); |
|
110 | }); | |
|
111 | } | |||
111 |
|
|
112 | }; | |
112 | } |
|
|||
113 |
|
113 | |||
114 | $('.delete_issuetracker_entry').on('click', function(e){ |
|
114 | $('.delete_issuetracker_entry').on('click', function(e){ | |
115 | e.preventDefault(); |
|
115 | e.preventDefault(); |
@@ -74,6 +74,8 b'' | |||||
74 | %else: |
|
74 | %else: | |
75 | % if c.file.size < c.visual.cut_off_limit_file: |
|
75 | % if c.file.size < c.visual.cut_off_limit_file: | |
76 | %if c.renderer and not c.annotate: |
|
76 | %if c.renderer and not c.annotate: | |
|
77 | ## pick relative url based on renderer | |||
|
78 | ${c.renderer} XXXX | |||
77 | <% |
|
79 | <% | |
78 | relative_urls = { |
|
80 | relative_urls = { | |
79 | 'raw': h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path), |
|
81 | 'raw': h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path), |
@@ -27,7 +27,7 b'' | |||||
27 | %if not c.repo_group: |
|
27 | %if not c.repo_group: | |
28 | ## no repository group context here |
|
28 | ## no repository group context here | |
29 | %if is_admin or create_repo: |
|
29 | %if is_admin or create_repo: | |
30 |
<a href="${h. |
|
30 | <a href="${h.route_path('repo_new')}" class="btn btn-small btn-success btn-primary">${_('Add Repository')}</a> | |
31 | %endif |
|
31 | %endif | |
32 |
|
32 | |||
33 | %if is_admin or create_repo_group: |
|
33 | %if is_admin or create_repo_group: | |
@@ -36,7 +36,7 b'' | |||||
36 | %else: |
|
36 | %else: | |
37 | ##we're inside other repository group other terms apply |
|
37 | ##we're inside other repository group other terms apply | |
38 | %if is_admin or group_admin or (group_write and create_on_write): |
|
38 | %if is_admin or group_admin or (group_write and create_on_write): | |
39 |
<a href="${h. |
|
39 | <a href="${h.route_path('repo_new',parent_group=c.repo_group.group_id)}" class="btn btn-small btn-success btn-primary">${_('Add Repository')}</a> | |
40 | %endif |
|
40 | %endif | |
41 | %if is_admin or group_admin: |
|
41 | %if is_admin or group_admin: | |
42 | <a href="${h.url('new_repo_group', parent_group=c.repo_group.group_id)}" class="btn btn-small btn-default">${_(u'Add Repository Group')}</a> |
|
42 | <a href="${h.url('new_repo_group', parent_group=c.repo_group.group_id)}" class="btn btn-small btn-default">${_(u'Add Repository Group')}</a> |
@@ -15,7 +15,7 b'' | |||||
15 | <div class="alert alert-dismissable alert-warning"> |
|
15 | <div class="alert alert-dismissable alert-warning"> | |
16 | <strong>Missing requirements</strong> |
|
16 | <strong>Missing requirements</strong> | |
17 | Commits cannot be displayed, because this repository uses one or more extensions, which was not enabled. <br/> |
|
17 | Commits cannot be displayed, because this repository uses one or more extensions, which was not enabled. <br/> | |
18 |
Please <a href="${h. |
|
18 | Please <a href="${h.route_path('edit_repo_vcs', repo_name=c.repo_name)}">enable extension in settings</a>, or contact the repository owner for help. | |
19 | Missing extensions could be: |
|
19 | Missing extensions could be: | |
20 | <pre> |
|
20 | <pre> | |
21 |
|
21 |
@@ -20,10 +20,7 b'' | |||||
20 |
|
20 | |||
21 | import pytest |
|
21 | import pytest | |
22 |
|
22 | |||
23 |
from rhodecode.tests import |
|
23 | from rhodecode.tests import TestController, url | |
24 | TestController, url, assert_session_flash, link_to) |
|
|||
25 | from rhodecode.model.db import User, UserGroup |
|
|||
26 | from rhodecode.model.meta import Session |
|
|||
27 | from rhodecode.tests.fixture import Fixture |
|
24 | from rhodecode.tests.fixture import Fixture | |
28 |
|
25 | |||
29 |
|
26 | |||
@@ -33,6 +30,8 b' def route_path(name, params=None, **kwar' | |||||
33 |
|
30 | |||
34 | base_url = { |
|
31 | base_url = { | |
35 | 'home': '/', |
|
32 | 'home': '/', | |
|
33 | 'repos': | |||
|
34 | ADMIN_PREFIX + '/repos', | |||
36 | 'user_groups': |
|
35 | 'user_groups': | |
37 | ADMIN_PREFIX + '/user_groups', |
|
36 | ADMIN_PREFIX + '/user_groups', | |
38 | 'user_groups_data': |
|
37 | 'user_groups_data': | |
@@ -63,7 +62,7 b' class TestAdminDelegatedUser(TestControl' | |||||
63 | assert_response.no_element_exists('li.local-admin-repo-groups') |
|
62 | assert_response.no_element_exists('li.local-admin-repo-groups') | |
64 | assert_response.no_element_exists('li.local-admin-user-groups') |
|
63 | assert_response.no_element_exists('li.local-admin-user-groups') | |
65 |
|
64 | |||
66 |
response = self.app.get( |
|
65 | response = self.app.get(route_path('repos'), status=200) | |
67 | response.mustcontain('data: []') |
|
66 | response.mustcontain('data: []') | |
68 |
|
67 | |||
69 | response = self.app.get(url('repo_groups'), status=200) |
|
68 | response = self.app.get(url('repo_groups'), status=200) | |
@@ -98,7 +97,7 b' class TestAdminDelegatedUser(TestControl' | |||||
98 | assert_response.one_element_exists('li.local-admin-user-groups') |
|
97 | assert_response.one_element_exists('li.local-admin-user-groups') | |
99 |
|
98 | |||
100 | # admin interfaces have visible elements |
|
99 | # admin interfaces have visible elements | |
101 |
response = self.app.get( |
|
100 | response = self.app.get(route_path('repos'), status=200) | |
102 | response.mustcontain('"name_raw": "{}"'.format(repo_name)) |
|
101 | response.mustcontain('"name_raw": "{}"'.format(repo_name)) | |
103 |
|
102 | |||
104 | response = self.app.get(url('repo_groups'), status=200) |
|
103 | response = self.app.get(url('repo_groups'), status=200) | |
@@ -140,7 +139,7 b' class TestAdminDelegatedUser(TestControl' | |||||
140 | assert_response.one_element_exists('li.local-admin-user-groups') |
|
139 | assert_response.one_element_exists('li.local-admin-user-groups') | |
141 |
|
140 | |||
142 | # admin interfaces have visible elements |
|
141 | # admin interfaces have visible elements | |
143 |
response = self.app.get( |
|
142 | response = self.app.get(route_path('repos'), status=200) | |
144 | response.mustcontain('"name_raw": "{}"'.format(repo_name)) |
|
143 | response.mustcontain('"name_raw": "{}"'.format(repo_name)) | |
145 |
|
144 | |||
146 | response = self.app.get(url('repo_groups'), status=200) |
|
145 | response = self.app.get(url('repo_groups'), status=200) |
@@ -22,8 +22,6 b' import pytest' | |||||
22 | from mock import Mock, patch |
|
22 | from mock import Mock, patch | |
23 |
|
23 | |||
24 | from rhodecode.lib import base |
|
24 | from rhodecode.lib import base | |
25 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
|||
26 | from rhodecode.lib import helpers as h |
|
|||
27 | from rhodecode.model import db |
|
25 | from rhodecode.model import db | |
28 |
|
26 | |||
29 |
|
27 | |||
@@ -94,162 +92,3 b' def call_vcs_operation_context(**kwargs_' | |||||
94 | return result |
|
92 | return result | |
95 |
|
93 | |||
96 |
|
94 | |||
97 | class TestBaseRepoController(object): |
|
|||
98 | def test_context_is_updated_when_update_global_counters_is_called(self): |
|
|||
99 | followers = 1 |
|
|||
100 | forks = 2 |
|
|||
101 | pull_requests = 3 |
|
|||
102 | is_following = True |
|
|||
103 | scm_model = Mock(name="scm_model") |
|
|||
104 | db_repo = Mock(name="db_repo") |
|
|||
105 | scm_model.get_followers.return_value = followers |
|
|||
106 | scm_model.get_forks.return_value = forks |
|
|||
107 | scm_model.get_pull_requests.return_value = pull_requests |
|
|||
108 | scm_model.is_following_repo.return_value = is_following |
|
|||
109 |
|
||||
110 | controller = base.BaseRepoController() |
|
|||
111 | with patch.object(base, 'c') as context_mock: |
|
|||
112 | controller._update_global_counters(scm_model, db_repo) |
|
|||
113 |
|
||||
114 | scm_model.get_pull_requests.assert_called_once_with(db_repo) |
|
|||
115 |
|
||||
116 | assert context_mock.repository_pull_requests == pull_requests |
|
|||
117 |
|
||||
118 |
|
||||
119 | class TestBaseRepoControllerHandleMissingRequirements(object): |
|
|||
120 | def test_logs_error_and_sets_repo_to_none(self, app): |
|
|||
121 | controller = base.BaseRepoController() |
|
|||
122 | error_message = 'Some message' |
|
|||
123 | error = RepositoryRequirementError(error_message) |
|
|||
124 | context_patcher = patch.object(base, 'c') |
|
|||
125 | log_patcher = patch.object(base, 'log') |
|
|||
126 | request_patcher = patch.object(base, 'request') |
|
|||
127 | redirect_patcher = patch.object(base, 'redirect') |
|
|||
128 | controller.rhodecode_repo = 'something' |
|
|||
129 |
|
||||
130 | with context_patcher as context_mock, log_patcher as log_mock, \ |
|
|||
131 | request_patcher, redirect_patcher: |
|
|||
132 | context_mock.repo_name = 'abcde' |
|
|||
133 | controller._handle_missing_requirements(error) |
|
|||
134 |
|
||||
135 | expected_log_message = ( |
|
|||
136 | 'Requirements are missing for repository %s: %s', 'abcde', |
|
|||
137 | error_message) |
|
|||
138 | log_mock.error.assert_called_once_with(*expected_log_message) |
|
|||
139 |
|
||||
140 | assert controller.rhodecode_repo is None |
|
|||
141 |
|
||||
142 | @pytest.mark.parametrize('path, should_redirect', [ |
|
|||
143 | ('/abcde', False), |
|
|||
144 | ('/abcde/settings', False), |
|
|||
145 | ('/abcde/settings/vcs', False), |
|
|||
146 | ('/_admin/repos/abcde', False), # Settings update |
|
|||
147 | ('/abcde/changelog', True), |
|
|||
148 | ('/abcde/files/tip', True), |
|
|||
149 | ('/abcde/settings/statistics', True), |
|
|||
150 | ]) |
|
|||
151 | def test_redirects_if_not_summary_or_settings_page( |
|
|||
152 | self, app, path, should_redirect): |
|
|||
153 | repo_name = 'abcde' |
|
|||
154 | controller = base.BaseRepoController() |
|
|||
155 | error = RepositoryRequirementError('Some message') |
|
|||
156 | context_patcher = patch.object(base, 'c') |
|
|||
157 | controller.rhodecode_repo = repo_name |
|
|||
158 | request_patcher = patch.object(base, 'request') |
|
|||
159 | redirect_patcher = patch.object(base, 'redirect') |
|
|||
160 |
|
||||
161 | with context_patcher as context_mock, \ |
|
|||
162 | request_patcher as request_mock, \ |
|
|||
163 | redirect_patcher as redirect_mock: |
|
|||
164 | request_mock.path = path |
|
|||
165 | context_mock.repo_name = repo_name |
|
|||
166 | controller._handle_missing_requirements(error) |
|
|||
167 |
|
||||
168 | expected_url = h.route_path('repo_summary', repo_name=repo_name) |
|
|||
169 | if should_redirect: |
|
|||
170 | redirect_mock.assert_called_once_with(expected_url) |
|
|||
171 | else: |
|
|||
172 | redirect_mock.call_count == 0 |
|
|||
173 |
|
||||
174 |
|
||||
175 | class TestBaseRepoControllerBefore(object): |
|
|||
176 | def test_flag_is_true_when_requirements_are_missing(self, before_mocks): |
|
|||
177 | controller = self._get_controller() |
|
|||
178 |
|
||||
179 | handle_patcher = patch.object( |
|
|||
180 | controller, '_handle_missing_requirements') |
|
|||
181 |
|
||||
182 | error = RepositoryRequirementError() |
|
|||
183 | before_mocks.repository.scm_instance.side_effect = error |
|
|||
184 |
|
||||
185 | with handle_patcher as handle_mock: |
|
|||
186 | controller.__before__() |
|
|||
187 |
|
||||
188 | handle_mock.assert_called_once_with(error) |
|
|||
189 | assert before_mocks['context'].repository_requirements_missing is True |
|
|||
190 |
|
||||
191 | def test_flag_is_false_when_no_requirements_are_missing( |
|
|||
192 | self, before_mocks): |
|
|||
193 | controller = self._get_controller() |
|
|||
194 |
|
||||
195 | handle_patcher = patch.object( |
|
|||
196 | controller, '_handle_missing_requirements') |
|
|||
197 | with handle_patcher as handle_mock: |
|
|||
198 | controller.__before__() |
|
|||
199 | handle_mock.call_count == 0 |
|
|||
200 | assert before_mocks['context'].repository_requirements_missing is False |
|
|||
201 |
|
||||
202 | def test_update_global_counters_is_called(self, before_mocks): |
|
|||
203 | controller = self._get_controller() |
|
|||
204 |
|
||||
205 | update_counters_patcher = patch.object( |
|
|||
206 | controller, '_update_global_counters') |
|
|||
207 |
|
||||
208 | with update_counters_patcher as update_counters_mock: |
|
|||
209 | controller.__before__() |
|
|||
210 | update_counters_mock.assert_called_once_with( |
|
|||
211 | controller.scm_model, before_mocks.repository) |
|
|||
212 |
|
||||
213 | def _get_controller(self): |
|
|||
214 | controller = base.BaseRepoController() |
|
|||
215 | controller.scm_model = Mock() |
|
|||
216 | controller.rhodecode_repo = Mock() |
|
|||
217 | return controller |
|
|||
218 |
|
||||
219 |
|
||||
220 | @pytest.fixture |
|
|||
221 | def before_mocks(request): |
|
|||
222 | patcher = BeforePatcher() |
|
|||
223 | patcher.start() |
|
|||
224 | request.addfinalizer(patcher.stop) |
|
|||
225 | return patcher |
|
|||
226 |
|
||||
227 |
|
||||
228 | class BeforePatcher(object): |
|
|||
229 | patchers = {} |
|
|||
230 | mocks = {} |
|
|||
231 | repository = None |
|
|||
232 |
|
||||
233 | def __init__(self): |
|
|||
234 | self.repository = Mock() |
|
|||
235 |
|
||||
236 | def start(self): |
|
|||
237 | self.patchers = { |
|
|||
238 | 'request': patch.object(base, 'request'), |
|
|||
239 | 'before': patch.object(base.BaseController, '__before__'), |
|
|||
240 | 'context': patch.object(base, 'c'), |
|
|||
241 | 'repo': patch.object( |
|
|||
242 | base.Repository, 'get_by_repo_name', |
|
|||
243 | return_value=self.repository) |
|
|||
244 |
|
||||
245 | } |
|
|||
246 | self.mocks = { |
|
|||
247 | p: self.patchers[p].start() for p in self.patchers |
|
|||
248 | } |
|
|||
249 |
|
||||
250 | def stop(self): |
|
|||
251 | for patcher in self.patchers.values(): |
|
|||
252 | patcher.stop() |
|
|||
253 |
|
||||
254 | def __getitem__(self, key): |
|
|||
255 | return self.mocks[key] |
|
@@ -1045,7 +1045,7 b' class TestCreateOrUpdateRepoSettings(obj' | |||||
1045 | def test_cache_is_marked_for_invalidation(self, repo_stub): |
|
1045 | def test_cache_is_marked_for_invalidation(self, repo_stub): | |
1046 | model = VcsSettingsModel(repo=repo_stub) |
|
1046 | model = VcsSettingsModel(repo=repo_stub) | |
1047 | invalidation_patcher = mock.patch( |
|
1047 | invalidation_patcher = mock.patch( | |
1048 |
'rhodecode. |
|
1048 | 'rhodecode.model.scm.ScmModel.mark_for_invalidation') | |
1049 | with invalidation_patcher as invalidation_mock: |
|
1049 | with invalidation_patcher as invalidation_mock: | |
1050 | model.create_or_update_repo_settings( |
|
1050 | model.create_or_update_repo_settings( | |
1051 | data=self.FORM_DATA, inherit_global_settings=True) |
|
1051 | data=self.FORM_DATA, inherit_global_settings=True) |
General Comments 0
You need to be logged in to leave comments.
Login now