##// END OF EJS Templates
added more validations when opening pull request...
marcink -
r2711:1de45f58 beta
parent child Browse files
Show More
@@ -1,356 +1,378 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.pullrequests
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 pull requests controller for rhodecode for initializing pull requests
7 7
8 8 :created_on: May 7, 2012
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 import logging
26 26 import traceback
27 import formencode
27 28
28 29 from webob.exc import HTTPNotFound, HTTPForbidden
29 30 from collections import defaultdict
30 31 from itertools import groupby
31 32
32 33 from pylons import request, response, session, tmpl_context as c, url
33 34 from pylons.controllers.util import abort, redirect
34 35 from pylons.i18n.translation import _
35 36 from pylons.decorators import jsonify
36 37
37 38 from rhodecode.lib.compat import json
38 39 from rhodecode.lib.base import BaseRepoController, render
39 40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
40 41 NotAnonymous
41 42 from rhodecode.lib import helpers as h
42 43 from rhodecode.lib import diffs
43 44 from rhodecode.lib.utils import action_logger
44 45 from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
45 46 ChangesetComment
46 47 from rhodecode.model.pull_request import PullRequestModel
47 48 from rhodecode.model.meta import Session
48 49 from rhodecode.model.repo import RepoModel
49 50 from rhodecode.model.comment import ChangesetCommentsModel
50 51 from rhodecode.model.changeset_status import ChangesetStatusModel
52 from rhodecode.model.forms import PullRequestForm
51 53
52 54 log = logging.getLogger(__name__)
53 55
54 56
55 57 class PullrequestsController(BaseRepoController):
56 58
57 59 @LoginRequired()
58 60 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
59 61 'repository.admin')
60 62 def __before__(self):
61 63 super(PullrequestsController, self).__before__()
62 64 repo_model = RepoModel()
63 65 c.users_array = repo_model.get_users_js()
64 66 c.users_groups_array = repo_model.get_users_groups_js()
65 67
66 68 def _get_repo_refs(self, repo):
67 69 hist_l = []
68 70
69 71 branches_group = ([('branch:%s:%s' % (k, v), k) for
70 72 k, v in repo.branches.iteritems()], _("Branches"))
71 73 bookmarks_group = ([('book:%s:%s' % (k, v), k) for
72 74 k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
73 75 tags_group = ([('tag:%s:%s' % (k, v), k) for
74 76 k, v in repo.tags.iteritems()], _("Tags"))
75 77
76 78 hist_l.append(bookmarks_group)
77 79 hist_l.append(branches_group)
78 80 hist_l.append(tags_group)
79 81
80 82 return hist_l
81 83
82 84 def show_all(self, repo_name):
83 85 c.pull_requests = PullRequestModel().get_all(repo_name)
84 86 c.repo_name = repo_name
85 87 return render('/pullrequests/pullrequest_show_all.html')
86 88
87 89 @NotAnonymous()
88 90 def index(self):
89 91 org_repo = c.rhodecode_db_repo
90 92
91 93 if org_repo.scm_instance.alias != 'hg':
92 94 log.error('Review not available for GIT REPOS')
93 95 raise HTTPNotFound
94 96
95 97 other_repos_info = {}
96 98
97 99 c.org_refs = self._get_repo_refs(c.rhodecode_repo)
98 100 c.org_repos = []
99 101 c.other_repos = []
100 102 c.org_repos.append((org_repo.repo_name, '%s/%s' % (
101 103 org_repo.user.username, c.repo_name))
102 104 )
103 105
104 106 c.other_refs = c.org_refs
105 107 c.other_repos.extend(c.org_repos)
106 108
107 109 #add orginal repo
108 110 other_repos_info[org_repo.repo_name] = {
109 111 'gravatar': h.gravatar_url(org_repo.user.email, 24),
110 112 'description': org_repo.description
111 113 }
112 114
113 115 c.default_pull_request = org_repo.repo_name
114 116 #gather forks and add to this list
115 117 for fork in org_repo.forks:
116 118 c.other_repos.append((fork.repo_name, '%s/%s' % (
117 119 fork.user.username, fork.repo_name))
118 120 )
119 121 other_repos_info[fork.repo_name] = {
120 122 'gravatar': h.gravatar_url(fork.user.email, 24),
121 123 'description': fork.description
122 124 }
123 125 #add parents of this fork also
124 126 if org_repo.parent:
125 127 c.default_pull_request = org_repo.parent.repo_name
126 128 c.other_repos.append((org_repo.parent.repo_name, '%s/%s' % (
127 129 org_repo.parent.user.username,
128 130 org_repo.parent.repo_name))
129 131 )
130 132 other_repos_info[org_repo.parent.repo_name] = {
131 133 'gravatar': h.gravatar_url(org_repo.parent.user.email, 24),
132 134 'description': org_repo.parent.description
133 135 }
134 136
135 137 c.other_repos_info = json.dumps(other_repos_info)
136 138 c.review_members = [org_repo.user]
137 139 return render('/pullrequests/pullrequest.html')
138 140
139 141 @NotAnonymous()
140 142 def create(self, repo_name):
141 req_p = request.POST
142 org_repo = req_p['org_repo']
143 org_ref = req_p['org_ref']
144 other_repo = req_p['other_repo']
145 other_ref = req_p['other_ref']
146 revisions = req_p.getall('revisions')
147 reviewers = req_p.getall('review_members')
143
144 try:
145 _form = PullRequestForm()().to_python(request.POST)
146 except formencode.Invalid, errors:
147 log.error(traceback.format_exc())
148 if errors.error_dict.get('revisions'):
149 msg = _('Cannot open a pull request with '
150 'empty list of changesets')
151 elif errors.error_dict.get('pullrequest_title'):
152 msg = _('Pull request requires a title with min. 3 chars')
153 else:
154 msg = _('error during creation of pull request')
148 155
149 #TODO: wrap this into a FORM !!!
156 h.flash(msg, 'error')
157 return redirect(url('pullrequest_home', repo_name=repo_name))
150 158
151 title = req_p['pullrequest_title']
152 description = req_p['pullrequest_desc']
159 org_repo = _form['org_repo']
160 org_ref = _form['org_ref']
161 other_repo = _form['other_repo']
162 other_ref = _form['other_ref']
163 revisions = _form['revisions']
164 reviewers = _form['review_members']
165
166 title = _form['pullrequest_title']
167 description = _form['pullrequest_desc']
153 168
154 169 try:
155 170 pull_request = PullRequestModel().create(
156 171 self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
157 172 other_ref, revisions, reviewers, title, description
158 173 )
159 174 Session().commit()
160 175 h.flash(_('Successfully opened new pull request'),
161 176 category='success')
162 177 except Exception:
163 178 h.flash(_('Error occurred during sending pull request'),
164 179 category='error')
165 180 log.error(traceback.format_exc())
166 return redirect(url('changelog_home', repo_name=org_repo,))
181 return redirect(url('pullrequest_home', repo_name=repo_name))
167 182
168 183 return redirect(url('pullrequest_show', repo_name=other_repo,
169 184 pull_request_id=pull_request.pull_request_id))
170 185
171 186 @NotAnonymous()
172 187 @jsonify
173 188 def update(self, repo_name, pull_request_id):
174 189 pull_request = PullRequest.get_or_404(pull_request_id)
175 190 if pull_request.is_closed():
176 191 raise HTTPForbidden()
177 192
178 193 reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
179 194 request.POST.get('reviewers_ids', '').split(',')))
180 195 PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
181 196 Session.commit()
182 197 return True
183 198
184 199 def _load_compare_data(self, pull_request, enable_comments=True):
185 200 """
186 201 Load context data needed for generating compare diff
187 202
188 203 :param pull_request:
189 204 :type pull_request:
190 205 """
191 206
192 207 org_repo = pull_request.org_repo
193 org_ref_type, org_ref_, org_ref = pull_request.org_ref.split(':')
208 (org_ref_type,
209 org_ref_name,
210 org_ref_rev) = pull_request.org_ref.split(':')
211
194 212 other_repo = pull_request.other_repo
195 other_ref_type, other_ref, other_ref_ = pull_request.other_ref.split(':')
213 (other_ref_type,
214 other_ref_name,
215 other_ref_rev) = pull_request.other_ref.split(':')
196 216
197 org_ref = (org_ref_type, org_ref)
198 other_ref = (other_ref_type, other_ref)
217 # dispite opening revisions for bookmarks/branches/tags, we always
218 # convert this to rev to prevent changes after book or branch change
219 org_ref = ('rev', org_ref_rev)
220 other_ref = ('rev', other_ref_rev)
199 221
200 222 c.org_repo = org_repo
201 223 c.other_repo = other_repo
202 224
203 225 c.cs_ranges, discovery_data = PullRequestModel().get_compare_data(
204 226 org_repo, org_ref, other_repo, other_ref
205 227 )
206 228
207 229 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
208 230 c.cs_ranges])
209 231 # defines that we need hidden inputs with changesets
210 232 c.as_form = request.GET.get('as_form', False)
211 233
212 234 c.org_ref = org_ref[1]
213 235 c.other_ref = other_ref[1]
214 236 # diff needs to have swapped org with other to generate proper diff
215 237 _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref,
216 238 discovery_data)
217 239 diff_processor = diffs.DiffProcessor(_diff, format='gitdiff')
218 240 _parsed = diff_processor.prepare()
219 241
220 242 c.files = []
221 243 c.changes = {}
222 244
223 245 for f in _parsed:
224 246 fid = h.FID('', f['filename'])
225 247 c.files.append([fid, f['operation'], f['filename'], f['stats']])
226 248 diff = diff_processor.as_html(enable_comments=enable_comments,
227 249 diff_lines=[f])
228 250 c.changes[fid] = [f['operation'], f['filename'], diff]
229 251
230 252 def show(self, repo_name, pull_request_id):
231 253 repo_model = RepoModel()
232 254 c.users_array = repo_model.get_users_js()
233 255 c.users_groups_array = repo_model.get_users_groups_js()
234 256 c.pull_request = PullRequest.get_or_404(pull_request_id)
235 257
236 258 cc_model = ChangesetCommentsModel()
237 259 cs_model = ChangesetStatusModel()
238 260 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
239 261 pull_request=c.pull_request,
240 262 with_revisions=True)
241 263
242 264 cs_statuses = defaultdict(list)
243 265 for st in _cs_statuses:
244 266 cs_statuses[st.author.username] += [st]
245 267
246 268 c.pull_request_reviewers = []
247 269 for o in c.pull_request.reviewers:
248 270 st = cs_statuses.get(o.user.username, None)
249 271 if st:
250 272 sorter = lambda k: k.version
251 273 st = [(x, list(y)[0])
252 274 for x, y in (groupby(sorted(st, key=sorter), sorter))]
253 275 c.pull_request_reviewers.append([o.user, st])
254 276
255 277 # pull_requests repo_name we opened it against
256 278 # ie. other_repo must match
257 279 if repo_name != c.pull_request.other_repo.repo_name:
258 280 raise HTTPNotFound
259 281
260 282 # load compare data into template context
261 283 enable_comments = not c.pull_request.is_closed()
262 284 self._load_compare_data(c.pull_request, enable_comments=enable_comments)
263 285
264 286 # inline comments
265 287 c.inline_cnt = 0
266 288 c.inline_comments = cc_model.get_inline_comments(
267 289 c.rhodecode_db_repo.repo_id,
268 290 pull_request=pull_request_id)
269 291 # count inline comments
270 292 for __, lines in c.inline_comments:
271 293 for comments in lines.values():
272 294 c.inline_cnt += len(comments)
273 295 # comments
274 296 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
275 297 pull_request=pull_request_id)
276 298
277 299 # changeset(pull-request) status
278 300 c.current_changeset_status = cs_model.calculate_status(
279 301 c.pull_request_reviewers
280 302 )
281 303 c.changeset_statuses = ChangesetStatus.STATUSES
282 304 c.target_repo = c.pull_request.org_repo.repo_name
283 305 return render('/pullrequests/pullrequest_show.html')
284 306
285 307 @NotAnonymous()
286 308 @jsonify
287 309 def comment(self, repo_name, pull_request_id):
288 310 pull_request = PullRequest.get_or_404(pull_request_id)
289 311 if pull_request.is_closed():
290 312 raise HTTPForbidden()
291 313
292 314 status = request.POST.get('changeset_status')
293 315 change_status = request.POST.get('change_changeset_status')
294 316
295 317 comm = ChangesetCommentsModel().create(
296 318 text=request.POST.get('text'),
297 319 repo=c.rhodecode_db_repo.repo_id,
298 320 user=c.rhodecode_user.user_id,
299 321 pull_request=pull_request_id,
300 322 f_path=request.POST.get('f_path'),
301 323 line_no=request.POST.get('line'),
302 324 status_change=(ChangesetStatus.get_status_lbl(status)
303 325 if status and change_status else None)
304 326 )
305 327
306 328 # get status if set !
307 329 if status and change_status:
308 330 ChangesetStatusModel().set_status(
309 331 c.rhodecode_db_repo.repo_id,
310 332 status,
311 333 c.rhodecode_user.user_id,
312 334 comm,
313 335 pull_request=pull_request_id
314 336 )
315 337 action_logger(self.rhodecode_user,
316 338 'user_commented_pull_request:%s' % pull_request_id,
317 339 c.rhodecode_db_repo, self.ip_addr, self.sa)
318 340
319 341 if request.POST.get('save_close'):
320 342 PullRequestModel().close_pull_request(pull_request_id)
321 343 action_logger(self.rhodecode_user,
322 344 'user_closed_pull_request:%s' % pull_request_id,
323 345 c.rhodecode_db_repo, self.ip_addr, self.sa)
324 346
325 347 Session().commit()
326 348
327 349 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
328 350 return redirect(h.url('pullrequest_show', repo_name=repo_name,
329 351 pull_request_id=pull_request_id))
330 352
331 353 data = {
332 354 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
333 355 }
334 356 if comm:
335 357 c.co = comm
336 358 data.update(comm.get_dict())
337 359 data.update({'rendered_text':
338 360 render('changeset/changeset_comment_block.html')})
339 361
340 362 return data
341 363
342 364 @NotAnonymous()
343 365 @jsonify
344 366 def delete_comment(self, repo_name, comment_id):
345 367 co = ChangesetComment.get(comment_id)
346 368 if co.pull_request.is_closed():
347 369 #don't allow deleting comments on closed pull request
348 370 raise HTTPForbidden()
349 371
350 372 owner = lambda: co.author.user_id == c.rhodecode_user.user_id
351 373 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
352 374 ChangesetCommentsModel().delete(comment=co)
353 375 Session().commit()
354 376 return True
355 377 else:
356 378 raise HTTPForbidden()
@@ -1,323 +1,342 b''
1 1 """ this is forms validation classes
2 2 http://formencode.org/module-formencode.validators.html
3 3 for list off all availible validators
4 4
5 5 we can create our own validators
6 6
7 7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 8 pre_validators [] These validators will be applied before the schema
9 9 chained_validators [] These validators will be applied after the schema
10 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 11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 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 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 16 <name> = formencode.validators.<name of validator>
17 17 <name> must equal form name
18 18 list=[1,2,3,4,5]
19 19 for SELECT use formencode.All(OneOf(list), Int())
20 20
21 21 """
22 22 import logging
23 23
24 24 import formencode
25 25 from formencode import All
26 26
27 27 from pylons.i18n.translation import _
28 28
29 29 from rhodecode.model import validators as v
30 30 from rhodecode import BACKENDS
31 31
32 32 log = logging.getLogger(__name__)
33 33
34 34
35 35 class LoginForm(formencode.Schema):
36 36 allow_extra_fields = True
37 37 filter_extra_fields = True
38 38 username = v.UnicodeString(
39 39 strip=True,
40 40 min=1,
41 41 not_empty=True,
42 42 messages={
43 43 'empty': _(u'Please enter a login'),
44 44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 45 )
46 46
47 47 password = v.UnicodeString(
48 48 strip=False,
49 49 min=3,
50 50 not_empty=True,
51 51 messages={
52 52 'empty': _(u'Please enter a password'),
53 53 'tooShort': _(u'Enter %(min)i characters or more')}
54 54 )
55 55
56 56 remember = v.StringBoolean(if_missing=False)
57 57
58 58 chained_validators = [v.ValidAuth()]
59 59
60 60
61 61 def UserForm(edit=False, old_data={}):
62 62 class _UserForm(formencode.Schema):
63 63 allow_extra_fields = True
64 64 filter_extra_fields = True
65 65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 66 v.ValidUsername(edit, old_data))
67 67 if edit:
68 68 new_password = All(
69 69 v.ValidPassword(),
70 70 v.UnicodeString(strip=False, min=6, not_empty=False)
71 71 )
72 72 password_confirmation = All(
73 73 v.ValidPassword(),
74 74 v.UnicodeString(strip=False, min=6, not_empty=False),
75 75 )
76 76 admin = v.StringBoolean(if_missing=False)
77 77 else:
78 78 password = All(
79 79 v.ValidPassword(),
80 80 v.UnicodeString(strip=False, min=6, not_empty=True)
81 81 )
82 82 password_confirmation = All(
83 83 v.ValidPassword(),
84 84 v.UnicodeString(strip=False, min=6, not_empty=False)
85 85 )
86 86
87 87 active = v.StringBoolean(if_missing=False)
88 88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
90 90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
91 91
92 92 chained_validators = [v.ValidPasswordsMatch()]
93 93
94 94 return _UserForm
95 95
96 96
97 97 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
98 98 class _UsersGroupForm(formencode.Schema):
99 99 allow_extra_fields = True
100 100 filter_extra_fields = True
101 101
102 102 users_group_name = All(
103 103 v.UnicodeString(strip=True, min=1, not_empty=True),
104 104 v.ValidUsersGroup(edit, old_data)
105 105 )
106 106
107 107 users_group_active = v.StringBoolean(if_missing=False)
108 108
109 109 if edit:
110 110 users_group_members = v.OneOf(
111 111 available_members, hideList=False, testValueList=True,
112 112 if_missing=None, not_empty=False
113 113 )
114 114
115 115 return _UsersGroupForm
116 116
117 117
118 118 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
119 119 class _ReposGroupForm(formencode.Schema):
120 120 allow_extra_fields = True
121 121 filter_extra_fields = False
122 122
123 123 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
124 124 v.SlugifyName())
125 125 group_description = v.UnicodeString(strip=True, min=1,
126 126 not_empty=True)
127 127 group_parent_id = v.OneOf(available_groups, hideList=False,
128 128 testValueList=True,
129 129 if_missing=None, not_empty=False)
130 130
131 131 chained_validators = [v.ValidReposGroup(edit, old_data),
132 132 v.ValidPerms('group')]
133 133
134 134 return _ReposGroupForm
135 135
136 136
137 137 def RegisterForm(edit=False, old_data={}):
138 138 class _RegisterForm(formencode.Schema):
139 139 allow_extra_fields = True
140 140 filter_extra_fields = True
141 141 username = All(
142 142 v.ValidUsername(edit, old_data),
143 143 v.UnicodeString(strip=True, min=1, not_empty=True)
144 144 )
145 145 password = All(
146 146 v.ValidPassword(),
147 147 v.UnicodeString(strip=False, min=6, not_empty=True)
148 148 )
149 149 password_confirmation = All(
150 150 v.ValidPassword(),
151 151 v.UnicodeString(strip=False, min=6, not_empty=True)
152 152 )
153 153 active = v.StringBoolean(if_missing=False)
154 154 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
155 155 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
156 156 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
157 157
158 158 chained_validators = [v.ValidPasswordsMatch()]
159 159
160 160 return _RegisterForm
161 161
162 162
163 163 def PasswordResetForm():
164 164 class _PasswordResetForm(formencode.Schema):
165 165 allow_extra_fields = True
166 166 filter_extra_fields = True
167 167 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
168 168 return _PasswordResetForm
169 169
170 170
171 171 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
172 172 repo_groups=[], landing_revs=[]):
173 173 class _RepoForm(formencode.Schema):
174 174 allow_extra_fields = True
175 175 filter_extra_fields = False
176 176 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
177 177 v.SlugifyName())
178 178 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
179 179 repo_group = v.OneOf(repo_groups, hideList=True)
180 180 repo_type = v.OneOf(supported_backends)
181 181 description = v.UnicodeString(strip=True, min=1, not_empty=False)
182 182 private = v.StringBoolean(if_missing=False)
183 183 enable_statistics = v.StringBoolean(if_missing=False)
184 184 enable_downloads = v.StringBoolean(if_missing=False)
185 185 landing_rev = v.OneOf(landing_revs, hideList=True)
186 186
187 187 if edit:
188 188 #this is repo owner
189 189 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
190 190
191 191 chained_validators = [v.ValidCloneUri(),
192 192 v.ValidRepoName(edit, old_data),
193 193 v.ValidPerms()]
194 194 return _RepoForm
195 195
196 196
197 197 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
198 198 repo_groups=[], landing_revs=[]):
199 199 class _RepoForkForm(formencode.Schema):
200 200 allow_extra_fields = True
201 201 filter_extra_fields = False
202 202 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
203 203 v.SlugifyName())
204 204 repo_group = v.OneOf(repo_groups, hideList=True)
205 205 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
206 206 description = v.UnicodeString(strip=True, min=1, not_empty=True)
207 207 private = v.StringBoolean(if_missing=False)
208 208 copy_permissions = v.StringBoolean(if_missing=False)
209 209 update_after_clone = v.StringBoolean(if_missing=False)
210 210 fork_parent_id = v.UnicodeString()
211 211 chained_validators = [v.ValidForkName(edit, old_data)]
212 212 landing_rev = v.OneOf(landing_revs, hideList=True)
213 213
214 214 return _RepoForkForm
215 215
216 216
217 217 def RepoSettingsForm(edit=False, old_data={},
218 218 supported_backends=BACKENDS.keys(), repo_groups=[],
219 219 landing_revs=[]):
220 220 class _RepoForm(formencode.Schema):
221 221 allow_extra_fields = True
222 222 filter_extra_fields = False
223 223 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
224 224 v.SlugifyName())
225 225 description = v.UnicodeString(strip=True, min=1, not_empty=True)
226 226 repo_group = v.OneOf(repo_groups, hideList=True)
227 227 private = v.StringBoolean(if_missing=False)
228 228 landing_rev = v.OneOf(landing_revs, hideList=True)
229 229 chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
230 230 v.ValidSettings()]
231 231 return _RepoForm
232 232
233 233
234 234 def ApplicationSettingsForm():
235 235 class _ApplicationSettingsForm(formencode.Schema):
236 236 allow_extra_fields = True
237 237 filter_extra_fields = False
238 238 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
239 239 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
240 240 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
241 241
242 242 return _ApplicationSettingsForm
243 243
244 244
245 245 def ApplicationVisualisationForm():
246 246 class _ApplicationVisualisationForm(formencode.Schema):
247 247 allow_extra_fields = True
248 248 filter_extra_fields = False
249 249 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
250 250 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
251 251 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
252 252
253 253 return _ApplicationVisualisationForm
254 254
255 255
256 256 def ApplicationUiSettingsForm():
257 257 class _ApplicationUiSettingsForm(formencode.Schema):
258 258 allow_extra_fields = True
259 259 filter_extra_fields = False
260 260 web_push_ssl = v.StringBoolean(if_missing=False)
261 261 paths_root_path = All(
262 262 v.ValidPath(),
263 263 v.UnicodeString(strip=True, min=1, not_empty=True)
264 264 )
265 265 hooks_changegroup_update = v.StringBoolean(if_missing=False)
266 266 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
267 267 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
268 268 hooks_preoutgoing_pull_logger = v.StringBoolean(if_missing=False)
269 269
270 270 extensions_largefiles = v.StringBoolean(if_missing=False)
271 271 extensions_hgsubversion = v.StringBoolean(if_missing=False)
272 272 extensions_hggit = v.StringBoolean(if_missing=False)
273 273
274 274 return _ApplicationUiSettingsForm
275 275
276 276
277 277 def DefaultPermissionsForm(perms_choices, register_choices, create_choices,
278 278 fork_choices):
279 279 class _DefaultPermissionsForm(formencode.Schema):
280 280 allow_extra_fields = True
281 281 filter_extra_fields = True
282 282 overwrite_default = v.StringBoolean(if_missing=False)
283 283 anonymous = v.StringBoolean(if_missing=False)
284 284 default_perm = v.OneOf(perms_choices)
285 285 default_register = v.OneOf(register_choices)
286 286 default_create = v.OneOf(create_choices)
287 287 default_fork = v.OneOf(fork_choices)
288 288
289 289 return _DefaultPermissionsForm
290 290
291 291
292 292 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
293 293 tls_kind_choices):
294 294 class _LdapSettingsForm(formencode.Schema):
295 295 allow_extra_fields = True
296 296 filter_extra_fields = True
297 297 #pre_validators = [LdapLibValidator]
298 298 ldap_active = v.StringBoolean(if_missing=False)
299 299 ldap_host = v.UnicodeString(strip=True,)
300 300 ldap_port = v.Number(strip=True,)
301 301 ldap_tls_kind = v.OneOf(tls_kind_choices)
302 302 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
303 303 ldap_dn_user = v.UnicodeString(strip=True,)
304 304 ldap_dn_pass = v.UnicodeString(strip=True,)
305 305 ldap_base_dn = v.UnicodeString(strip=True,)
306 306 ldap_filter = v.UnicodeString(strip=True,)
307 307 ldap_search_scope = v.OneOf(search_scope_choices)
308 308 ldap_attr_login = All(
309 309 v.AttrLoginValidator(),
310 310 v.UnicodeString(strip=True,)
311 311 )
312 312 ldap_attr_firstname = v.UnicodeString(strip=True,)
313 313 ldap_attr_lastname = v.UnicodeString(strip=True,)
314 314 ldap_attr_email = v.UnicodeString(strip=True,)
315 315
316 316 return _LdapSettingsForm
317 317
318 318
319 319 def UserExtraEmailForm():
320 320 class _UserExtraEmailForm(formencode.Schema):
321 321 email = All(v.UniqSystemEmail(), v.Email)
322 322
323 323 return _UserExtraEmailForm
324
325
326 def PullRequestForm():
327 class _PullRequestForm(formencode.Schema):
328 allow_extra_fields = True
329 filter_extra_fields = True
330
331 user = v.UnicodeString(strip=True, required=True)
332 org_repo = v.UnicodeString(strip=True, required=True)
333 org_ref = v.UnicodeString(strip=True, required=True)
334 other_repo = v.UnicodeString(strip=True, required=True)
335 other_ref = v.UnicodeString(strip=True, required=True)
336 revisions = v.Set(required=True)
337 review_members = v.Set(required=True)
338
339 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
340 pullrequest_desc = v.UnicodeString(strip=True, required=False)
341
342 return _PullRequestForm No newline at end of file
@@ -1,602 +1,601 b''
1 1 """
2 2 Set of generic validators
3 3 """
4 4 import os
5 5 import re
6 6 import formencode
7 7 import logging
8 8 from pylons.i18n.translation import _
9 9 from webhelpers.pylonslib.secure_form import authentication_token
10 10
11 11 from formencode.validators import (
12 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set
12 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
13 13 )
14
15 14 from rhodecode.lib.utils import repo_name_slug
16 15 from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User
17 16 from rhodecode.lib.exceptions import LdapImportError
18 17 from rhodecode.config.routing import ADMIN_PREFIX
19 18 # silence warnings and pylint
20 19 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set
21 20
22 21 log = logging.getLogger(__name__)
23 22
24 23
25 24 class StateObj(object):
26 25 """
27 26 this is needed to translate the messages using _() in validators
28 27 """
29 28 _ = staticmethod(_)
30 29
31 30
32 31 def M(self, key, state=None, **kwargs):
33 32 """
34 33 returns string from self.message based on given key,
35 34 passed kw params are used to substitute %(named)s params inside
36 35 translated strings
37 36
38 37 :param msg:
39 38 :param state:
40 39 """
41 40 if state is None:
42 41 state = StateObj()
43 42 else:
44 43 state._ = staticmethod(_)
45 44 #inject validator into state object
46 45 return self.message(key, state, **kwargs)
47 46
48 47
49 48 def ValidUsername(edit=False, old_data={}):
50 49 class _validator(formencode.validators.FancyValidator):
51 50 messages = {
52 51 'username_exists': _(u'Username "%(username)s" already exists'),
53 52 'system_invalid_username':
54 53 _(u'Username "%(username)s" is forbidden'),
55 54 'invalid_username':
56 55 _(u'Username may only contain alphanumeric characters '
57 56 'underscores, periods or dashes and must begin with '
58 57 'alphanumeric character')
59 58 }
60 59
61 60 def validate_python(self, value, state):
62 61 if value in ['default', 'new_user']:
63 62 msg = M(self, 'system_invalid_username', state, username=value)
64 63 raise formencode.Invalid(msg, value, state)
65 64 #check if user is unique
66 65 old_un = None
67 66 if edit:
68 67 old_un = User.get(old_data.get('user_id')).username
69 68
70 69 if old_un != value or not edit:
71 70 if User.get_by_username(value, case_insensitive=True):
72 71 msg = M(self, 'username_exists', state, username=value)
73 72 raise formencode.Invalid(msg, value, state)
74 73
75 74 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
76 75 msg = M(self, 'invalid_username', state)
77 76 raise formencode.Invalid(msg, value, state)
78 77 return _validator
79 78
80 79
81 80 def ValidRepoUser():
82 81 class _validator(formencode.validators.FancyValidator):
83 82 messages = {
84 83 'invalid_username': _(u'Username %(username)s is not valid')
85 84 }
86 85
87 86 def validate_python(self, value, state):
88 87 try:
89 88 User.query().filter(User.active == True)\
90 89 .filter(User.username == value).one()
91 90 except Exception:
92 91 msg = M(self, 'invalid_username', state, username=value)
93 92 raise formencode.Invalid(msg, value, state,
94 93 error_dict=dict(username=msg)
95 94 )
96 95
97 96 return _validator
98 97
99 98
100 99 def ValidUsersGroup(edit=False, old_data={}):
101 100 class _validator(formencode.validators.FancyValidator):
102 101 messages = {
103 102 'invalid_group': _(u'Invalid users group name'),
104 103 'group_exist': _(u'Users group "%(usersgroup)s" already exists'),
105 104 'invalid_usersgroup_name':
106 105 _(u'users group name may only contain alphanumeric '
107 106 'characters underscores, periods or dashes and must begin '
108 107 'with alphanumeric character')
109 108 }
110 109
111 110 def validate_python(self, value, state):
112 111 if value in ['default']:
113 112 msg = M(self, 'invalid_group', state)
114 113 raise formencode.Invalid(msg, value, state,
115 114 error_dict=dict(users_group_name=msg)
116 115 )
117 116 #check if group is unique
118 117 old_ugname = None
119 118 if edit:
120 119 old_id = old_data.get('users_group_id')
121 120 old_ugname = UsersGroup.get(old_id).users_group_name
122 121
123 122 if old_ugname != value or not edit:
124 123 is_existing_group = UsersGroup.get_by_group_name(value,
125 124 case_insensitive=True)
126 125 if is_existing_group:
127 126 msg = M(self, 'group_exist', state, usersgroup=value)
128 127 raise formencode.Invalid(msg, value, state,
129 128 error_dict=dict(users_group_name=msg)
130 129 )
131 130
132 131 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
133 132 msg = M(self, 'invalid_usersgroup_name', state)
134 133 raise formencode.Invalid(msg, value, state,
135 134 error_dict=dict(users_group_name=msg)
136 135 )
137 136
138 137 return _validator
139 138
140 139
141 140 def ValidReposGroup(edit=False, old_data={}):
142 141 class _validator(formencode.validators.FancyValidator):
143 142 messages = {
144 143 'group_parent_id': _(u'Cannot assign this group as parent'),
145 144 'group_exists': _(u'Group "%(group_name)s" already exists'),
146 145 'repo_exists':
147 146 _(u'Repository with name "%(group_name)s" already exists')
148 147 }
149 148
150 149 def validate_python(self, value, state):
151 150 # TODO WRITE VALIDATIONS
152 151 group_name = value.get('group_name')
153 152 group_parent_id = value.get('group_parent_id')
154 153
155 154 # slugify repo group just in case :)
156 155 slug = repo_name_slug(group_name)
157 156
158 157 # check for parent of self
159 158 parent_of_self = lambda: (
160 159 old_data['group_id'] == int(group_parent_id)
161 160 if group_parent_id else False
162 161 )
163 162 if edit and parent_of_self():
164 163 msg = M(self, 'group_parent_id', state)
165 164 raise formencode.Invalid(msg, value, state,
166 165 error_dict=dict(group_parent_id=msg)
167 166 )
168 167
169 168 old_gname = None
170 169 if edit:
171 170 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
172 171
173 172 if old_gname != group_name or not edit:
174 173
175 174 # check group
176 175 gr = RepoGroup.query()\
177 176 .filter(RepoGroup.group_name == slug)\
178 177 .filter(RepoGroup.group_parent_id == group_parent_id)\
179 178 .scalar()
180 179
181 180 if gr:
182 181 msg = M(self, 'group_exists', state, group_name=slug)
183 182 raise formencode.Invalid(msg, value, state,
184 183 error_dict=dict(group_name=msg)
185 184 )
186 185
187 186 # check for same repo
188 187 repo = Repository.query()\
189 188 .filter(Repository.repo_name == slug)\
190 189 .scalar()
191 190
192 191 if repo:
193 192 msg = M(self, 'repo_exists', state, group_name=slug)
194 193 raise formencode.Invalid(msg, value, state,
195 194 error_dict=dict(group_name=msg)
196 195 )
197 196
198 197 return _validator
199 198
200 199
201 200 def ValidPassword():
202 201 class _validator(formencode.validators.FancyValidator):
203 202 messages = {
204 203 'invalid_password':
205 204 _(u'Invalid characters (non-ascii) in password')
206 205 }
207 206
208 207 def validate_python(self, value, state):
209 208 try:
210 209 (value or '').decode('ascii')
211 210 except UnicodeError:
212 211 msg = M(self, 'invalid_password', state)
213 212 raise formencode.Invalid(msg, value, state,)
214 213 return _validator
215 214
216 215
217 216 def ValidPasswordsMatch():
218 217 class _validator(formencode.validators.FancyValidator):
219 218 messages = {
220 219 'password_mismatch': _(u'Passwords do not match'),
221 220 }
222 221
223 222 def validate_python(self, value, state):
224 223
225 224 pass_val = value.get('password') or value.get('new_password')
226 225 if pass_val != value['password_confirmation']:
227 226 msg = M(self, 'password_mismatch', state)
228 227 raise formencode.Invalid(msg, value, state,
229 228 error_dict=dict(password_confirmation=msg)
230 229 )
231 230 return _validator
232 231
233 232
234 233 def ValidAuth():
235 234 class _validator(formencode.validators.FancyValidator):
236 235 messages = {
237 236 'invalid_password': _(u'invalid password'),
238 237 'invalid_username': _(u'invalid user name'),
239 238 'disabled_account': _(u'Your account is disabled')
240 239 }
241 240
242 241 def validate_python(self, value, state):
243 242 from rhodecode.lib.auth import authenticate
244 243
245 244 password = value['password']
246 245 username = value['username']
247 246
248 247 if not authenticate(username, password):
249 248 user = User.get_by_username(username)
250 249 if user and user.active is False:
251 250 log.warning('user %s is disabled' % username)
252 251 msg = M(self, 'disabled_account', state)
253 252 raise formencode.Invalid(msg, value, state,
254 253 error_dict=dict(username=msg)
255 254 )
256 255 else:
257 256 log.warning('user %s failed to authenticate' % username)
258 257 msg = M(self, 'invalid_username', state)
259 258 msg2 = M(self, 'invalid_password', state)
260 259 raise formencode.Invalid(msg, value, state,
261 260 error_dict=dict(username=msg, password=msg2)
262 261 )
263 262 return _validator
264 263
265 264
266 265 def ValidAuthToken():
267 266 class _validator(formencode.validators.FancyValidator):
268 267 messages = {
269 268 'invalid_token': _(u'Token mismatch')
270 269 }
271 270
272 271 def validate_python(self, value, state):
273 272 if value != authentication_token():
274 273 msg = M(self, 'invalid_token', state)
275 274 raise formencode.Invalid(msg, value, state)
276 275 return _validator
277 276
278 277
279 278 def ValidRepoName(edit=False, old_data={}):
280 279 class _validator(formencode.validators.FancyValidator):
281 280 messages = {
282 281 'invalid_repo_name':
283 282 _(u'Repository name %(repo)s is disallowed'),
284 283 'repository_exists':
285 284 _(u'Repository named %(repo)s already exists'),
286 285 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
287 286 'exists in group "%(group)s"'),
288 287 'same_group_exists': _(u'Repositories group with name "%(repo)s" '
289 288 'already exists')
290 289 }
291 290
292 291 def _to_python(self, value, state):
293 292 repo_name = repo_name_slug(value.get('repo_name', ''))
294 293 repo_group = value.get('repo_group')
295 294 if repo_group:
296 295 gr = RepoGroup.get(repo_group)
297 296 group_path = gr.full_path
298 297 group_name = gr.group_name
299 298 # value needs to be aware of group name in order to check
300 299 # db key This is an actual just the name to store in the
301 300 # database
302 301 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
303 302 else:
304 303 group_name = group_path = ''
305 304 repo_name_full = repo_name
306 305
307 306 value['repo_name'] = repo_name
308 307 value['repo_name_full'] = repo_name_full
309 308 value['group_path'] = group_path
310 309 value['group_name'] = group_name
311 310 return value
312 311
313 312 def validate_python(self, value, state):
314 313
315 314 repo_name = value.get('repo_name')
316 315 repo_name_full = value.get('repo_name_full')
317 316 group_path = value.get('group_path')
318 317 group_name = value.get('group_name')
319 318
320 319 if repo_name in [ADMIN_PREFIX, '']:
321 320 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
322 321 raise formencode.Invalid(msg, value, state,
323 322 error_dict=dict(repo_name=msg)
324 323 )
325 324
326 325 rename = old_data.get('repo_name') != repo_name_full
327 326 create = not edit
328 327 if rename or create:
329 328
330 329 if group_path != '':
331 330 if Repository.get_by_repo_name(repo_name_full):
332 331 msg = M(self, 'repository_in_group_exists', state,
333 332 repo=repo_name, group=group_name)
334 333 raise formencode.Invalid(msg, value, state,
335 334 error_dict=dict(repo_name=msg)
336 335 )
337 336 elif RepoGroup.get_by_group_name(repo_name_full):
338 337 msg = M(self, 'same_group_exists', state,
339 338 repo=repo_name)
340 339 raise formencode.Invalid(msg, value, state,
341 340 error_dict=dict(repo_name=msg)
342 341 )
343 342
344 343 elif Repository.get_by_repo_name(repo_name_full):
345 344 msg = M(self, 'repository_exists', state,
346 345 repo=repo_name)
347 346 raise formencode.Invalid(msg, value, state,
348 347 error_dict=dict(repo_name=msg)
349 348 )
350 349 return value
351 350 return _validator
352 351
353 352
354 353 def ValidForkName(*args, **kwargs):
355 354 return ValidRepoName(*args, **kwargs)
356 355
357 356
358 357 def SlugifyName():
359 358 class _validator(formencode.validators.FancyValidator):
360 359
361 360 def _to_python(self, value, state):
362 361 return repo_name_slug(value)
363 362
364 363 def validate_python(self, value, state):
365 364 pass
366 365
367 366 return _validator
368 367
369 368
370 369 def ValidCloneUri():
371 370 from rhodecode.lib.utils import make_ui
372 371
373 372 def url_handler(repo_type, url, ui=None):
374 373 if repo_type == 'hg':
375 374 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
376 375 from mercurial.httppeer import httppeer
377 376 if url.startswith('http'):
378 377 ## initially check if it's at least the proper URL
379 378 ## or does it pass basic auth
380 379 MercurialRepository._check_url(url)
381 380 httppeer(make_ui('db'), url)._capabilities()
382 381 elif url.startswith('svn+http'):
383 382 from hgsubversion.svnrepo import svnremoterepo
384 383 svnremoterepo(make_ui('db'), url).capabilities
385 384 elif url.startswith('git+http'):
386 385 raise NotImplementedError()
387 386
388 387 elif repo_type == 'git':
389 388 from rhodecode.lib.vcs.backends.git.repository import GitRepository
390 389 if url.startswith('http'):
391 390 ## initially check if it's at least the proper URL
392 391 ## or does it pass basic auth
393 392 GitRepository._check_url(url)
394 393 elif url.startswith('svn+http'):
395 394 raise NotImplementedError()
396 395 elif url.startswith('hg+http'):
397 396 raise NotImplementedError()
398 397
399 398 class _validator(formencode.validators.FancyValidator):
400 399 messages = {
401 400 'clone_uri': _(u'invalid clone url'),
402 401 'invalid_clone_uri': _(u'Invalid clone url, provide a '
403 402 'valid clone http(s)/svn+http(s) url')
404 403 }
405 404
406 405 def validate_python(self, value, state):
407 406 repo_type = value.get('repo_type')
408 407 url = value.get('clone_uri')
409 408
410 409 if not url:
411 410 pass
412 411 else:
413 412 try:
414 413 url_handler(repo_type, url, make_ui('db'))
415 414 except Exception:
416 415 log.exception('Url validation failed')
417 416 msg = M(self, 'clone_uri')
418 417 raise formencode.Invalid(msg, value, state,
419 418 error_dict=dict(clone_uri=msg)
420 419 )
421 420 return _validator
422 421
423 422
424 423 def ValidForkType(old_data={}):
425 424 class _validator(formencode.validators.FancyValidator):
426 425 messages = {
427 426 'invalid_fork_type': _(u'Fork have to be the same type as parent')
428 427 }
429 428
430 429 def validate_python(self, value, state):
431 430 if old_data['repo_type'] != value:
432 431 msg = M(self, 'invalid_fork_type', state)
433 432 raise formencode.Invalid(msg, value, state,
434 433 error_dict=dict(repo_type=msg)
435 434 )
436 435 return _validator
437 436
438 437
439 438 def ValidPerms(type_='repo'):
440 439 if type_ == 'group':
441 440 EMPTY_PERM = 'group.none'
442 441 elif type_ == 'repo':
443 442 EMPTY_PERM = 'repository.none'
444 443
445 444 class _validator(formencode.validators.FancyValidator):
446 445 messages = {
447 446 'perm_new_member_name':
448 447 _(u'This username or users group name is not valid')
449 448 }
450 449
451 450 def to_python(self, value, state):
452 451 perms_update = []
453 452 perms_new = []
454 453 # build a list of permission to update and new permission to create
455 454 for k, v in value.items():
456 455 # means new added member to permissions
457 456 if k.startswith('perm_new_member'):
458 457 new_perm = value.get('perm_new_member', False)
459 458 new_member = value.get('perm_new_member_name', False)
460 459 new_type = value.get('perm_new_member_type')
461 460
462 461 if new_member and new_perm:
463 462 if (new_member, new_perm, new_type) not in perms_new:
464 463 perms_new.append((new_member, new_perm, new_type))
465 464 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
466 465 member = k[7:]
467 466 t = {'u': 'user',
468 467 'g': 'users_group'
469 468 }[k[0]]
470 469 if member == 'default':
471 470 if value.get('private'):
472 471 # set none for default when updating to
473 472 # private repo
474 473 v = EMPTY_PERM
475 474 perms_update.append((member, v, t))
476 475
477 476 value['perms_updates'] = perms_update
478 477 value['perms_new'] = perms_new
479 478
480 479 # update permissions
481 480 for k, v, t in perms_new:
482 481 try:
483 482 if t is 'user':
484 483 self.user_db = User.query()\
485 484 .filter(User.active == True)\
486 485 .filter(User.username == k).one()
487 486 if t is 'users_group':
488 487 self.user_db = UsersGroup.query()\
489 488 .filter(UsersGroup.users_group_active == True)\
490 489 .filter(UsersGroup.users_group_name == k).one()
491 490
492 491 except Exception:
493 492 log.exception('Updated permission failed')
494 493 msg = M(self, 'perm_new_member_type', state)
495 494 raise formencode.Invalid(msg, value, state,
496 495 error_dict=dict(perm_new_member_name=msg)
497 496 )
498 497 return value
499 498 return _validator
500 499
501 500
502 501 def ValidSettings():
503 502 class _validator(formencode.validators.FancyValidator):
504 503 def _to_python(self, value, state):
505 504 # settings form can't edit user
506 505 if 'user' in value:
507 506 del value['user']
508 507 return value
509 508
510 509 def validate_python(self, value, state):
511 510 pass
512 511 return _validator
513 512
514 513
515 514 def ValidPath():
516 515 class _validator(formencode.validators.FancyValidator):
517 516 messages = {
518 517 'invalid_path': _(u'This is not a valid path')
519 518 }
520 519
521 520 def validate_python(self, value, state):
522 521 if not os.path.isdir(value):
523 522 msg = M(self, 'invalid_path', state)
524 523 raise formencode.Invalid(msg, value, state,
525 524 error_dict=dict(paths_root_path=msg)
526 525 )
527 526 return _validator
528 527
529 528
530 529 def UniqSystemEmail(old_data={}):
531 530 class _validator(formencode.validators.FancyValidator):
532 531 messages = {
533 532 'email_taken': _(u'This e-mail address is already taken')
534 533 }
535 534
536 535 def _to_python(self, value, state):
537 536 return value.lower()
538 537
539 538 def validate_python(self, value, state):
540 539 if (old_data.get('email') or '').lower() != value:
541 540 user = User.get_by_email(value, case_insensitive=True)
542 541 if user:
543 542 msg = M(self, 'email_taken', state)
544 543 raise formencode.Invalid(msg, value, state,
545 544 error_dict=dict(email=msg)
546 545 )
547 546 return _validator
548 547
549 548
550 549 def ValidSystemEmail():
551 550 class _validator(formencode.validators.FancyValidator):
552 551 messages = {
553 552 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
554 553 }
555 554
556 555 def _to_python(self, value, state):
557 556 return value.lower()
558 557
559 558 def validate_python(self, value, state):
560 559 user = User.get_by_email(value, case_insensitive=True)
561 560 if user is None:
562 561 msg = M(self, 'non_existing_email', state, email=value)
563 562 raise formencode.Invalid(msg, value, state,
564 563 error_dict=dict(email=msg)
565 564 )
566 565
567 566 return _validator
568 567
569 568
570 569 def LdapLibValidator():
571 570 class _validator(formencode.validators.FancyValidator):
572 571 messages = {
573 572
574 573 }
575 574
576 575 def validate_python(self, value, state):
577 576 try:
578 577 import ldap
579 578 ldap # pyflakes silence !
580 579 except ImportError:
581 580 raise LdapImportError()
582 581
583 582 return _validator
584 583
585 584
586 585 def AttrLoginValidator():
587 586 class _validator(formencode.validators.FancyValidator):
588 587 messages = {
589 588 'invalid_cn':
590 589 _(u'The LDAP Login attribute of the CN must be specified - '
591 590 'this is the name of the attribute that is equivalent '
592 591 'to "username"')
593 592 }
594 593
595 594 def validate_python(self, value, state):
596 595 if not value or not isinstance(value, (str, unicode)):
597 596 msg = M(self, 'invalid_cn', state)
598 597 raise formencode.Invalid(msg, value, state,
599 598 error_dict=dict(ldap_attr_login=msg)
600 599 )
601 600
602 601 return _validator
General Comments 0
You need to be logged in to leave comments. Login now