##// END OF EJS Templates
api: fix get_changeset() when incomplete raw_id is passed with with_reviews...
Manuel Jacob -
r8758:ea1a6567 stable
parent child Browse files
Show More
@@ -1,1976 +1,1976 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.controllers.api.api
15 kallithea.controllers.api.api
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 API controller for Kallithea
18 API controller for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Aug 20, 2011
22 :created_on: Aug 20, 2011
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28 import logging
28 import logging
29 import traceback
29 import traceback
30 from datetime import datetime
30 from datetime import datetime
31
31
32 from tg import request
32 from tg import request
33
33
34 from kallithea.controllers.api import JSONRPCController, JSONRPCError
34 from kallithea.controllers.api import JSONRPCController, JSONRPCError
35 from kallithea.lib.auth import (AuthUser, HasPermissionAny, HasPermissionAnyDecorator, HasRepoGroupPermissionLevel, HasRepoPermissionLevel,
35 from kallithea.lib.auth import (AuthUser, HasPermissionAny, HasPermissionAnyDecorator, HasRepoGroupPermissionLevel, HasRepoPermissionLevel,
36 HasUserGroupPermissionLevel)
36 HasUserGroupPermissionLevel)
37 from kallithea.lib.exceptions import DefaultUserException, UserGroupsAssignedException
37 from kallithea.lib.exceptions import DefaultUserException, UserGroupsAssignedException
38 from kallithea.lib.utils import repo2db_mapper
38 from kallithea.lib.utils import repo2db_mapper
39 from kallithea.lib.vcs.backends.base import EmptyChangeset
39 from kallithea.lib.vcs.backends.base import EmptyChangeset
40 from kallithea.lib.vcs.exceptions import EmptyRepositoryError
40 from kallithea.lib.vcs.exceptions import EmptyRepositoryError
41 from kallithea.model import db, meta, userlog
41 from kallithea.model import db, meta, userlog
42 from kallithea.model.changeset_status import ChangesetStatusModel
42 from kallithea.model.changeset_status import ChangesetStatusModel
43 from kallithea.model.comment import ChangesetCommentsModel
43 from kallithea.model.comment import ChangesetCommentsModel
44 from kallithea.model.gist import GistModel
44 from kallithea.model.gist import GistModel
45 from kallithea.model.pull_request import PullRequestModel
45 from kallithea.model.pull_request import PullRequestModel
46 from kallithea.model.repo import RepoModel
46 from kallithea.model.repo import RepoModel
47 from kallithea.model.repo_group import RepoGroupModel
47 from kallithea.model.repo_group import RepoGroupModel
48 from kallithea.model.scm import ScmModel, UserGroupList
48 from kallithea.model.scm import ScmModel, UserGroupList
49 from kallithea.model.user import UserModel
49 from kallithea.model.user import UserModel
50 from kallithea.model.user_group import UserGroupModel
50 from kallithea.model.user_group import UserGroupModel
51
51
52
52
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55
55
56 def store_update(updates, attr, name):
56 def store_update(updates, attr, name):
57 """
57 """
58 Stores param in updates dict if it's not None (i.e. if user explicitly set
58 Stores param in updates dict if it's not None (i.e. if user explicitly set
59 a parameter). This allows easy updates of passed in params.
59 a parameter). This allows easy updates of passed in params.
60 """
60 """
61 if attr is not None:
61 if attr is not None:
62 updates[name] = attr
62 updates[name] = attr
63
63
64
64
65 def get_user_or_error(userid):
65 def get_user_or_error(userid):
66 """
66 """
67 Get user by id or name or return JsonRPCError if not found
67 Get user by id or name or return JsonRPCError if not found
68 """
68 """
69 user = UserModel().get_user(userid)
69 user = UserModel().get_user(userid)
70 if user is None:
70 if user is None:
71 raise JSONRPCError("user `%s` does not exist" % (userid,))
71 raise JSONRPCError("user `%s` does not exist" % (userid,))
72 return user
72 return user
73
73
74
74
75 def get_repo_or_error(repoid):
75 def get_repo_or_error(repoid):
76 """
76 """
77 Get repo by id or name or return JsonRPCError if not found
77 Get repo by id or name or return JsonRPCError if not found
78 """
78 """
79 repo = RepoModel().get_repo(repoid)
79 repo = RepoModel().get_repo(repoid)
80 if repo is None:
80 if repo is None:
81 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
81 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
82 return repo
82 return repo
83
83
84
84
85 def get_repo_group_or_error(repogroupid):
85 def get_repo_group_or_error(repogroupid):
86 """
86 """
87 Get repo group by id or name or return JsonRPCError if not found
87 Get repo group by id or name or return JsonRPCError if not found
88 """
88 """
89 repo_group = db.RepoGroup.guess_instance(repogroupid)
89 repo_group = db.RepoGroup.guess_instance(repogroupid)
90 if repo_group is None:
90 if repo_group is None:
91 raise JSONRPCError(
91 raise JSONRPCError(
92 'repository group `%s` does not exist' % (repogroupid,))
92 'repository group `%s` does not exist' % (repogroupid,))
93 return repo_group
93 return repo_group
94
94
95
95
96 def get_user_group_or_error(usergroupid):
96 def get_user_group_or_error(usergroupid):
97 """
97 """
98 Get user group by id or name or return JsonRPCError if not found
98 Get user group by id or name or return JsonRPCError if not found
99 """
99 """
100 user_group = UserGroupModel().get_group(usergroupid)
100 user_group = UserGroupModel().get_group(usergroupid)
101 if user_group is None:
101 if user_group is None:
102 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
102 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
103 return user_group
103 return user_group
104
104
105
105
106 def get_perm_or_error(permid, prefix=None):
106 def get_perm_or_error(permid, prefix=None):
107 """
107 """
108 Get permission by id or name or return JsonRPCError if not found
108 Get permission by id or name or return JsonRPCError if not found
109 """
109 """
110 perm = db.Permission.get_by_key(permid)
110 perm = db.Permission.get_by_key(permid)
111 if perm is None:
111 if perm is None:
112 raise JSONRPCError('permission `%s` does not exist' % (permid,))
112 raise JSONRPCError('permission `%s` does not exist' % (permid,))
113 if prefix:
113 if prefix:
114 if not perm.permission_name.startswith(prefix):
114 if not perm.permission_name.startswith(prefix):
115 raise JSONRPCError('permission `%s` is invalid, '
115 raise JSONRPCError('permission `%s` is invalid, '
116 'should start with %s' % (permid, prefix))
116 'should start with %s' % (permid, prefix))
117 return perm
117 return perm
118
118
119
119
120 def get_gist_or_error(gistid):
120 def get_gist_or_error(gistid):
121 """
121 """
122 Get gist by id or gist_access_id or return JsonRPCError if not found
122 Get gist by id or gist_access_id or return JsonRPCError if not found
123 """
123 """
124 gist = GistModel().get_gist(gistid)
124 gist = GistModel().get_gist(gistid)
125 if gist is None:
125 if gist is None:
126 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
126 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
127 return gist
127 return gist
128
128
129
129
130 class ApiController(JSONRPCController):
130 class ApiController(JSONRPCController):
131 """
131 """
132 API Controller
132 API Controller
133
133
134 The authenticated user can be found as request.authuser.
134 The authenticated user can be found as request.authuser.
135
135
136 Example function::
136 Example function::
137
137
138 def func(arg1, arg2,...):
138 def func(arg1, arg2,...):
139 pass
139 pass
140
140
141 Each function should also **raise** JSONRPCError for any
141 Each function should also **raise** JSONRPCError for any
142 errors that happens.
142 errors that happens.
143 """
143 """
144
144
145 @HasPermissionAnyDecorator('hg.admin')
145 @HasPermissionAnyDecorator('hg.admin')
146 def test(self, args):
146 def test(self, args):
147 return args
147 return args
148
148
149 @HasPermissionAnyDecorator('hg.admin')
149 @HasPermissionAnyDecorator('hg.admin')
150 def pull(self, repoid, clone_uri=None):
150 def pull(self, repoid, clone_uri=None):
151 """
151 """
152 Triggers a pull from remote location on given repo. Can be used to
152 Triggers a pull from remote location on given repo. Can be used to
153 automatically keep remote repos up to date. This command can be executed
153 automatically keep remote repos up to date. This command can be executed
154 only using api_key belonging to user with admin rights
154 only using api_key belonging to user with admin rights
155
155
156 OUTPUT::
156 OUTPUT::
157
157
158 id : <id_given_in_input>
158 id : <id_given_in_input>
159 result : {
159 result : {
160 "msg" : "Pulled from `<repository name>`",
160 "msg" : "Pulled from `<repository name>`",
161 "repository" : "<repository name>"
161 "repository" : "<repository name>"
162 }
162 }
163 error : null
163 error : null
164 """
164 """
165 repo = get_repo_or_error(repoid)
165 repo = get_repo_or_error(repoid)
166
166
167 try:
167 try:
168 ScmModel().pull_changes(repo.repo_name,
168 ScmModel().pull_changes(repo.repo_name,
169 request.authuser.username,
169 request.authuser.username,
170 request.ip_addr,
170 request.ip_addr,
171 clone_uri=clone_uri)
171 clone_uri=clone_uri)
172 return dict(
172 return dict(
173 msg='Pulled from `%s`' % repo.repo_name,
173 msg='Pulled from `%s`' % repo.repo_name,
174 repository=repo.repo_name
174 repository=repo.repo_name
175 )
175 )
176 except Exception:
176 except Exception:
177 log.error(traceback.format_exc())
177 log.error(traceback.format_exc())
178 raise JSONRPCError(
178 raise JSONRPCError(
179 'Unable to pull changes from `%s`' % repo.repo_name
179 'Unable to pull changes from `%s`' % repo.repo_name
180 )
180 )
181
181
182 @HasPermissionAnyDecorator('hg.admin')
182 @HasPermissionAnyDecorator('hg.admin')
183 def rescan_repos(self, remove_obsolete=False):
183 def rescan_repos(self, remove_obsolete=False):
184 """
184 """
185 Triggers rescan repositories action. If remove_obsolete is set
185 Triggers rescan repositories action. If remove_obsolete is set
186 than also delete repos that are in database but not in the filesystem.
186 than also delete repos that are in database but not in the filesystem.
187 aka "clean zombies". This command can be executed only using api_key
187 aka "clean zombies". This command can be executed only using api_key
188 belonging to user with admin rights.
188 belonging to user with admin rights.
189
189
190 OUTPUT::
190 OUTPUT::
191
191
192 id : <id_given_in_input>
192 id : <id_given_in_input>
193 result : {
193 result : {
194 'added': [<added repository name>,...]
194 'added': [<added repository name>,...]
195 'removed': [<removed repository name>,...]
195 'removed': [<removed repository name>,...]
196 }
196 }
197 error : null
197 error : null
198 """
198 """
199 try:
199 try:
200 rm_obsolete = remove_obsolete
200 rm_obsolete = remove_obsolete
201 added, removed = repo2db_mapper(ScmModel().repo_scan(),
201 added, removed = repo2db_mapper(ScmModel().repo_scan(),
202 remove_obsolete=rm_obsolete)
202 remove_obsolete=rm_obsolete)
203 return {'added': added, 'removed': removed}
203 return {'added': added, 'removed': removed}
204 except Exception:
204 except Exception:
205 log.error(traceback.format_exc())
205 log.error(traceback.format_exc())
206 raise JSONRPCError(
206 raise JSONRPCError(
207 'Error occurred during rescan repositories action'
207 'Error occurred during rescan repositories action'
208 )
208 )
209
209
210 def invalidate_cache(self, repoid):
210 def invalidate_cache(self, repoid):
211 """
211 """
212 Invalidate cache for repository.
212 Invalidate cache for repository.
213 This command can be executed only using api_key belonging to user with admin
213 This command can be executed only using api_key belonging to user with admin
214 rights or regular user that have write or admin or write access to repository.
214 rights or regular user that have write or admin or write access to repository.
215
215
216 OUTPUT::
216 OUTPUT::
217
217
218 id : <id_given_in_input>
218 id : <id_given_in_input>
219 result : {
219 result : {
220 'msg': Cache for repository `<repository name>` was invalidated,
220 'msg': Cache for repository `<repository name>` was invalidated,
221 'repository': <repository name>
221 'repository': <repository name>
222 }
222 }
223 error : null
223 error : null
224 """
224 """
225 repo = get_repo_or_error(repoid)
225 repo = get_repo_or_error(repoid)
226 if not HasPermissionAny('hg.admin')():
226 if not HasPermissionAny('hg.admin')():
227 if not HasRepoPermissionLevel('write')(repo.repo_name):
227 if not HasRepoPermissionLevel('write')(repo.repo_name):
228 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
228 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
229
229
230 try:
230 try:
231 ScmModel().mark_for_invalidation(repo.repo_name)
231 ScmModel().mark_for_invalidation(repo.repo_name)
232 return dict(
232 return dict(
233 msg='Cache for repository `%s` was invalidated' % (repoid,),
233 msg='Cache for repository `%s` was invalidated' % (repoid,),
234 repository=repo.repo_name
234 repository=repo.repo_name
235 )
235 )
236 except Exception:
236 except Exception:
237 log.error(traceback.format_exc())
237 log.error(traceback.format_exc())
238 raise JSONRPCError(
238 raise JSONRPCError(
239 'Error occurred during cache invalidation action'
239 'Error occurred during cache invalidation action'
240 )
240 )
241
241
242 @HasPermissionAnyDecorator('hg.admin')
242 @HasPermissionAnyDecorator('hg.admin')
243 def get_ip(self, userid=None):
243 def get_ip(self, userid=None):
244 """
244 """
245 Shows IP address as seen from Kallithea server, together with all
245 Shows IP address as seen from Kallithea server, together with all
246 defined IP addresses for given user. If userid is not passed data is
246 defined IP addresses for given user. If userid is not passed data is
247 returned for user who's calling this function.
247 returned for user who's calling this function.
248 This command can be executed only using api_key belonging to user with
248 This command can be executed only using api_key belonging to user with
249 admin rights.
249 admin rights.
250
250
251 OUTPUT::
251 OUTPUT::
252
252
253 id : <id_given_in_input>
253 id : <id_given_in_input>
254 result : {
254 result : {
255 "server_ip_addr" : "<ip_from_client>",
255 "server_ip_addr" : "<ip_from_client>",
256 "user_ips" : [
256 "user_ips" : [
257 {
257 {
258 "ip_addr" : "<ip_with_mask>",
258 "ip_addr" : "<ip_with_mask>",
259 "ip_range" : ["<start_ip>", "<end_ip>"]
259 "ip_range" : ["<start_ip>", "<end_ip>"]
260 },
260 },
261 ...
261 ...
262 ]
262 ]
263 }
263 }
264 error : null
264 error : null
265 """
265 """
266 if userid is None:
266 if userid is None:
267 userid = request.authuser.user_id
267 userid = request.authuser.user_id
268 user = get_user_or_error(userid)
268 user = get_user_or_error(userid)
269 ips = db.UserIpMap.query().filter(db.UserIpMap.user == user).all()
269 ips = db.UserIpMap.query().filter(db.UserIpMap.user == user).all()
270 return dict(
270 return dict(
271 server_ip_addr=request.ip_addr,
271 server_ip_addr=request.ip_addr,
272 user_ips=ips
272 user_ips=ips
273 )
273 )
274
274
275 # alias for old
275 # alias for old
276 show_ip = get_ip
276 show_ip = get_ip
277
277
278 @HasPermissionAnyDecorator('hg.admin')
278 @HasPermissionAnyDecorator('hg.admin')
279 def get_server_info(self):
279 def get_server_info(self):
280 """
280 """
281 return server info, including Kallithea version and installed packages
281 return server info, including Kallithea version and installed packages
282
282
283 OUTPUT::
283 OUTPUT::
284
284
285 id : <id_given_in_input>
285 id : <id_given_in_input>
286 result : {
286 result : {
287 'modules' : [ [<module name>, <module version>], ...]
287 'modules' : [ [<module name>, <module version>], ...]
288 'py_version' : <python version>,
288 'py_version' : <python version>,
289 'platform' : <platform type>,
289 'platform' : <platform type>,
290 'kallithea_version' : <kallithea version>,
290 'kallithea_version' : <kallithea version>,
291 'git_version' : '<git version>',
291 'git_version' : '<git version>',
292 'git_path' : '<git path>'
292 'git_path' : '<git path>'
293 }
293 }
294 error : null
294 error : null
295 """
295 """
296 return db.Setting.get_server_info()
296 return db.Setting.get_server_info()
297
297
298 def get_user(self, userid=None):
298 def get_user(self, userid=None):
299 """
299 """
300 Gets a user by username or user_id, Returns empty result if user is
300 Gets a user by username or user_id, Returns empty result if user is
301 not found. If userid param is skipped it is set to id of user who is
301 not found. If userid param is skipped it is set to id of user who is
302 calling this method. This command can be executed only using api_key
302 calling this method. This command can be executed only using api_key
303 belonging to user with admin rights, or regular users that cannot
303 belonging to user with admin rights, or regular users that cannot
304 specify different userid than theirs
304 specify different userid than theirs
305
305
306 OUTPUT::
306 OUTPUT::
307
307
308 id : <id_given_in_input>
308 id : <id_given_in_input>
309 result : None if user does not exist or
309 result : None if user does not exist or
310 {
310 {
311 "user_id" : "<user_id>",
311 "user_id" : "<user_id>",
312 "username" : "<username>",
312 "username" : "<username>",
313 "firstname" : "<firstname>",
313 "firstname" : "<firstname>",
314 "lastname" : "<lastname>",
314 "lastname" : "<lastname>",
315 "email" : "<email>",
315 "email" : "<email>",
316 "emails" : "[<list of all emails including additional ones>]",
316 "emails" : "[<list of all emails including additional ones>]",
317 "active" : "<bool: user active>",
317 "active" : "<bool: user active>",
318 "admin" : "<bool: user is admin>",
318 "admin" : "<bool: user is admin>",
319 "permissions" : {
319 "permissions" : {
320 "global" : ["hg.create.repository",
320 "global" : ["hg.create.repository",
321 "repository.read",
321 "repository.read",
322 "hg.register.manual_activate"],
322 "hg.register.manual_activate"],
323 "repositories" : {"repo1" : "repository.none"},
323 "repositories" : {"repo1" : "repository.none"},
324 "repositories_groups" : {"Group1" : "group.read"},
324 "repositories_groups" : {"Group1" : "group.read"},
325 "user_groups" : { "usrgrp1" : "usergroup.admin" }
325 "user_groups" : { "usrgrp1" : "usergroup.admin" }
326 }
326 }
327 }
327 }
328 error : null
328 error : null
329 """
329 """
330 if not HasPermissionAny('hg.admin')():
330 if not HasPermissionAny('hg.admin')():
331 # make sure normal user does not pass someone else userid,
331 # make sure normal user does not pass someone else userid,
332 # he is not allowed to do that
332 # he is not allowed to do that
333 if userid is not None and userid != request.authuser.user_id:
333 if userid is not None and userid != request.authuser.user_id:
334 raise JSONRPCError(
334 raise JSONRPCError(
335 'userid is not the same as your user'
335 'userid is not the same as your user'
336 )
336 )
337
337
338 if userid is None:
338 if userid is None:
339 userid = request.authuser.user_id
339 userid = request.authuser.user_id
340
340
341 user = get_user_or_error(userid)
341 user = get_user_or_error(userid)
342 data = user.get_api_data()
342 data = user.get_api_data()
343 data['permissions'] = AuthUser(user_id=user.user_id).permissions
343 data['permissions'] = AuthUser(user_id=user.user_id).permissions
344 return data
344 return data
345
345
346 @HasPermissionAnyDecorator('hg.admin')
346 @HasPermissionAnyDecorator('hg.admin')
347 def get_users(self):
347 def get_users(self):
348 """
348 """
349 Lists all existing users. This command can be executed only using api_key
349 Lists all existing users. This command can be executed only using api_key
350 belonging to user with admin rights.
350 belonging to user with admin rights.
351
351
352 OUTPUT::
352 OUTPUT::
353
353
354 id : <id_given_in_input>
354 id : <id_given_in_input>
355 result : [<user_object>, ...]
355 result : [<user_object>, ...]
356 error : null
356 error : null
357 """
357 """
358 return [
358 return [
359 user.get_api_data()
359 user.get_api_data()
360 for user in db.User.query()
360 for user in db.User.query()
361 .order_by(db.User.username)
361 .order_by(db.User.username)
362 .filter_by(is_default_user=False)
362 .filter_by(is_default_user=False)
363 ]
363 ]
364
364
365 @HasPermissionAnyDecorator('hg.admin')
365 @HasPermissionAnyDecorator('hg.admin')
366 def create_user(self, username, email, password='',
366 def create_user(self, username, email, password='',
367 firstname='', lastname='',
367 firstname='', lastname='',
368 active=True, admin=False,
368 active=True, admin=False,
369 extern_type=db.User.DEFAULT_AUTH_TYPE,
369 extern_type=db.User.DEFAULT_AUTH_TYPE,
370 extern_name=''):
370 extern_name=''):
371 """
371 """
372 Creates new user. Returns new user object. This command can
372 Creates new user. Returns new user object. This command can
373 be executed only using api_key belonging to user with admin rights.
373 be executed only using api_key belonging to user with admin rights.
374
374
375 OUTPUT::
375 OUTPUT::
376
376
377 id : <id_given_in_input>
377 id : <id_given_in_input>
378 result : {
378 result : {
379 "msg" : "created new user `<username>`",
379 "msg" : "created new user `<username>`",
380 "user" : <user_obj>
380 "user" : <user_obj>
381 }
381 }
382 error : null
382 error : null
383 """
383 """
384 if db.User.get_by_username(username):
384 if db.User.get_by_username(username):
385 raise JSONRPCError("user `%s` already exist" % (username,))
385 raise JSONRPCError("user `%s` already exist" % (username,))
386
386
387 if db.User.get_by_email(email):
387 if db.User.get_by_email(email):
388 raise JSONRPCError("email `%s` already exist" % (email,))
388 raise JSONRPCError("email `%s` already exist" % (email,))
389
389
390 try:
390 try:
391 user = UserModel().create_or_update(
391 user = UserModel().create_or_update(
392 username=username,
392 username=username,
393 password=password,
393 password=password,
394 email=email,
394 email=email,
395 firstname=firstname,
395 firstname=firstname,
396 lastname=lastname,
396 lastname=lastname,
397 active=active,
397 active=active,
398 admin=admin,
398 admin=admin,
399 extern_type=extern_type,
399 extern_type=extern_type,
400 extern_name=extern_name
400 extern_name=extern_name
401 )
401 )
402 meta.Session().commit()
402 meta.Session().commit()
403 return dict(
403 return dict(
404 msg='created new user `%s`' % username,
404 msg='created new user `%s`' % username,
405 user=user.get_api_data()
405 user=user.get_api_data()
406 )
406 )
407 except Exception:
407 except Exception:
408 log.error(traceback.format_exc())
408 log.error(traceback.format_exc())
409 raise JSONRPCError('failed to create user `%s`' % (username,))
409 raise JSONRPCError('failed to create user `%s`' % (username,))
410
410
411 @HasPermissionAnyDecorator('hg.admin')
411 @HasPermissionAnyDecorator('hg.admin')
412 def update_user(self, userid, username=None,
412 def update_user(self, userid, username=None,
413 email=None, password=None,
413 email=None, password=None,
414 firstname=None, lastname=None,
414 firstname=None, lastname=None,
415 active=None, admin=None,
415 active=None, admin=None,
416 extern_type=None, extern_name=None):
416 extern_type=None, extern_name=None):
417 """
417 """
418 updates given user if such user exists. This command can
418 updates given user if such user exists. This command can
419 be executed only using api_key belonging to user with admin rights.
419 be executed only using api_key belonging to user with admin rights.
420
420
421 OUTPUT::
421 OUTPUT::
422
422
423 id : <id_given_in_input>
423 id : <id_given_in_input>
424 result : {
424 result : {
425 "msg" : "updated user ID:<userid> <username>",
425 "msg" : "updated user ID:<userid> <username>",
426 "user" : <user_object>
426 "user" : <user_object>
427 }
427 }
428 error : null
428 error : null
429 """
429 """
430 user = get_user_or_error(userid)
430 user = get_user_or_error(userid)
431
431
432 # only non optional arguments will be stored in updates
432 # only non optional arguments will be stored in updates
433 updates = {}
433 updates = {}
434
434
435 try:
435 try:
436
436
437 store_update(updates, username, 'username')
437 store_update(updates, username, 'username')
438 store_update(updates, password, 'password')
438 store_update(updates, password, 'password')
439 store_update(updates, email, 'email')
439 store_update(updates, email, 'email')
440 store_update(updates, firstname, 'name')
440 store_update(updates, firstname, 'name')
441 store_update(updates, lastname, 'lastname')
441 store_update(updates, lastname, 'lastname')
442 store_update(updates, active, 'active')
442 store_update(updates, active, 'active')
443 store_update(updates, admin, 'admin')
443 store_update(updates, admin, 'admin')
444 store_update(updates, extern_name, 'extern_name')
444 store_update(updates, extern_name, 'extern_name')
445 store_update(updates, extern_type, 'extern_type')
445 store_update(updates, extern_type, 'extern_type')
446
446
447 user = UserModel().update_user(user, **updates)
447 user = UserModel().update_user(user, **updates)
448 meta.Session().commit()
448 meta.Session().commit()
449 return dict(
449 return dict(
450 msg='updated user ID:%s %s' % (user.user_id, user.username),
450 msg='updated user ID:%s %s' % (user.user_id, user.username),
451 user=user.get_api_data()
451 user=user.get_api_data()
452 )
452 )
453 except DefaultUserException:
453 except DefaultUserException:
454 log.error(traceback.format_exc())
454 log.error(traceback.format_exc())
455 raise JSONRPCError('editing default user is forbidden')
455 raise JSONRPCError('editing default user is forbidden')
456 except Exception:
456 except Exception:
457 log.error(traceback.format_exc())
457 log.error(traceback.format_exc())
458 raise JSONRPCError('failed to update user `%s`' % (userid,))
458 raise JSONRPCError('failed to update user `%s`' % (userid,))
459
459
460 @HasPermissionAnyDecorator('hg.admin')
460 @HasPermissionAnyDecorator('hg.admin')
461 def delete_user(self, userid):
461 def delete_user(self, userid):
462 """
462 """
463 deletes given user if such user exists. This command can
463 deletes given user if such user exists. This command can
464 be executed only using api_key belonging to user with admin rights.
464 be executed only using api_key belonging to user with admin rights.
465
465
466 OUTPUT::
466 OUTPUT::
467
467
468 id : <id_given_in_input>
468 id : <id_given_in_input>
469 result : {
469 result : {
470 "msg" : "deleted user ID:<userid> <username>",
470 "msg" : "deleted user ID:<userid> <username>",
471 "user" : null
471 "user" : null
472 }
472 }
473 error : null
473 error : null
474 """
474 """
475 user = get_user_or_error(userid)
475 user = get_user_or_error(userid)
476
476
477 try:
477 try:
478 UserModel().delete(userid)
478 UserModel().delete(userid)
479 meta.Session().commit()
479 meta.Session().commit()
480 return dict(
480 return dict(
481 msg='deleted user ID:%s %s' % (user.user_id, user.username),
481 msg='deleted user ID:%s %s' % (user.user_id, user.username),
482 user=None
482 user=None
483 )
483 )
484 except Exception:
484 except Exception:
485
485
486 log.error(traceback.format_exc())
486 log.error(traceback.format_exc())
487 raise JSONRPCError('failed to delete user ID:%s %s'
487 raise JSONRPCError('failed to delete user ID:%s %s'
488 % (user.user_id, user.username))
488 % (user.user_id, user.username))
489
489
490 # permission check inside
490 # permission check inside
491 def get_user_group(self, usergroupid):
491 def get_user_group(self, usergroupid):
492 """
492 """
493 Gets an existing user group. This command can be executed only using api_key
493 Gets an existing user group. This command can be executed only using api_key
494 belonging to user with admin rights or user who has at least
494 belonging to user with admin rights or user who has at least
495 read access to user group.
495 read access to user group.
496
496
497 OUTPUT::
497 OUTPUT::
498
498
499 id : <id_given_in_input>
499 id : <id_given_in_input>
500 result : None if group not exist
500 result : None if group not exist
501 {
501 {
502 "users_group_id" : "<id>",
502 "users_group_id" : "<id>",
503 "group_name" : "<groupname>",
503 "group_name" : "<groupname>",
504 "group_description" : "<description>",
504 "group_description" : "<description>",
505 "active" : "<bool>",
505 "active" : "<bool>",
506 "owner" : "<username>",
506 "owner" : "<username>",
507 "members" : [<user_obj>,...]
507 "members" : [<user_obj>,...]
508 }
508 }
509 error : null
509 error : null
510 """
510 """
511 user_group = get_user_group_or_error(usergroupid)
511 user_group = get_user_group_or_error(usergroupid)
512 if not HasPermissionAny('hg.admin')():
512 if not HasPermissionAny('hg.admin')():
513 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
513 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
514 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
514 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
515
515
516 data = user_group.get_api_data()
516 data = user_group.get_api_data()
517 return data
517 return data
518
518
519 # permission check inside
519 # permission check inside
520 def get_user_groups(self):
520 def get_user_groups(self):
521 """
521 """
522 Lists all existing user groups. This command can be executed only using
522 Lists all existing user groups. This command can be executed only using
523 api_key belonging to user with admin rights or user who has at least
523 api_key belonging to user with admin rights or user who has at least
524 read access to user group.
524 read access to user group.
525
525
526 OUTPUT::
526 OUTPUT::
527
527
528 id : <id_given_in_input>
528 id : <id_given_in_input>
529 result : [<user_group_obj>,...]
529 result : [<user_group_obj>,...]
530 error : null
530 error : null
531 """
531 """
532 return [
532 return [
533 user_group.get_api_data()
533 user_group.get_api_data()
534 for user_group in UserGroupList(db.UserGroup.query().all(), perm_level='read')
534 for user_group in UserGroupList(db.UserGroup.query().all(), perm_level='read')
535 ]
535 ]
536
536
537 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
537 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
538 def create_user_group(self, group_name, description='',
538 def create_user_group(self, group_name, description='',
539 owner=None, active=True):
539 owner=None, active=True):
540 """
540 """
541 Creates new user group. This command can be executed only using api_key
541 Creates new user group. This command can be executed only using api_key
542 belonging to user with admin rights or an user who has create user group
542 belonging to user with admin rights or an user who has create user group
543 permission
543 permission
544
544
545 OUTPUT::
545 OUTPUT::
546
546
547 id : <id_given_in_input>
547 id : <id_given_in_input>
548 result : {
548 result : {
549 "msg" : "created new user group `<groupname>`",
549 "msg" : "created new user group `<groupname>`",
550 "user_group" : <user_group_object>
550 "user_group" : <user_group_object>
551 }
551 }
552 error : null
552 error : null
553 """
553 """
554 if UserGroupModel().get_by_name(group_name):
554 if UserGroupModel().get_by_name(group_name):
555 raise JSONRPCError("user group `%s` already exist" % (group_name,))
555 raise JSONRPCError("user group `%s` already exist" % (group_name,))
556
556
557 try:
557 try:
558 if owner is None:
558 if owner is None:
559 owner = request.authuser.user_id
559 owner = request.authuser.user_id
560
560
561 owner = get_user_or_error(owner)
561 owner = get_user_or_error(owner)
562 ug = UserGroupModel().create(name=group_name, description=description,
562 ug = UserGroupModel().create(name=group_name, description=description,
563 owner=owner, active=active)
563 owner=owner, active=active)
564 meta.Session().commit()
564 meta.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 user_group=ug.get_api_data()
567 user_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 # permission check inside
573 # permission check inside
574 def update_user_group(self, usergroupid, group_name=None,
574 def update_user_group(self, usergroupid, group_name=None,
575 description=None, owner=None,
575 description=None, owner=None,
576 active=None):
576 active=None):
577 """
577 """
578 Updates given usergroup. This command can be executed only using api_key
578 Updates given usergroup. This command can be executed only using api_key
579 belonging to user with admin rights or an admin of given user group
579 belonging to user with admin rights or an admin of given user group
580
580
581 OUTPUT::
581 OUTPUT::
582
582
583 id : <id_given_in_input>
583 id : <id_given_in_input>
584 result : {
584 result : {
585 "msg" : 'updated user group ID:<user group id> <user group name>',
585 "msg" : 'updated user group ID:<user group id> <user group name>',
586 "user_group" : <user_group_object>
586 "user_group" : <user_group_object>
587 }
587 }
588 error : null
588 error : null
589 """
589 """
590 user_group = get_user_group_or_error(usergroupid)
590 user_group = get_user_group_or_error(usergroupid)
591 if not HasPermissionAny('hg.admin')():
591 if not HasPermissionAny('hg.admin')():
592 if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
592 if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
593 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
593 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
594
594
595 if owner is not None:
595 if owner is not None:
596 owner = get_user_or_error(owner)
596 owner = get_user_or_error(owner)
597
597
598 updates = {}
598 updates = {}
599 store_update(updates, group_name, 'users_group_name')
599 store_update(updates, group_name, 'users_group_name')
600 store_update(updates, description, 'user_group_description')
600 store_update(updates, description, 'user_group_description')
601 store_update(updates, owner, 'owner')
601 store_update(updates, owner, 'owner')
602 store_update(updates, active, 'users_group_active')
602 store_update(updates, active, 'users_group_active')
603 try:
603 try:
604 UserGroupModel().update(user_group, updates)
604 UserGroupModel().update(user_group, updates)
605 meta.Session().commit()
605 meta.Session().commit()
606 return dict(
606 return dict(
607 msg='updated user group ID:%s %s' % (user_group.users_group_id,
607 msg='updated user group ID:%s %s' % (user_group.users_group_id,
608 user_group.users_group_name),
608 user_group.users_group_name),
609 user_group=user_group.get_api_data()
609 user_group=user_group.get_api_data()
610 )
610 )
611 except Exception:
611 except Exception:
612 log.error(traceback.format_exc())
612 log.error(traceback.format_exc())
613 raise JSONRPCError('failed to update user group `%s`' % (usergroupid,))
613 raise JSONRPCError('failed to update user group `%s`' % (usergroupid,))
614
614
615 # permission check inside
615 # permission check inside
616 def delete_user_group(self, usergroupid):
616 def delete_user_group(self, usergroupid):
617 """
617 """
618 Delete given user group by user group id or name.
618 Delete given user group by user group id or name.
619 This command can be executed only using api_key
619 This command can be executed only using api_key
620 belonging to user with admin rights or an admin of given user group
620 belonging to user with admin rights or an admin of given user group
621
621
622 OUTPUT::
622 OUTPUT::
623
623
624 id : <id_given_in_input>
624 id : <id_given_in_input>
625 result : {
625 result : {
626 "msg" : "deleted user group ID:<user_group_id> <user_group_name>"
626 "msg" : "deleted user group ID:<user_group_id> <user_group_name>"
627 }
627 }
628 error : null
628 error : null
629 """
629 """
630 user_group = get_user_group_or_error(usergroupid)
630 user_group = get_user_group_or_error(usergroupid)
631 if not HasPermissionAny('hg.admin')():
631 if not HasPermissionAny('hg.admin')():
632 if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
632 if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
633 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
633 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
634
634
635 try:
635 try:
636 UserGroupModel().delete(user_group)
636 UserGroupModel().delete(user_group)
637 meta.Session().commit()
637 meta.Session().commit()
638 return dict(
638 return dict(
639 msg='deleted user group ID:%s %s' %
639 msg='deleted user group ID:%s %s' %
640 (user_group.users_group_id, user_group.users_group_name),
640 (user_group.users_group_id, user_group.users_group_name),
641 user_group=None
641 user_group=None
642 )
642 )
643 except UserGroupsAssignedException as e:
643 except UserGroupsAssignedException as e:
644 log.error(traceback.format_exc())
644 log.error(traceback.format_exc())
645 raise JSONRPCError(str(e))
645 raise JSONRPCError(str(e))
646 except Exception:
646 except Exception:
647 log.error(traceback.format_exc())
647 log.error(traceback.format_exc())
648 raise JSONRPCError('failed to delete user group ID:%s %s' %
648 raise JSONRPCError('failed to delete user group ID:%s %s' %
649 (user_group.users_group_id,
649 (user_group.users_group_id,
650 user_group.users_group_name)
650 user_group.users_group_name)
651 )
651 )
652
652
653 # permission check inside
653 # permission check inside
654 def add_user_to_user_group(self, usergroupid, userid):
654 def add_user_to_user_group(self, usergroupid, userid):
655 """
655 """
656 Adds a user to a user group. If user exists in that group success will be
656 Adds a user to a user group. If user exists in that group success will be
657 `false`. This command can be executed only using api_key
657 `false`. This command can be executed only using api_key
658 belonging to user with admin rights or an admin of a given user group
658 belonging to user with admin rights or an admin of a given user group
659
659
660 OUTPUT::
660 OUTPUT::
661
661
662 id : <id_given_in_input>
662 id : <id_given_in_input>
663 result : {
663 result : {
664 "success" : True|False # depends on if member is in group
664 "success" : True|False # depends on if member is in group
665 "msg" : "added member `<username>` to a user group `<groupname>` |
665 "msg" : "added member `<username>` to a user group `<groupname>` |
666 User is already in that group"
666 User is already in that group"
667 }
667 }
668 error : null
668 error : null
669 """
669 """
670 user = get_user_or_error(userid)
670 user = get_user_or_error(userid)
671 user_group = get_user_group_or_error(usergroupid)
671 user_group = get_user_group_or_error(usergroupid)
672 if not HasPermissionAny('hg.admin')():
672 if not HasPermissionAny('hg.admin')():
673 if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
673 if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
674 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
674 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
675
675
676 try:
676 try:
677 ugm = UserGroupModel().add_user_to_group(user_group, user)
677 ugm = UserGroupModel().add_user_to_group(user_group, user)
678 success = True if ugm is not True else False
678 success = True if ugm is not True else False
679 msg = 'added member `%s` to user group `%s`' % (
679 msg = 'added member `%s` to user group `%s`' % (
680 user.username, user_group.users_group_name
680 user.username, user_group.users_group_name
681 )
681 )
682 msg = msg if success else 'User is already in that group'
682 msg = msg if success else 'User is already in that group'
683 meta.Session().commit()
683 meta.Session().commit()
684
684
685 return dict(
685 return dict(
686 success=success,
686 success=success,
687 msg=msg
687 msg=msg
688 )
688 )
689 except Exception:
689 except Exception:
690 log.error(traceback.format_exc())
690 log.error(traceback.format_exc())
691 raise JSONRPCError(
691 raise JSONRPCError(
692 'failed to add member to user group `%s`' % (
692 'failed to add member to user group `%s`' % (
693 user_group.users_group_name,
693 user_group.users_group_name,
694 )
694 )
695 )
695 )
696
696
697 # permission check inside
697 # permission check inside
698 def remove_user_from_user_group(self, usergroupid, userid):
698 def remove_user_from_user_group(self, usergroupid, userid):
699 """
699 """
700 Removes a user from a user group. If user is not in given group success will
700 Removes a user from a user group. If user is not in given group success will
701 be `false`. This command can be executed only
701 be `false`. This command can be executed only
702 using api_key belonging to user with admin rights or an admin of given user group
702 using api_key belonging to user with admin rights or an admin of given user group
703
703
704 OUTPUT::
704 OUTPUT::
705
705
706 id : <id_given_in_input>
706 id : <id_given_in_input>
707 result : {
707 result : {
708 "success" : True|False, # depends on if member is in group
708 "success" : True|False, # depends on if member is in group
709 "msg" : "removed member <username> from user group <groupname> |
709 "msg" : "removed member <username> from user group <groupname> |
710 User wasn't in group"
710 User wasn't in group"
711 }
711 }
712 error : null
712 error : null
713 """
713 """
714 user = get_user_or_error(userid)
714 user = get_user_or_error(userid)
715 user_group = get_user_group_or_error(usergroupid)
715 user_group = get_user_group_or_error(usergroupid)
716 if not HasPermissionAny('hg.admin')():
716 if not HasPermissionAny('hg.admin')():
717 if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
717 if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
718 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
718 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
719
719
720 try:
720 try:
721 success = UserGroupModel().remove_user_from_group(user_group, user)
721 success = UserGroupModel().remove_user_from_group(user_group, user)
722 msg = 'removed member `%s` from user group `%s`' % (
722 msg = 'removed member `%s` from user group `%s`' % (
723 user.username, user_group.users_group_name
723 user.username, user_group.users_group_name
724 )
724 )
725 msg = msg if success else "User wasn't in group"
725 msg = msg if success else "User wasn't in group"
726 meta.Session().commit()
726 meta.Session().commit()
727 return dict(success=success, msg=msg)
727 return dict(success=success, msg=msg)
728 except Exception:
728 except Exception:
729 log.error(traceback.format_exc())
729 log.error(traceback.format_exc())
730 raise JSONRPCError(
730 raise JSONRPCError(
731 'failed to remove member from user group `%s`' % (
731 'failed to remove member from user group `%s`' % (
732 user_group.users_group_name,
732 user_group.users_group_name,
733 )
733 )
734 )
734 )
735
735
736 # permission check inside
736 # permission check inside
737 def get_repo(self, repoid,
737 def get_repo(self, repoid,
738 with_revision_names=False,
738 with_revision_names=False,
739 with_pullrequests=False):
739 with_pullrequests=False):
740 """
740 """
741 Gets an existing repository by it's name or repository_id. Members will return
741 Gets an existing repository by it's name or repository_id. Members will return
742 either users_group or user associated to that repository. This command can be
742 either users_group or user associated to that repository. This command can be
743 executed only using api_key belonging to user with admin
743 executed only using api_key belonging to user with admin
744 rights or regular user that have at least read access to repository.
744 rights or regular user that have at least read access to repository.
745
745
746 OUTPUT::
746 OUTPUT::
747
747
748 id : <id_given_in_input>
748 id : <id_given_in_input>
749 result : {
749 result : {
750 "repo_id" : "<repo_id>",
750 "repo_id" : "<repo_id>",
751 "repo_name" : "<reponame>",
751 "repo_name" : "<reponame>",
752 "repo_type" : "<repo_type>",
752 "repo_type" : "<repo_type>",
753 "clone_uri" : "<clone_uri>",
753 "clone_uri" : "<clone_uri>",
754 "enable_downloads" : "<bool>",
754 "enable_downloads" : "<bool>",
755 "enable_statistics": "<bool>",
755 "enable_statistics": "<bool>",
756 "private" : "<bool>",
756 "private" : "<bool>",
757 "created_on" : "<date_time_created>",
757 "created_on" : "<date_time_created>",
758 "description" : "<description>",
758 "description" : "<description>",
759 "landing_rev" : "<landing_rev>",
759 "landing_rev" : "<landing_rev>",
760 "last_changeset" : {
760 "last_changeset" : {
761 "author" : "<full_author>",
761 "author" : "<full_author>",
762 "date" : "<date_time_of_commit>",
762 "date" : "<date_time_of_commit>",
763 "message" : "<commit_message>",
763 "message" : "<commit_message>",
764 "raw_id" : "<raw_id>",
764 "raw_id" : "<raw_id>",
765 "revision": "<numeric_revision>",
765 "revision": "<numeric_revision>",
766 "short_id": "<short_id>"
766 "short_id": "<short_id>"
767 },
767 },
768 "owner" : "<repo_owner>",
768 "owner" : "<repo_owner>",
769 "fork_of" : "<name_of_fork_parent>",
769 "fork_of" : "<name_of_fork_parent>",
770 "members" : [
770 "members" : [
771 {
771 {
772 "name" : "<username>",
772 "name" : "<username>",
773 "type" : "user",
773 "type" : "user",
774 "permission" : "repository.(read|write|admin)"
774 "permission" : "repository.(read|write|admin)"
775 },
775 },
776 …
776 …
777 {
777 {
778 "name" : "<usergroup name>",
778 "name" : "<usergroup name>",
779 "type" : "user_group",
779 "type" : "user_group",
780 "permission" : "usergroup.(read|write|admin)"
780 "permission" : "usergroup.(read|write|admin)"
781 },
781 },
782 …
782 …
783 ],
783 ],
784 "followers" : [<user_obj>, ...],
784 "followers" : [<user_obj>, ...],
785 <if with_revision_names == True>
785 <if with_revision_names == True>
786 "tags" : {
786 "tags" : {
787 "<tagname>" : "<raw_id>",
787 "<tagname>" : "<raw_id>",
788 ...
788 ...
789 },
789 },
790 "branches" : {
790 "branches" : {
791 "<branchname>" : "<raw_id>",
791 "<branchname>" : "<raw_id>",
792 ...
792 ...
793 },
793 },
794 "bookmarks" : {
794 "bookmarks" : {
795 "<bookmarkname>" : "<raw_id>",
795 "<bookmarkname>" : "<raw_id>",
796 ...
796 ...
797 }
797 }
798 }
798 }
799 error : null
799 error : null
800 """
800 """
801 repo = get_repo_or_error(repoid)
801 repo = get_repo_or_error(repoid)
802
802
803 if not HasPermissionAny('hg.admin')():
803 if not HasPermissionAny('hg.admin')():
804 if not HasRepoPermissionLevel('read')(repo.repo_name):
804 if not HasRepoPermissionLevel('read')(repo.repo_name):
805 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
805 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
806
806
807 members = []
807 members = []
808 for user in repo.repo_to_perm:
808 for user in repo.repo_to_perm:
809 perm = user.permission.permission_name
809 perm = user.permission.permission_name
810 user = user.user
810 user = user.user
811 user_data = {
811 user_data = {
812 'name': user.username,
812 'name': user.username,
813 'type': "user",
813 'type': "user",
814 'permission': perm
814 'permission': perm
815 }
815 }
816 members.append(user_data)
816 members.append(user_data)
817
817
818 for user_group in repo.users_group_to_perm:
818 for user_group in repo.users_group_to_perm:
819 perm = user_group.permission.permission_name
819 perm = user_group.permission.permission_name
820 user_group = user_group.users_group
820 user_group = user_group.users_group
821 user_group_data = {
821 user_group_data = {
822 'name': user_group.users_group_name,
822 'name': user_group.users_group_name,
823 'type': "user_group",
823 'type': "user_group",
824 'permission': perm
824 'permission': perm
825 }
825 }
826 members.append(user_group_data)
826 members.append(user_group_data)
827
827
828 followers = [
828 followers = [
829 uf.user.get_api_data()
829 uf.user.get_api_data()
830 for uf in repo.followers
830 for uf in repo.followers
831 ]
831 ]
832
832
833 data = repo.get_api_data(with_revision_names=with_revision_names,
833 data = repo.get_api_data(with_revision_names=with_revision_names,
834 with_pullrequests=with_pullrequests)
834 with_pullrequests=with_pullrequests)
835 data['members'] = members
835 data['members'] = members
836 data['followers'] = followers
836 data['followers'] = followers
837 return data
837 return data
838
838
839 # permission check inside
839 # permission check inside
840 def get_repos(self):
840 def get_repos(self):
841 """
841 """
842 Lists all existing repositories. This command can be executed only using
842 Lists all existing repositories. This command can be executed only using
843 api_key belonging to user with admin rights or regular user that have
843 api_key belonging to user with admin rights or regular user that have
844 admin, write or read access to repository.
844 admin, write or read access to repository.
845
845
846 OUTPUT::
846 OUTPUT::
847
847
848 id : <id_given_in_input>
848 id : <id_given_in_input>
849 result : [
849 result : [
850 {
850 {
851 "repo_id" : "<repo_id>",
851 "repo_id" : "<repo_id>",
852 "repo_name" : "<reponame>",
852 "repo_name" : "<reponame>",
853 "repo_type" : "<repo_type>",
853 "repo_type" : "<repo_type>",
854 "clone_uri" : "<clone_uri>",
854 "clone_uri" : "<clone_uri>",
855 "private" : "<bool>",
855 "private" : "<bool>",
856 "created_on" : "<datetimecreated>",
856 "created_on" : "<datetimecreated>",
857 "description" : "<description>",
857 "description" : "<description>",
858 "landing_rev" : "<landing_rev>",
858 "landing_rev" : "<landing_rev>",
859 "owner" : "<repo_owner>",
859 "owner" : "<repo_owner>",
860 "fork_of" : "<name_of_fork_parent>",
860 "fork_of" : "<name_of_fork_parent>",
861 "enable_downloads" : "<bool>",
861 "enable_downloads" : "<bool>",
862 "enable_statistics": "<bool>"
862 "enable_statistics": "<bool>"
863 },
863 },
864 …
864 …
865 ]
865 ]
866 error : null
866 error : null
867 """
867 """
868 if not HasPermissionAny('hg.admin')():
868 if not HasPermissionAny('hg.admin')():
869 repos = request.authuser.get_all_user_repos()
869 repos = request.authuser.get_all_user_repos()
870 else:
870 else:
871 repos = db.Repository.query()
871 repos = db.Repository.query()
872
872
873 return [
873 return [
874 repo.get_api_data()
874 repo.get_api_data()
875 for repo in repos
875 for repo in repos
876 ]
876 ]
877
877
878 # permission check inside
878 # permission check inside
879 def get_repo_nodes(self, repoid, revision, root_path,
879 def get_repo_nodes(self, repoid, revision, root_path,
880 ret_type='all'):
880 ret_type='all'):
881 """
881 """
882 returns a list of nodes and it's children in a flat list for a given path
882 returns a list of nodes and it's children in a flat list for a given path
883 at given revision. It's possible to specify ret_type to show only `files` or
883 at given revision. It's possible to specify ret_type to show only `files` or
884 `dirs`. This command can be executed only using api_key belonging to
884 `dirs`. This command can be executed only using api_key belonging to
885 user with admin rights or regular user that have at least read access to repository.
885 user with admin rights or regular user that have at least read access to repository.
886
886
887 OUTPUT::
887 OUTPUT::
888
888
889 id : <id_given_in_input>
889 id : <id_given_in_input>
890 result : [
890 result : [
891 {
891 {
892 "name" : "<name>",
892 "name" : "<name>",
893 "type" : "<type>"
893 "type" : "<type>"
894 },
894 },
895 …
895 …
896 ]
896 ]
897 error : null
897 error : null
898 """
898 """
899 repo = get_repo_or_error(repoid)
899 repo = get_repo_or_error(repoid)
900
900
901 if not HasPermissionAny('hg.admin')():
901 if not HasPermissionAny('hg.admin')():
902 if not HasRepoPermissionLevel('read')(repo.repo_name):
902 if not HasRepoPermissionLevel('read')(repo.repo_name):
903 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
903 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
904
904
905 _map = {}
905 _map = {}
906 try:
906 try:
907 _d, _f = ScmModel().get_nodes(repo, revision, root_path,
907 _d, _f = ScmModel().get_nodes(repo, revision, root_path,
908 flat=False)
908 flat=False)
909 _map = {
909 _map = {
910 'all': _d + _f,
910 'all': _d + _f,
911 'files': _f,
911 'files': _f,
912 'dirs': _d,
912 'dirs': _d,
913 }
913 }
914 return _map[ret_type]
914 return _map[ret_type]
915 except KeyError:
915 except KeyError:
916 raise JSONRPCError('ret_type must be one of %s'
916 raise JSONRPCError('ret_type must be one of %s'
917 % (','.join(sorted(_map))))
917 % (','.join(sorted(_map))))
918 except Exception:
918 except Exception:
919 log.error(traceback.format_exc())
919 log.error(traceback.format_exc())
920 raise JSONRPCError(
920 raise JSONRPCError(
921 'failed to get repo: `%s` nodes' % repo.repo_name
921 'failed to get repo: `%s` nodes' % repo.repo_name
922 )
922 )
923
923
924 # permission check inside
924 # permission check inside
925 def create_repo(self, repo_name, owner=None,
925 def create_repo(self, repo_name, owner=None,
926 repo_type=None, description='',
926 repo_type=None, description='',
927 private=False, clone_uri=None,
927 private=False, clone_uri=None,
928 landing_rev='rev:tip',
928 landing_rev='rev:tip',
929 enable_statistics=None,
929 enable_statistics=None,
930 enable_downloads=None,
930 enable_downloads=None,
931 copy_permissions=False):
931 copy_permissions=False):
932 """
932 """
933 Creates a repository. The repository name contains the full path, but the
933 Creates a repository. The repository name contains the full path, but the
934 parent repository group must exist. For example "foo/bar/baz" require the groups
934 parent repository group must exist. For example "foo/bar/baz" require the groups
935 "foo" and "bar" (with "foo" as parent), and create "baz" repository with
935 "foo" and "bar" (with "foo" as parent), and create "baz" repository with
936 "bar" as group. This command can be executed only using api_key
936 "bar" as group. This command can be executed only using api_key
937 belonging to user with admin rights or regular user that have create
937 belonging to user with admin rights or regular user that have create
938 repository permission. Regular users cannot specify owner parameter
938 repository permission. Regular users cannot specify owner parameter
939
939
940 OUTPUT::
940 OUTPUT::
941
941
942 id : <id_given_in_input>
942 id : <id_given_in_input>
943 result : {
943 result : {
944 "msg" : "Created new repository `<reponame>`",
944 "msg" : "Created new repository `<reponame>`",
945 "success" : true
945 "success" : true
946 }
946 }
947 error : null
947 error : null
948 """
948 """
949 group_name = None
949 group_name = None
950 repo_name_parts = repo_name.split('/')
950 repo_name_parts = repo_name.split('/')
951 if len(repo_name_parts) > 1:
951 if len(repo_name_parts) > 1:
952 group_name = '/'.join(repo_name_parts[:-1])
952 group_name = '/'.join(repo_name_parts[:-1])
953 repo_group = db.RepoGroup.get_by_group_name(group_name)
953 repo_group = db.RepoGroup.get_by_group_name(group_name)
954 if repo_group is None:
954 if repo_group is None:
955 raise JSONRPCError("repo group `%s` not found" % group_name)
955 raise JSONRPCError("repo group `%s` not found" % group_name)
956 if not(HasPermissionAny('hg.admin')() or HasRepoGroupPermissionLevel('write')(group_name)):
956 if not(HasPermissionAny('hg.admin')() or HasRepoGroupPermissionLevel('write')(group_name)):
957 raise JSONRPCError("no permission to create repo in %s" % group_name)
957 raise JSONRPCError("no permission to create repo in %s" % group_name)
958 else:
958 else:
959 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
959 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
960 raise JSONRPCError("no permission to create top level repo")
960 raise JSONRPCError("no permission to create top level repo")
961
961
962 if not HasPermissionAny('hg.admin')():
962 if not HasPermissionAny('hg.admin')():
963 if owner is not None:
963 if owner is not None:
964 # forbid setting owner for non-admins
964 # forbid setting owner for non-admins
965 raise JSONRPCError(
965 raise JSONRPCError(
966 'Only Kallithea admin can specify `owner` param'
966 'Only Kallithea admin can specify `owner` param'
967 )
967 )
968 if owner is None:
968 if owner is None:
969 owner = request.authuser.user_id
969 owner = request.authuser.user_id
970
970
971 owner = get_user_or_error(owner)
971 owner = get_user_or_error(owner)
972
972
973 if RepoModel().get_by_repo_name(repo_name):
973 if RepoModel().get_by_repo_name(repo_name):
974 raise JSONRPCError("repo `%s` already exist" % repo_name)
974 raise JSONRPCError("repo `%s` already exist" % repo_name)
975
975
976 defs = db.Setting.get_default_repo_settings(strip_prefix=True)
976 defs = db.Setting.get_default_repo_settings(strip_prefix=True)
977 if private is None:
977 if private is None:
978 private = defs.get('repo_private') or False
978 private = defs.get('repo_private') or False
979 if repo_type is None:
979 if repo_type is None:
980 repo_type = defs.get('repo_type')
980 repo_type = defs.get('repo_type')
981 if enable_statistics is None:
981 if enable_statistics is None:
982 enable_statistics = defs.get('repo_enable_statistics')
982 enable_statistics = defs.get('repo_enable_statistics')
983 if enable_downloads is None:
983 if enable_downloads is None:
984 enable_downloads = defs.get('repo_enable_downloads')
984 enable_downloads = defs.get('repo_enable_downloads')
985
985
986 try:
986 try:
987 data = dict(
987 data = dict(
988 repo_name=repo_name_parts[-1],
988 repo_name=repo_name_parts[-1],
989 repo_name_full=repo_name,
989 repo_name_full=repo_name,
990 repo_type=repo_type,
990 repo_type=repo_type,
991 repo_description=description,
991 repo_description=description,
992 repo_private=private,
992 repo_private=private,
993 clone_uri=clone_uri,
993 clone_uri=clone_uri,
994 repo_group=group_name,
994 repo_group=group_name,
995 repo_landing_rev=landing_rev,
995 repo_landing_rev=landing_rev,
996 repo_enable_statistics=enable_statistics,
996 repo_enable_statistics=enable_statistics,
997 repo_enable_downloads=enable_downloads,
997 repo_enable_downloads=enable_downloads,
998 repo_copy_permissions=copy_permissions,
998 repo_copy_permissions=copy_permissions,
999 )
999 )
1000
1000
1001 RepoModel().create(form_data=data, cur_user=owner.username)
1001 RepoModel().create(form_data=data, cur_user=owner.username)
1002 # no commit, it's done in RepoModel, or async via celery
1002 # no commit, it's done in RepoModel, or async via celery
1003 return dict(
1003 return dict(
1004 msg="Created new repository `%s`" % (repo_name,),
1004 msg="Created new repository `%s`" % (repo_name,),
1005 success=True, # cannot return the repo data here since fork
1005 success=True, # cannot return the repo data here since fork
1006 # can be done async
1006 # can be done async
1007 )
1007 )
1008 except Exception:
1008 except Exception:
1009 log.error(traceback.format_exc())
1009 log.error(traceback.format_exc())
1010 raise JSONRPCError(
1010 raise JSONRPCError(
1011 'failed to create repository `%s`' % (repo_name,))
1011 'failed to create repository `%s`' % (repo_name,))
1012
1012
1013 # permission check inside
1013 # permission check inside
1014 def update_repo(self, repoid, name=None,
1014 def update_repo(self, repoid, name=None,
1015 owner=None,
1015 owner=None,
1016 group=None,
1016 group=None,
1017 description=None, private=None,
1017 description=None, private=None,
1018 clone_uri=None, landing_rev=None,
1018 clone_uri=None, landing_rev=None,
1019 enable_statistics=None,
1019 enable_statistics=None,
1020 enable_downloads=None):
1020 enable_downloads=None):
1021 """
1021 """
1022 Updates repo
1022 Updates repo
1023 """
1023 """
1024 repo = get_repo_or_error(repoid)
1024 repo = get_repo_or_error(repoid)
1025 if not HasPermissionAny('hg.admin')():
1025 if not HasPermissionAny('hg.admin')():
1026 if not HasRepoPermissionLevel('admin')(repo.repo_name):
1026 if not HasRepoPermissionLevel('admin')(repo.repo_name):
1027 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1027 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1028
1028
1029 if (name != repo.repo_name and repo.group_id is None and
1029 if (name != repo.repo_name and repo.group_id is None and
1030 not HasPermissionAny('hg.create.repository')()
1030 not HasPermissionAny('hg.create.repository')()
1031 ):
1031 ):
1032 raise JSONRPCError('no permission to create (or move) top level repositories')
1032 raise JSONRPCError('no permission to create (or move) top level repositories')
1033
1033
1034 if owner is not None:
1034 if owner is not None:
1035 # forbid setting owner for non-admins
1035 # forbid setting owner for non-admins
1036 raise JSONRPCError(
1036 raise JSONRPCError(
1037 'Only Kallithea admin can specify `owner` param'
1037 'Only Kallithea admin can specify `owner` param'
1038 )
1038 )
1039
1039
1040 updates = {}
1040 updates = {}
1041 repo_group = group
1041 repo_group = group
1042 if repo_group is not None:
1042 if repo_group is not None:
1043 repo_group = get_repo_group_or_error(repo_group) # TODO: repos can thus currently not be moved to root
1043 repo_group = get_repo_group_or_error(repo_group) # TODO: repos can thus currently not be moved to root
1044 if repo_group.group_id != repo.group_id:
1044 if repo_group.group_id != repo.group_id:
1045 if not(HasPermissionAny('hg.admin')() or HasRepoGroupPermissionLevel('write')(repo_group.group_name)):
1045 if not(HasPermissionAny('hg.admin')() or HasRepoGroupPermissionLevel('write')(repo_group.group_name)):
1046 raise JSONRPCError("no permission to create (or move) repo in %s" % repo_group.group_name)
1046 raise JSONRPCError("no permission to create (or move) repo in %s" % repo_group.group_name)
1047 repo_group = repo_group.group_id
1047 repo_group = repo_group.group_id
1048 try:
1048 try:
1049 store_update(updates, name, 'repo_name')
1049 store_update(updates, name, 'repo_name')
1050 store_update(updates, repo_group, 'repo_group')
1050 store_update(updates, repo_group, 'repo_group')
1051 store_update(updates, owner, 'owner')
1051 store_update(updates, owner, 'owner')
1052 store_update(updates, description, 'repo_description')
1052 store_update(updates, description, 'repo_description')
1053 store_update(updates, private, 'repo_private')
1053 store_update(updates, private, 'repo_private')
1054 store_update(updates, clone_uri, 'clone_uri')
1054 store_update(updates, clone_uri, 'clone_uri')
1055 store_update(updates, landing_rev, 'repo_landing_rev')
1055 store_update(updates, landing_rev, 'repo_landing_rev')
1056 store_update(updates, enable_statistics, 'repo_enable_statistics')
1056 store_update(updates, enable_statistics, 'repo_enable_statistics')
1057 store_update(updates, enable_downloads, 'repo_enable_downloads')
1057 store_update(updates, enable_downloads, 'repo_enable_downloads')
1058
1058
1059 RepoModel().update(repo, **updates)
1059 RepoModel().update(repo, **updates)
1060 meta.Session().commit()
1060 meta.Session().commit()
1061 return dict(
1061 return dict(
1062 msg='updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
1062 msg='updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
1063 repository=repo.get_api_data()
1063 repository=repo.get_api_data()
1064 )
1064 )
1065 except Exception:
1065 except Exception:
1066 log.error(traceback.format_exc())
1066 log.error(traceback.format_exc())
1067 raise JSONRPCError('failed to update repo `%s`' % repoid)
1067 raise JSONRPCError('failed to update repo `%s`' % repoid)
1068
1068
1069 # permission check inside
1069 # permission check inside
1070 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
1070 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
1071 def fork_repo(self, repoid, fork_name,
1071 def fork_repo(self, repoid, fork_name,
1072 owner=None,
1072 owner=None,
1073 description='', copy_permissions=False,
1073 description='', copy_permissions=False,
1074 private=False, landing_rev='rev:tip'):
1074 private=False, landing_rev='rev:tip'):
1075 """
1075 """
1076 Creates a fork of given repo. In case of using celery this will
1076 Creates a fork of given repo. In case of using celery this will
1077 immediately return success message, while fork is going to be created
1077 immediately return success message, while fork is going to be created
1078 asynchronous. This command can be executed only using api_key belonging to
1078 asynchronous. This command can be executed only using api_key belonging to
1079 user with admin rights or regular user that have fork permission, and at least
1079 user with admin rights or regular user that have fork permission, and at least
1080 read access to forking repository. Regular users cannot specify owner parameter.
1080 read access to forking repository. Regular users cannot specify owner parameter.
1081
1081
1082 INPUT::
1082 INPUT::
1083
1083
1084 id : <id_for_response>
1084 id : <id_for_response>
1085 api_key : "<api_key>"
1085 api_key : "<api_key>"
1086 method : "fork_repo"
1086 method : "fork_repo"
1087 args : {
1087 args : {
1088 "repoid" : "<reponame or repo_id>",
1088 "repoid" : "<reponame or repo_id>",
1089 "fork_name" : "<forkname>",
1089 "fork_name" : "<forkname>",
1090 "owner" : "<username or user_id = Optional(=apiuser)>",
1090 "owner" : "<username or user_id = Optional(=apiuser)>",
1091 "description" : "<description>",
1091 "description" : "<description>",
1092 "copy_permissions": "<bool>",
1092 "copy_permissions": "<bool>",
1093 "private" : "<bool>",
1093 "private" : "<bool>",
1094 "landing_rev" : "<landing_rev>"
1094 "landing_rev" : "<landing_rev>"
1095 }
1095 }
1096
1096
1097 OUTPUT::
1097 OUTPUT::
1098
1098
1099 id : <id_given_in_input>
1099 id : <id_given_in_input>
1100 result : {
1100 result : {
1101 "msg" : "Created fork of `<reponame>` as `<forkname>`",
1101 "msg" : "Created fork of `<reponame>` as `<forkname>`",
1102 "success" : true
1102 "success" : true
1103 }
1103 }
1104 error : null
1104 error : null
1105 """
1105 """
1106 repo = get_repo_or_error(repoid)
1106 repo = get_repo_or_error(repoid)
1107 repo_name = repo.repo_name
1107 repo_name = repo.repo_name
1108
1108
1109 _repo = RepoModel().get_by_repo_name(fork_name)
1109 _repo = RepoModel().get_by_repo_name(fork_name)
1110 if _repo:
1110 if _repo:
1111 type_ = 'fork' if _repo.fork else 'repo'
1111 type_ = 'fork' if _repo.fork else 'repo'
1112 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
1112 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
1113
1113
1114 group_name = None
1114 group_name = None
1115 fork_name_parts = fork_name.split('/')
1115 fork_name_parts = fork_name.split('/')
1116 if len(fork_name_parts) > 1:
1116 if len(fork_name_parts) > 1:
1117 group_name = '/'.join(fork_name_parts[:-1])
1117 group_name = '/'.join(fork_name_parts[:-1])
1118 repo_group = db.RepoGroup.get_by_group_name(group_name)
1118 repo_group = db.RepoGroup.get_by_group_name(group_name)
1119 if repo_group is None:
1119 if repo_group is None:
1120 raise JSONRPCError("repo group `%s` not found" % group_name)
1120 raise JSONRPCError("repo group `%s` not found" % group_name)
1121 if not(HasPermissionAny('hg.admin')() or HasRepoGroupPermissionLevel('write')(group_name)):
1121 if not(HasPermissionAny('hg.admin')() or HasRepoGroupPermissionLevel('write')(group_name)):
1122 raise JSONRPCError("no permission to create repo in %s" % group_name)
1122 raise JSONRPCError("no permission to create repo in %s" % group_name)
1123 else:
1123 else:
1124 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
1124 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
1125 raise JSONRPCError("no permission to create top level repo")
1125 raise JSONRPCError("no permission to create top level repo")
1126
1126
1127 if HasPermissionAny('hg.admin')():
1127 if HasPermissionAny('hg.admin')():
1128 pass
1128 pass
1129 elif HasRepoPermissionLevel('read')(repo.repo_name):
1129 elif HasRepoPermissionLevel('read')(repo.repo_name):
1130 if owner is not None:
1130 if owner is not None:
1131 # forbid setting owner for non-admins
1131 # forbid setting owner for non-admins
1132 raise JSONRPCError(
1132 raise JSONRPCError(
1133 'Only Kallithea admin can specify `owner` param'
1133 'Only Kallithea admin can specify `owner` param'
1134 )
1134 )
1135 else:
1135 else:
1136 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1136 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1137
1137
1138 if owner is None:
1138 if owner is None:
1139 owner = request.authuser.user_id
1139 owner = request.authuser.user_id
1140
1140
1141 owner = get_user_or_error(owner)
1141 owner = get_user_or_error(owner)
1142
1142
1143 try:
1143 try:
1144 form_data = dict(
1144 form_data = dict(
1145 repo_name=fork_name_parts[-1],
1145 repo_name=fork_name_parts[-1],
1146 repo_name_full=fork_name,
1146 repo_name_full=fork_name,
1147 repo_group=group_name,
1147 repo_group=group_name,
1148 repo_type=repo.repo_type,
1148 repo_type=repo.repo_type,
1149 description=description,
1149 description=description,
1150 private=private,
1150 private=private,
1151 copy_permissions=copy_permissions,
1151 copy_permissions=copy_permissions,
1152 landing_rev=landing_rev,
1152 landing_rev=landing_rev,
1153 update_after_clone=False,
1153 update_after_clone=False,
1154 fork_parent_id=repo.repo_id,
1154 fork_parent_id=repo.repo_id,
1155 )
1155 )
1156 RepoModel().create_fork(form_data, cur_user=owner.username)
1156 RepoModel().create_fork(form_data, cur_user=owner.username)
1157 # no commit, it's done in RepoModel, or async via celery
1157 # no commit, it's done in RepoModel, or async via celery
1158 return dict(
1158 return dict(
1159 msg='Created fork of `%s` as `%s`' % (repo.repo_name,
1159 msg='Created fork of `%s` as `%s`' % (repo.repo_name,
1160 fork_name),
1160 fork_name),
1161 success=True, # cannot return the repo data here since fork
1161 success=True, # cannot return the repo data here since fork
1162 # can be done async
1162 # can be done async
1163 )
1163 )
1164 except Exception:
1164 except Exception:
1165 log.error(traceback.format_exc())
1165 log.error(traceback.format_exc())
1166 raise JSONRPCError(
1166 raise JSONRPCError(
1167 'failed to fork repository `%s` as `%s`' % (repo_name,
1167 'failed to fork repository `%s` as `%s`' % (repo_name,
1168 fork_name)
1168 fork_name)
1169 )
1169 )
1170
1170
1171 # permission check inside
1171 # permission check inside
1172 def delete_repo(self, repoid, forks=''):
1172 def delete_repo(self, repoid, forks=''):
1173 """
1173 """
1174 Deletes a repository. This command can be executed only using api_key belonging
1174 Deletes a repository. This command can be executed only using api_key belonging
1175 to user with admin rights or regular user that have admin access to repository.
1175 to user with admin rights or regular user that have admin access to repository.
1176 When `forks` param is set it's possible to detach or delete forks of deleting
1176 When `forks` param is set it's possible to detach or delete forks of deleting
1177 repository
1177 repository
1178
1178
1179 OUTPUT::
1179 OUTPUT::
1180
1180
1181 id : <id_given_in_input>
1181 id : <id_given_in_input>
1182 result : {
1182 result : {
1183 "msg" : "Deleted repository `<reponame>`",
1183 "msg" : "Deleted repository `<reponame>`",
1184 "success" : true
1184 "success" : true
1185 }
1185 }
1186 error : null
1186 error : null
1187 """
1187 """
1188 repo = get_repo_or_error(repoid)
1188 repo = get_repo_or_error(repoid)
1189
1189
1190 if not HasPermissionAny('hg.admin')():
1190 if not HasPermissionAny('hg.admin')():
1191 if not HasRepoPermissionLevel('admin')(repo.repo_name):
1191 if not HasRepoPermissionLevel('admin')(repo.repo_name):
1192 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1192 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1193
1193
1194 try:
1194 try:
1195 handle_forks = forks
1195 handle_forks = forks
1196 _forks_msg = ''
1196 _forks_msg = ''
1197 _forks = [f for f in repo.forks]
1197 _forks = [f for f in repo.forks]
1198 if handle_forks == 'detach':
1198 if handle_forks == 'detach':
1199 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1199 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1200 elif handle_forks == 'delete':
1200 elif handle_forks == 'delete':
1201 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1201 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1202 elif _forks:
1202 elif _forks:
1203 raise JSONRPCError(
1203 raise JSONRPCError(
1204 'Cannot delete `%s` it still contains attached forks' %
1204 'Cannot delete `%s` it still contains attached forks' %
1205 (repo.repo_name,)
1205 (repo.repo_name,)
1206 )
1206 )
1207
1207
1208 RepoModel().delete(repo, forks=forks)
1208 RepoModel().delete(repo, forks=forks)
1209 meta.Session().commit()
1209 meta.Session().commit()
1210 return dict(
1210 return dict(
1211 msg='Deleted repository `%s`%s' % (repo.repo_name, _forks_msg),
1211 msg='Deleted repository `%s`%s' % (repo.repo_name, _forks_msg),
1212 success=True
1212 success=True
1213 )
1213 )
1214 except Exception:
1214 except Exception:
1215 log.error(traceback.format_exc())
1215 log.error(traceback.format_exc())
1216 raise JSONRPCError(
1216 raise JSONRPCError(
1217 'failed to delete repository `%s`' % (repo.repo_name,)
1217 'failed to delete repository `%s`' % (repo.repo_name,)
1218 )
1218 )
1219
1219
1220 @HasPermissionAnyDecorator('hg.admin')
1220 @HasPermissionAnyDecorator('hg.admin')
1221 def grant_user_permission(self, repoid, userid, perm):
1221 def grant_user_permission(self, repoid, userid, perm):
1222 """
1222 """
1223 Grant permission for user on given repository, or update existing one
1223 Grant permission for user on given repository, or update existing one
1224 if found. This command can be executed only using api_key belonging to user
1224 if found. This command can be executed only using api_key belonging to user
1225 with admin rights.
1225 with admin rights.
1226
1226
1227 OUTPUT::
1227 OUTPUT::
1228
1228
1229 id : <id_given_in_input>
1229 id : <id_given_in_input>
1230 result : {
1230 result : {
1231 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1231 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1232 "success" : true
1232 "success" : true
1233 }
1233 }
1234 error : null
1234 error : null
1235 """
1235 """
1236 repo = get_repo_or_error(repoid)
1236 repo = get_repo_or_error(repoid)
1237 user = get_user_or_error(userid)
1237 user = get_user_or_error(userid)
1238 perm = get_perm_or_error(perm)
1238 perm = get_perm_or_error(perm)
1239
1239
1240 try:
1240 try:
1241
1241
1242 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1242 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1243
1243
1244 meta.Session().commit()
1244 meta.Session().commit()
1245 return dict(
1245 return dict(
1246 msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1246 msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1247 perm.permission_name, user.username, repo.repo_name
1247 perm.permission_name, user.username, repo.repo_name
1248 ),
1248 ),
1249 success=True
1249 success=True
1250 )
1250 )
1251 except Exception:
1251 except Exception:
1252 log.error(traceback.format_exc())
1252 log.error(traceback.format_exc())
1253 raise JSONRPCError(
1253 raise JSONRPCError(
1254 'failed to edit permission for user: `%s` in repo: `%s`' % (
1254 'failed to edit permission for user: `%s` in repo: `%s`' % (
1255 userid, repoid
1255 userid, repoid
1256 )
1256 )
1257 )
1257 )
1258
1258
1259 @HasPermissionAnyDecorator('hg.admin')
1259 @HasPermissionAnyDecorator('hg.admin')
1260 def revoke_user_permission(self, repoid, userid):
1260 def revoke_user_permission(self, repoid, userid):
1261 """
1261 """
1262 Revoke permission for user on given repository. This command can be executed
1262 Revoke permission for user on given repository. This command can be executed
1263 only using api_key belonging to user with admin rights.
1263 only using api_key belonging to user with admin rights.
1264
1264
1265 OUTPUT::
1265 OUTPUT::
1266
1266
1267 id : <id_given_in_input>
1267 id : <id_given_in_input>
1268 result : {
1268 result : {
1269 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1269 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1270 "success" : true
1270 "success" : true
1271 }
1271 }
1272 error : null
1272 error : null
1273 """
1273 """
1274 repo = get_repo_or_error(repoid)
1274 repo = get_repo_or_error(repoid)
1275 user = get_user_or_error(userid)
1275 user = get_user_or_error(userid)
1276 try:
1276 try:
1277 RepoModel().revoke_user_permission(repo=repo, user=user)
1277 RepoModel().revoke_user_permission(repo=repo, user=user)
1278 meta.Session().commit()
1278 meta.Session().commit()
1279 return dict(
1279 return dict(
1280 msg='Revoked perm for user: `%s` in repo: `%s`' % (
1280 msg='Revoked perm for user: `%s` in repo: `%s`' % (
1281 user.username, repo.repo_name
1281 user.username, repo.repo_name
1282 ),
1282 ),
1283 success=True
1283 success=True
1284 )
1284 )
1285 except Exception:
1285 except Exception:
1286 log.error(traceback.format_exc())
1286 log.error(traceback.format_exc())
1287 raise JSONRPCError(
1287 raise JSONRPCError(
1288 'failed to edit permission for user: `%s` in repo: `%s`' % (
1288 'failed to edit permission for user: `%s` in repo: `%s`' % (
1289 userid, repoid
1289 userid, repoid
1290 )
1290 )
1291 )
1291 )
1292
1292
1293 # permission check inside
1293 # permission check inside
1294 def grant_user_group_permission(self, repoid, usergroupid, perm):
1294 def grant_user_group_permission(self, repoid, usergroupid, perm):
1295 """
1295 """
1296 Grant permission for user group on given repository, or update
1296 Grant permission for user group on given repository, or update
1297 existing one if found. This command can be executed only using
1297 existing one if found. This command can be executed only using
1298 api_key belonging to user with admin rights.
1298 api_key belonging to user with admin rights.
1299
1299
1300 OUTPUT::
1300 OUTPUT::
1301
1301
1302 id : <id_given_in_input>
1302 id : <id_given_in_input>
1303 result : {
1303 result : {
1304 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1304 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1305 "success" : true
1305 "success" : true
1306 }
1306 }
1307 error : null
1307 error : null
1308 """
1308 """
1309 repo = get_repo_or_error(repoid)
1309 repo = get_repo_or_error(repoid)
1310 perm = get_perm_or_error(perm)
1310 perm = get_perm_or_error(perm)
1311 user_group = get_user_group_or_error(usergroupid)
1311 user_group = get_user_group_or_error(usergroupid)
1312 if not HasPermissionAny('hg.admin')():
1312 if not HasPermissionAny('hg.admin')():
1313 if not HasRepoPermissionLevel('admin')(repo.repo_name):
1313 if not HasRepoPermissionLevel('admin')(repo.repo_name):
1314 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1314 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1315
1315
1316 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
1316 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
1317 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1317 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1318
1318
1319 try:
1319 try:
1320 RepoModel().grant_user_group_permission(
1320 RepoModel().grant_user_group_permission(
1321 repo=repo, group_name=user_group, perm=perm)
1321 repo=repo, group_name=user_group, perm=perm)
1322
1322
1323 meta.Session().commit()
1323 meta.Session().commit()
1324 return dict(
1324 return dict(
1325 msg='Granted perm: `%s` for user group: `%s` in '
1325 msg='Granted perm: `%s` for user group: `%s` in '
1326 'repo: `%s`' % (
1326 'repo: `%s`' % (
1327 perm.permission_name, user_group.users_group_name,
1327 perm.permission_name, user_group.users_group_name,
1328 repo.repo_name
1328 repo.repo_name
1329 ),
1329 ),
1330 success=True
1330 success=True
1331 )
1331 )
1332 except Exception:
1332 except Exception:
1333 log.error(traceback.format_exc())
1333 log.error(traceback.format_exc())
1334 raise JSONRPCError(
1334 raise JSONRPCError(
1335 'failed to edit permission for user group: `%s` in '
1335 'failed to edit permission for user group: `%s` in '
1336 'repo: `%s`' % (
1336 'repo: `%s`' % (
1337 usergroupid, repo.repo_name
1337 usergroupid, repo.repo_name
1338 )
1338 )
1339 )
1339 )
1340
1340
1341 # permission check inside
1341 # permission check inside
1342 def revoke_user_group_permission(self, repoid, usergroupid):
1342 def revoke_user_group_permission(self, repoid, usergroupid):
1343 """
1343 """
1344 Revoke permission for user group on given repository. This command can be
1344 Revoke permission for user group on given repository. This command can be
1345 executed only using api_key belonging to user with admin rights.
1345 executed only using api_key belonging to user with admin rights.
1346
1346
1347 OUTPUT::
1347 OUTPUT::
1348
1348
1349 id : <id_given_in_input>
1349 id : <id_given_in_input>
1350 result : {
1350 result : {
1351 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1351 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1352 "success" : true
1352 "success" : true
1353 }
1353 }
1354 error : null
1354 error : null
1355 """
1355 """
1356 repo = get_repo_or_error(repoid)
1356 repo = get_repo_or_error(repoid)
1357 user_group = get_user_group_or_error(usergroupid)
1357 user_group = get_user_group_or_error(usergroupid)
1358 if not HasPermissionAny('hg.admin')():
1358 if not HasPermissionAny('hg.admin')():
1359 if not HasRepoPermissionLevel('admin')(repo.repo_name):
1359 if not HasRepoPermissionLevel('admin')(repo.repo_name):
1360 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1360 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
1361
1361
1362 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
1362 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
1363 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1363 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
1364
1364
1365 try:
1365 try:
1366 RepoModel().revoke_user_group_permission(
1366 RepoModel().revoke_user_group_permission(
1367 repo=repo, group_name=user_group)
1367 repo=repo, group_name=user_group)
1368
1368
1369 meta.Session().commit()
1369 meta.Session().commit()
1370 return dict(
1370 return dict(
1371 msg='Revoked perm for user group: `%s` in repo: `%s`' % (
1371 msg='Revoked perm for user group: `%s` in repo: `%s`' % (
1372 user_group.users_group_name, repo.repo_name
1372 user_group.users_group_name, repo.repo_name
1373 ),
1373 ),
1374 success=True
1374 success=True
1375 )
1375 )
1376 except Exception:
1376 except Exception:
1377 log.error(traceback.format_exc())
1377 log.error(traceback.format_exc())
1378 raise JSONRPCError(
1378 raise JSONRPCError(
1379 'failed to edit permission for user group: `%s` in '
1379 'failed to edit permission for user group: `%s` in '
1380 'repo: `%s`' % (
1380 'repo: `%s`' % (
1381 user_group.users_group_name, repo.repo_name
1381 user_group.users_group_name, repo.repo_name
1382 )
1382 )
1383 )
1383 )
1384
1384
1385 @HasPermissionAnyDecorator('hg.admin')
1385 @HasPermissionAnyDecorator('hg.admin')
1386 def get_repo_group(self, repogroupid):
1386 def get_repo_group(self, repogroupid):
1387 """
1387 """
1388 Returns given repo group together with permissions, and repositories
1388 Returns given repo group together with permissions, and repositories
1389 inside the group
1389 inside the group
1390 """
1390 """
1391 repo_group = get_repo_group_or_error(repogroupid)
1391 repo_group = get_repo_group_or_error(repogroupid)
1392
1392
1393 members = []
1393 members = []
1394 for user in repo_group.repo_group_to_perm:
1394 for user in repo_group.repo_group_to_perm:
1395 perm = user.permission.permission_name
1395 perm = user.permission.permission_name
1396 user = user.user
1396 user = user.user
1397 user_data = {
1397 user_data = {
1398 'name': user.username,
1398 'name': user.username,
1399 'type': "user",
1399 'type': "user",
1400 'permission': perm
1400 'permission': perm
1401 }
1401 }
1402 members.append(user_data)
1402 members.append(user_data)
1403
1403
1404 for user_group in repo_group.users_group_to_perm:
1404 for user_group in repo_group.users_group_to_perm:
1405 perm = user_group.permission.permission_name
1405 perm = user_group.permission.permission_name
1406 user_group = user_group.users_group
1406 user_group = user_group.users_group
1407 user_group_data = {
1407 user_group_data = {
1408 'name': user_group.users_group_name,
1408 'name': user_group.users_group_name,
1409 'type': "user_group",
1409 'type': "user_group",
1410 'permission': perm
1410 'permission': perm
1411 }
1411 }
1412 members.append(user_group_data)
1412 members.append(user_group_data)
1413
1413
1414 data = repo_group.get_api_data()
1414 data = repo_group.get_api_data()
1415 data["members"] = members
1415 data["members"] = members
1416 return data
1416 return data
1417
1417
1418 @HasPermissionAnyDecorator('hg.admin')
1418 @HasPermissionAnyDecorator('hg.admin')
1419 def get_repo_groups(self):
1419 def get_repo_groups(self):
1420 """
1420 """
1421 Returns all repository groups
1421 Returns all repository groups
1422 """
1422 """
1423 return [
1423 return [
1424 repo_group.get_api_data()
1424 repo_group.get_api_data()
1425 for repo_group in db.RepoGroup.query()
1425 for repo_group in db.RepoGroup.query()
1426 ]
1426 ]
1427
1427
1428 @HasPermissionAnyDecorator('hg.admin')
1428 @HasPermissionAnyDecorator('hg.admin')
1429 def create_repo_group(self, group_name, description='',
1429 def create_repo_group(self, group_name, description='',
1430 owner=None,
1430 owner=None,
1431 parent=None,
1431 parent=None,
1432 copy_permissions=False):
1432 copy_permissions=False):
1433 """
1433 """
1434 Creates a repository group. This command can be executed only using
1434 Creates a repository group. This command can be executed only using
1435 api_key belonging to user with admin rights.
1435 api_key belonging to user with admin rights.
1436
1436
1437 OUTPUT::
1437 OUTPUT::
1438
1438
1439 id : <id_given_in_input>
1439 id : <id_given_in_input>
1440 result : {
1440 result : {
1441 "msg" : "created new repo group `<repo_group_name>`",
1441 "msg" : "created new repo group `<repo_group_name>`",
1442 "repo_group" : <repogroup_object>
1442 "repo_group" : <repogroup_object>
1443 }
1443 }
1444 error : null
1444 error : null
1445 """
1445 """
1446 if db.RepoGroup.get_by_group_name(group_name):
1446 if db.RepoGroup.get_by_group_name(group_name):
1447 raise JSONRPCError("repo group `%s` already exist" % (group_name,))
1447 raise JSONRPCError("repo group `%s` already exist" % (group_name,))
1448
1448
1449 if owner is None:
1449 if owner is None:
1450 owner = request.authuser.user_id
1450 owner = request.authuser.user_id
1451 group_description = description
1451 group_description = description
1452 parent_group = None
1452 parent_group = None
1453 if parent is not None:
1453 if parent is not None:
1454 parent_group = get_repo_group_or_error(parent)
1454 parent_group = get_repo_group_or_error(parent)
1455
1455
1456 try:
1456 try:
1457 repo_group = RepoGroupModel().create(
1457 repo_group = RepoGroupModel().create(
1458 group_name=group_name,
1458 group_name=group_name,
1459 group_description=group_description,
1459 group_description=group_description,
1460 owner=owner,
1460 owner=owner,
1461 parent=parent_group,
1461 parent=parent_group,
1462 copy_permissions=copy_permissions
1462 copy_permissions=copy_permissions
1463 )
1463 )
1464 meta.Session().commit()
1464 meta.Session().commit()
1465 return dict(
1465 return dict(
1466 msg='created new repo group `%s`' % group_name,
1466 msg='created new repo group `%s`' % group_name,
1467 repo_group=repo_group.get_api_data()
1467 repo_group=repo_group.get_api_data()
1468 )
1468 )
1469 except Exception:
1469 except Exception:
1470
1470
1471 log.error(traceback.format_exc())
1471 log.error(traceback.format_exc())
1472 raise JSONRPCError('failed to create repo group `%s`' % (group_name,))
1472 raise JSONRPCError('failed to create repo group `%s`' % (group_name,))
1473
1473
1474 @HasPermissionAnyDecorator('hg.admin')
1474 @HasPermissionAnyDecorator('hg.admin')
1475 def update_repo_group(self, repogroupid, group_name=None,
1475 def update_repo_group(self, repogroupid, group_name=None,
1476 description=None,
1476 description=None,
1477 owner=None,
1477 owner=None,
1478 parent=None):
1478 parent=None):
1479 """
1479 """
1480 TODO
1480 TODO
1481 """
1481 """
1482 repo_group = get_repo_group_or_error(repogroupid)
1482 repo_group = get_repo_group_or_error(repogroupid)
1483 parent_repo_group_id = None if parent is None else get_repo_group_or_error(parent).group_id
1483 parent_repo_group_id = None if parent is None else get_repo_group_or_error(parent).group_id
1484
1484
1485 updates = {}
1485 updates = {}
1486 try:
1486 try:
1487 store_update(updates, group_name, 'group_name')
1487 store_update(updates, group_name, 'group_name')
1488 store_update(updates, description, 'group_description')
1488 store_update(updates, description, 'group_description')
1489 store_update(updates, owner, 'owner')
1489 store_update(updates, owner, 'owner')
1490 store_update(updates, parent_repo_group_id, 'parent_group_id')
1490 store_update(updates, parent_repo_group_id, 'parent_group_id')
1491 repo_group = RepoGroupModel().update(repo_group, updates)
1491 repo_group = RepoGroupModel().update(repo_group, updates)
1492 meta.Session().commit()
1492 meta.Session().commit()
1493 return dict(
1493 return dict(
1494 msg='updated repository group ID:%s %s' % (repo_group.group_id,
1494 msg='updated repository group ID:%s %s' % (repo_group.group_id,
1495 repo_group.group_name),
1495 repo_group.group_name),
1496 repo_group=repo_group.get_api_data()
1496 repo_group=repo_group.get_api_data()
1497 )
1497 )
1498 except Exception:
1498 except Exception:
1499 log.error(traceback.format_exc())
1499 log.error(traceback.format_exc())
1500 raise JSONRPCError('failed to update repository group `%s`'
1500 raise JSONRPCError('failed to update repository group `%s`'
1501 % (repogroupid,))
1501 % (repogroupid,))
1502
1502
1503 @HasPermissionAnyDecorator('hg.admin')
1503 @HasPermissionAnyDecorator('hg.admin')
1504 def delete_repo_group(self, repogroupid):
1504 def delete_repo_group(self, repogroupid):
1505 """
1505 """
1506 OUTPUT::
1506 OUTPUT::
1507
1507
1508 id : <id_given_in_input>
1508 id : <id_given_in_input>
1509 result : {
1509 result : {
1510 'msg' : 'deleted repo group ID:<repogroupid> <repogroupname>
1510 'msg' : 'deleted repo group ID:<repogroupid> <repogroupname>
1511 'repo_group' : null
1511 'repo_group' : null
1512 }
1512 }
1513 error : null
1513 error : null
1514 """
1514 """
1515 repo_group = get_repo_group_or_error(repogroupid)
1515 repo_group = get_repo_group_or_error(repogroupid)
1516
1516
1517 try:
1517 try:
1518 RepoGroupModel().delete(repo_group)
1518 RepoGroupModel().delete(repo_group)
1519 meta.Session().commit()
1519 meta.Session().commit()
1520 return dict(
1520 return dict(
1521 msg='deleted repo group ID:%s %s' %
1521 msg='deleted repo group ID:%s %s' %
1522 (repo_group.group_id, repo_group.group_name),
1522 (repo_group.group_id, repo_group.group_name),
1523 repo_group=None
1523 repo_group=None
1524 )
1524 )
1525 except Exception:
1525 except Exception:
1526 log.error(traceback.format_exc())
1526 log.error(traceback.format_exc())
1527 raise JSONRPCError('failed to delete repo group ID:%s %s' %
1527 raise JSONRPCError('failed to delete repo group ID:%s %s' %
1528 (repo_group.group_id, repo_group.group_name)
1528 (repo_group.group_id, repo_group.group_name)
1529 )
1529 )
1530
1530
1531 # permission check inside
1531 # permission check inside
1532 def grant_user_permission_to_repo_group(self, repogroupid, userid,
1532 def grant_user_permission_to_repo_group(self, repogroupid, userid,
1533 perm, apply_to_children='none'):
1533 perm, apply_to_children='none'):
1534 """
1534 """
1535 Grant permission for user on given repository group, or update existing
1535 Grant permission for user on given repository group, or update existing
1536 one if found. This command can be executed only using api_key belonging
1536 one if found. This command can be executed only using api_key belonging
1537 to user with admin rights, or user who has admin right to given repository
1537 to user with admin rights, or user who has admin right to given repository
1538 group.
1538 group.
1539
1539
1540 OUTPUT::
1540 OUTPUT::
1541
1541
1542 id : <id_given_in_input>
1542 id : <id_given_in_input>
1543 result : {
1543 result : {
1544 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
1544 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
1545 "success" : true
1545 "success" : true
1546 }
1546 }
1547 error : null
1547 error : null
1548 """
1548 """
1549 repo_group = get_repo_group_or_error(repogroupid)
1549 repo_group = get_repo_group_or_error(repogroupid)
1550
1550
1551 if not HasPermissionAny('hg.admin')():
1551 if not HasPermissionAny('hg.admin')():
1552 if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
1552 if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
1553 raise JSONRPCError('repository group `%s` does not exist' % (repogroupid,))
1553 raise JSONRPCError('repository group `%s` does not exist' % (repogroupid,))
1554
1554
1555 user = get_user_or_error(userid)
1555 user = get_user_or_error(userid)
1556 perm = get_perm_or_error(perm, prefix='group.')
1556 perm = get_perm_or_error(perm, prefix='group.')
1557
1557
1558 try:
1558 try:
1559 RepoGroupModel().add_permission(repo_group=repo_group,
1559 RepoGroupModel().add_permission(repo_group=repo_group,
1560 obj=user,
1560 obj=user,
1561 obj_type="user",
1561 obj_type="user",
1562 perm=perm,
1562 perm=perm,
1563 recursive=apply_to_children)
1563 recursive=apply_to_children)
1564 meta.Session().commit()
1564 meta.Session().commit()
1565 return dict(
1565 return dict(
1566 msg='Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
1566 msg='Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
1567 perm.permission_name, apply_to_children, user.username, repo_group.name
1567 perm.permission_name, apply_to_children, user.username, repo_group.name
1568 ),
1568 ),
1569 success=True
1569 success=True
1570 )
1570 )
1571 except Exception:
1571 except Exception:
1572 log.error(traceback.format_exc())
1572 log.error(traceback.format_exc())
1573 raise JSONRPCError(
1573 raise JSONRPCError(
1574 'failed to edit permission for user: `%s` in repo group: `%s`' % (
1574 'failed to edit permission for user: `%s` in repo group: `%s`' % (
1575 userid, repo_group.name))
1575 userid, repo_group.name))
1576
1576
1577 # permission check inside
1577 # permission check inside
1578 def revoke_user_permission_from_repo_group(self, repogroupid, userid,
1578 def revoke_user_permission_from_repo_group(self, repogroupid, userid,
1579 apply_to_children='none'):
1579 apply_to_children='none'):
1580 """
1580 """
1581 Revoke permission for user on given repository group. This command can
1581 Revoke permission for user on given repository group. This command can
1582 be executed only using api_key belonging to user with admin rights, or
1582 be executed only using api_key belonging to user with admin rights, or
1583 user who has admin right to given repository group.
1583 user who has admin right to given repository group.
1584
1584
1585 OUTPUT::
1585 OUTPUT::
1586
1586
1587 id : <id_given_in_input>
1587 id : <id_given_in_input>
1588 result : {
1588 result : {
1589 "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
1589 "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
1590 "success" : true
1590 "success" : true
1591 }
1591 }
1592 error : null
1592 error : null
1593 """
1593 """
1594 repo_group = get_repo_group_or_error(repogroupid)
1594 repo_group = get_repo_group_or_error(repogroupid)
1595
1595
1596 if not HasPermissionAny('hg.admin')():
1596 if not HasPermissionAny('hg.admin')():
1597 if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
1597 if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
1598 raise JSONRPCError('repository group `%s` does not exist' % (repogroupid,))
1598 raise JSONRPCError('repository group `%s` does not exist' % (repogroupid,))
1599
1599
1600 user = get_user_or_error(userid)
1600 user = get_user_or_error(userid)
1601
1601
1602 try:
1602 try:
1603 RepoGroupModel().delete_permission(repo_group=repo_group,
1603 RepoGroupModel().delete_permission(repo_group=repo_group,
1604 obj=user,
1604 obj=user,
1605 obj_type="user",
1605 obj_type="user",
1606 recursive=apply_to_children)
1606 recursive=apply_to_children)
1607
1607
1608 meta.Session().commit()
1608 meta.Session().commit()
1609 return dict(
1609 return dict(
1610 msg='Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
1610 msg='Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
1611 apply_to_children, user.username, repo_group.name
1611 apply_to_children, user.username, repo_group.name
1612 ),
1612 ),
1613 success=True
1613 success=True
1614 )
1614 )
1615 except Exception:
1615 except Exception:
1616 log.error(traceback.format_exc())
1616 log.error(traceback.format_exc())
1617 raise JSONRPCError(
1617 raise JSONRPCError(
1618 'failed to edit permission for user: `%s` in repo group: `%s`' % (
1618 'failed to edit permission for user: `%s` in repo group: `%s`' % (
1619 userid, repo_group.name))
1619 userid, repo_group.name))
1620
1620
1621 # permission check inside
1621 # permission check inside
1622 def grant_user_group_permission_to_repo_group(
1622 def grant_user_group_permission_to_repo_group(
1623 self, repogroupid, usergroupid, perm,
1623 self, repogroupid, usergroupid, perm,
1624 apply_to_children='none'):
1624 apply_to_children='none'):
1625 """
1625 """
1626 Grant permission for user group on given repository group, or update
1626 Grant permission for user group on given repository group, or update
1627 existing one if found. This command can be executed only using
1627 existing one if found. This command can be executed only using
1628 api_key belonging to user with admin rights, or user who has admin
1628 api_key belonging to user with admin rights, or user who has admin
1629 right to given repository group.
1629 right to given repository group.
1630
1630
1631 OUTPUT::
1631 OUTPUT::
1632
1632
1633 id : <id_given_in_input>
1633 id : <id_given_in_input>
1634 result : {
1634 result : {
1635 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
1635 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
1636 "success" : true
1636 "success" : true
1637 }
1637 }
1638 error : null
1638 error : null
1639 """
1639 """
1640 repo_group = get_repo_group_or_error(repogroupid)
1640 repo_group = get_repo_group_or_error(repogroupid)
1641 perm = get_perm_or_error(perm, prefix='group.')
1641 perm = get_perm_or_error(perm, prefix='group.')
1642 user_group = get_user_group_or_error(usergroupid)
1642 user_group = get_user_group_or_error(usergroupid)
1643 if not HasPermissionAny('hg.admin')():
1643 if not HasPermissionAny('hg.admin')():
1644 if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
1644 if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
1645 raise JSONRPCError(
1645 raise JSONRPCError(
1646 'repository group `%s` does not exist' % (repogroupid,))
1646 'repository group `%s` does not exist' % (repogroupid,))
1647
1647
1648 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
1648 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
1649 raise JSONRPCError(
1649 raise JSONRPCError(
1650 'user group `%s` does not exist' % (usergroupid,))
1650 'user group `%s` does not exist' % (usergroupid,))
1651
1651
1652 try:
1652 try:
1653 RepoGroupModel().add_permission(repo_group=repo_group,
1653 RepoGroupModel().add_permission(repo_group=repo_group,
1654 obj=user_group,
1654 obj=user_group,
1655 obj_type="user_group",
1655 obj_type="user_group",
1656 perm=perm,
1656 perm=perm,
1657 recursive=apply_to_children)
1657 recursive=apply_to_children)
1658 meta.Session().commit()
1658 meta.Session().commit()
1659 return dict(
1659 return dict(
1660 msg='Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
1660 msg='Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
1661 perm.permission_name, apply_to_children,
1661 perm.permission_name, apply_to_children,
1662 user_group.users_group_name, repo_group.name
1662 user_group.users_group_name, repo_group.name
1663 ),
1663 ),
1664 success=True
1664 success=True
1665 )
1665 )
1666 except Exception:
1666 except Exception:
1667 log.error(traceback.format_exc())
1667 log.error(traceback.format_exc())
1668 raise JSONRPCError(
1668 raise JSONRPCError(
1669 'failed to edit permission for user group: `%s` in '
1669 'failed to edit permission for user group: `%s` in '
1670 'repo group: `%s`' % (
1670 'repo group: `%s`' % (
1671 usergroupid, repo_group.name
1671 usergroupid, repo_group.name
1672 )
1672 )
1673 )
1673 )
1674
1674
1675 # permission check inside
1675 # permission check inside
1676 def revoke_user_group_permission_from_repo_group(
1676 def revoke_user_group_permission_from_repo_group(
1677 self, repogroupid, usergroupid,
1677 self, repogroupid, usergroupid,
1678 apply_to_children='none'):
1678 apply_to_children='none'):
1679 """
1679 """
1680 Revoke permission for user group on given repository. This command can be
1680 Revoke permission for user group on given repository. This command can be
1681 executed only using api_key belonging to user with admin rights, or
1681 executed only using api_key belonging to user with admin rights, or
1682 user who has admin right to given repository group.
1682 user who has admin right to given repository group.
1683
1683
1684 OUTPUT::
1684 OUTPUT::
1685
1685
1686 id : <id_given_in_input>
1686 id : <id_given_in_input>
1687 result : {
1687 result : {
1688 "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
1688 "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
1689 "success" : true
1689 "success" : true
1690 }
1690 }
1691 error : null
1691 error : null
1692 """
1692 """
1693 repo_group = get_repo_group_or_error(repogroupid)
1693 repo_group = get_repo_group_or_error(repogroupid)
1694 user_group = get_user_group_or_error(usergroupid)
1694 user_group = get_user_group_or_error(usergroupid)
1695 if not HasPermissionAny('hg.admin')():
1695 if not HasPermissionAny('hg.admin')():
1696 if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
1696 if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
1697 raise JSONRPCError(
1697 raise JSONRPCError(
1698 'repository group `%s` does not exist' % (repogroupid,))
1698 'repository group `%s` does not exist' % (repogroupid,))
1699
1699
1700 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
1700 if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
1701 raise JSONRPCError(
1701 raise JSONRPCError(
1702 'user group `%s` does not exist' % (usergroupid,))
1702 'user group `%s` does not exist' % (usergroupid,))
1703
1703
1704 try:
1704 try:
1705 RepoGroupModel().delete_permission(repo_group=repo_group,
1705 RepoGroupModel().delete_permission(repo_group=repo_group,
1706 obj=user_group,
1706 obj=user_group,
1707 obj_type="user_group",
1707 obj_type="user_group",
1708 recursive=apply_to_children)
1708 recursive=apply_to_children)
1709 meta.Session().commit()
1709 meta.Session().commit()
1710 return dict(
1710 return dict(
1711 msg='Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
1711 msg='Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
1712 apply_to_children, user_group.users_group_name, repo_group.name
1712 apply_to_children, user_group.users_group_name, repo_group.name
1713 ),
1713 ),
1714 success=True
1714 success=True
1715 )
1715 )
1716 except Exception:
1716 except Exception:
1717 log.error(traceback.format_exc())
1717 log.error(traceback.format_exc())
1718 raise JSONRPCError(
1718 raise JSONRPCError(
1719 'failed to edit permission for user group: `%s` in repo group: `%s`' % (
1719 'failed to edit permission for user group: `%s` in repo group: `%s`' % (
1720 user_group.users_group_name, repo_group.name
1720 user_group.users_group_name, repo_group.name
1721 )
1721 )
1722 )
1722 )
1723
1723
1724 def get_gist(self, gistid):
1724 def get_gist(self, gistid):
1725 """
1725 """
1726 Get given gist by id
1726 Get given gist by id
1727 """
1727 """
1728 gist = get_gist_or_error(gistid)
1728 gist = get_gist_or_error(gistid)
1729 if not HasPermissionAny('hg.admin')():
1729 if not HasPermissionAny('hg.admin')():
1730 if gist.owner_id != request.authuser.user_id:
1730 if gist.owner_id != request.authuser.user_id:
1731 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
1731 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
1732 return gist.get_api_data()
1732 return gist.get_api_data()
1733
1733
1734 def get_gists(self, userid=None):
1734 def get_gists(self, userid=None):
1735 """
1735 """
1736 Get all gists for given user. If userid is empty returned gists
1736 Get all gists for given user. If userid is empty returned gists
1737 are for user who called the api
1737 are for user who called the api
1738 """
1738 """
1739 if not HasPermissionAny('hg.admin')():
1739 if not HasPermissionAny('hg.admin')():
1740 # make sure normal user does not pass someone else userid,
1740 # make sure normal user does not pass someone else userid,
1741 # he is not allowed to do that
1741 # he is not allowed to do that
1742 if userid is not None and userid != request.authuser.user_id:
1742 if userid is not None and userid != request.authuser.user_id:
1743 raise JSONRPCError(
1743 raise JSONRPCError(
1744 'userid is not the same as your user'
1744 'userid is not the same as your user'
1745 )
1745 )
1746
1746
1747 if userid is None:
1747 if userid is None:
1748 user_id = request.authuser.user_id
1748 user_id = request.authuser.user_id
1749 else:
1749 else:
1750 user_id = get_user_or_error(userid).user_id
1750 user_id = get_user_or_error(userid).user_id
1751
1751
1752 return [
1752 return [
1753 gist.get_api_data()
1753 gist.get_api_data()
1754 for gist in db.Gist().query()
1754 for gist in db.Gist().query()
1755 .filter_by(is_expired=False)
1755 .filter_by(is_expired=False)
1756 .filter(db.Gist.owner_id == user_id)
1756 .filter(db.Gist.owner_id == user_id)
1757 .order_by(db.Gist.created_on.desc())
1757 .order_by(db.Gist.created_on.desc())
1758 ]
1758 ]
1759
1759
1760 def create_gist(self, files, owner=None,
1760 def create_gist(self, files, owner=None,
1761 gist_type=db.Gist.GIST_PUBLIC, lifetime=-1,
1761 gist_type=db.Gist.GIST_PUBLIC, lifetime=-1,
1762 description=''):
1762 description=''):
1763 """
1763 """
1764 Creates new Gist
1764 Creates new Gist
1765
1765
1766 OUTPUT::
1766 OUTPUT::
1767
1767
1768 id : <id_given_in_input>
1768 id : <id_given_in_input>
1769 result : {
1769 result : {
1770 "msg" : "created new gist",
1770 "msg" : "created new gist",
1771 "gist" : <gist_object>
1771 "gist" : <gist_object>
1772 }
1772 }
1773 error : null
1773 error : null
1774 """
1774 """
1775 try:
1775 try:
1776 if owner is None:
1776 if owner is None:
1777 owner = request.authuser.user_id
1777 owner = request.authuser.user_id
1778
1778
1779 owner = get_user_or_error(owner)
1779 owner = get_user_or_error(owner)
1780
1780
1781 gist = GistModel().create(description=description,
1781 gist = GistModel().create(description=description,
1782 owner=owner,
1782 owner=owner,
1783 ip_addr=request.ip_addr,
1783 ip_addr=request.ip_addr,
1784 gist_mapping=files,
1784 gist_mapping=files,
1785 gist_type=gist_type,
1785 gist_type=gist_type,
1786 lifetime=lifetime)
1786 lifetime=lifetime)
1787 meta.Session().commit()
1787 meta.Session().commit()
1788 return dict(
1788 return dict(
1789 msg='created new gist',
1789 msg='created new gist',
1790 gist=gist.get_api_data()
1790 gist=gist.get_api_data()
1791 )
1791 )
1792 except Exception:
1792 except Exception:
1793 log.error(traceback.format_exc())
1793 log.error(traceback.format_exc())
1794 raise JSONRPCError('failed to create gist')
1794 raise JSONRPCError('failed to create gist')
1795
1795
1796 # permission check inside
1796 # permission check inside
1797 def delete_gist(self, gistid):
1797 def delete_gist(self, gistid):
1798 """
1798 """
1799 Deletes existing gist
1799 Deletes existing gist
1800
1800
1801 OUTPUT::
1801 OUTPUT::
1802
1802
1803 id : <id_given_in_input>
1803 id : <id_given_in_input>
1804 result : {
1804 result : {
1805 "msg" : "deleted gist ID: <gist_id>",
1805 "msg" : "deleted gist ID: <gist_id>",
1806 "gist" : null
1806 "gist" : null
1807 }
1807 }
1808 error : null
1808 error : null
1809 """
1809 """
1810 gist = get_gist_or_error(gistid)
1810 gist = get_gist_or_error(gistid)
1811 if not HasPermissionAny('hg.admin')():
1811 if not HasPermissionAny('hg.admin')():
1812 if gist.owner_id != request.authuser.user_id:
1812 if gist.owner_id != request.authuser.user_id:
1813 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
1813 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
1814
1814
1815 try:
1815 try:
1816 GistModel().delete(gist)
1816 GistModel().delete(gist)
1817 meta.Session().commit()
1817 meta.Session().commit()
1818 return dict(
1818 return dict(
1819 msg='deleted gist ID:%s' % (gist.gist_access_id,),
1819 msg='deleted gist ID:%s' % (gist.gist_access_id,),
1820 gist=None
1820 gist=None
1821 )
1821 )
1822 except Exception:
1822 except Exception:
1823 log.error(traceback.format_exc())
1823 log.error(traceback.format_exc())
1824 raise JSONRPCError('failed to delete gist ID:%s'
1824 raise JSONRPCError('failed to delete gist ID:%s'
1825 % (gist.gist_access_id,))
1825 % (gist.gist_access_id,))
1826
1826
1827 # permission check inside
1827 # permission check inside
1828 def get_changesets(self, repoid, start=None, end=None, start_date=None,
1828 def get_changesets(self, repoid, start=None, end=None, start_date=None,
1829 end_date=None, branch_name=None, reverse=False, with_file_list=False, max_revisions=None):
1829 end_date=None, branch_name=None, reverse=False, with_file_list=False, max_revisions=None):
1830 """
1830 """
1831 TODO
1831 TODO
1832 """
1832 """
1833 repo = get_repo_or_error(repoid)
1833 repo = get_repo_or_error(repoid)
1834 if not HasRepoPermissionLevel('read')(repo.repo_name):
1834 if not HasRepoPermissionLevel('read')(repo.repo_name):
1835 raise JSONRPCError('Access denied to repo %s' % repo.repo_name)
1835 raise JSONRPCError('Access denied to repo %s' % repo.repo_name)
1836
1836
1837 format = "%Y-%m-%dT%H:%M:%S"
1837 format = "%Y-%m-%dT%H:%M:%S"
1838 try:
1838 try:
1839 return [e.__json__(with_file_list) for e in
1839 return [e.__json__(with_file_list) for e in
1840 repo.scm_instance.get_changesets(start,
1840 repo.scm_instance.get_changesets(start,
1841 end,
1841 end,
1842 datetime.strptime(start_date, format) if start_date else None,
1842 datetime.strptime(start_date, format) if start_date else None,
1843 datetime.strptime(end_date, format) if end_date else None,
1843 datetime.strptime(end_date, format) if end_date else None,
1844 branch_name,
1844 branch_name,
1845 reverse, max_revisions)]
1845 reverse, max_revisions)]
1846 except EmptyRepositoryError as e:
1846 except EmptyRepositoryError as e:
1847 raise JSONRPCError('Repository is empty')
1847 raise JSONRPCError('Repository is empty')
1848
1848
1849 # permission check inside
1849 # permission check inside
1850 def get_changeset(self, repoid, raw_id, with_reviews=False):
1850 def get_changeset(self, repoid, raw_id, with_reviews=False):
1851 """
1851 """
1852 TODO
1852 TODO
1853 """
1853 """
1854 repo = get_repo_or_error(repoid)
1854 repo = get_repo_or_error(repoid)
1855 if not HasRepoPermissionLevel('read')(repo.repo_name):
1855 if not HasRepoPermissionLevel('read')(repo.repo_name):
1856 raise JSONRPCError('Access denied to repo %s' % repo.repo_name)
1856 raise JSONRPCError('Access denied to repo %s' % repo.repo_name)
1857 changeset = repo.get_changeset(raw_id)
1857 changeset = repo.get_changeset(raw_id)
1858 if isinstance(changeset, EmptyChangeset):
1858 if isinstance(changeset, EmptyChangeset):
1859 raise JSONRPCError('Changeset %s does not exist' % raw_id)
1859 raise JSONRPCError('Changeset %s does not exist' % raw_id)
1860
1860
1861 info = dict(changeset.as_dict())
1861 info = dict(changeset.as_dict())
1862
1862
1863 if with_reviews:
1863 if with_reviews:
1864 reviews = ChangesetStatusModel().get_statuses(
1864 reviews = ChangesetStatusModel().get_statuses(
1865 repo.repo_name, raw_id)
1865 repo.repo_name, changeset.raw_id)
1866 info["reviews"] = reviews
1866 info["reviews"] = reviews
1867
1867
1868 return info
1868 return info
1869
1869
1870 # permission check inside
1870 # permission check inside
1871 def get_pullrequest(self, pullrequest_id):
1871 def get_pullrequest(self, pullrequest_id):
1872 """
1872 """
1873 Get given pull request by id
1873 Get given pull request by id
1874 """
1874 """
1875 pull_request = db.PullRequest.get(pullrequest_id)
1875 pull_request = db.PullRequest.get(pullrequest_id)
1876 if pull_request is None:
1876 if pull_request is None:
1877 raise JSONRPCError('pull request `%s` does not exist' % (pullrequest_id,))
1877 raise JSONRPCError('pull request `%s` does not exist' % (pullrequest_id,))
1878 if not HasRepoPermissionLevel('read')(pull_request.org_repo.repo_name):
1878 if not HasRepoPermissionLevel('read')(pull_request.org_repo.repo_name):
1879 raise JSONRPCError('not allowed')
1879 raise JSONRPCError('not allowed')
1880 return pull_request.get_api_data()
1880 return pull_request.get_api_data()
1881
1881
1882 # permission check inside
1882 # permission check inside
1883 def comment_pullrequest(self, pull_request_id, comment_msg='', status=None, close_pr=False):
1883 def comment_pullrequest(self, pull_request_id, comment_msg='', status=None, close_pr=False):
1884 """
1884 """
1885 Add comment, close and change status of pull request.
1885 Add comment, close and change status of pull request.
1886 """
1886 """
1887 apiuser = get_user_or_error(request.authuser.user_id)
1887 apiuser = get_user_or_error(request.authuser.user_id)
1888 pull_request = db.PullRequest.get(pull_request_id)
1888 pull_request = db.PullRequest.get(pull_request_id)
1889 if pull_request is None:
1889 if pull_request is None:
1890 raise JSONRPCError('pull request `%s` does not exist' % (pull_request_id,))
1890 raise JSONRPCError('pull request `%s` does not exist' % (pull_request_id,))
1891 if (not HasRepoPermissionLevel('read')(pull_request.org_repo.repo_name)):
1891 if (not HasRepoPermissionLevel('read')(pull_request.org_repo.repo_name)):
1892 raise JSONRPCError('No permission to add comment. User needs at least reading permissions'
1892 raise JSONRPCError('No permission to add comment. User needs at least reading permissions'
1893 ' to the source repository.')
1893 ' to the source repository.')
1894 owner = apiuser.user_id == pull_request.owner_id
1894 owner = apiuser.user_id == pull_request.owner_id
1895 reviewer = apiuser.user_id in [reviewer.user_id for reviewer in pull_request.reviewers]
1895 reviewer = apiuser.user_id in [reviewer.user_id for reviewer in pull_request.reviewers]
1896 if close_pr and not (apiuser.admin or owner):
1896 if close_pr and not (apiuser.admin or owner):
1897 raise JSONRPCError('No permission to close pull request. User needs to be admin or owner.')
1897 raise JSONRPCError('No permission to close pull request. User needs to be admin or owner.')
1898 if status and not (apiuser.admin or owner or reviewer):
1898 if status and not (apiuser.admin or owner or reviewer):
1899 raise JSONRPCError('No permission to change pull request status. User needs to be admin, owner or reviewer.')
1899 raise JSONRPCError('No permission to change pull request status. User needs to be admin, owner or reviewer.')
1900 if pull_request.is_closed():
1900 if pull_request.is_closed():
1901 raise JSONRPCError('pull request is already closed')
1901 raise JSONRPCError('pull request is already closed')
1902
1902
1903 comment = ChangesetCommentsModel().create(
1903 comment = ChangesetCommentsModel().create(
1904 text=comment_msg,
1904 text=comment_msg,
1905 repo=pull_request.org_repo.repo_id,
1905 repo=pull_request.org_repo.repo_id,
1906 author=apiuser.user_id,
1906 author=apiuser.user_id,
1907 pull_request=pull_request.pull_request_id,
1907 pull_request=pull_request.pull_request_id,
1908 f_path=None,
1908 f_path=None,
1909 line_no=None,
1909 line_no=None,
1910 status_change=db.ChangesetStatus.get_status_lbl(status),
1910 status_change=db.ChangesetStatus.get_status_lbl(status),
1911 closing_pr=close_pr
1911 closing_pr=close_pr
1912 )
1912 )
1913 userlog.action_logger(apiuser,
1913 userlog.action_logger(apiuser,
1914 'user_commented_pull_request:%s' % pull_request_id,
1914 'user_commented_pull_request:%s' % pull_request_id,
1915 pull_request.org_repo, request.ip_addr)
1915 pull_request.org_repo, request.ip_addr)
1916 if status:
1916 if status:
1917 ChangesetStatusModel().set_status(
1917 ChangesetStatusModel().set_status(
1918 pull_request.org_repo_id,
1918 pull_request.org_repo_id,
1919 status,
1919 status,
1920 apiuser.user_id,
1920 apiuser.user_id,
1921 comment,
1921 comment,
1922 pull_request=pull_request_id
1922 pull_request=pull_request_id
1923 )
1923 )
1924 if close_pr:
1924 if close_pr:
1925 PullRequestModel().close_pull_request(pull_request_id)
1925 PullRequestModel().close_pull_request(pull_request_id)
1926 userlog.action_logger(apiuser,
1926 userlog.action_logger(apiuser,
1927 'user_closed_pull_request:%s' % pull_request_id,
1927 'user_closed_pull_request:%s' % pull_request_id,
1928 pull_request.org_repo, request.ip_addr)
1928 pull_request.org_repo, request.ip_addr)
1929 meta.Session().commit()
1929 meta.Session().commit()
1930 return True
1930 return True
1931
1931
1932 # permission check inside
1932 # permission check inside
1933 def edit_reviewers(self, pull_request_id, add=None, remove=None):
1933 def edit_reviewers(self, pull_request_id, add=None, remove=None):
1934 """
1934 """
1935 Add and/or remove one or more reviewers to a pull request, by username
1935 Add and/or remove one or more reviewers to a pull request, by username
1936 or user ID. Reviewers are specified either as a single-user string or
1936 or user ID. Reviewers are specified either as a single-user string or
1937 as a JSON list of one or more strings.
1937 as a JSON list of one or more strings.
1938 """
1938 """
1939 if add is None and remove is None:
1939 if add is None and remove is None:
1940 raise JSONRPCError('''Invalid request. Neither 'add' nor 'remove' is specified.''')
1940 raise JSONRPCError('''Invalid request. Neither 'add' nor 'remove' is specified.''')
1941
1941
1942 pull_request = db.PullRequest.get(pull_request_id)
1942 pull_request = db.PullRequest.get(pull_request_id)
1943 if pull_request is None:
1943 if pull_request is None:
1944 raise JSONRPCError('pull request `%s` does not exist' % (pull_request_id,))
1944 raise JSONRPCError('pull request `%s` does not exist' % (pull_request_id,))
1945
1945
1946 apiuser = get_user_or_error(request.authuser.user_id)
1946 apiuser = get_user_or_error(request.authuser.user_id)
1947 is_owner = apiuser.user_id == pull_request.owner_id
1947 is_owner = apiuser.user_id == pull_request.owner_id
1948 is_repo_admin = HasRepoPermissionLevel('admin')(pull_request.other_repo.repo_name)
1948 is_repo_admin = HasRepoPermissionLevel('admin')(pull_request.other_repo.repo_name)
1949 if not (apiuser.admin or is_repo_admin or is_owner):
1949 if not (apiuser.admin or is_repo_admin or is_owner):
1950 raise JSONRPCError('No permission to edit reviewers of this pull request. User needs to be admin or pull request owner.')
1950 raise JSONRPCError('No permission to edit reviewers of this pull request. User needs to be admin or pull request owner.')
1951 if pull_request.is_closed():
1951 if pull_request.is_closed():
1952 raise JSONRPCError('Cannot edit reviewers of a closed pull request.')
1952 raise JSONRPCError('Cannot edit reviewers of a closed pull request.')
1953
1953
1954 if not isinstance(add, list):
1954 if not isinstance(add, list):
1955 add = [add]
1955 add = [add]
1956 if not isinstance(remove, list):
1956 if not isinstance(remove, list):
1957 remove = [remove]
1957 remove = [remove]
1958
1958
1959 # look up actual user objects from given name or id. Bail out if unknown.
1959 # look up actual user objects from given name or id. Bail out if unknown.
1960 add_objs = set(get_user_or_error(user) for user in add if user is not None)
1960 add_objs = set(get_user_or_error(user) for user in add if user is not None)
1961 remove_objs = set(get_user_or_error(user) for user in remove if user is not None)
1961 remove_objs = set(get_user_or_error(user) for user in remove if user is not None)
1962
1962
1963 new_reviewers = redundant_reviewers = set()
1963 new_reviewers = redundant_reviewers = set()
1964 if add_objs:
1964 if add_objs:
1965 new_reviewers, redundant_reviewers = PullRequestModel().add_reviewers(apiuser, pull_request, add_objs)
1965 new_reviewers, redundant_reviewers = PullRequestModel().add_reviewers(apiuser, pull_request, add_objs)
1966 if remove_objs:
1966 if remove_objs:
1967 PullRequestModel().remove_reviewers(apiuser, pull_request, remove_objs)
1967 PullRequestModel().remove_reviewers(apiuser, pull_request, remove_objs)
1968
1968
1969 meta.Session().commit()
1969 meta.Session().commit()
1970
1970
1971 return {
1971 return {
1972 'added': [x.username for x in new_reviewers],
1972 'added': [x.username for x in new_reviewers],
1973 'already_present': [x.username for x in redundant_reviewers],
1973 'already_present': [x.username for x in redundant_reviewers],
1974 # NOTE: no explicit check that removed reviewers were actually present.
1974 # NOTE: no explicit check that removed reviewers were actually present.
1975 'removed': [x.username for x in remove_objs],
1975 'removed': [x.username for x in remove_objs],
1976 }
1976 }
General Comments 0
You need to be logged in to leave comments. Login now