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