##// END OF EJS Templates
bugfix: remove accidental addition
dan -
r69:7ddb83ce default
parent child Browse files
Show More
@@ -1,1779 +1,1777 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2016 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 colander
24 import colander
25
25
26 from rhodecode import BACKENDS
26 from rhodecode import BACKENDS
27 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden, json
27 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden, json
28 from rhodecode.api.utils import (
28 from rhodecode.api.utils import (
29 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
29 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
30 get_user_group_or_error, get_user_or_error, has_repo_permissions,
30 get_user_group_or_error, get_user_or_error, has_repo_permissions,
31 get_perm_or_error, store_update, get_repo_group_or_error, parse_args,
31 get_perm_or_error, store_update, get_repo_group_or_error, parse_args,
32 get_origin, build_commit_data)
32 get_origin, build_commit_data)
33 from rhodecode.lib.auth import (
33 from rhodecode.lib.auth import (
34 HasPermissionAnyApi, HasRepoGroupPermissionAnyApi,
34 HasPermissionAnyApi, HasRepoGroupPermissionAnyApi,
35 HasUserGroupPermissionAnyApi)
35 HasUserGroupPermissionAnyApi)
36 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
36 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
37 from rhodecode.lib.utils import map_groups
37 from rhodecode.lib.utils import map_groups
38 from rhodecode.lib.utils2 import str2bool, time_to_datetime
38 from rhodecode.lib.utils2 import str2bool, time_to_datetime
39 from rhodecode.model.changeset_status import ChangesetStatusModel
39 from rhodecode.model.changeset_status import ChangesetStatusModel
40 from rhodecode.model.comment import ChangesetCommentsModel
40 from rhodecode.model.comment import ChangesetCommentsModel
41 from rhodecode.model.db import (
41 from rhodecode.model.db import (
42 Session, ChangesetStatus, RepositoryField, Repository)
42 Session, ChangesetStatus, RepositoryField, Repository)
43 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.repo_group import RepoGroupModel
44 from rhodecode.model.repo_group import RepoGroupModel
45 from rhodecode.model.scm import ScmModel, RepoList
45 from rhodecode.model.scm import ScmModel, RepoList
46 from rhodecode.model.settings import SettingsModel
46 from rhodecode.model.settings import SettingsModel
47 from rhodecode.model.validation_schema import RepoSchema
47 from rhodecode.model.validation_schema import RepoSchema
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51
51
52 @jsonrpc_method()
52 @jsonrpc_method()
53 def get_repo(request, apiuser, repoid, cache=Optional(True)):
53 def get_repo(request, apiuser, repoid, cache=Optional(True)):
54 """
54 """
55 Gets an existing repository by its name or repository_id.
55 Gets an existing repository by its name or repository_id.
56
56
57 The members section so the output returns users groups or users
57 The members section so the output returns users groups or users
58 associated with that repository.
58 associated with that repository.
59
59
60 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,
61 or users with at least read rights to the |repo|.
61 or users with at least read rights to the |repo|.
62
62
63 :param apiuser: This is filled automatically from the |authtoken|.
63 :param apiuser: This is filled automatically from the |authtoken|.
64 :type apiuser: AuthUser
64 :type apiuser: AuthUser
65 :param repoid: The repository name or repository id.
65 :param repoid: The repository name or repository id.
66 :type repoid: str or int
66 :type repoid: str or int
67 :param cache: use the cached value for last changeset
67 :param cache: use the cached value for last changeset
68 :type: cache: Optional(bool)
68 :type: cache: Optional(bool)
69
69
70 Example output:
70 Example output:
71
71
72 .. code-block:: bash
72 .. code-block:: bash
73
73
74 {
74 {
75 "error": null,
75 "error": null,
76 "id": <repo_id>,
76 "id": <repo_id>,
77 "result": {
77 "result": {
78 "clone_uri": null,
78 "clone_uri": null,
79 "created_on": "timestamp",
79 "created_on": "timestamp",
80 "description": "repo description",
80 "description": "repo description",
81 "enable_downloads": false,
81 "enable_downloads": false,
82 "enable_locking": false,
82 "enable_locking": false,
83 "enable_statistics": false,
83 "enable_statistics": false,
84 "followers": [
84 "followers": [
85 {
85 {
86 "active": true,
86 "active": true,
87 "admin": false,
87 "admin": false,
88 "api_key": "****************************************",
88 "api_key": "****************************************",
89 "api_keys": [
89 "api_keys": [
90 "****************************************"
90 "****************************************"
91 ],
91 ],
92 "email": "user@example.com",
92 "email": "user@example.com",
93 "emails": [
93 "emails": [
94 "user@example.com"
94 "user@example.com"
95 ],
95 ],
96 "extern_name": "rhodecode",
96 "extern_name": "rhodecode",
97 "extern_type": "rhodecode",
97 "extern_type": "rhodecode",
98 "firstname": "username",
98 "firstname": "username",
99 "ip_addresses": [],
99 "ip_addresses": [],
100 "language": null,
100 "language": null,
101 "last_login": "2015-09-16T17:16:35.854",
101 "last_login": "2015-09-16T17:16:35.854",
102 "lastname": "surname",
102 "lastname": "surname",
103 "user_id": <user_id>,
103 "user_id": <user_id>,
104 "username": "name"
104 "username": "name"
105 }
105 }
106 ],
106 ],
107 "fork_of": "parent-repo",
107 "fork_of": "parent-repo",
108 "landing_rev": [
108 "landing_rev": [
109 "rev",
109 "rev",
110 "tip"
110 "tip"
111 ],
111 ],
112 "last_changeset": {
112 "last_changeset": {
113 "author": "User <user@example.com>",
113 "author": "User <user@example.com>",
114 "branch": "default",
114 "branch": "default",
115 "date": "timestamp",
115 "date": "timestamp",
116 "message": "last commit message",
116 "message": "last commit message",
117 "parents": [
117 "parents": [
118 {
118 {
119 "raw_id": "commit-id"
119 "raw_id": "commit-id"
120 }
120 }
121 ],
121 ],
122 "raw_id": "commit-id",
122 "raw_id": "commit-id",
123 "revision": <revision number>,
123 "revision": <revision number>,
124 "short_id": "short id"
124 "short_id": "short id"
125 },
125 },
126 "lock_reason": null,
126 "lock_reason": null,
127 "locked_by": null,
127 "locked_by": null,
128 "locked_date": null,
128 "locked_date": null,
129 "members": [
129 "members": [
130 {
130 {
131 "name": "super-admin-name",
131 "name": "super-admin-name",
132 "origin": "super-admin",
132 "origin": "super-admin",
133 "permission": "repository.admin",
133 "permission": "repository.admin",
134 "type": "user"
134 "type": "user"
135 },
135 },
136 {
136 {
137 "name": "owner-name",
137 "name": "owner-name",
138 "origin": "owner",
138 "origin": "owner",
139 "permission": "repository.admin",
139 "permission": "repository.admin",
140 "type": "user"
140 "type": "user"
141 },
141 },
142 {
142 {
143 "name": "user-group-name",
143 "name": "user-group-name",
144 "origin": "permission",
144 "origin": "permission",
145 "permission": "repository.write",
145 "permission": "repository.write",
146 "type": "user_group"
146 "type": "user_group"
147 }
147 }
148 ],
148 ],
149 "owner": "owner-name",
149 "owner": "owner-name",
150 "permissions": [
150 "permissions": [
151 {
151 {
152 "name": "super-admin-name",
152 "name": "super-admin-name",
153 "origin": "super-admin",
153 "origin": "super-admin",
154 "permission": "repository.admin",
154 "permission": "repository.admin",
155 "type": "user"
155 "type": "user"
156 },
156 },
157 {
157 {
158 "name": "owner-name",
158 "name": "owner-name",
159 "origin": "owner",
159 "origin": "owner",
160 "permission": "repository.admin",
160 "permission": "repository.admin",
161 "type": "user"
161 "type": "user"
162 },
162 },
163 {
163 {
164 "name": "user-group-name",
164 "name": "user-group-name",
165 "origin": "permission",
165 "origin": "permission",
166 "permission": "repository.write",
166 "permission": "repository.write",
167 "type": "user_group"
167 "type": "user_group"
168 }
168 }
169 ],
169 ],
170 "private": true,
170 "private": true,
171 "repo_id": 676,
171 "repo_id": 676,
172 "repo_name": "user-group/repo-name",
172 "repo_name": "user-group/repo-name",
173 "repo_type": "hg"
173 "repo_type": "hg"
174 }
174 }
175 }
175 }
176 """
176 """
177
177
178 repo = get_repo_or_error(repoid)
178 repo = get_repo_or_error(repoid)
179 cache = Optional.extract(cache)
179 cache = Optional.extract(cache)
180 include_secrets = False
180 include_secrets = False
181 if has_superadmin_permission(apiuser):
181 if has_superadmin_permission(apiuser):
182 include_secrets = True
182 include_secrets = True
183 else:
183 else:
184 # check if we have at least read permission for this repo !
184 # check if we have at least read permission for this repo !
185 _perms = (
185 _perms = (
186 'repository.admin', 'repository.write', 'repository.read',)
186 'repository.admin', 'repository.write', 'repository.read',)
187 has_repo_permissions(apiuser, repoid, repo, _perms)
187 has_repo_permissions(apiuser, repoid, repo, _perms)
188
188
189 permissions = []
189 permissions = []
190 for _user in repo.permissions():
190 for _user in repo.permissions():
191 user_data = {
191 user_data = {
192 'name': _user.username,
192 'name': _user.username,
193 'permission': _user.permission,
193 'permission': _user.permission,
194 'origin': get_origin(_user),
194 'origin': get_origin(_user),
195 'type': "user",
195 'type': "user",
196 }
196 }
197 permissions.append(user_data)
197 permissions.append(user_data)
198
198
199 for _user_group in repo.permission_user_groups():
199 for _user_group in repo.permission_user_groups():
200 user_group_data = {
200 user_group_data = {
201 'name': _user_group.users_group_name,
201 'name': _user_group.users_group_name,
202 'permission': _user_group.permission,
202 'permission': _user_group.permission,
203 'origin': get_origin(_user_group),
203 'origin': get_origin(_user_group),
204 'type': "user_group",
204 'type': "user_group",
205 }
205 }
206 permissions.append(user_group_data)
206 permissions.append(user_group_data)
207
207
208 following_users = [
208 following_users = [
209 user.user.get_api_data(include_secrets=include_secrets)
209 user.user.get_api_data(include_secrets=include_secrets)
210 for user in repo.followers]
210 for user in repo.followers]
211
211
212 if not cache:
212 if not cache:
213 repo.update_commit_cache()
213 repo.update_commit_cache()
214 data = repo.get_api_data(include_secrets=include_secrets)
214 data = repo.get_api_data(include_secrets=include_secrets)
215 data['members'] = permissions # TODO: this should be deprecated soon
215 data['members'] = permissions # TODO: this should be deprecated soon
216 data['permissions'] = permissions
216 data['permissions'] = permissions
217 data['followers'] = following_users
217 data['followers'] = following_users
218 return data
218 return data
219
219
220
220
221 @jsonrpc_method()
221 @jsonrpc_method()
222 def get_repos(request, apiuser):
222 def get_repos(request, apiuser):
223 """
223 """
224 Lists all existing repositories.
224 Lists all existing repositories.
225
225
226 This command can only be run using an |authtoken| with admin rights,
226 This command can only be run using an |authtoken| with admin rights,
227 or users with at least read rights to |repos|.
227 or users with at least read rights to |repos|.
228
228
229 :param apiuser: This is filled automatically from the |authtoken|.
229 :param apiuser: This is filled automatically from the |authtoken|.
230 :type apiuser: AuthUser
230 :type apiuser: AuthUser
231
231
232 Example output:
232 Example output:
233
233
234 .. code-block:: bash
234 .. code-block:: bash
235
235
236 id : <id_given_in_input>
236 id : <id_given_in_input>
237 result: [
237 result: [
238 {
238 {
239 "repo_id" : "<repo_id>",
239 "repo_id" : "<repo_id>",
240 "repo_name" : "<reponame>"
240 "repo_name" : "<reponame>"
241 "repo_type" : "<repo_type>",
241 "repo_type" : "<repo_type>",
242 "clone_uri" : "<clone_uri>",
242 "clone_uri" : "<clone_uri>",
243 "private": : "<bool>",
243 "private": : "<bool>",
244 "created_on" : "<datetimecreated>",
244 "created_on" : "<datetimecreated>",
245 "description" : "<description>",
245 "description" : "<description>",
246 "landing_rev": "<landing_rev>",
246 "landing_rev": "<landing_rev>",
247 "owner": "<repo_owner>",
247 "owner": "<repo_owner>",
248 "fork_of": "<name_of_fork_parent>",
248 "fork_of": "<name_of_fork_parent>",
249 "enable_downloads": "<bool>",
249 "enable_downloads": "<bool>",
250 "enable_locking": "<bool>",
250 "enable_locking": "<bool>",
251 "enable_statistics": "<bool>",
251 "enable_statistics": "<bool>",
252 },
252 },
253 ...
253 ...
254 ]
254 ]
255 error: null
255 error: null
256 """
256 """
257
257
258 include_secrets = has_superadmin_permission(apiuser)
258 include_secrets = has_superadmin_permission(apiuser)
259 _perms = ('repository.read', 'repository.write', 'repository.admin',)
259 _perms = ('repository.read', 'repository.write', 'repository.admin',)
260 extras = {'user': apiuser}
260 extras = {'user': apiuser}
261
261
262 repo_list = RepoList(
262 repo_list = RepoList(
263 RepoModel().get_all(), perm_set=_perms, extra_kwargs=extras)
263 RepoModel().get_all(), perm_set=_perms, extra_kwargs=extras)
264 return [repo.get_api_data(include_secrets=include_secrets)
264 return [repo.get_api_data(include_secrets=include_secrets)
265 for repo in repo_list]
265 for repo in repo_list]
266
266
267
267
268 @jsonrpc_method()
268 @jsonrpc_method()
269 def get_repo_changeset(request, apiuser, repoid, revision,
269 def get_repo_changeset(request, apiuser, repoid, revision,
270 details=Optional('basic')):
270 details=Optional('basic')):
271 """
271 """
272 Returns information about a changeset.
272 Returns information about a changeset.
273
273
274 Additionally parameters define the amount of details returned by
274 Additionally parameters define the amount of details returned by
275 this function.
275 this function.
276
276
277 This command can only be run using an |authtoken| with admin rights,
277 This command can only be run using an |authtoken| with admin rights,
278 or users with at least read rights to the |repo|.
278 or users with at least read rights to the |repo|.
279
279
280 :param apiuser: This is filled automatically from the |authtoken|.
280 :param apiuser: This is filled automatically from the |authtoken|.
281 :type apiuser: AuthUser
281 :type apiuser: AuthUser
282 :param repoid: The repository name or repository id
282 :param repoid: The repository name or repository id
283 :type repoid: str or int
283 :type repoid: str or int
284 :param revision: revision for which listing should be done
284 :param revision: revision for which listing should be done
285 :type revision: str
285 :type revision: str
286 :param details: details can be 'basic|extended|full' full gives diff
286 :param details: details can be 'basic|extended|full' full gives diff
287 info details like the diff itself, and number of changed files etc.
287 info details like the diff itself, and number of changed files etc.
288 :type details: Optional(str)
288 :type details: Optional(str)
289
289
290 """
290 """
291 repo = get_repo_or_error(repoid)
291 repo = get_repo_or_error(repoid)
292 if not has_superadmin_permission(apiuser):
292 if not has_superadmin_permission(apiuser):
293 _perms = (
293 _perms = (
294 'repository.admin', 'repository.write', 'repository.read',)
294 'repository.admin', 'repository.write', 'repository.read',)
295 has_repo_permissions(apiuser, repoid, repo, _perms)
295 has_repo_permissions(apiuser, repoid, repo, _perms)
296
296
297 changes_details = Optional.extract(details)
297 changes_details = Optional.extract(details)
298 _changes_details_types = ['basic', 'extended', 'full']
298 _changes_details_types = ['basic', 'extended', 'full']
299 if changes_details not in _changes_details_types:
299 if changes_details not in _changes_details_types:
300 raise JSONRPCError(
300 raise JSONRPCError(
301 'ret_type must be one of %s' % (
301 'ret_type must be one of %s' % (
302 ','.join(_changes_details_types)))
302 ','.join(_changes_details_types)))
303
303
304 pre_load = ['author', 'branch', 'date', 'message', 'parents',
304 pre_load = ['author', 'branch', 'date', 'message', 'parents',
305 'status', '_commit', '_file_paths']
305 'status', '_commit', '_file_paths']
306
306
307 try:
307 try:
308 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
308 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
309 except TypeError as e:
309 except TypeError as e:
310 raise JSONRPCError(e.message)
310 raise JSONRPCError(e.message)
311 _cs_json = cs.__json__()
311 _cs_json = cs.__json__()
312 _cs_json['diff'] = build_commit_data(cs, changes_details)
312 _cs_json['diff'] = build_commit_data(cs, changes_details)
313 if changes_details == 'full':
313 if changes_details == 'full':
314 _cs_json['refs'] = {
314 _cs_json['refs'] = {
315 'branches': [cs.branch],
315 'branches': [cs.branch],
316 'bookmarks': getattr(cs, 'bookmarks', []),
316 'bookmarks': getattr(cs, 'bookmarks', []),
317 'tags': cs.tags
317 'tags': cs.tags
318 }
318 }
319 return _cs_json
319 return _cs_json
320
320
321
321
322 @jsonrpc_method()
322 @jsonrpc_method()
323 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
323 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
324 details=Optional('basic')):
324 details=Optional('basic')):
325 """
325 """
326 Returns a set of commits limited by the number starting
326 Returns a set of commits limited by the number starting
327 from the `start_rev` option.
327 from the `start_rev` option.
328
328
329 Additional parameters define the amount of details returned by this
329 Additional parameters define the amount of details returned by this
330 function.
330 function.
331
331
332 This command can only be run using an |authtoken| with admin rights,
332 This command can only be run using an |authtoken| with admin rights,
333 or users with at least read rights to |repos|.
333 or users with at least read rights to |repos|.
334
334
335 :param apiuser: This is filled automatically from the |authtoken|.
335 :param apiuser: This is filled automatically from the |authtoken|.
336 :type apiuser: AuthUser
336 :type apiuser: AuthUser
337 :param repoid: The repository name or repository ID.
337 :param repoid: The repository name or repository ID.
338 :type repoid: str or int
338 :type repoid: str or int
339 :param start_rev: The starting revision from where to get changesets.
339 :param start_rev: The starting revision from where to get changesets.
340 :type start_rev: str
340 :type start_rev: str
341 :param limit: Limit the number of commits to this amount
341 :param limit: Limit the number of commits to this amount
342 :type limit: str or int
342 :type limit: str or int
343 :param details: Set the level of detail returned. Valid option are:
343 :param details: Set the level of detail returned. Valid option are:
344 ``basic``, ``extended`` and ``full``.
344 ``basic``, ``extended`` and ``full``.
345 :type details: Optional(str)
345 :type details: Optional(str)
346
346
347 .. note::
347 .. note::
348
348
349 Setting the parameter `details` to the value ``full`` is extensive
349 Setting the parameter `details` to the value ``full`` is extensive
350 and returns details like the diff itself, and the number
350 and returns details like the diff itself, and the number
351 of changed files.
351 of changed files.
352
352
353 """
353 """
354 repo = get_repo_or_error(repoid)
354 repo = get_repo_or_error(repoid)
355 if not has_superadmin_permission(apiuser):
355 if not has_superadmin_permission(apiuser):
356 _perms = (
356 _perms = (
357 'repository.admin', 'repository.write', 'repository.read',)
357 'repository.admin', 'repository.write', 'repository.read',)
358 has_repo_permissions(apiuser, repoid, repo, _perms)
358 has_repo_permissions(apiuser, repoid, repo, _perms)
359
359
360 changes_details = Optional.extract(details)
360 changes_details = Optional.extract(details)
361 _changes_details_types = ['basic', 'extended', 'full']
361 _changes_details_types = ['basic', 'extended', 'full']
362 if changes_details not in _changes_details_types:
362 if changes_details not in _changes_details_types:
363 raise JSONRPCError(
363 raise JSONRPCError(
364 'ret_type must be one of %s' % (
364 'ret_type must be one of %s' % (
365 ','.join(_changes_details_types)))
365 ','.join(_changes_details_types)))
366
366
367 limit = int(limit)
367 limit = int(limit)
368 pre_load = ['author', 'branch', 'date', 'message', 'parents',
368 pre_load = ['author', 'branch', 'date', 'message', 'parents',
369 'status', '_commit', '_file_paths']
369 'status', '_commit', '_file_paths']
370
370
371 vcs_repo = repo.scm_instance()
371 vcs_repo = repo.scm_instance()
372 # SVN needs a special case to distinguish its index and commit id
372 # SVN needs a special case to distinguish its index and commit id
373 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
373 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
374 start_rev = vcs_repo.commit_ids[0]
374 start_rev = vcs_repo.commit_ids[0]
375
375
376 try:
376 try:
377 commits = vcs_repo.get_commits(
377 commits = vcs_repo.get_commits(
378 start_id=start_rev, pre_load=pre_load)
378 start_id=start_rev, pre_load=pre_load)
379 except TypeError as e:
379 except TypeError as e:
380 raise JSONRPCError(e.message)
380 raise JSONRPCError(e.message)
381 except Exception:
381 except Exception:
382 log.exception('Fetching of commits failed')
382 log.exception('Fetching of commits failed')
383 raise JSONRPCError('Error occurred during commit fetching')
383 raise JSONRPCError('Error occurred during commit fetching')
384
384
385 ret = []
385 ret = []
386 for cnt, commit in enumerate(commits):
386 for cnt, commit in enumerate(commits):
387 if cnt >= limit != -1:
387 if cnt >= limit != -1:
388 break
388 break
389 _cs_json = commit.__json__()
389 _cs_json = commit.__json__()
390 _cs_json['diff'] = build_commit_data(commit, changes_details)
390 _cs_json['diff'] = build_commit_data(commit, changes_details)
391 if changes_details == 'full':
391 if changes_details == 'full':
392 _cs_json['refs'] = {
392 _cs_json['refs'] = {
393 'branches': [commit.branch],
393 'branches': [commit.branch],
394 'bookmarks': getattr(commit, 'bookmarks', []),
394 'bookmarks': getattr(commit, 'bookmarks', []),
395 'tags': commit.tags
395 'tags': commit.tags
396 }
396 }
397 ret.append(_cs_json)
397 ret.append(_cs_json)
398 return ret
398 return ret
399
399
400
400
401 @jsonrpc_method()
401 @jsonrpc_method()
402 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
402 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
403 ret_type=Optional('all'), details=Optional('basic')):
403 ret_type=Optional('all'), details=Optional('basic')):
404 """
404 """
405 Returns a list of nodes and children in a flat list for a given
405 Returns a list of nodes and children in a flat list for a given
406 path at given revision.
406 path at given revision.
407
407
408 It's possible to specify ret_type to show only `files` or `dirs`.
408 It's possible to specify ret_type to show only `files` or `dirs`.
409
409
410 This command can only be run using an |authtoken| with admin rights,
410 This command can only be run using an |authtoken| with admin rights,
411 or users with at least read rights to |repos|.
411 or users with at least read rights to |repos|.
412
412
413 :param apiuser: This is filled automatically from the |authtoken|.
413 :param apiuser: This is filled automatically from the |authtoken|.
414 :type apiuser: AuthUser
414 :type apiuser: AuthUser
415 :param repoid: The repository name or repository ID.
415 :param repoid: The repository name or repository ID.
416 :type repoid: str or int
416 :type repoid: str or int
417 :param revision: The revision for which listing should be done.
417 :param revision: The revision for which listing should be done.
418 :type revision: str
418 :type revision: str
419 :param root_path: The path from which to start displaying.
419 :param root_path: The path from which to start displaying.
420 :type root_path: str
420 :type root_path: str
421 :param ret_type: Set the return type. Valid options are
421 :param ret_type: Set the return type. Valid options are
422 ``all`` (default), ``files`` and ``dirs``.
422 ``all`` (default), ``files`` and ``dirs``.
423 :type ret_type: Optional(str)
423 :type ret_type: Optional(str)
424 :param details: Returns extended information about nodes, such as
424 :param details: Returns extended information about nodes, such as
425 md5, binary, and or content. The valid options are ``basic`` and
425 md5, binary, and or content. The valid options are ``basic`` and
426 ``full``.
426 ``full``.
427 :type details: Optional(str)
427 :type details: Optional(str)
428
428
429 Example output:
429 Example output:
430
430
431 .. code-block:: bash
431 .. code-block:: bash
432
432
433 id : <id_given_in_input>
433 id : <id_given_in_input>
434 result: [
434 result: [
435 {
435 {
436 "name" : "<name>"
436 "name" : "<name>"
437 "type" : "<type>",
437 "type" : "<type>",
438 "binary": "<true|false>" (only in extended mode)
438 "binary": "<true|false>" (only in extended mode)
439 "md5" : "<md5 of file content>" (only in extended mode)
439 "md5" : "<md5 of file content>" (only in extended mode)
440 },
440 },
441 ...
441 ...
442 ]
442 ]
443 error: null
443 error: null
444 """
444 """
445
445
446 repo = get_repo_or_error(repoid)
446 repo = get_repo_or_error(repoid)
447 if not has_superadmin_permission(apiuser):
447 if not has_superadmin_permission(apiuser):
448 _perms = (
448 _perms = (
449 'repository.admin', 'repository.write', 'repository.read',)
449 'repository.admin', 'repository.write', 'repository.read',)
450 has_repo_permissions(apiuser, repoid, repo, _perms)
450 has_repo_permissions(apiuser, repoid, repo, _perms)
451
451
452 ret_type = Optional.extract(ret_type)
452 ret_type = Optional.extract(ret_type)
453 details = Optional.extract(details)
453 details = Optional.extract(details)
454 _extended_types = ['basic', 'full']
454 _extended_types = ['basic', 'full']
455 if details not in _extended_types:
455 if details not in _extended_types:
456 raise JSONRPCError(
456 raise JSONRPCError(
457 'ret_type must be one of %s' % (','.join(_extended_types)))
457 'ret_type must be one of %s' % (','.join(_extended_types)))
458 extended_info = False
458 extended_info = False
459 content = False
459 content = False
460 if details == 'basic':
460 if details == 'basic':
461 extended_info = True
461 extended_info = True
462
462
463 if details == 'full':
463 if details == 'full':
464 extended_info = content = True
464 extended_info = content = True
465
465
466 _map = {}
466 _map = {}
467 try:
467 try:
468 # check if repo is not empty by any chance, skip quicker if it is.
468 # check if repo is not empty by any chance, skip quicker if it is.
469 _scm = repo.scm_instance()
469 _scm = repo.scm_instance()
470 if _scm.is_empty():
470 if _scm.is_empty():
471 return []
471 return []
472
472
473 _d, _f = ScmModel().get_nodes(
473 _d, _f = ScmModel().get_nodes(
474 repo, revision, root_path, flat=False,
474 repo, revision, root_path, flat=False,
475 extended_info=extended_info, content=content)
475 extended_info=extended_info, content=content)
476 _map = {
476 _map = {
477 'all': _d + _f,
477 'all': _d + _f,
478 'files': _f,
478 'files': _f,
479 'dirs': _d,
479 'dirs': _d,
480 }
480 }
481 return _map[ret_type]
481 return _map[ret_type]
482 except KeyError:
482 except KeyError:
483 raise JSONRPCError(
483 raise JSONRPCError(
484 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
484 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
485 except Exception:
485 except Exception:
486 log.exception("Exception occurred while trying to get repo nodes")
486 log.exception("Exception occurred while trying to get repo nodes")
487 raise JSONRPCError(
487 raise JSONRPCError(
488 'failed to get repo: `%s` nodes' % repo.repo_name
488 'failed to get repo: `%s` nodes' % repo.repo_name
489 )
489 )
490
490
491
491
492 @jsonrpc_method()
492 @jsonrpc_method()
493 def get_repo_refs(request, apiuser, repoid):
493 def get_repo_refs(request, apiuser, repoid):
494 """
494 """
495 Returns a dictionary of current references. It returns
495 Returns a dictionary of current references. It returns
496 bookmarks, branches, closed_branches, and tags for given repository
496 bookmarks, branches, closed_branches, and tags for given repository
497
497
498 It's possible to specify ret_type to show only `files` or `dirs`.
498 It's possible to specify ret_type to show only `files` or `dirs`.
499
499
500 This command can only be run using an |authtoken| with admin rights,
500 This command can only be run using an |authtoken| with admin rights,
501 or users with at least read rights to |repos|.
501 or users with at least read rights to |repos|.
502
502
503 :param apiuser: This is filled automatically from the |authtoken|.
503 :param apiuser: This is filled automatically from the |authtoken|.
504 :type apiuser: AuthUser
504 :type apiuser: AuthUser
505 :param repoid: The repository name or repository ID.
505 :param repoid: The repository name or repository ID.
506 :type repoid: str or int
506 :type repoid: str or int
507
507
508 Example output:
508 Example output:
509
509
510 .. code-block:: bash
510 .. code-block:: bash
511
511
512 id : <id_given_in_input>
512 id : <id_given_in_input>
513 result: [
513 result: [
514 TODO...
514 TODO...
515 ]
515 ]
516 error: null
516 error: null
517 """
517 """
518
518
519 repo = get_repo_or_error(repoid)
519 repo = get_repo_or_error(repoid)
520 if not has_superadmin_permission(apiuser):
520 if not has_superadmin_permission(apiuser):
521 _perms = ('repository.admin', 'repository.write', 'repository.read',)
521 _perms = ('repository.admin', 'repository.write', 'repository.read',)
522 has_repo_permissions(apiuser, repoid, repo, _perms)
522 has_repo_permissions(apiuser, repoid, repo, _perms)
523
523
524 try:
524 try:
525 # check if repo is not empty by any chance, skip quicker if it is.
525 # check if repo is not empty by any chance, skip quicker if it is.
526 vcs_instance = repo.scm_instance()
526 vcs_instance = repo.scm_instance()
527 refs = vcs_instance.refs()
527 refs = vcs_instance.refs()
528 return refs
528 return refs
529 except Exception:
529 except Exception:
530 log.exception("Exception occurred while trying to get repo refs")
530 log.exception("Exception occurred while trying to get repo refs")
531 raise JSONRPCError(
531 raise JSONRPCError(
532 'failed to get repo: `%s` references' % repo.repo_name
532 'failed to get repo: `%s` references' % repo.repo_name
533 )
533 )
534
534
535
535
536 @jsonrpc_method()
536 @jsonrpc_method()
537 def create_repo(request, apiuser, repo_name, repo_type,
537 def create_repo(request, apiuser, repo_name, repo_type,
538 owner=Optional(OAttr('apiuser')), description=Optional(''),
538 owner=Optional(OAttr('apiuser')), description=Optional(''),
539 private=Optional(False), clone_uri=Optional(None),
539 private=Optional(False), clone_uri=Optional(None),
540 landing_rev=Optional('rev:tip'),
540 landing_rev=Optional('rev:tip'),
541 enable_statistics=Optional(False),
541 enable_statistics=Optional(False),
542 enable_locking=Optional(False),
542 enable_locking=Optional(False),
543 enable_downloads=Optional(False),
543 enable_downloads=Optional(False),
544 copy_permissions=Optional(False)):
544 copy_permissions=Optional(False)):
545 """
545 """
546 Creates a repository.
546 Creates a repository.
547
547
548 * If the repository name contains "/", all the required repository
548 * If the repository name contains "/", all the required repository
549 groups will be created.
549 groups will be created.
550
550
551 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
551 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
552 (with "foo" as parent). It will also create the "baz" repository
552 (with "foo" as parent). It will also create the "baz" repository
553 with "bar" as |repo| group.
553 with "bar" as |repo| group.
554
554
555 This command can only be run using an |authtoken| with at least
555 This command can only be run using an |authtoken| with at least
556 write permissions to the |repo|.
556 write permissions to the |repo|.
557
557
558 :param apiuser: This is filled automatically from the |authtoken|.
558 :param apiuser: This is filled automatically from the |authtoken|.
559 :type apiuser: AuthUser
559 :type apiuser: AuthUser
560 :param repo_name: Set the repository name.
560 :param repo_name: Set the repository name.
561 :type repo_name: str
561 :type repo_name: str
562 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
562 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
563 :type repo_type: str
563 :type repo_type: str
564 :param owner: user_id or username
564 :param owner: user_id or username
565 :type owner: Optional(str)
565 :type owner: Optional(str)
566 :param description: Set the repository description.
566 :param description: Set the repository description.
567 :type description: Optional(str)
567 :type description: Optional(str)
568 :param private:
568 :param private:
569 :type private: bool
569 :type private: bool
570 :param clone_uri:
570 :param clone_uri:
571 :type clone_uri: str
571 :type clone_uri: str
572 :param landing_rev: <rev_type>:<rev>
572 :param landing_rev: <rev_type>:<rev>
573 :type landing_rev: str
573 :type landing_rev: str
574 :param enable_locking:
574 :param enable_locking:
575 :type enable_locking: bool
575 :type enable_locking: bool
576 :param enable_downloads:
576 :param enable_downloads:
577 :type enable_downloads: bool
577 :type enable_downloads: bool
578 :param enable_statistics:
578 :param enable_statistics:
579 :type enable_statistics: bool
579 :type enable_statistics: bool
580 :param copy_permissions: Copy permission from group in which the
580 :param copy_permissions: Copy permission from group in which the
581 repository is being created.
581 repository is being created.
582 :type copy_permissions: bool
582 :type copy_permissions: bool
583
583
584
584
585 Example output:
585 Example output:
586
586
587 .. code-block:: bash
587 .. code-block:: bash
588
588
589 id : <id_given_in_input>
589 id : <id_given_in_input>
590 result: {
590 result: {
591 "msg": "Created new repository `<reponame>`",
591 "msg": "Created new repository `<reponame>`",
592 "success": true,
592 "success": true,
593 "task": "<celery task id or None if done sync>"
593 "task": "<celery task id or None if done sync>"
594 }
594 }
595 error: null
595 error: null
596
596
597
597
598 Example error output:
598 Example error output:
599
599
600 .. code-block:: bash
600 .. code-block:: bash
601
601
602 id : <id_given_in_input>
602 id : <id_given_in_input>
603 result : null
603 result : null
604 error : {
604 error : {
605 'failed to create repository `<repo_name>`
605 'failed to create repository `<repo_name>`
606 }
606 }
607
607
608 """
608 """
609 schema = RepoSchema()
609 schema = RepoSchema()
610 try:
610 try:
611 data = schema.deserialize({
611 data = schema.deserialize({
612 'repo_name': repo_name
612 'repo_name': repo_name
613 })
613 })
614 except colander.Invalid as e:
614 except colander.Invalid as e:
615 raise JSONRPCError("Validation failed: %s" % (e.asdict(),))
615 raise JSONRPCError("Validation failed: %s" % (e.asdict(),))
616 repo_name = data['repo_name']
616 repo_name = data['repo_name']
617
617
618 (repo_name_cleaned,
618 (repo_name_cleaned,
619 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
619 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
620 repo_name)
620 repo_name)
621
621
622 if not HasPermissionAnyApi(
622 if not HasPermissionAnyApi(
623 'hg.admin', 'hg.create.repository')(user=apiuser):
623 'hg.admin', 'hg.create.repository')(user=apiuser):
624 # check if we have admin permission for this repo group if given !
624 # check if we have admin permission for this repo group if given !
625
625
626 if parent_group_name:
626 if parent_group_name:
627 repogroupid = parent_group_name
627 repogroupid = parent_group_name
628 repo_group = get_repo_group_or_error(parent_group_name)
628 repo_group = get_repo_group_or_error(parent_group_name)
629
629
630 _perms = ('group.admin',)
630 _perms = ('group.admin',)
631 if not HasRepoGroupPermissionAnyApi(*_perms)(
631 if not HasRepoGroupPermissionAnyApi(*_perms)(
632 user=apiuser, group_name=repo_group.group_name):
632 user=apiuser, group_name=repo_group.group_name):
633 raise JSONRPCError(
633 raise JSONRPCError(
634 'repository group `%s` does not exist' % (
634 'repository group `%s` does not exist' % (
635 repogroupid,))
635 repogroupid,))
636 else:
636 else:
637 raise JSONRPCForbidden()
637 raise JSONRPCForbidden()
638
638
639 if not has_superadmin_permission(apiuser):
639 if not has_superadmin_permission(apiuser):
640 if not isinstance(owner, Optional):
640 if not isinstance(owner, Optional):
641 # forbid setting owner for non-admins
641 # forbid setting owner for non-admins
642 raise JSONRPCError(
642 raise JSONRPCError(
643 'Only RhodeCode admin can specify `owner` param')
643 'Only RhodeCode admin can specify `owner` param')
644
644
645 if isinstance(owner, Optional):
645 if isinstance(owner, Optional):
646 owner = apiuser.user_id
646 owner = apiuser.user_id
647
647
648 owner = get_user_or_error(owner)
648 owner = get_user_or_error(owner)
649
649
650 if RepoModel().get_by_repo_name(repo_name):
650 if RepoModel().get_by_repo_name(repo_name):
651 raise JSONRPCError("repo `%s` already exist" % repo_name)
651 raise JSONRPCError("repo `%s` already exist" % repo_name)
652
652
653 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
653 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
654 if isinstance(private, Optional):
654 if isinstance(private, Optional):
655 private = defs.get('repo_private') or Optional.extract(private)
655 private = defs.get('repo_private') or Optional.extract(private)
656 if isinstance(repo_type, Optional):
656 if isinstance(repo_type, Optional):
657 repo_type = defs.get('repo_type')
657 repo_type = defs.get('repo_type')
658 if isinstance(enable_statistics, Optional):
658 if isinstance(enable_statistics, Optional):
659 enable_statistics = defs.get('repo_enable_statistics')
659 enable_statistics = defs.get('repo_enable_statistics')
660 if isinstance(enable_locking, Optional):
660 if isinstance(enable_locking, Optional):
661 enable_locking = defs.get('repo_enable_locking')
661 enable_locking = defs.get('repo_enable_locking')
662 if isinstance(enable_downloads, Optional):
662 if isinstance(enable_downloads, Optional):
663 enable_downloads = defs.get('repo_enable_downloads')
663 enable_downloads = defs.get('repo_enable_downloads')
664
664
665 clone_uri = Optional.extract(clone_uri)
665 clone_uri = Optional.extract(clone_uri)
666 description = Optional.extract(description)
666 description = Optional.extract(description)
667 landing_rev = Optional.extract(landing_rev)
667 landing_rev = Optional.extract(landing_rev)
668 copy_permissions = Optional.extract(copy_permissions)
668 copy_permissions = Optional.extract(copy_permissions)
669
669
670 try:
670 try:
671 # create structure of groups and return the last group
671 # create structure of groups and return the last group
672 repo_group = map_groups(repo_name)
672 repo_group = map_groups(repo_name)
673 data = {
673 data = {
674 'repo_name': repo_name_cleaned,
674 'repo_name': repo_name_cleaned,
675 'repo_name_full': repo_name,
675 'repo_name_full': repo_name,
676 'repo_type': repo_type,
676 'repo_type': repo_type,
677 'repo_description': description,
677 'repo_description': description,
678 'owner': owner,
678 'owner': owner,
679 'repo_private': private,
679 'repo_private': private,
680 'clone_uri': clone_uri,
680 'clone_uri': clone_uri,
681 'repo_group': repo_group.group_id if repo_group else None,
681 'repo_group': repo_group.group_id if repo_group else None,
682 'repo_landing_rev': landing_rev,
682 'repo_landing_rev': landing_rev,
683 'enable_statistics': enable_statistics,
683 'enable_statistics': enable_statistics,
684 'enable_locking': enable_locking,
684 'enable_locking': enable_locking,
685 'enable_downloads': enable_downloads,
685 'enable_downloads': enable_downloads,
686 'repo_copy_permissions': copy_permissions,
686 'repo_copy_permissions': copy_permissions,
687 }
687 }
688
688
689 if repo_type not in BACKENDS.keys():
689 if repo_type not in BACKENDS.keys():
690 raise Exception("Invalid backend type %s" % repo_type)
690 raise Exception("Invalid backend type %s" % repo_type)
691 task = RepoModel().create(form_data=data, cur_user=owner)
691 task = RepoModel().create(form_data=data, cur_user=owner)
692 from celery.result import BaseAsyncResult
692 from celery.result import BaseAsyncResult
693 task_id = None
693 task_id = None
694 if isinstance(task, BaseAsyncResult):
694 if isinstance(task, BaseAsyncResult):
695 task_id = task.task_id
695 task_id = task.task_id
696 # no commit, it's done in RepoModel, or async via celery
696 # no commit, it's done in RepoModel, or async via celery
697 return {
697 return {
698 'msg': "Created new repository `%s`" % (repo_name,),
698 'msg': "Created new repository `%s`" % (repo_name,),
699 'success': True, # cannot return the repo data here since fork
699 'success': True, # cannot return the repo data here since fork
700 # cann be done async
700 # cann be done async
701 'task': task_id
701 'task': task_id
702 }
702 }
703 except Exception:
703 except Exception:
704 log.exception(
704 log.exception(
705 u"Exception while trying to create the repository %s",
705 u"Exception while trying to create the repository %s",
706 repo_name)
706 repo_name)
707 raise JSONRPCError(
707 raise JSONRPCError(
708 'failed to create repository `%s`' % (repo_name,))
708 'failed to create repository `%s`' % (repo_name,))
709
709
710
710
711 @jsonrpc_method()
711 @jsonrpc_method()
712 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
712 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
713 description=Optional('')):
713 description=Optional('')):
714 """
714 """
715 Adds an extra field to a repository.
715 Adds an extra field to a repository.
716
716
717 This command can only be run using an |authtoken| with at least
717 This command can only be run using an |authtoken| with at least
718 write permissions to the |repo|.
718 write permissions to the |repo|.
719
719
720 :param apiuser: This is filled automatically from the |authtoken|.
720 :param apiuser: This is filled automatically from the |authtoken|.
721 :type apiuser: AuthUser
721 :type apiuser: AuthUser
722 :param repoid: Set the repository name or repository id.
722 :param repoid: Set the repository name or repository id.
723 :type repoid: str or int
723 :type repoid: str or int
724 :param key: Create a unique field key for this repository.
724 :param key: Create a unique field key for this repository.
725 :type key: str
725 :type key: str
726 :param label:
726 :param label:
727 :type label: Optional(str)
727 :type label: Optional(str)
728 :param description:
728 :param description:
729 :type description: Optional(str)
729 :type description: Optional(str)
730 """
730 """
731 repo = get_repo_or_error(repoid)
731 repo = get_repo_or_error(repoid)
732 if not has_superadmin_permission(apiuser):
732 if not has_superadmin_permission(apiuser):
733 _perms = ('repository.admin',)
733 _perms = ('repository.admin',)
734 has_repo_permissions(apiuser, repoid, repo, _perms)
734 has_repo_permissions(apiuser, repoid, repo, _perms)
735
735
736 label = Optional.extract(label) or key
736 label = Optional.extract(label) or key
737 description = Optional.extract(description)
737 description = Optional.extract(description)
738
738
739 field = RepositoryField.get_by_key_name(key, repo)
739 field = RepositoryField.get_by_key_name(key, repo)
740 if field:
740 if field:
741 raise JSONRPCError('Field with key '
741 raise JSONRPCError('Field with key '
742 '`%s` exists for repo `%s`' % (key, repoid))
742 '`%s` exists for repo `%s`' % (key, repoid))
743
743
744 try:
744 try:
745 RepoModel().add_repo_field(repo, key, field_label=label,
745 RepoModel().add_repo_field(repo, key, field_label=label,
746 field_desc=description)
746 field_desc=description)
747 Session().commit()
747 Session().commit()
748 return {
748 return {
749 'msg': "Added new repository field `%s`" % (key,),
749 'msg': "Added new repository field `%s`" % (key,),
750 'success': True,
750 'success': True,
751 }
751 }
752 except Exception:
752 except Exception:
753 log.exception("Exception occurred while trying to add field to repo")
753 log.exception("Exception occurred while trying to add field to repo")
754 raise JSONRPCError(
754 raise JSONRPCError(
755 'failed to create new field for repository `%s`' % (repoid,))
755 'failed to create new field for repository `%s`' % (repoid,))
756
756
757
757
758 @jsonrpc_method()
758 @jsonrpc_method()
759 def remove_field_from_repo(request, apiuser, repoid, key):
759 def remove_field_from_repo(request, apiuser, repoid, key):
760 """
760 """
761 Removes an extra field from a repository.
761 Removes an extra field from a repository.
762
762
763 This command can only be run using an |authtoken| with at least
763 This command can only be run using an |authtoken| with at least
764 write permissions to the |repo|.
764 write permissions to the |repo|.
765
765
766 :param apiuser: This is filled automatically from the |authtoken|.
766 :param apiuser: This is filled automatically from the |authtoken|.
767 :type apiuser: AuthUser
767 :type apiuser: AuthUser
768 :param repoid: Set the repository name or repository ID.
768 :param repoid: Set the repository name or repository ID.
769 :type repoid: str or int
769 :type repoid: str or int
770 :param key: Set the unique field key for this repository.
770 :param key: Set the unique field key for this repository.
771 :type key: str
771 :type key: str
772 """
772 """
773
773
774 repo = get_repo_or_error(repoid)
774 repo = get_repo_or_error(repoid)
775 if not has_superadmin_permission(apiuser):
775 if not has_superadmin_permission(apiuser):
776 _perms = ('repository.admin',)
776 _perms = ('repository.admin',)
777 has_repo_permissions(apiuser, repoid, repo, _perms)
777 has_repo_permissions(apiuser, repoid, repo, _perms)
778
778
779 field = RepositoryField.get_by_key_name(key, repo)
779 field = RepositoryField.get_by_key_name(key, repo)
780 if not field:
780 if not field:
781 raise JSONRPCError('Field with key `%s` does not '
781 raise JSONRPCError('Field with key `%s` does not '
782 'exists for repo `%s`' % (key, repoid))
782 'exists for repo `%s`' % (key, repoid))
783
783
784 try:
784 try:
785 RepoModel().delete_repo_field(repo, field_key=key)
785 RepoModel().delete_repo_field(repo, field_key=key)
786 Session().commit()
786 Session().commit()
787 return {
787 return {
788 'msg': "Deleted repository field `%s`" % (key,),
788 'msg': "Deleted repository field `%s`" % (key,),
789 'success': True,
789 'success': True,
790 }
790 }
791 except Exception:
791 except Exception:
792 log.exception(
792 log.exception(
793 "Exception occurred while trying to delete field from repo")
793 "Exception occurred while trying to delete field from repo")
794 raise JSONRPCError(
794 raise JSONRPCError(
795 'failed to delete field for repository `%s`' % (repoid,))
795 'failed to delete field for repository `%s`' % (repoid,))
796
796
797
797
798 @jsonrpc_method()
798 @jsonrpc_method()
799 def update_repo(request, apiuser, repoid, name=Optional(None),
799 def update_repo(request, apiuser, repoid, name=Optional(None),
800 owner=Optional(OAttr('apiuser')),
800 owner=Optional(OAttr('apiuser')),
801 group=Optional(None),
801 group=Optional(None),
802 active=Optional(True),
803 fork_of=Optional(None),
802 fork_of=Optional(None),
804 description=Optional(''), private=Optional(False),
803 description=Optional(''), private=Optional(False),
805 clone_uri=Optional(None), landing_rev=Optional('rev:tip'),
804 clone_uri=Optional(None), landing_rev=Optional('rev:tip'),
806 enable_statistics=Optional(False),
805 enable_statistics=Optional(False),
807 enable_locking=Optional(False),
806 enable_locking=Optional(False),
808 enable_downloads=Optional(False),
807 enable_downloads=Optional(False),
809 fields=Optional('')):
808 fields=Optional('')):
810 """
809 """
811 Updates a repository with the given information.
810 Updates a repository with the given information.
812
811
813 This command can only be run using an |authtoken| with at least
812 This command can only be run using an |authtoken| with at least
814 write permissions to the |repo|.
813 write permissions to the |repo|.
815
814
816 :param apiuser: This is filled automatically from the |authtoken|.
815 :param apiuser: This is filled automatically from the |authtoken|.
817 :type apiuser: AuthUser
816 :type apiuser: AuthUser
818 :param repoid: repository name or repository ID.
817 :param repoid: repository name or repository ID.
819 :type repoid: str or int
818 :type repoid: str or int
820 :param name: Update the |repo| name.
819 :param name: Update the |repo| name.
821 :type name: str
820 :type name: str
822 :param owner: Set the |repo| owner.
821 :param owner: Set the |repo| owner.
823 :type owner: str
822 :type owner: str
824 :param group: Set the |repo| group the |repo| belongs to.
823 :param group: Set the |repo| group the |repo| belongs to.
825 :type group: str
824 :type group: str
826 :param fork_of: Set the master |repo| name.
825 :param fork_of: Set the master |repo| name.
827 :type fork_of: str
826 :type fork_of: str
828 :param description: Update the |repo| description.
827 :param description: Update the |repo| description.
829 :type description: str
828 :type description: str
830 :param private: Set the |repo| as private. (True | False)
829 :param private: Set the |repo| as private. (True | False)
831 :type private: bool
830 :type private: bool
832 :param clone_uri: Update the |repo| clone URI.
831 :param clone_uri: Update the |repo| clone URI.
833 :type clone_uri: str
832 :type clone_uri: str
834 :param landing_rev: Set the |repo| landing revision. Default is
833 :param landing_rev: Set the |repo| landing revision. Default is
835 ``tip``.
834 ``tip``.
836 :type landing_rev: str
835 :type landing_rev: str
837 :param enable_statistics: Enable statistics on the |repo|,
836 :param enable_statistics: Enable statistics on the |repo|,
838 (True | False).
837 (True | False).
839 :type enable_statistics: bool
838 :type enable_statistics: bool
840 :param enable_locking: Enable |repo| locking.
839 :param enable_locking: Enable |repo| locking.
841 :type enable_locking: bool
840 :type enable_locking: bool
842 :param enable_downloads: Enable downloads from the |repo|,
841 :param enable_downloads: Enable downloads from the |repo|,
843 (True | False).
842 (True | False).
844 :type enable_downloads: bool
843 :type enable_downloads: bool
845 :param fields: Add extra fields to the |repo|. Use the following
844 :param fields: Add extra fields to the |repo|. Use the following
846 example format: ``field_key=field_val,field_key2=fieldval2``.
845 example format: ``field_key=field_val,field_key2=fieldval2``.
847 Escape ', ' with \,
846 Escape ', ' with \,
848 :type fields: str
847 :type fields: str
849 """
848 """
850 repo = get_repo_or_error(repoid)
849 repo = get_repo_or_error(repoid)
851 include_secrets = False
850 include_secrets = False
852 if has_superadmin_permission(apiuser):
851 if has_superadmin_permission(apiuser):
853 include_secrets = True
852 include_secrets = True
854 else:
853 else:
855 _perms = ('repository.admin',)
854 _perms = ('repository.admin',)
856 has_repo_permissions(apiuser, repoid, repo, _perms)
855 has_repo_permissions(apiuser, repoid, repo, _perms)
857
856
858 updates = {
857 updates = {
859 # update function requires this.
858 # update function requires this.
860 'repo_name': repo.just_name
859 'repo_name': repo.just_name
861 }
860 }
862 repo_group = group
861 repo_group = group
863 if not isinstance(repo_group, Optional):
862 if not isinstance(repo_group, Optional):
864 repo_group = get_repo_group_or_error(repo_group)
863 repo_group = get_repo_group_or_error(repo_group)
865 repo_group = repo_group.group_id
864 repo_group = repo_group.group_id
866
865
867 repo_fork_of = fork_of
866 repo_fork_of = fork_of
868 if not isinstance(repo_fork_of, Optional):
867 if not isinstance(repo_fork_of, Optional):
869 repo_fork_of = get_repo_or_error(repo_fork_of)
868 repo_fork_of = get_repo_or_error(repo_fork_of)
870 repo_fork_of = repo_fork_of.repo_id
869 repo_fork_of = repo_fork_of.repo_id
871
870
872 try:
871 try:
873 store_update(updates, name, 'repo_name')
872 store_update(updates, name, 'repo_name')
874 store_update(updates, repo_group, 'repo_group')
873 store_update(updates, repo_group, 'repo_group')
875 store_update(updates, repo_fork_of, 'fork_id')
874 store_update(updates, repo_fork_of, 'fork_id')
876 store_update(updates, owner, 'user')
875 store_update(updates, owner, 'user')
877 store_update(updates, active, 'active')
878 store_update(updates, description, 'repo_description')
876 store_update(updates, description, 'repo_description')
879 store_update(updates, private, 'repo_private')
877 store_update(updates, private, 'repo_private')
880 store_update(updates, clone_uri, 'clone_uri')
878 store_update(updates, clone_uri, 'clone_uri')
881 store_update(updates, landing_rev, 'repo_landing_rev')
879 store_update(updates, landing_rev, 'repo_landing_rev')
882 store_update(updates, enable_statistics, 'repo_enable_statistics')
880 store_update(updates, enable_statistics, 'repo_enable_statistics')
883 store_update(updates, enable_locking, 'repo_enable_locking')
881 store_update(updates, enable_locking, 'repo_enable_locking')
884 store_update(updates, enable_downloads, 'repo_enable_downloads')
882 store_update(updates, enable_downloads, 'repo_enable_downloads')
885
883
886 # extra fields
884 # extra fields
887 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
885 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
888 if fields:
886 if fields:
889 updates.update(fields)
887 updates.update(fields)
890
888
891 RepoModel().update(repo, **updates)
889 RepoModel().update(repo, **updates)
892 Session().commit()
890 Session().commit()
893 return {
891 return {
894 'msg': 'updated repo ID:%s %s' % (
892 'msg': 'updated repo ID:%s %s' % (
895 repo.repo_id, repo.repo_name),
893 repo.repo_id, repo.repo_name),
896 'repository': repo.get_api_data(
894 'repository': repo.get_api_data(
897 include_secrets=include_secrets)
895 include_secrets=include_secrets)
898 }
896 }
899 except Exception:
897 except Exception:
900 log.exception(
898 log.exception(
901 u"Exception while trying to update the repository %s",
899 u"Exception while trying to update the repository %s",
902 repoid)
900 repoid)
903 raise JSONRPCError('failed to update repo `%s`' % repoid)
901 raise JSONRPCError('failed to update repo `%s`' % repoid)
904
902
905
903
906 @jsonrpc_method()
904 @jsonrpc_method()
907 def fork_repo(request, apiuser, repoid, fork_name,
905 def fork_repo(request, apiuser, repoid, fork_name,
908 owner=Optional(OAttr('apiuser')),
906 owner=Optional(OAttr('apiuser')),
909 description=Optional(''), copy_permissions=Optional(False),
907 description=Optional(''), copy_permissions=Optional(False),
910 private=Optional(False), landing_rev=Optional('rev:tip')):
908 private=Optional(False), landing_rev=Optional('rev:tip')):
911 """
909 """
912 Creates a fork of the specified |repo|.
910 Creates a fork of the specified |repo|.
913
911
914 * If using |RCE| with Celery this will immediately return a success
912 * If using |RCE| with Celery this will immediately return a success
915 message, even though the fork will be created asynchronously.
913 message, even though the fork will be created asynchronously.
916
914
917 This command can only be run using an |authtoken| with fork
915 This command can only be run using an |authtoken| with fork
918 permissions on the |repo|.
916 permissions on the |repo|.
919
917
920 :param apiuser: This is filled automatically from the |authtoken|.
918 :param apiuser: This is filled automatically from the |authtoken|.
921 :type apiuser: AuthUser
919 :type apiuser: AuthUser
922 :param repoid: Set repository name or repository ID.
920 :param repoid: Set repository name or repository ID.
923 :type repoid: str or int
921 :type repoid: str or int
924 :param fork_name: Set the fork name.
922 :param fork_name: Set the fork name.
925 :type fork_name: str
923 :type fork_name: str
926 :param owner: Set the fork owner.
924 :param owner: Set the fork owner.
927 :type owner: str
925 :type owner: str
928 :param description: Set the fork descripton.
926 :param description: Set the fork descripton.
929 :type description: str
927 :type description: str
930 :param copy_permissions: Copy permissions from parent |repo|. The
928 :param copy_permissions: Copy permissions from parent |repo|. The
931 default is False.
929 default is False.
932 :type copy_permissions: bool
930 :type copy_permissions: bool
933 :param private: Make the fork private. The default is False.
931 :param private: Make the fork private. The default is False.
934 :type private: bool
932 :type private: bool
935 :param landing_rev: Set the landing revision. The default is tip.
933 :param landing_rev: Set the landing revision. The default is tip.
936
934
937 Example output:
935 Example output:
938
936
939 .. code-block:: bash
937 .. code-block:: bash
940
938
941 id : <id_for_response>
939 id : <id_for_response>
942 api_key : "<api_key>"
940 api_key : "<api_key>"
943 args: {
941 args: {
944 "repoid" : "<reponame or repo_id>",
942 "repoid" : "<reponame or repo_id>",
945 "fork_name": "<forkname>",
943 "fork_name": "<forkname>",
946 "owner": "<username or user_id = Optional(=apiuser)>",
944 "owner": "<username or user_id = Optional(=apiuser)>",
947 "description": "<description>",
945 "description": "<description>",
948 "copy_permissions": "<bool>",
946 "copy_permissions": "<bool>",
949 "private": "<bool>",
947 "private": "<bool>",
950 "landing_rev": "<landing_rev>"
948 "landing_rev": "<landing_rev>"
951 }
949 }
952
950
953 Example error output:
951 Example error output:
954
952
955 .. code-block:: bash
953 .. code-block:: bash
956
954
957 id : <id_given_in_input>
955 id : <id_given_in_input>
958 result: {
956 result: {
959 "msg": "Created fork of `<reponame>` as `<forkname>`",
957 "msg": "Created fork of `<reponame>` as `<forkname>`",
960 "success": true,
958 "success": true,
961 "task": "<celery task id or None if done sync>"
959 "task": "<celery task id or None if done sync>"
962 }
960 }
963 error: null
961 error: null
964
962
965 """
963 """
966 if not has_superadmin_permission(apiuser):
964 if not has_superadmin_permission(apiuser):
967 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
965 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
968 raise JSONRPCForbidden()
966 raise JSONRPCForbidden()
969
967
970 repo = get_repo_or_error(repoid)
968 repo = get_repo_or_error(repoid)
971 repo_name = repo.repo_name
969 repo_name = repo.repo_name
972
970
973 (fork_name_cleaned,
971 (fork_name_cleaned,
974 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
972 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
975 fork_name)
973 fork_name)
976
974
977 if not has_superadmin_permission(apiuser):
975 if not has_superadmin_permission(apiuser):
978 # check if we have at least read permission for
976 # check if we have at least read permission for
979 # this repo that we fork !
977 # this repo that we fork !
980 _perms = (
978 _perms = (
981 'repository.admin', 'repository.write', 'repository.read')
979 'repository.admin', 'repository.write', 'repository.read')
982 has_repo_permissions(apiuser, repoid, repo, _perms)
980 has_repo_permissions(apiuser, repoid, repo, _perms)
983
981
984 if not isinstance(owner, Optional):
982 if not isinstance(owner, Optional):
985 # forbid setting owner for non super admins
983 # forbid setting owner for non super admins
986 raise JSONRPCError(
984 raise JSONRPCError(
987 'Only RhodeCode admin can specify `owner` param'
985 'Only RhodeCode admin can specify `owner` param'
988 )
986 )
989 # check if we have a create.repo permission if not maybe the parent
987 # check if we have a create.repo permission if not maybe the parent
990 # group permission
988 # group permission
991 if not HasPermissionAnyApi('hg.create.repository')(user=apiuser):
989 if not HasPermissionAnyApi('hg.create.repository')(user=apiuser):
992 if parent_group_name:
990 if parent_group_name:
993 repogroupid = parent_group_name
991 repogroupid = parent_group_name
994 repo_group = get_repo_group_or_error(parent_group_name)
992 repo_group = get_repo_group_or_error(parent_group_name)
995
993
996 _perms = ('group.admin',)
994 _perms = ('group.admin',)
997 if not HasRepoGroupPermissionAnyApi(*_perms)(
995 if not HasRepoGroupPermissionAnyApi(*_perms)(
998 user=apiuser, group_name=repo_group.group_name):
996 user=apiuser, group_name=repo_group.group_name):
999 raise JSONRPCError(
997 raise JSONRPCError(
1000 'repository group `%s` does not exist' % (
998 'repository group `%s` does not exist' % (
1001 repogroupid,))
999 repogroupid,))
1002 else:
1000 else:
1003 raise JSONRPCForbidden()
1001 raise JSONRPCForbidden()
1004
1002
1005 _repo = RepoModel().get_by_repo_name(fork_name)
1003 _repo = RepoModel().get_by_repo_name(fork_name)
1006 if _repo:
1004 if _repo:
1007 type_ = 'fork' if _repo.fork else 'repo'
1005 type_ = 'fork' if _repo.fork else 'repo'
1008 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
1006 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
1009
1007
1010 if isinstance(owner, Optional):
1008 if isinstance(owner, Optional):
1011 owner = apiuser.user_id
1009 owner = apiuser.user_id
1012
1010
1013 owner = get_user_or_error(owner)
1011 owner = get_user_or_error(owner)
1014
1012
1015 try:
1013 try:
1016 # create structure of groups and return the last group
1014 # create structure of groups and return the last group
1017 repo_group = map_groups(fork_name)
1015 repo_group = map_groups(fork_name)
1018 form_data = {
1016 form_data = {
1019 'repo_name': fork_name_cleaned,
1017 'repo_name': fork_name_cleaned,
1020 'repo_name_full': fork_name,
1018 'repo_name_full': fork_name,
1021 'repo_group': repo_group.group_id if repo_group else None,
1019 'repo_group': repo_group.group_id if repo_group else None,
1022 'repo_type': repo.repo_type,
1020 'repo_type': repo.repo_type,
1023 'description': Optional.extract(description),
1021 'description': Optional.extract(description),
1024 'private': Optional.extract(private),
1022 'private': Optional.extract(private),
1025 'copy_permissions': Optional.extract(copy_permissions),
1023 'copy_permissions': Optional.extract(copy_permissions),
1026 'landing_rev': Optional.extract(landing_rev),
1024 'landing_rev': Optional.extract(landing_rev),
1027 'fork_parent_id': repo.repo_id,
1025 'fork_parent_id': repo.repo_id,
1028 }
1026 }
1029
1027
1030 task = RepoModel().create_fork(form_data, cur_user=owner)
1028 task = RepoModel().create_fork(form_data, cur_user=owner)
1031 # no commit, it's done in RepoModel, or async via celery
1029 # no commit, it's done in RepoModel, or async via celery
1032 from celery.result import BaseAsyncResult
1030 from celery.result import BaseAsyncResult
1033 task_id = None
1031 task_id = None
1034 if isinstance(task, BaseAsyncResult):
1032 if isinstance(task, BaseAsyncResult):
1035 task_id = task.task_id
1033 task_id = task.task_id
1036 return {
1034 return {
1037 'msg': 'Created fork of `%s` as `%s`' % (
1035 'msg': 'Created fork of `%s` as `%s`' % (
1038 repo.repo_name, fork_name),
1036 repo.repo_name, fork_name),
1039 'success': True, # cannot return the repo data here since fork
1037 'success': True, # cannot return the repo data here since fork
1040 # can be done async
1038 # can be done async
1041 'task': task_id
1039 'task': task_id
1042 }
1040 }
1043 except Exception:
1041 except Exception:
1044 log.exception("Exception occurred while trying to fork a repo")
1042 log.exception("Exception occurred while trying to fork a repo")
1045 raise JSONRPCError(
1043 raise JSONRPCError(
1046 'failed to fork repository `%s` as `%s`' % (
1044 'failed to fork repository `%s` as `%s`' % (
1047 repo_name, fork_name))
1045 repo_name, fork_name))
1048
1046
1049
1047
1050 @jsonrpc_method()
1048 @jsonrpc_method()
1051 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1049 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1052 """
1050 """
1053 Deletes a repository.
1051 Deletes a repository.
1054
1052
1055 * When the `forks` parameter is set it's possible to detach or delete
1053 * When the `forks` parameter is set it's possible to detach or delete
1056 forks of deleted repository.
1054 forks of deleted repository.
1057
1055
1058 This command can only be run using an |authtoken| with admin
1056 This command can only be run using an |authtoken| with admin
1059 permissions on the |repo|.
1057 permissions on the |repo|.
1060
1058
1061 :param apiuser: This is filled automatically from the |authtoken|.
1059 :param apiuser: This is filled automatically from the |authtoken|.
1062 :type apiuser: AuthUser
1060 :type apiuser: AuthUser
1063 :param repoid: Set the repository name or repository ID.
1061 :param repoid: Set the repository name or repository ID.
1064 :type repoid: str or int
1062 :type repoid: str or int
1065 :param forks: Set to `detach` or `delete` forks from the |repo|.
1063 :param forks: Set to `detach` or `delete` forks from the |repo|.
1066 :type forks: Optional(str)
1064 :type forks: Optional(str)
1067
1065
1068 Example error output:
1066 Example error output:
1069
1067
1070 .. code-block:: bash
1068 .. code-block:: bash
1071
1069
1072 id : <id_given_in_input>
1070 id : <id_given_in_input>
1073 result: {
1071 result: {
1074 "msg": "Deleted repository `<reponame>`",
1072 "msg": "Deleted repository `<reponame>`",
1075 "success": true
1073 "success": true
1076 }
1074 }
1077 error: null
1075 error: null
1078 """
1076 """
1079
1077
1080 repo = get_repo_or_error(repoid)
1078 repo = get_repo_or_error(repoid)
1081 if not has_superadmin_permission(apiuser):
1079 if not has_superadmin_permission(apiuser):
1082 _perms = ('repository.admin',)
1080 _perms = ('repository.admin',)
1083 has_repo_permissions(apiuser, repoid, repo, _perms)
1081 has_repo_permissions(apiuser, repoid, repo, _perms)
1084
1082
1085 try:
1083 try:
1086 handle_forks = Optional.extract(forks)
1084 handle_forks = Optional.extract(forks)
1087 _forks_msg = ''
1085 _forks_msg = ''
1088 _forks = [f for f in repo.forks]
1086 _forks = [f for f in repo.forks]
1089 if handle_forks == 'detach':
1087 if handle_forks == 'detach':
1090 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1088 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1091 elif handle_forks == 'delete':
1089 elif handle_forks == 'delete':
1092 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1090 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1093 elif _forks:
1091 elif _forks:
1094 raise JSONRPCError(
1092 raise JSONRPCError(
1095 'Cannot delete `%s` it still contains attached forks' %
1093 'Cannot delete `%s` it still contains attached forks' %
1096 (repo.repo_name,)
1094 (repo.repo_name,)
1097 )
1095 )
1098
1096
1099 RepoModel().delete(repo, forks=forks)
1097 RepoModel().delete(repo, forks=forks)
1100 Session().commit()
1098 Session().commit()
1101 return {
1099 return {
1102 'msg': 'Deleted repository `%s`%s' % (
1100 'msg': 'Deleted repository `%s`%s' % (
1103 repo.repo_name, _forks_msg),
1101 repo.repo_name, _forks_msg),
1104 'success': True
1102 'success': True
1105 }
1103 }
1106 except Exception:
1104 except Exception:
1107 log.exception("Exception occurred while trying to delete repo")
1105 log.exception("Exception occurred while trying to delete repo")
1108 raise JSONRPCError(
1106 raise JSONRPCError(
1109 'failed to delete repository `%s`' % (repo.repo_name,)
1107 'failed to delete repository `%s`' % (repo.repo_name,)
1110 )
1108 )
1111
1109
1112
1110
1113 #TODO: marcink, change name ?
1111 #TODO: marcink, change name ?
1114 @jsonrpc_method()
1112 @jsonrpc_method()
1115 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1113 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1116 """
1114 """
1117 Invalidates the cache for the specified repository.
1115 Invalidates the cache for the specified repository.
1118
1116
1119 This command can only be run using an |authtoken| with admin rights to
1117 This command can only be run using an |authtoken| with admin rights to
1120 the specified repository.
1118 the specified repository.
1121
1119
1122 This command takes the following options:
1120 This command takes the following options:
1123
1121
1124 :param apiuser: This is filled automatically from |authtoken|.
1122 :param apiuser: This is filled automatically from |authtoken|.
1125 :type apiuser: AuthUser
1123 :type apiuser: AuthUser
1126 :param repoid: Sets the repository name or repository ID.
1124 :param repoid: Sets the repository name or repository ID.
1127 :type repoid: str or int
1125 :type repoid: str or int
1128 :param delete_keys: This deletes the invalidated keys instead of
1126 :param delete_keys: This deletes the invalidated keys instead of
1129 just flagging them.
1127 just flagging them.
1130 :type delete_keys: Optional(``True`` | ``False``)
1128 :type delete_keys: Optional(``True`` | ``False``)
1131
1129
1132 Example output:
1130 Example output:
1133
1131
1134 .. code-block:: bash
1132 .. code-block:: bash
1135
1133
1136 id : <id_given_in_input>
1134 id : <id_given_in_input>
1137 result : {
1135 result : {
1138 'msg': Cache for repository `<repository name>` was invalidated,
1136 'msg': Cache for repository `<repository name>` was invalidated,
1139 'repository': <repository name>
1137 'repository': <repository name>
1140 }
1138 }
1141 error : null
1139 error : null
1142
1140
1143 Example error output:
1141 Example error output:
1144
1142
1145 .. code-block:: bash
1143 .. code-block:: bash
1146
1144
1147 id : <id_given_in_input>
1145 id : <id_given_in_input>
1148 result : null
1146 result : null
1149 error : {
1147 error : {
1150 'Error occurred during cache invalidation action'
1148 'Error occurred during cache invalidation action'
1151 }
1149 }
1152
1150
1153 """
1151 """
1154
1152
1155 repo = get_repo_or_error(repoid)
1153 repo = get_repo_or_error(repoid)
1156 if not has_superadmin_permission(apiuser):
1154 if not has_superadmin_permission(apiuser):
1157 _perms = ('repository.admin', 'repository.write',)
1155 _perms = ('repository.admin', 'repository.write',)
1158 has_repo_permissions(apiuser, repoid, repo, _perms)
1156 has_repo_permissions(apiuser, repoid, repo, _perms)
1159
1157
1160 delete = Optional.extract(delete_keys)
1158 delete = Optional.extract(delete_keys)
1161 try:
1159 try:
1162 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1160 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1163 return {
1161 return {
1164 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1162 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1165 'repository': repo.repo_name
1163 'repository': repo.repo_name
1166 }
1164 }
1167 except Exception:
1165 except Exception:
1168 log.exception(
1166 log.exception(
1169 "Exception occurred while trying to invalidate repo cache")
1167 "Exception occurred while trying to invalidate repo cache")
1170 raise JSONRPCError(
1168 raise JSONRPCError(
1171 'Error occurred during cache invalidation action'
1169 'Error occurred during cache invalidation action'
1172 )
1170 )
1173
1171
1174
1172
1175 #TODO: marcink, change name ?
1173 #TODO: marcink, change name ?
1176 @jsonrpc_method()
1174 @jsonrpc_method()
1177 def lock(request, apiuser, repoid, locked=Optional(None),
1175 def lock(request, apiuser, repoid, locked=Optional(None),
1178 userid=Optional(OAttr('apiuser'))):
1176 userid=Optional(OAttr('apiuser'))):
1179 """
1177 """
1180 Sets the lock state of the specified |repo| by the given user.
1178 Sets the lock state of the specified |repo| by the given user.
1181 From more information, see :ref:`repo-locking`.
1179 From more information, see :ref:`repo-locking`.
1182
1180
1183 * If the ``userid`` option is not set, the repository is locked to the
1181 * If the ``userid`` option is not set, the repository is locked to the
1184 user who called the method.
1182 user who called the method.
1185 * If the ``locked`` parameter is not set, the current lock state of the
1183 * If the ``locked`` parameter is not set, the current lock state of the
1186 repository is displayed.
1184 repository is displayed.
1187
1185
1188 This command can only be run using an |authtoken| with admin rights to
1186 This command can only be run using an |authtoken| with admin rights to
1189 the specified repository.
1187 the specified repository.
1190
1188
1191 This command takes the following options:
1189 This command takes the following options:
1192
1190
1193 :param apiuser: This is filled automatically from the |authtoken|.
1191 :param apiuser: This is filled automatically from the |authtoken|.
1194 :type apiuser: AuthUser
1192 :type apiuser: AuthUser
1195 :param repoid: Sets the repository name or repository ID.
1193 :param repoid: Sets the repository name or repository ID.
1196 :type repoid: str or int
1194 :type repoid: str or int
1197 :param locked: Sets the lock state.
1195 :param locked: Sets the lock state.
1198 :type locked: Optional(``True`` | ``False``)
1196 :type locked: Optional(``True`` | ``False``)
1199 :param userid: Set the repository lock to this user.
1197 :param userid: Set the repository lock to this user.
1200 :type userid: Optional(str or int)
1198 :type userid: Optional(str or int)
1201
1199
1202 Example error output:
1200 Example error output:
1203
1201
1204 .. code-block:: bash
1202 .. code-block:: bash
1205
1203
1206 id : <id_given_in_input>
1204 id : <id_given_in_input>
1207 result : {
1205 result : {
1208 'repo': '<reponame>',
1206 'repo': '<reponame>',
1209 'locked': <bool: lock state>,
1207 'locked': <bool: lock state>,
1210 'locked_since': <int: lock timestamp>,
1208 'locked_since': <int: lock timestamp>,
1211 'locked_by': <username of person who made the lock>,
1209 'locked_by': <username of person who made the lock>,
1212 'lock_reason': <str: reason for locking>,
1210 'lock_reason': <str: reason for locking>,
1213 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1211 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1214 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1212 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1215 or
1213 or
1216 'msg': 'Repo `<repository name>` not locked.'
1214 'msg': 'Repo `<repository name>` not locked.'
1217 or
1215 or
1218 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1216 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1219 }
1217 }
1220 error : null
1218 error : null
1221
1219
1222 Example error output:
1220 Example error output:
1223
1221
1224 .. code-block:: bash
1222 .. code-block:: bash
1225
1223
1226 id : <id_given_in_input>
1224 id : <id_given_in_input>
1227 result : null
1225 result : null
1228 error : {
1226 error : {
1229 'Error occurred locking repository `<reponame>`
1227 'Error occurred locking repository `<reponame>`
1230 }
1228 }
1231 """
1229 """
1232
1230
1233 repo = get_repo_or_error(repoid)
1231 repo = get_repo_or_error(repoid)
1234 if not has_superadmin_permission(apiuser):
1232 if not has_superadmin_permission(apiuser):
1235 # check if we have at least write permission for this repo !
1233 # check if we have at least write permission for this repo !
1236 _perms = ('repository.admin', 'repository.write',)
1234 _perms = ('repository.admin', 'repository.write',)
1237 has_repo_permissions(apiuser, repoid, repo, _perms)
1235 has_repo_permissions(apiuser, repoid, repo, _perms)
1238
1236
1239 # make sure normal user does not pass someone else userid,
1237 # make sure normal user does not pass someone else userid,
1240 # he is not allowed to do that
1238 # he is not allowed to do that
1241 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1239 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1242 raise JSONRPCError('userid is not the same as your user')
1240 raise JSONRPCError('userid is not the same as your user')
1243
1241
1244 if isinstance(userid, Optional):
1242 if isinstance(userid, Optional):
1245 userid = apiuser.user_id
1243 userid = apiuser.user_id
1246
1244
1247 user = get_user_or_error(userid)
1245 user = get_user_or_error(userid)
1248
1246
1249 if isinstance(locked, Optional):
1247 if isinstance(locked, Optional):
1250 lockobj = repo.locked
1248 lockobj = repo.locked
1251
1249
1252 if lockobj[0] is None:
1250 if lockobj[0] is None:
1253 _d = {
1251 _d = {
1254 'repo': repo.repo_name,
1252 'repo': repo.repo_name,
1255 'locked': False,
1253 'locked': False,
1256 'locked_since': None,
1254 'locked_since': None,
1257 'locked_by': None,
1255 'locked_by': None,
1258 'lock_reason': None,
1256 'lock_reason': None,
1259 'lock_state_changed': False,
1257 'lock_state_changed': False,
1260 'msg': 'Repo `%s` not locked.' % repo.repo_name
1258 'msg': 'Repo `%s` not locked.' % repo.repo_name
1261 }
1259 }
1262 return _d
1260 return _d
1263 else:
1261 else:
1264 _user_id, _time, _reason = lockobj
1262 _user_id, _time, _reason = lockobj
1265 lock_user = get_user_or_error(userid)
1263 lock_user = get_user_or_error(userid)
1266 _d = {
1264 _d = {
1267 'repo': repo.repo_name,
1265 'repo': repo.repo_name,
1268 'locked': True,
1266 'locked': True,
1269 'locked_since': _time,
1267 'locked_since': _time,
1270 'locked_by': lock_user.username,
1268 'locked_by': lock_user.username,
1271 'lock_reason': _reason,
1269 'lock_reason': _reason,
1272 'lock_state_changed': False,
1270 'lock_state_changed': False,
1273 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1271 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1274 % (repo.repo_name, lock_user.username,
1272 % (repo.repo_name, lock_user.username,
1275 json.dumps(time_to_datetime(_time))))
1273 json.dumps(time_to_datetime(_time))))
1276 }
1274 }
1277 return _d
1275 return _d
1278
1276
1279 # force locked state through a flag
1277 # force locked state through a flag
1280 else:
1278 else:
1281 locked = str2bool(locked)
1279 locked = str2bool(locked)
1282 lock_reason = Repository.LOCK_API
1280 lock_reason = Repository.LOCK_API
1283 try:
1281 try:
1284 if locked:
1282 if locked:
1285 lock_time = time.time()
1283 lock_time = time.time()
1286 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1284 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1287 else:
1285 else:
1288 lock_time = None
1286 lock_time = None
1289 Repository.unlock(repo)
1287 Repository.unlock(repo)
1290 _d = {
1288 _d = {
1291 'repo': repo.repo_name,
1289 'repo': repo.repo_name,
1292 'locked': locked,
1290 'locked': locked,
1293 'locked_since': lock_time,
1291 'locked_since': lock_time,
1294 'locked_by': user.username,
1292 'locked_by': user.username,
1295 'lock_reason': lock_reason,
1293 'lock_reason': lock_reason,
1296 'lock_state_changed': True,
1294 'lock_state_changed': True,
1297 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1295 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1298 % (user.username, repo.repo_name, locked))
1296 % (user.username, repo.repo_name, locked))
1299 }
1297 }
1300 return _d
1298 return _d
1301 except Exception:
1299 except Exception:
1302 log.exception(
1300 log.exception(
1303 "Exception occurred while trying to lock repository")
1301 "Exception occurred while trying to lock repository")
1304 raise JSONRPCError(
1302 raise JSONRPCError(
1305 'Error occurred locking repository `%s`' % repo.repo_name
1303 'Error occurred locking repository `%s`' % repo.repo_name
1306 )
1304 )
1307
1305
1308
1306
1309 @jsonrpc_method()
1307 @jsonrpc_method()
1310 def comment_commit(
1308 def comment_commit(
1311 request, apiuser, repoid, commit_id, message,
1309 request, apiuser, repoid, commit_id, message,
1312 userid=Optional(OAttr('apiuser')), status=Optional(None)):
1310 userid=Optional(OAttr('apiuser')), status=Optional(None)):
1313 """
1311 """
1314 Set a commit comment, and optionally change the status of the commit.
1312 Set a commit comment, and optionally change the status of the commit.
1315 This command can be executed only using api_key belonging to user
1313 This command can be executed only using api_key belonging to user
1316 with admin rights, or repository administrator.
1314 with admin rights, or repository administrator.
1317
1315
1318 :param apiuser: This is filled automatically from the |authtoken|.
1316 :param apiuser: This is filled automatically from the |authtoken|.
1319 :type apiuser: AuthUser
1317 :type apiuser: AuthUser
1320 :param repoid: Set the repository name or repository ID.
1318 :param repoid: Set the repository name or repository ID.
1321 :type repoid: str or int
1319 :type repoid: str or int
1322 :param commit_id: Specify the commit_id for which to set a comment.
1320 :param commit_id: Specify the commit_id for which to set a comment.
1323 :type commit_id: str
1321 :type commit_id: str
1324 :param message: The comment text.
1322 :param message: The comment text.
1325 :type message: str
1323 :type message: str
1326 :param userid: Set the user name of the comment creator.
1324 :param userid: Set the user name of the comment creator.
1327 :type userid: Optional(str or int)
1325 :type userid: Optional(str or int)
1328 :param status: status, one of 'not_reviewed', 'approved', 'rejected',
1326 :param status: status, one of 'not_reviewed', 'approved', 'rejected',
1329 'under_review'
1327 'under_review'
1330 :type status: str
1328 :type status: str
1331
1329
1332 Example error output:
1330 Example error output:
1333
1331
1334 .. code-block:: json
1332 .. code-block:: json
1335
1333
1336 {
1334 {
1337 "id" : <id_given_in_input>,
1335 "id" : <id_given_in_input>,
1338 "result" : {
1336 "result" : {
1339 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1337 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1340 "status_change": null or <status>,
1338 "status_change": null or <status>,
1341 "success": true
1339 "success": true
1342 },
1340 },
1343 "error" : null
1341 "error" : null
1344 }
1342 }
1345
1343
1346 """
1344 """
1347 repo = get_repo_or_error(repoid)
1345 repo = get_repo_or_error(repoid)
1348 if not has_superadmin_permission(apiuser):
1346 if not has_superadmin_permission(apiuser):
1349 _perms = ('repository.admin',)
1347 _perms = ('repository.admin',)
1350 has_repo_permissions(apiuser, repoid, repo, _perms)
1348 has_repo_permissions(apiuser, repoid, repo, _perms)
1351
1349
1352 if isinstance(userid, Optional):
1350 if isinstance(userid, Optional):
1353 userid = apiuser.user_id
1351 userid = apiuser.user_id
1354
1352
1355 user = get_user_or_error(userid)
1353 user = get_user_or_error(userid)
1356 status = Optional.extract(status)
1354 status = Optional.extract(status)
1357
1355
1358 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1356 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1359 if status and status not in allowed_statuses:
1357 if status and status not in allowed_statuses:
1360 raise JSONRPCError('Bad status, must be on '
1358 raise JSONRPCError('Bad status, must be on '
1361 'of %s got %s' % (allowed_statuses, status,))
1359 'of %s got %s' % (allowed_statuses, status,))
1362
1360
1363 try:
1361 try:
1364 rc_config = SettingsModel().get_all_settings()
1362 rc_config = SettingsModel().get_all_settings()
1365 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1363 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1366
1364
1367 comm = ChangesetCommentsModel().create(
1365 comm = ChangesetCommentsModel().create(
1368 message, repo, user, revision=commit_id, status_change=status,
1366 message, repo, user, revision=commit_id, status_change=status,
1369 renderer=renderer)
1367 renderer=renderer)
1370 if status:
1368 if status:
1371 # also do a status change
1369 # also do a status change
1372 try:
1370 try:
1373 ChangesetStatusModel().set_status(
1371 ChangesetStatusModel().set_status(
1374 repo, status, user, comm, revision=commit_id,
1372 repo, status, user, comm, revision=commit_id,
1375 dont_allow_on_closed_pull_request=True
1373 dont_allow_on_closed_pull_request=True
1376 )
1374 )
1377 except StatusChangeOnClosedPullRequestError:
1375 except StatusChangeOnClosedPullRequestError:
1378 log.exception(
1376 log.exception(
1379 "Exception occurred while trying to change repo commit status")
1377 "Exception occurred while trying to change repo commit status")
1380 msg = ('Changing status on a changeset associated with '
1378 msg = ('Changing status on a changeset associated with '
1381 'a closed pull request is not allowed')
1379 'a closed pull request is not allowed')
1382 raise JSONRPCError(msg)
1380 raise JSONRPCError(msg)
1383
1381
1384 Session().commit()
1382 Session().commit()
1385 return {
1383 return {
1386 'msg': (
1384 'msg': (
1387 'Commented on commit `%s` for repository `%s`' % (
1385 'Commented on commit `%s` for repository `%s`' % (
1388 comm.revision, repo.repo_name)),
1386 comm.revision, repo.repo_name)),
1389 'status_change': status,
1387 'status_change': status,
1390 'success': True,
1388 'success': True,
1391 }
1389 }
1392 except JSONRPCError:
1390 except JSONRPCError:
1393 # catch any inside errors, and re-raise them to prevent from
1391 # catch any inside errors, and re-raise them to prevent from
1394 # below global catch to silence them
1392 # below global catch to silence them
1395 raise
1393 raise
1396 except Exception:
1394 except Exception:
1397 log.exception("Exception occurred while trying to comment on commit")
1395 log.exception("Exception occurred while trying to comment on commit")
1398 raise JSONRPCError(
1396 raise JSONRPCError(
1399 'failed to set comment on repository `%s`' % (repo.repo_name,)
1397 'failed to set comment on repository `%s`' % (repo.repo_name,)
1400 )
1398 )
1401
1399
1402
1400
1403 @jsonrpc_method()
1401 @jsonrpc_method()
1404 def grant_user_permission(request, apiuser, repoid, userid, perm):
1402 def grant_user_permission(request, apiuser, repoid, userid, perm):
1405 """
1403 """
1406 Grant permissions for the specified user on the given repository,
1404 Grant permissions for the specified user on the given repository,
1407 or update existing permissions if found.
1405 or update existing permissions if found.
1408
1406
1409 This command can only be run using an |authtoken| with admin
1407 This command can only be run using an |authtoken| with admin
1410 permissions on the |repo|.
1408 permissions on the |repo|.
1411
1409
1412 :param apiuser: This is filled automatically from the |authtoken|.
1410 :param apiuser: This is filled automatically from the |authtoken|.
1413 :type apiuser: AuthUser
1411 :type apiuser: AuthUser
1414 :param repoid: Set the repository name or repository ID.
1412 :param repoid: Set the repository name or repository ID.
1415 :type repoid: str or int
1413 :type repoid: str or int
1416 :param userid: Set the user name.
1414 :param userid: Set the user name.
1417 :type userid: str
1415 :type userid: str
1418 :param perm: Set the user permissions, using the following format
1416 :param perm: Set the user permissions, using the following format
1419 ``(repository.(none|read|write|admin))``
1417 ``(repository.(none|read|write|admin))``
1420 :type perm: str
1418 :type perm: str
1421
1419
1422 Example output:
1420 Example output:
1423
1421
1424 .. code-block:: bash
1422 .. code-block:: bash
1425
1423
1426 id : <id_given_in_input>
1424 id : <id_given_in_input>
1427 result: {
1425 result: {
1428 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1426 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1429 "success": true
1427 "success": true
1430 }
1428 }
1431 error: null
1429 error: null
1432 """
1430 """
1433
1431
1434 repo = get_repo_or_error(repoid)
1432 repo = get_repo_or_error(repoid)
1435 user = get_user_or_error(userid)
1433 user = get_user_or_error(userid)
1436 perm = get_perm_or_error(perm)
1434 perm = get_perm_or_error(perm)
1437 if not has_superadmin_permission(apiuser):
1435 if not has_superadmin_permission(apiuser):
1438 _perms = ('repository.admin',)
1436 _perms = ('repository.admin',)
1439 has_repo_permissions(apiuser, repoid, repo, _perms)
1437 has_repo_permissions(apiuser, repoid, repo, _perms)
1440
1438
1441 try:
1439 try:
1442
1440
1443 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1441 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1444
1442
1445 Session().commit()
1443 Session().commit()
1446 return {
1444 return {
1447 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1445 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1448 perm.permission_name, user.username, repo.repo_name
1446 perm.permission_name, user.username, repo.repo_name
1449 ),
1447 ),
1450 'success': True
1448 'success': True
1451 }
1449 }
1452 except Exception:
1450 except Exception:
1453 log.exception(
1451 log.exception(
1454 "Exception occurred while trying edit permissions for repo")
1452 "Exception occurred while trying edit permissions for repo")
1455 raise JSONRPCError(
1453 raise JSONRPCError(
1456 'failed to edit permission for user: `%s` in repo: `%s`' % (
1454 'failed to edit permission for user: `%s` in repo: `%s`' % (
1457 userid, repoid
1455 userid, repoid
1458 )
1456 )
1459 )
1457 )
1460
1458
1461
1459
1462 @jsonrpc_method()
1460 @jsonrpc_method()
1463 def revoke_user_permission(request, apiuser, repoid, userid):
1461 def revoke_user_permission(request, apiuser, repoid, userid):
1464 """
1462 """
1465 Revoke permission for a user on the specified repository.
1463 Revoke permission for a user on the specified repository.
1466
1464
1467 This command can only be run using an |authtoken| with admin
1465 This command can only be run using an |authtoken| with admin
1468 permissions on the |repo|.
1466 permissions on the |repo|.
1469
1467
1470 :param apiuser: This is filled automatically from the |authtoken|.
1468 :param apiuser: This is filled automatically from the |authtoken|.
1471 :type apiuser: AuthUser
1469 :type apiuser: AuthUser
1472 :param repoid: Set the repository name or repository ID.
1470 :param repoid: Set the repository name or repository ID.
1473 :type repoid: str or int
1471 :type repoid: str or int
1474 :param userid: Set the user name of revoked user.
1472 :param userid: Set the user name of revoked user.
1475 :type userid: str or int
1473 :type userid: str or int
1476
1474
1477 Example error output:
1475 Example error output:
1478
1476
1479 .. code-block:: bash
1477 .. code-block:: bash
1480
1478
1481 id : <id_given_in_input>
1479 id : <id_given_in_input>
1482 result: {
1480 result: {
1483 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1481 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1484 "success": true
1482 "success": true
1485 }
1483 }
1486 error: null
1484 error: null
1487 """
1485 """
1488
1486
1489 repo = get_repo_or_error(repoid)
1487 repo = get_repo_or_error(repoid)
1490 user = get_user_or_error(userid)
1488 user = get_user_or_error(userid)
1491 if not has_superadmin_permission(apiuser):
1489 if not has_superadmin_permission(apiuser):
1492 _perms = ('repository.admin',)
1490 _perms = ('repository.admin',)
1493 has_repo_permissions(apiuser, repoid, repo, _perms)
1491 has_repo_permissions(apiuser, repoid, repo, _perms)
1494
1492
1495 try:
1493 try:
1496 RepoModel().revoke_user_permission(repo=repo, user=user)
1494 RepoModel().revoke_user_permission(repo=repo, user=user)
1497 Session().commit()
1495 Session().commit()
1498 return {
1496 return {
1499 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1497 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1500 user.username, repo.repo_name
1498 user.username, repo.repo_name
1501 ),
1499 ),
1502 'success': True
1500 'success': True
1503 }
1501 }
1504 except Exception:
1502 except Exception:
1505 log.exception(
1503 log.exception(
1506 "Exception occurred while trying revoke permissions to repo")
1504 "Exception occurred while trying revoke permissions to repo")
1507 raise JSONRPCError(
1505 raise JSONRPCError(
1508 'failed to edit permission for user: `%s` in repo: `%s`' % (
1506 'failed to edit permission for user: `%s` in repo: `%s`' % (
1509 userid, repoid
1507 userid, repoid
1510 )
1508 )
1511 )
1509 )
1512
1510
1513
1511
1514 @jsonrpc_method()
1512 @jsonrpc_method()
1515 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1513 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1516 """
1514 """
1517 Grant permission for a user group on the specified repository,
1515 Grant permission for a user group on the specified repository,
1518 or update existing permissions.
1516 or update existing permissions.
1519
1517
1520 This command can only be run using an |authtoken| with admin
1518 This command can only be run using an |authtoken| with admin
1521 permissions on the |repo|.
1519 permissions on the |repo|.
1522
1520
1523 :param apiuser: This is filled automatically from the |authtoken|.
1521 :param apiuser: This is filled automatically from the |authtoken|.
1524 :type apiuser: AuthUser
1522 :type apiuser: AuthUser
1525 :param repoid: Set the repository name or repository ID.
1523 :param repoid: Set the repository name or repository ID.
1526 :type repoid: str or int
1524 :type repoid: str or int
1527 :param usergroupid: Specify the ID of the user group.
1525 :param usergroupid: Specify the ID of the user group.
1528 :type usergroupid: str or int
1526 :type usergroupid: str or int
1529 :param perm: Set the user group permissions using the following
1527 :param perm: Set the user group permissions using the following
1530 format: (repository.(none|read|write|admin))
1528 format: (repository.(none|read|write|admin))
1531 :type perm: str
1529 :type perm: str
1532
1530
1533 Example output:
1531 Example output:
1534
1532
1535 .. code-block:: bash
1533 .. code-block:: bash
1536
1534
1537 id : <id_given_in_input>
1535 id : <id_given_in_input>
1538 result : {
1536 result : {
1539 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1537 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1540 "success": true
1538 "success": true
1541
1539
1542 }
1540 }
1543 error : null
1541 error : null
1544
1542
1545 Example error output:
1543 Example error output:
1546
1544
1547 .. code-block:: bash
1545 .. code-block:: bash
1548
1546
1549 id : <id_given_in_input>
1547 id : <id_given_in_input>
1550 result : null
1548 result : null
1551 error : {
1549 error : {
1552 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1550 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1553 }
1551 }
1554
1552
1555 """
1553 """
1556
1554
1557 repo = get_repo_or_error(repoid)
1555 repo = get_repo_or_error(repoid)
1558 perm = get_perm_or_error(perm)
1556 perm = get_perm_or_error(perm)
1559 if not has_superadmin_permission(apiuser):
1557 if not has_superadmin_permission(apiuser):
1560 _perms = ('repository.admin',)
1558 _perms = ('repository.admin',)
1561 has_repo_permissions(apiuser, repoid, repo, _perms)
1559 has_repo_permissions(apiuser, repoid, repo, _perms)
1562
1560
1563 user_group = get_user_group_or_error(usergroupid)
1561 user_group = get_user_group_or_error(usergroupid)
1564 if not has_superadmin_permission(apiuser):
1562 if not has_superadmin_permission(apiuser):
1565 # check if we have at least read permission for this user group !
1563 # check if we have at least read permission for this user group !
1566 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1564 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1567 if not HasUserGroupPermissionAnyApi(*_perms)(
1565 if not HasUserGroupPermissionAnyApi(*_perms)(
1568 user=apiuser, user_group_name=user_group.users_group_name):
1566 user=apiuser, user_group_name=user_group.users_group_name):
1569 raise JSONRPCError(
1567 raise JSONRPCError(
1570 'user group `%s` does not exist' % (usergroupid,))
1568 'user group `%s` does not exist' % (usergroupid,))
1571
1569
1572 try:
1570 try:
1573 RepoModel().grant_user_group_permission(
1571 RepoModel().grant_user_group_permission(
1574 repo=repo, group_name=user_group, perm=perm)
1572 repo=repo, group_name=user_group, perm=perm)
1575
1573
1576 Session().commit()
1574 Session().commit()
1577 return {
1575 return {
1578 'msg': 'Granted perm: `%s` for user group: `%s` in '
1576 'msg': 'Granted perm: `%s` for user group: `%s` in '
1579 'repo: `%s`' % (
1577 'repo: `%s`' % (
1580 perm.permission_name, user_group.users_group_name,
1578 perm.permission_name, user_group.users_group_name,
1581 repo.repo_name
1579 repo.repo_name
1582 ),
1580 ),
1583 'success': True
1581 'success': True
1584 }
1582 }
1585 except Exception:
1583 except Exception:
1586 log.exception(
1584 log.exception(
1587 "Exception occurred while trying change permission on repo")
1585 "Exception occurred while trying change permission on repo")
1588 raise JSONRPCError(
1586 raise JSONRPCError(
1589 'failed to edit permission for user group: `%s` in '
1587 'failed to edit permission for user group: `%s` in '
1590 'repo: `%s`' % (
1588 'repo: `%s`' % (
1591 usergroupid, repo.repo_name
1589 usergroupid, repo.repo_name
1592 )
1590 )
1593 )
1591 )
1594
1592
1595
1593
1596 @jsonrpc_method()
1594 @jsonrpc_method()
1597 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1595 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1598 """
1596 """
1599 Revoke the permissions of a user group on a given repository.
1597 Revoke the permissions of a user group on a given repository.
1600
1598
1601 This command can only be run using an |authtoken| with admin
1599 This command can only be run using an |authtoken| with admin
1602 permissions on the |repo|.
1600 permissions on the |repo|.
1603
1601
1604 :param apiuser: This is filled automatically from the |authtoken|.
1602 :param apiuser: This is filled automatically from the |authtoken|.
1605 :type apiuser: AuthUser
1603 :type apiuser: AuthUser
1606 :param repoid: Set the repository name or repository ID.
1604 :param repoid: Set the repository name or repository ID.
1607 :type repoid: str or int
1605 :type repoid: str or int
1608 :param usergroupid: Specify the user group ID.
1606 :param usergroupid: Specify the user group ID.
1609 :type usergroupid: str or int
1607 :type usergroupid: str or int
1610
1608
1611 Example output:
1609 Example output:
1612
1610
1613 .. code-block:: bash
1611 .. code-block:: bash
1614
1612
1615 id : <id_given_in_input>
1613 id : <id_given_in_input>
1616 result: {
1614 result: {
1617 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1615 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1618 "success": true
1616 "success": true
1619 }
1617 }
1620 error: null
1618 error: null
1621 """
1619 """
1622
1620
1623 repo = get_repo_or_error(repoid)
1621 repo = get_repo_or_error(repoid)
1624 if not has_superadmin_permission(apiuser):
1622 if not has_superadmin_permission(apiuser):
1625 _perms = ('repository.admin',)
1623 _perms = ('repository.admin',)
1626 has_repo_permissions(apiuser, repoid, repo, _perms)
1624 has_repo_permissions(apiuser, repoid, repo, _perms)
1627
1625
1628 user_group = get_user_group_or_error(usergroupid)
1626 user_group = get_user_group_or_error(usergroupid)
1629 if not has_superadmin_permission(apiuser):
1627 if not has_superadmin_permission(apiuser):
1630 # check if we have at least read permission for this user group !
1628 # check if we have at least read permission for this user group !
1631 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1629 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1632 if not HasUserGroupPermissionAnyApi(*_perms)(
1630 if not HasUserGroupPermissionAnyApi(*_perms)(
1633 user=apiuser, user_group_name=user_group.users_group_name):
1631 user=apiuser, user_group_name=user_group.users_group_name):
1634 raise JSONRPCError(
1632 raise JSONRPCError(
1635 'user group `%s` does not exist' % (usergroupid,))
1633 'user group `%s` does not exist' % (usergroupid,))
1636
1634
1637 try:
1635 try:
1638 RepoModel().revoke_user_group_permission(
1636 RepoModel().revoke_user_group_permission(
1639 repo=repo, group_name=user_group)
1637 repo=repo, group_name=user_group)
1640
1638
1641 Session().commit()
1639 Session().commit()
1642 return {
1640 return {
1643 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1641 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1644 user_group.users_group_name, repo.repo_name
1642 user_group.users_group_name, repo.repo_name
1645 ),
1643 ),
1646 'success': True
1644 'success': True
1647 }
1645 }
1648 except Exception:
1646 except Exception:
1649 log.exception("Exception occurred while trying revoke "
1647 log.exception("Exception occurred while trying revoke "
1650 "user group permission on repo")
1648 "user group permission on repo")
1651 raise JSONRPCError(
1649 raise JSONRPCError(
1652 'failed to edit permission for user group: `%s` in '
1650 'failed to edit permission for user group: `%s` in '
1653 'repo: `%s`' % (
1651 'repo: `%s`' % (
1654 user_group.users_group_name, repo.repo_name
1652 user_group.users_group_name, repo.repo_name
1655 )
1653 )
1656 )
1654 )
1657
1655
1658
1656
1659 @jsonrpc_method()
1657 @jsonrpc_method()
1660 def pull(request, apiuser, repoid):
1658 def pull(request, apiuser, repoid):
1661 """
1659 """
1662 Triggers a pull on the given repository from a remote location. You
1660 Triggers a pull on the given repository from a remote location. You
1663 can use this to keep remote repositories up-to-date.
1661 can use this to keep remote repositories up-to-date.
1664
1662
1665 This command can only be run using an |authtoken| with admin
1663 This command can only be run using an |authtoken| with admin
1666 rights to the specified repository. For more information,
1664 rights to the specified repository. For more information,
1667 see :ref:`config-token-ref`.
1665 see :ref:`config-token-ref`.
1668
1666
1669 This command takes the following options:
1667 This command takes the following options:
1670
1668
1671 :param apiuser: This is filled automatically from the |authtoken|.
1669 :param apiuser: This is filled automatically from the |authtoken|.
1672 :type apiuser: AuthUser
1670 :type apiuser: AuthUser
1673 :param repoid: The repository name or repository ID.
1671 :param repoid: The repository name or repository ID.
1674 :type repoid: str or int
1672 :type repoid: str or int
1675
1673
1676 Example output:
1674 Example output:
1677
1675
1678 .. code-block:: bash
1676 .. code-block:: bash
1679
1677
1680 id : <id_given_in_input>
1678 id : <id_given_in_input>
1681 result : {
1679 result : {
1682 "msg": "Pulled from `<repository name>`"
1680 "msg": "Pulled from `<repository name>`"
1683 "repository": "<repository name>"
1681 "repository": "<repository name>"
1684 }
1682 }
1685 error : null
1683 error : null
1686
1684
1687 Example error output:
1685 Example error output:
1688
1686
1689 .. code-block:: bash
1687 .. code-block:: bash
1690
1688
1691 id : <id_given_in_input>
1689 id : <id_given_in_input>
1692 result : null
1690 result : null
1693 error : {
1691 error : {
1694 "Unable to pull changes from `<reponame>`"
1692 "Unable to pull changes from `<reponame>`"
1695 }
1693 }
1696
1694
1697 """
1695 """
1698
1696
1699 repo = get_repo_or_error(repoid)
1697 repo = get_repo_or_error(repoid)
1700 if not has_superadmin_permission(apiuser):
1698 if not has_superadmin_permission(apiuser):
1701 _perms = ('repository.admin',)
1699 _perms = ('repository.admin',)
1702 has_repo_permissions(apiuser, repoid, repo, _perms)
1700 has_repo_permissions(apiuser, repoid, repo, _perms)
1703
1701
1704 try:
1702 try:
1705 ScmModel().pull_changes(repo.repo_name, apiuser.username)
1703 ScmModel().pull_changes(repo.repo_name, apiuser.username)
1706 return {
1704 return {
1707 'msg': 'Pulled from `%s`' % repo.repo_name,
1705 'msg': 'Pulled from `%s`' % repo.repo_name,
1708 'repository': repo.repo_name
1706 'repository': repo.repo_name
1709 }
1707 }
1710 except Exception:
1708 except Exception:
1711 log.exception("Exception occurred while trying to "
1709 log.exception("Exception occurred while trying to "
1712 "pull changes from remote location")
1710 "pull changes from remote location")
1713 raise JSONRPCError(
1711 raise JSONRPCError(
1714 'Unable to pull changes from `%s`' % repo.repo_name
1712 'Unable to pull changes from `%s`' % repo.repo_name
1715 )
1713 )
1716
1714
1717
1715
1718 @jsonrpc_method()
1716 @jsonrpc_method()
1719 def strip(request, apiuser, repoid, revision, branch):
1717 def strip(request, apiuser, repoid, revision, branch):
1720 """
1718 """
1721 Strips the given revision from the specified repository.
1719 Strips the given revision from the specified repository.
1722
1720
1723 * This will remove the revision and all of its decendants.
1721 * This will remove the revision and all of its decendants.
1724
1722
1725 This command can only be run using an |authtoken| with admin rights to
1723 This command can only be run using an |authtoken| with admin rights to
1726 the specified repository.
1724 the specified repository.
1727
1725
1728 This command takes the following options:
1726 This command takes the following options:
1729
1727
1730 :param apiuser: This is filled automatically from the |authtoken|.
1728 :param apiuser: This is filled automatically from the |authtoken|.
1731 :type apiuser: AuthUser
1729 :type apiuser: AuthUser
1732 :param repoid: The repository name or repository ID.
1730 :param repoid: The repository name or repository ID.
1733 :type repoid: str or int
1731 :type repoid: str or int
1734 :param revision: The revision you wish to strip.
1732 :param revision: The revision you wish to strip.
1735 :type revision: str
1733 :type revision: str
1736 :param branch: The branch from which to strip the revision.
1734 :param branch: The branch from which to strip the revision.
1737 :type branch: str
1735 :type branch: str
1738
1736
1739 Example output:
1737 Example output:
1740
1738
1741 .. code-block:: bash
1739 .. code-block:: bash
1742
1740
1743 id : <id_given_in_input>
1741 id : <id_given_in_input>
1744 result : {
1742 result : {
1745 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1743 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1746 "repository": "<repository name>"
1744 "repository": "<repository name>"
1747 }
1745 }
1748 error : null
1746 error : null
1749
1747
1750 Example error output:
1748 Example error output:
1751
1749
1752 .. code-block:: bash
1750 .. code-block:: bash
1753
1751
1754 id : <id_given_in_input>
1752 id : <id_given_in_input>
1755 result : null
1753 result : null
1756 error : {
1754 error : {
1757 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1755 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1758 }
1756 }
1759
1757
1760 """
1758 """
1761
1759
1762 repo = get_repo_or_error(repoid)
1760 repo = get_repo_or_error(repoid)
1763 if not has_superadmin_permission(apiuser):
1761 if not has_superadmin_permission(apiuser):
1764 _perms = ('repository.admin',)
1762 _perms = ('repository.admin',)
1765 has_repo_permissions(apiuser, repoid, repo, _perms)
1763 has_repo_permissions(apiuser, repoid, repo, _perms)
1766
1764
1767 try:
1765 try:
1768 ScmModel().strip(repo, revision, branch)
1766 ScmModel().strip(repo, revision, branch)
1769 return {
1767 return {
1770 'msg': 'Stripped commit %s from repo `%s`' % (
1768 'msg': 'Stripped commit %s from repo `%s`' % (
1771 revision, repo.repo_name),
1769 revision, repo.repo_name),
1772 'repository': repo.repo_name
1770 'repository': repo.repo_name
1773 }
1771 }
1774 except Exception:
1772 except Exception:
1775 log.exception("Exception while trying to strip")
1773 log.exception("Exception while trying to strip")
1776 raise JSONRPCError(
1774 raise JSONRPCError(
1777 'Unable to strip commit %s from repo `%s`' % (
1775 'Unable to strip commit %s from repo `%s`' % (
1778 revision, repo.repo_name)
1776 revision, repo.repo_name)
1779 )
1777 )
General Comments 0
You need to be logged in to leave comments. Login now