##// END OF EJS Templates
API updates...
marcink -
r2009:b63adad7 beta
parent child Browse files
Show More
@@ -1,626 +1,627 b''
1 1 .. _api:
2 2
3 3
4 4 API
5 5 ===
6 6
7 7
8 8 Starting from RhodeCode version 1.2 a simple API was implemented.
9 9 There's a single schema for calling all api methods. API is implemented
10 10 with JSON protocol both ways. An url to send API request in RhodeCode is
11 11 <your_server>/_admin/api
12 12
13 13 API ACCESS FOR WEB VIEWS
14 14 ++++++++++++++++++++++++
15 15
16 16 API access can also be turned on for each web view in RhodeCode that is
17 17 decorated with `@LoginRequired` decorator. To enable API access simple change
18 18 the standard login decorator to `@LoginRequired(api_access=True)`.
19 19 After this change, a rhodecode view can be accessed without login by adding a
20 20 GET parameter `?api_key=<api_key>` to url. By default this is only
21 21 enabled on RSS/ATOM feed views.
22 22
23 23
24 24 API ACCESS
25 25 ++++++++++
26 26
27 27 All clients are required to send JSON-RPC spec JSON data::
28 28
29 29 {
30 30 "id:<id>,
31 31 "api_key":"<api_key>",
32 32 "method":"<method_name>",
33 33 "args":{"<arg_key>":"<arg_val>"}
34 34 }
35 35
36 36 Example call for autopulling remotes repos using curl::
37 37 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
38 38
39 39 Simply provide
40 40 - *id* A value of any type, which is used to match the response with the request that it is replying to.
41 41 - *api_key* for access and permission validation.
42 42 - *method* is name of method to call
43 43 - *args* is an key:value list of arguments to pass to method
44 44
45 45 .. note::
46 46
47 47 api_key can be found in your user account page
48 48
49 49
50 50 RhodeCode API will return always a JSON-RPC response::
51 51
52 52 {
53 53 "id":<id>,
54 54 "result": "<result>",
55 55 "error": null
56 56 }
57 57
58 58 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
59 59 calling api *error* key from response will contain failure description
60 60 and result will be null.
61 61
62 62 API METHODS
63 63 +++++++++++
64 64
65 65
66 66 pull
67 67 ----
68 68
69 69 Pulls given repo from remote location. Can be used to automatically keep
70 70 remote repos up to date. This command can be executed only using api_key
71 71 belonging to user with admin rights
72 72
73 73 INPUT::
74 74
75 75 api_key : "<api_key>"
76 76 method : "pull"
77 77 args : {
78 78 "repo_name" : "<reponame>"
79 79 }
80 80
81 81 OUTPUT::
82 82
83 83 result : "Pulled from <reponame>"
84 84 error : null
85 85
86 86
87 87 get_user
88 88 --------
89 89
90 90 Get's an user by username, Returns empty result if user is not found.
91 91 This command can be executed only using api_key belonging to user with admin
92 92 rights.
93 93
94 94
95 95 INPUT::
96 96
97 97 api_key : "<api_key>"
98 98 method : "get_user"
99 99 args : {
100 100 "username" : "<username>"
101 101 }
102 102
103 103 OUTPUT::
104 104
105 105 result: None if user does not exist or
106 106 {
107 107 "id" : "<id>",
108 108 "username" : "<username>",
109 109 "firstname": "<firstname>",
110 110 "lastname" : "<lastname>",
111 111 "email" : "<email>",
112 112 "active" : "<bool>",
113 113 "admin" :Β  "<bool>",
114 "ldap" : "<ldap_dn>"
114 "ldap_dn" : "<ldap_dn>"
115 115 }
116 116
117 117 error: null
118 118
119 119
120 120 get_users
121 121 ---------
122 122
123 123 Lists all existing users. This command can be executed only using api_key
124 124 belonging to user with admin rights.
125 125
126 126
127 127 INPUT::
128 128
129 129 api_key : "<api_key>"
130 130 method : "get_users"
131 131 args : { }
132 132
133 133 OUTPUT::
134 134
135 135 result: [
136 136 {
137 137 "id" : "<id>",
138 138 "username" : "<username>",
139 139 "firstname": "<firstname>",
140 140 "lastname" : "<lastname>",
141 141 "email" : "<email>",
142 142 "active" : "<bool>",
143 143 "admin" :Β  "<bool>",
144 "ldap" : "<ldap_dn>"
144 "ldap_dn" : "<ldap_dn>"
145 145 },
146 146 …
147 147 ]
148 148 error: null
149 149
150 150
151 151 create_user
152 152 -----------
153 153
154 154 Creates new user. This command can
155 155 be executed only using api_key belonging to user with admin rights.
156 156
157 157
158 158 INPUT::
159 159
160 160 api_key : "<api_key>"
161 161 method : "create_user"
162 162 args : {
163 163 "username" : "<username>",
164 164 "password" : "<password>",
165 165 "email" : "<useremail>",
166 166 "firstname" : "<firstname> = None",
167 167 "lastname" : "<lastname> = None",
168 168 "active" : "<bool> = True",
169 169 "admin" : "<bool> = False",
170 170 "ldap_dn" : "<ldap_dn> = None"
171 171 }
172 172
173 173 OUTPUT::
174 174
175 175 result: {
176 176 "id" : "<new_user_id>",
177 177 "msg" : "created new user <username>"
178 178 }
179 179 error: null
180 180
181 181
182 182 update_user
183 183 -----------
184 184
185 185 updates current one if such user exists. This command can
186 186 be executed only using api_key belonging to user with admin rights.
187 187
188 188
189 189 INPUT::
190 190
191 191 api_key : "<api_key>"
192 192 method : "update_user"
193 193 args : {
194 "userid" : "<user_id or username>",
194 195 "username" : "<username>",
195 196 "password" : "<password>",
196 197 "email" : "<useremail>",
197 "firstname" : "<firstname> = None",
198 "lastname" : "<lastname> = None",
199 "active" : "<bool> = True",
200 "admin" : "<bool> = False",
201 "ldap_dn" : "<ldap_dn> = None"
198 "firstname" : "<firstname>",
199 "lastname" : "<lastname>",
200 "active" : "<bool>",
201 "admin" : "<bool>",
202 "ldap_dn" : "<ldap_dn>"
202 203 }
203 204
204 205 OUTPUT::
205 206
206 207 result: {
207 208 "id" : "<edited_user_id>",
208 209 "msg" : "updated user <username>"
209 210 }
210 211 error: null
211 212
212 213
213 214 get_users_group
214 215 ---------------
215 216
216 217 Gets an existing users group. This command can be executed only using api_key
217 218 belonging to user with admin rights.
218 219
219 220
220 221 INPUT::
221 222
222 223 api_key : "<api_key>"
223 224 method : "get_users_group"
224 225 args : {
225 226 "group_name" : "<name>"
226 227 }
227 228
228 229 OUTPUT::
229 230
230 231 result : None if group not exist
231 232 {
232 233 "id" : "<id>",
233 234 "group_name" : "<groupname>",
234 235 "active": "<bool>",
235 236 "members" : [
236 237 { "id" : "<userid>",
237 238 "username" : "<username>",
238 239 "firstname": "<firstname>",
239 240 "lastname" : "<lastname>",
240 241 "email" : "<email>",
241 242 "active" : "<bool>",
242 243 "admin" :Β  "<bool>",
243 244 "ldap" : "<ldap_dn>"
244 245 },
245 246 …
246 247 ]
247 248 }
248 249 error : null
249 250
250 251
251 252 get_users_groups
252 253 ----------------
253 254
254 255 Lists all existing users groups. This command can be executed only using
255 256 api_key belonging to user with admin rights.
256 257
257 258
258 259 INPUT::
259 260
260 261 api_key : "<api_key>"
261 262 method : "get_users_groups"
262 263 args : { }
263 264
264 265 OUTPUT::
265 266
266 267 result : [
267 268 {
268 269 "id" : "<id>",
269 270 "group_name" : "<groupname>",
270 271 "active": "<bool>",
271 272 "members" : [
272 273 {
273 274 "id" : "<userid>",
274 275 "username" : "<username>",
275 276 "firstname": "<firstname>",
276 277 "lastname" : "<lastname>",
277 278 "email" : "<email>",
278 279 "active" : "<bool>",
279 280 "admin" :Β  "<bool>",
280 281 "ldap" : "<ldap_dn>"
281 282 },
282 283 …
283 284 ]
284 285 }
285 286 ]
286 287 error : null
287 288
288 289
289 290 create_users_group
290 291 ------------------
291 292
292 293 Creates new users group. This command can be executed only using api_key
293 294 belonging to user with admin rights
294 295
295 296
296 297 INPUT::
297 298
298 299 api_key : "<api_key>"
299 300 method : "create_users_group"
300 301 args: {
301 302 "group_name": "<groupname>",
302 303 "active":"<bool> = True"
303 304 }
304 305
305 306 OUTPUT::
306 307
307 308 result: {
308 309 "id": "<newusersgroupid>",
309 310 "msg": "created new users group <groupname>"
310 311 }
311 312 error: null
312 313
313 314
314 315 add_user_to_users_group
315 316 -----------------------
316 317
317 318 Adds a user to a users group. If user exists in that group success will be
318 319 `false`. This command can be executed only using api_key
319 320 belonging to user with admin rights
320 321
321 322
322 323 INPUT::
323 324
324 325 api_key : "<api_key>"
325 326 method : "add_user_users_group"
326 327 args: {
327 328 "group_name" : "<groupname>",
328 329 "username" : "<username>"
329 330 }
330 331
331 332 OUTPUT::
332 333
333 334 result: {
334 335 "id": "<newusersgroupmemberid>",
335 336 "success": True|False # depends on if member is in group
336 337 "msg": "added member <username> to users group <groupname> |
337 338 User is already in that group"
338 339 }
339 340 error: null
340 341
341 342
342 343 remove_user_from_users_group
343 344 ----------------------------
344 345
345 346 Removes a user from a users group. If user is not in given group success will
346 347 be `false`. This command can be executed only
347 348 using api_key belonging to user with admin rights
348 349
349 350
350 351 INPUT::
351 352
352 353 api_key : "<api_key>"
353 354 method : "remove_user_from_users_group"
354 355 args: {
355 356 "group_name" : "<groupname>",
356 357 "username" : "<username>"
357 358 }
358 359
359 360 OUTPUT::
360 361
361 362 result: {
362 363 "success": True|False, # depends on if member is in group
363 364 "msg": "removed member <username> from users group <groupname> |
364 365 User wasn't in group"
365 366 }
366 367 error: null
367 368
368 369
369 370 get_repo
370 371 --------
371 372
372 373 Gets an existing repository. This command can be executed only using api_key
373 374 belonging to user with admin rights
374 375
375 376
376 377 INPUT::
377 378
378 379 api_key : "<api_key>"
379 380 method : "get_repo"
380 381 args: {
381 382 "repo_name" : "<reponame>"
382 383 }
383 384
384 385 OUTPUT::
385 386
386 387 result: None if repository does not exist or
387 388 {
388 389 "id" : "<id>",
389 390 "repo_name" : "<reponame>"
390 391 "type" : "<type>",
391 392 "description" : "<description>",
392 393 "members" : [
393 394 { "id" : "<userid>",
394 395 "username" : "<username>",
395 396 "firstname": "<firstname>",
396 397 "lastname" : "<lastname>",
397 398 "email" : "<email>",
398 399 "active" : "<bool>",
399 400 "admin" :Β  "<bool>",
400 401 "ldap" : "<ldap_dn>",
401 402 "permission" : "repository.(read|write|admin)"
402 403 },
403 404 …
404 405 {
405 406 "id" : "<usersgroupid>",
406 407 "name" : "<usersgroupname>",
407 408 "active": "<bool>",
408 409 "permission" : "repository.(read|write|admin)"
409 410 },
410 411 …
411 412 ]
412 413 }
413 414 error: null
414 415
415 416
416 417 get_repos
417 418 ---------
418 419
419 420 Lists all existing repositories. This command can be executed only using api_key
420 421 belonging to user with admin rights
421 422
422 423
423 424 INPUT::
424 425
425 426 api_key : "<api_key>"
426 427 method : "get_repos"
427 428 args: { }
428 429
429 430 OUTPUT::
430 431
431 432 result: [
432 433 {
433 434 "id" : "<id>",
434 435 "repo_name" : "<reponame>"
435 436 "type" : "<type>",
436 437 "description" : "<description>"
437 438 },
438 439 …
439 440 ]
440 441 error: null
441 442
442 443
443 444 get_repo_nodes
444 445 --------------
445 446
446 447 returns a list of nodes and it's children in a flat list for a given path
447 448 at given revision. It's possible to specify ret_type to show only `files` or
448 449 `dirs`. This command can be executed only using api_key belonging to user
449 450 with admin rights
450 451
451 452
452 453 INPUT::
453 454
454 455 api_key : "<api_key>"
455 456 method : "get_repo_nodes"
456 457 args: {
457 458 "repo_name" : "<reponame>",
458 459 "revision" : "<revision>",
459 460 "root_path" : "<root_path>",
460 461 "ret_type" : "<ret_type>" = 'all'
461 462 }
462 463
463 464 OUTPUT::
464 465
465 466 result: [
466 467 {
467 468 "name" : "<name>"
468 469 "type" : "<type>",
469 470 },
470 471 …
471 472 ]
472 473 error: null
473 474
474 475
475 476 create_repo
476 477 -----------
477 478
478 479 Creates a repository. This command can be executed only using api_key
479 480 belonging to user with admin rights.
480 481 If repository name contains "/", all needed repository groups will be created.
481 482 For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
482 483 and create "baz" repository with "bar" as group.
483 484
484 485
485 486 INPUT::
486 487
487 488 api_key : "<api_key>"
488 489 method : "create_repo"
489 490 args: {
490 491 "repo_name" : "<reponame>",
491 492 "owner_name" : "<ownername>",
492 493 "description" : "<description> = ''",
493 494 "repo_type" : "<type> = 'hg'",
494 495 "private" : "<bool> = False",
495 496 "clone_uri" : "<clone_uri> = None",
496 497 }
497 498
498 499 OUTPUT::
499 500
500 501 result: {
501 502 "id": "<newrepoid>",
502 503 "msg": "Created new repository <reponame>",
503 504 }
504 505 error: null
505 506
506 507
507 508 delete_repo
508 509 -----------
509 510
510 511 Deletes a repository. This command can be executed only using api_key
511 512 belonging to user with admin rights.
512 513
513 514
514 515 INPUT::
515 516
516 517 api_key : "<api_key>"
517 518 method : "delete_repo"
518 519 args: {
519 520 "repo_name" : "<reponame>",
520 521 }
521 522
522 523 OUTPUT::
523 524
524 525 result: {
525 526 "msg": "Deleted repository <reponame>",
526 527 }
527 528 error: null
528 529
529 530
530 531 grant_user_permission
531 532 ---------------------
532 533
533 534 Grant permission for user on given repository, or update existing one
534 535 if found. This command can be executed only using api_key belonging to user
535 536 with admin rights.
536 537
537 538
538 539 INPUT::
539 540
540 541 api_key : "<api_key>"
541 542 method : "grant_user_permission"
542 543 args: {
543 544 "repo_name" : "<reponame>",
544 545 "username" : "<username>",
545 546 "perm" : "(repository.(none|read|write|admin))",
546 547 }
547 548
548 549 OUTPUT::
549 550
550 551 result: {
551 552 "msg" : "Granted perm: <perm> for user: <username> in repo: <reponame>"
552 553 }
553 554 error: null
554 555
555 556
556 557 revoke_user_permission
557 558 ----------------------
558 559
559 560 Revoke permission for user on given repository. This command can be executed
560 561 only using api_key belonging to user with admin rights.
561 562
562 563
563 564 INPUT::
564 565
565 566 api_key : "<api_key>"
566 567 method : "revoke_user_permission"
567 568 args: {
568 569 "repo_name" : "<reponame>",
569 570 "username" : "<username>",
570 571 }
571 572
572 573 OUTPUT::
573 574
574 575 result: {
575 576 "msg" : "Revoked perm for user: <suername> in repo: <reponame>"
576 577 }
577 578 error: null
578 579
579 580
580 581 grant_users_group_permission
581 582 ----------------------------
582 583
583 584 Grant permission for users group on given repository, or update
584 585 existing one if found. This command can be executed only using
585 586 api_key belonging to user with admin rights.
586 587
587 588
588 589 INPUT::
589 590
590 591 api_key : "<api_key>"
591 592 method : "grant_users_group_permission"
592 593 args: {
593 594 "repo_name" : "<reponame>",
594 595 "group_name" : "<usersgroupname>",
595 596 "perm" : "(repository.(none|read|write|admin))",
596 597 }
597 598
598 599 OUTPUT::
599 600
600 601 result: {
601 602 "msg" : "Granted perm: <perm> for group: <usersgroupname> in repo: <reponame>"
602 603 }
603 604 error: null
604 605
605 606
606 607 revoke_users_group_permission
607 608 -----------------------------
608 609
609 610 Revoke permission for users group on given repository.This command can be
610 611 executed only using api_key belonging to user with admin rights.
611 612
612 613 INPUT::
613 614
614 615 api_key : "<api_key>"
615 616 method : "revoke_users_group_permission"
616 617 args: {
617 618 "repo_name" : "<reponame>",
618 619 "users_group" : "<usersgroupname>",
619 620 }
620 621
621 622 OUTPUT::
622 623
623 624 result: {
624 625 "msg" : "Revoked perm for group: <usersgroupname> in repo: <reponame>"
625 626 }
626 627 error: null No newline at end of file
@@ -1,660 +1,660 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.api
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 API controller for RhodeCode
7 7
8 8 :created_on: Aug 20, 2011
9 9 :author: marcink
10 10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import traceback
29 29 import logging
30 30
31 31 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
32 32 from rhodecode.lib.auth import HasPermissionAllDecorator, \
33 33 HasPermissionAnyDecorator, PasswordGenerator
34 34
35 35 from rhodecode.model.meta import Session
36 36 from rhodecode.model.scm import ScmModel
37 37 from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository
38 38 from rhodecode.model.repo import RepoModel
39 39 from rhodecode.model.user import UserModel
40 40 from rhodecode.model.users_group import UsersGroupModel
41 41 from rhodecode.model.repos_group import ReposGroupModel
42 42
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46
47 47 class ApiController(JSONRPCController):
48 48 """
49 49 API Controller
50 50
51 51
52 52 Each method needs to have USER as argument this is then based on given
53 53 API_KEY propagated as instance of user object
54 54
55 55 Preferably this should be first argument also
56 56
57 57
58 58 Each function should also **raise** JSONRPCError for any
59 59 errors that happens
60 60
61 61 """
62 62
63 63 @HasPermissionAllDecorator('hg.admin')
64 64 def pull(self, apiuser, repo_name):
65 65 """
66 66 Dispatch pull action on given repo
67 67
68 68
69 69 :param user:
70 70 :param repo_name:
71 71 """
72 72
73 73 if Repository.is_valid(repo_name) is False:
74 74 raise JSONRPCError('Unknown repo "%s"' % repo_name)
75 75
76 76 try:
77 77 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
78 78 return 'Pulled from %s' % repo_name
79 79 except Exception:
80 80 raise JSONRPCError('Unable to pull changes from "%s"' % repo_name)
81 81
82 82 @HasPermissionAllDecorator('hg.admin')
83 83 def get_user(self, apiuser, username):
84 84 """"
85 85 Get a user by username
86 86
87 87 :param apiuser:
88 88 :param username:
89 89 """
90 90
91 91 user = User.get_by_username(username)
92 92 if user is None:
93 93 return user
94 94
95 95 return dict(
96 96 id=user.user_id,
97 97 username=user.username,
98 98 firstname=user.name,
99 99 lastname=user.lastname,
100 100 email=user.email,
101 101 active=user.active,
102 102 admin=user.admin,
103 ldap=user.ldap_dn
103 ldap_dn=user.ldap_dn
104 104 )
105 105
106 106 @HasPermissionAllDecorator('hg.admin')
107 107 def get_users(self, apiuser):
108 108 """"
109 109 Get all users
110 110
111 111 :param apiuser:
112 112 """
113 113
114 114 result = []
115 115 for user in User.getAll():
116 116 result.append(
117 117 dict(
118 118 id=user.user_id,
119 119 username=user.username,
120 120 firstname=user.name,
121 121 lastname=user.lastname,
122 122 email=user.email,
123 123 active=user.active,
124 124 admin=user.admin,
125 ldap=user.ldap_dn
125 ldap_dn=user.ldap_dn
126 126 )
127 127 )
128 128 return result
129 129
130 130 @HasPermissionAllDecorator('hg.admin')
131 131 def create_user(self, apiuser, username, email, password, firstname=None,
132 132 lastname=None, active=True, admin=False, ldap_dn=None):
133 133 """
134 134 Create new user
135 135
136 136 :param apiuser:
137 137 :param username:
138 138 :param password:
139 139 :param email:
140 140 :param name:
141 141 :param lastname:
142 142 :param active:
143 143 :param admin:
144 144 :param ldap_dn:
145 145 """
146 146 if User.get_by_username(username):
147 147 raise JSONRPCError("user %s already exist" % username)
148 148
149 149 if User.get_by_email(email, case_insensitive=True):
150 150 raise JSONRPCError("email %s already exist" % email)
151 151
152 152 if ldap_dn:
153 153 # generate temporary password if ldap_dn
154 154 password = PasswordGenerator().gen_password(length=8)
155 155
156 156 try:
157 157 usr = UserModel().create_or_update(
158 158 username, password, email, firstname,
159 159 lastname, active, admin, ldap_dn
160 160 )
161 161 Session.commit()
162 162 return dict(
163 163 id=usr.user_id,
164 164 msg='created new user %s' % username
165 165 )
166 166 except Exception:
167 167 log.error(traceback.format_exc())
168 168 raise JSONRPCError('failed to create user %s' % username)
169 169
170 170 @HasPermissionAllDecorator('hg.admin')
171 def update_user(self, apiuser, username, password, email, firstname=None,
172 lastname=None, active=True, admin=False, ldap_dn=None):
171 def update_user(self, apiuser, userid, username, password, email,
172 firstname, lastname, active, admin, ldap_dn):
173 173 """
174 174 Updates given user
175 175
176 176 :param apiuser:
177 177 :param username:
178 178 :param password:
179 179 :param email:
180 180 :param name:
181 181 :param lastname:
182 182 :param active:
183 183 :param admin:
184 184 :param ldap_dn:
185 185 """
186 if not User.get_by_username(username):
186 if not UserModel().get_user(userid):
187 187 raise JSONRPCError("user %s does not exist" % username)
188 188
189 189 try:
190 190 usr = UserModel().create_or_update(
191 191 username, password, email, firstname,
192 192 lastname, active, admin, ldap_dn
193 193 )
194 194 Session.commit()
195 195 return dict(
196 196 id=usr.user_id,
197 197 msg='updated user %s' % username
198 198 )
199 199 except Exception:
200 200 log.error(traceback.format_exc())
201 201 raise JSONRPCError('failed to update user %s' % username)
202 202
203 203 @HasPermissionAllDecorator('hg.admin')
204 204 def get_users_group(self, apiuser, group_name):
205 205 """"
206 206 Get users group by name
207 207
208 208 :param apiuser:
209 209 :param group_name:
210 210 """
211 211
212 212 users_group = UsersGroup.get_by_group_name(group_name)
213 213 if not users_group:
214 214 return None
215 215
216 216 members = []
217 217 for user in users_group.members:
218 218 user = user.user
219 219 members.append(dict(id=user.user_id,
220 220 username=user.username,
221 221 firstname=user.name,
222 222 lastname=user.lastname,
223 223 email=user.email,
224 224 active=user.active,
225 225 admin=user.admin,
226 226 ldap=user.ldap_dn))
227 227
228 228 return dict(id=users_group.users_group_id,
229 229 group_name=users_group.users_group_name,
230 230 active=users_group.users_group_active,
231 231 members=members)
232 232
233 233 @HasPermissionAllDecorator('hg.admin')
234 234 def get_users_groups(self, apiuser):
235 235 """"
236 236 Get all users groups
237 237
238 238 :param apiuser:
239 239 """
240 240
241 241 result = []
242 242 for users_group in UsersGroup.getAll():
243 243 members = []
244 244 for user in users_group.members:
245 245 user = user.user
246 246 members.append(dict(id=user.user_id,
247 247 username=user.username,
248 248 firstname=user.name,
249 249 lastname=user.lastname,
250 250 email=user.email,
251 251 active=user.active,
252 252 admin=user.admin,
253 253 ldap=user.ldap_dn))
254 254
255 255 result.append(dict(id=users_group.users_group_id,
256 256 group_name=users_group.users_group_name,
257 257 active=users_group.users_group_active,
258 258 members=members))
259 259 return result
260 260
261 261 @HasPermissionAllDecorator('hg.admin')
262 262 def create_users_group(self, apiuser, group_name, active=True):
263 263 """
264 264 Creates an new usergroup
265 265
266 266 :param group_name:
267 267 :param active:
268 268 """
269 269
270 270 if self.get_users_group(apiuser, group_name):
271 271 raise JSONRPCError("users group %s already exist" % group_name)
272 272
273 273 try:
274 274 ug = UsersGroupModel().create(name=group_name, active=active)
275 275 Session.commit()
276 276 return dict(id=ug.users_group_id,
277 277 msg='created new users group %s' % group_name)
278 278 except Exception:
279 279 log.error(traceback.format_exc())
280 280 raise JSONRPCError('failed to create group %s' % group_name)
281 281
282 282 @HasPermissionAllDecorator('hg.admin')
283 283 def add_user_to_users_group(self, apiuser, group_name, username):
284 284 """"
285 285 Add a user to a group
286 286
287 287 :param apiuser:
288 288 :param group_name:
289 289 :param username:
290 290 """
291 291
292 292 try:
293 293 users_group = UsersGroup.get_by_group_name(group_name)
294 294 if not users_group:
295 295 raise JSONRPCError('unknown users group %s' % group_name)
296 296
297 297 user = User.get_by_username(username)
298 298 if user is None:
299 299 raise JSONRPCError('unknown user %s' % username)
300 300
301 301 ugm = UsersGroupModel().add_user_to_group(users_group, user)
302 302 success = True if ugm != True else False
303 303 msg = 'added member %s to users group %s' % (username, group_name)
304 304 msg = msg if success else 'User is already in that group'
305 305 Session.commit()
306 306
307 307 return dict(
308 308 id=ugm.users_group_member_id if ugm != True else None,
309 309 success=success,
310 310 msg=msg
311 311 )
312 312 except Exception:
313 313 log.error(traceback.format_exc())
314 314 raise JSONRPCError('failed to add users group member')
315 315
316 316 @HasPermissionAllDecorator('hg.admin')
317 317 def remove_user_from_users_group(self, apiuser, group_name, username):
318 318 """
319 319 Remove user from a group
320 320
321 321 :param apiuser
322 322 :param group_name
323 323 :param username
324 324 """
325 325
326 326 try:
327 327 users_group = UsersGroup.get_by_group_name(group_name)
328 328 if not users_group:
329 329 raise JSONRPCError('unknown users group %s' % group_name)
330 330
331 331 user = User.get_by_username(username)
332 332 if user is None:
333 333 raise JSONRPCError('unknown user %s' % username)
334 334
335 335 success = UsersGroupModel().remove_user_from_group(users_group, user)
336 336 msg = 'removed member %s from users group %s' % (username, group_name)
337 337 msg = msg if success else "User wasn't in group"
338 338 Session.commit()
339 339 return dict(success=success, msg=msg)
340 340 except Exception:
341 341 log.error(traceback.format_exc())
342 342 raise JSONRPCError('failed to remove user from group')
343 343
344 344 @HasPermissionAnyDecorator('hg.admin')
345 345 def get_repo(self, apiuser, repo_name):
346 346 """"
347 347 Get repository by name
348 348
349 349 :param apiuser:
350 350 :param repo_name:
351 351 """
352 352
353 353 repo = Repository.get_by_repo_name(repo_name)
354 354 if repo is None:
355 355 raise JSONRPCError('unknown repository %s' % repo)
356 356
357 357 members = []
358 358 for user in repo.repo_to_perm:
359 359 perm = user.permission.permission_name
360 360 user = user.user
361 361 members.append(
362 362 dict(
363 363 type_="user",
364 364 id=user.user_id,
365 365 username=user.username,
366 366 firstname=user.name,
367 367 lastname=user.lastname,
368 368 email=user.email,
369 369 active=user.active,
370 370 admin=user.admin,
371 371 ldap=user.ldap_dn,
372 372 permission=perm
373 373 )
374 374 )
375 375 for users_group in repo.users_group_to_perm:
376 376 perm = users_group.permission.permission_name
377 377 users_group = users_group.users_group
378 378 members.append(
379 379 dict(
380 380 type_="users_group",
381 381 id=users_group.users_group_id,
382 382 name=users_group.users_group_name,
383 383 active=users_group.users_group_active,
384 384 permission=perm
385 385 )
386 386 )
387 387
388 388 return dict(
389 389 id=repo.repo_id,
390 390 repo_name=repo.repo_name,
391 391 type=repo.repo_type,
392 392 description=repo.description,
393 393 members=members
394 394 )
395 395
396 396 @HasPermissionAnyDecorator('hg.admin')
397 397 def get_repos(self, apiuser):
398 398 """"
399 399 Get all repositories
400 400
401 401 :param apiuser:
402 402 """
403 403
404 404 result = []
405 405 for repository in Repository.getAll():
406 406 result.append(
407 407 dict(
408 408 id=repository.repo_id,
409 409 repo_name=repository.repo_name,
410 410 type=repository.repo_type,
411 411 description=repository.description
412 412 )
413 413 )
414 414 return result
415 415
416 416 @HasPermissionAnyDecorator('hg.admin')
417 417 def get_repo_nodes(self, apiuser, repo_name, revision, root_path,
418 418 ret_type='all'):
419 419 """
420 420 returns a list of nodes and it's children
421 421 for a given path at given revision. It's possible to specify ret_type
422 422 to show only files or dirs
423 423
424 424 :param apiuser:
425 425 :param repo_name: name of repository
426 426 :param revision: revision for which listing should be done
427 427 :param root_path: path from which start displaying
428 428 :param ret_type: return type 'all|files|dirs' nodes
429 429 """
430 430 try:
431 431 _d, _f = ScmModel().get_nodes(repo_name, revision, root_path,
432 432 flat=False)
433 433 _map = {
434 434 'all': _d + _f,
435 435 'files': _f,
436 436 'dirs': _d,
437 437 }
438 438 return _map[ret_type]
439 439 except KeyError:
440 440 raise JSONRPCError('ret_type must be one of %s' % _map.keys())
441 441 except Exception, e:
442 442 raise JSONRPCError(e)
443 443
444 444 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
445 445 def create_repo(self, apiuser, repo_name, owner_name, description='',
446 446 repo_type='hg', private=False, clone_uri=None):
447 447 """
448 448 Create repository, if clone_url is given it makes a remote clone
449 449
450 450 :param apiuser:
451 451 :param repo_name:
452 452 :param owner_name:
453 453 :param description:
454 454 :param repo_type:
455 455 :param private:
456 456 :param clone_uri:
457 457 """
458 458
459 459 try:
460 460 owner = User.get_by_username(owner_name)
461 461 if owner is None:
462 462 raise JSONRPCError('unknown user %s' % owner_name)
463 463
464 464 if Repository.get_by_repo_name(repo_name):
465 465 raise JSONRPCError("repo %s already exist" % repo_name)
466 466
467 467 groups = repo_name.split('/')
468 468 real_name = groups[-1]
469 469 groups = groups[:-1]
470 470 parent_id = None
471 471 for g in groups:
472 472 group = RepoGroup.get_by_group_name(g)
473 473 if not group:
474 474 group = ReposGroupModel().create(g, '', parent_id)
475 475 parent_id = group.group_id
476 476
477 477 repo = RepoModel().create(
478 478 dict(
479 479 repo_name=real_name,
480 480 repo_name_full=repo_name,
481 481 description=description,
482 482 private=private,
483 483 repo_type=repo_type,
484 484 repo_group=parent_id,
485 485 clone_uri=clone_uri
486 486 ),
487 487 owner
488 488 )
489 489 Session.commit()
490 490
491 491 return dict(
492 492 id=repo.repo_id,
493 493 msg="Created new repository %s" % repo.repo_name
494 494 )
495 495
496 496 except Exception:
497 497 log.error(traceback.format_exc())
498 498 raise JSONRPCError('failed to create repository %s' % repo_name)
499 499
500 500 @HasPermissionAnyDecorator('hg.admin')
501 501 def delete_repo(self, apiuser, repo_name):
502 502 """
503 503 Deletes a given repository
504 504
505 505 :param repo_name:
506 506 """
507 507 if not Repository.get_by_repo_name(repo_name):
508 508 raise JSONRPCError("repo %s does not exist" % repo_name)
509 509 try:
510 510 RepoModel().delete(repo_name)
511 511 Session.commit()
512 512 return dict(
513 513 msg='Deleted repository %s' % repo_name
514 514 )
515 515 except Exception:
516 516 log.error(traceback.format_exc())
517 517 raise JSONRPCError('failed to delete repository %s' % repo_name)
518 518
519 519 @HasPermissionAnyDecorator('hg.admin')
520 520 def grant_user_permission(self, apiuser, repo_name, username, perm):
521 521 """
522 522 Grant permission for user on given repository, or update existing one
523 523 if found
524 524
525 525 :param repo_name:
526 526 :param username:
527 527 :param perm:
528 528 """
529 529
530 530 try:
531 531 repo = Repository.get_by_repo_name(repo_name)
532 532 if repo is None:
533 533 raise JSONRPCError('unknown repository %s' % repo)
534 534
535 535 user = User.get_by_username(username)
536 536 if user is None:
537 537 raise JSONRPCError('unknown user %s' % username)
538 538
539 539 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
540 540
541 541 Session.commit()
542 542 return dict(
543 543 msg='Granted perm: %s for user: %s in repo: %s' % (
544 544 perm, username, repo_name
545 545 )
546 546 )
547 547 except Exception:
548 548 log.error(traceback.format_exc())
549 549 raise JSONRPCError(
550 550 'failed to edit permission %(repo)s for %(user)s' % dict(
551 551 user=username, repo=repo_name
552 552 )
553 553 )
554 554
555 555 @HasPermissionAnyDecorator('hg.admin')
556 556 def revoke_user_permission(self, apiuser, repo_name, username):
557 557 """
558 558 Revoke permission for user on given repository
559 559
560 560 :param repo_name:
561 561 :param username:
562 562 """
563 563
564 564 try:
565 565 repo = Repository.get_by_repo_name(repo_name)
566 566 if repo is None:
567 567 raise JSONRPCError('unknown repository %s' % repo)
568 568
569 569 user = User.get_by_username(username)
570 570 if user is None:
571 571 raise JSONRPCError('unknown user %s' % username)
572 572
573 573 RepoModel().revoke_user_permission(repo=repo_name, user=username)
574 574
575 575 Session.commit()
576 576 return dict(
577 577 msg='Revoked perm for user: %s in repo: %s' % (
578 578 username, repo_name
579 579 )
580 580 )
581 581 except Exception:
582 582 log.error(traceback.format_exc())
583 583 raise JSONRPCError(
584 584 'failed to edit permission %(repo)s for %(user)s' % dict(
585 585 user=username, repo=repo_name
586 586 )
587 587 )
588 588
589 589 @HasPermissionAnyDecorator('hg.admin')
590 590 def grant_users_group_permission(self, apiuser, repo_name, group_name, perm):
591 591 """
592 592 Grant permission for users group on given repository, or update
593 593 existing one if found
594 594
595 595 :param repo_name:
596 596 :param group_name:
597 597 :param perm:
598 598 """
599 599
600 600 try:
601 601 repo = Repository.get_by_repo_name(repo_name)
602 602 if repo is None:
603 603 raise JSONRPCError('unknown repository %s' % repo)
604 604
605 605 user_group = UsersGroup.get_by_group_name(group_name)
606 606 if user_group is None:
607 607 raise JSONRPCError('unknown users group %s' % user_group)
608 608
609 609 RepoModel().grant_users_group_permission(repo=repo_name,
610 610 group_name=group_name,
611 611 perm=perm)
612 612
613 613 Session.commit()
614 614 return dict(
615 615 msg='Granted perm: %s for group: %s in repo: %s' % (
616 616 perm, group_name, repo_name
617 617 )
618 618 )
619 619 except Exception:
620 620 log.error(traceback.format_exc())
621 621 raise JSONRPCError(
622 622 'failed to edit permission %(repo)s for %(usersgr)s' % dict(
623 623 usersgr=group_name, repo=repo_name
624 624 )
625 625 )
626 626
627 627 @HasPermissionAnyDecorator('hg.admin')
628 628 def revoke_users_group_permission(self, apiuser, repo_name, group_name):
629 629 """
630 630 Revoke permission for users group on given repository
631 631
632 632 :param repo_name:
633 633 :param group_name:
634 634 """
635 635
636 636 try:
637 637 repo = Repository.get_by_repo_name(repo_name)
638 638 if repo is None:
639 639 raise JSONRPCError('unknown repository %s' % repo)
640 640
641 641 user_group = UsersGroup.get_by_group_name(group_name)
642 642 if user_group is None:
643 643 raise JSONRPCError('unknown users group %s' % user_group)
644 644
645 645 RepoModel().revoke_users_group_permission(repo=repo_name,
646 646 group_name=group_name)
647 647
648 648 Session.commit()
649 649 return dict(
650 650 msg='Revoked perm for group: %s in repo: %s' % (
651 651 group_name, repo_name
652 652 )
653 653 )
654 654 except Exception:
655 655 log.error(traceback.format_exc())
656 656 raise JSONRPCError(
657 657 'failed to edit permission %(repo)s for %(usersgr)s' % dict(
658 658 usersgr=group_name, repo=repo_name
659 659 )
660 660 )
@@ -1,549 +1,552 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.user
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users model for RhodeCode
7 7
8 8 :created_on: Apr 9, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28
29 29 from pylons import url
30 30 from pylons.i18n.translation import _
31 31
32 32 from rhodecode.lib import safe_unicode
33 33 from rhodecode.lib.caching_query import FromCache
34 34
35 35 from rhodecode.model import BaseModel
36 36 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
37 37 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
38 38 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroup
39 39 from rhodecode.lib.exceptions import DefaultUserException, \
40 40 UserOwnsReposException
41 41
42 42 from sqlalchemy.exc import DatabaseError
43 43 from rhodecode.lib import generate_api_key
44 44 from sqlalchemy.orm import joinedload
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48
49 49 PERM_WEIGHTS = {
50 50 'repository.none': 0,
51 51 'repository.read': 1,
52 52 'repository.write': 3,
53 53 'repository.admin': 4,
54 54 'group.none': 0,
55 55 'group.read': 1,
56 56 'group.write': 3,
57 57 'group.admin': 4,
58 58 }
59 59
60 60
61 61 class UserModel(BaseModel):
62 62
63 63 def __get_user(self, user):
64 64 return self._get_instance(User, user, callback=User.get_by_username)
65 65
66 66 def __get_perm(self, permission):
67 67 return self._get_instance(Permission, permission,
68 68 callback=Permission.get_by_key)
69 69
70 70 def get(self, user_id, cache=False):
71 71 user = self.sa.query(User)
72 72 if cache:
73 73 user = user.options(FromCache("sql_cache_short",
74 74 "get_user_%s" % user_id))
75 75 return user.get(user_id)
76 76
77 def get_user(self, user):
78 return self.__get_user(user)
79
77 80 def get_by_username(self, username, cache=False, case_insensitive=False):
78 81
79 82 if case_insensitive:
80 83 user = self.sa.query(User).filter(User.username.ilike(username))
81 84 else:
82 85 user = self.sa.query(User)\
83 86 .filter(User.username == username)
84 87 if cache:
85 88 user = user.options(FromCache("sql_cache_short",
86 89 "get_user_%s" % username))
87 90 return user.scalar()
88 91
89 92 def get_by_api_key(self, api_key, cache=False):
90 93 return User.get_by_api_key(api_key, cache)
91 94
92 95 def create(self, form_data):
93 96 try:
94 97 new_user = User()
95 98 for k, v in form_data.items():
96 99 setattr(new_user, k, v)
97 100
98 101 new_user.api_key = generate_api_key(form_data['username'])
99 102 self.sa.add(new_user)
100 103 return new_user
101 104 except:
102 105 log.error(traceback.format_exc())
103 106 raise
104 107
105 108 def create_or_update(self, username, password, email, name, lastname,
106 109 active=True, admin=False, ldap_dn=None):
107 110 """
108 111 Creates a new instance if not found, or updates current one
109 112
110 113 :param username:
111 114 :param password:
112 115 :param email:
113 116 :param active:
114 117 :param name:
115 118 :param lastname:
116 119 :param active:
117 120 :param admin:
118 121 :param ldap_dn:
119 122 """
120 123
121 124 from rhodecode.lib.auth import get_crypt_password
122 125
123 126 log.debug('Checking for %s account in RhodeCode database' % username)
124 127 user = User.get_by_username(username, case_insensitive=True)
125 128 if user is None:
126 129 log.debug('creating new user %s' % username)
127 130 new_user = User()
128 131 else:
129 132 log.debug('updating user %s' % username)
130 133 new_user = user
131 134
132 135 try:
133 136 new_user.username = username
134 137 new_user.admin = admin
135 138 new_user.password = get_crypt_password(password)
136 139 new_user.api_key = generate_api_key(username)
137 140 new_user.email = email
138 141 new_user.active = active
139 142 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
140 143 new_user.name = name
141 144 new_user.lastname = lastname
142 145 self.sa.add(new_user)
143 146 return new_user
144 147 except (DatabaseError,):
145 148 log.error(traceback.format_exc())
146 149 raise
147 150
148 151 def create_for_container_auth(self, username, attrs):
149 152 """
150 153 Creates the given user if it's not already in the database
151 154
152 155 :param username:
153 156 :param attrs:
154 157 """
155 158 if self.get_by_username(username, case_insensitive=True) is None:
156 159
157 160 # autogenerate email for container account without one
158 161 generate_email = lambda usr: '%s@container_auth.account' % usr
159 162
160 163 try:
161 164 new_user = User()
162 165 new_user.username = username
163 166 new_user.password = None
164 167 new_user.api_key = generate_api_key(username)
165 168 new_user.email = attrs['email']
166 169 new_user.active = attrs.get('active', True)
167 170 new_user.name = attrs['name'] or generate_email(username)
168 171 new_user.lastname = attrs['lastname']
169 172
170 173 self.sa.add(new_user)
171 174 return new_user
172 175 except (DatabaseError,):
173 176 log.error(traceback.format_exc())
174 177 self.sa.rollback()
175 178 raise
176 179 log.debug('User %s already exists. Skipping creation of account'
177 180 ' for container auth.', username)
178 181 return None
179 182
180 183 def create_ldap(self, username, password, user_dn, attrs):
181 184 """
182 185 Checks if user is in database, if not creates this user marked
183 186 as ldap user
184 187
185 188 :param username:
186 189 :param password:
187 190 :param user_dn:
188 191 :param attrs:
189 192 """
190 193 from rhodecode.lib.auth import get_crypt_password
191 194 log.debug('Checking for such ldap account in RhodeCode database')
192 195 if self.get_by_username(username, case_insensitive=True) is None:
193 196
194 197 # autogenerate email for ldap account without one
195 198 generate_email = lambda usr: '%s@ldap.account' % usr
196 199
197 200 try:
198 201 new_user = User()
199 202 username = username.lower()
200 203 # add ldap account always lowercase
201 204 new_user.username = username
202 205 new_user.password = get_crypt_password(password)
203 206 new_user.api_key = generate_api_key(username)
204 207 new_user.email = attrs['email'] or generate_email(username)
205 208 new_user.active = attrs.get('active', True)
206 209 new_user.ldap_dn = safe_unicode(user_dn)
207 210 new_user.name = attrs['name']
208 211 new_user.lastname = attrs['lastname']
209 212
210 213 self.sa.add(new_user)
211 214 return new_user
212 215 except (DatabaseError,):
213 216 log.error(traceback.format_exc())
214 217 self.sa.rollback()
215 218 raise
216 219 log.debug('this %s user exists skipping creation of ldap account',
217 220 username)
218 221 return None
219 222
220 223 def create_registration(self, form_data):
221 224 from rhodecode.model.notification import NotificationModel
222 225
223 226 try:
224 227 new_user = User()
225 228 for k, v in form_data.items():
226 229 if k != 'admin':
227 230 setattr(new_user, k, v)
228 231
229 232 self.sa.add(new_user)
230 233 self.sa.flush()
231 234
232 235 # notification to admins
233 236 subject = _('new user registration')
234 237 body = ('New user registration\n'
235 238 '---------------------\n'
236 239 '- Username: %s\n'
237 240 '- Full Name: %s\n'
238 241 '- Email: %s\n')
239 242 body = body % (new_user.username, new_user.full_name,
240 243 new_user.email)
241 244 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
242 245 kw = {'registered_user_url': edit_url}
243 246 NotificationModel().create(created_by=new_user, subject=subject,
244 247 body=body, recipients=None,
245 248 type_=Notification.TYPE_REGISTRATION,
246 249 email_kwargs=kw)
247 250
248 251 except:
249 252 log.error(traceback.format_exc())
250 253 raise
251 254
252 255 def update(self, user_id, form_data):
253 256 try:
254 257 user = self.get(user_id, cache=False)
255 258 if user.username == 'default':
256 259 raise DefaultUserException(
257 260 _("You can't Edit this user since it's"
258 261 " crucial for entire application"))
259 262
260 263 for k, v in form_data.items():
261 264 if k == 'new_password' and v != '':
262 265 user.password = v
263 266 user.api_key = generate_api_key(user.username)
264 267 else:
265 268 setattr(user, k, v)
266 269
267 270 self.sa.add(user)
268 271 except:
269 272 log.error(traceback.format_exc())
270 273 raise
271 274
272 275 def update_my_account(self, user_id, form_data):
273 276 try:
274 277 user = self.get(user_id, cache=False)
275 278 if user.username == 'default':
276 279 raise DefaultUserException(
277 280 _("You can't Edit this user since it's"
278 281 " crucial for entire application"))
279 282 for k, v in form_data.items():
280 283 if k == 'new_password' and v != '':
281 284 user.password = v
282 285 user.api_key = generate_api_key(user.username)
283 286 else:
284 287 if k not in ['admin', 'active']:
285 288 setattr(user, k, v)
286 289
287 290 self.sa.add(user)
288 291 except:
289 292 log.error(traceback.format_exc())
290 293 raise
291 294
292 295 def delete(self, user):
293 296 user = self.__get_user(user)
294 297
295 298 try:
296 299 if user.username == 'default':
297 300 raise DefaultUserException(
298 301 _("You can't remove this user since it's"
299 302 " crucial for entire application"))
300 303 if user.repositories:
301 304 raise UserOwnsReposException(_('This user still owns %s '
302 305 'repositories and cannot be '
303 306 'removed. Switch owners or '
304 307 'remove those repositories') \
305 308 % user.repositories)
306 309 self.sa.delete(user)
307 310 except:
308 311 log.error(traceback.format_exc())
309 312 raise
310 313
311 314 def reset_password_link(self, data):
312 315 from rhodecode.lib.celerylib import tasks, run_task
313 316 run_task(tasks.send_password_link, data['email'])
314 317
315 318 def reset_password(self, data):
316 319 from rhodecode.lib.celerylib import tasks, run_task
317 320 run_task(tasks.reset_user_password, data['email'])
318 321
319 322 def fill_data(self, auth_user, user_id=None, api_key=None):
320 323 """
321 324 Fetches auth_user by user_id,or api_key if present.
322 325 Fills auth_user attributes with those taken from database.
323 326 Additionally set's is_authenitated if lookup fails
324 327 present in database
325 328
326 329 :param auth_user: instance of user to set attributes
327 330 :param user_id: user id to fetch by
328 331 :param api_key: api key to fetch by
329 332 """
330 333 if user_id is None and api_key is None:
331 334 raise Exception('You need to pass user_id or api_key')
332 335
333 336 try:
334 337 if api_key:
335 338 dbuser = self.get_by_api_key(api_key)
336 339 else:
337 340 dbuser = self.get(user_id)
338 341
339 342 if dbuser is not None and dbuser.active:
340 343 log.debug('filling %s data' % dbuser)
341 344 for k, v in dbuser.get_dict().items():
342 345 setattr(auth_user, k, v)
343 346 else:
344 347 return False
345 348
346 349 except:
347 350 log.error(traceback.format_exc())
348 351 auth_user.is_authenticated = False
349 352 return False
350 353
351 354 return True
352 355
353 356 def fill_perms(self, user):
354 357 """
355 358 Fills user permission attribute with permissions taken from database
356 359 works for permissions given for repositories, and for permissions that
357 360 are granted to groups
358 361
359 362 :param user: user instance to fill his perms
360 363 """
361 364 RK = 'repositories'
362 365 GK = 'repositories_groups'
363 366 GLOBAL = 'global'
364 367 user.permissions[RK] = {}
365 368 user.permissions[GK] = {}
366 369 user.permissions[GLOBAL] = set()
367 370
368 371 #======================================================================
369 372 # fetch default permissions
370 373 #======================================================================
371 374 default_user = User.get_by_username('default', cache=True)
372 375 default_user_id = default_user.user_id
373 376
374 377 default_repo_perms = Permission.get_default_perms(default_user_id)
375 378 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
376 379
377 380 if user.is_admin:
378 381 #==================================================================
379 382 # admin user have all default rights for repositories
380 383 # and groups set to admin
381 384 #==================================================================
382 385 user.permissions[GLOBAL].add('hg.admin')
383 386
384 387 # repositories
385 388 for perm in default_repo_perms:
386 389 r_k = perm.UserRepoToPerm.repository.repo_name
387 390 p = 'repository.admin'
388 391 user.permissions[RK][r_k] = p
389 392
390 393 # repositories groups
391 394 for perm in default_repo_groups_perms:
392 395 rg_k = perm.UserRepoGroupToPerm.group.group_name
393 396 p = 'group.admin'
394 397 user.permissions[GK][rg_k] = p
395 398
396 399 else:
397 400 #==================================================================
398 401 # set default permissions first for repositories and groups
399 402 #==================================================================
400 403 uid = user.user_id
401 404
402 405 # default global permissions
403 406 default_global_perms = self.sa.query(UserToPerm)\
404 407 .filter(UserToPerm.user_id == default_user_id)
405 408
406 409 for perm in default_global_perms:
407 410 user.permissions[GLOBAL].add(perm.permission.permission_name)
408 411
409 412 # default for repositories
410 413 for perm in default_repo_perms:
411 414 r_k = perm.UserRepoToPerm.repository.repo_name
412 415 if perm.Repository.private and not (perm.Repository.user_id == uid):
413 416 # disable defaults for private repos,
414 417 p = 'repository.none'
415 418 elif perm.Repository.user_id == uid:
416 419 # set admin if owner
417 420 p = 'repository.admin'
418 421 else:
419 422 p = perm.Permission.permission_name
420 423
421 424 user.permissions[RK][r_k] = p
422 425
423 426 # default for repositories groups
424 427 for perm in default_repo_groups_perms:
425 428 rg_k = perm.UserRepoGroupToPerm.group.group_name
426 429 p = perm.Permission.permission_name
427 430 user.permissions[GK][rg_k] = p
428 431
429 432 #==================================================================
430 433 # overwrite default with user permissions if any
431 434 #==================================================================
432 435
433 436 # user global
434 437 user_perms = self.sa.query(UserToPerm)\
435 438 .options(joinedload(UserToPerm.permission))\
436 439 .filter(UserToPerm.user_id == uid).all()
437 440
438 441 for perm in user_perms:
439 442 user.permissions[GLOBAL].add(perm.permission.permission_name)
440 443
441 444 # user repositories
442 445 user_repo_perms = \
443 446 self.sa.query(UserRepoToPerm, Permission, Repository)\
444 447 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
445 448 .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
446 449 .filter(UserRepoToPerm.user_id == uid)\
447 450 .all()
448 451
449 452 for perm in user_repo_perms:
450 453 # set admin if owner
451 454 r_k = perm.UserRepoToPerm.repository.repo_name
452 455 if perm.Repository.user_id == uid:
453 456 p = 'repository.admin'
454 457 else:
455 458 p = perm.Permission.permission_name
456 459 user.permissions[RK][r_k] = p
457 460
458 461 #==================================================================
459 462 # check if user is part of groups for this repository and fill in
460 463 # (or replace with higher) permissions
461 464 #==================================================================
462 465
463 466 # users group global
464 467 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
465 468 .options(joinedload(UsersGroupToPerm.permission))\
466 469 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
467 470 UsersGroupMember.users_group_id))\
468 471 .filter(UsersGroupMember.user_id == uid).all()
469 472
470 473 for perm in user_perms_from_users_groups:
471 474 user.permissions[GLOBAL].add(perm.permission.permission_name)
472 475
473 476 # users group repositories
474 477 user_repo_perms_from_users_groups = \
475 478 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
476 479 .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\
477 480 .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\
478 481 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\
479 482 .filter(UsersGroupMember.user_id == uid)\
480 483 .all()
481 484
482 485 for perm in user_repo_perms_from_users_groups:
483 486 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
484 487 p = perm.Permission.permission_name
485 488 cur_perm = user.permissions[RK][r_k]
486 489 # overwrite permission only if it's greater than permission
487 490 # given from other sources
488 491 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
489 492 user.permissions[RK][r_k] = p
490 493
491 494 #==================================================================
492 495 # get access for this user for repos group and override defaults
493 496 #==================================================================
494 497
495 498 # user repositories groups
496 499 user_repo_groups_perms = \
497 500 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
498 501 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
499 502 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
500 503 .filter(UserRepoToPerm.user_id == uid)\
501 504 .all()
502 505
503 506 for perm in user_repo_groups_perms:
504 507 rg_k = perm.UserRepoGroupToPerm.group.group_name
505 508 p = perm.Permission.permission_name
506 509 cur_perm = user.permissions[GK][rg_k]
507 510 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
508 511 user.permissions[GK][rg_k] = p
509 512
510 513 return user
511 514
512 515 def has_perm(self, user, perm):
513 516 if not isinstance(perm, Permission):
514 517 raise Exception('perm needs to be an instance of Permission class '
515 518 'got %s instead' % type(perm))
516 519
517 520 user = self.__get_user(user)
518 521
519 522 return UserToPerm.query().filter(UserToPerm.user == user)\
520 523 .filter(UserToPerm.permission == perm).scalar() is not None
521 524
522 525 def grant_perm(self, user, perm):
523 526 """
524 527 Grant user global permissions
525 528
526 529 :param user:
527 530 :param perm:
528 531 """
529 532 user = self.__get_user(user)
530 533 perm = self.__get_perm(perm)
531 534 new = UserToPerm()
532 535 new.user = user
533 536 new.permission = perm
534 537 self.sa.add(new)
535 538
536 539 def revoke_perm(self, user, perm):
537 540 """
538 541 Revoke users global permissions
539 542
540 543 :param user:
541 544 :param perm:
542 545 """
543 546 user = self.__get_user(user)
544 547 perm = self.__get_perm(perm)
545 548
546 549 obj = UserToPerm.query().filter(UserToPerm.user == user)\
547 550 .filter(UserToPerm.permission == perm).scalar()
548 551 if obj:
549 552 self.sa.delete(obj)
General Comments 0
You need to be logged in to leave comments. Login now