Record creation / update screen simplification

This change moves the record create and update screen
so that users only need to provide the leftmost label of the
record they would like to use.

Change-Id: I033c7c6bf327f667397f0aca5ed3eb17259c9543
Closes-bug: #1461213
This commit is contained in:
eric
2015-06-19 14:07:51 -06:00
parent e425d70188
commit e172b1807c
6 changed files with 63 additions and 37 deletions

View File

@@ -18,6 +18,7 @@ import re
from designateclient import exceptions as designate_exceptions
from django.core.exceptions import ValidationError # noqa
from django.core import validators
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import forms
@@ -38,6 +39,8 @@ WILDCARD_DOMAIN_NAME_REGEX = r'^(?!.{255,})(?:(^\*|(?!\-)[A-Za-z0-9_\-]{1,63})(?
SRV_NAME_REGEX = r'^(?:_[A-Za-z0-9_\-]{1,62}\.){2}'
SRV_DATA_REGEX = r'^(?:(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])\s){2}(?!.{255,})((?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+$' # noqa
SSHFP_DATA_REGEX = r'^[1-3]\s[1-2]\s\b([0-9a-fA-F]{5,40}|[0-9a-fA-F]{64})\b$'
# The max length for a dns label
NAME_MAX_LENGTH = 63
def handle_exc(func):
@@ -189,6 +192,16 @@ class DomainUpdate(DomainForm):
return domain
class PrefixWidget(forms.TextInput):
def render(self, name, value, attrs=None):
template_name = 'project/dns_domains/prefix_html_widget.html'
result = super(PrefixWidget, self).render(name, value, attrs)
view_data = {'input': result,
'suffix': getattr(self, "suffix", '')}
return render_to_string(template_name, view_data)
class RecordForm(forms.SelfHandlingForm):
'''Base class for RecordCreate and RecordUpdate forms.
@@ -224,9 +237,8 @@ class RecordForm(forms.SelfHandlingForm):
)
name = forms.CharField(
max_length=256,
required=False,
widget=forms.TextInput(attrs={
widget=PrefixWidget(attrs={
'class': 'switched',
'data-switch-on': 'record_type',
'data-record_type-a': _('Name'),
@@ -324,6 +336,10 @@ class RecordForm(forms.SelfHandlingForm):
def __init__(self, request, *args, **kwargs):
super(RecordForm, self).__init__(request, *args, **kwargs)
initial = kwargs.get('initial', {})
domain_suffix = "." + initial['domain_name']
self.fields['name'].widget.suffix = domain_suffix
self.fields['name'].max_length = min(NAME_MAX_LENGTH,
255 - len(domain_suffix))
if limit_records_to_fips():
del self.fields['data'].widget.attrs['data-record_type-a']
del self.fields['data'].widget.attrs['data-record_type-aaaa']
@@ -390,16 +406,14 @@ class RecordForm(forms.SelfHandlingForm):
else:
cleaned_data['name'] += domain_name
else:
cleaned_data['name'] += "." + domain_name
if not re.match(WILDCARD_DOMAIN_NAME_REGEX,
cleaned_data['name']):
self._add_field_error('name', _('Enter a valid hostname.'
' The hostname should end'
' with a period.'))
elif not cleaned_data['name'].endswith(domain_name):
self._add_field_error(
'name',
_('Name must be in the current domain'))
self._add_field_error('name',
_('Enter a valid hostname. The '
'hostname should contain letters '
'and numbers, and be no more than '
'63 characters.'))
# Data field
if self._is_field_blank(cleaned_data, 'data'):
if record_type in ['A', 'AAAA', 'CNAME', 'MX', 'SRV']:

View File

@@ -7,13 +7,16 @@
{% block modal_id %}create_record_modal{% endblock %}
{% block modal-header %}{% trans "Create Record for" %} {{ domain.name }}{% endblock %}
{% block modal-body-right %}
<h3>{% trans "Description:" %}</h3>
{% block modal-body %}
<div id="scoped-content">
{% include 'project/dns_domains/prefix_field_style.html' %}
<fieldset>
{% include "horizon/common/_form_fields.html" %}
</fieldset>
</div>
{% blocktrans %}
<p>
<strong>Please note:</strong>
For record types, the name <strong>must</strong> end with a period.
</p>
<p>
<strong>TTL</strong>
The TTL is the time-to-live for the record, in seconds.

View File

@@ -0,0 +1,4 @@
<style type = "text/css" scoped>
.form_field_suffix { float: right; padding-top:10px; }
.form_field_prefix { display: block; overflow: hidden; }
</style>

View File

@@ -0,0 +1,2 @@
<label class="form_field_suffix">{{ suffix }}</label>
<span class="form_field_prefix">{{ input }}</span>

View File

@@ -223,7 +223,7 @@ class UpdateRecordView(BaseRecordFormView):
initial.update({
'id': self.record.id,
'name': self.record.name,
'name': self.record.name.replace("." + initial['domain_name'], ''),
'data': self.record.data,
'txt': self.record.data,
'priority': self.record.priority,

View File

@@ -86,13 +86,14 @@ DOMAIN_ID = '123'
class BaseRecordFormCleanTests(test.TestCase):
DOMAIN_NAME = 'foo.com.'
HOSTNAME = 'www.foo.com.'
HOSTNAME = 'www'
MSG_FIELD_REQUIRED = 'This field is required'
MSG_INVALID_HOSTNAME = 'Enter a valid hostname. The hostname should end '\
'with a period.'
MSG_INVALID_HOSTNAME = 'Enter a valid hostname. The '\
'hostname should contain letters '\
'and numbers, and be no more than '\
'63 characters.'
MSG_INVALID_HOSTNAME_SHORT = 'Enter a valid hostname'
MSG_OUTSIDE_DOMAIN = 'Name must be in the current domain'
def setUp(self):
super(BaseRecordFormCleanTests, self).setUp()
@@ -101,7 +102,9 @@ class BaseRecordFormCleanTests(test.TestCase):
self.request = self.factory.get('', {})
# Set-up form instance
self.form = forms.RecordCreate(self.request)
kwargs = {}
kwargs['initial'] = {'domain_name': self.DOMAIN_NAME}
self.form = forms.RecordCreate(self.request, **kwargs)
self.form._errors = {}
self.form.cleaned_data = {
'domain_name': self.DOMAIN_NAME,
@@ -139,7 +142,7 @@ class ARecordFormTests(BaseRecordFormCleanTests):
self.assert_no_errors()
def test_valid_name_field_wild_card(self):
self.form.cleaned_data['name'] = '*.' + self.DOMAIN_NAME
self.form.cleaned_data['name'] = '*'
self.form.clean()
self.assert_no_errors()
@@ -154,17 +157,17 @@ class ARecordFormTests(BaseRecordFormCleanTests):
self.assert_required_error('data')
def test_invalid_name_field(self):
self.form.cleaned_data['name'] = 'foo'
self.form.cleaned_data['name'] = '$#%foo!!'
self.form.clean()
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
def test_invalid_name_field_starting_dash(self):
self.form.cleaned_data['name'] = '-ww.foo.com'
self.form.cleaned_data['name'] = '-ww'
self.form.clean()
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
def test_invalid_name_field_trailing_dash(self):
self.form.cleaned_data['name'] = 'www.foo.co-'
self.form.cleaned_data['name'] = 'co-'
self.form.clean()
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
@@ -176,7 +179,7 @@ class ARecordFormTests(BaseRecordFormCleanTests):
def test_outside_of_domain_name_field(self):
self.form.cleaned_data['name'] = 'www.bar.com.'
self.form.clean()
self.assert_error('name', self.MSG_OUTSIDE_DOMAIN)
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
def test_invalid_data_field(self):
self.form.cleaned_data['data'] = 'foo'
@@ -201,7 +204,7 @@ class AAAARecordFormTests(BaseRecordFormCleanTests):
self.assert_no_errors()
def test_valid_name_field_wild_card(self):
self.form.cleaned_data['name'] = '*.' + self.DOMAIN_NAME
self.form.cleaned_data['name'] = '*'
self.form.clean()
self.assert_no_errors()
@@ -216,7 +219,7 @@ class AAAARecordFormTests(BaseRecordFormCleanTests):
self.assert_required_error('data')
def test_invalid_name_field(self):
self.form.cleaned_data['name'] = 'foo'
self.form.cleaned_data['name'] = '#@$foo!!'
self.form.clean()
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
@@ -238,7 +241,7 @@ class AAAARecordFormTests(BaseRecordFormCleanTests):
def test_outside_of_domain_name_field(self):
self.form.cleaned_data['name'] = 'www.bar.com.'
self.form.clean()
self.assert_error('name', self.MSG_OUTSIDE_DOMAIN)
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
def test_invalid_data_field(self):
self.form.cleaned_data['data'] = 'foo'
@@ -261,7 +264,7 @@ class CNAMERecordFormTests(BaseRecordFormCleanTests):
self.assert_no_errors()
def test_valid_name_field_wild_card(self):
self.form.cleaned_data['name'] = '*.' + self.DOMAIN_NAME
self.form.cleaned_data['name'] = '*'
self.form.clean()
self.assert_no_errors()
@@ -276,7 +279,7 @@ class CNAMERecordFormTests(BaseRecordFormCleanTests):
self.assert_required_error('data')
def test_invalid_name_field(self):
self.form.cleaned_data['name'] = 'foo'
self.form.cleaned_data['name'] = '$#%#$foo!!!'
self.form.clean()
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
@@ -298,7 +301,7 @@ class CNAMERecordFormTests(BaseRecordFormCleanTests):
def test_outside_of_domain_name_field(self):
self.form.cleaned_data['name'] = 'www.bar.com.'
self.form.clean()
self.assert_error('name', self.MSG_OUTSIDE_DOMAIN)
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
def test_invalid_data_field(self):
self.form.cleaned_data['data'] = 'foo'
@@ -356,7 +359,7 @@ class TXTRecordFormTests(BaseRecordFormCleanTests):
self.assert_no_errors()
def test_valid_name_field_wild_card(self):
self.form.cleaned_data['name'] = '*.' + self.DOMAIN_NAME
self.form.cleaned_data['name'] = '*'
self.form.clean()
self.assert_no_errors()
@@ -371,7 +374,7 @@ class TXTRecordFormTests(BaseRecordFormCleanTests):
self.assert_required_error('txt')
def test_invalid_name_field(self):
self.form.cleaned_data['name'] = 'foo'
self.form.cleaned_data['name'] = 'foo-'
self.form.clean()
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
@@ -386,14 +389,14 @@ class TXTRecordFormTests(BaseRecordFormCleanTests):
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
def test_invalid_name_field_bad_wild_card(self):
self.form.cleaned_data['name'] = 'derp.*.' + self.DOMAIN_NAME
self.form.cleaned_data['name'] = 'derp.*'
self.form.clean()
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
def test_outside_of_domain_name_field(self):
self.form.cleaned_data['name'] = 'www.bar.com.'
self.form.clean()
self.assert_error('name', self.MSG_OUTSIDE_DOMAIN)
self.assert_error('name', self.MSG_INVALID_HOSTNAME)
def test_default_assignment_data_field(self):
self.form.clean()