##// END OF EJS Templates
audit-logger: unify calls to repo.delete and also store source of call, api/web.
marcink -
r1752:9e047971 default
parent child Browse files
Show More
@@ -1,72 +1,74 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.model.repo import RepoModel
24 from rhodecode.model.repo import RepoModel
25 from rhodecode.api.tests.utils import (
25 from rhodecode.api.tests.utils import (
26 build_data, api_call, assert_error, assert_ok, crash)
26 build_data, api_call, assert_error, assert_ok, crash)
27
27
28
28
29 @pytest.mark.usefixtures("testuser_api", "app")
29 @pytest.mark.usefixtures("testuser_api", "app")
30 class TestApiDeleteRepo(object):
30 class TestApiDeleteRepo(object):
31 def test_api_delete_repo(self, backend):
31 def test_api_delete_repo(self, backend):
32 repo = backend.create_repo()
32 repo = backend.create_repo()
33
33 repo_name = repo.repo_name
34 id_, params = build_data(
34 id_, params = build_data(
35 self.apikey, 'delete_repo', repoid=repo.repo_name, )
35 self.apikey, 'delete_repo', repoid=repo.repo_name, )
36 response = api_call(self.app, params)
36 response = api_call(self.app, params)
37
37
38 expected = {
38 expected = {
39 'msg': 'Deleted repository `%s`' % (repo.repo_name,),
39 'msg': 'Deleted repository `%s`' % (repo_name,),
40 'success': True
40 'success': True
41 }
41 }
42 assert_ok(id_, expected, given=response.body)
42 assert_ok(id_, expected, given=response.body)
43
43
44 def test_api_delete_repo_by_non_admin(self, backend, user_regular):
44 def test_api_delete_repo_by_non_admin(self, backend, user_regular):
45 repo = backend.create_repo(cur_user=user_regular.username)
45 repo = backend.create_repo(cur_user=user_regular.username)
46 repo_name = repo.repo_name
46 id_, params = build_data(
47 id_, params = build_data(
47 user_regular.api_key, 'delete_repo', repoid=repo.repo_name, )
48 user_regular.api_key, 'delete_repo', repoid=repo.repo_name, )
48 response = api_call(self.app, params)
49 response = api_call(self.app, params)
49
50
50 expected = {
51 expected = {
51 'msg': 'Deleted repository `%s`' % (repo.repo_name,),
52 'msg': 'Deleted repository `%s`' % (repo_name,),
52 'success': True
53 'success': True
53 }
54 }
54 assert_ok(id_, expected, given=response.body)
55 assert_ok(id_, expected, given=response.body)
55
56
56 def test_api_delete_repo_by_non_admin_no_permission(self, backend):
57 def test_api_delete_repo_by_non_admin_no_permission(self, backend):
57 repo = backend.create_repo()
58 repo = backend.create_repo()
59 repo_name = repo.repo_name
58 id_, params = build_data(
60 id_, params = build_data(
59 self.apikey_regular, 'delete_repo', repoid=repo.repo_name, )
61 self.apikey_regular, 'delete_repo', repoid=repo.repo_name, )
60 response = api_call(self.app, params)
62 response = api_call(self.app, params)
61 expected = 'repository `%s` does not exist' % (repo.repo_name)
63 expected = 'repository `%s` does not exist' % (repo_name)
62 assert_error(id_, expected, given=response.body)
64 assert_error(id_, expected, given=response.body)
63
65
64 def test_api_delete_repo_exception_occurred(self, backend):
66 def test_api_delete_repo_exception_occurred(self, backend):
65 repo = backend.create_repo()
67 repo = backend.create_repo()
68 repo_name = repo.repo_name
66 id_, params = build_data(
69 id_, params = build_data(
67 self.apikey, 'delete_repo', repoid=repo.repo_name, )
70 self.apikey, 'delete_repo', repoid=repo.repo_name, )
68 with mock.patch.object(RepoModel, 'delete', crash):
71 with mock.patch.object(RepoModel, 'delete', crash):
69 response = api_call(self.app, params)
72 response = api_call(self.app, params)
70 expected = 'failed to delete repository `%s`' % (
73 expected = 'failed to delete repository `%s`' % (repo_name,)
71 repo.repo_name,)
72 assert_error(id_, expected, given=response.body)
74 assert_error(id_, expected, given=response.body)
@@ -1,2051 +1,2062 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-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 logging
21 import logging
22 import time
22 import time
23
23
24 import rhodecode
24 import rhodecode
25 from rhodecode.api import (
25 from rhodecode.api import (
26 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
26 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
27 from rhodecode.api.utils import (
27 from rhodecode.api.utils import (
28 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
28 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
29 get_user_group_or_error, get_user_or_error, validate_repo_permissions,
29 get_user_group_or_error, get_user_or_error, validate_repo_permissions,
30 get_perm_or_error, parse_args, get_origin, build_commit_data,
30 get_perm_or_error, parse_args, get_origin, build_commit_data,
31 validate_set_owner_permissions)
31 validate_set_owner_permissions)
32 from rhodecode.lib import audit_logger
32 from rhodecode.lib import repo_maintenance
33 from rhodecode.lib import repo_maintenance
33 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
34 from rhodecode.lib.utils2 import str2bool, time_to_datetime
35 from rhodecode.lib.utils2 import str2bool, time_to_datetime
35 from rhodecode.lib.ext_json import json
36 from rhodecode.lib.ext_json import json
36 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
37 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
37 from rhodecode.model.changeset_status import ChangesetStatusModel
38 from rhodecode.model.changeset_status import ChangesetStatusModel
38 from rhodecode.model.comment import CommentsModel
39 from rhodecode.model.comment import CommentsModel
39 from rhodecode.model.db import (
40 from rhodecode.model.db import (
40 Session, ChangesetStatus, RepositoryField, Repository, RepoGroup,
41 Session, ChangesetStatus, RepositoryField, Repository, RepoGroup,
41 ChangesetComment)
42 ChangesetComment)
42 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.scm import ScmModel, RepoList
44 from rhodecode.model.scm import ScmModel, RepoList
44 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
45 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
45 from rhodecode.model import validation_schema
46 from rhodecode.model import validation_schema
46 from rhodecode.model.validation_schema.schemas import repo_schema
47 from rhodecode.model.validation_schema.schemas import repo_schema
47
48
48 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
49
50
50
51
51 @jsonrpc_method()
52 @jsonrpc_method()
52 def get_repo(request, apiuser, repoid, cache=Optional(True)):
53 def get_repo(request, apiuser, repoid, cache=Optional(True)):
53 """
54 """
54 Gets an existing repository by its name or repository_id.
55 Gets an existing repository by its name or repository_id.
55
56
56 The members section so the output returns users groups or users
57 The members section so the output returns users groups or users
57 associated with that repository.
58 associated with that repository.
58
59
59 This command can only be run using an |authtoken| with admin rights,
60 This command can only be run using an |authtoken| with admin rights,
60 or users with at least read rights to the |repo|.
61 or users with at least read rights to the |repo|.
61
62
62 :param apiuser: This is filled automatically from the |authtoken|.
63 :param apiuser: This is filled automatically from the |authtoken|.
63 :type apiuser: AuthUser
64 :type apiuser: AuthUser
64 :param repoid: The repository name or repository id.
65 :param repoid: The repository name or repository id.
65 :type repoid: str or int
66 :type repoid: str or int
66 :param cache: use the cached value for last changeset
67 :param cache: use the cached value for last changeset
67 :type: cache: Optional(bool)
68 :type: cache: Optional(bool)
68
69
69 Example output:
70 Example output:
70
71
71 .. code-block:: bash
72 .. code-block:: bash
72
73
73 {
74 {
74 "error": null,
75 "error": null,
75 "id": <repo_id>,
76 "id": <repo_id>,
76 "result": {
77 "result": {
77 "clone_uri": null,
78 "clone_uri": null,
78 "created_on": "timestamp",
79 "created_on": "timestamp",
79 "description": "repo description",
80 "description": "repo description",
80 "enable_downloads": false,
81 "enable_downloads": false,
81 "enable_locking": false,
82 "enable_locking": false,
82 "enable_statistics": false,
83 "enable_statistics": false,
83 "followers": [
84 "followers": [
84 {
85 {
85 "active": true,
86 "active": true,
86 "admin": false,
87 "admin": false,
87 "api_key": "****************************************",
88 "api_key": "****************************************",
88 "api_keys": [
89 "api_keys": [
89 "****************************************"
90 "****************************************"
90 ],
91 ],
91 "email": "user@example.com",
92 "email": "user@example.com",
92 "emails": [
93 "emails": [
93 "user@example.com"
94 "user@example.com"
94 ],
95 ],
95 "extern_name": "rhodecode",
96 "extern_name": "rhodecode",
96 "extern_type": "rhodecode",
97 "extern_type": "rhodecode",
97 "firstname": "username",
98 "firstname": "username",
98 "ip_addresses": [],
99 "ip_addresses": [],
99 "language": null,
100 "language": null,
100 "last_login": "2015-09-16T17:16:35.854",
101 "last_login": "2015-09-16T17:16:35.854",
101 "lastname": "surname",
102 "lastname": "surname",
102 "user_id": <user_id>,
103 "user_id": <user_id>,
103 "username": "name"
104 "username": "name"
104 }
105 }
105 ],
106 ],
106 "fork_of": "parent-repo",
107 "fork_of": "parent-repo",
107 "landing_rev": [
108 "landing_rev": [
108 "rev",
109 "rev",
109 "tip"
110 "tip"
110 ],
111 ],
111 "last_changeset": {
112 "last_changeset": {
112 "author": "User <user@example.com>",
113 "author": "User <user@example.com>",
113 "branch": "default",
114 "branch": "default",
114 "date": "timestamp",
115 "date": "timestamp",
115 "message": "last commit message",
116 "message": "last commit message",
116 "parents": [
117 "parents": [
117 {
118 {
118 "raw_id": "commit-id"
119 "raw_id": "commit-id"
119 }
120 }
120 ],
121 ],
121 "raw_id": "commit-id",
122 "raw_id": "commit-id",
122 "revision": <revision number>,
123 "revision": <revision number>,
123 "short_id": "short id"
124 "short_id": "short id"
124 },
125 },
125 "lock_reason": null,
126 "lock_reason": null,
126 "locked_by": null,
127 "locked_by": null,
127 "locked_date": null,
128 "locked_date": null,
128 "members": [
129 "members": [
129 {
130 {
130 "name": "super-admin-name",
131 "name": "super-admin-name",
131 "origin": "super-admin",
132 "origin": "super-admin",
132 "permission": "repository.admin",
133 "permission": "repository.admin",
133 "type": "user"
134 "type": "user"
134 },
135 },
135 {
136 {
136 "name": "owner-name",
137 "name": "owner-name",
137 "origin": "owner",
138 "origin": "owner",
138 "permission": "repository.admin",
139 "permission": "repository.admin",
139 "type": "user"
140 "type": "user"
140 },
141 },
141 {
142 {
142 "name": "user-group-name",
143 "name": "user-group-name",
143 "origin": "permission",
144 "origin": "permission",
144 "permission": "repository.write",
145 "permission": "repository.write",
145 "type": "user_group"
146 "type": "user_group"
146 }
147 }
147 ],
148 ],
148 "owner": "owner-name",
149 "owner": "owner-name",
149 "permissions": [
150 "permissions": [
150 {
151 {
151 "name": "super-admin-name",
152 "name": "super-admin-name",
152 "origin": "super-admin",
153 "origin": "super-admin",
153 "permission": "repository.admin",
154 "permission": "repository.admin",
154 "type": "user"
155 "type": "user"
155 },
156 },
156 {
157 {
157 "name": "owner-name",
158 "name": "owner-name",
158 "origin": "owner",
159 "origin": "owner",
159 "permission": "repository.admin",
160 "permission": "repository.admin",
160 "type": "user"
161 "type": "user"
161 },
162 },
162 {
163 {
163 "name": "user-group-name",
164 "name": "user-group-name",
164 "origin": "permission",
165 "origin": "permission",
165 "permission": "repository.write",
166 "permission": "repository.write",
166 "type": "user_group"
167 "type": "user_group"
167 }
168 }
168 ],
169 ],
169 "private": true,
170 "private": true,
170 "repo_id": 676,
171 "repo_id": 676,
171 "repo_name": "user-group/repo-name",
172 "repo_name": "user-group/repo-name",
172 "repo_type": "hg"
173 "repo_type": "hg"
173 }
174 }
174 }
175 }
175 """
176 """
176
177
177 repo = get_repo_or_error(repoid)
178 repo = get_repo_or_error(repoid)
178 cache = Optional.extract(cache)
179 cache = Optional.extract(cache)
179
180
180 include_secrets = False
181 include_secrets = False
181 if has_superadmin_permission(apiuser):
182 if has_superadmin_permission(apiuser):
182 include_secrets = True
183 include_secrets = True
183 else:
184 else:
184 # check if we have at least read permission for this repo !
185 # check if we have at least read permission for this repo !
185 _perms = (
186 _perms = (
186 'repository.admin', 'repository.write', 'repository.read',)
187 'repository.admin', 'repository.write', 'repository.read',)
187 validate_repo_permissions(apiuser, repoid, repo, _perms)
188 validate_repo_permissions(apiuser, repoid, repo, _perms)
188
189
189 permissions = []
190 permissions = []
190 for _user in repo.permissions():
191 for _user in repo.permissions():
191 user_data = {
192 user_data = {
192 'name': _user.username,
193 'name': _user.username,
193 'permission': _user.permission,
194 'permission': _user.permission,
194 'origin': get_origin(_user),
195 'origin': get_origin(_user),
195 'type': "user",
196 'type': "user",
196 }
197 }
197 permissions.append(user_data)
198 permissions.append(user_data)
198
199
199 for _user_group in repo.permission_user_groups():
200 for _user_group in repo.permission_user_groups():
200 user_group_data = {
201 user_group_data = {
201 'name': _user_group.users_group_name,
202 'name': _user_group.users_group_name,
202 'permission': _user_group.permission,
203 'permission': _user_group.permission,
203 'origin': get_origin(_user_group),
204 'origin': get_origin(_user_group),
204 'type': "user_group",
205 'type': "user_group",
205 }
206 }
206 permissions.append(user_group_data)
207 permissions.append(user_group_data)
207
208
208 following_users = [
209 following_users = [
209 user.user.get_api_data(include_secrets=include_secrets)
210 user.user.get_api_data(include_secrets=include_secrets)
210 for user in repo.followers]
211 for user in repo.followers]
211
212
212 if not cache:
213 if not cache:
213 repo.update_commit_cache()
214 repo.update_commit_cache()
214 data = repo.get_api_data(include_secrets=include_secrets)
215 data = repo.get_api_data(include_secrets=include_secrets)
215 data['members'] = permissions # TODO: this should be deprecated soon
216 data['members'] = permissions # TODO: this should be deprecated soon
216 data['permissions'] = permissions
217 data['permissions'] = permissions
217 data['followers'] = following_users
218 data['followers'] = following_users
218 return data
219 return data
219
220
220
221
221 @jsonrpc_method()
222 @jsonrpc_method()
222 def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
223 def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
223 """
224 """
224 Lists all existing repositories.
225 Lists all existing repositories.
225
226
226 This command can only be run using an |authtoken| with admin rights,
227 This command can only be run using an |authtoken| with admin rights,
227 or users with at least read rights to |repos|.
228 or users with at least read rights to |repos|.
228
229
229 :param apiuser: This is filled automatically from the |authtoken|.
230 :param apiuser: This is filled automatically from the |authtoken|.
230 :type apiuser: AuthUser
231 :type apiuser: AuthUser
231 :param root: specify root repository group to fetch repositories.
232 :param root: specify root repository group to fetch repositories.
232 filters the returned repositories to be members of given root group.
233 filters the returned repositories to be members of given root group.
233 :type root: Optional(None)
234 :type root: Optional(None)
234 :param traverse: traverse given root into subrepositories. With this flag
235 :param traverse: traverse given root into subrepositories. With this flag
235 set to False, it will only return top-level repositories from `root`.
236 set to False, it will only return top-level repositories from `root`.
236 if root is empty it will return just top-level repositories.
237 if root is empty it will return just top-level repositories.
237 :type traverse: Optional(True)
238 :type traverse: Optional(True)
238
239
239
240
240 Example output:
241 Example output:
241
242
242 .. code-block:: bash
243 .. code-block:: bash
243
244
244 id : <id_given_in_input>
245 id : <id_given_in_input>
245 result: [
246 result: [
246 {
247 {
247 "repo_id" : "<repo_id>",
248 "repo_id" : "<repo_id>",
248 "repo_name" : "<reponame>"
249 "repo_name" : "<reponame>"
249 "repo_type" : "<repo_type>",
250 "repo_type" : "<repo_type>",
250 "clone_uri" : "<clone_uri>",
251 "clone_uri" : "<clone_uri>",
251 "private": : "<bool>",
252 "private": : "<bool>",
252 "created_on" : "<datetimecreated>",
253 "created_on" : "<datetimecreated>",
253 "description" : "<description>",
254 "description" : "<description>",
254 "landing_rev": "<landing_rev>",
255 "landing_rev": "<landing_rev>",
255 "owner": "<repo_owner>",
256 "owner": "<repo_owner>",
256 "fork_of": "<name_of_fork_parent>",
257 "fork_of": "<name_of_fork_parent>",
257 "enable_downloads": "<bool>",
258 "enable_downloads": "<bool>",
258 "enable_locking": "<bool>",
259 "enable_locking": "<bool>",
259 "enable_statistics": "<bool>",
260 "enable_statistics": "<bool>",
260 },
261 },
261 ...
262 ...
262 ]
263 ]
263 error: null
264 error: null
264 """
265 """
265
266
266 include_secrets = has_superadmin_permission(apiuser)
267 include_secrets = has_superadmin_permission(apiuser)
267 _perms = ('repository.read', 'repository.write', 'repository.admin',)
268 _perms = ('repository.read', 'repository.write', 'repository.admin',)
268 extras = {'user': apiuser}
269 extras = {'user': apiuser}
269
270
270 root = Optional.extract(root)
271 root = Optional.extract(root)
271 traverse = Optional.extract(traverse, binary=True)
272 traverse = Optional.extract(traverse, binary=True)
272
273
273 if root:
274 if root:
274 # verify parent existance, if it's empty return an error
275 # verify parent existance, if it's empty return an error
275 parent = RepoGroup.get_by_group_name(root)
276 parent = RepoGroup.get_by_group_name(root)
276 if not parent:
277 if not parent:
277 raise JSONRPCError(
278 raise JSONRPCError(
278 'Root repository group `{}` does not exist'.format(root))
279 'Root repository group `{}` does not exist'.format(root))
279
280
280 if traverse:
281 if traverse:
281 repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
282 repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
282 else:
283 else:
283 repos = RepoModel().get_repos_for_root(root=parent)
284 repos = RepoModel().get_repos_for_root(root=parent)
284 else:
285 else:
285 if traverse:
286 if traverse:
286 repos = RepoModel().get_all()
287 repos = RepoModel().get_all()
287 else:
288 else:
288 # return just top-level
289 # return just top-level
289 repos = RepoModel().get_repos_for_root(root=None)
290 repos = RepoModel().get_repos_for_root(root=None)
290
291
291 repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
292 repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
292 return [repo.get_api_data(include_secrets=include_secrets)
293 return [repo.get_api_data(include_secrets=include_secrets)
293 for repo in repo_list]
294 for repo in repo_list]
294
295
295
296
296 @jsonrpc_method()
297 @jsonrpc_method()
297 def get_repo_changeset(request, apiuser, repoid, revision,
298 def get_repo_changeset(request, apiuser, repoid, revision,
298 details=Optional('basic')):
299 details=Optional('basic')):
299 """
300 """
300 Returns information about a changeset.
301 Returns information about a changeset.
301
302
302 Additionally parameters define the amount of details returned by
303 Additionally parameters define the amount of details returned by
303 this function.
304 this function.
304
305
305 This command can only be run using an |authtoken| with admin rights,
306 This command can only be run using an |authtoken| with admin rights,
306 or users with at least read rights to the |repo|.
307 or users with at least read rights to the |repo|.
307
308
308 :param apiuser: This is filled automatically from the |authtoken|.
309 :param apiuser: This is filled automatically from the |authtoken|.
309 :type apiuser: AuthUser
310 :type apiuser: AuthUser
310 :param repoid: The repository name or repository id
311 :param repoid: The repository name or repository id
311 :type repoid: str or int
312 :type repoid: str or int
312 :param revision: revision for which listing should be done
313 :param revision: revision for which listing should be done
313 :type revision: str
314 :type revision: str
314 :param details: details can be 'basic|extended|full' full gives diff
315 :param details: details can be 'basic|extended|full' full gives diff
315 info details like the diff itself, and number of changed files etc.
316 info details like the diff itself, and number of changed files etc.
316 :type details: Optional(str)
317 :type details: Optional(str)
317
318
318 """
319 """
319 repo = get_repo_or_error(repoid)
320 repo = get_repo_or_error(repoid)
320 if not has_superadmin_permission(apiuser):
321 if not has_superadmin_permission(apiuser):
321 _perms = (
322 _perms = (
322 'repository.admin', 'repository.write', 'repository.read',)
323 'repository.admin', 'repository.write', 'repository.read',)
323 validate_repo_permissions(apiuser, repoid, repo, _perms)
324 validate_repo_permissions(apiuser, repoid, repo, _perms)
324
325
325 changes_details = Optional.extract(details)
326 changes_details = Optional.extract(details)
326 _changes_details_types = ['basic', 'extended', 'full']
327 _changes_details_types = ['basic', 'extended', 'full']
327 if changes_details not in _changes_details_types:
328 if changes_details not in _changes_details_types:
328 raise JSONRPCError(
329 raise JSONRPCError(
329 'ret_type must be one of %s' % (
330 'ret_type must be one of %s' % (
330 ','.join(_changes_details_types)))
331 ','.join(_changes_details_types)))
331
332
332 pre_load = ['author', 'branch', 'date', 'message', 'parents',
333 pre_load = ['author', 'branch', 'date', 'message', 'parents',
333 'status', '_commit', '_file_paths']
334 'status', '_commit', '_file_paths']
334
335
335 try:
336 try:
336 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
337 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
337 except TypeError as e:
338 except TypeError as e:
338 raise JSONRPCError(e.message)
339 raise JSONRPCError(e.message)
339 _cs_json = cs.__json__()
340 _cs_json = cs.__json__()
340 _cs_json['diff'] = build_commit_data(cs, changes_details)
341 _cs_json['diff'] = build_commit_data(cs, changes_details)
341 if changes_details == 'full':
342 if changes_details == 'full':
342 _cs_json['refs'] = {
343 _cs_json['refs'] = {
343 'branches': [cs.branch],
344 'branches': [cs.branch],
344 'bookmarks': getattr(cs, 'bookmarks', []),
345 'bookmarks': getattr(cs, 'bookmarks', []),
345 'tags': cs.tags
346 'tags': cs.tags
346 }
347 }
347 return _cs_json
348 return _cs_json
348
349
349
350
350 @jsonrpc_method()
351 @jsonrpc_method()
351 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
352 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
352 details=Optional('basic')):
353 details=Optional('basic')):
353 """
354 """
354 Returns a set of commits limited by the number starting
355 Returns a set of commits limited by the number starting
355 from the `start_rev` option.
356 from the `start_rev` option.
356
357
357 Additional parameters define the amount of details returned by this
358 Additional parameters define the amount of details returned by this
358 function.
359 function.
359
360
360 This command can only be run using an |authtoken| with admin rights,
361 This command can only be run using an |authtoken| with admin rights,
361 or users with at least read rights to |repos|.
362 or users with at least read rights to |repos|.
362
363
363 :param apiuser: This is filled automatically from the |authtoken|.
364 :param apiuser: This is filled automatically from the |authtoken|.
364 :type apiuser: AuthUser
365 :type apiuser: AuthUser
365 :param repoid: The repository name or repository ID.
366 :param repoid: The repository name or repository ID.
366 :type repoid: str or int
367 :type repoid: str or int
367 :param start_rev: The starting revision from where to get changesets.
368 :param start_rev: The starting revision from where to get changesets.
368 :type start_rev: str
369 :type start_rev: str
369 :param limit: Limit the number of commits to this amount
370 :param limit: Limit the number of commits to this amount
370 :type limit: str or int
371 :type limit: str or int
371 :param details: Set the level of detail returned. Valid option are:
372 :param details: Set the level of detail returned. Valid option are:
372 ``basic``, ``extended`` and ``full``.
373 ``basic``, ``extended`` and ``full``.
373 :type details: Optional(str)
374 :type details: Optional(str)
374
375
375 .. note::
376 .. note::
376
377
377 Setting the parameter `details` to the value ``full`` is extensive
378 Setting the parameter `details` to the value ``full`` is extensive
378 and returns details like the diff itself, and the number
379 and returns details like the diff itself, and the number
379 of changed files.
380 of changed files.
380
381
381 """
382 """
382 repo = get_repo_or_error(repoid)
383 repo = get_repo_or_error(repoid)
383 if not has_superadmin_permission(apiuser):
384 if not has_superadmin_permission(apiuser):
384 _perms = (
385 _perms = (
385 'repository.admin', 'repository.write', 'repository.read',)
386 'repository.admin', 'repository.write', 'repository.read',)
386 validate_repo_permissions(apiuser, repoid, repo, _perms)
387 validate_repo_permissions(apiuser, repoid, repo, _perms)
387
388
388 changes_details = Optional.extract(details)
389 changes_details = Optional.extract(details)
389 _changes_details_types = ['basic', 'extended', 'full']
390 _changes_details_types = ['basic', 'extended', 'full']
390 if changes_details not in _changes_details_types:
391 if changes_details not in _changes_details_types:
391 raise JSONRPCError(
392 raise JSONRPCError(
392 'ret_type must be one of %s' % (
393 'ret_type must be one of %s' % (
393 ','.join(_changes_details_types)))
394 ','.join(_changes_details_types)))
394
395
395 limit = int(limit)
396 limit = int(limit)
396 pre_load = ['author', 'branch', 'date', 'message', 'parents',
397 pre_load = ['author', 'branch', 'date', 'message', 'parents',
397 'status', '_commit', '_file_paths']
398 'status', '_commit', '_file_paths']
398
399
399 vcs_repo = repo.scm_instance()
400 vcs_repo = repo.scm_instance()
400 # SVN needs a special case to distinguish its index and commit id
401 # SVN needs a special case to distinguish its index and commit id
401 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
402 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
402 start_rev = vcs_repo.commit_ids[0]
403 start_rev = vcs_repo.commit_ids[0]
403
404
404 try:
405 try:
405 commits = vcs_repo.get_commits(
406 commits = vcs_repo.get_commits(
406 start_id=start_rev, pre_load=pre_load)
407 start_id=start_rev, pre_load=pre_load)
407 except TypeError as e:
408 except TypeError as e:
408 raise JSONRPCError(e.message)
409 raise JSONRPCError(e.message)
409 except Exception:
410 except Exception:
410 log.exception('Fetching of commits failed')
411 log.exception('Fetching of commits failed')
411 raise JSONRPCError('Error occurred during commit fetching')
412 raise JSONRPCError('Error occurred during commit fetching')
412
413
413 ret = []
414 ret = []
414 for cnt, commit in enumerate(commits):
415 for cnt, commit in enumerate(commits):
415 if cnt >= limit != -1:
416 if cnt >= limit != -1:
416 break
417 break
417 _cs_json = commit.__json__()
418 _cs_json = commit.__json__()
418 _cs_json['diff'] = build_commit_data(commit, changes_details)
419 _cs_json['diff'] = build_commit_data(commit, changes_details)
419 if changes_details == 'full':
420 if changes_details == 'full':
420 _cs_json['refs'] = {
421 _cs_json['refs'] = {
421 'branches': [commit.branch],
422 'branches': [commit.branch],
422 'bookmarks': getattr(commit, 'bookmarks', []),
423 'bookmarks': getattr(commit, 'bookmarks', []),
423 'tags': commit.tags
424 'tags': commit.tags
424 }
425 }
425 ret.append(_cs_json)
426 ret.append(_cs_json)
426 return ret
427 return ret
427
428
428
429
429 @jsonrpc_method()
430 @jsonrpc_method()
430 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
431 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
431 ret_type=Optional('all'), details=Optional('basic'),
432 ret_type=Optional('all'), details=Optional('basic'),
432 max_file_bytes=Optional(None)):
433 max_file_bytes=Optional(None)):
433 """
434 """
434 Returns a list of nodes and children in a flat list for a given
435 Returns a list of nodes and children in a flat list for a given
435 path at given revision.
436 path at given revision.
436
437
437 It's possible to specify ret_type to show only `files` or `dirs`.
438 It's possible to specify ret_type to show only `files` or `dirs`.
438
439
439 This command can only be run using an |authtoken| with admin rights,
440 This command can only be run using an |authtoken| with admin rights,
440 or users with at least read rights to |repos|.
441 or users with at least read rights to |repos|.
441
442
442 :param apiuser: This is filled automatically from the |authtoken|.
443 :param apiuser: This is filled automatically from the |authtoken|.
443 :type apiuser: AuthUser
444 :type apiuser: AuthUser
444 :param repoid: The repository name or repository ID.
445 :param repoid: The repository name or repository ID.
445 :type repoid: str or int
446 :type repoid: str or int
446 :param revision: The revision for which listing should be done.
447 :param revision: The revision for which listing should be done.
447 :type revision: str
448 :type revision: str
448 :param root_path: The path from which to start displaying.
449 :param root_path: The path from which to start displaying.
449 :type root_path: str
450 :type root_path: str
450 :param ret_type: Set the return type. Valid options are
451 :param ret_type: Set the return type. Valid options are
451 ``all`` (default), ``files`` and ``dirs``.
452 ``all`` (default), ``files`` and ``dirs``.
452 :type ret_type: Optional(str)
453 :type ret_type: Optional(str)
453 :param details: Returns extended information about nodes, such as
454 :param details: Returns extended information about nodes, such as
454 md5, binary, and or content. The valid options are ``basic`` and
455 md5, binary, and or content. The valid options are ``basic`` and
455 ``full``.
456 ``full``.
456 :type details: Optional(str)
457 :type details: Optional(str)
457 :param max_file_bytes: Only return file content under this file size bytes
458 :param max_file_bytes: Only return file content under this file size bytes
458 :type details: Optional(int)
459 :type details: Optional(int)
459
460
460 Example output:
461 Example output:
461
462
462 .. code-block:: bash
463 .. code-block:: bash
463
464
464 id : <id_given_in_input>
465 id : <id_given_in_input>
465 result: [
466 result: [
466 {
467 {
467 "name" : "<name>"
468 "name" : "<name>"
468 "type" : "<type>",
469 "type" : "<type>",
469 "binary": "<true|false>" (only in extended mode)
470 "binary": "<true|false>" (only in extended mode)
470 "md5" : "<md5 of file content>" (only in extended mode)
471 "md5" : "<md5 of file content>" (only in extended mode)
471 },
472 },
472 ...
473 ...
473 ]
474 ]
474 error: null
475 error: null
475 """
476 """
476
477
477 repo = get_repo_or_error(repoid)
478 repo = get_repo_or_error(repoid)
478 if not has_superadmin_permission(apiuser):
479 if not has_superadmin_permission(apiuser):
479 _perms = (
480 _perms = (
480 'repository.admin', 'repository.write', 'repository.read',)
481 'repository.admin', 'repository.write', 'repository.read',)
481 validate_repo_permissions(apiuser, repoid, repo, _perms)
482 validate_repo_permissions(apiuser, repoid, repo, _perms)
482
483
483 ret_type = Optional.extract(ret_type)
484 ret_type = Optional.extract(ret_type)
484 details = Optional.extract(details)
485 details = Optional.extract(details)
485 _extended_types = ['basic', 'full']
486 _extended_types = ['basic', 'full']
486 if details not in _extended_types:
487 if details not in _extended_types:
487 raise JSONRPCError(
488 raise JSONRPCError(
488 'ret_type must be one of %s' % (','.join(_extended_types)))
489 'ret_type must be one of %s' % (','.join(_extended_types)))
489 extended_info = False
490 extended_info = False
490 content = False
491 content = False
491 if details == 'basic':
492 if details == 'basic':
492 extended_info = True
493 extended_info = True
493
494
494 if details == 'full':
495 if details == 'full':
495 extended_info = content = True
496 extended_info = content = True
496
497
497 _map = {}
498 _map = {}
498 try:
499 try:
499 # check if repo is not empty by any chance, skip quicker if it is.
500 # check if repo is not empty by any chance, skip quicker if it is.
500 _scm = repo.scm_instance()
501 _scm = repo.scm_instance()
501 if _scm.is_empty():
502 if _scm.is_empty():
502 return []
503 return []
503
504
504 _d, _f = ScmModel().get_nodes(
505 _d, _f = ScmModel().get_nodes(
505 repo, revision, root_path, flat=False,
506 repo, revision, root_path, flat=False,
506 extended_info=extended_info, content=content,
507 extended_info=extended_info, content=content,
507 max_file_bytes=max_file_bytes)
508 max_file_bytes=max_file_bytes)
508 _map = {
509 _map = {
509 'all': _d + _f,
510 'all': _d + _f,
510 'files': _f,
511 'files': _f,
511 'dirs': _d,
512 'dirs': _d,
512 }
513 }
513 return _map[ret_type]
514 return _map[ret_type]
514 except KeyError:
515 except KeyError:
515 raise JSONRPCError(
516 raise JSONRPCError(
516 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
517 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
517 except Exception:
518 except Exception:
518 log.exception("Exception occurred while trying to get repo nodes")
519 log.exception("Exception occurred while trying to get repo nodes")
519 raise JSONRPCError(
520 raise JSONRPCError(
520 'failed to get repo: `%s` nodes' % repo.repo_name
521 'failed to get repo: `%s` nodes' % repo.repo_name
521 )
522 )
522
523
523
524
524 @jsonrpc_method()
525 @jsonrpc_method()
525 def get_repo_refs(request, apiuser, repoid):
526 def get_repo_refs(request, apiuser, repoid):
526 """
527 """
527 Returns a dictionary of current references. It returns
528 Returns a dictionary of current references. It returns
528 bookmarks, branches, closed_branches, and tags for given repository
529 bookmarks, branches, closed_branches, and tags for given repository
529
530
530 It's possible to specify ret_type to show only `files` or `dirs`.
531 It's possible to specify ret_type to show only `files` or `dirs`.
531
532
532 This command can only be run using an |authtoken| with admin rights,
533 This command can only be run using an |authtoken| with admin rights,
533 or users with at least read rights to |repos|.
534 or users with at least read rights to |repos|.
534
535
535 :param apiuser: This is filled automatically from the |authtoken|.
536 :param apiuser: This is filled automatically from the |authtoken|.
536 :type apiuser: AuthUser
537 :type apiuser: AuthUser
537 :param repoid: The repository name or repository ID.
538 :param repoid: The repository name or repository ID.
538 :type repoid: str or int
539 :type repoid: str or int
539
540
540 Example output:
541 Example output:
541
542
542 .. code-block:: bash
543 .. code-block:: bash
543
544
544 id : <id_given_in_input>
545 id : <id_given_in_input>
545 "result": {
546 "result": {
546 "bookmarks": {
547 "bookmarks": {
547 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
548 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
548 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
549 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
549 },
550 },
550 "branches": {
551 "branches": {
551 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
552 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
552 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
553 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
553 },
554 },
554 "branches_closed": {},
555 "branches_closed": {},
555 "tags": {
556 "tags": {
556 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
557 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
557 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
558 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
558 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
559 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
559 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
560 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
560 }
561 }
561 }
562 }
562 error: null
563 error: null
563 """
564 """
564
565
565 repo = get_repo_or_error(repoid)
566 repo = get_repo_or_error(repoid)
566 if not has_superadmin_permission(apiuser):
567 if not has_superadmin_permission(apiuser):
567 _perms = ('repository.admin', 'repository.write', 'repository.read',)
568 _perms = ('repository.admin', 'repository.write', 'repository.read',)
568 validate_repo_permissions(apiuser, repoid, repo, _perms)
569 validate_repo_permissions(apiuser, repoid, repo, _perms)
569
570
570 try:
571 try:
571 # check if repo is not empty by any chance, skip quicker if it is.
572 # check if repo is not empty by any chance, skip quicker if it is.
572 vcs_instance = repo.scm_instance()
573 vcs_instance = repo.scm_instance()
573 refs = vcs_instance.refs()
574 refs = vcs_instance.refs()
574 return refs
575 return refs
575 except Exception:
576 except Exception:
576 log.exception("Exception occurred while trying to get repo refs")
577 log.exception("Exception occurred while trying to get repo refs")
577 raise JSONRPCError(
578 raise JSONRPCError(
578 'failed to get repo: `%s` references' % repo.repo_name
579 'failed to get repo: `%s` references' % repo.repo_name
579 )
580 )
580
581
581
582
582 @jsonrpc_method()
583 @jsonrpc_method()
583 def create_repo(
584 def create_repo(
584 request, apiuser, repo_name, repo_type,
585 request, apiuser, repo_name, repo_type,
585 owner=Optional(OAttr('apiuser')),
586 owner=Optional(OAttr('apiuser')),
586 description=Optional(''),
587 description=Optional(''),
587 private=Optional(False),
588 private=Optional(False),
588 clone_uri=Optional(None),
589 clone_uri=Optional(None),
589 landing_rev=Optional('rev:tip'),
590 landing_rev=Optional('rev:tip'),
590 enable_statistics=Optional(False),
591 enable_statistics=Optional(False),
591 enable_locking=Optional(False),
592 enable_locking=Optional(False),
592 enable_downloads=Optional(False),
593 enable_downloads=Optional(False),
593 copy_permissions=Optional(False)):
594 copy_permissions=Optional(False)):
594 """
595 """
595 Creates a repository.
596 Creates a repository.
596
597
597 * If the repository name contains "/", repository will be created inside
598 * If the repository name contains "/", repository will be created inside
598 a repository group or nested repository groups
599 a repository group or nested repository groups
599
600
600 For example "foo/bar/repo1" will create |repo| called "repo1" inside
601 For example "foo/bar/repo1" will create |repo| called "repo1" inside
601 group "foo/bar". You have to have permissions to access and write to
602 group "foo/bar". You have to have permissions to access and write to
602 the last repository group ("bar" in this example)
603 the last repository group ("bar" in this example)
603
604
604 This command can only be run using an |authtoken| with at least
605 This command can only be run using an |authtoken| with at least
605 permissions to create repositories, or write permissions to
606 permissions to create repositories, or write permissions to
606 parent repository groups.
607 parent repository groups.
607
608
608 :param apiuser: This is filled automatically from the |authtoken|.
609 :param apiuser: This is filled automatically from the |authtoken|.
609 :type apiuser: AuthUser
610 :type apiuser: AuthUser
610 :param repo_name: Set the repository name.
611 :param repo_name: Set the repository name.
611 :type repo_name: str
612 :type repo_name: str
612 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
613 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
613 :type repo_type: str
614 :type repo_type: str
614 :param owner: user_id or username
615 :param owner: user_id or username
615 :type owner: Optional(str)
616 :type owner: Optional(str)
616 :param description: Set the repository description.
617 :param description: Set the repository description.
617 :type description: Optional(str)
618 :type description: Optional(str)
618 :param private: set repository as private
619 :param private: set repository as private
619 :type private: bool
620 :type private: bool
620 :param clone_uri: set clone_uri
621 :param clone_uri: set clone_uri
621 :type clone_uri: str
622 :type clone_uri: str
622 :param landing_rev: <rev_type>:<rev>
623 :param landing_rev: <rev_type>:<rev>
623 :type landing_rev: str
624 :type landing_rev: str
624 :param enable_locking:
625 :param enable_locking:
625 :type enable_locking: bool
626 :type enable_locking: bool
626 :param enable_downloads:
627 :param enable_downloads:
627 :type enable_downloads: bool
628 :type enable_downloads: bool
628 :param enable_statistics:
629 :param enable_statistics:
629 :type enable_statistics: bool
630 :type enable_statistics: bool
630 :param copy_permissions: Copy permission from group in which the
631 :param copy_permissions: Copy permission from group in which the
631 repository is being created.
632 repository is being created.
632 :type copy_permissions: bool
633 :type copy_permissions: bool
633
634
634
635
635 Example output:
636 Example output:
636
637
637 .. code-block:: bash
638 .. code-block:: bash
638
639
639 id : <id_given_in_input>
640 id : <id_given_in_input>
640 result: {
641 result: {
641 "msg": "Created new repository `<reponame>`",
642 "msg": "Created new repository `<reponame>`",
642 "success": true,
643 "success": true,
643 "task": "<celery task id or None if done sync>"
644 "task": "<celery task id or None if done sync>"
644 }
645 }
645 error: null
646 error: null
646
647
647
648
648 Example error output:
649 Example error output:
649
650
650 .. code-block:: bash
651 .. code-block:: bash
651
652
652 id : <id_given_in_input>
653 id : <id_given_in_input>
653 result : null
654 result : null
654 error : {
655 error : {
655 'failed to create repository `<repo_name>`'
656 'failed to create repository `<repo_name>`'
656 }
657 }
657
658
658 """
659 """
659
660
660 owner = validate_set_owner_permissions(apiuser, owner)
661 owner = validate_set_owner_permissions(apiuser, owner)
661
662
662 description = Optional.extract(description)
663 description = Optional.extract(description)
663 copy_permissions = Optional.extract(copy_permissions)
664 copy_permissions = Optional.extract(copy_permissions)
664 clone_uri = Optional.extract(clone_uri)
665 clone_uri = Optional.extract(clone_uri)
665 landing_commit_ref = Optional.extract(landing_rev)
666 landing_commit_ref = Optional.extract(landing_rev)
666
667
667 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
668 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
668 if isinstance(private, Optional):
669 if isinstance(private, Optional):
669 private = defs.get('repo_private') or Optional.extract(private)
670 private = defs.get('repo_private') or Optional.extract(private)
670 if isinstance(repo_type, Optional):
671 if isinstance(repo_type, Optional):
671 repo_type = defs.get('repo_type')
672 repo_type = defs.get('repo_type')
672 if isinstance(enable_statistics, Optional):
673 if isinstance(enable_statistics, Optional):
673 enable_statistics = defs.get('repo_enable_statistics')
674 enable_statistics = defs.get('repo_enable_statistics')
674 if isinstance(enable_locking, Optional):
675 if isinstance(enable_locking, Optional):
675 enable_locking = defs.get('repo_enable_locking')
676 enable_locking = defs.get('repo_enable_locking')
676 if isinstance(enable_downloads, Optional):
677 if isinstance(enable_downloads, Optional):
677 enable_downloads = defs.get('repo_enable_downloads')
678 enable_downloads = defs.get('repo_enable_downloads')
678
679
679 schema = repo_schema.RepoSchema().bind(
680 schema = repo_schema.RepoSchema().bind(
680 repo_type_options=rhodecode.BACKENDS.keys(),
681 repo_type_options=rhodecode.BACKENDS.keys(),
681 # user caller
682 # user caller
682 user=apiuser)
683 user=apiuser)
683
684
684 try:
685 try:
685 schema_data = schema.deserialize(dict(
686 schema_data = schema.deserialize(dict(
686 repo_name=repo_name,
687 repo_name=repo_name,
687 repo_type=repo_type,
688 repo_type=repo_type,
688 repo_owner=owner.username,
689 repo_owner=owner.username,
689 repo_description=description,
690 repo_description=description,
690 repo_landing_commit_ref=landing_commit_ref,
691 repo_landing_commit_ref=landing_commit_ref,
691 repo_clone_uri=clone_uri,
692 repo_clone_uri=clone_uri,
692 repo_private=private,
693 repo_private=private,
693 repo_copy_permissions=copy_permissions,
694 repo_copy_permissions=copy_permissions,
694 repo_enable_statistics=enable_statistics,
695 repo_enable_statistics=enable_statistics,
695 repo_enable_downloads=enable_downloads,
696 repo_enable_downloads=enable_downloads,
696 repo_enable_locking=enable_locking))
697 repo_enable_locking=enable_locking))
697 except validation_schema.Invalid as err:
698 except validation_schema.Invalid as err:
698 raise JSONRPCValidationError(colander_exc=err)
699 raise JSONRPCValidationError(colander_exc=err)
699
700
700 try:
701 try:
701 data = {
702 data = {
702 'owner': owner,
703 'owner': owner,
703 'repo_name': schema_data['repo_group']['repo_name_without_group'],
704 'repo_name': schema_data['repo_group']['repo_name_without_group'],
704 'repo_name_full': schema_data['repo_name'],
705 'repo_name_full': schema_data['repo_name'],
705 'repo_group': schema_data['repo_group']['repo_group_id'],
706 'repo_group': schema_data['repo_group']['repo_group_id'],
706 'repo_type': schema_data['repo_type'],
707 'repo_type': schema_data['repo_type'],
707 'repo_description': schema_data['repo_description'],
708 'repo_description': schema_data['repo_description'],
708 'repo_private': schema_data['repo_private'],
709 'repo_private': schema_data['repo_private'],
709 'clone_uri': schema_data['repo_clone_uri'],
710 'clone_uri': schema_data['repo_clone_uri'],
710 'repo_landing_rev': schema_data['repo_landing_commit_ref'],
711 'repo_landing_rev': schema_data['repo_landing_commit_ref'],
711 'enable_statistics': schema_data['repo_enable_statistics'],
712 'enable_statistics': schema_data['repo_enable_statistics'],
712 'enable_locking': schema_data['repo_enable_locking'],
713 'enable_locking': schema_data['repo_enable_locking'],
713 'enable_downloads': schema_data['repo_enable_downloads'],
714 'enable_downloads': schema_data['repo_enable_downloads'],
714 'repo_copy_permissions': schema_data['repo_copy_permissions'],
715 'repo_copy_permissions': schema_data['repo_copy_permissions'],
715 }
716 }
716
717
717 task = RepoModel().create(form_data=data, cur_user=owner)
718 task = RepoModel().create(form_data=data, cur_user=owner)
718 from celery.result import BaseAsyncResult
719 from celery.result import BaseAsyncResult
719 task_id = None
720 task_id = None
720 if isinstance(task, BaseAsyncResult):
721 if isinstance(task, BaseAsyncResult):
721 task_id = task.task_id
722 task_id = task.task_id
722 # no commit, it's done in RepoModel, or async via celery
723 # no commit, it's done in RepoModel, or async via celery
723 return {
724 return {
724 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
725 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
725 'success': True, # cannot return the repo data here since fork
726 'success': True, # cannot return the repo data here since fork
726 # can be done async
727 # can be done async
727 'task': task_id
728 'task': task_id
728 }
729 }
729 except Exception:
730 except Exception:
730 log.exception(
731 log.exception(
731 u"Exception while trying to create the repository %s",
732 u"Exception while trying to create the repository %s",
732 schema_data['repo_name'])
733 schema_data['repo_name'])
733 raise JSONRPCError(
734 raise JSONRPCError(
734 'failed to create repository `%s`' % (schema_data['repo_name'],))
735 'failed to create repository `%s`' % (schema_data['repo_name'],))
735
736
736
737
737 @jsonrpc_method()
738 @jsonrpc_method()
738 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
739 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
739 description=Optional('')):
740 description=Optional('')):
740 """
741 """
741 Adds an extra field to a repository.
742 Adds an extra field to a repository.
742
743
743 This command can only be run using an |authtoken| with at least
744 This command can only be run using an |authtoken| with at least
744 write permissions to the |repo|.
745 write permissions to the |repo|.
745
746
746 :param apiuser: This is filled automatically from the |authtoken|.
747 :param apiuser: This is filled automatically from the |authtoken|.
747 :type apiuser: AuthUser
748 :type apiuser: AuthUser
748 :param repoid: Set the repository name or repository id.
749 :param repoid: Set the repository name or repository id.
749 :type repoid: str or int
750 :type repoid: str or int
750 :param key: Create a unique field key for this repository.
751 :param key: Create a unique field key for this repository.
751 :type key: str
752 :type key: str
752 :param label:
753 :param label:
753 :type label: Optional(str)
754 :type label: Optional(str)
754 :param description:
755 :param description:
755 :type description: Optional(str)
756 :type description: Optional(str)
756 """
757 """
757 repo = get_repo_or_error(repoid)
758 repo = get_repo_or_error(repoid)
758 if not has_superadmin_permission(apiuser):
759 if not has_superadmin_permission(apiuser):
759 _perms = ('repository.admin',)
760 _perms = ('repository.admin',)
760 validate_repo_permissions(apiuser, repoid, repo, _perms)
761 validate_repo_permissions(apiuser, repoid, repo, _perms)
761
762
762 label = Optional.extract(label) or key
763 label = Optional.extract(label) or key
763 description = Optional.extract(description)
764 description = Optional.extract(description)
764
765
765 field = RepositoryField.get_by_key_name(key, repo)
766 field = RepositoryField.get_by_key_name(key, repo)
766 if field:
767 if field:
767 raise JSONRPCError('Field with key '
768 raise JSONRPCError('Field with key '
768 '`%s` exists for repo `%s`' % (key, repoid))
769 '`%s` exists for repo `%s`' % (key, repoid))
769
770
770 try:
771 try:
771 RepoModel().add_repo_field(repo, key, field_label=label,
772 RepoModel().add_repo_field(repo, key, field_label=label,
772 field_desc=description)
773 field_desc=description)
773 Session().commit()
774 Session().commit()
774 return {
775 return {
775 'msg': "Added new repository field `%s`" % (key,),
776 'msg': "Added new repository field `%s`" % (key,),
776 'success': True,
777 'success': True,
777 }
778 }
778 except Exception:
779 except Exception:
779 log.exception("Exception occurred while trying to add field to repo")
780 log.exception("Exception occurred while trying to add field to repo")
780 raise JSONRPCError(
781 raise JSONRPCError(
781 'failed to create new field for repository `%s`' % (repoid,))
782 'failed to create new field for repository `%s`' % (repoid,))
782
783
783
784
784 @jsonrpc_method()
785 @jsonrpc_method()
785 def remove_field_from_repo(request, apiuser, repoid, key):
786 def remove_field_from_repo(request, apiuser, repoid, key):
786 """
787 """
787 Removes an extra field from a repository.
788 Removes an extra field from a repository.
788
789
789 This command can only be run using an |authtoken| with at least
790 This command can only be run using an |authtoken| with at least
790 write permissions to the |repo|.
791 write permissions to the |repo|.
791
792
792 :param apiuser: This is filled automatically from the |authtoken|.
793 :param apiuser: This is filled automatically from the |authtoken|.
793 :type apiuser: AuthUser
794 :type apiuser: AuthUser
794 :param repoid: Set the repository name or repository ID.
795 :param repoid: Set the repository name or repository ID.
795 :type repoid: str or int
796 :type repoid: str or int
796 :param key: Set the unique field key for this repository.
797 :param key: Set the unique field key for this repository.
797 :type key: str
798 :type key: str
798 """
799 """
799
800
800 repo = get_repo_or_error(repoid)
801 repo = get_repo_or_error(repoid)
801 if not has_superadmin_permission(apiuser):
802 if not has_superadmin_permission(apiuser):
802 _perms = ('repository.admin',)
803 _perms = ('repository.admin',)
803 validate_repo_permissions(apiuser, repoid, repo, _perms)
804 validate_repo_permissions(apiuser, repoid, repo, _perms)
804
805
805 field = RepositoryField.get_by_key_name(key, repo)
806 field = RepositoryField.get_by_key_name(key, repo)
806 if not field:
807 if not field:
807 raise JSONRPCError('Field with key `%s` does not '
808 raise JSONRPCError('Field with key `%s` does not '
808 'exists for repo `%s`' % (key, repoid))
809 'exists for repo `%s`' % (key, repoid))
809
810
810 try:
811 try:
811 RepoModel().delete_repo_field(repo, field_key=key)
812 RepoModel().delete_repo_field(repo, field_key=key)
812 Session().commit()
813 Session().commit()
813 return {
814 return {
814 'msg': "Deleted repository field `%s`" % (key,),
815 'msg': "Deleted repository field `%s`" % (key,),
815 'success': True,
816 'success': True,
816 }
817 }
817 except Exception:
818 except Exception:
818 log.exception(
819 log.exception(
819 "Exception occurred while trying to delete field from repo")
820 "Exception occurred while trying to delete field from repo")
820 raise JSONRPCError(
821 raise JSONRPCError(
821 'failed to delete field for repository `%s`' % (repoid,))
822 'failed to delete field for repository `%s`' % (repoid,))
822
823
823
824
824 @jsonrpc_method()
825 @jsonrpc_method()
825 def update_repo(
826 def update_repo(
826 request, apiuser, repoid, repo_name=Optional(None),
827 request, apiuser, repoid, repo_name=Optional(None),
827 owner=Optional(OAttr('apiuser')), description=Optional(''),
828 owner=Optional(OAttr('apiuser')), description=Optional(''),
828 private=Optional(False), clone_uri=Optional(None),
829 private=Optional(False), clone_uri=Optional(None),
829 landing_rev=Optional('rev:tip'), fork_of=Optional(None),
830 landing_rev=Optional('rev:tip'), fork_of=Optional(None),
830 enable_statistics=Optional(False),
831 enable_statistics=Optional(False),
831 enable_locking=Optional(False),
832 enable_locking=Optional(False),
832 enable_downloads=Optional(False), fields=Optional('')):
833 enable_downloads=Optional(False), fields=Optional('')):
833 """
834 """
834 Updates a repository with the given information.
835 Updates a repository with the given information.
835
836
836 This command can only be run using an |authtoken| with at least
837 This command can only be run using an |authtoken| with at least
837 admin permissions to the |repo|.
838 admin permissions to the |repo|.
838
839
839 * If the repository name contains "/", repository will be updated
840 * If the repository name contains "/", repository will be updated
840 accordingly with a repository group or nested repository groups
841 accordingly with a repository group or nested repository groups
841
842
842 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
843 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
843 called "repo-test" and place it inside group "foo/bar".
844 called "repo-test" and place it inside group "foo/bar".
844 You have to have permissions to access and write to the last repository
845 You have to have permissions to access and write to the last repository
845 group ("bar" in this example)
846 group ("bar" in this example)
846
847
847 :param apiuser: This is filled automatically from the |authtoken|.
848 :param apiuser: This is filled automatically from the |authtoken|.
848 :type apiuser: AuthUser
849 :type apiuser: AuthUser
849 :param repoid: repository name or repository ID.
850 :param repoid: repository name or repository ID.
850 :type repoid: str or int
851 :type repoid: str or int
851 :param repo_name: Update the |repo| name, including the
852 :param repo_name: Update the |repo| name, including the
852 repository group it's in.
853 repository group it's in.
853 :type repo_name: str
854 :type repo_name: str
854 :param owner: Set the |repo| owner.
855 :param owner: Set the |repo| owner.
855 :type owner: str
856 :type owner: str
856 :param fork_of: Set the |repo| as fork of another |repo|.
857 :param fork_of: Set the |repo| as fork of another |repo|.
857 :type fork_of: str
858 :type fork_of: str
858 :param description: Update the |repo| description.
859 :param description: Update the |repo| description.
859 :type description: str
860 :type description: str
860 :param private: Set the |repo| as private. (True | False)
861 :param private: Set the |repo| as private. (True | False)
861 :type private: bool
862 :type private: bool
862 :param clone_uri: Update the |repo| clone URI.
863 :param clone_uri: Update the |repo| clone URI.
863 :type clone_uri: str
864 :type clone_uri: str
864 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
865 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
865 :type landing_rev: str
866 :type landing_rev: str
866 :param enable_statistics: Enable statistics on the |repo|, (True | False).
867 :param enable_statistics: Enable statistics on the |repo|, (True | False).
867 :type enable_statistics: bool
868 :type enable_statistics: bool
868 :param enable_locking: Enable |repo| locking.
869 :param enable_locking: Enable |repo| locking.
869 :type enable_locking: bool
870 :type enable_locking: bool
870 :param enable_downloads: Enable downloads from the |repo|, (True | False).
871 :param enable_downloads: Enable downloads from the |repo|, (True | False).
871 :type enable_downloads: bool
872 :type enable_downloads: bool
872 :param fields: Add extra fields to the |repo|. Use the following
873 :param fields: Add extra fields to the |repo|. Use the following
873 example format: ``field_key=field_val,field_key2=fieldval2``.
874 example format: ``field_key=field_val,field_key2=fieldval2``.
874 Escape ', ' with \,
875 Escape ', ' with \,
875 :type fields: str
876 :type fields: str
876 """
877 """
877
878
878 repo = get_repo_or_error(repoid)
879 repo = get_repo_or_error(repoid)
879
880
880 include_secrets = False
881 include_secrets = False
881 if not has_superadmin_permission(apiuser):
882 if not has_superadmin_permission(apiuser):
882 validate_repo_permissions(apiuser, repoid, repo, ('repository.admin',))
883 validate_repo_permissions(apiuser, repoid, repo, ('repository.admin',))
883 else:
884 else:
884 include_secrets = True
885 include_secrets = True
885
886
886 updates = dict(
887 updates = dict(
887 repo_name=repo_name
888 repo_name=repo_name
888 if not isinstance(repo_name, Optional) else repo.repo_name,
889 if not isinstance(repo_name, Optional) else repo.repo_name,
889
890
890 fork_id=fork_of
891 fork_id=fork_of
891 if not isinstance(fork_of, Optional) else repo.fork.repo_name if repo.fork else None,
892 if not isinstance(fork_of, Optional) else repo.fork.repo_name if repo.fork else None,
892
893
893 user=owner
894 user=owner
894 if not isinstance(owner, Optional) else repo.user.username,
895 if not isinstance(owner, Optional) else repo.user.username,
895
896
896 repo_description=description
897 repo_description=description
897 if not isinstance(description, Optional) else repo.description,
898 if not isinstance(description, Optional) else repo.description,
898
899
899 repo_private=private
900 repo_private=private
900 if not isinstance(private, Optional) else repo.private,
901 if not isinstance(private, Optional) else repo.private,
901
902
902 clone_uri=clone_uri
903 clone_uri=clone_uri
903 if not isinstance(clone_uri, Optional) else repo.clone_uri,
904 if not isinstance(clone_uri, Optional) else repo.clone_uri,
904
905
905 repo_landing_rev=landing_rev
906 repo_landing_rev=landing_rev
906 if not isinstance(landing_rev, Optional) else repo._landing_revision,
907 if not isinstance(landing_rev, Optional) else repo._landing_revision,
907
908
908 repo_enable_statistics=enable_statistics
909 repo_enable_statistics=enable_statistics
909 if not isinstance(enable_statistics, Optional) else repo.enable_statistics,
910 if not isinstance(enable_statistics, Optional) else repo.enable_statistics,
910
911
911 repo_enable_locking=enable_locking
912 repo_enable_locking=enable_locking
912 if not isinstance(enable_locking, Optional) else repo.enable_locking,
913 if not isinstance(enable_locking, Optional) else repo.enable_locking,
913
914
914 repo_enable_downloads=enable_downloads
915 repo_enable_downloads=enable_downloads
915 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
916 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
916
917
917 ref_choices, _labels = ScmModel().get_repo_landing_revs(repo=repo)
918 ref_choices, _labels = ScmModel().get_repo_landing_revs(repo=repo)
918
919
919 schema = repo_schema.RepoSchema().bind(
920 schema = repo_schema.RepoSchema().bind(
920 repo_type_options=rhodecode.BACKENDS.keys(),
921 repo_type_options=rhodecode.BACKENDS.keys(),
921 repo_ref_options=ref_choices,
922 repo_ref_options=ref_choices,
922 # user caller
923 # user caller
923 user=apiuser,
924 user=apiuser,
924 old_values=repo.get_api_data())
925 old_values=repo.get_api_data())
925 try:
926 try:
926 schema_data = schema.deserialize(dict(
927 schema_data = schema.deserialize(dict(
927 # we save old value, users cannot change type
928 # we save old value, users cannot change type
928 repo_type=repo.repo_type,
929 repo_type=repo.repo_type,
929
930
930 repo_name=updates['repo_name'],
931 repo_name=updates['repo_name'],
931 repo_owner=updates['user'],
932 repo_owner=updates['user'],
932 repo_description=updates['repo_description'],
933 repo_description=updates['repo_description'],
933 repo_clone_uri=updates['clone_uri'],
934 repo_clone_uri=updates['clone_uri'],
934 repo_fork_of=updates['fork_id'],
935 repo_fork_of=updates['fork_id'],
935 repo_private=updates['repo_private'],
936 repo_private=updates['repo_private'],
936 repo_landing_commit_ref=updates['repo_landing_rev'],
937 repo_landing_commit_ref=updates['repo_landing_rev'],
937 repo_enable_statistics=updates['repo_enable_statistics'],
938 repo_enable_statistics=updates['repo_enable_statistics'],
938 repo_enable_downloads=updates['repo_enable_downloads'],
939 repo_enable_downloads=updates['repo_enable_downloads'],
939 repo_enable_locking=updates['repo_enable_locking']))
940 repo_enable_locking=updates['repo_enable_locking']))
940 except validation_schema.Invalid as err:
941 except validation_schema.Invalid as err:
941 raise JSONRPCValidationError(colander_exc=err)
942 raise JSONRPCValidationError(colander_exc=err)
942
943
943 # save validated data back into the updates dict
944 # save validated data back into the updates dict
944 validated_updates = dict(
945 validated_updates = dict(
945 repo_name=schema_data['repo_group']['repo_name_without_group'],
946 repo_name=schema_data['repo_group']['repo_name_without_group'],
946 repo_group=schema_data['repo_group']['repo_group_id'],
947 repo_group=schema_data['repo_group']['repo_group_id'],
947
948
948 user=schema_data['repo_owner'],
949 user=schema_data['repo_owner'],
949 repo_description=schema_data['repo_description'],
950 repo_description=schema_data['repo_description'],
950 repo_private=schema_data['repo_private'],
951 repo_private=schema_data['repo_private'],
951 clone_uri=schema_data['repo_clone_uri'],
952 clone_uri=schema_data['repo_clone_uri'],
952 repo_landing_rev=schema_data['repo_landing_commit_ref'],
953 repo_landing_rev=schema_data['repo_landing_commit_ref'],
953 repo_enable_statistics=schema_data['repo_enable_statistics'],
954 repo_enable_statistics=schema_data['repo_enable_statistics'],
954 repo_enable_locking=schema_data['repo_enable_locking'],
955 repo_enable_locking=schema_data['repo_enable_locking'],
955 repo_enable_downloads=schema_data['repo_enable_downloads'],
956 repo_enable_downloads=schema_data['repo_enable_downloads'],
956 )
957 )
957
958
958 if schema_data['repo_fork_of']:
959 if schema_data['repo_fork_of']:
959 fork_repo = get_repo_or_error(schema_data['repo_fork_of'])
960 fork_repo = get_repo_or_error(schema_data['repo_fork_of'])
960 validated_updates['fork_id'] = fork_repo.repo_id
961 validated_updates['fork_id'] = fork_repo.repo_id
961
962
962 # extra fields
963 # extra fields
963 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
964 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
964 if fields:
965 if fields:
965 validated_updates.update(fields)
966 validated_updates.update(fields)
966
967
967 try:
968 try:
968 RepoModel().update(repo, **validated_updates)
969 RepoModel().update(repo, **validated_updates)
969 Session().commit()
970 Session().commit()
970 return {
971 return {
971 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
972 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
972 'repository': repo.get_api_data(include_secrets=include_secrets)
973 'repository': repo.get_api_data(include_secrets=include_secrets)
973 }
974 }
974 except Exception:
975 except Exception:
975 log.exception(
976 log.exception(
976 u"Exception while trying to update the repository %s",
977 u"Exception while trying to update the repository %s",
977 repoid)
978 repoid)
978 raise JSONRPCError('failed to update repo `%s`' % repoid)
979 raise JSONRPCError('failed to update repo `%s`' % repoid)
979
980
980
981
981 @jsonrpc_method()
982 @jsonrpc_method()
982 def fork_repo(request, apiuser, repoid, fork_name,
983 def fork_repo(request, apiuser, repoid, fork_name,
983 owner=Optional(OAttr('apiuser')),
984 owner=Optional(OAttr('apiuser')),
984 description=Optional(''),
985 description=Optional(''),
985 private=Optional(False),
986 private=Optional(False),
986 clone_uri=Optional(None),
987 clone_uri=Optional(None),
987 landing_rev=Optional('rev:tip'),
988 landing_rev=Optional('rev:tip'),
988 copy_permissions=Optional(False)):
989 copy_permissions=Optional(False)):
989 """
990 """
990 Creates a fork of the specified |repo|.
991 Creates a fork of the specified |repo|.
991
992
992 * If the fork_name contains "/", fork will be created inside
993 * If the fork_name contains "/", fork will be created inside
993 a repository group or nested repository groups
994 a repository group or nested repository groups
994
995
995 For example "foo/bar/fork-repo" will create fork called "fork-repo"
996 For example "foo/bar/fork-repo" will create fork called "fork-repo"
996 inside group "foo/bar". You have to have permissions to access and
997 inside group "foo/bar". You have to have permissions to access and
997 write to the last repository group ("bar" in this example)
998 write to the last repository group ("bar" in this example)
998
999
999 This command can only be run using an |authtoken| with minimum
1000 This command can only be run using an |authtoken| with minimum
1000 read permissions of the forked repo, create fork permissions for an user.
1001 read permissions of the forked repo, create fork permissions for an user.
1001
1002
1002 :param apiuser: This is filled automatically from the |authtoken|.
1003 :param apiuser: This is filled automatically from the |authtoken|.
1003 :type apiuser: AuthUser
1004 :type apiuser: AuthUser
1004 :param repoid: Set repository name or repository ID.
1005 :param repoid: Set repository name or repository ID.
1005 :type repoid: str or int
1006 :type repoid: str or int
1006 :param fork_name: Set the fork name, including it's repository group membership.
1007 :param fork_name: Set the fork name, including it's repository group membership.
1007 :type fork_name: str
1008 :type fork_name: str
1008 :param owner: Set the fork owner.
1009 :param owner: Set the fork owner.
1009 :type owner: str
1010 :type owner: str
1010 :param description: Set the fork description.
1011 :param description: Set the fork description.
1011 :type description: str
1012 :type description: str
1012 :param copy_permissions: Copy permissions from parent |repo|. The
1013 :param copy_permissions: Copy permissions from parent |repo|. The
1013 default is False.
1014 default is False.
1014 :type copy_permissions: bool
1015 :type copy_permissions: bool
1015 :param private: Make the fork private. The default is False.
1016 :param private: Make the fork private. The default is False.
1016 :type private: bool
1017 :type private: bool
1017 :param landing_rev: Set the landing revision. The default is tip.
1018 :param landing_rev: Set the landing revision. The default is tip.
1018
1019
1019 Example output:
1020 Example output:
1020
1021
1021 .. code-block:: bash
1022 .. code-block:: bash
1022
1023
1023 id : <id_for_response>
1024 id : <id_for_response>
1024 api_key : "<api_key>"
1025 api_key : "<api_key>"
1025 args: {
1026 args: {
1026 "repoid" : "<reponame or repo_id>",
1027 "repoid" : "<reponame or repo_id>",
1027 "fork_name": "<forkname>",
1028 "fork_name": "<forkname>",
1028 "owner": "<username or user_id = Optional(=apiuser)>",
1029 "owner": "<username or user_id = Optional(=apiuser)>",
1029 "description": "<description>",
1030 "description": "<description>",
1030 "copy_permissions": "<bool>",
1031 "copy_permissions": "<bool>",
1031 "private": "<bool>",
1032 "private": "<bool>",
1032 "landing_rev": "<landing_rev>"
1033 "landing_rev": "<landing_rev>"
1033 }
1034 }
1034
1035
1035 Example error output:
1036 Example error output:
1036
1037
1037 .. code-block:: bash
1038 .. code-block:: bash
1038
1039
1039 id : <id_given_in_input>
1040 id : <id_given_in_input>
1040 result: {
1041 result: {
1041 "msg": "Created fork of `<reponame>` as `<forkname>`",
1042 "msg": "Created fork of `<reponame>` as `<forkname>`",
1042 "success": true,
1043 "success": true,
1043 "task": "<celery task id or None if done sync>"
1044 "task": "<celery task id or None if done sync>"
1044 }
1045 }
1045 error: null
1046 error: null
1046
1047
1047 """
1048 """
1048
1049
1049 repo = get_repo_or_error(repoid)
1050 repo = get_repo_or_error(repoid)
1050 repo_name = repo.repo_name
1051 repo_name = repo.repo_name
1051
1052
1052 if not has_superadmin_permission(apiuser):
1053 if not has_superadmin_permission(apiuser):
1053 # check if we have at least read permission for
1054 # check if we have at least read permission for
1054 # this repo that we fork !
1055 # this repo that we fork !
1055 _perms = (
1056 _perms = (
1056 'repository.admin', 'repository.write', 'repository.read')
1057 'repository.admin', 'repository.write', 'repository.read')
1057 validate_repo_permissions(apiuser, repoid, repo, _perms)
1058 validate_repo_permissions(apiuser, repoid, repo, _perms)
1058
1059
1059 # check if the regular user has at least fork permissions as well
1060 # check if the regular user has at least fork permissions as well
1060 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
1061 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
1061 raise JSONRPCForbidden()
1062 raise JSONRPCForbidden()
1062
1063
1063 # check if user can set owner parameter
1064 # check if user can set owner parameter
1064 owner = validate_set_owner_permissions(apiuser, owner)
1065 owner = validate_set_owner_permissions(apiuser, owner)
1065
1066
1066 description = Optional.extract(description)
1067 description = Optional.extract(description)
1067 copy_permissions = Optional.extract(copy_permissions)
1068 copy_permissions = Optional.extract(copy_permissions)
1068 clone_uri = Optional.extract(clone_uri)
1069 clone_uri = Optional.extract(clone_uri)
1069 landing_commit_ref = Optional.extract(landing_rev)
1070 landing_commit_ref = Optional.extract(landing_rev)
1070 private = Optional.extract(private)
1071 private = Optional.extract(private)
1071
1072
1072 schema = repo_schema.RepoSchema().bind(
1073 schema = repo_schema.RepoSchema().bind(
1073 repo_type_options=rhodecode.BACKENDS.keys(),
1074 repo_type_options=rhodecode.BACKENDS.keys(),
1074 # user caller
1075 # user caller
1075 user=apiuser)
1076 user=apiuser)
1076
1077
1077 try:
1078 try:
1078 schema_data = schema.deserialize(dict(
1079 schema_data = schema.deserialize(dict(
1079 repo_name=fork_name,
1080 repo_name=fork_name,
1080 repo_type=repo.repo_type,
1081 repo_type=repo.repo_type,
1081 repo_owner=owner.username,
1082 repo_owner=owner.username,
1082 repo_description=description,
1083 repo_description=description,
1083 repo_landing_commit_ref=landing_commit_ref,
1084 repo_landing_commit_ref=landing_commit_ref,
1084 repo_clone_uri=clone_uri,
1085 repo_clone_uri=clone_uri,
1085 repo_private=private,
1086 repo_private=private,
1086 repo_copy_permissions=copy_permissions))
1087 repo_copy_permissions=copy_permissions))
1087 except validation_schema.Invalid as err:
1088 except validation_schema.Invalid as err:
1088 raise JSONRPCValidationError(colander_exc=err)
1089 raise JSONRPCValidationError(colander_exc=err)
1089
1090
1090 try:
1091 try:
1091 data = {
1092 data = {
1092 'fork_parent_id': repo.repo_id,
1093 'fork_parent_id': repo.repo_id,
1093
1094
1094 'repo_name': schema_data['repo_group']['repo_name_without_group'],
1095 'repo_name': schema_data['repo_group']['repo_name_without_group'],
1095 'repo_name_full': schema_data['repo_name'],
1096 'repo_name_full': schema_data['repo_name'],
1096 'repo_group': schema_data['repo_group']['repo_group_id'],
1097 'repo_group': schema_data['repo_group']['repo_group_id'],
1097 'repo_type': schema_data['repo_type'],
1098 'repo_type': schema_data['repo_type'],
1098 'description': schema_data['repo_description'],
1099 'description': schema_data['repo_description'],
1099 'private': schema_data['repo_private'],
1100 'private': schema_data['repo_private'],
1100 'copy_permissions': schema_data['repo_copy_permissions'],
1101 'copy_permissions': schema_data['repo_copy_permissions'],
1101 'landing_rev': schema_data['repo_landing_commit_ref'],
1102 'landing_rev': schema_data['repo_landing_commit_ref'],
1102 }
1103 }
1103
1104
1104 task = RepoModel().create_fork(data, cur_user=owner)
1105 task = RepoModel().create_fork(data, cur_user=owner)
1105 # no commit, it's done in RepoModel, or async via celery
1106 # no commit, it's done in RepoModel, or async via celery
1106 from celery.result import BaseAsyncResult
1107 from celery.result import BaseAsyncResult
1107 task_id = None
1108 task_id = None
1108 if isinstance(task, BaseAsyncResult):
1109 if isinstance(task, BaseAsyncResult):
1109 task_id = task.task_id
1110 task_id = task.task_id
1110 return {
1111 return {
1111 'msg': 'Created fork of `%s` as `%s`' % (
1112 'msg': 'Created fork of `%s` as `%s`' % (
1112 repo.repo_name, schema_data['repo_name']),
1113 repo.repo_name, schema_data['repo_name']),
1113 'success': True, # cannot return the repo data here since fork
1114 'success': True, # cannot return the repo data here since fork
1114 # can be done async
1115 # can be done async
1115 'task': task_id
1116 'task': task_id
1116 }
1117 }
1117 except Exception:
1118 except Exception:
1118 log.exception(
1119 log.exception(
1119 u"Exception while trying to create fork %s",
1120 u"Exception while trying to create fork %s",
1120 schema_data['repo_name'])
1121 schema_data['repo_name'])
1121 raise JSONRPCError(
1122 raise JSONRPCError(
1122 'failed to fork repository `%s` as `%s`' % (
1123 'failed to fork repository `%s` as `%s`' % (
1123 repo_name, schema_data['repo_name']))
1124 repo_name, schema_data['repo_name']))
1124
1125
1125
1126
1126 @jsonrpc_method()
1127 @jsonrpc_method()
1127 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1128 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1128 """
1129 """
1129 Deletes a repository.
1130 Deletes a repository.
1130
1131
1131 * When the `forks` parameter is set it's possible to detach or delete
1132 * When the `forks` parameter is set it's possible to detach or delete
1132 forks of deleted repository.
1133 forks of deleted repository.
1133
1134
1134 This command can only be run using an |authtoken| with admin
1135 This command can only be run using an |authtoken| with admin
1135 permissions on the |repo|.
1136 permissions on the |repo|.
1136
1137
1137 :param apiuser: This is filled automatically from the |authtoken|.
1138 :param apiuser: This is filled automatically from the |authtoken|.
1138 :type apiuser: AuthUser
1139 :type apiuser: AuthUser
1139 :param repoid: Set the repository name or repository ID.
1140 :param repoid: Set the repository name or repository ID.
1140 :type repoid: str or int
1141 :type repoid: str or int
1141 :param forks: Set to `detach` or `delete` forks from the |repo|.
1142 :param forks: Set to `detach` or `delete` forks from the |repo|.
1142 :type forks: Optional(str)
1143 :type forks: Optional(str)
1143
1144
1144 Example error output:
1145 Example error output:
1145
1146
1146 .. code-block:: bash
1147 .. code-block:: bash
1147
1148
1148 id : <id_given_in_input>
1149 id : <id_given_in_input>
1149 result: {
1150 result: {
1150 "msg": "Deleted repository `<reponame>`",
1151 "msg": "Deleted repository `<reponame>`",
1151 "success": true
1152 "success": true
1152 }
1153 }
1153 error: null
1154 error: null
1154 """
1155 """
1155
1156
1156 repo = get_repo_or_error(repoid)
1157 repo = get_repo_or_error(repoid)
1158 repo_name = repo.repo_name
1157 if not has_superadmin_permission(apiuser):
1159 if not has_superadmin_permission(apiuser):
1158 _perms = ('repository.admin',)
1160 _perms = ('repository.admin',)
1159 validate_repo_permissions(apiuser, repoid, repo, _perms)
1161 validate_repo_permissions(apiuser, repoid, repo, _perms)
1160
1162
1161 try:
1163 try:
1162 handle_forks = Optional.extract(forks)
1164 handle_forks = Optional.extract(forks)
1163 _forks_msg = ''
1165 _forks_msg = ''
1164 _forks = [f for f in repo.forks]
1166 _forks = [f for f in repo.forks]
1165 if handle_forks == 'detach':
1167 if handle_forks == 'detach':
1166 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1168 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1167 elif handle_forks == 'delete':
1169 elif handle_forks == 'delete':
1168 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1170 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1169 elif _forks:
1171 elif _forks:
1170 raise JSONRPCError(
1172 raise JSONRPCError(
1171 'Cannot delete `%s` it still contains attached forks' %
1173 'Cannot delete `%s` it still contains attached forks' %
1172 (repo.repo_name,)
1174 (repo.repo_name,)
1173 )
1175 )
1176 repo_data = repo.get_api_data()
1177 RepoModel().delete(repo, forks=forks)
1174
1178
1175 RepoModel().delete(repo, forks=forks)
1179 repo = audit_logger.RepoWrap(repo_id=None,
1180 repo_name=repo.repo_name)
1181
1182 audit_logger.store(
1183 action='repo.delete',
1184 action_data={'repo_data': repo_data, 'source': 'api_call'},
1185 user=apiuser, repo=repo, commit=False)
1186
1187 ScmModel().mark_for_invalidation(repo_name, delete=True)
1176 Session().commit()
1188 Session().commit()
1177 return {
1189 return {
1178 'msg': 'Deleted repository `%s`%s' % (
1190 'msg': 'Deleted repository `%s`%s' % (repo_name, _forks_msg),
1179 repo.repo_name, _forks_msg),
1180 'success': True
1191 'success': True
1181 }
1192 }
1182 except Exception:
1193 except Exception:
1183 log.exception("Exception occurred while trying to delete repo")
1194 log.exception("Exception occurred while trying to delete repo")
1184 raise JSONRPCError(
1195 raise JSONRPCError(
1185 'failed to delete repository `%s`' % (repo.repo_name,)
1196 'failed to delete repository `%s`' % (repo_name,)
1186 )
1197 )
1187
1198
1188
1199
1189 #TODO: marcink, change name ?
1200 #TODO: marcink, change name ?
1190 @jsonrpc_method()
1201 @jsonrpc_method()
1191 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1202 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1192 """
1203 """
1193 Invalidates the cache for the specified repository.
1204 Invalidates the cache for the specified repository.
1194
1205
1195 This command can only be run using an |authtoken| with admin rights to
1206 This command can only be run using an |authtoken| with admin rights to
1196 the specified repository.
1207 the specified repository.
1197
1208
1198 This command takes the following options:
1209 This command takes the following options:
1199
1210
1200 :param apiuser: This is filled automatically from |authtoken|.
1211 :param apiuser: This is filled automatically from |authtoken|.
1201 :type apiuser: AuthUser
1212 :type apiuser: AuthUser
1202 :param repoid: Sets the repository name or repository ID.
1213 :param repoid: Sets the repository name or repository ID.
1203 :type repoid: str or int
1214 :type repoid: str or int
1204 :param delete_keys: This deletes the invalidated keys instead of
1215 :param delete_keys: This deletes the invalidated keys instead of
1205 just flagging them.
1216 just flagging them.
1206 :type delete_keys: Optional(``True`` | ``False``)
1217 :type delete_keys: Optional(``True`` | ``False``)
1207
1218
1208 Example output:
1219 Example output:
1209
1220
1210 .. code-block:: bash
1221 .. code-block:: bash
1211
1222
1212 id : <id_given_in_input>
1223 id : <id_given_in_input>
1213 result : {
1224 result : {
1214 'msg': Cache for repository `<repository name>` was invalidated,
1225 'msg': Cache for repository `<repository name>` was invalidated,
1215 'repository': <repository name>
1226 'repository': <repository name>
1216 }
1227 }
1217 error : null
1228 error : null
1218
1229
1219 Example error output:
1230 Example error output:
1220
1231
1221 .. code-block:: bash
1232 .. code-block:: bash
1222
1233
1223 id : <id_given_in_input>
1234 id : <id_given_in_input>
1224 result : null
1235 result : null
1225 error : {
1236 error : {
1226 'Error occurred during cache invalidation action'
1237 'Error occurred during cache invalidation action'
1227 }
1238 }
1228
1239
1229 """
1240 """
1230
1241
1231 repo = get_repo_or_error(repoid)
1242 repo = get_repo_or_error(repoid)
1232 if not has_superadmin_permission(apiuser):
1243 if not has_superadmin_permission(apiuser):
1233 _perms = ('repository.admin', 'repository.write',)
1244 _perms = ('repository.admin', 'repository.write',)
1234 validate_repo_permissions(apiuser, repoid, repo, _perms)
1245 validate_repo_permissions(apiuser, repoid, repo, _perms)
1235
1246
1236 delete = Optional.extract(delete_keys)
1247 delete = Optional.extract(delete_keys)
1237 try:
1248 try:
1238 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1249 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1239 return {
1250 return {
1240 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1251 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1241 'repository': repo.repo_name
1252 'repository': repo.repo_name
1242 }
1253 }
1243 except Exception:
1254 except Exception:
1244 log.exception(
1255 log.exception(
1245 "Exception occurred while trying to invalidate repo cache")
1256 "Exception occurred while trying to invalidate repo cache")
1246 raise JSONRPCError(
1257 raise JSONRPCError(
1247 'Error occurred during cache invalidation action'
1258 'Error occurred during cache invalidation action'
1248 )
1259 )
1249
1260
1250
1261
1251 #TODO: marcink, change name ?
1262 #TODO: marcink, change name ?
1252 @jsonrpc_method()
1263 @jsonrpc_method()
1253 def lock(request, apiuser, repoid, locked=Optional(None),
1264 def lock(request, apiuser, repoid, locked=Optional(None),
1254 userid=Optional(OAttr('apiuser'))):
1265 userid=Optional(OAttr('apiuser'))):
1255 """
1266 """
1256 Sets the lock state of the specified |repo| by the given user.
1267 Sets the lock state of the specified |repo| by the given user.
1257 From more information, see :ref:`repo-locking`.
1268 From more information, see :ref:`repo-locking`.
1258
1269
1259 * If the ``userid`` option is not set, the repository is locked to the
1270 * If the ``userid`` option is not set, the repository is locked to the
1260 user who called the method.
1271 user who called the method.
1261 * If the ``locked`` parameter is not set, the current lock state of the
1272 * If the ``locked`` parameter is not set, the current lock state of the
1262 repository is displayed.
1273 repository is displayed.
1263
1274
1264 This command can only be run using an |authtoken| with admin rights to
1275 This command can only be run using an |authtoken| with admin rights to
1265 the specified repository.
1276 the specified repository.
1266
1277
1267 This command takes the following options:
1278 This command takes the following options:
1268
1279
1269 :param apiuser: This is filled automatically from the |authtoken|.
1280 :param apiuser: This is filled automatically from the |authtoken|.
1270 :type apiuser: AuthUser
1281 :type apiuser: AuthUser
1271 :param repoid: Sets the repository name or repository ID.
1282 :param repoid: Sets the repository name or repository ID.
1272 :type repoid: str or int
1283 :type repoid: str or int
1273 :param locked: Sets the lock state.
1284 :param locked: Sets the lock state.
1274 :type locked: Optional(``True`` | ``False``)
1285 :type locked: Optional(``True`` | ``False``)
1275 :param userid: Set the repository lock to this user.
1286 :param userid: Set the repository lock to this user.
1276 :type userid: Optional(str or int)
1287 :type userid: Optional(str or int)
1277
1288
1278 Example error output:
1289 Example error output:
1279
1290
1280 .. code-block:: bash
1291 .. code-block:: bash
1281
1292
1282 id : <id_given_in_input>
1293 id : <id_given_in_input>
1283 result : {
1294 result : {
1284 'repo': '<reponame>',
1295 'repo': '<reponame>',
1285 'locked': <bool: lock state>,
1296 'locked': <bool: lock state>,
1286 'locked_since': <int: lock timestamp>,
1297 'locked_since': <int: lock timestamp>,
1287 'locked_by': <username of person who made the lock>,
1298 'locked_by': <username of person who made the lock>,
1288 'lock_reason': <str: reason for locking>,
1299 'lock_reason': <str: reason for locking>,
1289 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1300 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1290 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1301 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1291 or
1302 or
1292 'msg': 'Repo `<repository name>` not locked.'
1303 'msg': 'Repo `<repository name>` not locked.'
1293 or
1304 or
1294 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1305 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1295 }
1306 }
1296 error : null
1307 error : null
1297
1308
1298 Example error output:
1309 Example error output:
1299
1310
1300 .. code-block:: bash
1311 .. code-block:: bash
1301
1312
1302 id : <id_given_in_input>
1313 id : <id_given_in_input>
1303 result : null
1314 result : null
1304 error : {
1315 error : {
1305 'Error occurred locking repository `<reponame>`'
1316 'Error occurred locking repository `<reponame>`'
1306 }
1317 }
1307 """
1318 """
1308
1319
1309 repo = get_repo_or_error(repoid)
1320 repo = get_repo_or_error(repoid)
1310 if not has_superadmin_permission(apiuser):
1321 if not has_superadmin_permission(apiuser):
1311 # check if we have at least write permission for this repo !
1322 # check if we have at least write permission for this repo !
1312 _perms = ('repository.admin', 'repository.write',)
1323 _perms = ('repository.admin', 'repository.write',)
1313 validate_repo_permissions(apiuser, repoid, repo, _perms)
1324 validate_repo_permissions(apiuser, repoid, repo, _perms)
1314
1325
1315 # make sure normal user does not pass someone else userid,
1326 # make sure normal user does not pass someone else userid,
1316 # he is not allowed to do that
1327 # he is not allowed to do that
1317 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1328 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1318 raise JSONRPCError('userid is not the same as your user')
1329 raise JSONRPCError('userid is not the same as your user')
1319
1330
1320 if isinstance(userid, Optional):
1331 if isinstance(userid, Optional):
1321 userid = apiuser.user_id
1332 userid = apiuser.user_id
1322
1333
1323 user = get_user_or_error(userid)
1334 user = get_user_or_error(userid)
1324
1335
1325 if isinstance(locked, Optional):
1336 if isinstance(locked, Optional):
1326 lockobj = repo.locked
1337 lockobj = repo.locked
1327
1338
1328 if lockobj[0] is None:
1339 if lockobj[0] is None:
1329 _d = {
1340 _d = {
1330 'repo': repo.repo_name,
1341 'repo': repo.repo_name,
1331 'locked': False,
1342 'locked': False,
1332 'locked_since': None,
1343 'locked_since': None,
1333 'locked_by': None,
1344 'locked_by': None,
1334 'lock_reason': None,
1345 'lock_reason': None,
1335 'lock_state_changed': False,
1346 'lock_state_changed': False,
1336 'msg': 'Repo `%s` not locked.' % repo.repo_name
1347 'msg': 'Repo `%s` not locked.' % repo.repo_name
1337 }
1348 }
1338 return _d
1349 return _d
1339 else:
1350 else:
1340 _user_id, _time, _reason = lockobj
1351 _user_id, _time, _reason = lockobj
1341 lock_user = get_user_or_error(userid)
1352 lock_user = get_user_or_error(userid)
1342 _d = {
1353 _d = {
1343 'repo': repo.repo_name,
1354 'repo': repo.repo_name,
1344 'locked': True,
1355 'locked': True,
1345 'locked_since': _time,
1356 'locked_since': _time,
1346 'locked_by': lock_user.username,
1357 'locked_by': lock_user.username,
1347 'lock_reason': _reason,
1358 'lock_reason': _reason,
1348 'lock_state_changed': False,
1359 'lock_state_changed': False,
1349 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1360 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1350 % (repo.repo_name, lock_user.username,
1361 % (repo.repo_name, lock_user.username,
1351 json.dumps(time_to_datetime(_time))))
1362 json.dumps(time_to_datetime(_time))))
1352 }
1363 }
1353 return _d
1364 return _d
1354
1365
1355 # force locked state through a flag
1366 # force locked state through a flag
1356 else:
1367 else:
1357 locked = str2bool(locked)
1368 locked = str2bool(locked)
1358 lock_reason = Repository.LOCK_API
1369 lock_reason = Repository.LOCK_API
1359 try:
1370 try:
1360 if locked:
1371 if locked:
1361 lock_time = time.time()
1372 lock_time = time.time()
1362 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1373 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1363 else:
1374 else:
1364 lock_time = None
1375 lock_time = None
1365 Repository.unlock(repo)
1376 Repository.unlock(repo)
1366 _d = {
1377 _d = {
1367 'repo': repo.repo_name,
1378 'repo': repo.repo_name,
1368 'locked': locked,
1379 'locked': locked,
1369 'locked_since': lock_time,
1380 'locked_since': lock_time,
1370 'locked_by': user.username,
1381 'locked_by': user.username,
1371 'lock_reason': lock_reason,
1382 'lock_reason': lock_reason,
1372 'lock_state_changed': True,
1383 'lock_state_changed': True,
1373 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1384 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1374 % (user.username, repo.repo_name, locked))
1385 % (user.username, repo.repo_name, locked))
1375 }
1386 }
1376 return _d
1387 return _d
1377 except Exception:
1388 except Exception:
1378 log.exception(
1389 log.exception(
1379 "Exception occurred while trying to lock repository")
1390 "Exception occurred while trying to lock repository")
1380 raise JSONRPCError(
1391 raise JSONRPCError(
1381 'Error occurred locking repository `%s`' % repo.repo_name
1392 'Error occurred locking repository `%s`' % repo.repo_name
1382 )
1393 )
1383
1394
1384
1395
1385 @jsonrpc_method()
1396 @jsonrpc_method()
1386 def comment_commit(
1397 def comment_commit(
1387 request, apiuser, repoid, commit_id, message, status=Optional(None),
1398 request, apiuser, repoid, commit_id, message, status=Optional(None),
1388 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
1399 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
1389 resolves_comment_id=Optional(None),
1400 resolves_comment_id=Optional(None),
1390 userid=Optional(OAttr('apiuser'))):
1401 userid=Optional(OAttr('apiuser'))):
1391 """
1402 """
1392 Set a commit comment, and optionally change the status of the commit.
1403 Set a commit comment, and optionally change the status of the commit.
1393
1404
1394 :param apiuser: This is filled automatically from the |authtoken|.
1405 :param apiuser: This is filled automatically from the |authtoken|.
1395 :type apiuser: AuthUser
1406 :type apiuser: AuthUser
1396 :param repoid: Set the repository name or repository ID.
1407 :param repoid: Set the repository name or repository ID.
1397 :type repoid: str or int
1408 :type repoid: str or int
1398 :param commit_id: Specify the commit_id for which to set a comment.
1409 :param commit_id: Specify the commit_id for which to set a comment.
1399 :type commit_id: str
1410 :type commit_id: str
1400 :param message: The comment text.
1411 :param message: The comment text.
1401 :type message: str
1412 :type message: str
1402 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
1413 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
1403 'approved', 'rejected', 'under_review'
1414 'approved', 'rejected', 'under_review'
1404 :type status: str
1415 :type status: str
1405 :param comment_type: Comment type, one of: 'note', 'todo'
1416 :param comment_type: Comment type, one of: 'note', 'todo'
1406 :type comment_type: Optional(str), default: 'note'
1417 :type comment_type: Optional(str), default: 'note'
1407 :param userid: Set the user name of the comment creator.
1418 :param userid: Set the user name of the comment creator.
1408 :type userid: Optional(str or int)
1419 :type userid: Optional(str or int)
1409
1420
1410 Example error output:
1421 Example error output:
1411
1422
1412 .. code-block:: bash
1423 .. code-block:: bash
1413
1424
1414 {
1425 {
1415 "id" : <id_given_in_input>,
1426 "id" : <id_given_in_input>,
1416 "result" : {
1427 "result" : {
1417 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1428 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1418 "status_change": null or <status>,
1429 "status_change": null or <status>,
1419 "success": true
1430 "success": true
1420 },
1431 },
1421 "error" : null
1432 "error" : null
1422 }
1433 }
1423
1434
1424 """
1435 """
1425 repo = get_repo_or_error(repoid)
1436 repo = get_repo_or_error(repoid)
1426 if not has_superadmin_permission(apiuser):
1437 if not has_superadmin_permission(apiuser):
1427 _perms = ('repository.read', 'repository.write', 'repository.admin')
1438 _perms = ('repository.read', 'repository.write', 'repository.admin')
1428 validate_repo_permissions(apiuser, repoid, repo, _perms)
1439 validate_repo_permissions(apiuser, repoid, repo, _perms)
1429
1440
1430 try:
1441 try:
1431 commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
1442 commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
1432 except Exception as e:
1443 except Exception as e:
1433 log.exception('Failed to fetch commit')
1444 log.exception('Failed to fetch commit')
1434 raise JSONRPCError(e.message)
1445 raise JSONRPCError(e.message)
1435
1446
1436 if isinstance(userid, Optional):
1447 if isinstance(userid, Optional):
1437 userid = apiuser.user_id
1448 userid = apiuser.user_id
1438
1449
1439 user = get_user_or_error(userid)
1450 user = get_user_or_error(userid)
1440 status = Optional.extract(status)
1451 status = Optional.extract(status)
1441 comment_type = Optional.extract(comment_type)
1452 comment_type = Optional.extract(comment_type)
1442 resolves_comment_id = Optional.extract(resolves_comment_id)
1453 resolves_comment_id = Optional.extract(resolves_comment_id)
1443
1454
1444 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1455 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1445 if status and status not in allowed_statuses:
1456 if status and status not in allowed_statuses:
1446 raise JSONRPCError('Bad status, must be on '
1457 raise JSONRPCError('Bad status, must be on '
1447 'of %s got %s' % (allowed_statuses, status,))
1458 'of %s got %s' % (allowed_statuses, status,))
1448
1459
1449 if resolves_comment_id:
1460 if resolves_comment_id:
1450 comment = ChangesetComment.get(resolves_comment_id)
1461 comment = ChangesetComment.get(resolves_comment_id)
1451 if not comment:
1462 if not comment:
1452 raise JSONRPCError(
1463 raise JSONRPCError(
1453 'Invalid resolves_comment_id `%s` for this commit.'
1464 'Invalid resolves_comment_id `%s` for this commit.'
1454 % resolves_comment_id)
1465 % resolves_comment_id)
1455 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
1466 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
1456 raise JSONRPCError(
1467 raise JSONRPCError(
1457 'Comment `%s` is wrong type for setting status to resolved.'
1468 'Comment `%s` is wrong type for setting status to resolved.'
1458 % resolves_comment_id)
1469 % resolves_comment_id)
1459
1470
1460 try:
1471 try:
1461 rc_config = SettingsModel().get_all_settings()
1472 rc_config = SettingsModel().get_all_settings()
1462 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1473 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1463 status_change_label = ChangesetStatus.get_status_lbl(status)
1474 status_change_label = ChangesetStatus.get_status_lbl(status)
1464 comm = CommentsModel().create(
1475 comm = CommentsModel().create(
1465 message, repo, user, commit_id=commit_id,
1476 message, repo, user, commit_id=commit_id,
1466 status_change=status_change_label,
1477 status_change=status_change_label,
1467 status_change_type=status,
1478 status_change_type=status,
1468 renderer=renderer,
1479 renderer=renderer,
1469 comment_type=comment_type,
1480 comment_type=comment_type,
1470 resolves_comment_id=resolves_comment_id
1481 resolves_comment_id=resolves_comment_id
1471 )
1482 )
1472 if status:
1483 if status:
1473 # also do a status change
1484 # also do a status change
1474 try:
1485 try:
1475 ChangesetStatusModel().set_status(
1486 ChangesetStatusModel().set_status(
1476 repo, status, user, comm, revision=commit_id,
1487 repo, status, user, comm, revision=commit_id,
1477 dont_allow_on_closed_pull_request=True
1488 dont_allow_on_closed_pull_request=True
1478 )
1489 )
1479 except StatusChangeOnClosedPullRequestError:
1490 except StatusChangeOnClosedPullRequestError:
1480 log.exception(
1491 log.exception(
1481 "Exception occurred while trying to change repo commit status")
1492 "Exception occurred while trying to change repo commit status")
1482 msg = ('Changing status on a changeset associated with '
1493 msg = ('Changing status on a changeset associated with '
1483 'a closed pull request is not allowed')
1494 'a closed pull request is not allowed')
1484 raise JSONRPCError(msg)
1495 raise JSONRPCError(msg)
1485
1496
1486 Session().commit()
1497 Session().commit()
1487 return {
1498 return {
1488 'msg': (
1499 'msg': (
1489 'Commented on commit `%s` for repository `%s`' % (
1500 'Commented on commit `%s` for repository `%s`' % (
1490 comm.revision, repo.repo_name)),
1501 comm.revision, repo.repo_name)),
1491 'status_change': status,
1502 'status_change': status,
1492 'success': True,
1503 'success': True,
1493 }
1504 }
1494 except JSONRPCError:
1505 except JSONRPCError:
1495 # catch any inside errors, and re-raise them to prevent from
1506 # catch any inside errors, and re-raise them to prevent from
1496 # below global catch to silence them
1507 # below global catch to silence them
1497 raise
1508 raise
1498 except Exception:
1509 except Exception:
1499 log.exception("Exception occurred while trying to comment on commit")
1510 log.exception("Exception occurred while trying to comment on commit")
1500 raise JSONRPCError(
1511 raise JSONRPCError(
1501 'failed to set comment on repository `%s`' % (repo.repo_name,)
1512 'failed to set comment on repository `%s`' % (repo.repo_name,)
1502 )
1513 )
1503
1514
1504
1515
1505 @jsonrpc_method()
1516 @jsonrpc_method()
1506 def grant_user_permission(request, apiuser, repoid, userid, perm):
1517 def grant_user_permission(request, apiuser, repoid, userid, perm):
1507 """
1518 """
1508 Grant permissions for the specified user on the given repository,
1519 Grant permissions for the specified user on the given repository,
1509 or update existing permissions if found.
1520 or update existing permissions if found.
1510
1521
1511 This command can only be run using an |authtoken| with admin
1522 This command can only be run using an |authtoken| with admin
1512 permissions on the |repo|.
1523 permissions on the |repo|.
1513
1524
1514 :param apiuser: This is filled automatically from the |authtoken|.
1525 :param apiuser: This is filled automatically from the |authtoken|.
1515 :type apiuser: AuthUser
1526 :type apiuser: AuthUser
1516 :param repoid: Set the repository name or repository ID.
1527 :param repoid: Set the repository name or repository ID.
1517 :type repoid: str or int
1528 :type repoid: str or int
1518 :param userid: Set the user name.
1529 :param userid: Set the user name.
1519 :type userid: str
1530 :type userid: str
1520 :param perm: Set the user permissions, using the following format
1531 :param perm: Set the user permissions, using the following format
1521 ``(repository.(none|read|write|admin))``
1532 ``(repository.(none|read|write|admin))``
1522 :type perm: str
1533 :type perm: str
1523
1534
1524 Example output:
1535 Example output:
1525
1536
1526 .. code-block:: bash
1537 .. code-block:: bash
1527
1538
1528 id : <id_given_in_input>
1539 id : <id_given_in_input>
1529 result: {
1540 result: {
1530 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1541 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1531 "success": true
1542 "success": true
1532 }
1543 }
1533 error: null
1544 error: null
1534 """
1545 """
1535
1546
1536 repo = get_repo_or_error(repoid)
1547 repo = get_repo_or_error(repoid)
1537 user = get_user_or_error(userid)
1548 user = get_user_or_error(userid)
1538 perm = get_perm_or_error(perm)
1549 perm = get_perm_or_error(perm)
1539 if not has_superadmin_permission(apiuser):
1550 if not has_superadmin_permission(apiuser):
1540 _perms = ('repository.admin',)
1551 _perms = ('repository.admin',)
1541 validate_repo_permissions(apiuser, repoid, repo, _perms)
1552 validate_repo_permissions(apiuser, repoid, repo, _perms)
1542
1553
1543 try:
1554 try:
1544
1555
1545 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1556 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1546
1557
1547 Session().commit()
1558 Session().commit()
1548 return {
1559 return {
1549 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1560 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1550 perm.permission_name, user.username, repo.repo_name
1561 perm.permission_name, user.username, repo.repo_name
1551 ),
1562 ),
1552 'success': True
1563 'success': True
1553 }
1564 }
1554 except Exception:
1565 except Exception:
1555 log.exception(
1566 log.exception(
1556 "Exception occurred while trying edit permissions for repo")
1567 "Exception occurred while trying edit permissions for repo")
1557 raise JSONRPCError(
1568 raise JSONRPCError(
1558 'failed to edit permission for user: `%s` in repo: `%s`' % (
1569 'failed to edit permission for user: `%s` in repo: `%s`' % (
1559 userid, repoid
1570 userid, repoid
1560 )
1571 )
1561 )
1572 )
1562
1573
1563
1574
1564 @jsonrpc_method()
1575 @jsonrpc_method()
1565 def revoke_user_permission(request, apiuser, repoid, userid):
1576 def revoke_user_permission(request, apiuser, repoid, userid):
1566 """
1577 """
1567 Revoke permission for a user on the specified repository.
1578 Revoke permission for a user on the specified repository.
1568
1579
1569 This command can only be run using an |authtoken| with admin
1580 This command can only be run using an |authtoken| with admin
1570 permissions on the |repo|.
1581 permissions on the |repo|.
1571
1582
1572 :param apiuser: This is filled automatically from the |authtoken|.
1583 :param apiuser: This is filled automatically from the |authtoken|.
1573 :type apiuser: AuthUser
1584 :type apiuser: AuthUser
1574 :param repoid: Set the repository name or repository ID.
1585 :param repoid: Set the repository name or repository ID.
1575 :type repoid: str or int
1586 :type repoid: str or int
1576 :param userid: Set the user name of revoked user.
1587 :param userid: Set the user name of revoked user.
1577 :type userid: str or int
1588 :type userid: str or int
1578
1589
1579 Example error output:
1590 Example error output:
1580
1591
1581 .. code-block:: bash
1592 .. code-block:: bash
1582
1593
1583 id : <id_given_in_input>
1594 id : <id_given_in_input>
1584 result: {
1595 result: {
1585 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1596 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1586 "success": true
1597 "success": true
1587 }
1598 }
1588 error: null
1599 error: null
1589 """
1600 """
1590
1601
1591 repo = get_repo_or_error(repoid)
1602 repo = get_repo_or_error(repoid)
1592 user = get_user_or_error(userid)
1603 user = get_user_or_error(userid)
1593 if not has_superadmin_permission(apiuser):
1604 if not has_superadmin_permission(apiuser):
1594 _perms = ('repository.admin',)
1605 _perms = ('repository.admin',)
1595 validate_repo_permissions(apiuser, repoid, repo, _perms)
1606 validate_repo_permissions(apiuser, repoid, repo, _perms)
1596
1607
1597 try:
1608 try:
1598 RepoModel().revoke_user_permission(repo=repo, user=user)
1609 RepoModel().revoke_user_permission(repo=repo, user=user)
1599 Session().commit()
1610 Session().commit()
1600 return {
1611 return {
1601 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1612 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1602 user.username, repo.repo_name
1613 user.username, repo.repo_name
1603 ),
1614 ),
1604 'success': True
1615 'success': True
1605 }
1616 }
1606 except Exception:
1617 except Exception:
1607 log.exception(
1618 log.exception(
1608 "Exception occurred while trying revoke permissions to repo")
1619 "Exception occurred while trying revoke permissions to repo")
1609 raise JSONRPCError(
1620 raise JSONRPCError(
1610 'failed to edit permission for user: `%s` in repo: `%s`' % (
1621 'failed to edit permission for user: `%s` in repo: `%s`' % (
1611 userid, repoid
1622 userid, repoid
1612 )
1623 )
1613 )
1624 )
1614
1625
1615
1626
1616 @jsonrpc_method()
1627 @jsonrpc_method()
1617 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1628 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1618 """
1629 """
1619 Grant permission for a user group on the specified repository,
1630 Grant permission for a user group on the specified repository,
1620 or update existing permissions.
1631 or update existing permissions.
1621
1632
1622 This command can only be run using an |authtoken| with admin
1633 This command can only be run using an |authtoken| with admin
1623 permissions on the |repo|.
1634 permissions on the |repo|.
1624
1635
1625 :param apiuser: This is filled automatically from the |authtoken|.
1636 :param apiuser: This is filled automatically from the |authtoken|.
1626 :type apiuser: AuthUser
1637 :type apiuser: AuthUser
1627 :param repoid: Set the repository name or repository ID.
1638 :param repoid: Set the repository name or repository ID.
1628 :type repoid: str or int
1639 :type repoid: str or int
1629 :param usergroupid: Specify the ID of the user group.
1640 :param usergroupid: Specify the ID of the user group.
1630 :type usergroupid: str or int
1641 :type usergroupid: str or int
1631 :param perm: Set the user group permissions using the following
1642 :param perm: Set the user group permissions using the following
1632 format: (repository.(none|read|write|admin))
1643 format: (repository.(none|read|write|admin))
1633 :type perm: str
1644 :type perm: str
1634
1645
1635 Example output:
1646 Example output:
1636
1647
1637 .. code-block:: bash
1648 .. code-block:: bash
1638
1649
1639 id : <id_given_in_input>
1650 id : <id_given_in_input>
1640 result : {
1651 result : {
1641 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1652 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1642 "success": true
1653 "success": true
1643
1654
1644 }
1655 }
1645 error : null
1656 error : null
1646
1657
1647 Example error output:
1658 Example error output:
1648
1659
1649 .. code-block:: bash
1660 .. code-block:: bash
1650
1661
1651 id : <id_given_in_input>
1662 id : <id_given_in_input>
1652 result : null
1663 result : null
1653 error : {
1664 error : {
1654 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1665 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1655 }
1666 }
1656
1667
1657 """
1668 """
1658
1669
1659 repo = get_repo_or_error(repoid)
1670 repo = get_repo_or_error(repoid)
1660 perm = get_perm_or_error(perm)
1671 perm = get_perm_or_error(perm)
1661 if not has_superadmin_permission(apiuser):
1672 if not has_superadmin_permission(apiuser):
1662 _perms = ('repository.admin',)
1673 _perms = ('repository.admin',)
1663 validate_repo_permissions(apiuser, repoid, repo, _perms)
1674 validate_repo_permissions(apiuser, repoid, repo, _perms)
1664
1675
1665 user_group = get_user_group_or_error(usergroupid)
1676 user_group = get_user_group_or_error(usergroupid)
1666 if not has_superadmin_permission(apiuser):
1677 if not has_superadmin_permission(apiuser):
1667 # check if we have at least read permission for this user group !
1678 # check if we have at least read permission for this user group !
1668 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1679 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1669 if not HasUserGroupPermissionAnyApi(*_perms)(
1680 if not HasUserGroupPermissionAnyApi(*_perms)(
1670 user=apiuser, user_group_name=user_group.users_group_name):
1681 user=apiuser, user_group_name=user_group.users_group_name):
1671 raise JSONRPCError(
1682 raise JSONRPCError(
1672 'user group `%s` does not exist' % (usergroupid,))
1683 'user group `%s` does not exist' % (usergroupid,))
1673
1684
1674 try:
1685 try:
1675 RepoModel().grant_user_group_permission(
1686 RepoModel().grant_user_group_permission(
1676 repo=repo, group_name=user_group, perm=perm)
1687 repo=repo, group_name=user_group, perm=perm)
1677
1688
1678 Session().commit()
1689 Session().commit()
1679 return {
1690 return {
1680 'msg': 'Granted perm: `%s` for user group: `%s` in '
1691 'msg': 'Granted perm: `%s` for user group: `%s` in '
1681 'repo: `%s`' % (
1692 'repo: `%s`' % (
1682 perm.permission_name, user_group.users_group_name,
1693 perm.permission_name, user_group.users_group_name,
1683 repo.repo_name
1694 repo.repo_name
1684 ),
1695 ),
1685 'success': True
1696 'success': True
1686 }
1697 }
1687 except Exception:
1698 except Exception:
1688 log.exception(
1699 log.exception(
1689 "Exception occurred while trying change permission on repo")
1700 "Exception occurred while trying change permission on repo")
1690 raise JSONRPCError(
1701 raise JSONRPCError(
1691 'failed to edit permission for user group: `%s` in '
1702 'failed to edit permission for user group: `%s` in '
1692 'repo: `%s`' % (
1703 'repo: `%s`' % (
1693 usergroupid, repo.repo_name
1704 usergroupid, repo.repo_name
1694 )
1705 )
1695 )
1706 )
1696
1707
1697
1708
1698 @jsonrpc_method()
1709 @jsonrpc_method()
1699 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1710 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1700 """
1711 """
1701 Revoke the permissions of a user group on a given repository.
1712 Revoke the permissions of a user group on a given repository.
1702
1713
1703 This command can only be run using an |authtoken| with admin
1714 This command can only be run using an |authtoken| with admin
1704 permissions on the |repo|.
1715 permissions on the |repo|.
1705
1716
1706 :param apiuser: This is filled automatically from the |authtoken|.
1717 :param apiuser: This is filled automatically from the |authtoken|.
1707 :type apiuser: AuthUser
1718 :type apiuser: AuthUser
1708 :param repoid: Set the repository name or repository ID.
1719 :param repoid: Set the repository name or repository ID.
1709 :type repoid: str or int
1720 :type repoid: str or int
1710 :param usergroupid: Specify the user group ID.
1721 :param usergroupid: Specify the user group ID.
1711 :type usergroupid: str or int
1722 :type usergroupid: str or int
1712
1723
1713 Example output:
1724 Example output:
1714
1725
1715 .. code-block:: bash
1726 .. code-block:: bash
1716
1727
1717 id : <id_given_in_input>
1728 id : <id_given_in_input>
1718 result: {
1729 result: {
1719 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1730 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1720 "success": true
1731 "success": true
1721 }
1732 }
1722 error: null
1733 error: null
1723 """
1734 """
1724
1735
1725 repo = get_repo_or_error(repoid)
1736 repo = get_repo_or_error(repoid)
1726 if not has_superadmin_permission(apiuser):
1737 if not has_superadmin_permission(apiuser):
1727 _perms = ('repository.admin',)
1738 _perms = ('repository.admin',)
1728 validate_repo_permissions(apiuser, repoid, repo, _perms)
1739 validate_repo_permissions(apiuser, repoid, repo, _perms)
1729
1740
1730 user_group = get_user_group_or_error(usergroupid)
1741 user_group = get_user_group_or_error(usergroupid)
1731 if not has_superadmin_permission(apiuser):
1742 if not has_superadmin_permission(apiuser):
1732 # check if we have at least read permission for this user group !
1743 # check if we have at least read permission for this user group !
1733 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1744 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1734 if not HasUserGroupPermissionAnyApi(*_perms)(
1745 if not HasUserGroupPermissionAnyApi(*_perms)(
1735 user=apiuser, user_group_name=user_group.users_group_name):
1746 user=apiuser, user_group_name=user_group.users_group_name):
1736 raise JSONRPCError(
1747 raise JSONRPCError(
1737 'user group `%s` does not exist' % (usergroupid,))
1748 'user group `%s` does not exist' % (usergroupid,))
1738
1749
1739 try:
1750 try:
1740 RepoModel().revoke_user_group_permission(
1751 RepoModel().revoke_user_group_permission(
1741 repo=repo, group_name=user_group)
1752 repo=repo, group_name=user_group)
1742
1753
1743 Session().commit()
1754 Session().commit()
1744 return {
1755 return {
1745 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1756 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1746 user_group.users_group_name, repo.repo_name
1757 user_group.users_group_name, repo.repo_name
1747 ),
1758 ),
1748 'success': True
1759 'success': True
1749 }
1760 }
1750 except Exception:
1761 except Exception:
1751 log.exception("Exception occurred while trying revoke "
1762 log.exception("Exception occurred while trying revoke "
1752 "user group permission on repo")
1763 "user group permission on repo")
1753 raise JSONRPCError(
1764 raise JSONRPCError(
1754 'failed to edit permission for user group: `%s` in '
1765 'failed to edit permission for user group: `%s` in '
1755 'repo: `%s`' % (
1766 'repo: `%s`' % (
1756 user_group.users_group_name, repo.repo_name
1767 user_group.users_group_name, repo.repo_name
1757 )
1768 )
1758 )
1769 )
1759
1770
1760
1771
1761 @jsonrpc_method()
1772 @jsonrpc_method()
1762 def pull(request, apiuser, repoid):
1773 def pull(request, apiuser, repoid):
1763 """
1774 """
1764 Triggers a pull on the given repository from a remote location. You
1775 Triggers a pull on the given repository from a remote location. You
1765 can use this to keep remote repositories up-to-date.
1776 can use this to keep remote repositories up-to-date.
1766
1777
1767 This command can only be run using an |authtoken| with admin
1778 This command can only be run using an |authtoken| with admin
1768 rights to the specified repository. For more information,
1779 rights to the specified repository. For more information,
1769 see :ref:`config-token-ref`.
1780 see :ref:`config-token-ref`.
1770
1781
1771 This command takes the following options:
1782 This command takes the following options:
1772
1783
1773 :param apiuser: This is filled automatically from the |authtoken|.
1784 :param apiuser: This is filled automatically from the |authtoken|.
1774 :type apiuser: AuthUser
1785 :type apiuser: AuthUser
1775 :param repoid: The repository name or repository ID.
1786 :param repoid: The repository name or repository ID.
1776 :type repoid: str or int
1787 :type repoid: str or int
1777
1788
1778 Example output:
1789 Example output:
1779
1790
1780 .. code-block:: bash
1791 .. code-block:: bash
1781
1792
1782 id : <id_given_in_input>
1793 id : <id_given_in_input>
1783 result : {
1794 result : {
1784 "msg": "Pulled from `<repository name>`"
1795 "msg": "Pulled from `<repository name>`"
1785 "repository": "<repository name>"
1796 "repository": "<repository name>"
1786 }
1797 }
1787 error : null
1798 error : null
1788
1799
1789 Example error output:
1800 Example error output:
1790
1801
1791 .. code-block:: bash
1802 .. code-block:: bash
1792
1803
1793 id : <id_given_in_input>
1804 id : <id_given_in_input>
1794 result : null
1805 result : null
1795 error : {
1806 error : {
1796 "Unable to pull changes from `<reponame>`"
1807 "Unable to pull changes from `<reponame>`"
1797 }
1808 }
1798
1809
1799 """
1810 """
1800
1811
1801 repo = get_repo_or_error(repoid)
1812 repo = get_repo_or_error(repoid)
1802 if not has_superadmin_permission(apiuser):
1813 if not has_superadmin_permission(apiuser):
1803 _perms = ('repository.admin',)
1814 _perms = ('repository.admin',)
1804 validate_repo_permissions(apiuser, repoid, repo, _perms)
1815 validate_repo_permissions(apiuser, repoid, repo, _perms)
1805
1816
1806 try:
1817 try:
1807 ScmModel().pull_changes(repo.repo_name, apiuser.username)
1818 ScmModel().pull_changes(repo.repo_name, apiuser.username)
1808 return {
1819 return {
1809 'msg': 'Pulled from `%s`' % repo.repo_name,
1820 'msg': 'Pulled from `%s`' % repo.repo_name,
1810 'repository': repo.repo_name
1821 'repository': repo.repo_name
1811 }
1822 }
1812 except Exception:
1823 except Exception:
1813 log.exception("Exception occurred while trying to "
1824 log.exception("Exception occurred while trying to "
1814 "pull changes from remote location")
1825 "pull changes from remote location")
1815 raise JSONRPCError(
1826 raise JSONRPCError(
1816 'Unable to pull changes from `%s`' % repo.repo_name
1827 'Unable to pull changes from `%s`' % repo.repo_name
1817 )
1828 )
1818
1829
1819
1830
1820 @jsonrpc_method()
1831 @jsonrpc_method()
1821 def strip(request, apiuser, repoid, revision, branch):
1832 def strip(request, apiuser, repoid, revision, branch):
1822 """
1833 """
1823 Strips the given revision from the specified repository.
1834 Strips the given revision from the specified repository.
1824
1835
1825 * This will remove the revision and all of its decendants.
1836 * This will remove the revision and all of its decendants.
1826
1837
1827 This command can only be run using an |authtoken| with admin rights to
1838 This command can only be run using an |authtoken| with admin rights to
1828 the specified repository.
1839 the specified repository.
1829
1840
1830 This command takes the following options:
1841 This command takes the following options:
1831
1842
1832 :param apiuser: This is filled automatically from the |authtoken|.
1843 :param apiuser: This is filled automatically from the |authtoken|.
1833 :type apiuser: AuthUser
1844 :type apiuser: AuthUser
1834 :param repoid: The repository name or repository ID.
1845 :param repoid: The repository name or repository ID.
1835 :type repoid: str or int
1846 :type repoid: str or int
1836 :param revision: The revision you wish to strip.
1847 :param revision: The revision you wish to strip.
1837 :type revision: str
1848 :type revision: str
1838 :param branch: The branch from which to strip the revision.
1849 :param branch: The branch from which to strip the revision.
1839 :type branch: str
1850 :type branch: str
1840
1851
1841 Example output:
1852 Example output:
1842
1853
1843 .. code-block:: bash
1854 .. code-block:: bash
1844
1855
1845 id : <id_given_in_input>
1856 id : <id_given_in_input>
1846 result : {
1857 result : {
1847 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1858 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1848 "repository": "<repository name>"
1859 "repository": "<repository name>"
1849 }
1860 }
1850 error : null
1861 error : null
1851
1862
1852 Example error output:
1863 Example error output:
1853
1864
1854 .. code-block:: bash
1865 .. code-block:: bash
1855
1866
1856 id : <id_given_in_input>
1867 id : <id_given_in_input>
1857 result : null
1868 result : null
1858 error : {
1869 error : {
1859 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1870 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1860 }
1871 }
1861
1872
1862 """
1873 """
1863
1874
1864 repo = get_repo_or_error(repoid)
1875 repo = get_repo_or_error(repoid)
1865 if not has_superadmin_permission(apiuser):
1876 if not has_superadmin_permission(apiuser):
1866 _perms = ('repository.admin',)
1877 _perms = ('repository.admin',)
1867 validate_repo_permissions(apiuser, repoid, repo, _perms)
1878 validate_repo_permissions(apiuser, repoid, repo, _perms)
1868
1879
1869 try:
1880 try:
1870 ScmModel().strip(repo, revision, branch)
1881 ScmModel().strip(repo, revision, branch)
1871 return {
1882 return {
1872 'msg': 'Stripped commit %s from repo `%s`' % (
1883 'msg': 'Stripped commit %s from repo `%s`' % (
1873 revision, repo.repo_name),
1884 revision, repo.repo_name),
1874 'repository': repo.repo_name
1885 'repository': repo.repo_name
1875 }
1886 }
1876 except Exception:
1887 except Exception:
1877 log.exception("Exception while trying to strip")
1888 log.exception("Exception while trying to strip")
1878 raise JSONRPCError(
1889 raise JSONRPCError(
1879 'Unable to strip commit %s from repo `%s`' % (
1890 'Unable to strip commit %s from repo `%s`' % (
1880 revision, repo.repo_name)
1891 revision, repo.repo_name)
1881 )
1892 )
1882
1893
1883
1894
1884 @jsonrpc_method()
1895 @jsonrpc_method()
1885 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
1896 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
1886 """
1897 """
1887 Returns all settings for a repository. If key is given it only returns the
1898 Returns all settings for a repository. If key is given it only returns the
1888 setting identified by the key or null.
1899 setting identified by the key or null.
1889
1900
1890 :param apiuser: This is filled automatically from the |authtoken|.
1901 :param apiuser: This is filled automatically from the |authtoken|.
1891 :type apiuser: AuthUser
1902 :type apiuser: AuthUser
1892 :param repoid: The repository name or repository id.
1903 :param repoid: The repository name or repository id.
1893 :type repoid: str or int
1904 :type repoid: str or int
1894 :param key: Key of the setting to return.
1905 :param key: Key of the setting to return.
1895 :type: key: Optional(str)
1906 :type: key: Optional(str)
1896
1907
1897 Example output:
1908 Example output:
1898
1909
1899 .. code-block:: bash
1910 .. code-block:: bash
1900
1911
1901 {
1912 {
1902 "error": null,
1913 "error": null,
1903 "id": 237,
1914 "id": 237,
1904 "result": {
1915 "result": {
1905 "extensions_largefiles": true,
1916 "extensions_largefiles": true,
1906 "extensions_evolve": true,
1917 "extensions_evolve": true,
1907 "hooks_changegroup_push_logger": true,
1918 "hooks_changegroup_push_logger": true,
1908 "hooks_changegroup_repo_size": false,
1919 "hooks_changegroup_repo_size": false,
1909 "hooks_outgoing_pull_logger": true,
1920 "hooks_outgoing_pull_logger": true,
1910 "phases_publish": "True",
1921 "phases_publish": "True",
1911 "rhodecode_hg_use_rebase_for_merging": true,
1922 "rhodecode_hg_use_rebase_for_merging": true,
1912 "rhodecode_pr_merge_enabled": true,
1923 "rhodecode_pr_merge_enabled": true,
1913 "rhodecode_use_outdated_comments": true
1924 "rhodecode_use_outdated_comments": true
1914 }
1925 }
1915 }
1926 }
1916 """
1927 """
1917
1928
1918 # Restrict access to this api method to admins only.
1929 # Restrict access to this api method to admins only.
1919 if not has_superadmin_permission(apiuser):
1930 if not has_superadmin_permission(apiuser):
1920 raise JSONRPCForbidden()
1931 raise JSONRPCForbidden()
1921
1932
1922 try:
1933 try:
1923 repo = get_repo_or_error(repoid)
1934 repo = get_repo_or_error(repoid)
1924 settings_model = VcsSettingsModel(repo=repo)
1935 settings_model = VcsSettingsModel(repo=repo)
1925 settings = settings_model.get_global_settings()
1936 settings = settings_model.get_global_settings()
1926 settings.update(settings_model.get_repo_settings())
1937 settings.update(settings_model.get_repo_settings())
1927
1938
1928 # If only a single setting is requested fetch it from all settings.
1939 # If only a single setting is requested fetch it from all settings.
1929 key = Optional.extract(key)
1940 key = Optional.extract(key)
1930 if key is not None:
1941 if key is not None:
1931 settings = settings.get(key, None)
1942 settings = settings.get(key, None)
1932 except Exception:
1943 except Exception:
1933 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
1944 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
1934 log.exception(msg)
1945 log.exception(msg)
1935 raise JSONRPCError(msg)
1946 raise JSONRPCError(msg)
1936
1947
1937 return settings
1948 return settings
1938
1949
1939
1950
1940 @jsonrpc_method()
1951 @jsonrpc_method()
1941 def set_repo_settings(request, apiuser, repoid, settings):
1952 def set_repo_settings(request, apiuser, repoid, settings):
1942 """
1953 """
1943 Update repository settings. Returns true on success.
1954 Update repository settings. Returns true on success.
1944
1955
1945 :param apiuser: This is filled automatically from the |authtoken|.
1956 :param apiuser: This is filled automatically from the |authtoken|.
1946 :type apiuser: AuthUser
1957 :type apiuser: AuthUser
1947 :param repoid: The repository name or repository id.
1958 :param repoid: The repository name or repository id.
1948 :type repoid: str or int
1959 :type repoid: str or int
1949 :param settings: The new settings for the repository.
1960 :param settings: The new settings for the repository.
1950 :type: settings: dict
1961 :type: settings: dict
1951
1962
1952 Example output:
1963 Example output:
1953
1964
1954 .. code-block:: bash
1965 .. code-block:: bash
1955
1966
1956 {
1967 {
1957 "error": null,
1968 "error": null,
1958 "id": 237,
1969 "id": 237,
1959 "result": true
1970 "result": true
1960 }
1971 }
1961 """
1972 """
1962 # Restrict access to this api method to admins only.
1973 # Restrict access to this api method to admins only.
1963 if not has_superadmin_permission(apiuser):
1974 if not has_superadmin_permission(apiuser):
1964 raise JSONRPCForbidden()
1975 raise JSONRPCForbidden()
1965
1976
1966 if type(settings) is not dict:
1977 if type(settings) is not dict:
1967 raise JSONRPCError('Settings have to be a JSON Object.')
1978 raise JSONRPCError('Settings have to be a JSON Object.')
1968
1979
1969 try:
1980 try:
1970 settings_model = VcsSettingsModel(repo=repoid)
1981 settings_model = VcsSettingsModel(repo=repoid)
1971
1982
1972 # Merge global, repo and incoming settings.
1983 # Merge global, repo and incoming settings.
1973 new_settings = settings_model.get_global_settings()
1984 new_settings = settings_model.get_global_settings()
1974 new_settings.update(settings_model.get_repo_settings())
1985 new_settings.update(settings_model.get_repo_settings())
1975 new_settings.update(settings)
1986 new_settings.update(settings)
1976
1987
1977 # Update the settings.
1988 # Update the settings.
1978 inherit_global_settings = new_settings.get(
1989 inherit_global_settings = new_settings.get(
1979 'inherit_global_settings', False)
1990 'inherit_global_settings', False)
1980 settings_model.create_or_update_repo_settings(
1991 settings_model.create_or_update_repo_settings(
1981 new_settings, inherit_global_settings=inherit_global_settings)
1992 new_settings, inherit_global_settings=inherit_global_settings)
1982 Session().commit()
1993 Session().commit()
1983 except Exception:
1994 except Exception:
1984 msg = 'Failed to update settings for repository `{}`'.format(repoid)
1995 msg = 'Failed to update settings for repository `{}`'.format(repoid)
1985 log.exception(msg)
1996 log.exception(msg)
1986 raise JSONRPCError(msg)
1997 raise JSONRPCError(msg)
1987
1998
1988 # Indicate success.
1999 # Indicate success.
1989 return True
2000 return True
1990
2001
1991
2002
1992 @jsonrpc_method()
2003 @jsonrpc_method()
1993 def maintenance(request, apiuser, repoid):
2004 def maintenance(request, apiuser, repoid):
1994 """
2005 """
1995 Triggers a maintenance on the given repository.
2006 Triggers a maintenance on the given repository.
1996
2007
1997 This command can only be run using an |authtoken| with admin
2008 This command can only be run using an |authtoken| with admin
1998 rights to the specified repository. For more information,
2009 rights to the specified repository. For more information,
1999 see :ref:`config-token-ref`.
2010 see :ref:`config-token-ref`.
2000
2011
2001 This command takes the following options:
2012 This command takes the following options:
2002
2013
2003 :param apiuser: This is filled automatically from the |authtoken|.
2014 :param apiuser: This is filled automatically from the |authtoken|.
2004 :type apiuser: AuthUser
2015 :type apiuser: AuthUser
2005 :param repoid: The repository name or repository ID.
2016 :param repoid: The repository name or repository ID.
2006 :type repoid: str or int
2017 :type repoid: str or int
2007
2018
2008 Example output:
2019 Example output:
2009
2020
2010 .. code-block:: bash
2021 .. code-block:: bash
2011
2022
2012 id : <id_given_in_input>
2023 id : <id_given_in_input>
2013 result : {
2024 result : {
2014 "msg": "executed maintenance command",
2025 "msg": "executed maintenance command",
2015 "executed_actions": [
2026 "executed_actions": [
2016 <action_message>, <action_message2>...
2027 <action_message>, <action_message2>...
2017 ],
2028 ],
2018 "repository": "<repository name>"
2029 "repository": "<repository name>"
2019 }
2030 }
2020 error : null
2031 error : null
2021
2032
2022 Example error output:
2033 Example error output:
2023
2034
2024 .. code-block:: bash
2035 .. code-block:: bash
2025
2036
2026 id : <id_given_in_input>
2037 id : <id_given_in_input>
2027 result : null
2038 result : null
2028 error : {
2039 error : {
2029 "Unable to execute maintenance on `<reponame>`"
2040 "Unable to execute maintenance on `<reponame>`"
2030 }
2041 }
2031
2042
2032 """
2043 """
2033
2044
2034 repo = get_repo_or_error(repoid)
2045 repo = get_repo_or_error(repoid)
2035 if not has_superadmin_permission(apiuser):
2046 if not has_superadmin_permission(apiuser):
2036 _perms = ('repository.admin',)
2047 _perms = ('repository.admin',)
2037 validate_repo_permissions(apiuser, repoid, repo, _perms)
2048 validate_repo_permissions(apiuser, repoid, repo, _perms)
2038
2049
2039 try:
2050 try:
2040 maintenance = repo_maintenance.RepoMaintenance()
2051 maintenance = repo_maintenance.RepoMaintenance()
2041 executed_actions = maintenance.execute(repo)
2052 executed_actions = maintenance.execute(repo)
2042
2053
2043 return {
2054 return {
2044 'msg': 'executed maintenance command',
2055 'msg': 'executed maintenance command',
2045 'executed_actions': executed_actions,
2056 'executed_actions': executed_actions,
2046 'repository': repo.repo_name
2057 'repository': repo.repo_name
2047 }
2058 }
2048 except Exception:
2059 except Exception:
2049 log.exception("Exception occurred while trying to run maintenance")
2060 log.exception("Exception occurred while trying to run maintenance")
2050 raise JSONRPCError(
2061 raise JSONRPCError(
2051 'Unable to execute maintenance on `%s`' % repo.repo_name)
2062 'Unable to execute maintenance on `%s`' % repo.repo_name)
@@ -1,225 +1,226 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-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 logging
21 import logging
22
22
23 from pyramid.view import view_config
23 from pyramid.view import view_config
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25
25
26 from rhodecode.apps._base import RepoAppView
26 from rhodecode.apps._base import RepoAppView
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import (
29 from rhodecode.lib.auth import (
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.lib.exceptions import AttachedForksError
31 from rhodecode.lib.exceptions import AttachedForksError
32 from rhodecode.lib.utils2 import safe_int
32 from rhodecode.lib.utils2 import safe_int
33 from rhodecode.lib.vcs import RepositoryError
33 from rhodecode.lib.vcs import RepositoryError
34 from rhodecode.model.db import Session, UserFollowing, User, Repository
34 from rhodecode.model.db import Session, UserFollowing, User, Repository
35 from rhodecode.model.repo import RepoModel
35 from rhodecode.model.repo import RepoModel
36 from rhodecode.model.scm import ScmModel
36 from rhodecode.model.scm import ScmModel
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40
40
41 class RepoSettingsView(RepoAppView):
41 class RepoSettingsView(RepoAppView):
42
42
43 def load_default_context(self):
43 def load_default_context(self):
44 c = self._get_local_tmpl_context()
44 c = self._get_local_tmpl_context()
45
45
46 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
46 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
47 c.repo_info = self.db_repo
47 c.repo_info = self.db_repo
48
48
49 self._register_global_c(c)
49 self._register_global_c(c)
50 return c
50 return c
51
51
52 @LoginRequired()
52 @LoginRequired()
53 @HasRepoPermissionAnyDecorator('repository.admin')
53 @HasRepoPermissionAnyDecorator('repository.admin')
54 @view_config(
54 @view_config(
55 route_name='edit_repo_advanced', request_method='GET',
55 route_name='edit_repo_advanced', request_method='GET',
56 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
56 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
57 def edit_advanced(self):
57 def edit_advanced(self):
58 c = self.load_default_context()
58 c = self.load_default_context()
59 c.active = 'advanced'
59 c.active = 'advanced'
60
60
61 c.default_user_id = User.get_default_user().user_id
61 c.default_user_id = User.get_default_user().user_id
62 c.in_public_journal = UserFollowing.query() \
62 c.in_public_journal = UserFollowing.query() \
63 .filter(UserFollowing.user_id == c.default_user_id) \
63 .filter(UserFollowing.user_id == c.default_user_id) \
64 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
64 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
65
65
66 c.has_origin_repo_read_perm = False
66 c.has_origin_repo_read_perm = False
67 if self.db_repo.fork:
67 if self.db_repo.fork:
68 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
68 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
69 'repository.write', 'repository.read', 'repository.admin')(
69 'repository.write', 'repository.read', 'repository.admin')(
70 self.db_repo.fork.repo_name, 'repo set as fork page')
70 self.db_repo.fork.repo_name, 'repo set as fork page')
71
71
72 return self._get_template_context(c)
72 return self._get_template_context(c)
73
73
74 @LoginRequired()
74 @LoginRequired()
75 @HasRepoPermissionAnyDecorator('repository.admin')
75 @HasRepoPermissionAnyDecorator('repository.admin')
76 @view_config(
76 @view_config(
77 route_name='edit_repo_advanced_delete', request_method='POST',
77 route_name='edit_repo_advanced_delete', request_method='POST',
78 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
78 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
79 def edit_advanced_delete(self):
79 def edit_advanced_delete(self):
80 """
80 """
81 Deletes the repository, or shows warnings if deletion is not possible
81 Deletes the repository, or shows warnings if deletion is not possible
82 because of attached forks or other errors.
82 because of attached forks or other errors.
83 """
83 """
84 _ = self.request.translate
84 _ = self.request.translate
85 handle_forks = self.request.POST.get('forks', None)
85 handle_forks = self.request.POST.get('forks', None)
86
86
87 try:
87 try:
88 _forks = self.db_repo.forks.count()
88 _forks = self.db_repo.forks.count()
89 if _forks and handle_forks:
89 if _forks and handle_forks:
90 if handle_forks == 'detach_forks':
90 if handle_forks == 'detach_forks':
91 handle_forks = 'detach'
91 handle_forks = 'detach'
92 h.flash(_('Detached %s forks') % _forks, category='success')
92 h.flash(_('Detached %s forks') % _forks, category='success')
93 elif handle_forks == 'delete_forks':
93 elif handle_forks == 'delete_forks':
94 handle_forks = 'delete'
94 handle_forks = 'delete'
95 h.flash(_('Deleted %s forks') % _forks, category='success')
95 h.flash(_('Deleted %s forks') % _forks, category='success')
96
96
97 repo_data = self.db_repo.get_api_data()
97 repo_data = self.db_repo.get_api_data()
98 RepoModel().delete(self.db_repo, forks=handle_forks)
98 RepoModel().delete(self.db_repo, forks=handle_forks)
99
99
100 repo = audit_logger.RepoWrap(repo_id=self.db_repo.repo_id,
100 repo = audit_logger.RepoWrap(repo_id=None,
101 repo_name=self.db_repo.repo_name)
101 repo_name=self.db_repo.repo_name)
102 audit_logger.store(
102 audit_logger.store(
103 action='repo.delete', action_data={'repo_data': repo_data},
103 action='repo.delete',
104 action_data={'repo_data': repo_data, 'source': 'web_action'},
104 user=self._rhodecode_user, repo=repo, commit=False)
105 user=self._rhodecode_user, repo=repo, commit=False)
105
106
106 ScmModel().mark_for_invalidation(self.db_repo_name)
107 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
107 h.flash(
108 h.flash(
108 _('Deleted repository `%s`') % self.db_repo_name,
109 _('Deleted repository `%s`') % self.db_repo_name,
109 category='success')
110 category='success')
110 Session().commit()
111 Session().commit()
111 except AttachedForksError:
112 except AttachedForksError:
112 repo_advanced_url = h.route_path(
113 repo_advanced_url = h.route_path(
113 'edit_repo_advanced', repo_name=self.db_repo_name,
114 'edit_repo_advanced', repo_name=self.db_repo_name,
114 _anchor='advanced-delete')
115 _anchor='advanced-delete')
115 delete_anchor = h.link_to(_('detach or delete'), repo_advanced_url)
116 delete_anchor = h.link_to(_('detach or delete'), repo_advanced_url)
116 h.flash(_('Cannot delete `{repo}` it still contains attached forks. '
117 h.flash(_('Cannot delete `{repo}` it still contains attached forks. '
117 'Try using {delete_or_detach} option.')
118 'Try using {delete_or_detach} option.')
118 .format(repo=self.db_repo_name, delete_or_detach=delete_anchor),
119 .format(repo=self.db_repo_name, delete_or_detach=delete_anchor),
119 category='warning')
120 category='warning')
120
121
121 # redirect to advanced for forks handle action ?
122 # redirect to advanced for forks handle action ?
122 raise HTTPFound(repo_advanced_url)
123 raise HTTPFound(repo_advanced_url)
123
124
124 except Exception:
125 except Exception:
125 log.exception("Exception during deletion of repository")
126 log.exception("Exception during deletion of repository")
126 h.flash(_('An error occurred during deletion of `%s`')
127 h.flash(_('An error occurred during deletion of `%s`')
127 % self.db_repo_name, category='error')
128 % self.db_repo_name, category='error')
128 # redirect to advanced for more deletion options
129 # redirect to advanced for more deletion options
129 raise HTTPFound(
130 raise HTTPFound(
130 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name),
131 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name),
131 _anchor='advanced-delete')
132 _anchor='advanced-delete')
132
133
133 raise HTTPFound(h.route_path('home'))
134 raise HTTPFound(h.route_path('home'))
134
135
135 @LoginRequired()
136 @LoginRequired()
136 @HasRepoPermissionAnyDecorator('repository.admin')
137 @HasRepoPermissionAnyDecorator('repository.admin')
137 @CSRFRequired()
138 @CSRFRequired()
138 @view_config(
139 @view_config(
139 route_name='edit_repo_advanced_journal', request_method='POST',
140 route_name='edit_repo_advanced_journal', request_method='POST',
140 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
141 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
141 def edit_advanced_journal(self):
142 def edit_advanced_journal(self):
142 """
143 """
143 Set's this repository to be visible in public journal,
144 Set's this repository to be visible in public journal,
144 in other words making default user to follow this repo
145 in other words making default user to follow this repo
145 """
146 """
146 _ = self.request.translate
147 _ = self.request.translate
147
148
148 try:
149 try:
149 user_id = User.get_default_user().user_id
150 user_id = User.get_default_user().user_id
150 ScmModel().toggle_following_repo(self.db_repo.repo_id, user_id)
151 ScmModel().toggle_following_repo(self.db_repo.repo_id, user_id)
151 h.flash(_('Updated repository visibility in public journal'),
152 h.flash(_('Updated repository visibility in public journal'),
152 category='success')
153 category='success')
153 Session().commit()
154 Session().commit()
154 except Exception:
155 except Exception:
155 h.flash(_('An error occurred during setting this '
156 h.flash(_('An error occurred during setting this '
156 'repository in public journal'),
157 'repository in public journal'),
157 category='error')
158 category='error')
158
159
159 raise HTTPFound(
160 raise HTTPFound(
160 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
161 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
161
162
162 @LoginRequired()
163 @LoginRequired()
163 @HasRepoPermissionAnyDecorator('repository.admin')
164 @HasRepoPermissionAnyDecorator('repository.admin')
164 @CSRFRequired()
165 @CSRFRequired()
165 @view_config(
166 @view_config(
166 route_name='edit_repo_advanced_fork', request_method='POST',
167 route_name='edit_repo_advanced_fork', request_method='POST',
167 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
168 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
168 def edit_advanced_fork(self):
169 def edit_advanced_fork(self):
169 """
170 """
170 Mark given repository as a fork of another
171 Mark given repository as a fork of another
171 """
172 """
172 _ = self.request.translate
173 _ = self.request.translate
173
174
174 new_fork_id = self.request.POST.get('id_fork_of')
175 new_fork_id = self.request.POST.get('id_fork_of')
175 try:
176 try:
176
177
177 if new_fork_id and not new_fork_id.isdigit():
178 if new_fork_id and not new_fork_id.isdigit():
178 log.error('Given fork id %s is not an INT', new_fork_id)
179 log.error('Given fork id %s is not an INT', new_fork_id)
179
180
180 fork_id = safe_int(new_fork_id)
181 fork_id = safe_int(new_fork_id)
181 repo = ScmModel().mark_as_fork(
182 repo = ScmModel().mark_as_fork(
182 self.db_repo_name, fork_id, self._rhodecode_user.user_id)
183 self.db_repo_name, fork_id, self._rhodecode_user.user_id)
183 fork = repo.fork.repo_name if repo.fork else _('Nothing')
184 fork = repo.fork.repo_name if repo.fork else _('Nothing')
184 Session().commit()
185 Session().commit()
185 h.flash(_('Marked repo %s as fork of %s') % (self.db_repo_name, fork),
186 h.flash(_('Marked repo %s as fork of %s') % (self.db_repo_name, fork),
186 category='success')
187 category='success')
187 except RepositoryError as e:
188 except RepositoryError as e:
188 log.exception("Repository Error occurred")
189 log.exception("Repository Error occurred")
189 h.flash(str(e), category='error')
190 h.flash(str(e), category='error')
190 except Exception as e:
191 except Exception as e:
191 log.exception("Exception while editing fork")
192 log.exception("Exception while editing fork")
192 h.flash(_('An error occurred during this operation'),
193 h.flash(_('An error occurred during this operation'),
193 category='error')
194 category='error')
194
195
195 raise HTTPFound(
196 raise HTTPFound(
196 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
197 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
197
198
198 @LoginRequired()
199 @LoginRequired()
199 @HasRepoPermissionAnyDecorator('repository.admin')
200 @HasRepoPermissionAnyDecorator('repository.admin')
200 @CSRFRequired()
201 @CSRFRequired()
201 @view_config(
202 @view_config(
202 route_name='edit_repo_advanced_locking', request_method='POST',
203 route_name='edit_repo_advanced_locking', request_method='POST',
203 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
204 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
204 def edit_advanced_locking(self):
205 def edit_advanced_locking(self):
205 """
206 """
206 Toggle locking of repository
207 Toggle locking of repository
207 """
208 """
208 _ = self.request.translate
209 _ = self.request.translate
209 set_lock = self.request.POST.get('set_lock')
210 set_lock = self.request.POST.get('set_lock')
210 set_unlock = self.request.POST.get('set_unlock')
211 set_unlock = self.request.POST.get('set_unlock')
211
212
212 try:
213 try:
213 if set_lock:
214 if set_lock:
214 Repository.lock(self.db_repo, self._rhodecode_user.user_id,
215 Repository.lock(self.db_repo, self._rhodecode_user.user_id,
215 lock_reason=Repository.LOCK_WEB)
216 lock_reason=Repository.LOCK_WEB)
216 h.flash(_('Locked repository'), category='success')
217 h.flash(_('Locked repository'), category='success')
217 elif set_unlock:
218 elif set_unlock:
218 Repository.unlock(self.db_repo)
219 Repository.unlock(self.db_repo)
219 h.flash(_('Unlocked repository'), category='success')
220 h.flash(_('Unlocked repository'), category='success')
220 except Exception as e:
221 except Exception as e:
221 log.exception("Exception during unlocking")
222 log.exception("Exception during unlocking")
222 h.flash(_('An error occurred during unlocking'), category='error')
223 h.flash(_('An error occurred during unlocking'), category='error')
223
224
224 raise HTTPFound(
225 raise HTTPFound(
225 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
226 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
@@ -1,127 +1,127 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', '/', []);
16 pyroutes.register('new_repo', '/_admin/create_repository', []);
15 pyroutes.register('new_repo', '/_admin/create_repository', []);
17 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
16 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']);
17 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
19 pyroutes.register('gists', '/_admin/gists', []);
18 pyroutes.register('gists', '/_admin/gists', []);
20 pyroutes.register('new_gist', '/_admin/gists/new', []);
19 pyroutes.register('new_gist', '/_admin/gists/new', []);
21 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
20 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
22 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
21 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']);
22 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']);
23 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']);
24 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']);
25 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
27 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
26 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
28 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
27 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
29 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
28 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
30 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
29 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
31 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']);
30 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('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
31 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
33 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
32 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
34 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
33 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_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
34 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
36 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
35 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
37 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
36 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
37 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
39 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
40 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
39 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
41 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
40 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
42 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
41 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
43 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
42 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
44 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
43 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
45 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
44 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
46 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
45 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
46 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
48 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
50 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
51 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
50 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('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
51 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
53 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
52 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
54 pyroutes.register('favicon', '/favicon.ico', []);
53 pyroutes.register('favicon', '/favicon.ico', []);
55 pyroutes.register('robots', '/robots.txt', []);
54 pyroutes.register('robots', '/robots.txt', []);
56 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
55 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
57 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
56 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
58 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
57 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
59 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
58 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
60 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
59 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
61 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
60 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
62 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
61 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
63 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
62 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
64 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
63 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
65 pyroutes.register('repo_group_integrations_create', '%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
64 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_edit', '%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
65 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_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
66 pyroutes.register('repo_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
68 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
67 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
69 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
68 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
70 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
69 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
71 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
70 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
72 pyroutes.register('ops_ping', '_admin/ops/ping', []);
71 pyroutes.register('ops_ping', '_admin/ops/ping', []);
73 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
72 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
74 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
73 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
75 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
74 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
76 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
75 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
77 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
76 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
78 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
77 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
79 pyroutes.register('users', '_admin/users', []);
78 pyroutes.register('users', '_admin/users', []);
80 pyroutes.register('users_data', '_admin/users_data', []);
79 pyroutes.register('users_data', '_admin/users_data', []);
81 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
80 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
82 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
81 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_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
82 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
84 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
83 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
85 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
84 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_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
85 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
87 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
86 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
88 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
87 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
89 pyroutes.register('channelstream_proxy', '/_channelstream', []);
88 pyroutes.register('channelstream_proxy', '/_channelstream', []);
90 pyroutes.register('login', '/_admin/login', []);
89 pyroutes.register('login', '/_admin/login', []);
91 pyroutes.register('logout', '/_admin/logout', []);
90 pyroutes.register('logout', '/_admin/logout', []);
92 pyroutes.register('register', '/_admin/register', []);
91 pyroutes.register('register', '/_admin/register', []);
93 pyroutes.register('reset_password', '/_admin/password_reset', []);
92 pyroutes.register('reset_password', '/_admin/password_reset', []);
94 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
93 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
94 pyroutes.register('home', '/', []);
95 pyroutes.register('user_autocomplete_data', '/_users', []);
95 pyroutes.register('user_autocomplete_data', '/_users', []);
96 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
96 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
97 pyroutes.register('repo_list_data', '/_repos', []);
97 pyroutes.register('repo_list_data', '/_repos', []);
98 pyroutes.register('goto_switcher_data', '/_goto_data', []);
98 pyroutes.register('goto_switcher_data', '/_goto_data', []);
99 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
99 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
100 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
100 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
101 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
101 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
102 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
102 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
103 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
103 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
104 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
104 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
105 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
105 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
106 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
106 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
107 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
107 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
108 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
108 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
109 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
109 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
110 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
110 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
111 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
111 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
112 pyroutes.register('repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
112 pyroutes.register('repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
113 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
113 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
114 pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']);
114 pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']);
115 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
115 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
116 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
116 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
117 pyroutes.register('search', '/_admin/search', []);
117 pyroutes.register('search', '/_admin/search', []);
118 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
118 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
119 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
119 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
120 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
120 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
121 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
121 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
122 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
122 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
123 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
123 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
124 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
124 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
125 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
125 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
126 pyroutes.register('apiv2', '/_admin/api', []);
126 pyroutes.register('apiv2', '/_admin/api', []);
127 }
127 }
General Comments 0
You need to be logged in to leave comments. Login now