##// END OF EJS Templates
Pass in old groups data to CanWriteToGroup validator for later skipping group checks....
marcink -
r3524:af96fb19 beta
parent child Browse files
Show More
@@ -1,536 +1,538 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 Repositories controller for RhodeCode
6 Repositories 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) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29 from formencode import htmlfill
29 from formencode import htmlfill
30
30
31 from webob.exc import HTTPInternalServerError, HTTPForbidden
31 from webob.exc import HTTPInternalServerError, HTTPForbidden
32 from pylons import request, session, tmpl_context as c, url
32 from pylons import request, session, tmpl_context as c, url
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35 from sqlalchemy.exc import IntegrityError
35 from sqlalchemy.exc import IntegrityError
36
36
37 import rhodecode
37 import rhodecode
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator, NotAnonymous,\
40 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator, NotAnonymous,\
41 HasPermissionAny, HasReposGroupPermissionAny
41 HasPermissionAny, HasReposGroupPermissionAny
42 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
44 from rhodecode.lib.helpers import get_token
44 from rhodecode.lib.helpers import get_token
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
46 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
47 RhodeCodeSetting, RepositoryField
47 RhodeCodeSetting, RepositoryField
48 from rhodecode.model.forms import RepoForm, RepoFieldForm
48 from rhodecode.model.forms import RepoForm, RepoFieldForm
49 from rhodecode.model.scm import ScmModel, GroupList
49 from rhodecode.model.scm import ScmModel, GroupList
50 from rhodecode.model.repo import RepoModel
50 from rhodecode.model.repo import RepoModel
51 from rhodecode.lib.compat import json
51 from rhodecode.lib.compat import json
52 from sqlalchemy.sql.expression import func
52 from sqlalchemy.sql.expression import func
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56
56
57 class ReposController(BaseRepoController):
57 class ReposController(BaseRepoController):
58 """
58 """
59 REST Controller styled on the Atom Publishing Protocol"""
59 REST Controller styled on the Atom Publishing Protocol"""
60 # To properly map this controller, ensure your config/routing.py
60 # To properly map this controller, ensure your config/routing.py
61 # file has a resource setup:
61 # file has a resource setup:
62 # map.resource('repo', 'repos')
62 # map.resource('repo', 'repos')
63
63
64 @LoginRequired()
64 @LoginRequired()
65 def __before__(self):
65 def __before__(self):
66 c.admin_user = session.get('admin_user')
66 c.admin_user = session.get('admin_user')
67 c.admin_username = session.get('admin_username')
67 c.admin_username = session.get('admin_username')
68 super(ReposController, self).__before__()
68 super(ReposController, self).__before__()
69
69
70 def __load_defaults(self):
70 def __load_defaults(self):
71 acl_groups = GroupList(RepoGroup.query().all(),
71 acl_groups = GroupList(RepoGroup.query().all(),
72 perm_set=['group.write', 'group.admin'])
72 perm_set=['group.write', 'group.admin'])
73 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
73 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
74 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
74 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
75
75
76 repo_model = RepoModel()
76 repo_model = RepoModel()
77 c.users_array = repo_model.get_users_js()
77 c.users_array = repo_model.get_users_js()
78 c.users_groups_array = repo_model.get_users_groups_js()
78 c.users_groups_array = repo_model.get_users_groups_js()
79 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
79 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
80 c.landing_revs_choices = choices
80 c.landing_revs_choices = choices
81
81
82 def __load_data(self, repo_name=None):
82 def __load_data(self, repo_name=None):
83 """
83 """
84 Load defaults settings for edit, and update
84 Load defaults settings for edit, and update
85
85
86 :param repo_name:
86 :param repo_name:
87 """
87 """
88 self.__load_defaults()
88 self.__load_defaults()
89
89
90 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
90 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
91 repo = db_repo.scm_instance
91 repo = db_repo.scm_instance
92
92
93 if c.repo_info is None:
93 if c.repo_info is None:
94 h.not_mapped_error(repo_name)
94 h.not_mapped_error(repo_name)
95 return redirect(url('repos'))
95 return redirect(url('repos'))
96
96
97 ##override defaults for exact repo info here git/hg etc
97 ##override defaults for exact repo info here git/hg etc
98 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
98 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
99 c.landing_revs_choices = choices
99 c.landing_revs_choices = choices
100
100
101 c.default_user_id = User.get_by_username('default').user_id
101 c.default_user_id = User.get_by_username('default').user_id
102 c.in_public_journal = UserFollowing.query()\
102 c.in_public_journal = UserFollowing.query()\
103 .filter(UserFollowing.user_id == c.default_user_id)\
103 .filter(UserFollowing.user_id == c.default_user_id)\
104 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
104 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
105
105
106 if c.repo_info.stats:
106 if c.repo_info.stats:
107 # this is on what revision we ended up so we add +1 for count
107 # this is on what revision we ended up so we add +1 for count
108 last_rev = c.repo_info.stats.stat_on_revision + 1
108 last_rev = c.repo_info.stats.stat_on_revision + 1
109 else:
109 else:
110 last_rev = 0
110 last_rev = 0
111 c.stats_revision = last_rev
111 c.stats_revision = last_rev
112
112
113 c.repo_last_rev = repo.count() if repo.revisions else 0
113 c.repo_last_rev = repo.count() if repo.revisions else 0
114
114
115 if last_rev == 0 or c.repo_last_rev == 0:
115 if last_rev == 0 or c.repo_last_rev == 0:
116 c.stats_percentage = 0
116 c.stats_percentage = 0
117 else:
117 else:
118 c.stats_percentage = '%.2f' % ((float((last_rev)) /
118 c.stats_percentage = '%.2f' % ((float((last_rev)) /
119 c.repo_last_rev) * 100)
119 c.repo_last_rev) * 100)
120
120
121 c.repo_fields = RepositoryField.query()\
121 c.repo_fields = RepositoryField.query()\
122 .filter(RepositoryField.repository == db_repo).all()
122 .filter(RepositoryField.repository == db_repo).all()
123
123
124 defaults = RepoModel()._get_defaults(repo_name)
124 defaults = RepoModel()._get_defaults(repo_name)
125
125
126 c.repos_list = [('', _('--REMOVE FORK--'))]
126 c.repos_list = [('', _('--REMOVE FORK--'))]
127 c.repos_list += [(x.repo_id, x.repo_name) for x in
127 c.repos_list += [(x.repo_id, x.repo_name) for x in
128 Repository.query().order_by(Repository.repo_name).all()
128 Repository.query().order_by(Repository.repo_name).all()
129 if x.repo_id != c.repo_info.repo_id]
129 if x.repo_id != c.repo_info.repo_id]
130
130
131 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
131 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
132 return defaults
132 return defaults
133
133
134 @HasPermissionAllDecorator('hg.admin')
134 @HasPermissionAllDecorator('hg.admin')
135 def index(self, format='html'):
135 def index(self, format='html'):
136 """GET /repos: All items in the collection"""
136 """GET /repos: All items in the collection"""
137 # url('repos')
137 # url('repos')
138
138
139 c.repos_list = Repository.query()\
139 c.repos_list = Repository.query()\
140 .order_by(func.lower(Repository.repo_name))\
140 .order_by(func.lower(Repository.repo_name))\
141 .all()
141 .all()
142
142
143 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
143 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
144 admin=True,
144 admin=True,
145 super_user_actions=True)
145 super_user_actions=True)
146 #json used to render the grid
146 #json used to render the grid
147 c.data = json.dumps(repos_data)
147 c.data = json.dumps(repos_data)
148
148
149 return render('admin/repos/repos.html')
149 return render('admin/repos/repos.html')
150
150
151 @NotAnonymous()
151 @NotAnonymous()
152 def create(self):
152 def create(self):
153 """
153 """
154 POST /repos: Create a new item"""
154 POST /repos: Create a new item"""
155 # url('repos')
155 # url('repos')
156
156
157 self.__load_defaults()
157 self.__load_defaults()
158 form_result = {}
158 form_result = {}
159 try:
159 try:
160 form_result = RepoForm(repo_groups=c.repo_groups_choices,
160 form_result = RepoForm(repo_groups=c.repo_groups_choices,
161 landing_revs=c.landing_revs_choices)()\
161 landing_revs=c.landing_revs_choices)()\
162 .to_python(dict(request.POST))
162 .to_python(dict(request.POST))
163
163
164 new_repo = RepoModel().create(form_result,
164 new_repo = RepoModel().create(form_result,
165 self.rhodecode_user.user_id)
165 self.rhodecode_user.user_id)
166 if form_result['clone_uri']:
166 if form_result['clone_uri']:
167 h.flash(_('created repository %s from %s') \
167 h.flash(_('created repository %s from %s') \
168 % (form_result['repo_name'], form_result['clone_uri']),
168 % (form_result['repo_name'], form_result['clone_uri']),
169 category='success')
169 category='success')
170 else:
170 else:
171 h.flash(_('created repository %s') % form_result['repo_name'],
171 h.flash(_('created repository %s') % form_result['repo_name'],
172 category='success')
172 category='success')
173
173
174 if request.POST.get('user_created'):
174 if request.POST.get('user_created'):
175 # created by regular non admin user
175 # created by regular non admin user
176 action_logger(self.rhodecode_user, 'user_created_repo',
176 action_logger(self.rhodecode_user, 'user_created_repo',
177 form_result['repo_name_full'], self.ip_addr,
177 form_result['repo_name_full'], self.ip_addr,
178 self.sa)
178 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_full'], self.ip_addr,
181 form_result['repo_name_full'], self.ip_addr,
182 self.sa)
182 self.sa)
183 Session().commit()
183 Session().commit()
184 except formencode.Invalid, errors:
184 except formencode.Invalid, errors:
185 return htmlfill.render(
185 return htmlfill.render(
186 render('admin/repos/repo_add.html'),
186 render('admin/repos/repo_add.html'),
187 defaults=errors.value,
187 defaults=errors.value,
188 errors=errors.error_dict or {},
188 errors=errors.error_dict or {},
189 prefix_error=False,
189 prefix_error=False,
190 encoding="UTF-8")
190 encoding="UTF-8")
191
191
192 except Exception:
192 except Exception:
193 log.error(traceback.format_exc())
193 log.error(traceback.format_exc())
194 msg = _('error occurred during creation of repository %s') \
194 msg = _('error occurred during creation of repository %s') \
195 % form_result.get('repo_name')
195 % form_result.get('repo_name')
196 h.flash(msg, category='error')
196 h.flash(msg, category='error')
197 if c.rhodecode_user.is_admin:
197 if c.rhodecode_user.is_admin:
198 return redirect(url('repos'))
198 return redirect(url('repos'))
199 return redirect(url('home'))
199 return redirect(url('home'))
200 #redirect to our new repo !
200 #redirect to our new repo !
201 return redirect(url('summary_home', repo_name=new_repo.repo_name))
201 return redirect(url('summary_home', repo_name=new_repo.repo_name))
202
202
203 @HasPermissionAllDecorator('hg.admin')
203 @HasPermissionAllDecorator('hg.admin')
204 def new(self, format='html'):
204 def new(self, format='html'):
205 """
205 """
206 WARNING: this function is depracated see settings.create_repo !!
206 WARNING: this function is depracated see settings.create_repo !!
207
207
208 GET /repos/new: Form to create a new item
208 GET /repos/new: Form to create a new item
209 """
209 """
210
210
211 parent_group = request.GET.get('parent_group')
211 parent_group = request.GET.get('parent_group')
212 self.__load_defaults()
212 self.__load_defaults()
213 ## apply the defaults from defaults page
213 ## apply the defaults from defaults page
214 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
214 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
215 if parent_group:
215 if parent_group:
216 defaults.update({'repo_group': parent_group})
216 defaults.update({'repo_group': parent_group})
217
217
218 return htmlfill.render(
218 return htmlfill.render(
219 render('admin/repos/repo_add.html'),
219 render('admin/repos/repo_add.html'),
220 defaults=defaults,
220 defaults=defaults,
221 errors={},
221 errors={},
222 prefix_error=False,
222 prefix_error=False,
223 encoding="UTF-8"
223 encoding="UTF-8"
224 )
224 )
225
225
226 @HasPermissionAllDecorator('hg.admin')
226 @HasPermissionAllDecorator('hg.admin')
227 def update(self, repo_name):
227 def update(self, repo_name):
228 """
228 """
229 PUT /repos/repo_name: Update an existing item"""
229 PUT /repos/repo_name: Update an existing item"""
230 # Forms posted to this method should contain a hidden field:
230 # Forms posted to this method should contain a hidden field:
231 # <input type="hidden" name="_method" value="PUT" />
231 # <input type="hidden" name="_method" value="PUT" />
232 # Or using helpers:
232 # Or using helpers:
233 # h.form(url('repo', repo_name=ID),
233 # h.form(url('repo', repo_name=ID),
234 # method='put')
234 # method='put')
235 # url('repo', repo_name=ID)
235 # url('repo', repo_name=ID)
236 self.__load_defaults()
236 self.__load_defaults()
237 repo_model = RepoModel()
237 repo_model = RepoModel()
238 changed_name = repo_name
238 changed_name = repo_name
239 #override the choices with extracted revisions !
239 #override the choices with extracted revisions !
240 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
240 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
241 c.landing_revs_choices = choices
241 c.landing_revs_choices = choices
242
242 repo = Repository.get_by_repo_name(repo_name)
243 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
243 _form = RepoForm(edit=True, old_data={'repo_name': repo_name,
244 'repo_group': repo.group.get_dict() \
245 if repo.group else {}},
244 repo_groups=c.repo_groups_choices,
246 repo_groups=c.repo_groups_choices,
245 landing_revs=c.landing_revs_choices)()
247 landing_revs=c.landing_revs_choices)()
246 try:
248 try:
247 form_result = _form.to_python(dict(request.POST))
249 form_result = _form.to_python(dict(request.POST))
248 repo = repo_model.update(repo_name, **form_result)
250 repo = repo_model.update(repo_name, **form_result)
249 invalidate_cache('get_repo_cached_%s' % repo_name)
251 invalidate_cache('get_repo_cached_%s' % repo_name)
250 h.flash(_('Repository %s updated successfully') % repo_name,
252 h.flash(_('Repository %s updated successfully') % repo_name,
251 category='success')
253 category='success')
252 changed_name = repo.repo_name
254 changed_name = repo.repo_name
253 action_logger(self.rhodecode_user, 'admin_updated_repo',
255 action_logger(self.rhodecode_user, 'admin_updated_repo',
254 changed_name, self.ip_addr, self.sa)
256 changed_name, self.ip_addr, self.sa)
255 Session().commit()
257 Session().commit()
256 except formencode.Invalid, errors:
258 except formencode.Invalid, errors:
257 defaults = self.__load_data(repo_name)
259 defaults = self.__load_data(repo_name)
258 defaults.update(errors.value)
260 defaults.update(errors.value)
259 return htmlfill.render(
261 return htmlfill.render(
260 render('admin/repos/repo_edit.html'),
262 render('admin/repos/repo_edit.html'),
261 defaults=defaults,
263 defaults=defaults,
262 errors=errors.error_dict or {},
264 errors=errors.error_dict or {},
263 prefix_error=False,
265 prefix_error=False,
264 encoding="UTF-8")
266 encoding="UTF-8")
265
267
266 except Exception:
268 except Exception:
267 log.error(traceback.format_exc())
269 log.error(traceback.format_exc())
268 h.flash(_('error occurred during update of repository %s') \
270 h.flash(_('error occurred during update of repository %s') \
269 % repo_name, category='error')
271 % repo_name, category='error')
270 return redirect(url('edit_repo', repo_name=changed_name))
272 return redirect(url('edit_repo', repo_name=changed_name))
271
273
272 @HasPermissionAllDecorator('hg.admin')
274 @HasPermissionAllDecorator('hg.admin')
273 def delete(self, repo_name):
275 def delete(self, repo_name):
274 """
276 """
275 DELETE /repos/repo_name: Delete an existing item"""
277 DELETE /repos/repo_name: Delete an existing item"""
276 # Forms posted to this method should contain a hidden field:
278 # Forms posted to this method should contain a hidden field:
277 # <input type="hidden" name="_method" value="DELETE" />
279 # <input type="hidden" name="_method" value="DELETE" />
278 # Or using helpers:
280 # Or using helpers:
279 # h.form(url('repo', repo_name=ID),
281 # h.form(url('repo', repo_name=ID),
280 # method='delete')
282 # method='delete')
281 # url('repo', repo_name=ID)
283 # url('repo', repo_name=ID)
282
284
283 repo_model = RepoModel()
285 repo_model = RepoModel()
284 repo = repo_model.get_by_repo_name(repo_name)
286 repo = repo_model.get_by_repo_name(repo_name)
285 if not repo:
287 if not repo:
286 h.not_mapped_error(repo_name)
288 h.not_mapped_error(repo_name)
287 return redirect(url('repos'))
289 return redirect(url('repos'))
288 try:
290 try:
289 _forks = repo.forks.count()
291 _forks = repo.forks.count()
290 if _forks and request.POST.get('forks'):
292 if _forks and request.POST.get('forks'):
291 do = request.POST['forks']
293 do = request.POST['forks']
292 if do == 'detach_forks':
294 if do == 'detach_forks':
293 for r in repo.forks:
295 for r in repo.forks:
294 log.debug('Detaching fork %s from repo %s' % (r, repo))
296 log.debug('Detaching fork %s from repo %s' % (r, repo))
295 r.fork = None
297 r.fork = None
296 Session().add(r)
298 Session().add(r)
297 h.flash(_('detached %s forks') % _forks, category='success')
299 h.flash(_('detached %s forks') % _forks, category='success')
298 elif do == 'delete_forks':
300 elif do == 'delete_forks':
299 for r in repo.forks:
301 for r in repo.forks:
300 log.debug('Deleting fork %s of repo %s' % (r, repo))
302 log.debug('Deleting fork %s of repo %s' % (r, repo))
301 repo_model.delete(r)
303 repo_model.delete(r)
302 h.flash(_('deleted %s forks') % _forks, category='success')
304 h.flash(_('deleted %s forks') % _forks, category='success')
303 action_logger(self.rhodecode_user, 'admin_deleted_repo',
305 action_logger(self.rhodecode_user, 'admin_deleted_repo',
304 repo_name, self.ip_addr, self.sa)
306 repo_name, self.ip_addr, self.sa)
305 repo_model.delete(repo)
307 repo_model.delete(repo)
306 invalidate_cache('get_repo_cached_%s' % repo_name)
308 invalidate_cache('get_repo_cached_%s' % repo_name)
307 h.flash(_('deleted repository %s') % repo_name, category='success')
309 h.flash(_('deleted repository %s') % repo_name, category='success')
308 Session().commit()
310 Session().commit()
309 except IntegrityError, e:
311 except IntegrityError, e:
310 if e.message.find('repositories_fork_id_fkey') != -1:
312 if e.message.find('repositories_fork_id_fkey') != -1:
311 log.error(traceback.format_exc())
313 log.error(traceback.format_exc())
312 h.flash(_('Cannot delete %s it still contains attached '
314 h.flash(_('Cannot delete %s it still contains attached '
313 'forks') % repo_name,
315 'forks') % repo_name,
314 category='warning')
316 category='warning')
315 else:
317 else:
316 log.error(traceback.format_exc())
318 log.error(traceback.format_exc())
317 h.flash(_('An error occurred during '
319 h.flash(_('An error occurred during '
318 'deletion of %s') % repo_name,
320 'deletion of %s') % repo_name,
319 category='error')
321 category='error')
320
322
321 except Exception, e:
323 except Exception, e:
322 log.error(traceback.format_exc())
324 log.error(traceback.format_exc())
323 h.flash(_('An error occurred during deletion of %s') % repo_name,
325 h.flash(_('An error occurred during deletion of %s') % repo_name,
324 category='error')
326 category='error')
325
327
326 return redirect(url('repos'))
328 return redirect(url('repos'))
327
329
328 @HasRepoPermissionAllDecorator('repository.admin')
330 @HasRepoPermissionAllDecorator('repository.admin')
329 def delete_perm_user(self, repo_name):
331 def delete_perm_user(self, repo_name):
330 """
332 """
331 DELETE an existing repository permission user
333 DELETE an existing repository permission user
332
334
333 :param repo_name:
335 :param repo_name:
334 """
336 """
335 try:
337 try:
336 RepoModel().revoke_user_permission(repo=repo_name,
338 RepoModel().revoke_user_permission(repo=repo_name,
337 user=request.POST['user_id'])
339 user=request.POST['user_id'])
338 Session().commit()
340 Session().commit()
339 except Exception:
341 except Exception:
340 log.error(traceback.format_exc())
342 log.error(traceback.format_exc())
341 h.flash(_('An error occurred during deletion of repository user'),
343 h.flash(_('An error occurred during deletion of repository user'),
342 category='error')
344 category='error')
343 raise HTTPInternalServerError()
345 raise HTTPInternalServerError()
344
346
345 @HasRepoPermissionAllDecorator('repository.admin')
347 @HasRepoPermissionAllDecorator('repository.admin')
346 def delete_perm_users_group(self, repo_name):
348 def delete_perm_users_group(self, repo_name):
347 """
349 """
348 DELETE an existing repository permission user group
350 DELETE an existing repository permission user group
349
351
350 :param repo_name:
352 :param repo_name:
351 """
353 """
352
354
353 try:
355 try:
354 RepoModel().revoke_users_group_permission(
356 RepoModel().revoke_users_group_permission(
355 repo=repo_name, group_name=request.POST['users_group_id']
357 repo=repo_name, group_name=request.POST['users_group_id']
356 )
358 )
357 Session().commit()
359 Session().commit()
358 except Exception:
360 except Exception:
359 log.error(traceback.format_exc())
361 log.error(traceback.format_exc())
360 h.flash(_('An error occurred during deletion of repository'
362 h.flash(_('An error occurred during deletion of repository'
361 ' user groups'),
363 ' user groups'),
362 category='error')
364 category='error')
363 raise HTTPInternalServerError()
365 raise HTTPInternalServerError()
364
366
365 @HasPermissionAllDecorator('hg.admin')
367 @HasPermissionAllDecorator('hg.admin')
366 def repo_stats(self, repo_name):
368 def repo_stats(self, repo_name):
367 """
369 """
368 DELETE an existing repository statistics
370 DELETE an existing repository statistics
369
371
370 :param repo_name:
372 :param repo_name:
371 """
373 """
372
374
373 try:
375 try:
374 RepoModel().delete_stats(repo_name)
376 RepoModel().delete_stats(repo_name)
375 Session().commit()
377 Session().commit()
376 except Exception, e:
378 except Exception, e:
377 log.error(traceback.format_exc())
379 log.error(traceback.format_exc())
378 h.flash(_('An error occurred during deletion of repository stats'),
380 h.flash(_('An error occurred during deletion of repository stats'),
379 category='error')
381 category='error')
380 return redirect(url('edit_repo', repo_name=repo_name))
382 return redirect(url('edit_repo', repo_name=repo_name))
381
383
382 @HasPermissionAllDecorator('hg.admin')
384 @HasPermissionAllDecorator('hg.admin')
383 def repo_cache(self, repo_name):
385 def repo_cache(self, repo_name):
384 """
386 """
385 INVALIDATE existing repository cache
387 INVALIDATE existing repository cache
386
388
387 :param repo_name:
389 :param repo_name:
388 """
390 """
389
391
390 try:
392 try:
391 ScmModel().mark_for_invalidation(repo_name)
393 ScmModel().mark_for_invalidation(repo_name)
392 Session().commit()
394 Session().commit()
393 except Exception, e:
395 except Exception, e:
394 log.error(traceback.format_exc())
396 log.error(traceback.format_exc())
395 h.flash(_('An error occurred during cache invalidation'),
397 h.flash(_('An error occurred during cache invalidation'),
396 category='error')
398 category='error')
397 return redirect(url('edit_repo', repo_name=repo_name))
399 return redirect(url('edit_repo', repo_name=repo_name))
398
400
399 @HasPermissionAllDecorator('hg.admin')
401 @HasPermissionAllDecorator('hg.admin')
400 def repo_locking(self, repo_name):
402 def repo_locking(self, repo_name):
401 """
403 """
402 Unlock repository when it is locked !
404 Unlock repository when it is locked !
403
405
404 :param repo_name:
406 :param repo_name:
405 """
407 """
406
408
407 try:
409 try:
408 repo = Repository.get_by_repo_name(repo_name)
410 repo = Repository.get_by_repo_name(repo_name)
409 if request.POST.get('set_lock'):
411 if request.POST.get('set_lock'):
410 Repository.lock(repo, c.rhodecode_user.user_id)
412 Repository.lock(repo, c.rhodecode_user.user_id)
411 elif request.POST.get('set_unlock'):
413 elif request.POST.get('set_unlock'):
412 Repository.unlock(repo)
414 Repository.unlock(repo)
413 except Exception, e:
415 except Exception, e:
414 log.error(traceback.format_exc())
416 log.error(traceback.format_exc())
415 h.flash(_('An error occurred during unlocking'),
417 h.flash(_('An error occurred during unlocking'),
416 category='error')
418 category='error')
417 return redirect(url('edit_repo', repo_name=repo_name))
419 return redirect(url('edit_repo', repo_name=repo_name))
418
420
419 @HasPermissionAllDecorator('hg.admin')
421 @HasPermissionAllDecorator('hg.admin')
420 def repo_public_journal(self, repo_name):
422 def repo_public_journal(self, repo_name):
421 """
423 """
422 Set's this repository to be visible in public journal,
424 Set's this repository to be visible in public journal,
423 in other words assing default user to follow this repo
425 in other words assing default user to follow this repo
424
426
425 :param repo_name:
427 :param repo_name:
426 """
428 """
427
429
428 cur_token = request.POST.get('auth_token')
430 cur_token = request.POST.get('auth_token')
429 token = get_token()
431 token = get_token()
430 if cur_token == token:
432 if cur_token == token:
431 try:
433 try:
432 repo_id = Repository.get_by_repo_name(repo_name).repo_id
434 repo_id = Repository.get_by_repo_name(repo_name).repo_id
433 user_id = User.get_by_username('default').user_id
435 user_id = User.get_by_username('default').user_id
434 self.scm_model.toggle_following_repo(repo_id, user_id)
436 self.scm_model.toggle_following_repo(repo_id, user_id)
435 h.flash(_('Updated repository visibility in public journal'),
437 h.flash(_('Updated repository visibility in public journal'),
436 category='success')
438 category='success')
437 Session().commit()
439 Session().commit()
438 except:
440 except:
439 h.flash(_('An error occurred during setting this'
441 h.flash(_('An error occurred during setting this'
440 ' repository in public journal'),
442 ' repository in public journal'),
441 category='error')
443 category='error')
442
444
443 else:
445 else:
444 h.flash(_('Token mismatch'), category='error')
446 h.flash(_('Token mismatch'), category='error')
445 return redirect(url('edit_repo', repo_name=repo_name))
447 return redirect(url('edit_repo', repo_name=repo_name))
446
448
447 @HasPermissionAllDecorator('hg.admin')
449 @HasPermissionAllDecorator('hg.admin')
448 def repo_pull(self, repo_name):
450 def repo_pull(self, repo_name):
449 """
451 """
450 Runs task to update given repository with remote changes,
452 Runs task to update given repository with remote changes,
451 ie. make pull on remote location
453 ie. make pull on remote location
452
454
453 :param repo_name:
455 :param repo_name:
454 """
456 """
455 try:
457 try:
456 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
458 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
457 h.flash(_('Pulled from remote location'), category='success')
459 h.flash(_('Pulled from remote location'), category='success')
458 except Exception, e:
460 except Exception, e:
459 h.flash(_('An error occurred during pull from remote location'),
461 h.flash(_('An error occurred during pull from remote location'),
460 category='error')
462 category='error')
461
463
462 return redirect(url('edit_repo', repo_name=repo_name))
464 return redirect(url('edit_repo', repo_name=repo_name))
463
465
464 @HasPermissionAllDecorator('hg.admin')
466 @HasPermissionAllDecorator('hg.admin')
465 def repo_as_fork(self, repo_name):
467 def repo_as_fork(self, repo_name):
466 """
468 """
467 Mark given repository as a fork of another
469 Mark given repository as a fork of another
468
470
469 :param repo_name:
471 :param repo_name:
470 """
472 """
471 try:
473 try:
472 fork_id = request.POST.get('id_fork_of')
474 fork_id = request.POST.get('id_fork_of')
473 repo = ScmModel().mark_as_fork(repo_name, fork_id,
475 repo = ScmModel().mark_as_fork(repo_name, fork_id,
474 self.rhodecode_user.username)
476 self.rhodecode_user.username)
475 fork = repo.fork.repo_name if repo.fork else _('Nothing')
477 fork = repo.fork.repo_name if repo.fork else _('Nothing')
476 Session().commit()
478 Session().commit()
477 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
479 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
478 category='success')
480 category='success')
479 except Exception, e:
481 except Exception, e:
480 log.error(traceback.format_exc())
482 log.error(traceback.format_exc())
481 h.flash(_('An error occurred during this operation'),
483 h.flash(_('An error occurred during this operation'),
482 category='error')
484 category='error')
483
485
484 return redirect(url('edit_repo', repo_name=repo_name))
486 return redirect(url('edit_repo', repo_name=repo_name))
485
487
486 @HasPermissionAllDecorator('hg.admin')
488 @HasPermissionAllDecorator('hg.admin')
487 def show(self, repo_name, format='html'):
489 def show(self, repo_name, format='html'):
488 """GET /repos/repo_name: Show a specific item"""
490 """GET /repos/repo_name: Show a specific item"""
489 # url('repo', repo_name=ID)
491 # url('repo', repo_name=ID)
490
492
491 @HasPermissionAllDecorator('hg.admin')
493 @HasPermissionAllDecorator('hg.admin')
492 def edit(self, repo_name, format='html'):
494 def edit(self, repo_name, format='html'):
493 """GET /repos/repo_name/edit: Form to edit an existing item"""
495 """GET /repos/repo_name/edit: Form to edit an existing item"""
494 # url('edit_repo', repo_name=ID)
496 # url('edit_repo', repo_name=ID)
495 defaults = self.__load_data(repo_name)
497 defaults = self.__load_data(repo_name)
496
498
497 return htmlfill.render(
499 return htmlfill.render(
498 render('admin/repos/repo_edit.html'),
500 render('admin/repos/repo_edit.html'),
499 defaults=defaults,
501 defaults=defaults,
500 encoding="UTF-8",
502 encoding="UTF-8",
501 force_defaults=False
503 force_defaults=False
502 )
504 )
503
505
504 @HasPermissionAllDecorator('hg.admin')
506 @HasPermissionAllDecorator('hg.admin')
505 def create_repo_field(self, repo_name):
507 def create_repo_field(self, repo_name):
506 try:
508 try:
507 form_result = RepoFieldForm()().to_python(dict(request.POST))
509 form_result = RepoFieldForm()().to_python(dict(request.POST))
508 new_field = RepositoryField()
510 new_field = RepositoryField()
509 new_field.repository = Repository.get_by_repo_name(repo_name)
511 new_field.repository = Repository.get_by_repo_name(repo_name)
510 new_field.field_key = form_result['new_field_key']
512 new_field.field_key = form_result['new_field_key']
511 new_field.field_type = form_result['new_field_type'] # python type
513 new_field.field_type = form_result['new_field_type'] # python type
512 new_field.field_value = form_result['new_field_value'] # set initial blank value
514 new_field.field_value = form_result['new_field_value'] # set initial blank value
513 new_field.field_desc = form_result['new_field_desc']
515 new_field.field_desc = form_result['new_field_desc']
514 new_field.field_label = form_result['new_field_label']
516 new_field.field_label = form_result['new_field_label']
515 Session().add(new_field)
517 Session().add(new_field)
516 Session().commit()
518 Session().commit()
517
519
518 except Exception, e:
520 except Exception, e:
519 log.error(traceback.format_exc())
521 log.error(traceback.format_exc())
520 msg = _('An error occurred during creation of field')
522 msg = _('An error occurred during creation of field')
521 if isinstance(e, formencode.Invalid):
523 if isinstance(e, formencode.Invalid):
522 msg += ". " + e.msg
524 msg += ". " + e.msg
523 h.flash(msg, category='error')
525 h.flash(msg, category='error')
524 return redirect(url('edit_repo', repo_name=repo_name))
526 return redirect(url('edit_repo', repo_name=repo_name))
525
527
526 @HasPermissionAllDecorator('hg.admin')
528 @HasPermissionAllDecorator('hg.admin')
527 def delete_repo_field(self, repo_name, field_id):
529 def delete_repo_field(self, repo_name, field_id):
528 field = RepositoryField.get_or_404(field_id)
530 field = RepositoryField.get_or_404(field_id)
529 try:
531 try:
530 Session().delete(field)
532 Session().delete(field)
531 Session().commit()
533 Session().commit()
532 except Exception, e:
534 except Exception, e:
533 log.error(traceback.format_exc())
535 log.error(traceback.format_exc())
534 msg = _('An error occurred during removal of field')
536 msg = _('An error occurred during removal of field')
535 h.flash(msg, category='error')
537 h.flash(msg, category='error')
536 return redirect(url('edit_repo', repo_name=repo_name))
538 return redirect(url('edit_repo', repo_name=repo_name))
@@ -1,198 +1,200 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.settings
3 rhodecode.controllers.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Settings controller for rhodecode
6 Settings controller for rhodecode
7
7
8 :created_on: Jun 30, 2010
8 :created_on: Jun 30, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31
31
32 from pylons import tmpl_context as c, request, url
32 from pylons import tmpl_context as c, request, url
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 import rhodecode.lib.helpers as h
36 import rhodecode.lib.helpers as h
37
37
38 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator,\
38 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator,\
39 HasRepoPermissionAnyDecorator
39 HasRepoPermissionAnyDecorator
40 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.utils import invalidate_cache, action_logger
41 from rhodecode.lib.utils import invalidate_cache, action_logger
42
42
43 from rhodecode.model.forms import RepoSettingsForm
43 from rhodecode.model.forms import RepoSettingsForm
44 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.repo import RepoModel
45 from rhodecode.model.db import RepoGroup, Repository, RepositoryField
45 from rhodecode.model.db import RepoGroup, Repository, RepositoryField
46 from rhodecode.model.meta import Session
46 from rhodecode.model.meta import Session
47 from rhodecode.model.scm import ScmModel, GroupList
47 from rhodecode.model.scm import ScmModel, GroupList
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51
51
52 class SettingsController(BaseRepoController):
52 class SettingsController(BaseRepoController):
53
53
54 @LoginRequired()
54 @LoginRequired()
55 def __before__(self):
55 def __before__(self):
56 super(SettingsController, self).__before__()
56 super(SettingsController, self).__before__()
57
57
58 def __load_defaults(self):
58 def __load_defaults(self):
59 acl_groups = GroupList(RepoGroup.query().all(),
59 acl_groups = GroupList(RepoGroup.query().all(),
60 perm_set=['group.write', 'group.admin'])
60 perm_set=['group.write', 'group.admin'])
61 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
61 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
62 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
62 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
63
63
64 repo_model = RepoModel()
64 repo_model = RepoModel()
65 c.users_array = repo_model.get_users_js()
65 c.users_array = repo_model.get_users_js()
66 c.users_groups_array = repo_model.get_users_groups_js()
66 c.users_groups_array = repo_model.get_users_groups_js()
67 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
67 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
68 c.landing_revs_choices = choices
68 c.landing_revs_choices = choices
69
69
70 def __load_data(self, repo_name=None):
70 def __load_data(self, repo_name=None):
71 """
71 """
72 Load defaults settings for edit, and update
72 Load defaults settings for edit, and update
73
73
74 :param repo_name:
74 :param repo_name:
75 """
75 """
76 self.__load_defaults()
76 self.__load_defaults()
77
77
78 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
78 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
79
79
80 if c.repo_info is None:
80 if c.repo_info is None:
81 h.not_mapped_error(repo_name)
81 h.not_mapped_error(repo_name)
82 return redirect(url('home'))
82 return redirect(url('home'))
83
83
84 ##override defaults for exact repo info here git/hg etc
84 ##override defaults for exact repo info here git/hg etc
85 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
85 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
86 c.landing_revs_choices = choices
86 c.landing_revs_choices = choices
87 c.repo_fields = RepositoryField.query()\
87 c.repo_fields = RepositoryField.query()\
88 .filter(RepositoryField.repository == db_repo).all()
88 .filter(RepositoryField.repository == db_repo).all()
89 defaults = RepoModel()._get_defaults(repo_name)
89 defaults = RepoModel()._get_defaults(repo_name)
90
90
91 return defaults
91 return defaults
92
92
93 @HasRepoPermissionAllDecorator('repository.admin')
93 @HasRepoPermissionAllDecorator('repository.admin')
94 def index(self, repo_name):
94 def index(self, repo_name):
95 defaults = self.__load_data(repo_name)
95 defaults = self.__load_data(repo_name)
96
96
97 return htmlfill.render(
97 return htmlfill.render(
98 render('settings/repo_settings.html'),
98 render('settings/repo_settings.html'),
99 defaults=defaults,
99 defaults=defaults,
100 encoding="UTF-8",
100 encoding="UTF-8",
101 force_defaults=False
101 force_defaults=False
102 )
102 )
103
103
104 @HasRepoPermissionAllDecorator('repository.admin')
104 @HasRepoPermissionAllDecorator('repository.admin')
105 def update(self, repo_name):
105 def update(self, repo_name):
106 self.__load_defaults()
106 self.__load_defaults()
107 repo_model = RepoModel()
107 repo_model = RepoModel()
108 changed_name = repo_name
108 changed_name = repo_name
109 #override the choices with extracted revisions !
109 #override the choices with extracted revisions !
110 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
110 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
111 c.landing_revs_choices = choices
111 c.landing_revs_choices = choices
112
112 repo = Repository.get_by_repo_name(repo_name)
113 _form = RepoSettingsForm(edit=True,
113 _form = RepoSettingsForm(edit=True,
114 old_data={'repo_name': repo_name},
114 old_data={'repo_name': repo_name,
115 'repo_group': repo.group.get_dict() \
116 if repo.group else {}},
115 repo_groups=c.repo_groups_choices,
117 repo_groups=c.repo_groups_choices,
116 landing_revs=c.landing_revs_choices)()
118 landing_revs=c.landing_revs_choices)()
117 try:
119 try:
118 form_result = _form.to_python(dict(request.POST))
120 form_result = _form.to_python(dict(request.POST))
119 repo_model.update(repo_name, **form_result)
121 repo_model.update(repo_name, **form_result)
120 invalidate_cache('get_repo_cached_%s' % repo_name)
122 invalidate_cache('get_repo_cached_%s' % repo_name)
121 h.flash(_('Repository %s updated successfully') % repo_name,
123 h.flash(_('Repository %s updated successfully') % repo_name,
122 category='success')
124 category='success')
123 changed_name = form_result['repo_name_full']
125 changed_name = form_result['repo_name_full']
124 action_logger(self.rhodecode_user, 'user_updated_repo',
126 action_logger(self.rhodecode_user, 'user_updated_repo',
125 changed_name, self.ip_addr, self.sa)
127 changed_name, self.ip_addr, self.sa)
126 Session().commit()
128 Session().commit()
127 except formencode.Invalid, errors:
129 except formencode.Invalid, errors:
128 defaults = self.__load_data(repo_name)
130 defaults = self.__load_data(repo_name)
129 defaults.update(errors.value)
131 defaults.update(errors.value)
130 return htmlfill.render(
132 return htmlfill.render(
131 render('settings/repo_settings.html'),
133 render('settings/repo_settings.html'),
132 defaults=errors.value,
134 defaults=errors.value,
133 errors=errors.error_dict or {},
135 errors=errors.error_dict or {},
134 prefix_error=False,
136 prefix_error=False,
135 encoding="UTF-8")
137 encoding="UTF-8")
136
138
137 except Exception:
139 except Exception:
138 log.error(traceback.format_exc())
140 log.error(traceback.format_exc())
139 h.flash(_('error occurred during update of repository %s') \
141 h.flash(_('error occurred during update of repository %s') \
140 % repo_name, category='error')
142 % repo_name, category='error')
141
143
142 return redirect(url('repo_settings_home', repo_name=changed_name))
144 return redirect(url('repo_settings_home', repo_name=changed_name))
143
145
144 @HasRepoPermissionAllDecorator('repository.admin')
146 @HasRepoPermissionAllDecorator('repository.admin')
145 def delete(self, repo_name):
147 def delete(self, repo_name):
146 """DELETE /repos/repo_name: Delete an existing item"""
148 """DELETE /repos/repo_name: Delete an existing item"""
147 # Forms posted to this method should contain a hidden field:
149 # Forms posted to this method should contain a hidden field:
148 # <input type="hidden" name="_method" value="DELETE" />
150 # <input type="hidden" name="_method" value="DELETE" />
149 # Or using helpers:
151 # Or using helpers:
150 # h.form(url('repo_settings_delete', repo_name=ID),
152 # h.form(url('repo_settings_delete', repo_name=ID),
151 # method='delete')
153 # method='delete')
152 # url('repo_settings_delete', repo_name=ID)
154 # url('repo_settings_delete', repo_name=ID)
153
155
154 repo_model = RepoModel()
156 repo_model = RepoModel()
155 repo = repo_model.get_by_repo_name(repo_name)
157 repo = repo_model.get_by_repo_name(repo_name)
156 if not repo:
158 if not repo:
157 h.not_mapped_error(repo_name)
159 h.not_mapped_error(repo_name)
158 return redirect(url('home'))
160 return redirect(url('home'))
159 try:
161 try:
160 action_logger(self.rhodecode_user, 'user_deleted_repo',
162 action_logger(self.rhodecode_user, 'user_deleted_repo',
161 repo_name, self.ip_addr, self.sa)
163 repo_name, self.ip_addr, self.sa)
162 repo_model.delete(repo)
164 repo_model.delete(repo)
163 invalidate_cache('get_repo_cached_%s' % repo_name)
165 invalidate_cache('get_repo_cached_%s' % repo_name)
164 h.flash(_('deleted repository %s') % repo_name, category='success')
166 h.flash(_('deleted repository %s') % repo_name, category='success')
165 Session().commit()
167 Session().commit()
166 except Exception:
168 except Exception:
167 log.error(traceback.format_exc())
169 log.error(traceback.format_exc())
168 h.flash(_('An error occurred during deletion of %s') % repo_name,
170 h.flash(_('An error occurred during deletion of %s') % repo_name,
169 category='error')
171 category='error')
170
172
171 return redirect(url('admin_settings_my_account', anchor='my'))
173 return redirect(url('admin_settings_my_account', anchor='my'))
172
174
173 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
175 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
174 def toggle_locking(self, repo_name):
176 def toggle_locking(self, repo_name):
175 """
177 """
176 Toggle locking of repository by simple GET call to url
178 Toggle locking of repository by simple GET call to url
177
179
178 :param repo_name:
180 :param repo_name:
179 """
181 """
180
182
181 try:
183 try:
182 repo = Repository.get_by_repo_name(repo_name)
184 repo = Repository.get_by_repo_name(repo_name)
183
185
184 if repo.enable_locking:
186 if repo.enable_locking:
185 if repo.locked[0]:
187 if repo.locked[0]:
186 Repository.unlock(repo)
188 Repository.unlock(repo)
187 action = _('unlocked')
189 action = _('unlocked')
188 else:
190 else:
189 Repository.lock(repo, c.rhodecode_user.user_id)
191 Repository.lock(repo, c.rhodecode_user.user_id)
190 action = _('locked')
192 action = _('locked')
191
193
192 h.flash(_('Repository has been %s') % action,
194 h.flash(_('Repository has been %s') % action,
193 category='success')
195 category='success')
194 except Exception, e:
196 except Exception, e:
195 log.error(traceback.format_exc())
197 log.error(traceback.format_exc())
196 h.flash(_('An error occurred during unlocking'),
198 h.flash(_('An error occurred during unlocking'),
197 category='error')
199 category='error')
198 return redirect(url('summary_home', repo_name=repo_name))
200 return redirect(url('summary_home', repo_name=repo_name))
@@ -1,401 +1,401 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 logging
22 import logging
23
23
24 import formencode
24 import formencode
25 from formencode import All
25 from formencode import All
26
26
27 from pylons.i18n.translation import _
27 from pylons.i18n.translation import _
28
28
29 from rhodecode.model import validators as v
29 from rhodecode.model import validators as v
30 from rhodecode import BACKENDS
30 from rhodecode import BACKENDS
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 class LoginForm(formencode.Schema):
35 class LoginForm(formencode.Schema):
36 allow_extra_fields = True
36 allow_extra_fields = True
37 filter_extra_fields = True
37 filter_extra_fields = True
38 username = v.UnicodeString(
38 username = v.UnicodeString(
39 strip=True,
39 strip=True,
40 min=1,
40 min=1,
41 not_empty=True,
41 not_empty=True,
42 messages={
42 messages={
43 'empty': _(u'Please enter a login'),
43 'empty': _(u'Please enter a login'),
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 )
45 )
46
46
47 password = v.UnicodeString(
47 password = v.UnicodeString(
48 strip=False,
48 strip=False,
49 min=3,
49 min=3,
50 not_empty=True,
50 not_empty=True,
51 messages={
51 messages={
52 'empty': _(u'Please enter a password'),
52 'empty': _(u'Please enter a password'),
53 'tooShort': _(u'Enter %(min)i characters or more')}
53 'tooShort': _(u'Enter %(min)i characters or more')}
54 )
54 )
55
55
56 remember = v.StringBoolean(if_missing=False)
56 remember = v.StringBoolean(if_missing=False)
57
57
58 chained_validators = [v.ValidAuth()]
58 chained_validators = [v.ValidAuth()]
59
59
60
60
61 def UserForm(edit=False, old_data={}):
61 def UserForm(edit=False, old_data={}):
62 class _UserForm(formencode.Schema):
62 class _UserForm(formencode.Schema):
63 allow_extra_fields = True
63 allow_extra_fields = True
64 filter_extra_fields = True
64 filter_extra_fields = True
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 v.ValidUsername(edit, old_data))
66 v.ValidUsername(edit, old_data))
67 if edit:
67 if edit:
68 new_password = All(
68 new_password = All(
69 v.ValidPassword(),
69 v.ValidPassword(),
70 v.UnicodeString(strip=False, min=6, not_empty=False)
70 v.UnicodeString(strip=False, min=6, not_empty=False)
71 )
71 )
72 password_confirmation = All(
72 password_confirmation = All(
73 v.ValidPassword(),
73 v.ValidPassword(),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
75 )
75 )
76 admin = v.StringBoolean(if_missing=False)
76 admin = v.StringBoolean(if_missing=False)
77 else:
77 else:
78 password = All(
78 password = All(
79 v.ValidPassword(),
79 v.ValidPassword(),
80 v.UnicodeString(strip=False, min=6, not_empty=True)
80 v.UnicodeString(strip=False, min=6, not_empty=True)
81 )
81 )
82 password_confirmation = All(
82 password_confirmation = All(
83 v.ValidPassword(),
83 v.ValidPassword(),
84 v.UnicodeString(strip=False, min=6, not_empty=False)
84 v.UnicodeString(strip=False, min=6, not_empty=False)
85 )
85 )
86
86
87 active = v.StringBoolean(if_missing=False)
87 active = v.StringBoolean(if_missing=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
91
91
92 chained_validators = [v.ValidPasswordsMatch()]
92 chained_validators = [v.ValidPasswordsMatch()]
93
93
94 return _UserForm
94 return _UserForm
95
95
96
96
97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
98 class _UserGroupForm(formencode.Schema):
98 class _UserGroupForm(formencode.Schema):
99 allow_extra_fields = True
99 allow_extra_fields = True
100 filter_extra_fields = True
100 filter_extra_fields = True
101
101
102 users_group_name = All(
102 users_group_name = All(
103 v.UnicodeString(strip=True, min=1, not_empty=True),
103 v.UnicodeString(strip=True, min=1, not_empty=True),
104 v.ValidUserGroup(edit, old_data)
104 v.ValidUserGroup(edit, old_data)
105 )
105 )
106
106
107 users_group_active = v.StringBoolean(if_missing=False)
107 users_group_active = v.StringBoolean(if_missing=False)
108
108
109 if edit:
109 if edit:
110 users_group_members = v.OneOf(
110 users_group_members = v.OneOf(
111 available_members, hideList=False, testValueList=True,
111 available_members, hideList=False, testValueList=True,
112 if_missing=None, not_empty=False
112 if_missing=None, not_empty=False
113 )
113 )
114
114
115 return _UserGroupForm
115 return _UserGroupForm
116
116
117
117
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
119 can_create_in_root=False):
119 can_create_in_root=False):
120 class _ReposGroupForm(formencode.Schema):
120 class _ReposGroupForm(formencode.Schema):
121 allow_extra_fields = True
121 allow_extra_fields = True
122 filter_extra_fields = False
122 filter_extra_fields = False
123
123
124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
125 v.SlugifyName())
125 v.SlugifyName())
126 group_description = v.UnicodeString(strip=True, min=1,
126 group_description = v.UnicodeString(strip=True, min=1,
127 not_empty=False)
127 not_empty=False)
128 if edit:
128 if edit:
129 #FIXME: do a special check that we cannot move a group to one of
129 #FIXME: do a special check that we cannot move a group to one of
130 #it's children
130 #it's children
131 pass
131 pass
132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
133 v.OneOf(available_groups, hideList=False,
133 v.OneOf(available_groups, hideList=False,
134 testValueList=True,
134 testValueList=True,
135 if_missing=None, not_empty=True))
135 if_missing=None, not_empty=True))
136 enable_locking = v.StringBoolean(if_missing=False)
136 enable_locking = v.StringBoolean(if_missing=False)
137 recursive = v.StringBoolean(if_missing=False)
137 recursive = v.StringBoolean(if_missing=False)
138 chained_validators = [v.ValidReposGroup(edit, old_data),
138 chained_validators = [v.ValidReposGroup(edit, old_data),
139 v.ValidPerms('group')]
139 v.ValidPerms('group')]
140
140
141 return _ReposGroupForm
141 return _ReposGroupForm
142
142
143
143
144 def RegisterForm(edit=False, old_data={}):
144 def RegisterForm(edit=False, old_data={}):
145 class _RegisterForm(formencode.Schema):
145 class _RegisterForm(formencode.Schema):
146 allow_extra_fields = True
146 allow_extra_fields = True
147 filter_extra_fields = True
147 filter_extra_fields = True
148 username = All(
148 username = All(
149 v.ValidUsername(edit, old_data),
149 v.ValidUsername(edit, old_data),
150 v.UnicodeString(strip=True, min=1, not_empty=True)
150 v.UnicodeString(strip=True, min=1, not_empty=True)
151 )
151 )
152 password = All(
152 password = All(
153 v.ValidPassword(),
153 v.ValidPassword(),
154 v.UnicodeString(strip=False, min=6, not_empty=True)
154 v.UnicodeString(strip=False, min=6, not_empty=True)
155 )
155 )
156 password_confirmation = All(
156 password_confirmation = All(
157 v.ValidPassword(),
157 v.ValidPassword(),
158 v.UnicodeString(strip=False, min=6, not_empty=True)
158 v.UnicodeString(strip=False, min=6, not_empty=True)
159 )
159 )
160 active = v.StringBoolean(if_missing=False)
160 active = v.StringBoolean(if_missing=False)
161 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
161 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
162 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
162 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
163 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
163 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
164
164
165 chained_validators = [v.ValidPasswordsMatch()]
165 chained_validators = [v.ValidPasswordsMatch()]
166
166
167 return _RegisterForm
167 return _RegisterForm
168
168
169
169
170 def PasswordResetForm():
170 def PasswordResetForm():
171 class _PasswordResetForm(formencode.Schema):
171 class _PasswordResetForm(formencode.Schema):
172 allow_extra_fields = True
172 allow_extra_fields = True
173 filter_extra_fields = True
173 filter_extra_fields = True
174 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
174 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
175 return _PasswordResetForm
175 return _PasswordResetForm
176
176
177
177
178 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
178 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
179 repo_groups=[], landing_revs=[]):
179 repo_groups=[], landing_revs=[]):
180 class _RepoForm(formencode.Schema):
180 class _RepoForm(formencode.Schema):
181 allow_extra_fields = True
181 allow_extra_fields = True
182 filter_extra_fields = False
182 filter_extra_fields = False
183 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
183 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
184 v.SlugifyName())
184 v.SlugifyName())
185 repo_group = All(v.CanWriteGroup(),
185 repo_group = All(v.CanWriteGroup(old_data),
186 v.OneOf(repo_groups, hideList=True))
186 v.OneOf(repo_groups, hideList=True))
187 repo_type = v.OneOf(supported_backends)
187 repo_type = v.OneOf(supported_backends)
188 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
188 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
189 repo_private = v.StringBoolean(if_missing=False)
189 repo_private = v.StringBoolean(if_missing=False)
190 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
190 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
191 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
191 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
192
192
193 repo_enable_statistics = v.StringBoolean(if_missing=False)
193 repo_enable_statistics = v.StringBoolean(if_missing=False)
194 repo_enable_downloads = v.StringBoolean(if_missing=False)
194 repo_enable_downloads = v.StringBoolean(if_missing=False)
195 repo_enable_locking = v.StringBoolean(if_missing=False)
195 repo_enable_locking = v.StringBoolean(if_missing=False)
196
196
197 if edit:
197 if edit:
198 #this is repo owner
198 #this is repo owner
199 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
199 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
200
200
201 chained_validators = [v.ValidCloneUri(),
201 chained_validators = [v.ValidCloneUri(),
202 v.ValidRepoName(edit, old_data),
202 v.ValidRepoName(edit, old_data),
203 v.ValidPerms()]
203 v.ValidPerms()]
204 return _RepoForm
204 return _RepoForm
205
205
206
206
207 def RepoFieldForm():
207 def RepoFieldForm():
208 class _RepoFieldForm(formencode.Schema):
208 class _RepoFieldForm(formencode.Schema):
209 filter_extra_fields = True
209 filter_extra_fields = True
210 allow_extra_fields = True
210 allow_extra_fields = True
211
211
212 new_field_key = All(v.FieldKey(),
212 new_field_key = All(v.FieldKey(),
213 v.UnicodeString(strip=True, min=3, not_empty=True))
213 v.UnicodeString(strip=True, min=3, not_empty=True))
214 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
214 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
215 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
215 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
216 if_missing='str')
216 if_missing='str')
217 new_field_label = v.UnicodeString(not_empty=False)
217 new_field_label = v.UnicodeString(not_empty=False)
218 new_field_desc = v.UnicodeString(not_empty=False)
218 new_field_desc = v.UnicodeString(not_empty=False)
219
219
220 return _RepoFieldForm
220 return _RepoFieldForm
221
221
222
222
223 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
223 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
224 repo_groups=[], landing_revs=[]):
224 repo_groups=[], landing_revs=[]):
225 class _RepoForm(formencode.Schema):
225 class _RepoForm(formencode.Schema):
226 allow_extra_fields = True
226 allow_extra_fields = True
227 filter_extra_fields = False
227 filter_extra_fields = False
228 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
228 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
229 v.SlugifyName())
229 v.SlugifyName())
230 repo_group = All(v.CanWriteGroup(),
230 repo_group = All(v.CanWriteGroup(old_data),
231 v.OneOf(repo_groups, hideList=True))
231 v.OneOf(repo_groups, hideList=True))
232 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
232 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
233 repo_private = v.StringBoolean(if_missing=False)
233 repo_private = v.StringBoolean(if_missing=False)
234 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
234 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
235 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
235 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
236
236
237 chained_validators = [v.ValidCloneUri(),
237 chained_validators = [v.ValidCloneUri(),
238 v.ValidRepoName(edit, old_data),
238 v.ValidRepoName(edit, old_data),
239 v.ValidPerms(),
239 v.ValidPerms(),
240 v.ValidSettings()]
240 v.ValidSettings()]
241 return _RepoForm
241 return _RepoForm
242
242
243
243
244 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
244 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
245 repo_groups=[], landing_revs=[]):
245 repo_groups=[], landing_revs=[]):
246 class _RepoForkForm(formencode.Schema):
246 class _RepoForkForm(formencode.Schema):
247 allow_extra_fields = True
247 allow_extra_fields = True
248 filter_extra_fields = False
248 filter_extra_fields = False
249 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
249 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
250 v.SlugifyName())
250 v.SlugifyName())
251 repo_group = All(v.CanWriteGroup(),
251 repo_group = All(v.CanWriteGroup(),
252 v.OneOf(repo_groups, hideList=True))
252 v.OneOf(repo_groups, hideList=True))
253 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
253 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
254 description = v.UnicodeString(strip=True, min=1, not_empty=True)
254 description = v.UnicodeString(strip=True, min=1, not_empty=True)
255 private = v.StringBoolean(if_missing=False)
255 private = v.StringBoolean(if_missing=False)
256 copy_permissions = v.StringBoolean(if_missing=False)
256 copy_permissions = v.StringBoolean(if_missing=False)
257 update_after_clone = v.StringBoolean(if_missing=False)
257 update_after_clone = v.StringBoolean(if_missing=False)
258 fork_parent_id = v.UnicodeString()
258 fork_parent_id = v.UnicodeString()
259 chained_validators = [v.ValidForkName(edit, old_data)]
259 chained_validators = [v.ValidForkName(edit, old_data)]
260 landing_rev = v.OneOf(landing_revs, hideList=True)
260 landing_rev = v.OneOf(landing_revs, hideList=True)
261
261
262 return _RepoForkForm
262 return _RepoForkForm
263
263
264
264
265 def ApplicationSettingsForm():
265 def ApplicationSettingsForm():
266 class _ApplicationSettingsForm(formencode.Schema):
266 class _ApplicationSettingsForm(formencode.Schema):
267 allow_extra_fields = True
267 allow_extra_fields = True
268 filter_extra_fields = False
268 filter_extra_fields = False
269 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
269 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
270 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
270 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
271 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
271 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
272
272
273 return _ApplicationSettingsForm
273 return _ApplicationSettingsForm
274
274
275
275
276 def ApplicationVisualisationForm():
276 def ApplicationVisualisationForm():
277 class _ApplicationVisualisationForm(formencode.Schema):
277 class _ApplicationVisualisationForm(formencode.Schema):
278 allow_extra_fields = True
278 allow_extra_fields = True
279 filter_extra_fields = False
279 filter_extra_fields = False
280 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
280 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
281 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
281 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
282 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
282 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
283
283
284 rhodecode_lightweight_dashboard = v.StringBoolean(if_missing=False)
284 rhodecode_lightweight_dashboard = v.StringBoolean(if_missing=False)
285 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
285 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
286 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
286 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
287
287
288 return _ApplicationVisualisationForm
288 return _ApplicationVisualisationForm
289
289
290
290
291 def ApplicationUiSettingsForm():
291 def ApplicationUiSettingsForm():
292 class _ApplicationUiSettingsForm(formencode.Schema):
292 class _ApplicationUiSettingsForm(formencode.Schema):
293 allow_extra_fields = True
293 allow_extra_fields = True
294 filter_extra_fields = False
294 filter_extra_fields = False
295 web_push_ssl = v.StringBoolean(if_missing=False)
295 web_push_ssl = v.StringBoolean(if_missing=False)
296 paths_root_path = All(
296 paths_root_path = All(
297 v.ValidPath(),
297 v.ValidPath(),
298 v.UnicodeString(strip=True, min=1, not_empty=True)
298 v.UnicodeString(strip=True, min=1, not_empty=True)
299 )
299 )
300 hooks_changegroup_update = v.StringBoolean(if_missing=False)
300 hooks_changegroup_update = v.StringBoolean(if_missing=False)
301 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
301 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
302 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
302 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
303 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
303 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
304
304
305 extensions_largefiles = v.StringBoolean(if_missing=False)
305 extensions_largefiles = v.StringBoolean(if_missing=False)
306 extensions_hgsubversion = v.StringBoolean(if_missing=False)
306 extensions_hgsubversion = v.StringBoolean(if_missing=False)
307 extensions_hggit = v.StringBoolean(if_missing=False)
307 extensions_hggit = v.StringBoolean(if_missing=False)
308
308
309 return _ApplicationUiSettingsForm
309 return _ApplicationUiSettingsForm
310
310
311
311
312 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
312 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
313 register_choices, create_choices, fork_choices):
313 register_choices, create_choices, fork_choices):
314 class _DefaultPermissionsForm(formencode.Schema):
314 class _DefaultPermissionsForm(formencode.Schema):
315 allow_extra_fields = True
315 allow_extra_fields = True
316 filter_extra_fields = True
316 filter_extra_fields = True
317 overwrite_default_repo = v.StringBoolean(if_missing=False)
317 overwrite_default_repo = v.StringBoolean(if_missing=False)
318 overwrite_default_group = v.StringBoolean(if_missing=False)
318 overwrite_default_group = v.StringBoolean(if_missing=False)
319 anonymous = v.StringBoolean(if_missing=False)
319 anonymous = v.StringBoolean(if_missing=False)
320 default_repo_perm = v.OneOf(repo_perms_choices)
320 default_repo_perm = v.OneOf(repo_perms_choices)
321 default_group_perm = v.OneOf(group_perms_choices)
321 default_group_perm = v.OneOf(group_perms_choices)
322 default_register = v.OneOf(register_choices)
322 default_register = v.OneOf(register_choices)
323 default_create = v.OneOf(create_choices)
323 default_create = v.OneOf(create_choices)
324 default_fork = v.OneOf(fork_choices)
324 default_fork = v.OneOf(fork_choices)
325
325
326 return _DefaultPermissionsForm
326 return _DefaultPermissionsForm
327
327
328
328
329 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
329 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
330 class _DefaultsForm(formencode.Schema):
330 class _DefaultsForm(formencode.Schema):
331 allow_extra_fields = True
331 allow_extra_fields = True
332 filter_extra_fields = True
332 filter_extra_fields = True
333 default_repo_type = v.OneOf(supported_backends)
333 default_repo_type = v.OneOf(supported_backends)
334 default_repo_private = v.StringBoolean(if_missing=False)
334 default_repo_private = v.StringBoolean(if_missing=False)
335 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
335 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
336 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
336 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
337 default_repo_enable_locking = v.StringBoolean(if_missing=False)
337 default_repo_enable_locking = v.StringBoolean(if_missing=False)
338
338
339 return _DefaultsForm
339 return _DefaultsForm
340
340
341
341
342 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
342 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
343 tls_kind_choices):
343 tls_kind_choices):
344 class _LdapSettingsForm(formencode.Schema):
344 class _LdapSettingsForm(formencode.Schema):
345 allow_extra_fields = True
345 allow_extra_fields = True
346 filter_extra_fields = True
346 filter_extra_fields = True
347 #pre_validators = [LdapLibValidator]
347 #pre_validators = [LdapLibValidator]
348 ldap_active = v.StringBoolean(if_missing=False)
348 ldap_active = v.StringBoolean(if_missing=False)
349 ldap_host = v.UnicodeString(strip=True,)
349 ldap_host = v.UnicodeString(strip=True,)
350 ldap_port = v.Number(strip=True,)
350 ldap_port = v.Number(strip=True,)
351 ldap_tls_kind = v.OneOf(tls_kind_choices)
351 ldap_tls_kind = v.OneOf(tls_kind_choices)
352 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
352 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
353 ldap_dn_user = v.UnicodeString(strip=True,)
353 ldap_dn_user = v.UnicodeString(strip=True,)
354 ldap_dn_pass = v.UnicodeString(strip=True,)
354 ldap_dn_pass = v.UnicodeString(strip=True,)
355 ldap_base_dn = v.UnicodeString(strip=True,)
355 ldap_base_dn = v.UnicodeString(strip=True,)
356 ldap_filter = v.UnicodeString(strip=True,)
356 ldap_filter = v.UnicodeString(strip=True,)
357 ldap_search_scope = v.OneOf(search_scope_choices)
357 ldap_search_scope = v.OneOf(search_scope_choices)
358 ldap_attr_login = All(
358 ldap_attr_login = All(
359 v.AttrLoginValidator(),
359 v.AttrLoginValidator(),
360 v.UnicodeString(strip=True,)
360 v.UnicodeString(strip=True,)
361 )
361 )
362 ldap_attr_firstname = v.UnicodeString(strip=True,)
362 ldap_attr_firstname = v.UnicodeString(strip=True,)
363 ldap_attr_lastname = v.UnicodeString(strip=True,)
363 ldap_attr_lastname = v.UnicodeString(strip=True,)
364 ldap_attr_email = v.UnicodeString(strip=True,)
364 ldap_attr_email = v.UnicodeString(strip=True,)
365
365
366 return _LdapSettingsForm
366 return _LdapSettingsForm
367
367
368
368
369 def UserExtraEmailForm():
369 def UserExtraEmailForm():
370 class _UserExtraEmailForm(formencode.Schema):
370 class _UserExtraEmailForm(formencode.Schema):
371 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
371 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
372 return _UserExtraEmailForm
372 return _UserExtraEmailForm
373
373
374
374
375 def UserExtraIpForm():
375 def UserExtraIpForm():
376 class _UserExtraIpForm(formencode.Schema):
376 class _UserExtraIpForm(formencode.Schema):
377 ip = v.ValidIp()(not_empty=True)
377 ip = v.ValidIp()(not_empty=True)
378 return _UserExtraIpForm
378 return _UserExtraIpForm
379
379
380
380
381 def PullRequestForm(repo_id):
381 def PullRequestForm(repo_id):
382 class _PullRequestForm(formencode.Schema):
382 class _PullRequestForm(formencode.Schema):
383 allow_extra_fields = True
383 allow_extra_fields = True
384 filter_extra_fields = True
384 filter_extra_fields = True
385
385
386 user = v.UnicodeString(strip=True, required=True)
386 user = v.UnicodeString(strip=True, required=True)
387 org_repo = v.UnicodeString(strip=True, required=True)
387 org_repo = v.UnicodeString(strip=True, required=True)
388 org_ref = v.UnicodeString(strip=True, required=True)
388 org_ref = v.UnicodeString(strip=True, required=True)
389 other_repo = v.UnicodeString(strip=True, required=True)
389 other_repo = v.UnicodeString(strip=True, required=True)
390 other_ref = v.UnicodeString(strip=True, required=True)
390 other_ref = v.UnicodeString(strip=True, required=True)
391 revisions = All(#v.NotReviewedRevisions(repo_id)(),
391 revisions = All(#v.NotReviewedRevisions(repo_id)(),
392 v.UniqueList(not_empty=True))
392 v.UniqueList(not_empty=True))
393 review_members = v.UniqueList(not_empty=True)
393 review_members = v.UniqueList(not_empty=True)
394
394
395 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
395 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
396 pullrequest_desc = v.UnicodeString(strip=True, required=False)
396 pullrequest_desc = v.UnicodeString(strip=True, required=False)
397
397
398 ancestor_rev = v.UnicodeString(strip=True, required=True)
398 ancestor_rev = v.UnicodeString(strip=True, required=True)
399 merge_rev = v.UnicodeString(strip=True, required=True)
399 merge_rev = v.UnicodeString(strip=True, required=True)
400
400
401 return _PullRequestForm
401 return _PullRequestForm
@@ -1,813 +1,816 b''
1 """
1 """
2 Set of generic validators
2 Set of generic validators
3 """
3 """
4 import os
4 import os
5 import re
5 import re
6 import formencode
6 import formencode
7 import logging
7 import logging
8 from collections import defaultdict
8 from collections import defaultdict
9 from pylons.i18n.translation import _
9 from pylons.i18n.translation import _
10 from webhelpers.pylonslib.secure_form import authentication_token
10 from webhelpers.pylonslib.secure_form import authentication_token
11
11
12 from formencode.validators import (
12 from formencode.validators import (
13 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
13 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
14 NotEmpty, IPAddress, CIDR
14 NotEmpty, IPAddress, CIDR
15 )
15 )
16 from rhodecode.lib.compat import OrderedSet
16 from rhodecode.lib.compat import OrderedSet
17 from rhodecode.lib import ipaddr
17 from rhodecode.lib import ipaddr
18 from rhodecode.lib.utils import repo_name_slug
18 from rhodecode.lib.utils import repo_name_slug
19 from rhodecode.lib.utils2 import safe_int
19 from rhodecode.model.db import RepoGroup, Repository, UserGroup, User,\
20 from rhodecode.model.db import RepoGroup, Repository, UserGroup, User,\
20 ChangesetStatus
21 ChangesetStatus
21 from rhodecode.lib.exceptions import LdapImportError
22 from rhodecode.lib.exceptions import LdapImportError
22 from rhodecode.config.routing import ADMIN_PREFIX
23 from rhodecode.config.routing import ADMIN_PREFIX
23 from rhodecode.lib.auth import HasReposGroupPermissionAny, HasPermissionAny
24 from rhodecode.lib.auth import HasReposGroupPermissionAny, HasPermissionAny
24
25
25 # silence warnings and pylint
26 # silence warnings and pylint
26 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
27 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
27 NotEmpty, IPAddress, CIDR
28 NotEmpty, IPAddress, CIDR
28
29
29 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
30
31
31
32
32 class UniqueList(formencode.FancyValidator):
33 class UniqueList(formencode.FancyValidator):
33 """
34 """
34 Unique List !
35 Unique List !
35 """
36 """
36 messages = dict(
37 messages = dict(
37 empty=_('Value cannot be an empty list'),
38 empty=_('Value cannot be an empty list'),
38 missing_value=_('Value cannot be an empty list'),
39 missing_value=_('Value cannot be an empty list'),
39 )
40 )
40
41
41 def _to_python(self, value, state):
42 def _to_python(self, value, state):
42 if isinstance(value, list):
43 if isinstance(value, list):
43 return value
44 return value
44 elif isinstance(value, set):
45 elif isinstance(value, set):
45 return list(value)
46 return list(value)
46 elif isinstance(value, tuple):
47 elif isinstance(value, tuple):
47 return list(value)
48 return list(value)
48 elif value is None:
49 elif value is None:
49 return []
50 return []
50 else:
51 else:
51 return [value]
52 return [value]
52
53
53 def empty_value(self, value):
54 def empty_value(self, value):
54 return []
55 return []
55
56
56
57
57 class StateObj(object):
58 class StateObj(object):
58 """
59 """
59 this is needed to translate the messages using _() in validators
60 this is needed to translate the messages using _() in validators
60 """
61 """
61 _ = staticmethod(_)
62 _ = staticmethod(_)
62
63
63
64
64 def M(self, key, state=None, **kwargs):
65 def M(self, key, state=None, **kwargs):
65 """
66 """
66 returns string from self.message based on given key,
67 returns string from self.message based on given key,
67 passed kw params are used to substitute %(named)s params inside
68 passed kw params are used to substitute %(named)s params inside
68 translated strings
69 translated strings
69
70
70 :param msg:
71 :param msg:
71 :param state:
72 :param state:
72 """
73 """
73 if state is None:
74 if state is None:
74 state = StateObj()
75 state = StateObj()
75 else:
76 else:
76 state._ = staticmethod(_)
77 state._ = staticmethod(_)
77 #inject validator into state object
78 #inject validator into state object
78 return self.message(key, state, **kwargs)
79 return self.message(key, state, **kwargs)
79
80
80
81
81 def ValidUsername(edit=False, old_data={}):
82 def ValidUsername(edit=False, old_data={}):
82 class _validator(formencode.validators.FancyValidator):
83 class _validator(formencode.validators.FancyValidator):
83 messages = {
84 messages = {
84 'username_exists': _(u'Username "%(username)s" already exists'),
85 'username_exists': _(u'Username "%(username)s" already exists'),
85 'system_invalid_username':
86 'system_invalid_username':
86 _(u'Username "%(username)s" is forbidden'),
87 _(u'Username "%(username)s" is forbidden'),
87 'invalid_username':
88 'invalid_username':
88 _(u'Username may only contain alphanumeric characters '
89 _(u'Username may only contain alphanumeric characters '
89 'underscores, periods or dashes and must begin with '
90 'underscores, periods or dashes and must begin with '
90 'alphanumeric character')
91 'alphanumeric character')
91 }
92 }
92
93
93 def validate_python(self, value, state):
94 def validate_python(self, value, state):
94 if value in ['default', 'new_user']:
95 if value in ['default', 'new_user']:
95 msg = M(self, 'system_invalid_username', state, username=value)
96 msg = M(self, 'system_invalid_username', state, username=value)
96 raise formencode.Invalid(msg, value, state)
97 raise formencode.Invalid(msg, value, state)
97 #check if user is unique
98 #check if user is unique
98 old_un = None
99 old_un = None
99 if edit:
100 if edit:
100 old_un = User.get(old_data.get('user_id')).username
101 old_un = User.get(old_data.get('user_id')).username
101
102
102 if old_un != value or not edit:
103 if old_un != value or not edit:
103 if User.get_by_username(value, case_insensitive=True):
104 if User.get_by_username(value, case_insensitive=True):
104 msg = M(self, 'username_exists', state, username=value)
105 msg = M(self, 'username_exists', state, username=value)
105 raise formencode.Invalid(msg, value, state)
106 raise formencode.Invalid(msg, value, state)
106
107
107 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*$', value) is None:
108 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*$', value) is None:
108 msg = M(self, 'invalid_username', state)
109 msg = M(self, 'invalid_username', state)
109 raise formencode.Invalid(msg, value, state)
110 raise formencode.Invalid(msg, value, state)
110 return _validator
111 return _validator
111
112
112
113
113 def ValidRepoUser():
114 def ValidRepoUser():
114 class _validator(formencode.validators.FancyValidator):
115 class _validator(formencode.validators.FancyValidator):
115 messages = {
116 messages = {
116 'invalid_username': _(u'Username %(username)s is not valid')
117 'invalid_username': _(u'Username %(username)s is not valid')
117 }
118 }
118
119
119 def validate_python(self, value, state):
120 def validate_python(self, value, state):
120 try:
121 try:
121 User.query().filter(User.active == True)\
122 User.query().filter(User.active == True)\
122 .filter(User.username == value).one()
123 .filter(User.username == value).one()
123 except Exception:
124 except Exception:
124 msg = M(self, 'invalid_username', state, username=value)
125 msg = M(self, 'invalid_username', state, username=value)
125 raise formencode.Invalid(msg, value, state,
126 raise formencode.Invalid(msg, value, state,
126 error_dict=dict(username=msg)
127 error_dict=dict(username=msg)
127 )
128 )
128
129
129 return _validator
130 return _validator
130
131
131
132
132 def ValidUserGroup(edit=False, old_data={}):
133 def ValidUserGroup(edit=False, old_data={}):
133 class _validator(formencode.validators.FancyValidator):
134 class _validator(formencode.validators.FancyValidator):
134 messages = {
135 messages = {
135 'invalid_group': _(u'Invalid user group name'),
136 'invalid_group': _(u'Invalid user group name'),
136 'group_exist': _(u'User group "%(usergroup)s" already exists'),
137 'group_exist': _(u'User group "%(usergroup)s" already exists'),
137 'invalid_usergroup_name':
138 'invalid_usergroup_name':
138 _(u'user group name may only contain alphanumeric '
139 _(u'user group name may only contain alphanumeric '
139 'characters underscores, periods or dashes and must begin '
140 'characters underscores, periods or dashes and must begin '
140 'with alphanumeric character')
141 'with alphanumeric character')
141 }
142 }
142
143
143 def validate_python(self, value, state):
144 def validate_python(self, value, state):
144 if value in ['default']:
145 if value in ['default']:
145 msg = M(self, 'invalid_group', state)
146 msg = M(self, 'invalid_group', state)
146 raise formencode.Invalid(msg, value, state,
147 raise formencode.Invalid(msg, value, state,
147 error_dict=dict(users_group_name=msg)
148 error_dict=dict(users_group_name=msg)
148 )
149 )
149 #check if group is unique
150 #check if group is unique
150 old_ugname = None
151 old_ugname = None
151 if edit:
152 if edit:
152 old_id = old_data.get('users_group_id')
153 old_id = old_data.get('users_group_id')
153 old_ugname = UserGroup.get(old_id).users_group_name
154 old_ugname = UserGroup.get(old_id).users_group_name
154
155
155 if old_ugname != value or not edit:
156 if old_ugname != value or not edit:
156 is_existing_group = UserGroup.get_by_group_name(value,
157 is_existing_group = UserGroup.get_by_group_name(value,
157 case_insensitive=True)
158 case_insensitive=True)
158 if is_existing_group:
159 if is_existing_group:
159 msg = M(self, 'group_exist', state, usergroup=value)
160 msg = M(self, 'group_exist', state, usergroup=value)
160 raise formencode.Invalid(msg, value, state,
161 raise formencode.Invalid(msg, value, state,
161 error_dict=dict(users_group_name=msg)
162 error_dict=dict(users_group_name=msg)
162 )
163 )
163
164
164 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
165 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
165 msg = M(self, 'invalid_usergroup_name', state)
166 msg = M(self, 'invalid_usergroup_name', state)
166 raise formencode.Invalid(msg, value, state,
167 raise formencode.Invalid(msg, value, state,
167 error_dict=dict(users_group_name=msg)
168 error_dict=dict(users_group_name=msg)
168 )
169 )
169
170
170 return _validator
171 return _validator
171
172
172
173
173 def ValidReposGroup(edit=False, old_data={}):
174 def ValidReposGroup(edit=False, old_data={}):
174 class _validator(formencode.validators.FancyValidator):
175 class _validator(formencode.validators.FancyValidator):
175 messages = {
176 messages = {
176 'group_parent_id': _(u'Cannot assign this group as parent'),
177 'group_parent_id': _(u'Cannot assign this group as parent'),
177 'group_exists': _(u'Group "%(group_name)s" already exists'),
178 'group_exists': _(u'Group "%(group_name)s" already exists'),
178 'repo_exists':
179 'repo_exists':
179 _(u'Repository with name "%(group_name)s" already exists')
180 _(u'Repository with name "%(group_name)s" already exists')
180 }
181 }
181
182
182 def validate_python(self, value, state):
183 def validate_python(self, value, state):
183 # TODO WRITE VALIDATIONS
184 # TODO WRITE VALIDATIONS
184 group_name = value.get('group_name')
185 group_name = value.get('group_name')
185 group_parent_id = value.get('group_parent_id')
186 group_parent_id = value.get('group_parent_id')
186
187
187 # slugify repo group just in case :)
188 # slugify repo group just in case :)
188 slug = repo_name_slug(group_name)
189 slug = repo_name_slug(group_name)
189
190
190 # check for parent of self
191 # check for parent of self
191 parent_of_self = lambda: (
192 parent_of_self = lambda: (
192 old_data['group_id'] == int(group_parent_id)
193 old_data['group_id'] == int(group_parent_id)
193 if group_parent_id else False
194 if group_parent_id else False
194 )
195 )
195 if edit and parent_of_self():
196 if edit and parent_of_self():
196 msg = M(self, 'group_parent_id', state)
197 msg = M(self, 'group_parent_id', state)
197 raise formencode.Invalid(msg, value, state,
198 raise formencode.Invalid(msg, value, state,
198 error_dict=dict(group_parent_id=msg)
199 error_dict=dict(group_parent_id=msg)
199 )
200 )
200
201
201 old_gname = None
202 old_gname = None
202 if edit:
203 if edit:
203 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
204 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
204
205
205 if old_gname != group_name or not edit:
206 if old_gname != group_name or not edit:
206
207
207 # check group
208 # check group
208 gr = RepoGroup.query()\
209 gr = RepoGroup.query()\
209 .filter(RepoGroup.group_name == slug)\
210 .filter(RepoGroup.group_name == slug)\
210 .filter(RepoGroup.group_parent_id == group_parent_id)\
211 .filter(RepoGroup.group_parent_id == group_parent_id)\
211 .scalar()
212 .scalar()
212
213
213 if gr:
214 if gr:
214 msg = M(self, 'group_exists', state, group_name=slug)
215 msg = M(self, 'group_exists', state, group_name=slug)
215 raise formencode.Invalid(msg, value, state,
216 raise formencode.Invalid(msg, value, state,
216 error_dict=dict(group_name=msg)
217 error_dict=dict(group_name=msg)
217 )
218 )
218
219
219 # check for same repo
220 # check for same repo
220 repo = Repository.query()\
221 repo = Repository.query()\
221 .filter(Repository.repo_name == slug)\
222 .filter(Repository.repo_name == slug)\
222 .scalar()
223 .scalar()
223
224
224 if repo:
225 if repo:
225 msg = M(self, 'repo_exists', state, group_name=slug)
226 msg = M(self, 'repo_exists', state, group_name=slug)
226 raise formencode.Invalid(msg, value, state,
227 raise formencode.Invalid(msg, value, state,
227 error_dict=dict(group_name=msg)
228 error_dict=dict(group_name=msg)
228 )
229 )
229
230
230 return _validator
231 return _validator
231
232
232
233
233 def ValidPassword():
234 def ValidPassword():
234 class _validator(formencode.validators.FancyValidator):
235 class _validator(formencode.validators.FancyValidator):
235 messages = {
236 messages = {
236 'invalid_password':
237 'invalid_password':
237 _(u'Invalid characters (non-ascii) in password')
238 _(u'Invalid characters (non-ascii) in password')
238 }
239 }
239
240
240 def validate_python(self, value, state):
241 def validate_python(self, value, state):
241 try:
242 try:
242 (value or '').decode('ascii')
243 (value or '').decode('ascii')
243 except UnicodeError:
244 except UnicodeError:
244 msg = M(self, 'invalid_password', state)
245 msg = M(self, 'invalid_password', state)
245 raise formencode.Invalid(msg, value, state,)
246 raise formencode.Invalid(msg, value, state,)
246 return _validator
247 return _validator
247
248
248
249
249 def ValidPasswordsMatch():
250 def ValidPasswordsMatch():
250 class _validator(formencode.validators.FancyValidator):
251 class _validator(formencode.validators.FancyValidator):
251 messages = {
252 messages = {
252 'password_mismatch': _(u'Passwords do not match'),
253 'password_mismatch': _(u'Passwords do not match'),
253 }
254 }
254
255
255 def validate_python(self, value, state):
256 def validate_python(self, value, state):
256
257
257 pass_val = value.get('password') or value.get('new_password')
258 pass_val = value.get('password') or value.get('new_password')
258 if pass_val != value['password_confirmation']:
259 if pass_val != value['password_confirmation']:
259 msg = M(self, 'password_mismatch', state)
260 msg = M(self, 'password_mismatch', state)
260 raise formencode.Invalid(msg, value, state,
261 raise formencode.Invalid(msg, value, state,
261 error_dict=dict(password_confirmation=msg)
262 error_dict=dict(password_confirmation=msg)
262 )
263 )
263 return _validator
264 return _validator
264
265
265
266
266 def ValidAuth():
267 def ValidAuth():
267 class _validator(formencode.validators.FancyValidator):
268 class _validator(formencode.validators.FancyValidator):
268 messages = {
269 messages = {
269 'invalid_password': _(u'invalid password'),
270 'invalid_password': _(u'invalid password'),
270 'invalid_username': _(u'invalid user name'),
271 'invalid_username': _(u'invalid user name'),
271 'disabled_account': _(u'Your account is disabled')
272 'disabled_account': _(u'Your account is disabled')
272 }
273 }
273
274
274 def validate_python(self, value, state):
275 def validate_python(self, value, state):
275 from rhodecode.lib.auth import authenticate
276 from rhodecode.lib.auth import authenticate
276
277
277 password = value['password']
278 password = value['password']
278 username = value['username']
279 username = value['username']
279
280
280 if not authenticate(username, password):
281 if not authenticate(username, password):
281 user = User.get_by_username(username)
282 user = User.get_by_username(username)
282 if user and user.active is False:
283 if user and user.active is False:
283 log.warning('user %s is disabled' % username)
284 log.warning('user %s is disabled' % username)
284 msg = M(self, 'disabled_account', state)
285 msg = M(self, 'disabled_account', state)
285 raise formencode.Invalid(msg, value, state,
286 raise formencode.Invalid(msg, value, state,
286 error_dict=dict(username=msg)
287 error_dict=dict(username=msg)
287 )
288 )
288 else:
289 else:
289 log.warning('user %s failed to authenticate' % username)
290 log.warning('user %s failed to authenticate' % username)
290 msg = M(self, 'invalid_username', state)
291 msg = M(self, 'invalid_username', state)
291 msg2 = M(self, 'invalid_password', state)
292 msg2 = M(self, 'invalid_password', state)
292 raise formencode.Invalid(msg, value, state,
293 raise formencode.Invalid(msg, value, state,
293 error_dict=dict(username=msg, password=msg2)
294 error_dict=dict(username=msg, password=msg2)
294 )
295 )
295 return _validator
296 return _validator
296
297
297
298
298 def ValidAuthToken():
299 def ValidAuthToken():
299 class _validator(formencode.validators.FancyValidator):
300 class _validator(formencode.validators.FancyValidator):
300 messages = {
301 messages = {
301 'invalid_token': _(u'Token mismatch')
302 'invalid_token': _(u'Token mismatch')
302 }
303 }
303
304
304 def validate_python(self, value, state):
305 def validate_python(self, value, state):
305 if value != authentication_token():
306 if value != authentication_token():
306 msg = M(self, 'invalid_token', state)
307 msg = M(self, 'invalid_token', state)
307 raise formencode.Invalid(msg, value, state)
308 raise formencode.Invalid(msg, value, state)
308 return _validator
309 return _validator
309
310
310
311
311 def ValidRepoName(edit=False, old_data={}):
312 def ValidRepoName(edit=False, old_data={}):
312 class _validator(formencode.validators.FancyValidator):
313 class _validator(formencode.validators.FancyValidator):
313 messages = {
314 messages = {
314 'invalid_repo_name':
315 'invalid_repo_name':
315 _(u'Repository name %(repo)s is disallowed'),
316 _(u'Repository name %(repo)s is disallowed'),
316 'repository_exists':
317 'repository_exists':
317 _(u'Repository named %(repo)s already exists'),
318 _(u'Repository named %(repo)s already exists'),
318 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
319 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
319 'exists in group "%(group)s"'),
320 'exists in group "%(group)s"'),
320 'same_group_exists': _(u'Repository group with name "%(repo)s" '
321 'same_group_exists': _(u'Repository group with name "%(repo)s" '
321 'already exists')
322 'already exists')
322 }
323 }
323
324
324 def _to_python(self, value, state):
325 def _to_python(self, value, state):
325 repo_name = repo_name_slug(value.get('repo_name', ''))
326 repo_name = repo_name_slug(value.get('repo_name', ''))
326 repo_group = value.get('repo_group')
327 repo_group = value.get('repo_group')
327 if repo_group:
328 if repo_group:
328 gr = RepoGroup.get(repo_group)
329 gr = RepoGroup.get(repo_group)
329 group_path = gr.full_path
330 group_path = gr.full_path
330 group_name = gr.group_name
331 group_name = gr.group_name
331 # value needs to be aware of group name in order to check
332 # value needs to be aware of group name in order to check
332 # db key This is an actual just the name to store in the
333 # db key This is an actual just the name to store in the
333 # database
334 # database
334 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
335 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
335 else:
336 else:
336 group_name = group_path = ''
337 group_name = group_path = ''
337 repo_name_full = repo_name
338 repo_name_full = repo_name
338
339
339 value['repo_name'] = repo_name
340 value['repo_name'] = repo_name
340 value['repo_name_full'] = repo_name_full
341 value['repo_name_full'] = repo_name_full
341 value['group_path'] = group_path
342 value['group_path'] = group_path
342 value['group_name'] = group_name
343 value['group_name'] = group_name
343 return value
344 return value
344
345
345 def validate_python(self, value, state):
346 def validate_python(self, value, state):
346
347
347 repo_name = value.get('repo_name')
348 repo_name = value.get('repo_name')
348 repo_name_full = value.get('repo_name_full')
349 repo_name_full = value.get('repo_name_full')
349 group_path = value.get('group_path')
350 group_path = value.get('group_path')
350 group_name = value.get('group_name')
351 group_name = value.get('group_name')
351
352
352 if repo_name in [ADMIN_PREFIX, '']:
353 if repo_name in [ADMIN_PREFIX, '']:
353 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
354 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
354 raise formencode.Invalid(msg, value, state,
355 raise formencode.Invalid(msg, value, state,
355 error_dict=dict(repo_name=msg)
356 error_dict=dict(repo_name=msg)
356 )
357 )
357
358
358 rename = old_data.get('repo_name') != repo_name_full
359 rename = old_data.get('repo_name') != repo_name_full
359 create = not edit
360 create = not edit
360 if rename or create:
361 if rename or create:
361
362
362 if group_path != '':
363 if group_path != '':
363 if Repository.get_by_repo_name(repo_name_full):
364 if Repository.get_by_repo_name(repo_name_full):
364 msg = M(self, 'repository_in_group_exists', state,
365 msg = M(self, 'repository_in_group_exists', state,
365 repo=repo_name, group=group_name)
366 repo=repo_name, group=group_name)
366 raise formencode.Invalid(msg, value, state,
367 raise formencode.Invalid(msg, value, state,
367 error_dict=dict(repo_name=msg)
368 error_dict=dict(repo_name=msg)
368 )
369 )
369 elif RepoGroup.get_by_group_name(repo_name_full):
370 elif RepoGroup.get_by_group_name(repo_name_full):
370 msg = M(self, 'same_group_exists', state,
371 msg = M(self, 'same_group_exists', state,
371 repo=repo_name)
372 repo=repo_name)
372 raise formencode.Invalid(msg, value, state,
373 raise formencode.Invalid(msg, value, state,
373 error_dict=dict(repo_name=msg)
374 error_dict=dict(repo_name=msg)
374 )
375 )
375
376
376 elif Repository.get_by_repo_name(repo_name_full):
377 elif Repository.get_by_repo_name(repo_name_full):
377 msg = M(self, 'repository_exists', state,
378 msg = M(self, 'repository_exists', state,
378 repo=repo_name)
379 repo=repo_name)
379 raise formencode.Invalid(msg, value, state,
380 raise formencode.Invalid(msg, value, state,
380 error_dict=dict(repo_name=msg)
381 error_dict=dict(repo_name=msg)
381 )
382 )
382 return value
383 return value
383 return _validator
384 return _validator
384
385
385
386
386 def ValidForkName(*args, **kwargs):
387 def ValidForkName(*args, **kwargs):
387 return ValidRepoName(*args, **kwargs)
388 return ValidRepoName(*args, **kwargs)
388
389
389
390
390 def SlugifyName():
391 def SlugifyName():
391 class _validator(formencode.validators.FancyValidator):
392 class _validator(formencode.validators.FancyValidator):
392
393
393 def _to_python(self, value, state):
394 def _to_python(self, value, state):
394 return repo_name_slug(value)
395 return repo_name_slug(value)
395
396
396 def validate_python(self, value, state):
397 def validate_python(self, value, state):
397 pass
398 pass
398
399
399 return _validator
400 return _validator
400
401
401
402
402 def ValidCloneUri():
403 def ValidCloneUri():
403 from rhodecode.lib.utils import make_ui
404 from rhodecode.lib.utils import make_ui
404
405
405 def url_handler(repo_type, url, ui=None):
406 def url_handler(repo_type, url, ui=None):
406 if repo_type == 'hg':
407 if repo_type == 'hg':
407 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
408 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
408 from mercurial.httppeer import httppeer
409 from mercurial.httppeer import httppeer
409 if url.startswith('http'):
410 if url.startswith('http'):
410 ## initially check if it's at least the proper URL
411 ## initially check if it's at least the proper URL
411 ## or does it pass basic auth
412 ## or does it pass basic auth
412 MercurialRepository._check_url(url)
413 MercurialRepository._check_url(url)
413 httppeer(ui, url)._capabilities()
414 httppeer(ui, url)._capabilities()
414 elif url.startswith('svn+http'):
415 elif url.startswith('svn+http'):
415 from hgsubversion.svnrepo import svnremoterepo
416 from hgsubversion.svnrepo import svnremoterepo
416 svnremoterepo(ui, url).capabilities
417 svnremoterepo(ui, url).capabilities
417 elif url.startswith('git+http'):
418 elif url.startswith('git+http'):
418 raise NotImplementedError()
419 raise NotImplementedError()
419 else:
420 else:
420 raise Exception('clone from URI %s not allowed' % (url))
421 raise Exception('clone from URI %s not allowed' % (url))
421
422
422 elif repo_type == 'git':
423 elif repo_type == 'git':
423 from rhodecode.lib.vcs.backends.git.repository import GitRepository
424 from rhodecode.lib.vcs.backends.git.repository import GitRepository
424 if url.startswith('http'):
425 if url.startswith('http'):
425 ## initially check if it's at least the proper URL
426 ## initially check if it's at least the proper URL
426 ## or does it pass basic auth
427 ## or does it pass basic auth
427 GitRepository._check_url(url)
428 GitRepository._check_url(url)
428 elif url.startswith('svn+http'):
429 elif url.startswith('svn+http'):
429 raise NotImplementedError()
430 raise NotImplementedError()
430 elif url.startswith('hg+http'):
431 elif url.startswith('hg+http'):
431 raise NotImplementedError()
432 raise NotImplementedError()
432 else:
433 else:
433 raise Exception('clone from URI %s not allowed' % (url))
434 raise Exception('clone from URI %s not allowed' % (url))
434
435
435 class _validator(formencode.validators.FancyValidator):
436 class _validator(formencode.validators.FancyValidator):
436 messages = {
437 messages = {
437 'clone_uri': _(u'invalid clone url'),
438 'clone_uri': _(u'invalid clone url'),
438 'invalid_clone_uri': _(u'Invalid clone url, provide a '
439 'invalid_clone_uri': _(u'Invalid clone url, provide a '
439 'valid clone http(s)/svn+http(s) url')
440 'valid clone http(s)/svn+http(s) url')
440 }
441 }
441
442
442 def validate_python(self, value, state):
443 def validate_python(self, value, state):
443 repo_type = value.get('repo_type')
444 repo_type = value.get('repo_type')
444 url = value.get('clone_uri')
445 url = value.get('clone_uri')
445
446
446 if not url:
447 if not url:
447 pass
448 pass
448 else:
449 else:
449 try:
450 try:
450 url_handler(repo_type, url, make_ui('db', clear_session=False))
451 url_handler(repo_type, url, make_ui('db', clear_session=False))
451 except Exception:
452 except Exception:
452 log.exception('Url validation failed')
453 log.exception('Url validation failed')
453 msg = M(self, 'clone_uri')
454 msg = M(self, 'clone_uri')
454 raise formencode.Invalid(msg, value, state,
455 raise formencode.Invalid(msg, value, state,
455 error_dict=dict(clone_uri=msg)
456 error_dict=dict(clone_uri=msg)
456 )
457 )
457 return _validator
458 return _validator
458
459
459
460
460 def ValidForkType(old_data={}):
461 def ValidForkType(old_data={}):
461 class _validator(formencode.validators.FancyValidator):
462 class _validator(formencode.validators.FancyValidator):
462 messages = {
463 messages = {
463 'invalid_fork_type': _(u'Fork have to be the same type as parent')
464 'invalid_fork_type': _(u'Fork have to be the same type as parent')
464 }
465 }
465
466
466 def validate_python(self, value, state):
467 def validate_python(self, value, state):
467 if old_data['repo_type'] != value:
468 if old_data['repo_type'] != value:
468 msg = M(self, 'invalid_fork_type', state)
469 msg = M(self, 'invalid_fork_type', state)
469 raise formencode.Invalid(msg, value, state,
470 raise formencode.Invalid(msg, value, state,
470 error_dict=dict(repo_type=msg)
471 error_dict=dict(repo_type=msg)
471 )
472 )
472 return _validator
473 return _validator
473
474
474
475
475 def CanWriteGroup():
476 def CanWriteGroup(old_data=None):
476 class _validator(formencode.validators.FancyValidator):
477 class _validator(formencode.validators.FancyValidator):
477 messages = {
478 messages = {
478 'permission_denied': _(u"You don't have permissions "
479 'permission_denied': _(u"You don't have permissions "
479 "to create repository in this group"),
480 "to create repository in this group"),
480 'permission_denied_root': _(u"no permission to create repository "
481 'permission_denied_root': _(u"no permission to create repository "
481 "in root location")
482 "in root location")
482 }
483 }
483
484
484 def _to_python(self, value, state):
485 def _to_python(self, value, state):
485 #root location
486 #root location
486 if value in [-1, "-1"]:
487 if value in [-1, "-1"]:
487 return None
488 return None
488 return value
489 return value
489
490
490 def validate_python(self, value, state):
491 def validate_python(self, value, state):
491 gr = RepoGroup.get(value)
492 gr = RepoGroup.get(value)
492 gr_name = gr.group_name if gr else None # None means ROOT location
493 gr_name = gr.group_name if gr else None # None means ROOT location
493 val = HasReposGroupPermissionAny('group.write', 'group.admin')
494 val = HasReposGroupPermissionAny('group.write', 'group.admin')
494 can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository')
495 can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository')
495 forbidden = not val(gr_name, 'can write into group validator')
496 forbidden = not val(gr_name, 'can write into group validator')
496 #parent group need to be existing
497 value_changed = True # old_data['repo_group'].get('group_id') != safe_int(value)
497 if gr and forbidden:
498 if value_changed: # do check if we changed the value
498 msg = M(self, 'permission_denied', state)
499 #parent group need to be existing
499 raise formencode.Invalid(msg, value, state,
500 if gr and forbidden:
500 error_dict=dict(repo_type=msg)
501 msg = M(self, 'permission_denied', state)
501 )
502 raise formencode.Invalid(msg, value, state,
502 ## check if we can write to root location !
503 error_dict=dict(repo_type=msg)
503 elif gr is None and can_create_repos() is False:
504 )
504 msg = M(self, 'permission_denied_root', state)
505 ## check if we can write to root location !
505 raise formencode.Invalid(msg, value, state,
506 elif gr is None and can_create_repos() is False:
506 error_dict=dict(repo_type=msg)
507 msg = M(self, 'permission_denied_root', state)
507 )
508 raise formencode.Invalid(msg, value, state,
509 error_dict=dict(repo_type=msg)
510 )
508
511
509 return _validator
512 return _validator
510
513
511
514
512 def CanCreateGroup(can_create_in_root=False):
515 def CanCreateGroup(can_create_in_root=False):
513 class _validator(formencode.validators.FancyValidator):
516 class _validator(formencode.validators.FancyValidator):
514 messages = {
517 messages = {
515 'permission_denied': _(u"You don't have permissions "
518 'permission_denied': _(u"You don't have permissions "
516 "to create a group in this location")
519 "to create a group in this location")
517 }
520 }
518
521
519 def to_python(self, value, state):
522 def to_python(self, value, state):
520 #root location
523 #root location
521 if value in [-1, "-1"]:
524 if value in [-1, "-1"]:
522 return None
525 return None
523 return value
526 return value
524
527
525 def validate_python(self, value, state):
528 def validate_python(self, value, state):
526 gr = RepoGroup.get(value)
529 gr = RepoGroup.get(value)
527 gr_name = gr.group_name if gr else None # None means ROOT location
530 gr_name = gr.group_name if gr else None # None means ROOT location
528
531
529 if can_create_in_root and gr is None:
532 if can_create_in_root and gr is None:
530 #we can create in root, we're fine no validations required
533 #we can create in root, we're fine no validations required
531 return
534 return
532
535
533 forbidden_in_root = gr is None and can_create_in_root is False
536 forbidden_in_root = gr is None and can_create_in_root is False
534 val = HasReposGroupPermissionAny('group.admin')
537 val = HasReposGroupPermissionAny('group.admin')
535 forbidden = not val(gr_name, 'can create group validator')
538 forbidden = not val(gr_name, 'can create group validator')
536 if forbidden_in_root or forbidden:
539 if forbidden_in_root or forbidden:
537 msg = M(self, 'permission_denied', state)
540 msg = M(self, 'permission_denied', state)
538 raise formencode.Invalid(msg, value, state,
541 raise formencode.Invalid(msg, value, state,
539 error_dict=dict(group_parent_id=msg)
542 error_dict=dict(group_parent_id=msg)
540 )
543 )
541
544
542 return _validator
545 return _validator
543
546
544
547
545 def ValidPerms(type_='repo'):
548 def ValidPerms(type_='repo'):
546 if type_ == 'group':
549 if type_ == 'group':
547 EMPTY_PERM = 'group.none'
550 EMPTY_PERM = 'group.none'
548 elif type_ == 'repo':
551 elif type_ == 'repo':
549 EMPTY_PERM = 'repository.none'
552 EMPTY_PERM = 'repository.none'
550
553
551 class _validator(formencode.validators.FancyValidator):
554 class _validator(formencode.validators.FancyValidator):
552 messages = {
555 messages = {
553 'perm_new_member_name':
556 'perm_new_member_name':
554 _(u'This username or user group name is not valid')
557 _(u'This username or user group name is not valid')
555 }
558 }
556
559
557 def to_python(self, value, state):
560 def to_python(self, value, state):
558 perms_update = OrderedSet()
561 perms_update = OrderedSet()
559 perms_new = OrderedSet()
562 perms_new = OrderedSet()
560 # build a list of permission to update and new permission to create
563 # build a list of permission to update and new permission to create
561
564
562 #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
565 #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
563 new_perms_group = defaultdict(dict)
566 new_perms_group = defaultdict(dict)
564 for k, v in value.copy().iteritems():
567 for k, v in value.copy().iteritems():
565 if k.startswith('perm_new_member'):
568 if k.startswith('perm_new_member'):
566 del value[k]
569 del value[k]
567 _type, part = k.split('perm_new_member_')
570 _type, part = k.split('perm_new_member_')
568 args = part.split('_')
571 args = part.split('_')
569 if len(args) == 1:
572 if len(args) == 1:
570 new_perms_group[args[0]]['perm'] = v
573 new_perms_group[args[0]]['perm'] = v
571 elif len(args) == 2:
574 elif len(args) == 2:
572 _key, pos = args
575 _key, pos = args
573 new_perms_group[pos][_key] = v
576 new_perms_group[pos][_key] = v
574
577
575 # fill new permissions in order of how they were added
578 # fill new permissions in order of how they were added
576 for k in sorted(map(int, new_perms_group.keys())):
579 for k in sorted(map(int, new_perms_group.keys())):
577 perm_dict = new_perms_group[str(k)]
580 perm_dict = new_perms_group[str(k)]
578 new_member = perm_dict.get('name')
581 new_member = perm_dict.get('name')
579 new_perm = perm_dict.get('perm')
582 new_perm = perm_dict.get('perm')
580 new_type = perm_dict.get('type')
583 new_type = perm_dict.get('type')
581 if new_member and new_perm and new_type:
584 if new_member and new_perm and new_type:
582 perms_new.add((new_member, new_perm, new_type))
585 perms_new.add((new_member, new_perm, new_type))
583
586
584 for k, v in value.iteritems():
587 for k, v in value.iteritems():
585 if k.startswith('u_perm_') or k.startswith('g_perm_'):
588 if k.startswith('u_perm_') or k.startswith('g_perm_'):
586 member = k[7:]
589 member = k[7:]
587 t = {'u': 'user',
590 t = {'u': 'user',
588 'g': 'users_group'
591 'g': 'users_group'
589 }[k[0]]
592 }[k[0]]
590 if member == 'default':
593 if member == 'default':
591 if value.get('repo_private'):
594 if value.get('repo_private'):
592 # set none for default when updating to
595 # set none for default when updating to
593 # private repo
596 # private repo
594 v = EMPTY_PERM
597 v = EMPTY_PERM
595 perms_update.add((member, v, t))
598 perms_update.add((member, v, t))
596 #always set NONE when private flag is set
599 #always set NONE when private flag is set
597 if value.get('repo_private'):
600 if value.get('repo_private'):
598 perms_update.add(('default', EMPTY_PERM, 'user'))
601 perms_update.add(('default', EMPTY_PERM, 'user'))
599
602
600 value['perms_updates'] = list(perms_update)
603 value['perms_updates'] = list(perms_update)
601 value['perms_new'] = list(perms_new)
604 value['perms_new'] = list(perms_new)
602
605
603 # update permissions
606 # update permissions
604 for k, v, t in perms_new:
607 for k, v, t in perms_new:
605 try:
608 try:
606 if t is 'user':
609 if t is 'user':
607 self.user_db = User.query()\
610 self.user_db = User.query()\
608 .filter(User.active == True)\
611 .filter(User.active == True)\
609 .filter(User.username == k).one()
612 .filter(User.username == k).one()
610 if t is 'users_group':
613 if t is 'users_group':
611 self.user_db = UserGroup.query()\
614 self.user_db = UserGroup.query()\
612 .filter(UserGroup.users_group_active == True)\
615 .filter(UserGroup.users_group_active == True)\
613 .filter(UserGroup.users_group_name == k).one()
616 .filter(UserGroup.users_group_name == k).one()
614
617
615 except Exception:
618 except Exception:
616 log.exception('Updated permission failed')
619 log.exception('Updated permission failed')
617 msg = M(self, 'perm_new_member_type', state)
620 msg = M(self, 'perm_new_member_type', state)
618 raise formencode.Invalid(msg, value, state,
621 raise formencode.Invalid(msg, value, state,
619 error_dict=dict(perm_new_member_name=msg)
622 error_dict=dict(perm_new_member_name=msg)
620 )
623 )
621 return value
624 return value
622 return _validator
625 return _validator
623
626
624
627
625 def ValidSettings():
628 def ValidSettings():
626 class _validator(formencode.validators.FancyValidator):
629 class _validator(formencode.validators.FancyValidator):
627 def _to_python(self, value, state):
630 def _to_python(self, value, state):
628 # settings form for users that are not admin
631 # settings form for users that are not admin
629 # can't edit certain parameters, it's extra backup if they mangle
632 # can't edit certain parameters, it's extra backup if they mangle
630 # with forms
633 # with forms
631
634
632 forbidden_params = [
635 forbidden_params = [
633 'user', 'repo_type', 'repo_enable_locking',
636 'user', 'repo_type', 'repo_enable_locking',
634 'repo_enable_downloads', 'repo_enable_statistics'
637 'repo_enable_downloads', 'repo_enable_statistics'
635 ]
638 ]
636
639
637 for param in forbidden_params:
640 for param in forbidden_params:
638 if param in value:
641 if param in value:
639 del value[param]
642 del value[param]
640 return value
643 return value
641
644
642 def validate_python(self, value, state):
645 def validate_python(self, value, state):
643 pass
646 pass
644 return _validator
647 return _validator
645
648
646
649
647 def ValidPath():
650 def ValidPath():
648 class _validator(formencode.validators.FancyValidator):
651 class _validator(formencode.validators.FancyValidator):
649 messages = {
652 messages = {
650 'invalid_path': _(u'This is not a valid path')
653 'invalid_path': _(u'This is not a valid path')
651 }
654 }
652
655
653 def validate_python(self, value, state):
656 def validate_python(self, value, state):
654 if not os.path.isdir(value):
657 if not os.path.isdir(value):
655 msg = M(self, 'invalid_path', state)
658 msg = M(self, 'invalid_path', state)
656 raise formencode.Invalid(msg, value, state,
659 raise formencode.Invalid(msg, value, state,
657 error_dict=dict(paths_root_path=msg)
660 error_dict=dict(paths_root_path=msg)
658 )
661 )
659 return _validator
662 return _validator
660
663
661
664
662 def UniqSystemEmail(old_data={}):
665 def UniqSystemEmail(old_data={}):
663 class _validator(formencode.validators.FancyValidator):
666 class _validator(formencode.validators.FancyValidator):
664 messages = {
667 messages = {
665 'email_taken': _(u'This e-mail address is already taken')
668 'email_taken': _(u'This e-mail address is already taken')
666 }
669 }
667
670
668 def _to_python(self, value, state):
671 def _to_python(self, value, state):
669 return value.lower()
672 return value.lower()
670
673
671 def validate_python(self, value, state):
674 def validate_python(self, value, state):
672 if (old_data.get('email') or '').lower() != value:
675 if (old_data.get('email') or '').lower() != value:
673 user = User.get_by_email(value, case_insensitive=True)
676 user = User.get_by_email(value, case_insensitive=True)
674 if user:
677 if user:
675 msg = M(self, 'email_taken', state)
678 msg = M(self, 'email_taken', state)
676 raise formencode.Invalid(msg, value, state,
679 raise formencode.Invalid(msg, value, state,
677 error_dict=dict(email=msg)
680 error_dict=dict(email=msg)
678 )
681 )
679 return _validator
682 return _validator
680
683
681
684
682 def ValidSystemEmail():
685 def ValidSystemEmail():
683 class _validator(formencode.validators.FancyValidator):
686 class _validator(formencode.validators.FancyValidator):
684 messages = {
687 messages = {
685 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
688 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
686 }
689 }
687
690
688 def _to_python(self, value, state):
691 def _to_python(self, value, state):
689 return value.lower()
692 return value.lower()
690
693
691 def validate_python(self, value, state):
694 def validate_python(self, value, state):
692 user = User.get_by_email(value, case_insensitive=True)
695 user = User.get_by_email(value, case_insensitive=True)
693 if user is None:
696 if user is None:
694 msg = M(self, 'non_existing_email', state, email=value)
697 msg = M(self, 'non_existing_email', state, email=value)
695 raise formencode.Invalid(msg, value, state,
698 raise formencode.Invalid(msg, value, state,
696 error_dict=dict(email=msg)
699 error_dict=dict(email=msg)
697 )
700 )
698
701
699 return _validator
702 return _validator
700
703
701
704
702 def LdapLibValidator():
705 def LdapLibValidator():
703 class _validator(formencode.validators.FancyValidator):
706 class _validator(formencode.validators.FancyValidator):
704 messages = {
707 messages = {
705
708
706 }
709 }
707
710
708 def validate_python(self, value, state):
711 def validate_python(self, value, state):
709 try:
712 try:
710 import ldap
713 import ldap
711 ldap # pyflakes silence !
714 ldap # pyflakes silence !
712 except ImportError:
715 except ImportError:
713 raise LdapImportError()
716 raise LdapImportError()
714
717
715 return _validator
718 return _validator
716
719
717
720
718 def AttrLoginValidator():
721 def AttrLoginValidator():
719 class _validator(formencode.validators.FancyValidator):
722 class _validator(formencode.validators.FancyValidator):
720 messages = {
723 messages = {
721 'invalid_cn':
724 'invalid_cn':
722 _(u'The LDAP Login attribute of the CN must be specified - '
725 _(u'The LDAP Login attribute of the CN must be specified - '
723 'this is the name of the attribute that is equivalent '
726 'this is the name of the attribute that is equivalent '
724 'to "username"')
727 'to "username"')
725 }
728 }
726
729
727 def validate_python(self, value, state):
730 def validate_python(self, value, state):
728 if not value or not isinstance(value, (str, unicode)):
731 if not value or not isinstance(value, (str, unicode)):
729 msg = M(self, 'invalid_cn', state)
732 msg = M(self, 'invalid_cn', state)
730 raise formencode.Invalid(msg, value, state,
733 raise formencode.Invalid(msg, value, state,
731 error_dict=dict(ldap_attr_login=msg)
734 error_dict=dict(ldap_attr_login=msg)
732 )
735 )
733
736
734 return _validator
737 return _validator
735
738
736
739
737 def NotReviewedRevisions(repo_id):
740 def NotReviewedRevisions(repo_id):
738 class _validator(formencode.validators.FancyValidator):
741 class _validator(formencode.validators.FancyValidator):
739 messages = {
742 messages = {
740 'rev_already_reviewed':
743 'rev_already_reviewed':
741 _(u'Revisions %(revs)s are already part of pull request '
744 _(u'Revisions %(revs)s are already part of pull request '
742 'or have set status')
745 'or have set status')
743 }
746 }
744
747
745 def validate_python(self, value, state):
748 def validate_python(self, value, state):
746 # check revisions if they are not reviewed, or a part of another
749 # check revisions if they are not reviewed, or a part of another
747 # pull request
750 # pull request
748 statuses = ChangesetStatus.query()\
751 statuses = ChangesetStatus.query()\
749 .filter(ChangesetStatus.revision.in_(value))\
752 .filter(ChangesetStatus.revision.in_(value))\
750 .filter(ChangesetStatus.repo_id == repo_id)\
753 .filter(ChangesetStatus.repo_id == repo_id)\
751 .all()
754 .all()
752
755
753 errors = []
756 errors = []
754 for cs in statuses:
757 for cs in statuses:
755 if cs.pull_request_id:
758 if cs.pull_request_id:
756 errors.append(['pull_req', cs.revision[:12]])
759 errors.append(['pull_req', cs.revision[:12]])
757 elif cs.status:
760 elif cs.status:
758 errors.append(['status', cs.revision[:12]])
761 errors.append(['status', cs.revision[:12]])
759
762
760 if errors:
763 if errors:
761 revs = ','.join([x[1] for x in errors])
764 revs = ','.join([x[1] for x in errors])
762 msg = M(self, 'rev_already_reviewed', state, revs=revs)
765 msg = M(self, 'rev_already_reviewed', state, revs=revs)
763 raise formencode.Invalid(msg, value, state,
766 raise formencode.Invalid(msg, value, state,
764 error_dict=dict(revisions=revs)
767 error_dict=dict(revisions=revs)
765 )
768 )
766
769
767 return _validator
770 return _validator
768
771
769
772
770 def ValidIp():
773 def ValidIp():
771 class _validator(CIDR):
774 class _validator(CIDR):
772 messages = dict(
775 messages = dict(
773 badFormat=_('Please enter a valid IPv4 or IpV6 address'),
776 badFormat=_('Please enter a valid IPv4 or IpV6 address'),
774 illegalBits=_('The network size (bits) must be within the range'
777 illegalBits=_('The network size (bits) must be within the range'
775 ' of 0-32 (not %(bits)r)'))
778 ' of 0-32 (not %(bits)r)'))
776
779
777 def to_python(self, value, state):
780 def to_python(self, value, state):
778 v = super(_validator, self).to_python(value, state)
781 v = super(_validator, self).to_python(value, state)
779 v = v.strip()
782 v = v.strip()
780 net = ipaddr.IPNetwork(address=v)
783 net = ipaddr.IPNetwork(address=v)
781 if isinstance(net, ipaddr.IPv4Network):
784 if isinstance(net, ipaddr.IPv4Network):
782 #if IPv4 doesn't end with a mask, add /32
785 #if IPv4 doesn't end with a mask, add /32
783 if '/' not in value:
786 if '/' not in value:
784 v += '/32'
787 v += '/32'
785 if isinstance(net, ipaddr.IPv6Network):
788 if isinstance(net, ipaddr.IPv6Network):
786 #if IPv6 doesn't end with a mask, add /128
789 #if IPv6 doesn't end with a mask, add /128
787 if '/' not in value:
790 if '/' not in value:
788 v += '/128'
791 v += '/128'
789 return v
792 return v
790
793
791 def validate_python(self, value, state):
794 def validate_python(self, value, state):
792 try:
795 try:
793 addr = value.strip()
796 addr = value.strip()
794 #this raises an ValueError if address is not IpV4 or IpV6
797 #this raises an ValueError if address is not IpV4 or IpV6
795 ipaddr.IPNetwork(address=addr)
798 ipaddr.IPNetwork(address=addr)
796 except ValueError:
799 except ValueError:
797 raise formencode.Invalid(self.message('badFormat', state),
800 raise formencode.Invalid(self.message('badFormat', state),
798 value, state)
801 value, state)
799
802
800 return _validator
803 return _validator
801
804
802
805
803 def FieldKey():
806 def FieldKey():
804 class _validator(formencode.validators.FancyValidator):
807 class _validator(formencode.validators.FancyValidator):
805 messages = dict(
808 messages = dict(
806 badFormat=_('Key name can only consist of letters, '
809 badFormat=_('Key name can only consist of letters, '
807 'underscore, dash or numbers'),)
810 'underscore, dash or numbers'),)
808
811
809 def validate_python(self, value, state):
812 def validate_python(self, value, state):
810 if not re.match('[a-zA-Z0-9_-]+$', value):
813 if not re.match('[a-zA-Z0-9_-]+$', value):
811 raise formencode.Invalid(self.message('badFormat', state),
814 raise formencode.Invalid(self.message('badFormat', state),
812 value, state)
815 value, state)
813 return _validator
816 return _validator
General Comments 0
You need to be logged in to leave comments. Login now