##// END OF EJS Templates
Improve API with user/group/repo CRUD methods
Nicolas VINOT -
r1584:3338a099 beta
parent child Browse files
Show More
@@ -1,6 +1,8 b''
1 1 syntax: glob
2 2 *.pyc
3 3 *.swp
4 *.ini
5 Paste*
4 6
5 7 syntax: regexp
6 8 ^build
@@ -14,3 +16,4 b' syntax: regexp'
14 16 ^test\.db$
15 17 ^repositories\.config$
16 18 ^RhodeCode\.egg-info$
19 ^env$
@@ -2,10 +2,11 b' import traceback'
2 2 import logging
3 3
4 4 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
5 from rhodecode.lib.auth import HasPermissionAllDecorator
5 from rhodecode.lib.auth import HasPermissionAllDecorator, HasPermissionAnyDecorator
6 6 from rhodecode.model.scm import ScmModel
7 7
8 from rhodecode.model.db import User, UsersGroup, Repository
8 from rhodecode.model.db import User, UsersGroup, UsersGroupMember, Group, Repository
9 from rhodecode.model.repo import RepoModel
9 10
10 11 log = logging.getLogger(__name__)
11 12
@@ -13,25 +14,25 b' log = logging.getLogger(__name__)'
13 14 class ApiController(JSONRPCController):
14 15 """
15 16 API Controller
16
17
17
18
18 19 Each method needs to have USER as argument this is then based on given
19 20 API_KEY propagated as instance of user object
20
21
21 22 Preferably this should be first argument also
22
23
24 Each function should also **raise** JSONRPCError for any
23
24
25 Each function should also **raise** JSONRPCError for any
25 26 errors that happens
26
27
27 28 """
28 29
29 30 @HasPermissionAllDecorator('hg.admin')
30 31 def pull(self, apiuser, repo):
31 32 """
32 33 Dispatch pull action on given repo
33
34
34
35
35 36 :param user:
36 37 :param repo:
37 38 """
@@ -47,28 +48,30 b' class ApiController(JSONRPCController):'
47 48
48 49
49 50 @HasPermissionAllDecorator('hg.admin')
50 def create_user(self, apiuser, username, password, active, admin, name,
51 lastname, email):
51 def create_user(self, apiuser, username, password, name,
52 lastname, email, active=True, admin=False, ldap_dn=None):
52 53 """
53 54 Creates new user
54
55
55 56 :param apiuser:
56 57 :param username:
57 58 :param password:
58 :param active:
59 :param admin:
60 59 :param name:
61 60 :param lastname:
62 61 :param email:
62 :param active:
63 :param admin:
64 :param ldap_dn:
63 65 """
64
66
65 67 form_data = dict(username=username,
66 68 password=password,
67 69 active=active,
68 70 admin=admin,
69 71 name=name,
70 72 lastname=lastname,
71 email=email)
73 email=email,
74 ldap_dn=ldap_dn)
72 75 try:
73 76 u = User.create(form_data)
74 77 return {'id':u.user_id,
@@ -77,12 +80,27 b' class ApiController(JSONRPCController):'
77 80 log.error(traceback.format_exc())
78 81 raise JSONRPCError('failed to create user %s' % name)
79 82
83 @HasPermissionAllDecorator('hg.admin')
84 def list_users(self, apiuser):
85 """"
86 Lists all users
87
88 :param apiuser
89 """
90 result = []
91 for user in User.getAll():
92 result.append({ 'username':user.username,
93 'name': user.name,
94 'lastname': user.lastname,
95 'email': user.email })
96 return result
97
80 98
81 99 @HasPermissionAllDecorator('hg.admin')
82 def create_users_group(self, apiuser, name, active):
100 def create_users_group(self, apiuser, name, active=True):
83 101 """
84 102 Creates an new usergroup
85
103
86 104 :param name:
87 105 :param active:
88 106 """
@@ -95,4 +113,81 b' class ApiController(JSONRPCController):'
95 113 except Exception:
96 114 log.error(traceback.format_exc())
97 115 raise JSONRPCError('failed to create group %s' % name)
98 No newline at end of file
116
117 @HasPermissionAllDecorator('hg.admin')
118 def list_users_groups(self, apiuser):
119 """"
120 Lists all users groups
121
122 :param apiuser
123 """
124 result = []
125 for users_group in UsersGroup.getAll():
126 result.append({ 'name': users_group.name })
127 return result
128
129
130 @HasPermissionAllDecorator('hg.admin')
131 def add_user_to_group(self, apiuser, user_name, group_name):
132 """"
133 Add a user to a group
134
135 :param apiuser
136 :param user_name
137 :param group_name
138 """
139
140 users_group = UsersGroup.get_by_group_name(group_name)
141 if not users_group:
142 raise JSONRPCError('unknown users group %s' % group_name)
143
144 user = User.by_username(user_name)
145 if not user:
146 raise JSONRPCError('unknown user %s' % user_name)
147
148 try:
149 UsersGroupMember.create(user, users_group)
150 except Exception:
151 log.error(traceback.format_exc())
152 raise JSONRPCError('failed to create users group member')
153
154 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
155 def create_repo(self, apiuser, name, owner_name, description=None, repo_type='hg', \
156 private=False, group_name=None):
157 """
158 Create a repository
159
160 :param apiuser
161 :param name
162 :param description
163 :param type
164 :param private
165 :param owner_name
166 :param group_name
167 :param clone
168 """
169
170 if group_name:
171 group = Group.get_by_group_name(group_name)
172 if group is None:
173 raise JSONRPCError('unknown group %s' % group_name)
174 else:
175 group = None
176
177 owner = User.by_username(owner_name)
178 if owner is None:
179 raise JSONRPCError('unknown user %s' % owner)
180
181 try:
182 RepoModel().create({ "repo_name" : name,
183 "repo_name_full" : name,
184 "description" : description,
185 "private" : private,
186 "repo_type" : repo_type,
187 "repo_group" : group,
188 "clone_uri" : None }, owner)
189 except Exception:
190 log.error(traceback.format_exc())
191 raise JSONRPCError('failed to create repository %s' % name)
192
193
@@ -57,24 +57,24 b' log = logging.getLogger(__name__)'
57 57 class ModelSerializer(json.JSONEncoder):
58 58 """
59 59 Simple Serializer for JSON,
60
60
61 61 usage::
62
62
63 63 to make object customized for serialization implement a __json__
64 64 method that will return a dict for serialization into json
65
65
66 66 example::
67
67
68 68 class Task(object):
69
69
70 70 def __init__(self, name, value):
71 71 self.name = name
72 72 self.value = value
73
73
74 74 def __json__(self):
75 75 return dict(name=self.name,
76 value=self.value)
77
76 value=self.value)
77
78 78 """
79 79
80 80 def default(self, obj):
@@ -125,11 +125,15 b' class BaseModel(object):'
125 125
126 126 @classmethod
127 127 def get(cls, id_):
128 return Session.query(cls).get(id_)
128 return cls.query().get(id_)
129
130 @classmethod
131 def getAll(cls):
132 return cls.query().all()
129 133
130 134 @classmethod
131 135 def delete(cls, id_):
132 obj = Session.query(cls).get(id_)
136 obj = cls.query().get(id_)
133 137 Session.delete(obj)
134 138 Session.commit()
135 139
@@ -152,13 +156,13 b' class RhodeCodeSettings(Base, BaseModel)'
152 156
153 157 @classmethod
154 158 def get_by_name(cls, ldap_key):
155 return Session.query(cls)\
159 return cls.query()\
156 160 .filter(cls.app_settings_name == ldap_key).scalar()
157 161
158 162 @classmethod
159 163 def get_app_settings(cls, cache=False):
160 164
161 ret = Session.query(cls)
165 ret = cls.query()
162 166
163 167 if cache:
164 168 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
@@ -174,7 +178,7 b' class RhodeCodeSettings(Base, BaseModel)'
174 178
175 179 @classmethod
176 180 def get_ldap_settings(cls, cache=False):
177 ret = Session.query(cls)\
181 ret = cls.query()\
178 182 .filter(cls.app_settings_name.startswith('ldap_'))\
179 183 .all()
180 184 fd = {}
@@ -204,7 +208,7 b' class RhodeCodeUi(Base, BaseModel):'
204 208
205 209 @classmethod
206 210 def get_by_key(cls, key):
207 return Session.query(cls).filter(cls.ui_key == key)
211 return cls.query().filter(cls.ui_key == key)
208 212
209 213
210 214 @classmethod
@@ -282,14 +286,13 b' class User(Base, BaseModel):'
282 286 @classmethod
283 287 def by_username(cls, username, case_insensitive=False):
284 288 if case_insensitive:
285 return Session.query(cls).filter(cls.username.like(username)).one()
289 return cls.query().filter(cls.username.like(username)).one()
286 290 else:
287 return Session.query(cls).filter(cls.username == username).one()
291 return cls.query().filter(cls.username == username).one()
288 292
289 293 @classmethod
290 294 def get_by_api_key(cls, api_key):
291 return Session.query(cls).filter(cls.api_key == api_key).one()
292
295 return cls.query().filter(cls.api_key == api_key).one()
293 296
294 297 def update_lastlogin(self):
295 298 """Update user lastlogin"""
@@ -302,7 +305,7 b' class User(Base, BaseModel):'
302 305 @classmethod
303 306 def create(cls, form_data):
304 307 from rhodecode.lib.auth import get_crypt_password
305
308
306 309 try:
307 310 new_user = cls()
308 311 for k, v in form_data.items():
@@ -354,11 +357,11 b' class UsersGroup(Base, BaseModel):'
354 357 @classmethod
355 358 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
356 359 if case_insensitive:
357 gr = Session.query(cls)\
358 .filter(cls.users_group_name.ilike(group_name))
360 gr = cls.query()\
361 .filter(cls.users_group_name.ilike(group_name))
359 362 else:
360 gr = Session.query(UsersGroup)\
361 .filter(UsersGroup.users_group_name == group_name)
363 gr = cls.query()\
364 .filter(cls.users_group_name == group_name)
362 365 if cache:
363 366 gr = gr.options(FromCache("sql_cache_short",
364 367 "get_user_%s" % group_name))
@@ -367,7 +370,7 b' class UsersGroup(Base, BaseModel):'
367 370
368 371 @classmethod
369 372 def get(cls, users_group_id, cache=False):
370 users_group = Session.query(cls)
373 users_group = cls.query()
371 374 if cache:
372 375 users_group = users_group.options(FromCache("sql_cache_short",
373 376 "get_users_group_%s" % users_group_id))
@@ -451,6 +454,22 b' class UsersGroupMember(Base, BaseModel):'
451 454 self.users_group_id = gr_id
452 455 self.user_id = u_id
453 456
457 @classmethod
458 def create(cls, user, users_group):
459 try:
460 users_group_member = cls()
461 users_group_member.user = user
462 users_group_member.users_group = users_group
463
464 Session.add(users_group_member)
465 Session.commit()
466 return users_group_member
467 except:
468 log.error(traceback.format_exc())
469 Session.rollback()
470 raise
471
472
454 473 class Repository(Base, BaseModel):
455 474 __tablename__ = 'repositories'
456 475 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
@@ -485,9 +504,31 b' class Repository(Base, BaseModel):'
485 504 return "<%s('%s:%s')>" % (self.__class__.__name__,
486 505 self.repo_id, self.repo_name)
487 506
507 @staticmethod
508 def create(name, description, repo_type, private, owner, group, clone):
509 try:
510 repo = Repository()
511 repo.repo_name = name
512 repo.clone_uri = clone
513 repo.repo_type = repo_type
514 repo.user = owner
515 repo.private = private
516 repo.description = description
517 repo.group = group
518
519 Session.add(repo)
520 Session.commit()
521
522 RepoToPerm.create(repo, owner, Permission.get_by_name('repository.write'))
523 return repo
524 except:
525 log.error(traceback.format_exc())
526 Session.rollback()
527 raise
528
488 529 @classmethod
489 530 def by_repo_name(cls, repo_name):
490 q = Session.query(cls).filter(cls.repo_name == repo_name)
531 q = cls.query().filter(cls.repo_name == repo_name)
491 532
492 533 q = q.options(joinedload(Repository.fork))\
493 534 .options(joinedload(Repository.user))\
@@ -497,7 +538,7 b' class Repository(Base, BaseModel):'
497 538
498 539 @classmethod
499 540 def get_repo_forks(cls, repo_id):
500 return Session.query(cls).filter(Repository.fork_id == repo_id)
541 return cls.query().filter(Repository.fork_id == repo_id)
501 542
502 543 @classmethod
503 544 def base_path(cls):
@@ -541,7 +582,7 b' class Repository(Base, BaseModel):'
541 582 Returns base full path for that repository means where it actually
542 583 exists on a filesystem
543 584 """
544 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/')
585 q = RhodeCodeUi.query().filter(RhodeCodeUi.ui_key == '/')
545 586 q.options(FromCache("sql_cache_short", "repository_repo_path"))
546 587 return q.one().ui_value
547 588
@@ -569,7 +610,7 b' class Repository(Base, BaseModel):'
569 610 baseui._tcfg = config.config()
570 611
571 612
572 ret = Session.query(RhodeCodeUi)\
613 ret = RhodeCodeUi.query()\
573 614 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
574 615
575 616 hg_ui = ret
@@ -624,7 +665,7 b' class Repository(Base, BaseModel):'
624 665 None otherwise. `cache_active = False` means that this cache
625 666 state is not valid and needs to be invalidated
626 667 """
627 return Session.query(CacheInvalidation)\
668 return CacheInvalidation.query()\
628 669 .filter(CacheInvalidation.cache_key == self.repo_name)\
629 670 .filter(CacheInvalidation.cache_active == False)\
630 671 .scalar()
@@ -633,7 +674,7 b' class Repository(Base, BaseModel):'
633 674 """
634 675 set a cache for invalidation for this instance
635 676 """
636 inv = Session.query(CacheInvalidation)\
677 inv = CacheInvalidation.query()\
637 678 .filter(CacheInvalidation.cache_key == self.repo_name)\
638 679 .scalar()
639 680
@@ -721,6 +762,19 b' class Group(Base, BaseModel):'
721 762 def url_sep(cls):
722 763 return '/'
723 764
765 @classmethod
766 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
767 if case_insensitive:
768 gr = cls.query()\
769 .filter(cls.group_name.ilike(group_name))
770 else:
771 gr = cls.query()\
772 .filter(cls.group_name == group_name)
773 if cache:
774 gr = gr.options(FromCache("sql_cache_short",
775 "get_group_%s" % group_name))
776 return gr.scalar()
777
724 778 @property
725 779 def parents(self):
726 780 parents_recursion_limit = 5
@@ -747,7 +801,7 b' class Group(Base, BaseModel):'
747 801
748 802 @property
749 803 def children(self):
750 return Session.query(Group).filter(Group.parent_group == self)
804 return Group.query().filter(Group.parent_group == self)
751 805
752 806 @property
753 807 def full_path(self):
@@ -756,7 +810,7 b' class Group(Base, BaseModel):'
756 810
757 811 @property
758 812 def repositories(self):
759 return Session.query(Repository).filter(Repository.group == self)
813 return Repository.query().filter(Repository.group == self)
760 814
761 815 @property
762 816 def repositories_recursive_count(self):
@@ -784,7 +838,11 b' class Permission(Base, BaseModel):'
784 838
785 839 @classmethod
786 840 def get_by_key(cls, key):
787 return Session.query(cls).filter(cls.permission_name == key).scalar()
841 return cls.query().filter(cls.permission_name == key).scalar()
842
843 @classmethod
844 def get_by_name(cls, name):
845 return cls.query().filter(cls.permission_name == name).one()
788 846
789 847 class RepoToPerm(Base, BaseModel):
790 848 __tablename__ = 'repo_to_perm'
@@ -798,6 +856,23 b' class RepoToPerm(Base, BaseModel):'
798 856 permission = relationship('Permission')
799 857 repository = relationship('Repository')
800 858
859 @staticmethod
860 def create(repo, user, p):
861 try:
862 perm = RepoToPerm()
863 perm.repository = repo
864 perm.user = user
865 perm.permission = p
866
867 Session.add(perm)
868 Session.commit()
869
870 return perm
871 except:
872 log.error(traceback.format_exc())
873 Session.rollback()
874 raise
875
801 876 class UserToPerm(Base, BaseModel):
802 877 __tablename__ = 'user_to_perm'
803 878 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True})
@@ -813,7 +888,7 b' class UserToPerm(Base, BaseModel):'
813 888 if not isinstance(perm, Permission):
814 889 raise Exception('perm needs to be an instance of Permission class')
815 890
816 return Session.query(cls).filter(cls.user_id == user_id)\
891 return cls.query().filter(cls.user_id == user_id)\
817 892 .filter(cls.permission == perm).scalar() is not None
818 893
819 894 @classmethod
@@ -837,7 +912,7 b' class UserToPerm(Base, BaseModel):'
837 912 raise Exception('perm needs to be an instance of Permission class')
838 913
839 914 try:
840 Session.query(cls).filter(cls.user_id == user_id)\
915 cls.query().filter(cls.user_id == user_id)\
841 916 .filter(cls.permission == perm).delete()
842 917 Session.commit()
843 918 except:
@@ -873,7 +948,7 b' class UsersGroupToPerm(Base, BaseModel):'
873 948 if not isinstance(perm, Permission):
874 949 raise Exception('perm needs to be an instance of Permission class')
875 950
876 return Session.query(cls).filter(cls.users_group_id ==
951 return cls.query().filter(cls.users_group_id ==
877 952 users_group_id)\
878 953 .filter(cls.permission == perm)\
879 954 .scalar() is not None
@@ -899,7 +974,7 b' class UsersGroupToPerm(Base, BaseModel):'
899 974 raise Exception('perm needs to be an instance of Permission class')
900 975
901 976 try:
902 Session.query(cls).filter(cls.users_group_id == users_group_id)\
977 cls.query().filter(cls.users_group_id == users_group_id)\
903 978 .filter(cls.permission == perm).delete()
904 979 Session.commit()
905 980 except:
@@ -951,7 +1026,7 b' class UserFollowing(Base, BaseModel):'
951 1026
952 1027 @classmethod
953 1028 def get_repo_followers(cls, repo_id):
954 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
1029 return cls.query().filter(cls.follows_repo_id == repo_id)
955 1030
956 1031 class CacheInvalidation(Base, BaseModel):
957 1032 __tablename__ = 'cache_invalidation'
General Comments 0
You need to be logged in to leave comments. Login now