##// END OF EJS Templates
fix required repo_type param on repo edit form
marcink -
r3862:2b2f5e6c default
parent child Browse files
Show More
@@ -1,606 +1,610 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, HasRepoPermissionAnyDecorator
41 HasPermissionAny, HasReposGroupPermissionAny, HasRepoPermissionAnyDecorator
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, RepoPermsForm
48 from rhodecode.model.forms import RepoForm, RepoFieldForm, RepoPermsForm
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 from rhodecode.lib.exceptions import AttachedForksError
53 from rhodecode.lib.exceptions import AttachedForksError
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57
57
58 class ReposController(BaseRepoController):
58 class ReposController(BaseRepoController):
59 """
59 """
60 REST Controller styled on the Atom Publishing Protocol"""
60 REST Controller styled on the Atom Publishing Protocol"""
61 # To properly map this controller, ensure your config/routing.py
61 # To properly map this controller, ensure your config/routing.py
62 # file has a resource setup:
62 # file has a resource setup:
63 # map.resource('repo', 'repos')
63 # map.resource('repo', 'repos')
64
64
65 @LoginRequired()
65 @LoginRequired()
66 def __before__(self):
66 def __before__(self):
67 c.admin_user = session.get('admin_user')
67 c.admin_user = session.get('admin_user')
68 c.admin_username = session.get('admin_username')
68 c.admin_username = session.get('admin_username')
69 super(ReposController, self).__before__()
69 super(ReposController, self).__before__()
70
70
71 def __load_defaults(self):
71 def __load_defaults(self):
72 acl_groups = GroupList(RepoGroup.query().all(),
72 acl_groups = GroupList(RepoGroup.query().all(),
73 perm_set=['group.write', 'group.admin'])
73 perm_set=['group.write', 'group.admin'])
74 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
74 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
75 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
75 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
76
76
77 repo_model = RepoModel()
77 repo_model = RepoModel()
78 c.users_array = repo_model.get_users_js()
78 c.users_array = repo_model.get_users_js()
79 c.users_groups_array = repo_model.get_users_groups_js()
79 c.users_groups_array = repo_model.get_users_groups_js()
80 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
80 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
81 c.landing_revs_choices = choices
81 c.landing_revs_choices = choices
82
82
83 def __load_data(self, repo_name=None):
83 def __load_data(self, repo_name=None):
84 """
84 """
85 Load defaults settings for edit, and update
85 Load defaults settings for edit, and update
86
86
87 :param repo_name:
87 :param repo_name:
88 """
88 """
89 self.__load_defaults()
89 self.__load_defaults()
90
90
91 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
91 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
92 repo = db_repo.scm_instance
92 repo = db_repo.scm_instance
93
93
94 if c.repo_info is None:
94 if c.repo_info is None:
95 h.not_mapped_error(repo_name)
95 h.not_mapped_error(repo_name)
96 return redirect(url('repos'))
96 return redirect(url('repos'))
97
97
98 ##override defaults for exact repo info here git/hg etc
98 ##override defaults for exact repo info here git/hg etc
99 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
99 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
100 c.landing_revs_choices = choices
100 c.landing_revs_choices = choices
101
101
102 c.default_user_id = User.get_by_username('default').user_id
102 c.default_user_id = User.get_by_username('default').user_id
103 c.in_public_journal = UserFollowing.query()\
103 c.in_public_journal = UserFollowing.query()\
104 .filter(UserFollowing.user_id == c.default_user_id)\
104 .filter(UserFollowing.user_id == c.default_user_id)\
105 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
105 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
106
106
107 if c.repo_info.stats:
107 if c.repo_info.stats:
108 # this is on what revision we ended up so we add +1 for count
108 # this is on what revision we ended up so we add +1 for count
109 last_rev = c.repo_info.stats.stat_on_revision + 1
109 last_rev = c.repo_info.stats.stat_on_revision + 1
110 else:
110 else:
111 last_rev = 0
111 last_rev = 0
112 c.stats_revision = last_rev
112 c.stats_revision = last_rev
113
113
114 c.repo_last_rev = repo.count() if repo.revisions else 0
114 c.repo_last_rev = repo.count() if repo.revisions else 0
115
115
116 if last_rev == 0 or c.repo_last_rev == 0:
116 if last_rev == 0 or c.repo_last_rev == 0:
117 c.stats_percentage = 0
117 c.stats_percentage = 0
118 else:
118 else:
119 c.stats_percentage = '%.2f' % ((float((last_rev)) /
119 c.stats_percentage = '%.2f' % ((float((last_rev)) /
120 c.repo_last_rev) * 100)
120 c.repo_last_rev) * 100)
121
121
122 c.repo_fields = RepositoryField.query()\
122 c.repo_fields = RepositoryField.query()\
123 .filter(RepositoryField.repository == db_repo).all()
123 .filter(RepositoryField.repository == db_repo).all()
124
124
125 defaults = RepoModel()._get_defaults(repo_name)
125 defaults = RepoModel()._get_defaults(repo_name)
126
126
127 c.repos_list = [('', _('--REMOVE FORK--'))]
127 c.repos_list = [('', _('--REMOVE FORK--'))]
128 c.repos_list += [(x.repo_id, x.repo_name) for x in
128 c.repos_list += [(x.repo_id, x.repo_name) for x in
129 Repository.query().order_by(Repository.repo_name).all()
129 Repository.query().order_by(Repository.repo_name).all()
130 if x.repo_id != c.repo_info.repo_id]
130 if x.repo_id != c.repo_info.repo_id]
131
131
132 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
132 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
133 return defaults
133 return defaults
134
134
135 @HasPermissionAllDecorator('hg.admin')
135 @HasPermissionAllDecorator('hg.admin')
136 def index(self, format='html'):
136 def index(self, format='html'):
137 """GET /repos: All items in the collection"""
137 """GET /repos: All items in the collection"""
138 # url('repos')
138 # url('repos')
139
139
140 c.repos_list = Repository.query()\
140 c.repos_list = Repository.query()\
141 .order_by(func.lower(Repository.repo_name))\
141 .order_by(func.lower(Repository.repo_name))\
142 .all()
142 .all()
143
143
144 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
144 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
145 admin=True,
145 admin=True,
146 super_user_actions=True)
146 super_user_actions=True)
147 #json used to render the grid
147 #json used to render the grid
148 c.data = json.dumps(repos_data)
148 c.data = json.dumps(repos_data)
149
149
150 return render('admin/repos/repos.html')
150 return render('admin/repos/repos.html')
151
151
152 @NotAnonymous()
152 @NotAnonymous()
153 def create(self):
153 def create(self):
154 """
154 """
155 POST /repos: Create a new item"""
155 POST /repos: Create a new item"""
156 # url('repos')
156 # url('repos')
157
157
158 self.__load_defaults()
158 self.__load_defaults()
159 form_result = {}
159 form_result = {}
160 try:
160 try:
161 form_result = RepoForm(repo_groups=c.repo_groups_choices,
161 form_result = RepoForm(repo_groups=c.repo_groups_choices,
162 landing_revs=c.landing_revs_choices)()\
162 landing_revs=c.landing_revs_choices)()\
163 .to_python(dict(request.POST))
163 .to_python(dict(request.POST))
164
164
165 new_repo = RepoModel().create(form_result,
165 new_repo = RepoModel().create(form_result,
166 self.rhodecode_user.user_id)
166 self.rhodecode_user.user_id)
167 if form_result['clone_uri']:
167 if form_result['clone_uri']:
168 h.flash(_('Created repository %s from %s') \
168 h.flash(_('Created repository %s from %s') \
169 % (form_result['repo_name'], form_result['clone_uri']),
169 % (form_result['repo_name'], form_result['clone_uri']),
170 category='success')
170 category='success')
171 else:
171 else:
172 repo_url = h.link_to(form_result['repo_name'],
172 repo_url = h.link_to(form_result['repo_name'],
173 h.url('summary_home', repo_name=form_result['repo_name_full']))
173 h.url('summary_home', repo_name=form_result['repo_name_full']))
174 h.flash(h.literal(_('Created repository %s') % repo_url),
174 h.flash(h.literal(_('Created repository %s') % repo_url),
175 category='success')
175 category='success')
176
176
177 if request.POST.get('user_created'):
177 if request.POST.get('user_created'):
178 # created by regular non admin user
178 # created by regular non admin user
179 action_logger(self.rhodecode_user, 'user_created_repo',
179 action_logger(self.rhodecode_user, 'user_created_repo',
180 form_result['repo_name_full'], self.ip_addr,
180 form_result['repo_name_full'], self.ip_addr,
181 self.sa)
181 self.sa)
182 else:
182 else:
183 action_logger(self.rhodecode_user, 'admin_created_repo',
183 action_logger(self.rhodecode_user, 'admin_created_repo',
184 form_result['repo_name_full'], self.ip_addr,
184 form_result['repo_name_full'], self.ip_addr,
185 self.sa)
185 self.sa)
186 Session().commit()
186 Session().commit()
187 except formencode.Invalid, errors:
187 except formencode.Invalid, errors:
188 return htmlfill.render(
188 return htmlfill.render(
189 render('admin/repos/repo_add.html'),
189 render('admin/repos/repo_add.html'),
190 defaults=errors.value,
190 defaults=errors.value,
191 errors=errors.error_dict or {},
191 errors=errors.error_dict or {},
192 prefix_error=False,
192 prefix_error=False,
193 encoding="UTF-8")
193 encoding="UTF-8")
194
194
195 except Exception:
195 except Exception:
196 log.error(traceback.format_exc())
196 log.error(traceback.format_exc())
197 msg = _('Error creating repository %s') \
197 msg = _('Error creating repository %s') \
198 % form_result.get('repo_name')
198 % form_result.get('repo_name')
199 h.flash(msg, category='error')
199 h.flash(msg, category='error')
200 if c.rhodecode_user.is_admin:
200 if c.rhodecode_user.is_admin:
201 return redirect(url('repos'))
201 return redirect(url('repos'))
202 return redirect(url('home'))
202 return redirect(url('home'))
203 #redirect to our new repo !
203 #redirect to our new repo !
204 return redirect(url('summary_home', repo_name=new_repo.repo_name))
204 return redirect(url('summary_home', repo_name=new_repo.repo_name))
205
205
206 @NotAnonymous()
206 @NotAnonymous()
207 def create_repository(self):
207 def create_repository(self):
208 """GET /_admin/create_repository: Form to create a new item"""
208 """GET /_admin/create_repository: Form to create a new item"""
209 new_repo = request.GET.get('repo', '')
209 new_repo = request.GET.get('repo', '')
210 parent_group = request.GET.get('parent_group')
210 parent_group = request.GET.get('parent_group')
211 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
211 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
212 #you're not super admin nor have global create permissions,
212 #you're not super admin nor have global create permissions,
213 #but maybe you have at least write permission to a parent group ?
213 #but maybe you have at least write permission to a parent group ?
214 _gr = RepoGroup.get(parent_group)
214 _gr = RepoGroup.get(parent_group)
215 gr_name = _gr.group_name if _gr else None
215 gr_name = _gr.group_name if _gr else None
216 if not HasReposGroupPermissionAny('group.admin', 'group.write')(group_name=gr_name):
216 if not HasReposGroupPermissionAny('group.admin', 'group.write')(group_name=gr_name):
217 raise HTTPForbidden
217 raise HTTPForbidden
218
218
219 acl_groups = GroupList(RepoGroup.query().all(),
219 acl_groups = GroupList(RepoGroup.query().all(),
220 perm_set=['group.write', 'group.admin'])
220 perm_set=['group.write', 'group.admin'])
221 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
221 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
222 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
222 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
223 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
223 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
224
224
225 c.new_repo = repo_name_slug(new_repo)
225 c.new_repo = repo_name_slug(new_repo)
226
226
227 ## apply the defaults from defaults page
227 ## apply the defaults from defaults page
228 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
228 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
229 if parent_group:
229 if parent_group:
230 defaults.update({'repo_group': parent_group})
230 defaults.update({'repo_group': parent_group})
231
231
232 return htmlfill.render(
232 return htmlfill.render(
233 render('admin/repos/repo_add.html'),
233 render('admin/repos/repo_add.html'),
234 defaults=defaults,
234 defaults=defaults,
235 errors={},
235 errors={},
236 prefix_error=False,
236 prefix_error=False,
237 encoding="UTF-8"
237 encoding="UTF-8"
238 )
238 )
239
239
240 @HasRepoPermissionAllDecorator('repository.admin')
240 @HasRepoPermissionAllDecorator('repository.admin')
241 def update(self, repo_name):
241 def update(self, repo_name):
242 """
242 """
243 PUT /repos/repo_name: Update an existing item"""
243 PUT /repos/repo_name: Update an existing item"""
244 # Forms posted to this method should contain a hidden field:
244 # Forms posted to this method should contain a hidden field:
245 # <input type="hidden" name="_method" value="PUT" />
245 # <input type="hidden" name="_method" value="PUT" />
246 # Or using helpers:
246 # Or using helpers:
247 # h.form(url('repo', repo_name=ID),
247 # h.form(url('repo', repo_name=ID),
248 # method='put')
248 # method='put')
249 # url('repo', repo_name=ID)
249 # url('repo', repo_name=ID)
250 self.__load_defaults()
250 self.__load_defaults()
251 repo_model = RepoModel()
251 repo_model = RepoModel()
252 changed_name = repo_name
252 changed_name = repo_name
253 #override the choices with extracted revisions !
253 #override the choices with extracted revisions !
254 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
254 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
255 c.landing_revs_choices = choices
255 c.landing_revs_choices = choices
256 repo = Repository.get_by_repo_name(repo_name)
256 repo = Repository.get_by_repo_name(repo_name)
257 _form = RepoForm(edit=True, old_data={'repo_name': repo_name,
257 old_data = {
258 'repo_group': repo.group.get_dict() \
258 'repo_name': repo_name,
259 if repo.group else {}},
259 'repo_group': repo.group.get_dict() if repo.group else {},
260 'repo_type': repo.repo_type,
261 }
262 _form = RepoForm(edit=True, old_data=old_data,
260 repo_groups=c.repo_groups_choices,
263 repo_groups=c.repo_groups_choices,
261 landing_revs=c.landing_revs_choices)()
264 landing_revs=c.landing_revs_choices)()
265
262 try:
266 try:
263 form_result = _form.to_python(dict(request.POST))
267 form_result = _form.to_python(dict(request.POST))
264 repo = repo_model.update(repo_name, **form_result)
268 repo = repo_model.update(repo_name, **form_result)
265 invalidate_cache('get_repo_cached_%s' % repo_name)
269 invalidate_cache('get_repo_cached_%s' % repo_name)
266 h.flash(_('Repository %s updated successfully') % repo_name,
270 h.flash(_('Repository %s updated successfully') % repo_name,
267 category='success')
271 category='success')
268 changed_name = repo.repo_name
272 changed_name = repo.repo_name
269 action_logger(self.rhodecode_user, 'admin_updated_repo',
273 action_logger(self.rhodecode_user, 'admin_updated_repo',
270 changed_name, self.ip_addr, self.sa)
274 changed_name, self.ip_addr, self.sa)
271 Session().commit()
275 Session().commit()
272 except formencode.Invalid, errors:
276 except formencode.Invalid, errors:
273 defaults = self.__load_data(repo_name)
277 defaults = self.__load_data(repo_name)
274 defaults.update(errors.value)
278 defaults.update(errors.value)
275 return htmlfill.render(
279 return htmlfill.render(
276 render('admin/repos/repo_edit.html'),
280 render('admin/repos/repo_edit.html'),
277 defaults=defaults,
281 defaults=defaults,
278 errors=errors.error_dict or {},
282 errors=errors.error_dict or {},
279 prefix_error=False,
283 prefix_error=False,
280 encoding="UTF-8")
284 encoding="UTF-8")
281
285
282 except Exception:
286 except Exception:
283 log.error(traceback.format_exc())
287 log.error(traceback.format_exc())
284 h.flash(_('Error occurred during update of repository %s') \
288 h.flash(_('Error occurred during update of repository %s') \
285 % repo_name, category='error')
289 % repo_name, category='error')
286 return redirect(url('edit_repo', repo_name=changed_name))
290 return redirect(url('edit_repo', repo_name=changed_name))
287
291
288 @HasRepoPermissionAllDecorator('repository.admin')
292 @HasRepoPermissionAllDecorator('repository.admin')
289 def delete(self, repo_name):
293 def delete(self, repo_name):
290 """
294 """
291 DELETE /repos/repo_name: Delete an existing item"""
295 DELETE /repos/repo_name: Delete an existing item"""
292 # Forms posted to this method should contain a hidden field:
296 # Forms posted to this method should contain a hidden field:
293 # <input type="hidden" name="_method" value="DELETE" />
297 # <input type="hidden" name="_method" value="DELETE" />
294 # Or using helpers:
298 # Or using helpers:
295 # h.form(url('repo', repo_name=ID),
299 # h.form(url('repo', repo_name=ID),
296 # method='delete')
300 # method='delete')
297 # url('repo', repo_name=ID)
301 # url('repo', repo_name=ID)
298
302
299 repo_model = RepoModel()
303 repo_model = RepoModel()
300 repo = repo_model.get_by_repo_name(repo_name)
304 repo = repo_model.get_by_repo_name(repo_name)
301 if not repo:
305 if not repo:
302 h.not_mapped_error(repo_name)
306 h.not_mapped_error(repo_name)
303 return redirect(url('repos'))
307 return redirect(url('repos'))
304 try:
308 try:
305 _forks = repo.forks.count()
309 _forks = repo.forks.count()
306 handle_forks = None
310 handle_forks = None
307 if _forks and request.POST.get('forks'):
311 if _forks and request.POST.get('forks'):
308 do = request.POST['forks']
312 do = request.POST['forks']
309 if do == 'detach_forks':
313 if do == 'detach_forks':
310 handle_forks = 'detach'
314 handle_forks = 'detach'
311 h.flash(_('Detached %s forks') % _forks, category='success')
315 h.flash(_('Detached %s forks') % _forks, category='success')
312 elif do == 'delete_forks':
316 elif do == 'delete_forks':
313 handle_forks = 'delete'
317 handle_forks = 'delete'
314 h.flash(_('Deleted %s forks') % _forks, category='success')
318 h.flash(_('Deleted %s forks') % _forks, category='success')
315 repo_model.delete(repo, forks=handle_forks)
319 repo_model.delete(repo, forks=handle_forks)
316 action_logger(self.rhodecode_user, 'admin_deleted_repo',
320 action_logger(self.rhodecode_user, 'admin_deleted_repo',
317 repo_name, self.ip_addr, self.sa)
321 repo_name, self.ip_addr, self.sa)
318 invalidate_cache('get_repo_cached_%s' % repo_name)
322 invalidate_cache('get_repo_cached_%s' % repo_name)
319 h.flash(_('Deleted repository %s') % repo_name, category='success')
323 h.flash(_('Deleted repository %s') % repo_name, category='success')
320 Session().commit()
324 Session().commit()
321 except AttachedForksError:
325 except AttachedForksError:
322 h.flash(_('Cannot delete %s it still contains attached forks')
326 h.flash(_('Cannot delete %s it still contains attached forks')
323 % repo_name, category='warning')
327 % repo_name, category='warning')
324
328
325 except Exception:
329 except Exception:
326 log.error(traceback.format_exc())
330 log.error(traceback.format_exc())
327 h.flash(_('An error occurred during deletion of %s') % repo_name,
331 h.flash(_('An error occurred during deletion of %s') % repo_name,
328 category='error')
332 category='error')
329
333
330 return redirect(url('repos'))
334 return redirect(url('repos'))
331
335
332 @HasRepoPermissionAllDecorator('repository.admin')
336 @HasRepoPermissionAllDecorator('repository.admin')
333 def set_repo_perm_member(self, repo_name):
337 def set_repo_perm_member(self, repo_name):
334 form = RepoPermsForm()().to_python(request.POST)
338 form = RepoPermsForm()().to_python(request.POST)
335
339
336 perms_new = form['perms_new']
340 perms_new = form['perms_new']
337 perms_updates = form['perms_updates']
341 perms_updates = form['perms_updates']
338 cur_repo = repo_name
342 cur_repo = repo_name
339
343
340 # update permissions
344 # update permissions
341 for member, perm, member_type in perms_updates:
345 for member, perm, member_type in perms_updates:
342 if member_type == 'user':
346 if member_type == 'user':
343 # this updates existing one
347 # this updates existing one
344 RepoModel().grant_user_permission(
348 RepoModel().grant_user_permission(
345 repo=cur_repo, user=member, perm=perm
349 repo=cur_repo, user=member, perm=perm
346 )
350 )
347 else:
351 else:
348 RepoModel().grant_users_group_permission(
352 RepoModel().grant_users_group_permission(
349 repo=cur_repo, group_name=member, perm=perm
353 repo=cur_repo, group_name=member, perm=perm
350 )
354 )
351 # set new permissions
355 # set new permissions
352 for member, perm, member_type in perms_new:
356 for member, perm, member_type in perms_new:
353 if member_type == 'user':
357 if member_type == 'user':
354 RepoModel().grant_user_permission(
358 RepoModel().grant_user_permission(
355 repo=cur_repo, user=member, perm=perm
359 repo=cur_repo, user=member, perm=perm
356 )
360 )
357 else:
361 else:
358 RepoModel().grant_users_group_permission(
362 RepoModel().grant_users_group_permission(
359 repo=cur_repo, group_name=member, perm=perm
363 repo=cur_repo, group_name=member, perm=perm
360 )
364 )
361 #TODO: implement this
365 #TODO: implement this
362 #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions',
366 #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions',
363 # repo_name, self.ip_addr, self.sa)
367 # repo_name, self.ip_addr, self.sa)
364 Session().commit()
368 Session().commit()
365 h.flash(_('Repository permissions updated'), category='success')
369 h.flash(_('Repository permissions updated'), category='success')
366 return redirect(url('edit_repo', repo_name=repo_name))
370 return redirect(url('edit_repo', repo_name=repo_name))
367
371
368 @HasRepoPermissionAllDecorator('repository.admin')
372 @HasRepoPermissionAllDecorator('repository.admin')
369 def delete_perm_user(self, repo_name):
373 def delete_perm_user(self, repo_name):
370 """
374 """
371 DELETE an existing repository permission user
375 DELETE an existing repository permission user
372
376
373 :param repo_name:
377 :param repo_name:
374 """
378 """
375 try:
379 try:
376 RepoModel().revoke_user_permission(repo=repo_name,
380 RepoModel().revoke_user_permission(repo=repo_name,
377 user=request.POST['user_id'])
381 user=request.POST['user_id'])
378 #TODO: implement this
382 #TODO: implement this
379 #action_logger(self.rhodecode_user, 'admin_revoked_repo_permissions',
383 #action_logger(self.rhodecode_user, 'admin_revoked_repo_permissions',
380 # repo_name, self.ip_addr, self.sa)
384 # repo_name, self.ip_addr, self.sa)
381 Session().commit()
385 Session().commit()
382 except Exception:
386 except Exception:
383 log.error(traceback.format_exc())
387 log.error(traceback.format_exc())
384 h.flash(_('An error occurred during deletion of repository user'),
388 h.flash(_('An error occurred during deletion of repository user'),
385 category='error')
389 category='error')
386 raise HTTPInternalServerError()
390 raise HTTPInternalServerError()
387
391
388 @HasRepoPermissionAllDecorator('repository.admin')
392 @HasRepoPermissionAllDecorator('repository.admin')
389 def delete_perm_users_group(self, repo_name):
393 def delete_perm_users_group(self, repo_name):
390 """
394 """
391 DELETE an existing repository permission user group
395 DELETE an existing repository permission user group
392
396
393 :param repo_name:
397 :param repo_name:
394 """
398 """
395
399
396 try:
400 try:
397 RepoModel().revoke_users_group_permission(
401 RepoModel().revoke_users_group_permission(
398 repo=repo_name, group_name=request.POST['users_group_id']
402 repo=repo_name, group_name=request.POST['users_group_id']
399 )
403 )
400 Session().commit()
404 Session().commit()
401 except Exception:
405 except Exception:
402 log.error(traceback.format_exc())
406 log.error(traceback.format_exc())
403 h.flash(_('An error occurred during deletion of repository'
407 h.flash(_('An error occurred during deletion of repository'
404 ' user groups'),
408 ' user groups'),
405 category='error')
409 category='error')
406 raise HTTPInternalServerError()
410 raise HTTPInternalServerError()
407
411
408 @HasRepoPermissionAllDecorator('repository.admin')
412 @HasRepoPermissionAllDecorator('repository.admin')
409 def repo_stats(self, repo_name):
413 def repo_stats(self, repo_name):
410 """
414 """
411 DELETE an existing repository statistics
415 DELETE an existing repository statistics
412
416
413 :param repo_name:
417 :param repo_name:
414 """
418 """
415
419
416 try:
420 try:
417 RepoModel().delete_stats(repo_name)
421 RepoModel().delete_stats(repo_name)
418 Session().commit()
422 Session().commit()
419 except Exception, e:
423 except Exception, e:
420 log.error(traceback.format_exc())
424 log.error(traceback.format_exc())
421 h.flash(_('An error occurred during deletion of repository stats'),
425 h.flash(_('An error occurred during deletion of repository stats'),
422 category='error')
426 category='error')
423 return redirect(url('edit_repo', repo_name=repo_name))
427 return redirect(url('edit_repo', repo_name=repo_name))
424
428
425 @HasRepoPermissionAllDecorator('repository.admin')
429 @HasRepoPermissionAllDecorator('repository.admin')
426 def repo_cache(self, repo_name):
430 def repo_cache(self, repo_name):
427 """
431 """
428 INVALIDATE existing repository cache
432 INVALIDATE existing repository cache
429
433
430 :param repo_name:
434 :param repo_name:
431 """
435 """
432
436
433 try:
437 try:
434 ScmModel().mark_for_invalidation(repo_name)
438 ScmModel().mark_for_invalidation(repo_name)
435 Session().commit()
439 Session().commit()
436 except Exception, e:
440 except Exception, e:
437 log.error(traceback.format_exc())
441 log.error(traceback.format_exc())
438 h.flash(_('An error occurred during cache invalidation'),
442 h.flash(_('An error occurred during cache invalidation'),
439 category='error')
443 category='error')
440 return redirect(url('edit_repo', repo_name=repo_name))
444 return redirect(url('edit_repo', repo_name=repo_name))
441
445
442 @HasRepoPermissionAllDecorator('repository.admin')
446 @HasRepoPermissionAllDecorator('repository.admin')
443 def repo_locking(self, repo_name):
447 def repo_locking(self, repo_name):
444 """
448 """
445 Unlock repository when it is locked !
449 Unlock repository when it is locked !
446
450
447 :param repo_name:
451 :param repo_name:
448 """
452 """
449
453
450 try:
454 try:
451 repo = Repository.get_by_repo_name(repo_name)
455 repo = Repository.get_by_repo_name(repo_name)
452 if request.POST.get('set_lock'):
456 if request.POST.get('set_lock'):
453 Repository.lock(repo, c.rhodecode_user.user_id)
457 Repository.lock(repo, c.rhodecode_user.user_id)
454 elif request.POST.get('set_unlock'):
458 elif request.POST.get('set_unlock'):
455 Repository.unlock(repo)
459 Repository.unlock(repo)
456 except Exception, e:
460 except Exception, e:
457 log.error(traceback.format_exc())
461 log.error(traceback.format_exc())
458 h.flash(_('An error occurred during unlocking'),
462 h.flash(_('An error occurred during unlocking'),
459 category='error')
463 category='error')
460 return redirect(url('edit_repo', repo_name=repo_name))
464 return redirect(url('edit_repo', repo_name=repo_name))
461
465
462 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
466 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
463 def toggle_locking(self, repo_name):
467 def toggle_locking(self, repo_name):
464 """
468 """
465 Toggle locking of repository by simple GET call to url
469 Toggle locking of repository by simple GET call to url
466
470
467 :param repo_name:
471 :param repo_name:
468 """
472 """
469
473
470 try:
474 try:
471 repo = Repository.get_by_repo_name(repo_name)
475 repo = Repository.get_by_repo_name(repo_name)
472
476
473 if repo.enable_locking:
477 if repo.enable_locking:
474 if repo.locked[0]:
478 if repo.locked[0]:
475 Repository.unlock(repo)
479 Repository.unlock(repo)
476 action = _('Unlocked')
480 action = _('Unlocked')
477 else:
481 else:
478 Repository.lock(repo, c.rhodecode_user.user_id)
482 Repository.lock(repo, c.rhodecode_user.user_id)
479 action = _('Locked')
483 action = _('Locked')
480
484
481 h.flash(_('Repository has been %s') % action,
485 h.flash(_('Repository has been %s') % action,
482 category='success')
486 category='success')
483 except Exception, e:
487 except Exception, e:
484 log.error(traceback.format_exc())
488 log.error(traceback.format_exc())
485 h.flash(_('An error occurred during unlocking'),
489 h.flash(_('An error occurred during unlocking'),
486 category='error')
490 category='error')
487 return redirect(url('summary_home', repo_name=repo_name))
491 return redirect(url('summary_home', repo_name=repo_name))
488
492
489 @HasRepoPermissionAllDecorator('repository.admin')
493 @HasRepoPermissionAllDecorator('repository.admin')
490 def repo_public_journal(self, repo_name):
494 def repo_public_journal(self, repo_name):
491 """
495 """
492 Set's this repository to be visible in public journal,
496 Set's this repository to be visible in public journal,
493 in other words assing default user to follow this repo
497 in other words assing default user to follow this repo
494
498
495 :param repo_name:
499 :param repo_name:
496 """
500 """
497
501
498 cur_token = request.POST.get('auth_token')
502 cur_token = request.POST.get('auth_token')
499 token = get_token()
503 token = get_token()
500 if cur_token == token:
504 if cur_token == token:
501 try:
505 try:
502 repo_id = Repository.get_by_repo_name(repo_name).repo_id
506 repo_id = Repository.get_by_repo_name(repo_name).repo_id
503 user_id = User.get_by_username('default').user_id
507 user_id = User.get_by_username('default').user_id
504 self.scm_model.toggle_following_repo(repo_id, user_id)
508 self.scm_model.toggle_following_repo(repo_id, user_id)
505 h.flash(_('Updated repository visibility in public journal'),
509 h.flash(_('Updated repository visibility in public journal'),
506 category='success')
510 category='success')
507 Session().commit()
511 Session().commit()
508 except Exception:
512 except Exception:
509 h.flash(_('An error occurred during setting this'
513 h.flash(_('An error occurred during setting this'
510 ' repository in public journal'),
514 ' repository in public journal'),
511 category='error')
515 category='error')
512
516
513 else:
517 else:
514 h.flash(_('Token mismatch'), category='error')
518 h.flash(_('Token mismatch'), category='error')
515 return redirect(url('edit_repo', repo_name=repo_name))
519 return redirect(url('edit_repo', repo_name=repo_name))
516
520
517 @HasRepoPermissionAllDecorator('repository.admin')
521 @HasRepoPermissionAllDecorator('repository.admin')
518 def repo_pull(self, repo_name):
522 def repo_pull(self, repo_name):
519 """
523 """
520 Runs task to update given repository with remote changes,
524 Runs task to update given repository with remote changes,
521 ie. make pull on remote location
525 ie. make pull on remote location
522
526
523 :param repo_name:
527 :param repo_name:
524 """
528 """
525 try:
529 try:
526 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
530 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
527 h.flash(_('Pulled from remote location'), category='success')
531 h.flash(_('Pulled from remote location'), category='success')
528 except Exception, e:
532 except Exception, e:
529 h.flash(_('An error occurred during pull from remote location'),
533 h.flash(_('An error occurred during pull from remote location'),
530 category='error')
534 category='error')
531
535
532 return redirect(url('edit_repo', repo_name=repo_name))
536 return redirect(url('edit_repo', repo_name=repo_name))
533
537
534 @HasRepoPermissionAllDecorator('repository.admin')
538 @HasRepoPermissionAllDecorator('repository.admin')
535 def repo_as_fork(self, repo_name):
539 def repo_as_fork(self, repo_name):
536 """
540 """
537 Mark given repository as a fork of another
541 Mark given repository as a fork of another
538
542
539 :param repo_name:
543 :param repo_name:
540 """
544 """
541 try:
545 try:
542 fork_id = request.POST.get('id_fork_of')
546 fork_id = request.POST.get('id_fork_of')
543 repo = ScmModel().mark_as_fork(repo_name, fork_id,
547 repo = ScmModel().mark_as_fork(repo_name, fork_id,
544 self.rhodecode_user.username)
548 self.rhodecode_user.username)
545 fork = repo.fork.repo_name if repo.fork else _('Nothing')
549 fork = repo.fork.repo_name if repo.fork else _('Nothing')
546 Session().commit()
550 Session().commit()
547 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
551 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
548 category='success')
552 category='success')
549 except Exception, e:
553 except Exception, e:
550 log.error(traceback.format_exc())
554 log.error(traceback.format_exc())
551 h.flash(_('An error occurred during this operation'),
555 h.flash(_('An error occurred during this operation'),
552 category='error')
556 category='error')
553
557
554 return redirect(url('edit_repo', repo_name=repo_name))
558 return redirect(url('edit_repo', repo_name=repo_name))
555
559
556 @HasPermissionAllDecorator('hg.admin')
560 @HasPermissionAllDecorator('hg.admin')
557 def show(self, repo_name, format='html'):
561 def show(self, repo_name, format='html'):
558 """GET /repos/repo_name: Show a specific item"""
562 """GET /repos/repo_name: Show a specific item"""
559 # url('repo', repo_name=ID)
563 # url('repo', repo_name=ID)
560
564
561 @HasRepoPermissionAllDecorator('repository.admin')
565 @HasRepoPermissionAllDecorator('repository.admin')
562 def edit(self, repo_name, format='html'):
566 def edit(self, repo_name, format='html'):
563 """GET /repos/repo_name/edit: Form to edit an existing item"""
567 """GET /repos/repo_name/edit: Form to edit an existing item"""
564 # url('edit_repo', repo_name=ID)
568 # url('edit_repo', repo_name=ID)
565 defaults = self.__load_data(repo_name)
569 defaults = self.__load_data(repo_name)
566
570
567 return htmlfill.render(
571 return htmlfill.render(
568 render('admin/repos/repo_edit.html'),
572 render('admin/repos/repo_edit.html'),
569 defaults=defaults,
573 defaults=defaults,
570 encoding="UTF-8",
574 encoding="UTF-8",
571 force_defaults=False
575 force_defaults=False
572 )
576 )
573
577
574 @HasPermissionAllDecorator('hg.admin')
578 @HasPermissionAllDecorator('hg.admin')
575 def create_repo_field(self, repo_name):
579 def create_repo_field(self, repo_name):
576 try:
580 try:
577 form_result = RepoFieldForm()().to_python(dict(request.POST))
581 form_result = RepoFieldForm()().to_python(dict(request.POST))
578 new_field = RepositoryField()
582 new_field = RepositoryField()
579 new_field.repository = Repository.get_by_repo_name(repo_name)
583 new_field.repository = Repository.get_by_repo_name(repo_name)
580 new_field.field_key = form_result['new_field_key']
584 new_field.field_key = form_result['new_field_key']
581 new_field.field_type = form_result['new_field_type'] # python type
585 new_field.field_type = form_result['new_field_type'] # python type
582 new_field.field_value = form_result['new_field_value'] # set initial blank value
586 new_field.field_value = form_result['new_field_value'] # set initial blank value
583 new_field.field_desc = form_result['new_field_desc']
587 new_field.field_desc = form_result['new_field_desc']
584 new_field.field_label = form_result['new_field_label']
588 new_field.field_label = form_result['new_field_label']
585 Session().add(new_field)
589 Session().add(new_field)
586 Session().commit()
590 Session().commit()
587
591
588 except Exception, e:
592 except Exception, e:
589 log.error(traceback.format_exc())
593 log.error(traceback.format_exc())
590 msg = _('An error occurred during creation of field')
594 msg = _('An error occurred during creation of field')
591 if isinstance(e, formencode.Invalid):
595 if isinstance(e, formencode.Invalid):
592 msg += ". " + e.msg
596 msg += ". " + e.msg
593 h.flash(msg, category='error')
597 h.flash(msg, category='error')
594 return redirect(url('edit_repo', repo_name=repo_name))
598 return redirect(url('edit_repo', repo_name=repo_name))
595
599
596 @HasPermissionAllDecorator('hg.admin')
600 @HasPermissionAllDecorator('hg.admin')
597 def delete_repo_field(self, repo_name, field_id):
601 def delete_repo_field(self, repo_name, field_id):
598 field = RepositoryField.get_or_404(field_id)
602 field = RepositoryField.get_or_404(field_id)
599 try:
603 try:
600 Session().delete(field)
604 Session().delete(field)
601 Session().commit()
605 Session().commit()
602 except Exception, e:
606 except Exception, e:
603 log.error(traceback.format_exc())
607 log.error(traceback.format_exc())
604 msg = _('An error occurred during removal of field')
608 msg = _('An error occurred during removal of field')
605 h.flash(msg, category='error')
609 h.flash(msg, category='error')
606 return redirect(url('edit_repo', repo_name=repo_name))
610 return redirect(url('edit_repo', repo_name=repo_name))
@@ -1,384 +1,385 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(old_data),
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, required=False,
188 if_missing=old_data.get('repo_type'))
188 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
189 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
189 repo_private = v.StringBoolean(if_missing=False)
190 repo_private = v.StringBoolean(if_missing=False)
190 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
191 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
191 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
192 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
192
193
193 repo_enable_statistics = v.StringBoolean(if_missing=False)
194 repo_enable_statistics = v.StringBoolean(if_missing=False)
194 repo_enable_downloads = v.StringBoolean(if_missing=False)
195 repo_enable_downloads = v.StringBoolean(if_missing=False)
195 repo_enable_locking = v.StringBoolean(if_missing=False)
196 repo_enable_locking = v.StringBoolean(if_missing=False)
196
197
197 if edit:
198 if edit:
198 #this is repo owner
199 #this is repo owner
199 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
200 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
200
201
201 chained_validators = [v.ValidCloneUri(),
202 chained_validators = [v.ValidCloneUri(),
202 v.ValidRepoName(edit, old_data)]
203 v.ValidRepoName(edit, old_data)]
203 return _RepoForm
204 return _RepoForm
204
205
205
206
206 def RepoPermsForm():
207 def RepoPermsForm():
207 class _RepoPermsForm(formencode.Schema):
208 class _RepoPermsForm(formencode.Schema):
208 allow_extra_fields = True
209 allow_extra_fields = True
209 filter_extra_fields = False
210 filter_extra_fields = False
210 chained_validators = [v.ValidPerms()]
211 chained_validators = [v.ValidPerms()]
211 return _RepoPermsForm
212 return _RepoPermsForm
212
213
213
214
214 def RepoFieldForm():
215 def RepoFieldForm():
215 class _RepoFieldForm(formencode.Schema):
216 class _RepoFieldForm(formencode.Schema):
216 filter_extra_fields = True
217 filter_extra_fields = True
217 allow_extra_fields = True
218 allow_extra_fields = True
218
219
219 new_field_key = All(v.FieldKey(),
220 new_field_key = All(v.FieldKey(),
220 v.UnicodeString(strip=True, min=3, not_empty=True))
221 v.UnicodeString(strip=True, min=3, not_empty=True))
221 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
222 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
222 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
223 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
223 if_missing='str')
224 if_missing='str')
224 new_field_label = v.UnicodeString(not_empty=False)
225 new_field_label = v.UnicodeString(not_empty=False)
225 new_field_desc = v.UnicodeString(not_empty=False)
226 new_field_desc = v.UnicodeString(not_empty=False)
226
227
227 return _RepoFieldForm
228 return _RepoFieldForm
228
229
229
230
230 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
231 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
231 repo_groups=[], landing_revs=[]):
232 repo_groups=[], landing_revs=[]):
232 class _RepoForkForm(formencode.Schema):
233 class _RepoForkForm(formencode.Schema):
233 allow_extra_fields = True
234 allow_extra_fields = True
234 filter_extra_fields = False
235 filter_extra_fields = False
235 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
236 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
236 v.SlugifyName())
237 v.SlugifyName())
237 repo_group = All(v.CanWriteGroup(),
238 repo_group = All(v.CanWriteGroup(),
238 v.OneOf(repo_groups, hideList=True))
239 v.OneOf(repo_groups, hideList=True))
239 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
240 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
240 description = v.UnicodeString(strip=True, min=1, not_empty=True)
241 description = v.UnicodeString(strip=True, min=1, not_empty=True)
241 private = v.StringBoolean(if_missing=False)
242 private = v.StringBoolean(if_missing=False)
242 copy_permissions = v.StringBoolean(if_missing=False)
243 copy_permissions = v.StringBoolean(if_missing=False)
243 update_after_clone = v.StringBoolean(if_missing=False)
244 update_after_clone = v.StringBoolean(if_missing=False)
244 fork_parent_id = v.UnicodeString()
245 fork_parent_id = v.UnicodeString()
245 chained_validators = [v.ValidForkName(edit, old_data)]
246 chained_validators = [v.ValidForkName(edit, old_data)]
246 landing_rev = v.OneOf(landing_revs, hideList=True)
247 landing_rev = v.OneOf(landing_revs, hideList=True)
247
248
248 return _RepoForkForm
249 return _RepoForkForm
249
250
250
251
251 def ApplicationSettingsForm():
252 def ApplicationSettingsForm():
252 class _ApplicationSettingsForm(formencode.Schema):
253 class _ApplicationSettingsForm(formencode.Schema):
253 allow_extra_fields = True
254 allow_extra_fields = True
254 filter_extra_fields = False
255 filter_extra_fields = False
255 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
256 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
256 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
257 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
257 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
258 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
258
259
259 return _ApplicationSettingsForm
260 return _ApplicationSettingsForm
260
261
261
262
262 def ApplicationVisualisationForm():
263 def ApplicationVisualisationForm():
263 class _ApplicationVisualisationForm(formencode.Schema):
264 class _ApplicationVisualisationForm(formencode.Schema):
264 allow_extra_fields = True
265 allow_extra_fields = True
265 filter_extra_fields = False
266 filter_extra_fields = False
266 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
267 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
267 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
268 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
268 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
269 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
269
270
270 rhodecode_lightweight_dashboard = v.StringBoolean(if_missing=False)
271 rhodecode_lightweight_dashboard = v.StringBoolean(if_missing=False)
271 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
272 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
272 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
273 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
273
274
274 return _ApplicationVisualisationForm
275 return _ApplicationVisualisationForm
275
276
276
277
277 def ApplicationUiSettingsForm():
278 def ApplicationUiSettingsForm():
278 class _ApplicationUiSettingsForm(formencode.Schema):
279 class _ApplicationUiSettingsForm(formencode.Schema):
279 allow_extra_fields = True
280 allow_extra_fields = True
280 filter_extra_fields = False
281 filter_extra_fields = False
281 web_push_ssl = v.StringBoolean(if_missing=False)
282 web_push_ssl = v.StringBoolean(if_missing=False)
282 paths_root_path = All(
283 paths_root_path = All(
283 v.ValidPath(),
284 v.ValidPath(),
284 v.UnicodeString(strip=True, min=1, not_empty=True)
285 v.UnicodeString(strip=True, min=1, not_empty=True)
285 )
286 )
286 hooks_changegroup_update = v.StringBoolean(if_missing=False)
287 hooks_changegroup_update = v.StringBoolean(if_missing=False)
287 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
288 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
288 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
289 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
289 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
290 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
290
291
291 extensions_largefiles = v.StringBoolean(if_missing=False)
292 extensions_largefiles = v.StringBoolean(if_missing=False)
292 extensions_hgsubversion = v.StringBoolean(if_missing=False)
293 extensions_hgsubversion = v.StringBoolean(if_missing=False)
293 extensions_hggit = v.StringBoolean(if_missing=False)
294 extensions_hggit = v.StringBoolean(if_missing=False)
294
295
295 return _ApplicationUiSettingsForm
296 return _ApplicationUiSettingsForm
296
297
297
298
298 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
299 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
299 register_choices, create_choices, fork_choices):
300 register_choices, create_choices, fork_choices):
300 class _DefaultPermissionsForm(formencode.Schema):
301 class _DefaultPermissionsForm(formencode.Schema):
301 allow_extra_fields = True
302 allow_extra_fields = True
302 filter_extra_fields = True
303 filter_extra_fields = True
303 overwrite_default_repo = v.StringBoolean(if_missing=False)
304 overwrite_default_repo = v.StringBoolean(if_missing=False)
304 overwrite_default_group = v.StringBoolean(if_missing=False)
305 overwrite_default_group = v.StringBoolean(if_missing=False)
305 anonymous = v.StringBoolean(if_missing=False)
306 anonymous = v.StringBoolean(if_missing=False)
306 default_repo_perm = v.OneOf(repo_perms_choices)
307 default_repo_perm = v.OneOf(repo_perms_choices)
307 default_group_perm = v.OneOf(group_perms_choices)
308 default_group_perm = v.OneOf(group_perms_choices)
308 default_register = v.OneOf(register_choices)
309 default_register = v.OneOf(register_choices)
309 default_create = v.OneOf(create_choices)
310 default_create = v.OneOf(create_choices)
310 default_fork = v.OneOf(fork_choices)
311 default_fork = v.OneOf(fork_choices)
311
312
312 return _DefaultPermissionsForm
313 return _DefaultPermissionsForm
313
314
314
315
315 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
316 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
316 class _DefaultsForm(formencode.Schema):
317 class _DefaultsForm(formencode.Schema):
317 allow_extra_fields = True
318 allow_extra_fields = True
318 filter_extra_fields = True
319 filter_extra_fields = True
319 default_repo_type = v.OneOf(supported_backends)
320 default_repo_type = v.OneOf(supported_backends)
320 default_repo_private = v.StringBoolean(if_missing=False)
321 default_repo_private = v.StringBoolean(if_missing=False)
321 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
322 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
322 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
323 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
323 default_repo_enable_locking = v.StringBoolean(if_missing=False)
324 default_repo_enable_locking = v.StringBoolean(if_missing=False)
324
325
325 return _DefaultsForm
326 return _DefaultsForm
326
327
327
328
328 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
329 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
329 tls_kind_choices):
330 tls_kind_choices):
330 class _LdapSettingsForm(formencode.Schema):
331 class _LdapSettingsForm(formencode.Schema):
331 allow_extra_fields = True
332 allow_extra_fields = True
332 filter_extra_fields = True
333 filter_extra_fields = True
333 #pre_validators = [LdapLibValidator]
334 #pre_validators = [LdapLibValidator]
334 ldap_active = v.StringBoolean(if_missing=False)
335 ldap_active = v.StringBoolean(if_missing=False)
335 ldap_host = v.UnicodeString(strip=True,)
336 ldap_host = v.UnicodeString(strip=True,)
336 ldap_port = v.Number(strip=True,)
337 ldap_port = v.Number(strip=True,)
337 ldap_tls_kind = v.OneOf(tls_kind_choices)
338 ldap_tls_kind = v.OneOf(tls_kind_choices)
338 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
339 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
339 ldap_dn_user = v.UnicodeString(strip=True,)
340 ldap_dn_user = v.UnicodeString(strip=True,)
340 ldap_dn_pass = v.UnicodeString(strip=True,)
341 ldap_dn_pass = v.UnicodeString(strip=True,)
341 ldap_base_dn = v.UnicodeString(strip=True,)
342 ldap_base_dn = v.UnicodeString(strip=True,)
342 ldap_filter = v.UnicodeString(strip=True,)
343 ldap_filter = v.UnicodeString(strip=True,)
343 ldap_search_scope = v.OneOf(search_scope_choices)
344 ldap_search_scope = v.OneOf(search_scope_choices)
344 ldap_attr_login = v.AttrLoginValidator()(not_empty=True)
345 ldap_attr_login = v.AttrLoginValidator()(not_empty=True)
345 ldap_attr_firstname = v.UnicodeString(strip=True,)
346 ldap_attr_firstname = v.UnicodeString(strip=True,)
346 ldap_attr_lastname = v.UnicodeString(strip=True,)
347 ldap_attr_lastname = v.UnicodeString(strip=True,)
347 ldap_attr_email = v.UnicodeString(strip=True,)
348 ldap_attr_email = v.UnicodeString(strip=True,)
348
349
349 return _LdapSettingsForm
350 return _LdapSettingsForm
350
351
351
352
352 def UserExtraEmailForm():
353 def UserExtraEmailForm():
353 class _UserExtraEmailForm(formencode.Schema):
354 class _UserExtraEmailForm(formencode.Schema):
354 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
355 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
355 return _UserExtraEmailForm
356 return _UserExtraEmailForm
356
357
357
358
358 def UserExtraIpForm():
359 def UserExtraIpForm():
359 class _UserExtraIpForm(formencode.Schema):
360 class _UserExtraIpForm(formencode.Schema):
360 ip = v.ValidIp()(not_empty=True)
361 ip = v.ValidIp()(not_empty=True)
361 return _UserExtraIpForm
362 return _UserExtraIpForm
362
363
363
364
364 def PullRequestForm(repo_id):
365 def PullRequestForm(repo_id):
365 class _PullRequestForm(formencode.Schema):
366 class _PullRequestForm(formencode.Schema):
366 allow_extra_fields = True
367 allow_extra_fields = True
367 filter_extra_fields = True
368 filter_extra_fields = True
368
369
369 user = v.UnicodeString(strip=True, required=True)
370 user = v.UnicodeString(strip=True, required=True)
370 org_repo = v.UnicodeString(strip=True, required=True)
371 org_repo = v.UnicodeString(strip=True, required=True)
371 org_ref = v.UnicodeString(strip=True, required=True)
372 org_ref = v.UnicodeString(strip=True, required=True)
372 other_repo = v.UnicodeString(strip=True, required=True)
373 other_repo = v.UnicodeString(strip=True, required=True)
373 other_ref = v.UnicodeString(strip=True, required=True)
374 other_ref = v.UnicodeString(strip=True, required=True)
374 revisions = All(#v.NotReviewedRevisions(repo_id)(),
375 revisions = All(#v.NotReviewedRevisions(repo_id)(),
375 v.UniqueList(not_empty=True))
376 v.UniqueList(not_empty=True))
376 review_members = v.UniqueList(not_empty=True)
377 review_members = v.UniqueList(not_empty=True)
377
378
378 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
379 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
379 pullrequest_desc = v.UnicodeString(strip=True, required=False)
380 pullrequest_desc = v.UnicodeString(strip=True, required=False)
380
381
381 ancestor_rev = v.UnicodeString(strip=True, required=True)
382 ancestor_rev = v.UnicodeString(strip=True, required=True)
382 merge_rev = v.UnicodeString(strip=True, required=True)
383 merge_rev = v.UnicodeString(strip=True, required=True)
383
384
384 return _PullRequestForm
385 return _PullRequestForm
General Comments 0
You need to be logged in to leave comments. Login now