##// END OF EJS Templates
Share common getter functions in base model, and remove duplicated functions from other models
marcink -
r2432:d3ac7491 codereview
parent child Browse files
Show More
@@ -1,98 +1,128 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.__init__
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 The application's model objects
7 7
8 8 :created_on: Nov 25, 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
14 14 :example:
15 15
16 16 .. code-block:: python
17 17
18 18 from paste.deploy import appconfig
19 19 from pylons import config
20 20 from sqlalchemy import engine_from_config
21 21 from rhodecode.config.environment import load_environment
22 22
23 23 conf = appconfig('config:development.ini', relative_to = './../../')
24 24 load_environment(conf.global_conf, conf.local_conf)
25 25
26 26 engine = engine_from_config(config, 'sqlalchemy.')
27 27 init_model(engine)
28 28 # RUN YOUR CODE HERE
29 29
30 30 """
31 31 # This program is free software: you can redistribute it and/or modify
32 32 # it under the terms of the GNU General Public License as published by
33 33 # the Free Software Foundation, either version 3 of the License, or
34 34 # (at your option) any later version.
35 35 #
36 36 # This program is distributed in the hope that it will be useful,
37 37 # but WITHOUT ANY WARRANTY; without even the implied warranty of
38 38 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 39 # GNU General Public License for more details.
40 40 #
41 41 # You should have received a copy of the GNU General Public License
42 42 # along with this program. If not, see <http://www.gnu.org/licenses/>.
43 43
44 44 import logging
45
45 from rhodecode.model.db import User, Repository, Permission
46 46 from rhodecode.model import meta
47 47
48 48 log = logging.getLogger(__name__)
49 49
50 50
51 51 def init_model(engine):
52 52 """
53 53 Initializes db session, bind the engine with the metadata,
54 54 Call this before using any of the tables or classes in the model,
55 55 preferably once in application start
56 56
57 57 :param engine: engine to bind to
58 58 """
59 59 log.info("initializing db for %s" % engine)
60 60 meta.Base.metadata.bind = engine
61 61
62 62
63 63 class BaseModel(object):
64 64 """
65 65 Base Model for all RhodeCode models, it adds sql alchemy session
66 66 into instance of model
67 67
68 68 :param sa: If passed it reuses this session instead of creating a new one
69 69 """
70 70
71 71 def __init__(self, sa=None):
72 72 if sa is not None:
73 73 self.sa = sa
74 74 else:
75 75 self.sa = meta.Session
76 76
77 77 def _get_instance(self, cls, instance, callback=None):
78 78 """
79 79 Get's instance of given cls using some simple lookup mechanism.
80 80
81 81 :param cls: class to fetch
82 82 :param instance: int or Instance
83 83 :param callback: callback to call if all lookups failed
84 84 """
85 85
86 86 if isinstance(instance, cls):
87 87 return instance
88 88 elif isinstance(instance, (int, long)) or str(instance).isdigit():
89 89 return cls.get(instance)
90 90 else:
91 91 if instance:
92 92 if callback is None:
93 93 raise Exception(
94 94 'given object must be int, long or Instance of %s '
95 95 'got %s, no callback provided' % (cls, type(instance))
96 96 )
97 97 else:
98 98 return callback(instance)
99
100 def _get_user(self, user):
101 """
102 Helper method to get user by ID, or username fallback
103
104 :param user:
105 :type user: UserID, username, or User instance
106 """
107 return self._get_instance(User, user,
108 callback=User.get_by_username)
109
110 def _get_repo(self, repository):
111 """
112 Helper method to get repository by ID, or repository name
113
114 :param repository:
115 :type repository: RepoID, repository name or Repository Instance
116 """
117 return self._get_instance(Repository, repository,
118 callback=Repository.get_by_repo_name)
119
120 def _get_perm(self, permission):
121 """
122 Helper method to get permission by ID, or permission name
123
124 :param permission:
125 :type permission: PermissionID, permission_name or Permission instance
126 """
127 return self._get_instance(Permission, permission,
128 callback=Permission.get_by_key)
@@ -1,105 +1,94 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.changeset_status
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6
7 7 :created_on: Apr 30, 2012
8 8 :author: marcink
9 9 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
10 10 :license: GPLv3, see COPYING for more details.
11 11 """
12 12 # This program is free software: you can redistribute it and/or modify
13 13 # it under the terms of the GNU General Public License as published by
14 14 # the Free Software Foundation, either version 3 of the License, or
15 15 # (at your option) any later version.
16 16 #
17 17 # This program is distributed in the hope that it will be useful,
18 18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 20 # GNU General Public License for more details.
21 21 #
22 22 # You should have received a copy of the GNU General Public License
23 23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 24
25 25
26 26 import logging
27 import traceback
28 27
29 from pylons.i18n.translation import _
30
31 from rhodecode.lib.utils2 import safe_unicode
32 28 from rhodecode.model import BaseModel
33 from rhodecode.model.db import ChangesetStatus, Repository, User
29 from rhodecode.model.db import ChangesetStatus
34 30
35 31 log = logging.getLogger(__name__)
36 32
37 33
38 34 class ChangesetStatusModel(BaseModel):
39 35
40 36 def __get_changeset_status(self, changeset_status):
41 37 return self._get_instance(ChangesetStatus, changeset_status)
42 38
43 def __get_repo(self, repository):
44 return self._get_instance(Repository, repository,
45 callback=Repository.get_by_repo_name)
46
47 def __get_user(self, user):
48 return self._get_instance(User, user, callback=User.get_by_username)
49
50 39 def get_status(self, repo, revision):
51 40 """
52 41 Returns status of changeset for given revision and version 0
53 42 versioning makes a history of statuses, and version == 0 is always the
54 43 current one
55 44
56 45 :param repo:
57 46 :type repo:
58 47 :param revision: 40char hash
59 48 :type revision: str
60 49 """
61 repo = self.__get_repo(repo)
50 repo = self._get_repo(repo)
62 51
63 52 status = ChangesetStatus.query()\
64 53 .filter(ChangesetStatus.repo == repo)\
65 54 .filter(ChangesetStatus.revision == revision)\
66 55 .filter(ChangesetStatus.version == 0).scalar()
67 56 status = status.status if status else status
68 57 st = status or ChangesetStatus.DEFAULT
69 58 return str(st)
70 59
71 60 def set_status(self, repo, revision, status, user, comment):
72 61 """
73 62 Creates new status for changeset or updates the old ones bumping their
74 63 version, leaving the current status at
75 64
76 65 :param repo:
77 66 :type repo:
78 67 :param revision:
79 68 :type revision:
80 69 :param status:
81 70 :type status:
82 71 :param user:
83 72 :type user:
84 73 :param comment:
85 74 :type comment:
86 75 """
87 repo = self.__get_repo(repo)
76 repo = self._get_repo(repo)
88 77
89 78 cur_statuses = ChangesetStatus.query()\
90 79 .filter(ChangesetStatus.repo == repo)\
91 80 .filter(ChangesetStatus.revision == revision)\
92 81 .all()
93 82 if cur_statuses:
94 83 for st in cur_statuses:
95 84 st.version += 1
96 85 self.sa.add(st)
97 86 new_status = ChangesetStatus()
98 new_status.author = self.__get_user(user)
99 new_status.repo = self.__get_repo(repo)
87 new_status.author = self._get_user(user)
88 new_status.repo = self._get_repo(repo)
100 89 new_status.status = status
101 90 new_status.revision = revision
102 91 new_status.comment = comment
103 92 self.sa.add(new_status)
104 93 return new_status
105 94
@@ -1,230 +1,227 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.notification
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Model for notifications
7 7
8 8
9 9 :created_on: Nov 20, 2011
10 10 :author: marcink
11 11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26
27 27 import os
28 28 import logging
29 29 import traceback
30 30 import datetime
31 31
32 32 from pylons.i18n.translation import _
33 33
34 34 import rhodecode
35 35 from rhodecode.config.conf import DATETIME_FORMAT
36 36 from rhodecode.lib import helpers as h
37 37 from rhodecode.model import BaseModel
38 38 from rhodecode.model.db import Notification, User, UserNotification
39 39
40 40 log = logging.getLogger(__name__)
41 41
42 42
43 43 class NotificationModel(BaseModel):
44 44
45 def __get_user(self, user):
46 return self._get_instance(User, user, callback=User.get_by_username)
47
48 45 def __get_notification(self, notification):
49 46 if isinstance(notification, Notification):
50 47 return notification
51 48 elif isinstance(notification, (int, long)):
52 49 return Notification.get(notification)
53 50 else:
54 51 if notification:
55 52 raise Exception('notification must be int, long or Instance'
56 53 ' of Notification got %s' % type(notification))
57 54
58 55 def create(self, created_by, subject, body, recipients=None,
59 56 type_=Notification.TYPE_MESSAGE, with_email=True,
60 57 email_kwargs={}):
61 58 """
62 59
63 60 Creates notification of given type
64 61
65 62 :param created_by: int, str or User instance. User who created this
66 63 notification
67 64 :param subject:
68 65 :param body:
69 66 :param recipients: list of int, str or User objects, when None
70 67 is given send to all admins
71 68 :param type_: type of notification
72 69 :param with_email: send email with this notification
73 70 :param email_kwargs: additional dict to pass as args to email template
74 71 """
75 72 from rhodecode.lib.celerylib import tasks, run_task
76 73
77 74 if recipients and not getattr(recipients, '__iter__', False):
78 75 raise Exception('recipients must be a list of iterable')
79 76
80 created_by_obj = self.__get_user(created_by)
77 created_by_obj = self._get_user(created_by)
81 78
82 79 if recipients:
83 80 recipients_objs = []
84 81 for u in recipients:
85 obj = self.__get_user(u)
82 obj = self._get_user(u)
86 83 if obj:
87 84 recipients_objs.append(obj)
88 85 recipients_objs = set(recipients_objs)
89 86 log.debug('sending notifications %s to %s' % (
90 87 type_, recipients_objs)
91 88 )
92 89 else:
93 90 # empty recipients means to all admins
94 91 recipients_objs = User.query().filter(User.admin == True).all()
95 92 log.debug('sending notifications %s to admins: %s' % (
96 93 type_, recipients_objs)
97 94 )
98 95 notif = Notification.create(
99 96 created_by=created_by_obj, subject=subject,
100 97 body=body, recipients=recipients_objs, type_=type_
101 98 )
102 99
103 100 if with_email is False:
104 101 return notif
105 102
106 103 #don't send email to person who created this comment
107 104 rec_objs = set(recipients_objs).difference(set([created_by_obj]))
108 105
109 106 # send email with notification to all other participants
110 107 for rec in rec_objs:
111 108 email_subject = NotificationModel().make_description(notif, False)
112 109 type_ = type_
113 110 email_body = body
114 111 ## this is passed into template
115 112 kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)}
116 113 kwargs.update(email_kwargs)
117 114 email_body_html = EmailNotificationModel()\
118 115 .get_email_tmpl(type_, **kwargs)
119 116
120 117 run_task(tasks.send_email, rec.email, email_subject, email_body,
121 118 email_body_html)
122 119
123 120 return notif
124 121
125 122 def delete(self, user, notification):
126 123 # we don't want to remove actual notification just the assignment
127 124 try:
128 125 notification = self.__get_notification(notification)
129 user = self.__get_user(user)
126 user = self._get_user(user)
130 127 if notification and user:
131 128 obj = UserNotification.query()\
132 129 .filter(UserNotification.user == user)\
133 130 .filter(UserNotification.notification
134 131 == notification)\
135 132 .one()
136 133 self.sa.delete(obj)
137 134 return True
138 135 except Exception:
139 136 log.error(traceback.format_exc())
140 137 raise
141 138
142 139 def get_for_user(self, user):
143 user = self.__get_user(user)
140 user = self._get_user(user)
144 141 return user.notifications
145 142
146 143 def mark_all_read_for_user(self, user):
147 user = self.__get_user(user)
144 user = self._get_user(user)
148 145 UserNotification.query()\
149 146 .filter(UserNotification.read == False)\
150 147 .update({'read': True})
151 148
152 149 def get_unread_cnt_for_user(self, user):
153 user = self.__get_user(user)
150 user = self._get_user(user)
154 151 return UserNotification.query()\
155 152 .filter(UserNotification.read == False)\
156 153 .filter(UserNotification.user == user).count()
157 154
158 155 def get_unread_for_user(self, user):
159 user = self.__get_user(user)
156 user = self._get_user(user)
160 157 return [x.notification for x in UserNotification.query()\
161 158 .filter(UserNotification.read == False)\
162 159 .filter(UserNotification.user == user).all()]
163 160
164 161 def get_user_notification(self, user, notification):
165 user = self.__get_user(user)
162 user = self._get_user(user)
166 163 notification = self.__get_notification(notification)
167 164
168 165 return UserNotification.query()\
169 166 .filter(UserNotification.notification == notification)\
170 167 .filter(UserNotification.user == user).scalar()
171 168
172 169 def make_description(self, notification, show_age=True):
173 170 """
174 171 Creates a human readable description based on properties
175 172 of notification object
176 173 """
177 174
178 175 _map = {
179 176 notification.TYPE_CHANGESET_COMMENT: _('commented on commit'),
180 177 notification.TYPE_MESSAGE: _('sent message'),
181 178 notification.TYPE_MENTION: _('mentioned you'),
182 179 notification.TYPE_REGISTRATION: _('registered in RhodeCode')
183 180 }
184 181
185 182 tmpl = "%(user)s %(action)s %(when)s"
186 183 if show_age:
187 184 when = h.age(notification.created_on)
188 185 else:
189 186 DTF = lambda d: datetime.datetime.strftime(d, DATETIME_FORMAT)
190 187 when = DTF(notification.created_on)
191 188
192 189 data = dict(
193 190 user=notification.created_by_user.username,
194 191 action=_map[notification.type_], when=when,
195 192 )
196 193 return tmpl % data
197 194
198 195
199 196 class EmailNotificationModel(BaseModel):
200 197
201 198 TYPE_CHANGESET_COMMENT = Notification.TYPE_CHANGESET_COMMENT
202 199 TYPE_PASSWORD_RESET = 'passoword_link'
203 200 TYPE_REGISTRATION = Notification.TYPE_REGISTRATION
204 201 TYPE_DEFAULT = 'default'
205 202
206 203 def __init__(self):
207 204 self._template_root = rhodecode.CONFIG['pylons.paths']['templates'][0]
208 205 self._tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
209 206
210 207 self.email_types = {
211 208 self.TYPE_CHANGESET_COMMENT: 'email_templates/changeset_comment.html',
212 209 self.TYPE_PASSWORD_RESET: 'email_templates/password_reset.html',
213 210 self.TYPE_REGISTRATION: 'email_templates/registration.html',
214 211 self.TYPE_DEFAULT: 'email_templates/default.html'
215 212 }
216 213
217 214 def get_email_tmpl(self, type_, **kwargs):
218 215 """
219 216 return generated template for email based on given type
220 217
221 218 :param type_:
222 219 """
223 220
224 221 base = self.email_types.get(type_, self.email_types[self.TYPE_DEFAULT])
225 222 email_template = self._tmpl_lookup.get_template(base)
226 223 # translator inject
227 224 _kwargs = {'_': _}
228 225 _kwargs.update(kwargs)
229 226 log.debug('rendering tmpl %s with kwargs %s' % (base, _kwargs))
230 227 return email_template.render(**_kwargs)
@@ -1,527 +1,516 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.repo
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repository model for rhodecode
7 7
8 8 :created_on: Jun 5, 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 from __future__ import with_statement
26 26 import os
27 27 import shutil
28 28 import logging
29 29 import traceback
30 30 import pkg_resources
31 31 from os.path import dirname as dn, join as jn
32 32 from datetime import datetime
33 33
34 34 from rhodecode.lib.vcs.backends import get_backend
35 35 from rhodecode.lib.compat import json
36 36 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
37 37 from rhodecode.lib.caching_query import FromCache
38 38 from rhodecode.lib.hooks import log_create_repository
39 39
40 40 from rhodecode.model import BaseModel
41 41 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
42 42 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
43 43 from rhodecode.lib import helpers as h
44 44
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48
49 49 class RepoModel(BaseModel):
50 50
51 def __get_user(self, user):
52 return self._get_instance(User, user, callback=User.get_by_username)
53
54 51 def __get_users_group(self, users_group):
55 52 return self._get_instance(UsersGroup, users_group,
56 53 callback=UsersGroup.get_by_group_name)
57 54
58 55 def __get_repos_group(self, repos_group):
59 56 return self._get_instance(RepoGroup, repos_group,
60 57 callback=RepoGroup.get_by_group_name)
61 58
62 def __get_repo(self, repository):
63 return self._get_instance(Repository, repository,
64 callback=Repository.get_by_repo_name)
65
66 def __get_perm(self, permission):
67 return self._get_instance(Permission, permission,
68 callback=Permission.get_by_key)
69
70 59 @LazyProperty
71 60 def repos_path(self):
72 61 """
73 62 Get's the repositories root path from database
74 63 """
75 64
76 65 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
77 66 return q.ui_value
78 67
79 68 def get(self, repo_id, cache=False):
80 69 repo = self.sa.query(Repository)\
81 70 .filter(Repository.repo_id == repo_id)
82 71
83 72 if cache:
84 73 repo = repo.options(FromCache("sql_cache_short",
85 74 "get_repo_%s" % repo_id))
86 75 return repo.scalar()
87 76
88 77 def get_repo(self, repository):
89 return self.__get_repo(repository)
78 return self._get_repo(repository)
90 79
91 80 def get_by_repo_name(self, repo_name, cache=False):
92 81 repo = self.sa.query(Repository)\
93 82 .filter(Repository.repo_name == repo_name)
94 83
95 84 if cache:
96 85 repo = repo.options(FromCache("sql_cache_short",
97 86 "get_repo_%s" % repo_name))
98 87 return repo.scalar()
99 88
100 89 def get_users_js(self):
101 90 users = self.sa.query(User).filter(User.active == True).all()
102 91 return json.dumps([
103 92 {
104 93 'id': u.user_id,
105 94 'fname': u.name,
106 95 'lname': u.lastname,
107 96 'nname': u.username,
108 97 'gravatar_lnk': h.gravatar_url(u.email, 14)
109 98 } for u in users]
110 99 )
111 100
112 101 def get_users_groups_js(self):
113 102 users_groups = self.sa.query(UsersGroup)\
114 103 .filter(UsersGroup.users_group_active == True).all()
115 104
116 105 return json.dumps([
117 106 {
118 107 'id': gr.users_group_id,
119 108 'grname': gr.users_group_name,
120 109 'grmembers': len(gr.members),
121 110 } for gr in users_groups]
122 111 )
123 112
124 113 def _get_defaults(self, repo_name):
125 114 """
126 115 Get's information about repository, and returns a dict for
127 116 usage in forms
128 117
129 118 :param repo_name:
130 119 """
131 120
132 121 repo_info = Repository.get_by_repo_name(repo_name)
133 122
134 123 if repo_info is None:
135 124 return None
136 125
137 126 defaults = repo_info.get_dict()
138 127 group, repo_name = repo_info.groups_and_repo
139 128 defaults['repo_name'] = repo_name
140 129 defaults['repo_group'] = getattr(group[-1] if group else None,
141 130 'group_id', None)
142 131
143 132 # fill owner
144 133 if repo_info.user:
145 134 defaults.update({'user': repo_info.user.username})
146 135 else:
147 136 replacement_user = User.query().filter(User.admin ==
148 137 True).first().username
149 138 defaults.update({'user': replacement_user})
150 139
151 140 # fill repository users
152 141 for p in repo_info.repo_to_perm:
153 142 defaults.update({'u_perm_%s' % p.user.username:
154 143 p.permission.permission_name})
155 144
156 145 # fill repository groups
157 146 for p in repo_info.users_group_to_perm:
158 147 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
159 148 p.permission.permission_name})
160 149
161 150 return defaults
162 151
163 152 def update(self, repo_name, form_data):
164 153 try:
165 154 cur_repo = self.get_by_repo_name(repo_name, cache=False)
166 155
167 156 # update permissions
168 157 for member, perm, member_type in form_data['perms_updates']:
169 158 if member_type == 'user':
170 159 # this updates existing one
171 160 RepoModel().grant_user_permission(
172 161 repo=cur_repo, user=member, perm=perm
173 162 )
174 163 else:
175 164 RepoModel().grant_users_group_permission(
176 165 repo=cur_repo, group_name=member, perm=perm
177 166 )
178 167 # set new permissions
179 168 for member, perm, member_type in form_data['perms_new']:
180 169 if member_type == 'user':
181 170 RepoModel().grant_user_permission(
182 171 repo=cur_repo, user=member, perm=perm
183 172 )
184 173 else:
185 174 RepoModel().grant_users_group_permission(
186 175 repo=cur_repo, group_name=member, perm=perm
187 176 )
188 177
189 178 # update current repo
190 179 for k, v in form_data.items():
191 180 if k == 'user':
192 181 cur_repo.user = User.get_by_username(v)
193 182 elif k == 'repo_name':
194 183 pass
195 184 elif k == 'repo_group':
196 185 cur_repo.group = RepoGroup.get(v)
197 186
198 187 else:
199 188 setattr(cur_repo, k, v)
200 189
201 190 new_name = cur_repo.get_new_name(form_data['repo_name'])
202 191 cur_repo.repo_name = new_name
203 192
204 193 self.sa.add(cur_repo)
205 194
206 195 if repo_name != new_name:
207 196 # rename repository
208 197 self.__rename_repo(old=repo_name, new=new_name)
209 198
210 199 return cur_repo
211 200 except:
212 201 log.error(traceback.format_exc())
213 202 raise
214 203
215 204 def create(self, form_data, cur_user, just_db=False, fork=False):
216 205 from rhodecode.model.scm import ScmModel
217 206
218 207 try:
219 208 if fork:
220 209 fork_parent_id = form_data['fork_parent_id']
221 210
222 211 # repo name is just a name of repository
223 212 # while repo_name_full is a full qualified name that is combined
224 213 # with name and path of group
225 214 repo_name = form_data['repo_name']
226 215 repo_name_full = form_data['repo_name_full']
227 216
228 217 new_repo = Repository()
229 218 new_repo.enable_statistics = False
230 219
231 220 for k, v in form_data.items():
232 221 if k == 'repo_name':
233 222 v = repo_name_full
234 223 if k == 'repo_group':
235 224 k = 'group_id'
236 225 if k == 'description':
237 226 v = v or repo_name
238 227
239 228 setattr(new_repo, k, v)
240 229
241 230 if fork:
242 231 parent_repo = Repository.get(fork_parent_id)
243 232 new_repo.fork = parent_repo
244 233
245 234 new_repo.user_id = cur_user.user_id
246 235 self.sa.add(new_repo)
247 236
248 237 def _create_default_perms():
249 238 # create default permission
250 239 repo_to_perm = UserRepoToPerm()
251 240 default = 'repository.read'
252 241 for p in User.get_by_username('default').user_perms:
253 242 if p.permission.permission_name.startswith('repository.'):
254 243 default = p.permission.permission_name
255 244 break
256 245
257 246 default_perm = 'repository.none' if form_data['private'] else default
258 247
259 248 repo_to_perm.permission_id = self.sa.query(Permission)\
260 249 .filter(Permission.permission_name == default_perm)\
261 250 .one().permission_id
262 251
263 252 repo_to_perm.repository = new_repo
264 253 repo_to_perm.user_id = User.get_by_username('default').user_id
265 254
266 255 self.sa.add(repo_to_perm)
267 256
268 257 if fork:
269 258 if form_data.get('copy_permissions'):
270 259 repo = Repository.get(fork_parent_id)
271 260 user_perms = UserRepoToPerm.query()\
272 261 .filter(UserRepoToPerm.repository == repo).all()
273 262 group_perms = UsersGroupRepoToPerm.query()\
274 263 .filter(UsersGroupRepoToPerm.repository == repo).all()
275 264
276 265 for perm in user_perms:
277 266 UserRepoToPerm.create(perm.user, new_repo,
278 267 perm.permission)
279 268
280 269 for perm in group_perms:
281 270 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
282 271 perm.permission)
283 272 else:
284 273 _create_default_perms()
285 274 else:
286 275 _create_default_perms()
287 276
288 277 if not just_db:
289 278 self.__create_repo(repo_name, form_data['repo_type'],
290 279 form_data['repo_group'],
291 280 form_data['clone_uri'])
292 281 log_create_repository(new_repo.get_dict(),
293 282 created_by=cur_user.username)
294 283
295 284 # now automatically start following this repository as owner
296 285 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
297 286 cur_user.user_id)
298 287 return new_repo
299 288 except:
300 289 log.error(traceback.format_exc())
301 290 raise
302 291
303 292 def create_fork(self, form_data, cur_user):
304 293 """
305 294 Simple wrapper into executing celery task for fork creation
306 295
307 296 :param form_data:
308 297 :param cur_user:
309 298 """
310 299 from rhodecode.lib.celerylib import tasks, run_task
311 300 run_task(tasks.create_repo_fork, form_data, cur_user)
312 301
313 302 def delete(self, repo):
314 repo = self.__get_repo(repo)
303 repo = self._get_repo(repo)
315 304 try:
316 305 self.sa.delete(repo)
317 306 self.__delete_repo(repo)
318 307 except:
319 308 log.error(traceback.format_exc())
320 309 raise
321 310
322 311 def grant_user_permission(self, repo, user, perm):
323 312 """
324 313 Grant permission for user on given repository, or update existing one
325 314 if found
326 315
327 316 :param repo: Instance of Repository, repository_id, or repository name
328 317 :param user: Instance of User, user_id or username
329 318 :param perm: Instance of Permission, or permission_name
330 319 """
331 user = self.__get_user(user)
332 repo = self.__get_repo(repo)
333 permission = self.__get_perm(perm)
320 user = self._get_user(user)
321 repo = self._get_repo(repo)
322 permission = self._get_perm(perm)
334 323
335 324 # check if we have that permission already
336 325 obj = self.sa.query(UserRepoToPerm)\
337 326 .filter(UserRepoToPerm.user == user)\
338 327 .filter(UserRepoToPerm.repository == repo)\
339 328 .scalar()
340 329 if obj is None:
341 330 # create new !
342 331 obj = UserRepoToPerm()
343 332 obj.repository = repo
344 333 obj.user = user
345 334 obj.permission = permission
346 335 self.sa.add(obj)
347 336
348 337 def revoke_user_permission(self, repo, user):
349 338 """
350 339 Revoke permission for user on given repository
351 340
352 341 :param repo: Instance of Repository, repository_id, or repository name
353 342 :param user: Instance of User, user_id or username
354 343 """
355 344
356 user = self.__get_user(user)
357 repo = self.__get_repo(repo)
345 user = self._get_user(user)
346 repo = self._get_repo(repo)
358 347
359 348 obj = self.sa.query(UserRepoToPerm)\
360 349 .filter(UserRepoToPerm.repository == repo)\
361 350 .filter(UserRepoToPerm.user == user)\
362 351 .one()
363 352 self.sa.delete(obj)
364 353
365 354 def grant_users_group_permission(self, repo, group_name, perm):
366 355 """
367 356 Grant permission for users group on given repository, or update
368 357 existing one if found
369 358
370 359 :param repo: Instance of Repository, repository_id, or repository name
371 360 :param group_name: Instance of UserGroup, users_group_id,
372 361 or users group name
373 362 :param perm: Instance of Permission, or permission_name
374 363 """
375 repo = self.__get_repo(repo)
364 repo = self._get_repo(repo)
376 365 group_name = self.__get_users_group(group_name)
377 permission = self.__get_perm(perm)
366 permission = self._get_perm(perm)
378 367
379 368 # check if we have that permission already
380 369 obj = self.sa.query(UsersGroupRepoToPerm)\
381 370 .filter(UsersGroupRepoToPerm.users_group == group_name)\
382 371 .filter(UsersGroupRepoToPerm.repository == repo)\
383 372 .scalar()
384 373
385 374 if obj is None:
386 375 # create new
387 376 obj = UsersGroupRepoToPerm()
388 377
389 378 obj.repository = repo
390 379 obj.users_group = group_name
391 380 obj.permission = permission
392 381 self.sa.add(obj)
393 382
394 383 def revoke_users_group_permission(self, repo, group_name):
395 384 """
396 385 Revoke permission for users group on given repository
397 386
398 387 :param repo: Instance of Repository, repository_id, or repository name
399 388 :param group_name: Instance of UserGroup, users_group_id,
400 389 or users group name
401 390 """
402 repo = self.__get_repo(repo)
391 repo = self._get_repo(repo)
403 392 group_name = self.__get_users_group(group_name)
404 393
405 394 obj = self.sa.query(UsersGroupRepoToPerm)\
406 395 .filter(UsersGroupRepoToPerm.repository == repo)\
407 396 .filter(UsersGroupRepoToPerm.users_group == group_name)\
408 397 .one()
409 398 self.sa.delete(obj)
410 399
411 400 def delete_stats(self, repo_name):
412 401 """
413 402 removes stats for given repo
414 403
415 404 :param repo_name:
416 405 """
417 406 try:
418 407 obj = self.sa.query(Statistics)\
419 408 .filter(Statistics.repository ==
420 409 self.get_by_repo_name(repo_name))\
421 410 .one()
422 411 self.sa.delete(obj)
423 412 except:
424 413 log.error(traceback.format_exc())
425 414 raise
426 415
427 416 def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
428 417 """
429 418 makes repository on filesystem. It's group aware means it'll create
430 419 a repository within a group, and alter the paths accordingly of
431 420 group location
432 421
433 422 :param repo_name:
434 423 :param alias:
435 424 :param parent_id:
436 425 :param clone_uri:
437 426 """
438 427 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
439 428
440 429 if new_parent_id:
441 430 paths = RepoGroup.get(new_parent_id)\
442 431 .full_path.split(RepoGroup.url_sep())
443 432 new_parent_path = os.sep.join(paths)
444 433 else:
445 434 new_parent_path = ''
446 435
447 436 # we need to make it str for mercurial
448 437 repo_path = os.path.join(*map(lambda x: safe_str(x),
449 438 [self.repos_path, new_parent_path, repo_name]))
450 439
451 440 # check if this path is not a repository
452 441 if is_valid_repo(repo_path, self.repos_path):
453 442 raise Exception('This path %s is a valid repository' % repo_path)
454 443
455 444 # check if this path is a group
456 445 if is_valid_repos_group(repo_path, self.repos_path):
457 446 raise Exception('This path %s is a valid group' % repo_path)
458 447
459 448 log.info('creating repo %s in %s @ %s' % (
460 449 repo_name, safe_unicode(repo_path), clone_uri
461 450 )
462 451 )
463 452 backend = get_backend(alias)
464 453 if alias == 'hg':
465 454 backend(repo_path, create=True, src_url=clone_uri)
466 455 elif alias == 'git':
467 456 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
468 457 # add rhodecode hook into this repo
469 458
470 459 loc = jn(r.path, 'hooks')
471 460 if not r.bare:
472 461 loc = jn(r.path, '.git', 'hooks')
473 462 if not os.path.isdir(loc):
474 463 os.makedirs(loc)
475 464
476 465 tmpl = pkg_resources.resource_string(
477 466 'rhodecode', jn('config', 'post_receive_tmpl.py')
478 467 )
479 468 _hook_file = jn(loc, 'post-receive')
480 469 with open(_hook_file, 'wb') as f:
481 470 f.write(tmpl)
482 471 os.chmod(_hook_file, 0755)
483 472
484 473 else:
485 474 raise Exception('Undefined alias %s' % alias)
486 475
487 476 def __rename_repo(self, old, new):
488 477 """
489 478 renames repository on filesystem
490 479
491 480 :param old: old name
492 481 :param new: new name
493 482 """
494 483 log.info('renaming repo from %s to %s' % (old, new))
495 484
496 485 old_path = os.path.join(self.repos_path, old)
497 486 new_path = os.path.join(self.repos_path, new)
498 487 if os.path.isdir(new_path):
499 488 raise Exception(
500 489 'Was trying to rename to already existing dir %s' % new_path
501 490 )
502 491 shutil.move(old_path, new_path)
503 492
504 493 def __delete_repo(self, repo):
505 494 """
506 495 removes repo from filesystem, the removal is acctually made by
507 496 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
508 497 repository is no longer valid for rhodecode, can be undeleted later on
509 498 by reverting the renames on this repository
510 499
511 500 :param repo: repo object
512 501 """
513 502 rm_path = os.path.join(self.repos_path, repo.repo_name)
514 503 log.info("Removing %s" % (rm_path))
515 504 # disable hg/git internal that it doesn't get detected as repo
516 505 alias = repo.repo_type
517 506
518 507 bare = getattr(repo.scm_instance, 'bare', False)
519 508
520 509 if not bare:
521 510 # skip this for bare git repos
522 511 shutil.move(os.path.join(rm_path, '.%s' % alias),
523 512 os.path.join(rm_path, 'rm__.%s' % alias))
524 513 # disable repo
525 514 _d = 'rm__%s__%s' % (datetime.now().strftime('%Y%m%d_%H%M%S_%f'),
526 515 repo.repo_name)
527 516 shutil.move(rm_path, os.path.join(self.repos_path, _d))
@@ -1,112 +1,101 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.users_group
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 repository permission model for RhodeCode
7 7
8 8 :created_on: Oct 1, 2011
9 9 :author: nvinot, marcink
10 10 :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
11 11 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26
27 27 import logging
28 28 from rhodecode.model import BaseModel
29 from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, Permission,\
30 User, Repository
29 from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, \
30 Permission
31 31
32 32 log = logging.getLogger(__name__)
33 33
34 34
35 35 class RepositoryPermissionModel(BaseModel):
36 36
37 def __get_user(self, user):
38 return self._get_instance(User, user, callback=User.get_by_username)
39
40 def __get_repo(self, repository):
41 return self._get_instance(Repository, repository,
42 callback=Repository.get_by_repo_name)
43
44 def __get_perm(self, permission):
45 return self._get_instance(Permission, permission,
46 callback=Permission.get_by_key)
47
48 37 def get_user_permission(self, repository, user):
49 repository = self.__get_repo(repository)
50 user = self.__get_user(user)
38 repository = self._get_repo(repository)
39 user = self._get_user(user)
51 40
52 41 return UserRepoToPerm.query() \
53 42 .filter(UserRepoToPerm.user == user) \
54 43 .filter(UserRepoToPerm.repository == repository) \
55 44 .scalar()
56 45
57 46 def update_user_permission(self, repository, user, permission):
58 47 permission = Permission.get_by_key(permission)
59 48 current = self.get_user_permission(repository, user)
60 49 if current:
61 50 if not current.permission is permission:
62 51 current.permission = permission
63 52 else:
64 53 p = UserRepoToPerm()
65 54 p.user = user
66 55 p.repository = repository
67 56 p.permission = permission
68 57 self.sa.add(p)
69 58
70 59 def delete_user_permission(self, repository, user):
71 60 current = self.get_user_permission(repository, user)
72 61 if current:
73 62 self.sa.delete(current)
74 63
75 64 def get_users_group_permission(self, repository, users_group):
76 65 return UsersGroupRepoToPerm.query() \
77 66 .filter(UsersGroupRepoToPerm.users_group == users_group) \
78 67 .filter(UsersGroupRepoToPerm.repository == repository) \
79 68 .scalar()
80 69
81 70 def update_users_group_permission(self, repository, users_group,
82 71 permission):
83 72 permission = Permission.get_by_key(permission)
84 73 current = self.get_users_group_permission(repository, users_group)
85 74 if current:
86 75 if not current.permission is permission:
87 76 current.permission = permission
88 77 else:
89 78 p = UsersGroupRepoToPerm()
90 79 p.users_group = users_group
91 80 p.repository = repository
92 81 p.permission = permission
93 82 self.sa.add(p)
94 83
95 84 def delete_users_group_permission(self, repository, users_group):
96 85 current = self.get_users_group_permission(repository, users_group)
97 86 if current:
98 87 self.sa.delete(current)
99 88
100 89 def update_or_delete_user_permission(self, repository, user, permission):
101 90 if permission:
102 91 self.update_user_permission(repository, user, permission)
103 92 else:
104 93 self.delete_user_permission(repository, user)
105 94
106 95 def update_or_delete_users_group_permission(self, repository, user_group,
107 96 permission):
108 97 if permission:
109 98 self.update_users_group_permission(repository, user_group,
110 99 permission)
111 100 else:
112 101 self.delete_users_group_permission(repository, user_group)
@@ -1,310 +1,303 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.user_group
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users groups model for RhodeCode
7 7
8 8 :created_on: Jan 25, 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 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 os
27 27 import logging
28 28 import traceback
29 29 import shutil
30 30
31 31 from rhodecode.lib.utils2 import LazyProperty
32 32
33 33 from rhodecode.model import BaseModel
34 34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
35 35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39
40 40 class ReposGroupModel(BaseModel):
41 41
42 def __get_user(self, user):
43 return self._get_instance(User, user, callback=User.get_by_username)
44
45 42 def __get_users_group(self, users_group):
46 43 return self._get_instance(UsersGroup, users_group,
47 44 callback=UsersGroup.get_by_group_name)
48 45
49 46 def __get_repos_group(self, repos_group):
50 47 return self._get_instance(RepoGroup, repos_group,
51 48 callback=RepoGroup.get_by_group_name)
52 49
53 def __get_perm(self, permission):
54 return self._get_instance(Permission, permission,
55 callback=Permission.get_by_key)
56
57 50 @LazyProperty
58 51 def repos_path(self):
59 52 """
60 53 Get's the repositories root path from database
61 54 """
62 55
63 56 q = RhodeCodeUi.get_by_key('/').one()
64 57 return q.ui_value
65 58
66 59 def _create_default_perms(self, new_group):
67 60 # create default permission
68 61 repo_group_to_perm = UserRepoGroupToPerm()
69 62 default_perm = 'group.read'
70 63 for p in User.get_by_username('default').user_perms:
71 64 if p.permission.permission_name.startswith('group.'):
72 65 default_perm = p.permission.permission_name
73 66 break
74 67
75 68 repo_group_to_perm.permission_id = self.sa.query(Permission)\
76 69 .filter(Permission.permission_name == default_perm)\
77 70 .one().permission_id
78 71
79 72 repo_group_to_perm.group = new_group
80 73 repo_group_to_perm.user_id = User.get_by_username('default').user_id
81 74
82 75 self.sa.add(repo_group_to_perm)
83 76
84 77 def __create_group(self, group_name):
85 78 """
86 79 makes repositories group on filesystem
87 80
88 81 :param repo_name:
89 82 :param parent_id:
90 83 """
91 84
92 85 create_path = os.path.join(self.repos_path, group_name)
93 86 log.debug('creating new group in %s' % create_path)
94 87
95 88 if os.path.isdir(create_path):
96 89 raise Exception('That directory already exists !')
97 90
98 91 os.makedirs(create_path)
99 92
100 93 def __rename_group(self, old, new):
101 94 """
102 95 Renames a group on filesystem
103 96
104 97 :param group_name:
105 98 """
106 99
107 100 if old == new:
108 101 log.debug('skipping group rename')
109 102 return
110 103
111 104 log.debug('renaming repos group from %s to %s' % (old, new))
112 105
113 106 old_path = os.path.join(self.repos_path, old)
114 107 new_path = os.path.join(self.repos_path, new)
115 108
116 109 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
117 110
118 111 if os.path.isdir(new_path):
119 112 raise Exception('Was trying to rename to already '
120 113 'existing dir %s' % new_path)
121 114 shutil.move(old_path, new_path)
122 115
123 116 def __delete_group(self, group):
124 117 """
125 118 Deletes a group from a filesystem
126 119
127 120 :param group: instance of group from database
128 121 """
129 122 paths = group.full_path.split(RepoGroup.url_sep())
130 123 paths = os.sep.join(paths)
131 124
132 125 rm_path = os.path.join(self.repos_path, paths)
133 126 if os.path.isdir(rm_path):
134 127 # delete only if that path really exists
135 128 os.rmdir(rm_path)
136 129
137 130 def create(self, group_name, group_description, parent, just_db=False):
138 131 try:
139 132 new_repos_group = RepoGroup()
140 133 new_repos_group.group_description = group_description
141 134 new_repos_group.parent_group = self.__get_repos_group(parent)
142 135 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
143 136
144 137 self.sa.add(new_repos_group)
145 138 self._create_default_perms(new_repos_group)
146 139
147 140 if not just_db:
148 141 # we need to flush here, in order to check if database won't
149 142 # throw any exceptions, create filesystem dirs at the very end
150 143 self.sa.flush()
151 144 self.__create_group(new_repos_group.group_name)
152 145
153 146 return new_repos_group
154 147 except:
155 148 log.error(traceback.format_exc())
156 149 raise
157 150
158 151 def update(self, repos_group_id, form_data):
159 152
160 153 try:
161 154 repos_group = RepoGroup.get(repos_group_id)
162 155
163 156 # update permissions
164 157 for member, perm, member_type in form_data['perms_updates']:
165 158 if member_type == 'user':
166 159 # this updates also current one if found
167 160 ReposGroupModel().grant_user_permission(
168 161 repos_group=repos_group, user=member, perm=perm
169 162 )
170 163 else:
171 164 ReposGroupModel().grant_users_group_permission(
172 165 repos_group=repos_group, group_name=member, perm=perm
173 166 )
174 167 # set new permissions
175 168 for member, perm, member_type in form_data['perms_new']:
176 169 if member_type == 'user':
177 170 ReposGroupModel().grant_user_permission(
178 171 repos_group=repos_group, user=member, perm=perm
179 172 )
180 173 else:
181 174 ReposGroupModel().grant_users_group_permission(
182 175 repos_group=repos_group, group_name=member, perm=perm
183 176 )
184 177
185 178 old_path = repos_group.full_path
186 179
187 180 # change properties
188 181 repos_group.group_description = form_data['group_description']
189 182 repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
190 183 repos_group.group_parent_id = form_data['group_parent_id']
191 184 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
192 185 new_path = repos_group.full_path
193 186
194 187 self.sa.add(repos_group)
195 188
196 189 # we need to get all repositories from this new group and
197 190 # rename them accordingly to new group path
198 191 for r in repos_group.repositories:
199 192 r.repo_name = r.get_new_name(r.just_name)
200 193 self.sa.add(r)
201 194
202 195 self.__rename_group(old_path, new_path)
203 196
204 197 return repos_group
205 198 except:
206 199 log.error(traceback.format_exc())
207 200 raise
208 201
209 202 def delete(self, users_group_id):
210 203 try:
211 204 users_group = RepoGroup.get(users_group_id)
212 205 self.sa.delete(users_group)
213 206 self.__delete_group(users_group)
214 207 except:
215 208 log.error(traceback.format_exc())
216 209 raise
217 210
218 211 def grant_user_permission(self, repos_group, user, perm):
219 212 """
220 213 Grant permission for user on given repositories group, or update
221 214 existing one if found
222 215
223 216 :param repos_group: Instance of ReposGroup, repositories_group_id,
224 217 or repositories_group name
225 218 :param user: Instance of User, user_id or username
226 219 :param perm: Instance of Permission, or permission_name
227 220 """
228 221
229 222 repos_group = self.__get_repos_group(repos_group)
230 user = self.__get_user(user)
231 permission = self.__get_perm(perm)
223 user = self._get_user(user)
224 permission = self._get_perm(perm)
232 225
233 226 # check if we have that permission already
234 227 obj = self.sa.query(UserRepoGroupToPerm)\
235 228 .filter(UserRepoGroupToPerm.user == user)\
236 229 .filter(UserRepoGroupToPerm.group == repos_group)\
237 230 .scalar()
238 231 if obj is None:
239 232 # create new !
240 233 obj = UserRepoGroupToPerm()
241 234 obj.group = repos_group
242 235 obj.user = user
243 236 obj.permission = permission
244 237 self.sa.add(obj)
245 238
246 239 def revoke_user_permission(self, repos_group, user):
247 240 """
248 241 Revoke permission for user on given repositories group
249 242
250 243 :param repos_group: Instance of ReposGroup, repositories_group_id,
251 244 or repositories_group name
252 245 :param user: Instance of User, user_id or username
253 246 """
254 247
255 248 repos_group = self.__get_repos_group(repos_group)
256 user = self.__get_user(user)
249 user = self._get_user(user)
257 250
258 251 obj = self.sa.query(UserRepoGroupToPerm)\
259 252 .filter(UserRepoGroupToPerm.user == user)\
260 253 .filter(UserRepoGroupToPerm.group == repos_group)\
261 254 .one()
262 255 self.sa.delete(obj)
263 256
264 257 def grant_users_group_permission(self, repos_group, group_name, perm):
265 258 """
266 259 Grant permission for users group on given repositories group, or update
267 260 existing one if found
268 261
269 262 :param repos_group: Instance of ReposGroup, repositories_group_id,
270 263 or repositories_group name
271 264 :param group_name: Instance of UserGroup, users_group_id,
272 265 or users group name
273 266 :param perm: Instance of Permission, or permission_name
274 267 """
275 268 repos_group = self.__get_repos_group(repos_group)
276 269 group_name = self.__get_users_group(group_name)
277 permission = self.__get_perm(perm)
270 permission = self._get_perm(perm)
278 271
279 272 # check if we have that permission already
280 273 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
281 274 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
282 275 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
283 276 .scalar()
284 277
285 278 if obj is None:
286 279 # create new
287 280 obj = UsersGroupRepoGroupToPerm()
288 281
289 282 obj.group = repos_group
290 283 obj.users_group = group_name
291 284 obj.permission = permission
292 285 self.sa.add(obj)
293 286
294 287 def revoke_users_group_permission(self, repos_group, group_name):
295 288 """
296 289 Revoke permission for users group on given repositories group
297 290
298 291 :param repos_group: Instance of ReposGroup, repositories_group_id,
299 292 or repositories_group name
300 293 :param group_name: Instance of UserGroup, users_group_id,
301 294 or users group name
302 295 """
303 296 repos_group = self.__get_repos_group(repos_group)
304 297 group_name = self.__get_users_group(group_name)
305 298
306 299 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
307 300 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
308 301 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
309 302 .one()
310 303 self.sa.delete(obj)
@@ -1,615 +1,608 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.utils2 import safe_unicode, generate_api_key
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 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroup,\
39 UsersGroupRepoGroupToPerm, UserEmailMap
38 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
39 UserEmailMap
40 40 from rhodecode.lib.exceptions import DefaultUserException, \
41 41 UserOwnsReposException
42 42
43 43 from sqlalchemy.exc import DatabaseError
44 44
45 45 from sqlalchemy.orm import joinedload
46 46
47 47 log = logging.getLogger(__name__)
48 48
49 49
50 50 PERM_WEIGHTS = {
51 51 'repository.none': 0,
52 52 'repository.read': 1,
53 53 'repository.write': 3,
54 54 'repository.admin': 4,
55 55 'group.none': 0,
56 56 'group.read': 1,
57 57 'group.write': 3,
58 58 'group.admin': 4,
59 59 }
60 60
61 61
62 62 class UserModel(BaseModel):
63 63
64 def __get_user(self, user):
65 return self._get_instance(User, user, callback=User.get_by_username)
66
67 def __get_perm(self, permission):
68 return self._get_instance(Permission, permission,
69 callback=Permission.get_by_key)
70
71 64 def get(self, user_id, cache=False):
72 65 user = self.sa.query(User)
73 66 if cache:
74 67 user = user.options(FromCache("sql_cache_short",
75 68 "get_user_%s" % user_id))
76 69 return user.get(user_id)
77 70
78 71 def get_user(self, user):
79 return self.__get_user(user)
72 return self._get_user(user)
80 73
81 74 def get_by_username(self, username, cache=False, case_insensitive=False):
82 75
83 76 if case_insensitive:
84 77 user = self.sa.query(User).filter(User.username.ilike(username))
85 78 else:
86 79 user = self.sa.query(User)\
87 80 .filter(User.username == username)
88 81 if cache:
89 82 user = user.options(FromCache("sql_cache_short",
90 83 "get_user_%s" % username))
91 84 return user.scalar()
92 85
93 86 def get_by_api_key(self, api_key, cache=False):
94 87 return User.get_by_api_key(api_key, cache)
95 88
96 89 def create(self, form_data):
97 90 try:
98 91 new_user = User()
99 92 for k, v in form_data.items():
100 93 setattr(new_user, k, v)
101 94
102 95 new_user.api_key = generate_api_key(form_data['username'])
103 96 self.sa.add(new_user)
104 97 return new_user
105 98 except:
106 99 log.error(traceback.format_exc())
107 100 raise
108 101
109 102 def create_or_update(self, username, password, email, name, lastname,
110 103 active=True, admin=False, ldap_dn=None):
111 104 """
112 105 Creates a new instance if not found, or updates current one
113 106
114 107 :param username:
115 108 :param password:
116 109 :param email:
117 110 :param active:
118 111 :param name:
119 112 :param lastname:
120 113 :param active:
121 114 :param admin:
122 115 :param ldap_dn:
123 116 """
124 117
125 118 from rhodecode.lib.auth import get_crypt_password
126 119
127 120 log.debug('Checking for %s account in RhodeCode database' % username)
128 121 user = User.get_by_username(username, case_insensitive=True)
129 122 if user is None:
130 123 log.debug('creating new user %s' % username)
131 124 new_user = User()
132 125 else:
133 126 log.debug('updating user %s' % username)
134 127 new_user = user
135 128
136 129 try:
137 130 new_user.username = username
138 131 new_user.admin = admin
139 132 new_user.password = get_crypt_password(password)
140 133 new_user.api_key = generate_api_key(username)
141 134 new_user.email = email
142 135 new_user.active = active
143 136 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
144 137 new_user.name = name
145 138 new_user.lastname = lastname
146 139 self.sa.add(new_user)
147 140 return new_user
148 141 except (DatabaseError,):
149 142 log.error(traceback.format_exc())
150 143 raise
151 144
152 145 def create_for_container_auth(self, username, attrs):
153 146 """
154 147 Creates the given user if it's not already in the database
155 148
156 149 :param username:
157 150 :param attrs:
158 151 """
159 152 if self.get_by_username(username, case_insensitive=True) is None:
160 153
161 154 # autogenerate email for container account without one
162 155 generate_email = lambda usr: '%s@container_auth.account' % usr
163 156
164 157 try:
165 158 new_user = User()
166 159 new_user.username = username
167 160 new_user.password = None
168 161 new_user.api_key = generate_api_key(username)
169 162 new_user.email = attrs['email']
170 163 new_user.active = attrs.get('active', True)
171 164 new_user.name = attrs['name'] or generate_email(username)
172 165 new_user.lastname = attrs['lastname']
173 166
174 167 self.sa.add(new_user)
175 168 return new_user
176 169 except (DatabaseError,):
177 170 log.error(traceback.format_exc())
178 171 self.sa.rollback()
179 172 raise
180 173 log.debug('User %s already exists. Skipping creation of account'
181 174 ' for container auth.', username)
182 175 return None
183 176
184 177 def create_ldap(self, username, password, user_dn, attrs):
185 178 """
186 179 Checks if user is in database, if not creates this user marked
187 180 as ldap user
188 181
189 182 :param username:
190 183 :param password:
191 184 :param user_dn:
192 185 :param attrs:
193 186 """
194 187 from rhodecode.lib.auth import get_crypt_password
195 188 log.debug('Checking for such ldap account in RhodeCode database')
196 189 if self.get_by_username(username, case_insensitive=True) is None:
197 190
198 191 # autogenerate email for ldap account without one
199 192 generate_email = lambda usr: '%s@ldap.account' % usr
200 193
201 194 try:
202 195 new_user = User()
203 196 username = username.lower()
204 197 # add ldap account always lowercase
205 198 new_user.username = username
206 199 new_user.password = get_crypt_password(password)
207 200 new_user.api_key = generate_api_key(username)
208 201 new_user.email = attrs['email'] or generate_email(username)
209 202 new_user.active = attrs.get('active', True)
210 203 new_user.ldap_dn = safe_unicode(user_dn)
211 204 new_user.name = attrs['name']
212 205 new_user.lastname = attrs['lastname']
213 206
214 207 self.sa.add(new_user)
215 208 return new_user
216 209 except (DatabaseError,):
217 210 log.error(traceback.format_exc())
218 211 self.sa.rollback()
219 212 raise
220 213 log.debug('this %s user exists skipping creation of ldap account',
221 214 username)
222 215 return None
223 216
224 217 def create_registration(self, form_data):
225 218 from rhodecode.model.notification import NotificationModel
226 219
227 220 try:
228 221 form_data['admin'] = False
229 222 new_user = self.create(form_data)
230 223
231 224 self.sa.add(new_user)
232 225 self.sa.flush()
233 226
234 227 # notification to admins
235 228 subject = _('new user registration')
236 229 body = ('New user registration\n'
237 230 '---------------------\n'
238 231 '- Username: %s\n'
239 232 '- Full Name: %s\n'
240 233 '- Email: %s\n')
241 234 body = body % (new_user.username, new_user.full_name,
242 235 new_user.email)
243 236 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
244 237 kw = {'registered_user_url': edit_url}
245 238 NotificationModel().create(created_by=new_user, subject=subject,
246 239 body=body, recipients=None,
247 240 type_=Notification.TYPE_REGISTRATION,
248 241 email_kwargs=kw)
249 242
250 243 except:
251 244 log.error(traceback.format_exc())
252 245 raise
253 246
254 247 def update(self, user_id, form_data):
255 248 try:
256 249 user = self.get(user_id, cache=False)
257 250 if user.username == 'default':
258 251 raise DefaultUserException(
259 252 _("You can't Edit this user since it's"
260 253 " crucial for entire application"))
261 254
262 255 for k, v in form_data.items():
263 256 if k == 'new_password' and v != '':
264 257 user.password = v
265 258 user.api_key = generate_api_key(user.username)
266 259 else:
267 260 setattr(user, k, v)
268 261
269 262 self.sa.add(user)
270 263 except:
271 264 log.error(traceback.format_exc())
272 265 raise
273 266
274 267 def update_my_account(self, user_id, form_data):
275 268 try:
276 269 user = self.get(user_id, cache=False)
277 270 if user.username == 'default':
278 271 raise DefaultUserException(
279 272 _("You can't Edit this user since it's"
280 273 " crucial for entire application"))
281 274 for k, v in form_data.items():
282 275 if k == 'new_password' and v != '':
283 276 user.password = v
284 277 user.api_key = generate_api_key(user.username)
285 278 else:
286 279 if k not in ['admin', 'active']:
287 280 setattr(user, k, v)
288 281
289 282 self.sa.add(user)
290 283 except:
291 284 log.error(traceback.format_exc())
292 285 raise
293 286
294 287 def delete(self, user):
295 user = self.__get_user(user)
288 user = self._get_user(user)
296 289
297 290 try:
298 291 if user.username == 'default':
299 292 raise DefaultUserException(
300 293 _(u"You can't remove this user since it's"
301 294 " crucial for entire application")
302 295 )
303 296 if user.repositories:
304 297 repos = [x.repo_name for x in user.repositories]
305 298 raise UserOwnsReposException(
306 299 _(u'user "%s" still owns %s repositories and cannot be '
307 300 'removed. Switch owners or remove those repositories. %s')
308 301 % (user.username, len(repos), ', '.join(repos))
309 302 )
310 303 self.sa.delete(user)
311 304 except:
312 305 log.error(traceback.format_exc())
313 306 raise
314 307
315 308 def reset_password_link(self, data):
316 309 from rhodecode.lib.celerylib import tasks, run_task
317 310 run_task(tasks.send_password_link, data['email'])
318 311
319 312 def reset_password(self, data):
320 313 from rhodecode.lib.celerylib import tasks, run_task
321 314 run_task(tasks.reset_user_password, data['email'])
322 315
323 316 def fill_data(self, auth_user, user_id=None, api_key=None):
324 317 """
325 318 Fetches auth_user by user_id,or api_key if present.
326 319 Fills auth_user attributes with those taken from database.
327 320 Additionally set's is_authenitated if lookup fails
328 321 present in database
329 322
330 323 :param auth_user: instance of user to set attributes
331 324 :param user_id: user id to fetch by
332 325 :param api_key: api key to fetch by
333 326 """
334 327 if user_id is None and api_key is None:
335 328 raise Exception('You need to pass user_id or api_key')
336 329
337 330 try:
338 331 if api_key:
339 332 dbuser = self.get_by_api_key(api_key)
340 333 else:
341 334 dbuser = self.get(user_id)
342 335
343 336 if dbuser is not None and dbuser.active:
344 337 log.debug('filling %s data' % dbuser)
345 338 for k, v in dbuser.get_dict().items():
346 339 setattr(auth_user, k, v)
347 340 else:
348 341 return False
349 342
350 343 except:
351 344 log.error(traceback.format_exc())
352 345 auth_user.is_authenticated = False
353 346 return False
354 347
355 348 return True
356 349
357 350 def fill_perms(self, user):
358 351 """
359 352 Fills user permission attribute with permissions taken from database
360 353 works for permissions given for repositories, and for permissions that
361 354 are granted to groups
362 355
363 356 :param user: user instance to fill his perms
364 357 """
365 358 RK = 'repositories'
366 359 GK = 'repositories_groups'
367 360 GLOBAL = 'global'
368 361 user.permissions[RK] = {}
369 362 user.permissions[GK] = {}
370 363 user.permissions[GLOBAL] = set()
371 364
372 365 #======================================================================
373 366 # fetch default permissions
374 367 #======================================================================
375 368 default_user = User.get_by_username('default', cache=True)
376 369 default_user_id = default_user.user_id
377 370
378 371 default_repo_perms = Permission.get_default_perms(default_user_id)
379 372 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
380 373
381 374 if user.is_admin:
382 375 #==================================================================
383 376 # admin user have all default rights for repositories
384 377 # and groups set to admin
385 378 #==================================================================
386 379 user.permissions[GLOBAL].add('hg.admin')
387 380
388 381 # repositories
389 382 for perm in default_repo_perms:
390 383 r_k = perm.UserRepoToPerm.repository.repo_name
391 384 p = 'repository.admin'
392 385 user.permissions[RK][r_k] = p
393 386
394 387 # repositories groups
395 388 for perm in default_repo_groups_perms:
396 389 rg_k = perm.UserRepoGroupToPerm.group.group_name
397 390 p = 'group.admin'
398 391 user.permissions[GK][rg_k] = p
399 392 return user
400 393
401 394 #==================================================================
402 395 # set default permissions first for repositories and groups
403 396 #==================================================================
404 397 uid = user.user_id
405 398
406 399 # default global permissions
407 400 default_global_perms = self.sa.query(UserToPerm)\
408 401 .filter(UserToPerm.user_id == default_user_id)
409 402
410 403 for perm in default_global_perms:
411 404 user.permissions[GLOBAL].add(perm.permission.permission_name)
412 405
413 406 # defaults for repositories, taken from default user
414 407 for perm in default_repo_perms:
415 408 r_k = perm.UserRepoToPerm.repository.repo_name
416 409 if perm.Repository.private and not (perm.Repository.user_id == uid):
417 410 # disable defaults for private repos,
418 411 p = 'repository.none'
419 412 elif perm.Repository.user_id == uid:
420 413 # set admin if owner
421 414 p = 'repository.admin'
422 415 else:
423 416 p = perm.Permission.permission_name
424 417
425 418 user.permissions[RK][r_k] = p
426 419
427 420 # defaults for repositories groups taken from default user permission
428 421 # on given group
429 422 for perm in default_repo_groups_perms:
430 423 rg_k = perm.UserRepoGroupToPerm.group.group_name
431 424 p = perm.Permission.permission_name
432 425 user.permissions[GK][rg_k] = p
433 426
434 427 #==================================================================
435 428 # overwrite defaults with user permissions if any found
436 429 #==================================================================
437 430
438 431 # user global permissions
439 432 user_perms = self.sa.query(UserToPerm)\
440 433 .options(joinedload(UserToPerm.permission))\
441 434 .filter(UserToPerm.user_id == uid).all()
442 435
443 436 for perm in user_perms:
444 437 user.permissions[GLOBAL].add(perm.permission.permission_name)
445 438
446 439 # user explicit permissions for repositories
447 440 user_repo_perms = \
448 441 self.sa.query(UserRepoToPerm, Permission, Repository)\
449 442 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
450 443 .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
451 444 .filter(UserRepoToPerm.user_id == uid)\
452 445 .all()
453 446
454 447 for perm in user_repo_perms:
455 448 # set admin if owner
456 449 r_k = perm.UserRepoToPerm.repository.repo_name
457 450 if perm.Repository.user_id == uid:
458 451 p = 'repository.admin'
459 452 else:
460 453 p = perm.Permission.permission_name
461 454 user.permissions[RK][r_k] = p
462 455
463 456 # USER GROUP
464 457 #==================================================================
465 458 # check if user is part of user groups for this repository and
466 459 # fill in (or replace with higher) permissions
467 460 #==================================================================
468 461
469 462 # users group global
470 463 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
471 464 .options(joinedload(UsersGroupToPerm.permission))\
472 465 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
473 466 UsersGroupMember.users_group_id))\
474 467 .filter(UsersGroupMember.user_id == uid).all()
475 468
476 469 for perm in user_perms_from_users_groups:
477 470 user.permissions[GLOBAL].add(perm.permission.permission_name)
478 471
479 472 # users group for repositories permissions
480 473 user_repo_perms_from_users_groups = \
481 474 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
482 475 .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\
483 476 .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\
484 477 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\
485 478 .filter(UsersGroupMember.user_id == uid)\
486 479 .all()
487 480
488 481 for perm in user_repo_perms_from_users_groups:
489 482 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
490 483 p = perm.Permission.permission_name
491 484 cur_perm = user.permissions[RK][r_k]
492 485 # overwrite permission only if it's greater than permission
493 486 # given from other sources
494 487 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
495 488 user.permissions[RK][r_k] = p
496 489
497 490 # REPO GROUP
498 491 #==================================================================
499 492 # get access for this user for repos group and override defaults
500 493 #==================================================================
501 494
502 495 # user explicit permissions for repository
503 496 user_repo_groups_perms = \
504 497 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
505 498 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
506 499 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
507 500 .filter(UserRepoGroupToPerm.user_id == uid)\
508 501 .all()
509 502
510 503 for perm in user_repo_groups_perms:
511 504 rg_k = perm.UserRepoGroupToPerm.group.group_name
512 505 p = perm.Permission.permission_name
513 506 cur_perm = user.permissions[GK][rg_k]
514 507 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
515 508 user.permissions[GK][rg_k] = p
516 509
517 510 # REPO GROUP + USER GROUP
518 511 #==================================================================
519 512 # check if user is part of user groups for this repo group and
520 513 # fill in (or replace with higher) permissions
521 514 #==================================================================
522 515
523 516 # users group for repositories permissions
524 517 user_repo_group_perms_from_users_groups = \
525 518 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
526 519 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
527 520 .join((Permission, UsersGroupRepoGroupToPerm.permission_id == Permission.permission_id))\
528 521 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
529 522 .filter(UsersGroupMember.user_id == uid)\
530 523 .all()
531 524
532 525 for perm in user_repo_group_perms_from_users_groups:
533 526 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
534 527 p = perm.Permission.permission_name
535 528 cur_perm = user.permissions[GK][g_k]
536 529 # overwrite permission only if it's greater than permission
537 530 # given from other sources
538 531 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
539 532 user.permissions[GK][g_k] = p
540 533
541 534 return user
542 535
543 536 def has_perm(self, user, perm):
544 537 if not isinstance(perm, Permission):
545 538 raise Exception('perm needs to be an instance of Permission class '
546 539 'got %s instead' % type(perm))
547 540
548 user = self.__get_user(user)
541 user = self._get_user(user)
549 542
550 543 return UserToPerm.query().filter(UserToPerm.user == user)\
551 544 .filter(UserToPerm.permission == perm).scalar() is not None
552 545
553 546 def grant_perm(self, user, perm):
554 547 """
555 548 Grant user global permissions
556 549
557 550 :param user:
558 551 :param perm:
559 552 """
560 user = self.__get_user(user)
561 perm = self.__get_perm(perm)
553 user = self._get_user(user)
554 perm = self._get_perm(perm)
562 555 # if this permission is already granted skip it
563 556 _perm = UserToPerm.query()\
564 557 .filter(UserToPerm.user == user)\
565 558 .filter(UserToPerm.permission == perm)\
566 559 .scalar()
567 560 if _perm:
568 561 return
569 562 new = UserToPerm()
570 563 new.user = user
571 564 new.permission = perm
572 565 self.sa.add(new)
573 566
574 567 def revoke_perm(self, user, perm):
575 568 """
576 569 Revoke users global permissions
577 570
578 571 :param user:
579 572 :param perm:
580 573 """
581 user = self.__get_user(user)
582 perm = self.__get_perm(perm)
574 user = self._get_user(user)
575 perm = self._get_perm(perm)
583 576
584 577 obj = UserToPerm.query()\
585 578 .filter(UserToPerm.user == user)\
586 579 .filter(UserToPerm.permission == perm)\
587 580 .scalar()
588 581 if obj:
589 582 self.sa.delete(obj)
590 583
591 584 def add_extra_email(self, user, email):
592 585 """
593 586 Adds email address to UserEmailMap
594 587
595 588 :param user:
596 589 :param email:
597 590 """
598 user = self.__get_user(user)
591 user = self._get_user(user)
599 592 obj = UserEmailMap()
600 593 obj.user = user
601 594 obj.email = email
602 595 self.sa.add(obj)
603 596 return obj
604 597
605 598 def delete_extra_email(self, user, email_id):
606 599 """
607 600 Removes email address from UserEmailMap
608 601
609 602 :param user:
610 603 :param email_id:
611 604 """
612 user = self.__get_user(user)
605 user = self._get_user(user)
613 606 obj = UserEmailMap.query().get(email_id)
614 607 if obj:
615 608 self.sa.delete(obj) No newline at end of file
@@ -1,196 +1,189 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.users_group
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users group model for RhodeCode
7 7
8 8 :created_on: Oct 1, 2011
9 9 :author: nvinot
10 10 :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
11 11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26
27 27 import logging
28 28 import traceback
29 29
30 30 from rhodecode.model import BaseModel
31 31 from rhodecode.model.db import UsersGroupMember, UsersGroup,\
32 32 UsersGroupRepoToPerm, Permission, UsersGroupToPerm, User
33 33 from rhodecode.lib.exceptions import UsersGroupsAssignedException
34 34
35 35 log = logging.getLogger(__name__)
36 36
37 37
38 38 class UsersGroupModel(BaseModel):
39 39
40 def __get_user(self, user):
41 return self._get_instance(User, user, callback=User.get_by_username)
42
43 40 def __get_users_group(self, users_group):
44 41 return self._get_instance(UsersGroup, users_group,
45 42 callback=UsersGroup.get_by_group_name)
46 43
47 def __get_perm(self, permission):
48 return self._get_instance(Permission, permission,
49 callback=Permission.get_by_key)
50
51 44 def get(self, users_group_id, cache=False):
52 45 return UsersGroup.get(users_group_id)
53 46
54 47 def get_by_name(self, name, cache=False, case_insensitive=False):
55 48 return UsersGroup.get_by_group_name(name, cache, case_insensitive)
56 49
57 50 def create(self, name, active=True):
58 51 try:
59 52 new = UsersGroup()
60 53 new.users_group_name = name
61 54 new.users_group_active = active
62 55 self.sa.add(new)
63 56 return new
64 57 except:
65 58 log.error(traceback.format_exc())
66 59 raise
67 60
68 61 def update(self, users_group, form_data):
69 62
70 63 try:
71 64 users_group = self.__get_users_group(users_group)
72 65
73 66 for k, v in form_data.items():
74 67 if k == 'users_group_members':
75 68 users_group.members = []
76 69 self.sa.flush()
77 70 members_list = []
78 71 if v:
79 72 v = [v] if isinstance(v, basestring) else v
80 73 for u_id in set(v):
81 74 member = UsersGroupMember(users_group.users_group_id, u_id)
82 75 members_list.append(member)
83 76 setattr(users_group, 'members', members_list)
84 77 setattr(users_group, k, v)
85 78
86 79 self.sa.add(users_group)
87 80 except:
88 81 log.error(traceback.format_exc())
89 82 raise
90 83
91 84 def delete(self, users_group, force=False):
92 85 """
93 86 Deletes repos group, unless force flag is used
94 87 raises exception if there are members in that group, else deletes
95 88 group and users
96 89
97 90 :param users_group:
98 91 :param force:
99 92 """
100 93 try:
101 94 users_group = self.__get_users_group(users_group)
102 95
103 96 # check if this group is not assigned to repo
104 97 assigned_groups = UsersGroupRepoToPerm.query()\
105 98 .filter(UsersGroupRepoToPerm.users_group == users_group).all()
106 99
107 100 if assigned_groups and force is False:
108 101 raise UsersGroupsAssignedException('RepoGroup assigned to %s' %
109 102 assigned_groups)
110 103
111 104 self.sa.delete(users_group)
112 105 except:
113 106 log.error(traceback.format_exc())
114 107 raise
115 108
116 109 def add_user_to_group(self, users_group, user):
117 110 users_group = self.__get_users_group(users_group)
118 user = self.__get_user(user)
111 user = self._get_user(user)
119 112
120 113 for m in users_group.members:
121 114 u = m.user
122 115 if u.user_id == user.user_id:
123 116 return True
124 117
125 118 try:
126 119 users_group_member = UsersGroupMember()
127 120 users_group_member.user = user
128 121 users_group_member.users_group = users_group
129 122
130 123 users_group.members.append(users_group_member)
131 124 user.group_member.append(users_group_member)
132 125
133 126 self.sa.add(users_group_member)
134 127 return users_group_member
135 128 except:
136 129 log.error(traceback.format_exc())
137 130 raise
138 131
139 132 def remove_user_from_group(self, users_group, user):
140 133 users_group = self.__get_users_group(users_group)
141 user = self.__get_user(user)
134 user = self._get_user(user)
142 135
143 136 users_group_member = None
144 137 for m in users_group.members:
145 138 if m.user.user_id == user.user_id:
146 139 # Found this user's membership row
147 140 users_group_member = m
148 141 break
149 142
150 143 if users_group_member:
151 144 try:
152 145 self.sa.delete(users_group_member)
153 146 return True
154 147 except:
155 148 log.error(traceback.format_exc())
156 149 raise
157 150 else:
158 151 # User isn't in that group
159 152 return False
160 153
161 154 def has_perm(self, users_group, perm):
162 155 users_group = self.__get_users_group(users_group)
163 perm = self.__get_perm(perm)
156 perm = self._get_perm(perm)
164 157
165 158 return UsersGroupToPerm.query()\
166 159 .filter(UsersGroupToPerm.users_group == users_group)\
167 160 .filter(UsersGroupToPerm.permission == perm).scalar() is not None
168 161
169 162 def grant_perm(self, users_group, perm):
170 163 if not isinstance(perm, Permission):
171 164 raise Exception('perm needs to be an instance of Permission class')
172 165
173 166 users_group = self.__get_users_group(users_group)
174 167
175 168 # if this permission is already granted skip it
176 169 _perm = UsersGroupToPerm.query()\
177 170 .filter(UsersGroupToPerm.users_group == users_group)\
178 171 .filter(UsersGroupToPerm.permission == perm)\
179 172 .scalar()
180 173 if _perm:
181 174 return
182 175
183 176 new = UsersGroupToPerm()
184 177 new.users_group = users_group
185 178 new.permission = perm
186 179 self.sa.add(new)
187 180
188 181 def revoke_perm(self, users_group, perm):
189 182 users_group = self.__get_users_group(users_group)
190 perm = self.__get_perm(perm)
183 perm = self._get_perm(perm)
191 184
192 185 obj = UsersGroupToPerm.query()\
193 186 .filter(UsersGroupToPerm.users_group == users_group)\
194 187 .filter(UsersGroupToPerm.permission == perm).scalar()
195 188 if obj:
196 189 self.sa.delete(obj)
General Comments 0
You need to be logged in to leave comments. Login now