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