Skip to content
Snippets Groups Projects
Verified Commit fa4ec33f authored by Tom Teichler's avatar Tom Teichler :beers:
Browse files

Merge branch 'master' into 331-user-registration

parents 9d068430 52cde73c
No related branches found
No related tags found
1 merge request!413Resolve "User registration"
# Generated by Django 3.2 on 2021-04-17 18:47
import aleksis.core.models
from django.db import migrations, models
def _get_upload_path(instance, filename): # noqa
return f"pdfs/{instance.secret}.pdf"
class Migration(migrations.Migration):
......@@ -14,6 +16,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='pdffile',
name='file',
field=models.FileField(blank=True, null=True, upload_to=aleksis.core.models.PDFFile._get_upload_path, verbose_name='Generated PDF file'),
field=models.FileField(blank=True, null=True, upload_to=_get_upload_path, verbose_name='Generated PDF file'),
),
]
# Generated by Django 3.2.3 on 2021-05-20 14:25
from django.db import migrations, models
from django.core.files.base import ContentFile
def _get_default():
return ContentFile("")
class Migration(migrations.Migration):
dependencies = [
('core', '0017_dashboardwidget_broken'),
]
operations = [
migrations.RemoveField(
model_name='pdffile',
name='html',
),
migrations.AddField(
model_name='pdffile',
name='html_file',
field=models.FileField(default=_get_default, upload_to='pdfs/', verbose_name='Generated HTML file'),
preserve_default=False,
),
migrations.AlterField(
model_name='pdffile',
name='file',
field=models.FileField(blank=True, null=True, upload_to='pdfs/', verbose_name='Generated PDF file'),
),
]
......@@ -24,6 +24,7 @@ from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
import jsonstore
from cachalot.api import cachalot_disabled
from cache_memoize import cache_memoize
from django_celery_results.models import TaskResult
from dynamic_preferences.models import PerInstancePreferenceModel
......@@ -1005,41 +1006,20 @@ class PDFFile(ExtensibleModel):
def _get_default_expiration(): # noqa
return timezone.now() + timedelta(minutes=get_site_preferences()["general__pdf_expiration"])
def _get_upload_path(instance, filename): # noqa
return f"pdfs/{instance.secret}.pdf"
person = models.ForeignKey(
to=Person, on_delete=models.CASCADE, verbose_name=_("Owner"), related_name="pdf_files"
)
expires_at = models.DateTimeField(
verbose_name=_("File expires at"), default=_get_default_expiration
)
html = models.TextField(verbose_name=_("Rendered HTML"))
html_file = models.FileField(upload_to="pdfs/", verbose_name=_("Generated HTML file"))
file = models.FileField(
upload_to=_get_upload_path, blank=True, null=True, verbose_name=_("Generated PDF file")
upload_to="pdfs/", blank=True, null=True, verbose_name=_("Generated PDF file")
)
def __str__(self):
return f"{self.person} ({self.pk})"
@property
def secret(self) -> str:
"""Get secret needed for accessing the HTML page."""
return hmac.new(
bytes(settings.SECRET_KEY, "utf-8"),
msg=bytes(self.html + str(self.expires_at), "utf-8"),
digestmod="sha256",
).hexdigest()
@property
def html_url(self) -> str:
"""Get URL for the HTML page."""
return (
urlparse(reverse("html_for_pdf_file", args=[self.pk]))
._replace(query=f"secret={self.secret}")
.geturl()
)
class Meta:
verbose_name = _("PDF file")
verbose_name_plural = _("PDF files")
......@@ -1057,7 +1037,8 @@ class TaskUserAssignment(ExtensibleModel):
def create_for_task_id(cls, task_id: str, user: "User") -> "TaskUserAssignment":
# Use get_or_create to ensure the TaskResult exists
# django-celery-results will later add the missing information
result, __ = TaskResult.objects.get_or_create(task_id=task_id)
with cachalot_disabled():
result, __ = TaskResult.objects.get_or_create(task_id=task_id)
return cls.objects.create(task_result=result, user=user)
class Meta:
......
......@@ -3,6 +3,7 @@ import re
from datetime import datetime, timedelta
from django.core.files import File
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.template.loader import render_to_string
from django.test import TransactionTestCase, override_settings
......@@ -25,14 +26,13 @@ class PDFFIleTest(TransactionTestCase):
_test_pdf = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test.pdf")
def _get_test_html(self):
return render_to_string("core/pages/test_pdf.html")
return ContentFile(render_to_string("core/pages/test_pdf.html"), name="source.html")
def test_pdf_file(self):
dummy_person = Person.objects.create(first_name="Jane", last_name="Doe")
html = self._get_test_html()
assert "html" in html
file_object = PDFFile.objects.create(person=dummy_person, html=html)
file_object = PDFFile.objects.create(person=dummy_person, html_file=html)
assert isinstance(file_object.expires_at, datetime)
assert file_object.expires_at > timezone.now()
assert not bool(file_object.file)
......@@ -40,12 +40,12 @@ class PDFFIleTest(TransactionTestCase):
with open(self._test_pdf, "rb") as f:
file_object.file.save("print.pdf", File(f))
file_object.save()
re_base = r"pdfs/[a-zA-Z0-9]+\.pdf"
re_base = r"pdfs/print_[a-zA-Z0-9]+\.pdf"
assert re.match(re_base, file_object.file.name)
def test_delete_signal(self):
dummy_person = Person.objects.create(first_name="Jane", last_name="Doe")
file_object = PDFFile.objects.create(person=dummy_person, html=self._get_test_html())
file_object = PDFFile.objects.create(person=dummy_person, html_file=self._get_test_html())
with open(self._test_pdf, "rb") as f:
file_object.file.save("print.pdf", File(f))
file_object.save()
......@@ -59,10 +59,10 @@ class PDFFIleTest(TransactionTestCase):
def test_delete_expired_files(self):
# Create test instances
dummy_person = Person.objects.create(first_name="Jane", last_name="Doe")
file_object = PDFFile.objects.create(person=dummy_person, html=self._get_test_html())
file_object = PDFFile.objects.create(person=dummy_person, html_file=self._get_test_html())
file_object2 = PDFFile.objects.create(
person=dummy_person,
html=self._get_test_html(),
html_file=self._get_test_html(),
expires_at=timezone.now() + timedelta(minutes=10),
)
with open(self._test_pdf, "rb") as f:
......
......@@ -213,7 +213,6 @@ urlpatterns = [
name="edit_default_dashboard",
),
path("pdfs/<int:pk>/", views.RedirectToPDFFile.as_view(), name="redirect_to_pdf_file"),
path("pdfs/<int:pk>/html/", views.HTMLForPDFFile.as_view(), name="html_for_pdf_file"),
]
# Add URLs for optional features
......
......@@ -4,6 +4,7 @@ from tempfile import TemporaryDirectory
from typing import Optional
from django.core.files import File
from django.core.files.base import ContentFile
from django.http.request import HttpRequest
from django.http.response import HttpResponse
from django.shortcuts import get_object_or_404
......@@ -73,8 +74,10 @@ def render_pdf(request: HttpRequest, template_name: str, context: dict = None) -
html_template = render_to_string(template_name, context, request)
file_object = PDFFile.objects.create(person=request.user.person, html=html_template)
html_url = request.build_absolute_uri(file_object.html_url)
file_object = PDFFile.objects.create(
person=request.user.person, html_file=ContentFile(html_template, name="source.html")
)
html_url = request.build_absolute_uri(file_object.html_file.url)
result = generate_pdf.delay(file_object.pk, html_url, lang=get_language())
......
......@@ -1081,18 +1081,6 @@ class RedirectToPDFFile(SingleObjectMixin, View):
return redirect(file_object.file.url)
class HTMLForPDFFile(SingleObjectMixin, View):
"""Return rendered HTML for generating a PDF file."""
model = PDFFile
def get(self, request, *args, **kwargs):
file_object = self.get_object()
if request.GET.get("secret") != file_object.secret:
raise PermissionDenied()
return HttpResponse(file_object.html)
class CeleryProgressView(View):
"""Wrap celery-progress view to check permissions before."""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment