##// END OF EJS Templates
Removed hardcoded hooks names from settings....
marcink -
r2401:e2af60e4 beta
parent child Browse files
Show More
@@ -1,425 +1,426 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.settings
3 rhodecode.controllers.admin.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 settings controller for rhodecode admin
6 settings controller for rhodecode admin
7
7
8 :created_on: Jul 14, 2010
8 :created_on: Jul 14, 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 import formencode
28 import formencode
29 import pkg_resources
29 import pkg_resources
30 import platform
30 import platform
31
31
32 from sqlalchemy import func
32 from sqlalchemy import func
33 from formencode import htmlfill
33 from formencode import htmlfill
34 from pylons import request, session, tmpl_context as c, url, config
34 from pylons import request, session, tmpl_context as c, url, config
35 from pylons.controllers.util import abort, redirect
35 from pylons.controllers.util import abort, redirect
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 HasPermissionAnyDecorator, NotAnonymous
40 HasPermissionAnyDecorator, NotAnonymous
41 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.celerylib import tasks, run_task
42 from rhodecode.lib.celerylib import tasks, run_task
43 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
43 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
44 set_rhodecode_config, repo_name_slug
44 set_rhodecode_config, repo_name_slug
45 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
45 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
46 RhodeCodeSetting
46 RhodeCodeSetting
47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
48 ApplicationUiSettingsForm
48 ApplicationUiSettingsForm
49 from rhodecode.model.scm import ScmModel
49 from rhodecode.model.scm import ScmModel
50 from rhodecode.model.user import UserModel
50 from rhodecode.model.user import UserModel
51 from rhodecode.model.db import User
51 from rhodecode.model.db import User
52 from rhodecode.model.notification import EmailNotificationModel
52 from rhodecode.model.notification import EmailNotificationModel
53 from rhodecode.model.meta import Session
53 from rhodecode.model.meta import Session
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57
57
58 class SettingsController(BaseController):
58 class SettingsController(BaseController):
59 """REST Controller styled on the Atom Publishing Protocol"""
59 """REST Controller styled on the Atom Publishing Protocol"""
60 # To properly map this controller, ensure your config/routing.py
60 # To properly map this controller, ensure your config/routing.py
61 # file has a resource setup:
61 # file has a resource setup:
62 # map.resource('setting', 'settings', controller='admin/settings',
62 # map.resource('setting', 'settings', controller='admin/settings',
63 # path_prefix='/admin', name_prefix='admin_')
63 # path_prefix='/admin', name_prefix='admin_')
64
64
65 @LoginRequired()
65 @LoginRequired()
66 def __before__(self):
66 def __before__(self):
67 c.admin_user = session.get('admin_user')
67 c.admin_user = session.get('admin_user')
68 c.admin_username = session.get('admin_username')
68 c.admin_username = session.get('admin_username')
69 c.modules = sorted([(p.project_name, p.version)
69 c.modules = sorted([(p.project_name, p.version)
70 for p in pkg_resources.working_set],
70 for p in pkg_resources.working_set],
71 key=lambda k: k[0].lower())
71 key=lambda k: k[0].lower())
72 c.py_version = platform.python_version()
72 c.py_version = platform.python_version()
73 c.platform = platform.platform()
73 c.platform = platform.platform()
74 super(SettingsController, self).__before__()
74 super(SettingsController, self).__before__()
75
75
76 @HasPermissionAllDecorator('hg.admin')
76 @HasPermissionAllDecorator('hg.admin')
77 def index(self, format='html'):
77 def index(self, format='html'):
78 """GET /admin/settings: All items in the collection"""
78 """GET /admin/settings: All items in the collection"""
79 # url('admin_settings')
79 # url('admin_settings')
80
80
81 defaults = RhodeCodeSetting.get_app_settings()
81 defaults = RhodeCodeSetting.get_app_settings()
82 defaults.update(self.get_hg_ui_settings())
82 defaults.update(self.get_hg_ui_settings())
83
83
84 return htmlfill.render(
84 return htmlfill.render(
85 render('admin/settings/settings.html'),
85 render('admin/settings/settings.html'),
86 defaults=defaults,
86 defaults=defaults,
87 encoding="UTF-8",
87 encoding="UTF-8",
88 force_defaults=False
88 force_defaults=False
89 )
89 )
90
90
91 @HasPermissionAllDecorator('hg.admin')
91 @HasPermissionAllDecorator('hg.admin')
92 def create(self):
92 def create(self):
93 """POST /admin/settings: Create a new item"""
93 """POST /admin/settings: Create a new item"""
94 # url('admin_settings')
94 # url('admin_settings')
95
95
96 @HasPermissionAllDecorator('hg.admin')
96 @HasPermissionAllDecorator('hg.admin')
97 def new(self, format='html'):
97 def new(self, format='html'):
98 """GET /admin/settings/new: Form to create a new item"""
98 """GET /admin/settings/new: Form to create a new item"""
99 # url('admin_new_setting')
99 # url('admin_new_setting')
100
100
101 @HasPermissionAllDecorator('hg.admin')
101 @HasPermissionAllDecorator('hg.admin')
102 def update(self, setting_id):
102 def update(self, setting_id):
103 """PUT /admin/settings/setting_id: Update an existing item"""
103 """PUT /admin/settings/setting_id: Update an existing item"""
104 # Forms posted to this method should contain a hidden field:
104 # Forms posted to this method should contain a hidden field:
105 # <input type="hidden" name="_method" value="PUT" />
105 # <input type="hidden" name="_method" value="PUT" />
106 # Or using helpers:
106 # Or using helpers:
107 # h.form(url('admin_setting', setting_id=ID),
107 # h.form(url('admin_setting', setting_id=ID),
108 # method='put')
108 # method='put')
109 # url('admin_setting', setting_id=ID)
109 # url('admin_setting', setting_id=ID)
110 if setting_id == 'mapping':
110 if setting_id == 'mapping':
111 rm_obsolete = request.POST.get('destroy', False)
111 rm_obsolete = request.POST.get('destroy', False)
112 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
112 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
113 initial = ScmModel().repo_scan()
113 initial = ScmModel().repo_scan()
114 log.debug('invalidating all repositories')
114 log.debug('invalidating all repositories')
115 for repo_name in initial.keys():
115 for repo_name in initial.keys():
116 invalidate_cache('get_repo_cached_%s' % repo_name)
116 invalidate_cache('get_repo_cached_%s' % repo_name)
117
117
118 added, removed = repo2db_mapper(initial, rm_obsolete)
118 added, removed = repo2db_mapper(initial, rm_obsolete)
119
119
120 h.flash(_('Repositories successfully'
120 h.flash(_('Repositories successfully'
121 ' rescanned added: %s,removed: %s') % (added, removed),
121 ' rescanned added: %s,removed: %s') % (added, removed),
122 category='success')
122 category='success')
123
123
124 if setting_id == 'whoosh':
124 if setting_id == 'whoosh':
125 repo_location = self.get_hg_ui_settings()['paths_root_path']
125 repo_location = self.get_hg_ui_settings()['paths_root_path']
126 full_index = request.POST.get('full_index', False)
126 full_index = request.POST.get('full_index', False)
127 run_task(tasks.whoosh_index, repo_location, full_index)
127 run_task(tasks.whoosh_index, repo_location, full_index)
128
128
129 h.flash(_('Whoosh reindex task scheduled'), category='success')
129 h.flash(_('Whoosh reindex task scheduled'), category='success')
130 if setting_id == 'global':
130 if setting_id == 'global':
131
131
132 application_form = ApplicationSettingsForm()()
132 application_form = ApplicationSettingsForm()()
133 try:
133 try:
134 form_result = application_form.to_python(dict(request.POST))
134 form_result = application_form.to_python(dict(request.POST))
135
135
136 try:
136 try:
137 hgsettings1 = RhodeCodeSetting.get_by_name('title')
137 hgsettings1 = RhodeCodeSetting.get_by_name('title')
138 hgsettings1.app_settings_value = \
138 hgsettings1.app_settings_value = \
139 form_result['rhodecode_title']
139 form_result['rhodecode_title']
140
140
141 hgsettings2 = RhodeCodeSetting.get_by_name('realm')
141 hgsettings2 = RhodeCodeSetting.get_by_name('realm')
142 hgsettings2.app_settings_value = \
142 hgsettings2.app_settings_value = \
143 form_result['rhodecode_realm']
143 form_result['rhodecode_realm']
144
144
145 hgsettings3 = RhodeCodeSetting.get_by_name('ga_code')
145 hgsettings3 = RhodeCodeSetting.get_by_name('ga_code')
146 hgsettings3.app_settings_value = \
146 hgsettings3.app_settings_value = \
147 form_result['rhodecode_ga_code']
147 form_result['rhodecode_ga_code']
148
148
149 self.sa.add(hgsettings1)
149 self.sa.add(hgsettings1)
150 self.sa.add(hgsettings2)
150 self.sa.add(hgsettings2)
151 self.sa.add(hgsettings3)
151 self.sa.add(hgsettings3)
152 self.sa.commit()
152 self.sa.commit()
153 set_rhodecode_config(config)
153 set_rhodecode_config(config)
154 h.flash(_('Updated application settings'),
154 h.flash(_('Updated application settings'),
155 category='success')
155 category='success')
156
156
157 except Exception:
157 except Exception:
158 log.error(traceback.format_exc())
158 log.error(traceback.format_exc())
159 h.flash(_('error occurred during updating '
159 h.flash(_('error occurred during updating '
160 'application settings'),
160 'application settings'),
161 category='error')
161 category='error')
162
162
163 self.sa.rollback()
163 self.sa.rollback()
164
164
165 except formencode.Invalid, errors:
165 except formencode.Invalid, errors:
166 return htmlfill.render(
166 return htmlfill.render(
167 render('admin/settings/settings.html'),
167 render('admin/settings/settings.html'),
168 defaults=errors.value,
168 defaults=errors.value,
169 errors=errors.error_dict or {},
169 errors=errors.error_dict or {},
170 prefix_error=False,
170 prefix_error=False,
171 encoding="UTF-8")
171 encoding="UTF-8")
172
172
173 if setting_id == 'mercurial':
173 if setting_id == 'mercurial':
174 application_form = ApplicationUiSettingsForm()()
174 application_form = ApplicationUiSettingsForm()()
175 try:
175 try:
176 form_result = application_form.to_python(dict(request.POST))
176 form_result = application_form.to_python(dict(request.POST))
177
177 # fix namespaces for hooks
178 _f = lambda s: s.replace('.', '_')
178 try:
179 try:
179
180
180 hgsettings1 = self.sa.query(RhodeCodeUi)\
181 hgsettings1 = self.sa.query(RhodeCodeUi)\
181 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
182 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
182 hgsettings1.ui_value = form_result['web_push_ssl']
183 hgsettings1.ui_value = form_result['web_push_ssl']
183
184
184 hgsettings2 = self.sa.query(RhodeCodeUi)\
185 hgsettings2 = self.sa.query(RhodeCodeUi)\
185 .filter(RhodeCodeUi.ui_key == '/').one()
186 .filter(RhodeCodeUi.ui_key == '/').one()
186 hgsettings2.ui_value = form_result['paths_root_path']
187 hgsettings2.ui_value = form_result['paths_root_path']
187
188
188 #HOOKS
189 #HOOKS
189 hgsettings3 = self.sa.query(RhodeCodeUi)\
190 hgsettings3 = self.sa.query(RhodeCodeUi)\
190 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
191 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_UPDATE)\
191 hgsettings3.ui_active = \
192 .one()
192 bool(form_result['hooks_changegroup_update'])
193 hgsettings3.ui_active = bool(form_result[_f('hooks_%s' %
194 RhodeCodeUi.HOOK_UPDATE)])
193
195
194 hgsettings4 = self.sa.query(RhodeCodeUi)\
196 hgsettings4 = self.sa.query(RhodeCodeUi)\
195 .filter(RhodeCodeUi.ui_key ==
197 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_REPO_SIZE)\
196 'changegroup.repo_size').one()
198 .one()
197 hgsettings4.ui_active = \
199 hgsettings4.ui_active = bool(form_result[_f('hooks_%s' %
198 bool(form_result['hooks_changegroup_repo_size'])
200 RhodeCodeUi.HOOK_REPO_SIZE)])
199
201
200 hgsettings5 = self.sa.query(RhodeCodeUi)\
202 hgsettings5 = self.sa.query(RhodeCodeUi)\
201 .filter(RhodeCodeUi.ui_key ==
203 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_PUSH)\
202 'pretxnchangegroup.push_logger').one()
204 .one()
203 hgsettings5.ui_active = \
205 hgsettings5.ui_active = bool(form_result[_f('hooks_%s' %
204 bool(form_result['hooks_pretxnchangegroup'
206 RhodeCodeUi.HOOK_PUSH)])
205 '_push_logger'])
206
207
207 hgsettings6 = self.sa.query(RhodeCodeUi)\
208 hgsettings6 = self.sa.query(RhodeCodeUi)\
208 .filter(RhodeCodeUi.ui_key ==
209 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_PULL)\
209 'preoutgoing.pull_logger').one()
210 .one()
210 hgsettings6.ui_active = \
211 hgsettings6.ui_active = bool(form_result[_f('hooks_%s' %
211 bool(form_result['hooks_preoutgoing_pull_logger'])
212 RhodeCodeUi.HOOK_PULL)])
212
213
213 self.sa.add(hgsettings1)
214 self.sa.add(hgsettings1)
214 self.sa.add(hgsettings2)
215 self.sa.add(hgsettings2)
215 self.sa.add(hgsettings3)
216 self.sa.add(hgsettings3)
216 self.sa.add(hgsettings4)
217 self.sa.add(hgsettings4)
217 self.sa.add(hgsettings5)
218 self.sa.add(hgsettings5)
218 self.sa.add(hgsettings6)
219 self.sa.add(hgsettings6)
219 self.sa.commit()
220 self.sa.commit()
220
221
221 h.flash(_('Updated mercurial settings'),
222 h.flash(_('Updated mercurial settings'),
222 category='success')
223 category='success')
223
224
224 except:
225 except:
225 log.error(traceback.format_exc())
226 log.error(traceback.format_exc())
226 h.flash(_('error occurred during updating '
227 h.flash(_('error occurred during updating '
227 'application settings'), category='error')
228 'application settings'), category='error')
228
229
229 self.sa.rollback()
230 self.sa.rollback()
230
231
231 except formencode.Invalid, errors:
232 except formencode.Invalid, errors:
232 return htmlfill.render(
233 return htmlfill.render(
233 render('admin/settings/settings.html'),
234 render('admin/settings/settings.html'),
234 defaults=errors.value,
235 defaults=errors.value,
235 errors=errors.error_dict or {},
236 errors=errors.error_dict or {},
236 prefix_error=False,
237 prefix_error=False,
237 encoding="UTF-8")
238 encoding="UTF-8")
238
239
239 if setting_id == 'hooks':
240 if setting_id == 'hooks':
240 ui_key = request.POST.get('new_hook_ui_key')
241 ui_key = request.POST.get('new_hook_ui_key')
241 ui_value = request.POST.get('new_hook_ui_value')
242 ui_value = request.POST.get('new_hook_ui_value')
242 try:
243 try:
243
244
244 if ui_value and ui_key:
245 if ui_value and ui_key:
245 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
246 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
246 h.flash(_('Added new hook'),
247 h.flash(_('Added new hook'),
247 category='success')
248 category='success')
248
249
249 # check for edits
250 # check for edits
250 update = False
251 update = False
251 _d = request.POST.dict_of_lists()
252 _d = request.POST.dict_of_lists()
252 for k, v in zip(_d.get('hook_ui_key', []),
253 for k, v in zip(_d.get('hook_ui_key', []),
253 _d.get('hook_ui_value_new', [])):
254 _d.get('hook_ui_value_new', [])):
254 RhodeCodeUi.create_or_update_hook(k, v)
255 RhodeCodeUi.create_or_update_hook(k, v)
255 update = True
256 update = True
256
257
257 if update:
258 if update:
258 h.flash(_('Updated hooks'), category='success')
259 h.flash(_('Updated hooks'), category='success')
259 self.sa.commit()
260 self.sa.commit()
260 except:
261 except:
261 log.error(traceback.format_exc())
262 log.error(traceback.format_exc())
262 h.flash(_('error occurred during hook creation'),
263 h.flash(_('error occurred during hook creation'),
263 category='error')
264 category='error')
264
265
265 return redirect(url('admin_edit_setting', setting_id='hooks'))
266 return redirect(url('admin_edit_setting', setting_id='hooks'))
266
267
267 if setting_id == 'email':
268 if setting_id == 'email':
268 test_email = request.POST.get('test_email')
269 test_email = request.POST.get('test_email')
269 test_email_subj = 'RhodeCode TestEmail'
270 test_email_subj = 'RhodeCode TestEmail'
270 test_email_body = 'RhodeCode Email test'
271 test_email_body = 'RhodeCode Email test'
271
272
272 test_email_html_body = EmailNotificationModel()\
273 test_email_html_body = EmailNotificationModel()\
273 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
274 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
274 body=test_email_body)
275 body=test_email_body)
275
276
276 recipients = [test_email] if [test_email] else None
277 recipients = [test_email] if [test_email] else None
277
278
278 run_task(tasks.send_email, recipients, test_email_subj,
279 run_task(tasks.send_email, recipients, test_email_subj,
279 test_email_body, test_email_html_body)
280 test_email_body, test_email_html_body)
280
281
281 h.flash(_('Email task created'), category='success')
282 h.flash(_('Email task created'), category='success')
282 return redirect(url('admin_settings'))
283 return redirect(url('admin_settings'))
283
284
284 @HasPermissionAllDecorator('hg.admin')
285 @HasPermissionAllDecorator('hg.admin')
285 def delete(self, setting_id):
286 def delete(self, setting_id):
286 """DELETE /admin/settings/setting_id: Delete an existing item"""
287 """DELETE /admin/settings/setting_id: Delete an existing item"""
287 # Forms posted to this method should contain a hidden field:
288 # Forms posted to this method should contain a hidden field:
288 # <input type="hidden" name="_method" value="DELETE" />
289 # <input type="hidden" name="_method" value="DELETE" />
289 # Or using helpers:
290 # Or using helpers:
290 # h.form(url('admin_setting', setting_id=ID),
291 # h.form(url('admin_setting', setting_id=ID),
291 # method='delete')
292 # method='delete')
292 # url('admin_setting', setting_id=ID)
293 # url('admin_setting', setting_id=ID)
293 if setting_id == 'hooks':
294 if setting_id == 'hooks':
294 hook_id = request.POST.get('hook_id')
295 hook_id = request.POST.get('hook_id')
295 RhodeCodeUi.delete(hook_id)
296 RhodeCodeUi.delete(hook_id)
296 self.sa.commit()
297 self.sa.commit()
297
298
298 @HasPermissionAllDecorator('hg.admin')
299 @HasPermissionAllDecorator('hg.admin')
299 def show(self, setting_id, format='html'):
300 def show(self, setting_id, format='html'):
300 """
301 """
301 GET /admin/settings/setting_id: Show a specific item"""
302 GET /admin/settings/setting_id: Show a specific item"""
302 # url('admin_setting', setting_id=ID)
303 # url('admin_setting', setting_id=ID)
303
304
304 @HasPermissionAllDecorator('hg.admin')
305 @HasPermissionAllDecorator('hg.admin')
305 def edit(self, setting_id, format='html'):
306 def edit(self, setting_id, format='html'):
306 """
307 """
307 GET /admin/settings/setting_id/edit: Form to
308 GET /admin/settings/setting_id/edit: Form to
308 edit an existing item"""
309 edit an existing item"""
309 # url('admin_edit_setting', setting_id=ID)
310 # url('admin_edit_setting', setting_id=ID)
310
311
311 c.hooks = RhodeCodeUi.get_builtin_hooks()
312 c.hooks = RhodeCodeUi.get_builtin_hooks()
312 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
313 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
313
314
314 return htmlfill.render(
315 return htmlfill.render(
315 render('admin/settings/hooks.html'),
316 render('admin/settings/hooks.html'),
316 defaults={},
317 defaults={},
317 encoding="UTF-8",
318 encoding="UTF-8",
318 force_defaults=False
319 force_defaults=False
319 )
320 )
320
321
321 @NotAnonymous()
322 @NotAnonymous()
322 def my_account(self):
323 def my_account(self):
323 """
324 """
324 GET /_admin/my_account Displays info about my account
325 GET /_admin/my_account Displays info about my account
325 """
326 """
326 # url('admin_settings_my_account')
327 # url('admin_settings_my_account')
327
328
328 c.user = User.get(self.rhodecode_user.user_id)
329 c.user = User.get(self.rhodecode_user.user_id)
329 all_repos = self.sa.query(Repository)\
330 all_repos = self.sa.query(Repository)\
330 .filter(Repository.user_id == c.user.user_id)\
331 .filter(Repository.user_id == c.user.user_id)\
331 .order_by(func.lower(Repository.repo_name)).all()
332 .order_by(func.lower(Repository.repo_name)).all()
332
333
333 c.user_repos = ScmModel().get_repos(all_repos)
334 c.user_repos = ScmModel().get_repos(all_repos)
334
335
335 if c.user.username == 'default':
336 if c.user.username == 'default':
336 h.flash(_("You can't edit this user since it's"
337 h.flash(_("You can't edit this user since it's"
337 " crucial for entire application"), category='warning')
338 " crucial for entire application"), category='warning')
338 return redirect(url('users'))
339 return redirect(url('users'))
339
340
340 defaults = c.user.get_dict()
341 defaults = c.user.get_dict()
341
342
342 c.form = htmlfill.render(
343 c.form = htmlfill.render(
343 render('admin/users/user_edit_my_account_form.html'),
344 render('admin/users/user_edit_my_account_form.html'),
344 defaults=defaults,
345 defaults=defaults,
345 encoding="UTF-8",
346 encoding="UTF-8",
346 force_defaults=False
347 force_defaults=False
347 )
348 )
348 return render('admin/users/user_edit_my_account.html')
349 return render('admin/users/user_edit_my_account.html')
349
350
350 def my_account_update(self):
351 def my_account_update(self):
351 """PUT /_admin/my_account_update: Update an existing item"""
352 """PUT /_admin/my_account_update: Update an existing item"""
352 # Forms posted to this method should contain a hidden field:
353 # Forms posted to this method should contain a hidden field:
353 # <input type="hidden" name="_method" value="PUT" />
354 # <input type="hidden" name="_method" value="PUT" />
354 # Or using helpers:
355 # Or using helpers:
355 # h.form(url('admin_settings_my_account_update'),
356 # h.form(url('admin_settings_my_account_update'),
356 # method='put')
357 # method='put')
357 # url('admin_settings_my_account_update', id=ID)
358 # url('admin_settings_my_account_update', id=ID)
358 user_model = UserModel()
359 user_model = UserModel()
359 uid = self.rhodecode_user.user_id
360 uid = self.rhodecode_user.user_id
360 _form = UserForm(edit=True,
361 _form = UserForm(edit=True,
361 old_data={'user_id': uid,
362 old_data={'user_id': uid,
362 'email': self.rhodecode_user.email})()
363 'email': self.rhodecode_user.email})()
363 form_result = {}
364 form_result = {}
364 try:
365 try:
365 form_result = _form.to_python(dict(request.POST))
366 form_result = _form.to_python(dict(request.POST))
366 user_model.update_my_account(uid, form_result)
367 user_model.update_my_account(uid, form_result)
367 h.flash(_('Your account was updated successfully'),
368 h.flash(_('Your account was updated successfully'),
368 category='success')
369 category='success')
369 Session.commit()
370 Session.commit()
370 except formencode.Invalid, errors:
371 except formencode.Invalid, errors:
371 c.user = User.get(self.rhodecode_user.user_id)
372 c.user = User.get(self.rhodecode_user.user_id)
372 all_repos = self.sa.query(Repository)\
373 all_repos = self.sa.query(Repository)\
373 .filter(Repository.user_id == c.user.user_id)\
374 .filter(Repository.user_id == c.user.user_id)\
374 .order_by(func.lower(Repository.repo_name))\
375 .order_by(func.lower(Repository.repo_name))\
375 .all()
376 .all()
376 c.user_repos = ScmModel().get_repos(all_repos)
377 c.user_repos = ScmModel().get_repos(all_repos)
377
378
378 c.form = htmlfill.render(
379 c.form = htmlfill.render(
379 render('admin/users/user_edit_my_account_form.html'),
380 render('admin/users/user_edit_my_account_form.html'),
380 defaults=errors.value,
381 defaults=errors.value,
381 errors=errors.error_dict or {},
382 errors=errors.error_dict or {},
382 prefix_error=False,
383 prefix_error=False,
383 encoding="UTF-8")
384 encoding="UTF-8")
384 return render('admin/users/user_edit_my_account.html')
385 return render('admin/users/user_edit_my_account.html')
385 except Exception:
386 except Exception:
386 log.error(traceback.format_exc())
387 log.error(traceback.format_exc())
387 h.flash(_('error occurred during update of user %s') \
388 h.flash(_('error occurred during update of user %s') \
388 % form_result.get('username'), category='error')
389 % form_result.get('username'), category='error')
389
390
390 return redirect(url('my_account'))
391 return redirect(url('my_account'))
391
392
392 @NotAnonymous()
393 @NotAnonymous()
393 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
394 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
394 def create_repository(self):
395 def create_repository(self):
395 """GET /_admin/create_repository: Form to create a new item"""
396 """GET /_admin/create_repository: Form to create a new item"""
396
397
397 c.repo_groups = RepoGroup.groups_choices()
398 c.repo_groups = RepoGroup.groups_choices()
398 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
399 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
399
400
400 new_repo = request.GET.get('repo', '')
401 new_repo = request.GET.get('repo', '')
401 c.new_repo = repo_name_slug(new_repo)
402 c.new_repo = repo_name_slug(new_repo)
402
403
403 return render('admin/repos/repo_add_create_repository.html')
404 return render('admin/repos/repo_add_create_repository.html')
404
405
405 def get_hg_ui_settings(self):
406 def get_hg_ui_settings(self):
406 ret = self.sa.query(RhodeCodeUi).all()
407 ret = self.sa.query(RhodeCodeUi).all()
407
408
408 if not ret:
409 if not ret:
409 raise Exception('Could not get application ui settings !')
410 raise Exception('Could not get application ui settings !')
410 settings = {}
411 settings = {}
411 for each in ret:
412 for each in ret:
412 k = each.ui_key
413 k = each.ui_key
413 v = each.ui_value
414 v = each.ui_value
414 if k == '/':
415 if k == '/':
415 k = 'root_path'
416 k = 'root_path'
416
417
417 if k.find('.') != -1:
418 if k.find('.') != -1:
418 k = k.replace('.', '_')
419 k = k.replace('.', '_')
419
420
420 if each.ui_section == 'hooks':
421 if each.ui_section == 'hooks':
421 v = each.ui_active
422 v = each.ui_active
422
423
423 settings[each.ui_section + '_' + k] = v
424 settings[each.ui_section + '_' + k] = v
424
425
425 return settings
426 return settings
@@ -1,1344 +1,1348 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.db
3 rhodecode.model.db
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 Database Models for RhodeCode
6 Database Models for RhodeCode
7
7
8 :created_on: Apr 08, 2010
8 :created_on: Apr 08, 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 os
26 import os
27 import logging
27 import logging
28 import datetime
28 import datetime
29 import traceback
29 import traceback
30 import hashlib
30 import hashlib
31 from collections import defaultdict
31 from collections import defaultdict
32
32
33 from sqlalchemy import *
33 from sqlalchemy import *
34 from sqlalchemy.ext.hybrid import hybrid_property
34 from sqlalchemy.ext.hybrid import hybrid_property
35 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
35 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
36 from beaker.cache import cache_region, region_invalidate
36 from beaker.cache import cache_region, region_invalidate
37
37
38 from rhodecode.lib.vcs import get_backend
38 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs.utils.helpers import get_scm
39 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.exceptions import VCSError
40 from rhodecode.lib.vcs.exceptions import VCSError
41 from rhodecode.lib.vcs.utils.lazy import LazyProperty
41 from rhodecode.lib.vcs.utils.lazy import LazyProperty
42
42
43 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
43 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
44 safe_unicode
44 safe_unicode
45 from rhodecode.lib.compat import json
45 from rhodecode.lib.compat import json
46 from rhodecode.lib.caching_query import FromCache
46 from rhodecode.lib.caching_query import FromCache
47 from rhodecode.model.meta import Base, Session
47 from rhodecode.model.meta import Base, Session
48
48
49
49
50 URL_SEP = '/'
50 URL_SEP = '/'
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53 #==============================================================================
53 #==============================================================================
54 # BASE CLASSES
54 # BASE CLASSES
55 #==============================================================================
55 #==============================================================================
56
56
57 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
57 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
58
58
59
59
60 class ModelSerializer(json.JSONEncoder):
60 class ModelSerializer(json.JSONEncoder):
61 """
61 """
62 Simple Serializer for JSON,
62 Simple Serializer for JSON,
63
63
64 usage::
64 usage::
65
65
66 to make object customized for serialization implement a __json__
66 to make object customized for serialization implement a __json__
67 method that will return a dict for serialization into json
67 method that will return a dict for serialization into json
68
68
69 example::
69 example::
70
70
71 class Task(object):
71 class Task(object):
72
72
73 def __init__(self, name, value):
73 def __init__(self, name, value):
74 self.name = name
74 self.name = name
75 self.value = value
75 self.value = value
76
76
77 def __json__(self):
77 def __json__(self):
78 return dict(name=self.name,
78 return dict(name=self.name,
79 value=self.value)
79 value=self.value)
80
80
81 """
81 """
82
82
83 def default(self, obj):
83 def default(self, obj):
84
84
85 if hasattr(obj, '__json__'):
85 if hasattr(obj, '__json__'):
86 return obj.__json__()
86 return obj.__json__()
87 else:
87 else:
88 return json.JSONEncoder.default(self, obj)
88 return json.JSONEncoder.default(self, obj)
89
89
90
90
91 class BaseModel(object):
91 class BaseModel(object):
92 """
92 """
93 Base Model for all classess
93 Base Model for all classess
94 """
94 """
95
95
96 @classmethod
96 @classmethod
97 def _get_keys(cls):
97 def _get_keys(cls):
98 """return column names for this model """
98 """return column names for this model """
99 return class_mapper(cls).c.keys()
99 return class_mapper(cls).c.keys()
100
100
101 def get_dict(self):
101 def get_dict(self):
102 """
102 """
103 return dict with keys and values corresponding
103 return dict with keys and values corresponding
104 to this model data """
104 to this model data """
105
105
106 d = {}
106 d = {}
107 for k in self._get_keys():
107 for k in self._get_keys():
108 d[k] = getattr(self, k)
108 d[k] = getattr(self, k)
109
109
110 # also use __json__() if present to get additional fields
110 # also use __json__() if present to get additional fields
111 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
111 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
112 d[k] = val
112 d[k] = val
113 return d
113 return d
114
114
115 def get_appstruct(self):
115 def get_appstruct(self):
116 """return list with keys and values tupples corresponding
116 """return list with keys and values tupples corresponding
117 to this model data """
117 to this model data """
118
118
119 l = []
119 l = []
120 for k in self._get_keys():
120 for k in self._get_keys():
121 l.append((k, getattr(self, k),))
121 l.append((k, getattr(self, k),))
122 return l
122 return l
123
123
124 def populate_obj(self, populate_dict):
124 def populate_obj(self, populate_dict):
125 """populate model with data from given populate_dict"""
125 """populate model with data from given populate_dict"""
126
126
127 for k in self._get_keys():
127 for k in self._get_keys():
128 if k in populate_dict:
128 if k in populate_dict:
129 setattr(self, k, populate_dict[k])
129 setattr(self, k, populate_dict[k])
130
130
131 @classmethod
131 @classmethod
132 def query(cls):
132 def query(cls):
133 return Session.query(cls)
133 return Session.query(cls)
134
134
135 @classmethod
135 @classmethod
136 def get(cls, id_):
136 def get(cls, id_):
137 if id_:
137 if id_:
138 return cls.query().get(id_)
138 return cls.query().get(id_)
139
139
140 @classmethod
140 @classmethod
141 def getAll(cls):
141 def getAll(cls):
142 return cls.query().all()
142 return cls.query().all()
143
143
144 @classmethod
144 @classmethod
145 def delete(cls, id_):
145 def delete(cls, id_):
146 obj = cls.query().get(id_)
146 obj = cls.query().get(id_)
147 Session.delete(obj)
147 Session.delete(obj)
148
148
149 def __repr__(self):
149 def __repr__(self):
150 if hasattr(self, '__unicode__'):
150 if hasattr(self, '__unicode__'):
151 # python repr needs to return str
151 # python repr needs to return str
152 return safe_str(self.__unicode__())
152 return safe_str(self.__unicode__())
153 return '<DB:%s>' % (self.__class__.__name__)
153 return '<DB:%s>' % (self.__class__.__name__)
154
154
155
155
156 class RhodeCodeSetting(Base, BaseModel):
156 class RhodeCodeSetting(Base, BaseModel):
157 __tablename__ = 'rhodecode_settings'
157 __tablename__ = 'rhodecode_settings'
158 __table_args__ = (
158 __table_args__ = (
159 UniqueConstraint('app_settings_name'),
159 UniqueConstraint('app_settings_name'),
160 {'extend_existing': True, 'mysql_engine': 'InnoDB',
160 {'extend_existing': True, 'mysql_engine': 'InnoDB',
161 'mysql_charset': 'utf8'}
161 'mysql_charset': 'utf8'}
162 )
162 )
163 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
163 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
164 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
164 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
165 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
165 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
166
166
167 def __init__(self, k='', v=''):
167 def __init__(self, k='', v=''):
168 self.app_settings_name = k
168 self.app_settings_name = k
169 self.app_settings_value = v
169 self.app_settings_value = v
170
170
171 @validates('_app_settings_value')
171 @validates('_app_settings_value')
172 def validate_settings_value(self, key, val):
172 def validate_settings_value(self, key, val):
173 assert type(val) == unicode
173 assert type(val) == unicode
174 return val
174 return val
175
175
176 @hybrid_property
176 @hybrid_property
177 def app_settings_value(self):
177 def app_settings_value(self):
178 v = self._app_settings_value
178 v = self._app_settings_value
179 if self.app_settings_name == 'ldap_active':
179 if self.app_settings_name == 'ldap_active':
180 v = str2bool(v)
180 v = str2bool(v)
181 return v
181 return v
182
182
183 @app_settings_value.setter
183 @app_settings_value.setter
184 def app_settings_value(self, val):
184 def app_settings_value(self, val):
185 """
185 """
186 Setter that will always make sure we use unicode in app_settings_value
186 Setter that will always make sure we use unicode in app_settings_value
187
187
188 :param val:
188 :param val:
189 """
189 """
190 self._app_settings_value = safe_unicode(val)
190 self._app_settings_value = safe_unicode(val)
191
191
192 def __unicode__(self):
192 def __unicode__(self):
193 return u"<%s('%s:%s')>" % (
193 return u"<%s('%s:%s')>" % (
194 self.__class__.__name__,
194 self.__class__.__name__,
195 self.app_settings_name, self.app_settings_value
195 self.app_settings_name, self.app_settings_value
196 )
196 )
197
197
198 @classmethod
198 @classmethod
199 def get_by_name(cls, ldap_key):
199 def get_by_name(cls, ldap_key):
200 return cls.query()\
200 return cls.query()\
201 .filter(cls.app_settings_name == ldap_key).scalar()
201 .filter(cls.app_settings_name == ldap_key).scalar()
202
202
203 @classmethod
203 @classmethod
204 def get_app_settings(cls, cache=False):
204 def get_app_settings(cls, cache=False):
205
205
206 ret = cls.query()
206 ret = cls.query()
207
207
208 if cache:
208 if cache:
209 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
209 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
210
210
211 if not ret:
211 if not ret:
212 raise Exception('Could not get application settings !')
212 raise Exception('Could not get application settings !')
213 settings = {}
213 settings = {}
214 for each in ret:
214 for each in ret:
215 settings['rhodecode_' + each.app_settings_name] = \
215 settings['rhodecode_' + each.app_settings_name] = \
216 each.app_settings_value
216 each.app_settings_value
217
217
218 return settings
218 return settings
219
219
220 @classmethod
220 @classmethod
221 def get_ldap_settings(cls, cache=False):
221 def get_ldap_settings(cls, cache=False):
222 ret = cls.query()\
222 ret = cls.query()\
223 .filter(cls.app_settings_name.startswith('ldap_')).all()
223 .filter(cls.app_settings_name.startswith('ldap_')).all()
224 fd = {}
224 fd = {}
225 for row in ret:
225 for row in ret:
226 fd.update({row.app_settings_name: row.app_settings_value})
226 fd.update({row.app_settings_name: row.app_settings_value})
227
227
228 return fd
228 return fd
229
229
230
230
231 class RhodeCodeUi(Base, BaseModel):
231 class RhodeCodeUi(Base, BaseModel):
232 __tablename__ = 'rhodecode_ui'
232 __tablename__ = 'rhodecode_ui'
233 __table_args__ = (
233 __table_args__ = (
234 UniqueConstraint('ui_key'),
234 UniqueConstraint('ui_key'),
235 {'extend_existing': True, 'mysql_engine': 'InnoDB',
235 {'extend_existing': True, 'mysql_engine': 'InnoDB',
236 'mysql_charset': 'utf8'}
236 'mysql_charset': 'utf8'}
237 )
237 )
238
238
239 HOOK_UPDATE = 'changegroup.update'
239 HOOK_UPDATE = 'changegroup.update'
240 HOOK_REPO_SIZE = 'changegroup.repo_size'
240 HOOK_REPO_SIZE = 'changegroup.repo_size'
241 HOOK_PUSH = 'pretxnchangegroup.push_logger'
241 HOOK_PUSH = 'pretxnchangegroup.push_logger'
242 HOOK_PULL = 'preoutgoing.pull_logger'
242 HOOK_PULL = 'preoutgoing.pull_logger'
243
243
244 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
244 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
245 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
245 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
246 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
246 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
247 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
247 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
248 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
248 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
249
249
250 @classmethod
250 @classmethod
251 def get_by_key(cls, key):
251 def get_by_key(cls, key):
252 return cls.query().filter(cls.ui_key == key)
252 return cls.query().filter(cls.ui_key == key)
253
253
254 @classmethod
254 @classmethod
255 def get_builtin_hooks(cls):
255 def get_builtin_hooks(cls):
256 q = cls.query()
256 q = cls.query()
257 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
257 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
258 cls.HOOK_REPO_SIZE,
258 cls.HOOK_REPO_SIZE,
259 cls.HOOK_PUSH, cls.HOOK_PULL]))
259 cls.HOOK_PUSH, cls.HOOK_PULL]))
260 return q.all()
260 return q.all()
261
261
262 @classmethod
262 @classmethod
263 def get_custom_hooks(cls):
263 def get_custom_hooks(cls):
264 q = cls.query()
264 q = cls.query()
265 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
265 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
266 cls.HOOK_REPO_SIZE,
266 cls.HOOK_REPO_SIZE,
267 cls.HOOK_PUSH, cls.HOOK_PULL]))
267 cls.HOOK_PUSH, cls.HOOK_PULL]))
268 q = q.filter(cls.ui_section == 'hooks')
268 q = q.filter(cls.ui_section == 'hooks')
269 return q.all()
269 return q.all()
270
270
271 @classmethod
271 @classmethod
272 def get_repos_location(cls):
273 return cls.get_by_key('/').one().ui_value
274
275 @classmethod
272 def create_or_update_hook(cls, key, val):
276 def create_or_update_hook(cls, key, val):
273 new_ui = cls.get_by_key(key).scalar() or cls()
277 new_ui = cls.get_by_key(key).scalar() or cls()
274 new_ui.ui_section = 'hooks'
278 new_ui.ui_section = 'hooks'
275 new_ui.ui_active = True
279 new_ui.ui_active = True
276 new_ui.ui_key = key
280 new_ui.ui_key = key
277 new_ui.ui_value = val
281 new_ui.ui_value = val
278
282
279 Session.add(new_ui)
283 Session.add(new_ui)
280
284
281
285
282 class User(Base, BaseModel):
286 class User(Base, BaseModel):
283 __tablename__ = 'users'
287 __tablename__ = 'users'
284 __table_args__ = (
288 __table_args__ = (
285 UniqueConstraint('username'), UniqueConstraint('email'),
289 UniqueConstraint('username'), UniqueConstraint('email'),
286 {'extend_existing': True, 'mysql_engine': 'InnoDB',
290 {'extend_existing': True, 'mysql_engine': 'InnoDB',
287 'mysql_charset': 'utf8'}
291 'mysql_charset': 'utf8'}
288 )
292 )
289 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
293 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
290 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
294 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
291 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
295 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
292 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
296 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
293 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
297 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
294 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
298 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
295 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
299 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
296 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
300 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
297 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
301 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
298 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
302 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
299 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
303 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
300
304
301 user_log = relationship('UserLog', cascade='all')
305 user_log = relationship('UserLog', cascade='all')
302 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
306 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
303
307
304 repositories = relationship('Repository')
308 repositories = relationship('Repository')
305 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
309 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
306 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
310 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
307 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
311 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
308
312
309 group_member = relationship('UsersGroupMember', cascade='all')
313 group_member = relationship('UsersGroupMember', cascade='all')
310
314
311 notifications = relationship('UserNotification', cascade='all')
315 notifications = relationship('UserNotification', cascade='all')
312 # notifications assigned to this user
316 # notifications assigned to this user
313 user_created_notifications = relationship('Notification', cascade='all')
317 user_created_notifications = relationship('Notification', cascade='all')
314 # comments created by this user
318 # comments created by this user
315 user_comments = relationship('ChangesetComment', cascade='all')
319 user_comments = relationship('ChangesetComment', cascade='all')
316
320
317 @hybrid_property
321 @hybrid_property
318 def email(self):
322 def email(self):
319 return self._email
323 return self._email
320
324
321 @email.setter
325 @email.setter
322 def email(self, val):
326 def email(self, val):
323 self._email = val.lower() if val else None
327 self._email = val.lower() if val else None
324
328
325 @property
329 @property
326 def full_name(self):
330 def full_name(self):
327 return '%s %s' % (self.name, self.lastname)
331 return '%s %s' % (self.name, self.lastname)
328
332
329 @property
333 @property
330 def full_name_or_username(self):
334 def full_name_or_username(self):
331 return ('%s %s' % (self.name, self.lastname)
335 return ('%s %s' % (self.name, self.lastname)
332 if (self.name and self.lastname) else self.username)
336 if (self.name and self.lastname) else self.username)
333
337
334 @property
338 @property
335 def full_contact(self):
339 def full_contact(self):
336 return '%s %s <%s>' % (self.name, self.lastname, self.email)
340 return '%s %s <%s>' % (self.name, self.lastname, self.email)
337
341
338 @property
342 @property
339 def short_contact(self):
343 def short_contact(self):
340 return '%s %s' % (self.name, self.lastname)
344 return '%s %s' % (self.name, self.lastname)
341
345
342 @property
346 @property
343 def is_admin(self):
347 def is_admin(self):
344 return self.admin
348 return self.admin
345
349
346 def __unicode__(self):
350 def __unicode__(self):
347 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
351 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
348 self.user_id, self.username)
352 self.user_id, self.username)
349
353
350 @classmethod
354 @classmethod
351 def get_by_username(cls, username, case_insensitive=False, cache=False):
355 def get_by_username(cls, username, case_insensitive=False, cache=False):
352 if case_insensitive:
356 if case_insensitive:
353 q = cls.query().filter(cls.username.ilike(username))
357 q = cls.query().filter(cls.username.ilike(username))
354 else:
358 else:
355 q = cls.query().filter(cls.username == username)
359 q = cls.query().filter(cls.username == username)
356
360
357 if cache:
361 if cache:
358 q = q.options(FromCache(
362 q = q.options(FromCache(
359 "sql_cache_short",
363 "sql_cache_short",
360 "get_user_%s" % _hash_key(username)
364 "get_user_%s" % _hash_key(username)
361 )
365 )
362 )
366 )
363 return q.scalar()
367 return q.scalar()
364
368
365 @classmethod
369 @classmethod
366 def get_by_api_key(cls, api_key, cache=False):
370 def get_by_api_key(cls, api_key, cache=False):
367 q = cls.query().filter(cls.api_key == api_key)
371 q = cls.query().filter(cls.api_key == api_key)
368
372
369 if cache:
373 if cache:
370 q = q.options(FromCache("sql_cache_short",
374 q = q.options(FromCache("sql_cache_short",
371 "get_api_key_%s" % api_key))
375 "get_api_key_%s" % api_key))
372 return q.scalar()
376 return q.scalar()
373
377
374 @classmethod
378 @classmethod
375 def get_by_email(cls, email, case_insensitive=False, cache=False):
379 def get_by_email(cls, email, case_insensitive=False, cache=False):
376 if case_insensitive:
380 if case_insensitive:
377 q = cls.query().filter(cls.email.ilike(email))
381 q = cls.query().filter(cls.email.ilike(email))
378 else:
382 else:
379 q = cls.query().filter(cls.email == email)
383 q = cls.query().filter(cls.email == email)
380
384
381 if cache:
385 if cache:
382 q = q.options(FromCache("sql_cache_short",
386 q = q.options(FromCache("sql_cache_short",
383 "get_api_key_%s" % email))
387 "get_api_key_%s" % email))
384 return q.scalar()
388 return q.scalar()
385
389
386 def update_lastlogin(self):
390 def update_lastlogin(self):
387 """Update user lastlogin"""
391 """Update user lastlogin"""
388 self.last_login = datetime.datetime.now()
392 self.last_login = datetime.datetime.now()
389 Session.add(self)
393 Session.add(self)
390 log.debug('updated user %s lastlogin' % self.username)
394 log.debug('updated user %s lastlogin' % self.username)
391
395
392 def __json__(self):
396 def __json__(self):
393 return dict(
397 return dict(
394 user_id=self.user_id,
398 user_id=self.user_id,
395 first_name=self.name,
399 first_name=self.name,
396 last_name=self.lastname,
400 last_name=self.lastname,
397 email=self.email,
401 email=self.email,
398 full_name=self.full_name,
402 full_name=self.full_name,
399 full_name_or_username=self.full_name_or_username,
403 full_name_or_username=self.full_name_or_username,
400 short_contact=self.short_contact,
404 short_contact=self.short_contact,
401 full_contact=self.full_contact
405 full_contact=self.full_contact
402 )
406 )
403
407
404
408
405 class UserLog(Base, BaseModel):
409 class UserLog(Base, BaseModel):
406 __tablename__ = 'user_logs'
410 __tablename__ = 'user_logs'
407 __table_args__ = (
411 __table_args__ = (
408 {'extend_existing': True, 'mysql_engine': 'InnoDB',
412 {'extend_existing': True, 'mysql_engine': 'InnoDB',
409 'mysql_charset': 'utf8'},
413 'mysql_charset': 'utf8'},
410 )
414 )
411 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
415 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
412 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
416 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
413 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
417 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
414 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
418 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
415 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
419 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
416 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
420 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
417 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
421 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
418
422
419 @property
423 @property
420 def action_as_day(self):
424 def action_as_day(self):
421 return datetime.date(*self.action_date.timetuple()[:3])
425 return datetime.date(*self.action_date.timetuple()[:3])
422
426
423 user = relationship('User')
427 user = relationship('User')
424 repository = relationship('Repository', cascade='')
428 repository = relationship('Repository', cascade='')
425
429
426
430
427 class UsersGroup(Base, BaseModel):
431 class UsersGroup(Base, BaseModel):
428 __tablename__ = 'users_groups'
432 __tablename__ = 'users_groups'
429 __table_args__ = (
433 __table_args__ = (
430 {'extend_existing': True, 'mysql_engine': 'InnoDB',
434 {'extend_existing': True, 'mysql_engine': 'InnoDB',
431 'mysql_charset': 'utf8'},
435 'mysql_charset': 'utf8'},
432 )
436 )
433
437
434 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
438 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
435 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
439 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
436 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
440 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
437
441
438 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
442 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
439 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
443 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
440 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
444 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
441
445
442 def __unicode__(self):
446 def __unicode__(self):
443 return u'<userGroup(%s)>' % (self.users_group_name)
447 return u'<userGroup(%s)>' % (self.users_group_name)
444
448
445 @classmethod
449 @classmethod
446 def get_by_group_name(cls, group_name, cache=False,
450 def get_by_group_name(cls, group_name, cache=False,
447 case_insensitive=False):
451 case_insensitive=False):
448 if case_insensitive:
452 if case_insensitive:
449 q = cls.query().filter(cls.users_group_name.ilike(group_name))
453 q = cls.query().filter(cls.users_group_name.ilike(group_name))
450 else:
454 else:
451 q = cls.query().filter(cls.users_group_name == group_name)
455 q = cls.query().filter(cls.users_group_name == group_name)
452 if cache:
456 if cache:
453 q = q.options(FromCache(
457 q = q.options(FromCache(
454 "sql_cache_short",
458 "sql_cache_short",
455 "get_user_%s" % _hash_key(group_name)
459 "get_user_%s" % _hash_key(group_name)
456 )
460 )
457 )
461 )
458 return q.scalar()
462 return q.scalar()
459
463
460 @classmethod
464 @classmethod
461 def get(cls, users_group_id, cache=False):
465 def get(cls, users_group_id, cache=False):
462 users_group = cls.query()
466 users_group = cls.query()
463 if cache:
467 if cache:
464 users_group = users_group.options(FromCache("sql_cache_short",
468 users_group = users_group.options(FromCache("sql_cache_short",
465 "get_users_group_%s" % users_group_id))
469 "get_users_group_%s" % users_group_id))
466 return users_group.get(users_group_id)
470 return users_group.get(users_group_id)
467
471
468
472
469 class UsersGroupMember(Base, BaseModel):
473 class UsersGroupMember(Base, BaseModel):
470 __tablename__ = 'users_groups_members'
474 __tablename__ = 'users_groups_members'
471 __table_args__ = (
475 __table_args__ = (
472 {'extend_existing': True, 'mysql_engine': 'InnoDB',
476 {'extend_existing': True, 'mysql_engine': 'InnoDB',
473 'mysql_charset': 'utf8'},
477 'mysql_charset': 'utf8'},
474 )
478 )
475
479
476 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
480 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
477 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
481 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
478 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
482 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
479
483
480 user = relationship('User', lazy='joined')
484 user = relationship('User', lazy='joined')
481 users_group = relationship('UsersGroup')
485 users_group = relationship('UsersGroup')
482
486
483 def __init__(self, gr_id='', u_id=''):
487 def __init__(self, gr_id='', u_id=''):
484 self.users_group_id = gr_id
488 self.users_group_id = gr_id
485 self.user_id = u_id
489 self.user_id = u_id
486
490
487
491
488 class Repository(Base, BaseModel):
492 class Repository(Base, BaseModel):
489 __tablename__ = 'repositories'
493 __tablename__ = 'repositories'
490 __table_args__ = (
494 __table_args__ = (
491 UniqueConstraint('repo_name'),
495 UniqueConstraint('repo_name'),
492 {'extend_existing': True, 'mysql_engine': 'InnoDB',
496 {'extend_existing': True, 'mysql_engine': 'InnoDB',
493 'mysql_charset': 'utf8'},
497 'mysql_charset': 'utf8'},
494 )
498 )
495
499
496 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
500 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
497 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
501 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
498 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
502 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
499 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
503 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
500 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
504 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
501 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
505 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
502 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
506 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
503 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
507 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
504 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
508 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
505 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
509 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
506
510
507 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
511 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
508 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
512 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
509
513
510 user = relationship('User')
514 user = relationship('User')
511 fork = relationship('Repository', remote_side=repo_id)
515 fork = relationship('Repository', remote_side=repo_id)
512 group = relationship('RepoGroup')
516 group = relationship('RepoGroup')
513 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
517 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
514 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
518 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
515 stats = relationship('Statistics', cascade='all', uselist=False)
519 stats = relationship('Statistics', cascade='all', uselist=False)
516
520
517 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
521 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
518
522
519 logs = relationship('UserLog')
523 logs = relationship('UserLog')
520
524
521 def __unicode__(self):
525 def __unicode__(self):
522 return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id,
526 return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id,
523 self.repo_name)
527 self.repo_name)
524
528
525 @classmethod
529 @classmethod
526 def url_sep(cls):
530 def url_sep(cls):
527 return URL_SEP
531 return URL_SEP
528
532
529 @classmethod
533 @classmethod
530 def get_by_repo_name(cls, repo_name):
534 def get_by_repo_name(cls, repo_name):
531 q = Session.query(cls).filter(cls.repo_name == repo_name)
535 q = Session.query(cls).filter(cls.repo_name == repo_name)
532 q = q.options(joinedload(Repository.fork))\
536 q = q.options(joinedload(Repository.fork))\
533 .options(joinedload(Repository.user))\
537 .options(joinedload(Repository.user))\
534 .options(joinedload(Repository.group))
538 .options(joinedload(Repository.group))
535 return q.scalar()
539 return q.scalar()
536
540
537 @classmethod
541 @classmethod
538 def get_by_full_path(cls, repo_full_path):
542 def get_by_full_path(cls, repo_full_path):
539 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
543 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
540 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
544 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
541
545
542 @classmethod
546 @classmethod
543 def get_repo_forks(cls, repo_id):
547 def get_repo_forks(cls, repo_id):
544 return cls.query().filter(Repository.fork_id == repo_id)
548 return cls.query().filter(Repository.fork_id == repo_id)
545
549
546 @classmethod
550 @classmethod
547 def base_path(cls):
551 def base_path(cls):
548 """
552 """
549 Returns base path when all repos are stored
553 Returns base path when all repos are stored
550
554
551 :param cls:
555 :param cls:
552 """
556 """
553 q = Session.query(RhodeCodeUi)\
557 q = Session.query(RhodeCodeUi)\
554 .filter(RhodeCodeUi.ui_key == cls.url_sep())
558 .filter(RhodeCodeUi.ui_key == cls.url_sep())
555 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
559 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
556 return q.one().ui_value
560 return q.one().ui_value
557
561
558 @property
562 @property
559 def just_name(self):
563 def just_name(self):
560 return self.repo_name.split(Repository.url_sep())[-1]
564 return self.repo_name.split(Repository.url_sep())[-1]
561
565
562 @property
566 @property
563 def groups_with_parents(self):
567 def groups_with_parents(self):
564 groups = []
568 groups = []
565 if self.group is None:
569 if self.group is None:
566 return groups
570 return groups
567
571
568 cur_gr = self.group
572 cur_gr = self.group
569 groups.insert(0, cur_gr)
573 groups.insert(0, cur_gr)
570 while 1:
574 while 1:
571 gr = getattr(cur_gr, 'parent_group', None)
575 gr = getattr(cur_gr, 'parent_group', None)
572 cur_gr = cur_gr.parent_group
576 cur_gr = cur_gr.parent_group
573 if gr is None:
577 if gr is None:
574 break
578 break
575 groups.insert(0, gr)
579 groups.insert(0, gr)
576
580
577 return groups
581 return groups
578
582
579 @property
583 @property
580 def groups_and_repo(self):
584 def groups_and_repo(self):
581 return self.groups_with_parents, self.just_name
585 return self.groups_with_parents, self.just_name
582
586
583 @LazyProperty
587 @LazyProperty
584 def repo_path(self):
588 def repo_path(self):
585 """
589 """
586 Returns base full path for that repository means where it actually
590 Returns base full path for that repository means where it actually
587 exists on a filesystem
591 exists on a filesystem
588 """
592 """
589 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
593 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
590 Repository.url_sep())
594 Repository.url_sep())
591 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
595 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
592 return q.one().ui_value
596 return q.one().ui_value
593
597
594 @property
598 @property
595 def repo_full_path(self):
599 def repo_full_path(self):
596 p = [self.repo_path]
600 p = [self.repo_path]
597 # we need to split the name by / since this is how we store the
601 # we need to split the name by / since this is how we store the
598 # names in the database, but that eventually needs to be converted
602 # names in the database, but that eventually needs to be converted
599 # into a valid system path
603 # into a valid system path
600 p += self.repo_name.split(Repository.url_sep())
604 p += self.repo_name.split(Repository.url_sep())
601 return os.path.join(*p)
605 return os.path.join(*p)
602
606
603 def get_new_name(self, repo_name):
607 def get_new_name(self, repo_name):
604 """
608 """
605 returns new full repository name based on assigned group and new new
609 returns new full repository name based on assigned group and new new
606
610
607 :param group_name:
611 :param group_name:
608 """
612 """
609 path_prefix = self.group.full_path_splitted if self.group else []
613 path_prefix = self.group.full_path_splitted if self.group else []
610 return Repository.url_sep().join(path_prefix + [repo_name])
614 return Repository.url_sep().join(path_prefix + [repo_name])
611
615
612 @property
616 @property
613 def _ui(self):
617 def _ui(self):
614 """
618 """
615 Creates an db based ui object for this repository
619 Creates an db based ui object for this repository
616 """
620 """
617 from mercurial import ui
621 from mercurial import ui
618 from mercurial import config
622 from mercurial import config
619 baseui = ui.ui()
623 baseui = ui.ui()
620
624
621 #clean the baseui object
625 #clean the baseui object
622 baseui._ocfg = config.config()
626 baseui._ocfg = config.config()
623 baseui._ucfg = config.config()
627 baseui._ucfg = config.config()
624 baseui._tcfg = config.config()
628 baseui._tcfg = config.config()
625
629
626 ret = RhodeCodeUi.query()\
630 ret = RhodeCodeUi.query()\
627 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
631 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
628
632
629 hg_ui = ret
633 hg_ui = ret
630 for ui_ in hg_ui:
634 for ui_ in hg_ui:
631 if ui_.ui_active:
635 if ui_.ui_active:
632 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
636 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
633 ui_.ui_key, ui_.ui_value)
637 ui_.ui_key, ui_.ui_value)
634 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
638 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
635
639
636 return baseui
640 return baseui
637
641
638 @classmethod
642 @classmethod
639 def is_valid(cls, repo_name):
643 def is_valid(cls, repo_name):
640 """
644 """
641 returns True if given repo name is a valid filesystem repository
645 returns True if given repo name is a valid filesystem repository
642
646
643 :param cls:
647 :param cls:
644 :param repo_name:
648 :param repo_name:
645 """
649 """
646 from rhodecode.lib.utils import is_valid_repo
650 from rhodecode.lib.utils import is_valid_repo
647
651
648 return is_valid_repo(repo_name, cls.base_path())
652 return is_valid_repo(repo_name, cls.base_path())
649
653
650 #==========================================================================
654 #==========================================================================
651 # SCM PROPERTIES
655 # SCM PROPERTIES
652 #==========================================================================
656 #==========================================================================
653
657
654 def get_changeset(self, rev=None):
658 def get_changeset(self, rev=None):
655 return get_changeset_safe(self.scm_instance, rev)
659 return get_changeset_safe(self.scm_instance, rev)
656
660
657 @property
661 @property
658 def tip(self):
662 def tip(self):
659 return self.get_changeset('tip')
663 return self.get_changeset('tip')
660
664
661 @property
665 @property
662 def author(self):
666 def author(self):
663 return self.tip.author
667 return self.tip.author
664
668
665 @property
669 @property
666 def last_change(self):
670 def last_change(self):
667 return self.scm_instance.last_change
671 return self.scm_instance.last_change
668
672
669 def comments(self, revisions=None):
673 def comments(self, revisions=None):
670 """
674 """
671 Returns comments for this repository grouped by revisions
675 Returns comments for this repository grouped by revisions
672
676
673 :param revisions: filter query by revisions only
677 :param revisions: filter query by revisions only
674 """
678 """
675 cmts = ChangesetComment.query()\
679 cmts = ChangesetComment.query()\
676 .filter(ChangesetComment.repo == self)
680 .filter(ChangesetComment.repo == self)
677 if revisions:
681 if revisions:
678 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
682 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
679 grouped = defaultdict(list)
683 grouped = defaultdict(list)
680 for cmt in cmts.all():
684 for cmt in cmts.all():
681 grouped[cmt.revision].append(cmt)
685 grouped[cmt.revision].append(cmt)
682 return grouped
686 return grouped
683
687
684 #==========================================================================
688 #==========================================================================
685 # SCM CACHE INSTANCE
689 # SCM CACHE INSTANCE
686 #==========================================================================
690 #==========================================================================
687
691
688 @property
692 @property
689 def invalidate(self):
693 def invalidate(self):
690 return CacheInvalidation.invalidate(self.repo_name)
694 return CacheInvalidation.invalidate(self.repo_name)
691
695
692 def set_invalidate(self):
696 def set_invalidate(self):
693 """
697 """
694 set a cache for invalidation for this instance
698 set a cache for invalidation for this instance
695 """
699 """
696 CacheInvalidation.set_invalidate(self.repo_name)
700 CacheInvalidation.set_invalidate(self.repo_name)
697
701
698 @LazyProperty
702 @LazyProperty
699 def scm_instance(self):
703 def scm_instance(self):
700 return self.__get_instance()
704 return self.__get_instance()
701
705
702 def scm_instance_cached(self, cache_map=None):
706 def scm_instance_cached(self, cache_map=None):
703 @cache_region('long_term')
707 @cache_region('long_term')
704 def _c(repo_name):
708 def _c(repo_name):
705 return self.__get_instance()
709 return self.__get_instance()
706 rn = self.repo_name
710 rn = self.repo_name
707 log.debug('Getting cached instance of repo')
711 log.debug('Getting cached instance of repo')
708
712
709 if cache_map:
713 if cache_map:
710 # get using prefilled cache_map
714 # get using prefilled cache_map
711 invalidate_repo = cache_map[self.repo_name]
715 invalidate_repo = cache_map[self.repo_name]
712 if invalidate_repo:
716 if invalidate_repo:
713 invalidate_repo = (None if invalidate_repo.cache_active
717 invalidate_repo = (None if invalidate_repo.cache_active
714 else invalidate_repo)
718 else invalidate_repo)
715 else:
719 else:
716 # get from invalidate
720 # get from invalidate
717 invalidate_repo = self.invalidate
721 invalidate_repo = self.invalidate
718
722
719 if invalidate_repo is not None:
723 if invalidate_repo is not None:
720 region_invalidate(_c, None, rn)
724 region_invalidate(_c, None, rn)
721 # update our cache
725 # update our cache
722 CacheInvalidation.set_valid(invalidate_repo.cache_key)
726 CacheInvalidation.set_valid(invalidate_repo.cache_key)
723 return _c(rn)
727 return _c(rn)
724
728
725 def __get_instance(self):
729 def __get_instance(self):
726 repo_full_path = self.repo_full_path
730 repo_full_path = self.repo_full_path
727 try:
731 try:
728 alias = get_scm(repo_full_path)[0]
732 alias = get_scm(repo_full_path)[0]
729 log.debug('Creating instance of %s repository' % alias)
733 log.debug('Creating instance of %s repository' % alias)
730 backend = get_backend(alias)
734 backend = get_backend(alias)
731 except VCSError:
735 except VCSError:
732 log.error(traceback.format_exc())
736 log.error(traceback.format_exc())
733 log.error('Perhaps this repository is in db and not in '
737 log.error('Perhaps this repository is in db and not in '
734 'filesystem run rescan repositories with '
738 'filesystem run rescan repositories with '
735 '"destroy old data " option from admin panel')
739 '"destroy old data " option from admin panel')
736 return
740 return
737
741
738 if alias == 'hg':
742 if alias == 'hg':
739
743
740 repo = backend(safe_str(repo_full_path), create=False,
744 repo = backend(safe_str(repo_full_path), create=False,
741 baseui=self._ui)
745 baseui=self._ui)
742 # skip hidden web repository
746 # skip hidden web repository
743 if repo._get_hidden():
747 if repo._get_hidden():
744 return
748 return
745 else:
749 else:
746 repo = backend(repo_full_path, create=False)
750 repo = backend(repo_full_path, create=False)
747
751
748 return repo
752 return repo
749
753
750
754
751 class RepoGroup(Base, BaseModel):
755 class RepoGroup(Base, BaseModel):
752 __tablename__ = 'groups'
756 __tablename__ = 'groups'
753 __table_args__ = (
757 __table_args__ = (
754 UniqueConstraint('group_name', 'group_parent_id'),
758 UniqueConstraint('group_name', 'group_parent_id'),
755 CheckConstraint('group_id != group_parent_id'),
759 CheckConstraint('group_id != group_parent_id'),
756 {'extend_existing': True, 'mysql_engine': 'InnoDB',
760 {'extend_existing': True, 'mysql_engine': 'InnoDB',
757 'mysql_charset': 'utf8'},
761 'mysql_charset': 'utf8'},
758 )
762 )
759 __mapper_args__ = {'order_by': 'group_name'}
763 __mapper_args__ = {'order_by': 'group_name'}
760
764
761 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
765 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
762 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
766 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
763 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
767 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
764 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
768 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
765
769
766 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
770 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
767 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
771 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
768
772
769 parent_group = relationship('RepoGroup', remote_side=group_id)
773 parent_group = relationship('RepoGroup', remote_side=group_id)
770
774
771 def __init__(self, group_name='', parent_group=None):
775 def __init__(self, group_name='', parent_group=None):
772 self.group_name = group_name
776 self.group_name = group_name
773 self.parent_group = parent_group
777 self.parent_group = parent_group
774
778
775 def __unicode__(self):
779 def __unicode__(self):
776 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
780 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
777 self.group_name)
781 self.group_name)
778
782
779 @classmethod
783 @classmethod
780 def groups_choices(cls):
784 def groups_choices(cls):
781 from webhelpers.html import literal as _literal
785 from webhelpers.html import literal as _literal
782 repo_groups = [('', '')]
786 repo_groups = [('', '')]
783 sep = ' &raquo; '
787 sep = ' &raquo; '
784 _name = lambda k: _literal(sep.join(k))
788 _name = lambda k: _literal(sep.join(k))
785
789
786 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
790 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
787 for x in cls.query().all()])
791 for x in cls.query().all()])
788
792
789 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
793 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
790 return repo_groups
794 return repo_groups
791
795
792 @classmethod
796 @classmethod
793 def url_sep(cls):
797 def url_sep(cls):
794 return URL_SEP
798 return URL_SEP
795
799
796 @classmethod
800 @classmethod
797 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
801 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
798 if case_insensitive:
802 if case_insensitive:
799 gr = cls.query()\
803 gr = cls.query()\
800 .filter(cls.group_name.ilike(group_name))
804 .filter(cls.group_name.ilike(group_name))
801 else:
805 else:
802 gr = cls.query()\
806 gr = cls.query()\
803 .filter(cls.group_name == group_name)
807 .filter(cls.group_name == group_name)
804 if cache:
808 if cache:
805 gr = gr.options(FromCache(
809 gr = gr.options(FromCache(
806 "sql_cache_short",
810 "sql_cache_short",
807 "get_group_%s" % _hash_key(group_name)
811 "get_group_%s" % _hash_key(group_name)
808 )
812 )
809 )
813 )
810 return gr.scalar()
814 return gr.scalar()
811
815
812 @property
816 @property
813 def parents(self):
817 def parents(self):
814 parents_recursion_limit = 5
818 parents_recursion_limit = 5
815 groups = []
819 groups = []
816 if self.parent_group is None:
820 if self.parent_group is None:
817 return groups
821 return groups
818 cur_gr = self.parent_group
822 cur_gr = self.parent_group
819 groups.insert(0, cur_gr)
823 groups.insert(0, cur_gr)
820 cnt = 0
824 cnt = 0
821 while 1:
825 while 1:
822 cnt += 1
826 cnt += 1
823 gr = getattr(cur_gr, 'parent_group', None)
827 gr = getattr(cur_gr, 'parent_group', None)
824 cur_gr = cur_gr.parent_group
828 cur_gr = cur_gr.parent_group
825 if gr is None:
829 if gr is None:
826 break
830 break
827 if cnt == parents_recursion_limit:
831 if cnt == parents_recursion_limit:
828 # this will prevent accidental infinit loops
832 # this will prevent accidental infinit loops
829 log.error('group nested more than %s' %
833 log.error('group nested more than %s' %
830 parents_recursion_limit)
834 parents_recursion_limit)
831 break
835 break
832
836
833 groups.insert(0, gr)
837 groups.insert(0, gr)
834 return groups
838 return groups
835
839
836 @property
840 @property
837 def children(self):
841 def children(self):
838 return RepoGroup.query().filter(RepoGroup.parent_group == self)
842 return RepoGroup.query().filter(RepoGroup.parent_group == self)
839
843
840 @property
844 @property
841 def name(self):
845 def name(self):
842 return self.group_name.split(RepoGroup.url_sep())[-1]
846 return self.group_name.split(RepoGroup.url_sep())[-1]
843
847
844 @property
848 @property
845 def full_path(self):
849 def full_path(self):
846 return self.group_name
850 return self.group_name
847
851
848 @property
852 @property
849 def full_path_splitted(self):
853 def full_path_splitted(self):
850 return self.group_name.split(RepoGroup.url_sep())
854 return self.group_name.split(RepoGroup.url_sep())
851
855
852 @property
856 @property
853 def repositories(self):
857 def repositories(self):
854 return Repository.query()\
858 return Repository.query()\
855 .filter(Repository.group == self)\
859 .filter(Repository.group == self)\
856 .order_by(Repository.repo_name)
860 .order_by(Repository.repo_name)
857
861
858 @property
862 @property
859 def repositories_recursive_count(self):
863 def repositories_recursive_count(self):
860 cnt = self.repositories.count()
864 cnt = self.repositories.count()
861
865
862 def children_count(group):
866 def children_count(group):
863 cnt = 0
867 cnt = 0
864 for child in group.children:
868 for child in group.children:
865 cnt += child.repositories.count()
869 cnt += child.repositories.count()
866 cnt += children_count(child)
870 cnt += children_count(child)
867 return cnt
871 return cnt
868
872
869 return cnt + children_count(self)
873 return cnt + children_count(self)
870
874
871 def get_new_name(self, group_name):
875 def get_new_name(self, group_name):
872 """
876 """
873 returns new full group name based on parent and new name
877 returns new full group name based on parent and new name
874
878
875 :param group_name:
879 :param group_name:
876 """
880 """
877 path_prefix = (self.parent_group.full_path_splitted if
881 path_prefix = (self.parent_group.full_path_splitted if
878 self.parent_group else [])
882 self.parent_group else [])
879 return RepoGroup.url_sep().join(path_prefix + [group_name])
883 return RepoGroup.url_sep().join(path_prefix + [group_name])
880
884
881
885
882 class Permission(Base, BaseModel):
886 class Permission(Base, BaseModel):
883 __tablename__ = 'permissions'
887 __tablename__ = 'permissions'
884 __table_args__ = (
888 __table_args__ = (
885 {'extend_existing': True, 'mysql_engine': 'InnoDB',
889 {'extend_existing': True, 'mysql_engine': 'InnoDB',
886 'mysql_charset': 'utf8'},
890 'mysql_charset': 'utf8'},
887 )
891 )
888 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
892 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
889 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
893 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
890 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
894 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
891
895
892 def __unicode__(self):
896 def __unicode__(self):
893 return u"<%s('%s:%s')>" % (
897 return u"<%s('%s:%s')>" % (
894 self.__class__.__name__, self.permission_id, self.permission_name
898 self.__class__.__name__, self.permission_id, self.permission_name
895 )
899 )
896
900
897 @classmethod
901 @classmethod
898 def get_by_key(cls, key):
902 def get_by_key(cls, key):
899 return cls.query().filter(cls.permission_name == key).scalar()
903 return cls.query().filter(cls.permission_name == key).scalar()
900
904
901 @classmethod
905 @classmethod
902 def get_default_perms(cls, default_user_id):
906 def get_default_perms(cls, default_user_id):
903 q = Session.query(UserRepoToPerm, Repository, cls)\
907 q = Session.query(UserRepoToPerm, Repository, cls)\
904 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
908 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
905 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
909 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
906 .filter(UserRepoToPerm.user_id == default_user_id)
910 .filter(UserRepoToPerm.user_id == default_user_id)
907
911
908 return q.all()
912 return q.all()
909
913
910 @classmethod
914 @classmethod
911 def get_default_group_perms(cls, default_user_id):
915 def get_default_group_perms(cls, default_user_id):
912 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
916 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
913 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
917 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
914 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
918 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
915 .filter(UserRepoGroupToPerm.user_id == default_user_id)
919 .filter(UserRepoGroupToPerm.user_id == default_user_id)
916
920
917 return q.all()
921 return q.all()
918
922
919
923
920 class UserRepoToPerm(Base, BaseModel):
924 class UserRepoToPerm(Base, BaseModel):
921 __tablename__ = 'repo_to_perm'
925 __tablename__ = 'repo_to_perm'
922 __table_args__ = (
926 __table_args__ = (
923 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
927 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
924 {'extend_existing': True, 'mysql_engine': 'InnoDB',
928 {'extend_existing': True, 'mysql_engine': 'InnoDB',
925 'mysql_charset': 'utf8'}
929 'mysql_charset': 'utf8'}
926 )
930 )
927 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
931 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
928 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
932 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
929 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
933 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
930 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
934 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
931
935
932 user = relationship('User')
936 user = relationship('User')
933 repository = relationship('Repository')
937 repository = relationship('Repository')
934 permission = relationship('Permission')
938 permission = relationship('Permission')
935
939
936 @classmethod
940 @classmethod
937 def create(cls, user, repository, permission):
941 def create(cls, user, repository, permission):
938 n = cls()
942 n = cls()
939 n.user = user
943 n.user = user
940 n.repository = repository
944 n.repository = repository
941 n.permission = permission
945 n.permission = permission
942 Session.add(n)
946 Session.add(n)
943 return n
947 return n
944
948
945 def __unicode__(self):
949 def __unicode__(self):
946 return u'<user:%s => %s >' % (self.user, self.repository)
950 return u'<user:%s => %s >' % (self.user, self.repository)
947
951
948
952
949 class UserToPerm(Base, BaseModel):
953 class UserToPerm(Base, BaseModel):
950 __tablename__ = 'user_to_perm'
954 __tablename__ = 'user_to_perm'
951 __table_args__ = (
955 __table_args__ = (
952 UniqueConstraint('user_id', 'permission_id'),
956 UniqueConstraint('user_id', 'permission_id'),
953 {'extend_existing': True, 'mysql_engine': 'InnoDB',
957 {'extend_existing': True, 'mysql_engine': 'InnoDB',
954 'mysql_charset': 'utf8'}
958 'mysql_charset': 'utf8'}
955 )
959 )
956 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
960 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
957 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
961 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
958 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
962 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
959
963
960 user = relationship('User')
964 user = relationship('User')
961 permission = relationship('Permission', lazy='joined')
965 permission = relationship('Permission', lazy='joined')
962
966
963
967
964 class UsersGroupRepoToPerm(Base, BaseModel):
968 class UsersGroupRepoToPerm(Base, BaseModel):
965 __tablename__ = 'users_group_repo_to_perm'
969 __tablename__ = 'users_group_repo_to_perm'
966 __table_args__ = (
970 __table_args__ = (
967 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
971 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
968 {'extend_existing': True, 'mysql_engine': 'InnoDB',
972 {'extend_existing': True, 'mysql_engine': 'InnoDB',
969 'mysql_charset': 'utf8'}
973 'mysql_charset': 'utf8'}
970 )
974 )
971 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
975 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
972 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
976 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
973 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
977 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
974 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
978 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
975
979
976 users_group = relationship('UsersGroup')
980 users_group = relationship('UsersGroup')
977 permission = relationship('Permission')
981 permission = relationship('Permission')
978 repository = relationship('Repository')
982 repository = relationship('Repository')
979
983
980 @classmethod
984 @classmethod
981 def create(cls, users_group, repository, permission):
985 def create(cls, users_group, repository, permission):
982 n = cls()
986 n = cls()
983 n.users_group = users_group
987 n.users_group = users_group
984 n.repository = repository
988 n.repository = repository
985 n.permission = permission
989 n.permission = permission
986 Session.add(n)
990 Session.add(n)
987 return n
991 return n
988
992
989 def __unicode__(self):
993 def __unicode__(self):
990 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
994 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
991
995
992
996
993 class UsersGroupToPerm(Base, BaseModel):
997 class UsersGroupToPerm(Base, BaseModel):
994 __tablename__ = 'users_group_to_perm'
998 __tablename__ = 'users_group_to_perm'
995 __table_args__ = (
999 __table_args__ = (
996 UniqueConstraint('users_group_id', 'permission_id',),
1000 UniqueConstraint('users_group_id', 'permission_id',),
997 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1001 {'extend_existing': True, 'mysql_engine': 'InnoDB',
998 'mysql_charset': 'utf8'}
1002 'mysql_charset': 'utf8'}
999 )
1003 )
1000 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1004 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1001 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1005 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1002 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1006 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1003
1007
1004 users_group = relationship('UsersGroup')
1008 users_group = relationship('UsersGroup')
1005 permission = relationship('Permission')
1009 permission = relationship('Permission')
1006
1010
1007
1011
1008 class UserRepoGroupToPerm(Base, BaseModel):
1012 class UserRepoGroupToPerm(Base, BaseModel):
1009 __tablename__ = 'user_repo_group_to_perm'
1013 __tablename__ = 'user_repo_group_to_perm'
1010 __table_args__ = (
1014 __table_args__ = (
1011 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1015 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1012 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1016 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1013 'mysql_charset': 'utf8'}
1017 'mysql_charset': 'utf8'}
1014 )
1018 )
1015
1019
1016 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1020 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1017 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1021 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1018 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1022 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1019 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1023 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1020
1024
1021 user = relationship('User')
1025 user = relationship('User')
1022 group = relationship('RepoGroup')
1026 group = relationship('RepoGroup')
1023 permission = relationship('Permission')
1027 permission = relationship('Permission')
1024
1028
1025
1029
1026 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1030 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1027 __tablename__ = 'users_group_repo_group_to_perm'
1031 __tablename__ = 'users_group_repo_group_to_perm'
1028 __table_args__ = (
1032 __table_args__ = (
1029 UniqueConstraint('users_group_id', 'group_id'),
1033 UniqueConstraint('users_group_id', 'group_id'),
1030 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1034 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1031 'mysql_charset': 'utf8'}
1035 'mysql_charset': 'utf8'}
1032 )
1036 )
1033
1037
1034 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1038 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1035 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1039 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1036 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1040 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1037 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1041 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1038
1042
1039 users_group = relationship('UsersGroup')
1043 users_group = relationship('UsersGroup')
1040 permission = relationship('Permission')
1044 permission = relationship('Permission')
1041 group = relationship('RepoGroup')
1045 group = relationship('RepoGroup')
1042
1046
1043
1047
1044 class Statistics(Base, BaseModel):
1048 class Statistics(Base, BaseModel):
1045 __tablename__ = 'statistics'
1049 __tablename__ = 'statistics'
1046 __table_args__ = (
1050 __table_args__ = (
1047 UniqueConstraint('repository_id'),
1051 UniqueConstraint('repository_id'),
1048 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1052 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1049 'mysql_charset': 'utf8'}
1053 'mysql_charset': 'utf8'}
1050 )
1054 )
1051 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1055 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1052 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1056 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1053 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1057 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1054 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1058 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1055 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1059 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1056 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1060 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1057
1061
1058 repository = relationship('Repository', single_parent=True)
1062 repository = relationship('Repository', single_parent=True)
1059
1063
1060
1064
1061 class UserFollowing(Base, BaseModel):
1065 class UserFollowing(Base, BaseModel):
1062 __tablename__ = 'user_followings'
1066 __tablename__ = 'user_followings'
1063 __table_args__ = (
1067 __table_args__ = (
1064 UniqueConstraint('user_id', 'follows_repository_id'),
1068 UniqueConstraint('user_id', 'follows_repository_id'),
1065 UniqueConstraint('user_id', 'follows_user_id'),
1069 UniqueConstraint('user_id', 'follows_user_id'),
1066 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1070 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1067 'mysql_charset': 'utf8'}
1071 'mysql_charset': 'utf8'}
1068 )
1072 )
1069
1073
1070 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1074 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1071 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1075 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1072 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1076 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1073 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1077 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1074 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1078 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1075
1079
1076 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1080 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1077
1081
1078 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1082 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1079 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1083 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1080
1084
1081 @classmethod
1085 @classmethod
1082 def get_repo_followers(cls, repo_id):
1086 def get_repo_followers(cls, repo_id):
1083 return cls.query().filter(cls.follows_repo_id == repo_id)
1087 return cls.query().filter(cls.follows_repo_id == repo_id)
1084
1088
1085
1089
1086 class CacheInvalidation(Base, BaseModel):
1090 class CacheInvalidation(Base, BaseModel):
1087 __tablename__ = 'cache_invalidation'
1091 __tablename__ = 'cache_invalidation'
1088 __table_args__ = (
1092 __table_args__ = (
1089 UniqueConstraint('cache_key'),
1093 UniqueConstraint('cache_key'),
1090 Index('key_idx', 'cache_key'),
1094 Index('key_idx', 'cache_key'),
1091 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1095 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1092 'mysql_charset': 'utf8'},
1096 'mysql_charset': 'utf8'},
1093 )
1097 )
1094 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1098 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1095 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1099 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1096 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1100 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1097 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1101 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1098
1102
1099 def __init__(self, cache_key, cache_args=''):
1103 def __init__(self, cache_key, cache_args=''):
1100 self.cache_key = cache_key
1104 self.cache_key = cache_key
1101 self.cache_args = cache_args
1105 self.cache_args = cache_args
1102 self.cache_active = False
1106 self.cache_active = False
1103
1107
1104 def __unicode__(self):
1108 def __unicode__(self):
1105 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1109 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1106 self.cache_id, self.cache_key)
1110 self.cache_id, self.cache_key)
1107
1111
1108 @classmethod
1112 @classmethod
1109 def clear_cache(cls):
1113 def clear_cache(cls):
1110 cls.query().delete()
1114 cls.query().delete()
1111
1115
1112 @classmethod
1116 @classmethod
1113 def _get_key(cls, key):
1117 def _get_key(cls, key):
1114 """
1118 """
1115 Wrapper for generating a key, together with a prefix
1119 Wrapper for generating a key, together with a prefix
1116
1120
1117 :param key:
1121 :param key:
1118 """
1122 """
1119 import rhodecode
1123 import rhodecode
1120 prefix = ''
1124 prefix = ''
1121 iid = rhodecode.CONFIG.get('instance_id')
1125 iid = rhodecode.CONFIG.get('instance_id')
1122 if iid:
1126 if iid:
1123 prefix = iid
1127 prefix = iid
1124 return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
1128 return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
1125
1129
1126 @classmethod
1130 @classmethod
1127 def get_by_key(cls, key):
1131 def get_by_key(cls, key):
1128 return cls.query().filter(cls.cache_key == key).scalar()
1132 return cls.query().filter(cls.cache_key == key).scalar()
1129
1133
1130 @classmethod
1134 @classmethod
1131 def _get_or_create_key(cls, key, prefix, org_key):
1135 def _get_or_create_key(cls, key, prefix, org_key):
1132 inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
1136 inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
1133 if not inv_obj:
1137 if not inv_obj:
1134 try:
1138 try:
1135 inv_obj = CacheInvalidation(key, org_key)
1139 inv_obj = CacheInvalidation(key, org_key)
1136 Session.add(inv_obj)
1140 Session.add(inv_obj)
1137 Session.commit()
1141 Session.commit()
1138 except Exception:
1142 except Exception:
1139 log.error(traceback.format_exc())
1143 log.error(traceback.format_exc())
1140 Session.rollback()
1144 Session.rollback()
1141 return inv_obj
1145 return inv_obj
1142
1146
1143 @classmethod
1147 @classmethod
1144 def invalidate(cls, key):
1148 def invalidate(cls, key):
1145 """
1149 """
1146 Returns Invalidation object if this given key should be invalidated
1150 Returns Invalidation object if this given key should be invalidated
1147 None otherwise. `cache_active = False` means that this cache
1151 None otherwise. `cache_active = False` means that this cache
1148 state is not valid and needs to be invalidated
1152 state is not valid and needs to be invalidated
1149
1153
1150 :param key:
1154 :param key:
1151 """
1155 """
1152
1156
1153 key, _prefix, _org_key = cls._get_key(key)
1157 key, _prefix, _org_key = cls._get_key(key)
1154 inv = cls._get_or_create_key(key, _prefix, _org_key)
1158 inv = cls._get_or_create_key(key, _prefix, _org_key)
1155
1159
1156 if inv and inv.cache_active is False:
1160 if inv and inv.cache_active is False:
1157 return inv
1161 return inv
1158
1162
1159 @classmethod
1163 @classmethod
1160 def set_invalidate(cls, key):
1164 def set_invalidate(cls, key):
1161 """
1165 """
1162 Mark this Cache key for invalidation
1166 Mark this Cache key for invalidation
1163
1167
1164 :param key:
1168 :param key:
1165 """
1169 """
1166
1170
1167 key, _prefix, _org_key = cls._get_key(key)
1171 key, _prefix, _org_key = cls._get_key(key)
1168 inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
1172 inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
1169 log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs),
1173 log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs),
1170 _org_key))
1174 _org_key))
1171 try:
1175 try:
1172 for inv_obj in inv_objs:
1176 for inv_obj in inv_objs:
1173 if inv_obj:
1177 if inv_obj:
1174 inv_obj.cache_active = False
1178 inv_obj.cache_active = False
1175
1179
1176 Session.add(inv_obj)
1180 Session.add(inv_obj)
1177 Session.commit()
1181 Session.commit()
1178 except Exception:
1182 except Exception:
1179 log.error(traceback.format_exc())
1183 log.error(traceback.format_exc())
1180 Session.rollback()
1184 Session.rollback()
1181
1185
1182 @classmethod
1186 @classmethod
1183 def set_valid(cls, key):
1187 def set_valid(cls, key):
1184 """
1188 """
1185 Mark this cache key as active and currently cached
1189 Mark this cache key as active and currently cached
1186
1190
1187 :param key:
1191 :param key:
1188 """
1192 """
1189 inv_obj = cls.get_by_key(key)
1193 inv_obj = cls.get_by_key(key)
1190 inv_obj.cache_active = True
1194 inv_obj.cache_active = True
1191 Session.add(inv_obj)
1195 Session.add(inv_obj)
1192 Session.commit()
1196 Session.commit()
1193
1197
1194 @classmethod
1198 @classmethod
1195 def get_cache_map(cls):
1199 def get_cache_map(cls):
1196
1200
1197 class cachemapdict(dict):
1201 class cachemapdict(dict):
1198
1202
1199 def __init__(self, *args, **kwargs):
1203 def __init__(self, *args, **kwargs):
1200 fixkey = kwargs.get('fixkey')
1204 fixkey = kwargs.get('fixkey')
1201 if fixkey:
1205 if fixkey:
1202 del kwargs['fixkey']
1206 del kwargs['fixkey']
1203 self.fixkey = fixkey
1207 self.fixkey = fixkey
1204 super(cachemapdict, self).__init__(*args, **kwargs)
1208 super(cachemapdict, self).__init__(*args, **kwargs)
1205
1209
1206 def __getattr__(self, name):
1210 def __getattr__(self, name):
1207 key = name
1211 key = name
1208 if self.fixkey:
1212 if self.fixkey:
1209 key, _prefix, _org_key = cls._get_key(key)
1213 key, _prefix, _org_key = cls._get_key(key)
1210 if key in self.__dict__:
1214 if key in self.__dict__:
1211 return self.__dict__[key]
1215 return self.__dict__[key]
1212 else:
1216 else:
1213 return self[key]
1217 return self[key]
1214
1218
1215 def __getitem__(self, key):
1219 def __getitem__(self, key):
1216 if self.fixkey:
1220 if self.fixkey:
1217 key, _prefix, _org_key = cls._get_key(key)
1221 key, _prefix, _org_key = cls._get_key(key)
1218 try:
1222 try:
1219 return super(cachemapdict, self).__getitem__(key)
1223 return super(cachemapdict, self).__getitem__(key)
1220 except KeyError:
1224 except KeyError:
1221 return
1225 return
1222
1226
1223 cache_map = cachemapdict(fixkey=True)
1227 cache_map = cachemapdict(fixkey=True)
1224 for obj in cls.query().all():
1228 for obj in cls.query().all():
1225 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1229 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1226 return cache_map
1230 return cache_map
1227
1231
1228
1232
1229 class ChangesetComment(Base, BaseModel):
1233 class ChangesetComment(Base, BaseModel):
1230 __tablename__ = 'changeset_comments'
1234 __tablename__ = 'changeset_comments'
1231 __table_args__ = (
1235 __table_args__ = (
1232 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1236 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1233 'mysql_charset': 'utf8'},
1237 'mysql_charset': 'utf8'},
1234 )
1238 )
1235 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1239 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1236 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1240 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1237 revision = Column('revision', String(40), nullable=False)
1241 revision = Column('revision', String(40), nullable=False)
1238 line_no = Column('line_no', Unicode(10), nullable=True)
1242 line_no = Column('line_no', Unicode(10), nullable=True)
1239 f_path = Column('f_path', Unicode(1000), nullable=True)
1243 f_path = Column('f_path', Unicode(1000), nullable=True)
1240 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1244 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1241 text = Column('text', Unicode(25000), nullable=False)
1245 text = Column('text', Unicode(25000), nullable=False)
1242 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1246 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1243
1247
1244 author = relationship('User', lazy='joined')
1248 author = relationship('User', lazy='joined')
1245 repo = relationship('Repository')
1249 repo = relationship('Repository')
1246
1250
1247 @classmethod
1251 @classmethod
1248 def get_users(cls, revision):
1252 def get_users(cls, revision):
1249 """
1253 """
1250 Returns user associated with this changesetComment. ie those
1254 Returns user associated with this changesetComment. ie those
1251 who actually commented
1255 who actually commented
1252
1256
1253 :param cls:
1257 :param cls:
1254 :param revision:
1258 :param revision:
1255 """
1259 """
1256 return Session.query(User)\
1260 return Session.query(User)\
1257 .filter(cls.revision == revision)\
1261 .filter(cls.revision == revision)\
1258 .join(ChangesetComment.author).all()
1262 .join(ChangesetComment.author).all()
1259
1263
1260
1264
1261 class Notification(Base, BaseModel):
1265 class Notification(Base, BaseModel):
1262 __tablename__ = 'notifications'
1266 __tablename__ = 'notifications'
1263 __table_args__ = (
1267 __table_args__ = (
1264 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1268 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1265 'mysql_charset': 'utf8'},
1269 'mysql_charset': 'utf8'},
1266 )
1270 )
1267
1271
1268 TYPE_CHANGESET_COMMENT = u'cs_comment'
1272 TYPE_CHANGESET_COMMENT = u'cs_comment'
1269 TYPE_MESSAGE = u'message'
1273 TYPE_MESSAGE = u'message'
1270 TYPE_MENTION = u'mention'
1274 TYPE_MENTION = u'mention'
1271 TYPE_REGISTRATION = u'registration'
1275 TYPE_REGISTRATION = u'registration'
1272
1276
1273 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1277 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1274 subject = Column('subject', Unicode(512), nullable=True)
1278 subject = Column('subject', Unicode(512), nullable=True)
1275 body = Column('body', Unicode(50000), nullable=True)
1279 body = Column('body', Unicode(50000), nullable=True)
1276 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1280 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1277 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1281 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1278 type_ = Column('type', Unicode(256))
1282 type_ = Column('type', Unicode(256))
1279
1283
1280 created_by_user = relationship('User')
1284 created_by_user = relationship('User')
1281 notifications_to_users = relationship('UserNotification', lazy='joined',
1285 notifications_to_users = relationship('UserNotification', lazy='joined',
1282 cascade="all, delete, delete-orphan")
1286 cascade="all, delete, delete-orphan")
1283
1287
1284 @property
1288 @property
1285 def recipients(self):
1289 def recipients(self):
1286 return [x.user for x in UserNotification.query()\
1290 return [x.user for x in UserNotification.query()\
1287 .filter(UserNotification.notification == self)\
1291 .filter(UserNotification.notification == self)\
1288 .order_by(UserNotification.user).all()]
1292 .order_by(UserNotification.user).all()]
1289
1293
1290 @classmethod
1294 @classmethod
1291 def create(cls, created_by, subject, body, recipients, type_=None):
1295 def create(cls, created_by, subject, body, recipients, type_=None):
1292 if type_ is None:
1296 if type_ is None:
1293 type_ = Notification.TYPE_MESSAGE
1297 type_ = Notification.TYPE_MESSAGE
1294
1298
1295 notification = cls()
1299 notification = cls()
1296 notification.created_by_user = created_by
1300 notification.created_by_user = created_by
1297 notification.subject = subject
1301 notification.subject = subject
1298 notification.body = body
1302 notification.body = body
1299 notification.type_ = type_
1303 notification.type_ = type_
1300 notification.created_on = datetime.datetime.now()
1304 notification.created_on = datetime.datetime.now()
1301
1305
1302 for u in recipients:
1306 for u in recipients:
1303 assoc = UserNotification()
1307 assoc = UserNotification()
1304 assoc.notification = notification
1308 assoc.notification = notification
1305 u.notifications.append(assoc)
1309 u.notifications.append(assoc)
1306 Session.add(notification)
1310 Session.add(notification)
1307 return notification
1311 return notification
1308
1312
1309 @property
1313 @property
1310 def description(self):
1314 def description(self):
1311 from rhodecode.model.notification import NotificationModel
1315 from rhodecode.model.notification import NotificationModel
1312 return NotificationModel().make_description(self)
1316 return NotificationModel().make_description(self)
1313
1317
1314
1318
1315 class UserNotification(Base, BaseModel):
1319 class UserNotification(Base, BaseModel):
1316 __tablename__ = 'user_to_notification'
1320 __tablename__ = 'user_to_notification'
1317 __table_args__ = (
1321 __table_args__ = (
1318 UniqueConstraint('user_id', 'notification_id'),
1322 UniqueConstraint('user_id', 'notification_id'),
1319 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1323 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1320 'mysql_charset': 'utf8'}
1324 'mysql_charset': 'utf8'}
1321 )
1325 )
1322 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1326 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1323 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1327 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1324 read = Column('read', Boolean, default=False)
1328 read = Column('read', Boolean, default=False)
1325 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1329 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1326
1330
1327 user = relationship('User', lazy="joined")
1331 user = relationship('User', lazy="joined")
1328 notification = relationship('Notification', lazy="joined",
1332 notification = relationship('Notification', lazy="joined",
1329 order_by=lambda: Notification.created_on.desc(),)
1333 order_by=lambda: Notification.created_on.desc(),)
1330
1334
1331 def mark_as_read(self):
1335 def mark_as_read(self):
1332 self.read = True
1336 self.read = True
1333 Session.add(self)
1337 Session.add(self)
1334
1338
1335
1339
1336 class DbMigrateVersion(Base, BaseModel):
1340 class DbMigrateVersion(Base, BaseModel):
1337 __tablename__ = 'db_migrate_version'
1341 __tablename__ = 'db_migrate_version'
1338 __table_args__ = (
1342 __table_args__ = (
1339 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1343 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1340 'mysql_charset': 'utf8'},
1344 'mysql_charset': 'utf8'},
1341 )
1345 )
1342 repository_id = Column('repository_id', String(250), primary_key=True)
1346 repository_id = Column('repository_id', String(250), primary_key=True)
1343 repository_path = Column('repository_path', Text)
1347 repository_path = Column('repository_path', Text)
1344 version = Column('version', Integer)
1348 version = Column('version', Integer)
General Comments 0
You need to be logged in to leave comments. Login now