##// END OF EJS Templates
fixed saving settings on repositories inside groups, also fixes #187...
marcink -
r1323:a7a772ea beta
parent child Browse files
Show More
@@ -1,415 +1,415 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos
3 rhodecode.controllers.admin.repos
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Admin controller for RhodeCode
6 Admin controller for RhodeCode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 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 from operator import itemgetter
29 from operator import itemgetter
30 from formencode import htmlfill
30 from formencode import htmlfill
31
31
32 from paste.httpexceptions import HTTPInternalServerError
32 from paste.httpexceptions import HTTPInternalServerError
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34 from pylons.controllers.util import abort, redirect
34 from pylons.controllers.util import abort, redirect
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36
36
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 HasPermissionAnyDecorator
39 HasPermissionAnyDecorator
40 from rhodecode.lib.base import BaseController, render
40 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
41 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
42 from rhodecode.lib.helpers import get_token
42 from rhodecode.lib.helpers import get_token
43 from rhodecode.model.db import User, Repository, UserFollowing, Group
43 from rhodecode.model.db import User, Repository, UserFollowing, Group
44 from rhodecode.model.forms import RepoForm
44 from rhodecode.model.forms import RepoForm
45 from rhodecode.model.scm import ScmModel
45 from rhodecode.model.scm import ScmModel
46 from rhodecode.model.repo import RepoModel
46 from rhodecode.model.repo import RepoModel
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50
51 class ReposController(BaseController):
51 class ReposController(BaseController):
52 """
52 """
53 REST Controller styled on the Atom Publishing Protocol"""
53 REST Controller styled on the Atom Publishing Protocol"""
54 # To properly map this controller, ensure your config/routing.py
54 # To properly map this controller, ensure your config/routing.py
55 # file has a resource setup:
55 # file has a resource setup:
56 # map.resource('repo', 'repos')
56 # map.resource('repo', 'repos')
57
57
58 @LoginRequired()
58 @LoginRequired()
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
60 def __before__(self):
60 def __before__(self):
61 c.admin_user = session.get('admin_user')
61 c.admin_user = session.get('admin_user')
62 c.admin_username = session.get('admin_username')
62 c.admin_username = session.get('admin_username')
63 super(ReposController, self).__before__()
63 super(ReposController, self).__before__()
64
64
65 def __load_defaults(self):
65 def __load_defaults(self):
66 repo_model = RepoModel()
66 repo_model = RepoModel()
67
67
68 c.repo_groups = [('', '')]
68 c.repo_groups = [('', '')]
69 parents_link = lambda k: h.literal('&raquo;'.join(
69 parents_link = lambda k: h.literal('&raquo;'.join(
70 map(lambda k: k.group_name,
70 map(lambda k: k.group_name,
71 k.parents + [k])
71 k.parents + [k])
72 )
72 )
73 )
73 )
74
74
75 c.repo_groups.extend([(x.group_id, parents_link(x)) for \
75 c.repo_groups.extend([(x.group_id, parents_link(x)) for \
76 x in self.sa.query(Group).all()])
76 x in self.sa.query(Group).all()])
77 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
77 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
78 c.users_array = repo_model.get_users_js()
78 c.users_array = repo_model.get_users_js()
79 c.users_groups_array = repo_model.get_users_groups_js()
79 c.users_groups_array = repo_model.get_users_groups_js()
80
80
81 def __load_data(self, repo_name=None):
81 def __load_data(self, repo_name=None):
82 """
82 """
83 Load defaults settings for edit, and update
83 Load defaults settings for edit, and update
84
84
85 :param repo_name:
85 :param repo_name:
86 """
86 """
87 self.__load_defaults()
87 self.__load_defaults()
88
88
89 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
89 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
90
90
91 repo_model = RepoModel()
91 repo_model = RepoModel()
92 c.repo_info = repo_model.get_by_repo_name(repo_name)
92 c.repo_info = repo_model.get_by_repo_name(repo_name)
93
93
94 if c.repo_info is None:
94 if c.repo_info is None:
95 h.flash(_('%s repository is not mapped to db perhaps'
95 h.flash(_('%s repository is not mapped to db perhaps'
96 ' it was created or renamed from the filesystem'
96 ' it was created or renamed from the filesystem'
97 ' please run the application again'
97 ' please run the application again'
98 ' in order to rescan repositories') % repo_name,
98 ' in order to rescan repositories') % repo_name,
99 category='error')
99 category='error')
100
100
101 return redirect(url('repos'))
101 return redirect(url('repos'))
102
102
103 c.default_user_id = User.by_username('default').user_id
103 c.default_user_id = User.by_username('default').user_id
104 c.in_public_journal = self.sa.query(UserFollowing)\
104 c.in_public_journal = self.sa.query(UserFollowing)\
105 .filter(UserFollowing.user_id == c.default_user_id)\
105 .filter(UserFollowing.user_id == c.default_user_id)\
106 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
106 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
107
107
108 if c.repo_info.stats:
108 if c.repo_info.stats:
109 last_rev = c.repo_info.stats.stat_on_revision
109 last_rev = c.repo_info.stats.stat_on_revision
110 else:
110 else:
111 last_rev = 0
111 last_rev = 0
112 c.stats_revision = last_rev
112 c.stats_revision = last_rev
113
113
114 c.repo_last_rev = repo.count() - 1 if repo.revisions else 0
114 c.repo_last_rev = repo.count() - 1 if repo.revisions else 0
115
115
116 if last_rev == 0 or c.repo_last_rev == 0:
116 if last_rev == 0 or c.repo_last_rev == 0:
117 c.stats_percentage = 0
117 c.stats_percentage = 0
118 else:
118 else:
119 c.stats_percentage = '%.2f' % ((float((last_rev)) /
119 c.stats_percentage = '%.2f' % ((float((last_rev)) /
120 c.repo_last_rev) * 100)
120 c.repo_last_rev) * 100)
121
121
122 defaults = c.repo_info.get_dict()
122 defaults = c.repo_info.get_dict()
123 group, repo_name = c.repo_info.groups_and_repo
123 group, repo_name = c.repo_info.groups_and_repo
124 defaults['repo_name'] = repo_name
124 defaults['repo_name'] = repo_name
125 defaults['repo_group'] = getattr(group[-1] if group else None,
125 defaults['repo_group'] = getattr(group[-1] if group else None,
126 'group_id', None)
126 'group_id', None)
127
127
128 #fill owner
128 #fill owner
129 if c.repo_info.user:
129 if c.repo_info.user:
130 defaults.update({'user': c.repo_info.user.username})
130 defaults.update({'user': c.repo_info.user.username})
131 else:
131 else:
132 replacement_user = self.sa.query(User)\
132 replacement_user = self.sa.query(User)\
133 .filter(User.admin == True).first().username
133 .filter(User.admin == True).first().username
134 defaults.update({'user': replacement_user})
134 defaults.update({'user': replacement_user})
135
135
136 #fill repository users
136 #fill repository users
137 for p in c.repo_info.repo_to_perm:
137 for p in c.repo_info.repo_to_perm:
138 defaults.update({'u_perm_%s' % p.user.username:
138 defaults.update({'u_perm_%s' % p.user.username:
139 p.permission.permission_name})
139 p.permission.permission_name})
140
140
141 #fill repository groups
141 #fill repository groups
142 for p in c.repo_info.users_group_to_perm:
142 for p in c.repo_info.users_group_to_perm:
143 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
143 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
144 p.permission.permission_name})
144 p.permission.permission_name})
145
145
146 return defaults
146 return defaults
147
147
148 @HasPermissionAllDecorator('hg.admin')
148 @HasPermissionAllDecorator('hg.admin')
149 def index(self, format='html'):
149 def index(self, format='html'):
150 """GET /repos: All items in the collection"""
150 """GET /repos: All items in the collection"""
151 # url('repos')
151 # url('repos')
152 cached_repo_list = ScmModel().get_repos()
152 cached_repo_list = ScmModel().get_repos()
153 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
153 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
154 return render('admin/repos/repos.html')
154 return render('admin/repos/repos.html')
155
155
156 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
156 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
157 def create(self):
157 def create(self):
158 """
158 """
159 POST /repos: Create a new item"""
159 POST /repos: Create a new item"""
160 # url('repos')
160 # url('repos')
161 repo_model = RepoModel()
161 repo_model = RepoModel()
162 self.__load_defaults()
162 self.__load_defaults()
163 form_result = {}
163 form_result = {}
164 try:
164 try:
165 form_result = RepoForm(repo_groups=c.repo_groups_choices)()\
165 form_result = RepoForm(repo_groups=c.repo_groups_choices)()\
166 .to_python(dict(request.POST))
166 .to_python(dict(request.POST))
167 repo_model.create(form_result, self.rhodecode_user)
167 repo_model.create(form_result, self.rhodecode_user)
168 if form_result['clone_uri']:
168 if form_result['clone_uri']:
169 h.flash(_('created repository %s from %s') \
169 h.flash(_('created repository %s from %s') \
170 % (form_result['repo_name'], form_result['clone_uri']),
170 % (form_result['repo_name'], form_result['clone_uri']),
171 category='success')
171 category='success')
172 else:
172 else:
173 h.flash(_('created repository %s') % form_result['repo_name'],
173 h.flash(_('created repository %s') % form_result['repo_name'],
174 category='success')
174 category='success')
175
175
176 if request.POST.get('user_created'):
176 if request.POST.get('user_created'):
177 action_logger(self.rhodecode_user, 'user_created_repo',
177 action_logger(self.rhodecode_user, 'user_created_repo',
178 form_result['repo_name'], '', self.sa)
178 form_result['repo_name'], '', self.sa)
179 else:
179 else:
180 action_logger(self.rhodecode_user, 'admin_created_repo',
180 action_logger(self.rhodecode_user, 'admin_created_repo',
181 form_result['repo_name'], '', self.sa)
181 form_result['repo_name'], '', self.sa)
182
182
183 except formencode.Invalid, errors:
183 except formencode.Invalid, errors:
184
184
185 c.new_repo = errors.value['repo_name']
185 c.new_repo = errors.value['repo_name']
186
186
187 if request.POST.get('user_created'):
187 if request.POST.get('user_created'):
188 r = render('admin/repos/repo_add_create_repository.html')
188 r = render('admin/repos/repo_add_create_repository.html')
189 else:
189 else:
190 r = render('admin/repos/repo_add.html')
190 r = render('admin/repos/repo_add.html')
191
191
192 return htmlfill.render(
192 return htmlfill.render(
193 r,
193 r,
194 defaults=errors.value,
194 defaults=errors.value,
195 errors=errors.error_dict or {},
195 errors=errors.error_dict or {},
196 prefix_error=False,
196 prefix_error=False,
197 encoding="UTF-8")
197 encoding="UTF-8")
198
198
199 except Exception:
199 except Exception:
200 log.error(traceback.format_exc())
200 log.error(traceback.format_exc())
201 msg = _('error occurred during creation of repository %s') \
201 msg = _('error occurred during creation of repository %s') \
202 % form_result.get('repo_name')
202 % form_result.get('repo_name')
203 h.flash(msg, category='error')
203 h.flash(msg, category='error')
204 if request.POST.get('user_created'):
204 if request.POST.get('user_created'):
205 return redirect(url('home'))
205 return redirect(url('home'))
206 return redirect(url('repos'))
206 return redirect(url('repos'))
207
207
208 @HasPermissionAllDecorator('hg.admin')
208 @HasPermissionAllDecorator('hg.admin')
209 def new(self, format='html'):
209 def new(self, format='html'):
210 """GET /repos/new: Form to create a new item"""
210 """GET /repos/new: Form to create a new item"""
211 new_repo = request.GET.get('repo', '')
211 new_repo = request.GET.get('repo', '')
212 c.new_repo = repo_name_slug(new_repo)
212 c.new_repo = repo_name_slug(new_repo)
213 self.__load_defaults()
213 self.__load_defaults()
214 return render('admin/repos/repo_add.html')
214 return render('admin/repos/repo_add.html')
215
215
216 @HasPermissionAllDecorator('hg.admin')
216 @HasPermissionAllDecorator('hg.admin')
217 def update(self, repo_name):
217 def update(self, repo_name):
218 """
218 """
219 PUT /repos/repo_name: Update an existing item"""
219 PUT /repos/repo_name: Update an existing item"""
220 # Forms posted to this method should contain a hidden field:
220 # Forms posted to this method should contain a hidden field:
221 # <input type="hidden" name="_method" value="PUT" />
221 # <input type="hidden" name="_method" value="PUT" />
222 # Or using helpers:
222 # Or using helpers:
223 # h.form(url('repo', repo_name=ID),
223 # h.form(url('repo', repo_name=ID),
224 # method='put')
224 # method='put')
225 # url('repo', repo_name=ID)
225 # url('repo', repo_name=ID)
226 self.__load_defaults()
226 self.__load_defaults()
227 repo_model = RepoModel()
227 repo_model = RepoModel()
228 changed_name = repo_name
228 changed_name = repo_name
229 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
229 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
230 repo_groups=c.repo_groups_choices)()
230 repo_groups=c.repo_groups_choices)()
231 try:
231 try:
232 form_result = _form.to_python(dict(request.POST))
232 form_result = _form.to_python(dict(request.POST))
233 repo_model.update(repo_name, form_result)
233 repo_model.update(repo_name, form_result)
234 invalidate_cache('get_repo_cached_%s' % repo_name)
234 invalidate_cache('get_repo_cached_%s' % repo_name)
235 h.flash(_('Repository %s updated successfully' % repo_name),
235 h.flash(_('Repository %s updated successfully' % repo_name),
236 category='success')
236 category='success')
237 changed_name = form_result['repo_name']
237 changed_name = form_result['repo_name_full']
238 action_logger(self.rhodecode_user, 'admin_updated_repo',
238 action_logger(self.rhodecode_user, 'admin_updated_repo',
239 changed_name, '', self.sa)
239 changed_name, '', self.sa)
240
240
241 except formencode.Invalid, errors:
241 except formencode.Invalid, errors:
242 defaults = self.__load_data(repo_name)
242 defaults = self.__load_data(repo_name)
243 defaults.update(errors.value)
243 defaults.update(errors.value)
244 return htmlfill.render(
244 return htmlfill.render(
245 render('admin/repos/repo_edit.html'),
245 render('admin/repos/repo_edit.html'),
246 defaults=defaults,
246 defaults=defaults,
247 errors=errors.error_dict or {},
247 errors=errors.error_dict or {},
248 prefix_error=False,
248 prefix_error=False,
249 encoding="UTF-8")
249 encoding="UTF-8")
250
250
251 except Exception:
251 except Exception:
252 log.error(traceback.format_exc())
252 log.error(traceback.format_exc())
253 h.flash(_('error occurred during update of repository %s') \
253 h.flash(_('error occurred during update of repository %s') \
254 % repo_name, category='error')
254 % repo_name, category='error')
255 return redirect(url('edit_repo', repo_name=changed_name))
255 return redirect(url('edit_repo', repo_name=changed_name))
256
256
257 @HasPermissionAllDecorator('hg.admin')
257 @HasPermissionAllDecorator('hg.admin')
258 def delete(self, repo_name):
258 def delete(self, repo_name):
259 """
259 """
260 DELETE /repos/repo_name: Delete an existing item"""
260 DELETE /repos/repo_name: Delete an existing item"""
261 # Forms posted to this method should contain a hidden field:
261 # Forms posted to this method should contain a hidden field:
262 # <input type="hidden" name="_method" value="DELETE" />
262 # <input type="hidden" name="_method" value="DELETE" />
263 # Or using helpers:
263 # Or using helpers:
264 # h.form(url('repo', repo_name=ID),
264 # h.form(url('repo', repo_name=ID),
265 # method='delete')
265 # method='delete')
266 # url('repo', repo_name=ID)
266 # url('repo', repo_name=ID)
267
267
268 repo_model = RepoModel()
268 repo_model = RepoModel()
269 repo = repo_model.get_by_repo_name(repo_name)
269 repo = repo_model.get_by_repo_name(repo_name)
270 if not repo:
270 if not repo:
271 h.flash(_('%s repository is not mapped to db perhaps'
271 h.flash(_('%s repository is not mapped to db perhaps'
272 ' it was moved or renamed from the filesystem'
272 ' it was moved or renamed from the filesystem'
273 ' please run the application again'
273 ' please run the application again'
274 ' in order to rescan repositories') % repo_name,
274 ' in order to rescan repositories') % repo_name,
275 category='error')
275 category='error')
276
276
277 return redirect(url('repos'))
277 return redirect(url('repos'))
278 try:
278 try:
279 action_logger(self.rhodecode_user, 'admin_deleted_repo',
279 action_logger(self.rhodecode_user, 'admin_deleted_repo',
280 repo_name, '', self.sa)
280 repo_name, '', self.sa)
281 repo_model.delete(repo)
281 repo_model.delete(repo)
282 invalidate_cache('get_repo_cached_%s' % repo_name)
282 invalidate_cache('get_repo_cached_%s' % repo_name)
283 h.flash(_('deleted repository %s') % repo_name, category='success')
283 h.flash(_('deleted repository %s') % repo_name, category='success')
284
284
285 except Exception, e:
285 except Exception, e:
286 log.error(traceback.format_exc())
286 log.error(traceback.format_exc())
287 h.flash(_('An error occurred during deletion of %s') % repo_name,
287 h.flash(_('An error occurred during deletion of %s') % repo_name,
288 category='error')
288 category='error')
289
289
290 return redirect(url('repos'))
290 return redirect(url('repos'))
291
291
292 @HasPermissionAllDecorator('hg.admin')
292 @HasPermissionAllDecorator('hg.admin')
293 def delete_perm_user(self, repo_name):
293 def delete_perm_user(self, repo_name):
294 """
294 """
295 DELETE an existing repository permission user
295 DELETE an existing repository permission user
296
296
297 :param repo_name:
297 :param repo_name:
298 """
298 """
299
299
300 try:
300 try:
301 repo_model = RepoModel()
301 repo_model = RepoModel()
302 repo_model.delete_perm_user(request.POST, repo_name)
302 repo_model.delete_perm_user(request.POST, repo_name)
303 except Exception, e:
303 except Exception, e:
304 h.flash(_('An error occurred during deletion of repository user'),
304 h.flash(_('An error occurred during deletion of repository user'),
305 category='error')
305 category='error')
306 raise HTTPInternalServerError()
306 raise HTTPInternalServerError()
307
307
308 @HasPermissionAllDecorator('hg.admin')
308 @HasPermissionAllDecorator('hg.admin')
309 def delete_perm_users_group(self, repo_name):
309 def delete_perm_users_group(self, repo_name):
310 """
310 """
311 DELETE an existing repository permission users group
311 DELETE an existing repository permission users group
312
312
313 :param repo_name:
313 :param repo_name:
314 """
314 """
315 try:
315 try:
316 repo_model = RepoModel()
316 repo_model = RepoModel()
317 repo_model.delete_perm_users_group(request.POST, repo_name)
317 repo_model.delete_perm_users_group(request.POST, repo_name)
318 except Exception, e:
318 except Exception, e:
319 h.flash(_('An error occurred during deletion of repository'
319 h.flash(_('An error occurred during deletion of repository'
320 ' users groups'),
320 ' users groups'),
321 category='error')
321 category='error')
322 raise HTTPInternalServerError()
322 raise HTTPInternalServerError()
323
323
324 @HasPermissionAllDecorator('hg.admin')
324 @HasPermissionAllDecorator('hg.admin')
325 def repo_stats(self, repo_name):
325 def repo_stats(self, repo_name):
326 """
326 """
327 DELETE an existing repository statistics
327 DELETE an existing repository statistics
328
328
329 :param repo_name:
329 :param repo_name:
330 """
330 """
331
331
332 try:
332 try:
333 repo_model = RepoModel()
333 repo_model = RepoModel()
334 repo_model.delete_stats(repo_name)
334 repo_model.delete_stats(repo_name)
335 except Exception, e:
335 except Exception, e:
336 h.flash(_('An error occurred during deletion of repository stats'),
336 h.flash(_('An error occurred during deletion of repository stats'),
337 category='error')
337 category='error')
338 return redirect(url('edit_repo', repo_name=repo_name))
338 return redirect(url('edit_repo', repo_name=repo_name))
339
339
340 @HasPermissionAllDecorator('hg.admin')
340 @HasPermissionAllDecorator('hg.admin')
341 def repo_cache(self, repo_name):
341 def repo_cache(self, repo_name):
342 """
342 """
343 INVALIDATE existing repository cache
343 INVALIDATE existing repository cache
344
344
345 :param repo_name:
345 :param repo_name:
346 """
346 """
347
347
348 try:
348 try:
349 ScmModel().mark_for_invalidation(repo_name)
349 ScmModel().mark_for_invalidation(repo_name)
350 except Exception, e:
350 except Exception, e:
351 h.flash(_('An error occurred during cache invalidation'),
351 h.flash(_('An error occurred during cache invalidation'),
352 category='error')
352 category='error')
353 return redirect(url('edit_repo', repo_name=repo_name))
353 return redirect(url('edit_repo', repo_name=repo_name))
354
354
355 @HasPermissionAllDecorator('hg.admin')
355 @HasPermissionAllDecorator('hg.admin')
356 def repo_public_journal(self, repo_name):
356 def repo_public_journal(self, repo_name):
357 """
357 """
358 Set's this repository to be visible in public journal,
358 Set's this repository to be visible in public journal,
359 in other words assing default user to follow this repo
359 in other words assing default user to follow this repo
360
360
361 :param repo_name:
361 :param repo_name:
362 """
362 """
363
363
364 cur_token = request.POST.get('auth_token')
364 cur_token = request.POST.get('auth_token')
365 token = get_token()
365 token = get_token()
366 if cur_token == token:
366 if cur_token == token:
367 try:
367 try:
368 repo_id = Repository.by_repo_name(repo_name).repo_id
368 repo_id = Repository.by_repo_name(repo_name).repo_id
369 user_id = User.by_username('default').user_id
369 user_id = User.by_username('default').user_id
370 self.scm_model.toggle_following_repo(repo_id, user_id)
370 self.scm_model.toggle_following_repo(repo_id, user_id)
371 h.flash(_('Updated repository visibility in public journal'),
371 h.flash(_('Updated repository visibility in public journal'),
372 category='success')
372 category='success')
373 except:
373 except:
374 h.flash(_('An error occurred during setting this'
374 h.flash(_('An error occurred during setting this'
375 ' repository in public journal'),
375 ' repository in public journal'),
376 category='error')
376 category='error')
377
377
378 else:
378 else:
379 h.flash(_('Token mismatch'), category='error')
379 h.flash(_('Token mismatch'), category='error')
380 return redirect(url('edit_repo', repo_name=repo_name))
380 return redirect(url('edit_repo', repo_name=repo_name))
381
381
382 @HasPermissionAllDecorator('hg.admin')
382 @HasPermissionAllDecorator('hg.admin')
383 def repo_pull(self, repo_name):
383 def repo_pull(self, repo_name):
384 """
384 """
385 Runs task to update given repository with remote changes,
385 Runs task to update given repository with remote changes,
386 ie. make pull on remote location
386 ie. make pull on remote location
387
387
388 :param repo_name:
388 :param repo_name:
389 """
389 """
390 try:
390 try:
391 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
391 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
392 h.flash(_('Pulled from remote location'), category='success')
392 h.flash(_('Pulled from remote location'), category='success')
393 except Exception, e:
393 except Exception, e:
394 h.flash(_('An error occurred during pull from remote location'),
394 h.flash(_('An error occurred during pull from remote location'),
395 category='error')
395 category='error')
396
396
397 return redirect(url('edit_repo', repo_name=repo_name))
397 return redirect(url('edit_repo', repo_name=repo_name))
398
398
399 @HasPermissionAllDecorator('hg.admin')
399 @HasPermissionAllDecorator('hg.admin')
400 def show(self, repo_name, format='html'):
400 def show(self, repo_name, format='html'):
401 """GET /repos/repo_name: Show a specific item"""
401 """GET /repos/repo_name: Show a specific item"""
402 # url('repo', repo_name=ID)
402 # url('repo', repo_name=ID)
403
403
404 @HasPermissionAllDecorator('hg.admin')
404 @HasPermissionAllDecorator('hg.admin')
405 def edit(self, repo_name, format='html'):
405 def edit(self, repo_name, format='html'):
406 """GET /repos/repo_name/edit: Form to edit an existing item"""
406 """GET /repos/repo_name/edit: Form to edit an existing item"""
407 # url('edit_repo', repo_name=ID)
407 # url('edit_repo', repo_name=ID)
408 defaults = self.__load_data(repo_name)
408 defaults = self.__load_data(repo_name)
409
409
410 return htmlfill.render(
410 return htmlfill.render(
411 render('admin/repos/repo_edit.html'),
411 render('admin/repos/repo_edit.html'),
412 defaults=defaults,
412 defaults=defaults,
413 encoding="UTF-8",
413 encoding="UTF-8",
414 force_defaults=False
414 force_defaults=False
415 )
415 )
@@ -1,538 +1,544 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) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 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 from datetime import date
29 from datetime import date
30
30
31 from sqlalchemy import *
31 from sqlalchemy import *
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.orm import relationship, backref
33 from sqlalchemy.orm import relationship, backref
34 from sqlalchemy.orm.interfaces import MapperExtension
34 from sqlalchemy.orm.interfaces import MapperExtension
35
35
36 from rhodecode.lib import str2bool
36 from rhodecode.lib import str2bool
37 from rhodecode.model.meta import Base, Session
37 from rhodecode.model.meta import Base, Session
38 from rhodecode.model.caching_query import FromCache
38 from rhodecode.model.caching_query import FromCache
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42 #==============================================================================
42 #==============================================================================
43 # MAPPER EXTENSIONS
43 # MAPPER EXTENSIONS
44 #==============================================================================
44 #==============================================================================
45
45
46 class RepositoryMapper(MapperExtension):
46 class RepositoryMapper(MapperExtension):
47 def after_update(self, mapper, connection, instance):
47 def after_update(self, mapper, connection, instance):
48 pass
48 pass
49
49
50
50
51 class RhodeCodeSettings(Base):
51 class RhodeCodeSettings(Base):
52 __tablename__ = 'rhodecode_settings'
52 __tablename__ = 'rhodecode_settings'
53 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
53 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
54 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
54 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
55 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
55 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
56 app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
56 app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
57
57
58 def __init__(self, k='', v=''):
58 def __init__(self, k='', v=''):
59 self.app_settings_name = k
59 self.app_settings_name = k
60 self.app_settings_value = v
60 self.app_settings_value = v
61
61
62 def __repr__(self):
62 def __repr__(self):
63 return "<%s('%s:%s')>" % (self.__class__.__name__,
63 return "<%s('%s:%s')>" % (self.__class__.__name__,
64 self.app_settings_name, self.app_settings_value)
64 self.app_settings_name, self.app_settings_value)
65
65
66
66
67 @classmethod
67 @classmethod
68 def get_by_name(cls, ldap_key):
68 def get_by_name(cls, ldap_key):
69 return Session.query(cls)\
69 return Session.query(cls)\
70 .filter(cls.app_settings_name == ldap_key).scalar()
70 .filter(cls.app_settings_name == ldap_key).scalar()
71
71
72 @classmethod
72 @classmethod
73 def get_app_settings(cls, cache=False):
73 def get_app_settings(cls, cache=False):
74
74
75 ret = Session.query(cls)
75 ret = Session.query(cls)
76
76
77 if cache:
77 if cache:
78 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
78 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
79
79
80 if not ret:
80 if not ret:
81 raise Exception('Could not get application settings !')
81 raise Exception('Could not get application settings !')
82 settings = {}
82 settings = {}
83 for each in ret:
83 for each in ret:
84 settings['rhodecode_' + each.app_settings_name] = \
84 settings['rhodecode_' + each.app_settings_name] = \
85 each.app_settings_value
85 each.app_settings_value
86
86
87 return settings
87 return settings
88
88
89 @classmethod
89 @classmethod
90 def get_ldap_settings(cls, cache=False):
90 def get_ldap_settings(cls, cache=False):
91 ret = Session.query(cls)\
91 ret = Session.query(cls)\
92 .filter(cls.app_settings_name.startswith('ldap_'))\
92 .filter(cls.app_settings_name.startswith('ldap_'))\
93 .all()
93 .all()
94 fd = {}
94 fd = {}
95 for row in ret:
95 for row in ret:
96 fd.update({row.app_settings_name:row.app_settings_value})
96 fd.update({row.app_settings_name:row.app_settings_value})
97 return fd
97 return fd
98
98
99
99
100 class RhodeCodeUi(Base):
100 class RhodeCodeUi(Base):
101 __tablename__ = 'rhodecode_ui'
101 __tablename__ = 'rhodecode_ui'
102 __table_args__ = {'useexisting':True}
102 __table_args__ = {'useexisting':True}
103 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
103 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
104 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
104 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
105 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
105 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
106 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
106 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
107 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
107 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
108
108
109
109
110 class User(Base):
110 class User(Base):
111 __tablename__ = 'users'
111 __tablename__ = 'users'
112 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
112 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
113 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
113 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
114 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
114 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
115 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
115 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
116 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
116 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
117 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
117 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
118 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
118 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
119 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
119 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
120 email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
120 email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
121 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
121 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
122 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
122 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
123 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
123 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
124
124
125 user_log = relationship('UserLog', cascade='all')
125 user_log = relationship('UserLog', cascade='all')
126 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
126 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
127
127
128 repositories = relationship('Repository')
128 repositories = relationship('Repository')
129 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
129 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
130
130
131 group_member = relationship('UsersGroupMember', cascade='all')
131 group_member = relationship('UsersGroupMember', cascade='all')
132
132
133 @property
133 @property
134 def full_contact(self):
134 def full_contact(self):
135 return '%s %s <%s>' % (self.name, self.lastname, self.email)
135 return '%s %s <%s>' % (self.name, self.lastname, self.email)
136
136
137 @property
137 @property
138 def short_contact(self):
138 def short_contact(self):
139 return '%s %s' % (self.name, self.lastname)
139 return '%s %s' % (self.name, self.lastname)
140
140
141
141
142 @property
142 @property
143 def is_admin(self):
143 def is_admin(self):
144 return self.admin
144 return self.admin
145
145
146 def __repr__(self):
146 def __repr__(self):
147 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
147 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
148 self.user_id, self.username)
148 self.user_id, self.username)
149
149
150 @classmethod
150 @classmethod
151 def by_username(cls, username):
151 def by_username(cls, username):
152 return Session.query(cls).filter(cls.username == username).one()
152 return Session.query(cls).filter(cls.username == username).one()
153
153
154
154
155 def update_lastlogin(self):
155 def update_lastlogin(self):
156 """Update user lastlogin"""
156 """Update user lastlogin"""
157
157
158 try:
158 try:
159 session = Session.object_session(self)
159 session = Session.object_session(self)
160 self.last_login = datetime.datetime.now()
160 self.last_login = datetime.datetime.now()
161 session.add(self)
161 session.add(self)
162 session.commit()
162 session.commit()
163 log.debug('updated user %s lastlogin', self.username)
163 log.debug('updated user %s lastlogin', self.username)
164 except (DatabaseError,):
164 except (DatabaseError,):
165 session.rollback()
165 session.rollback()
166
166
167
167
168 class UserLog(Base):
168 class UserLog(Base):
169 __tablename__ = 'user_logs'
169 __tablename__ = 'user_logs'
170 __table_args__ = {'useexisting':True}
170 __table_args__ = {'useexisting':True}
171 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
171 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
172 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
172 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
173 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
173 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
174 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
174 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
175 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
175 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
176 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
176 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
177 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
177 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
178
178
179 @property
179 @property
180 def action_as_day(self):
180 def action_as_day(self):
181 return date(*self.action_date.timetuple()[:3])
181 return date(*self.action_date.timetuple()[:3])
182
182
183 user = relationship('User')
183 user = relationship('User')
184 repository = relationship('Repository')
184 repository = relationship('Repository')
185
185
186
186
187 class UsersGroup(Base):
187 class UsersGroup(Base):
188 __tablename__ = 'users_groups'
188 __tablename__ = 'users_groups'
189 __table_args__ = {'useexisting':True}
189 __table_args__ = {'useexisting':True}
190
190
191 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
191 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
192 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
192 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
193 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
193 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
194
194
195 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
195 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
196
196
197
197
198 @classmethod
198 @classmethod
199 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
199 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
200 if case_insensitive:
200 if case_insensitive:
201 gr = Session.query(cls)\
201 gr = Session.query(cls)\
202 .filter(cls.users_group_name.ilike(group_name))
202 .filter(cls.users_group_name.ilike(group_name))
203 else:
203 else:
204 gr = Session.query(UsersGroup)\
204 gr = Session.query(UsersGroup)\
205 .filter(UsersGroup.users_group_name == group_name)
205 .filter(UsersGroup.users_group_name == group_name)
206 if cache:
206 if cache:
207 gr = gr.options(FromCache("sql_cache_short",
207 gr = gr.options(FromCache("sql_cache_short",
208 "get_user_%s" % group_name))
208 "get_user_%s" % group_name))
209 return gr.scalar()
209 return gr.scalar()
210
210
211 class UsersGroupMember(Base):
211 class UsersGroupMember(Base):
212 __tablename__ = 'users_groups_members'
212 __tablename__ = 'users_groups_members'
213 __table_args__ = {'useexisting':True}
213 __table_args__ = {'useexisting':True}
214
214
215 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
215 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
216 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
216 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
217 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
217 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
218
218
219 user = relationship('User', lazy='joined')
219 user = relationship('User', lazy='joined')
220 users_group = relationship('UsersGroup')
220 users_group = relationship('UsersGroup')
221
221
222 def __init__(self, gr_id='', u_id=''):
222 def __init__(self, gr_id='', u_id=''):
223 self.users_group_id = gr_id
223 self.users_group_id = gr_id
224 self.user_id = u_id
224 self.user_id = u_id
225
225
226 class Repository(Base):
226 class Repository(Base):
227 __tablename__ = 'repositories'
227 __tablename__ = 'repositories'
228 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
228 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
229 __mapper_args__ = {'extension':RepositoryMapper()}
229 __mapper_args__ = {'extension':RepositoryMapper()}
230
230
231 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
231 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
232 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
232 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
233 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
233 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
234 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
234 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
235 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
235 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
236 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
236 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
237 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
237 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
238 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
238 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
239 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
239 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
240 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
240 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
241
241
242 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
242 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
243 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
243 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
244
244
245
245
246 user = relationship('User')
246 user = relationship('User')
247 fork = relationship('Repository', remote_side=repo_id)
247 fork = relationship('Repository', remote_side=repo_id)
248 group = relationship('Group')
248 group = relationship('Group')
249 repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
249 repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
250 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
250 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
251 stats = relationship('Statistics', cascade='all', uselist=False)
251 stats = relationship('Statistics', cascade='all', uselist=False)
252
252
253 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
253 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
254
254
255 logs = relationship('UserLog', cascade='all')
255 logs = relationship('UserLog', cascade='all')
256
256
257 def __repr__(self):
257 def __repr__(self):
258 return "<%s('%s:%s')>" % (self.__class__.__name__,
258 return "<%s('%s:%s')>" % (self.__class__.__name__,
259 self.repo_id, self.repo_name)
259 self.repo_id, self.repo_name)
260
260
261 @classmethod
261 @classmethod
262 def by_repo_name(cls, repo_name):
262 def by_repo_name(cls, repo_name):
263 return Session.query(cls).filter(cls.repo_name == repo_name).one()
263 return Session.query(cls).filter(cls.repo_name == repo_name).one()
264
264
265
265
266 @classmethod
266 @classmethod
267 def get_repo_forks(cls, repo_id):
267 def get_repo_forks(cls, repo_id):
268 return Session.query(cls).filter(Repository.fork_id == repo_id)
268 return Session.query(cls).filter(Repository.fork_id == repo_id)
269
269
270 @property
270 @property
271 def just_name(self):
271 def just_name(self):
272 return self.repo_name.split(os.sep)[-1]
272 return self.repo_name.split(os.sep)[-1]
273
273
274 @property
274 @property
275 def groups_with_parents(self):
275 def groups_with_parents(self):
276 groups = []
276 groups = []
277 if self.group is None:
277 if self.group is None:
278 return groups
278 return groups
279
279
280 cur_gr = self.group
280 cur_gr = self.group
281 groups.insert(0, cur_gr)
281 groups.insert(0, cur_gr)
282 while 1:
282 while 1:
283 gr = getattr(cur_gr, 'parent_group', None)
283 gr = getattr(cur_gr, 'parent_group', None)
284 cur_gr = cur_gr.parent_group
284 cur_gr = cur_gr.parent_group
285 if gr is None:
285 if gr is None:
286 break
286 break
287 groups.insert(0, gr)
287 groups.insert(0, gr)
288
288
289 return groups
289 return groups
290
290
291 @property
291 @property
292 def groups_and_repo(self):
292 def groups_and_repo(self):
293 return self.groups_with_parents, self.just_name
293 return self.groups_with_parents, self.just_name
294
294
295
295
296 class Group(Base):
296 class Group(Base):
297 __tablename__ = 'groups'
297 __tablename__ = 'groups'
298 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
298 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
299
299
300 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
300 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
301 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
301 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
302 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
302 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
303
303
304 parent_group = relationship('Group', remote_side=group_id)
304 parent_group = relationship('Group', remote_side=group_id)
305
305
306
306
307 def __init__(self, group_name='', parent_group=None):
307 def __init__(self, group_name='', parent_group=None):
308 self.group_name = group_name
308 self.group_name = group_name
309 self.parent_group = parent_group
309 self.parent_group = parent_group
310
310
311 def __repr__(self):
311 def __repr__(self):
312 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
312 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
313 self.group_name)
313 self.group_name)
314
314
315 @property
315 @property
316 def parents(self):
316 def parents(self):
317 groups = []
317 groups = []
318 if self.parent_group is None:
318 if self.parent_group is None:
319 return groups
319 return groups
320 cur_gr = self.parent_group
320 cur_gr = self.parent_group
321 groups.insert(0, cur_gr)
321 groups.insert(0, cur_gr)
322 while 1:
322 while 1:
323 gr = getattr(cur_gr, 'parent_group', None)
323 gr = getattr(cur_gr, 'parent_group', None)
324 cur_gr = cur_gr.parent_group
324 cur_gr = cur_gr.parent_group
325 if gr is None:
325 if gr is None:
326 break
326 break
327 groups.insert(0, gr)
327 groups.insert(0, gr)
328 return groups
328 return groups
329
329
330
331 @property
332 def full_path(self):
333 return '/'.join([g.group_name for g in self.parents] +
334 [self.group_name])
335
330 @property
336 @property
331 def repositories(self):
337 def repositories(self):
332 return Session.query(Repository).filter(Repository.group == self).all()
338 return Session.query(Repository).filter(Repository.group == self).all()
333
339
334 class Permission(Base):
340 class Permission(Base):
335 __tablename__ = 'permissions'
341 __tablename__ = 'permissions'
336 __table_args__ = {'useexisting':True}
342 __table_args__ = {'useexisting':True}
337 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
343 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
338 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
344 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
339 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
345 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
340
346
341 def __repr__(self):
347 def __repr__(self):
342 return "<%s('%s:%s')>" % (self.__class__.__name__,
348 return "<%s('%s:%s')>" % (self.__class__.__name__,
343 self.permission_id, self.permission_name)
349 self.permission_id, self.permission_name)
344
350
345 @classmethod
351 @classmethod
346 def get_by_key(cls, key):
352 def get_by_key(cls, key):
347 return Session.query(cls).filter(cls.permission_name == key).scalar()
353 return Session.query(cls).filter(cls.permission_name == key).scalar()
348
354
349 class RepoToPerm(Base):
355 class RepoToPerm(Base):
350 __tablename__ = 'repo_to_perm'
356 __tablename__ = 'repo_to_perm'
351 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
357 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
352 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
358 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
353 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
359 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
354 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
360 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
355 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
361 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
356
362
357 user = relationship('User')
363 user = relationship('User')
358 permission = relationship('Permission')
364 permission = relationship('Permission')
359 repository = relationship('Repository')
365 repository = relationship('Repository')
360
366
361 class UserToPerm(Base):
367 class UserToPerm(Base):
362 __tablename__ = 'user_to_perm'
368 __tablename__ = 'user_to_perm'
363 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
369 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
364 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
370 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
365 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
371 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
366 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
372 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
367
373
368 user = relationship('User')
374 user = relationship('User')
369 permission = relationship('Permission')
375 permission = relationship('Permission')
370
376
371 @classmethod
377 @classmethod
372 def has_perm(cls, user_id, perm):
378 def has_perm(cls, user_id, perm):
373 if not isinstance(perm, Permission):
379 if not isinstance(perm, Permission):
374 raise Exception('perm needs to be an instance of Permission class')
380 raise Exception('perm needs to be an instance of Permission class')
375
381
376 return Session.query(cls).filter(cls.user_id == user_id)\
382 return Session.query(cls).filter(cls.user_id == user_id)\
377 .filter(cls.permission == perm).scalar() is not None
383 .filter(cls.permission == perm).scalar() is not None
378
384
379 @classmethod
385 @classmethod
380 def grant_perm(cls, user_id, perm):
386 def grant_perm(cls, user_id, perm):
381 if not isinstance(perm, Permission):
387 if not isinstance(perm, Permission):
382 raise Exception('perm needs to be an instance of Permission class')
388 raise Exception('perm needs to be an instance of Permission class')
383
389
384 new = cls()
390 new = cls()
385 new.user_id = user_id
391 new.user_id = user_id
386 new.permission = perm
392 new.permission = perm
387 try:
393 try:
388 Session.add(new)
394 Session.add(new)
389 Session.commit()
395 Session.commit()
390 except:
396 except:
391 Session.rollback()
397 Session.rollback()
392
398
393
399
394 @classmethod
400 @classmethod
395 def revoke_perm(cls, user_id, perm):
401 def revoke_perm(cls, user_id, perm):
396 if not isinstance(perm, Permission):
402 if not isinstance(perm, Permission):
397 raise Exception('perm needs to be an instance of Permission class')
403 raise Exception('perm needs to be an instance of Permission class')
398
404
399 try:
405 try:
400 Session.query(cls).filter(cls.user_id == user_id)\
406 Session.query(cls).filter(cls.user_id == user_id)\
401 .filter(cls.permission == perm).delete()
407 .filter(cls.permission == perm).delete()
402 Session.commit()
408 Session.commit()
403 except:
409 except:
404 Session.rollback()
410 Session.rollback()
405
411
406 class UsersGroupRepoToPerm(Base):
412 class UsersGroupRepoToPerm(Base):
407 __tablename__ = 'users_group_repo_to_perm'
413 __tablename__ = 'users_group_repo_to_perm'
408 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
414 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
409 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
415 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
410 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
416 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
411 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
417 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
412 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
418 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
413
419
414 users_group = relationship('UsersGroup')
420 users_group = relationship('UsersGroup')
415 permission = relationship('Permission')
421 permission = relationship('Permission')
416 repository = relationship('Repository')
422 repository = relationship('Repository')
417
423
418
424
419 class UsersGroupToPerm(Base):
425 class UsersGroupToPerm(Base):
420 __tablename__ = 'users_group_to_perm'
426 __tablename__ = 'users_group_to_perm'
421 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
427 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
422 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
428 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
423 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
429 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
424
430
425 users_group = relationship('UsersGroup')
431 users_group = relationship('UsersGroup')
426 permission = relationship('Permission')
432 permission = relationship('Permission')
427
433
428
434
429 @classmethod
435 @classmethod
430 def has_perm(cls, users_group_id, perm):
436 def has_perm(cls, users_group_id, perm):
431 if not isinstance(perm, Permission):
437 if not isinstance(perm, Permission):
432 raise Exception('perm needs to be an instance of Permission class')
438 raise Exception('perm needs to be an instance of Permission class')
433
439
434 return Session.query(cls).filter(cls.users_group_id ==
440 return Session.query(cls).filter(cls.users_group_id ==
435 users_group_id)\
441 users_group_id)\
436 .filter(cls.permission == perm)\
442 .filter(cls.permission == perm)\
437 .scalar() is not None
443 .scalar() is not None
438
444
439 @classmethod
445 @classmethod
440 def grant_perm(cls, users_group_id, perm):
446 def grant_perm(cls, users_group_id, perm):
441 if not isinstance(perm, Permission):
447 if not isinstance(perm, Permission):
442 raise Exception('perm needs to be an instance of Permission class')
448 raise Exception('perm needs to be an instance of Permission class')
443
449
444 new = cls()
450 new = cls()
445 new.users_group_id = users_group_id
451 new.users_group_id = users_group_id
446 new.permission = perm
452 new.permission = perm
447 try:
453 try:
448 Session.add(new)
454 Session.add(new)
449 Session.commit()
455 Session.commit()
450 except:
456 except:
451 Session.rollback()
457 Session.rollback()
452
458
453
459
454 @classmethod
460 @classmethod
455 def revoke_perm(cls, users_group_id, perm):
461 def revoke_perm(cls, users_group_id, perm):
456 if not isinstance(perm, Permission):
462 if not isinstance(perm, Permission):
457 raise Exception('perm needs to be an instance of Permission class')
463 raise Exception('perm needs to be an instance of Permission class')
458
464
459 try:
465 try:
460 Session.query(cls).filter(cls.users_group_id == users_group_id)\
466 Session.query(cls).filter(cls.users_group_id == users_group_id)\
461 .filter(cls.permission == perm).delete()
467 .filter(cls.permission == perm).delete()
462 Session.commit()
468 Session.commit()
463 except:
469 except:
464 Session.rollback()
470 Session.rollback()
465
471
466
472
467 class GroupToPerm(Base):
473 class GroupToPerm(Base):
468 __tablename__ = 'group_to_perm'
474 __tablename__ = 'group_to_perm'
469 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
475 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
470
476
471 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
477 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
472 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
478 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
473 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
479 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
474 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
480 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
475
481
476 user = relationship('User')
482 user = relationship('User')
477 permission = relationship('Permission')
483 permission = relationship('Permission')
478 group = relationship('Group')
484 group = relationship('Group')
479
485
480 class Statistics(Base):
486 class Statistics(Base):
481 __tablename__ = 'statistics'
487 __tablename__ = 'statistics'
482 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
488 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
483 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
489 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
484 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
490 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
485 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
491 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
486 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
492 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
487 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
493 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
488 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
494 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
489
495
490 repository = relationship('Repository', single_parent=True)
496 repository = relationship('Repository', single_parent=True)
491
497
492 class UserFollowing(Base):
498 class UserFollowing(Base):
493 __tablename__ = 'user_followings'
499 __tablename__ = 'user_followings'
494 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
500 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
495 UniqueConstraint('user_id', 'follows_user_id')
501 UniqueConstraint('user_id', 'follows_user_id')
496 , {'useexisting':True})
502 , {'useexisting':True})
497
503
498 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
504 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
499 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
505 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
500 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
506 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
501 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
507 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
502 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
508 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
503
509
504 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
510 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
505
511
506 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
512 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
507 follows_repository = relationship('Repository', order_by='Repository.repo_name')
513 follows_repository = relationship('Repository', order_by='Repository.repo_name')
508
514
509
515
510
516
511 @classmethod
517 @classmethod
512 def get_repo_followers(cls, repo_id):
518 def get_repo_followers(cls, repo_id):
513 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
519 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
514
520
515 class CacheInvalidation(Base):
521 class CacheInvalidation(Base):
516 __tablename__ = 'cache_invalidation'
522 __tablename__ = 'cache_invalidation'
517 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
523 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
518 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
524 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
519 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
525 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
520 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
526 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
521 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
527 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
522
528
523
529
524 def __init__(self, cache_key, cache_args=''):
530 def __init__(self, cache_key, cache_args=''):
525 self.cache_key = cache_key
531 self.cache_key = cache_key
526 self.cache_args = cache_args
532 self.cache_args = cache_args
527 self.cache_active = False
533 self.cache_active = False
528
534
529 def __repr__(self):
535 def __repr__(self):
530 return "<%s('%s:%s')>" % (self.__class__.__name__,
536 return "<%s('%s:%s')>" % (self.__class__.__name__,
531 self.cache_id, self.cache_key)
537 self.cache_id, self.cache_key)
532
538
533 class DbMigrateVersion(Base):
539 class DbMigrateVersion(Base):
534 __tablename__ = 'db_migrate_version'
540 __tablename__ = 'db_migrate_version'
535 __table_args__ = {'useexisting':True}
541 __table_args__ = {'useexisting':True}
536 repository_id = Column('repository_id', String(250), primary_key=True)
542 repository_id = Column('repository_id', String(250), primary_key=True)
537 repository_path = Column('repository_path', Text)
543 repository_path = Column('repository_path', Text)
538 version = Column('version', Integer)
544 version = Column('version', Integer)
@@ -1,584 +1,611 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import os
22 import os
23 import re
23 import re
24 import logging
24 import logging
25 import traceback
25 import traceback
26
26
27 import formencode
27 import formencode
28 from formencode import All
28 from formencode import All
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
30 Email, Bool, StringBoolean, Set
30 Email, Bool, StringBoolean, Set
31
31
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34
34
35 from rhodecode.lib.utils import repo_name_slug
35 from rhodecode.lib.utils import repo_name_slug
36 from rhodecode.lib.auth import authenticate, get_crypt_password
36 from rhodecode.lib.auth import authenticate, get_crypt_password
37 from rhodecode.lib.exceptions import LdapImportError
37 from rhodecode.lib.exceptions import LdapImportError
38 from rhodecode.model import meta
38 from rhodecode.model import meta
39 from rhodecode.model.user import UserModel
39 from rhodecode.model.user import UserModel
40 from rhodecode.model.repo import RepoModel
40 from rhodecode.model.repo import RepoModel
41 from rhodecode.model.db import User, UsersGroup
41 from rhodecode.model.db import User, UsersGroup, Group
42 from rhodecode import BACKENDS
42 from rhodecode import BACKENDS
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46 #this is needed to translate the messages using _() in validators
46 #this is needed to translate the messages using _() in validators
47 class State_obj(object):
47 class State_obj(object):
48 _ = staticmethod(_)
48 _ = staticmethod(_)
49
49
50 #==============================================================================
50 #==============================================================================
51 # VALIDATORS
51 # VALIDATORS
52 #==============================================================================
52 #==============================================================================
53 class ValidAuthToken(formencode.validators.FancyValidator):
53 class ValidAuthToken(formencode.validators.FancyValidator):
54 messages = {'invalid_token':_('Token mismatch')}
54 messages = {'invalid_token':_('Token mismatch')}
55
55
56 def validate_python(self, value, state):
56 def validate_python(self, value, state):
57
57
58 if value != authentication_token():
58 if value != authentication_token():
59 raise formencode.Invalid(self.message('invalid_token', state,
59 raise formencode.Invalid(self.message('invalid_token', state,
60 search_number=value), value, state)
60 search_number=value), value, state)
61
61
62 def ValidUsername(edit, old_data):
62 def ValidUsername(edit, old_data):
63 class _ValidUsername(formencode.validators.FancyValidator):
63 class _ValidUsername(formencode.validators.FancyValidator):
64
64
65 def validate_python(self, value, state):
65 def validate_python(self, value, state):
66 if value in ['default', 'new_user']:
66 if value in ['default', 'new_user']:
67 raise formencode.Invalid(_('Invalid username'), value, state)
67 raise formencode.Invalid(_('Invalid username'), value, state)
68 #check if user is unique
68 #check if user is unique
69 old_un = None
69 old_un = None
70 if edit:
70 if edit:
71 old_un = UserModel().get(old_data.get('user_id')).username
71 old_un = UserModel().get(old_data.get('user_id')).username
72
72
73 if old_un != value or not edit:
73 if old_un != value or not edit:
74 if UserModel().get_by_username(value, cache=False,
74 if UserModel().get_by_username(value, cache=False,
75 case_insensitive=True):
75 case_insensitive=True):
76 raise formencode.Invalid(_('This username already '
76 raise formencode.Invalid(_('This username already '
77 'exists') , value, state)
77 'exists') , value, state)
78
78
79 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
79 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
80 raise formencode.Invalid(_('Username may only contain '
80 raise formencode.Invalid(_('Username may only contain '
81 'alphanumeric characters '
81 'alphanumeric characters '
82 'underscores, periods or dashes '
82 'underscores, periods or dashes '
83 'and must begin with alphanumeric '
83 'and must begin with alphanumeric '
84 'character'), value, state)
84 'character'), value, state)
85
85
86 return _ValidUsername
86 return _ValidUsername
87
87
88
88
89 def ValidUsersGroup(edit, old_data):
89 def ValidUsersGroup(edit, old_data):
90
90
91 class _ValidUsersGroup(formencode.validators.FancyValidator):
91 class _ValidUsersGroup(formencode.validators.FancyValidator):
92
92
93 def validate_python(self, value, state):
93 def validate_python(self, value, state):
94 if value in ['default']:
94 if value in ['default']:
95 raise formencode.Invalid(_('Invalid group name'), value, state)
95 raise formencode.Invalid(_('Invalid group name'), value, state)
96 #check if group is unique
96 #check if group is unique
97 old_ugname = None
97 old_ugname = None
98 if edit:
98 if edit:
99 old_ugname = UsersGroup.get(
99 old_ugname = UsersGroup.get(
100 old_data.get('users_group_id')).users_group_name
100 old_data.get('users_group_id')).users_group_name
101
101
102 if old_ugname != value or not edit:
102 if old_ugname != value or not edit:
103 if UsersGroup.get_by_group_name(value, cache=False,
103 if UsersGroup.get_by_group_name(value, cache=False,
104 case_insensitive=True):
104 case_insensitive=True):
105 raise formencode.Invalid(_('This users group '
105 raise formencode.Invalid(_('This users group '
106 'already exists') , value,
106 'already exists') , value,
107 state)
107 state)
108
108
109
109
110 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
110 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
111 raise formencode.Invalid(_('Group name may only contain '
111 raise formencode.Invalid(_('Group name may only contain '
112 'alphanumeric characters '
112 'alphanumeric characters '
113 'underscores, periods or dashes '
113 'underscores, periods or dashes '
114 'and must begin with alphanumeric '
114 'and must begin with alphanumeric '
115 'character'), value, state)
115 'character'), value, state)
116
116
117 return _ValidUsersGroup
117 return _ValidUsersGroup
118
118
119
119
120
120
121 class ValidPassword(formencode.validators.FancyValidator):
121 class ValidPassword(formencode.validators.FancyValidator):
122
122
123 def to_python(self, value, state):
123 def to_python(self, value, state):
124
124
125 if value:
125 if value:
126
126
127 if value.get('password'):
127 if value.get('password'):
128 try:
128 try:
129 value['password'] = get_crypt_password(value['password'])
129 value['password'] = get_crypt_password(value['password'])
130 except UnicodeEncodeError:
130 except UnicodeEncodeError:
131 e_dict = {'password':_('Invalid characters in password')}
131 e_dict = {'password':_('Invalid characters in password')}
132 raise formencode.Invalid('', value, state, error_dict=e_dict)
132 raise formencode.Invalid('', value, state, error_dict=e_dict)
133
133
134 if value.get('password_confirmation'):
134 if value.get('password_confirmation'):
135 try:
135 try:
136 value['password_confirmation'] = \
136 value['password_confirmation'] = \
137 get_crypt_password(value['password_confirmation'])
137 get_crypt_password(value['password_confirmation'])
138 except UnicodeEncodeError:
138 except UnicodeEncodeError:
139 e_dict = {'password_confirmation':_('Invalid characters in password')}
139 e_dict = {'password_confirmation':_('Invalid characters in password')}
140 raise formencode.Invalid('', value, state, error_dict=e_dict)
140 raise formencode.Invalid('', value, state, error_dict=e_dict)
141
141
142 if value.get('new_password'):
142 if value.get('new_password'):
143 try:
143 try:
144 value['new_password'] = \
144 value['new_password'] = \
145 get_crypt_password(value['new_password'])
145 get_crypt_password(value['new_password'])
146 except UnicodeEncodeError:
146 except UnicodeEncodeError:
147 e_dict = {'new_password':_('Invalid characters in password')}
147 e_dict = {'new_password':_('Invalid characters in password')}
148 raise formencode.Invalid('', value, state, error_dict=e_dict)
148 raise formencode.Invalid('', value, state, error_dict=e_dict)
149
149
150 return value
150 return value
151
151
152 class ValidPasswordsMatch(formencode.validators.FancyValidator):
152 class ValidPasswordsMatch(formencode.validators.FancyValidator):
153
153
154 def validate_python(self, value, state):
154 def validate_python(self, value, state):
155
155
156 if value['password'] != value['password_confirmation']:
156 if value['password'] != value['password_confirmation']:
157 e_dict = {'password_confirmation':
157 e_dict = {'password_confirmation':
158 _('Password do not match')}
158 _('Password do not match')}
159 raise formencode.Invalid('', value, state, error_dict=e_dict)
159 raise formencode.Invalid('', value, state, error_dict=e_dict)
160
160
161 class ValidAuth(formencode.validators.FancyValidator):
161 class ValidAuth(formencode.validators.FancyValidator):
162 messages = {
162 messages = {
163 'invalid_password':_('invalid password'),
163 'invalid_password':_('invalid password'),
164 'invalid_login':_('invalid user name'),
164 'invalid_login':_('invalid user name'),
165 'disabled_account':_('Your account is disabled')
165 'disabled_account':_('Your account is disabled')
166
166
167 }
167 }
168 #error mapping
168 #error mapping
169 e_dict = {'username':messages['invalid_login'],
169 e_dict = {'username':messages['invalid_login'],
170 'password':messages['invalid_password']}
170 'password':messages['invalid_password']}
171 e_dict_disable = {'username':messages['disabled_account']}
171 e_dict_disable = {'username':messages['disabled_account']}
172
172
173 def validate_python(self, value, state):
173 def validate_python(self, value, state):
174 password = value['password']
174 password = value['password']
175 username = value['username']
175 username = value['username']
176 user = UserModel().get_by_username(username)
176 user = UserModel().get_by_username(username)
177
177
178 if authenticate(username, password):
178 if authenticate(username, password):
179 return value
179 return value
180 else:
180 else:
181 if user and user.active is False:
181 if user and user.active is False:
182 log.warning('user %s is disabled', username)
182 log.warning('user %s is disabled', username)
183 raise formencode.Invalid(self.message('disabled_account',
183 raise formencode.Invalid(self.message('disabled_account',
184 state=State_obj),
184 state=State_obj),
185 value, state,
185 value, state,
186 error_dict=self.e_dict_disable)
186 error_dict=self.e_dict_disable)
187 else:
187 else:
188 log.warning('user %s not authenticated', username)
188 log.warning('user %s not authenticated', username)
189 raise formencode.Invalid(self.message('invalid_password',
189 raise formencode.Invalid(self.message('invalid_password',
190 state=State_obj), value, state,
190 state=State_obj), value, state,
191 error_dict=self.e_dict)
191 error_dict=self.e_dict)
192
192
193 class ValidRepoUser(formencode.validators.FancyValidator):
193 class ValidRepoUser(formencode.validators.FancyValidator):
194
194
195 def to_python(self, value, state):
195 def to_python(self, value, state):
196 sa = meta.Session()
196 sa = meta.Session()
197 try:
197 try:
198 self.user_db = sa.query(User)\
198 self.user_db = sa.query(User)\
199 .filter(User.active == True)\
199 .filter(User.active == True)\
200 .filter(User.username == value).one()
200 .filter(User.username == value).one()
201 except Exception:
201 except Exception:
202 raise formencode.Invalid(_('This username is not valid'),
202 raise formencode.Invalid(_('This username is not valid'),
203 value, state)
203 value, state)
204 finally:
204 finally:
205 meta.Session.remove()
205 meta.Session.remove()
206
206
207 return self.user_db.user_id
207 return value
208
208
209 def ValidRepoName(edit, old_data):
209 def ValidRepoName(edit, old_data):
210 class _ValidRepoName(formencode.validators.FancyValidator):
210 class _ValidRepoName(formencode.validators.FancyValidator):
211 def to_python(self, value, state):
211
212
212 def to_python(self, value, state):
213 repo_name = value.get('repo_name')
213 slug = repo_name_slug(value)
214
214 if slug in ['_admin']:
215 slug = repo_name_slug(repo_name)
215 raise formencode.Invalid(_('This repository name is disallowed'),
216 if slug in ['_admin', '']:
216 value, state)
217 e_dict = {'repo_name': _('This repository name is disallowed')}
217 if old_data.get('repo_name') != value or not edit:
218 raise formencode.Invalid('', value, state, error_dict=e_dict)
218 if RepoModel().get_by_repo_name(slug, cache=False):
219
219 raise formencode.Invalid(_('This repository already exists') ,
220 gr = Group.get(value.get('repo_group'))
220 value, state)
221
221 return slug
222 # value needs to be aware of group name
223 repo_name_full = gr.full_path + '/' + repo_name
224 value['repo_name_full'] = repo_name_full
225 if old_data.get('repo_name') != repo_name_full or not edit:
226
227 if gr.full_path != '':
228 if RepoModel().get_by_repo_name(repo_name_full,):
229 e_dict = {'repo_name':_('This repository already '
230 'exists in group "%s"') %
231 gr.group_name}
232 raise formencode.Invalid('', value, state,
233 error_dict=e_dict)
234
235 else:
236 if RepoModel().get_by_repo_name(repo_name_full):
237 e_dict = {'repo_name':_('This repository already exists')}
238 raise formencode.Invalid('', value, state,
239 error_dict=e_dict)
240 return value
222
241
223
242
224 return _ValidRepoName
243 return _ValidRepoName
225
244
245 def SlugifyRepo():
246 class _SlugifyRepo(formencode.validators.FancyValidator):
247
248 def to_python(self, value, state):
249 return repo_name_slug(value)
250
251 return _SlugifyRepo
252
226 def ValidCloneUri():
253 def ValidCloneUri():
227 from mercurial.httprepo import httprepository, httpsrepository
254 from mercurial.httprepo import httprepository, httpsrepository
228 from rhodecode.lib.utils import make_ui
255 from rhodecode.lib.utils import make_ui
229
256
230 class _ValidCloneUri(formencode.validators.FancyValidator):
257 class _ValidCloneUri(formencode.validators.FancyValidator):
231
258
232 def to_python(self, value, state):
259 def to_python(self, value, state):
233 if not value:
260 if not value:
234 pass
261 pass
235 elif value.startswith('https'):
262 elif value.startswith('https'):
236 try:
263 try:
237 httpsrepository(make_ui('db'), value).capabilities
264 httpsrepository(make_ui('db'), value).capabilities
238 except Exception, e:
265 except Exception, e:
239 log.error(traceback.format_exc())
266 log.error(traceback.format_exc())
240 raise formencode.Invalid(_('invalid clone url'), value,
267 raise formencode.Invalid(_('invalid clone url'), value,
241 state)
268 state)
242 elif value.startswith('http'):
269 elif value.startswith('http'):
243 try:
270 try:
244 httprepository(make_ui('db'), value).capabilities
271 httprepository(make_ui('db'), value).capabilities
245 except Exception, e:
272 except Exception, e:
246 log.error(traceback.format_exc())
273 log.error(traceback.format_exc())
247 raise formencode.Invalid(_('invalid clone url'), value,
274 raise formencode.Invalid(_('invalid clone url'), value,
248 state)
275 state)
249 else:
276 else:
250 raise formencode.Invalid(_('Invalid clone url, provide a '
277 raise formencode.Invalid(_('Invalid clone url, provide a '
251 'valid clone http\s url'), value,
278 'valid clone http\s url'), value,
252 state)
279 state)
253 return value
280 return value
254
281
255 return _ValidCloneUri
282 return _ValidCloneUri
256
283
257 def ValidForkType(old_data):
284 def ValidForkType(old_data):
258 class _ValidForkType(formencode.validators.FancyValidator):
285 class _ValidForkType(formencode.validators.FancyValidator):
259
286
260 def to_python(self, value, state):
287 def to_python(self, value, state):
261 if old_data['repo_type'] != value:
288 if old_data['repo_type'] != value:
262 raise formencode.Invalid(_('Fork have to be the same '
289 raise formencode.Invalid(_('Fork have to be the same '
263 'type as original'), value, state)
290 'type as original'), value, state)
264 return value
291 return value
265 return _ValidForkType
292 return _ValidForkType
266
293
267 class ValidPerms(formencode.validators.FancyValidator):
294 class ValidPerms(formencode.validators.FancyValidator):
268 messages = {'perm_new_member_name':_('This username or users group name'
295 messages = {'perm_new_member_name':_('This username or users group name'
269 ' is not valid')}
296 ' is not valid')}
270
297
271 def to_python(self, value, state):
298 def to_python(self, value, state):
272 perms_update = []
299 perms_update = []
273 perms_new = []
300 perms_new = []
274 #build a list of permission to update and new permission to create
301 #build a list of permission to update and new permission to create
275 for k, v in value.items():
302 for k, v in value.items():
276 #means new added member to permissions
303 #means new added member to permissions
277 if k.startswith('perm_new_member'):
304 if k.startswith('perm_new_member'):
278 new_perm = value.get('perm_new_member', False)
305 new_perm = value.get('perm_new_member', False)
279 new_member = value.get('perm_new_member_name', False)
306 new_member = value.get('perm_new_member_name', False)
280 new_type = value.get('perm_new_member_type')
307 new_type = value.get('perm_new_member_type')
281
308
282 if new_member and new_perm:
309 if new_member and new_perm:
283 if (new_member, new_perm, new_type) not in perms_new:
310 if (new_member, new_perm, new_type) not in perms_new:
284 perms_new.append((new_member, new_perm, new_type))
311 perms_new.append((new_member, new_perm, new_type))
285 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
312 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
286 member = k[7:]
313 member = k[7:]
287 t = {'u':'user',
314 t = {'u':'user',
288 'g':'users_group'}[k[0]]
315 'g':'users_group'}[k[0]]
289 if member == 'default':
316 if member == 'default':
290 if value['private']:
317 if value['private']:
291 #set none for default when updating to private repo
318 #set none for default when updating to private repo
292 v = 'repository.none'
319 v = 'repository.none'
293 perms_update.append((member, v, t))
320 perms_update.append((member, v, t))
294
321
295 value['perms_updates'] = perms_update
322 value['perms_updates'] = perms_update
296 value['perms_new'] = perms_new
323 value['perms_new'] = perms_new
297
324
298 #update permissions
325 #update permissions
299 sa = meta.Session
326 sa = meta.Session
300 for k, v, t in perms_new:
327 for k, v, t in perms_new:
301 try:
328 try:
302 if t is 'user':
329 if t is 'user':
303 self.user_db = sa.query(User)\
330 self.user_db = sa.query(User)\
304 .filter(User.active == True)\
331 .filter(User.active == True)\
305 .filter(User.username == k).one()
332 .filter(User.username == k).one()
306 if t is 'users_group':
333 if t is 'users_group':
307 self.user_db = sa.query(UsersGroup)\
334 self.user_db = sa.query(UsersGroup)\
308 .filter(UsersGroup.users_group_active == True)\
335 .filter(UsersGroup.users_group_active == True)\
309 .filter(UsersGroup.users_group_name == k).one()
336 .filter(UsersGroup.users_group_name == k).one()
310
337
311 except Exception:
338 except Exception:
312 msg = self.message('perm_new_member_name',
339 msg = self.message('perm_new_member_name',
313 state=State_obj)
340 state=State_obj)
314 raise formencode.Invalid(msg, value, state,
341 raise formencode.Invalid(msg, value, state,
315 error_dict={'perm_new_member_name':msg})
342 error_dict={'perm_new_member_name':msg})
316 return value
343 return value
317
344
318 class ValidSettings(formencode.validators.FancyValidator):
345 class ValidSettings(formencode.validators.FancyValidator):
319
346
320 def to_python(self, value, state):
347 def to_python(self, value, state):
321 #settings form can't edit user
348 #settings form can't edit user
322 if value.has_key('user'):
349 if value.has_key('user'):
323 del['value']['user']
350 del['value']['user']
324
351
325 return value
352 return value
326
353
327 class ValidPath(formencode.validators.FancyValidator):
354 class ValidPath(formencode.validators.FancyValidator):
328 def to_python(self, value, state):
355 def to_python(self, value, state):
329
356
330 if not os.path.isdir(value):
357 if not os.path.isdir(value):
331 msg = _('This is not a valid path')
358 msg = _('This is not a valid path')
332 raise formencode.Invalid(msg, value, state,
359 raise formencode.Invalid(msg, value, state,
333 error_dict={'paths_root_path':msg})
360 error_dict={'paths_root_path':msg})
334 return value
361 return value
335
362
336 def UniqSystemEmail(old_data):
363 def UniqSystemEmail(old_data):
337 class _UniqSystemEmail(formencode.validators.FancyValidator):
364 class _UniqSystemEmail(formencode.validators.FancyValidator):
338 def to_python(self, value, state):
365 def to_python(self, value, state):
339 value = value.lower()
366 value = value.lower()
340 if old_data.get('email') != value:
367 if old_data.get('email') != value:
341 sa = meta.Session()
368 sa = meta.Session()
342 try:
369 try:
343 user = sa.query(User).filter(User.email == value).scalar()
370 user = sa.query(User).filter(User.email == value).scalar()
344 if user:
371 if user:
345 raise formencode.Invalid(_("This e-mail address is already taken") ,
372 raise formencode.Invalid(_("This e-mail address is already taken") ,
346 value, state)
373 value, state)
347 finally:
374 finally:
348 meta.Session.remove()
375 meta.Session.remove()
349
376
350 return value
377 return value
351
378
352 return _UniqSystemEmail
379 return _UniqSystemEmail
353
380
354 class ValidSystemEmail(formencode.validators.FancyValidator):
381 class ValidSystemEmail(formencode.validators.FancyValidator):
355 def to_python(self, value, state):
382 def to_python(self, value, state):
356 value = value.lower()
383 value = value.lower()
357 sa = meta.Session
384 sa = meta.Session
358 try:
385 try:
359 user = sa.query(User).filter(User.email == value).scalar()
386 user = sa.query(User).filter(User.email == value).scalar()
360 if user is None:
387 if user is None:
361 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
388 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
362 value, state)
389 value, state)
363 finally:
390 finally:
364 meta.Session.remove()
391 meta.Session.remove()
365
392
366 return value
393 return value
367
394
368 class LdapLibValidator(formencode.validators.FancyValidator):
395 class LdapLibValidator(formencode.validators.FancyValidator):
369
396
370 def to_python(self, value, state):
397 def to_python(self, value, state):
371
398
372 try:
399 try:
373 import ldap
400 import ldap
374 except ImportError:
401 except ImportError:
375 raise LdapImportError
402 raise LdapImportError
376 return value
403 return value
377
404
378 class AttrLoginValidator(formencode.validators.FancyValidator):
405 class AttrLoginValidator(formencode.validators.FancyValidator):
379
406
380 def to_python(self, value, state):
407 def to_python(self, value, state):
381
408
382 if not value or not isinstance(value, (str, unicode)):
409 if not value or not isinstance(value, (str, unicode)):
383 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
410 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
384 "must be specified - this is the name "
411 "must be specified - this is the name "
385 "of the attribute that is equivalent "
412 "of the attribute that is equivalent "
386 "to 'username'"),
413 "to 'username'"),
387 value, state)
414 value, state)
388
415
389 return value
416 return value
390
417
391 #===============================================================================
418 #===============================================================================
392 # FORMS
419 # FORMS
393 #===============================================================================
420 #===============================================================================
394 class LoginForm(formencode.Schema):
421 class LoginForm(formencode.Schema):
395 allow_extra_fields = True
422 allow_extra_fields = True
396 filter_extra_fields = True
423 filter_extra_fields = True
397 username = UnicodeString(
424 username = UnicodeString(
398 strip=True,
425 strip=True,
399 min=1,
426 min=1,
400 not_empty=True,
427 not_empty=True,
401 messages={
428 messages={
402 'empty':_('Please enter a login'),
429 'empty':_('Please enter a login'),
403 'tooShort':_('Enter a value %(min)i characters long or more')}
430 'tooShort':_('Enter a value %(min)i characters long or more')}
404 )
431 )
405
432
406 password = UnicodeString(
433 password = UnicodeString(
407 strip=True,
434 strip=True,
408 min=6,
435 min=6,
409 not_empty=True,
436 not_empty=True,
410 messages={
437 messages={
411 'empty':_('Please enter a password'),
438 'empty':_('Please enter a password'),
412 'tooShort':_('Enter %(min)i characters or more')}
439 'tooShort':_('Enter %(min)i characters or more')}
413 )
440 )
414
441
415
442
416 #chained validators have access to all data
443 #chained validators have access to all data
417 chained_validators = [ValidAuth]
444 chained_validators = [ValidAuth]
418
445
419 def UserForm(edit=False, old_data={}):
446 def UserForm(edit=False, old_data={}):
420 class _UserForm(formencode.Schema):
447 class _UserForm(formencode.Schema):
421 allow_extra_fields = True
448 allow_extra_fields = True
422 filter_extra_fields = True
449 filter_extra_fields = True
423 username = All(UnicodeString(strip=True, min=1, not_empty=True),
450 username = All(UnicodeString(strip=True, min=1, not_empty=True),
424 ValidUsername(edit, old_data))
451 ValidUsername(edit, old_data))
425 if edit:
452 if edit:
426 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
453 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
427 admin = StringBoolean(if_missing=False)
454 admin = StringBoolean(if_missing=False)
428 else:
455 else:
429 password = All(UnicodeString(strip=True, min=6, not_empty=True))
456 password = All(UnicodeString(strip=True, min=6, not_empty=True))
430 active = StringBoolean(if_missing=False)
457 active = StringBoolean(if_missing=False)
431 name = UnicodeString(strip=True, min=1, not_empty=True)
458 name = UnicodeString(strip=True, min=1, not_empty=True)
432 lastname = UnicodeString(strip=True, min=1, not_empty=True)
459 lastname = UnicodeString(strip=True, min=1, not_empty=True)
433 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
460 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
434
461
435 chained_validators = [ValidPassword]
462 chained_validators = [ValidPassword]
436
463
437 return _UserForm
464 return _UserForm
438
465
439
466
440 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
467 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
441 class _UsersGroupForm(formencode.Schema):
468 class _UsersGroupForm(formencode.Schema):
442 allow_extra_fields = True
469 allow_extra_fields = True
443 filter_extra_fields = True
470 filter_extra_fields = True
444
471
445 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
472 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
446 ValidUsersGroup(edit, old_data))
473 ValidUsersGroup(edit, old_data))
447
474
448 users_group_active = StringBoolean(if_missing=False)
475 users_group_active = StringBoolean(if_missing=False)
449
476
450 if edit:
477 if edit:
451 users_group_members = OneOf(available_members, hideList=False,
478 users_group_members = OneOf(available_members, hideList=False,
452 testValueList=True,
479 testValueList=True,
453 if_missing=None, not_empty=False)
480 if_missing=None, not_empty=False)
454
481
455 return _UsersGroupForm
482 return _UsersGroupForm
456
483
457 def RegisterForm(edit=False, old_data={}):
484 def RegisterForm(edit=False, old_data={}):
458 class _RegisterForm(formencode.Schema):
485 class _RegisterForm(formencode.Schema):
459 allow_extra_fields = True
486 allow_extra_fields = True
460 filter_extra_fields = True
487 filter_extra_fields = True
461 username = All(ValidUsername(edit, old_data),
488 username = All(ValidUsername(edit, old_data),
462 UnicodeString(strip=True, min=1, not_empty=True))
489 UnicodeString(strip=True, min=1, not_empty=True))
463 password = All(UnicodeString(strip=True, min=6, not_empty=True))
490 password = All(UnicodeString(strip=True, min=6, not_empty=True))
464 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
491 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
465 active = StringBoolean(if_missing=False)
492 active = StringBoolean(if_missing=False)
466 name = UnicodeString(strip=True, min=1, not_empty=True)
493 name = UnicodeString(strip=True, min=1, not_empty=True)
467 lastname = UnicodeString(strip=True, min=1, not_empty=True)
494 lastname = UnicodeString(strip=True, min=1, not_empty=True)
468 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
495 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
469
496
470 chained_validators = [ValidPasswordsMatch, ValidPassword]
497 chained_validators = [ValidPasswordsMatch, ValidPassword]
471
498
472 return _RegisterForm
499 return _RegisterForm
473
500
474 def PasswordResetForm():
501 def PasswordResetForm():
475 class _PasswordResetForm(formencode.Schema):
502 class _PasswordResetForm(formencode.Schema):
476 allow_extra_fields = True
503 allow_extra_fields = True
477 filter_extra_fields = True
504 filter_extra_fields = True
478 email = All(ValidSystemEmail(), Email(not_empty=True))
505 email = All(ValidSystemEmail(), Email(not_empty=True))
479 return _PasswordResetForm
506 return _PasswordResetForm
480
507
481 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
508 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
482 repo_groups=[]):
509 repo_groups=[]):
483 class _RepoForm(formencode.Schema):
510 class _RepoForm(formencode.Schema):
484 allow_extra_fields = True
511 allow_extra_fields = True
485 filter_extra_fields = False
512 filter_extra_fields = False
486 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
513 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
487 ValidRepoName(edit, old_data))
514 SlugifyRepo())
488 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
515 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
489 ValidCloneUri()())
516 ValidCloneUri()())
490 repo_group = OneOf(repo_groups, hideList=True)
517 repo_group = OneOf(repo_groups, hideList=True)
491 repo_type = OneOf(supported_backends)
518 repo_type = OneOf(supported_backends)
492 description = UnicodeString(strip=True, min=1, not_empty=True)
519 description = UnicodeString(strip=True, min=1, not_empty=True)
493 private = StringBoolean(if_missing=False)
520 private = StringBoolean(if_missing=False)
494 enable_statistics = StringBoolean(if_missing=False)
521 enable_statistics = StringBoolean(if_missing=False)
495 enable_downloads = StringBoolean(if_missing=False)
522 enable_downloads = StringBoolean(if_missing=False)
496
523
497 if edit:
524 if edit:
498 #this is repo owner
525 #this is repo owner
499 user = All(Int(not_empty=True), ValidRepoUser)
526 user = All(UnicodeString(not_empty=True), ValidRepoUser)
500
527
501 chained_validators = [ValidPerms]
528 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
502 return _RepoForm
529 return _RepoForm
503
530
504 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
531 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
505 class _RepoForkForm(formencode.Schema):
532 class _RepoForkForm(formencode.Schema):
506 allow_extra_fields = True
533 allow_extra_fields = True
507 filter_extra_fields = False
534 filter_extra_fields = False
508 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
535 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
509 ValidRepoName(edit, old_data))
536 SlugifyRepo())
510 description = UnicodeString(strip=True, min=1, not_empty=True)
537 description = UnicodeString(strip=True, min=1, not_empty=True)
511 private = StringBoolean(if_missing=False)
538 private = StringBoolean(if_missing=False)
512 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
539 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
513 return _RepoForkForm
540 return _RepoForkForm
514
541
515 def RepoSettingsForm(edit=False, old_data={}):
542 def RepoSettingsForm(edit=False, old_data={}):
516 class _RepoForm(formencode.Schema):
543 class _RepoForm(formencode.Schema):
517 allow_extra_fields = True
544 allow_extra_fields = True
518 filter_extra_fields = False
545 filter_extra_fields = False
519 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
546 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
520 ValidRepoName(edit, old_data))
547 SlugifyRepo())
521 description = UnicodeString(strip=True, min=1, not_empty=True)
548 description = UnicodeString(strip=True, min=1, not_empty=True)
522 private = StringBoolean(if_missing=False)
549 private = StringBoolean(if_missing=False)
523
550
524 chained_validators = [ValidPerms, ValidSettings]
551 chained_validators = [ValidRepoName(edit, old_data), ValidPerms, ValidSettings]
525 return _RepoForm
552 return _RepoForm
526
553
527
554
528 def ApplicationSettingsForm():
555 def ApplicationSettingsForm():
529 class _ApplicationSettingsForm(formencode.Schema):
556 class _ApplicationSettingsForm(formencode.Schema):
530 allow_extra_fields = True
557 allow_extra_fields = True
531 filter_extra_fields = False
558 filter_extra_fields = False
532 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
559 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
533 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
560 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
534 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
561 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
535
562
536 return _ApplicationSettingsForm
563 return _ApplicationSettingsForm
537
564
538 def ApplicationUiSettingsForm():
565 def ApplicationUiSettingsForm():
539 class _ApplicationUiSettingsForm(formencode.Schema):
566 class _ApplicationUiSettingsForm(formencode.Schema):
540 allow_extra_fields = True
567 allow_extra_fields = True
541 filter_extra_fields = False
568 filter_extra_fields = False
542 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
569 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
543 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
570 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
544 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
571 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
545 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
572 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
546 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
573 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
547 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
574 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
548
575
549 return _ApplicationUiSettingsForm
576 return _ApplicationUiSettingsForm
550
577
551 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
578 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
552 class _DefaultPermissionsForm(formencode.Schema):
579 class _DefaultPermissionsForm(formencode.Schema):
553 allow_extra_fields = True
580 allow_extra_fields = True
554 filter_extra_fields = True
581 filter_extra_fields = True
555 overwrite_default = StringBoolean(if_missing=False)
582 overwrite_default = StringBoolean(if_missing=False)
556 anonymous = OneOf(['True', 'False'], if_missing=False)
583 anonymous = OneOf(['True', 'False'], if_missing=False)
557 default_perm = OneOf(perms_choices)
584 default_perm = OneOf(perms_choices)
558 default_register = OneOf(register_choices)
585 default_register = OneOf(register_choices)
559 default_create = OneOf(create_choices)
586 default_create = OneOf(create_choices)
560
587
561 return _DefaultPermissionsForm
588 return _DefaultPermissionsForm
562
589
563
590
564 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
591 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
565 class _LdapSettingsForm(formencode.Schema):
592 class _LdapSettingsForm(formencode.Schema):
566 allow_extra_fields = True
593 allow_extra_fields = True
567 filter_extra_fields = True
594 filter_extra_fields = True
568 pre_validators = [LdapLibValidator]
595 pre_validators = [LdapLibValidator]
569 ldap_active = StringBoolean(if_missing=False)
596 ldap_active = StringBoolean(if_missing=False)
570 ldap_host = UnicodeString(strip=True,)
597 ldap_host = UnicodeString(strip=True,)
571 ldap_port = Number(strip=True,)
598 ldap_port = Number(strip=True,)
572 ldap_tls_kind = OneOf(tls_kind_choices)
599 ldap_tls_kind = OneOf(tls_kind_choices)
573 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
600 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
574 ldap_dn_user = UnicodeString(strip=True,)
601 ldap_dn_user = UnicodeString(strip=True,)
575 ldap_dn_pass = UnicodeString(strip=True,)
602 ldap_dn_pass = UnicodeString(strip=True,)
576 ldap_base_dn = UnicodeString(strip=True,)
603 ldap_base_dn = UnicodeString(strip=True,)
577 ldap_filter = UnicodeString(strip=True,)
604 ldap_filter = UnicodeString(strip=True,)
578 ldap_search_scope = OneOf(search_scope_choices)
605 ldap_search_scope = OneOf(search_scope_choices)
579 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
606 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
580 ldap_attr_firstname = UnicodeString(strip=True,)
607 ldap_attr_firstname = UnicodeString(strip=True,)
581 ldap_attr_lastname = UnicodeString(strip=True,)
608 ldap_attr_lastname = UnicodeString(strip=True,)
582 ldap_attr_email = UnicodeString(strip=True,)
609 ldap_attr_email = UnicodeString(strip=True,)
583
610
584 return _LdapSettingsForm
611 return _LdapSettingsForm
@@ -1,349 +1,355 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.repo
3 rhodecode.model.repo
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Repository model for rhodecode
6 Repository model for rhodecode
7
7
8 :created_on: Jun 5, 2010
8 :created_on: Jun 5, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 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 import os
25 import os
26 import shutil
26 import shutil
27 import logging
27 import logging
28 import traceback
28 import traceback
29 from datetime import datetime
29 from datetime import datetime
30
30
31 from sqlalchemy.orm import joinedload, make_transient
31 from sqlalchemy.orm import joinedload, make_transient
32
32
33 from vcs.utils.lazy import LazyProperty
33 from vcs.utils.lazy import LazyProperty
34 from vcs.backends import get_backend
34 from vcs.backends import get_backend
35
35
36 from rhodecode.model import BaseModel
36 from rhodecode.model import BaseModel
37 from rhodecode.model.caching_query import FromCache
37 from rhodecode.model.caching_query import FromCache
38 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
38 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
39 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi
39 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, Group
40 from rhodecode.model.user import UserModel
40 from rhodecode.model.user import UserModel
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 class RepoModel(BaseModel):
45 class RepoModel(BaseModel):
46
46
47 @LazyProperty
47 @LazyProperty
48 def repos_path(self):
48 def repos_path(self):
49 """Get's the repositories root path from database
49 """Get's the repositories root path from database
50 """
50 """
51
51
52 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
52 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
53 return q.ui_value
53 return q.ui_value
54
54
55 def get(self, repo_id, cache=False):
55 def get(self, repo_id, cache=False):
56 repo = self.sa.query(Repository)\
56 repo = self.sa.query(Repository)\
57 .filter(Repository.repo_id == repo_id)
57 .filter(Repository.repo_id == repo_id)
58
58
59 if cache:
59 if cache:
60 repo = repo.options(FromCache("sql_cache_short",
60 repo = repo.options(FromCache("sql_cache_short",
61 "get_repo_%s" % repo_id))
61 "get_repo_%s" % repo_id))
62 return repo.scalar()
62 return repo.scalar()
63
63
64 def get_by_repo_name(self, repo_name, cache=False):
64 def get_by_repo_name(self, repo_name, cache=False):
65 repo = self.sa.query(Repository)\
65 repo = self.sa.query(Repository)\
66 .filter(Repository.repo_name == repo_name)
66 .filter(Repository.repo_name == repo_name)
67
67
68 if cache:
68 if cache:
69 repo = repo.options(FromCache("sql_cache_short",
69 repo = repo.options(FromCache("sql_cache_short",
70 "get_repo_%s" % repo_name))
70 "get_repo_%s" % repo_name))
71 return repo.scalar()
71 return repo.scalar()
72
72
73 def get_full(self, repo_name, cache=False, invalidate=False):
73 def get_full(self, repo_name, cache=False, invalidate=False):
74 repo = self.sa.query(Repository)\
74 repo = self.sa.query(Repository)\
75 .options(joinedload(Repository.fork))\
75 .options(joinedload(Repository.fork))\
76 .options(joinedload(Repository.user))\
76 .options(joinedload(Repository.user))\
77 .filter(Repository.repo_name == repo_name)\
77 .filter(Repository.repo_name == repo_name)\
78
78
79 if cache:
79 if cache:
80 repo = repo.options(FromCache("sql_cache_long",
80 repo = repo.options(FromCache("sql_cache_long",
81 "get_repo_full_%s" % repo_name))
81 "get_repo_full_%s" % repo_name))
82 if invalidate and cache:
82 if invalidate and cache:
83 repo.invalidate()
83 repo.invalidate()
84
84
85 ret = repo.scalar()
85 ret = repo.scalar()
86
86
87 #make transient for sake of errors
87 #make transient for sake of errors
88 make_transient(ret)
88 make_transient(ret)
89 for k in ['fork', 'user']:
89 for k in ['fork', 'user']:
90 attr = getattr(ret, k, False)
90 attr = getattr(ret, k, False)
91 if attr:
91 if attr:
92 make_transient(attr)
92 make_transient(attr)
93 return ret
93 return ret
94
94
95 def get_users_js(self):
95 def get_users_js(self):
96
96
97 users = self.sa.query(User).filter(User.active == True).all()
97 users = self.sa.query(User).filter(User.active == True).all()
98 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
98 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
99 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
99 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
100 u.lastname, u.username)
100 u.lastname, u.username)
101 for u in users])
101 for u in users])
102 return users_array
102 return users_array
103
103
104 def get_users_groups_js(self):
104 def get_users_groups_js(self):
105 users_groups = self.sa.query(UsersGroup)\
105 users_groups = self.sa.query(UsersGroup)\
106 .filter(UsersGroup.users_group_active == True).all()
106 .filter(UsersGroup.users_group_active == True).all()
107
107
108 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
108 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
109
109
110 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
110 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
111 (gr.users_group_id, gr.users_group_name,
111 (gr.users_group_id, gr.users_group_name,
112 len(gr.members))
112 len(gr.members))
113 for gr in users_groups])
113 for gr in users_groups])
114 return users_groups_array
114 return users_groups_array
115
115
116 def update(self, repo_name, form_data):
116 def update(self, repo_name, form_data):
117 try:
117 try:
118 cur_repo = self.get_by_repo_name(repo_name, cache=False)
118 cur_repo = self.get_by_repo_name(repo_name, cache=False)
119 user_model = UserModel(self.sa)
119 user_model = UserModel(self.sa)
120
120
121 #update permissions
121 #update permissions
122 for member, perm, member_type in form_data['perms_updates']:
122 for member, perm, member_type in form_data['perms_updates']:
123 if member_type == 'user':
123 if member_type == 'user':
124 r2p = self.sa.query(RepoToPerm)\
124 r2p = self.sa.query(RepoToPerm)\
125 .filter(RepoToPerm.user == user_model.
125 .filter(RepoToPerm.user == user_model.
126 get_by_username(member))\
126 get_by_username(member))\
127 .filter(RepoToPerm.repository == cur_repo)\
127 .filter(RepoToPerm.repository == cur_repo)\
128 .one()
128 .one()
129
129
130 r2p.permission = self.sa.query(Permission)\
130 r2p.permission = self.sa.query(Permission)\
131 .filter(Permission.permission_name ==
131 .filter(Permission.permission_name ==
132 perm).scalar()
132 perm).scalar()
133 self.sa.add(r2p)
133 self.sa.add(r2p)
134 else:
134 else:
135 g2p = self.sa.query(UsersGroupRepoToPerm)\
135 g2p = self.sa.query(UsersGroupRepoToPerm)\
136 .filter(UsersGroupRepoToPerm.users_group ==
136 .filter(UsersGroupRepoToPerm.users_group ==
137 UsersGroup.get_by_group_name(member))\
137 UsersGroup.get_by_group_name(member))\
138 .filter(UsersGroupRepoToPerm.repository ==
138 .filter(UsersGroupRepoToPerm.repository ==
139 cur_repo).one()
139 cur_repo).one()
140
140
141 g2p.permission = self.sa.query(Permission)\
141 g2p.permission = self.sa.query(Permission)\
142 .filter(Permission.permission_name ==
142 .filter(Permission.permission_name ==
143 perm).scalar()
143 perm).scalar()
144 self.sa.add(g2p)
144 self.sa.add(g2p)
145
145
146 #set new permissions
146 #set new permissions
147 for member, perm, member_type in form_data['perms_new']:
147 for member, perm, member_type in form_data['perms_new']:
148 if member_type == 'user':
148 if member_type == 'user':
149 r2p = RepoToPerm()
149 r2p = RepoToPerm()
150 r2p.repository = cur_repo
150 r2p.repository = cur_repo
151 r2p.user = user_model.get_by_username(member)
151 r2p.user = user_model.get_by_username(member)
152
152
153 r2p.permission = self.sa.query(Permission)\
153 r2p.permission = self.sa.query(Permission)\
154 .filter(Permission.
154 .filter(Permission.
155 permission_name == perm)\
155 permission_name == perm)\
156 .scalar()
156 .scalar()
157 self.sa.add(r2p)
157 self.sa.add(r2p)
158 else:
158 else:
159 g2p = UsersGroupRepoToPerm()
159 g2p = UsersGroupRepoToPerm()
160 g2p.repository = cur_repo
160 g2p.repository = cur_repo
161 g2p.users_group = UsersGroup.get_by_group_name(member)
161 g2p.users_group = UsersGroup.get_by_group_name(member)
162
162
163 g2p.permission = self.sa.query(Permission)\
163 g2p.permission = self.sa.query(Permission)\
164 .filter(Permission.
164 .filter(Permission.
165 permission_name == perm)\
165 permission_name == perm)\
166 .scalar()
166 .scalar()
167 self.sa.add(g2p)
167 self.sa.add(g2p)
168
168
169 #update current repo
169 #update current repo
170 for k, v in form_data.items():
170 for k, v in form_data.items():
171 if k == 'user':
171 if k == 'user':
172 cur_repo.user = user_model.get(v)
172 cur_repo.user = user_model.get_by_username(v)
173 elif k == 'repo_name':
174 cur_repo.repo_name = form_data['repo_name_full']
175 elif k == 'repo_group' and v:
176 cur_repo.group_id = v
177
173 else:
178 else:
174 setattr(cur_repo, k, v)
179 setattr(cur_repo, k, v)
175
180
176 self.sa.add(cur_repo)
181 self.sa.add(cur_repo)
177
182
178 if repo_name != form_data['repo_name']:
183 if repo_name != form_data['repo_name_full']:
179 #rename our data
184 # rename repository
180 self.__rename_repo(repo_name, form_data['repo_name'])
185 self.__rename_repo(old=repo_name,
186 new=form_data['repo_name_full'])
181
187
182 self.sa.commit()
188 self.sa.commit()
183 except:
189 except:
184 log.error(traceback.format_exc())
190 log.error(traceback.format_exc())
185 self.sa.rollback()
191 self.sa.rollback()
186 raise
192 raise
187
193
188 def create(self, form_data, cur_user, just_db=False, fork=False):
194 def create(self, form_data, cur_user, just_db=False, fork=False):
189 try:
195 try:
190 if fork:
196 if fork:
191 #force str since hg doesn't go with unicode
197 #force str since hg doesn't go with unicode
192 repo_name = str(form_data['fork_name'])
198 repo_name = str(form_data['fork_name'])
193 org_name = str(form_data['repo_name'])
199 org_name = str(form_data['repo_name'])
194
200
195 else:
201 else:
196 org_name = repo_name = str(form_data['repo_name'])
202 org_name = repo_name = str(form_data['repo_name'])
197 new_repo = Repository()
203 new_repo = Repository()
198 new_repo.enable_statistics = False
204 new_repo.enable_statistics = False
199 for k, v in form_data.items():
205 for k, v in form_data.items():
200 if k == 'repo_name':
206 if k == 'repo_name':
201 v = repo_name
207 v = repo_name
202 setattr(new_repo, k, v)
208 setattr(new_repo, k, v)
203
209
204 if fork:
210 if fork:
205 parent_repo = self.sa.query(Repository)\
211 parent_repo = self.sa.query(Repository)\
206 .filter(Repository.repo_name == org_name).scalar()
212 .filter(Repository.repo_name == org_name).scalar()
207 new_repo.fork = parent_repo
213 new_repo.fork = parent_repo
208
214
209 new_repo.user_id = cur_user.user_id
215 new_repo.user_id = cur_user.user_id
210 self.sa.add(new_repo)
216 self.sa.add(new_repo)
211
217
212 #create default permission
218 #create default permission
213 repo_to_perm = RepoToPerm()
219 repo_to_perm = RepoToPerm()
214 default = 'repository.read'
220 default = 'repository.read'
215 for p in UserModel(self.sa).get_by_username('default',
221 for p in UserModel(self.sa).get_by_username('default',
216 cache=False).user_perms:
222 cache=False).user_perms:
217 if p.permission.permission_name.startswith('repository.'):
223 if p.permission.permission_name.startswith('repository.'):
218 default = p.permission.permission_name
224 default = p.permission.permission_name
219 break
225 break
220
226
221 default_perm = 'repository.none' if form_data['private'] else default
227 default_perm = 'repository.none' if form_data['private'] else default
222
228
223 repo_to_perm.permission_id = self.sa.query(Permission)\
229 repo_to_perm.permission_id = self.sa.query(Permission)\
224 .filter(Permission.permission_name == default_perm)\
230 .filter(Permission.permission_name == default_perm)\
225 .one().permission_id
231 .one().permission_id
226
232
227 repo_to_perm.repository = new_repo
233 repo_to_perm.repository = new_repo
228 repo_to_perm.user_id = UserModel(self.sa)\
234 repo_to_perm.user_id = UserModel(self.sa)\
229 .get_by_username('default', cache=False).user_id
235 .get_by_username('default', cache=False).user_id
230
236
231 self.sa.add(repo_to_perm)
237 self.sa.add(repo_to_perm)
232
238
233 if not just_db:
239 if not just_db:
234 self.__create_repo(repo_name, form_data['repo_type'],
240 self.__create_repo(repo_name, form_data['repo_type'],
235 form_data['clone_uri'])
241 form_data['clone_uri'])
236
242
237 self.sa.commit()
243 self.sa.commit()
238
244
239 #now automatically start following this repository as owner
245 #now automatically start following this repository as owner
240 from rhodecode.model.scm import ScmModel
246 from rhodecode.model.scm import ScmModel
241 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
247 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
242 cur_user.user_id)
248 cur_user.user_id)
243
249
244 except:
250 except:
245 log.error(traceback.format_exc())
251 log.error(traceback.format_exc())
246 self.sa.rollback()
252 self.sa.rollback()
247 raise
253 raise
248
254
249 def create_fork(self, form_data, cur_user):
255 def create_fork(self, form_data, cur_user):
250 from rhodecode.lib.celerylib import tasks, run_task
256 from rhodecode.lib.celerylib import tasks, run_task
251 run_task(tasks.create_repo_fork, form_data, cur_user)
257 run_task(tasks.create_repo_fork, form_data, cur_user)
252
258
253 def delete(self, repo):
259 def delete(self, repo):
254 try:
260 try:
255 self.sa.delete(repo)
261 self.sa.delete(repo)
256 self.__delete_repo(repo)
262 self.__delete_repo(repo)
257 self.sa.commit()
263 self.sa.commit()
258 except:
264 except:
259 log.error(traceback.format_exc())
265 log.error(traceback.format_exc())
260 self.sa.rollback()
266 self.sa.rollback()
261 raise
267 raise
262
268
263 def delete_perm_user(self, form_data, repo_name):
269 def delete_perm_user(self, form_data, repo_name):
264 try:
270 try:
265 self.sa.query(RepoToPerm)\
271 self.sa.query(RepoToPerm)\
266 .filter(RepoToPerm.repository \
272 .filter(RepoToPerm.repository \
267 == self.get_by_repo_name(repo_name))\
273 == self.get_by_repo_name(repo_name))\
268 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
274 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
269 self.sa.commit()
275 self.sa.commit()
270 except:
276 except:
271 log.error(traceback.format_exc())
277 log.error(traceback.format_exc())
272 self.sa.rollback()
278 self.sa.rollback()
273 raise
279 raise
274
280
275 def delete_perm_users_group(self, form_data, repo_name):
281 def delete_perm_users_group(self, form_data, repo_name):
276 try:
282 try:
277 self.sa.query(UsersGroupRepoToPerm)\
283 self.sa.query(UsersGroupRepoToPerm)\
278 .filter(UsersGroupRepoToPerm.repository \
284 .filter(UsersGroupRepoToPerm.repository \
279 == self.get_by_repo_name(repo_name))\
285 == self.get_by_repo_name(repo_name))\
280 .filter(UsersGroupRepoToPerm.users_group_id \
286 .filter(UsersGroupRepoToPerm.users_group_id \
281 == form_data['users_group_id']).delete()
287 == form_data['users_group_id']).delete()
282 self.sa.commit()
288 self.sa.commit()
283 except:
289 except:
284 log.error(traceback.format_exc())
290 log.error(traceback.format_exc())
285 self.sa.rollback()
291 self.sa.rollback()
286 raise
292 raise
287
293
288 def delete_stats(self, repo_name):
294 def delete_stats(self, repo_name):
289 try:
295 try:
290 self.sa.query(Statistics)\
296 self.sa.query(Statistics)\
291 .filter(Statistics.repository == \
297 .filter(Statistics.repository == \
292 self.get_by_repo_name(repo_name)).delete()
298 self.get_by_repo_name(repo_name)).delete()
293 self.sa.commit()
299 self.sa.commit()
294 except:
300 except:
295 log.error(traceback.format_exc())
301 log.error(traceback.format_exc())
296 self.sa.rollback()
302 self.sa.rollback()
297 raise
303 raise
298
304
299 def __create_repo(self, repo_name, alias, clone_uri=False):
305 def __create_repo(self, repo_name, alias, clone_uri=False):
300 """
306 """
301 makes repository on filesystem
307 makes repository on filesystem
302
308
303 :param repo_name:
309 :param repo_name:
304 :param alias:
310 :param alias:
305 """
311 """
306 from rhodecode.lib.utils import check_repo
312 from rhodecode.lib.utils import check_repo
307 repo_path = os.path.join(self.repos_path, repo_name)
313 repo_path = os.path.join(self.repos_path, repo_name)
308 if check_repo(repo_name, self.repos_path):
314 if check_repo(repo_name, self.repos_path):
309 log.info('creating repo %s in %s @ %s', repo_name, repo_path,
315 log.info('creating repo %s in %s @ %s', repo_name, repo_path,
310 clone_uri)
316 clone_uri)
311 backend = get_backend(alias)
317 backend = get_backend(alias)
312 backend(repo_path, create=True, src_url=clone_uri)
318 backend(repo_path, create=True, src_url=clone_uri)
313
319
314 def __rename_repo(self, old, new):
320 def __rename_repo(self, old, new):
315 """
321 """
316 renames repository on filesystem
322 renames repository on filesystem
317
323
318 :param old: old name
324 :param old: old name
319 :param new: new name
325 :param new: new name
320 """
326 """
321 log.info('renaming repo from %s to %s', old, new)
327 log.info('renaming repo from %s to %s', old, new)
322
328
323 old_path = os.path.join(self.repos_path, old)
329 old_path = os.path.join(self.repos_path, old)
324 new_path = os.path.join(self.repos_path, new)
330 new_path = os.path.join(self.repos_path, new)
325 if os.path.isdir(new_path):
331 if os.path.isdir(new_path):
326 raise Exception('Was trying to rename to already existing dir %s',
332 raise Exception('Was trying to rename to already existing dir %s',
327 new_path)
333 new_path)
328 shutil.move(old_path, new_path)
334 shutil.move(old_path, new_path)
329
335
330 def __delete_repo(self, repo):
336 def __delete_repo(self, repo):
331 """
337 """
332 removes repo from filesystem, the removal is acctually made by
338 removes repo from filesystem, the removal is acctually made by
333 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
339 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
334 repository is no longer valid for rhodecode, can be undeleted later on
340 repository is no longer valid for rhodecode, can be undeleted later on
335 by reverting the renames on this repository
341 by reverting the renames on this repository
336
342
337 :param repo: repo object
343 :param repo: repo object
338 """
344 """
339 rm_path = os.path.join(self.repos_path, repo.repo_name)
345 rm_path = os.path.join(self.repos_path, repo.repo_name)
340 log.info("Removing %s", rm_path)
346 log.info("Removing %s", rm_path)
341 #disable hg/git
347 #disable hg/git
342 alias = repo.repo_type
348 alias = repo.repo_type
343 shutil.move(os.path.join(rm_path, '.%s' % alias),
349 shutil.move(os.path.join(rm_path, '.%s' % alias),
344 os.path.join(rm_path, 'rm__.%s' % alias))
350 os.path.join(rm_path, 'rm__.%s' % alias))
345 #disable repo
351 #disable repo
346 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
352 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
347 % (datetime.today()\
353 % (datetime.today()\
348 .strftime('%Y%m%d_%H%M%S_%f'),
354 .strftime('%Y%m%d_%H%M%S_%f'),
349 repo.repo_name)))
355 repo.repo_name)))
General Comments 0
You need to be logged in to leave comments. Login now