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