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