##// END OF EJS Templates
repo-caches: moved view into pyramid.
marcink -
r1722:1a4c1af0 default
parent child Browse files
Show More
@@ -0,0 +1,76 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2011-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.auth import LoginRequired, HasRepoPermissionAnyDecorator
28 from rhodecode.lib import helpers as h
29 from rhodecode.model.meta import Session
30 from rhodecode.model.scm import ScmModel
31
32 log = logging.getLogger(__name__)
33
34
35 class RepoCachesView(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_caches', request_method='GET',
49 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
50 def repo_caches(self):
51 c = self.load_default_context()
52 c.active = 'caches'
53
54 return self._get_template_context(c)
55
56 @LoginRequired()
57 @HasRepoPermissionAnyDecorator('repository.admin')
58 @view_config(
59 route_name='edit_repo_caches', request_method='POST')
60 def repo_caches_purge(self):
61 _ = self.request.translate
62 c = self.load_default_context()
63 c.active = 'caches'
64
65 try:
66 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
67 Session().commit()
68 h.flash(_('Cache invalidation successful'),
69 category='success')
70 except Exception:
71 log.exception("Exception during cache invalidation")
72 h.flash(_('An error occurred during cache invalidation'),
73 category='error')
74
75 raise HTTPFound(h.route_path(
76 'edit_repo_caches', repo_name=self.db_repo_name)) No newline at end of file
@@ -1,50 +1,56 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
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
21
22 def includeme(config):
22 def includeme(config):
23
23
24 # Settings
24 # Settings
25 config.add_route(
25 config.add_route(
26 name='edit_repo',
26 name='edit_repo',
27 pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
27 pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
28
28
29 # Caches
30 config.add_route(
31 name='edit_repo_caches',
32 pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True)
33
34 # Maintenance
29 config.add_route(
35 config.add_route(
30 name='repo_maintenance',
36 name='repo_maintenance',
31 pattern='/{repo_name:.*?[^/]}/maintenance', repo_route=True)
37 pattern='/{repo_name:.*?[^/]}/maintenance', repo_route=True)
32
38
33 config.add_route(
39 config.add_route(
34 name='repo_maintenance_execute',
40 name='repo_maintenance_execute',
35 pattern='/{repo_name:.*?[^/]}/maintenance/execute', repo_route=True)
41 pattern='/{repo_name:.*?[^/]}/maintenance/execute', repo_route=True)
36
42
37 # Strip
43 # Strip
38 config.add_route(
44 config.add_route(
39 name='strip',
45 name='strip',
40 pattern='/{repo_name:.*?[^/]}/strip', repo_route=True)
46 pattern='/{repo_name:.*?[^/]}/strip', repo_route=True)
41
47
42 config.add_route(
48 config.add_route(
43 name='strip_check',
49 name='strip_check',
44 pattern='/{repo_name:.*?[^/]}/strip_check', repo_route=True)
50 pattern='/{repo_name:.*?[^/]}/strip_check', repo_route=True)
45
51
46 config.add_route(
52 config.add_route(
47 name='strip_execute',
53 name='strip_execute',
48 pattern='/{repo_name:.*?[^/]}/strip_execute', repo_route=True)
54 pattern='/{repo_name:.*?[^/]}/strip_execute', repo_route=True)
49 # Scan module for configuration decorators.
55 # Scan module for configuration decorators.
50 config.scan()
56 config.scan()
@@ -1,230 +1,231 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
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 import mock
21 import mock
22 import pytest
22 import pytest
23
23
24 from rhodecode.lib.utils2 import str2bool
24 from rhodecode.lib.utils2 import str2bool
25 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
25 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
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 url, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN,
29 url, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN,
30 assert_session_flash)
30 assert_session_flash)
31 from rhodecode.tests.fixture import Fixture
31 from rhodecode.tests.fixture import Fixture
32
32
33 fixture = Fixture()
33 fixture = Fixture()
34
34
35
35
36 def route_path(name, params=None, **kwargs):
36 def route_path(name, params=None, **kwargs):
37 import urllib
37 import urllib
38
38
39 base_url = {
39 base_url = {
40 'edit_repo': '/{repo_name}/settings',
40 'edit_repo': '/{repo_name}/settings',
41 'edit_repo_caches': '/{repo_name}/settings/caches',
41 }[name].format(**kwargs)
42 }[name].format(**kwargs)
42
43
43 if params:
44 if params:
44 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
45 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
45 return base_url
46 return base_url
46
47
47
48
48 def _get_permission_for_user(user, repo):
49 def _get_permission_for_user(user, repo):
49 perm = UserRepoToPerm.query()\
50 perm = UserRepoToPerm.query()\
50 .filter(UserRepoToPerm.repository ==
51 .filter(UserRepoToPerm.repository ==
51 Repository.get_by_repo_name(repo))\
52 Repository.get_by_repo_name(repo))\
52 .filter(UserRepoToPerm.user == User.get_by_username(user))\
53 .filter(UserRepoToPerm.user == User.get_by_username(user))\
53 .all()
54 .all()
54 return perm
55 return perm
55
56
56
57
57 @pytest.mark.usefixtures('autologin_user', 'app')
58 @pytest.mark.usefixtures('autologin_user', 'app')
58 class TestAdminRepoSettings(object):
59 class TestAdminRepoSettings(object):
59 @pytest.mark.parametrize('urlname', [
60 @pytest.mark.parametrize('urlname', [
60 'edit_repo',
61 'edit_repo',
62 'edit_repo_caches'
61 ])
63 ])
62 def test_show_page(self, urlname, app, backend):
64 def test_show_page(self, urlname, app, backend):
63 app.get(route_path(urlname, repo_name=backend.repo_name), status=200)
65 app.get(route_path(urlname, repo_name=backend.repo_name), status=200)
64
66
65 def test_edit_accessible_when_missing_requirements(
67 def test_edit_accessible_when_missing_requirements(
66 self, backend_hg, autologin_user):
68 self, backend_hg, autologin_user):
67 scm_patcher = mock.patch.object(
69 scm_patcher = mock.patch.object(
68 Repository, 'scm_instance', side_effect=RepositoryRequirementError)
70 Repository, 'scm_instance', side_effect=RepositoryRequirementError)
69 with scm_patcher:
71 with scm_patcher:
70 self.app.get(route_path('edit_repo', repo_name=backend_hg.repo_name))
72 self.app.get(route_path('edit_repo', repo_name=backend_hg.repo_name))
71
73
72 @pytest.mark.parametrize('urlname', [
74 @pytest.mark.parametrize('urlname', [
73 'edit_repo_perms',
75 'edit_repo_perms',
74 'edit_repo_advanced',
76 'edit_repo_advanced',
75 'repo_vcs_settings',
77 'repo_vcs_settings',
76 'edit_repo_fields',
78 'edit_repo_fields',
77 'repo_settings_issuetracker',
79 'repo_settings_issuetracker',
78 'edit_repo_caches',
79 'edit_repo_remote',
80 'edit_repo_remote',
80 'edit_repo_statistics',
81 'edit_repo_statistics',
81 ])
82 ])
82 def test_show_page_pylons(self, urlname, app):
83 def test_show_page_pylons(self, urlname, app):
83 app.get(url(urlname, repo_name=HG_REPO))
84 app.get(url(urlname, repo_name=HG_REPO))
84
85
85 @pytest.mark.parametrize('update_settings', [
86 @pytest.mark.parametrize('update_settings', [
86 {'repo_description': 'alter-desc'},
87 {'repo_description': 'alter-desc'},
87 {'repo_owner': TEST_USER_REGULAR_LOGIN},
88 {'repo_owner': TEST_USER_REGULAR_LOGIN},
88 {'repo_private': 'true'},
89 {'repo_private': 'true'},
89 {'repo_enable_locking': 'true'},
90 {'repo_enable_locking': 'true'},
90 {'repo_enable_downloads': 'true'},
91 {'repo_enable_downloads': 'true'},
91 ])
92 ])
92 def test_update_repo_settings(self, update_settings, csrf_token, backend, user_util):
93 def test_update_repo_settings(self, update_settings, csrf_token, backend, user_util):
93 repo = user_util.create_repo(repo_type=backend.alias)
94 repo = user_util.create_repo(repo_type=backend.alias)
94 repo_name = repo.repo_name
95 repo_name = repo.repo_name
95
96
96 params = fixture._get_repo_create_params(
97 params = fixture._get_repo_create_params(
97 csrf_token=csrf_token,
98 csrf_token=csrf_token,
98 repo_name=repo_name,
99 repo_name=repo_name,
99 repo_type=backend.alias,
100 repo_type=backend.alias,
100 repo_owner=TEST_USER_ADMIN_LOGIN,
101 repo_owner=TEST_USER_ADMIN_LOGIN,
101 repo_description='DESC',
102 repo_description='DESC',
102
103
103 repo_private='false',
104 repo_private='false',
104 repo_enable_locking='false',
105 repo_enable_locking='false',
105 repo_enable_downloads='false')
106 repo_enable_downloads='false')
106 params.update(update_settings)
107 params.update(update_settings)
107 self.app.post(
108 self.app.post(
108 route_path('edit_repo', repo_name=repo_name),
109 route_path('edit_repo', repo_name=repo_name),
109 params=params, status=302)
110 params=params, status=302)
110
111
111 repo = Repository.get_by_repo_name(repo_name)
112 repo = Repository.get_by_repo_name(repo_name)
112 assert repo.user.username == \
113 assert repo.user.username == \
113 update_settings.get('repo_owner', repo.user.username)
114 update_settings.get('repo_owner', repo.user.username)
114
115
115 assert repo.description == \
116 assert repo.description == \
116 update_settings.get('repo_description', repo.description)
117 update_settings.get('repo_description', repo.description)
117
118
118 assert repo.private == \
119 assert repo.private == \
119 str2bool(update_settings.get(
120 str2bool(update_settings.get(
120 'repo_private', repo.private))
121 'repo_private', repo.private))
121
122
122 assert repo.enable_locking == \
123 assert repo.enable_locking == \
123 str2bool(update_settings.get(
124 str2bool(update_settings.get(
124 'repo_enable_locking', repo.enable_locking))
125 'repo_enable_locking', repo.enable_locking))
125
126
126 assert repo.enable_downloads == \
127 assert repo.enable_downloads == \
127 str2bool(update_settings.get(
128 str2bool(update_settings.get(
128 'repo_enable_downloads', repo.enable_downloads))
129 'repo_enable_downloads', repo.enable_downloads))
129
130
130 def test_update_repo_name_via_settings(self, csrf_token, user_util, backend):
131 def test_update_repo_name_via_settings(self, csrf_token, user_util, backend):
131 repo = user_util.create_repo(repo_type=backend.alias)
132 repo = user_util.create_repo(repo_type=backend.alias)
132 repo_name = repo.repo_name
133 repo_name = repo.repo_name
133
134
134 repo_group = user_util.create_repo_group()
135 repo_group = user_util.create_repo_group()
135 repo_group_name = repo_group.group_name
136 repo_group_name = repo_group.group_name
136 new_name = repo_group_name + '_' + repo_name
137 new_name = repo_group_name + '_' + repo_name
137
138
138 params = fixture._get_repo_create_params(
139 params = fixture._get_repo_create_params(
139 csrf_token=csrf_token,
140 csrf_token=csrf_token,
140 repo_name=new_name,
141 repo_name=new_name,
141 repo_type=backend.alias,
142 repo_type=backend.alias,
142 repo_owner=TEST_USER_ADMIN_LOGIN,
143 repo_owner=TEST_USER_ADMIN_LOGIN,
143 repo_description='DESC',
144 repo_description='DESC',
144 repo_private='false',
145 repo_private='false',
145 repo_enable_locking='false',
146 repo_enable_locking='false',
146 repo_enable_downloads='false')
147 repo_enable_downloads='false')
147 self.app.post(
148 self.app.post(
148 route_path('edit_repo', repo_name=repo_name),
149 route_path('edit_repo', repo_name=repo_name),
149 params=params, status=302)
150 params=params, status=302)
150 repo = Repository.get_by_repo_name(new_name)
151 repo = Repository.get_by_repo_name(new_name)
151 assert repo.repo_name == new_name
152 assert repo.repo_name == new_name
152
153
153 def test_update_repo_group_via_settings(self, csrf_token, user_util, backend):
154 def test_update_repo_group_via_settings(self, csrf_token, user_util, backend):
154 repo = user_util.create_repo(repo_type=backend.alias)
155 repo = user_util.create_repo(repo_type=backend.alias)
155 repo_name = repo.repo_name
156 repo_name = repo.repo_name
156
157
157 repo_group = user_util.create_repo_group()
158 repo_group = user_util.create_repo_group()
158 repo_group_name = repo_group.group_name
159 repo_group_name = repo_group.group_name
159 repo_group_id = repo_group.group_id
160 repo_group_id = repo_group.group_id
160
161
161 new_name = repo_group_name + '/' + repo_name
162 new_name = repo_group_name + '/' + repo_name
162 params = fixture._get_repo_create_params(
163 params = fixture._get_repo_create_params(
163 csrf_token=csrf_token,
164 csrf_token=csrf_token,
164 repo_name=repo_name,
165 repo_name=repo_name,
165 repo_type=backend.alias,
166 repo_type=backend.alias,
166 repo_owner=TEST_USER_ADMIN_LOGIN,
167 repo_owner=TEST_USER_ADMIN_LOGIN,
167 repo_description='DESC',
168 repo_description='DESC',
168 repo_group=repo_group_id,
169 repo_group=repo_group_id,
169 repo_private='false',
170 repo_private='false',
170 repo_enable_locking='false',
171 repo_enable_locking='false',
171 repo_enable_downloads='false')
172 repo_enable_downloads='false')
172 self.app.post(
173 self.app.post(
173 route_path('edit_repo', repo_name=repo_name),
174 route_path('edit_repo', repo_name=repo_name),
174 params=params, status=302)
175 params=params, status=302)
175 repo = Repository.get_by_repo_name(new_name)
176 repo = Repository.get_by_repo_name(new_name)
176 assert repo.repo_name == new_name
177 assert repo.repo_name == new_name
177
178
178 def test_set_private_flag_sets_default_user_permissions_to_none(
179 def test_set_private_flag_sets_default_user_permissions_to_none(
179 self, autologin_user, backend, csrf_token):
180 self, autologin_user, backend, csrf_token):
180
181
181 # initially repository perm should be read
182 # initially repository perm should be read
182 perm = _get_permission_for_user(user='default', repo=backend.repo_name)
183 perm = _get_permission_for_user(user='default', repo=backend.repo_name)
183 assert len(perm) == 1
184 assert len(perm) == 1
184 assert perm[0].permission.permission_name == 'repository.read'
185 assert perm[0].permission.permission_name == 'repository.read'
185 assert not backend.repo.private
186 assert not backend.repo.private
186
187
187 response = self.app.post(
188 response = self.app.post(
188 route_path('edit_repo', repo_name=backend.repo_name),
189 route_path('edit_repo', repo_name=backend.repo_name),
189 params=fixture._get_repo_create_params(
190 params=fixture._get_repo_create_params(
190 repo_private='true',
191 repo_private='true',
191 repo_name=backend.repo_name,
192 repo_name=backend.repo_name,
192 repo_type=backend.alias,
193 repo_type=backend.alias,
193 repo_owner=TEST_USER_ADMIN_LOGIN,
194 repo_owner=TEST_USER_ADMIN_LOGIN,
194 csrf_token=csrf_token), status=302)
195 csrf_token=csrf_token), status=302)
195
196
196 assert_session_flash(
197 assert_session_flash(
197 response,
198 response,
198 msg='Repository %s updated successfully' % (backend.repo_name))
199 msg='Repository %s updated successfully' % (backend.repo_name))
199
200
200 repo = Repository.get_by_repo_name(backend.repo_name)
201 repo = Repository.get_by_repo_name(backend.repo_name)
201 assert repo.private is True
202 assert repo.private is True
202
203
203 # now the repo default permission should be None
204 # now the repo default permission should be None
204 perm = _get_permission_for_user(user='default', repo=backend.repo_name)
205 perm = _get_permission_for_user(user='default', repo=backend.repo_name)
205 assert len(perm) == 1
206 assert len(perm) == 1
206 assert perm[0].permission.permission_name == 'repository.none'
207 assert perm[0].permission.permission_name == 'repository.none'
207
208
208 response = self.app.post(
209 response = self.app.post(
209 route_path('edit_repo', repo_name=backend.repo_name),
210 route_path('edit_repo', repo_name=backend.repo_name),
210 params=fixture._get_repo_create_params(
211 params=fixture._get_repo_create_params(
211 repo_private='false',
212 repo_private='false',
212 repo_name=backend.repo_name,
213 repo_name=backend.repo_name,
213 repo_type=backend.alias,
214 repo_type=backend.alias,
214 repo_owner=TEST_USER_ADMIN_LOGIN,
215 repo_owner=TEST_USER_ADMIN_LOGIN,
215 csrf_token=csrf_token), status=302)
216 csrf_token=csrf_token), status=302)
216
217
217 assert_session_flash(
218 assert_session_flash(
218 response,
219 response,
219 msg='Repository %s updated successfully' % (backend.repo_name))
220 msg='Repository %s updated successfully' % (backend.repo_name))
220 assert backend.repo.private is False
221 assert backend.repo.private is False
221
222
222 # we turn off private now the repo default permission should stay None
223 # we turn off private now the repo default permission should stay None
223 perm = _get_permission_for_user(user='default', repo=backend.repo_name)
224 perm = _get_permission_for_user(user='default', repo=backend.repo_name)
224 assert len(perm) == 1
225 assert len(perm) == 1
225 assert perm[0].permission.permission_name == 'repository.none'
226 assert perm[0].permission.permission_name == 'repository.none'
226
227
227 # update this permission back
228 # update this permission back
228 perm[0].permission = Permission.get_by_key('repository.read')
229 perm[0].permission = Permission.get_by_key('repository.read')
229 Session().add(perm[0])
230 Session().add(perm[0])
230 Session().commit()
231 Session().commit()
@@ -1,1107 +1,1098 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
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 """
21 """
22 Routes configuration
22 Routes configuration
23
23
24 The more specific and detailed routes should be defined first so they
24 The more specific and detailed routes should be defined first so they
25 may take precedent over the more generic routes. For more information
25 may take precedent over the more generic routes. For more information
26 refer to the routes manual at http://routes.groovie.org/docs/
26 refer to the routes manual at http://routes.groovie.org/docs/
27
27
28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 and _route_name variable which uses some of stored naming here to do redirects.
29 and _route_name variable which uses some of stored naming here to do redirects.
30 """
30 """
31 import os
31 import os
32 import re
32 import re
33 from routes import Mapper
33 from routes import Mapper
34
34
35 # prefix for non repository related links needs to be prefixed with `/`
35 # prefix for non repository related links needs to be prefixed with `/`
36 ADMIN_PREFIX = '/_admin'
36 ADMIN_PREFIX = '/_admin'
37 STATIC_FILE_PREFIX = '/_static'
37 STATIC_FILE_PREFIX = '/_static'
38
38
39 # Default requirements for URL parts
39 # Default requirements for URL parts
40 URL_NAME_REQUIREMENTS = {
40 URL_NAME_REQUIREMENTS = {
41 # group name can have a slash in them, but they must not end with a slash
41 # group name can have a slash in them, but they must not end with a slash
42 'group_name': r'.*?[^/]',
42 'group_name': r'.*?[^/]',
43 'repo_group_name': r'.*?[^/]',
43 'repo_group_name': r'.*?[^/]',
44 # repo names can have a slash in them, but they must not end with a slash
44 # repo names can have a slash in them, but they must not end with a slash
45 'repo_name': r'.*?[^/]',
45 'repo_name': r'.*?[^/]',
46 # file path eats up everything at the end
46 # file path eats up everything at the end
47 'f_path': r'.*',
47 'f_path': r'.*',
48 # reference types
48 # reference types
49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
51 }
51 }
52
52
53
53
54 def add_route_requirements(route_path, requirements):
54 def add_route_requirements(route_path, requirements):
55 """
55 """
56 Adds regex requirements to pyramid routes using a mapping dict
56 Adds regex requirements to pyramid routes using a mapping dict
57
57
58 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
58 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
59 '/{action}/{id:\d+}'
59 '/{action}/{id:\d+}'
60
60
61 """
61 """
62 for key, regex in requirements.items():
62 for key, regex in requirements.items():
63 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
63 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
64 return route_path
64 return route_path
65
65
66
66
67 class JSRoutesMapper(Mapper):
67 class JSRoutesMapper(Mapper):
68 """
68 """
69 Wrapper for routes.Mapper to make pyroutes compatible url definitions
69 Wrapper for routes.Mapper to make pyroutes compatible url definitions
70 """
70 """
71 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
71 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
72 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
72 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
73 def __init__(self, *args, **kw):
73 def __init__(self, *args, **kw):
74 super(JSRoutesMapper, self).__init__(*args, **kw)
74 super(JSRoutesMapper, self).__init__(*args, **kw)
75 self._jsroutes = []
75 self._jsroutes = []
76
76
77 def connect(self, *args, **kw):
77 def connect(self, *args, **kw):
78 """
78 """
79 Wrapper for connect to take an extra argument jsroute=True
79 Wrapper for connect to take an extra argument jsroute=True
80
80
81 :param jsroute: boolean, if True will add the route to the pyroutes list
81 :param jsroute: boolean, if True will add the route to the pyroutes list
82 """
82 """
83 if kw.pop('jsroute', False):
83 if kw.pop('jsroute', False):
84 if not self._named_route_regex.match(args[0]):
84 if not self._named_route_regex.match(args[0]):
85 raise Exception('only named routes can be added to pyroutes')
85 raise Exception('only named routes can be added to pyroutes')
86 self._jsroutes.append(args[0])
86 self._jsroutes.append(args[0])
87
87
88 super(JSRoutesMapper, self).connect(*args, **kw)
88 super(JSRoutesMapper, self).connect(*args, **kw)
89
89
90 def _extract_route_information(self, route):
90 def _extract_route_information(self, route):
91 """
91 """
92 Convert a route into tuple(name, path, args), eg:
92 Convert a route into tuple(name, path, args), eg:
93 ('show_user', '/profile/%(username)s', ['username'])
93 ('show_user', '/profile/%(username)s', ['username'])
94 """
94 """
95 routepath = route.routepath
95 routepath = route.routepath
96 def replace(matchobj):
96 def replace(matchobj):
97 if matchobj.group(1):
97 if matchobj.group(1):
98 return "%%(%s)s" % matchobj.group(1).split(':')[0]
98 return "%%(%s)s" % matchobj.group(1).split(':')[0]
99 else:
99 else:
100 return "%%(%s)s" % matchobj.group(2)
100 return "%%(%s)s" % matchobj.group(2)
101
101
102 routepath = self._argument_prog.sub(replace, routepath)
102 routepath = self._argument_prog.sub(replace, routepath)
103 return (
103 return (
104 route.name,
104 route.name,
105 routepath,
105 routepath,
106 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
106 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
107 for arg in self._argument_prog.findall(route.routepath)]
107 for arg in self._argument_prog.findall(route.routepath)]
108 )
108 )
109
109
110 def jsroutes(self):
110 def jsroutes(self):
111 """
111 """
112 Return a list of pyroutes.js compatible routes
112 Return a list of pyroutes.js compatible routes
113 """
113 """
114 for route_name in self._jsroutes:
114 for route_name in self._jsroutes:
115 yield self._extract_route_information(self._routenames[route_name])
115 yield self._extract_route_information(self._routenames[route_name])
116
116
117
117
118 def make_map(config):
118 def make_map(config):
119 """Create, configure and return the routes Mapper"""
119 """Create, configure and return the routes Mapper"""
120 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
120 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
121 always_scan=config['debug'])
121 always_scan=config['debug'])
122 rmap.minimization = False
122 rmap.minimization = False
123 rmap.explicit = False
123 rmap.explicit = False
124
124
125 from rhodecode.lib.utils2 import str2bool
125 from rhodecode.lib.utils2 import str2bool
126 from rhodecode.model import repo, repo_group
126 from rhodecode.model import repo, repo_group
127
127
128 def check_repo(environ, match_dict):
128 def check_repo(environ, match_dict):
129 """
129 """
130 check for valid repository for proper 404 handling
130 check for valid repository for proper 404 handling
131
131
132 :param environ:
132 :param environ:
133 :param match_dict:
133 :param match_dict:
134 """
134 """
135 repo_name = match_dict.get('repo_name')
135 repo_name = match_dict.get('repo_name')
136
136
137 if match_dict.get('f_path'):
137 if match_dict.get('f_path'):
138 # fix for multiple initial slashes that causes errors
138 # fix for multiple initial slashes that causes errors
139 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
139 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
140 repo_model = repo.RepoModel()
140 repo_model = repo.RepoModel()
141 by_name_match = repo_model.get_by_repo_name(repo_name)
141 by_name_match = repo_model.get_by_repo_name(repo_name)
142 # if we match quickly from database, short circuit the operation,
142 # if we match quickly from database, short circuit the operation,
143 # and validate repo based on the type.
143 # and validate repo based on the type.
144 if by_name_match:
144 if by_name_match:
145 return True
145 return True
146
146
147 by_id_match = repo_model.get_repo_by_id(repo_name)
147 by_id_match = repo_model.get_repo_by_id(repo_name)
148 if by_id_match:
148 if by_id_match:
149 repo_name = by_id_match.repo_name
149 repo_name = by_id_match.repo_name
150 match_dict['repo_name'] = repo_name
150 match_dict['repo_name'] = repo_name
151 return True
151 return True
152
152
153 return False
153 return False
154
154
155 def check_group(environ, match_dict):
155 def check_group(environ, match_dict):
156 """
156 """
157 check for valid repository group path for proper 404 handling
157 check for valid repository group path for proper 404 handling
158
158
159 :param environ:
159 :param environ:
160 :param match_dict:
160 :param match_dict:
161 """
161 """
162 repo_group_name = match_dict.get('group_name')
162 repo_group_name = match_dict.get('group_name')
163 repo_group_model = repo_group.RepoGroupModel()
163 repo_group_model = repo_group.RepoGroupModel()
164 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
164 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
165 if by_name_match:
165 if by_name_match:
166 return True
166 return True
167
167
168 return False
168 return False
169
169
170 def check_user_group(environ, match_dict):
170 def check_user_group(environ, match_dict):
171 """
171 """
172 check for valid user group for proper 404 handling
172 check for valid user group for proper 404 handling
173
173
174 :param environ:
174 :param environ:
175 :param match_dict:
175 :param match_dict:
176 """
176 """
177 return True
177 return True
178
178
179 def check_int(environ, match_dict):
179 def check_int(environ, match_dict):
180 return match_dict.get('id').isdigit()
180 return match_dict.get('id').isdigit()
181
181
182
182
183 #==========================================================================
183 #==========================================================================
184 # CUSTOM ROUTES HERE
184 # CUSTOM ROUTES HERE
185 #==========================================================================
185 #==========================================================================
186
186
187 # MAIN PAGE
187 # MAIN PAGE
188 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
188 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
189
189
190 # ping and pylons error test
190 # ping and pylons error test
191 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
191 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
192 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
192 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
193
193
194 # ADMIN REPOSITORY ROUTES
194 # ADMIN REPOSITORY ROUTES
195 with rmap.submapper(path_prefix=ADMIN_PREFIX,
195 with rmap.submapper(path_prefix=ADMIN_PREFIX,
196 controller='admin/repos') as m:
196 controller='admin/repos') as m:
197 m.connect('repos', '/repos',
197 m.connect('repos', '/repos',
198 action='create', conditions={'method': ['POST']})
198 action='create', conditions={'method': ['POST']})
199 m.connect('repos', '/repos',
199 m.connect('repos', '/repos',
200 action='index', conditions={'method': ['GET']})
200 action='index', conditions={'method': ['GET']})
201 m.connect('new_repo', '/create_repository', jsroute=True,
201 m.connect('new_repo', '/create_repository', jsroute=True,
202 action='create_repository', conditions={'method': ['GET']})
202 action='create_repository', conditions={'method': ['GET']})
203 m.connect('delete_repo', '/repos/{repo_name}',
203 m.connect('delete_repo', '/repos/{repo_name}',
204 action='delete', conditions={'method': ['DELETE']},
204 action='delete', conditions={'method': ['DELETE']},
205 requirements=URL_NAME_REQUIREMENTS)
205 requirements=URL_NAME_REQUIREMENTS)
206 m.connect('repo', '/repos/{repo_name}',
206 m.connect('repo', '/repos/{repo_name}',
207 action='show', conditions={'method': ['GET'],
207 action='show', conditions={'method': ['GET'],
208 'function': check_repo},
208 'function': check_repo},
209 requirements=URL_NAME_REQUIREMENTS)
209 requirements=URL_NAME_REQUIREMENTS)
210
210
211 # ADMIN REPOSITORY GROUPS ROUTES
211 # ADMIN REPOSITORY GROUPS ROUTES
212 with rmap.submapper(path_prefix=ADMIN_PREFIX,
212 with rmap.submapper(path_prefix=ADMIN_PREFIX,
213 controller='admin/repo_groups') as m:
213 controller='admin/repo_groups') as m:
214 m.connect('repo_groups', '/repo_groups',
214 m.connect('repo_groups', '/repo_groups',
215 action='create', conditions={'method': ['POST']})
215 action='create', conditions={'method': ['POST']})
216 m.connect('repo_groups', '/repo_groups',
216 m.connect('repo_groups', '/repo_groups',
217 action='index', conditions={'method': ['GET']})
217 action='index', conditions={'method': ['GET']})
218 m.connect('new_repo_group', '/repo_groups/new',
218 m.connect('new_repo_group', '/repo_groups/new',
219 action='new', conditions={'method': ['GET']})
219 action='new', conditions={'method': ['GET']})
220 m.connect('update_repo_group', '/repo_groups/{group_name}',
220 m.connect('update_repo_group', '/repo_groups/{group_name}',
221 action='update', conditions={'method': ['PUT'],
221 action='update', conditions={'method': ['PUT'],
222 'function': check_group},
222 'function': check_group},
223 requirements=URL_NAME_REQUIREMENTS)
223 requirements=URL_NAME_REQUIREMENTS)
224
224
225 # EXTRAS REPO GROUP ROUTES
225 # EXTRAS REPO GROUP ROUTES
226 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
226 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
227 action='edit',
227 action='edit',
228 conditions={'method': ['GET'], 'function': check_group},
228 conditions={'method': ['GET'], 'function': check_group},
229 requirements=URL_NAME_REQUIREMENTS)
229 requirements=URL_NAME_REQUIREMENTS)
230 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
230 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
231 action='edit',
231 action='edit',
232 conditions={'method': ['PUT'], 'function': check_group},
232 conditions={'method': ['PUT'], 'function': check_group},
233 requirements=URL_NAME_REQUIREMENTS)
233 requirements=URL_NAME_REQUIREMENTS)
234
234
235 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
235 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
236 action='edit_repo_group_advanced',
236 action='edit_repo_group_advanced',
237 conditions={'method': ['GET'], 'function': check_group},
237 conditions={'method': ['GET'], 'function': check_group},
238 requirements=URL_NAME_REQUIREMENTS)
238 requirements=URL_NAME_REQUIREMENTS)
239 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
239 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
240 action='edit_repo_group_advanced',
240 action='edit_repo_group_advanced',
241 conditions={'method': ['PUT'], 'function': check_group},
241 conditions={'method': ['PUT'], 'function': check_group},
242 requirements=URL_NAME_REQUIREMENTS)
242 requirements=URL_NAME_REQUIREMENTS)
243
243
244 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
244 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
245 action='edit_repo_group_perms',
245 action='edit_repo_group_perms',
246 conditions={'method': ['GET'], 'function': check_group},
246 conditions={'method': ['GET'], 'function': check_group},
247 requirements=URL_NAME_REQUIREMENTS)
247 requirements=URL_NAME_REQUIREMENTS)
248 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
248 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
249 action='update_perms',
249 action='update_perms',
250 conditions={'method': ['PUT'], 'function': check_group},
250 conditions={'method': ['PUT'], 'function': check_group},
251 requirements=URL_NAME_REQUIREMENTS)
251 requirements=URL_NAME_REQUIREMENTS)
252
252
253 m.connect('delete_repo_group', '/repo_groups/{group_name}',
253 m.connect('delete_repo_group', '/repo_groups/{group_name}',
254 action='delete', conditions={'method': ['DELETE'],
254 action='delete', conditions={'method': ['DELETE'],
255 'function': check_group},
255 'function': check_group},
256 requirements=URL_NAME_REQUIREMENTS)
256 requirements=URL_NAME_REQUIREMENTS)
257
257
258 # ADMIN USER ROUTES
258 # ADMIN USER ROUTES
259 with rmap.submapper(path_prefix=ADMIN_PREFIX,
259 with rmap.submapper(path_prefix=ADMIN_PREFIX,
260 controller='admin/users') as m:
260 controller='admin/users') as m:
261 m.connect('users', '/users',
261 m.connect('users', '/users',
262 action='create', conditions={'method': ['POST']})
262 action='create', conditions={'method': ['POST']})
263 m.connect('new_user', '/users/new',
263 m.connect('new_user', '/users/new',
264 action='new', conditions={'method': ['GET']})
264 action='new', conditions={'method': ['GET']})
265 m.connect('update_user', '/users/{user_id}',
265 m.connect('update_user', '/users/{user_id}',
266 action='update', conditions={'method': ['PUT']})
266 action='update', conditions={'method': ['PUT']})
267 m.connect('delete_user', '/users/{user_id}',
267 m.connect('delete_user', '/users/{user_id}',
268 action='delete', conditions={'method': ['DELETE']})
268 action='delete', conditions={'method': ['DELETE']})
269 m.connect('edit_user', '/users/{user_id}/edit',
269 m.connect('edit_user', '/users/{user_id}/edit',
270 action='edit', conditions={'method': ['GET']}, jsroute=True)
270 action='edit', conditions={'method': ['GET']}, jsroute=True)
271 m.connect('user', '/users/{user_id}',
271 m.connect('user', '/users/{user_id}',
272 action='show', conditions={'method': ['GET']})
272 action='show', conditions={'method': ['GET']})
273 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
273 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
274 action='reset_password', conditions={'method': ['POST']})
274 action='reset_password', conditions={'method': ['POST']})
275 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
275 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
276 action='create_personal_repo_group', conditions={'method': ['POST']})
276 action='create_personal_repo_group', conditions={'method': ['POST']})
277
277
278 # EXTRAS USER ROUTES
278 # EXTRAS USER ROUTES
279 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
279 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
280 action='edit_advanced', conditions={'method': ['GET']})
280 action='edit_advanced', conditions={'method': ['GET']})
281 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
281 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
282 action='update_advanced', conditions={'method': ['PUT']})
282 action='update_advanced', conditions={'method': ['PUT']})
283
283
284 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
284 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
285 action='edit_global_perms', conditions={'method': ['GET']})
285 action='edit_global_perms', conditions={'method': ['GET']})
286 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
286 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
287 action='update_global_perms', conditions={'method': ['PUT']})
287 action='update_global_perms', conditions={'method': ['PUT']})
288
288
289 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
289 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
290 action='edit_perms_summary', conditions={'method': ['GET']})
290 action='edit_perms_summary', conditions={'method': ['GET']})
291
291
292 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
292 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
293 action='edit_emails', conditions={'method': ['GET']})
293 action='edit_emails', conditions={'method': ['GET']})
294 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
294 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
295 action='add_email', conditions={'method': ['PUT']})
295 action='add_email', conditions={'method': ['PUT']})
296 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
296 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
297 action='delete_email', conditions={'method': ['DELETE']})
297 action='delete_email', conditions={'method': ['DELETE']})
298
298
299 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
299 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
300 action='edit_ips', conditions={'method': ['GET']})
300 action='edit_ips', conditions={'method': ['GET']})
301 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
301 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
302 action='add_ip', conditions={'method': ['PUT']})
302 action='add_ip', conditions={'method': ['PUT']})
303 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
303 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
304 action='delete_ip', conditions={'method': ['DELETE']})
304 action='delete_ip', conditions={'method': ['DELETE']})
305
305
306 # ADMIN USER GROUPS REST ROUTES
306 # ADMIN USER GROUPS REST ROUTES
307 with rmap.submapper(path_prefix=ADMIN_PREFIX,
307 with rmap.submapper(path_prefix=ADMIN_PREFIX,
308 controller='admin/user_groups') as m:
308 controller='admin/user_groups') as m:
309 m.connect('users_groups', '/user_groups',
309 m.connect('users_groups', '/user_groups',
310 action='create', conditions={'method': ['POST']})
310 action='create', conditions={'method': ['POST']})
311 m.connect('users_groups', '/user_groups',
311 m.connect('users_groups', '/user_groups',
312 action='index', conditions={'method': ['GET']})
312 action='index', conditions={'method': ['GET']})
313 m.connect('new_users_group', '/user_groups/new',
313 m.connect('new_users_group', '/user_groups/new',
314 action='new', conditions={'method': ['GET']})
314 action='new', conditions={'method': ['GET']})
315 m.connect('update_users_group', '/user_groups/{user_group_id}',
315 m.connect('update_users_group', '/user_groups/{user_group_id}',
316 action='update', conditions={'method': ['PUT']})
316 action='update', conditions={'method': ['PUT']})
317 m.connect('delete_users_group', '/user_groups/{user_group_id}',
317 m.connect('delete_users_group', '/user_groups/{user_group_id}',
318 action='delete', conditions={'method': ['DELETE']})
318 action='delete', conditions={'method': ['DELETE']})
319 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
319 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
320 action='edit', conditions={'method': ['GET']},
320 action='edit', conditions={'method': ['GET']},
321 function=check_user_group)
321 function=check_user_group)
322
322
323 # EXTRAS USER GROUP ROUTES
323 # EXTRAS USER GROUP ROUTES
324 m.connect('edit_user_group_global_perms',
324 m.connect('edit_user_group_global_perms',
325 '/user_groups/{user_group_id}/edit/global_permissions',
325 '/user_groups/{user_group_id}/edit/global_permissions',
326 action='edit_global_perms', conditions={'method': ['GET']})
326 action='edit_global_perms', conditions={'method': ['GET']})
327 m.connect('edit_user_group_global_perms',
327 m.connect('edit_user_group_global_perms',
328 '/user_groups/{user_group_id}/edit/global_permissions',
328 '/user_groups/{user_group_id}/edit/global_permissions',
329 action='update_global_perms', conditions={'method': ['PUT']})
329 action='update_global_perms', conditions={'method': ['PUT']})
330 m.connect('edit_user_group_perms_summary',
330 m.connect('edit_user_group_perms_summary',
331 '/user_groups/{user_group_id}/edit/permissions_summary',
331 '/user_groups/{user_group_id}/edit/permissions_summary',
332 action='edit_perms_summary', conditions={'method': ['GET']})
332 action='edit_perms_summary', conditions={'method': ['GET']})
333
333
334 m.connect('edit_user_group_perms',
334 m.connect('edit_user_group_perms',
335 '/user_groups/{user_group_id}/edit/permissions',
335 '/user_groups/{user_group_id}/edit/permissions',
336 action='edit_perms', conditions={'method': ['GET']})
336 action='edit_perms', conditions={'method': ['GET']})
337 m.connect('edit_user_group_perms',
337 m.connect('edit_user_group_perms',
338 '/user_groups/{user_group_id}/edit/permissions',
338 '/user_groups/{user_group_id}/edit/permissions',
339 action='update_perms', conditions={'method': ['PUT']})
339 action='update_perms', conditions={'method': ['PUT']})
340
340
341 m.connect('edit_user_group_advanced',
341 m.connect('edit_user_group_advanced',
342 '/user_groups/{user_group_id}/edit/advanced',
342 '/user_groups/{user_group_id}/edit/advanced',
343 action='edit_advanced', conditions={'method': ['GET']})
343 action='edit_advanced', conditions={'method': ['GET']})
344
344
345 m.connect('edit_user_group_advanced_sync',
345 m.connect('edit_user_group_advanced_sync',
346 '/user_groups/{user_group_id}/edit/advanced/sync',
346 '/user_groups/{user_group_id}/edit/advanced/sync',
347 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
347 action='edit_advanced_set_synchronization', conditions={'method': ['POST']})
348
348
349 m.connect('edit_user_group_members',
349 m.connect('edit_user_group_members',
350 '/user_groups/{user_group_id}/edit/members', jsroute=True,
350 '/user_groups/{user_group_id}/edit/members', jsroute=True,
351 action='user_group_members', conditions={'method': ['GET']})
351 action='user_group_members', conditions={'method': ['GET']})
352
352
353 # ADMIN PERMISSIONS ROUTES
353 # ADMIN PERMISSIONS ROUTES
354 with rmap.submapper(path_prefix=ADMIN_PREFIX,
354 with rmap.submapper(path_prefix=ADMIN_PREFIX,
355 controller='admin/permissions') as m:
355 controller='admin/permissions') as m:
356 m.connect('admin_permissions_application', '/permissions/application',
356 m.connect('admin_permissions_application', '/permissions/application',
357 action='permission_application_update', conditions={'method': ['POST']})
357 action='permission_application_update', conditions={'method': ['POST']})
358 m.connect('admin_permissions_application', '/permissions/application',
358 m.connect('admin_permissions_application', '/permissions/application',
359 action='permission_application', conditions={'method': ['GET']})
359 action='permission_application', conditions={'method': ['GET']})
360
360
361 m.connect('admin_permissions_global', '/permissions/global',
361 m.connect('admin_permissions_global', '/permissions/global',
362 action='permission_global_update', conditions={'method': ['POST']})
362 action='permission_global_update', conditions={'method': ['POST']})
363 m.connect('admin_permissions_global', '/permissions/global',
363 m.connect('admin_permissions_global', '/permissions/global',
364 action='permission_global', conditions={'method': ['GET']})
364 action='permission_global', conditions={'method': ['GET']})
365
365
366 m.connect('admin_permissions_object', '/permissions/object',
366 m.connect('admin_permissions_object', '/permissions/object',
367 action='permission_objects_update', conditions={'method': ['POST']})
367 action='permission_objects_update', conditions={'method': ['POST']})
368 m.connect('admin_permissions_object', '/permissions/object',
368 m.connect('admin_permissions_object', '/permissions/object',
369 action='permission_objects', conditions={'method': ['GET']})
369 action='permission_objects', conditions={'method': ['GET']})
370
370
371 m.connect('admin_permissions_ips', '/permissions/ips',
371 m.connect('admin_permissions_ips', '/permissions/ips',
372 action='permission_ips', conditions={'method': ['POST']})
372 action='permission_ips', conditions={'method': ['POST']})
373 m.connect('admin_permissions_ips', '/permissions/ips',
373 m.connect('admin_permissions_ips', '/permissions/ips',
374 action='permission_ips', conditions={'method': ['GET']})
374 action='permission_ips', conditions={'method': ['GET']})
375
375
376 m.connect('admin_permissions_overview', '/permissions/overview',
376 m.connect('admin_permissions_overview', '/permissions/overview',
377 action='permission_perms', conditions={'method': ['GET']})
377 action='permission_perms', conditions={'method': ['GET']})
378
378
379 # ADMIN DEFAULTS REST ROUTES
379 # ADMIN DEFAULTS REST ROUTES
380 with rmap.submapper(path_prefix=ADMIN_PREFIX,
380 with rmap.submapper(path_prefix=ADMIN_PREFIX,
381 controller='admin/defaults') as m:
381 controller='admin/defaults') as m:
382 m.connect('admin_defaults_repositories', '/defaults/repositories',
382 m.connect('admin_defaults_repositories', '/defaults/repositories',
383 action='update_repository_defaults', conditions={'method': ['POST']})
383 action='update_repository_defaults', conditions={'method': ['POST']})
384 m.connect('admin_defaults_repositories', '/defaults/repositories',
384 m.connect('admin_defaults_repositories', '/defaults/repositories',
385 action='index', conditions={'method': ['GET']})
385 action='index', conditions={'method': ['GET']})
386
386
387 # ADMIN DEBUG STYLE ROUTES
387 # ADMIN DEBUG STYLE ROUTES
388 if str2bool(config.get('debug_style')):
388 if str2bool(config.get('debug_style')):
389 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
389 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
390 controller='debug_style') as m:
390 controller='debug_style') as m:
391 m.connect('debug_style_home', '',
391 m.connect('debug_style_home', '',
392 action='index', conditions={'method': ['GET']})
392 action='index', conditions={'method': ['GET']})
393 m.connect('debug_style_template', '/t/{t_path}',
393 m.connect('debug_style_template', '/t/{t_path}',
394 action='template', conditions={'method': ['GET']})
394 action='template', conditions={'method': ['GET']})
395
395
396 # ADMIN SETTINGS ROUTES
396 # ADMIN SETTINGS ROUTES
397 with rmap.submapper(path_prefix=ADMIN_PREFIX,
397 with rmap.submapper(path_prefix=ADMIN_PREFIX,
398 controller='admin/settings') as m:
398 controller='admin/settings') as m:
399
399
400 # default
400 # default
401 m.connect('admin_settings', '/settings',
401 m.connect('admin_settings', '/settings',
402 action='settings_global_update',
402 action='settings_global_update',
403 conditions={'method': ['POST']})
403 conditions={'method': ['POST']})
404 m.connect('admin_settings', '/settings',
404 m.connect('admin_settings', '/settings',
405 action='settings_global', conditions={'method': ['GET']})
405 action='settings_global', conditions={'method': ['GET']})
406
406
407 m.connect('admin_settings_vcs', '/settings/vcs',
407 m.connect('admin_settings_vcs', '/settings/vcs',
408 action='settings_vcs_update',
408 action='settings_vcs_update',
409 conditions={'method': ['POST']})
409 conditions={'method': ['POST']})
410 m.connect('admin_settings_vcs', '/settings/vcs',
410 m.connect('admin_settings_vcs', '/settings/vcs',
411 action='settings_vcs',
411 action='settings_vcs',
412 conditions={'method': ['GET']})
412 conditions={'method': ['GET']})
413 m.connect('admin_settings_vcs', '/settings/vcs',
413 m.connect('admin_settings_vcs', '/settings/vcs',
414 action='delete_svn_pattern',
414 action='delete_svn_pattern',
415 conditions={'method': ['DELETE']})
415 conditions={'method': ['DELETE']})
416
416
417 m.connect('admin_settings_mapping', '/settings/mapping',
417 m.connect('admin_settings_mapping', '/settings/mapping',
418 action='settings_mapping_update',
418 action='settings_mapping_update',
419 conditions={'method': ['POST']})
419 conditions={'method': ['POST']})
420 m.connect('admin_settings_mapping', '/settings/mapping',
420 m.connect('admin_settings_mapping', '/settings/mapping',
421 action='settings_mapping', conditions={'method': ['GET']})
421 action='settings_mapping', conditions={'method': ['GET']})
422
422
423 m.connect('admin_settings_global', '/settings/global',
423 m.connect('admin_settings_global', '/settings/global',
424 action='settings_global_update',
424 action='settings_global_update',
425 conditions={'method': ['POST']})
425 conditions={'method': ['POST']})
426 m.connect('admin_settings_global', '/settings/global',
426 m.connect('admin_settings_global', '/settings/global',
427 action='settings_global', conditions={'method': ['GET']})
427 action='settings_global', conditions={'method': ['GET']})
428
428
429 m.connect('admin_settings_visual', '/settings/visual',
429 m.connect('admin_settings_visual', '/settings/visual',
430 action='settings_visual_update',
430 action='settings_visual_update',
431 conditions={'method': ['POST']})
431 conditions={'method': ['POST']})
432 m.connect('admin_settings_visual', '/settings/visual',
432 m.connect('admin_settings_visual', '/settings/visual',
433 action='settings_visual', conditions={'method': ['GET']})
433 action='settings_visual', conditions={'method': ['GET']})
434
434
435 m.connect('admin_settings_issuetracker',
435 m.connect('admin_settings_issuetracker',
436 '/settings/issue-tracker', action='settings_issuetracker',
436 '/settings/issue-tracker', action='settings_issuetracker',
437 conditions={'method': ['GET']})
437 conditions={'method': ['GET']})
438 m.connect('admin_settings_issuetracker_save',
438 m.connect('admin_settings_issuetracker_save',
439 '/settings/issue-tracker/save',
439 '/settings/issue-tracker/save',
440 action='settings_issuetracker_save',
440 action='settings_issuetracker_save',
441 conditions={'method': ['POST']})
441 conditions={'method': ['POST']})
442 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
442 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
443 action='settings_issuetracker_test',
443 action='settings_issuetracker_test',
444 conditions={'method': ['POST']})
444 conditions={'method': ['POST']})
445 m.connect('admin_issuetracker_delete',
445 m.connect('admin_issuetracker_delete',
446 '/settings/issue-tracker/delete',
446 '/settings/issue-tracker/delete',
447 action='settings_issuetracker_delete',
447 action='settings_issuetracker_delete',
448 conditions={'method': ['DELETE']})
448 conditions={'method': ['DELETE']})
449
449
450 m.connect('admin_settings_email', '/settings/email',
450 m.connect('admin_settings_email', '/settings/email',
451 action='settings_email_update',
451 action='settings_email_update',
452 conditions={'method': ['POST']})
452 conditions={'method': ['POST']})
453 m.connect('admin_settings_email', '/settings/email',
453 m.connect('admin_settings_email', '/settings/email',
454 action='settings_email', conditions={'method': ['GET']})
454 action='settings_email', conditions={'method': ['GET']})
455
455
456 m.connect('admin_settings_hooks', '/settings/hooks',
456 m.connect('admin_settings_hooks', '/settings/hooks',
457 action='settings_hooks_update',
457 action='settings_hooks_update',
458 conditions={'method': ['POST', 'DELETE']})
458 conditions={'method': ['POST', 'DELETE']})
459 m.connect('admin_settings_hooks', '/settings/hooks',
459 m.connect('admin_settings_hooks', '/settings/hooks',
460 action='settings_hooks', conditions={'method': ['GET']})
460 action='settings_hooks', conditions={'method': ['GET']})
461
461
462 m.connect('admin_settings_search', '/settings/search',
462 m.connect('admin_settings_search', '/settings/search',
463 action='settings_search', conditions={'method': ['GET']})
463 action='settings_search', conditions={'method': ['GET']})
464
464
465 m.connect('admin_settings_supervisor', '/settings/supervisor',
465 m.connect('admin_settings_supervisor', '/settings/supervisor',
466 action='settings_supervisor', conditions={'method': ['GET']})
466 action='settings_supervisor', conditions={'method': ['GET']})
467 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
467 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
468 action='settings_supervisor_log', conditions={'method': ['GET']})
468 action='settings_supervisor_log', conditions={'method': ['GET']})
469
469
470 m.connect('admin_settings_labs', '/settings/labs',
470 m.connect('admin_settings_labs', '/settings/labs',
471 action='settings_labs_update',
471 action='settings_labs_update',
472 conditions={'method': ['POST']})
472 conditions={'method': ['POST']})
473 m.connect('admin_settings_labs', '/settings/labs',
473 m.connect('admin_settings_labs', '/settings/labs',
474 action='settings_labs', conditions={'method': ['GET']})
474 action='settings_labs', conditions={'method': ['GET']})
475
475
476 # ADMIN MY ACCOUNT
476 # ADMIN MY ACCOUNT
477 with rmap.submapper(path_prefix=ADMIN_PREFIX,
477 with rmap.submapper(path_prefix=ADMIN_PREFIX,
478 controller='admin/my_account') as m:
478 controller='admin/my_account') as m:
479
479
480 m.connect('my_account_edit', '/my_account/edit',
480 m.connect('my_account_edit', '/my_account/edit',
481 action='my_account_edit', conditions={'method': ['GET']})
481 action='my_account_edit', conditions={'method': ['GET']})
482 m.connect('my_account', '/my_account/update',
482 m.connect('my_account', '/my_account/update',
483 action='my_account_update', conditions={'method': ['POST']})
483 action='my_account_update', conditions={'method': ['POST']})
484
484
485 # NOTE(marcink): this needs to be kept for password force flag to be
485 # NOTE(marcink): this needs to be kept for password force flag to be
486 # handler, remove after migration to pyramid
486 # handler, remove after migration to pyramid
487 m.connect('my_account_password', '/my_account/password',
487 m.connect('my_account_password', '/my_account/password',
488 action='my_account_password', conditions={'method': ['GET']})
488 action='my_account_password', conditions={'method': ['GET']})
489
489
490 m.connect('my_account_repos', '/my_account/repos',
490 m.connect('my_account_repos', '/my_account/repos',
491 action='my_account_repos', conditions={'method': ['GET']})
491 action='my_account_repos', conditions={'method': ['GET']})
492
492
493 m.connect('my_account_watched', '/my_account/watched',
493 m.connect('my_account_watched', '/my_account/watched',
494 action='my_account_watched', conditions={'method': ['GET']})
494 action='my_account_watched', conditions={'method': ['GET']})
495
495
496 m.connect('my_account_pullrequests', '/my_account/pull_requests',
496 m.connect('my_account_pullrequests', '/my_account/pull_requests',
497 action='my_account_pullrequests', conditions={'method': ['GET']})
497 action='my_account_pullrequests', conditions={'method': ['GET']})
498
498
499 m.connect('my_account_perms', '/my_account/perms',
499 m.connect('my_account_perms', '/my_account/perms',
500 action='my_account_perms', conditions={'method': ['GET']})
500 action='my_account_perms', conditions={'method': ['GET']})
501
501
502 m.connect('my_account_emails', '/my_account/emails',
502 m.connect('my_account_emails', '/my_account/emails',
503 action='my_account_emails', conditions={'method': ['GET']})
503 action='my_account_emails', conditions={'method': ['GET']})
504 m.connect('my_account_emails', '/my_account/emails',
504 m.connect('my_account_emails', '/my_account/emails',
505 action='my_account_emails_add', conditions={'method': ['POST']})
505 action='my_account_emails_add', conditions={'method': ['POST']})
506 m.connect('my_account_emails', '/my_account/emails',
506 m.connect('my_account_emails', '/my_account/emails',
507 action='my_account_emails_delete', conditions={'method': ['DELETE']})
507 action='my_account_emails_delete', conditions={'method': ['DELETE']})
508
508
509 m.connect('my_account_notifications', '/my_account/notifications',
509 m.connect('my_account_notifications', '/my_account/notifications',
510 action='my_notifications',
510 action='my_notifications',
511 conditions={'method': ['GET']})
511 conditions={'method': ['GET']})
512 m.connect('my_account_notifications_toggle_visibility',
512 m.connect('my_account_notifications_toggle_visibility',
513 '/my_account/toggle_visibility',
513 '/my_account/toggle_visibility',
514 action='my_notifications_toggle_visibility',
514 action='my_notifications_toggle_visibility',
515 conditions={'method': ['POST']})
515 conditions={'method': ['POST']})
516 m.connect('my_account_notifications_test_channelstream',
516 m.connect('my_account_notifications_test_channelstream',
517 '/my_account/test_channelstream',
517 '/my_account/test_channelstream',
518 action='my_account_notifications_test_channelstream',
518 action='my_account_notifications_test_channelstream',
519 conditions={'method': ['POST']})
519 conditions={'method': ['POST']})
520
520
521 # NOTIFICATION REST ROUTES
521 # NOTIFICATION REST ROUTES
522 with rmap.submapper(path_prefix=ADMIN_PREFIX,
522 with rmap.submapper(path_prefix=ADMIN_PREFIX,
523 controller='admin/notifications') as m:
523 controller='admin/notifications') as m:
524 m.connect('notifications', '/notifications',
524 m.connect('notifications', '/notifications',
525 action='index', conditions={'method': ['GET']})
525 action='index', conditions={'method': ['GET']})
526 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
526 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
527 action='mark_all_read', conditions={'method': ['POST']})
527 action='mark_all_read', conditions={'method': ['POST']})
528 m.connect('/notifications/{notification_id}',
528 m.connect('/notifications/{notification_id}',
529 action='update', conditions={'method': ['PUT']})
529 action='update', conditions={'method': ['PUT']})
530 m.connect('/notifications/{notification_id}',
530 m.connect('/notifications/{notification_id}',
531 action='delete', conditions={'method': ['DELETE']})
531 action='delete', conditions={'method': ['DELETE']})
532 m.connect('notification', '/notifications/{notification_id}',
532 m.connect('notification', '/notifications/{notification_id}',
533 action='show', conditions={'method': ['GET']})
533 action='show', conditions={'method': ['GET']})
534
534
535 # ADMIN GIST
535 # ADMIN GIST
536 with rmap.submapper(path_prefix=ADMIN_PREFIX,
536 with rmap.submapper(path_prefix=ADMIN_PREFIX,
537 controller='admin/gists') as m:
537 controller='admin/gists') as m:
538 m.connect('gists', '/gists',
538 m.connect('gists', '/gists',
539 action='create', conditions={'method': ['POST']})
539 action='create', conditions={'method': ['POST']})
540 m.connect('gists', '/gists', jsroute=True,
540 m.connect('gists', '/gists', jsroute=True,
541 action='index', conditions={'method': ['GET']})
541 action='index', conditions={'method': ['GET']})
542 m.connect('new_gist', '/gists/new', jsroute=True,
542 m.connect('new_gist', '/gists/new', jsroute=True,
543 action='new', conditions={'method': ['GET']})
543 action='new', conditions={'method': ['GET']})
544
544
545 m.connect('/gists/{gist_id}',
545 m.connect('/gists/{gist_id}',
546 action='delete', conditions={'method': ['DELETE']})
546 action='delete', conditions={'method': ['DELETE']})
547 m.connect('edit_gist', '/gists/{gist_id}/edit',
547 m.connect('edit_gist', '/gists/{gist_id}/edit',
548 action='edit_form', conditions={'method': ['GET']})
548 action='edit_form', conditions={'method': ['GET']})
549 m.connect('edit_gist', '/gists/{gist_id}/edit',
549 m.connect('edit_gist', '/gists/{gist_id}/edit',
550 action='edit', conditions={'method': ['POST']})
550 action='edit', conditions={'method': ['POST']})
551 m.connect(
551 m.connect(
552 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
552 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
553 action='check_revision', conditions={'method': ['GET']})
553 action='check_revision', conditions={'method': ['GET']})
554
554
555 m.connect('gist', '/gists/{gist_id}',
555 m.connect('gist', '/gists/{gist_id}',
556 action='show', conditions={'method': ['GET']})
556 action='show', conditions={'method': ['GET']})
557 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
557 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
558 revision='tip',
558 revision='tip',
559 action='show', conditions={'method': ['GET']})
559 action='show', conditions={'method': ['GET']})
560 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
560 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
561 revision='tip',
561 revision='tip',
562 action='show', conditions={'method': ['GET']})
562 action='show', conditions={'method': ['GET']})
563 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
563 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
564 revision='tip',
564 revision='tip',
565 action='show', conditions={'method': ['GET']},
565 action='show', conditions={'method': ['GET']},
566 requirements=URL_NAME_REQUIREMENTS)
566 requirements=URL_NAME_REQUIREMENTS)
567
567
568 # ADMIN MAIN PAGES
568 # ADMIN MAIN PAGES
569 with rmap.submapper(path_prefix=ADMIN_PREFIX,
569 with rmap.submapper(path_prefix=ADMIN_PREFIX,
570 controller='admin/admin') as m:
570 controller='admin/admin') as m:
571 m.connect('admin_home', '', action='index')
571 m.connect('admin_home', '', action='index')
572 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
572 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
573 action='add_repo')
573 action='add_repo')
574 m.connect(
574 m.connect(
575 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
575 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
576 action='pull_requests')
576 action='pull_requests')
577 m.connect(
577 m.connect(
578 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
578 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
579 action='pull_requests')
579 action='pull_requests')
580 m.connect(
580 m.connect(
581 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
581 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
582 action='pull_requests')
582 action='pull_requests')
583
583
584 # USER JOURNAL
584 # USER JOURNAL
585 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
585 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
586 controller='journal', action='index')
586 controller='journal', action='index')
587 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
587 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
588 controller='journal', action='journal_rss')
588 controller='journal', action='journal_rss')
589 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
589 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
590 controller='journal', action='journal_atom')
590 controller='journal', action='journal_atom')
591
591
592 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
592 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
593 controller='journal', action='public_journal')
593 controller='journal', action='public_journal')
594
594
595 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
595 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
596 controller='journal', action='public_journal_rss')
596 controller='journal', action='public_journal_rss')
597
597
598 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
598 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
599 controller='journal', action='public_journal_rss')
599 controller='journal', action='public_journal_rss')
600
600
601 rmap.connect('public_journal_atom',
601 rmap.connect('public_journal_atom',
602 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
602 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
603 action='public_journal_atom')
603 action='public_journal_atom')
604
604
605 rmap.connect('public_journal_atom_old',
605 rmap.connect('public_journal_atom_old',
606 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
606 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
607 action='public_journal_atom')
607 action='public_journal_atom')
608
608
609 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
609 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
610 controller='journal', action='toggle_following', jsroute=True,
610 controller='journal', action='toggle_following', jsroute=True,
611 conditions={'method': ['POST']})
611 conditions={'method': ['POST']})
612
612
613 # FEEDS
613 # FEEDS
614 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
614 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
615 controller='feed', action='rss',
615 controller='feed', action='rss',
616 conditions={'function': check_repo},
616 conditions={'function': check_repo},
617 requirements=URL_NAME_REQUIREMENTS)
617 requirements=URL_NAME_REQUIREMENTS)
618
618
619 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
619 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
620 controller='feed', action='atom',
620 controller='feed', action='atom',
621 conditions={'function': check_repo},
621 conditions={'function': check_repo},
622 requirements=URL_NAME_REQUIREMENTS)
622 requirements=URL_NAME_REQUIREMENTS)
623
623
624 #==========================================================================
624 #==========================================================================
625 # REPOSITORY ROUTES
625 # REPOSITORY ROUTES
626 #==========================================================================
626 #==========================================================================
627
627
628 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
628 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
629 controller='admin/repos', action='repo_creating',
629 controller='admin/repos', action='repo_creating',
630 requirements=URL_NAME_REQUIREMENTS)
630 requirements=URL_NAME_REQUIREMENTS)
631 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
631 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
632 controller='admin/repos', action='repo_check',
632 controller='admin/repos', action='repo_check',
633 requirements=URL_NAME_REQUIREMENTS)
633 requirements=URL_NAME_REQUIREMENTS)
634
634
635 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
635 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
636 controller='summary', action='repo_stats',
636 controller='summary', action='repo_stats',
637 conditions={'function': check_repo},
637 conditions={'function': check_repo},
638 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
638 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
639
639
640 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
640 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
641 controller='summary', action='repo_refs_data',
641 controller='summary', action='repo_refs_data',
642 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
642 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
643 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
643 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
644 controller='summary', action='repo_refs_changelog_data',
644 controller='summary', action='repo_refs_changelog_data',
645 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
645 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
646 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
646 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
647 controller='summary', action='repo_default_reviewers_data',
647 controller='summary', action='repo_default_reviewers_data',
648 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
648 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
649
649
650 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
650 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
651 controller='changeset', revision='tip',
651 controller='changeset', revision='tip',
652 conditions={'function': check_repo},
652 conditions={'function': check_repo},
653 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
653 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
654 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
654 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
655 controller='changeset', revision='tip', action='changeset_children',
655 controller='changeset', revision='tip', action='changeset_children',
656 conditions={'function': check_repo},
656 conditions={'function': check_repo},
657 requirements=URL_NAME_REQUIREMENTS)
657 requirements=URL_NAME_REQUIREMENTS)
658 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
658 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
659 controller='changeset', revision='tip', action='changeset_parents',
659 controller='changeset', revision='tip', action='changeset_parents',
660 conditions={'function': check_repo},
660 conditions={'function': check_repo},
661 requirements=URL_NAME_REQUIREMENTS)
661 requirements=URL_NAME_REQUIREMENTS)
662
662
663 # repo edit options
663 # repo edit options
664 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
664 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
665 jsroute=True,
665 jsroute=True,
666 controller='admin/repos', action='edit_permissions',
666 controller='admin/repos', action='edit_permissions',
667 conditions={'method': ['GET'], 'function': check_repo},
667 conditions={'method': ['GET'], 'function': check_repo},
668 requirements=URL_NAME_REQUIREMENTS)
668 requirements=URL_NAME_REQUIREMENTS)
669 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
669 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
670 controller='admin/repos', action='edit_permissions_update',
670 controller='admin/repos', action='edit_permissions_update',
671 conditions={'method': ['PUT'], 'function': check_repo},
671 conditions={'method': ['PUT'], 'function': check_repo},
672 requirements=URL_NAME_REQUIREMENTS)
672 requirements=URL_NAME_REQUIREMENTS)
673
673
674 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
674 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
675 controller='admin/repos', action='edit_fields',
675 controller='admin/repos', action='edit_fields',
676 conditions={'method': ['GET'], 'function': check_repo},
676 conditions={'method': ['GET'], 'function': check_repo},
677 requirements=URL_NAME_REQUIREMENTS)
677 requirements=URL_NAME_REQUIREMENTS)
678 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
678 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
679 controller='admin/repos', action='create_repo_field',
679 controller='admin/repos', action='create_repo_field',
680 conditions={'method': ['PUT'], 'function': check_repo},
680 conditions={'method': ['PUT'], 'function': check_repo},
681 requirements=URL_NAME_REQUIREMENTS)
681 requirements=URL_NAME_REQUIREMENTS)
682 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
682 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
683 controller='admin/repos', action='delete_repo_field',
683 controller='admin/repos', action='delete_repo_field',
684 conditions={'method': ['DELETE'], 'function': check_repo},
684 conditions={'method': ['DELETE'], 'function': check_repo},
685 requirements=URL_NAME_REQUIREMENTS)
685 requirements=URL_NAME_REQUIREMENTS)
686
686
687 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
687 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
688 controller='admin/repos', action='edit_advanced',
688 controller='admin/repos', action='edit_advanced',
689 conditions={'method': ['GET'], 'function': check_repo},
689 conditions={'method': ['GET'], 'function': check_repo},
690 requirements=URL_NAME_REQUIREMENTS)
690 requirements=URL_NAME_REQUIREMENTS)
691
691
692 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
692 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
693 controller='admin/repos', action='edit_advanced_locking',
693 controller='admin/repos', action='edit_advanced_locking',
694 conditions={'method': ['PUT'], 'function': check_repo},
694 conditions={'method': ['PUT'], 'function': check_repo},
695 requirements=URL_NAME_REQUIREMENTS)
695 requirements=URL_NAME_REQUIREMENTS)
696 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
696 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
697 controller='admin/repos', action='toggle_locking',
697 controller='admin/repos', action='toggle_locking',
698 conditions={'method': ['GET'], 'function': check_repo},
698 conditions={'method': ['GET'], 'function': check_repo},
699 requirements=URL_NAME_REQUIREMENTS)
699 requirements=URL_NAME_REQUIREMENTS)
700
700
701 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
701 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
702 controller='admin/repos', action='edit_advanced_journal',
702 controller='admin/repos', action='edit_advanced_journal',
703 conditions={'method': ['PUT'], 'function': check_repo},
703 conditions={'method': ['PUT'], 'function': check_repo},
704 requirements=URL_NAME_REQUIREMENTS)
704 requirements=URL_NAME_REQUIREMENTS)
705
705
706 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
706 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
707 controller='admin/repos', action='edit_advanced_fork',
707 controller='admin/repos', action='edit_advanced_fork',
708 conditions={'method': ['PUT'], 'function': check_repo},
708 conditions={'method': ['PUT'], 'function': check_repo},
709 requirements=URL_NAME_REQUIREMENTS)
709 requirements=URL_NAME_REQUIREMENTS)
710
710
711 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
712 controller='admin/repos', action='edit_caches_form',
713 conditions={'method': ['GET'], 'function': check_repo},
714 requirements=URL_NAME_REQUIREMENTS)
715 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
716 controller='admin/repos', action='edit_caches',
717 conditions={'method': ['PUT'], 'function': check_repo},
718 requirements=URL_NAME_REQUIREMENTS)
719
720 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
711 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
721 controller='admin/repos', action='edit_remote_form',
712 controller='admin/repos', action='edit_remote_form',
722 conditions={'method': ['GET'], 'function': check_repo},
713 conditions={'method': ['GET'], 'function': check_repo},
723 requirements=URL_NAME_REQUIREMENTS)
714 requirements=URL_NAME_REQUIREMENTS)
724 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
715 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
725 controller='admin/repos', action='edit_remote',
716 controller='admin/repos', action='edit_remote',
726 conditions={'method': ['PUT'], 'function': check_repo},
717 conditions={'method': ['PUT'], 'function': check_repo},
727 requirements=URL_NAME_REQUIREMENTS)
718 requirements=URL_NAME_REQUIREMENTS)
728
719
729 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
720 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
730 controller='admin/repos', action='edit_statistics_form',
721 controller='admin/repos', action='edit_statistics_form',
731 conditions={'method': ['GET'], 'function': check_repo},
722 conditions={'method': ['GET'], 'function': check_repo},
732 requirements=URL_NAME_REQUIREMENTS)
723 requirements=URL_NAME_REQUIREMENTS)
733 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
724 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
734 controller='admin/repos', action='edit_statistics',
725 controller='admin/repos', action='edit_statistics',
735 conditions={'method': ['PUT'], 'function': check_repo},
726 conditions={'method': ['PUT'], 'function': check_repo},
736 requirements=URL_NAME_REQUIREMENTS)
727 requirements=URL_NAME_REQUIREMENTS)
737 rmap.connect('repo_settings_issuetracker',
728 rmap.connect('repo_settings_issuetracker',
738 '/{repo_name}/settings/issue-tracker',
729 '/{repo_name}/settings/issue-tracker',
739 controller='admin/repos', action='repo_issuetracker',
730 controller='admin/repos', action='repo_issuetracker',
740 conditions={'method': ['GET'], 'function': check_repo},
731 conditions={'method': ['GET'], 'function': check_repo},
741 requirements=URL_NAME_REQUIREMENTS)
732 requirements=URL_NAME_REQUIREMENTS)
742 rmap.connect('repo_issuetracker_test',
733 rmap.connect('repo_issuetracker_test',
743 '/{repo_name}/settings/issue-tracker/test',
734 '/{repo_name}/settings/issue-tracker/test',
744 controller='admin/repos', action='repo_issuetracker_test',
735 controller='admin/repos', action='repo_issuetracker_test',
745 conditions={'method': ['POST'], 'function': check_repo},
736 conditions={'method': ['POST'], 'function': check_repo},
746 requirements=URL_NAME_REQUIREMENTS)
737 requirements=URL_NAME_REQUIREMENTS)
747 rmap.connect('repo_issuetracker_delete',
738 rmap.connect('repo_issuetracker_delete',
748 '/{repo_name}/settings/issue-tracker/delete',
739 '/{repo_name}/settings/issue-tracker/delete',
749 controller='admin/repos', action='repo_issuetracker_delete',
740 controller='admin/repos', action='repo_issuetracker_delete',
750 conditions={'method': ['DELETE'], 'function': check_repo},
741 conditions={'method': ['DELETE'], 'function': check_repo},
751 requirements=URL_NAME_REQUIREMENTS)
742 requirements=URL_NAME_REQUIREMENTS)
752 rmap.connect('repo_issuetracker_save',
743 rmap.connect('repo_issuetracker_save',
753 '/{repo_name}/settings/issue-tracker/save',
744 '/{repo_name}/settings/issue-tracker/save',
754 controller='admin/repos', action='repo_issuetracker_save',
745 controller='admin/repos', action='repo_issuetracker_save',
755 conditions={'method': ['POST'], 'function': check_repo},
746 conditions={'method': ['POST'], 'function': check_repo},
756 requirements=URL_NAME_REQUIREMENTS)
747 requirements=URL_NAME_REQUIREMENTS)
757 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
748 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
758 controller='admin/repos', action='repo_settings_vcs_update',
749 controller='admin/repos', action='repo_settings_vcs_update',
759 conditions={'method': ['POST'], 'function': check_repo},
750 conditions={'method': ['POST'], 'function': check_repo},
760 requirements=URL_NAME_REQUIREMENTS)
751 requirements=URL_NAME_REQUIREMENTS)
761 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
752 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
762 controller='admin/repos', action='repo_settings_vcs',
753 controller='admin/repos', action='repo_settings_vcs',
763 conditions={'method': ['GET'], 'function': check_repo},
754 conditions={'method': ['GET'], 'function': check_repo},
764 requirements=URL_NAME_REQUIREMENTS)
755 requirements=URL_NAME_REQUIREMENTS)
765 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
756 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
766 controller='admin/repos', action='repo_delete_svn_pattern',
757 controller='admin/repos', action='repo_delete_svn_pattern',
767 conditions={'method': ['DELETE'], 'function': check_repo},
758 conditions={'method': ['DELETE'], 'function': check_repo},
768 requirements=URL_NAME_REQUIREMENTS)
759 requirements=URL_NAME_REQUIREMENTS)
769 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
760 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
770 controller='admin/repos', action='repo_settings_pullrequest',
761 controller='admin/repos', action='repo_settings_pullrequest',
771 conditions={'method': ['GET', 'POST'], 'function': check_repo},
762 conditions={'method': ['GET', 'POST'], 'function': check_repo},
772 requirements=URL_NAME_REQUIREMENTS)
763 requirements=URL_NAME_REQUIREMENTS)
773
764
774 # still working url for backward compat.
765 # still working url for backward compat.
775 rmap.connect('raw_changeset_home_depraced',
766 rmap.connect('raw_changeset_home_depraced',
776 '/{repo_name}/raw-changeset/{revision}',
767 '/{repo_name}/raw-changeset/{revision}',
777 controller='changeset', action='changeset_raw',
768 controller='changeset', action='changeset_raw',
778 revision='tip', conditions={'function': check_repo},
769 revision='tip', conditions={'function': check_repo},
779 requirements=URL_NAME_REQUIREMENTS)
770 requirements=URL_NAME_REQUIREMENTS)
780
771
781 # new URLs
772 # new URLs
782 rmap.connect('changeset_raw_home',
773 rmap.connect('changeset_raw_home',
783 '/{repo_name}/changeset-diff/{revision}',
774 '/{repo_name}/changeset-diff/{revision}',
784 controller='changeset', action='changeset_raw',
775 controller='changeset', action='changeset_raw',
785 revision='tip', conditions={'function': check_repo},
776 revision='tip', conditions={'function': check_repo},
786 requirements=URL_NAME_REQUIREMENTS)
777 requirements=URL_NAME_REQUIREMENTS)
787
778
788 rmap.connect('changeset_patch_home',
779 rmap.connect('changeset_patch_home',
789 '/{repo_name}/changeset-patch/{revision}',
780 '/{repo_name}/changeset-patch/{revision}',
790 controller='changeset', action='changeset_patch',
781 controller='changeset', action='changeset_patch',
791 revision='tip', conditions={'function': check_repo},
782 revision='tip', conditions={'function': check_repo},
792 requirements=URL_NAME_REQUIREMENTS)
783 requirements=URL_NAME_REQUIREMENTS)
793
784
794 rmap.connect('changeset_download_home',
785 rmap.connect('changeset_download_home',
795 '/{repo_name}/changeset-download/{revision}',
786 '/{repo_name}/changeset-download/{revision}',
796 controller='changeset', action='changeset_download',
787 controller='changeset', action='changeset_download',
797 revision='tip', conditions={'function': check_repo},
788 revision='tip', conditions={'function': check_repo},
798 requirements=URL_NAME_REQUIREMENTS)
789 requirements=URL_NAME_REQUIREMENTS)
799
790
800 rmap.connect('changeset_comment',
791 rmap.connect('changeset_comment',
801 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
792 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
802 controller='changeset', revision='tip', action='comment',
793 controller='changeset', revision='tip', action='comment',
803 conditions={'function': check_repo},
794 conditions={'function': check_repo},
804 requirements=URL_NAME_REQUIREMENTS)
795 requirements=URL_NAME_REQUIREMENTS)
805
796
806 rmap.connect('changeset_comment_preview',
797 rmap.connect('changeset_comment_preview',
807 '/{repo_name}/changeset/comment/preview', jsroute=True,
798 '/{repo_name}/changeset/comment/preview', jsroute=True,
808 controller='changeset', action='preview_comment',
799 controller='changeset', action='preview_comment',
809 conditions={'function': check_repo, 'method': ['POST']},
800 conditions={'function': check_repo, 'method': ['POST']},
810 requirements=URL_NAME_REQUIREMENTS)
801 requirements=URL_NAME_REQUIREMENTS)
811
802
812 rmap.connect('changeset_comment_delete',
803 rmap.connect('changeset_comment_delete',
813 '/{repo_name}/changeset/comment/{comment_id}/delete',
804 '/{repo_name}/changeset/comment/{comment_id}/delete',
814 controller='changeset', action='delete_comment',
805 controller='changeset', action='delete_comment',
815 conditions={'function': check_repo, 'method': ['DELETE']},
806 conditions={'function': check_repo, 'method': ['DELETE']},
816 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
807 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
817
808
818 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
809 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
819 controller='changeset', action='changeset_info',
810 controller='changeset', action='changeset_info',
820 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
811 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
821
812
822 rmap.connect('compare_home',
813 rmap.connect('compare_home',
823 '/{repo_name}/compare',
814 '/{repo_name}/compare',
824 controller='compare', action='index',
815 controller='compare', action='index',
825 conditions={'function': check_repo},
816 conditions={'function': check_repo},
826 requirements=URL_NAME_REQUIREMENTS)
817 requirements=URL_NAME_REQUIREMENTS)
827
818
828 rmap.connect('compare_url',
819 rmap.connect('compare_url',
829 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
820 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
830 controller='compare', action='compare',
821 controller='compare', action='compare',
831 conditions={'function': check_repo},
822 conditions={'function': check_repo},
832 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
823 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
833
824
834 rmap.connect('pullrequest_home',
825 rmap.connect('pullrequest_home',
835 '/{repo_name}/pull-request/new', controller='pullrequests',
826 '/{repo_name}/pull-request/new', controller='pullrequests',
836 action='index', conditions={'function': check_repo,
827 action='index', conditions={'function': check_repo,
837 'method': ['GET']},
828 'method': ['GET']},
838 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
829 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
839
830
840 rmap.connect('pullrequest',
831 rmap.connect('pullrequest',
841 '/{repo_name}/pull-request/new', controller='pullrequests',
832 '/{repo_name}/pull-request/new', controller='pullrequests',
842 action='create', conditions={'function': check_repo,
833 action='create', conditions={'function': check_repo,
843 'method': ['POST']},
834 'method': ['POST']},
844 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
835 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
845
836
846 rmap.connect('pullrequest_repo_refs',
837 rmap.connect('pullrequest_repo_refs',
847 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
838 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
848 controller='pullrequests',
839 controller='pullrequests',
849 action='get_repo_refs',
840 action='get_repo_refs',
850 conditions={'function': check_repo, 'method': ['GET']},
841 conditions={'function': check_repo, 'method': ['GET']},
851 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
842 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
852
843
853 rmap.connect('pullrequest_repo_destinations',
844 rmap.connect('pullrequest_repo_destinations',
854 '/{repo_name}/pull-request/repo-destinations',
845 '/{repo_name}/pull-request/repo-destinations',
855 controller='pullrequests',
846 controller='pullrequests',
856 action='get_repo_destinations',
847 action='get_repo_destinations',
857 conditions={'function': check_repo, 'method': ['GET']},
848 conditions={'function': check_repo, 'method': ['GET']},
858 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
849 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
859
850
860 rmap.connect('pullrequest_show',
851 rmap.connect('pullrequest_show',
861 '/{repo_name}/pull-request/{pull_request_id}',
852 '/{repo_name}/pull-request/{pull_request_id}',
862 controller='pullrequests',
853 controller='pullrequests',
863 action='show', conditions={'function': check_repo,
854 action='show', conditions={'function': check_repo,
864 'method': ['GET']},
855 'method': ['GET']},
865 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
856 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
866
857
867 rmap.connect('pullrequest_update',
858 rmap.connect('pullrequest_update',
868 '/{repo_name}/pull-request/{pull_request_id}',
859 '/{repo_name}/pull-request/{pull_request_id}',
869 controller='pullrequests',
860 controller='pullrequests',
870 action='update', conditions={'function': check_repo,
861 action='update', conditions={'function': check_repo,
871 'method': ['PUT']},
862 'method': ['PUT']},
872 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
863 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
873
864
874 rmap.connect('pullrequest_merge',
865 rmap.connect('pullrequest_merge',
875 '/{repo_name}/pull-request/{pull_request_id}',
866 '/{repo_name}/pull-request/{pull_request_id}',
876 controller='pullrequests',
867 controller='pullrequests',
877 action='merge', conditions={'function': check_repo,
868 action='merge', conditions={'function': check_repo,
878 'method': ['POST']},
869 'method': ['POST']},
879 requirements=URL_NAME_REQUIREMENTS)
870 requirements=URL_NAME_REQUIREMENTS)
880
871
881 rmap.connect('pullrequest_delete',
872 rmap.connect('pullrequest_delete',
882 '/{repo_name}/pull-request/{pull_request_id}',
873 '/{repo_name}/pull-request/{pull_request_id}',
883 controller='pullrequests',
874 controller='pullrequests',
884 action='delete', conditions={'function': check_repo,
875 action='delete', conditions={'function': check_repo,
885 'method': ['DELETE']},
876 'method': ['DELETE']},
886 requirements=URL_NAME_REQUIREMENTS)
877 requirements=URL_NAME_REQUIREMENTS)
887
878
888 rmap.connect('pullrequest_show_all',
879 rmap.connect('pullrequest_show_all',
889 '/{repo_name}/pull-request',
880 '/{repo_name}/pull-request',
890 controller='pullrequests',
881 controller='pullrequests',
891 action='show_all', conditions={'function': check_repo,
882 action='show_all', conditions={'function': check_repo,
892 'method': ['GET']},
883 'method': ['GET']},
893 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
884 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
894
885
895 rmap.connect('pullrequest_comment',
886 rmap.connect('pullrequest_comment',
896 '/{repo_name}/pull-request-comment/{pull_request_id}',
887 '/{repo_name}/pull-request-comment/{pull_request_id}',
897 controller='pullrequests',
888 controller='pullrequests',
898 action='comment', conditions={'function': check_repo,
889 action='comment', conditions={'function': check_repo,
899 'method': ['POST']},
890 'method': ['POST']},
900 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
891 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
901
892
902 rmap.connect('pullrequest_comment_delete',
893 rmap.connect('pullrequest_comment_delete',
903 '/{repo_name}/pull-request-comment/{comment_id}/delete',
894 '/{repo_name}/pull-request-comment/{comment_id}/delete',
904 controller='pullrequests', action='delete_comment',
895 controller='pullrequests', action='delete_comment',
905 conditions={'function': check_repo, 'method': ['DELETE']},
896 conditions={'function': check_repo, 'method': ['DELETE']},
906 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
897 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
907
898
908 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
899 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
909 controller='summary', conditions={'function': check_repo},
900 controller='summary', conditions={'function': check_repo},
910 requirements=URL_NAME_REQUIREMENTS)
901 requirements=URL_NAME_REQUIREMENTS)
911
902
912 rmap.connect('branches_home', '/{repo_name}/branches',
903 rmap.connect('branches_home', '/{repo_name}/branches',
913 controller='branches', conditions={'function': check_repo},
904 controller='branches', conditions={'function': check_repo},
914 requirements=URL_NAME_REQUIREMENTS)
905 requirements=URL_NAME_REQUIREMENTS)
915
906
916 rmap.connect('tags_home', '/{repo_name}/tags',
907 rmap.connect('tags_home', '/{repo_name}/tags',
917 controller='tags', conditions={'function': check_repo},
908 controller='tags', conditions={'function': check_repo},
918 requirements=URL_NAME_REQUIREMENTS)
909 requirements=URL_NAME_REQUIREMENTS)
919
910
920 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
911 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
921 controller='bookmarks', conditions={'function': check_repo},
912 controller='bookmarks', conditions={'function': check_repo},
922 requirements=URL_NAME_REQUIREMENTS)
913 requirements=URL_NAME_REQUIREMENTS)
923
914
924 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
915 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
925 controller='changelog', conditions={'function': check_repo},
916 controller='changelog', conditions={'function': check_repo},
926 requirements=URL_NAME_REQUIREMENTS)
917 requirements=URL_NAME_REQUIREMENTS)
927
918
928 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
919 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
929 controller='changelog', action='changelog_summary',
920 controller='changelog', action='changelog_summary',
930 conditions={'function': check_repo},
921 conditions={'function': check_repo},
931 requirements=URL_NAME_REQUIREMENTS)
922 requirements=URL_NAME_REQUIREMENTS)
932
923
933 rmap.connect('changelog_file_home',
924 rmap.connect('changelog_file_home',
934 '/{repo_name}/changelog/{revision}/{f_path}',
925 '/{repo_name}/changelog/{revision}/{f_path}',
935 controller='changelog', f_path=None,
926 controller='changelog', f_path=None,
936 conditions={'function': check_repo},
927 conditions={'function': check_repo},
937 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
928 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
938
929
939 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
930 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
940 controller='changelog', action='changelog_elements',
931 controller='changelog', action='changelog_elements',
941 conditions={'function': check_repo},
932 conditions={'function': check_repo},
942 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
933 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
943
934
944 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
935 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
945 controller='files', revision='tip', f_path='',
936 controller='files', revision='tip', f_path='',
946 conditions={'function': check_repo},
937 conditions={'function': check_repo},
947 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
938 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
948
939
949 rmap.connect('files_home_simple_catchrev',
940 rmap.connect('files_home_simple_catchrev',
950 '/{repo_name}/files/{revision}',
941 '/{repo_name}/files/{revision}',
951 controller='files', revision='tip', f_path='',
942 controller='files', revision='tip', f_path='',
952 conditions={'function': check_repo},
943 conditions={'function': check_repo},
953 requirements=URL_NAME_REQUIREMENTS)
944 requirements=URL_NAME_REQUIREMENTS)
954
945
955 rmap.connect('files_home_simple_catchall',
946 rmap.connect('files_home_simple_catchall',
956 '/{repo_name}/files',
947 '/{repo_name}/files',
957 controller='files', revision='tip', f_path='',
948 controller='files', revision='tip', f_path='',
958 conditions={'function': check_repo},
949 conditions={'function': check_repo},
959 requirements=URL_NAME_REQUIREMENTS)
950 requirements=URL_NAME_REQUIREMENTS)
960
951
961 rmap.connect('files_history_home',
952 rmap.connect('files_history_home',
962 '/{repo_name}/history/{revision}/{f_path}',
953 '/{repo_name}/history/{revision}/{f_path}',
963 controller='files', action='history', revision='tip', f_path='',
954 controller='files', action='history', revision='tip', f_path='',
964 conditions={'function': check_repo},
955 conditions={'function': check_repo},
965 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
956 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
966
957
967 rmap.connect('files_authors_home',
958 rmap.connect('files_authors_home',
968 '/{repo_name}/authors/{revision}/{f_path}',
959 '/{repo_name}/authors/{revision}/{f_path}',
969 controller='files', action='authors', revision='tip', f_path='',
960 controller='files', action='authors', revision='tip', f_path='',
970 conditions={'function': check_repo},
961 conditions={'function': check_repo},
971 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
962 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
972
963
973 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
964 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
974 controller='files', action='diff', f_path='',
965 controller='files', action='diff', f_path='',
975 conditions={'function': check_repo},
966 conditions={'function': check_repo},
976 requirements=URL_NAME_REQUIREMENTS)
967 requirements=URL_NAME_REQUIREMENTS)
977
968
978 rmap.connect('files_diff_2way_home',
969 rmap.connect('files_diff_2way_home',
979 '/{repo_name}/diff-2way/{f_path}',
970 '/{repo_name}/diff-2way/{f_path}',
980 controller='files', action='diff_2way', f_path='',
971 controller='files', action='diff_2way', f_path='',
981 conditions={'function': check_repo},
972 conditions={'function': check_repo},
982 requirements=URL_NAME_REQUIREMENTS)
973 requirements=URL_NAME_REQUIREMENTS)
983
974
984 rmap.connect('files_rawfile_home',
975 rmap.connect('files_rawfile_home',
985 '/{repo_name}/rawfile/{revision}/{f_path}',
976 '/{repo_name}/rawfile/{revision}/{f_path}',
986 controller='files', action='rawfile', revision='tip',
977 controller='files', action='rawfile', revision='tip',
987 f_path='', conditions={'function': check_repo},
978 f_path='', conditions={'function': check_repo},
988 requirements=URL_NAME_REQUIREMENTS)
979 requirements=URL_NAME_REQUIREMENTS)
989
980
990 rmap.connect('files_raw_home',
981 rmap.connect('files_raw_home',
991 '/{repo_name}/raw/{revision}/{f_path}',
982 '/{repo_name}/raw/{revision}/{f_path}',
992 controller='files', action='raw', revision='tip', f_path='',
983 controller='files', action='raw', revision='tip', f_path='',
993 conditions={'function': check_repo},
984 conditions={'function': check_repo},
994 requirements=URL_NAME_REQUIREMENTS)
985 requirements=URL_NAME_REQUIREMENTS)
995
986
996 rmap.connect('files_render_home',
987 rmap.connect('files_render_home',
997 '/{repo_name}/render/{revision}/{f_path}',
988 '/{repo_name}/render/{revision}/{f_path}',
998 controller='files', action='index', revision='tip', f_path='',
989 controller='files', action='index', revision='tip', f_path='',
999 rendered=True, conditions={'function': check_repo},
990 rendered=True, conditions={'function': check_repo},
1000 requirements=URL_NAME_REQUIREMENTS)
991 requirements=URL_NAME_REQUIREMENTS)
1001
992
1002 rmap.connect('files_annotate_home',
993 rmap.connect('files_annotate_home',
1003 '/{repo_name}/annotate/{revision}/{f_path}',
994 '/{repo_name}/annotate/{revision}/{f_path}',
1004 controller='files', action='index', revision='tip',
995 controller='files', action='index', revision='tip',
1005 f_path='', annotate=True, conditions={'function': check_repo},
996 f_path='', annotate=True, conditions={'function': check_repo},
1006 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
997 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1007
998
1008 rmap.connect('files_annotate_previous',
999 rmap.connect('files_annotate_previous',
1009 '/{repo_name}/annotate-previous/{revision}/{f_path}',
1000 '/{repo_name}/annotate-previous/{revision}/{f_path}',
1010 controller='files', action='annotate_previous', revision='tip',
1001 controller='files', action='annotate_previous', revision='tip',
1011 f_path='', annotate=True, conditions={'function': check_repo},
1002 f_path='', annotate=True, conditions={'function': check_repo},
1012 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1003 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1013
1004
1014 rmap.connect('files_edit',
1005 rmap.connect('files_edit',
1015 '/{repo_name}/edit/{revision}/{f_path}',
1006 '/{repo_name}/edit/{revision}/{f_path}',
1016 controller='files', action='edit', revision='tip',
1007 controller='files', action='edit', revision='tip',
1017 f_path='',
1008 f_path='',
1018 conditions={'function': check_repo, 'method': ['POST']},
1009 conditions={'function': check_repo, 'method': ['POST']},
1019 requirements=URL_NAME_REQUIREMENTS)
1010 requirements=URL_NAME_REQUIREMENTS)
1020
1011
1021 rmap.connect('files_edit_home',
1012 rmap.connect('files_edit_home',
1022 '/{repo_name}/edit/{revision}/{f_path}',
1013 '/{repo_name}/edit/{revision}/{f_path}',
1023 controller='files', action='edit_home', revision='tip',
1014 controller='files', action='edit_home', revision='tip',
1024 f_path='', conditions={'function': check_repo},
1015 f_path='', conditions={'function': check_repo},
1025 requirements=URL_NAME_REQUIREMENTS)
1016 requirements=URL_NAME_REQUIREMENTS)
1026
1017
1027 rmap.connect('files_add',
1018 rmap.connect('files_add',
1028 '/{repo_name}/add/{revision}/{f_path}',
1019 '/{repo_name}/add/{revision}/{f_path}',
1029 controller='files', action='add', revision='tip',
1020 controller='files', action='add', revision='tip',
1030 f_path='',
1021 f_path='',
1031 conditions={'function': check_repo, 'method': ['POST']},
1022 conditions={'function': check_repo, 'method': ['POST']},
1032 requirements=URL_NAME_REQUIREMENTS)
1023 requirements=URL_NAME_REQUIREMENTS)
1033
1024
1034 rmap.connect('files_add_home',
1025 rmap.connect('files_add_home',
1035 '/{repo_name}/add/{revision}/{f_path}',
1026 '/{repo_name}/add/{revision}/{f_path}',
1036 controller='files', action='add_home', revision='tip',
1027 controller='files', action='add_home', revision='tip',
1037 f_path='', conditions={'function': check_repo},
1028 f_path='', conditions={'function': check_repo},
1038 requirements=URL_NAME_REQUIREMENTS)
1029 requirements=URL_NAME_REQUIREMENTS)
1039
1030
1040 rmap.connect('files_delete',
1031 rmap.connect('files_delete',
1041 '/{repo_name}/delete/{revision}/{f_path}',
1032 '/{repo_name}/delete/{revision}/{f_path}',
1042 controller='files', action='delete', revision='tip',
1033 controller='files', action='delete', revision='tip',
1043 f_path='',
1034 f_path='',
1044 conditions={'function': check_repo, 'method': ['POST']},
1035 conditions={'function': check_repo, 'method': ['POST']},
1045 requirements=URL_NAME_REQUIREMENTS)
1036 requirements=URL_NAME_REQUIREMENTS)
1046
1037
1047 rmap.connect('files_delete_home',
1038 rmap.connect('files_delete_home',
1048 '/{repo_name}/delete/{revision}/{f_path}',
1039 '/{repo_name}/delete/{revision}/{f_path}',
1049 controller='files', action='delete_home', revision='tip',
1040 controller='files', action='delete_home', revision='tip',
1050 f_path='', conditions={'function': check_repo},
1041 f_path='', conditions={'function': check_repo},
1051 requirements=URL_NAME_REQUIREMENTS)
1042 requirements=URL_NAME_REQUIREMENTS)
1052
1043
1053 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1044 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1054 controller='files', action='archivefile',
1045 controller='files', action='archivefile',
1055 conditions={'function': check_repo},
1046 conditions={'function': check_repo},
1056 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1047 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1057
1048
1058 rmap.connect('files_nodelist_home',
1049 rmap.connect('files_nodelist_home',
1059 '/{repo_name}/nodelist/{revision}/{f_path}',
1050 '/{repo_name}/nodelist/{revision}/{f_path}',
1060 controller='files', action='nodelist',
1051 controller='files', action='nodelist',
1061 conditions={'function': check_repo},
1052 conditions={'function': check_repo},
1062 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1053 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1063
1054
1064 rmap.connect('files_nodetree_full',
1055 rmap.connect('files_nodetree_full',
1065 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1056 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1066 controller='files', action='nodetree_full',
1057 controller='files', action='nodetree_full',
1067 conditions={'function': check_repo},
1058 conditions={'function': check_repo},
1068 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1059 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1069
1060
1070 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1061 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1071 controller='forks', action='fork_create',
1062 controller='forks', action='fork_create',
1072 conditions={'function': check_repo, 'method': ['POST']},
1063 conditions={'function': check_repo, 'method': ['POST']},
1073 requirements=URL_NAME_REQUIREMENTS)
1064 requirements=URL_NAME_REQUIREMENTS)
1074
1065
1075 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1066 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1076 controller='forks', action='fork',
1067 controller='forks', action='fork',
1077 conditions={'function': check_repo},
1068 conditions={'function': check_repo},
1078 requirements=URL_NAME_REQUIREMENTS)
1069 requirements=URL_NAME_REQUIREMENTS)
1079
1070
1080 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1071 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1081 controller='forks', action='forks',
1072 controller='forks', action='forks',
1082 conditions={'function': check_repo},
1073 conditions={'function': check_repo},
1083 requirements=URL_NAME_REQUIREMENTS)
1074 requirements=URL_NAME_REQUIREMENTS)
1084
1075
1085 # must be here for proper group/repo catching pattern
1076 # must be here for proper group/repo catching pattern
1086 _connect_with_slash(
1077 _connect_with_slash(
1087 rmap, 'repo_group_home', '/{group_name}',
1078 rmap, 'repo_group_home', '/{group_name}',
1088 controller='home', action='index_repo_group',
1079 controller='home', action='index_repo_group',
1089 conditions={'function': check_group},
1080 conditions={'function': check_group},
1090 requirements=URL_NAME_REQUIREMENTS)
1081 requirements=URL_NAME_REQUIREMENTS)
1091
1082
1092 # catch all, at the end
1083 # catch all, at the end
1093 _connect_with_slash(
1084 _connect_with_slash(
1094 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1085 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1095 controller='summary', action='index',
1086 controller='summary', action='index',
1096 conditions={'function': check_repo},
1087 conditions={'function': check_repo},
1097 requirements=URL_NAME_REQUIREMENTS)
1088 requirements=URL_NAME_REQUIREMENTS)
1098
1089
1099 return rmap
1090 return rmap
1100
1091
1101
1092
1102 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1093 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1103 """
1094 """
1104 Connect a route with an optional trailing slash in `path`.
1095 Connect a route with an optional trailing slash in `path`.
1105 """
1096 """
1106 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1097 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1107 mapper.connect(name, path, *args, **kwargs)
1098 mapper.connect(name, path, *args, **kwargs)
@@ -1,805 +1,781 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2013-2017 RhodeCode GmbH
3 # Copyright (C) 2013-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
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
21
22 """
22 """
23 Repositories controller for RhodeCode
23 Repositories controller for RhodeCode
24 """
24 """
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 import formencode
29 import formencode
30 from formencode import htmlfill
30 from formencode import htmlfill
31 from pylons import request, tmpl_context as c, url
31 from pylons import request, tmpl_context as c, url
32 from pylons.controllers.util import redirect
32 from pylons.controllers.util import redirect
33 from pylons.i18n.translation import _
33 from pylons.i18n.translation import _
34 from webob.exc import HTTPForbidden, HTTPNotFound, HTTPBadRequest
34 from webob.exc import HTTPForbidden, HTTPNotFound, HTTPBadRequest
35
35
36 import rhodecode
36 import rhodecode
37 from rhodecode.lib import auth, helpers as h
37 from rhodecode.lib import auth, helpers as h
38 from rhodecode.lib.auth import (
38 from rhodecode.lib.auth import (
39 LoginRequired, HasPermissionAllDecorator,
39 LoginRequired, HasPermissionAllDecorator,
40 HasRepoPermissionAllDecorator, NotAnonymous, HasPermissionAny,
40 HasRepoPermissionAllDecorator, NotAnonymous, HasPermissionAny,
41 HasRepoGroupPermissionAny, HasRepoPermissionAnyDecorator)
41 HasRepoGroupPermissionAny, HasRepoPermissionAnyDecorator)
42 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.ext_json import json
43 from rhodecode.lib.ext_json import json
44 from rhodecode.lib.exceptions import AttachedForksError
44 from rhodecode.lib.exceptions import AttachedForksError
45 from rhodecode.lib.utils import action_logger, repo_name_slug, jsonify
45 from rhodecode.lib.utils import action_logger, repo_name_slug, jsonify
46 from rhodecode.lib.utils2 import safe_int, str2bool
46 from rhodecode.lib.utils2 import safe_int, str2bool
47 from rhodecode.lib.vcs import RepositoryError
47 from rhodecode.lib.vcs import RepositoryError
48 from rhodecode.model.db import (
48 from rhodecode.model.db import (
49 User, Repository, UserFollowing, RepoGroup, RepositoryField)
49 User, Repository, UserFollowing, RepoGroup, RepositoryField)
50 from rhodecode.model.forms import (
50 from rhodecode.model.forms import (
51 RepoForm, RepoFieldForm, RepoPermsForm, RepoVcsSettingsForm,
51 RepoForm, RepoFieldForm, RepoPermsForm, RepoVcsSettingsForm,
52 IssueTrackerPatternsForm)
52 IssueTrackerPatternsForm)
53 from rhodecode.model.meta import Session
53 from rhodecode.model.meta import Session
54 from rhodecode.model.repo import RepoModel
54 from rhodecode.model.repo import RepoModel
55 from rhodecode.model.scm import ScmModel, RepoGroupList, RepoList
55 from rhodecode.model.scm import ScmModel, RepoGroupList, RepoList
56 from rhodecode.model.settings import (
56 from rhodecode.model.settings import (
57 SettingsModel, IssueTrackerSettingsModel, VcsSettingsModel,
57 SettingsModel, IssueTrackerSettingsModel, VcsSettingsModel,
58 SettingNotFound)
58 SettingNotFound)
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62
62
63 class ReposController(BaseRepoController):
63 class ReposController(BaseRepoController):
64 """
64 """
65 REST Controller styled on the Atom Publishing Protocol"""
65 REST Controller styled on the Atom Publishing Protocol"""
66 # To properly map this controller, ensure your config/routing.py
66 # To properly map this controller, ensure your config/routing.py
67 # file has a resource setup:
67 # file has a resource setup:
68 # map.resource('repo', 'repos')
68 # map.resource('repo', 'repos')
69
69
70 @LoginRequired()
70 @LoginRequired()
71 def __before__(self):
71 def __before__(self):
72 super(ReposController, self).__before__()
72 super(ReposController, self).__before__()
73
73
74 def _load_repo(self, repo_name):
74 def _load_repo(self, repo_name):
75 repo_obj = Repository.get_by_repo_name(repo_name)
75 repo_obj = Repository.get_by_repo_name(repo_name)
76
76
77 if repo_obj is None:
77 if repo_obj is None:
78 h.not_mapped_error(repo_name)
78 h.not_mapped_error(repo_name)
79 return redirect(url('repos'))
79 return redirect(url('repos'))
80
80
81 return repo_obj
81 return repo_obj
82
82
83 def __load_defaults(self, repo=None):
83 def __load_defaults(self, repo=None):
84 acl_groups = RepoGroupList(RepoGroup.query().all(),
84 acl_groups = RepoGroupList(RepoGroup.query().all(),
85 perm_set=['group.write', 'group.admin'])
85 perm_set=['group.write', 'group.admin'])
86 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
86 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
87 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
87 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
88
88
89 # in case someone no longer have a group.write access to a repository
89 # in case someone no longer have a group.write access to a repository
90 # pre fill the list with this entry, we don't care if this is the same
90 # pre fill the list with this entry, we don't care if this is the same
91 # but it will allow saving repo data properly.
91 # but it will allow saving repo data properly.
92
92
93 repo_group = None
93 repo_group = None
94 if repo:
94 if repo:
95 repo_group = repo.group
95 repo_group = repo.group
96 if repo_group and unicode(repo_group.group_id) not in c.repo_groups_choices:
96 if repo_group and unicode(repo_group.group_id) not in c.repo_groups_choices:
97 c.repo_groups_choices.append(unicode(repo_group.group_id))
97 c.repo_groups_choices.append(unicode(repo_group.group_id))
98 c.repo_groups.append(RepoGroup._generate_choice(repo_group))
98 c.repo_groups.append(RepoGroup._generate_choice(repo_group))
99
99
100 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
100 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
101 c.landing_revs_choices = choices
101 c.landing_revs_choices = choices
102
102
103 def __load_data(self, repo_name=None):
103 def __load_data(self, repo_name=None):
104 """
104 """
105 Load defaults settings for edit, and update
105 Load defaults settings for edit, and update
106
106
107 :param repo_name:
107 :param repo_name:
108 """
108 """
109 c.repo_info = self._load_repo(repo_name)
109 c.repo_info = self._load_repo(repo_name)
110 self.__load_defaults(c.repo_info)
110 self.__load_defaults(c.repo_info)
111
111
112 # override defaults for exact repo info here git/hg etc
112 # override defaults for exact repo info here git/hg etc
113 if not c.repository_requirements_missing:
113 if not c.repository_requirements_missing:
114 choices, c.landing_revs = ScmModel().get_repo_landing_revs(
114 choices, c.landing_revs = ScmModel().get_repo_landing_revs(
115 c.repo_info)
115 c.repo_info)
116 c.landing_revs_choices = choices
116 c.landing_revs_choices = choices
117 defaults = RepoModel()._get_defaults(repo_name)
117 defaults = RepoModel()._get_defaults(repo_name)
118
118
119 return defaults
119 return defaults
120
120
121 def _log_creation_exception(self, e, repo_name):
121 def _log_creation_exception(self, e, repo_name):
122 reason = None
122 reason = None
123 if len(e.args) == 2:
123 if len(e.args) == 2:
124 reason = e.args[1]
124 reason = e.args[1]
125
125
126 if reason == 'INVALID_CERTIFICATE':
126 if reason == 'INVALID_CERTIFICATE':
127 log.exception(
127 log.exception(
128 'Exception creating a repository: invalid certificate')
128 'Exception creating a repository: invalid certificate')
129 msg = (_('Error creating repository %s: invalid certificate')
129 msg = (_('Error creating repository %s: invalid certificate')
130 % repo_name)
130 % repo_name)
131 else:
131 else:
132 log.exception("Exception creating a repository")
132 log.exception("Exception creating a repository")
133 msg = (_('Error creating repository %s')
133 msg = (_('Error creating repository %s')
134 % repo_name)
134 % repo_name)
135
135
136 return msg
136 return msg
137
137
138 @NotAnonymous()
138 @NotAnonymous()
139 def index(self, format='html'):
139 def index(self, format='html'):
140 """GET /repos: All items in the collection"""
140 """GET /repos: All items in the collection"""
141 # url('repos')
141 # url('repos')
142
142
143 repo_list = Repository.get_all_repos()
143 repo_list = Repository.get_all_repos()
144 c.repo_list = RepoList(repo_list, perm_set=['repository.admin'])
144 c.repo_list = RepoList(repo_list, perm_set=['repository.admin'])
145 repos_data = RepoModel().get_repos_as_dict(
145 repos_data = RepoModel().get_repos_as_dict(
146 repo_list=c.repo_list, admin=True, super_user_actions=True)
146 repo_list=c.repo_list, admin=True, super_user_actions=True)
147 # json used to render the grid
147 # json used to render the grid
148 c.data = json.dumps(repos_data)
148 c.data = json.dumps(repos_data)
149
149
150 return render('admin/repos/repos.mako')
150 return render('admin/repos/repos.mako')
151
151
152 # perms check inside
152 # perms check inside
153 @NotAnonymous()
153 @NotAnonymous()
154 @auth.CSRFRequired()
154 @auth.CSRFRequired()
155 def create(self):
155 def create(self):
156 """
156 """
157 POST /repos: Create a new item"""
157 POST /repos: Create a new item"""
158 # url('repos')
158 # url('repos')
159
159
160 self.__load_defaults()
160 self.__load_defaults()
161 form_result = {}
161 form_result = {}
162 task_id = None
162 task_id = None
163 c.personal_repo_group = c.rhodecode_user.personal_repo_group
163 c.personal_repo_group = c.rhodecode_user.personal_repo_group
164 try:
164 try:
165 # CanWriteToGroup validators checks permissions of this POST
165 # CanWriteToGroup validators checks permissions of this POST
166 form_result = RepoForm(repo_groups=c.repo_groups_choices,
166 form_result = RepoForm(repo_groups=c.repo_groups_choices,
167 landing_revs=c.landing_revs_choices)()\
167 landing_revs=c.landing_revs_choices)()\
168 .to_python(dict(request.POST))
168 .to_python(dict(request.POST))
169
169
170 # create is done sometimes async on celery, db transaction
170 # create is done sometimes async on celery, db transaction
171 # management is handled there.
171 # management is handled there.
172 task = RepoModel().create(form_result, c.rhodecode_user.user_id)
172 task = RepoModel().create(form_result, c.rhodecode_user.user_id)
173 from celery.result import BaseAsyncResult
173 from celery.result import BaseAsyncResult
174 if isinstance(task, BaseAsyncResult):
174 if isinstance(task, BaseAsyncResult):
175 task_id = task.task_id
175 task_id = task.task_id
176 except formencode.Invalid as errors:
176 except formencode.Invalid as errors:
177 return htmlfill.render(
177 return htmlfill.render(
178 render('admin/repos/repo_add.mako'),
178 render('admin/repos/repo_add.mako'),
179 defaults=errors.value,
179 defaults=errors.value,
180 errors=errors.error_dict or {},
180 errors=errors.error_dict or {},
181 prefix_error=False,
181 prefix_error=False,
182 encoding="UTF-8",
182 encoding="UTF-8",
183 force_defaults=False)
183 force_defaults=False)
184
184
185 except Exception as e:
185 except Exception as e:
186 msg = self._log_creation_exception(e, form_result.get('repo_name'))
186 msg = self._log_creation_exception(e, form_result.get('repo_name'))
187 h.flash(msg, category='error')
187 h.flash(msg, category='error')
188 return redirect(url('home'))
188 return redirect(url('home'))
189
189
190 return redirect(h.url('repo_creating_home',
190 return redirect(h.url('repo_creating_home',
191 repo_name=form_result['repo_name_full'],
191 repo_name=form_result['repo_name_full'],
192 task_id=task_id))
192 task_id=task_id))
193
193
194 # perms check inside
194 # perms check inside
195 @NotAnonymous()
195 @NotAnonymous()
196 def create_repository(self):
196 def create_repository(self):
197 """GET /_admin/create_repository: Form to create a new item"""
197 """GET /_admin/create_repository: Form to create a new item"""
198 new_repo = request.GET.get('repo', '')
198 new_repo = request.GET.get('repo', '')
199 parent_group = safe_int(request.GET.get('parent_group'))
199 parent_group = safe_int(request.GET.get('parent_group'))
200 _gr = RepoGroup.get(parent_group)
200 _gr = RepoGroup.get(parent_group)
201
201
202 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
202 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
203 # you're not super admin nor have global create permissions,
203 # you're not super admin nor have global create permissions,
204 # but maybe you have at least write permission to a parent group ?
204 # but maybe you have at least write permission to a parent group ?
205
205
206 gr_name = _gr.group_name if _gr else None
206 gr_name = _gr.group_name if _gr else None
207 # create repositories with write permission on group is set to true
207 # create repositories with write permission on group is set to true
208 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
208 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
209 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
209 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
210 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
210 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
211 if not (group_admin or (group_write and create_on_write)):
211 if not (group_admin or (group_write and create_on_write)):
212 raise HTTPForbidden
212 raise HTTPForbidden
213
213
214 acl_groups = RepoGroupList(RepoGroup.query().all(),
214 acl_groups = RepoGroupList(RepoGroup.query().all(),
215 perm_set=['group.write', 'group.admin'])
215 perm_set=['group.write', 'group.admin'])
216 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
216 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
217 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
217 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
218 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
218 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
219 c.personal_repo_group = c.rhodecode_user.personal_repo_group
219 c.personal_repo_group = c.rhodecode_user.personal_repo_group
220 c.new_repo = repo_name_slug(new_repo)
220 c.new_repo = repo_name_slug(new_repo)
221
221
222 # apply the defaults from defaults page
222 # apply the defaults from defaults page
223 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
223 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
224 # set checkbox to autochecked
224 # set checkbox to autochecked
225 defaults['repo_copy_permissions'] = True
225 defaults['repo_copy_permissions'] = True
226
226
227 parent_group_choice = '-1'
227 parent_group_choice = '-1'
228 if not c.rhodecode_user.is_admin and c.rhodecode_user.personal_repo_group:
228 if not c.rhodecode_user.is_admin and c.rhodecode_user.personal_repo_group:
229 parent_group_choice = c.rhodecode_user.personal_repo_group
229 parent_group_choice = c.rhodecode_user.personal_repo_group
230
230
231 if parent_group and _gr:
231 if parent_group and _gr:
232 if parent_group in [x[0] for x in c.repo_groups]:
232 if parent_group in [x[0] for x in c.repo_groups]:
233 parent_group_choice = unicode(parent_group)
233 parent_group_choice = unicode(parent_group)
234
234
235 defaults.update({'repo_group': parent_group_choice})
235 defaults.update({'repo_group': parent_group_choice})
236
236
237 return htmlfill.render(
237 return htmlfill.render(
238 render('admin/repos/repo_add.mako'),
238 render('admin/repos/repo_add.mako'),
239 defaults=defaults,
239 defaults=defaults,
240 errors={},
240 errors={},
241 prefix_error=False,
241 prefix_error=False,
242 encoding="UTF-8",
242 encoding="UTF-8",
243 force_defaults=False
243 force_defaults=False
244 )
244 )
245
245
246 @NotAnonymous()
246 @NotAnonymous()
247 def repo_creating(self, repo_name):
247 def repo_creating(self, repo_name):
248 c.repo = repo_name
248 c.repo = repo_name
249 c.task_id = request.GET.get('task_id')
249 c.task_id = request.GET.get('task_id')
250 if not c.repo:
250 if not c.repo:
251 raise HTTPNotFound()
251 raise HTTPNotFound()
252 return render('admin/repos/repo_creating.mako')
252 return render('admin/repos/repo_creating.mako')
253
253
254 @NotAnonymous()
254 @NotAnonymous()
255 @jsonify
255 @jsonify
256 def repo_check(self, repo_name):
256 def repo_check(self, repo_name):
257 c.repo = repo_name
257 c.repo = repo_name
258 task_id = request.GET.get('task_id')
258 task_id = request.GET.get('task_id')
259
259
260 if task_id and task_id not in ['None']:
260 if task_id and task_id not in ['None']:
261 import rhodecode
261 import rhodecode
262 from celery.result import AsyncResult
262 from celery.result import AsyncResult
263 if rhodecode.CELERY_ENABLED:
263 if rhodecode.CELERY_ENABLED:
264 task = AsyncResult(task_id)
264 task = AsyncResult(task_id)
265 if task.failed():
265 if task.failed():
266 msg = self._log_creation_exception(task.result, c.repo)
266 msg = self._log_creation_exception(task.result, c.repo)
267 h.flash(msg, category='error')
267 h.flash(msg, category='error')
268 return redirect(url('home'), code=501)
268 return redirect(url('home'), code=501)
269
269
270 repo = Repository.get_by_repo_name(repo_name)
270 repo = Repository.get_by_repo_name(repo_name)
271 if repo and repo.repo_state == Repository.STATE_CREATED:
271 if repo and repo.repo_state == Repository.STATE_CREATED:
272 if repo.clone_uri:
272 if repo.clone_uri:
273 clone_uri = repo.clone_uri_hidden
273 clone_uri = repo.clone_uri_hidden
274 h.flash(_('Created repository %s from %s')
274 h.flash(_('Created repository %s from %s')
275 % (repo.repo_name, clone_uri), category='success')
275 % (repo.repo_name, clone_uri), category='success')
276 else:
276 else:
277 repo_url = h.link_to(repo.repo_name,
277 repo_url = h.link_to(repo.repo_name,
278 h.url('summary_home',
278 h.url('summary_home',
279 repo_name=repo.repo_name))
279 repo_name=repo.repo_name))
280 fork = repo.fork
280 fork = repo.fork
281 if fork:
281 if fork:
282 fork_name = fork.repo_name
282 fork_name = fork.repo_name
283 h.flash(h.literal(_('Forked repository %s as %s')
283 h.flash(h.literal(_('Forked repository %s as %s')
284 % (fork_name, repo_url)), category='success')
284 % (fork_name, repo_url)), category='success')
285 else:
285 else:
286 h.flash(h.literal(_('Created repository %s') % repo_url),
286 h.flash(h.literal(_('Created repository %s') % repo_url),
287 category='success')
287 category='success')
288 return {'result': True}
288 return {'result': True}
289 return {'result': False}
289 return {'result': False}
290
290
291 @HasRepoPermissionAllDecorator('repository.admin')
291 @HasRepoPermissionAllDecorator('repository.admin')
292 @auth.CSRFRequired()
292 @auth.CSRFRequired()
293 def delete(self, repo_name):
293 def delete(self, repo_name):
294 """
294 """
295 DELETE /repos/repo_name: Delete an existing item"""
295 DELETE /repos/repo_name: Delete an existing item"""
296 # Forms posted to this method should contain a hidden field:
296 # Forms posted to this method should contain a hidden field:
297 # <input type="hidden" name="_method" value="DELETE" />
297 # <input type="hidden" name="_method" value="DELETE" />
298 # Or using helpers:
298 # Or using helpers:
299 # h.form(url('repo', repo_name=ID),
299 # h.form(url('repo', repo_name=ID),
300 # method='delete')
300 # method='delete')
301 # url('repo', repo_name=ID)
301 # url('repo', repo_name=ID)
302
302
303 repo_model = RepoModel()
303 repo_model = RepoModel()
304 repo = repo_model.get_by_repo_name(repo_name)
304 repo = repo_model.get_by_repo_name(repo_name)
305 if not repo:
305 if not repo:
306 h.not_mapped_error(repo_name)
306 h.not_mapped_error(repo_name)
307 return redirect(url('repos'))
307 return redirect(url('repos'))
308 try:
308 try:
309 _forks = repo.forks.count()
309 _forks = repo.forks.count()
310 handle_forks = None
310 handle_forks = None
311 if _forks and request.POST.get('forks'):
311 if _forks and request.POST.get('forks'):
312 do = request.POST['forks']
312 do = request.POST['forks']
313 if do == 'detach_forks':
313 if do == 'detach_forks':
314 handle_forks = 'detach'
314 handle_forks = 'detach'
315 h.flash(_('Detached %s forks') % _forks, category='success')
315 h.flash(_('Detached %s forks') % _forks, category='success')
316 elif do == 'delete_forks':
316 elif do == 'delete_forks':
317 handle_forks = 'delete'
317 handle_forks = 'delete'
318 h.flash(_('Deleted %s forks') % _forks, category='success')
318 h.flash(_('Deleted %s forks') % _forks, category='success')
319 repo_model.delete(repo, forks=handle_forks)
319 repo_model.delete(repo, forks=handle_forks)
320 action_logger(c.rhodecode_user, 'admin_deleted_repo',
320 action_logger(c.rhodecode_user, 'admin_deleted_repo',
321 repo_name, self.ip_addr, self.sa)
321 repo_name, self.ip_addr, self.sa)
322 ScmModel().mark_for_invalidation(repo_name)
322 ScmModel().mark_for_invalidation(repo_name)
323 h.flash(_('Deleted repository %s') % repo_name, category='success')
323 h.flash(_('Deleted repository %s') % repo_name, category='success')
324 Session().commit()
324 Session().commit()
325 except AttachedForksError:
325 except AttachedForksError:
326 h.flash(_('Cannot delete %s it still contains attached forks')
326 h.flash(_('Cannot delete %s it still contains attached forks')
327 % repo_name, category='warning')
327 % repo_name, category='warning')
328
328
329 except Exception:
329 except Exception:
330 log.exception("Exception during deletion of repository")
330 log.exception("Exception during deletion of repository")
331 h.flash(_('An error occurred during deletion of %s') % repo_name,
331 h.flash(_('An error occurred during deletion of %s') % repo_name,
332 category='error')
332 category='error')
333
333
334 return redirect(url('repos'))
334 return redirect(url('repos'))
335
335
336 @HasPermissionAllDecorator('hg.admin')
336 @HasPermissionAllDecorator('hg.admin')
337 def show(self, repo_name, format='html'):
337 def show(self, repo_name, format='html'):
338 """GET /repos/repo_name: Show a specific item"""
338 """GET /repos/repo_name: Show a specific item"""
339 # url('repo', repo_name=ID)
339 # url('repo', repo_name=ID)
340
340
341 @HasRepoPermissionAllDecorator('repository.admin')
341 @HasRepoPermissionAllDecorator('repository.admin')
342 def edit_permissions(self, repo_name):
342 def edit_permissions(self, repo_name):
343 """GET /repo_name/settings: Form to edit an existing item"""
343 """GET /repo_name/settings: Form to edit an existing item"""
344 c.repo_info = self._load_repo(repo_name)
344 c.repo_info = self._load_repo(repo_name)
345 c.active = 'permissions'
345 c.active = 'permissions'
346 defaults = RepoModel()._get_defaults(repo_name)
346 defaults = RepoModel()._get_defaults(repo_name)
347
347
348 return htmlfill.render(
348 return htmlfill.render(
349 render('admin/repos/repo_edit.mako'),
349 render('admin/repos/repo_edit.mako'),
350 defaults=defaults,
350 defaults=defaults,
351 encoding="UTF-8",
351 encoding="UTF-8",
352 force_defaults=False)
352 force_defaults=False)
353
353
354 @HasRepoPermissionAllDecorator('repository.admin')
354 @HasRepoPermissionAllDecorator('repository.admin')
355 @auth.CSRFRequired()
355 @auth.CSRFRequired()
356 def edit_permissions_update(self, repo_name):
356 def edit_permissions_update(self, repo_name):
357 form = RepoPermsForm()().to_python(request.POST)
357 form = RepoPermsForm()().to_python(request.POST)
358 RepoModel().update_permissions(repo_name,
358 RepoModel().update_permissions(repo_name,
359 form['perm_additions'], form['perm_updates'], form['perm_deletions'])
359 form['perm_additions'], form['perm_updates'], form['perm_deletions'])
360
360
361 #TODO: implement this
361 #TODO: implement this
362 #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions',
362 #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions',
363 # repo_name, self.ip_addr, self.sa)
363 # repo_name, self.ip_addr, self.sa)
364 Session().commit()
364 Session().commit()
365 h.flash(_('Repository permissions updated'), category='success')
365 h.flash(_('Repository permissions updated'), category='success')
366 return redirect(url('edit_repo_perms', repo_name=repo_name))
366 return redirect(url('edit_repo_perms', repo_name=repo_name))
367
367
368 @HasRepoPermissionAllDecorator('repository.admin')
368 @HasRepoPermissionAllDecorator('repository.admin')
369 def edit_fields(self, repo_name):
369 def edit_fields(self, repo_name):
370 """GET /repo_name/settings: Form to edit an existing item"""
370 """GET /repo_name/settings: Form to edit an existing item"""
371 c.repo_info = self._load_repo(repo_name)
371 c.repo_info = self._load_repo(repo_name)
372 c.repo_fields = RepositoryField.query()\
372 c.repo_fields = RepositoryField.query()\
373 .filter(RepositoryField.repository == c.repo_info).all()
373 .filter(RepositoryField.repository == c.repo_info).all()
374 c.active = 'fields'
374 c.active = 'fields'
375 if request.POST:
375 if request.POST:
376
376
377 return redirect(url('repo_edit_fields'))
377 return redirect(url('repo_edit_fields'))
378 return render('admin/repos/repo_edit.mako')
378 return render('admin/repos/repo_edit.mako')
379
379
380 @HasRepoPermissionAllDecorator('repository.admin')
380 @HasRepoPermissionAllDecorator('repository.admin')
381 @auth.CSRFRequired()
381 @auth.CSRFRequired()
382 def create_repo_field(self, repo_name):
382 def create_repo_field(self, repo_name):
383 try:
383 try:
384 form_result = RepoFieldForm()().to_python(dict(request.POST))
384 form_result = RepoFieldForm()().to_python(dict(request.POST))
385 RepoModel().add_repo_field(
385 RepoModel().add_repo_field(
386 repo_name, form_result['new_field_key'],
386 repo_name, form_result['new_field_key'],
387 field_type=form_result['new_field_type'],
387 field_type=form_result['new_field_type'],
388 field_value=form_result['new_field_value'],
388 field_value=form_result['new_field_value'],
389 field_label=form_result['new_field_label'],
389 field_label=form_result['new_field_label'],
390 field_desc=form_result['new_field_desc'])
390 field_desc=form_result['new_field_desc'])
391
391
392 Session().commit()
392 Session().commit()
393 except Exception as e:
393 except Exception as e:
394 log.exception("Exception creating field")
394 log.exception("Exception creating field")
395 msg = _('An error occurred during creation of field')
395 msg = _('An error occurred during creation of field')
396 if isinstance(e, formencode.Invalid):
396 if isinstance(e, formencode.Invalid):
397 msg += ". " + e.msg
397 msg += ". " + e.msg
398 h.flash(msg, category='error')
398 h.flash(msg, category='error')
399 return redirect(url('edit_repo_fields', repo_name=repo_name))
399 return redirect(url('edit_repo_fields', repo_name=repo_name))
400
400
401 @HasRepoPermissionAllDecorator('repository.admin')
401 @HasRepoPermissionAllDecorator('repository.admin')
402 @auth.CSRFRequired()
402 @auth.CSRFRequired()
403 def delete_repo_field(self, repo_name, field_id):
403 def delete_repo_field(self, repo_name, field_id):
404 field = RepositoryField.get_or_404(field_id)
404 field = RepositoryField.get_or_404(field_id)
405 try:
405 try:
406 RepoModel().delete_repo_field(repo_name, field.field_key)
406 RepoModel().delete_repo_field(repo_name, field.field_key)
407 Session().commit()
407 Session().commit()
408 except Exception as e:
408 except Exception as e:
409 log.exception("Exception during removal of field")
409 log.exception("Exception during removal of field")
410 msg = _('An error occurred during removal of field')
410 msg = _('An error occurred during removal of field')
411 h.flash(msg, category='error')
411 h.flash(msg, category='error')
412 return redirect(url('edit_repo_fields', repo_name=repo_name))
412 return redirect(url('edit_repo_fields', repo_name=repo_name))
413
413
414 @HasRepoPermissionAllDecorator('repository.admin')
414 @HasRepoPermissionAllDecorator('repository.admin')
415 def edit_advanced(self, repo_name):
415 def edit_advanced(self, repo_name):
416 """GET /repo_name/settings: Form to edit an existing item"""
416 """GET /repo_name/settings: Form to edit an existing item"""
417 c.repo_info = self._load_repo(repo_name)
417 c.repo_info = self._load_repo(repo_name)
418 c.default_user_id = User.get_default_user().user_id
418 c.default_user_id = User.get_default_user().user_id
419 c.in_public_journal = UserFollowing.query()\
419 c.in_public_journal = UserFollowing.query()\
420 .filter(UserFollowing.user_id == c.default_user_id)\
420 .filter(UserFollowing.user_id == c.default_user_id)\
421 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
421 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
422
422
423 c.active = 'advanced'
423 c.active = 'advanced'
424 c.has_origin_repo_read_perm = False
424 c.has_origin_repo_read_perm = False
425 if c.repo_info.fork:
425 if c.repo_info.fork:
426 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
426 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
427 'repository.write', 'repository.read', 'repository.admin')(
427 'repository.write', 'repository.read', 'repository.admin')(
428 c.repo_info.fork.repo_name, 'repo set as fork page')
428 c.repo_info.fork.repo_name, 'repo set as fork page')
429
429
430 if request.POST:
430 if request.POST:
431 return redirect(url('repo_edit_advanced'))
431 return redirect(url('repo_edit_advanced'))
432 return render('admin/repos/repo_edit.mako')
432 return render('admin/repos/repo_edit.mako')
433
433
434 @HasRepoPermissionAllDecorator('repository.admin')
434 @HasRepoPermissionAllDecorator('repository.admin')
435 @auth.CSRFRequired()
435 @auth.CSRFRequired()
436 def edit_advanced_journal(self, repo_name):
436 def edit_advanced_journal(self, repo_name):
437 """
437 """
438 Set's this repository to be visible in public journal,
438 Set's this repository to be visible in public journal,
439 in other words assing default user to follow this repo
439 in other words assing default user to follow this repo
440
440
441 :param repo_name:
441 :param repo_name:
442 """
442 """
443
443
444 try:
444 try:
445 repo_id = Repository.get_by_repo_name(repo_name).repo_id
445 repo_id = Repository.get_by_repo_name(repo_name).repo_id
446 user_id = User.get_default_user().user_id
446 user_id = User.get_default_user().user_id
447 self.scm_model.toggle_following_repo(repo_id, user_id)
447 self.scm_model.toggle_following_repo(repo_id, user_id)
448 h.flash(_('Updated repository visibility in public journal'),
448 h.flash(_('Updated repository visibility in public journal'),
449 category='success')
449 category='success')
450 Session().commit()
450 Session().commit()
451 except Exception:
451 except Exception:
452 h.flash(_('An error occurred during setting this'
452 h.flash(_('An error occurred during setting this'
453 ' repository in public journal'),
453 ' repository in public journal'),
454 category='error')
454 category='error')
455
455
456 return redirect(url('edit_repo_advanced', repo_name=repo_name))
456 return redirect(url('edit_repo_advanced', repo_name=repo_name))
457
457
458 @HasRepoPermissionAllDecorator('repository.admin')
458 @HasRepoPermissionAllDecorator('repository.admin')
459 @auth.CSRFRequired()
459 @auth.CSRFRequired()
460 def edit_advanced_fork(self, repo_name):
460 def edit_advanced_fork(self, repo_name):
461 """
461 """
462 Mark given repository as a fork of another
462 Mark given repository as a fork of another
463
463
464 :param repo_name:
464 :param repo_name:
465 """
465 """
466
466
467 new_fork_id = request.POST.get('id_fork_of')
467 new_fork_id = request.POST.get('id_fork_of')
468 try:
468 try:
469
469
470 if new_fork_id and not new_fork_id.isdigit():
470 if new_fork_id and not new_fork_id.isdigit():
471 log.error('Given fork id %s is not an INT', new_fork_id)
471 log.error('Given fork id %s is not an INT', new_fork_id)
472
472
473 fork_id = safe_int(new_fork_id)
473 fork_id = safe_int(new_fork_id)
474 repo = ScmModel().mark_as_fork(repo_name, fork_id,
474 repo = ScmModel().mark_as_fork(repo_name, fork_id,
475 c.rhodecode_user.username)
475 c.rhodecode_user.username)
476 fork = repo.fork.repo_name if repo.fork else _('Nothing')
476 fork = repo.fork.repo_name if repo.fork else _('Nothing')
477 Session().commit()
477 Session().commit()
478 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
478 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
479 category='success')
479 category='success')
480 except RepositoryError as e:
480 except RepositoryError as e:
481 log.exception("Repository Error occurred")
481 log.exception("Repository Error occurred")
482 h.flash(str(e), category='error')
482 h.flash(str(e), category='error')
483 except Exception as e:
483 except Exception as e:
484 log.exception("Exception while editing fork")
484 log.exception("Exception while editing fork")
485 h.flash(_('An error occurred during this operation'),
485 h.flash(_('An error occurred during this operation'),
486 category='error')
486 category='error')
487
487
488 return redirect(url('edit_repo_advanced', repo_name=repo_name))
488 return redirect(url('edit_repo_advanced', repo_name=repo_name))
489
489
490 @HasRepoPermissionAllDecorator('repository.admin')
490 @HasRepoPermissionAllDecorator('repository.admin')
491 @auth.CSRFRequired()
491 @auth.CSRFRequired()
492 def edit_advanced_locking(self, repo_name):
492 def edit_advanced_locking(self, repo_name):
493 """
493 """
494 Unlock repository when it is locked !
494 Unlock repository when it is locked !
495
495
496 :param repo_name:
496 :param repo_name:
497 """
497 """
498 try:
498 try:
499 repo = Repository.get_by_repo_name(repo_name)
499 repo = Repository.get_by_repo_name(repo_name)
500 if request.POST.get('set_lock'):
500 if request.POST.get('set_lock'):
501 Repository.lock(repo, c.rhodecode_user.user_id,
501 Repository.lock(repo, c.rhodecode_user.user_id,
502 lock_reason=Repository.LOCK_WEB)
502 lock_reason=Repository.LOCK_WEB)
503 h.flash(_('Locked repository'), category='success')
503 h.flash(_('Locked repository'), category='success')
504 elif request.POST.get('set_unlock'):
504 elif request.POST.get('set_unlock'):
505 Repository.unlock(repo)
505 Repository.unlock(repo)
506 h.flash(_('Unlocked repository'), category='success')
506 h.flash(_('Unlocked repository'), category='success')
507 except Exception as e:
507 except Exception as e:
508 log.exception("Exception during unlocking")
508 log.exception("Exception during unlocking")
509 h.flash(_('An error occurred during unlocking'),
509 h.flash(_('An error occurred during unlocking'),
510 category='error')
510 category='error')
511 return redirect(url('edit_repo_advanced', repo_name=repo_name))
511 return redirect(url('edit_repo_advanced', repo_name=repo_name))
512
512
513 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
513 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
514 @auth.CSRFRequired()
514 @auth.CSRFRequired()
515 def toggle_locking(self, repo_name):
515 def toggle_locking(self, repo_name):
516 """
516 """
517 Toggle locking of repository by simple GET call to url
517 Toggle locking of repository by simple GET call to url
518
518
519 :param repo_name:
519 :param repo_name:
520 """
520 """
521
521
522 try:
522 try:
523 repo = Repository.get_by_repo_name(repo_name)
523 repo = Repository.get_by_repo_name(repo_name)
524
524
525 if repo.enable_locking:
525 if repo.enable_locking:
526 if repo.locked[0]:
526 if repo.locked[0]:
527 Repository.unlock(repo)
527 Repository.unlock(repo)
528 action = _('Unlocked')
528 action = _('Unlocked')
529 else:
529 else:
530 Repository.lock(repo, c.rhodecode_user.user_id,
530 Repository.lock(repo, c.rhodecode_user.user_id,
531 lock_reason=Repository.LOCK_WEB)
531 lock_reason=Repository.LOCK_WEB)
532 action = _('Locked')
532 action = _('Locked')
533
533
534 h.flash(_('Repository has been %s') % action,
534 h.flash(_('Repository has been %s') % action,
535 category='success')
535 category='success')
536 except Exception:
536 except Exception:
537 log.exception("Exception during unlocking")
537 log.exception("Exception during unlocking")
538 h.flash(_('An error occurred during unlocking'),
538 h.flash(_('An error occurred during unlocking'),
539 category='error')
539 category='error')
540 return redirect(url('summary_home', repo_name=repo_name))
540 return redirect(url('summary_home', repo_name=repo_name))
541
541
542 @HasRepoPermissionAllDecorator('repository.admin')
542 @HasRepoPermissionAllDecorator('repository.admin')
543 @auth.CSRFRequired()
543 @auth.CSRFRequired()
544 def edit_caches(self, repo_name):
545 """PUT /{repo_name}/settings/caches: invalidate the repo caches."""
546 try:
547 ScmModel().mark_for_invalidation(repo_name, delete=True)
548 Session().commit()
549 h.flash(_('Cache invalidation successful'),
550 category='success')
551 except Exception:
552 log.exception("Exception during cache invalidation")
553 h.flash(_('An error occurred during cache invalidation'),
554 category='error')
555
556 return redirect(url('edit_repo_caches', repo_name=c.repo_name))
557
558 @HasRepoPermissionAllDecorator('repository.admin')
559 def edit_caches_form(self, repo_name):
560 """GET /repo_name/settings: Form to edit an existing item"""
561 c.repo_info = self._load_repo(repo_name)
562 c.active = 'caches'
563
564 return render('admin/repos/repo_edit.mako')
565
566 @HasRepoPermissionAllDecorator('repository.admin')
567 @auth.CSRFRequired()
568 def edit_remote(self, repo_name):
544 def edit_remote(self, repo_name):
569 """PUT /{repo_name}/settings/remote: edit the repo remote."""
545 """PUT /{repo_name}/settings/remote: edit the repo remote."""
570 try:
546 try:
571 ScmModel().pull_changes(repo_name, c.rhodecode_user.username)
547 ScmModel().pull_changes(repo_name, c.rhodecode_user.username)
572 h.flash(_('Pulled from remote location'), category='success')
548 h.flash(_('Pulled from remote location'), category='success')
573 except Exception:
549 except Exception:
574 log.exception("Exception during pull from remote")
550 log.exception("Exception during pull from remote")
575 h.flash(_('An error occurred during pull from remote location'),
551 h.flash(_('An error occurred during pull from remote location'),
576 category='error')
552 category='error')
577 return redirect(url('edit_repo_remote', repo_name=c.repo_name))
553 return redirect(url('edit_repo_remote', repo_name=c.repo_name))
578
554
579 @HasRepoPermissionAllDecorator('repository.admin')
555 @HasRepoPermissionAllDecorator('repository.admin')
580 def edit_remote_form(self, repo_name):
556 def edit_remote_form(self, repo_name):
581 """GET /repo_name/settings: Form to edit an existing item"""
557 """GET /repo_name/settings: Form to edit an existing item"""
582 c.repo_info = self._load_repo(repo_name)
558 c.repo_info = self._load_repo(repo_name)
583 c.active = 'remote'
559 c.active = 'remote'
584
560
585 return render('admin/repos/repo_edit.mako')
561 return render('admin/repos/repo_edit.mako')
586
562
587 @HasRepoPermissionAllDecorator('repository.admin')
563 @HasRepoPermissionAllDecorator('repository.admin')
588 @auth.CSRFRequired()
564 @auth.CSRFRequired()
589 def edit_statistics(self, repo_name):
565 def edit_statistics(self, repo_name):
590 """PUT /{repo_name}/settings/statistics: reset the repo statistics."""
566 """PUT /{repo_name}/settings/statistics: reset the repo statistics."""
591 try:
567 try:
592 RepoModel().delete_stats(repo_name)
568 RepoModel().delete_stats(repo_name)
593 Session().commit()
569 Session().commit()
594 except Exception as e:
570 except Exception as e:
595 log.error(traceback.format_exc())
571 log.error(traceback.format_exc())
596 h.flash(_('An error occurred during deletion of repository stats'),
572 h.flash(_('An error occurred during deletion of repository stats'),
597 category='error')
573 category='error')
598 return redirect(url('edit_repo_statistics', repo_name=c.repo_name))
574 return redirect(url('edit_repo_statistics', repo_name=c.repo_name))
599
575
600 @HasRepoPermissionAllDecorator('repository.admin')
576 @HasRepoPermissionAllDecorator('repository.admin')
601 def edit_statistics_form(self, repo_name):
577 def edit_statistics_form(self, repo_name):
602 """GET /repo_name/settings: Form to edit an existing item"""
578 """GET /repo_name/settings: Form to edit an existing item"""
603 c.repo_info = self._load_repo(repo_name)
579 c.repo_info = self._load_repo(repo_name)
604 repo = c.repo_info.scm_instance()
580 repo = c.repo_info.scm_instance()
605
581
606 if c.repo_info.stats:
582 if c.repo_info.stats:
607 # this is on what revision we ended up so we add +1 for count
583 # this is on what revision we ended up so we add +1 for count
608 last_rev = c.repo_info.stats.stat_on_revision + 1
584 last_rev = c.repo_info.stats.stat_on_revision + 1
609 else:
585 else:
610 last_rev = 0
586 last_rev = 0
611 c.stats_revision = last_rev
587 c.stats_revision = last_rev
612
588
613 c.repo_last_rev = repo.count()
589 c.repo_last_rev = repo.count()
614
590
615 if last_rev == 0 or c.repo_last_rev == 0:
591 if last_rev == 0 or c.repo_last_rev == 0:
616 c.stats_percentage = 0
592 c.stats_percentage = 0
617 else:
593 else:
618 c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100)
594 c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100)
619
595
620 c.active = 'statistics'
596 c.active = 'statistics'
621
597
622 return render('admin/repos/repo_edit.mako')
598 return render('admin/repos/repo_edit.mako')
623
599
624 @HasRepoPermissionAllDecorator('repository.admin')
600 @HasRepoPermissionAllDecorator('repository.admin')
625 @auth.CSRFRequired()
601 @auth.CSRFRequired()
626 def repo_issuetracker_test(self, repo_name):
602 def repo_issuetracker_test(self, repo_name):
627 if request.is_xhr:
603 if request.is_xhr:
628 return h.urlify_commit_message(
604 return h.urlify_commit_message(
629 request.POST.get('test_text', ''),
605 request.POST.get('test_text', ''),
630 repo_name)
606 repo_name)
631 else:
607 else:
632 raise HTTPBadRequest()
608 raise HTTPBadRequest()
633
609
634 @HasRepoPermissionAllDecorator('repository.admin')
610 @HasRepoPermissionAllDecorator('repository.admin')
635 @auth.CSRFRequired()
611 @auth.CSRFRequired()
636 def repo_issuetracker_delete(self, repo_name):
612 def repo_issuetracker_delete(self, repo_name):
637 uid = request.POST.get('uid')
613 uid = request.POST.get('uid')
638 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
614 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
639 try:
615 try:
640 repo_settings.delete_entries(uid)
616 repo_settings.delete_entries(uid)
641 except Exception:
617 except Exception:
642 h.flash(_('Error occurred during deleting issue tracker entry'),
618 h.flash(_('Error occurred during deleting issue tracker entry'),
643 category='error')
619 category='error')
644 else:
620 else:
645 h.flash(_('Removed issue tracker entry'), category='success')
621 h.flash(_('Removed issue tracker entry'), category='success')
646 return redirect(url('repo_settings_issuetracker',
622 return redirect(url('repo_settings_issuetracker',
647 repo_name=repo_name))
623 repo_name=repo_name))
648
624
649 def _update_patterns(self, form, repo_settings):
625 def _update_patterns(self, form, repo_settings):
650 for uid in form['delete_patterns']:
626 for uid in form['delete_patterns']:
651 repo_settings.delete_entries(uid)
627 repo_settings.delete_entries(uid)
652
628
653 for pattern in form['patterns']:
629 for pattern in form['patterns']:
654 for setting, value, type_ in pattern:
630 for setting, value, type_ in pattern:
655 sett = repo_settings.create_or_update_setting(
631 sett = repo_settings.create_or_update_setting(
656 setting, value, type_)
632 setting, value, type_)
657 Session().add(sett)
633 Session().add(sett)
658
634
659 Session().commit()
635 Session().commit()
660
636
661 @HasRepoPermissionAllDecorator('repository.admin')
637 @HasRepoPermissionAllDecorator('repository.admin')
662 @auth.CSRFRequired()
638 @auth.CSRFRequired()
663 def repo_issuetracker_save(self, repo_name):
639 def repo_issuetracker_save(self, repo_name):
664 # Save inheritance
640 # Save inheritance
665 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
641 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
666 inherited = (request.POST.get('inherit_global_issuetracker')
642 inherited = (request.POST.get('inherit_global_issuetracker')
667 == "inherited")
643 == "inherited")
668 repo_settings.inherit_global_settings = inherited
644 repo_settings.inherit_global_settings = inherited
669 Session().commit()
645 Session().commit()
670
646
671 form = IssueTrackerPatternsForm()().to_python(request.POST)
647 form = IssueTrackerPatternsForm()().to_python(request.POST)
672 if form:
648 if form:
673 self._update_patterns(form, repo_settings)
649 self._update_patterns(form, repo_settings)
674
650
675 h.flash(_('Updated issue tracker entries'), category='success')
651 h.flash(_('Updated issue tracker entries'), category='success')
676 return redirect(url('repo_settings_issuetracker',
652 return redirect(url('repo_settings_issuetracker',
677 repo_name=repo_name))
653 repo_name=repo_name))
678
654
679 @HasRepoPermissionAllDecorator('repository.admin')
655 @HasRepoPermissionAllDecorator('repository.admin')
680 def repo_issuetracker(self, repo_name):
656 def repo_issuetracker(self, repo_name):
681 """GET /admin/settings/issue-tracker: All items in the collection"""
657 """GET /admin/settings/issue-tracker: All items in the collection"""
682 c.active = 'issuetracker'
658 c.active = 'issuetracker'
683 c.data = 'data'
659 c.data = 'data'
684 c.repo_info = self._load_repo(repo_name)
660 c.repo_info = self._load_repo(repo_name)
685
661
686 repo = Repository.get_by_repo_name(repo_name)
662 repo = Repository.get_by_repo_name(repo_name)
687 c.settings_model = IssueTrackerSettingsModel(repo=repo)
663 c.settings_model = IssueTrackerSettingsModel(repo=repo)
688 c.global_patterns = c.settings_model.get_global_settings()
664 c.global_patterns = c.settings_model.get_global_settings()
689 c.repo_patterns = c.settings_model.get_repo_settings()
665 c.repo_patterns = c.settings_model.get_repo_settings()
690
666
691 return render('admin/repos/repo_edit.mako')
667 return render('admin/repos/repo_edit.mako')
692
668
693 @HasRepoPermissionAllDecorator('repository.admin')
669 @HasRepoPermissionAllDecorator('repository.admin')
694 def repo_settings_vcs(self, repo_name):
670 def repo_settings_vcs(self, repo_name):
695 """GET /{repo_name}/settings/vcs/: All items in the collection"""
671 """GET /{repo_name}/settings/vcs/: All items in the collection"""
696
672
697 model = VcsSettingsModel(repo=repo_name)
673 model = VcsSettingsModel(repo=repo_name)
698
674
699 c.active = 'vcs'
675 c.active = 'vcs'
700 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
676 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
701 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
677 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
702 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
678 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
703 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
679 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
704 c.repo_info = self._load_repo(repo_name)
680 c.repo_info = self._load_repo(repo_name)
705 defaults = self._vcs_form_defaults(repo_name)
681 defaults = self._vcs_form_defaults(repo_name)
706 c.inherit_global_settings = defaults['inherit_global_settings']
682 c.inherit_global_settings = defaults['inherit_global_settings']
707 c.labs_active = str2bool(
683 c.labs_active = str2bool(
708 rhodecode.CONFIG.get('labs_settings_active', 'true'))
684 rhodecode.CONFIG.get('labs_settings_active', 'true'))
709
685
710 return htmlfill.render(
686 return htmlfill.render(
711 render('admin/repos/repo_edit.mako'),
687 render('admin/repos/repo_edit.mako'),
712 defaults=defaults,
688 defaults=defaults,
713 encoding="UTF-8",
689 encoding="UTF-8",
714 force_defaults=False)
690 force_defaults=False)
715
691
716 @HasRepoPermissionAllDecorator('repository.admin')
692 @HasRepoPermissionAllDecorator('repository.admin')
717 @auth.CSRFRequired()
693 @auth.CSRFRequired()
718 def repo_settings_vcs_update(self, repo_name):
694 def repo_settings_vcs_update(self, repo_name):
719 """POST /{repo_name}/settings/vcs/: All items in the collection"""
695 """POST /{repo_name}/settings/vcs/: All items in the collection"""
720 c.active = 'vcs'
696 c.active = 'vcs'
721
697
722 model = VcsSettingsModel(repo=repo_name)
698 model = VcsSettingsModel(repo=repo_name)
723 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
699 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
724 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
700 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
725 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
701 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
726 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
702 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
727 c.repo_info = self._load_repo(repo_name)
703 c.repo_info = self._load_repo(repo_name)
728 defaults = self._vcs_form_defaults(repo_name)
704 defaults = self._vcs_form_defaults(repo_name)
729 c.inherit_global_settings = defaults['inherit_global_settings']
705 c.inherit_global_settings = defaults['inherit_global_settings']
730
706
731 application_form = RepoVcsSettingsForm(repo_name)()
707 application_form = RepoVcsSettingsForm(repo_name)()
732 try:
708 try:
733 form_result = application_form.to_python(dict(request.POST))
709 form_result = application_form.to_python(dict(request.POST))
734 except formencode.Invalid as errors:
710 except formencode.Invalid as errors:
735 h.flash(
711 h.flash(
736 _("Some form inputs contain invalid data."),
712 _("Some form inputs contain invalid data."),
737 category='error')
713 category='error')
738 return htmlfill.render(
714 return htmlfill.render(
739 render('admin/repos/repo_edit.mako'),
715 render('admin/repos/repo_edit.mako'),
740 defaults=errors.value,
716 defaults=errors.value,
741 errors=errors.error_dict or {},
717 errors=errors.error_dict or {},
742 prefix_error=False,
718 prefix_error=False,
743 encoding="UTF-8",
719 encoding="UTF-8",
744 force_defaults=False
720 force_defaults=False
745 )
721 )
746
722
747 try:
723 try:
748 inherit_global_settings = form_result['inherit_global_settings']
724 inherit_global_settings = form_result['inherit_global_settings']
749 model.create_or_update_repo_settings(
725 model.create_or_update_repo_settings(
750 form_result, inherit_global_settings=inherit_global_settings)
726 form_result, inherit_global_settings=inherit_global_settings)
751 except Exception:
727 except Exception:
752 log.exception("Exception while updating settings")
728 log.exception("Exception while updating settings")
753 h.flash(
729 h.flash(
754 _('Error occurred during updating repository VCS settings'),
730 _('Error occurred during updating repository VCS settings'),
755 category='error')
731 category='error')
756 else:
732 else:
757 Session().commit()
733 Session().commit()
758 h.flash(_('Updated VCS settings'), category='success')
734 h.flash(_('Updated VCS settings'), category='success')
759 return redirect(url('repo_vcs_settings', repo_name=repo_name))
735 return redirect(url('repo_vcs_settings', repo_name=repo_name))
760
736
761 return htmlfill.render(
737 return htmlfill.render(
762 render('admin/repos/repo_edit.mako'),
738 render('admin/repos/repo_edit.mako'),
763 defaults=self._vcs_form_defaults(repo_name),
739 defaults=self._vcs_form_defaults(repo_name),
764 encoding="UTF-8",
740 encoding="UTF-8",
765 force_defaults=False)
741 force_defaults=False)
766
742
767 @HasRepoPermissionAllDecorator('repository.admin')
743 @HasRepoPermissionAllDecorator('repository.admin')
768 @auth.CSRFRequired()
744 @auth.CSRFRequired()
769 @jsonify
745 @jsonify
770 def repo_delete_svn_pattern(self, repo_name):
746 def repo_delete_svn_pattern(self, repo_name):
771 if not request.is_xhr:
747 if not request.is_xhr:
772 return False
748 return False
773
749
774 delete_pattern_id = request.POST.get('delete_svn_pattern')
750 delete_pattern_id = request.POST.get('delete_svn_pattern')
775 model = VcsSettingsModel(repo=repo_name)
751 model = VcsSettingsModel(repo=repo_name)
776 try:
752 try:
777 model.delete_repo_svn_pattern(delete_pattern_id)
753 model.delete_repo_svn_pattern(delete_pattern_id)
778 except SettingNotFound:
754 except SettingNotFound:
779 raise HTTPBadRequest()
755 raise HTTPBadRequest()
780
756
781 Session().commit()
757 Session().commit()
782 return True
758 return True
783
759
784 def _vcs_form_defaults(self, repo_name):
760 def _vcs_form_defaults(self, repo_name):
785 model = VcsSettingsModel(repo=repo_name)
761 model = VcsSettingsModel(repo=repo_name)
786 global_defaults = model.get_global_settings()
762 global_defaults = model.get_global_settings()
787
763
788 repo_defaults = {}
764 repo_defaults = {}
789 repo_defaults.update(global_defaults)
765 repo_defaults.update(global_defaults)
790 repo_defaults.update(model.get_repo_settings())
766 repo_defaults.update(model.get_repo_settings())
791
767
792 global_defaults = {
768 global_defaults = {
793 '{}_inherited'.format(k): global_defaults[k]
769 '{}_inherited'.format(k): global_defaults[k]
794 for k in global_defaults}
770 for k in global_defaults}
795
771
796 defaults = {
772 defaults = {
797 'inherit_global_settings': model.inherit_global_settings
773 'inherit_global_settings': model.inherit_global_settings
798 }
774 }
799 defaults.update(global_defaults)
775 defaults.update(global_defaults)
800 defaults.update(repo_defaults)
776 defaults.update(repo_defaults)
801 defaults.update({
777 defaults.update({
802 'new_svn_branch': '',
778 'new_svn_branch': '',
803 'new_svn_tag': '',
779 'new_svn_tag': '',
804 })
780 })
805 return defaults
781 return defaults
@@ -1,116 +1,117 b''
1
1
2 /******************************************************************************
2 /******************************************************************************
3 * *
3 * *
4 * DO NOT CHANGE THIS FILE MANUALLY *
4 * DO NOT CHANGE THIS FILE MANUALLY *
5 * *
5 * *
6 * *
6 * *
7 * This file is automatically generated when the app starts up with *
7 * This file is automatically generated when the app starts up with *
8 * generate_js_files = true *
8 * generate_js_files = true *
9 * *
9 * *
10 * To add a route here pass jsroute=True to the route definition in the app *
10 * To add a route here pass jsroute=True to the route definition in the app *
11 * *
11 * *
12 ******************************************************************************/
12 ******************************************************************************/
13 function registerRCRoutes() {
13 function registerRCRoutes() {
14 // routes registration
14 // routes registration
15 pyroutes.register('home', '/', []);
15 pyroutes.register('home', '/', []);
16 pyroutes.register('new_repo', '/_admin/create_repository', []);
16 pyroutes.register('new_repo', '/_admin/create_repository', []);
17 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
17 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
18 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
18 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
19 pyroutes.register('gists', '/_admin/gists', []);
19 pyroutes.register('gists', '/_admin/gists', []);
20 pyroutes.register('new_gist', '/_admin/gists/new', []);
20 pyroutes.register('new_gist', '/_admin/gists/new', []);
21 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
21 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
22 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
22 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
23 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
23 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
24 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
24 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
25 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
25 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
26 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
26 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
27 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
27 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
28 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
28 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
29 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
29 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
30 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
30 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
31 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
31 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
32 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
32 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
33 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
33 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
34 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
34 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
35 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
35 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
36 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
36 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
37 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
37 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
39 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
39 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
40 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
40 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
41 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
41 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
42 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
42 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
43 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
43 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
44 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
44 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
45 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
45 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
46 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
46 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
50 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
50 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
51 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
51 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
52 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
52 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
53 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
53 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
54 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
54 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
55 pyroutes.register('favicon', '/favicon.ico', []);
55 pyroutes.register('favicon', '/favicon.ico', []);
56 pyroutes.register('robots', '/robots.txt', []);
56 pyroutes.register('robots', '/robots.txt', []);
57 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
57 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
58 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
58 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
59 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
59 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
60 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
60 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
61 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
61 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
62 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
62 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
63 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
63 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
64 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
64 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
65 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
65 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
66 pyroutes.register('repo_group_integrations_create', '%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
66 pyroutes.register('repo_group_integrations_create', '%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
67 pyroutes.register('repo_group_integrations_edit', '%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
67 pyroutes.register('repo_group_integrations_edit', '%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
68 pyroutes.register('repo_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
68 pyroutes.register('repo_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
69 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
69 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
70 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
70 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
71 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
71 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
72 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
72 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
73 pyroutes.register('ops_ping', '_admin/ops/ping', []);
73 pyroutes.register('ops_ping', '_admin/ops/ping', []);
74 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
74 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
75 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
75 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
76 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
76 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
77 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
77 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
78 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
78 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
80 pyroutes.register('users', '_admin/users', []);
80 pyroutes.register('users', '_admin/users', []);
81 pyroutes.register('users_data', '_admin/users_data', []);
81 pyroutes.register('users_data', '_admin/users_data', []);
82 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
82 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
83 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
83 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
84 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
84 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
85 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
85 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
86 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
86 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
87 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
87 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
88 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
88 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
89 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
89 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
90 pyroutes.register('channelstream_proxy', '/_channelstream', []);
90 pyroutes.register('channelstream_proxy', '/_channelstream', []);
91 pyroutes.register('login', '/_admin/login', []);
91 pyroutes.register('login', '/_admin/login', []);
92 pyroutes.register('logout', '/_admin/logout', []);
92 pyroutes.register('logout', '/_admin/logout', []);
93 pyroutes.register('register', '/_admin/register', []);
93 pyroutes.register('register', '/_admin/register', []);
94 pyroutes.register('reset_password', '/_admin/password_reset', []);
94 pyroutes.register('reset_password', '/_admin/password_reset', []);
95 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
95 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
96 pyroutes.register('user_autocomplete_data', '/_users', []);
96 pyroutes.register('user_autocomplete_data', '/_users', []);
97 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
97 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
98 pyroutes.register('repo_list_data', '/_repos', []);
98 pyroutes.register('repo_list_data', '/_repos', []);
99 pyroutes.register('goto_switcher_data', '/_goto_data', []);
99 pyroutes.register('goto_switcher_data', '/_goto_data', []);
100 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
100 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
101 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
101 pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']);
102 pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']);
102 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']);
103 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']);
103 pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']);
104 pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']);
104 pyroutes.register('strip_check', '/%(repo_name)s/strip_check', ['repo_name']);
105 pyroutes.register('strip_check', '/%(repo_name)s/strip_check', ['repo_name']);
105 pyroutes.register('strip_execute', '/%(repo_name)s/strip_execute', ['repo_name']);
106 pyroutes.register('strip_execute', '/%(repo_name)s/strip_execute', ['repo_name']);
106 pyroutes.register('search', '/_admin/search', []);
107 pyroutes.register('search', '/_admin/search', []);
107 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
108 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
108 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
109 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
109 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
110 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
110 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
111 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
111 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
112 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
112 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
113 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
113 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
114 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
114 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
115 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
115 pyroutes.register('apiv2', '/_admin/api', []);
116 pyroutes.register('apiv2', '/_admin/api', []);
116 }
117 }
@@ -1,106 +1,106 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 ##
2 ##
3 ## See also repo_settings.html
3 ## See also repo_settings.html
4 ##
4 ##
5 <%inherit file="/base/base.mako"/>
5 <%inherit file="/base/base.mako"/>
6
6
7 <%def name="title()">
7 <%def name="title()">
8 ${_('%s repository settings') % c.repo_info.repo_name}
8 ${_('%s repository settings') % c.repo_info.repo_name}
9 %if c.rhodecode_name:
9 %if c.rhodecode_name:
10 &middot; ${h.branding(c.rhodecode_name)}
10 &middot; ${h.branding(c.rhodecode_name)}
11 %endif
11 %endif
12 </%def>
12 </%def>
13
13
14 <%def name="breadcrumbs_links()">
14 <%def name="breadcrumbs_links()">
15 ${_('Settings')}
15 ${_('Settings')}
16 </%def>
16 </%def>
17
17
18 <%def name="menu_bar_nav()">
18 <%def name="menu_bar_nav()">
19 ${self.menu_items(active='repositories')}
19 ${self.menu_items(active='repositories')}
20 </%def>
20 </%def>
21
21
22 <%def name="menu_bar_subnav()">
22 <%def name="menu_bar_subnav()">
23 ${self.repo_menu(active='options')}
23 ${self.repo_menu(active='options')}
24 </%def>
24 </%def>
25
25
26 <%def name="main_content()">
26 <%def name="main_content()">
27 <%include file="/admin/repos/repo_edit_${c.active}.mako"/>
27 <%include file="/admin/repos/repo_edit_${c.active}.mako"/>
28 </%def>
28 </%def>
29
29
30
30
31 <%def name="main()">
31 <%def name="main()">
32 <div class="box">
32 <div class="box">
33 <div class="title">
33 <div class="title">
34 ${self.repo_page_title(c.rhodecode_db_repo)}
34 ${self.repo_page_title(c.rhodecode_db_repo)}
35 ${self.breadcrumbs()}
35 ${self.breadcrumbs()}
36 </div>
36 </div>
37
37
38 <div class="sidebar-col-wrapper scw-small">
38 <div class="sidebar-col-wrapper scw-small">
39 ##main
39 ##main
40 <div class="sidebar">
40 <div class="sidebar">
41 <ul class="nav nav-pills nav-stacked">
41 <ul class="nav nav-pills nav-stacked">
42 <li class="${'active' if c.active=='settings' else ''}">
42 <li class="${'active' if c.active=='settings' else ''}">
43 <a href="${h.route_path('edit_repo', repo_name=c.repo_name)}">${_('Settings')}</a>
43 <a href="${h.route_path('edit_repo', repo_name=c.repo_name)}">${_('Settings')}</a>
44 </li>
44 </li>
45 <li class="${'active' if c.active=='permissions' else ''}">
45 <li class="${'active' if c.active=='permissions' else ''}">
46 <a href="${h.url('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a>
46 <a href="${h.url('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a>
47 </li>
47 </li>
48 <li class="${'active' if c.active=='advanced' else ''}">
48 <li class="${'active' if c.active=='advanced' else ''}">
49 <a href="${h.url('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
49 <a href="${h.url('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
50 </li>
50 </li>
51 <li class="${'active' if c.active=='vcs' else ''}">
51 <li class="${'active' if c.active=='vcs' else ''}">
52 <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">${_('VCS')}</a>
52 <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">${_('VCS')}</a>
53 </li>
53 </li>
54 <li class="${'active' if c.active=='fields' else ''}">
54 <li class="${'active' if c.active=='fields' else ''}">
55 <a href="${h.url('edit_repo_fields', repo_name=c.repo_name)}">${_('Extra Fields')}</a>
55 <a href="${h.url('edit_repo_fields', repo_name=c.repo_name)}">${_('Extra Fields')}</a>
56 </li>
56 </li>
57 <li class="${'active' if c.active=='issuetracker' else ''}">
57 <li class="${'active' if c.active=='issuetracker' else ''}">
58 <a href="${h.url('repo_settings_issuetracker', repo_name=c.repo_name)}">${_('Issue Tracker')}</a>
58 <a href="${h.url('repo_settings_issuetracker', repo_name=c.repo_name)}">${_('Issue Tracker')}</a>
59 </li>
59 </li>
60 <li class="${'active' if c.active=='caches' else ''}">
60 <li class="${'active' if c.active=='caches' else ''}">
61 <a href="${h.url('edit_repo_caches', repo_name=c.repo_name)}">${_('Caches')}</a>
61 <a href="${h.route_path('edit_repo_caches', repo_name=c.repo_name)}">${_('Caches')}</a>
62 </li>
62 </li>
63 %if c.repo_info.repo_type != 'svn':
63 %if c.repo_info.repo_type != 'svn':
64 <li class="${'active' if c.active=='remote' else ''}">
64 <li class="${'active' if c.active=='remote' else ''}">
65 <a href="${h.url('edit_repo_remote', repo_name=c.repo_name)}">${_('Remote')}</a>
65 <a href="${h.url('edit_repo_remote', repo_name=c.repo_name)}">${_('Remote')}</a>
66 </li>
66 </li>
67 %endif
67 %endif
68 <li class="${'active' if c.active=='statistics' else ''}">
68 <li class="${'active' if c.active=='statistics' else ''}">
69 <a href="${h.url('edit_repo_statistics', repo_name=c.repo_name)}">${_('Statistics')}</a>
69 <a href="${h.url('edit_repo_statistics', repo_name=c.repo_name)}">${_('Statistics')}</a>
70 </li>
70 </li>
71 <li class="${'active' if c.active=='integrations' else ''}">
71 <li class="${'active' if c.active=='integrations' else ''}">
72 <a href="${h.route_path('repo_integrations_home', repo_name=c.repo_name)}">${_('Integrations')}</a>
72 <a href="${h.route_path('repo_integrations_home', repo_name=c.repo_name)}">${_('Integrations')}</a>
73 </li>
73 </li>
74 <li class="${'active' if c.active=='maintenance' else ''}">
74 <li class="${'active' if c.active=='maintenance' else ''}">
75 <a href="${h.route_path('repo_maintenance', repo_name=c.repo_name)}">${_('Maintenance')}</a>
75 <a href="${h.route_path('repo_maintenance', repo_name=c.repo_name)}">${_('Maintenance')}</a>
76 </li>
76 </li>
77 <li class="${'active' if c.active=='strip' else ''}">
77 <li class="${'active' if c.active=='strip' else ''}">
78 <a href="${h.route_path('strip', repo_name=c.repo_name)}">${_('Strip')}</a>
78 <a href="${h.route_path('strip', repo_name=c.repo_name)}">${_('Strip')}</a>
79 </li>
79 </li>
80 ## TODO: dan: replace repo navigation with navlist registry like with
80 ## TODO: dan: replace repo navigation with navlist registry like with
81 ## admin menu. First must find way to allow runtime configuration
81 ## admin menu. First must find way to allow runtime configuration
82 ## it to account for the c.repo_info.repo_type != 'svn' call above
82 ## it to account for the c.repo_info.repo_type != 'svn' call above
83 <%
83 <%
84 reviewer_settings = False
84 reviewer_settings = False
85 try:
85 try:
86 import rc_reviewers
86 import rc_reviewers
87 reviewer_settings = True
87 reviewer_settings = True
88 except ImportError:
88 except ImportError:
89 pass
89 pass
90 %>
90 %>
91 %if reviewer_settings:
91 %if reviewer_settings:
92 <li class="${'active' if c.active=='reviewers' else ''}">
92 <li class="${'active' if c.active=='reviewers' else ''}">
93 <a href="${h.route_path('repo_reviewers_home', repo_name=c.repo_name)}">${_('Reviewers')}</a>
93 <a href="${h.route_path('repo_reviewers_home', repo_name=c.repo_name)}">${_('Reviewers')}</a>
94 </li>
94 </li>
95 %endif
95 %endif
96 </ul>
96 </ul>
97 </div>
97 </div>
98
98
99 <div class="main-content-full-width">
99 <div class="main-content-full-width">
100 ${self.main_content()}
100 ${self.main_content()}
101 </div>
101 </div>
102
102
103 </div>
103 </div>
104 </div>
104 </div>
105
105
106 </%def> No newline at end of file
106 </%def>
@@ -1,51 +1,55 b''
1 <div class="panel panel-default">
1 <div class="panel panel-default">
2 <div class="panel-heading">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Invalidate Cache for Repository')}</h3>
3 <h3 class="panel-title">${_('Invalidate Cache for Repository')}</h3>
4 </div>
4 </div>
5 <div class="panel-body">
5 <div class="panel-body">
6 ${h.secure_form(url('edit_repo_caches', repo_name=c.repo_name), method='put')}
6
7 <div>
7 <h4>${_('Manually invalidate the repository cache. On the next access a repository cache will be recreated.')}</h4>
8 <div class="fields">
8
9 <p>
9 <p>
10 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
10 ${_('Cache purge can be automated by such api call called periodically (in crontab etc)')}
11 <br/>
12 <code>
13 curl ${h.route_url('apiv2')} -X POST -H 'content-type:text/plain' --data-binary '{"id":1, "auth_token":"SECRET", "method":"invalidate_cache", "args":{"repoid":"${c.repo_info.repo_name}"}}'
14 </code>
11 </p>
15 </p>
12 <div class="field" >
13 <span class="help-block">
14 ${_('Manually invalidate the repository cache. On the next access a repository cache will be recreated.')}
15 </span>
16 </div>
17
16
17 ${h.secure_form(h.route_path('edit_repo_caches', repo_name=c.repo_name), method='POST')}
18 <div class="form">
19 <div class="fields">
20 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
18 </div>
21 </div>
19 </div>
22 </div>
20 ${h.end_form()}
23 ${h.end_form()}
24
21 </div>
25 </div>
22 </div>
26 </div>
23
27
24
28
25 <div class="panel panel-default">
29 <div class="panel panel-default">
26 <div class="panel-heading">
30 <div class="panel-heading">
27 <h3 class="panel-title">
31 <h3 class="panel-title">
28 ${(ungettext('List of repository caches (%(count)s entry)', 'List of repository caches (%(count)s entries)' ,len(c.repo_info.cache_keys)) % {'count': len(c.repo_info.cache_keys)})}
32 ${(_ungettext('List of repository caches (%(count)s entry)', 'List of repository caches (%(count)s entries)' ,len(c.repo_info.cache_keys)) % {'count': len(c.repo_info.cache_keys)})}
29 </h3>
33 </h3>
30 </div>
34 </div>
31 <div class="panel-body">
35 <div class="panel-body">
32 <div class="field" >
36 <div class="field" >
33 <table class="rctable edit_cache">
37 <table class="rctable edit_cache">
34 <tr>
38 <tr>
35 <th>${_('Prefix')}</th>
39 <th>${_('Prefix')}</th>
36 <th>${_('Key')}</th>
40 <th>${_('Key')}</th>
37 <th>${_('Active')}</th>
41 <th>${_('Active')}</th>
38 </tr>
42 </tr>
39 %for cache in c.repo_info.cache_keys:
43 %for cache in c.repo_info.cache_keys:
40 <tr>
44 <tr>
41 <td class="td-prefix">${cache.get_prefix() or '-'}</td>
45 <td class="td-prefix">${cache.get_prefix() or '-'}</td>
42 <td class="td-cachekey">${cache.cache_key}</td>
46 <td class="td-cachekey">${cache.cache_key}</td>
43 <td class="td-active">${h.bool2icon(cache.cache_active)}</td>
47 <td class="td-active">${h.bool2icon(cache.cache_active)}</td>
44 </tr>
48 </tr>
45 %endfor
49 %endfor
46 </table>
50 </table>
47 </div>
51 </div>
48 </div>
52 </div>
49 </div>
53 </div>
50
54
51
55
General Comments 0
You need to be logged in to leave comments. Login now