зеркало из https://github.com/mozilla/kitsune.git
* 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:
Родитель
1e393cbf43
Коммит
953efe2d4b
|
@ -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));
|
||||
|
|
Загрузка…
Ссылка в новой задаче