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, |
|
|
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 |
|
|
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 = |
|
|
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 |
|
|
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 = |
|
|
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 = |
|
|
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 |
|
|
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 |
|
|
289 | return cls.query().filter(cls.username.like(username)).one() | |
|
286 | 290 | else: |
|
287 |
return |
|
|
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 |
|
|
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 = |
|
|
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 = |
|
|
361 |
.filter( |
|
|
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 = |
|
|
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 = |
|
|
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 |
|
|
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 = |
|
|
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 = |
|
|
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 |
|
|
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 = |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
|
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 |
|
|
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 |
|
|
|
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 |
|
|
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