##// END OF EJS Templates
make the permission update function idempotent
marcink -
r3730:e42e1d4e beta
parent child Browse files
Show More
@@ -1,1039 +1,1039 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 return ('Cache for repository `%s` was invalidated: '
224 return ('Cache for repository `%s` was invalidated: '
225 'invalidated cache keys: %s' % (repoid, invalidated_keys))
225 'invalidated cache keys: %s' % (repoid, invalidated_keys))
226 except Exception:
226 except Exception:
227 log.error(traceback.format_exc())
227 log.error(traceback.format_exc())
228 raise JSONRPCError(
228 raise JSONRPCError(
229 'Error occurred during cache invalidation action'
229 'Error occurred during cache invalidation action'
230 )
230 )
231
231
232 def lock(self, apiuser, repoid, locked=Optional(None),
232 def lock(self, apiuser, repoid, locked=Optional(None),
233 userid=Optional(OAttr('apiuser'))):
233 userid=Optional(OAttr('apiuser'))):
234 """
234 """
235 Set locking state on particular repository by given user, if
235 Set locking state on particular repository by given user, if
236 this command is runned by non-admin account userid is set to user
236 this command is runned by non-admin account userid is set to user
237 who is calling this method
237 who is calling this method
238
238
239 :param apiuser:
239 :param apiuser:
240 :param repoid:
240 :param repoid:
241 :param userid:
241 :param userid:
242 :param locked:
242 :param locked:
243 """
243 """
244 repo = get_repo_or_error(repoid)
244 repo = get_repo_or_error(repoid)
245 if HasPermissionAnyApi('hg.admin')(user=apiuser):
245 if HasPermissionAnyApi('hg.admin')(user=apiuser):
246 pass
246 pass
247 elif HasRepoPermissionAnyApi('repository.admin',
247 elif HasRepoPermissionAnyApi('repository.admin',
248 'repository.write')(user=apiuser,
248 'repository.write')(user=apiuser,
249 repo_name=repo.repo_name):
249 repo_name=repo.repo_name):
250 #make sure normal user does not pass someone else userid,
250 #make sure normal user does not pass someone else userid,
251 #he is not allowed to do that
251 #he is not allowed to do that
252 if not isinstance(userid, Optional) and userid != apiuser.user_id:
252 if not isinstance(userid, Optional) and userid != apiuser.user_id:
253 raise JSONRPCError(
253 raise JSONRPCError(
254 'userid is not the same as your user'
254 'userid is not the same as your user'
255 )
255 )
256 else:
256 else:
257 raise JSONRPCError('repository `%s` does not exist' % (repoid))
257 raise JSONRPCError('repository `%s` does not exist' % (repoid))
258
258
259 if isinstance(userid, Optional):
259 if isinstance(userid, Optional):
260 userid = apiuser.user_id
260 userid = apiuser.user_id
261
261
262 user = get_user_or_error(userid)
262 user = get_user_or_error(userid)
263
263
264 if isinstance(locked, Optional):
264 if isinstance(locked, Optional):
265 lockobj = Repository.getlock(repo)
265 lockobj = Repository.getlock(repo)
266
266
267 if lockobj[0] is None:
267 if lockobj[0] is None:
268 return ('Repo `%s` not locked. Locked=`False`.'
268 return ('Repo `%s` not locked. Locked=`False`.'
269 % (repo.repo_name))
269 % (repo.repo_name))
270 else:
270 else:
271 userid, time_ = lockobj
271 userid, time_ = lockobj
272 user = get_user_or_error(userid)
272 user = get_user_or_error(userid)
273
273
274 return ('Repo `%s` locked by `%s`. Locked=`True`. '
274 return ('Repo `%s` locked by `%s`. Locked=`True`. '
275 'Locked since: `%s`'
275 'Locked since: `%s`'
276 % (repo.repo_name, user.username,
276 % (repo.repo_name, user.username,
277 json.dumps(time_to_datetime(time_))))
277 json.dumps(time_to_datetime(time_))))
278
278
279 else:
279 else:
280 locked = str2bool(locked)
280 locked = str2bool(locked)
281 try:
281 try:
282 if locked:
282 if locked:
283 Repository.lock(repo, user.user_id)
283 Repository.lock(repo, user.user_id)
284 else:
284 else:
285 Repository.unlock(repo)
285 Repository.unlock(repo)
286
286
287 return ('User `%s` set lock state for repo `%s` to `%s`'
287 return ('User `%s` set lock state for repo `%s` to `%s`'
288 % (user.username, repo.repo_name, locked))
288 % (user.username, repo.repo_name, locked))
289 except Exception:
289 except Exception:
290 log.error(traceback.format_exc())
290 log.error(traceback.format_exc())
291 raise JSONRPCError(
291 raise JSONRPCError(
292 'Error occurred locking repository `%s`' % repo.repo_name
292 'Error occurred locking repository `%s`' % repo.repo_name
293 )
293 )
294
294
295 def get_locks(self, apiuser, userid=Optional(OAttr('apiuser'))):
295 def get_locks(self, apiuser, userid=Optional(OAttr('apiuser'))):
296 """
296 """
297 Get all locks for given userid, if
297 Get all locks for given userid, if
298 this command is runned by non-admin account userid is set to user
298 this command is runned by non-admin account userid is set to user
299 who is calling this method, thus returning locks for himself
299 who is calling this method, thus returning locks for himself
300
300
301 :param apiuser:
301 :param apiuser:
302 :param userid:
302 :param userid:
303 """
303 """
304 if HasPermissionAnyApi('hg.admin')(user=apiuser):
304 if HasPermissionAnyApi('hg.admin')(user=apiuser):
305 pass
305 pass
306 else:
306 else:
307 #make sure normal user does not pass someone else userid,
307 #make sure normal user does not pass someone else userid,
308 #he is not allowed to do that
308 #he is not allowed to do that
309 if not isinstance(userid, Optional) and userid != apiuser.user_id:
309 if not isinstance(userid, Optional) and userid != apiuser.user_id:
310 raise JSONRPCError(
310 raise JSONRPCError(
311 'userid is not the same as your user'
311 'userid is not the same as your user'
312 )
312 )
313 ret = []
313 ret = []
314 if isinstance(userid, Optional):
314 if isinstance(userid, Optional):
315 user = None
315 user = None
316 else:
316 else:
317 user = get_user_or_error(userid)
317 user = get_user_or_error(userid)
318
318
319 #show all locks
319 #show all locks
320 for r in Repository.getAll():
320 for r in Repository.getAll():
321 userid, time_ = r.locked
321 userid, time_ = r.locked
322 if time_:
322 if time_:
323 _api_data = r.get_api_data()
323 _api_data = r.get_api_data()
324 # if we use userfilter just show the locks for this user
324 # if we use userfilter just show the locks for this user
325 if user:
325 if user:
326 if safe_int(userid) == user.user_id:
326 if safe_int(userid) == user.user_id:
327 ret.append(_api_data)
327 ret.append(_api_data)
328 else:
328 else:
329 ret.append(_api_data)
329 ret.append(_api_data)
330
330
331 return ret
331 return ret
332
332
333 @HasPermissionAllDecorator('hg.admin')
333 @HasPermissionAllDecorator('hg.admin')
334 def show_ip(self, apiuser, userid):
334 def show_ip(self, apiuser, userid):
335 """
335 """
336 Shows IP address as seen from RhodeCode server, together with all
336 Shows IP address as seen from RhodeCode server, together with all
337 defined IP addresses for given user
337 defined IP addresses for given user
338
338
339 :param apiuser:
339 :param apiuser:
340 :param userid:
340 :param userid:
341 """
341 """
342 user = get_user_or_error(userid)
342 user = get_user_or_error(userid)
343 ips = UserIpMap.query().filter(UserIpMap.user == user).all()
343 ips = UserIpMap.query().filter(UserIpMap.user == user).all()
344 return dict(
344 return dict(
345 ip_addr_server=self.ip_addr,
345 ip_addr_server=self.ip_addr,
346 user_ips=ips
346 user_ips=ips
347 )
347 )
348
348
349 def get_user(self, apiuser, userid=Optional(OAttr('apiuser'))):
349 def get_user(self, apiuser, userid=Optional(OAttr('apiuser'))):
350 """"
350 """"
351 Get a user by username, or userid, if userid is given
351 Get a user by username, or userid, if userid is given
352
352
353 :param apiuser:
353 :param apiuser:
354 :param userid:
354 :param userid:
355 """
355 """
356 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
356 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
357 #make sure normal user does not pass someone else userid,
357 #make sure normal user does not pass someone else userid,
358 #he is not allowed to do that
358 #he is not allowed to do that
359 if not isinstance(userid, Optional) and userid != apiuser.user_id:
359 if not isinstance(userid, Optional) and userid != apiuser.user_id:
360 raise JSONRPCError(
360 raise JSONRPCError(
361 'userid is not the same as your user'
361 'userid is not the same as your user'
362 )
362 )
363
363
364 if isinstance(userid, Optional):
364 if isinstance(userid, Optional):
365 userid = apiuser.user_id
365 userid = apiuser.user_id
366
366
367 user = get_user_or_error(userid)
367 user = get_user_or_error(userid)
368 data = user.get_api_data()
368 data = user.get_api_data()
369 data['permissions'] = AuthUser(user_id=user.user_id).permissions
369 data['permissions'] = AuthUser(user_id=user.user_id).permissions
370 return data
370 return data
371
371
372 @HasPermissionAllDecorator('hg.admin')
372 @HasPermissionAllDecorator('hg.admin')
373 def get_users(self, apiuser):
373 def get_users(self, apiuser):
374 """"
374 """"
375 Get all users
375 Get all users
376
376
377 :param apiuser:
377 :param apiuser:
378 """
378 """
379
379
380 result = []
380 result = []
381 for user in UserModel().get_all():
381 for user in UserModel().get_all():
382 result.append(user.get_api_data())
382 result.append(user.get_api_data())
383 return result
383 return result
384
384
385 @HasPermissionAllDecorator('hg.admin')
385 @HasPermissionAllDecorator('hg.admin')
386 def create_user(self, apiuser, username, email, password,
386 def create_user(self, apiuser, username, email, password,
387 firstname=Optional(None), lastname=Optional(None),
387 firstname=Optional(None), lastname=Optional(None),
388 active=Optional(True), admin=Optional(False),
388 active=Optional(True), admin=Optional(False),
389 ldap_dn=Optional(None)):
389 ldap_dn=Optional(None)):
390 """
390 """
391 Create new user
391 Create new user
392
392
393 :param apiuser:
393 :param apiuser:
394 :param username:
394 :param username:
395 :param email:
395 :param email:
396 :param password:
396 :param password:
397 :param firstname:
397 :param firstname:
398 :param lastname:
398 :param lastname:
399 :param active:
399 :param active:
400 :param admin:
400 :param admin:
401 :param ldap_dn:
401 :param ldap_dn:
402 """
402 """
403
403
404 if UserModel().get_by_username(username):
404 if UserModel().get_by_username(username):
405 raise JSONRPCError("user `%s` already exist" % username)
405 raise JSONRPCError("user `%s` already exist" % username)
406
406
407 if UserModel().get_by_email(email, case_insensitive=True):
407 if UserModel().get_by_email(email, case_insensitive=True):
408 raise JSONRPCError("email `%s` already exist" % email)
408 raise JSONRPCError("email `%s` already exist" % email)
409
409
410 if Optional.extract(ldap_dn):
410 if Optional.extract(ldap_dn):
411 # generate temporary password if ldap_dn
411 # generate temporary password if ldap_dn
412 password = PasswordGenerator().gen_password(length=8)
412 password = PasswordGenerator().gen_password(length=8)
413
413
414 try:
414 try:
415 user = UserModel().create_or_update(
415 user = UserModel().create_or_update(
416 username=Optional.extract(username),
416 username=Optional.extract(username),
417 password=Optional.extract(password),
417 password=Optional.extract(password),
418 email=Optional.extract(email),
418 email=Optional.extract(email),
419 firstname=Optional.extract(firstname),
419 firstname=Optional.extract(firstname),
420 lastname=Optional.extract(lastname),
420 lastname=Optional.extract(lastname),
421 active=Optional.extract(active),
421 active=Optional.extract(active),
422 admin=Optional.extract(admin),
422 admin=Optional.extract(admin),
423 ldap_dn=Optional.extract(ldap_dn)
423 ldap_dn=Optional.extract(ldap_dn)
424 )
424 )
425 Session().commit()
425 Session().commit()
426 return dict(
426 return dict(
427 msg='created new user `%s`' % username,
427 msg='created new user `%s`' % username,
428 user=user.get_api_data()
428 user=user.get_api_data()
429 )
429 )
430 except Exception:
430 except Exception:
431 log.error(traceback.format_exc())
431 log.error(traceback.format_exc())
432 raise JSONRPCError('failed to create user `%s`' % username)
432 raise JSONRPCError('failed to create user `%s`' % username)
433
433
434 @HasPermissionAllDecorator('hg.admin')
434 @HasPermissionAllDecorator('hg.admin')
435 def update_user(self, apiuser, userid, username=Optional(None),
435 def update_user(self, apiuser, userid, username=Optional(None),
436 email=Optional(None), firstname=Optional(None),
436 email=Optional(None), firstname=Optional(None),
437 lastname=Optional(None), active=Optional(None),
437 lastname=Optional(None), active=Optional(None),
438 admin=Optional(None), ldap_dn=Optional(None),
438 admin=Optional(None), ldap_dn=Optional(None),
439 password=Optional(None)):
439 password=Optional(None)):
440 """
440 """
441 Updates given user
441 Updates given user
442
442
443 :param apiuser:
443 :param apiuser:
444 :param userid:
444 :param userid:
445 :param username:
445 :param username:
446 :param email:
446 :param email:
447 :param firstname:
447 :param firstname:
448 :param lastname:
448 :param lastname:
449 :param active:
449 :param active:
450 :param admin:
450 :param admin:
451 :param ldap_dn:
451 :param ldap_dn:
452 :param password:
452 :param password:
453 """
453 """
454
454
455 user = get_user_or_error(userid)
455 user = get_user_or_error(userid)
456
456
457 # call function and store only updated arguments
457 # call function and store only updated arguments
458 updates = {}
458 updates = {}
459
459
460 def store_update(attr, name):
460 def store_update(attr, name):
461 if not isinstance(attr, Optional):
461 if not isinstance(attr, Optional):
462 updates[name] = attr
462 updates[name] = attr
463
463
464 try:
464 try:
465
465
466 store_update(username, 'username')
466 store_update(username, 'username')
467 store_update(password, 'password')
467 store_update(password, 'password')
468 store_update(email, 'email')
468 store_update(email, 'email')
469 store_update(firstname, 'name')
469 store_update(firstname, 'name')
470 store_update(lastname, 'lastname')
470 store_update(lastname, 'lastname')
471 store_update(active, 'active')
471 store_update(active, 'active')
472 store_update(admin, 'admin')
472 store_update(admin, 'admin')
473 store_update(ldap_dn, 'ldap_dn')
473 store_update(ldap_dn, 'ldap_dn')
474
474
475 user = UserModel().update_user(user, **updates)
475 user = UserModel().update_user(user, **updates)
476 Session().commit()
476 Session().commit()
477 return dict(
477 return dict(
478 msg='updated user ID:%s %s' % (user.user_id, user.username),
478 msg='updated user ID:%s %s' % (user.user_id, user.username),
479 user=user.get_api_data()
479 user=user.get_api_data()
480 )
480 )
481 except Exception:
481 except Exception:
482 log.error(traceback.format_exc())
482 log.error(traceback.format_exc())
483 raise JSONRPCError('failed to update user `%s`' % userid)
483 raise JSONRPCError('failed to update user `%s`' % userid)
484
484
485 @HasPermissionAllDecorator('hg.admin')
485 @HasPermissionAllDecorator('hg.admin')
486 def delete_user(self, apiuser, userid):
486 def delete_user(self, apiuser, userid):
487 """"
487 """"
488 Deletes an user
488 Deletes an user
489
489
490 :param apiuser:
490 :param apiuser:
491 :param userid:
491 :param userid:
492 """
492 """
493 user = get_user_or_error(userid)
493 user = get_user_or_error(userid)
494
494
495 try:
495 try:
496 UserModel().delete(userid)
496 UserModel().delete(userid)
497 Session().commit()
497 Session().commit()
498 return dict(
498 return dict(
499 msg='deleted user ID:%s %s' % (user.user_id, user.username),
499 msg='deleted user ID:%s %s' % (user.user_id, user.username),
500 user=None
500 user=None
501 )
501 )
502 except Exception:
502 except Exception:
503 log.error(traceback.format_exc())
503 log.error(traceback.format_exc())
504 raise JSONRPCError('failed to delete ID:%s %s' % (user.user_id,
504 raise JSONRPCError('failed to delete ID:%s %s' % (user.user_id,
505 user.username))
505 user.username))
506
506
507 @HasPermissionAllDecorator('hg.admin')
507 @HasPermissionAllDecorator('hg.admin')
508 def get_users_group(self, apiuser, usersgroupid):
508 def get_users_group(self, apiuser, usersgroupid):
509 """"
509 """"
510 Get user group by name or id
510 Get user group by name or id
511
511
512 :param apiuser:
512 :param apiuser:
513 :param usersgroupid:
513 :param usersgroupid:
514 """
514 """
515 users_group = get_users_group_or_error(usersgroupid)
515 users_group = get_users_group_or_error(usersgroupid)
516
516
517 data = users_group.get_api_data()
517 data = users_group.get_api_data()
518
518
519 members = []
519 members = []
520 for user in users_group.members:
520 for user in users_group.members:
521 user = user.user
521 user = user.user
522 members.append(user.get_api_data())
522 members.append(user.get_api_data())
523 data['members'] = members
523 data['members'] = members
524 return data
524 return data
525
525
526 @HasPermissionAllDecorator('hg.admin')
526 @HasPermissionAllDecorator('hg.admin')
527 def get_users_groups(self, apiuser):
527 def get_users_groups(self, apiuser):
528 """"
528 """"
529 Get all user groups
529 Get all user groups
530
530
531 :param apiuser:
531 :param apiuser:
532 """
532 """
533
533
534 result = []
534 result = []
535 for users_group in UserGroupModel().get_all():
535 for users_group in UserGroupModel().get_all():
536 result.append(users_group.get_api_data())
536 result.append(users_group.get_api_data())
537 return result
537 return result
538
538
539 @HasPermissionAllDecorator('hg.admin')
539 @HasPermissionAllDecorator('hg.admin')
540 def create_users_group(self, apiuser, group_name,
540 def create_users_group(self, apiuser, group_name,
541 owner=Optional(OAttr('apiuser')),
541 owner=Optional(OAttr('apiuser')),
542 active=Optional(True)):
542 active=Optional(True)):
543 """
543 """
544 Creates an new usergroup
544 Creates an new usergroup
545
545
546 :param apiuser:
546 :param apiuser:
547 :param group_name:
547 :param group_name:
548 :param owner:
548 :param owner:
549 :param active:
549 :param active:
550 """
550 """
551
551
552 if UserGroupModel().get_by_name(group_name):
552 if UserGroupModel().get_by_name(group_name):
553 raise JSONRPCError("user group `%s` already exist" % group_name)
553 raise JSONRPCError("user group `%s` already exist" % group_name)
554
554
555 try:
555 try:
556 if isinstance(owner, Optional):
556 if isinstance(owner, Optional):
557 owner = apiuser.user_id
557 owner = apiuser.user_id
558
558
559 owner = get_user_or_error(owner)
559 owner = get_user_or_error(owner)
560 active = Optional.extract(active)
560 active = Optional.extract(active)
561 ug = UserGroupModel().create(name=group_name,
561 ug = UserGroupModel().create(name=group_name,
562 owner=owner,
562 owner=owner,
563 active=active)
563 active=active)
564 Session().commit()
564 Session().commit()
565 return dict(
565 return dict(
566 msg='created new user group `%s`' % group_name,
566 msg='created new user group `%s`' % group_name,
567 users_group=ug.get_api_data()
567 users_group=ug.get_api_data()
568 )
568 )
569 except Exception:
569 except Exception:
570 log.error(traceback.format_exc())
570 log.error(traceback.format_exc())
571 raise JSONRPCError('failed to create group `%s`' % group_name)
571 raise JSONRPCError('failed to create group `%s`' % group_name)
572
572
573 @HasPermissionAllDecorator('hg.admin')
573 @HasPermissionAllDecorator('hg.admin')
574 def add_user_to_users_group(self, apiuser, usersgroupid, userid):
574 def add_user_to_users_group(self, apiuser, usersgroupid, userid):
575 """"
575 """"
576 Add a user to a user group
576 Add a user to a user group
577
577
578 :param apiuser:
578 :param apiuser:
579 :param usersgroupid:
579 :param usersgroupid:
580 :param userid:
580 :param userid:
581 """
581 """
582 user = get_user_or_error(userid)
582 user = get_user_or_error(userid)
583 users_group = get_users_group_or_error(usersgroupid)
583 users_group = get_users_group_or_error(usersgroupid)
584
584
585 try:
585 try:
586 ugm = UserGroupModel().add_user_to_group(users_group, user)
586 ugm = UserGroupModel().add_user_to_group(users_group, user)
587 success = True if ugm != True else False
587 success = True if ugm != True else False
588 msg = 'added member `%s` to user group `%s`' % (
588 msg = 'added member `%s` to user group `%s`' % (
589 user.username, users_group.users_group_name
589 user.username, users_group.users_group_name
590 )
590 )
591 msg = msg if success else 'User is already in that group'
591 msg = msg if success else 'User is already in that group'
592 Session().commit()
592 Session().commit()
593
593
594 return dict(
594 return dict(
595 success=success,
595 success=success,
596 msg=msg
596 msg=msg
597 )
597 )
598 except Exception:
598 except Exception:
599 log.error(traceback.format_exc())
599 log.error(traceback.format_exc())
600 raise JSONRPCError(
600 raise JSONRPCError(
601 'failed to add member to user group `%s`' % (
601 'failed to add member to user group `%s`' % (
602 users_group.users_group_name
602 users_group.users_group_name
603 )
603 )
604 )
604 )
605
605
606 @HasPermissionAllDecorator('hg.admin')
606 @HasPermissionAllDecorator('hg.admin')
607 def remove_user_from_users_group(self, apiuser, usersgroupid, userid):
607 def remove_user_from_users_group(self, apiuser, usersgroupid, userid):
608 """
608 """
609 Remove user from a group
609 Remove user from a group
610
610
611 :param apiuser:
611 :param apiuser:
612 :param usersgroupid:
612 :param usersgroupid:
613 :param userid:
613 :param userid:
614 """
614 """
615 user = get_user_or_error(userid)
615 user = get_user_or_error(userid)
616 users_group = get_users_group_or_error(usersgroupid)
616 users_group = get_users_group_or_error(usersgroupid)
617
617
618 try:
618 try:
619 success = UserGroupModel().remove_user_from_group(users_group,
619 success = UserGroupModel().remove_user_from_group(users_group,
620 user)
620 user)
621 msg = 'removed member `%s` from user group `%s`' % (
621 msg = 'removed member `%s` from user group `%s`' % (
622 user.username, users_group.users_group_name
622 user.username, users_group.users_group_name
623 )
623 )
624 msg = msg if success else "User wasn't in group"
624 msg = msg if success else "User wasn't in group"
625 Session().commit()
625 Session().commit()
626 return dict(success=success, msg=msg)
626 return dict(success=success, msg=msg)
627 except Exception:
627 except Exception:
628 log.error(traceback.format_exc())
628 log.error(traceback.format_exc())
629 raise JSONRPCError(
629 raise JSONRPCError(
630 'failed to remove member from user group `%s`' % (
630 'failed to remove member from user group `%s`' % (
631 users_group.users_group_name
631 users_group.users_group_name
632 )
632 )
633 )
633 )
634
634
635 def get_repo(self, apiuser, repoid):
635 def get_repo(self, apiuser, repoid):
636 """"
636 """"
637 Get repository by name
637 Get repository by name
638
638
639 :param apiuser:
639 :param apiuser:
640 :param repoid:
640 :param repoid:
641 """
641 """
642 repo = get_repo_or_error(repoid)
642 repo = get_repo_or_error(repoid)
643
643
644 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
644 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
645 # check if we have admin permission for this repo !
645 # check if we have admin permission for this repo !
646 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
646 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
647 repo_name=repo.repo_name) is False:
647 repo_name=repo.repo_name) is False:
648 raise JSONRPCError('repository `%s` does not exist' % (repoid))
648 raise JSONRPCError('repository `%s` does not exist' % (repoid))
649
649
650 members = []
650 members = []
651 followers = []
651 followers = []
652 for user in repo.repo_to_perm:
652 for user in repo.repo_to_perm:
653 perm = user.permission.permission_name
653 perm = user.permission.permission_name
654 user = user.user
654 user = user.user
655 user_data = user.get_api_data()
655 user_data = user.get_api_data()
656 user_data['type'] = "user"
656 user_data['type'] = "user"
657 user_data['permission'] = perm
657 user_data['permission'] = perm
658 members.append(user_data)
658 members.append(user_data)
659
659
660 for users_group in repo.users_group_to_perm:
660 for users_group in repo.users_group_to_perm:
661 perm = users_group.permission.permission_name
661 perm = users_group.permission.permission_name
662 users_group = users_group.users_group
662 users_group = users_group.users_group
663 users_group_data = users_group.get_api_data()
663 users_group_data = users_group.get_api_data()
664 users_group_data['type'] = "users_group"
664 users_group_data['type'] = "users_group"
665 users_group_data['permission'] = perm
665 users_group_data['permission'] = perm
666 members.append(users_group_data)
666 members.append(users_group_data)
667
667
668 for user in repo.followers:
668 for user in repo.followers:
669 followers.append(user.user.get_api_data())
669 followers.append(user.user.get_api_data())
670
670
671 data = repo.get_api_data()
671 data = repo.get_api_data()
672 data['members'] = members
672 data['members'] = members
673 data['followers'] = followers
673 data['followers'] = followers
674 return data
674 return data
675
675
676 def get_repos(self, apiuser):
676 def get_repos(self, apiuser):
677 """"
677 """"
678 Get all repositories
678 Get all repositories
679
679
680 :param apiuser:
680 :param apiuser:
681 """
681 """
682 result = []
682 result = []
683 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
683 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
684 repos = RepoModel().get_all_user_repos(user=apiuser)
684 repos = RepoModel().get_all_user_repos(user=apiuser)
685 else:
685 else:
686 repos = RepoModel().get_all()
686 repos = RepoModel().get_all()
687
687
688 for repo in repos:
688 for repo in repos:
689 result.append(repo.get_api_data())
689 result.append(repo.get_api_data())
690 return result
690 return result
691
691
692 @HasPermissionAllDecorator('hg.admin')
692 @HasPermissionAllDecorator('hg.admin')
693 def get_repo_nodes(self, apiuser, repoid, revision, root_path,
693 def get_repo_nodes(self, apiuser, repoid, revision, root_path,
694 ret_type='all'):
694 ret_type='all'):
695 """
695 """
696 returns a list of nodes and it's children
696 returns a list of nodes and it's children
697 for a given path at given revision. It's possible to specify ret_type
697 for a given path at given revision. It's possible to specify ret_type
698 to show only files or dirs
698 to show only files or dirs
699
699
700 :param apiuser:
700 :param apiuser:
701 :param repoid: name or id of repository
701 :param repoid: name or id of repository
702 :param revision: revision for which listing should be done
702 :param revision: revision for which listing should be done
703 :param root_path: path from which start displaying
703 :param root_path: path from which start displaying
704 :param ret_type: return type 'all|files|dirs' nodes
704 :param ret_type: return type 'all|files|dirs' nodes
705 """
705 """
706 repo = get_repo_or_error(repoid)
706 repo = get_repo_or_error(repoid)
707 try:
707 try:
708 _d, _f = ScmModel().get_nodes(repo, revision, root_path,
708 _d, _f = ScmModel().get_nodes(repo, revision, root_path,
709 flat=False)
709 flat=False)
710 _map = {
710 _map = {
711 'all': _d + _f,
711 'all': _d + _f,
712 'files': _f,
712 'files': _f,
713 'dirs': _d,
713 'dirs': _d,
714 }
714 }
715 return _map[ret_type]
715 return _map[ret_type]
716 except KeyError:
716 except KeyError:
717 raise JSONRPCError('ret_type must be one of %s' % _map.keys())
717 raise JSONRPCError('ret_type must be one of %s' % _map.keys())
718 except Exception:
718 except Exception:
719 log.error(traceback.format_exc())
719 log.error(traceback.format_exc())
720 raise JSONRPCError(
720 raise JSONRPCError(
721 'failed to get repo: `%s` nodes' % repo.repo_name
721 'failed to get repo: `%s` nodes' % repo.repo_name
722 )
722 )
723
723
724 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
724 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
725 def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')),
725 def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')),
726 repo_type=Optional('hg'),
726 repo_type=Optional('hg'),
727 description=Optional(''), private=Optional(False),
727 description=Optional(''), private=Optional(False),
728 clone_uri=Optional(None), landing_rev=Optional('tip'),
728 clone_uri=Optional(None), landing_rev=Optional('tip'),
729 enable_statistics=Optional(False),
729 enable_statistics=Optional(False),
730 enable_locking=Optional(False),
730 enable_locking=Optional(False),
731 enable_downloads=Optional(False)):
731 enable_downloads=Optional(False)):
732 """
732 """
733 Create repository, if clone_url is given it makes a remote clone
733 Create repository, if clone_url is given it makes a remote clone
734 if repo_name is within a group name the groups will be created
734 if repo_name is within a group name the groups will be created
735 automatically if they aren't present
735 automatically if they aren't present
736
736
737 :param apiuser:
737 :param apiuser:
738 :param repo_name:
738 :param repo_name:
739 :param onwer:
739 :param onwer:
740 :param repo_type:
740 :param repo_type:
741 :param description:
741 :param description:
742 :param private:
742 :param private:
743 :param clone_uri:
743 :param clone_uri:
744 :param landing_rev:
744 :param landing_rev:
745 """
745 """
746 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
746 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
747 if not isinstance(owner, Optional):
747 if not isinstance(owner, Optional):
748 #forbid setting owner for non-admins
748 #forbid setting owner for non-admins
749 raise JSONRPCError(
749 raise JSONRPCError(
750 'Only RhodeCode admin can specify `owner` param'
750 'Only RhodeCode admin can specify `owner` param'
751 )
751 )
752 if isinstance(owner, Optional):
752 if isinstance(owner, Optional):
753 owner = apiuser.user_id
753 owner = apiuser.user_id
754
754
755 owner = get_user_or_error(owner)
755 owner = get_user_or_error(owner)
756
756
757 if RepoModel().get_by_repo_name(repo_name):
757 if RepoModel().get_by_repo_name(repo_name):
758 raise JSONRPCError("repo `%s` already exist" % repo_name)
758 raise JSONRPCError("repo `%s` already exist" % repo_name)
759
759
760 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
760 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
761 if isinstance(private, Optional):
761 if isinstance(private, Optional):
762 private = defs.get('repo_private') or Optional.extract(private)
762 private = defs.get('repo_private') or Optional.extract(private)
763 if isinstance(repo_type, Optional):
763 if isinstance(repo_type, Optional):
764 repo_type = defs.get('repo_type')
764 repo_type = defs.get('repo_type')
765 if isinstance(enable_statistics, Optional):
765 if isinstance(enable_statistics, Optional):
766 enable_statistics = defs.get('repo_enable_statistics')
766 enable_statistics = defs.get('repo_enable_statistics')
767 if isinstance(enable_locking, Optional):
767 if isinstance(enable_locking, Optional):
768 enable_locking = defs.get('repo_enable_locking')
768 enable_locking = defs.get('repo_enable_locking')
769 if isinstance(enable_downloads, Optional):
769 if isinstance(enable_downloads, Optional):
770 enable_downloads = defs.get('repo_enable_downloads')
770 enable_downloads = defs.get('repo_enable_downloads')
771
771
772 clone_uri = Optional.extract(clone_uri)
772 clone_uri = Optional.extract(clone_uri)
773 description = Optional.extract(description)
773 description = Optional.extract(description)
774 landing_rev = Optional.extract(landing_rev)
774 landing_rev = Optional.extract(landing_rev)
775
775
776 try:
776 try:
777 # create structure of groups and return the last group
777 # create structure of groups and return the last group
778 group = map_groups(repo_name)
778 group = map_groups(repo_name)
779
779
780 repo = RepoModel().create_repo(
780 repo = RepoModel().create_repo(
781 repo_name=repo_name,
781 repo_name=repo_name,
782 repo_type=repo_type,
782 repo_type=repo_type,
783 description=description,
783 description=description,
784 owner=owner,
784 owner=owner,
785 private=private,
785 private=private,
786 clone_uri=clone_uri,
786 clone_uri=clone_uri,
787 repos_group=group,
787 repos_group=group,
788 landing_rev=landing_rev,
788 landing_rev=landing_rev,
789 enable_statistics=enable_statistics,
789 enable_statistics=enable_statistics,
790 enable_downloads=enable_downloads,
790 enable_downloads=enable_downloads,
791 enable_locking=enable_locking
791 enable_locking=enable_locking
792 )
792 )
793
793
794 Session().commit()
794 Session().commit()
795 return dict(
795 return dict(
796 msg="Created new repository `%s`" % (repo.repo_name),
796 msg="Created new repository `%s`" % (repo.repo_name),
797 repo=repo.get_api_data()
797 repo=repo.get_api_data()
798 )
798 )
799 except Exception:
799 except Exception:
800 log.error(traceback.format_exc())
800 log.error(traceback.format_exc())
801 raise JSONRPCError('failed to create repository `%s`' % repo_name)
801 raise JSONRPCError('failed to create repository `%s`' % repo_name)
802
802
803 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
803 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
804 def fork_repo(self, apiuser, repoid, fork_name, owner=Optional(OAttr('apiuser')),
804 def fork_repo(self, apiuser, repoid, fork_name, owner=Optional(OAttr('apiuser')),
805 description=Optional(''), copy_permissions=Optional(False),
805 description=Optional(''), copy_permissions=Optional(False),
806 private=Optional(False), landing_rev=Optional('tip')):
806 private=Optional(False), landing_rev=Optional('tip')):
807 repo = get_repo_or_error(repoid)
807 repo = get_repo_or_error(repoid)
808 repo_name = repo.repo_name
808 repo_name = repo.repo_name
809
809
810 _repo = RepoModel().get_by_repo_name(fork_name)
810 _repo = RepoModel().get_by_repo_name(fork_name)
811 if _repo:
811 if _repo:
812 type_ = 'fork' if _repo.fork else 'repo'
812 type_ = 'fork' if _repo.fork else 'repo'
813 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
813 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
814
814
815 if HasPermissionAnyApi('hg.admin')(user=apiuser):
815 if HasPermissionAnyApi('hg.admin')(user=apiuser):
816 pass
816 pass
817 elif HasRepoPermissionAnyApi('repository.admin',
817 elif HasRepoPermissionAnyApi('repository.admin',
818 'repository.write',
818 'repository.write',
819 'repository.read')(user=apiuser,
819 'repository.read')(user=apiuser,
820 repo_name=repo.repo_name):
820 repo_name=repo.repo_name):
821 if not isinstance(owner, Optional):
821 if not isinstance(owner, Optional):
822 #forbid setting owner for non-admins
822 #forbid setting owner for non-admins
823 raise JSONRPCError(
823 raise JSONRPCError(
824 'Only RhodeCode admin can specify `owner` param'
824 'Only RhodeCode admin can specify `owner` param'
825 )
825 )
826 else:
826 else:
827 raise JSONRPCError('repository `%s` does not exist' % (repoid))
827 raise JSONRPCError('repository `%s` does not exist' % (repoid))
828
828
829 if isinstance(owner, Optional):
829 if isinstance(owner, Optional):
830 owner = apiuser.user_id
830 owner = apiuser.user_id
831
831
832 owner = get_user_or_error(owner)
832 owner = get_user_or_error(owner)
833
833
834 try:
834 try:
835 # create structure of groups and return the last group
835 # create structure of groups and return the last group
836 group = map_groups(fork_name)
836 group = map_groups(fork_name)
837
837
838 form_data = dict(
838 form_data = dict(
839 repo_name=fork_name,
839 repo_name=fork_name,
840 repo_name_full=fork_name,
840 repo_name_full=fork_name,
841 repo_group=group,
841 repo_group=group,
842 repo_type=repo.repo_type,
842 repo_type=repo.repo_type,
843 description=Optional.extract(description),
843 description=Optional.extract(description),
844 private=Optional.extract(private),
844 private=Optional.extract(private),
845 copy_permissions=Optional.extract(copy_permissions),
845 copy_permissions=Optional.extract(copy_permissions),
846 landing_rev=Optional.extract(landing_rev),
846 landing_rev=Optional.extract(landing_rev),
847 update_after_clone=False,
847 update_after_clone=False,
848 fork_parent_id=repo.repo_id,
848 fork_parent_id=repo.repo_id,
849 )
849 )
850 RepoModel().create_fork(form_data, cur_user=owner)
850 RepoModel().create_fork(form_data, cur_user=owner)
851 return dict(
851 return dict(
852 msg='Created fork of `%s` as `%s`' % (repo.repo_name,
852 msg='Created fork of `%s` as `%s`' % (repo.repo_name,
853 fork_name),
853 fork_name),
854 success=True # cannot return the repo data here since fork
854 success=True # cannot return the repo data here since fork
855 # cann be done async
855 # cann be done async
856 )
856 )
857 except Exception:
857 except Exception:
858 log.error(traceback.format_exc())
858 log.error(traceback.format_exc())
859 raise JSONRPCError(
859 raise JSONRPCError(
860 'failed to fork repository `%s` as `%s`' % (repo_name,
860 'failed to fork repository `%s` as `%s`' % (repo_name,
861 fork_name)
861 fork_name)
862 )
862 )
863
863
864 def delete_repo(self, apiuser, repoid, forks=Optional(None)):
864 def delete_repo(self, apiuser, repoid, forks=Optional(None)):
865 """
865 """
866 Deletes a given repository
866 Deletes a given repository
867
867
868 :param apiuser:
868 :param apiuser:
869 :param repoid:
869 :param repoid:
870 :param forks: detach or delete, what do do with attached forks for repo
870 :param forks: detach or delete, what do do with attached forks for repo
871 """
871 """
872 repo = get_repo_or_error(repoid)
872 repo = get_repo_or_error(repoid)
873
873
874 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
874 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
875 # check if we have admin permission for this repo !
875 # check if we have admin permission for this repo !
876 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
876 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
877 repo_name=repo.repo_name) is False:
877 repo_name=repo.repo_name) is False:
878 raise JSONRPCError('repository `%s` does not exist' % (repoid))
878 raise JSONRPCError('repository `%s` does not exist' % (repoid))
879
879
880 try:
880 try:
881 handle_forks = Optional.extract(forks)
881 handle_forks = Optional.extract(forks)
882 _forks_msg = ''
882 _forks_msg = ''
883 _forks = [f for f in repo.forks]
883 _forks = [f for f in repo.forks]
884 if handle_forks == 'detach':
884 if handle_forks == 'detach':
885 _forks_msg = ' ' + _('Detached %s forks') % len(_forks)
885 _forks_msg = ' ' + _('Detached %s forks') % len(_forks)
886 elif handle_forks == 'delete':
886 elif handle_forks == 'delete':
887 _forks_msg = ' ' + _('Deleted %s forks') % len(_forks)
887 _forks_msg = ' ' + _('Deleted %s forks') % len(_forks)
888 elif _forks:
888 elif _forks:
889 raise JSONRPCError(
889 raise JSONRPCError(
890 'Cannot delete `%s` it still contains attached forks'
890 'Cannot delete `%s` it still contains attached forks'
891 % repo.repo_name
891 % repo.repo_name
892 )
892 )
893
893
894 RepoModel().delete(repo, forks=forks)
894 RepoModel().delete(repo, forks=forks)
895 Session().commit()
895 Session().commit()
896 return dict(
896 return dict(
897 msg='Deleted repository `%s`%s' % (repo.repo_name, _forks_msg),
897 msg='Deleted repository `%s`%s' % (repo.repo_name, _forks_msg),
898 success=True
898 success=True
899 )
899 )
900 except Exception:
900 except Exception:
901 log.error(traceback.format_exc())
901 log.error(traceback.format_exc())
902 raise JSONRPCError(
902 raise JSONRPCError(
903 'failed to delete repository `%s`' % repo.repo_name
903 'failed to delete repository `%s`' % repo.repo_name
904 )
904 )
905
905
906 @HasPermissionAllDecorator('hg.admin')
906 @HasPermissionAllDecorator('hg.admin')
907 def grant_user_permission(self, apiuser, repoid, userid, perm):
907 def grant_user_permission(self, apiuser, repoid, userid, perm):
908 """
908 """
909 Grant permission for user on given repository, or update existing one
909 Grant permission for user on given repository, or update existing one
910 if found
910 if found
911
911
912 :param repoid:
912 :param repoid:
913 :param userid:
913 :param userid:
914 :param perm:
914 :param perm:
915 """
915 """
916 repo = get_repo_or_error(repoid)
916 repo = get_repo_or_error(repoid)
917 user = get_user_or_error(userid)
917 user = get_user_or_error(userid)
918 perm = get_perm_or_error(perm)
918 perm = get_perm_or_error(perm)
919
919
920 try:
920 try:
921
921
922 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
922 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
923
923
924 Session().commit()
924 Session().commit()
925 return dict(
925 return dict(
926 msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
926 msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
927 perm.permission_name, user.username, repo.repo_name
927 perm.permission_name, user.username, repo.repo_name
928 ),
928 ),
929 success=True
929 success=True
930 )
930 )
931 except Exception:
931 except Exception:
932 log.error(traceback.format_exc())
932 log.error(traceback.format_exc())
933 raise JSONRPCError(
933 raise JSONRPCError(
934 'failed to edit permission for user: `%s` in repo: `%s`' % (
934 'failed to edit permission for user: `%s` in repo: `%s`' % (
935 userid, repoid
935 userid, repoid
936 )
936 )
937 )
937 )
938
938
939 @HasPermissionAllDecorator('hg.admin')
939 @HasPermissionAllDecorator('hg.admin')
940 def revoke_user_permission(self, apiuser, repoid, userid):
940 def revoke_user_permission(self, apiuser, repoid, userid):
941 """
941 """
942 Revoke permission for user on given repository
942 Revoke permission for user on given repository
943
943
944 :param apiuser:
944 :param apiuser:
945 :param repoid:
945 :param repoid:
946 :param userid:
946 :param userid:
947 """
947 """
948
948
949 repo = get_repo_or_error(repoid)
949 repo = get_repo_or_error(repoid)
950 user = get_user_or_error(userid)
950 user = get_user_or_error(userid)
951 try:
951 try:
952
952
953 RepoModel().revoke_user_permission(repo=repo, user=user)
953 RepoModel().revoke_user_permission(repo=repo, user=user)
954
954
955 Session().commit()
955 Session().commit()
956 return dict(
956 return dict(
957 msg='Revoked perm for user: `%s` in repo: `%s`' % (
957 msg='Revoked perm for user: `%s` in repo: `%s`' % (
958 user.username, repo.repo_name
958 user.username, repo.repo_name
959 ),
959 ),
960 success=True
960 success=True
961 )
961 )
962 except Exception:
962 except Exception:
963 log.error(traceback.format_exc())
963 log.error(traceback.format_exc())
964 raise JSONRPCError(
964 raise JSONRPCError(
965 'failed to edit permission for user: `%s` in repo: `%s`' % (
965 'failed to edit permission for user: `%s` in repo: `%s`' % (
966 userid, repoid
966 userid, repoid
967 )
967 )
968 )
968 )
969
969
970 @HasPermissionAllDecorator('hg.admin')
970 @HasPermissionAllDecorator('hg.admin')
971 def grant_users_group_permission(self, apiuser, repoid, usersgroupid,
971 def grant_users_group_permission(self, apiuser, repoid, usersgroupid,
972 perm):
972 perm):
973 """
973 """
974 Grant permission for user group on given repository, or update
974 Grant permission for user group on given repository, or update
975 existing one if found
975 existing one if found
976
976
977 :param apiuser:
977 :param apiuser:
978 :param repoid:
978 :param repoid:
979 :param usersgroupid:
979 :param usersgroupid:
980 :param perm:
980 :param perm:
981 """
981 """
982 repo = get_repo_or_error(repoid)
982 repo = get_repo_or_error(repoid)
983 perm = get_perm_or_error(perm)
983 perm = get_perm_or_error(perm)
984 users_group = get_users_group_or_error(usersgroupid)
984 users_group = get_users_group_or_error(usersgroupid)
985
985
986 try:
986 try:
987 RepoModel().grant_users_group_permission(repo=repo,
987 RepoModel().grant_users_group_permission(repo=repo,
988 group_name=users_group,
988 group_name=users_group,
989 perm=perm)
989 perm=perm)
990
990
991 Session().commit()
991 Session().commit()
992 return dict(
992 return dict(
993 msg='Granted perm: `%s` for user group: `%s` in '
993 msg='Granted perm: `%s` for user group: `%s` in '
994 'repo: `%s`' % (
994 'repo: `%s`' % (
995 perm.permission_name, users_group.users_group_name,
995 perm.permission_name, users_group.users_group_name,
996 repo.repo_name
996 repo.repo_name
997 ),
997 ),
998 success=True
998 success=True
999 )
999 )
1000 except Exception:
1000 except Exception:
1001 log.error(traceback.format_exc())
1001 log.error(traceback.format_exc())
1002 raise JSONRPCError(
1002 raise JSONRPCError(
1003 'failed to edit permission for user group: `%s` in '
1003 'failed to edit permission for user group: `%s` in '
1004 'repo: `%s`' % (
1004 'repo: `%s`' % (
1005 usersgroupid, repo.repo_name
1005 usersgroupid, repo.repo_name
1006 )
1006 )
1007 )
1007 )
1008
1008
1009 @HasPermissionAllDecorator('hg.admin')
1009 @HasPermissionAllDecorator('hg.admin')
1010 def revoke_users_group_permission(self, apiuser, repoid, usersgroupid):
1010 def revoke_users_group_permission(self, apiuser, repoid, usersgroupid):
1011 """
1011 """
1012 Revoke permission for user group on given repository
1012 Revoke permission for user group on given repository
1013
1013
1014 :param apiuser:
1014 :param apiuser:
1015 :param repoid:
1015 :param repoid:
1016 :param usersgroupid:
1016 :param usersgroupid:
1017 """
1017 """
1018 repo = get_repo_or_error(repoid)
1018 repo = get_repo_or_error(repoid)
1019 users_group = get_users_group_or_error(usersgroupid)
1019 users_group = get_users_group_or_error(usersgroupid)
1020
1020
1021 try:
1021 try:
1022 RepoModel().revoke_users_group_permission(repo=repo,
1022 RepoModel().revoke_users_group_permission(repo=repo,
1023 group_name=users_group)
1023 group_name=users_group)
1024
1024
1025 Session().commit()
1025 Session().commit()
1026 return dict(
1026 return dict(
1027 msg='Revoked perm for user group: `%s` in repo: `%s`' % (
1027 msg='Revoked perm for user group: `%s` in repo: `%s`' % (
1028 users_group.users_group_name, repo.repo_name
1028 users_group.users_group_name, repo.repo_name
1029 ),
1029 ),
1030 success=True
1030 success=True
1031 )
1031 )
1032 except Exception:
1032 except Exception:
1033 log.error(traceback.format_exc())
1033 log.error(traceback.format_exc())
1034 raise JSONRPCError(
1034 raise JSONRPCError(
1035 'failed to edit permission for user group: `%s` in '
1035 'failed to edit permission for user group: `%s` in '
1036 'repo: `%s`' % (
1036 'repo: `%s`' % (
1037 users_group.users_group_name, repo.repo_name
1037 users_group.users_group_name, repo.repo_name
1038 )
1038 )
1039 )
1039 )
@@ -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(
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)
66 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