##// END OF EJS Templates
repo-schema: added a custom schema for repo settings....
marcink -
r1719:1b64c19a default
parent child Browse files
Show More
@@ -80,6 +80,7 b' class RepoSettingsView(RepoAppView):'
80
80
81 def _get_schema(self, c, old_values=None):
81 def _get_schema(self, c, old_values=None):
82 return repo_schema.RepoSettingsSchema().bind(
82 return repo_schema.RepoSettingsSchema().bind(
83 repo_type=self.db_repo.repo_type,
83 repo_type_options=[self.db_repo.repo_type],
84 repo_type_options=[self.db_repo.repo_type],
84 repo_ref_options=c.landing_revs_choices,
85 repo_ref_options=c.landing_revs_choices,
85 repo_ref_items=c.landing_revs,
86 repo_ref_items=c.landing_revs,
@@ -66,6 +66,13 b' def deferred_landing_ref_validator(node,'
66
66
67
67
68 @colander.deferred
68 @colander.deferred
69 def deferred_clone_uri_validator(node, kw):
70 repo_type = kw.get('repo_type')
71 validator = validators.CloneUriValidator(repo_type)
72 return validator
73
74
75 @colander.deferred
69 def deferred_landing_ref_widget(node, kw):
76 def deferred_landing_ref_widget(node, kw):
70 items = kw.get(
77 items = kw.get(
71 'repo_ref_items', [(DEFAULT_LANDING_REF, DEFAULT_LANDING_REF)])
78 'repo_ref_items', [(DEFAULT_LANDING_REF, DEFAULT_LANDING_REF)])
@@ -358,3 +365,50 b' class RepoSchema(colander.MappingSchema)'
358 third.deserialize({'unique_repo_name': validated_name})
365 third.deserialize({'unique_repo_name': validated_name})
359
366
360 return appstruct
367 return appstruct
368
369
370 class RepoSettingsSchema(RepoSchema):
371 repo_group = colander.SchemaNode(
372 colander.Integer(),
373 validator=deferred_repo_group_validator,
374 widget=deferred_repo_group_widget,
375 missing='')
376
377 repo_clone_uri_change = colander.SchemaNode(
378 colander.String(),
379 missing='NEW')
380
381 repo_clone_uri = colander.SchemaNode(
382 colander.String(),
383 preparers=[preparers.strip_preparer],
384 validator=deferred_clone_uri_validator,
385 missing='')
386
387 def deserialize(self, cstruct):
388 """
389 Custom deserialize that allows to chain validation, and verify
390 permissions, and as last step uniqueness
391 """
392
393 # first pass, to validate given data
394 appstruct = super(RepoSchema, self).deserialize(cstruct)
395 validated_name = appstruct['repo_name']
396 # because of repoSchema adds repo-group as an ID, we inject it as
397 # full name here because validators require it, it's unwrapped later
398 # so it's safe to use and final name is going to be without group anyway
399
400 group, separator = get_repo_group(appstruct['repo_group'])
401 if group:
402 validated_name = separator.join([group.group_name, validated_name])
403
404 # second pass to validate permissions to repo_group
405 second = RepoGroupAccessSchema().bind(**self.bindings)
406 appstruct_second = second.deserialize({'repo_group': validated_name})
407 # save result
408 appstruct['repo_group'] = appstruct_second['repo_group']
409
410 # thirds to validate uniqueness
411 third = RepoNameUniqueSchema().bind(**self.bindings)
412 third.deserialize({'unique_repo_name': validated_name})
413
414 return appstruct
@@ -1,5 +1,27 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
1 import os
21 import os
2 import re
22 import re
23 import logging
24
3
25
4 import ipaddress
26 import ipaddress
5 import colander
27 import colander
@@ -7,6 +29,8 b' import colander'
7 from rhodecode.translation import _
29 from rhodecode.translation import _
8 from rhodecode.lib.utils2 import glob2re
30 from rhodecode.lib.utils2 import glob2re
9
31
32 log = logging.getLogger(__name__)
33
10
34
11 def ip_addr_validator(node, value):
35 def ip_addr_validator(node, value):
12 try:
36 try:
@@ -46,3 +70,71 b' def valid_name_validator(node, value):'
46 msg = _('Name must start with a letter or number. Got `{}`').format(value)
70 msg = _('Name must start with a letter or number. Got `{}`').format(value)
47 if not re.match(r'^[a-zA-z0-9]{1,}', value):
71 if not re.match(r'^[a-zA-z0-9]{1,}', value):
48 raise colander.Invalid(node, msg)
72 raise colander.Invalid(node, msg)
73
74
75 class InvalidCloneUrl(Exception):
76 allowed_prefixes = ()
77
78
79 def url_validator(url, repo_type, config):
80 from rhodecode.lib.vcs.backends.hg import MercurialRepository
81 from rhodecode.lib.vcs.backends.git import GitRepository
82 from rhodecode.lib.vcs.backends.svn import SubversionRepository
83
84 if repo_type == 'hg':
85 allowed_prefixes = ('http', 'svn+http', 'git+http')
86
87 if 'http' in url[:4]:
88 # initially check if it's at least the proper URL
89 # or does it pass basic auth
90
91 MercurialRepository.check_url(url, config)
92 elif 'svn+http' in url[:8]: # svn->hg import
93 SubversionRepository.check_url(url, config)
94 elif 'git+http' in url[:8]: # git->hg import
95 raise NotImplementedError()
96 else:
97 exc = InvalidCloneUrl('Clone from URI %s not allowed. '
98 'Allowed url must start with one of %s'
99 % (url, ','.join(allowed_prefixes)))
100 exc.allowed_prefixes = allowed_prefixes
101 raise exc
102
103 elif repo_type == 'git':
104 allowed_prefixes = ('http', 'svn+http', 'hg+http')
105 if 'http' in url[:4]:
106 # initially check if it's at least the proper URL
107 # or does it pass basic auth
108 GitRepository.check_url(url, config)
109 elif 'svn+http' in url[:8]: # svn->git import
110 raise NotImplementedError()
111 elif 'hg+http' in url[:8]: # hg->git import
112 raise NotImplementedError()
113 else:
114 exc = InvalidCloneUrl('Clone from URI %s not allowed. '
115 'Allowed url must start with one of %s'
116 % (url, ','.join(allowed_prefixes)))
117 exc.allowed_prefixes = allowed_prefixes
118 raise exc
119
120
121 class CloneUriValidator(object):
122 def __init__(self, repo_type):
123 self.repo_type = repo_type
124
125 def __call__(self, node, value):
126 from rhodecode.lib.utils import make_db_config
127 try:
128 config = make_db_config(clear_session=False)
129 url_validator(value, self.repo_type, config)
130 except InvalidCloneUrl as e:
131 log.warning(e)
132 msg = _(u'Invalid clone url, provide a valid clone '
133 u'url starting with one of {allowed_prefixes}').format(
134 allowed_prefixes=e.allowed_prefixes)
135 raise colander.Invalid(node, msg)
136 except Exception:
137 log.exception('Url validation failed')
138 msg = _(u'invalid clone url for {repo_type} repository').format(
139 repo_type=self.repo_type)
140 raise colander.Invalid(node, msg)
@@ -52,18 +52,29 b''
52 </div>
52 </div>
53 <div class="input">
53 <div class="input">
54 %if c.rhodecode_db_repo.clone_uri:
54 %if c.rhodecode_db_repo.clone_uri:
55 ## display
55 ## display, if we don't have any errors
56 % if not c.form['repo_clone_uri'].error:
56 <div id="clone_uri_hidden" class='text-as-placeholder'>
57 <div id="clone_uri_hidden" class='text-as-placeholder'>
57 <span id="clone_uri_hidden_value">${c.rhodecode_db_repo.clone_uri_hidden}</span>
58 <span id="clone_uri_hidden_value">${c.rhodecode_db_repo.clone_uri_hidden}</span>
58 <span class="link" id="edit_clone_uri"><i class="icon-edit"></i>${_('edit')}</span>
59 <span class="link" id="edit_clone_uri"><i class="icon-edit"></i>${_('edit')}</span>
59 </div>
60 </div>
61 % endif
62
60 ## alter field
63 ## alter field
61 <div id="alter_clone_uri" style="display: none">
64 <div id="alter_clone_uri" style="${'' if c.form['repo_clone_uri'].error else 'display: none'}">
62 ${c.form['repo_clone_uri'].render(css_class='medium', oid='clone_uri', placeholder=_('enter new value, or leave empty to remove'))|n}
65 ${c.form['repo_clone_uri'].render(css_class='medium', oid='clone_uri', placeholder=_('enter new value, or leave empty to remove'))|n}
63 ${c.form.render_error(request, c.form['repo_clone_uri'])|n}
66 ${c.form.render_error(request, c.form['repo_clone_uri'])|n}
67 % if c.form['repo_clone_uri'].error:
68 ## we got error from form subit, means we modify the url
69 ${h.hidden('repo_clone_uri_change', 'MOD')}
70 % else:
64 ${h.hidden('repo_clone_uri_change', 'OLD')}
71 ${h.hidden('repo_clone_uri_change', 'OLD')}
72 % endif
65
73
74 % if not c.form['repo_clone_uri'].error:
66 <span class="link" id="cancel_edit_clone_uri">${_('cancel')}</span>
75 <span class="link" id="cancel_edit_clone_uri">${_('cancel')}</span>
76 % endif
77
67 </div>
78 </div>
68 %else:
79 %else:
69 ## not set yet, display form to set it
80 ## not set yet, display form to set it
General Comments 0
You need to be logged in to leave comments. Login now