1 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 from os.path import join, isfile
5 from django.urls import reverse
6 from django.db import models
7 from waiter.settings import WAITER_URL, WAITER_MAX_QUEUE
8 from waiter.utils import check_abspath
9 from picklefield import PickledObjectField
12 class WaitedFile(models.Model):
13 path = models.CharField(max_length=255, unique=True, db_index=True)
14 task_id = models.CharField(max_length=128, db_index=True, null=True, blank=True)
15 task = PickledObjectField(null=True, editable=False)
16 description = models.CharField(max_length=255, null=True, blank=True)
19 def exists(cls, path):
20 """Returns opened file or None.
22 `path` is relative to WAITER_ROOT.
23 Won't open a path leading outside of WAITER_ROOT.
25 abs_path = check_abspath(path)
26 # Pre-fetch objects for deletion to avoid minor race condition
27 relevant = [o.id for o in cls.objects.filter(path=path)]
29 cls.objects.filter(id__in=relevant).delete()
35 def can_order(cls, path):
36 return (cls.objects.filter(path=path).exists() or
38 cls.objects.count() < WAITER_MAX_QUEUE
42 def order(cls, path, task_creator, description=None):
44 Returns an URL for the user to follow.
45 If the file is ready, returns download URL.
46 If not, starts preparing it and returns waiting URL.
48 task_creator: function taking a path and generating the file;
49 description: a string or string proxy with a description for user;
51 already = cls.exists(path)
53 waited, created = cls.objects.get_or_create(path=path)
55 waited.task = task_creator(check_abspath(path), waited.pk)
56 waited.task_id = waited.task.task_id
57 waited.description = description
59 return reverse("waiter", args=[path])
60 return join(WAITER_URL, path)