comparison rhodecode/controllers/api/api.py @ 4116:ffd45b185016 rhodecode-2.2.5-gpl

Imported some of the GPLv3'd changes from RhodeCode v2.2.5. This imports changes between changesets 21af6c4eab3d and 6177597791c2 in RhodeCode's original repository, including only changes to Python files and HTML. RhodeCode clearly licensed its changes to these files under GPLv3 in their /LICENSE file, which states the following: The Python code and integrated HTML are licensed under the GPLv3 license. (See: https://code.rhodecode.com/rhodecode/files/v2.2.5/LICENSE or http://web.archive.org/web/20140512193334/https://code.rhodecode.com/rhodecode/files/f3b123159901f15426d18e3dc395e8369f70ebe0/LICENSE for an online copy of that LICENSE file) Conservancy reviewed these changes and confirmed that they can be licensed as a whole to the Kallithea project under GPLv3-only. While some of the contents committed herein are clearly licensed GPLv3-or-later, on the whole we must assume the are GPLv3-only, since the statement above from RhodeCode indicates that they intend GPLv3-only as their license, per GPLv3ยง14 and other relevant sections of GPLv3.
author Bradley M. Kuhn <bkuhn@sfconservancy.org>
date Wed, 02 Jul 2014 19:03:13 -0400
parents 5293d4bbb1ea
children 7e5f8c12a3fc
comparison
equal deleted inserted replaced
4115:8b7294a804a0 4116:ffd45b185016
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 """ 2 # This program is free software: you can redistribute it and/or modify
3 rhodecode.controllers.api 3 # it under the terms of the GNU General Public License as published by
4 ~~~~~~~~~~~~~~~~~~~~~~~~~ 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 API controller for RhodeCode
7
8 :created_on: Aug 20, 2011
9 :author: marcink
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
17 # 6 #
18 # This program is distributed in the hope that it will be useful, 7 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details. 10 # GNU General Public License for more details.
22 # 11 #
23 # You should have received a copy of the GNU General Public License 12 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 14 """
26 # MA 02110-1301, USA. 15 rhodecode.controllers.api
16 ~~~~~~~~~~~~~~~~~~~~~~~~~
17
18 API controller for RhodeCode
19
20 :created_on: Aug 20, 2011
21 :author: marcink
22 :copyright: (c) 2013 RhodeCode GmbH.
23 :license: GPLv3, see LICENSE for more details.
24 """
25
27 26
28 import time 27 import time
29 import traceback 28 import traceback
30 import logging 29 import logging
30 from sqlalchemy import or_
31 31
32 from rhodecode.controllers.api import JSONRPCController, JSONRPCError 32 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
33 from rhodecode.lib.auth import PasswordGenerator, AuthUser, \ 33 from rhodecode.lib.auth import (
34 HasPermissionAllDecorator, HasPermissionAnyDecorator, \ 34 PasswordGenerator, AuthUser, HasPermissionAllDecorator,
35 HasPermissionAnyApi, HasRepoPermissionAnyApi 35 HasPermissionAnyDecorator, HasPermissionAnyApi, HasRepoPermissionAnyApi,
36 HasRepoGroupPermissionAnyApi, HasUserGroupPermissionAny)
36 from rhodecode.lib.utils import map_groups, repo2db_mapper 37 from rhodecode.lib.utils import map_groups, repo2db_mapper
37 from rhodecode.lib.utils2 import str2bool, time_to_datetime, safe_int 38 from rhodecode.lib.utils2 import (
39 str2bool, time_to_datetime, safe_int, Optional, OAttr)
38 from rhodecode.model.meta import Session 40 from rhodecode.model.meta import Session
39 from rhodecode.model.scm import ScmModel 41 from rhodecode.model.repo_group import RepoGroupModel
42 from rhodecode.model.scm import ScmModel, UserGroupList
40 from rhodecode.model.repo import RepoModel 43 from rhodecode.model.repo import RepoModel
41 from rhodecode.model.user import UserModel 44 from rhodecode.model.user import UserModel
42 from rhodecode.model.users_group import UserGroupModel 45 from rhodecode.model.user_group import UserGroupModel
43 from rhodecode.model.repos_group import ReposGroupModel 46 from rhodecode.model.gist import GistModel
44 from rhodecode.model.db import Repository, RhodeCodeSetting, UserIpMap,\ 47 from rhodecode.model.db import (
45 Permission, User, Gist 48 Repository, RhodeCodeSetting, UserIpMap, Permission, User, Gist,
49 RepoGroup)
46 from rhodecode.lib.compat import json 50 from rhodecode.lib.compat import json
47 from rhodecode.lib.exceptions import DefaultUserException 51 from rhodecode.lib.exceptions import (
48 from rhodecode.model.gist import GistModel 52 DefaultUserException, UserGroupsAssignedException)
49 53
50 log = logging.getLogger(__name__) 54 log = logging.getLogger(__name__)
51 55
52 56
53 def store_update(updates, attr, name): 57 def store_update(updates, attr, name):
57 """ 61 """
58 if not isinstance(attr, Optional): 62 if not isinstance(attr, Optional):
59 updates[name] = attr 63 updates[name] = attr
60 64
61 65
62 class OptionalAttr(object):
63 """
64 Special Optional Option that defines other attribute
65 """
66 def __init__(self, attr_name):
67 self.attr_name = attr_name
68
69 def __repr__(self):
70 return '<OptionalAttr:%s>' % self.attr_name
71
72 def __call__(self):
73 return self
74 #alias
75 OAttr = OptionalAttr
76
77
78 class Optional(object):
79 """
80 Defines an optional parameter::
81
82 param = param.getval() if isinstance(param, Optional) else param
83 param = param() if isinstance(param, Optional) else param
84
85 is equivalent of::
86
87 param = Optional.extract(param)
88
89 """
90 def __init__(self, type_):
91 self.type_ = type_
92
93 def __repr__(self):
94 return '<Optional:%s>' % self.type_.__repr__()
95
96 def __call__(self):
97 return self.getval()
98
99 def getval(self):
100 """
101 returns value from this Optional instance
102 """
103 return self.type_
104
105 @classmethod
106 def extract(cls, val):
107 if isinstance(val, cls):
108 return val.getval()
109 return val
110
111
112 def get_user_or_error(userid): 66 def get_user_or_error(userid):
113 """ 67 """
114 Get user by id or name or return JsonRPCError if not found 68 Get user by id or name or return JsonRPCError if not found
115 69
116 :param userid: 70 :param userid:
117 """ 71 """
118 user = UserModel().get_user(userid) 72 user = UserModel().get_user(userid)
119 if user is None: 73 if user is None:
120 raise JSONRPCError("user `%s` does not exist" % userid) 74 raise JSONRPCError("user `%s` does not exist" % (userid,))
121 return user 75 return user
122 76
123 77
124 def get_repo_or_error(repoid): 78 def get_repo_or_error(repoid):
125 """ 79 """
127 81
128 :param repoid: 82 :param repoid:
129 """ 83 """
130 repo = RepoModel().get_repo(repoid) 84 repo = RepoModel().get_repo(repoid)
131 if repo is None: 85 if repo is None:
132 raise JSONRPCError('repository `%s` does not exist' % (repoid)) 86 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
133 return repo 87 return repo
134 88
135 89
136 def get_repo_group_or_error(repogroupid): 90 def get_repo_group_or_error(repogroupid):
137 """ 91 """
138 Get repo group by id or name or return JsonRPCError if not found 92 Get repo group by id or name or return JsonRPCError if not found
139 93
140 :param repogroupid: 94 :param repogroupid:
141 """ 95 """
142 repo_group = ReposGroupModel()._get_repo_group(repogroupid) 96 repo_group = RepoGroupModel()._get_repo_group(repogroupid)
143 if repo_group is None: 97 if repo_group is None:
144 raise JSONRPCError( 98 raise JSONRPCError(
145 'repository group `%s` does not exist' % (repogroupid,)) 99 'repository group `%s` does not exist' % (repogroupid,))
146 return repo_group 100 return repo_group
147 101
148 102
149 def get_users_group_or_error(usersgroupid): 103 def get_user_group_or_error(usergroupid):
150 """ 104 """
151 Get user group by id or name or return JsonRPCError if not found 105 Get user group by id or name or return JsonRPCError if not found
152 106
153 :param userid: 107 :param usergroupid:
154 """ 108 """
155 users_group = UserGroupModel().get_group(usersgroupid) 109 user_group = UserGroupModel().get_group(usergroupid)
156 if users_group is None: 110 if user_group is None:
157 raise JSONRPCError('user group `%s` does not exist' % usersgroupid) 111 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
158 return users_group 112 return user_group
159 113
160 114
161 def get_perm_or_error(permid): 115 def get_perm_or_error(permid, prefix=None):
162 """ 116 """
163 Get permission by id or name or return JsonRPCError if not found 117 Get permission by id or name or return JsonRPCError if not found
164 118
165 :param userid: 119 :param permid:
166 """ 120 """
167 perm = Permission.get_by_key(permid) 121 perm = Permission.get_by_key(permid)
168 if perm is None: 122 if perm is None:
169 raise JSONRPCError('permission `%s` does not exist' % (permid)) 123 raise JSONRPCError('permission `%s` does not exist' % (permid,))
124 if prefix:
125 if not perm.permission_name.startswith(prefix):
126 raise JSONRPCError('permission `%s` is invalid, '
127 'should start with %s' % (permid, prefix))
170 return perm 128 return perm
129
130
131 def get_gist_or_error(gistid):
132 """
133 Get gist by id or gist_access_id or return JsonRPCError if not found
134
135 :param gistid:
136 """
137 gist = GistModel().get_gist(gistid)
138 if gist is None:
139 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
140 return gist
171 141
172 142
173 class ApiController(JSONRPCController): 143 class ApiController(JSONRPCController):
174 """ 144 """
175 API Controller 145 API Controller
176 146
177 147 Each method takes USER as first argument. This is then, based on given
178 Each method needs to have USER as argument this is then based on given 148 API_KEY propagated as instance of user object who's making the call.
179 API_KEY propagated as instance of user object 149
180 150 example function::
181 Preferably this should be first argument also 151
182 152 def func(apiuser,arg1, arg2,...):
153 pass
183 154
184 Each function should also **raise** JSONRPCError for any 155 Each function should also **raise** JSONRPCError for any
185 errors that happens 156 errors that happens.
186 157
187 """ 158 """
159
160 @HasPermissionAllDecorator('hg.admin')
161 def test(self, apiuser, args):
162 return args
188 163
189 @HasPermissionAllDecorator('hg.admin') 164 @HasPermissionAllDecorator('hg.admin')
190 def pull(self, apiuser, repoid): 165 def pull(self, apiuser, repoid):
191 """ 166 """
192 Dispatch pull action on given repo 167 Triggers a pull from remote location on given repo. Can be used to
193 168 automatically keep remote repos up to date. This command can be executed
194 :param apiuser: 169 only using api_key belonging to user with admin rights
195 :param repoid: 170
171 :param apiuser: filled automatically from apikey
172 :type apiuser: AuthUser
173 :param repoid: repository name or repository id
174 :type repoid: str or int
175
176 OUTPUT::
177
178 id : <id_given_in_input>
179 result : {
180 "msg": "Pulled from `<repository name>`"
181 "repository": "<repository name>"
182 }
183 error : null
184
185 ERROR OUTPUT::
186
187 id : <id_given_in_input>
188 result : null
189 error : {
190 "Unable to pull changes from `<reponame>`"
191 }
192
196 """ 193 """
197 194
198 repo = get_repo_or_error(repoid) 195 repo = get_repo_or_error(repoid)
199 196
200 try: 197 try:
201 ScmModel().pull_changes(repo.repo_name, 198 ScmModel().pull_changes(repo.repo_name,
202 self.rhodecode_user.username) 199 self.rhodecode_user.username)
203 return 'Pulled from `%s`' % repo.repo_name 200 return dict(
201 msg='Pulled from `%s`' % repo.repo_name,
202 repository=repo.repo_name
203 )
204 except Exception: 204 except Exception:
205 log.error(traceback.format_exc()) 205 log.error(traceback.format_exc())
206 raise JSONRPCError( 206 raise JSONRPCError(
207 'Unable to pull changes from `%s`' % repo.repo_name 207 'Unable to pull changes from `%s`' % repo.repo_name
208 ) 208 )
209 209
210 @HasPermissionAllDecorator('hg.admin') 210 @HasPermissionAllDecorator('hg.admin')
211 def rescan_repos(self, apiuser, remove_obsolete=Optional(False)): 211 def rescan_repos(self, apiuser, remove_obsolete=Optional(False)):
212 """ 212 """
213 Dispatch rescan repositories action. If remove_obsolete is set 213 Triggers rescan repositories action. If remove_obsolete is set
214 than also delete repos that are in database but not in the filesystem. 214 than also delete repos that are in database but not in the filesystem.
215 aka "clean zombies" 215 aka "clean zombies". This command can be executed only using api_key
216 216 belonging to user with admin rights.
217 :param apiuser: 217
218 :param remove_obsolete: 218 :param apiuser: filled automatically from apikey
219 :type apiuser: AuthUser
220 :param remove_obsolete: deletes repositories from
221 database that are not found on the filesystem
222 :type remove_obsolete: Optional(bool)
223
224 OUTPUT::
225
226 id : <id_given_in_input>
227 result : {
228 'added': [<added repository name>,...]
229 'removed': [<removed repository name>,...]
230 }
231 error : null
232
233 ERROR OUTPUT::
234
235 id : <id_given_in_input>
236 result : null
237 error : {
238 'Error occurred during rescan repositories action'
239 }
240
219 """ 241 """
220 242
221 try: 243 try:
222 rm_obsolete = Optional.extract(remove_obsolete) 244 rm_obsolete = Optional.extract(remove_obsolete)
223 added, removed = repo2db_mapper(ScmModel().repo_scan(), 245 added, removed = repo2db_mapper(ScmModel().repo_scan(),
229 'Error occurred during rescan repositories action' 251 'Error occurred during rescan repositories action'
230 ) 252 )
231 253
232 def invalidate_cache(self, apiuser, repoid): 254 def invalidate_cache(self, apiuser, repoid):
233 """ 255 """
234 Dispatch cache invalidation action on given repo 256 Invalidate cache for repository.
235 257 This command can be executed only using api_key belonging to user with admin
236 :param apiuser: 258 rights or regular user that have write or admin or write access to repository.
237 :param repoid: 259
260 :param apiuser: filled automatically from apikey
261 :type apiuser: AuthUser
262 :param repoid: repository name or repository id
263 :type repoid: str or int
264
265 OUTPUT::
266
267 id : <id_given_in_input>
268 result : {
269 'msg': Cache for repository `<repository name>` was invalidated,
270 'repository': <repository name>
271 }
272 error : null
273
274 ERROR OUTPUT::
275
276 id : <id_given_in_input>
277 result : null
278 error : {
279 'Error occurred during cache invalidation action'
280 }
281
238 """ 282 """
239 repo = get_repo_or_error(repoid) 283 repo = get_repo_or_error(repoid)
240 if not HasPermissionAnyApi('hg.admin')(user=apiuser): 284 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
241 # check if we have admin permission for this repo ! 285 # check if we have admin permission for this repo !
242 if HasRepoPermissionAnyApi('repository.admin', 286 if not HasRepoPermissionAnyApi('repository.admin',
243 'repository.write')(user=apiuser, 287 'repository.write')(
244 repo_name=repo.repo_name) is False: 288 user=apiuser, repo_name=repo.repo_name):
245 raise JSONRPCError('repository `%s` does not exist' % (repoid)) 289 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
246 290
247 try: 291 try:
248 ScmModel().mark_for_invalidation(repo.repo_name) 292 ScmModel().mark_for_invalidation(repo.repo_name)
249 return ('Caches of repository `%s` was invalidated' % repoid) 293 return dict(
294 msg='Cache for repository `%s` was invalidated' % (repoid,),
295 repository=repo.repo_name
296 )
250 except Exception: 297 except Exception:
251 log.error(traceback.format_exc()) 298 log.error(traceback.format_exc())
252 raise JSONRPCError( 299 raise JSONRPCError(
253 'Error occurred during cache invalidation action' 300 'Error occurred during cache invalidation action'
254 ) 301 )
255 302
256 # permission check inside 303 # permission check inside
257 def lock(self, apiuser, repoid, locked=Optional(None), 304 def lock(self, apiuser, repoid, locked=Optional(None),
258 userid=Optional(OAttr('apiuser'))): 305 userid=Optional(OAttr('apiuser'))):
259 """ 306 """
260 Set locking state on particular repository by given user, if 307 Set locking state on given repository by given user. If userid param
261 this command is runned by non-admin account userid is set to user 308 is skipped, then it is set to id of user whos calling this method.
262 who is calling this method 309 If locked param is skipped then function shows current lock state of
263 310 given repo. This command can be executed only using api_key belonging
264 :param apiuser: 311 to user with admin rights or regular user that have admin or write
265 :param repoid: 312 access to repository.
266 :param userid: 313
267 :param locked: 314 :param apiuser: filled automatically from apikey
315 :type apiuser: AuthUser
316 :param repoid: repository name or repository id
317 :type repoid: str or int
318 :param locked: lock state to be set
319 :type locked: Optional(bool)
320 :param userid: set lock as user
321 :type userid: Optional(str or int)
322
323 OUTPUT::
324
325 id : <id_given_in_input>
326 result : {
327 'repo': '<reponame>',
328 'locked': <bool: lock state>,
329 'locked_since': <int: lock timestamp>,
330 'locked_by': <username of person who made the lock>,
331 'lock_state_changed': <bool: True if lock state has been changed in this request>,
332 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
333 or
334 'msg': 'Repo `<repository name>` not locked.'
335 or
336 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
337 }
338 error : null
339
340 ERROR OUTPUT::
341
342 id : <id_given_in_input>
343 result : null
344 error : {
345 'Error occurred locking repository `<reponame>`
346 }
347
268 """ 348 """
269 repo = get_repo_or_error(repoid) 349 repo = get_repo_or_error(repoid)
270 if HasPermissionAnyApi('hg.admin')(user=apiuser): 350 if HasPermissionAnyApi('hg.admin')(user=apiuser):
271 pass 351 pass
272 elif HasRepoPermissionAnyApi('repository.admin', 352 elif HasRepoPermissionAnyApi('repository.admin',
273 'repository.write')(user=apiuser, 353 'repository.write')(user=apiuser,
274 repo_name=repo.repo_name): 354 repo_name=repo.repo_name):
275 #make sure normal user does not pass someone else userid, 355 # make sure normal user does not pass someone else userid,
276 #he is not allowed to do that 356 # he is not allowed to do that
277 if not isinstance(userid, Optional) and userid != apiuser.user_id: 357 if not isinstance(userid, Optional) and userid != apiuser.user_id:
278 raise JSONRPCError( 358 raise JSONRPCError(
279 'userid is not the same as your user' 359 'userid is not the same as your user'
280 ) 360 )
281 else: 361 else:
282 raise JSONRPCError('repository `%s` does not exist' % (repoid)) 362 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
283 363
284 if isinstance(userid, Optional): 364 if isinstance(userid, Optional):
285 userid = apiuser.user_id 365 userid = apiuser.user_id
286 366
287 user = get_user_or_error(userid) 367 user = get_user_or_error(userid)
293 _d = { 373 _d = {
294 'repo': repo.repo_name, 374 'repo': repo.repo_name,
295 'locked': False, 375 'locked': False,
296 'locked_since': None, 376 'locked_since': None,
297 'locked_by': None, 377 'locked_by': None,
378 'lock_state_changed': False,
298 'msg': 'Repo `%s` not locked.' % repo.repo_name 379 'msg': 'Repo `%s` not locked.' % repo.repo_name
299 } 380 }
300 return _d 381 return _d
301 else: 382 else:
302 userid, time_ = lockobj 383 userid, time_ = lockobj
304 _d = { 385 _d = {
305 'repo': repo.repo_name, 386 'repo': repo.repo_name,
306 'locked': True, 387 'locked': True,
307 'locked_since': time_, 388 'locked_since': time_,
308 'locked_by': lock_user.username, 389 'locked_by': lock_user.username,
309 'msg': ('Repo `%s` locked by `%s`. ' 390 'lock_state_changed': False,
310 % (repo.repo_name, 391 'msg': ('Repo `%s` locked by `%s` on `%s`.'
392 % (repo.repo_name, lock_user.username,
311 json.dumps(time_to_datetime(time_)))) 393 json.dumps(time_to_datetime(time_))))
312 } 394 }
313 return _d 395 return _d
314 396
315 # force locked state through a flag 397 # force locked state through a flag
325 _d = { 407 _d = {
326 'repo': repo.repo_name, 408 'repo': repo.repo_name,
327 'locked': locked, 409 'locked': locked,
328 'locked_since': lock_time, 410 'locked_since': lock_time,
329 'locked_by': user.username, 411 'locked_by': user.username,
412 'lock_state_changed': True,
330 'msg': ('User `%s` set lock state for repo `%s` to `%s`' 413 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
331 % (user.username, repo.repo_name, locked)) 414 % (user.username, repo.repo_name, locked))
332 } 415 }
333 return _d 416 return _d
334 except Exception: 417 except Exception:
337 'Error occurred locking repository `%s`' % repo.repo_name 420 'Error occurred locking repository `%s`' % repo.repo_name
338 ) 421 )
339 422
340 def get_locks(self, apiuser, userid=Optional(OAttr('apiuser'))): 423 def get_locks(self, apiuser, userid=Optional(OAttr('apiuser'))):
341 """ 424 """
342 Get all locks for given userid, if 425 Get all repositories with locks for given userid, if
343 this command is runned by non-admin account userid is set to user 426 this command is runned by non-admin account userid is set to user
344 who is calling this method, thus returning locks for himself 427 who is calling this method, thus returning locks for himself.
345 428
346 :param apiuser: 429 :param apiuser: filled automatically from apikey
347 :param userid: 430 :type apiuser: AuthUser
431 :param userid: User to get locks for
432 :type userid: Optional(str or int)
433
434 OUTPUT::
435
436 id : <id_given_in_input>
437 result : {
438 [repo_object, repo_object,...]
439 }
440 error : null
348 """ 441 """
349 442
350 if not HasPermissionAnyApi('hg.admin')(user=apiuser): 443 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
351 #make sure normal user does not pass someone else userid, 444 # make sure normal user does not pass someone else userid,
352 #he is not allowed to do that 445 # he is not allowed to do that
353 if not isinstance(userid, Optional) and userid != apiuser.user_id: 446 if not isinstance(userid, Optional) and userid != apiuser.user_id:
354 raise JSONRPCError( 447 raise JSONRPCError(
355 'userid is not the same as your user' 448 'userid is not the same as your user'
356 ) 449 )
450
357 ret = [] 451 ret = []
358 if isinstance(userid, Optional): 452 if isinstance(userid, Optional):
359 user = None 453 user = None
360 else: 454 else:
361 user = get_user_or_error(userid) 455 user = get_user_or_error(userid)
362 456
363 #show all locks 457 # show all locks
364 for r in Repository.getAll(): 458 for r in Repository.getAll():
365 userid, time_ = r.locked 459 userid, time_ = r.locked
366 if time_: 460 if time_:
367 _api_data = r.get_api_data() 461 _api_data = r.get_api_data()
368 # if we use userfilter just show the locks for this user 462 # if we use userfilter just show the locks for this user
373 ret.append(_api_data) 467 ret.append(_api_data)
374 468
375 return ret 469 return ret
376 470
377 @HasPermissionAllDecorator('hg.admin') 471 @HasPermissionAllDecorator('hg.admin')
378 def show_ip(self, apiuser, userid): 472 def get_ip(self, apiuser, userid=Optional(OAttr('apiuser'))):
379 """ 473 """
380 Shows IP address as seen from RhodeCode server, together with all 474 Shows IP address as seen from RhodeCode server, together with all
381 defined IP addresses for given user 475 defined IP addresses for given user. If userid is not passed data is
382 476 returned for user who's calling this function.
383 :param apiuser: 477 This command can be executed only using api_key belonging to user with
384 :param userid: 478 admin rights.
385 """ 479
480 :param apiuser: filled automatically from apikey
481 :type apiuser: AuthUser
482 :param userid: username to show ips for
483 :type userid: Optional(str or int)
484
485 OUTPUT::
486
487 id : <id_given_in_input>
488 result : {
489 "server_ip_addr": "<ip_from_clien>",
490 "user_ips": [
491 {
492 "ip_addr": "<ip_with_mask>",
493 "ip_range": ["<start_ip>", "<end_ip>"],
494 },
495 ...
496 ]
497 }
498
499 """
500 if isinstance(userid, Optional):
501 userid = apiuser.user_id
386 user = get_user_or_error(userid) 502 user = get_user_or_error(userid)
387 ips = UserIpMap.query().filter(UserIpMap.user == user).all() 503 ips = UserIpMap.query().filter(UserIpMap.user == user).all()
388 return dict( 504 return dict(
389 ip_addr_server=self.ip_addr, 505 server_ip_addr=self.ip_addr,
390 user_ips=ips 506 user_ips=ips
391 ) 507 )
392 508
509 # alias for old
510 show_ip = get_ip
511
512 @HasPermissionAllDecorator('hg.admin')
513 def get_server_info(self, apiuser):
514 """
515 return server info, including RhodeCode version and installed packages
516
517 :param apiuser: filled automatically from apikey
518 :type apiuser: AuthUser
519
520 OUTPUT::
521
522 id : <id_given_in_input>
523 result : {
524 'modules': [<module name>,...]
525 'py_version': <python version>,
526 'platform': <platform type>,
527 'rhodecode_version': <rhodecode version>
528 }
529 error : null
530 """
531 return RhodeCodeSetting.get_server_info()
532
393 def get_user(self, apiuser, userid=Optional(OAttr('apiuser'))): 533 def get_user(self, apiuser, userid=Optional(OAttr('apiuser'))):
394 """" 534 """
395 Get a user by username, or userid, if userid is given 535 Get's an user by username or user_id, Returns empty result if user is
396 536 not found. If userid param is skipped it is set to id of user who is
397 :param apiuser: 537 calling this method. This command can be executed only using api_key
398 :param userid: 538 belonging to user with admin rights, or regular users that cannot
539 specify different userid than theirs
540
541 :param apiuser: filled automatically from apikey
542 :type apiuser: AuthUser
543 :param userid: user to get data for
544 :type userid: Optional(str or int)
545
546 OUTPUT::
547
548 id : <id_given_in_input>
549 result: None if user does not exist or
550 {
551 "user_id" : "<user_id>",
552 "api_key" : "<api_key>",
553 "api_keys": "[<list of all api keys including additional ones>]"
554 "username" : "<username>",
555 "firstname": "<firstname>",
556 "lastname" : "<lastname>",
557 "email" : "<email>",
558 "emails": "[<list of all emails including additional ones>]",
559 "ip_addresses": "[<ip_addresse_for_user>,...]",
560 "active" : "<bool: user active>",
561 "admin" :ย  "<bool: user is admin>",
562 "extern_name" : "<extern_name>",
563 "extern_type" : "<extern type>
564 "last_login": "<last_login>",
565 "permissions": {
566 "global": ["hg.create.repository",
567 "repository.read",
568 "hg.register.manual_activate"],
569 "repositories": {"repo1": "repository.none"},
570 "repositories_groups": {"Group1": "group.read"}
571 },
572 }
573
574 error: null
575
399 """ 576 """
400 if not HasPermissionAnyApi('hg.admin')(user=apiuser): 577 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
401 #make sure normal user does not pass someone else userid, 578 # make sure normal user does not pass someone else userid,
402 #he is not allowed to do that 579 # he is not allowed to do that
403 if not isinstance(userid, Optional) and userid != apiuser.user_id: 580 if not isinstance(userid, Optional) and userid != apiuser.user_id:
404 raise JSONRPCError( 581 raise JSONRPCError(
405 'userid is not the same as your user' 582 'userid is not the same as your user'
406 ) 583 )
407 584
413 data['permissions'] = AuthUser(user_id=user.user_id).permissions 590 data['permissions'] = AuthUser(user_id=user.user_id).permissions
414 return data 591 return data
415 592
416 @HasPermissionAllDecorator('hg.admin') 593 @HasPermissionAllDecorator('hg.admin')
417 def get_users(self, apiuser): 594 def get_users(self, apiuser):
418 """" 595 """
419 Get all users 596 Lists all existing users. This command can be executed only using api_key
420 597 belonging to user with admin rights.
421 :param apiuser: 598
599 :param apiuser: filled automatically from apikey
600 :type apiuser: AuthUser
601
602 OUTPUT::
603
604 id : <id_given_in_input>
605 result: [<user_object>, ...]
606 error: null
422 """ 607 """
423 608
424 result = [] 609 result = []
425 users_list = User.query().order_by(User.username)\ 610 users_list = User.query().order_by(User.username) \
426 .filter(User.username != User.DEFAULT_USER)\ 611 .filter(User.username != User.DEFAULT_USER) \
427 .all() 612 .all()
428 for user in users_list: 613 for user in users_list:
429 result.append(user.get_api_data()) 614 result.append(user.get_api_data())
430 return result 615 return result
431 616
432 @HasPermissionAllDecorator('hg.admin') 617 @HasPermissionAllDecorator('hg.admin')
433 def create_user(self, apiuser, username, email, password=Optional(None), 618 def create_user(self, apiuser, username, email, password=Optional(''),
434 firstname=Optional(None), lastname=Optional(None), 619 firstname=Optional(''), lastname=Optional(''),
435 active=Optional(True), admin=Optional(False), 620 active=Optional(True), admin=Optional(False),
436 ldap_dn=Optional(None)): 621 extern_name=Optional('rhodecode'),
437 """ 622 extern_type=Optional('rhodecode')):
438 Create new user 623 """
439 624 Creates new user. Returns new user object. This command can
440 :param apiuser: 625 be executed only using api_key belonging to user with admin rights.
441 :param username: 626
442 :param email: 627 :param apiuser: filled automatically from apikey
443 :param password: 628 :type apiuser: AuthUser
444 :param firstname: 629 :param username: new username
445 :param lastname: 630 :type username: str or int
446 :param active: 631 :param email: email
447 :param admin: 632 :type email: str
448 :param ldap_dn: 633 :param password: password
634 :type password: Optional(str)
635 :param firstname: firstname
636 :type firstname: Optional(str)
637 :param lastname: lastname
638 :type lastname: Optional(str)
639 :param active: active
640 :type active: Optional(bool)
641 :param admin: admin
642 :type admin: Optional(bool)
643 :param extern_name: name of extern
644 :type extern_name: Optional(str)
645 :param extern_type: extern_type
646 :type extern_type: Optional(str)
647
648
649 OUTPUT::
650
651 id : <id_given_in_input>
652 result: {
653 "msg" : "created new user `<username>`",
654 "user": <user_obj>
655 }
656 error: null
657
658 ERROR OUTPUT::
659
660 id : <id_given_in_input>
661 result : null
662 error : {
663 "user `<username>` already exist"
664 or
665 "email `<email>` already exist"
666 or
667 "failed to create user `<username>`"
668 }
669
449 """ 670 """
450 671
451 if UserModel().get_by_username(username): 672 if UserModel().get_by_username(username):
452 raise JSONRPCError("user `%s` already exist" % username) 673 raise JSONRPCError("user `%s` already exist" % (username,))
453 674
454 if UserModel().get_by_email(email, case_insensitive=True): 675 if UserModel().get_by_email(email, case_insensitive=True):
455 raise JSONRPCError("email `%s` already exist" % email) 676 raise JSONRPCError("email `%s` already exist" % (email,))
456 677
457 if Optional.extract(ldap_dn): 678 if Optional.extract(extern_name):
458 # generate temporary password if ldap_dn 679 # generate temporary password if user is external
459 password = PasswordGenerator().gen_password(length=8) 680 password = PasswordGenerator().gen_password(length=8)
460 681
461 try: 682 try:
462 user = UserModel().create_or_update( 683 user = UserModel().create_or_update(
463 username=Optional.extract(username), 684 username=Optional.extract(username),
465 email=Optional.extract(email), 686 email=Optional.extract(email),
466 firstname=Optional.extract(firstname), 687 firstname=Optional.extract(firstname),
467 lastname=Optional.extract(lastname), 688 lastname=Optional.extract(lastname),
468 active=Optional.extract(active), 689 active=Optional.extract(active),
469 admin=Optional.extract(admin), 690 admin=Optional.extract(admin),
470 ldap_dn=Optional.extract(ldap_dn) 691 extern_type=Optional.extract(extern_type),
692 extern_name=Optional.extract(extern_name)
471 ) 693 )
472 Session().commit() 694 Session().commit()
473 return dict( 695 return dict(
474 msg='created new user `%s`' % username, 696 msg='created new user `%s`' % username,
475 user=user.get_api_data() 697 user=user.get_api_data()
476 ) 698 )
477 except Exception: 699 except Exception:
478 log.error(traceback.format_exc()) 700 log.error(traceback.format_exc())
479 raise JSONRPCError('failed to create user `%s`' % username) 701 raise JSONRPCError('failed to create user `%s`' % (username,))
480 702
481 @HasPermissionAllDecorator('hg.admin') 703 @HasPermissionAllDecorator('hg.admin')
482 def update_user(self, apiuser, userid, username=Optional(None), 704 def update_user(self, apiuser, userid, username=Optional(None),
483 email=Optional(None), firstname=Optional(None), 705 email=Optional(None),password=Optional(None),
484 lastname=Optional(None), active=Optional(None), 706 firstname=Optional(None), lastname=Optional(None),
485 admin=Optional(None), ldap_dn=Optional(None), 707 active=Optional(None), admin=Optional(None),
486 password=Optional(None)): 708 extern_type=Optional(None), extern_name=Optional(None),):
487 """ 709 """
488 Updates given user 710 updates given user if such user exists. This command can
489 711 be executed only using api_key belonging to user with admin rights.
490 :param apiuser: 712
491 :param userid: 713 :param apiuser: filled automatically from apikey
492 :param username: 714 :type apiuser: AuthUser
493 :param email: 715 :param userid: userid to update
494 :param firstname: 716 :type userid: str or int
495 :param lastname: 717 :param username: new username
496 :param active: 718 :type username: str or int
497 :param admin: 719 :param email: email
498 :param ldap_dn: 720 :type email: str
499 :param password: 721 :param password: password
722 :type password: Optional(str)
723 :param firstname: firstname
724 :type firstname: Optional(str)
725 :param lastname: lastname
726 :type lastname: Optional(str)
727 :param active: active
728 :type active: Optional(bool)
729 :param admin: admin
730 :type admin: Optional(bool)
731 :param extern_name:
732 :type extern_name: Optional(str)
733 :param extern_type:
734 :type extern_type: Optional(str)
735
736
737 OUTPUT::
738
739 id : <id_given_in_input>
740 result: {
741 "msg" : "updated user ID:<userid> <username>",
742 "user": <user_object>,
743 }
744 error: null
745
746 ERROR OUTPUT::
747
748 id : <id_given_in_input>
749 result : null
750 error : {
751 "failed to update user `<username>`"
752 }
753
500 """ 754 """
501 755
502 user = get_user_or_error(userid) 756 user = get_user_or_error(userid)
503 757
504 # call function and store only updated arguments 758 # only non optional arguments will be stored in updates
505 updates = {} 759 updates = {}
506 760
507 def store_update(attr, name): 761 try:
508 if not isinstance(attr, Optional): 762
509 updates[name] = attr 763 store_update(updates, username, 'username')
510 764 store_update(updates, password, 'password')
511 try: 765 store_update(updates, email, 'email')
512 766 store_update(updates, firstname, 'name')
513 store_update(username, 'username') 767 store_update(updates, lastname, 'lastname')
514 store_update(password, 'password') 768 store_update(updates, active, 'active')
515 store_update(email, 'email') 769 store_update(updates, admin, 'admin')
516 store_update(firstname, 'name') 770 store_update(updates, extern_name, 'extern_name')
517 store_update(lastname, 'lastname') 771 store_update(updates, extern_type, 'extern_type')
518 store_update(active, 'active')
519 store_update(admin, 'admin')
520 store_update(ldap_dn, 'ldap_dn')
521 772
522 user = UserModel().update_user(user, **updates) 773 user = UserModel().update_user(user, **updates)
523 Session().commit() 774 Session().commit()
524 return dict( 775 return dict(
525 msg='updated user ID:%s %s' % (user.user_id, user.username), 776 msg='updated user ID:%s %s' % (user.user_id, user.username),
528 except DefaultUserException: 779 except DefaultUserException:
529 log.error(traceback.format_exc()) 780 log.error(traceback.format_exc())
530 raise JSONRPCError('editing default user is forbidden') 781 raise JSONRPCError('editing default user is forbidden')
531 except Exception: 782 except Exception:
532 log.error(traceback.format_exc()) 783 log.error(traceback.format_exc())
533 raise JSONRPCError('failed to update user `%s`' % userid) 784 raise JSONRPCError('failed to update user `%s`' % (userid,))
534 785
535 @HasPermissionAllDecorator('hg.admin') 786 @HasPermissionAllDecorator('hg.admin')
536 def delete_user(self, apiuser, userid): 787 def delete_user(self, apiuser, userid):
537 """" 788 """
538 Deletes an user 789 deletes givenuser if such user exists. This command can
539 790 be executed only using api_key belonging to user with admin rights.
540 :param apiuser: 791
541 :param userid: 792 :param apiuser: filled automatically from apikey
793 :type apiuser: AuthUser
794 :param userid: user to delete
795 :type userid: str or int
796
797 OUTPUT::
798
799 id : <id_given_in_input>
800 result: {
801 "msg" : "deleted user ID:<userid> <username>",
802 "user": null
803 }
804 error: null
805
806 ERROR OUTPUT::
807
808 id : <id_given_in_input>
809 result : null
810 error : {
811 "failed to delete user ID:<userid> <username>"
812 }
813
542 """ 814 """
543 user = get_user_or_error(userid) 815 user = get_user_or_error(userid)
544 816
545 try: 817 try:
546 UserModel().delete(userid) 818 UserModel().delete(userid)
548 return dict( 820 return dict(
549 msg='deleted user ID:%s %s' % (user.user_id, user.username), 821 msg='deleted user ID:%s %s' % (user.user_id, user.username),
550 user=None 822 user=None
551 ) 823 )
552 except Exception: 824 except Exception:
553 log.error(traceback.format_exc()) 825
554 raise JSONRPCError('failed to delete ID:%s %s' % (user.user_id, 826 log.error(traceback.format_exc())
555 user.username)) 827 raise JSONRPCError('failed to delete user ID:%s %s'
556 828 % (user.user_id, user.username))
557 @HasPermissionAllDecorator('hg.admin') 829
558 def get_users_group(self, apiuser, usersgroupid): 830 # permission check inside
559 """" 831 def get_user_group(self, apiuser, usergroupid):
560 Get user group by name or id 832 """
561 833 Gets an existing user group. This command can be executed only using api_key
562 :param apiuser: 834 belonging to user with admin rights or user who has at least
563 :param usersgroupid: 835 read access to user group.
564 """ 836
565 users_group = get_users_group_or_error(usersgroupid) 837 :param apiuser: filled automatically from apikey
566 838 :type apiuser: AuthUser
567 data = users_group.get_api_data() 839 :param usergroupid: id of user_group to edit
568 840 :type usergroupid: str or int
569 members = [] 841
570 for user in users_group.members: 842 OUTPUT::
571 user = user.user 843
572 members.append(user.get_api_data()) 844 id : <id_given_in_input>
573 data['members'] = members 845 result : None if group not exist
846 {
847 "users_group_id" : "<id>",
848 "group_name" : "<groupname>",
849 "active": "<bool>",
850 "members" : [<user_obj>,...]
851 }
852 error : null
853
854 """
855 user_group = get_user_group_or_error(usergroupid)
856 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
857 # check if we have at least read permission for this user group !
858 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
859 if not HasUserGroupPermissionAny(*_perms)(
860 user=apiuser, user_group_name=user_group.users_group_name):
861 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
862
863 data = user_group.get_api_data()
574 return data 864 return data
575 865
576 @HasPermissionAllDecorator('hg.admin') 866 # permission check inside
577 def get_users_groups(self, apiuser): 867 def get_user_groups(self, apiuser):
578 """" 868 """
579 Get all user groups 869 Lists all existing user groups. This command can be executed only using
580 870 api_key belonging to user with admin rights or user who has at least
581 :param apiuser: 871 read access to user group.
872
873 :param apiuser: filled automatically from apikey
874 :type apiuser: AuthUser
875
876 OUTPUT::
877
878 id : <id_given_in_input>
879 result : [<user_group_obj>,...]
880 error : null
582 """ 881 """
583 882
584 result = [] 883 result = []
585 for users_group in UserGroupModel().get_all(): 884 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
586 result.append(users_group.get_api_data()) 885 extras = {'user': apiuser}
886 for user_group in UserGroupList(UserGroupModel().get_all(),
887 perm_set=_perms, extra_kwargs=extras):
888 result.append(user_group.get_api_data())
587 return result 889 return result
588 890
589 @HasPermissionAllDecorator('hg.admin') 891 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
590 def create_users_group(self, apiuser, group_name, 892 def create_user_group(self, apiuser, group_name, description=Optional(''),
591 owner=Optional(OAttr('apiuser')), 893 owner=Optional(OAttr('apiuser')), active=Optional(True)):
592 active=Optional(True)): 894 """
593 """ 895 Creates new user group. This command can be executed only using api_key
594 Creates an new usergroup 896 belonging to user with admin rights or an user who has create user group
595 897 permission
596 :param apiuser: 898
597 :param group_name: 899 :param apiuser: filled automatically from apikey
598 :param owner: 900 :type apiuser: AuthUser
599 :param active: 901 :param group_name: name of new user group
902 :type group_name: str
903 :param description: group description
904 :type description: str
905 :param owner: owner of group. If not passed apiuser is the owner
906 :type owner: Optional(str or int)
907 :param active: group is active
908 :type active: Optional(bool)
909
910 OUTPUT::
911
912 id : <id_given_in_input>
913 result: {
914 "msg": "created new user group `<groupname>`",
915 "user_group": <user_group_object>
916 }
917 error: null
918
919 ERROR OUTPUT::
920
921 id : <id_given_in_input>
922 result : null
923 error : {
924 "user group `<group name>` already exist"
925 or
926 "failed to create group `<group name>`"
927 }
928
600 """ 929 """
601 930
602 if UserGroupModel().get_by_name(group_name): 931 if UserGroupModel().get_by_name(group_name):
603 raise JSONRPCError("user group `%s` already exist" % group_name) 932 raise JSONRPCError("user group `%s` already exist" % (group_name,))
604 933
605 try: 934 try:
606 if isinstance(owner, Optional): 935 if isinstance(owner, Optional):
607 owner = apiuser.user_id 936 owner = apiuser.user_id
608 937
609 owner = get_user_or_error(owner) 938 owner = get_user_or_error(owner)
610 active = Optional.extract(active) 939 active = Optional.extract(active)
611 ug = UserGroupModel().create(name=group_name, 940 description = Optional.extract(description)
612 owner=owner, 941 ug = UserGroupModel().create(name=group_name, description=description,
613 active=active) 942 owner=owner, active=active)
614 Session().commit() 943 Session().commit()
615 return dict( 944 return dict(
616 msg='created new user group `%s`' % group_name, 945 msg='created new user group `%s`' % group_name,
617 users_group=ug.get_api_data() 946 user_group=ug.get_api_data()
618 ) 947 )
619 except Exception: 948 except Exception:
620 log.error(traceback.format_exc()) 949 log.error(traceback.format_exc())
621 raise JSONRPCError('failed to create group `%s`' % group_name) 950 raise JSONRPCError('failed to create group `%s`' % (group_name,))
622 951
623 @HasPermissionAllDecorator('hg.admin') 952 # permission check inside
624 def add_user_to_users_group(self, apiuser, usersgroupid, userid): 953 def update_user_group(self, apiuser, usergroupid, group_name=Optional(''),
625 """" 954 description=Optional(''), owner=Optional(None),
626 Add a user to a user group 955 active=Optional(True)):
627 956 """
628 :param apiuser: 957 Updates given usergroup. This command can be executed only using api_key
629 :param usersgroupid: 958 belonging to user with admin rights or an admin of given user group
959
960 :param apiuser: filled automatically from apikey
961 :type apiuser: AuthUser
962 :param usergroupid: id of user group to update
963 :type usergroupid: str or int
964 :param group_name: name of new user group
965 :type group_name: str
966 :param description: group description
967 :type description: str
968 :param owner: owner of group.
969 :type owner: Optional(str or int)
970 :param active: group is active
971 :type active: Optional(bool)
972
973 OUTPUT::
974
975 id : <id_given_in_input>
976 result : {
977 "msg": 'updated user group ID:<user group id> <user group name>',
978 "user_group": <user_group_object>
979 }
980 error : null
981
982 ERROR OUTPUT::
983
984 id : <id_given_in_input>
985 result : null
986 error : {
987 "failed to update user group `<user group name>`"
988 }
989
990 """
991 user_group = get_user_group_or_error(usergroupid)
992 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
993 # check if we have admin permission for this user group !
994 _perms = ('usergroup.admin',)
995 if not HasUserGroupPermissionAny(*_perms)(
996 user=apiuser, user_group_name=user_group.users_group_name):
997 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
998
999 if not isinstance(owner, Optional):
1000 owner = get_user_or_error(owner)
1001
1002 updates = {}
1003 store_update(updates, group_name, 'users_group_name')
1004 store_update(updates, description, 'user_group_description')
1005 store_update(updates, owner, 'user')
1006 store_update(updates, active, 'users_group_active')
1007 try:
1008 UserGroupModel().update(user_group, updates)
1009 Session().commit()
1010 return dict(
1011 msg='updated user group ID:%s %s' % (user_group.users_group_id,
1012 user_group.users_group_name),
1013 user_group=user_group.get_api_data()
1014 )
1015 except Exception:
1016 log.error(traceback.format_exc())
1017 raise JSONRPCError('failed to update user group `%s`' % (usergroupid,))
1018
1019 # permission check inside
1020 def delete_user_group(self, apiuser, usergroupid):
1021 """
1022 Delete given user group by user group id or name.
1023 This command can be executed only using api_key
1024 belonging to user with admin rights or an admin of given user group
1025
1026 :param apiuser: filled automatically from apikey
1027 :type apiuser: AuthUser
1028 :param usergroupid:
1029 :type usergroupid: int
1030
1031 OUTPUT::
1032
1033 id : <id_given_in_input>
1034 result : {
1035 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
1036 }
1037 error : null
1038
1039 ERROR OUTPUT::
1040
1041 id : <id_given_in_input>
1042 result : null
1043 error : {
1044 "failed to delete user group ID:<user_group_id> <user_group_name>"
1045 or
1046 "RepoGroup assigned to <repo_groups_list>"
1047 }
1048
1049 """
1050 user_group = get_user_group_or_error(usergroupid)
1051 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
1052 # check if we have admin permission for this user group !
1053 _perms = ('usergroup.admin',)
1054 if not HasUserGroupPermissionAny(*_perms)(
1055 user=apiuser, user_group_name=user_group.users_group_name):
1056 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1057
1058 try:
1059 UserGroupModel().delete(user_group)
1060 Session().commit()
1061 return dict(
1062 msg='deleted user group ID:%s %s' %
1063 (user_group.users_group_id, user_group.users_group_name),
1064 user_group=None
1065 )
1066 except UserGroupsAssignedException, e:
1067 log.error(traceback.format_exc())
1068 raise JSONRPCError(str(e))
1069 except Exception:
1070 log.error(traceback.format_exc())
1071 raise JSONRPCError('failed to delete user group ID:%s %s' %
1072 (user_group.users_group_id,
1073 user_group.users_group_name)
1074 )
1075
1076 # permission check inside
1077 def add_user_to_user_group(self, apiuser, usergroupid, userid):
1078 """
1079 Adds a user to a user group. If user exists in that group success will be
1080 `false`. This command can be executed only using api_key
1081 belonging to user with admin rights or an admin of given user group
1082
1083 :param apiuser: filled automatically from apikey
1084 :type apiuser: AuthUser
1085 :param usergroupid:
1086 :type usergroupid: int
630 :param userid: 1087 :param userid:
1088 :type userid: int
1089
1090 OUTPUT::
1091
1092 id : <id_given_in_input>
1093 result : {
1094 "success": True|False # depends on if member is in group
1095 "msg": "added member `<username>` to user group `<groupname>` |
1096 User is already in that group"
1097
1098 }
1099 error : null
1100
1101 ERROR OUTPUT::
1102
1103 id : <id_given_in_input>
1104 result : null
1105 error : {
1106 "failed to add member to user group `<user_group_name>`"
1107 }
1108
631 """ 1109 """
632 user = get_user_or_error(userid) 1110 user = get_user_or_error(userid)
633 users_group = get_users_group_or_error(usersgroupid) 1111 user_group = get_user_group_or_error(usergroupid)
634 1112 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
635 try: 1113 # check if we have admin permission for this user group !
636 ugm = UserGroupModel().add_user_to_group(users_group, user) 1114 _perms = ('usergroup.admin',)
1115 if not HasUserGroupPermissionAny(*_perms)(
1116 user=apiuser, user_group_name=user_group.users_group_name):
1117 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1118
1119 try:
1120 ugm = UserGroupModel().add_user_to_group(user_group, user)
637 success = True if ugm != True else False 1121 success = True if ugm != True else False
638 msg = 'added member `%s` to user group `%s`' % ( 1122 msg = 'added member `%s` to user group `%s`' % (
639 user.username, users_group.users_group_name 1123 user.username, user_group.users_group_name
640 ) 1124 )
641 msg = msg if success else 'User is already in that group' 1125 msg = msg if success else 'User is already in that group'
642 Session().commit() 1126 Session().commit()
643 1127
644 return dict( 1128 return dict(
645 success=success, 1129 success=success,
647 ) 1131 )
648 except Exception: 1132 except Exception:
649 log.error(traceback.format_exc()) 1133 log.error(traceback.format_exc())
650 raise JSONRPCError( 1134 raise JSONRPCError(
651 'failed to add member to user group `%s`' % ( 1135 'failed to add member to user group `%s`' % (
652 users_group.users_group_name 1136 user_group.users_group_name,
653 ) 1137 )
654 ) 1138 )
655 1139
656 @HasPermissionAllDecorator('hg.admin') 1140 # permission check inside
657 def remove_user_from_users_group(self, apiuser, usersgroupid, userid): 1141 def remove_user_from_user_group(self, apiuser, usergroupid, userid):
658 """ 1142 """
659 Remove user from a group 1143 Removes a user from a user group. If user is not in given group success will
660 1144 be `false`. This command can be executed only
661 :param apiuser: 1145 using api_key belonging to user with admin rights or an admin of given user group
662 :param usersgroupid: 1146
1147 :param apiuser: filled automatically from apikey
1148 :type apiuser: AuthUser
1149 :param usergroupid:
663 :param userid: 1150 :param userid:
1151
1152
1153 OUTPUT::
1154
1155 id : <id_given_in_input>
1156 result: {
1157 "success": True|False, # depends on if member is in group
1158 "msg": "removed member <username> from user group <groupname> |
1159 User wasn't in group"
1160 }
1161 error: null
1162
664 """ 1163 """
665 user = get_user_or_error(userid) 1164 user = get_user_or_error(userid)
666 users_group = get_users_group_or_error(usersgroupid) 1165 user_group = get_user_group_or_error(usergroupid)
667 1166 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
668 try: 1167 # check if we have admin permission for this user group !
669 success = UserGroupModel().remove_user_from_group(users_group, 1168 _perms = ('usergroup.admin',)
670 user) 1169 if not HasUserGroupPermissionAny(*_perms)(
1170 user=apiuser, user_group_name=user_group.users_group_name):
1171 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1172
1173 try:
1174 success = UserGroupModel().remove_user_from_group(user_group, user)
671 msg = 'removed member `%s` from user group `%s`' % ( 1175 msg = 'removed member `%s` from user group `%s`' % (
672 user.username, users_group.users_group_name 1176 user.username, user_group.users_group_name
673 ) 1177 )
674 msg = msg if success else "User wasn't in group" 1178 msg = msg if success else "User wasn't in group"
675 Session().commit() 1179 Session().commit()
676 return dict(success=success, msg=msg) 1180 return dict(success=success, msg=msg)
677 except Exception: 1181 except Exception:
678 log.error(traceback.format_exc()) 1182 log.error(traceback.format_exc())
679 raise JSONRPCError( 1183 raise JSONRPCError(
680 'failed to remove member from user group `%s`' % ( 1184 'failed to remove member from user group `%s`' % (
681 users_group.users_group_name 1185 user_group.users_group_name,
682 ) 1186 )
683 ) 1187 )
684 1188
1189 # permission check inside
685 def get_repo(self, apiuser, repoid): 1190 def get_repo(self, apiuser, repoid):
686 """" 1191 """
687 Get repository by name 1192 Gets an existing repository by it's name or repository_id. Members will return
688 1193 either users_group or user associated to that repository. This command can be
689 :param apiuser: 1194 executed only using api_key belonging to user with admin
690 :param repoid: 1195 rights or regular user that have at least read access to repository.
1196
1197 :param apiuser: filled automatically from apikey
1198 :type apiuser: AuthUser
1199 :param repoid: repository name or repository id
1200 :type repoid: str or int
1201
1202 OUTPUT::
1203
1204 id : <id_given_in_input>
1205 result : {
1206 {
1207 "repo_id" : "<repo_id>",
1208 "repo_name" : "<reponame>"
1209 "repo_type" : "<repo_type>",
1210 "clone_uri" : "<clone_uri>",
1211 "enable_downloads": "<bool>",
1212 "enable_locking": "<bool>",
1213 "enable_statistics": "<bool>",
1214 "private": "<bool>",
1215 "created_on" : "<date_time_created>",
1216 "description" : "<description>",
1217 "landing_rev": "<landing_rev>",
1218 "last_changeset": {
1219 "author": "<full_author>",
1220 "date": "<date_time_of_commit>",
1221 "message": "<commit_message>",
1222 "raw_id": "<raw_id>",
1223 "revision": "<numeric_revision>",
1224 "short_id": "<short_id>"
1225 }
1226 "owner": "<repo_owner>",
1227 "fork_of": "<name_of_fork_parent>",
1228 "members" : [
1229 {
1230 "name": "<username>",
1231 "type" : "user",
1232 "permission" : "repository.(read|write|admin)"
1233 },
1234 โ€ฆ
1235 {
1236 "name": "<usergroup name>",
1237 "type" : "user_group",
1238 "permission" : "usergroup.(read|write|admin)"
1239 },
1240 โ€ฆ
1241 ]
1242 "followers": [<user_obj>, ...]
1243 ]
1244 }
1245 }
1246 error : null
1247
691 """ 1248 """
692 repo = get_repo_or_error(repoid) 1249 repo = get_repo_or_error(repoid)
693 1250
694 if not HasPermissionAnyApi('hg.admin')(user=apiuser): 1251 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
695 # check if we have admin permission for this repo ! 1252 # check if we have admin permission for this repo !
696 if not HasRepoPermissionAnyApi('repository.admin')(user=apiuser, 1253 perms = ('repository.admin', 'repository.write', 'repository.read')
697 repo_name=repo.repo_name): 1254 if not HasRepoPermissionAnyApi(*perms)(user=apiuser, repo_name=repo.repo_name):
698 raise JSONRPCError('repository `%s` does not exist' % (repoid)) 1255 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
699 1256
700 members = [] 1257 members = []
701 followers = [] 1258 followers = []
702 for user in repo.repo_to_perm: 1259 for user in repo.repo_to_perm:
703 perm = user.permission.permission_name 1260 perm = user.permission.permission_name
704 user = user.user 1261 user = user.user
705 user_data = user.get_api_data() 1262 user_data = {
706 user_data['type'] = "user" 1263 'name': user.username,
707 user_data['permission'] = perm 1264 'type': "user",
1265 'permission': perm
1266 }
708 members.append(user_data) 1267 members.append(user_data)
709 1268
710 for users_group in repo.users_group_to_perm: 1269 for user_group in repo.users_group_to_perm:
711 perm = users_group.permission.permission_name 1270 perm = user_group.permission.permission_name
712 users_group = users_group.users_group 1271 user_group = user_group.users_group
713 users_group_data = users_group.get_api_data() 1272 user_group_data = {
714 users_group_data['type'] = "users_group" 1273 'name': user_group.users_group_name,
715 users_group_data['permission'] = perm 1274 'type': "user_group",
716 members.append(users_group_data) 1275 'permission': perm
1276 }
1277 members.append(user_group_data)
717 1278
718 for user in repo.followers: 1279 for user in repo.followers:
719 followers.append(user.user.get_api_data()) 1280 followers.append(user.user.get_api_data())
720 1281
721 data = repo.get_api_data() 1282 data = repo.get_api_data()
723 data['followers'] = followers 1284 data['followers'] = followers
724 return data 1285 return data
725 1286
726 # permission check inside 1287 # permission check inside
727 def get_repos(self, apiuser): 1288 def get_repos(self, apiuser):
728 """" 1289 """
729 Get all repositories 1290 Lists all existing repositories. This command can be executed only using
730 1291 api_key belonging to user with admin rights or regular user that have
731 :param apiuser: 1292 admin, write or read access to repository.
1293
1294 :param apiuser: filled automatically from apikey
1295 :type apiuser: AuthUser
1296
1297 OUTPUT::
1298
1299 id : <id_given_in_input>
1300 result: [
1301 {
1302 "repo_id" : "<repo_id>",
1303 "repo_name" : "<reponame>"
1304 "repo_type" : "<repo_type>",
1305 "clone_uri" : "<clone_uri>",
1306 "private": : "<bool>",
1307 "created_on" : "<datetimecreated>",
1308 "description" : "<description>",
1309 "landing_rev": "<landing_rev>",
1310 "owner": "<repo_owner>",
1311 "fork_of": "<name_of_fork_parent>",
1312 "enable_downloads": "<bool>",
1313 "enable_locking": "<bool>",
1314 "enable_statistics": "<bool>",
1315 },
1316 โ€ฆ
1317 ]
1318 error: null
732 """ 1319 """
733 result = [] 1320 result = []
734 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False: 1321 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
735 repos = RepoModel().get_all_user_repos(user=apiuser) 1322 repos = RepoModel().get_all_user_repos(user=apiuser)
736 else: 1323 else:
737 repos = RepoModel().get_all() 1324 repos = RepoModel().get_all()
738 1325
739 for repo in repos: 1326 for repo in repos:
740 result.append(repo.get_api_data()) 1327 result.append(repo.get_api_data())
741 return result 1328 return result
742 1329
743 @HasPermissionAllDecorator('hg.admin') 1330 # permission check inside
744 def get_repo_nodes(self, apiuser, repoid, revision, root_path, 1331 def get_repo_nodes(self, apiuser, repoid, revision, root_path,
745 ret_type='all'): 1332 ret_type=Optional('all')):
746 """ 1333 """
747 returns a list of nodes and it's children 1334 returns a list of nodes and it's children in a flat list for a given path
748 for a given path at given revision. It's possible to specify ret_type 1335 at given revision. It's possible to specify ret_type to show only `files` or
749 to show only files or dirs 1336 `dirs`. This command can be executed only using api_key belonging to
750 1337 user with admin rights or regular user that have at least read access to repository.
751 :param apiuser: 1338
752 :param repoid: name or id of repository 1339 :param apiuser: filled automatically from apikey
1340 :type apiuser: AuthUser
1341 :param repoid: repository name or repository id
1342 :type repoid: str or int
753 :param revision: revision for which listing should be done 1343 :param revision: revision for which listing should be done
1344 :type revision: str
754 :param root_path: path from which start displaying 1345 :param root_path: path from which start displaying
1346 :type root_path: str
755 :param ret_type: return type 'all|files|dirs' nodes 1347 :param ret_type: return type 'all|files|dirs' nodes
1348 :type ret_type: Optional(str)
1349
1350
1351 OUTPUT::
1352
1353 id : <id_given_in_input>
1354 result: [
1355 {
1356 "name" : "<name>"
1357 "type" : "<type>",
1358 },
1359 โ€ฆ
1360 ]
1361 error: null
756 """ 1362 """
757 repo = get_repo_or_error(repoid) 1363 repo = get_repo_or_error(repoid)
1364
1365 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
1366 # check if we have admin permission for this repo !
1367 perms = ('repository.admin', 'repository.write', 'repository.read')
1368 if not HasRepoPermissionAnyApi(*perms)(user=apiuser, repo_name=repo.repo_name):
1369 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1370
1371 ret_type = Optional.extract(ret_type)
1372 _map = {}
758 try: 1373 try:
759 _d, _f = ScmModel().get_nodes(repo, revision, root_path, 1374 _d, _f = ScmModel().get_nodes(repo, revision, root_path,
760 flat=False) 1375 flat=False)
761 _map = { 1376 _map = {
762 'all': _d + _f, 1377 'all': _d + _f,
763 'files': _f, 1378 'files': _f,
764 'dirs': _d, 1379 'dirs': _d,
765 } 1380 }
766 return _map[ret_type] 1381 return _map[ret_type]
767 except KeyError: 1382 except KeyError:
768 raise JSONRPCError('ret_type must be one of %s' % _map.keys()) 1383 raise JSONRPCError('ret_type must be one of %s'
1384 % (','.join(_map.keys())))
769 except Exception: 1385 except Exception:
770 log.error(traceback.format_exc()) 1386 log.error(traceback.format_exc())
771 raise JSONRPCError( 1387 raise JSONRPCError(
772 'failed to get repo: `%s` nodes' % repo.repo_name 1388 'failed to get repo: `%s` nodes' % repo.repo_name
773 ) 1389 )
774 1390
775 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository') 1391 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
776 def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')), 1392 def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')),
777 repo_type=Optional('hg'), 1393 repo_type=Optional('hg'), description=Optional(''),
778 description=Optional(''), private=Optional(False), 1394 private=Optional(False), clone_uri=Optional(None),
779 clone_uri=Optional(None), landing_rev=Optional('tip'), 1395 landing_rev=Optional('rev:tip'),
780 enable_statistics=Optional(False), 1396 enable_statistics=Optional(False),
781 enable_locking=Optional(False), 1397 enable_locking=Optional(False),
782 enable_downloads=Optional(False)): 1398 enable_downloads=Optional(False),
783 """ 1399 copy_permissions=Optional(False)):
784 Create repository, if clone_url is given it makes a remote clone 1400 """
785 if repo_name is within a group name the groups will be created 1401 Creates a repository. If repository name contains "/", all needed repository
786 automatically if they aren't present 1402 groups will be created. For example "foo/bar/baz" will create groups
787 1403 "foo", "bar" (with "foo" as parent), and create "baz" repository with
788 :param apiuser: 1404 "bar" as group. This command can be executed only using api_key
789 :param repo_name: 1405 belonging to user with admin rights or regular user that have create
790 :param onwer: 1406 repository permission. Regular users cannot specify owner parameter
791 :param repo_type: 1407
792 :param description: 1408 :param apiuser: filled automatically from apikey
1409 :type apiuser: AuthUser
1410 :param repo_name: repository name
1411 :type repo_name: str
1412 :param owner: user_id or username
1413 :type owner: Optional(str)
1414 :param repo_type: 'hg' or 'git'
1415 :type repo_type: Optional(str)
1416 :param description: repository description
1417 :type description: Optional(str)
793 :param private: 1418 :param private:
1419 :type private: bool
794 :param clone_uri: 1420 :param clone_uri:
795 :param landing_rev: 1421 :type clone_uri: str
796 """ 1422 :param landing_rev: <rev_type>:<rev>
797 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False: 1423 :type landing_rev: str
1424 :param enable_locking:
1425 :type enable_locking: bool
1426 :param enable_downloads:
1427 :type enable_downloads: bool
1428 :param enable_statistics:
1429 :type enable_statistics: bool
1430 :param copy_permissions: Copy permission from group that repository is
1431 beeing created.
1432 :type copy_permissions: bool
1433
1434 OUTPUT::
1435
1436 id : <id_given_in_input>
1437 result: {
1438 "msg": "Created new repository `<reponame>`",
1439 "success": true,
1440 "task": "<celery task id or None if done sync>"
1441 }
1442 error: null
1443
1444 ERROR OUTPUT::
1445
1446 id : <id_given_in_input>
1447 result : null
1448 error : {
1449 'failed to create repository `<repo_name>`
1450 }
1451
1452 """
1453 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
798 if not isinstance(owner, Optional): 1454 if not isinstance(owner, Optional):
799 #forbid setting owner for non-admins 1455 #forbid setting owner for non-admins
800 raise JSONRPCError( 1456 raise JSONRPCError(
801 'Only RhodeCode admin can specify `owner` param' 1457 'Only RhodeCode admin can specify `owner` param'
802 ) 1458 )
821 enable_downloads = defs.get('repo_enable_downloads') 1477 enable_downloads = defs.get('repo_enable_downloads')
822 1478
823 clone_uri = Optional.extract(clone_uri) 1479 clone_uri = Optional.extract(clone_uri)
824 description = Optional.extract(description) 1480 description = Optional.extract(description)
825 landing_rev = Optional.extract(landing_rev) 1481 landing_rev = Optional.extract(landing_rev)
826 1482 copy_permissions = Optional.extract(copy_permissions)
827 try: 1483
1484 try:
1485 repo_name_cleaned = repo_name.split('/')[-1]
828 # create structure of groups and return the last group 1486 # create structure of groups and return the last group
829 group = map_groups(repo_name) 1487 repo_group = map_groups(repo_name)
830 1488 data = dict(
831 repo = RepoModel().create_repo( 1489 repo_name=repo_name_cleaned,
832 repo_name=repo_name, 1490 repo_name_full=repo_name,
833 repo_type=repo_type, 1491 repo_type=repo_type,
834 description=description, 1492 repo_description=description,
835 owner=owner, 1493 owner=owner,
836 private=private, 1494 repo_private=private,
837 clone_uri=clone_uri, 1495 clone_uri=clone_uri,
838 repos_group=group, 1496 repo_group=repo_group,
839 landing_rev=landing_rev, 1497 repo_landing_rev=landing_rev,
840 enable_statistics=enable_statistics, 1498 enable_statistics=enable_statistics,
1499 enable_locking=enable_locking,
841 enable_downloads=enable_downloads, 1500 enable_downloads=enable_downloads,
842 enable_locking=enable_locking 1501 repo_copy_permissions=copy_permissions,
843 ) 1502 )
844 1503
845 Session().commit() 1504 task = RepoModel().create(form_data=data, cur_user=owner)
1505 from celery.result import BaseAsyncResult
1506 task_id = None
1507 if isinstance(task, BaseAsyncResult):
1508 task_id = task.task_id
1509 # no commit, it's done in RepoModel, or async via celery
846 return dict( 1510 return dict(
847 msg="Created new repository `%s`" % (repo.repo_name), 1511 msg="Created new repository `%s`" % (repo_name,),
848 repo=repo.get_api_data() 1512 success=True, # cannot return the repo data here since fork
849 ) 1513 # cann be done async
850 except Exception: 1514 task=task_id
851 log.error(traceback.format_exc()) 1515 )
852 raise JSONRPCError('failed to create repository `%s`' % repo_name) 1516 except Exception:
1517 log.error(traceback.format_exc())
1518 raise JSONRPCError(
1519 'failed to create repository `%s`' % (repo_name,))
853 1520
854 # permission check inside 1521 # permission check inside
855 def update_repo(self, apiuser, repoid, name=Optional(None), 1522 def update_repo(self, apiuser, repoid, name=Optional(None),
856 owner=Optional(OAttr('apiuser')), 1523 owner=Optional(OAttr('apiuser')),
857 group=Optional(None), 1524 group=Optional(None),
858 description=Optional(''), private=Optional(False), 1525 description=Optional(''), private=Optional(False),
859 clone_uri=Optional(None), landing_rev=Optional('tip'), 1526 clone_uri=Optional(None), landing_rev=Optional('rev:tip'),
860 enable_statistics=Optional(False), 1527 enable_statistics=Optional(False),
861 enable_locking=Optional(False), 1528 enable_locking=Optional(False),
862 enable_downloads=Optional(False)): 1529 enable_downloads=Optional(False)):
863 1530
864 """ 1531 """
915 except Exception: 1582 except Exception:
916 log.error(traceback.format_exc()) 1583 log.error(traceback.format_exc())
917 raise JSONRPCError('failed to update repo `%s`' % repoid) 1584 raise JSONRPCError('failed to update repo `%s`' % repoid)
918 1585
919 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository') 1586 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
920 def fork_repo(self, apiuser, repoid, fork_name, owner=Optional(OAttr('apiuser')), 1587 def fork_repo(self, apiuser, repoid, fork_name,
1588 owner=Optional(OAttr('apiuser')),
921 description=Optional(''), copy_permissions=Optional(False), 1589 description=Optional(''), copy_permissions=Optional(False),
922 private=Optional(False), landing_rev=Optional('tip')): 1590 private=Optional(False), landing_rev=Optional('rev:tip')):
1591 """
1592 Creates a fork of given repo. In case of using celery this will
1593 immidiatelly return success message, while fork is going to be created
1594 asynchronous. This command can be executed only using api_key belonging to
1595 user with admin rights or regular user that have fork permission, and at least
1596 read access to forking repository. Regular users cannot specify owner parameter.
1597
1598 :param apiuser: filled automatically from apikey
1599 :type apiuser: AuthUser
1600 :param repoid: repository name or repository id
1601 :type repoid: str or int
1602 :param fork_name:
1603 :param owner:
1604 :param description:
1605 :param copy_permissions:
1606 :param private:
1607 :param landing_rev:
1608
1609 INPUT::
1610
1611 id : <id_for_response>
1612 api_key : "<api_key>"
1613 args: {
1614 "repoid" : "<reponame or repo_id>",
1615 "fork_name": "<forkname>",
1616 "owner": "<username or user_id = Optional(=apiuser)>",
1617 "description": "<description>",
1618 "copy_permissions": "<bool>",
1619 "private": "<bool>",
1620 "landing_rev": "<landing_rev>"
1621 }
1622
1623 OUTPUT::
1624
1625 id : <id_given_in_input>
1626 result: {
1627 "msg": "Created fork of `<reponame>` as `<forkname>`",
1628 "success": true,
1629 "task": "<celery task id or None if done sync>"
1630 }
1631 error: null
1632
1633 """
923 repo = get_repo_or_error(repoid) 1634 repo = get_repo_or_error(repoid)
924 repo_name = repo.repo_name 1635 repo_name = repo.repo_name
925 1636
926 _repo = RepoModel().get_by_repo_name(fork_name) 1637 _repo = RepoModel().get_by_repo_name(fork_name)
927 if _repo: 1638 if _repo:
938 #forbid setting owner for non-admins 1649 #forbid setting owner for non-admins
939 raise JSONRPCError( 1650 raise JSONRPCError(
940 'Only RhodeCode admin can specify `owner` param' 1651 'Only RhodeCode admin can specify `owner` param'
941 ) 1652 )
942 else: 1653 else:
943 raise JSONRPCError('repository `%s` does not exist' % (repoid)) 1654 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
944 1655
945 if isinstance(owner, Optional): 1656 if isinstance(owner, Optional):
946 owner = apiuser.user_id 1657 owner = apiuser.user_id
947 1658
948 owner = get_user_or_error(owner) 1659 owner = get_user_or_error(owner)
961 copy_permissions=Optional.extract(copy_permissions), 1672 copy_permissions=Optional.extract(copy_permissions),
962 landing_rev=Optional.extract(landing_rev), 1673 landing_rev=Optional.extract(landing_rev),
963 update_after_clone=False, 1674 update_after_clone=False,
964 fork_parent_id=repo.repo_id, 1675 fork_parent_id=repo.repo_id,
965 ) 1676 )
966 RepoModel().create_fork(form_data, cur_user=owner) 1677 task = RepoModel().create_fork(form_data, cur_user=owner)
1678 # no commit, it's done in RepoModel, or async via celery
1679 from celery.result import BaseAsyncResult
1680 task_id = None
1681 if isinstance(task, BaseAsyncResult):
1682 task_id = task.task_id
967 return dict( 1683 return dict(
968 msg='Created fork of `%s` as `%s`' % (repo.repo_name, 1684 msg='Created fork of `%s` as `%s`' % (repo.repo_name,
969 fork_name), 1685 fork_name),
970 success=True # cannot return the repo data here since fork 1686 success=True, # cannot return the repo data here since fork
971 # cann be done async 1687 # cann be done async
1688 task=task_id
972 ) 1689 )
973 except Exception: 1690 except Exception:
974 log.error(traceback.format_exc()) 1691 log.error(traceback.format_exc())
975 raise JSONRPCError( 1692 raise JSONRPCError(
976 'failed to fork repository `%s` as `%s`' % (repo_name, 1693 'failed to fork repository `%s` as `%s`' % (repo_name,
977 fork_name) 1694 fork_name)
978 ) 1695 )
979 1696
980 # perms handled inside 1697 # permission check inside
981 def delete_repo(self, apiuser, repoid, forks=Optional(None)): 1698 def delete_repo(self, apiuser, repoid, forks=Optional('')):
982 """ 1699 """
983 Deletes a given repository 1700 Deletes a repository. This command can be executed only using api_key belonging
984 1701 to user with admin rights or regular user that have admin access to repository.
985 :param apiuser: 1702 When `forks` param is set it's possible to detach or delete forks of deleting
986 :param repoid: 1703 repository
987 :param forks: detach or delete, what do do with attached forks for repo 1704
1705 :param apiuser: filled automatically from apikey
1706 :type apiuser: AuthUser
1707 :param repoid: repository name or repository id
1708 :type repoid: str or int
1709 :param forks: `detach` or `delete`, what do do with attached forks for repo
1710 :type forks: Optional(str)
1711
1712 OUTPUT::
1713
1714 id : <id_given_in_input>
1715 result: {
1716 "msg": "Deleted repository `<reponame>`",
1717 "success": true
1718 }
1719 error: null
1720
988 """ 1721 """
989 repo = get_repo_or_error(repoid) 1722 repo = get_repo_or_error(repoid)
990 1723
991 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False: 1724 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
992 # check if we have admin permission for this repo ! 1725 # check if we have admin permission for this repo !
993 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser, 1726 if not HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
994 repo_name=repo.repo_name) is False: 1727 repo_name=repo.repo_name):
995 raise JSONRPCError('repository `%s` does not exist' % (repoid)) 1728 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
996 1729
997 try: 1730 try:
998 handle_forks = Optional.extract(forks) 1731 handle_forks = Optional.extract(forks)
999 _forks_msg = '' 1732 _forks_msg = ''
1000 _forks = [f for f in repo.forks] 1733 _forks = [f for f in repo.forks]
1002 _forks_msg = ' ' + 'Detached %s forks' % len(_forks) 1735 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1003 elif handle_forks == 'delete': 1736 elif handle_forks == 'delete':
1004 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks) 1737 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1005 elif _forks: 1738 elif _forks:
1006 raise JSONRPCError( 1739 raise JSONRPCError(
1007 'Cannot delete `%s` it still contains attached forks' 1740 'Cannot delete `%s` it still contains attached forks' %
1008 % repo.repo_name 1741 (repo.repo_name,)
1009 ) 1742 )
1010 1743
1011 RepoModel().delete(repo, forks=forks) 1744 RepoModel().delete(repo, forks=forks)
1012 Session().commit() 1745 Session().commit()
1013 return dict( 1746 return dict(
1015 success=True 1748 success=True
1016 ) 1749 )
1017 except Exception: 1750 except Exception:
1018 log.error(traceback.format_exc()) 1751 log.error(traceback.format_exc())
1019 raise JSONRPCError( 1752 raise JSONRPCError(
1020 'failed to delete repository `%s`' % repo.repo_name 1753 'failed to delete repository `%s`' % (repo.repo_name,)
1021 ) 1754 )
1022 1755
1023 @HasPermissionAllDecorator('hg.admin') 1756 @HasPermissionAllDecorator('hg.admin')
1024 def grant_user_permission(self, apiuser, repoid, userid, perm): 1757 def grant_user_permission(self, apiuser, repoid, userid, perm):
1025 """ 1758 """
1026 Grant permission for user on given repository, or update existing one 1759 Grant permission for user on given repository, or update existing one
1027 if found 1760 if found. This command can be executed only using api_key belonging to user
1028 1761 with admin rights.
1029 :param repoid: 1762
1763 :param apiuser: filled automatically from apikey
1764 :type apiuser: AuthUser
1765 :param repoid: repository name or repository id
1766 :type repoid: str or int
1030 :param userid: 1767 :param userid:
1031 :param perm: 1768 :param perm: (repository.(none|read|write|admin))
1769 :type perm: str
1770
1771 OUTPUT::
1772
1773 id : <id_given_in_input>
1774 result: {
1775 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1776 "success": true
1777 }
1778 error: null
1032 """ 1779 """
1033 repo = get_repo_or_error(repoid) 1780 repo = get_repo_or_error(repoid)
1034 user = get_user_or_error(userid) 1781 user = get_user_or_error(userid)
1035 perm = get_perm_or_error(perm) 1782 perm = get_perm_or_error(perm)
1036 1783
1054 ) 1801 )
1055 1802
1056 @HasPermissionAllDecorator('hg.admin') 1803 @HasPermissionAllDecorator('hg.admin')
1057 def revoke_user_permission(self, apiuser, repoid, userid): 1804 def revoke_user_permission(self, apiuser, repoid, userid):
1058 """ 1805 """
1059 Revoke permission for user on given repository 1806 Revoke permission for user on given repository. This command can be executed
1060 1807 only using api_key belonging to user with admin rights.
1061 :param apiuser: 1808
1062 :param repoid: 1809 :param apiuser: filled automatically from apikey
1810 :type apiuser: AuthUser
1811 :param repoid: repository name or repository id
1812 :type repoid: str or int
1063 :param userid: 1813 :param userid:
1814
1815 OUTPUT::
1816
1817 id : <id_given_in_input>
1818 result: {
1819 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1820 "success": true
1821 }
1822 error: null
1823
1064 """ 1824 """
1065 1825
1066 repo = get_repo_or_error(repoid) 1826 repo = get_repo_or_error(repoid)
1067 user = get_user_or_error(userid) 1827 user = get_user_or_error(userid)
1068 try: 1828 try:
1069
1070 RepoModel().revoke_user_permission(repo=repo, user=user) 1829 RepoModel().revoke_user_permission(repo=repo, user=user)
1071
1072 Session().commit() 1830 Session().commit()
1073 return dict( 1831 return dict(
1074 msg='Revoked perm for user: `%s` in repo: `%s`' % ( 1832 msg='Revoked perm for user: `%s` in repo: `%s`' % (
1075 user.username, repo.repo_name 1833 user.username, repo.repo_name
1076 ), 1834 ),
1082 'failed to edit permission for user: `%s` in repo: `%s`' % ( 1840 'failed to edit permission for user: `%s` in repo: `%s`' % (
1083 userid, repoid 1841 userid, repoid
1084 ) 1842 )
1085 ) 1843 )
1086 1844
1087 @HasPermissionAllDecorator('hg.admin') 1845 # permission check inside
1088 def grant_users_group_permission(self, apiuser, repoid, usersgroupid, 1846 def grant_user_group_permission(self, apiuser, repoid, usergroupid, perm):
1089 perm):
1090 """ 1847 """
1091 Grant permission for user group on given repository, or update 1848 Grant permission for user group on given repository, or update
1092 existing one if found 1849 existing one if found. This command can be executed only using
1093 1850 api_key belonging to user with admin rights.
1094 :param apiuser: 1851
1095 :param repoid: 1852 :param apiuser: filled automatically from apikey
1096 :param usersgroupid: 1853 :type apiuser: AuthUser
1097 :param perm: 1854 :param repoid: repository name or repository id
1855 :type repoid: str or int
1856 :param usergroupid: id of usergroup
1857 :type usergroupid: str or int
1858 :param perm: (repository.(none|read|write|admin))
1859 :type perm: str
1860
1861 OUTPUT::
1862
1863 id : <id_given_in_input>
1864 result : {
1865 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1866 "success": true
1867
1868 }
1869 error : null
1870
1871 ERROR OUTPUT::
1872
1873 id : <id_given_in_input>
1874 result : null
1875 error : {
1876 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1877 }
1878
1098 """ 1879 """
1099 repo = get_repo_or_error(repoid) 1880 repo = get_repo_or_error(repoid)
1100 perm = get_perm_or_error(perm) 1881 perm = get_perm_or_error(perm)
1101 users_group = get_users_group_or_error(usersgroupid) 1882 user_group = get_user_group_or_error(usergroupid)
1102 1883 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
1103 try: 1884 # check if we have admin permission for this repo !
1104 RepoModel().grant_users_group_permission(repo=repo, 1885 _perms = ('repository.admin',)
1105 group_name=users_group, 1886 if not HasRepoPermissionAnyApi(*_perms)(
1106 perm=perm) 1887 user=apiuser, repo_name=repo.repo_name):
1888 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1889
1890 # check if we have at least read permission for this user group !
1891 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1892 if not HasUserGroupPermissionAny(*_perms)(
1893 user=apiuser, user_group_name=user_group.users_group_name):
1894 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1895
1896 try:
1897 RepoModel().grant_user_group_permission(
1898 repo=repo, group_name=user_group, perm=perm)
1107 1899
1108 Session().commit() 1900 Session().commit()
1109 return dict( 1901 return dict(
1110 msg='Granted perm: `%s` for user group: `%s` in ' 1902 msg='Granted perm: `%s` for user group: `%s` in '
1111 'repo: `%s`' % ( 1903 'repo: `%s`' % (
1112 perm.permission_name, users_group.users_group_name, 1904 perm.permission_name, user_group.users_group_name,
1113 repo.repo_name 1905 repo.repo_name
1114 ), 1906 ),
1115 success=True 1907 success=True
1116 ) 1908 )
1117 except Exception: 1909 except Exception:
1118 log.error(traceback.format_exc()) 1910 log.error(traceback.format_exc())
1119 raise JSONRPCError( 1911 raise JSONRPCError(
1120 'failed to edit permission for user group: `%s` in ' 1912 'failed to edit permission for user group: `%s` in '
1121 'repo: `%s`' % ( 1913 'repo: `%s`' % (
1122 usersgroupid, repo.repo_name 1914 usergroupid, repo.repo_name
1123 ) 1915 )
1124 ) 1916 )
1125 1917
1126 @HasPermissionAllDecorator('hg.admin') 1918 # permission check inside
1127 def revoke_users_group_permission(self, apiuser, repoid, usersgroupid): 1919 def revoke_user_group_permission(self, apiuser, repoid, usergroupid):
1128 """ 1920 """
1129 Revoke permission for user group on given repository 1921 Revoke permission for user group on given repository. This command can be
1130 1922 executed only using api_key belonging to user with admin rights.
1131 :param apiuser: 1923
1132 :param repoid: 1924 :param apiuser: filled automatically from apikey
1133 :param usersgroupid: 1925 :type apiuser: AuthUser
1926 :param repoid: repository name or repository id
1927 :type repoid: str or int
1928 :param usergroupid:
1929
1930 OUTPUT::
1931
1932 id : <id_given_in_input>
1933 result: {
1934 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1935 "success": true
1936 }
1937 error: null
1134 """ 1938 """
1135 repo = get_repo_or_error(repoid) 1939 repo = get_repo_or_error(repoid)
1136 users_group = get_users_group_or_error(usersgroupid) 1940 user_group = get_user_group_or_error(usergroupid)
1137 1941 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
1138 try: 1942 # check if we have admin permission for this repo !
1139 RepoModel().revoke_users_group_permission(repo=repo, 1943 _perms = ('repository.admin',)
1140 group_name=users_group) 1944 if not HasRepoPermissionAnyApi(*_perms)(
1945 user=apiuser, repo_name=repo.repo_name):
1946 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1947
1948 # check if we have at least read permission for this user group !
1949 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1950 if not HasUserGroupPermissionAny(*_perms)(
1951 user=apiuser, user_group_name=user_group.users_group_name):
1952 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1953
1954 try:
1955 RepoModel().revoke_user_group_permission(
1956 repo=repo, group_name=user_group)
1141 1957
1142 Session().commit() 1958 Session().commit()
1143 return dict( 1959 return dict(
1144 msg='Revoked perm for user group: `%s` in repo: `%s`' % ( 1960 msg='Revoked perm for user group: `%s` in repo: `%s`' % (
1145 users_group.users_group_name, repo.repo_name 1961 user_group.users_group_name, repo.repo_name
1146 ), 1962 ),
1147 success=True 1963 success=True
1148 ) 1964 )
1149 except Exception: 1965 except Exception:
1150 log.error(traceback.format_exc()) 1966 log.error(traceback.format_exc())
1151 raise JSONRPCError( 1967 raise JSONRPCError(
1152 'failed to edit permission for user group: `%s` in ' 1968 'failed to edit permission for user group: `%s` in '
1153 'repo: `%s`' % ( 1969 'repo: `%s`' % (
1154 users_group.users_group_name, repo.repo_name 1970 user_group.users_group_name, repo.repo_name
1155 ) 1971 )
1156 ) 1972 )
1973
1974 @HasPermissionAllDecorator('hg.admin')
1975 def get_repo_group(self, apiuser, repogroupid):
1976 """
1977 Returns given repo group together with permissions, and repositories
1978 inside the group
1979
1980 :param apiuser: filled automatically from apikey
1981 :type apiuser: AuthUser
1982 :param repogroupid: id/name of repository group
1983 :type repogroupid: str or int
1984 """
1985 repo_group = get_repo_group_or_error(repogroupid)
1986
1987 members = []
1988 for user in repo_group.repo_group_to_perm:
1989 perm = user.permission.permission_name
1990 user = user.user
1991 user_data = {
1992 'name': user.username,
1993 'type': "user",
1994 'permission': perm
1995 }
1996 members.append(user_data)
1997
1998 for user_group in repo_group.users_group_to_perm:
1999 perm = user_group.permission.permission_name
2000 user_group = user_group.users_group
2001 user_group_data = {
2002 'name': user_group.users_group_name,
2003 'type': "user_group",
2004 'permission': perm
2005 }
2006 members.append(user_group_data)
2007
2008 data = repo_group.get_api_data()
2009 data["members"] = members
2010 return data
2011
2012 @HasPermissionAllDecorator('hg.admin')
2013 def get_repo_groups(self, apiuser):
2014 """
2015 Returns all repository groups
2016
2017 :param apiuser: filled automatically from apikey
2018 :type apiuser: AuthUser
2019 """
2020 result = []
2021 for repo_group in RepoGroupModel().get_all():
2022 result.append(repo_group.get_api_data())
2023 return result
2024
2025 @HasPermissionAllDecorator('hg.admin')
2026 def create_repo_group(self, apiuser, group_name, description=Optional(''),
2027 owner=Optional(OAttr('apiuser')),
2028 parent=Optional(None),
2029 copy_permissions=Optional(False)):
2030 """
2031 Creates a repository group. This command can be executed only using
2032 api_key belonging to user with admin rights.
2033
2034 :param apiuser: filled automatically from apikey
2035 :type apiuser: AuthUser
2036 :param group_name:
2037 :type group_name:
2038 :param description:
2039 :type description:
2040 :param owner:
2041 :type owner:
2042 :param parent:
2043 :type parent:
2044 :param copy_permissions:
2045 :type copy_permissions:
2046
2047 OUTPUT::
2048
2049 id : <id_given_in_input>
2050 result : {
2051 "msg": "created new repo group `<repo_group_name>`"
2052 "repo_group": <repogroup_object>
2053 }
2054 error : null
2055
2056 ERROR OUTPUT::
2057
2058 id : <id_given_in_input>
2059 result : null
2060 error : {
2061 failed to create repo group `<repogroupid>`
2062 }
2063
2064 """
2065 if RepoGroup.get_by_group_name(group_name):
2066 raise JSONRPCError("repo group `%s` already exist" % (group_name,))
2067
2068 if isinstance(owner, Optional):
2069 owner = apiuser.user_id
2070 group_description = Optional.extract(description)
2071 parent_group = Optional.extract(parent)
2072 if not isinstance(parent, Optional):
2073 parent_group = get_repo_group_or_error(parent_group)
2074
2075 copy_permissions = Optional.extract(copy_permissions)
2076 try:
2077 repo_group = RepoGroupModel().create(
2078 group_name=group_name,
2079 group_description=group_description,
2080 owner=owner,
2081 parent=parent_group,
2082 copy_permissions=copy_permissions
2083 )
2084 Session().commit()
2085 return dict(
2086 msg='created new repo group `%s`' % group_name,
2087 repo_group=repo_group.get_api_data()
2088 )
2089 except Exception:
2090
2091 log.error(traceback.format_exc())
2092 raise JSONRPCError('failed to create repo group `%s`' % (group_name,))
2093
2094 @HasPermissionAllDecorator('hg.admin')
2095 def update_repo_group(self, apiuser, repogroupid, group_name=Optional(''),
2096 description=Optional(''),
2097 owner=Optional(OAttr('apiuser')),
2098 parent=Optional(None), enable_locking=Optional(False)):
2099 repo_group = get_repo_group_or_error(repogroupid)
2100
2101 updates = {}
2102 try:
2103 store_update(updates, group_name, 'group_name')
2104 store_update(updates, description, 'group_description')
2105 store_update(updates, owner, 'owner')
2106 store_update(updates, parent, 'parent_group')
2107 store_update(updates, enable_locking, 'enable_locking')
2108 repo_group = RepoGroupModel().update(repo_group, updates)
2109 Session().commit()
2110 return dict(
2111 msg='updated repository group ID:%s %s' % (repo_group.group_id,
2112 repo_group.group_name),
2113 repo_group=repo_group.get_api_data()
2114 )
2115 except Exception:
2116 log.error(traceback.format_exc())
2117 raise JSONRPCError('failed to update repository group `%s`'
2118 % (repogroupid,))
2119
2120 @HasPermissionAllDecorator('hg.admin')
2121 def delete_repo_group(self, apiuser, repogroupid):
2122 """
2123
2124 :param apiuser: filled automatically from apikey
2125 :type apiuser: AuthUser
2126 :param repogroupid: name or id of repository group
2127 :type repogroupid: str or int
2128
2129 OUTPUT::
2130
2131 id : <id_given_in_input>
2132 result : {
2133 'msg': 'deleted repo group ID:<repogroupid> <repogroupname>
2134 'repo_group': null
2135 }
2136 error : null
2137
2138 ERROR OUTPUT::
2139
2140 id : <id_given_in_input>
2141 result : null
2142 error : {
2143 "failed to delete repo group ID:<repogroupid> <repogroupname>"
2144 }
2145
2146 """
2147 repo_group = get_repo_group_or_error(repogroupid)
2148
2149 try:
2150 RepoGroupModel().delete(repo_group)
2151 Session().commit()
2152 return dict(
2153 msg='deleted repo group ID:%s %s' %
2154 (repo_group.group_id, repo_group.group_name),
2155 repo_group=None
2156 )
2157 except Exception:
2158 log.error(traceback.format_exc())
2159 raise JSONRPCError('failed to delete repo group ID:%s %s' %
2160 (repo_group.group_id, repo_group.group_name)
2161 )
2162
2163 # permission check inside
2164 def grant_user_permission_to_repo_group(self, apiuser, repogroupid, userid,
2165 perm, apply_to_children=Optional('none')):
2166 """
2167 Grant permission for user on given repository group, or update existing
2168 one if found. This command can be executed only using api_key belonging
2169 to user with admin rights, or user who has admin right to given repository
2170 group.
2171
2172 :param apiuser: filled automatically from apikey
2173 :type apiuser: AuthUser
2174 :param repogroupid: name or id of repository group
2175 :type repogroupid: str or int
2176 :param userid:
2177 :param perm: (group.(none|read|write|admin))
2178 :type perm: str
2179 :param apply_to_children: 'none', 'repos', 'groups', 'all'
2180 :type apply_to_children: str
2181
2182 OUTPUT::
2183
2184 id : <id_given_in_input>
2185 result: {
2186 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
2187 "success": true
2188 }
2189 error: null
2190
2191 ERROR OUTPUT::
2192
2193 id : <id_given_in_input>
2194 result : null
2195 error : {
2196 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
2197 }
2198
2199 """
2200
2201 repo_group = get_repo_group_or_error(repogroupid)
2202
2203 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
2204 # check if we have admin permission for this repo group !
2205 if not HasRepoGroupPermissionAnyApi('group.admin')(user=apiuser,
2206 group_name=repo_group.group_name):
2207 raise JSONRPCError('repository group `%s` does not exist' % (repogroupid,))
2208
2209 user = get_user_or_error(userid)
2210 perm = get_perm_or_error(perm, prefix='group.')
2211 apply_to_children = Optional.extract(apply_to_children)
2212
2213 try:
2214 RepoGroupModel().add_permission(repo_group=repo_group,
2215 obj=user,
2216 obj_type="user",
2217 perm=perm,
2218 recursive=apply_to_children)
2219 Session().commit()
2220 return dict(
2221 msg='Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
2222 perm.permission_name, apply_to_children, user.username, repo_group.name
2223 ),
2224 success=True
2225 )
2226 except Exception:
2227 log.error(traceback.format_exc())
2228 raise JSONRPCError(
2229 'failed to edit permission for user: `%s` in repo group: `%s`' % (
2230 userid, repo_group.name))
2231
2232 # permission check inside
2233 def revoke_user_permission_from_repo_group(self, apiuser, repogroupid, userid,
2234 apply_to_children=Optional('none')):
2235 """
2236 Revoke permission for user on given repository group. This command can
2237 be executed only using api_key belonging to user with admin rights, or
2238 user who has admin right to given repository group.
2239
2240 :param apiuser: filled automatically from apikey
2241 :type apiuser: AuthUser
2242 :param repogroupid: name or id of repository group
2243 :type repogroupid: str or int
2244 :param userid:
2245 :type userid:
2246 :param apply_to_children: 'none', 'repos', 'groups', 'all'
2247 :type apply_to_children: str
2248
2249 OUTPUT::
2250
2251 id : <id_given_in_input>
2252 result: {
2253 "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
2254 "success": true
2255 }
2256 error: null
2257
2258 ERROR OUTPUT::
2259
2260 id : <id_given_in_input>
2261 result : null
2262 error : {
2263 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
2264 }
2265
2266 """
2267
2268 repo_group = get_repo_group_or_error(repogroupid)
2269
2270 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
2271 # check if we have admin permission for this repo group !
2272 if not HasRepoGroupPermissionAnyApi('group.admin')(user=apiuser,
2273 group_name=repo_group.group_name):
2274 raise JSONRPCError('repository group `%s` does not exist' % (repogroupid,))
2275
2276 user = get_user_or_error(userid)
2277 apply_to_children = Optional.extract(apply_to_children)
2278
2279 try:
2280 RepoGroupModel().delete_permission(repo_group=repo_group,
2281 obj=user,
2282 obj_type="user",
2283 recursive=apply_to_children)
2284
2285 Session().commit()
2286 return dict(
2287 msg='Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
2288 apply_to_children, user.username, repo_group.name
2289 ),
2290 success=True
2291 )
2292 except Exception:
2293 log.error(traceback.format_exc())
2294 raise JSONRPCError(
2295 'failed to edit permission for user: `%s` in repo group: `%s`' % (
2296 userid, repo_group.name))
2297
2298 # permission check inside
2299 def grant_user_group_permission_to_repo_group(
2300 self, apiuser, repogroupid, usergroupid, perm,
2301 apply_to_children=Optional('none'),):
2302 """
2303 Grant permission for user group on given repository group, or update
2304 existing one if found. This command can be executed only using
2305 api_key belonging to user with admin rights, or user who has admin
2306 right to given repository group.
2307
2308 :param apiuser: filled automatically from apikey
2309 :type apiuser: AuthUser
2310 :param repogroupid: name or id of repository group
2311 :type repogroupid: str or int
2312 :param usergroupid: id of usergroup
2313 :type usergroupid: str or int
2314 :param perm: (group.(none|read|write|admin))
2315 :type perm: str
2316 :param apply_to_children: 'none', 'repos', 'groups', 'all'
2317 :type apply_to_children: str
2318
2319 OUTPUT::
2320
2321 id : <id_given_in_input>
2322 result : {
2323 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
2324 "success": true
2325
2326 }
2327 error : null
2328
2329 ERROR OUTPUT::
2330
2331 id : <id_given_in_input>
2332 result : null
2333 error : {
2334 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
2335 }
2336
2337 """
2338 repo_group = get_repo_group_or_error(repogroupid)
2339 perm = get_perm_or_error(perm, prefix='group.')
2340 user_group = get_user_group_or_error(usergroupid)
2341 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
2342 # check if we have admin permission for this repo group !
2343 _perms = ('group.admin',)
2344 if not HasRepoGroupPermissionAnyApi(*_perms)(
2345 user=apiuser, group_name=repo_group.group_name):
2346 raise JSONRPCError(
2347 'repository group `%s` does not exist' % (repogroupid,))
2348
2349 # check if we have at least read permission for this user group !
2350 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
2351 if not HasUserGroupPermissionAny(*_perms)(
2352 user=apiuser, user_group_name=user_group.users_group_name):
2353 raise JSONRPCError(
2354 'user group `%s` does not exist' % (usergroupid,))
2355
2356 apply_to_children = Optional.extract(apply_to_children)
2357
2358 try:
2359 RepoGroupModel().add_permission(repo_group=repo_group,
2360 obj=user_group,
2361 obj_type="user_group",
2362 perm=perm,
2363 recursive=apply_to_children)
2364 Session().commit()
2365 return dict(
2366 msg='Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2367 perm.permission_name, apply_to_children,
2368 user_group.users_group_name, repo_group.name
2369 ),
2370 success=True
2371 )
2372 except Exception:
2373 log.error(traceback.format_exc())
2374 raise JSONRPCError(
2375 'failed to edit permission for user group: `%s` in '
2376 'repo group: `%s`' % (
2377 usergroupid, repo_group.name
2378 )
2379 )
2380
2381 # permission check inside
2382 def revoke_user_group_permission_from_repo_group(
2383 self, apiuser, repogroupid, usergroupid,
2384 apply_to_children=Optional('none')):
2385 """
2386 Revoke permission for user group on given repository. This command can be
2387 executed only using api_key belonging to user with admin rights, or
2388 user who has admin right to given repository group.
2389
2390 :param apiuser: filled automatically from apikey
2391 :type apiuser: AuthUser
2392 :param repogroupid: name or id of repository group
2393 :type repogroupid: str or int
2394 :param usergroupid:
2395 :param apply_to_children: 'none', 'repos', 'groups', 'all'
2396 :type apply_to_children: str
2397
2398 OUTPUT::
2399
2400 id : <id_given_in_input>
2401 result: {
2402 "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
2403 "success": true
2404 }
2405 error: null
2406
2407 ERROR OUTPUT::
2408
2409 id : <id_given_in_input>
2410 result : null
2411 error : {
2412 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
2413 }
2414
2415
2416 """
2417 repo_group = get_repo_group_or_error(repogroupid)
2418 user_group = get_user_group_or_error(usergroupid)
2419 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
2420 # check if we have admin permission for this repo group !
2421 _perms = ('group.admin',)
2422 if not HasRepoGroupPermissionAnyApi(*_perms)(
2423 user=apiuser, group_name=repo_group.group_name):
2424 raise JSONRPCError(
2425 'repository group `%s` does not exist' % (repogroupid,))
2426
2427 # check if we have at least read permission for this user group !
2428 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
2429 if not HasUserGroupPermissionAny(*_perms)(
2430 user=apiuser, user_group_name=user_group.users_group_name):
2431 raise JSONRPCError(
2432 'user group `%s` does not exist' % (usergroupid,))
2433
2434 apply_to_children = Optional.extract(apply_to_children)
2435
2436 try:
2437 RepoGroupModel().delete_permission(repo_group=repo_group,
2438 obj=user_group,
2439 obj_type="user_group",
2440 recursive=apply_to_children)
2441 Session().commit()
2442 return dict(
2443 msg='Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2444 apply_to_children, user_group.users_group_name, repo_group.name
2445 ),
2446 success=True
2447 )
2448 except Exception:
2449 log.error(traceback.format_exc())
2450 raise JSONRPCError(
2451 'failed to edit permission for user group: `%s` in repo group: `%s`' % (
2452 user_group.users_group_name, repo_group.name
2453 )
2454 )
2455
2456 def get_gist(self, apiuser, gistid):
2457 """
2458 Get given gist by id
2459
2460 :param apiuser: filled automatically from apikey
2461 :type apiuser: AuthUser
2462 :param gistid: id of private or public gist
2463 :type gistid: str
2464 """
2465 gist = get_gist_or_error(gistid)
2466 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
2467 if gist.gist_owner != apiuser.user_id:
2468 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
2469 return gist.get_api_data()
2470
2471 def get_gists(self, apiuser, userid=Optional(OAttr('apiuser'))):
2472 """
2473 Get all gists for given user. If userid is empty returned gists
2474 are for user who called the api
2475
2476 :param apiuser: filled automatically from apikey
2477 :type apiuser: AuthUser
2478 :param userid: user to get gists for
2479 :type userid: Optional(str or int)
2480 """
2481 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
2482 # make sure normal user does not pass someone else userid,
2483 # he is not allowed to do that
2484 if not isinstance(userid, Optional) and userid != apiuser.user_id:
2485 raise JSONRPCError(
2486 'userid is not the same as your user'
2487 )
2488
2489 if isinstance(userid, Optional):
2490 user_id = apiuser.user_id
2491 else:
2492 user_id = get_user_or_error(userid).user_id
2493
2494 gists = []
2495 _gists = Gist().query()\
2496 .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\
2497 .filter(Gist.gist_owner == user_id)\
2498 .order_by(Gist.created_on.desc())
2499 for gist in _gists:
2500 gists.append(gist.get_api_data())
2501 return gists
1157 2502
1158 def create_gist(self, apiuser, files, owner=Optional(OAttr('apiuser')), 2503 def create_gist(self, apiuser, files, owner=Optional(OAttr('apiuser')),
1159 gist_type=Optional(Gist.GIST_PUBLIC), lifetime=Optional(-1), 2504 gist_type=Optional(Gist.GIST_PUBLIC), lifetime=Optional(-1),
1160 description=Optional('')): 2505 description=Optional('')):
1161 2506
2507 """
2508 Creates new Gist
2509
2510 :param apiuser: filled automatically from apikey
2511 :type apiuser: AuthUser
2512 :param files: files to be added to gist
2513 {'filename': {'content':'...', 'lexer': null},
2514 'filename2': {'content':'...', 'lexer': null}}
2515 :type files: dict
2516 :param owner: gist owner, defaults to api method caller
2517 :type owner: Optional(str or int)
2518 :param gist_type: type of gist 'public' or 'private'
2519 :type gist_type: Optional(str)
2520 :param lifetime: time in minutes of gist lifetime
2521 :type lifetime: Optional(int)
2522 :param description: gist description
2523 :type description: Optional(str)
2524
2525 OUTPUT::
2526
2527 id : <id_given_in_input>
2528 result : {
2529 "msg": "created new gist",
2530 "gist": {}
2531 }
2532 error : null
2533
2534 ERROR OUTPUT::
2535
2536 id : <id_given_in_input>
2537 result : null
2538 error : {
2539 "failed to create gist"
2540 }
2541
2542 """
1162 try: 2543 try:
1163 if isinstance(owner, Optional): 2544 if isinstance(owner, Optional):
1164 owner = apiuser.user_id 2545 owner = apiuser.user_id
1165 2546
1166 owner = get_user_or_error(owner) 2547 owner = get_user_or_error(owner)
1167 description = Optional.extract(description) 2548 description = Optional.extract(description)
1168 gist_type = Optional.extract(gist_type) 2549 gist_type = Optional.extract(gist_type)
1169 lifetime = Optional.extract(lifetime) 2550 lifetime = Optional.extract(lifetime)
1170 2551
1171 # files: {
1172 # 'filename': {'content':'...', 'lexer': null},
1173 # 'filename2': {'content':'...', 'lexer': null}
1174 #}
1175 gist = GistModel().create(description=description, 2552 gist = GistModel().create(description=description,
1176 owner=owner, 2553 owner=owner,
1177 gist_mapping=files, 2554 gist_mapping=files,
1178 gist_type=gist_type, 2555 gist_type=gist_type,
1179 lifetime=lifetime) 2556 lifetime=lifetime)
1183 gist=gist.get_api_data() 2560 gist=gist.get_api_data()
1184 ) 2561 )
1185 except Exception: 2562 except Exception:
1186 log.error(traceback.format_exc()) 2563 log.error(traceback.format_exc())
1187 raise JSONRPCError('failed to create gist') 2564 raise JSONRPCError('failed to create gist')
2565
2566 # def update_gist(self, apiuser, gistid, files, owner=Optional(OAttr('apiuser')),
2567 # gist_type=Optional(Gist.GIST_PUBLIC),
2568 # gist_lifetime=Optional(-1), gist_description=Optional('')):
2569 # gist = get_gist_or_error(gistid)
2570 # updates = {}
2571
2572 # permission check inside
2573 def delete_gist(self, apiuser, gistid):
2574 """
2575 Deletes existing gist
2576
2577 :param apiuser: filled automatically from apikey
2578 :type apiuser: AuthUser
2579 :param gistid: id of gist to delete
2580 :type gistid: str
2581
2582 OUTPUT::
2583
2584 id : <id_given_in_input>
2585 result : {
2586 "deleted gist ID: <gist_id>",
2587 "gist": null
2588 }
2589 error : null
2590
2591 ERROR OUTPUT::
2592
2593 id : <id_given_in_input>
2594 result : null
2595 error : {
2596 "failed to delete gist ID:<gist_id>"
2597 }
2598
2599 """
2600 gist = get_gist_or_error(gistid)
2601 if not HasPermissionAnyApi('hg.admin')(user=apiuser):
2602 if gist.gist_owner != apiuser.user_id:
2603 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
2604
2605 try:
2606 GistModel().delete(gist)
2607 Session().commit()
2608 return dict(
2609 msg='deleted gist ID:%s' % (gist.gist_access_id,),
2610 gist=None
2611 )
2612 except Exception:
2613 log.error(traceback.format_exc())
2614 raise JSONRPCError('failed to delete gist ID:%s'
2615 % (gist.gist_access_id,))