* Added locale to form so that the unique_together validation would occur correctly [bug 599989]

* Added javascript validation of Slug/Locale and Title/Locale uniqueness
This commit is contained in:
Ricky Rosario 2010-11-10 13:36:44 -05:00
Родитель 1e393cbf43
Коммит 953efe2d4b
9 изменённых файлов: 142 добавлений и 18 удалений

Просмотреть файл

@ -77,6 +77,8 @@ class DocumentForm(forms.ModelForm):
label=_('Allow translations'),
required=False)
locale = forms.CharField(widget=forms.HiddenInput())
def clean_firefox_versions(self):
data = self.cleaned_data['firefox_versions']
return [FirefoxVersion(item_id=int(x)) for x in data]
@ -87,12 +89,12 @@ class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ('title', 'slug', 'category', 'is_localizable', 'tags')
fields = ('title', 'slug', 'category', 'is_localizable', 'tags',
'locale')
def save(self, locale, parent_doc, **kwargs):
def save(self, parent_doc, **kwargs):
"""Persist the Document form, and return the saved Document."""
doc = super(DocumentForm, self).save(commit=False, **kwargs)
doc.locale = locale
doc.parent = parent_doc
doc.save()
self.save_m2m() # not strictly necessary since we didn't change

Просмотреть файл

@ -23,10 +23,10 @@
<details class="h2"{% if disclose_description %} open="open"{% endif %}>
<summary>{{ _('Edit Description') }}</summary>
{{ errorlist(document_form) }}
<form action="" method="post">
<form action="" method="post" data-json-url="{{ url('wiki.json') }}" data-document-id="{{ document.id }}">
{{ csrf() }}
<ul>
{% for field in document_form if field.name != 'firefox_versions' and field.name != 'operating_systems' and (field.name != 'is_localizable' or not document.translations.exists()) %}
{% for field in document_form.visible_fields() if field.name != 'firefox_versions' and field.name != 'operating_systems' and (field.name != 'is_localizable' or not document.translations.exists()) %}
<li>{{ field.label_tag()|safe }}{{ field|safe }}</li>
{% endfor %}
</ul>

Просмотреть файл

@ -18,10 +18,10 @@
<div id="document-form">
{{ errorlist(document_form) }}
{{ errorlist(revision_form) }}
<form action="" method="post">
<form action="" method="post" data-json-url="{{ url('wiki.json') }}">
{{ csrf() }}
<ul>
{% for field in document_form if field.name != 'firefox_versions' and field.name != 'operating_systems' %}
{% for field in document_form.visible_fields() if field.name != 'firefox_versions' and field.name != 'operating_systems' %}
<li>{{ field.label_tag()|safe }}{{ field|safe }}</li>
{% endfor %}
</ul>

Просмотреть файл

@ -42,7 +42,7 @@
</div>
{% if not document %}
{# If this is the first translation to this locale, we use 1 big form. #}
<form action="" method="post">
<form action="" method="post" data-json-url="{{ url('wiki.json') }}">
{{ csrf() }}
<input type="hidden" name="form" value="both" />
{% endif %}
@ -52,7 +52,7 @@
{{ errorlist(document_form) }}
{% if document %}
{# If there are existing translations in this locale, we use 2 separate forms. #}
<form action="" method="post">
<form action="" method="post" data-json-url="{{ url('wiki.json') }}" data-document-id="{{ document.id }}">
{{ csrf() }}
<input type="hidden" name="form" value="doc" />
{% endif %}

Просмотреть файл

@ -231,6 +231,36 @@ class NewDocumentTests(TestCaseBase):
eq_('Select a valid choice. 1337 is not one of the available choices.',
ul('li').text())
def test_slug_collision_validation(self):
"""Trying to create document with existing locale/slug should
show validation error."""
d = _create_document()
self.client.login(username='admin', password='testpass')
data = new_document_data()
data['slug'] = d.slug
response = self.client.post(reverse('wiki.new_document'), data)
eq_(200, response.status_code)
doc = pq(response.content)
ul = doc('#document-form > ul.errorlist')
eq_(1, len(ul))
eq_('Document with this Slug and Locale already exists.',
ul('li').text())
def test_title_collision_validation(self):
"""Trying to create document with existing locale/slug should
show validation error."""
d = _create_document()
self.client.login(username='admin', password='testpass')
data = new_document_data()
data['title'] = d.title
response = self.client.post(reverse('wiki.new_document'), data)
eq_(200, response.status_code)
doc = pq(response.content)
ul = doc('#document-form > ul.errorlist')
eq_(1, len(ul))
eq_('Document with this Title and Locale already exists.',
ul('li').text())
class NewRevisionTests(TestCaseBase):
"""Tests for the New Revision template"""

Просмотреть файл

@ -165,11 +165,13 @@ def new_document(request):
{'document_form': doc_form,
'revision_form': rev_form})
doc_form = DocumentForm(request.POST)
rev_form = RevisionForm(request.POST)
post_data = request.POST.copy()
post_data.update({'locale': request.locale})
doc_form = DocumentForm(post_data)
rev_form = RevisionForm(post_data)
if doc_form.is_valid() and rev_form.is_valid():
doc = doc_form.save(request.locale, None)
doc = doc_form.save(None)
_save_rev_and_notify(rev_form, request.user, doc)
return HttpResponseRedirect(reverse('wiki.document_revisions',
args=[doc.slug]))
@ -218,10 +220,12 @@ def edit_document(request, document_slug, revision_id=None):
if which_form == 'doc':
if doc.allows_editing_by(user):
doc_form = DocumentForm(request.POST, instance=doc)
post_data = request.POST.copy()
post_data.update({'locale': request.locale})
doc_form = DocumentForm(post_data, instance=doc)
if doc_form.is_valid():
# Get the possibly new slug for the imminent redirection:
doc = doc_form.save(request.locale, None)
doc = doc_form.save(None)
# Do we need to rebuild the KB?
_maybe_schedule_rebuild(doc_form)
@ -403,11 +407,13 @@ def translate(request, document_slug):
if user_has_doc_perm and which_form in ['doc', 'both']:
disclose_description = True
doc_form = DocumentForm(request.POST, instance=doc)
post_data = request.POST.copy()
post_data.update({'locale': request.locale})
doc_form = DocumentForm(post_data, instance=doc)
doc_form.instance.locale = request.locale
doc_form.instance.parent = parent_doc
if doc_form.is_valid():
doc = doc_form.save(request.locale, parent_doc)
doc = doc_form.save(parent_doc)
# Possibly schedule a rebuild.
_maybe_schedule_rebuild(doc_form)
@ -493,6 +499,7 @@ def json_view(request):
document = get_object_or_404(Document, **kwargs)
data = json.dumps({
'id': document.id,
'locale': document.locale,
'slug': document.slug,
'title': document.title,

Просмотреть файл

@ -820,6 +820,22 @@ article.form-page form li label {
margin: 0 .5em;
}
#document-form li ul.errorlist,
ul.description li ul.errorlist {
display: block;
padding: 2px 0;
margin: 0;
width: auto;
}
#document-form li ul.errorlist li,
ul.description li ul.errorlist li {
display: block;
margin: 0;
padding: 0;
width: auto;
}
article.main input[type="text"],
article.main textarea,
section.marky input[type="text"] {
@ -835,6 +851,10 @@ section.marky input[type="text"] {
width: 325px;
}
article.main input[type="text"].error {
border-color: #ff0000;
}
article.main textarea {
background: -webkit-gradient(linear, center top, center bottom, from(#deebf4), to(#fff), color-stop(0.5%, #deebf4), color-stop(1%, #fff));
height: 150px;

Просмотреть файл

@ -2,7 +2,8 @@
* Taken from Django's contrib/admin/media/js folder, thanks Django!
* Copyright Django and licensed under BSD, please see django/LICENSE for
* license details.
* Modified slightly to handle fallback to full title if slug is empty
* Modified slightly to handle fallback to full title if slug is empty.
* Also modified to only trigger onchange.
*/
(function($) {
$.fn.prepopulate = function(dependencies, maxLength) {
@ -37,7 +38,8 @@
field.val(field_val);
};
dependencies.keyup(populate).change(populate).focus(populate);
//rlr: Changed behavior to only run populate on the change event
dependencies/*.keyup(populate)*/.change(populate)/*.focus(populate)*/;
});
};
})(jQuery);

Просмотреть файл

@ -24,6 +24,7 @@
}
if ($('body').is('.edit, .new, .translate')) {
initArticlePreview();
initTitleAndSlugCheck();
}
Marky.createFullToolbar('.forum-editor-tools', '#id_content');
@ -512,6 +513,68 @@
$('#support-for select').selectbox();
}
function initTitleAndSlugCheck() {
$('#id_title').change(function() {
var $this = $(this),
$form = $this.closest('form'),
title = $this.val(),
slug = $('#id_slug').val();
verifyTitleUnique(title, $form);
// Check slug too, since it auto-updates and doesn't seem to fire
// off change event.
verifySlugUnique(slug, $form);
});
$('#id_slug').change(function() {
var $this = $(this),
$form = $this.closest('form'),
slug = $('#id_slug').val();
verifySlugUnique(slug, $form);
});
function verifyTitleUnique(title, $form) {
var errorMsg = gettext('A document with this title already exists in this locale.');
verifyUnique('title', title, $('#id_title'), $form, errorMsg);
}
function verifySlugUnique(slug, $form) {
var errorMsg = gettext('A document with this slug already exists in this locale.');
verifyUnique('slug', slug, $('#id_slug'), $form, errorMsg);
}
function verifyUnique(fieldname, value, $field, $form, errorMsg) {
$field.removeClass('error');
$field.parent().find('ul.errorlist').remove();
var data = {};
data[fieldname] = value;
$.ajax({
url: $form.attr('data-json-url'),
type: 'GET',
data: data,
dataType: 'json',
success: function(json) {
// Success means we found an existing doc
var docId = $form.attr('data-document-id');
if (!docId || (json.id && json.id !== parseInt(docId))) {
// Collision !!
$field.addClass('error');
$field.before(
$('<ul class="errorlist"><li/></ul>')
.find('li').text(errorMsg).end()
);
}
},
error: function(xhr, error) {
if(xhr.status === 404) {
// We are good!!
} else {
// Something went wrong, just fallback to server-side
// validation.
}
}
});
}
}
$(document).ready(init);
}(jQuery));