Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(cleanup): delete old files when template is deleted or changed #445

Merged
merged 1 commit into from
Nov 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions document_merge_service/api/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import os.path
import shutil

from django.conf import settings
from django.core.files import File

_data_path = os.path.dirname(os.path.realpath(__file__))


def path(name):
return os.path.join(_data_path, name)
def django_file(name, mode="rb"):
abspath = os.path.join(_data_path, name)
new_path = f"{settings.MEDIA_ROOT}/attachments"

try:
os.makedirs(new_path)
except FileExistsError: # pragma: no cover
pass

def django_file(name, mode="rb"):
abspath = path(name)
return File(open(abspath, mode))
shutil.copy(abspath, f"{new_path}/{name}")

return File(open(abspath, mode), name=f"attachments/{name}")
28 changes: 28 additions & 0 deletions document_merge_service/api/migrations/0004_cleanup_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import os
import logging


from django.db import migrations
from django.conf import settings

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


def cleanup_files(apps, schema_editor):
Template = apps.get_model("api", "Template")
used_files = [template.template.path for template in Template.objects.all()]

with os.scandir(settings.MEDIA_ROOT) as files:
for f in files:
if not f.path in used_files and os.path.isfile(f.path):
os.remove(f.path)


class Migration(migrations.Migration):

dependencies = [
("api", "0003_template_meta"),
]

operations = [migrations.RunPython(cleanup_files, migrations.RunPython.noop)]
27 changes: 27 additions & 0 deletions document_merge_service/api/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import os

from django.db import models
from django.dispatch import receiver


class Template(models.Model):
Expand All @@ -22,3 +25,27 @@ class Template(models.Model):
engine = models.CharField(max_length=20, choices=ENGINE_CHOICES_TUPLE)
group = models.CharField(max_length=255, db_index=True, blank=True, null=True)
meta = models.JSONField(default=dict)


@receiver(models.signals.post_delete, sender=Template)
def auto_delete_file_on_delete(sender, instance, **kwargs):
"""Delete template file from filesystem when `Template` object is deleted."""

if os.path.isfile(instance.template.path):
os.remove(instance.template.path)


@receiver(models.signals.pre_save, sender=Template)
def auto_delete_file_on_change(sender, instance, **kwargs):
"""Delete old template file from filesystem when `Template` is given a new template file."""

try:
old_file = Template.objects.get(pk=instance.pk).template
except Template.DoesNotExist:
return

if old_file:
new_file = instance.template
if not old_file == new_file:
if os.path.isfile(old_file.path):
os.remove(old_file.path)
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@
"""

snapshots[
"test_template_merge_jinja_filters_docx[docx-template-False-False-200] 1"
"test_template_merge_jinja_filters_docx[docx-template-template__template0-False-False-200] 1"
] = """<w:body xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml">
<w:p>
<w:pPr>
Expand Down
27 changes: 12 additions & 15 deletions document_merge_service/api/tests/test_template.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import io
import json
import os

import pytest
from django.urls import reverse
Expand Down Expand Up @@ -462,7 +463,10 @@ def test_template_create_with_available_placeholders(
Document(io.BytesIO(response.content))


@pytest.mark.parametrize("template__engine", [models.Template.DOCX_TEMPLATE])
@pytest.mark.parametrize(
"template__engine,template__template",
[(models.Template.DOCX_TEMPLATE, django_file("docx-template-filters.docx"))],
)
@pytest.mark.parametrize(
"template_name,status_code",
[
Expand All @@ -479,15 +483,18 @@ def test_template_update(db, client, template, template_name, status_code):
assert response.status_code == status_code

if status_code == status.HTTP_200_OK:
assert os.path.isfile(template.template.path) is False
template.refresh_from_db()
assert template.description == "Test description"


@pytest.mark.parametrize("template__template", [django_file("docx-template.docx")])
def test_template_destroy(db, client, template):
url = reverse("template-detail", args=[template.pk])

response = client.delete(url)
assert response.status_code == status.HTTP_204_NO_CONTENT
assert os.path.isfile(template.template.path) is False


@pytest.mark.parametrize(
Expand Down Expand Up @@ -652,8 +659,8 @@ def test_template_merge_jinja_extensions_docx(
],
)
@pytest.mark.parametrize(
"template__engine",
[models.Template.DOCX_TEMPLATE],
"template__engine,template__template",
[(models.Template.DOCX_TEMPLATE, django_file("docx-template-filters.docx"))],
)
def test_template_merge_jinja_filters_docx(
db,
Expand All @@ -670,11 +677,6 @@ def test_template_merge_jinja_filters_docx(
settings.LANGUAGE_CODE = "de-ch"
url = reverse("template-merge", args=[template.pk])

# Couldn't put this into `parametrize`. For some reason, in the second run, the
# template name is extended with a seemingly random string.
template.template = django_file("docx-template-filters.docx")
template.save()

data = {
"data": json.dumps(
{
Expand Down Expand Up @@ -715,8 +717,8 @@ def test_template_merge_jinja_filters_docx(


@pytest.mark.parametrize(
"template__engine",
[models.Template.DOCX_TEMPLATE],
"template__engine,template__template",
[(models.Template.DOCX_TEMPLATE, django_file("docx-template-filters.docx"))],
)
@pytest.mark.parametrize(
"file_value",
Expand All @@ -733,11 +735,6 @@ def test_template_merge_file_reset(
settings.LANGUAGE_CODE = "de-ch"
url = reverse("template-merge", args=[template.pk])

# Couldn't put this into `parametrize`. For some reason, in the second run, the
# template name is extended with a seemingly random string.
template.template = django_file("docx-template-filters.docx")
template.save()

data = {
"data": {
"test_date": "1984-09-15",
Expand Down
3 changes: 2 additions & 1 deletion document_merge_service/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ def mock_filefield_name_validation(mocker):
def docx_template_with_placeholder(admin_client, template):
"""Return a factory function to build a docx template with a given placeholder."""
template.engine = models.Template.DOCX_TEMPLATE
template.template = django_file("docx-template.docx")
template.save()

def make_template(placeholder):
engine = engines.get_engine(template.engine, django_file("docx-template.docx"))
engine = engines.get_engine(template.engine, template.template)
binary = BytesIO()
engine.merge({"test": placeholder}, binary)
binary.seek(0)
Expand Down
1 change: 0 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
-r requirements.txt
black==21.10b0
dj-inmemorystorage==2.1.0
factory-boy==3.2.1
flake8==4.0.1
flake8-debugger==4.0.0
Expand Down
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ filterwarnings =
error::PendingDeprecationWarning
env =
ADMINS=Test Example <test@example.com>,Test2 <test2@example.com>
FILE_STORAGE=inmemorystorage.InMemoryStorage
OIDC_USERINFO_ENDPOINT=mock://document-merge-service.github.com/openid/userinfo
OIDC_BEARER_TOKEN_REVALIDATION_TIME=60

Expand Down