##// END OF EJS Templates
api-utils: added helpers flag to extrac boolean flags from Optional parameters.
marcink -
r1265:59c22420 default
parent child Browse files
Show More
@@ -1,407 +1,412 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2014-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 JSON RPC utils
23 23 """
24 24
25 25 import collections
26 26 import logging
27 27
28 28 from rhodecode.api.exc import JSONRPCError
29 from rhodecode.lib.auth import HasPermissionAnyApi, HasRepoPermissionAnyApi, \
30 HasRepoGroupPermissionAnyApi
29 from rhodecode.lib.auth import (
30 HasPermissionAnyApi, HasRepoPermissionAnyApi, HasRepoGroupPermissionAnyApi)
31 31 from rhodecode.lib.utils import safe_unicode
32 from rhodecode.lib.vcs.exceptions import RepositoryError
32 33 from rhodecode.controllers.utils import get_commit_from_ref_name
33 from rhodecode.lib.vcs.exceptions import RepositoryError
34 from rhodecode.lib.utils2 import str2bool
34 35
35 36 log = logging.getLogger(__name__)
36 37
37 38
38 39 class OAttr(object):
39 40 """
40 41 Special Option that defines other attribute, and can default to them
41 42
42 43 Example::
43 44
44 45 def test(apiuser, userid=Optional(OAttr('apiuser')):
45 46 user = Optional.extract(userid, evaluate_locals=local())
46 47 #if we pass in userid, we get it, else it will default to apiuser
47 48 #attribute
48 49 """
49 50
50 51 def __init__(self, attr_name):
51 52 self.attr_name = attr_name
52 53
53 54 def __repr__(self):
54 55 return '<OptionalAttr:%s>' % self.attr_name
55 56
56 57 def __call__(self):
57 58 return self
58 59
59 60
60 61 class Optional(object):
61 62 """
62 63 Defines an optional parameter::
63 64
64 65 param = param.getval() if isinstance(param, Optional) else param
65 66 param = param() if isinstance(param, Optional) else param
66 67
67 68 is equivalent of::
68 69
69 70 param = Optional.extract(param)
70 71
71 72 """
72 73
73 74 def __init__(self, type_):
74 75 self.type_ = type_
75 76
76 77 def __repr__(self):
77 78 return '<Optional:%s>' % self.type_.__repr__()
78 79
79 80 def __call__(self):
80 81 return self.getval()
81 82
82 83 def getval(self, evaluate_locals=None):
83 84 """
84 85 returns value from this Optional instance
85 86 """
86 87 if isinstance(self.type_, OAttr):
87 88 param_name = self.type_.attr_name
88 89 if evaluate_locals:
89 90 return evaluate_locals[param_name]
90 91 # use params name
91 92 return param_name
92 93 return self.type_
93 94
94 95 @classmethod
95 def extract(cls, val, evaluate_locals=None):
96 def extract(cls, val, evaluate_locals=None, binary=None):
96 97 """
97 98 Extracts value from Optional() instance
98 99
99 100 :param val:
100 101 :return: original value if it's not Optional instance else
101 102 value of instance
102 103 """
103 104 if isinstance(val, cls):
104 return val.getval(evaluate_locals)
105 val = val.getval(evaluate_locals)
106
107 if binary:
108 val = str2bool(val)
109
105 110 return val
106 111
107 112
108 113 def parse_args(cli_args, key_prefix=''):
109 114 from rhodecode.lib.utils2 import (escape_split)
110 115 kwargs = collections.defaultdict(dict)
111 116 for el in escape_split(cli_args, ','):
112 117 kv = escape_split(el, '=', 1)
113 118 if len(kv) == 2:
114 119 k, v = kv
115 120 kwargs[key_prefix + k] = v
116 121 return kwargs
117 122
118 123
119 124 def get_origin(obj):
120 125 """
121 126 Get origin of permission from object.
122 127
123 128 :param obj:
124 129 """
125 130 origin = 'permission'
126 131
127 132 if getattr(obj, 'owner_row', '') and getattr(obj, 'admin_row', ''):
128 133 # admin and owner case, maybe we should use dual string ?
129 134 origin = 'owner'
130 135 elif getattr(obj, 'owner_row', ''):
131 136 origin = 'owner'
132 137 elif getattr(obj, 'admin_row', ''):
133 138 origin = 'super-admin'
134 139 return origin
135 140
136 141
137 142 def store_update(updates, attr, name):
138 143 """
139 144 Stores param in updates dict if it's not instance of Optional
140 145 allows easy updates of passed in params
141 146 """
142 147 if not isinstance(attr, Optional):
143 148 updates[name] = attr
144 149
145 150
146 151 def has_superadmin_permission(apiuser):
147 152 """
148 153 Return True if apiuser is admin or return False
149 154
150 155 :param apiuser:
151 156 """
152 157 if HasPermissionAnyApi('hg.admin')(user=apiuser):
153 158 return True
154 159 return False
155 160
156 161
157 162 def validate_repo_permissions(apiuser, repoid, repo, perms):
158 163 """
159 164 Raise JsonRPCError if apiuser is not authorized or return True
160 165
161 166 :param apiuser:
162 167 :param repoid:
163 168 :param repo:
164 169 :param perms:
165 170 """
166 171 if not HasRepoPermissionAnyApi(*perms)(
167 172 user=apiuser, repo_name=repo.repo_name):
168 173 raise JSONRPCError(
169 174 'repository `%s` does not exist' % repoid)
170 175
171 176 return True
172 177
173 178
174 179 def validate_repo_group_permissions(apiuser, repogroupid, repo_group, perms):
175 180 """
176 181 Raise JsonRPCError if apiuser is not authorized or return True
177 182
178 183 :param apiuser:
179 184 :param repogroupid: just the id of repository group
180 185 :param repo_group: instance of repo_group
181 186 :param perms:
182 187 """
183 188 if not HasRepoGroupPermissionAnyApi(*perms)(
184 189 user=apiuser, group_name=repo_group.group_name):
185 190 raise JSONRPCError(
186 191 'repository group `%s` does not exist' % repogroupid)
187 192
188 193 return True
189 194
190 195
191 196 def validate_set_owner_permissions(apiuser, owner):
192 197 if isinstance(owner, Optional):
193 198 owner = get_user_or_error(apiuser.user_id)
194 199 else:
195 200 if has_superadmin_permission(apiuser):
196 201 owner = get_user_or_error(owner)
197 202 else:
198 203 # forbid setting owner for non-admins
199 204 raise JSONRPCError(
200 205 'Only RhodeCode super-admin can specify `owner` param')
201 206 return owner
202 207
203 208
204 209 def get_user_or_error(userid):
205 210 """
206 211 Get user by id or name or return JsonRPCError if not found
207 212
208 213 :param userid:
209 214 """
210 215 from rhodecode.model.user import UserModel
211 216
212 217 user_model = UserModel()
213 218 try:
214 219 user = user_model.get_user(int(userid))
215 220 except ValueError:
216 221 user = user_model.get_by_username(userid)
217 222
218 223 if user is None:
219 224 raise JSONRPCError("user `%s` does not exist" % (userid,))
220 225 return user
221 226
222 227
223 228 def get_repo_or_error(repoid):
224 229 """
225 230 Get repo by id or name or return JsonRPCError if not found
226 231
227 232 :param repoid:
228 233 """
229 234 from rhodecode.model.repo import RepoModel
230 235
231 236 repo = RepoModel().get_repo(repoid)
232 237 if repo is None:
233 238 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
234 239 return repo
235 240
236 241
237 242 def get_repo_group_or_error(repogroupid):
238 243 """
239 244 Get repo group by id or name or return JsonRPCError if not found
240 245
241 246 :param repogroupid:
242 247 """
243 248 from rhodecode.model.repo_group import RepoGroupModel
244 249
245 250 repo_group = RepoGroupModel()._get_repo_group(repogroupid)
246 251 if repo_group is None:
247 252 raise JSONRPCError(
248 253 'repository group `%s` does not exist' % (repogroupid,))
249 254 return repo_group
250 255
251 256
252 257 def get_user_group_or_error(usergroupid):
253 258 """
254 259 Get user group by id or name or return JsonRPCError if not found
255 260
256 261 :param usergroupid:
257 262 """
258 263 from rhodecode.model.user_group import UserGroupModel
259 264
260 265 user_group = UserGroupModel().get_group(usergroupid)
261 266 if user_group is None:
262 267 raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
263 268 return user_group
264 269
265 270
266 271 def get_perm_or_error(permid, prefix=None):
267 272 """
268 273 Get permission by id or name or return JsonRPCError if not found
269 274
270 275 :param permid:
271 276 """
272 277 from rhodecode.model.permission import PermissionModel
273 278
274 279 perm = PermissionModel.cls.get_by_key(permid)
275 280 if perm is None:
276 281 raise JSONRPCError('permission `%s` does not exist' % (permid,))
277 282 if prefix:
278 283 if not perm.permission_name.startswith(prefix):
279 284 raise JSONRPCError('permission `%s` is invalid, '
280 285 'should start with %s' % (permid, prefix))
281 286 return perm
282 287
283 288
284 289 def get_gist_or_error(gistid):
285 290 """
286 291 Get gist by id or gist_access_id or return JsonRPCError if not found
287 292
288 293 :param gistid:
289 294 """
290 295 from rhodecode.model.gist import GistModel
291 296
292 297 gist = GistModel.cls.get_by_access_id(gistid)
293 298 if gist is None:
294 299 raise JSONRPCError('gist `%s` does not exist' % (gistid,))
295 300 return gist
296 301
297 302
298 303 def get_pull_request_or_error(pullrequestid):
299 304 """
300 305 Get pull request by id or return JsonRPCError if not found
301 306
302 307 :param pullrequestid:
303 308 """
304 309 from rhodecode.model.pull_request import PullRequestModel
305 310
306 311 try:
307 312 pull_request = PullRequestModel().get(int(pullrequestid))
308 313 except ValueError:
309 314 raise JSONRPCError('pullrequestid must be an integer')
310 315 if not pull_request:
311 316 raise JSONRPCError('pull request `%s` does not exist' % (
312 317 pullrequestid,))
313 318 return pull_request
314 319
315 320
316 321 def build_commit_data(commit, detail_level):
317 322 parsed_diff = []
318 323 if detail_level == 'extended':
319 324 for f in commit.added:
320 325 parsed_diff.append(_get_commit_dict(filename=f.path, op='A'))
321 326 for f in commit.changed:
322 327 parsed_diff.append(_get_commit_dict(filename=f.path, op='M'))
323 328 for f in commit.removed:
324 329 parsed_diff.append(_get_commit_dict(filename=f.path, op='D'))
325 330
326 331 elif detail_level == 'full':
327 332 from rhodecode.lib.diffs import DiffProcessor
328 333 diff_processor = DiffProcessor(commit.diff())
329 334 for dp in diff_processor.prepare():
330 335 del dp['stats']['ops']
331 336 _stats = dp['stats']
332 337 parsed_diff.append(_get_commit_dict(
333 338 filename=dp['filename'], op=dp['operation'],
334 339 new_revision=dp['new_revision'],
335 340 old_revision=dp['old_revision'],
336 341 raw_diff=dp['raw_diff'], stats=_stats))
337 342
338 343 return parsed_diff
339 344
340 345
341 346 def get_commit_or_error(ref, repo):
342 347 try:
343 348 ref_type, _, ref_hash = ref.split(':')
344 349 except ValueError:
345 350 raise JSONRPCError(
346 351 'Ref `{ref}` given in a wrong format. Please check the API'
347 352 ' documentation for more details'.format(ref=ref))
348 353 try:
349 354 # TODO: dan: refactor this to use repo.scm_instance().get_commit()
350 355 # once get_commit supports ref_types
351 356 return get_commit_from_ref_name(repo, ref_hash)
352 357 except RepositoryError:
353 358 raise JSONRPCError('Ref `{ref}` does not exist'.format(ref=ref))
354 359
355 360
356 361 def resolve_ref_or_error(ref, repo):
357 362 def _parse_ref(type_, name, hash_=None):
358 363 return type_, name, hash_
359 364
360 365 try:
361 366 ref_type, ref_name, ref_hash = _parse_ref(*ref.split(':'))
362 367 except TypeError:
363 368 raise JSONRPCError(
364 369 'Ref `{ref}` given in a wrong format. Please check the API'
365 370 ' documentation for more details'.format(ref=ref))
366 371
367 372 try:
368 373 ref_hash = ref_hash or _get_ref_hash(repo, ref_type, ref_name)
369 374 except (KeyError, ValueError):
370 375 raise JSONRPCError(
371 376 'The specified {type} `{name}` does not exist'.format(
372 377 type=ref_type, name=ref_name))
373 378
374 379 return ':'.join([ref_type, ref_name, ref_hash])
375 380
376 381
377 382 def _get_commit_dict(
378 383 filename, op, new_revision=None, old_revision=None,
379 384 raw_diff=None, stats=None):
380 385 if stats is None:
381 386 stats = {
382 387 "added": None,
383 388 "binary": None,
384 389 "deleted": None
385 390 }
386 391 return {
387 392 "filename": safe_unicode(filename),
388 393 "op": op,
389 394
390 395 # extra details
391 396 "new_revision": new_revision,
392 397 "old_revision": old_revision,
393 398
394 399 "raw_diff": raw_diff,
395 400 "stats": stats
396 401 }
397 402
398 403
399 404 # TODO: mikhail: Think about moving this function to some library
400 405 def _get_ref_hash(repo, type_, name):
401 406 vcs_repo = repo.scm_instance()
402 407 if type_ == 'branch' and vcs_repo.alias in ('hg', 'git'):
403 408 return vcs_repo.branches[name]
404 409 elif type_ == 'bookmark' and vcs_repo.alias == 'hg':
405 410 return vcs_repo.bookmarks[name]
406 411 else:
407 412 raise ValueError()
General Comments 0
You need to be logged in to leave comments. Login now