From: Radek Czajka Date: Wed, 26 Mar 2014 15:32:58 +0000 (+0100) Subject: Merge with master. X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/ec5b493bff5efa683aadf5f78aa891eff3550156?hp=-c Merge with master. --- ec5b493bff5efa683aadf5f78aa891eff3550156 diff --combined apps/catalogue/admin.py index 8ba803e7,7fbacad9..53e8a256 --- a/apps/catalogue/admin.py +++ b/apps/catalogue/admin.py @@@ -3,13 -3,14 +3,16 @@@ from django.contrib import admi from catalogue import models class BookAdmin(admin.ModelAdmin): + list_display = ['title', 'public', '_published', '_new_publishable', 'project'] + list_filter = ['public', '_published', '_new_publishable', 'project'] prepopulated_fields = {'slug': ['title']} search_fields = ['title'] + admin.site.register(models.Project) admin.site.register(models.Book, BookAdmin) admin.site.register(models.Chunk) - admin.site.register(models.Chunk.tag_model) + +admin.site.register(models.Image) +admin.site.register(models.Image.tag_model) diff --combined apps/catalogue/forms.py index 26d14aa4,7ae7ff40..83b16523 --- a/apps/catalogue/forms.py +++ b/apps/catalogue/forms.py @@@ -9,7 -9,7 +9,7 @@@ from django import form from django.utils.translation import ugettext_lazy as _ from catalogue.constants import MASTERS -from catalogue.models import Book, Chunk +from catalogue.models import Book, Chunk, Image class DocumentCreateForm(forms.ModelForm): """ @@@ -20,7 -20,7 +20,7 @@@ class Meta: model = Book - exclude = ['parent', 'parent_number'] + exclude = ['parent', 'parent_number', 'project'] def __init__(self, *args, **kwargs): super(DocumentCreateForm, self).__init__(*args, **kwargs) @@@ -72,7 -72,7 +72,7 @@@ class ChunkForm(forms.ModelForm) """ user = forms.ModelChoiceField(queryset= User.objects.annotate(count=Count('chunk')). - order_by('-count', 'last_name', 'first_name'), required=False, + order_by('last_name', 'first_name'), required=False, label=_('Assigned to')) class Meta: @@@ -130,6 -130,7 +130,7 @@@ class BookForm(forms.ModelForm) class Meta: model = Book + exclude = ['project'] def __init__(self, *args, **kwargs): ret = super(BookForm, self).__init__(*args, **kwargs) @@@ -144,7 -145,7 +145,7 @@@ class ReadonlyBookForm(BookForm) def __init__(self, *args, **kwargs): ret = super(ReadonlyBookForm, self).__init__(*args, **kwargs) for field in self.fields.values(): - field.widget.attrs.update({"readonly": True}) + field.widget.attrs.update({"disabled": "disabled"}) return ret @@@ -154,30 -155,3 +155,30 @@@ class ChooseMasterForm(forms.Form) """ master = forms.ChoiceField(choices=((m, m) for m in MASTERS)) + + +class ImageForm(forms.ModelForm): + """Form used for editing an Image.""" + user = forms.ModelChoiceField(queryset= + User.objects.annotate(count=Count('chunk')). + order_by('-count', 'last_name', 'first_name'), required=False, + label=_('Assigned to')) + + class Meta: + model = Image + fields = ['title', 'slug', 'user', 'stage'] + + def __init__(self, *args, **kwargs): + super(ImageForm, self).__init__(*args, **kwargs) + self.fields['slug'].widget.attrs={'class': 'autoslug'} + self.fields['title'].widget.attrs={'class': 'autoslug-source'} + + +class ReadonlyImageForm(ImageForm): + """Form used for not editing a Book.""" + + def __init__(self, *args, **kwargs): + ret = super(ReadonlyImageForm, self).__init__(*args, **kwargs) + for field in self.fields.values(): + field.widget.attrs.update({"disabled": "disabled"}) + return ret diff --combined apps/catalogue/locale/pl/LC_MESSAGES/django.mo index d933b5a9,b6a12e32..64f78b46 Binary files differ diff --combined apps/catalogue/locale/pl/LC_MESSAGES/django.po index 99241c46,6790400c..d98440f3 --- a/apps/catalogue/locale/pl/LC_MESSAGES/django.po +++ b/apps/catalogue/locale/pl/LC_MESSAGES/django.po @@@ -7,15 -7,18 +7,18 @@@ msgid " msgstr "" "Project-Id-Version: Platforma Redakcyjna\n" "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2011-12-21 12:44+0100\n" - "PO-Revision-Date: 2011-12-21 12:45+0100\n" -"POT-Creation-Date: 2013-07-16 13:22+0200\n" -"PO-Revision-Date: 2013-07-16 13:22+0100\n" ++"POT-Creation-Date: 2014-03-26 16:13+0100\n" ++"PO-Revision-Date: 2014-03-26 16:14+0100\n" "Last-Translator: Radek Czajka \n" - "Language-Team: Fundacja Nowoczesna Polska \n" + "Language-Team: Fundacja Nowoczesna Polska \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" - "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " + "|| n%100>=20) ? 1 : 2);\n" + "X-Generator: Poedit 1.5.4\n" #: forms.py:39 msgid "Text file must be UTF-8 encoded." @@@ -33,13 -36,11 +36,11 @@@ msgstr "Plik ZIP msgid "Directories are documents in chunks" msgstr "Katalogi zawierają dokumenty w częściach" --#: forms.py:76 - #: forms.py:164 ++#: forms.py:76 forms.py:165 msgid "Assigned to" msgstr "Przypisane do" - #: forms.py:97 - #: forms.py:111 + #: forms.py:97 forms.py:111 msgid "Chunk with this slug already exists" msgstr "Część z tym slugiem już istnieje" @@@ -47,83 -48,76 +48,76 @@@ msgid "Append to" msgstr "Dołącz do" - #: views.py:165 -#: views.py:160 ++#: views.py:166 #, python-format msgid "Slug already used for %s" msgstr "Slug taki sam jak dla pliku %s" - #: views.py:167 -#: views.py:162 ++#: views.py:168 msgid "Slug already used in repository." msgstr "Dokument o tym slugu już istnieje w repozytorium." - #: views.py:173 -#: views.py:168 ++#: views.py:174 msgid "File should be UTF-8 encoded." msgstr "Plik powinien mieć kodowanie UTF-8." - #: models/book.py:21 - #: models/chunk.py:23 - #: models/image.py:21 -#: views.py:498 models/book.py:56 ++#: views.py:552 models/book.py:56 + msgid "books" + msgstr "książki" + -#: views.py:500 ++#: views.py:554 + msgid "scan gallery" + msgstr "galeria skanów" + -#: models/book.py:28 models/chunk.py:23 ++#: models/book.py:28 models/chunk.py:23 models/image.py:21 msgid "title" msgstr "tytuł" - #: models/book.py:22 - #: models/chunk.py:24 - #: models/image.py:22 -#: models/book.py:29 models/chunk.py:24 ++#: models/book.py:29 models/chunk.py:24 models/image.py:22 msgid "slug" msgstr "slug" - #: models/book.py:23 - #: models/image.py:23 -#: models/book.py:30 ++#: models/book.py:30 models/image.py:23 msgid "public" msgstr "publiczna" - #: models/book.py:24 + #: models/book.py:31 msgid "scan gallery name" msgstr "nazwa galerii skanów" - #: models/book.py:27 + #: models/book.py:35 msgid "parent" msgstr "rodzic" - #: models/book.py:28 + #: models/book.py:36 msgid "parent number" msgstr "numeracja rodzica" - #: models/book.py:44 - #: models/chunk.py:21 - #: models/publish_log.py:17 + #: models/book.py:55 models/chunk.py:21 models/publish_log.py:17 msgid "book" msgstr "książka" - #: models/book.py:45 - msgid "books" - msgstr "książki" - - #: models/book.py:220 + #: models/book.py:255 msgid "No chunks in the book." msgstr "Książka nie ma części." - #: models/book.py:224 + #: models/book.py:259 msgid "Not all chunks have publishable revisions." msgstr "Niektóre części nie są gotowe do publikacji." - #: models/book.py:233 - #: models/image.py:80 -#: models/book.py:266 ++#: models/book.py:266 models/image.py:80 msgid "Invalid XML" msgstr "Nieprawidłowy XML" - #: models/book.py:235 - #: models/image.py:82 -#: models/book.py:268 ++#: models/book.py:268 models/image.py:82 msgid "No Dublin Core found." msgstr "Brak sekcji Dublin Core." - #: models/book.py:237 - #: models/image.py:84 -#: models/book.py:270 ++#: models/book.py:270 models/image.py:84 msgid "Invalid Dublin Core" msgstr "Nieprawidłowy Dublin Core" - #: models/book.py:240 - #: models/image.py:88 -#: models/book.py:273 ++#: models/book.py:273 models/image.py:88 msgid "rdf:about is not" msgstr "rdf:about jest różny od" @@@ -143,33 -137,31 +137,44 @@@ msgstr "część msgid "chunks" msgstr "części" - #: models/image.py:20 - #: models/image.py:34 - #: models/publish_log.py:45 ++#: models/image.py:20 models/image.py:34 models/publish_log.py:45 +msgid "image" +msgstr "obraz" + +#: models/image.py:35 +msgid "images" +msgstr "obrazy" + +#: models/image.py:73 +msgid "There is no publishable revision" +msgstr "Żadna wersja nie została oznaczona do publikacji." + - #: models/publish_log.py:18 - #: models/publish_log.py:46 + #: models/project.py:13 + msgid "name" + msgstr "nazwa" + + #: models/project.py:14 + msgid "notes" + msgstr "notatki" + -#: models/project.py:19 templates/catalogue/book_list/book_list.html:62 ++#: models/project.py:19 templates/catalogue/book_list/book_list.html:64 + msgid "project" + msgstr "projekt" + + #: models/project.py:20 + msgid "projects" + msgstr "projekty" + -#: models/publish_log.py:18 ++#: models/publish_log.py:18 models/publish_log.py:46 msgid "time" msgstr "czas" - #: models/publish_log.py:19 - #: models/publish_log.py:47 - #: templates/catalogue/wall.html:18 -#: models/publish_log.py:19 templates/catalogue/wall.html:18 ++#: models/publish_log.py:19 models/publish_log.py:47 ++#: templates/catalogue/wall.html:19 msgid "user" msgstr "użytkownik" - #: models/publish_log.py:24 - #: models/publish_log.py:33 + #: models/publish_log.py:24 models/publish_log.py:33 msgid "book publish record" msgstr "zapis publikacji książki" @@@ -177,8 -169,7 +182,7 @@@ msgid "book publish records" msgstr "zapisy publikacji książek" --#: models/publish_log.py:34 - #: models/publish_log.py:48 ++#: models/publish_log.py:34 models/publish_log.py:48 msgid "change" msgstr "zmiana" @@@ -190,16 -181,7 +194,16 @@@ msgstr "zapis publikacji części msgid "chunk publish records" msgstr "zapisy publikacji części" -#: templates/catalogue/activity.html:9 templatetags/catalogue.py:29 +#: models/publish_log.py:53 +msgid "image publish record" +msgstr "zapis publikacji obrazu" + +#: models/publish_log.py:54 +msgid "image publish records" +msgstr "zapisy publikacji obrazów" + - #: templates/catalogue/activity.html:10 ++#: templates/catalogue/activity.html:6 templates/catalogue/activity.html:12 +#: templatetags/catalogue.py:29 msgid "Activity" msgstr "Aktywność" @@@ -207,248 -189,210 +211,282 @@@ msgid "Platforma Redakcyjna" msgstr "Platforma Redakcyjna" --#: templates/catalogue/book_append_to.html:9 ++#: templates/catalogue/book_append_to.html:4 ++#: templates/catalogue/book_append_to.html:11 msgid "Append book" msgstr "Dołącz książkę" --#: templates/catalogue/book_detail.html:14 - #: templates/catalogue/book_edit.html:9 - #: templates/catalogue/chunk_edit.html:13 - #: templates/catalogue/image_detail.html:14 -#: templates/catalogue/book_edit.html:9 templates/catalogue/chunk_edit.html:12 ++#: templates/catalogue/book_detail.html:18 ++#: templates/catalogue/book_edit.html:13 ++#: templates/catalogue/chunk_edit.html:16 ++#: templates/catalogue/image_detail.html:18 msgid "Save" msgstr "Zapisz" --#: templates/catalogue/book_detail.html:21 ++#: templates/catalogue/book_detail.html:25 + msgid "Edit gallery" + msgstr "Edytuj galerię" + -#: templates/catalogue/book_detail.html:24 ++#: templates/catalogue/book_detail.html:28 msgid "Append to other book" msgstr "Dołącz do innej książki" - #: templates/catalogue/book_detail.html:27 -#: templates/catalogue/book_detail.html:30 ++#: templates/catalogue/book_detail.html:34 msgid "Chunks" msgstr "Części" - #: templates/catalogue/book_detail.html:42 - #: templates/catalogue/image_detail.html:32 - #: templatetags/wall.py:78 -#: templates/catalogue/book_detail.html:45 templatetags/wall.py:78 ++#: templates/catalogue/book_detail.html:49 ++#: templates/catalogue/image_detail.html:36 templatetags/wall.py:78 msgid "Publication" msgstr "Publikacja" - #: templates/catalogue/book_detail.html:44 - #: templates/catalogue/image_detail.html:34 -#: templates/catalogue/book_detail.html:54 ++#: templates/catalogue/book_detail.html:58 ++#: templates/catalogue/image_detail.html:38 msgid "Last published" msgstr "Ostatnio opublikowano" - #: templates/catalogue/book_detail.html:54 -#: templates/catalogue/book_detail.html:64 ++#: templates/catalogue/book_detail.html:68 msgid "Full XML" msgstr "Pełny XML" - #: templates/catalogue/book_detail.html:55 -#: templates/catalogue/book_detail.html:65 ++#: templates/catalogue/book_detail.html:69 msgid "HTML version" msgstr "Wersja HTML" - #: templates/catalogue/book_detail.html:56 -#: templates/catalogue/book_detail.html:66 ++#: templates/catalogue/book_detail.html:70 msgid "TXT version" msgstr "Wersja TXT" - #: templates/catalogue/book_detail.html:57 -#: templates/catalogue/book_detail.html:67 ++#: templates/catalogue/book_detail.html:71 msgid "PDF version" msgstr "Wersja PDF" - #: templates/catalogue/book_detail.html:58 -#: templates/catalogue/book_detail.html:68 ++#: templates/catalogue/book_detail.html:72 msgid "EPUB version" msgstr "Wersja EPUB" - #: templates/catalogue/book_detail.html:71 - #: templates/catalogue/image_detail.html:53 -#: templates/catalogue/book_detail.html:81 ++#: templates/catalogue/book_detail.html:85 ++#: templates/catalogue/image_detail.html:57 msgid "Publish" msgstr "Opublikuj" - #: templates/catalogue/book_detail.html:75 - #: templates/catalogue/image_detail.html:57 -#: templates/catalogue/book_detail.html:85 ++#: templates/catalogue/book_detail.html:89 ++#: templates/catalogue/image_detail.html:61 msgid "Log in to publish." msgstr "Zaloguj się, aby opublikować." - #: templates/catalogue/book_detail.html:78 - #: templates/catalogue/image_detail.html:60 -#: templates/catalogue/book_detail.html:88 ++#: templates/catalogue/book_detail.html:92 ++#: templates/catalogue/image_detail.html:64 msgid "This book can't be published yet, because:" msgstr "Ta książka nie może jeszcze zostać opublikowana. Powód:" - #: templates/catalogue/book_detail.html:87 - #: templates/catalogue/image_detail.html:68 -#: templates/catalogue/book_detail.html:98 ++#: templates/catalogue/book_detail.html:102 ++#: templates/catalogue/image_detail.html:72 msgid "Comments" msgstr "Komentarze" - #: templates/catalogue/book_html.html:13 -#: templates/catalogue/book_text.html:7 -msgid "Redakcja" -msgstr "" ++#: templates/catalogue/book_edit.html:5 ++msgid "Edit book" ++msgstr "Edytuj książkę" + -#: templates/catalogue/book_text.html:15 ++#: templates/catalogue/book_html.html:13 templates/catalogue/book_text.html:15 msgid "Table of contents" msgstr "Spis treści" - #: templates/catalogue/book_html.html:14 -#: templates/catalogue/book_text.html:17 ++#: templates/catalogue/book_html.html:14 templates/catalogue/book_text.html:17 msgid "Edit. note" msgstr "Nota red." -#: templates/catalogue/chunk_add.html:5 templates/catalogue/chunk_edit.html:18 +#: templates/catalogue/book_html.html:15 +msgid "Infobox" +msgstr "Informacje" + - #: templates/catalogue/chunk_add.html:5 - #: templates/catalogue/chunk_edit.html:19 ++#: templates/catalogue/book_text.html:7 ++msgid "Redakcja" ++msgstr "" ++ ++#: templates/catalogue/chunk_add.html:5 templates/catalogue/chunk_add.html:9 ++#: templates/catalogue/chunk_edit.html:22 msgid "Split chunk" msgstr "Podziel część" --#: templates/catalogue/chunk_add.html:10 ++#: templates/catalogue/chunk_add.html:14 msgid "Insert empty chunk after" msgstr "Wstaw pustą część po" --#: templates/catalogue/chunk_add.html:13 ++#: templates/catalogue/chunk_add.html:17 msgid "Add chunk" msgstr "Dodaj część" - #: templates/catalogue/chunk_edit.html:6 - #: templates/catalogue/book_list/book.html:7 - #: templates/catalogue/book_list/chunk.html:5 -#: templates/catalogue/chunk_edit.html:5 ++#: templates/catalogue/chunk_edit.html:5 templates/catalogue/chunk_edit.html:9 + #: templates/catalogue/book_list/book.html:8 + #: templates/catalogue/book_list/chunk.html:6 msgid "Chunk settings" msgstr "Ustawienia części" - #: templates/catalogue/chunk_edit.html:11 -#: templates/catalogue/chunk_edit.html:10 ++#: templates/catalogue/chunk_edit.html:14 msgid "Book" msgstr "Książka" #: templates/catalogue/document_create_missing.html:5 ++#: templates/catalogue/document_create_missing.html:9 msgid "Create a new book" msgstr "Utwórz nową książkę" --#: templates/catalogue/document_create_missing.html:11 ++#: templates/catalogue/document_create_missing.html:15 msgid "Create book" msgstr "Utwórz książkę" --#: templates/catalogue/document_upload.html:8 --msgid "Bulk documents upload" ++#: templates/catalogue/document_list.html:7 ++msgid "Book list" ++msgstr "Lista książek" ++ ++#: templates/catalogue/document_upload.html:5 ++msgid "Bulk document upload" msgstr "Hurtowe dodawanie dokumentów" #: templates/catalogue/document_upload.html:11 - msgid "Please submit a ZIP with UTF-8 encoded XML files. Files not ending with .xml will be ignored." - msgstr "Proszę wskazać archiwum ZIP z plikami XML w kodowaniu UTF-8. Pliki nie kończące się na .xml zostaną zignorowane." ++msgid "Bulk documents upload" ++msgstr "Hurtowe dodawanie dokumentów" ++ ++#: templates/catalogue/document_upload.html:14 + msgid "" + "Please submit a ZIP with UTF-8 encoded XML files. Files not ending with " + ".xml will be ignored." + msgstr "" + "Proszę wskazać archiwum ZIP z plikami XML w kodowaniu UTF-8. Pliki nie " + "kończące się na .xml zostaną zignorowane." - #: templates/catalogue/document_upload.html:17 - #: templates/catalogue/upload_pdf.html:13 - #: templatetags/catalogue.py:36 -#: templates/catalogue/document_upload.html:17 templatetags/catalogue.py:35 ++#: templates/catalogue/document_upload.html:20 ++#: templates/catalogue/upload_pdf.html:16 templatetags/catalogue.py:36 msgid "Upload" msgstr "Załaduj" --#: templates/catalogue/document_upload.html:24 - msgid "There have been some errors. No files have been added to the repository." ++#: templates/catalogue/document_upload.html:27 + 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/catalogue/document_upload.html:25 ++#: templates/catalogue/document_upload.html:28 msgid "Offending files" msgstr "Błędne pliki" --#: templates/catalogue/document_upload.html:33 ++#: templates/catalogue/document_upload.html:36 msgid "Correct files" msgstr "Poprawne pliki" --#: templates/catalogue/document_upload.html:44 ++#: templates/catalogue/document_upload.html:47 msgid "Files have been successfully uploaded to the repository." msgstr "Pliki zostały dodane do repozytorium." --#: templates/catalogue/document_upload.html:45 ++#: templates/catalogue/document_upload.html:48 msgid "Uploaded files" msgstr "Dodane pliki" --#: templates/catalogue/document_upload.html:55 ++#: templates/catalogue/document_upload.html:58 msgid "Skipped files" msgstr "Pominięte pliki" --#: templates/catalogue/document_upload.html:56 ++#: templates/catalogue/document_upload.html:59 msgid "Files skipped due to no .xml extension" msgstr "Pliki pominięte z powodu braku rozszerzenia .xml." - #: templates/catalogue/image_detail.html:22 -#: templates/catalogue/my_page.html:21 -msgid "Your last edited documents" -msgstr "Twoje ostatnie edycje" ++#: templates/catalogue/image_detail.html:26 +msgid "Editor" +msgstr "Edytor" - #: templates/catalogue/image_detail.html:24 -#: templates/catalogue/my_page.html:30 templates/catalogue/user_page.html:13 -msgid "Recent activity for" -msgstr "Ostatnia aktywność dla:" ++#: templates/catalogue/image_detail.html:28 +msgid "Proceed to the editor." +msgstr "Przejdź do edytora." -#: templates/catalogue/user_list.html:7 templatetags/catalogue.py:31 -msgid "Users" -msgstr "Użytkownicy" - -#: templates/catalogue/wall.html:28 -msgid "not logged in" -msgstr "nie zalogowany" ++#: templates/catalogue/image_list.html:7 ++msgid "Image list" ++msgstr "Lista obrazów" + -#: templates/catalogue/wall.html:33 -msgid "No activity recorded." -msgstr "Nie zanotowano aktywności." - -#: templates/catalogue/book_list/book.html:7 -#: templates/catalogue/book_list/book.html:28 -msgid "Book settings" -msgstr "Ustawienia książki" - -#: templates/catalogue/book_list/book_list.html:22 -msgid "Show hidden books" -msgstr "Pokaż ukryte książki" +#: templates/catalogue/image_short.html:4 +msgid "Image settings" +msgstr "Ustawienia obrazu" +#: templates/catalogue/image_table.html:19 - #: templates/catalogue/book_list/book_list.html:24 + #: templates/catalogue/book_list/book_list.html:27 msgid "Search in book titles" msgstr "Szukaj w tytułach książek" +#: templates/catalogue/image_table.html:24 - #: templates/catalogue/book_list/book_list.html:29 + #: templates/catalogue/book_list/book_list.html:32 msgid "stage" msgstr "etap" +#: templates/catalogue/image_table.html:26 +#: templates/catalogue/image_table.html:37 - #: templates/catalogue/book_list/book_list.html:31 - #: templates/catalogue/book_list/book_list.html:42 + #: templates/catalogue/book_list/book_list.html:34 + #: templates/catalogue/book_list/book_list.html:45 -#: templates/catalogue/book_list/book_list.html:64 ++#: templates/catalogue/book_list/book_list.html:66 msgid "none" msgstr "brak" +#: templates/catalogue/image_table.html:35 - #: templates/catalogue/book_list/book_list.html:40 + #: templates/catalogue/book_list/book_list.html:43 msgid "editor" msgstr "redaktor" -#: templates/catalogue/book_list/book_list.html:54 +#: templates/catalogue/image_table.html:46 - #: templates/catalogue/book_list/book_list.html:51 ++#: templates/catalogue/book_list/book_list.html:56 msgid "status" msgstr "status" -#: templates/catalogue/book_list/book_list.html:88 +#: templates/catalogue/image_table.html:63 +#, python-format +msgid "%(c)s image" +msgid_plural "%(c)s images" +msgstr[0] "%(c)s obraz" +msgstr[1] "%(c)s obrazy" +msgstr[2] "%(c)s obrazów" + +#: templates/catalogue/image_table.html:68 +msgid "No images found." +msgstr "Nie znaleziono obrazów." + - #: templates/catalogue/my_page.html:13 ++#: templates/catalogue/my_page.html:15 templatetags/catalogue.py:27 ++msgid "My page" ++msgstr "Moja strona" ++ ++#: templates/catalogue/my_page.html:24 +msgid "Your last edited documents" +msgstr "Twoje ostatnie edycje" + - #: templates/catalogue/my_page.html:22 - #: templates/catalogue/user_page.html:13 ++#: templates/catalogue/my_page.html:33 templates/catalogue/user_page.html:16 +msgid "Recent activity for" +msgstr "Ostatnia aktywność dla:" + - #: templates/catalogue/upload_pdf.html:8 ++#: templates/catalogue/upload_pdf.html:5 ++#: templates/catalogue/upload_pdf.html:11 +msgid "PDF file upload" - msgstr "" ++msgstr "Ładowanie pliku PDF" + - #: templates/catalogue/user_list.html:7 ++#: templates/catalogue/user_list.html:6 templates/catalogue/user_list.html:11 +#: templatetags/catalogue.py:32 +msgid "Users" +msgstr "Użytkownicy" + - #: templates/catalogue/wall.html:28 ++#: templates/catalogue/wall.html:29 +msgid "not logged in" +msgstr "nie zalogowany" + - #: templates/catalogue/wall.html:33 ++#: templates/catalogue/wall.html:34 +msgid "No activity recorded." +msgstr "Nie zanotowano aktywności." + - #: templates/catalogue/book_list/book.html:6 - #: templates/catalogue/book_list/book.html:25 ++#: templates/catalogue/book_list/book.html:7 ++#: templates/catalogue/book_list/book.html:28 +msgid "Book settings" +msgstr "Ustawienia książki" + - #: templates/catalogue/book_list/book_list.html:19 ++#: templates/catalogue/book_list/book_list.html:22 +msgid "Show hidden books" +msgstr "Pokaż ukryte książki" + - #: templates/catalogue/book_list/book_list.html:75 ++#: templates/catalogue/book_list/book_list.html:90 #, python-format msgid "%(c)s book" msgid_plural "%(c)s books" @@@ -456,51 -400,70 +494,70 @@@ msgstr[0] "%(c)s książka msgstr[1] "%(c)s książki" msgstr[2] "%(c)s książek" - #: templates/catalogue/book_list/book_list.html:80 -#: templates/catalogue/book_list/book_list.html:93 ++#: templates/catalogue/book_list/book_list.html:95 msgid "No books found." msgstr "Nie znaleziono książek." - #: templatetags/book_list.py:84 - #: templatetags/book_list.py:145 -#: templates/catalogue/book_list/book_list.html:99 ++#: templates/catalogue/book_list/book_list.html:101 + msgid "Set stage" + msgstr "Ustaw etap" + -#: templates/catalogue/book_list/book_list.html:100 ++#: templates/catalogue/book_list/book_list.html:102 + msgid "Set user" + msgstr "Przypisz redaktora" + -#: templates/catalogue/book_list/book_list.html:102 ++#: templates/catalogue/book_list/book_list.html:104 + msgid "Project" + msgstr "Projekt" + -#: templates/catalogue/book_list/book_list.html:103 ++#: templates/catalogue/book_list/book_list.html:105 + msgid "Mark publishable" + msgstr "Oznacz do publikacji" + -#: templates/catalogue/book_list/book_list.html:104 ++#: templates/catalogue/book_list/book_list.html:106 + msgid "Mark not publishable" + msgstr "Odznacz do publikacji" + -#: templates/catalogue/book_list/book_list.html:105 ++#: templates/catalogue/book_list/book_list.html:107 + msgid "Other user" + msgstr "Inny użytkownik" + -#: templatetags/book_list.py:84 ++#: templatetags/book_list.py:84 templatetags/book_list.py:152 msgid "publishable" msgstr "do publikacji" --#: templatetags/book_list.py:85 - #: templatetags/book_list.py:146 ++#: templatetags/book_list.py:85 templatetags/book_list.py:153 msgid "changed" msgstr "zmienione" --#: templatetags/book_list.py:86 - #: templatetags/book_list.py:147 ++#: templatetags/book_list.py:86 templatetags/book_list.py:154 msgid "published" msgstr "opublikowane" --#: templatetags/book_list.py:87 - #: templatetags/book_list.py:148 ++#: templatetags/book_list.py:87 templatetags/book_list.py:155 msgid "unpublished" msgstr "nie opublikowane" --#: templatetags/book_list.py:88 - #: templatetags/book_list.py:149 ++#: templatetags/book_list.py:88 templatetags/book_list.py:156 msgid "empty" msgstr "puste" --#: templatetags/catalogue.py:27 --msgid "My page" --msgstr "Moja strona" -- #: templatetags/catalogue.py:30 msgid "All" msgstr "Wszystkie" -#: templatetags/catalogue.py:34 +#: templatetags/catalogue.py:31 +msgid "Images" +msgstr "Obrazy" + +#: templatetags/catalogue.py:35 msgid "Add" msgstr "Dodaj" -#: templatetags/catalogue.py:37 ++#: templatetags/catalogue.py:38 + msgid "Covers" + msgstr "Okładki" + #: templatetags/wall.py:49 msgid "Related edit" msgstr "Powiązana zmiana" @@@ -513,6 -476,9 +570,6 @@@ msgstr "Zmiana msgid "Comment" msgstr "Komentarz" -#~ msgid "Infobox" -#~ msgstr "Informacje" - #~ msgid "Admin" #~ msgstr "Administracja" @@@ -570,9 -536,6 +627,6 @@@ #~ msgid "Describe the reason for reverting." #~ msgstr "Opisz powód przywrócenia." - #~ msgid "name" - #~ msgstr "nazwa" - #~ msgid "theme" #~ msgstr "motyw" @@@ -687,9 -650,6 +741,6 @@@ #~ msgid "Last edited by" #~ msgstr "Ostatnio edytowane przez" - #~ msgid "Link to gallery" - #~ msgstr "Link do galerii" - #~ msgid "Summary" #~ msgstr "Podsumowanie" diff --combined apps/catalogue/migrations/0012_auto__add_imagepublishrecord__add_imagechange__add_unique_imagechange_.py index 00000000,00000000..599e103e new file mode 100644 --- /dev/null +++ b/apps/catalogue/migrations/0012_auto__add_imagepublishrecord__add_imagechange__add_unique_imagechange_.py @@@ -1,0 -1,0 +1,270 @@@ ++# -*- coding: utf-8 -*- ++import datetime ++from south.db import db ++from south.v2 import SchemaMigration ++from django.db import models ++ ++ ++class Migration(SchemaMigration): ++ ++ def forwards(self, orm): ++ # Adding model 'ImagePublishRecord' ++ db.create_table(u'catalogue_imagepublishrecord', ( ++ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ++ ('image', self.gf('django.db.models.fields.related.ForeignKey')(related_name='publish_log', to=orm['catalogue.Image'])), ++ ('timestamp', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), ++ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), ++ ('change', self.gf('django.db.models.fields.related.ForeignKey')(related_name='publish_log', to=orm['catalogue.ImageChange'])), ++ )) ++ db.send_create_signal('catalogue', ['ImagePublishRecord']) ++ ++ # Adding model 'ImageChange' ++ db.create_table(u'catalogue_imagechange', ( ++ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ++ ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), ++ ('author_name', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), ++ ('author_email', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), ++ ('revision', self.gf('django.db.models.fields.IntegerField')(db_index=True)), ++ ('parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='children', null=True, blank=True, to=orm['catalogue.ImageChange'])), ++ ('merge_parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='merge_children', null=True, blank=True, to=orm['catalogue.ImageChange'])), ++ ('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)), ++ ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, db_index=True)), ++ ('publishable', self.gf('django.db.models.fields.BooleanField')(default=False)), ++ ('tree', self.gf('django.db.models.fields.related.ForeignKey')(related_name='change_set', to=orm['catalogue.Image'])), ++ ('data', self.gf('django.db.models.fields.files.FileField')(max_length=100)), ++ )) ++ db.send_create_signal('catalogue', ['ImageChange']) ++ ++ # Adding M2M table for field tags on 'ImageChange' ++ db.create_table(u'catalogue_imagechange_tags', ( ++ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), ++ ('imagechange', models.ForeignKey(orm['catalogue.imagechange'], null=False)), ++ ('imagetag', models.ForeignKey(orm['catalogue.imagetag'], null=False)) ++ )) ++ db.create_unique(u'catalogue_imagechange_tags', ['imagechange_id', 'imagetag_id']) ++ ++ # Adding unique constraint on 'ImageChange', fields ['tree', 'revision'] ++ db.create_unique(u'catalogue_imagechange', ['tree_id', 'revision']) ++ ++ # Adding model 'ImageTag' ++ db.create_table(u'catalogue_imagetag', ( ++ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ++ ('name', self.gf('django.db.models.fields.CharField')(max_length=64)), ++ ('slug', self.gf('django.db.models.fields.SlugField')(max_length=64, unique=True, null=True, blank=True)), ++ ('ordering', self.gf('django.db.models.fields.IntegerField')()), ++ )) ++ db.send_create_signal('catalogue', ['ImageTag']) ++ ++ # Adding model 'Image' ++ db.create_table(u'catalogue_image', ( ++ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ++ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), ++ ('image', self.gf('django.db.models.fields.files.FileField')(max_length=100)), ++ ('title', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), ++ ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=50)), ++ ('public', self.gf('django.db.models.fields.BooleanField')(default=True, db_index=True)), ++ ('_short_html', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), ++ ('_new_publishable', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), ++ ('_published', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), ++ ('_changed', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), ++ ('stage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['catalogue.ImageTag'], null=True, blank=True)), ++ ('head', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['catalogue.ImageChange'], null=True, blank=True)), ++ ('creator', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='created_image', null=True, to=orm['auth.User'])), ++ )) ++ db.send_create_signal('catalogue', ['Image']) ++ ++ ++ def backwards(self, orm): ++ # Removing unique constraint on 'ImageChange', fields ['tree', 'revision'] ++ db.delete_unique(u'catalogue_imagechange', ['tree_id', 'revision']) ++ ++ # Deleting model 'ImagePublishRecord' ++ db.delete_table(u'catalogue_imagepublishrecord') ++ ++ # Deleting model 'ImageChange' ++ db.delete_table(u'catalogue_imagechange') ++ ++ # Removing M2M table for field tags on 'ImageChange' ++ db.delete_table('catalogue_imagechange_tags') ++ ++ # Deleting model 'ImageTag' ++ db.delete_table(u'catalogue_imagetag') ++ ++ # Deleting model 'Image' ++ db.delete_table(u'catalogue_image') ++ ++ ++ models = { ++ u'auth.group': { ++ 'Meta': {'object_name': 'Group'}, ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), ++ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) ++ }, ++ u'auth.permission': { ++ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, ++ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), ++ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) ++ }, ++ u'auth.user': { ++ 'Meta': {'object_name': 'User'}, ++ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), ++ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), ++ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), ++ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), ++ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), ++ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), ++ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), ++ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), ++ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), ++ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), ++ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) ++ }, ++ 'catalogue.book': { ++ 'Meta': {'ordering': "['title', 'slug']", 'object_name': 'Book'}, ++ '_new_publishable': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), ++ '_on_track': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), ++ '_published': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), ++ '_short_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), ++ '_single': ('django.db.models.fields.NullBooleanField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), ++ 'dc_cover_image': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['cover.Image']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), ++ 'dc_slug': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '128', 'null': 'True', 'blank': 'True'}), ++ 'gallery': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}), ++ 'parent_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), ++ 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Project']", 'null': 'True', 'blank': 'True'}), ++ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}), ++ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '128'}), ++ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}) ++ }, ++ 'catalogue.bookpublishrecord': { ++ 'Meta': {'ordering': "['-timestamp']", 'object_name': 'BookPublishRecord'}, ++ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.Book']"}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), ++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) ++ }, ++ 'catalogue.chunk': { ++ 'Meta': {'ordering': "['number']", 'unique_together': "[['book', 'number'], ['book', 'slug']]", 'object_name': 'Chunk'}, ++ '_changed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), ++ '_hidden': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), ++ '_short_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), ++ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Book']"}), ++ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_chunk'", 'null': 'True', 'to': u"orm['auth.User']"}), ++ 'gallery_start': ('django.db.models.fields.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}), ++ 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['catalogue.ChunkChange']", 'null': 'True', 'blank': 'True'}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'number': ('django.db.models.fields.IntegerField', [], {}), ++ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), ++ 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.ChunkTag']", 'null': 'True', 'blank': 'True'}), ++ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), ++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}) ++ }, ++ 'catalogue.chunkchange': { ++ 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'ChunkChange'}, ++ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), ++ 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), ++ 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), ++ 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), ++ 'data': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), ++ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ChunkChange']"}), ++ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ChunkChange']"}), ++ 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), ++ 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), ++ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'change_set'", 'symmetrical': 'False', 'to': "orm['catalogue.ChunkTag']"}), ++ 'tree': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'change_set'", 'to': "orm['catalogue.Chunk']"}) ++ }, ++ 'catalogue.chunkpublishrecord': { ++ 'Meta': {'object_name': 'ChunkPublishRecord'}, ++ 'book_record': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.BookPublishRecord']"}), ++ 'change': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.ChunkChange']"}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) ++ }, ++ 'catalogue.chunktag': { ++ 'Meta': {'ordering': "['ordering']", 'object_name': 'ChunkTag'}, ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), ++ 'ordering': ('django.db.models.fields.IntegerField', [], {}), ++ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}) ++ }, ++ 'catalogue.image': { ++ 'Meta': {'ordering': "['title']", 'object_name': 'Image'}, ++ '_changed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), ++ '_new_publishable': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), ++ '_published': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), ++ '_short_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), ++ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_image'", 'null': 'True', 'to': u"orm['auth.User']"}), ++ 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['catalogue.ImageChange']", 'null': 'True', 'blank': 'True'}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'image': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), ++ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}), ++ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}), ++ 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.ImageTag']", 'null': 'True', 'blank': 'True'}), ++ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), ++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}) ++ }, ++ 'catalogue.imagechange': { ++ 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'ImageChange'}, ++ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), ++ 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), ++ 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), ++ 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), ++ 'data': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), ++ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ImageChange']"}), ++ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ImageChange']"}), ++ 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), ++ 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), ++ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'change_set'", 'symmetrical': 'False', 'to': "orm['catalogue.ImageTag']"}), ++ 'tree': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'change_set'", 'to': "orm['catalogue.Image']"}) ++ }, ++ 'catalogue.imagepublishrecord': { ++ 'Meta': {'ordering': "['-timestamp']", 'object_name': 'ImagePublishRecord'}, ++ 'change': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.ImageChange']"}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'image': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.Image']"}), ++ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), ++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) ++ }, ++ 'catalogue.imagetag': { ++ 'Meta': {'ordering': "['ordering']", 'object_name': 'ImageTag'}, ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), ++ 'ordering': ('django.db.models.fields.IntegerField', [], {}), ++ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}) ++ }, ++ 'catalogue.project': { ++ 'Meta': {'ordering': "['name']", 'object_name': 'Project'}, ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), ++ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) ++ }, ++ u'contenttypes.contenttype': { ++ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, ++ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), ++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) ++ }, ++ u'cover.image': { ++ 'Meta': {'object_name': 'Image'}, ++ 'author': ('django.db.models.fields.CharField', [], {'max_length': '255'}), ++ 'download_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'blank': 'True'}), ++ 'file': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), ++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), ++ 'license_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), ++ 'license_url': ('django.db.models.fields.URLField', [], {'max_length': '255', 'blank': 'True'}), ++ 'source_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), ++ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) ++ } ++ } ++ ++ complete_apps = ['catalogue'] diff --combined apps/catalogue/models/__init__.py index 08cedd00,bd069f1c..d0015c79 --- a/apps/catalogue/models/__init__.py +++ b/apps/catalogue/models/__init__.py @@@ -3,10 -3,9 +3,11 @@@ # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # + from catalogue.models.project import Project from catalogue.models.chunk import Chunk -from catalogue.models.publish_log import BookPublishRecord, ChunkPublishRecord +from catalogue.models.image import Image +from catalogue.models.publish_log import (BookPublishRecord, + ChunkPublishRecord, ImagePublishRecord) from catalogue.models.book import Book from catalogue.models.listeners import * diff --combined apps/catalogue/models/image.py index 558f4c1f,00000000..7b5ce1f2 mode 100755,000000..100755 --- a/apps/catalogue/models/image.py +++ b/apps/catalogue/models/image.py @@@ -1,157 -1,0 +1,165 @@@ +# -*- coding: utf-8 -*- +# +# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# +from django.conf import settings +from django.contrib.sites.models import Site +from django.db import models +from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ +from catalogue.helpers import cached_in_field +from catalogue.tasks import refresh_instance +from dvcs import models as dvcs_models + + +class Image(dvcs_models.Document): + """ An editable chunk of text. Every Book text is divided into chunks. """ + REPO_PATH = settings.CATALOGUE_IMAGE_REPO_PATH + + image = models.FileField(_('image'), upload_to='catalogue/images') + title = models.CharField(_('title'), max_length=255, blank=True) + slug = models.SlugField(_('slug'), unique=True) + public = models.BooleanField(_('public'), default=True, db_index=True) + + # cache + _short_html = models.TextField(null=True, blank=True, editable=False) + _new_publishable = models.NullBooleanField(editable=False) + _published = models.NullBooleanField(editable=False) + _changed = models.NullBooleanField(editable=False) + + class Meta: + app_label = 'catalogue' + ordering = ['title'] + verbose_name = _('image') + verbose_name_plural = _('images') + permissions = [('can_pubmark_image', 'Can mark images for publishing')] + + # Representing + # ============ + + def __unicode__(self): + return self.title + + @models.permalink + def get_absolute_url(self): + return ("catalogue_image", [self.slug]) + + def correct_about(self): + return "http://%s%s" % ( + Site.objects.get_current().domain, + self.get_absolute_url() + ) + + # State & cache + # ============= + + def last_published(self): + try: + return self.publish_log.all()[0].timestamp + except IndexError: + return None + + def assert_publishable(self): + from librarian.picture import WLPicture + from librarian import NoDublinCore, ParseError, ValidationError + + class SelfImageStore(object): + def path(self_, slug, mime_type): + """Returns own file object. Ignores slug ad mime_type.""" + return open(self.image.path) + + publishable = self.publishable() + assert publishable, _("There is no publishable revision") + picture_xml = publishable.materialize() + + try: + picture = WLPicture.from_string(picture_xml.encode('utf-8'), + image_store=SelfImageStore) + except ParseError, e: + raise AssertionError(_('Invalid XML') + ': ' + str(e)) + except NoDublinCore: + raise AssertionError(_('No Dublin Core found.')) + except ValidationError, e: + raise AssertionError(_('Invalid Dublin Core') + ': ' + str(e)) + + valid_about = self.correct_about() + assert picture.picture_info.about == valid_about, \ + _("rdf:about is not") + " " + valid_about + ++ def publishable_error(self): ++ try: ++ return self.assert_publishable() ++ except AssertionError, e: ++ return e ++ else: ++ return None ++ + def accessible(self, request): + return self.public or request.user.is_authenticated() + + def is_new_publishable(self): + change = self.publishable() + if not change: + return False + return not change.publish_log.exists() + new_publishable = cached_in_field('_new_publishable')(is_new_publishable) + + def is_published(self): + return self.publish_log.exists() + published = cached_in_field('_published')(is_published) + + def is_changed(self): + if self.head is None: + return False + return not self.head.publishable + changed = cached_in_field('_changed')(is_changed) + + @cached_in_field('_short_html') + def short_html(self): + return render_to_string( + 'catalogue/image_short.html', {'image': self}) + + def refresh(self): + """This should be done offline.""" + self.short_html + self.single + self.new_publishable + self.published + + def touch(self): + update = { + "_changed": self.is_changed(), + "_short_html": None, + "_new_publishable": self.is_new_publishable(), + "_published": self.is_published(), + } + Image.objects.filter(pk=self.pk).update(**update) + refresh_instance(self) + + def refresh(self): + """This should be done offline.""" + self.changed + self.short_html + + + # Publishing + # ========== + + def publish(self, user): + """Publishes the picture on behalf of a (local) user.""" + from base64 import b64encode + import apiclient + from catalogue.signals import post_publish + + self.assert_publishable() + change = self.publishable() + picture_xml = change.materialize() + picture_data = open(self.image.path).read() + apiclient.api_call(user, "pictures/", { + "picture_xml": picture_xml, + "picture_image_data": b64encode(picture_data), + }) + # record the publish + log = self.publish_log.create(user=user, change=change) + post_publish.send(sender=log) diff --combined apps/catalogue/templates/catalogue/activity.html index 125ae28e,c88b5388..3bb8afb2 --- a/apps/catalogue/templates/catalogue/activity.html +++ b/apps/catalogue/templates/catalogue/activity.html @@@ -1,12 -1,8 +1,11 @@@ {% extends "catalogue/base.html" %} {% load i18n %} - {% load url from future %} {% load wall %} +{% block titleextra %}{% trans "Activity" %}{% endblock %} + + {% block content %}

< diff --combined apps/catalogue/templates/catalogue/base.html index 78a8ee51,d2af462b..9a56d726 --- a/apps/catalogue/templates/catalogue/base.html +++ b/apps/catalogue/templates/catalogue/base.html @@@ -2,18 -2,18 +2,19 @@@ {% load catalogue %} - + {% compressed_css 'catalogue' %} - {% block title %}{% trans "Platforma Redakcyjna" %}{% endblock title %} + {% block title %}{% trans "Platforma Redakcyjna" %} :: + {% block titleextra %}{% endblock %}{% endblock title %} + {% block add_css %}{% endblock %}
- + - +
@@@ -43,8 -43,9 +44,9 @@@
- + {% compressed_js 'catalogue' %} + {% block add_js %}{% endblock %} {% block extrabody %} {% endblock %} diff --combined apps/catalogue/templates/catalogue/book_detail.html index cbc6c32a,eea6a6c7..4db8a9be --- a/apps/catalogue/templates/catalogue/book_detail.html +++ b/apps/catalogue/templates/catalogue/book_detail.html @@@ -1,10 -1,6 +1,10 @@@ {% extends "catalogue/base.html" %} {% load book_list comments i18n %} + +{% block titleextra %}{{ book.title }}{% endblock %} + + {% block content %} @@@ -20,9 -16,12 +20,12 @@@ {% if editable %}{% endif %} - {% if editable %} -

{% trans "Append to other book" %}

+ {% if book.gallery %} +

{% trans "Edit gallery" %}

+ {% endif %} + +

{% trans "Append to other book" %}

{% endif %} @@@ -45,6 -44,13 +48,13 @@@

{% trans "Publication" %}

+
+ + {% if book.dc_cover_image %} + {{ book.dc_cover_image }} + {% endif %} +
+

{% trans "Last published" %}: {% if book.last_published %} {{ book.last_published }} @@@ -55,11 -61,11 +65,11 @@@ {% if publishable %}

- {% trans "Full XML" %}
- {% trans "HTML version" %}
- {% trans "TXT version" %}
- {% trans "PDF version" %}
- {% trans "EPUB version" %}
+ {% trans "Full XML" %}
+ {% trans "HTML version" %}
+ {% trans "TXT version" %}
+ {% trans "PDF version" %}
+ {% trans "EPUB version" %}

{% if user.is_authenticated %} @@@ -69,20 -75,21 +79,21 @@@ mira66 (http://www.flickr.com/photos/21804434@N02/) / CC BY 2.0 (http://creativecommons.org/licenses/by/2.0/) --> -
{% csrf_token %} + {% csrf_token %}
{% else %} - {% trans "Log in to publish." %} + {% trans "Log in to publish." %} {% endif %} {% else %}

{% trans "This book can't be published yet, because:" %}

  • {{ publishable_error }}
{% endif %} +
diff --combined apps/catalogue/templates/catalogue/book_list/book_list.html index f8d18d57,90ae183f..8e254363 --- a/apps/catalogue/templates/catalogue/book_list/book_list.html +++ b/apps/catalogue/templates/catalogue/book_list/book_list.html @@@ -2,7 -2,7 +2,7 @@@ {% load pagination_tags %} -
+ {% if not viewed_user %} @@@ -10,10 -10,13 +10,13 @@@ {% endif %} +
+ + + {% else %} + {% endif %} + + {% with cnt=books|length %} @@@ -72,7 -83,7 +85,7 @@@ {% endif %} {% endwith %} {% endfor %} - @@@ -81,3 -92,22 +94,22 @@@ {% if not books %}

{% trans "No books found." %}

{% endif %} + + + {% csrf_token %} + + + + + + + + + + + diff --combined apps/catalogue/templates/catalogue/chunk_edit.html index cac192a2,3c1f3bf5..20062265 --- a/apps/catalogue/templates/catalogue/chunk_edit.html +++ b/apps/catalogue/templates/catalogue/chunk_edit.html @@@ -1,11 -1,6 +1,10 @@@ {% extends "catalogue/base.html" %} - {% load url from future %} {% load i18n %} + +{% block titleextra %}{% trans "Chunk settings" %}{% endblock %} + + {% block content %}

{% trans "Chunk settings" %}

diff --combined apps/catalogue/templates/catalogue/document_list.html index 2d608dcf,294c6299..f0bd50c8 --- a/apps/catalogue/templates/catalogue/document_list.html +++ b/apps/catalogue/templates/catalogue/document_list.html @@@ -2,10 -2,17 +2,19 @@@ {% load i18n %} {% load catalogue book_list %} + {% load compressed %} +{% block titleextra %}{% trans "Book list" %}{% endblock %} + + {% block add_js %} + {% compressed_js 'book_list' %} + {% endblock %} + + {% block add_css %} + {% compressed_css 'book_list' %} + {% endblock %} + {% block content %} {% book_list %} {% endblock content %} diff --combined apps/catalogue/templates/catalogue/document_upload.html index 0f8929cc,18637749..009d1540 --- a/apps/catalogue/templates/catalogue/document_upload.html +++ b/apps/catalogue/templates/catalogue/document_upload.html @@@ -2,9 -2,6 +2,9 @@@ {% load i18n %} +{% block titleextra %}{% trans "Bulk document upload" %}{% endblock %} + + {% block leftcolumn %} @@@ -14,7 -11,7 +14,7 @@@ {% trans "Please submit a ZIP with UTF-8 encoded XML files. Files not ending with .xml will be ignored." %}

- + {% csrf_token %} {{ form.as_p }}

@@@ -48,7 -45,7 +48,7 @@@

{% trans "Uploaded files" %}

    {% for filename, slug, title in ok_list %} -
  • {{ title }} ({{ filename }})
  • +
  • {{ title }} ({{ filename }})
  • {% endfor %}
{% endif %} diff --combined apps/catalogue/templates/catalogue/image_detail.html index cd77654f,00000000..d791bfd8 mode 100755,000000..100755 --- a/apps/catalogue/templates/catalogue/image_detail.html +++ b/apps/catalogue/templates/catalogue/image_detail.html @@@ -1,80 -1,0 +1,80 @@@ +{% extends "catalogue/base.html" %} +{% load book_list comments i18n %} + + +{% block titleextra %}{{ object.title }}{% endblock %} + + +{% block content %} + + +

{{ object.title }}

+ + +{% if editable %}{% csrf_token %}{% endif %} +
{{ user.first_name }} {{ user.last_name }} ({{ user.count }}) {% endfor %}
+
{% paginate %} {% blocktrans count c=cnt %}{{c}} book{% plural %}{{c}} books{% endblocktrans %}
+ {{ form.as_table }} + {% if editable %} + + {% endif %} +
+{% if editable %}{% endif %} + + + + + + + +
+ + +

{% trans "Publication" %}

+ +

{% trans "Last published" %}: + {% if object.last_published %} + {{ object.last_published }} + {% else %} + — + {% endif %} +

+ +{% if publishable %} + {% if user.is_authenticated %} + -
{% csrf_token %} ++ {% csrf_token %} + + + +
+ {% else %} - {% trans "Log in to publish." %} ++ {% trans "Log in to publish." %} + {% endif %} +{% else %} +

{% trans "This book can't be published yet, because:" %}

+
  • {{ publishable_error }}
+{% endif %} + +
+ + +
+

{% trans "Comments" %}

+ + {% render_comment_list for object %} + {% with object.get_absolute_url as next %} + {% render_comment_form for object %} + {% endwith %} +
+ +{% endblock content %} diff --combined apps/catalogue/templates/catalogue/image_short.html index 2e2b386c,00000000..e64733b6 mode 100755,000000..100755 --- a/apps/catalogue/templates/catalogue/image_short.html +++ b/apps/catalogue/templates/catalogue/image_short.html @@@ -1,18 -1,0 +1,18 @@@ +{% load i18n %} + + - [B] ++ [B] + ++ href="{% url 'wiki_img_editor' image.slug %}"> + {{ image.title }} + {% if image.stage %} + {{ image.stage }} + {% else %}– + {% endif %} - {% if image.user %}{{ image.user.first_name }} {{ image.user.last_name }}{% endif %} ++ {% if image.user %}{{ image.user.first_name }} {{ image.user.last_name }}{% endif %} + + {% if image.published %}P{% endif %} + {% if image.new_publishable %}p{% endif %} + {% if image.changed %}+{% endif %} + + diff --combined apps/catalogue/templates/catalogue/my_page.html index 07b92422,fd4e84ef..c6b61ce8 --- a/apps/catalogue/templates/catalogue/my_page.html +++ b/apps/catalogue/templates/catalogue/my_page.html @@@ -2,11 -2,16 +2,19 @@@ {% load i18n %} {% load catalogue book_list wall %} + {% load compressed %} + {% block add_js %} + {% compressed_js 'book_list' %} + {% endblock %} + + {% block add_css %} + {% compressed_css 'book_list' %} + {% endblock %} +{% block titleextra %}{% trans "My page" %}{% endblock %} + + {% block leftcolumn %} {% book_list request.user %} {% endblock leftcolumn %} @@@ -16,7 -21,7 +24,7 @@@

{% trans "Your last edited documents" %}

    {% for slugs, item in last_books %} -
  1. {{ item.title }}
    ({{ item.time|date:"H:i:s, d/m/Y" }})
  2. {% endfor %}
diff --combined apps/catalogue/templates/catalogue/user_list.html index bc8af637,c4b1dfc4..26434053 --- a/apps/catalogue/templates/catalogue/user_list.html +++ b/apps/catalogue/templates/catalogue/user_list.html @@@ -2,17 -2,13 +2,17 @@@ {% load i18n %} + +{% block titleextra %}{% trans "Users" %}{% endblock %} + + {% block leftcolumn %}

{% trans "Users" %}

    {% for user in users %} -
  • +
  • {{ forloop.counter }}. {{ user.first_name }} {{ user.last_name }} ({{ user.count }})
  • diff --combined apps/catalogue/templates/catalogue/wall.html index c277f940,25550fe6..d7f6c9e6 --- a/apps/catalogue/templates/catalogue/wall.html +++ b/apps/catalogue/templates/catalogue/wall.html @@@ -7,8 -7,7 +7,8 @@@
  • {% if item.get_email %} - {% gravatar_img_for_email item.get_email 32 %} + Avatar
    {% endif %}
    @@@ -18,7 -17,7 +18,7 @@@ {{ item.title }}
    {% trans "user" %}: {% if item.user %} - + {{ item.user.first_name }} {{ item.user.last_name }} <{{ item.user.email|email_link }}> {% else %} diff --combined apps/catalogue/templatetags/book_list.py index 9344053b,14149e84..1357c321 --- a/apps/catalogue/templatetags/book_list.py +++ b/apps/catalogue/templatetags/book_list.py @@@ -5,7 -5,7 +5,7 @@@ from django.db.models import Q, Coun from django import template from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User - from catalogue.models import Chunk, Image -from catalogue.models import Chunk, Project ++from catalogue.models import Chunk, Image, Project register = template.Library() @@@ -113,6 -113,7 +113,7 @@@ def document_list_filter(request, **kwa chunks = foreign_filter(chunks, arg_or_GET('user'), 'user', User, 'username') chunks = foreign_filter(chunks, arg_or_GET('stage'), 'stage', Chunk.tag_model, 'slug') chunks = search_filter(chunks, arg_or_GET('title'), ['book__title', 'title']) + chunks = foreign_filter(chunks, arg_or_GET('project'), 'book__project', Project, 'pk') return chunks @@@ -125,9 -126,14 +126,14 @@@ def book_list(context, user=None) new_context = {"viewed_user": user} else: filters = {} - new_context = {"users": User.objects.annotate( + new_context = { + "users": User.objects.annotate( count=Count('chunk')).filter(count__gt=0).order_by( - '-count', 'last_name', 'first_name')} + '-count', 'last_name', 'first_name'), + "other_users": User.objects.annotate( + count=Count('chunk')).filter(count=0).order_by( + 'last_name', 'first_name'), + } new_context.update({ "filters": True, @@@ -135,61 -141,7 +141,62 @@@ "books": ChunksList(document_list_filter(request, **filters)), "stages": Chunk.tag_model.objects.all(), "states": _states_options, + "projects": Project.objects.all(), }) return new_context + + + +_image_states = [ + ('publishable', _('publishable'), Q(_new_publishable=True)), + ('changed', _('changed'), Q(_changed=True)), + ('published', _('published'), Q(_published=True)), + ('unpublished', _('unpublished'), Q(_published=False)), + ('empty', _('empty'), Q(head=None)), + ] +_image_states_options = [s[:2] for s in _image_states] +_image_states_dict = dict([(s[0], s[2]) for s in _image_states]) + +def image_list_filter(request, **kwargs): + + def arg_or_GET(field): + return kwargs.get(field, request.GET.get(field)) + + images = Image.objects.all() + + if not request.user.is_authenticated(): + images = images.filter(public=True) + + state = arg_or_GET('status') + if state in _image_states_dict: + images = images.filter(_image_states_dict[state]) + + images = foreign_filter(images, arg_or_GET('user'), 'user', User, 'username') + images = foreign_filter(images, arg_or_GET('stage'), 'stage', Image.tag_model, 'slug') + images = search_filter(images, arg_or_GET('title'), ['title', 'title']) + return images + + +@register.inclusion_tag('catalogue/image_table.html', takes_context=True) +def image_list(context, user=None): + request = context['request'] + + if user: + filters = {"user": user} + new_context = {"viewed_user": user} + else: + filters = {} + new_context = {"users": User.objects.annotate( + count=Count('image')).filter(count__gt=0).order_by( + '-count', 'last_name', 'first_name')} + + new_context.update({ + "filters": True, + "request": request, + "objects": image_list_filter(request, **filters), + "stages": Image.tag_model.objects.all(), + "states": _image_states_options, + }) + + return new_context diff --combined apps/catalogue/templatetags/catalogue.py index 0b57b498,8d5ff65b..07c5cf9d --- a/apps/catalogue/templatetags/catalogue.py +++ b/apps/catalogue/templatetags/catalogue.py @@@ -28,13 -28,14 +28,15 @@@ def main_tabs(context) tabs.append(Tab('activity', _('Activity'), reverse("catalogue_activity"))) tabs.append(Tab('all', _('All'), reverse("catalogue_document_list"))) + tabs.append(Tab('images', _('Images'), reverse("catalogue_image_list"))) tabs.append(Tab('users', _('Users'), reverse("catalogue_users"))) if user.has_perm('catalogue.add_book'): tabs.append(Tab('create', _('Add'), reverse("catalogue_create_missing"))) tabs.append(Tab('upload', _('Upload'), reverse("catalogue_upload"))) + tabs.append(Tab('cover', _('Covers'), reverse("cover_image_list"))) + return {"tabs": tabs, "active_tab": active} diff --combined apps/catalogue/urls.py index 31df1c19,e72b88db..3627bf04 --- a/apps/catalogue/urls.py +++ b/apps/catalogue/urls.py @@@ -1,16 -1,14 +1,19 @@@ # -*- coding: utf-8 - from django.conf.urls.defaults import * - from django.views.generic.simple import redirect_to + from django.conf.urls import patterns, url + from django.contrib.auth.decorators import permission_required + from django.views.generic import RedirectView + from catalogue.feeds import PublishTrackFeed + from catalogue.views import GalleryView urlpatterns = patterns('catalogue.views', - url(r'^$', redirect_to, {'url': 'catalogue/'}), + url(r'^$', RedirectView.as_view(url='catalogue/')), + url(r'^images/$', 'image_list', name='catalogue_image_list'), + url(r'^image/(?P[^/]+)/$', 'image', name="catalogue_image"), + url(r'^image/(?P[^/]+)/publish$', 'publish_image', + name="catalogue_publish_image"), + url(r'^catalogue/$', 'document_list', name='catalogue_document_list'), url(r'^user/$', 'my', name='catalogue_user'), url(r'^user/(?P[^/]+)/$', 'user', name='catalogue_user'), @@@ -28,18 -26,26 +31,25 @@@ 'create_missing', name='catalogue_create_missing'), url(r'^book/(?P[^/]+)/publish$', 'publish', name="catalogue_publish"), - #url(r'^(?P[^/]+)/publish/(?P\d+)$', 'publish', name="catalogue_publish"), url(r'^book/(?P[^/]+)/$', 'book', name="catalogue_book"), + url(r'^book/(?P[^/]+)/gallery/$', + permission_required('catalogue.change_book')(GalleryView.as_view()), + name="catalogue_book_gallery"), url(r'^book/(?P[^/]+)/xml$', 'book_xml', name="catalogue_book_xml"), url(r'^book/(?P[^/]+)/txt$', 'book_txt', name="catalogue_book_txt"), url(r'^book/(?P[^/]+)/html$', 'book_html', name="catalogue_book_html"), url(r'^book/(?P[^/]+)/epub$', 'book_epub', name="catalogue_book_epub"), url(r'^book/(?P[^/]+)/pdf$', 'book_pdf', name="catalogue_book_pdf"), + url(r'^chunk_add/(?P[^/]+)/(?P[^/]+)/$', 'chunk_add', name="catalogue_chunk_add"), url(r'^chunk_edit/(?P[^/]+)/(?P[^/]+)/$', 'chunk_edit', name="catalogue_chunk_edit"), url(r'^book_append/(?P[^/]+)/$', 'book_append', name="catalogue_book_append"), + url(r'^chunk_mass_edit', + 'chunk_mass_edit', name='catalogue_chunk_mass_edit'), + url(r'^track/(?P[^/]*)/$', PublishTrackFeed()), ) diff --combined apps/catalogue/views.py index ed5b15f2,ebc35751..01e4d1fa --- a/apps/catalogue/views.py +++ b/apps/catalogue/views.py @@@ -5,27 -5,28 +5,28 @@@ from StringIO import StringI from urllib import unquote from urlparse import urlsplit, urlunsplit + from django.conf import settings from django.contrib import auth from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required, permission_required from django.core.urlresolvers import reverse from django.db.models import Count, Q + from django.db import transaction from django import http from django.http import Http404, HttpResponse, HttpResponseForbidden -from django.shortcuts import get_object_or_404, render, render_to_response +from django.shortcuts import get_object_or_404, render from django.utils.encoding import iri_to_uri from django.utils.http import urlquote_plus from django.utils.translation import ugettext_lazy as _ from django.views.decorators.http import require_POST - from django.views.generic.simple import direct_to_template -from django.template import RequestContext from apiclient import NotAuthorizedError from catalogue import forms from catalogue import helpers from catalogue.helpers import active_tab -from catalogue.models import Book, Chunk, BookPublishRecord, ChunkPublishRecord, Project +from catalogue.models import (Book, Chunk, Image, BookPublishRecord, - ChunkPublishRecord, ImagePublishRecord) - from catalogue.tasks import publishable_error ++ ChunkPublishRecord, ImagePublishRecord, Project) + from fileupload.views import UploadView # # Quick hack around caching problems, TODO: use ETags @@@ -41,12 -42,6 +42,12 @@@ def document_list(request) return render(request, 'catalogue/document_list.html') +@active_tab('images') +@never_cache +def image_list(request, user=None): + return render(request, 'catalogue/image_list.html') + + @never_cache def user(request, username): user = get_object_or_404(User, username=username) @@@ -67,7 -62,7 +68,7 @@@ def my(request) @active_tab('users') def users(request): - return direct_to_template(request, 'catalogue/user_list.html', extra_context={ + return render(request, 'catalogue/user_list.html', { 'users': User.objects.all().annotate(count=Count('chunk')).order_by( '-count', 'last_name', 'first_name'), }) @@@ -127,7 -122,7 +128,7 @@@ def create_missing(request, slug=None) "gallery": slug, }) - return direct_to_template(request, "catalogue/document_create_missing.html", extra_context={ + return render(request, "catalogue/document_create_missing.html", { "slug": slug, "form": form, @@@ -182,7 -177,7 +183,7 @@@ def upload(request) title=title, ) - return direct_to_template(request, "catalogue/document_upload.html", extra_context={ + return render(request, "catalogue/document_upload.html", { "form": form, "ok_list": ok_list, "skipped_list": skipped_list, @@@ -193,7 -188,7 +194,7 @@@ else: form = forms.DocumentsUploadForm() - return direct_to_template(request, "catalogue/document_upload.html", extra_context={ + return render(request, "catalogue/document_upload.html", { "form": form, "logout_to": '/', @@@ -217,13 -212,9 +218,9 @@@ def book_txt(request, slug) book = get_object_or_404(Book, slug=slug) if not book.accessible(request): return HttpResponseForbidden("Not authorized.") - xml = book.materialize() - output = StringIO() - # errors? - import librarian.text - librarian.text.transform(StringIO(xml), output) - text = output.getvalue() + doc = book.wldocument() + text = doc.as_text().get_string() response = http.HttpResponse(text, content_type='text/plain', mimetype='text/plain') response['Content-Disposition'] = 'attachment; filename=%s.txt' % slug return response @@@ -234,16 -225,22 +231,21 @@@ def book_html(request, slug) book = get_object_or_404(Book, slug=slug) if not book.accessible(request): return HttpResponseForbidden("Not authorized.") - xml = book.materialize() - output = StringIO() - # errors? - - import librarian.html - librarian.html.transform(StringIO(xml), output, parse_dublincore=False, - flags=['full-page']) - html = output.getvalue() - response = http.HttpResponse(html, content_type='text/html', mimetype='text/html') - return response + + doc = book.wldocument(parse_dublincore=False) + html = doc.as_html() + + html = html.get_string() if html is not None else '' + # response = http.HttpResponse(html, content_type='text/html', mimetype='text/html') + # return response + # book_themes = {} + # for fragment in book.fragments.all().iterator(): + # for theme in fragment.tags.filter(category='theme').iterator(): + # book_themes.setdefault(theme, []).append(fragment) + + # book_themes = book_themes.items() + # book_themes.sort(key=lambda s: s[0].sort_key) - return render_to_response('catalogue/book_text.html', locals(), - context_instance=RequestContext(request)) ++ return render(request, 'catalogue/book_text.html', locals()) @never_cache @@@ -252,25 -249,13 +254,13 @@@ def book_pdf(request, slug) if not book.accessible(request): return HttpResponseForbidden("Not authorized.") - from tempfile import NamedTemporaryFile - from os import unlink - from librarian import pdf - from catalogue.ebook_utils import RedakcjaDocProvider, serve_file - - xml = book.materialize() - xml_file = NamedTemporaryFile() - xml_file.write(xml.encode('utf-8')) - xml_file.flush() - - try: - pdf_file = NamedTemporaryFile(delete=False) - pdf.transform(RedakcjaDocProvider(publishable=True), - file_path=xml_file.name, - output_file=pdf_file, - ) - return serve_file(pdf_file.name, book.slug + '.pdf', 'application/pdf') - finally: - unlink(pdf_file.name) + # TODO: move to celery + doc = book.wldocument() + # TODO: error handling + pdf_file = doc.as_pdf() + from catalogue.ebook_utils import serve_file + return serve_file(pdf_file.get_filename(), + book.slug + '.pdf', 'application/pdf') @never_cache @@@ -279,23 -264,13 +269,13 @@@ def book_epub(request, slug) if not book.accessible(request): return HttpResponseForbidden("Not authorized.") - from StringIO import StringIO - from tempfile import NamedTemporaryFile - from librarian import epub - from catalogue.ebook_utils import RedakcjaDocProvider - - xml = book.materialize() - xml_file = NamedTemporaryFile() - xml_file.write(xml.encode('utf-8')) - xml_file.flush() - - epub_file = StringIO() - epub.transform(RedakcjaDocProvider(publishable=True), - file_path=xml_file.name, - output_file=epub_file) + # TODO: move to celery + doc = book.wldocument() + # TODO: error handling + epub = doc.as_epub().get_string() response = HttpResponse(mimetype='application/epub+zip') response['Content-Disposition'] = 'attachment; filename=%s' % book.slug + '.epub' - response.write(epub_file.getvalue()) + response.write(epub) return response @@@ -323,15 -298,15 +303,15 @@@ def book(request, slug) return http.HttpResponseRedirect(book.get_absolute_url()) else: form = forms.BookForm(instance=book) - editable = True + editable = True else: form = forms.ReadonlyBookForm(instance=book) editable = False - publish_error = publishable_error(book) + publish_error = book.publishable_error() publishable = publish_error is None - return direct_to_template(request, "catalogue/book_detail.html", extra_context={ + return render(request, "catalogue/book_detail.html", { "book": book, "publishable": publishable, "publishable_error": publish_error, @@@ -340,36 -315,6 +320,36 @@@ }) +def image(request, slug): + image = get_object_or_404(Image, slug=slug) + if not image.accessible(request): + return HttpResponseForbidden("Not authorized.") + + if request.user.has_perm('catalogue.change_image'): + if request.method == "POST": + form = forms.ImageForm(request.POST, instance=image) + if form.is_valid(): + form.save() + return http.HttpResponseRedirect(image.get_absolute_url()) + else: + form = forms.ImageForm(instance=image) + editable = True + else: + form = forms.ReadonlyImageForm(instance=image) + editable = False + - publish_error = publishable_error(image) ++ publish_error = image.publishable_error() + publishable = publish_error is None + - return direct_to_template(request, "catalogue/image_detail.html", extra_context={ ++ return render(request, "catalogue/image_detail.html", { + "object": image, + "publishable": publishable, + "publishable_error": publish_error, + "form": form, + "editable": editable, + }) + + @permission_required('catalogue.add_chunk') def chunk_add(request, slug, chunk): try: @@@ -401,12 -346,13 +381,13 @@@ "title": "cz. %d" % (doc.number + 1, ), }) - return direct_to_template(request, "catalogue/chunk_add.html", extra_context={ + return render(request, "catalogue/chunk_add.html", { "chunk": doc, "form": form, }) + @login_required def chunk_edit(request, slug, chunk): try: doc = Chunk.get(slug, chunk) @@@ -436,13 -382,73 +417,73 @@@ else: go_next = '' - return direct_to_template(request, "catalogue/chunk_edit.html", extra_context={ + return render(request, "catalogue/chunk_edit.html", { "chunk": doc, "form": form, "go_next": go_next, }) + @transaction.commit_on_success + @login_required + def chunk_mass_edit(request): + if request.method == 'POST': + ids = map(int, filter(lambda i: i.strip()!='', request.POST.get('ids').split(','))) + chunks = map(lambda i: Chunk.objects.get(id=i), ids) + + stage = request.POST.get('stage') + if stage: + try: + stage = Chunk.tag_model.objects.get(slug=stage) + except Chunk.DoesNotExist, e: + stage = None + + for c in chunks: c.stage = stage + + username = request.POST.get('user') + logger.info("username: %s" % username) + logger.info(request.POST) + if username: + try: + user = User.objects.get(username=username) + except User.DoesNotExist, e: + user = None + + for c in chunks: c.user = user + + status = request.POST.get('status') + if status: + books_affected = set() + for c in chunks: + if status == 'publish': + c.head.publishable = True + c.head.save() + elif status == 'unpublish': + c.head.publishable = False + c.head.save() + c.touch() # cache + books_affected.add(c.book) + for b in books_affected: + b.touch() # cache + + project_id = request.POST.get('project') + if project_id: + try: + project = Project.objects.get(pk=int(project_id)) + except (Project.DoesNotExist, ValueError), e: + project = None + for c in chunks: + book = c.book + book.project = project + book.save() + + for c in chunks: c.save() + + return HttpResponse("", content_type="text/plain") + else: + raise Http404 + + @permission_required('catalogue.change_book') def book_append(request, slug): book = get_object_or_404(Book, slug=slug) @@@ -457,7 -463,7 +498,7 @@@ return http.HttpResponseRedirect(append_to.get_absolute_url()) else: form = forms.BookAppendForm(book) - return direct_to_template(request, "catalogue/book_append_to.html", extra_context={ + return render(request, "catalogue/book_append_to.html", { "book": book, "form": form, @@@ -482,18 -488,19 +523,36 @@@ def publish(request, slug) return http.HttpResponseRedirect(book.get_absolute_url()) +@require_POST +@login_required +def publish_image(request, slug): + image = get_object_or_404(Image, slug=slug) + if not image.accessible(request): + return HttpResponseForbidden("Not authorized.") + + try: + image.publish(request.user) + except NotAuthorizedError: + return http.HttpResponseRedirect(reverse('apiclient_oauth')) + except BaseException, e: + return http.HttpResponse(e) + else: + return http.HttpResponseRedirect(image.get_absolute_url()) ++ ++ + class GalleryView(UploadView): + def get_object(self, request, slug): + book = get_object_or_404(Book, slug=slug) + if not book.gallery: + raise Http404 + return book + + def breadcrumbs(self): + return [ + (_('books'), reverse('catalogue_document_list')), + (self.object.title, self.object.get_absolute_url()), + (_('scan gallery'),), + ] + + def get_directory(self): + return "%s%s/" % (settings.IMAGE_DIR, self.object.gallery) diff --combined apps/dvcs/models.py index 2526028f,cf8d75dc..ec647946 --- a/apps/dvcs/models.py +++ b/apps/dvcs/models.py @@@ -6,8 -6,8 +6,8 @@@ from django.core.files.base import Cont from django.core.files.storage import FileSystemStorage from django.db import models, transaction from django.db.models.base import ModelBase -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import string_concat, ugettext_lazy as _ - from mercurial import mdiff, simplemerge + from mercurial import simplemerge from django.conf import settings from dvcs.signals import post_commit, post_publishable @@@ -26,6 -26,8 +26,6 @@@ class Tag(models.Model) class Meta: abstract = True ordering = ['ordering'] - verbose_name = _("tag") - verbose_name_plural = _("tags") def __unicode__(self): return self.name @@@ -43,7 -45,7 +43,7 @@@ def listener_changed(sender, instance, **kwargs): sender._object_cache = {} - def next(self): + def get_next(self): """ Returns the next tag - stage to work on. Returns None for the last stage. @@@ -97,6 -99,8 +97,6 @@@ class Change(models.Model) abstract = True ordering = ('created_at',) unique_together = ['tree', 'revision'] - verbose_name = _("change") - verbose_name_plural = _("changes") def __unicode__(self): return u"Id: %r, Tree %r, Parent %r, Data: %s" % (self.id, self.tree_id, self.parent_id, self.data) @@@ -166,17 -170,11 +166,15 @@@ post_publishable.send(sender=self, publishable=publishable) - - def create_tag_model(model): name = model.__name__ + 'Tag' class Meta(Tag.Meta): app_label = model._meta.app_label + verbose_name = string_concat(_("tag"), " ", _("for:"), " ", + model._meta.verbose_name) + verbose_name_plural = string_concat(_("tags"), " ", _("for:"), " ", + model._meta.verbose_name) attrs = { '__module__': model.__module__, @@@ -191,10 -189,6 +189,10 @@@ def create_change_model(model) class Meta(Change.Meta): app_label = model._meta.app_label + verbose_name = string_concat(_("change"), " ", _("for:"), " ", + model._meta.verbose_name) + verbose_name_plural = string_concat(_("changes"), " ", _("for:"), " ", + model._meta.verbose_name) attrs = { '__module__': model.__module__, @@@ -286,7 -280,7 +284,7 @@@ class Document(models.Model) tags = kwargs.get('tags', []) if tags: # set stage to next tag after the commited one - self.stage = max(tags, key=lambda t: t.ordering).next() + self.stage = max(tags, key=lambda t: t.ordering).get_next() change = self.change_set.create(author=author, author_name=author_name, diff --combined apps/wiki/templates/wiki/document_details_base.html index 5eda0942,e164a9ee..891e9e85 --- a/apps/wiki/templates/wiki/document_details_base.html +++ b/apps/wiki/templates/wiki/document_details_base.html @@@ -1,14 -1,14 +1,14 @@@ {% extends "base.html" %} {% load toolbar_tags i18n %} -{% block title %}{{ book.title }} - {{ block.super }}{% endblock %} +{% block titleextra %}{{ chunk.pretty_title }}{% endblock %} {% block extrahead %} {% load compressed %} {% compressed_css 'detail' %} {% endblock %} {% block extrabody %} - {% compressed_js 'detail' %} @@@ -27,7 -27,7 +27,7 @@@