From: Radek Czajka Date: Thu, 12 Aug 2010 10:31:38 +0000 (+0200) Subject: Fixes #656: bulk documents upload X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/1dfd391b507447d7f4a66863e4f6003979777426?ds=sidebyside Fixes #656: bulk documents upload --- diff --git a/apps/wiki/forms.py b/apps/wiki/forms.py index d8f425ab..0a5be8ca 100644 --- a/apps/wiki/forms.py +++ b/apps/wiki/forms.py @@ -42,6 +42,26 @@ class DocumentCreateForm(forms.Form): return self.cleaned_data +class DocumentsUploadForm(forms.Form): + """ + Form used for uploading new documents. + """ + file = forms.FileField(required=True, label=_('ZIP file')) + + def clean(self): + file = self.cleaned_data['file'] + + import zipfile + try: + z = self.cleaned_data['zip'] = zipfile.ZipFile(file) + except zipfile.BadZipfile: + raise forms.ValidationError("Should be a ZIP file.") + if z.testzip(): + raise forms.ValidationError("ZIP file corrupt.") + + return self.cleaned_data + + class DocumentTextSaveForm(forms.Form): """ Form for saving document's text: diff --git a/apps/wiki/locale/pl/LC_MESSAGES/django.mo b/apps/wiki/locale/pl/LC_MESSAGES/django.mo index b16e0a73..07128051 100644 Binary files a/apps/wiki/locale/pl/LC_MESSAGES/django.mo and b/apps/wiki/locale/pl/LC_MESSAGES/django.mo differ diff --git a/apps/wiki/locale/pl/LC_MESSAGES/django.po b/apps/wiki/locale/pl/LC_MESSAGES/django.po index 58e8d19c..6df7bab4 100644 --- a/apps/wiki/locale/pl/LC_MESSAGES/django.po +++ b/apps/wiki/locale/pl/LC_MESSAGES/django.po @@ -3,15 +3,14 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # -#, fuzzy msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: Platforma Redakcyjna\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-08-03 12:13+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"POT-Creation-Date: 2010-08-12 12:22+0200\n" +"PO-Revision-Date: 2010-08-12 12:24+0100\n" "Last-Translator: Radek Czajka \n" -"Language-Team: LANGUAGE \n" +"Language-Team: Fundacja Nowoczesna Polska \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -52,35 +51,39 @@ msgstr "Ostateczna redakcja techniczna" msgid "Ready to publish" msgstr "Gotowe do publikacji" -#: forms.py:62 +#: forms.py:49 +msgid "ZIP file" +msgstr "Plik ZIP" + +#: forms.py:82 msgid "Author" msgstr "Autor" -#: forms.py:63 +#: forms.py:83 msgid "Your name" msgstr "Imię i nazwisko" -#: forms.py:68 +#: forms.py:88 msgid "Author's email" msgstr "E-mail autora" -#: forms.py:69 +#: forms.py:89 msgid "Your email address, so we can show a gravatar :)" msgstr "Adres e-mail, żebyśmy mogli pokazać gravatar :)" -#: forms.py:75 +#: forms.py:95 msgid "Your comments" msgstr "Twój komentarz" -#: forms.py:76 +#: forms.py:96 msgid "Describe changes you made." msgstr "Opisz swoje zmiany" -#: forms.py:82 +#: forms.py:102 msgid "Completed" msgstr "Ukończono" -#: forms.py:83 +#: forms.py:103 msgid "If you completed a life cycle stage, select it." msgstr "Jeśli został ukończony etap prac, wskaż go." @@ -101,7 +104,16 @@ msgstr "motyw" msgid "themes" msgstr "motywy" -#: views.py:279 +#: views.py:165 +#, python-format +msgid "Title already used for %s" +msgstr "Nazwa taka sama jak dla pliku %s" + +#: views.py:167 +msgid "Title already used in repository." +msgstr "Plik o tej nazwie już istnieje w repozytorium." + +#: views.py:339 msgid "Tag added" msgstr "Dodano tag" @@ -144,7 +156,7 @@ msgstr "Zapisz" #: templates/wiki/document_details_base.html:41 msgid "Save attempt in progress" -msgstr "" +msgstr "Trwa zapisywanie" #: templates/wiki/document_list.html:30 msgid "Clear filter" @@ -154,6 +166,46 @@ msgstr "Wyczyść filtr" msgid "Your last edited documents" msgstr "Twoje ostatnie edycje" +#: templates/wiki/document_upload.html:9 +msgid "Bulk documents upload" +msgstr "Hurtowe dodawanie dokumentów" + +#: templates/wiki/document_upload.html:12 +msgid "Please submit a ZIP with XML files. Files not ending with .xml will be ignored." +msgstr "Proszę wskazać archiwum ZIP z plikami XML. Pliki nie kończące się na .xml zostaną zignorowane." + +#: templates/wiki/document_upload.html:17 +msgid "Upload" +msgstr "Dodaj" + +#: templates/wiki/document_upload.html:24 +msgid "There have been some errors. No files have been added to the repository." +msgstr "Wystąpiły błędy. Żadne pliki nie zostały dodane do repozytorium." + +#: templates/wiki/document_upload.html:25 +msgid "Offending files" +msgstr "Błędne pliki" + +#: templates/wiki/document_upload.html:33 +msgid "Correct files" +msgstr "Poprawne pliki" + +#: templates/wiki/document_upload.html:44 +msgid "Files have been successfully uploaded to the repository." +msgstr "Pliki zostały dodane do repozytorium." + +#: templates/wiki/document_upload.html:45 +msgid "Uploaded files" +msgstr "Dodane pliki" + +#: templates/wiki/document_upload.html:55 +msgid "Skipped files" +msgstr "Pominięte pliki" + +#: templates/wiki/document_upload.html:56 +msgid "Files skipped due to no .xml extension" +msgstr "Pliki pominięte z powodu braku rozszerzenia .xml." + #: templates/wiki/tag_dialog.html:16 msgid "Cancel" msgstr "Anuluj" @@ -270,3 +322,4 @@ msgstr "Wstaw przypis" #: templates/wiki/tabs/wysiwyg_editor_item.html:3 msgid "Visual editor" msgstr "Edytor wizualny" + diff --git a/apps/wiki/models.py b/apps/wiki/models.py index 3e892adc..438ec5d3 100644 --- a/apps/wiki/models.py +++ b/apps/wiki/models.py @@ -35,7 +35,7 @@ def normalize_name(name): >>> normalize_name("gąska".decode('utf-8')) u'g\u0105ska' """ - return name.translate(_PCHARS_DICT).lower() + return unicode(name).translate(_PCHARS_DICT).lower() STAGE_TAGS_RE = re.compile(r'^#stage-finished: (.*)$', re.MULTILINE) diff --git a/apps/wiki/templates/wiki/document_upload.html b/apps/wiki/templates/wiki/document_upload.html new file mode 100644 index 00000000..f1e37f76 --- /dev/null +++ b/apps/wiki/templates/wiki/document_upload.html @@ -0,0 +1,69 @@ +{% extends "wiki/base.html" %} +{% load i18n %} +{% load wiki %} + + +{% block leftcolumn %} + + +

{% trans "Bulk documents upload" %}

+ +

+{% trans "Please submit a ZIP with XML files. Files not ending with .xml will be ignored." %} +

+ +
+{{ form.as_p }} +

+
+ +
+ +{% if error_list %} + +

{% trans "There have been some errors. No files have been added to the repository." %} +

{% trans "Offending files" %}

+
    + {% for filename, title, error in error_list %} +
  • {{title|wiki_title}} ({{ filename }}): {{ error }}
  • + {% endfor %} +
+ + {% if ok_list %} +

{% trans "Correct files" %}

+
    + {% for filename, title in ok_list %} +
  • {{title|wiki_title}} ({{ filename }})
  • + {% endfor %} +
+ {% endif %} + +{% else %} + + {% if ok_list %} +

{% trans "Files have been successfully uploaded to the repository." %}

+

{% trans "Uploaded files" %}

+ + {% endif %} +{% endif %} + +{% if skipped_list %} +

{% trans "Skipped files" %}

+

{% trans "Files skipped due to no .xml extension" %}

+
    + {% for filename in skipped_list %} +
  • {{ filename }}
  • + {% endfor %} +
+{% endif %} + + +{% endblock leftcolumn %} + + +{% block rightcolumn %} +{% endblock rightcolumn %} diff --git a/apps/wiki/urls.py b/apps/wiki/urls.py index 351ecbc8..f4da5f37 100644 --- a/apps/wiki/urls.py +++ b/apps/wiki/urls.py @@ -20,6 +20,9 @@ urlpatterns = patterns('wiki.views', url(r'^(?P[^/]+)/readonly$', 'editor_readonly', name="wiki_editor_readonly"), + url(r'^upload/$', + 'upload', name='wiki_upload'), + url(r'^create/(?P[^/]+)', 'create_missing', name='wiki_create_missing'), diff --git a/apps/wiki/views.py b/apps/wiki/views.py index b57347c2..7417235b 100644 --- a/apps/wiki/views.py +++ b/apps/wiki/views.py @@ -13,7 +13,7 @@ from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError, from django import http from wiki.models import getstorage, DocumentNotFound, normalize_name, split_name, join_name, Theme -from wiki.forms import DocumentTextSaveForm, DocumentTagForm, DocumentCreateForm +from wiki.forms import DocumentTextSaveForm, DocumentTagForm, DocumentCreateForm, DocumentsUploadForm from datetime import datetime from django.utils.encoding import smart_unicode from django.utils.translation import ugettext_lazy as _ @@ -126,7 +126,7 @@ def create_missing(request, name): form = DocumentCreateForm(request.POST, request.FILES) if form.is_valid(): doc = storage.create_document( - id=form.cleaned_data['id'], + name=form.cleaned_data['id'], text=form.cleaned_data['text'], ) @@ -143,6 +143,58 @@ def create_missing(request, name): }) +def upload(request): + storage = getstorage() + + if request.method == "POST": + form = DocumentsUploadForm(request.POST, request.FILES) + if form.is_valid(): + zip = form.cleaned_data['zip'] + skipped_list = [] + ok_list = [] + error_list = [] + titles = {} + existing = storage.all() + for filename in zip.namelist(): + if filename[-1] == '/': + continue + title = normalize_name(os.path.basename(filename)[:-4]) + if not (title and filename.endswith('.xml')): + skipped_list.append(filename) + elif title in titles: + error_list.append((filename, title, _('Title already used for %s' % titles[title]))) + elif title in existing: + error_list.append((filename, title, _('Title already used in repository.'))) + else: + ok_list.append((filename, title)) + titles[title] = filename + if not error_list: + for filename, title in ok_list: + storage.create_document( + name=title, + text=zip.read(filename) + ) + + return direct_to_template(request, "wiki/document_upload.html", extra_context={ + "form": form, + "ok_list": ok_list, + "skipped_list": skipped_list, + "error_list": error_list, + }) + #doc = storage.create_document( + # name=base, + # text=form.cleaned_data['text'], + + + return http.HttpResponse('\n'.join(yeslist) + '\n\n' + '\n'.join(nolist)) + else: + form = DocumentsUploadForm() + + return direct_to_template(request, "wiki/document_upload.html", extra_context={ + "form": form, + }) + + @never_cache @normalized_name def text(request, name): diff --git a/redakcja/static/css/filelist.css b/redakcja/static/css/filelist.css index b2f51ed2..2ccf33ec 100644 --- a/redakcja/static/css/filelist.css +++ b/redakcja/static/css/filelist.css @@ -70,3 +70,20 @@ a:hover { #loading-overlay { display: none; } + +.error { + color: red; + font-weight: bold; +} + +.success { + color: green; +} + +#error-list { + color: red; +} + +#skipped-list { + color: #666; +} \ No newline at end of file