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