def test_template_merge_jinja_filters_docx( db, client, template, snapshot, settings, tmp_path, missing_file, wrong_mime, status_code, ): 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({ "test_date": "1984-09-15", "test_time": "23:24", "test_datetime": "1984-09-15 23:23", "test_datetime2": "23:23-1984-09-15", "test_none": None, "test_nested": { "multiline": "This is\na test." }, }), } if not missing_file: file = django_file("black.png").file if wrong_mime: # create a file with the correct filename (black.png) but with # the contents of a docx. file = tmp_path / "black.png" for line in template.template.file: file.write_bytes(line) file = file.open("rb") data["files"] = [file] response = client.post(url, data=data, format="multipart") assert response.status_code == status_code if status_code == status.HTTP_200_OK: assert ( response._headers["content-type"][1] == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) docx = Document(io.BytesIO(response.content)) xml = etree.tostring(docx._element.body, encoding="unicode", pretty_print=True) snapshot.assert_match(xml)
def test_disable_validation( db, status_code, admin_client, settings, disable_validation, ): settings.REQUIRE_AUTHENTICATION = False url = reverse("template-list") template_file = django_file("docx-template-syntax.docx") data = { "slug": "test-slug", "template": template_file.file, "engine": models.Template.DOCX_TEMPLATE, } if disable_validation: data["disable_template_validation"] = disable_validation response = admin_client.post(url, data=data, format="multipart") assert response.status_code == status_code if status_code == status.HTTP_201_CREATED: data = response.json() template_link = data["template"] response = admin_client.get(template_link) assert response.status_code == status.HTTP_200_OK Document(io.BytesIO(response.content))
def test_template_create_with_available_placeholders( db, admin_client, engine, template_name, available_placeholders, sample_data, files, status_code, settings, expect_missing_placeholders, ): settings.DOCXTEMPLATE_JINJA_EXTENSIONS = ["jinja2.ext.loopcontrols"] url = reverse("template-list") template_file = django_file(template_name) data = { "slug": "test-slug", "template": template_file.file, "files": files, "engine": engine, } if sample_data: data["sample_data"] = json.dumps(sample_data) if available_placeholders: data["available_placeholders"] = available_placeholders response = admin_client.post(url, data=data, format="multipart") assert response.status_code == status_code, response.json() if status_code == status.HTTP_400_BAD_REQUEST: resp = response.json() expect_missing_str = "; ".join(expect_missing_placeholders) if sample_data and available_placeholders: # validation only allows one of these two params assert ( resp["non_field_errors"][0] == "Only one of available_placeholders and sample_data is allowed" ) elif engine == models.Template.DOCX_MAILMERGE and files: assert (resp["non_field_errors"][0] == 'Files are only accepted with the "docx-template" engine') elif not sample_data and files: assert (resp["non_field_errors"][0] == "Files are only accepted when also providing sample_data") else: # we expect some missing placeholders assert ( resp["non_field_errors"][0] == f"Template uses unavailable placeholders: {expect_missing_str}" ) if status_code == status.HTTP_201_CREATED: data = response.json() template_link = data["template"] response = admin_client.get(template_link) assert response.status_code == status.HTTP_200_OK Document(io.BytesIO(response.content))
def test_template_create( db, client, admin_client, engine, template_name, status_code, group, require_authentication, settings, authenticated, ): if authenticated: client = admin_client settings.REQUIRE_AUTHENTICATION = require_authentication url = reverse("template-list") template_file = django_file(template_name) data = { "slug": "test-slug", "template": template_file.file, "engine": engine } if group: data["group"] = group response = client.post(url, data=data, format="multipart") assert response.status_code == status_code if status_code == status.HTTP_201_CREATED: data = response.json() template_link = data["template"] response = client.get(template_link) assert response.status_code == status.HTTP_200_OK Document(io.BytesIO(response.content))
def test_template_merge_file_reset( db, client, template, settings, file_value, ): 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", "test_time": "23:24", "test_datetime": "1984-09-15 23:23", "test_datetime2": "23:23-1984-09-15", "test_none": None, "test_nested": {"multiline": "This is\na test."}, "black.png": file_value, } } response = client.post(url, data=data, format="json") assert response.status_code == status.HTTP_200_OK assert ( response._headers["content-type"][1] == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" )
def make_template(placeholder): engine = engines.get_engine(template.engine, django_file("docx-template.docx")) binary = BytesIO() engine.merge({"test": placeholder}, binary) binary.seek(0) template.template.save("foo.docx", binary) template.save() return template
def test_clean_dangling_files(db, dry, settings, template_factory): templates = [ template_factory(template=django_file("docx-template.docx")), template_factory(template=django_file("docx-template-syntax.docx")), ] dangling_files = [ django_file("docx-template-filters.docx"), django_file("docx-template-loopcontrols.docx"), ] call_command("clean_dangling_files", dry=dry) assert (all([ os.path.isfile(os.path.join(settings.MEDIA_ROOT, file.name)) is dry for file in dangling_files ]) is True) assert (all([ os.path.isfile(template.template.path) is True for template in templates ]) is True)
def test_template_update(db, client, template, template_name, status_code): url = reverse("template-detail", args=[template.pk]) template_file = django_file(template_name) data = {"description": "Test description", "template": template_file.file} response = client.patch(url, data=data, format="multipart") assert response.status_code == status_code if status_code == status.HTTP_200_OK: template.refresh_from_db() assert template.description == "Test description"
def docx_template_with_placeholder(admin_client, template): """Return a factory function to build a docx template with a given placeholder.""" engine = engines.get_engine(template.engine, django_file("docx-template.docx")) def make_template(placeholder): binary = BytesIO() engine.merge({"test": placeholder}, binary) binary.seek(0) template.template.save("foo.docx", binary) template.save() return template return make_template
def validate_template_syntax(self, available_placeholders=None, sample_data=None): try: doc = DocxTemplate(self.template) root = _MagicPlaceholder() env = get_jinja_env() ph = { name: root[name] for name in doc.get_undeclared_template_variables(env) } xml = doc.get_xml() xml = doc.patch_xml(xml) image_match = re.match(r".*{{\s?(\S*)\s?\|\s?image\(.*", xml) images = image_match.groups() if image_match else [] for image in images: cleaned_image = image.strip('"').strip("'") ph[root[cleaned_image]] = django_file("black.png").file ph["_tpl"] = doc doc.render(ph, env) if sample_data: sample_data["_tpl"] = doc doc.render(sample_data, env) self.validate_available_placeholders( used_placeholders=root.reports, available_placeholders=available_placeholders, ) except TemplateSyntaxError as exc: arg_str = ";".join(exc.args) raise exceptions.ValidationError( f"Syntax error in template: {arg_str}") finally: self.template.seek(0)
{ "foo": "hello", "bar": { "some_attr": True, "list": [{ "attribute": "value" }, { "attribute": "value2" }], }, "baz": "1234", "list": [{ "attribute": "value" }], }, [django_file("black.png").file], [], models.Template.DOCX_TEMPLATE, status.HTTP_201_CREATED, ), ( "docx-template-placeholdercheck.docx", None, {}, [django_file("black.png").file], [], models.Template.DOCX_TEMPLATE, status.HTTP_400_BAD_REQUEST, ), ( "docx-template-placeholdercheck.docx",