##// END OF EJS Templates
backported update_repo API method from rhodecode-pam
marcink -
r3959:e1a0fdae beta
parent child Browse files
Show More
@@ -1,1100 +1,1187 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.api
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 API controller for RhodeCode
7 7
8 8 :created_on: Aug 20, 2011
9 9 :author: marcink
10 10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import time
29 29 import traceback
30 30 import logging
31 31
32 32 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
33 33 from rhodecode.lib.auth import PasswordGenerator, AuthUser, \
34 34 HasPermissionAllDecorator, HasPermissionAnyDecorator, \
35 35 HasPermissionAnyApi, HasRepoPermissionAnyApi
36 36 from rhodecode.lib.utils import map_groups, repo2db_mapper
37 37 from rhodecode.lib.utils2 import str2bool, time_to_datetime, safe_int
38 from rhodecode.lib import helpers as h
39 38 from rhodecode.model.meta import Session
40 39 from rhodecode.model.scm import ScmModel
41 40 from rhodecode.model.repo import RepoModel
42 41 from rhodecode.model.user import UserModel
43 42 from rhodecode.model.users_group import UserGroupModel
43 from rhodecode.model.repos_group import ReposGroupModel
44 44 from rhodecode.model.db import Repository, RhodeCodeSetting, UserIpMap,\
45 45 Permission, User, Gist
46 46 from rhodecode.lib.compat import json
47 47 from rhodecode.lib.exceptions import DefaultUserException
48 48 from rhodecode.model.gist import GistModel
49 49
50 50 log = logging.getLogger(__name__)
51 51
52 52
53 def store_update(updates, attr, name):
54 """
55 Stores param in updates dict if it's not instance of Optional
56 allows easy updates of passed in params
57 """
58 if not isinstance(attr, Optional):
59 updates[name] = attr
60
61
53 62 class OptionalAttr(object):
54 63 """
55 64 Special Optional Option that defines other attribute
56 65 """
57 66 def __init__(self, attr_name):
58 67 self.attr_name = attr_name
59 68
60 69 def __repr__(self):
61 70 return '<OptionalAttr:%s>' % self.attr_name
62 71
63 72 def __call__(self):
64 73 return self
65 74 #alias
66 75 OAttr = OptionalAttr
67 76
68 77
69 78 class Optional(object):
70 79 """
71 80 Defines an optional parameter::
72 81
73 82 param = param.getval() if isinstance(param, Optional) else param
74 83 param = param() if isinstance(param, Optional) else param
75 84
76 85 is equivalent of::
77 86
78 87 param = Optional.extract(param)
79 88
80 89 """
81 90 def __init__(self, type_):
82 91 self.type_ = type_
83 92
84 93 def __repr__(self):
85 94 return '<Optional:%s>' % self.type_.__repr__()
86 95
87 96 def __call__(self):
88 97 return self.getval()
89 98
90 99 def getval(self):
91 100 """
92 101 returns value from this Optional instance
93 102 """
94 103 return self.type_
95 104
96 105 @classmethod
97 106 def extract(cls, val):
98 107 if isinstance(val, cls):
99 108 return val.getval()
100 109 return val
101 110
102 111
103 112 def get_user_or_error(userid):
104 113 """
105 114 Get user by id or name or return JsonRPCError if not found
106 115
107 116 :param userid:
108 117 """
109 118 user = UserModel().get_user(userid)
110 119 if user is None:
111 120 raise JSONRPCError("user `%s` does not exist" % userid)
112 121 return user
113 122
114 123
115 124 def get_repo_or_error(repoid):
116 125 """
117 126 Get repo by id or name or return JsonRPCError if not found
118 127
119 128 :param repoid:
120 129 """
121 130 repo = RepoModel().get_repo(repoid)
122 131 if repo is None:
123 132 raise JSONRPCError('repository `%s` does not exist' % (repoid))
124 133 return repo
125 134
126 135
136 def get_repo_group_or_error(repogroupid):
137 """
138 Get repo group by id or name or return JsonRPCError if not found
139
140 :param repogroupid:
141 """
142 repo_group = ReposGroupModel()._get_repo_group(repogroupid)
143 if repo_group is None:
144 raise JSONRPCError(
145 'repository group `%s` does not exist' % (repogroupid,))
146 return repo_group
147
148
127 149 def get_users_group_or_error(usersgroupid):
128 150 """
129 151 Get user group by id or name or return JsonRPCError if not found
130 152
131 153 :param userid:
132 154 """
133 155 users_group = UserGroupModel().get_group(usersgroupid)
134 156 if users_group is None:
135 157 raise JSONRPCError('user group `%s` does not exist' % usersgroupid)
136 158 return users_group
137 159
138 160
139 161 def get_perm_or_error(permid):
140 162 """
141 163 Get permission by id or name or return JsonRPCError if not found
142 164
143 165 :param userid:
144 166 """
145 167 perm = Permission.get_by_key(permid)
146 168 if perm is None:
147 169 raise JSONRPCError('permission `%s` does not exist' % (permid))
148 170 return perm
149 171
150 172
151 173 class ApiController(JSONRPCController):
152 174 """
153 175 API Controller
154 176
155 177
156 178 Each method needs to have USER as argument this is then based on given
157 179 API_KEY propagated as instance of user object
158 180
159 181 Preferably this should be first argument also
160 182
161 183
162 184 Each function should also **raise** JSONRPCError for any
163 185 errors that happens
164 186
165 187 """
166 188
167 189 @HasPermissionAllDecorator('hg.admin')
168 190 def pull(self, apiuser, repoid):
169 191 """
170 192 Dispatch pull action on given repo
171 193
172 194 :param apiuser:
173 195 :param repoid:
174 196 """
175 197
176 198 repo = get_repo_or_error(repoid)
177 199
178 200 try:
179 201 ScmModel().pull_changes(repo.repo_name,
180 202 self.rhodecode_user.username)
181 203 return 'Pulled from `%s`' % repo.repo_name
182 204 except Exception:
183 205 log.error(traceback.format_exc())
184 206 raise JSONRPCError(
185 207 'Unable to pull changes from `%s`' % repo.repo_name
186 208 )
187 209
188 210 @HasPermissionAllDecorator('hg.admin')
189 211 def rescan_repos(self, apiuser, remove_obsolete=Optional(False)):
190 212 """
191 213 Dispatch rescan repositories action. If remove_obsolete is set
192 214 than also delete repos that are in database but not in the filesystem.
193 215 aka "clean zombies"
194 216
195 217 :param apiuser:
196 218 :param remove_obsolete:
197 219 """
198 220
199 221 try:
200 222 rm_obsolete = Optional.extract(remove_obsolete)
201 223 added, removed = repo2db_mapper(ScmModel().repo_scan(),
202 224 remove_obsolete=rm_obsolete)
203 225 return {'added': added, 'removed': removed}
204 226 except Exception:
205 227 log.error(traceback.format_exc())
206 228 raise JSONRPCError(
207 229 'Error occurred during rescan repositories action'
208 230 )
209 231
210 232 def invalidate_cache(self, apiuser, repoid):
211 233 """
212 234 Dispatch cache invalidation action on given repo
213 235
214 236 :param apiuser:
215 237 :param repoid:
216 238 """
217 239 repo = get_repo_or_error(repoid)
218 240 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
219 241 # check if we have admin permission for this repo !
220 242 if HasRepoPermissionAnyApi('repository.admin',
221 243 'repository.write')(user=apiuser,
222 244 repo_name=repo.repo_name) is False:
223 245 raise JSONRPCError('repository `%s` does not exist' % (repoid))
224 246
225 247 try:
226 248 ScmModel().mark_for_invalidation(repo.repo_name)
227 249 return ('Caches of repository `%s` was invalidated' % repoid)
228 250 except Exception:
229 251 log.error(traceback.format_exc())
230 252 raise JSONRPCError(
231 253 'Error occurred during cache invalidation action'
232 254 )
233 255
234 256 # permission check inside
235 257 def lock(self, apiuser, repoid, locked=Optional(None),
236 258 userid=Optional(OAttr('apiuser'))):
237 259 """
238 260 Set locking state on particular repository by given user, if
239 261 this command is runned by non-admin account userid is set to user
240 262 who is calling this method
241 263
242 264 :param apiuser:
243 265 :param repoid:
244 266 :param userid:
245 267 :param locked:
246 268 """
247 269 repo = get_repo_or_error(repoid)
248 270 if HasPermissionAnyApi('hg.admin')(user=apiuser):
249 271 pass
250 272 elif HasRepoPermissionAnyApi('repository.admin',
251 273 'repository.write')(user=apiuser,
252 274 repo_name=repo.repo_name):
253 275 #make sure normal user does not pass someone else userid,
254 276 #he is not allowed to do that
255 277 if not isinstance(userid, Optional) and userid != apiuser.user_id:
256 278 raise JSONRPCError(
257 279 'userid is not the same as your user'
258 280 )
259 281 else:
260 282 raise JSONRPCError('repository `%s` does not exist' % (repoid))
261 283
262 284 if isinstance(userid, Optional):
263 285 userid = apiuser.user_id
264 286
265 287 user = get_user_or_error(userid)
266 288
267 289 if isinstance(locked, Optional):
268 290 lockobj = Repository.getlock(repo)
269 291
270 292 if lockobj[0] is None:
271 293 _d = {
272 294 'repo': repo.repo_name,
273 295 'locked': False,
274 296 'locked_since': None,
275 297 'locked_by': None,
276 298 'msg': 'Repo `%s` not locked.' % repo.repo_name
277 299 }
278 300 return _d
279 301 else:
280 302 userid, time_ = lockobj
281 303 lock_user = get_user_or_error(userid)
282 304 _d = {
283 305 'repo': repo.repo_name,
284 306 'locked': True,
285 307 'locked_since': time_,
286 308 'locked_by': lock_user.username,
287 309 'msg': ('Repo `%s` locked by `%s`. '
288 310 % (repo.repo_name,
289 311 json.dumps(time_to_datetime(time_))))
290 312 }
291 313 return _d
292 314
293 315 # force locked state through a flag
294 316 else:
295 317 locked = str2bool(locked)
296 318 try:
297 319 if locked:
298 320 lock_time = time.time()
299 321 Repository.lock(repo, user.user_id, lock_time)
300 322 else:
301 323 lock_time = None
302 324 Repository.unlock(repo)
303 325 _d = {
304 326 'repo': repo.repo_name,
305 327 'locked': locked,
306 328 'locked_since': lock_time,
307 329 'locked_by': user.username,
308 330 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
309 331 % (user.username, repo.repo_name, locked))
310 332 }
311 333 return _d
312 334 except Exception:
313 335 log.error(traceback.format_exc())
314 336 raise JSONRPCError(
315 337 'Error occurred locking repository `%s`' % repo.repo_name
316 338 )
317 339
318 340 def get_locks(self, apiuser, userid=Optional(OAttr('apiuser'))):
319 341 """
320 342 Get all locks for given userid, if
321 343 this command is runned by non-admin account userid is set to user
322 344 who is calling this method, thus returning locks for himself
323 345
324 346 :param apiuser:
325 347 :param userid:
326 348 """
327 349
328 350 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
329 351 #make sure normal user does not pass someone else userid,
330 352 #he is not allowed to do that
331 353 if not isinstance(userid, Optional) and userid != apiuser.user_id:
332 354 raise JSONRPCError(
333 355 'userid is not the same as your user'
334 356 )
335 357 ret = []
336 358 if isinstance(userid, Optional):
337 359 user = None
338 360 else:
339 361 user = get_user_or_error(userid)
340 362
341 363 #show all locks
342 364 for r in Repository.getAll():
343 365 userid, time_ = r.locked
344 366 if time_:
345 367 _api_data = r.get_api_data()
346 368 # if we use userfilter just show the locks for this user
347 369 if user:
348 370 if safe_int(userid) == user.user_id:
349 371 ret.append(_api_data)
350 372 else:
351 373 ret.append(_api_data)
352 374
353 375 return ret
354 376
355 377 @HasPermissionAllDecorator('hg.admin')
356 378 def show_ip(self, apiuser, userid):
357 379 """
358 380 Shows IP address as seen from RhodeCode server, together with all
359 381 defined IP addresses for given user
360 382
361 383 :param apiuser:
362 384 :param userid:
363 385 """
364 386 user = get_user_or_error(userid)
365 387 ips = UserIpMap.query().filter(UserIpMap.user == user).all()
366 388 return dict(
367 389 ip_addr_server=self.ip_addr,
368 390 user_ips=ips
369 391 )
370 392
371 393 def get_user(self, apiuser, userid=Optional(OAttr('apiuser'))):
372 394 """"
373 395 Get a user by username, or userid, if userid is given
374 396
375 397 :param apiuser:
376 398 :param userid:
377 399 """
378 400 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
379 401 #make sure normal user does not pass someone else userid,
380 402 #he is not allowed to do that
381 403 if not isinstance(userid, Optional) and userid != apiuser.user_id:
382 404 raise JSONRPCError(
383 405 'userid is not the same as your user'
384 406 )
385 407
386 408 if isinstance(userid, Optional):
387 409 userid = apiuser.user_id
388 410
389 411 user = get_user_or_error(userid)
390 412 data = user.get_api_data()
391 413 data['permissions'] = AuthUser(user_id=user.user_id).permissions
392 414 return data
393 415
394 416 @HasPermissionAllDecorator('hg.admin')
395 417 def get_users(self, apiuser):
396 418 """"
397 419 Get all users
398 420
399 421 :param apiuser:
400 422 """
401 423
402 424 result = []
403 425 users_list = User.query().order_by(User.username)\
404 426 .filter(User.username != User.DEFAULT_USER)\
405 427 .all()
406 428 for user in users_list:
407 429 result.append(user.get_api_data())
408 430 return result
409 431
410 432 @HasPermissionAllDecorator('hg.admin')
411 433 def create_user(self, apiuser, username, email, password=Optional(None),
412 434 firstname=Optional(None), lastname=Optional(None),
413 435 active=Optional(True), admin=Optional(False),
414 436 ldap_dn=Optional(None)):
415 437 """
416 438 Create new user
417 439
418 440 :param apiuser:
419 441 :param username:
420 442 :param email:
421 443 :param password:
422 444 :param firstname:
423 445 :param lastname:
424 446 :param active:
425 447 :param admin:
426 448 :param ldap_dn:
427 449 """
428 450
429 451 if UserModel().get_by_username(username):
430 452 raise JSONRPCError("user `%s` already exist" % username)
431 453
432 454 if UserModel().get_by_email(email, case_insensitive=True):
433 455 raise JSONRPCError("email `%s` already exist" % email)
434 456
435 457 if Optional.extract(ldap_dn):
436 458 # generate temporary password if ldap_dn
437 459 password = PasswordGenerator().gen_password(length=8)
438 460
439 461 try:
440 462 user = UserModel().create_or_update(
441 463 username=Optional.extract(username),
442 464 password=Optional.extract(password),
443 465 email=Optional.extract(email),
444 466 firstname=Optional.extract(firstname),
445 467 lastname=Optional.extract(lastname),
446 468 active=Optional.extract(active),
447 469 admin=Optional.extract(admin),
448 470 ldap_dn=Optional.extract(ldap_dn)
449 471 )
450 472 Session().commit()
451 473 return dict(
452 474 msg='created new user `%s`' % username,
453 475 user=user.get_api_data()
454 476 )
455 477 except Exception:
456 478 log.error(traceback.format_exc())
457 479 raise JSONRPCError('failed to create user `%s`' % username)
458 480
459 481 @HasPermissionAllDecorator('hg.admin')
460 482 def update_user(self, apiuser, userid, username=Optional(None),
461 483 email=Optional(None), firstname=Optional(None),
462 484 lastname=Optional(None), active=Optional(None),
463 485 admin=Optional(None), ldap_dn=Optional(None),
464 486 password=Optional(None)):
465 487 """
466 488 Updates given user
467 489
468 490 :param apiuser:
469 491 :param userid:
470 492 :param username:
471 493 :param email:
472 494 :param firstname:
473 495 :param lastname:
474 496 :param active:
475 497 :param admin:
476 498 :param ldap_dn:
477 499 :param password:
478 500 """
479 501
480 502 user = get_user_or_error(userid)
481 503
482 504 # call function and store only updated arguments
483 505 updates = {}
484 506
485 507 def store_update(attr, name):
486 508 if not isinstance(attr, Optional):
487 509 updates[name] = attr
488 510
489 511 try:
490 512
491 513 store_update(username, 'username')
492 514 store_update(password, 'password')
493 515 store_update(email, 'email')
494 516 store_update(firstname, 'name')
495 517 store_update(lastname, 'lastname')
496 518 store_update(active, 'active')
497 519 store_update(admin, 'admin')
498 520 store_update(ldap_dn, 'ldap_dn')
499 521
500 522 user = UserModel().update_user(user, **updates)
501 523 Session().commit()
502 524 return dict(
503 525 msg='updated user ID:%s %s' % (user.user_id, user.username),
504 526 user=user.get_api_data()
505 527 )
506 528 except DefaultUserException:
507 529 log.error(traceback.format_exc())
508 530 raise JSONRPCError('editing default user is forbidden')
509 531 except Exception:
510 532 log.error(traceback.format_exc())
511 533 raise JSONRPCError('failed to update user `%s`' % userid)
512 534
513 535 @HasPermissionAllDecorator('hg.admin')
514 536 def delete_user(self, apiuser, userid):
515 537 """"
516 538 Deletes an user
517 539
518 540 :param apiuser:
519 541 :param userid:
520 542 """
521 543 user = get_user_or_error(userid)
522 544
523 545 try:
524 546 UserModel().delete(userid)
525 547 Session().commit()
526 548 return dict(
527 549 msg='deleted user ID:%s %s' % (user.user_id, user.username),
528 550 user=None
529 551 )
530 552 except Exception:
531 553 log.error(traceback.format_exc())
532 554 raise JSONRPCError('failed to delete ID:%s %s' % (user.user_id,
533 555 user.username))
534 556
535 557 @HasPermissionAllDecorator('hg.admin')
536 558 def get_users_group(self, apiuser, usersgroupid):
537 559 """"
538 560 Get user group by name or id
539 561
540 562 :param apiuser:
541 563 :param usersgroupid:
542 564 """
543 565 users_group = get_users_group_or_error(usersgroupid)
544 566
545 567 data = users_group.get_api_data()
546 568
547 569 members = []
548 570 for user in users_group.members:
549 571 user = user.user
550 572 members.append(user.get_api_data())
551 573 data['members'] = members
552 574 return data
553 575
554 576 @HasPermissionAllDecorator('hg.admin')
555 577 def get_users_groups(self, apiuser):
556 578 """"
557 579 Get all user groups
558 580
559 581 :param apiuser:
560 582 """
561 583
562 584 result = []
563 585 for users_group in UserGroupModel().get_all():
564 586 result.append(users_group.get_api_data())
565 587 return result
566 588
567 589 @HasPermissionAllDecorator('hg.admin')
568 590 def create_users_group(self, apiuser, group_name,
569 591 owner=Optional(OAttr('apiuser')),
570 592 active=Optional(True)):
571 593 """
572 594 Creates an new usergroup
573 595
574 596 :param apiuser:
575 597 :param group_name:
576 598 :param owner:
577 599 :param active:
578 600 """
579 601
580 602 if UserGroupModel().get_by_name(group_name):
581 603 raise JSONRPCError("user group `%s` already exist" % group_name)
582 604
583 605 try:
584 606 if isinstance(owner, Optional):
585 607 owner = apiuser.user_id
586 608
587 609 owner = get_user_or_error(owner)
588 610 active = Optional.extract(active)
589 611 ug = UserGroupModel().create(name=group_name,
590 612 owner=owner,
591 613 active=active)
592 614 Session().commit()
593 615 return dict(
594 616 msg='created new user group `%s`' % group_name,
595 617 users_group=ug.get_api_data()
596 618 )
597 619 except Exception:
598 620 log.error(traceback.format_exc())
599 621 raise JSONRPCError('failed to create group `%s`' % group_name)
600 622
601 623 @HasPermissionAllDecorator('hg.admin')
602 624 def add_user_to_users_group(self, apiuser, usersgroupid, userid):
603 625 """"
604 626 Add a user to a user group
605 627
606 628 :param apiuser:
607 629 :param usersgroupid:
608 630 :param userid:
609 631 """
610 632 user = get_user_or_error(userid)
611 633 users_group = get_users_group_or_error(usersgroupid)
612 634
613 635 try:
614 636 ugm = UserGroupModel().add_user_to_group(users_group, user)
615 637 success = True if ugm != True else False
616 638 msg = 'added member `%s` to user group `%s`' % (
617 639 user.username, users_group.users_group_name
618 640 )
619 641 msg = msg if success else 'User is already in that group'
620 642 Session().commit()
621 643
622 644 return dict(
623 645 success=success,
624 646 msg=msg
625 647 )
626 648 except Exception:
627 649 log.error(traceback.format_exc())
628 650 raise JSONRPCError(
629 651 'failed to add member to user group `%s`' % (
630 652 users_group.users_group_name
631 653 )
632 654 )
633 655
634 656 @HasPermissionAllDecorator('hg.admin')
635 657 def remove_user_from_users_group(self, apiuser, usersgroupid, userid):
636 658 """
637 659 Remove user from a group
638 660
639 661 :param apiuser:
640 662 :param usersgroupid:
641 663 :param userid:
642 664 """
643 665 user = get_user_or_error(userid)
644 666 users_group = get_users_group_or_error(usersgroupid)
645 667
646 668 try:
647 669 success = UserGroupModel().remove_user_from_group(users_group,
648 670 user)
649 671 msg = 'removed member `%s` from user group `%s`' % (
650 672 user.username, users_group.users_group_name
651 673 )
652 674 msg = msg if success else "User wasn't in group"
653 675 Session().commit()
654 676 return dict(success=success, msg=msg)
655 677 except Exception:
656 678 log.error(traceback.format_exc())
657 679 raise JSONRPCError(
658 680 'failed to remove member from user group `%s`' % (
659 681 users_group.users_group_name
660 682 )
661 683 )
662 684
663 685 def get_repo(self, apiuser, repoid):
664 686 """"
665 687 Get repository by name
666 688
667 689 :param apiuser:
668 690 :param repoid:
669 691 """
670 692 repo = get_repo_or_error(repoid)
671 693
672 694 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
673 695 # check if we have admin permission for this repo !
674 696 if not HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
675 697 repo_name=repo.repo_name):
676 698 raise JSONRPCError('repository `%s` does not exist' % (repoid))
677 699
678 700 members = []
679 701 followers = []
680 702 for user in repo.repo_to_perm:
681 703 perm = user.permission.permission_name
682 704 user = user.user
683 705 user_data = user.get_api_data()
684 706 user_data['type'] = "user"
685 707 user_data['permission'] = perm
686 708 members.append(user_data)
687 709
688 710 for users_group in repo.users_group_to_perm:
689 711 perm = users_group.permission.permission_name
690 712 users_group = users_group.users_group
691 713 users_group_data = users_group.get_api_data()
692 714 users_group_data['type'] = "users_group"
693 715 users_group_data['permission'] = perm
694 716 members.append(users_group_data)
695 717
696 718 for user in repo.followers:
697 719 followers.append(user.user.get_api_data())
698 720
699 721 data = repo.get_api_data()
700 722 data['members'] = members
701 723 data['followers'] = followers
702 724 return data
703 725
704 726 # permission check inside
705 727 def get_repos(self, apiuser):
706 728 """"
707 729 Get all repositories
708 730
709 731 :param apiuser:
710 732 """
711 733 result = []
712 734 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
713 735 repos = RepoModel().get_all_user_repos(user=apiuser)
714 736 else:
715 737 repos = RepoModel().get_all()
716 738
717 739 for repo in repos:
718 740 result.append(repo.get_api_data())
719 741 return result
720 742
721 743 @HasPermissionAllDecorator('hg.admin')
722 744 def get_repo_nodes(self, apiuser, repoid, revision, root_path,
723 745 ret_type='all'):
724 746 """
725 747 returns a list of nodes and it's children
726 748 for a given path at given revision. It's possible to specify ret_type
727 749 to show only files or dirs
728 750
729 751 :param apiuser:
730 752 :param repoid: name or id of repository
731 753 :param revision: revision for which listing should be done
732 754 :param root_path: path from which start displaying
733 755 :param ret_type: return type 'all|files|dirs' nodes
734 756 """
735 757 repo = get_repo_or_error(repoid)
736 758 try:
737 759 _d, _f = ScmModel().get_nodes(repo, revision, root_path,
738 760 flat=False)
739 761 _map = {
740 762 'all': _d + _f,
741 763 'files': _f,
742 764 'dirs': _d,
743 765 }
744 766 return _map[ret_type]
745 767 except KeyError:
746 768 raise JSONRPCError('ret_type must be one of %s' % _map.keys())
747 769 except Exception:
748 770 log.error(traceback.format_exc())
749 771 raise JSONRPCError(
750 772 'failed to get repo: `%s` nodes' % repo.repo_name
751 773 )
752 774
753 775 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
754 776 def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')),
755 777 repo_type=Optional('hg'),
756 778 description=Optional(''), private=Optional(False),
757 779 clone_uri=Optional(None), landing_rev=Optional('tip'),
758 780 enable_statistics=Optional(False),
759 781 enable_locking=Optional(False),
760 782 enable_downloads=Optional(False)):
761 783 """
762 784 Create repository, if clone_url is given it makes a remote clone
763 785 if repo_name is within a group name the groups will be created
764 786 automatically if they aren't present
765 787
766 788 :param apiuser:
767 789 :param repo_name:
768 790 :param onwer:
769 791 :param repo_type:
770 792 :param description:
771 793 :param private:
772 794 :param clone_uri:
773 795 :param landing_rev:
774 796 """
775 797 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
776 798 if not isinstance(owner, Optional):
777 799 #forbid setting owner for non-admins
778 800 raise JSONRPCError(
779 801 'Only RhodeCode admin can specify `owner` param'
780 802 )
781 803 if isinstance(owner, Optional):
782 804 owner = apiuser.user_id
783 805
784 806 owner = get_user_or_error(owner)
785 807
786 808 if RepoModel().get_by_repo_name(repo_name):
787 809 raise JSONRPCError("repo `%s` already exist" % repo_name)
788 810
789 811 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
790 812 if isinstance(private, Optional):
791 813 private = defs.get('repo_private') or Optional.extract(private)
792 814 if isinstance(repo_type, Optional):
793 815 repo_type = defs.get('repo_type')
794 816 if isinstance(enable_statistics, Optional):
795 817 enable_statistics = defs.get('repo_enable_statistics')
796 818 if isinstance(enable_locking, Optional):
797 819 enable_locking = defs.get('repo_enable_locking')
798 820 if isinstance(enable_downloads, Optional):
799 821 enable_downloads = defs.get('repo_enable_downloads')
800 822
801 823 clone_uri = Optional.extract(clone_uri)
802 824 description = Optional.extract(description)
803 825 landing_rev = Optional.extract(landing_rev)
804 826
805 827 try:
806 828 # create structure of groups and return the last group
807 829 group = map_groups(repo_name)
808 830
809 831 repo = RepoModel().create_repo(
810 832 repo_name=repo_name,
811 833 repo_type=repo_type,
812 834 description=description,
813 835 owner=owner,
814 836 private=private,
815 837 clone_uri=clone_uri,
816 838 repos_group=group,
817 839 landing_rev=landing_rev,
818 840 enable_statistics=enable_statistics,
819 841 enable_downloads=enable_downloads,
820 842 enable_locking=enable_locking
821 843 )
822 844
823 845 Session().commit()
824 846 return dict(
825 847 msg="Created new repository `%s`" % (repo.repo_name),
826 848 repo=repo.get_api_data()
827 849 )
828 850 except Exception:
829 851 log.error(traceback.format_exc())
830 852 raise JSONRPCError('failed to create repository `%s`' % repo_name)
831 853
854 # permission check inside
855 def update_repo(self, apiuser, repoid, name=Optional(None),
856 owner=Optional(OAttr('apiuser')),
857 group=Optional(None),
858 description=Optional(''), private=Optional(False),
859 clone_uri=Optional(None), landing_rev=Optional('tip'),
860 enable_statistics=Optional(False),
861 enable_locking=Optional(False),
862 enable_downloads=Optional(False)):
863
864 """
865 Updates repo
866
867 :param apiuser: filled automatically from apikey
868 :type apiuser: AuthUser
869 :param repoid: repository name or repository id
870 :type repoid: str or int
871 :param name:
872 :param owner:
873 :param group:
874 :param description:
875 :param private:
876 :param clone_uri:
877 :param landing_rev:
878 :param enable_statistics:
879 :param enable_locking:
880 :param enable_downloads:
881 """
882 repo = get_repo_or_error(repoid)
883 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
884 # check if we have admin permission for this repo !
885 if not HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
886 repo_name=repo.repo_name):
887 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
888
889 updates = {
890 # update function requires this.
891 'repo_name': repo.repo_name
892 }
893 repo_group = group
894 if not isinstance(repo_group, Optional):
895 repo_group = get_repo_group_or_error(repo_group)
896 repo_group = repo_group.group_id
897 try:
898 store_update(updates, name, 'repo_name')
899 store_update(updates, repo_group, 'repo_group')
900 store_update(updates, owner, 'user')
901 store_update(updates, description, 'repo_description')
902 store_update(updates, private, 'repo_private')
903 store_update(updates, clone_uri, 'clone_uri')
904 store_update(updates, landing_rev, 'repo_landing_rev')
905 store_update(updates, enable_statistics, 'repo_enable_statistics')
906 store_update(updates, enable_locking, 'repo_enable_locking')
907 store_update(updates, enable_downloads, 'repo_enable_downloads')
908
909 RepoModel().update(repo, **updates)
910 Session().commit()
911 return dict(
912 msg='updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
913 repository=repo.get_api_data()
914 )
915 except Exception:
916 log.error(traceback.format_exc())
917 raise JSONRPCError('failed to update repo `%s`' % repoid)
918
832 919 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
833 920 def fork_repo(self, apiuser, repoid, fork_name, owner=Optional(OAttr('apiuser')),
834 921 description=Optional(''), copy_permissions=Optional(False),
835 922 private=Optional(False), landing_rev=Optional('tip')):
836 923 repo = get_repo_or_error(repoid)
837 924 repo_name = repo.repo_name
838 925
839 926 _repo = RepoModel().get_by_repo_name(fork_name)
840 927 if _repo:
841 928 type_ = 'fork' if _repo.fork else 'repo'
842 929 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
843 930
844 931 if HasPermissionAnyApi('hg.admin')(user=apiuser):
845 932 pass
846 933 elif HasRepoPermissionAnyApi('repository.admin',
847 934 'repository.write',
848 935 'repository.read')(user=apiuser,
849 936 repo_name=repo.repo_name):
850 937 if not isinstance(owner, Optional):
851 938 #forbid setting owner for non-admins
852 939 raise JSONRPCError(
853 940 'Only RhodeCode admin can specify `owner` param'
854 941 )
855 942 else:
856 943 raise JSONRPCError('repository `%s` does not exist' % (repoid))
857 944
858 945 if isinstance(owner, Optional):
859 946 owner = apiuser.user_id
860 947
861 948 owner = get_user_or_error(owner)
862 949
863 950 try:
864 951 # create structure of groups and return the last group
865 952 group = map_groups(fork_name)
866 953
867 954 form_data = dict(
868 955 repo_name=fork_name,
869 956 repo_name_full=fork_name,
870 957 repo_group=group,
871 958 repo_type=repo.repo_type,
872 959 description=Optional.extract(description),
873 960 private=Optional.extract(private),
874 961 copy_permissions=Optional.extract(copy_permissions),
875 962 landing_rev=Optional.extract(landing_rev),
876 963 update_after_clone=False,
877 964 fork_parent_id=repo.repo_id,
878 965 )
879 966 RepoModel().create_fork(form_data, cur_user=owner)
880 967 return dict(
881 968 msg='Created fork of `%s` as `%s`' % (repo.repo_name,
882 969 fork_name),
883 970 success=True # cannot return the repo data here since fork
884 971 # cann be done async
885 972 )
886 973 except Exception:
887 974 log.error(traceback.format_exc())
888 975 raise JSONRPCError(
889 976 'failed to fork repository `%s` as `%s`' % (repo_name,
890 977 fork_name)
891 978 )
892 979
893 980 # perms handled inside
894 981 def delete_repo(self, apiuser, repoid, forks=Optional(None)):
895 982 """
896 983 Deletes a given repository
897 984
898 985 :param apiuser:
899 986 :param repoid:
900 987 :param forks: detach or delete, what do do with attached forks for repo
901 988 """
902 989 repo = get_repo_or_error(repoid)
903 990
904 991 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
905 992 # check if we have admin permission for this repo !
906 993 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
907 994 repo_name=repo.repo_name) is False:
908 995 raise JSONRPCError('repository `%s` does not exist' % (repoid))
909 996
910 997 try:
911 998 handle_forks = Optional.extract(forks)
912 999 _forks_msg = ''
913 1000 _forks = [f for f in repo.forks]
914 1001 if handle_forks == 'detach':
915 1002 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
916 1003 elif handle_forks == 'delete':
917 1004 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
918 1005 elif _forks:
919 1006 raise JSONRPCError(
920 1007 'Cannot delete `%s` it still contains attached forks'
921 1008 % repo.repo_name
922 1009 )
923 1010
924 1011 RepoModel().delete(repo, forks=forks)
925 1012 Session().commit()
926 1013 return dict(
927 1014 msg='Deleted repository `%s`%s' % (repo.repo_name, _forks_msg),
928 1015 success=True
929 1016 )
930 1017 except Exception:
931 1018 log.error(traceback.format_exc())
932 1019 raise JSONRPCError(
933 1020 'failed to delete repository `%s`' % repo.repo_name
934 1021 )
935 1022
936 1023 @HasPermissionAllDecorator('hg.admin')
937 1024 def grant_user_permission(self, apiuser, repoid, userid, perm):
938 1025 """
939 1026 Grant permission for user on given repository, or update existing one
940 1027 if found
941 1028
942 1029 :param repoid:
943 1030 :param userid:
944 1031 :param perm:
945 1032 """
946 1033 repo = get_repo_or_error(repoid)
947 1034 user = get_user_or_error(userid)
948 1035 perm = get_perm_or_error(perm)
949 1036
950 1037 try:
951 1038
952 1039 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
953 1040
954 1041 Session().commit()
955 1042 return dict(
956 1043 msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
957 1044 perm.permission_name, user.username, repo.repo_name
958 1045 ),
959 1046 success=True
960 1047 )
961 1048 except Exception:
962 1049 log.error(traceback.format_exc())
963 1050 raise JSONRPCError(
964 1051 'failed to edit permission for user: `%s` in repo: `%s`' % (
965 1052 userid, repoid
966 1053 )
967 1054 )
968 1055
969 1056 @HasPermissionAllDecorator('hg.admin')
970 1057 def revoke_user_permission(self, apiuser, repoid, userid):
971 1058 """
972 1059 Revoke permission for user on given repository
973 1060
974 1061 :param apiuser:
975 1062 :param repoid:
976 1063 :param userid:
977 1064 """
978 1065
979 1066 repo = get_repo_or_error(repoid)
980 1067 user = get_user_or_error(userid)
981 1068 try:
982 1069
983 1070 RepoModel().revoke_user_permission(repo=repo, user=user)
984 1071
985 1072 Session().commit()
986 1073 return dict(
987 1074 msg='Revoked perm for user: `%s` in repo: `%s`' % (
988 1075 user.username, repo.repo_name
989 1076 ),
990 1077 success=True
991 1078 )
992 1079 except Exception:
993 1080 log.error(traceback.format_exc())
994 1081 raise JSONRPCError(
995 1082 'failed to edit permission for user: `%s` in repo: `%s`' % (
996 1083 userid, repoid
997 1084 )
998 1085 )
999 1086
1000 1087 @HasPermissionAllDecorator('hg.admin')
1001 1088 def grant_users_group_permission(self, apiuser, repoid, usersgroupid,
1002 1089 perm):
1003 1090 """
1004 1091 Grant permission for user group on given repository, or update
1005 1092 existing one if found
1006 1093
1007 1094 :param apiuser:
1008 1095 :param repoid:
1009 1096 :param usersgroupid:
1010 1097 :param perm:
1011 1098 """
1012 1099 repo = get_repo_or_error(repoid)
1013 1100 perm = get_perm_or_error(perm)
1014 1101 users_group = get_users_group_or_error(usersgroupid)
1015 1102
1016 1103 try:
1017 1104 RepoModel().grant_users_group_permission(repo=repo,
1018 1105 group_name=users_group,
1019 1106 perm=perm)
1020 1107
1021 1108 Session().commit()
1022 1109 return dict(
1023 1110 msg='Granted perm: `%s` for user group: `%s` in '
1024 1111 'repo: `%s`' % (
1025 1112 perm.permission_name, users_group.users_group_name,
1026 1113 repo.repo_name
1027 1114 ),
1028 1115 success=True
1029 1116 )
1030 1117 except Exception:
1031 1118 log.error(traceback.format_exc())
1032 1119 raise JSONRPCError(
1033 1120 'failed to edit permission for user group: `%s` in '
1034 1121 'repo: `%s`' % (
1035 1122 usersgroupid, repo.repo_name
1036 1123 )
1037 1124 )
1038 1125
1039 1126 @HasPermissionAllDecorator('hg.admin')
1040 1127 def revoke_users_group_permission(self, apiuser, repoid, usersgroupid):
1041 1128 """
1042 1129 Revoke permission for user group on given repository
1043 1130
1044 1131 :param apiuser:
1045 1132 :param repoid:
1046 1133 :param usersgroupid:
1047 1134 """
1048 1135 repo = get_repo_or_error(repoid)
1049 1136 users_group = get_users_group_or_error(usersgroupid)
1050 1137
1051 1138 try:
1052 1139 RepoModel().revoke_users_group_permission(repo=repo,
1053 1140 group_name=users_group)
1054 1141
1055 1142 Session().commit()
1056 1143 return dict(
1057 1144 msg='Revoked perm for user group: `%s` in repo: `%s`' % (
1058 1145 users_group.users_group_name, repo.repo_name
1059 1146 ),
1060 1147 success=True
1061 1148 )
1062 1149 except Exception:
1063 1150 log.error(traceback.format_exc())
1064 1151 raise JSONRPCError(
1065 1152 'failed to edit permission for user group: `%s` in '
1066 1153 'repo: `%s`' % (
1067 1154 users_group.users_group_name, repo.repo_name
1068 1155 )
1069 1156 )
1070 1157
1071 1158 def create_gist(self, apiuser, files, owner=Optional(OAttr('apiuser')),
1072 1159 gist_type=Optional(Gist.GIST_PUBLIC), lifetime=Optional(-1),
1073 1160 description=Optional('')):
1074 1161
1075 1162 try:
1076 1163 if isinstance(owner, Optional):
1077 1164 owner = apiuser.user_id
1078 1165
1079 1166 owner = get_user_or_error(owner)
1080 1167 description = Optional.extract(description)
1081 1168 gist_type = Optional.extract(gist_type)
1082 1169 lifetime = Optional.extract(lifetime)
1083 1170
1084 1171 # files: {
1085 1172 # 'filename': {'content':'...', 'lexer': null},
1086 1173 # 'filename2': {'content':'...', 'lexer': null}
1087 1174 #}
1088 1175 gist = GistModel().create(description=description,
1089 1176 owner=owner,
1090 1177 gist_mapping=files,
1091 1178 gist_type=gist_type,
1092 1179 lifetime=lifetime)
1093 1180 Session().commit()
1094 1181 return dict(
1095 1182 msg='created new gist',
1096 1183 gist=gist.get_api_data()
1097 1184 )
1098 1185 except Exception:
1099 1186 log.error(traceback.format_exc())
1100 1187 raise JSONRPCError('failed to create gist')
General Comments 0
You need to be logged in to leave comments. Login now