From ffc2e047ca6712af8da3e13891b7ea16f184264a Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Wed, 21 Dec 2011 12:37:50 +0100 Subject: [PATCH 1/1] image publishing, some tag changes --- apps/catalogue/models/__init__.py | 3 +- apps/catalogue/models/book.py | 5 +- apps/catalogue/models/image.py | 62 ++++++++++++++++++- apps/catalogue/models/listeners.py | 18 +++--- .../templates/catalogue/image_detail.html | 47 ++++++++++++++ apps/catalogue/templatetags/book_list.py | 6 +- apps/catalogue/urls.py | 3 +- apps/catalogue/views.py | 24 +++++-- lib/librarian | 2 +- .../static/js/wiki_img/view_editor_motifs.js | 4 +- .../static/js/wiki_img/view_editor_objects.js | 4 +- redakcja/static/js/wiki_img/wikiapi.js | 6 +- 12 files changed, 155 insertions(+), 29 deletions(-) diff --git a/apps/catalogue/models/__init__.py b/apps/catalogue/models/__init__.py index 82e1c116..08cedd00 100755 --- a/apps/catalogue/models/__init__.py +++ b/apps/catalogue/models/__init__.py @@ -5,7 +5,8 @@ # from catalogue.models.chunk import Chunk from catalogue.models.image import Image -from catalogue.models.publish_log import BookPublishRecord, ChunkPublishRecord +from catalogue.models.publish_log import (BookPublishRecord, + ChunkPublishRecord, ImagePublishRecord) from catalogue.models.book import Book from catalogue.models.listeners import * diff --git a/apps/catalogue/models/book.py b/apps/catalogue/models/book.py index 46d11e83..90327b26 100755 --- a/apps/catalogue/models/book.py +++ b/apps/catalogue/models/book.py @@ -9,10 +9,8 @@ from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from slughifi import slughifi -import apiclient from catalogue.helpers import cached_in_field from catalogue.models import BookPublishRecord, ChunkPublishRecord -from catalogue.signals import post_publish from catalogue.tasks import refresh_instance, book_content_updated from catalogue.xml_tools import compile_text, split_xml @@ -350,6 +348,9 @@ class Book(models.Model): """ Publishes a book on behalf of a (local) user. """ + import apiclient + from catalogue.signals import post_publish + self.assert_publishable() changes = self.get_current_changes(publishable=True) book_xml = self.materialize(changes=changes) diff --git a/apps/catalogue/models/image.py b/apps/catalogue/models/image.py index c5d6bf0a..90a6e02a 100755 --- a/apps/catalogue/models/image.py +++ b/apps/catalogue/models/image.py @@ -4,6 +4,7 @@ # 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 _ @@ -44,9 +45,46 @@ class Image(dvcs_models.Document): 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) + + picture_xml = self.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 accessible(self, request): return self.public or request.user.is_authenticated() @@ -54,7 +92,7 @@ class Image(dvcs_models.Document): change = self.publishable() if not change: return False - return change.publish_log.exists() + return not change.publish_log.exists() new_publishable = cached_in_field('_new_publishable')(is_new_publishable) def is_published(self): @@ -93,3 +131,25 @@ class Image(dvcs_models.Document): """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 --git a/apps/catalogue/models/listeners.py b/apps/catalogue/models/listeners.py index 4e76b0d9..f98fba4d 100755 --- a/apps/catalogue/models/listeners.py +++ b/apps/catalogue/models/listeners.py @@ -5,7 +5,8 @@ # from django.contrib.auth.models import User from django.db import models -from catalogue.models import Book, Chunk, Image +from catalogue.models import (Book, Chunk, Image, BookPublishRecord, + ImagePublishRecord) from catalogue.signals import post_publish from dvcs.signals import post_publishable @@ -39,14 +40,13 @@ models.signals.post_save.connect(user_changed, sender=User) def publish_listener(sender, *args, **kwargs): - sender.touch() - for c in sender: - c.touch() -post_publish.connect(publish_listener, sender=Book) - -def publish_listener(sender, *args, **kwargs): - sender.touch() -post_publish.connect(publish_listener, sender=Image) + if isinstance(sender, BookPublishRecord): + sender.book.touch() + for c in sender.book: + c.touch() + elif isinstance(sender, ImagePublishRecord): + sender.image.touch() +post_publish.connect(publish_listener) def chunk_publishable_listener(sender, *args, **kwargs): diff --git a/apps/catalogue/templates/catalogue/image_detail.html b/apps/catalogue/templates/catalogue/image_detail.html index fea775b4..8049b55c 100755 --- a/apps/catalogue/templates/catalogue/image_detail.html +++ b/apps/catalogue/templates/catalogue/image_detail.html @@ -17,6 +17,53 @@ {% if editable %}{% endif %} + +
+

{% trans "Editor" %}

+ +

{% trans "Proceed to the editor." %}

+
+ + + +
+ + +

{% trans "Publication" %}

+ +

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

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

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

+ +{% endif %} + +
+ +

{% trans "Comments" %}

diff --git a/apps/catalogue/templatetags/book_list.py b/apps/catalogue/templatetags/book_list.py index 5e18b7e2..9344053b 100755 --- a/apps/catalogue/templatetags/book_list.py +++ b/apps/catalogue/templatetags/book_list.py @@ -148,8 +148,8 @@ _image_states = [ ('unpublished', _('unpublished'), Q(_published=False)), ('empty', _('empty'), Q(head=None)), ] -_image_states_options = [s[:2] for s in _states] -_image_states_dict = dict([(s[0], s[2]) for s in _states]) +_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): @@ -181,7 +181,7 @@ def image_list(context, user=None): else: filters = {} new_context = {"users": User.objects.annotate( - count=Count('chunk')).filter(count__gt=0).order_by( + count=Count('image')).filter(count__gt=0).order_by( '-count', 'last_name', 'first_name')} new_context.update({ diff --git a/apps/catalogue/urls.py b/apps/catalogue/urls.py index 621eb12a..31df1c19 100644 --- a/apps/catalogue/urls.py +++ b/apps/catalogue/urls.py @@ -8,6 +8,8 @@ urlpatterns = patterns('catalogue.views', 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'), @@ -26,7 +28,6 @@ urlpatterns = patterns('catalogue.views', '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[^/]+)/xml$', 'book_xml', name="catalogue_book_xml"), diff --git a/apps/catalogue/views.py b/apps/catalogue/views.py index 52008c9c..bc54c3ea 100644 --- a/apps/catalogue/views.py +++ b/apps/catalogue/views.py @@ -23,8 +23,8 @@ 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, Image) +from catalogue.models import (Book, Chunk, Image, BookPublishRecord, + ChunkPublishRecord, ImagePublishRecord) from catalogue.tasks import publishable_error # @@ -358,8 +358,7 @@ def image(request, slug): form = forms.ReadonlyImageForm(instance=image) editable = False - #publish_error = publishable_error(book) - publish_error = 'Publishing not implemented yet.' + publish_error = publishable_error(image) publishable = publish_error is None return direct_to_template(request, "catalogue/image_detail.html", extra_context={ @@ -481,3 +480,20 @@ def publish(request, slug): return http.HttpResponse(e) else: 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()) diff --git a/lib/librarian b/lib/librarian index 28878296..5b407667 160000 --- a/lib/librarian +++ b/lib/librarian @@ -1 +1 @@ -Subproject commit 28878296bacad453735a520f350ba5a971f8ffc8 +Subproject commit 5b407667ca47cf4d9752821fd49e5611737146d2 diff --git a/redakcja/static/js/wiki_img/view_editor_motifs.js b/redakcja/static/js/wiki_img/view_editor_motifs.js index 7ce96650..3b6f45d9 100644 --- a/redakcja/static/js/wiki_img/view_editor_motifs.js +++ b/redakcja/static/js/wiki_img/view_editor_motifs.js @@ -117,7 +117,7 @@ var self = this; this.$objects_list.children().remove(); - $.each(this.doc.getImageItems('motyw'), function(i, e) { + $.each(this.doc.getImageItems('theme'), function(i, e) { self._push.apply(self, e); }); @@ -140,7 +140,7 @@ args.unshift($(e).text()); motifs.push(args); }) - self.doc.setImageItems('motyw', motifs); + self.doc.setImageItems('theme', motifs); this.ias.setOptions({disable: true, hide: true}); diff --git a/redakcja/static/js/wiki_img/view_editor_objects.js b/redakcja/static/js/wiki_img/view_editor_objects.js index 9e6a3cb8..97d4ba25 100644 --- a/redakcja/static/js/wiki_img/view_editor_objects.js +++ b/redakcja/static/js/wiki_img/view_editor_objects.js @@ -108,7 +108,7 @@ var self = this; this.$objects_list.children().remove(); - $.each(this.doc.getImageItems('obiekt'), function(i, e) { + $.each(this.doc.getImageItems('object'), function(i, e) { self._push.apply(self, e); }); @@ -131,7 +131,7 @@ args.unshift($(e).text()); objects.push(args); }) - self.doc.setImageItems('obiekt', objects); + self.doc.setImageItems('object', objects); this.ias.setOptions({disable: true, hide: true}); diff --git a/redakcja/static/js/wiki_img/wikiapi.js b/redakcja/static/js/wiki_img/wikiapi.js index 33af1766..219f53ff 100644 --- a/redakcja/static/js/wiki_img/wikiapi.js +++ b/redakcja/static/js/wiki_img/wikiapi.js @@ -76,7 +76,7 @@ if (self.text === null || self.commit !== data.commit) { self.text = data.text; if (self.text === '') { - self.text = ''; + self.text = ''; } self.revision = data.revision; self.commit = data.commit; @@ -319,7 +319,7 @@ $e.find('div').each(function(i, div) { var $div = $(div); switch ($div.attr('type')) { - case 'area': + case 'rect': a.push([ value, $div.attr('x1'), @@ -361,7 +361,7 @@ $sem.attr(tag, e[0]); $div = $(doc.createElement("div")); if (e[1]) { - $div.attr('type', 'area'); + $div.attr('type', 'rect'); $div.attr('x1', e[1]); $div.attr('y1', e[2]); $div.attr('x2', e[3]); -- 2.20.1