form = self.form_class(*form_args, **form_kwargs)
if form.is_valid():
add_args = self.success(form, request)
- redirect = request.GET.get('next')
- if not request.is_ajax() and redirect:
- return HttpResponseRedirect(urlquote_plus(
- redirect, safe='/?=&'))
- response_data = {'success': True,
- 'message': self.success_message, 'redirect': redirect}
+ response_data = {
+ 'success': True,
+ 'message': self.success_message,
+ 'redirect': request.GET.get('next')
+ }
if add_args:
response_data.update(add_args)
+ if not request.is_ajax() and response_data['redirect']:
+ return HttpResponseRedirect(urlquote_plus(
+ response_data['redirect'], safe='/?=&'))
elif request.is_ajax():
# Form was sent with errors. Send them back.
if self.form_prefix:
from django.utils.translation import ugettext_lazy as _
from catalogue.models import Book
+from waiter.models import WaitedFile
+from django.core.exceptions import ValidationError
+from catalogue.utils import get_customized_pdf_path
+from catalogue.tasks import build_custom_pdf
class BookImportForm(forms.Form):
class CustomPDFForm(forms.Form):
- def __init__(self, *args, **kwargs):
+ def __init__(self, book, *args, **kwargs):
super(CustomPDFForm, self).__init__(*args, **kwargs)
+ self.book = book
for name, label in CUSTOMIZATION_FLAGS:
self.fields[name] = forms.BooleanField(required=False, label=label)
for name, label, choices in CUSTOMIZATION_OPTIONS:
self.fields[name] = forms.ChoiceField(choices, label=label)
+ def clean(self):
+ self.cleaned_data['cust'] = self.customizations
+ self.cleaned_data['path'] = get_customized_pdf_path(self.book,
+ self.cleaned_data['cust'])
+ if not WaitedFile.can_order(self.cleaned_data['path']):
+ raise ValidationError(_('Queue is full. Please try again later.'))
+ return self.cleaned_data
+
@property
def customizations(self):
c = []
c.append(self.cleaned_data[name])
c.sort()
return c
+
+ def save(self, *args, **kwargs):
+ url = WaitedFile.order(self.cleaned_data['path'],
+ lambda p: build_custom_pdf.delay(self.book.id,
+ self.cleaned_data['cust'], p),
+ self.book.pretty_title()
+ )
+ #return redirect(url)
+ return {"redirect": url}
{% endif %}
</li>
<li>
- <a href="{% url custom_pdf_form %}?slug={{book.slug}}" id="custom-pdf" class="ajaxable">{% trans "Download a custom PDF" %}</a>
+ <a href="{% url custom_pdf_form book.slug %}" id="custom-pdf" class="ajaxable">{% trans "Download a custom PDF" %}</a>
</li>
</ul>
</div>
'extra_info': book.get_extra_info_value(),
'hide_about': hide_about,
'themes': book_themes,
- 'custom_pdf_form': forms.CustomPDFForm(),
'request': context.get('request'),
}
url(r'^jtags/$', 'json_tags_starting_with', name='jhint'),
#url(r'^szukaj/$', 'search', name='old_search'),
+ url(r'^custompdf/(?P<slug>%s)/$' % SLUG, CustomPDFFormView(), name='custom_pdf_form'),
+
+ url(r'^audiobooki/(?P<type>mp3|ogg|daisy|all).xml$', AudiobookFeed(), name='audiobook_feed'),
+
+
# zip
url(r'^zip/pdf\.zip$', 'download_zip', {'format': 'pdf', 'slug': None}, 'download_zip_pdf'),
url(r'^zip/epub\.zip$', 'download_zip', {'format': 'epub', 'slug': None}, 'download_zip_epub'),
url(r'^lektura/(?P<slug>%s)/motyw/(?P<theme_slug>[a-zA-Z0-9-]+)/$' % SLUG,
'book_fragments', name='book_fragments'),
+ # This should be the last pattern.
url(r'^(?P<tags>[a-zA-Z0-9-/]*)/$', 'tagged_object_list', name='tagged_object_list'),
-
- url(r'^audiobooki/(?P<type>mp3|ogg|daisy|all).xml$', AudiobookFeed(), name='audiobook_feed'),
-
- url(r'^custompdf$', CustomPDFFormView(), name='custom_pdf_form'),
- url(r'^custompdf/(?P<slug>%s).pdf' % SLUG, 'download_custom_pdf'),
-
)
from catalogue import models
from catalogue import forms
-from catalogue.utils import split_tags, MultiQuerySet, get_customized_pdf_path
-from catalogue.tasks import build_custom_pdf
+from catalogue.utils import split_tags, MultiQuerySet
from pdcounter import models as pdcounter_models
from pdcounter import views as pdcounter_views
from suggest.forms import PublishingSuggestForm
from picture.models import Picture
-from waiter.models import WaitedFile
-
staff_required = user_passes_test(lambda user: user.is_staff)
return HttpResponseRedirect(urlquote_plus(settings.MEDIA_URL + url, safe='/?='))
-def download_custom_pdf(request, slug, method='GET'):
- book = get_object_or_404(models.Book, slug=slug)
-
- if request.method == method:
- form = forms.CustomPDFForm(method == 'GET' and request.GET or request.POST)
- if form.is_valid():
- cust = form.customizations
- pdf_file = get_customized_pdf_path(book, cust)
-
- url = WaitedFile.order(pdf_file,
- lambda p: build_custom_pdf.delay(book.id, cust, p),
- book.pretty_title()
- )
- return redirect(url)
- else:
- raise Http404(_('Incorrect customization options for PDF'))
- else:
- raise Http404(_('Bad method'))
-
-
class CustomPDFFormView(AjaxableFormView):
form_class = forms.CustomPDFForm
title = ugettext_lazy('Download custom PDF')
submit = ugettext_lazy('Download')
honeypot = True
- def __call__(self, request):
- from copy import copy
- if request.method == 'POST':
- request.GET = copy(request.GET)
- request.GET['next'] = "%s?%s" % (reverse('catalogue.views.download_custom_pdf', args=[request.GET.get('slug')]),
- request.POST.urlencode())
- return super(CustomPDFFormView, self).__call__(request)
+ def form_args(self, request, obj):
+ """Override to parse view args and give additional args to the form."""
+ return (obj,), {}
- def get_object(self, request):
- return get_object_or_404(models.Book, slug=request.GET.get('slug'))
+ def get_object(self, request, slug, *args, **kwargs):
+ return get_object_or_404(models.Book, slug=slug)
def context_description(self, request, obj):
return obj.pretty_title()
-
- def success(self, *args):
- pass
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_id', self.gf('django.db.models.fields.CharField')(db_index=True, max_length=128, null=True, blank=True)),
('task', self.gf('picklefield.fields.PickledObjectField')(null=True)),
('description', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
))
'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': ('picklefield.fields.PickledObjectField', [], {'null': 'True'})
+ 'task': ('picklefield.fields.PickledObjectField', [], {'null': 'True'}),
+ 'task_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '128', 'null': 'True', 'blank': 'True'})
}
}
from os.path import join, isfile
from django.core.urlresolvers import reverse
from django.db import models
-from djcelery.models import TaskMeta
-from waiter.settings import WAITER_URL
+from waiter.settings import WAITER_URL, WAITER_MAX_QUEUE
from waiter.utils import check_abspath
from picklefield import PickledObjectField
class WaitedFile(models.Model):
path = models.CharField(max_length=255, unique=True, db_index=True)
+ task_id = models.CharField(max_length=128, db_index=True, null=True, blank=True)
task = PickledObjectField(null=True, editable=False)
description = models.CharField(max_length=255, null=True, blank=True)
else:
return False
+ @classmethod
+ def can_order(cls, path):
+ return (cls.objects.filter(path=path).exists() or
+ cls.exists(path) or
+ cls.objects.count() < WAITER_MAX_QUEUE
+ )
+
def is_stale(self):
if self.task is None:
# Race; just let the other task roll.
waited, created = cls.objects.get_or_create(path=path)
if created or waited.is_stale():
waited.task = task_creator(check_abspath(path))
+ waited.task_id = waited.task.task_id
waited.description = description
waited.save()
return reverse("waiter", args=[path])
WAITER_URL = settings.WAITER_URL
except AttributeError:
WAITER_URL = join(settings.MEDIA_URL, 'waiter')
+
+try:
+ WAITER_MAX_QUEUE = settings.WAITER_MAX_QUEUE
+except AttributeError:
+ WAITER_MAX_QUEUE = 20
+
--- /dev/null
+from celery.signals import task_postrun
+from waiter.models import WaitedFile
+
+
+def task_delete_after(task_id=None, **kwargs):
+ WaitedFile.objects.filter(task_id=task_id).delete()
+task_postrun.connect(task_delete_after)