"""
h = customizations_hash(customizations)
pdf_name = '%s-custom-%s' % (book.slug, h)
- pdf_file = get_dynamic_path(None, pdf_name, ext='pdf')
+ pdf_file = pdf_name + '.pdf'
return pdf_file
</ul>
</div>
<div class="other-download">
- {% if related.media.mp3 or related.media.ogg %}
<h2 class="mono">{% trans "Download" %}</h2>
<ul class="plain">
<li>
{% if related.media.ogg %}<a href="{% url download_zip_ogg book.slug %}">OGG</a>{% endif %}.
{% endif %}
</li>
- {% comment %}
<li>
<a href="{% url custom_pdf_form %}?slug={{book.slug}}" id="custom-pdf" class="ajaxable">{% trans "Download a custom PDF" %}</a>
</li>
- {% endcomment %}
</ul>
- {% endif %}
</div>
</div>
{% endblock %}
from django.conf import settings
from django.template import RequestContext
-from django.shortcuts import render_to_response, get_object_or_404
+from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponsePermanentRedirect
from django.core.urlresolvers import reverse
from django.db.models import Q
from picture.models import Picture
from os import path
+from waiter.models import WaitedFile
staff_required = user_passes_test(lambda user: user.is_staff)
cust = form.customizations
pdf_file = models.get_customized_pdf_path(book, cust)
- if not path.exists(pdf_file):
- result = async_build_pdf.delay(book.id, cust, pdf_file)
- result.wait()
- return AttachmentHttpResponse(file_name=("%s.pdf" % book.slug), file_path=pdf_file, mimetype="application/pdf")
+ url = WaitedFile.order(pdf_file,
+ lambda p: async_build_pdf.delay(book.id, cust, p),
+ "%s: %s" % (book.pretty_title(), ", ".join(cust))
+ )
+ return redirect(url)
else:
raise Http404(_('Incorrect customization options for PDF'))
else:
--- /dev/null
+"""
+Waiting for and serving files generated in Celery to the user.
+
+Author: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
+"""
\ No newline at end of file
--- /dev/null
+# encoding: 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 'WaitedFile'
+ db.create_table('waiter_waitedfile', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('path', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255, db_index=True)),
+ ('task', self.gf('django.db.models.fields.CharField')(max_length=64, null=True)),
+ ('description', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+ ))
+ db.send_create_signal('waiter', ['WaitedFile'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'WaitedFile'
+ db.delete_table('waiter_waitedfile')
+
+
+ models = {
+ 'waiter.waitedfile': {
+ 'Meta': {'object_name': 'WaitedFile'},
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
+ 'task': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'})
+ }
+ }
+
+ complete_apps = ['waiter']
--- /dev/null
+from os.path import join, abspath, exists
+from django.db import models
+from waiter.settings import WAITER_ROOT, WAITER_URL
+from django.core.urlresolvers import reverse
+
+class WaitedFile(models.Model):
+ path = models.CharField(max_length=255, unique=True, db_index=True)
+ task = models.CharField(max_length=64, null=True, editable=False)
+ description = models.CharField(max_length=255, null=True, blank=True)
+
+ @staticmethod
+ def abspath(path):
+ abs_path = abspath(join(WAITER_ROOT, path))
+ if not abs_path.startswith(WAITER_ROOT):
+ raise ValueError('Path not inside WAITER_ROOT.')
+ return abs_path
+
+ @classmethod
+ def exists(cls, path):
+ """Returns opened file or None.
+
+ `path` is relative to WAITER_ROOT.
+ Won't open a path leading outside of WAITER_ROOT.
+ """
+ abs_path = cls.abspath(path)
+ # Pre-fetch objects to avoid minor race condition
+ relevant = [o.id for o in cls.objects.filter(path=path)]
+ print abs_path
+ if exists(abs_path):
+ cls.objects.filter(id__in=relevant).delete()
+ return True
+ else:
+ return False
+
+ @classmethod
+ def order(cls, path, task_creator, description=None):
+ """
+ Returns an URL for the user to follow.
+ If the file is ready, returns download URL.
+ If not, starts preparing it and returns waiting URL.
+ """
+ already = cls.exists(path)
+ if not already:
+ waited, created = cls.objects.get_or_create(path=path)
+ if created:
+ # TODO: makedirs
+ waited.task = task_creator(cls.abspath(path))
+ print waited.task
+ waited.description = description
+ waited.save()
+ # TODO: it the task exists, if stale delete, send some mail and restart
+ return reverse("waiter", args=[path])
+ return join(WAITER_URL, path)
--- /dev/null
+from os.path import join
+from django.conf import settings
+
+try:
+ WAITER_ROOT = settings.WAITER_ROOT
+except AttributeError:
+ WAITER_ROOT = join(settings.MEDIA_ROOT, 'waiter')
+
+try:
+ WAITER_URL = settings.WAITER_URL
+except AttributeError:
+ WAITER_URL = join(settings.MEDIA_URL, 'waiter')
--- /dev/null
+{% extends "base.html" %}
+
+{% block titleextra %}Prosię ciekać{% endblock %}
+
+
+{% block extrahead %}
+ {# TODO: Not like that! What are you, caveman?! #}
+ <meta http-equiv="refresh" content="{% if file_url %}0; url={{ file_url }}{% else %}5{% endif %}" />
+{% endblock %}
+
+
+{% block body %}
+ {% if file_url %}
+ <p>Plik jest gotowy! Jeśli pobieranie nie zacznie się automatycznie,
+ oto <a href="{{ file_url }}">bezpośredni link</a>.</p>
+ {% else %}
+ <p>Idź na kawę. To trochę potrwa.</p>
+
+ <p>{{ waiting_for.description }}</p>
+ {% endif %}
+{% endblock %}
--- /dev/null
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('waiter.views',
+ url(r'^(?P<path>.*)$', 'wait', name='waiter'),
+)
--- /dev/null
+from os.path import join
+from waiter.models import WaitedFile
+from waiter.settings import WAITER_URL
+from django.shortcuts import get_object_or_404, render, redirect
+
+def wait(request, path):
+ if WaitedFile.exists(path):
+ file_url = join(WAITER_URL, path)
+ else:
+ waiting_for = get_object_or_404(WaitedFile, path=path)
+ # TODO: check if not stale, inform the user and send some mail if so.
+ return render(request, "waiter/wait.html", locals())
'picture',
'search',
'social',
+ 'waiter',
]
# Load localsettings, if they exist
url(r'^info/', include('infopages.urls')),
url(r'^ludzie/', include('social.urls')),
url(r'^uzytkownik/', include('allauth.urls')),
+ url(r'^czekaj/', include('waiter.urls')),
# Admin panel
url(r'^admin/catalogue/book/import$', 'catalogue.views.import_book', name='import_book'),