Epub debugging.
[redakcja.git] / src / cover / views.py
index a7b96fb..39b12f9 100644 (file)
@@ -1,19 +1,28 @@
 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
+from hashlib import sha1
+from os import makedirs
 import os.path
 import os.path
+import PIL.Image
 from django.conf import settings
 from django.contrib.auth.decorators import permission_required
 from django.conf import settings
 from django.contrib.auth.decorators import permission_required
-from django.http import HttpResponse, HttpResponseRedirect, Http404
+from django.http import HttpResponse, HttpResponseRedirect, Http404, JsonResponse
 from django.shortcuts import get_object_or_404, render
 from django.views.decorators.csrf import csrf_exempt
 from django.views.decorators.http import require_POST
 from django.shortcuts import get_object_or_404, render
 from django.views.decorators.csrf import csrf_exempt
 from django.views.decorators.http import require_POST
+from lxml import etree
+from librarian import RDFNS, DCNS
+from librarian.cover import make_cover
+from librarian.dcparser import BookInfo
 from documents.helpers import active_tab
 from documents.helpers import active_tab
-from documents.models import Chunk
+from documents.models import Book, Chunk
 from cover.models import Image
 from cover import forms
 from cover.models import Image
 from cover import forms
+from cover.utils import get_import_data
 
 
-PREVIEW_SIZE = (216, 300)
+
+PREVIEW_SIZE = (212, 300)
 
 
 def preview(request, book, chunk=None, rev=None):
 
 
 def preview(request, book, chunk=None, rev=None):
@@ -22,11 +31,14 @@ def preview(request, book, chunk=None, rev=None):
     If chunk and rev number are given, use version from given revision.
     If rev is not given, use publishable version.
     """
     If chunk and rev number are given, use version from given revision.
     If rev is not given, use publishable version.
     """
-    from PIL import Image
-    from librarian.cover import make_cover
-    from librarian.dcparser import BookInfo
+    try:
+        chunk = Chunk.get(book, chunk)
+    except Chunk.DoesNotExist:
+        raise Http404
+
+    if chunk.book.cover and rev is None and not request.GET.get('width') and not request.GET.get('height'):
+        return HttpResponseRedirect(chunk.book.cover.url)
 
 
-    chunk = Chunk.get(book, chunk)
     if rev is not None:
         try:
             revision = chunk.at_revision(rev)
     if rev is not None:
         try:
             revision = chunk.at_revision(rev)
@@ -40,20 +52,22 @@ def preview(request, book, chunk=None, rev=None):
 
     try:
         info = BookInfo.from_bytes(xml)
 
     try:
         info = BookInfo.from_bytes(xml)
-    except:
+    except Exception as e:
+        print(e)
         return HttpResponseRedirect(os.path.join(settings.STATIC_URL, "img/sample_cover.png"))
     width = request.GET.get('width')
     width = int(width) if width else None
     height=request.GET.get('height')
     height = int(height) if height else None
         return HttpResponseRedirect(os.path.join(settings.STATIC_URL, "img/sample_cover.png"))
     width = request.GET.get('width')
     width = int(width) if width else None
     height=request.GET.get('height')
     height = int(height) if height else None
-    cover = make_cover(info, width=width, height=height)
-    #cover = make_cover(info)
+
+    if not (height or width):
+        width, height = PREVIEW_SIZE
+
+    cover_class = request.GET.get('cover_class', 'default')
+
+    cover = make_cover(info, cover_class=cover_class, width=width, height=height)
     response = HttpResponse(content_type=cover.mime_type())
     response = HttpResponse(content_type=cover.mime_type())
-    if height or width:
-        size = (width, height)
-    else:
-        size = PREVIEW_SIZE
-    img = cover.image().resize(size, Image.ANTIALIAS)
+    img = cover.final_image()
     img.save(response, cover.format)
 
     if 'download' in request.GET:
     img.save(response, cover.format)
 
     if 'download' in request.GET:
@@ -65,17 +79,11 @@ def preview(request, book, chunk=None, rev=None):
 @csrf_exempt
 @require_POST
 def preview_from_xml(request):
 @csrf_exempt
 @require_POST
 def preview_from_xml(request):
-    from hashlib import sha1
-    from PIL import Image
-    from os import makedirs
-    from lxml import etree
-    from librarian.cover import make_cover
-    from librarian.dcparser import BookInfo
-
     xml = request.POST['xml']
     try:
         info = BookInfo.from_bytes(xml.encode('utf-8'))
     xml = request.POST['xml']
     try:
         info = BookInfo.from_bytes(xml.encode('utf-8'))
-    except:
+    except Exception as e:
+        print(e)
         return HttpResponse(os.path.join(settings.STATIC_URL, "img/sample_cover.png"))
     coverid = sha1(etree.tostring(info.to_etree())).hexdigest()
     cover = make_cover(info)
         return HttpResponse(os.path.join(settings.STATIC_URL, "img/sample_cover.png"))
     coverid = sha1(etree.tostring(info.to_etree())).hexdigest()
     cover = make_cover(info)
@@ -86,7 +94,7 @@ def preview_from_xml(request):
     except OSError:
         pass
     fname = os.path.join(cover_dir, "%s.%s" % (coverid, cover.ext()))
     except OSError:
         pass
     fname = os.path.join(cover_dir, "%s.%s" % (coverid, cover.ext()))
-    img = cover.image().resize(PREVIEW_SIZE, Image.ANTIALIAS)
+    img = cover.image().resize(PREVIEW_SIZE, PIL.Image.ANTIALIAS)
     img.save(os.path.join(settings.MEDIA_ROOT, fname))
     return HttpResponse(os.path.join(settings.MEDIA_URL, fname))
 
     img.save(os.path.join(settings.MEDIA_ROOT, fname))
     return HttpResponse(os.path.join(settings.MEDIA_URL, fname))
 
@@ -95,6 +103,22 @@ def preview_from_xml(request):
 def image(request, pk):
     img = get_object_or_404(Image, pk=pk)
 
 def image(request, pk):
     img = get_object_or_404(Image, pk=pk)
 
+    if not request.accepts('text/html') and request.accepts('application/json') or request.GET.get('format') == 'json':
+        return JsonResponse({
+            'title': img.title,
+            'author': img.author,
+            'license_name': img.license_name,
+            'license_url': img.license_url,
+            'source_url': img.source_url,
+            'attribution': img.attribution,
+            'cut_left': img.cut_left,
+            'cut_right': img.cut_right,
+            'cut_top': img.cut_top,
+            'cut_bottom': img.cut_bottom,
+            'file': img.file.url,
+            'use_file': img.use_file.url,
+        })
+
     if request.user.has_perm('cover.change_image'):
         if request.method == "POST":
             form = forms.ImageEditForm(request.POST, request.FILES, instance=img)
     if request.user.has_perm('cover.change_image'):
         if request.method == "POST":
             form = forms.ImageEditForm(request.POST, request.FILES, instance=img)
@@ -123,7 +147,7 @@ def image_file(request, pk):
 @active_tab('cover')
 def image_list(request):
     return render(request, "cover/image_list.html", {
 @active_tab('cover')
 def image_list(request):
     return render(request, "cover/image_list.html", {
-        'object_list': Image.objects.all(),
+        'object_list': Image.objects.all().order_by('-id'),
         'can_add': request.user.has_perm('cover.add_image'),
     })
 
         'can_add': request.user.has_perm('cover.add_image'),
     })
 
@@ -150,3 +174,61 @@ def add_image(request):
             'form': form,
             'ff': ff,
         })
             'form': form,
             'ff': ff,
         })
+
+@permission_required('cover.add_image')
+def quick_import(request, pk):
+    url = request.POST.get('url')
+    if url.startswith('%s://%s/' % (
+            request.scheme,
+            request.get_host())):
+        cover_id = url.rstrip('/').rsplit('/', 1)[-1]
+        cover = Image.objects.get(pk=cover_id)
+    else:
+        data = get_import_data(url)
+        same = Image.objects.filter(source_url=data['source_url'])
+        if not same.exists():
+            same = Image.objects.filter(download_url=data['download_url'])
+        if same.exists():
+            cover = same.first()
+        else:
+            form = forms.ImageAddForm(data)
+            if form.is_valid():
+                cover = form.save()
+
+    # We have a cover. Now let's commit.
+    book = Book.objects.get(pk=pk)
+    chunk = book[0]
+    text = chunk.head.materialize()
+
+    root = etree.fromstring(text)
+    rdf = root.find('.//' + RDFNS('Description'))
+    for tag in 'url', 'attribution', 'source':
+        for elem in rdf.findall('.//' + DCNS('relation.coverImage.%s' % tag)):
+            rdf.remove(elem)
+    e = etree.Element(DCNS('relation.coverImage.url'))
+    e.text = request.build_absolute_uri(cover.use_file.url)
+    rdf.append(e)
+    e.tail = '\n    '
+    e = etree.Element(DCNS('relation.coverImage.attribution'))
+    e.text = ''
+    if cover.title:
+        e.text += cover.title + ', '
+    if cover.author:
+        e.text += cover.author + ', '
+    e.text += cover.license_name
+    e.tail = '\n    '
+    rdf.append(e)
+    e = etree.Element(DCNS('relation.coverImage.source'))
+    e.text = cover.get_full_url()
+    e.tail = '\n    '
+    rdf.append(e)
+
+    xml = etree.tostring(root, encoding='unicode')
+    chunk.commit(
+        xml,
+        author=request.user,
+        comment='Cover',
+        publishable=chunk.head.publishable,
+    )
+    return HttpResponseRedirect(book.get_absolute_url())
+