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