diff --git a/src/backend/core/models.py b/src/backend/core/models.py index e0030d52..94d84cfe 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -3,7 +3,6 @@ Declare and configure the models for the impress core application """ import hashlib -import os import tempfile import textwrap import uuid @@ -609,26 +608,25 @@ class Template(BaseModel): """ reference_docx = "core/static/reference.docx" + output = BytesIO() # Convert the HTML to a temporary docx file - with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as tmp_file: + with tempfile.NamedTemporaryFile(suffix=".docx", prefix="docx_") as tmp_file: output_path = tmp_file.name - pypandoc.convert_text( - html_string, - "docx", - format="html", - outputfile=output_path, - extra_args=["--reference-doc", reference_docx], - ) + pypandoc.convert_text( + html_string, + "docx", + format="html", + outputfile=output_path, + extra_args=["--reference-doc", reference_docx], + ) - # Create a BytesIO object to store the output of the temporary docx file - with open(output_path, "rb") as f: - output = BytesIO(f.read()) - - # Remove the temporary docx file - os.remove(output_path) + # Create a BytesIO object to store the output of the temporary docx file + with open(output_path, "rb") as f: + output = BytesIO(f.read()) + # Ensure the pointer is at the beginning output.seek(0) response = FileResponse( @@ -636,6 +634,7 @@ class Template(BaseModel): content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) response["Content-Disposition"] = f"attachment; filename={self.title}.docx" + return response def generate_document(self, body, body_type, export_format): diff --git a/src/backend/core/tests/test_models_templates.py b/src/backend/core/tests/test_models_templates.py index c086b063..f6a48fd4 100644 --- a/src/backend/core/tests/test_models_templates.py +++ b/src/backend/core/tests/test_models_templates.py @@ -2,6 +2,9 @@ Unit tests for the Template model """ +import os +from unittest import mock + from django.contrib.auth.models import AnonymousUser from django.core.exceptions import ValidationError @@ -185,3 +188,30 @@ def test_models_templates_get_abilities_preset_role(django_assert_num_queries): "partial_update": False, "generate_document": True, } + + +def test_models_templates__generate_word(): + """Generate word document and assert no tmp files are left in /tmp folder.""" + template = factories.TemplateFactory() + response = template.generate_word("
Test body
", {}) + + assert response.status_code == 200 + assert len([f for f in os.listdir("/tmp") if f.startswith("docx_")]) == 0 + + +@mock.patch( + "pypandoc.convert_text", + side_effect=RuntimeError("Conversion failed"), +) +def test_models_templates__generate_word__raise_error(_mock_send_mail): + """ + Generate word document and assert no tmp files are left in /tmp folder + even when the conversion fails. + """ + template = factories.TemplateFactory() + + try: + template.generate_word("Test body
", {}) + except RuntimeError as e: + assert str(e) == "Conversion failed" + assert len([f for f in os.listdir("/tmp") if f.startswith("docx_")]) == 0