Skip to content

Commit

Permalink
🐛 [#4980] Revise how attachments are processed
Browse files Browse the repository at this point in the history
There was a bug with the previous attachment processing, where attachments would get overwritten if multiple were uploaded
  • Loading branch information
viktorvanwijk committed Jan 14, 2025
1 parent 5eadd68 commit dae322a
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 12 deletions.
70 changes: 59 additions & 11 deletions src/openforms/registrations/contrib/json_dump/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

from zgw_consumers.client import build_client

from openforms.submissions.models import Submission
from openforms.formio.typing import Component
from openforms.submissions.models import Submission, SubmissionValueVariable, \
SubmissionFileAttachment
from openforms.typing import JSONObject
from openforms.variables.service import get_static_variables

from ...base import BasePlugin # openforms.registrations.base
from ...registry import register # openforms.registrations.registry
Expand All @@ -33,15 +34,8 @@ def register_submission(
if key in options["form_variables"]
}

# Encode (base64) and add attachments to values dict if their form keys were specified in the
# form variables list
for attachment in submission.attachments:
if attachment.form_key not in options["form_variables"]:
continue
options["form_variables"].remove(attachment.form_key)
with attachment.content.open("rb") as f:
f.seek(0)
values[attachment.form_key] = base64.b64encode(f.read()).decode()
# Process attachments
self.process_variables(submission, values)

# Generate schema
# TODO: will be added in #4980. Hardcoded example for now.
Expand Down Expand Up @@ -76,3 +70,57 @@ def register_submission(
def check_config(self) -> None:
# Config checks are not really relevant for this plugin right now
pass

@staticmethod
def process_variables(submission: Submission, values: JSONObject):
"""Process variables.
File components need special treatment, as we send the content of the file
encoded with base64, instead of the output from the serializer.
"""
state = submission.load_submission_value_variables_state()

for key in values.keys():
variable = state.variables.get(key)
if variable is None:
# None for static variables
continue

component = get_component(variable)
if component is None or component["type"] != "file":
continue

encoded_attachments = {
attachment.file_name: encode_attachment(attachment)
for attachment in submission.attachments
if attachment.form_key == key
}
multiple = component.get("multiple", False)
values[key] = (
encoded_attachments
if multiple
else list(encoded_attachments.values())[0]
)


def encode_attachment(attachment: SubmissionFileAttachment) -> str:
"""Encode an attachment using base64
:param attachment: Attachment to encode
:returns: Encoded base64 data as a string
"""
with attachment.content.open("rb") as f:
f.seek(0)
return base64.b64encode(f.read()).decode()


def get_component(variable: SubmissionValueVariable) -> Component:
"""Get the component from a submission value variable.
:param variable: SubmissionValueVariable
:return component: Component
"""
config_wrapper = variable.form_variable.form_definition.configuration_wrapper
component = config_wrapper.component_map[variable.key]

return component
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
VCR_TEST_FILES = Path(__file__).parent / "files"


class JSONDumpBackendTests(OFVCRMixin, TestCase):
class JSONDumpBackendTests(TestCase):
VCR_TEST_FILES = VCR_TEST_FILES

def test_submission_with_json_dump_backend(self):
Expand Down Expand Up @@ -116,3 +116,65 @@ def test_exception_raised_when_service_returns_unexpected_status_code(self):

with self.assertRaises(RequestException):
json_plugin.register_submission(submission, json_form_options)

def test_multiple_file_uploads(self):
submission = SubmissionFactory.from_components(
[{"key": "file", "type": "file", "multiple": True}],
completed=True,
submitted_data={
"file": [
{
"url": "some://url",
"name": "file1.txt",
"type": "application/text",
"originalName": "file1.txt",
},
{
"url": "some://url",
"name": "file2.txt",
"type": "application/text",
"originalName": "file2.txt",
}
],
},
)

SubmissionFileAttachmentFactory.create(
form_key="file",
submission_step=submission.submissionstep_set.get(),
file_name="file1.txt",
content_type="application/text",
content__data=b"This is example content.",
_component_configuration_path="components.2",
_component_data_path="file",
)

SubmissionFileAttachmentFactory.create(
form_key="file",
submission_step=submission.submissionstep_set.get(),
file_name="file2.txt",
content_type="application/text",
content__data=b"Content example is this.",
_component_configuration_path="components.2",
_component_data_path="file",
)

json_form_options = dict(
service=(ServiceFactory(api_root="http://localhost:80/")),
relative_api_endpoint="json_plugin",
form_variables=["file"],
)
json_plugin = JSONDumpRegistration("json_registration_plugin")
set_submission_reference(submission)

expected_values = {
"file": {
"file1.txt": "VGhpcyBpcyBleGFtcGxlIGNvbnRlbnQu", # This is example content.
"file2.txt": "Q29udGVudCBleGFtcGxlIGlzIHRoaXMu", # Content example is this.
},
}

res = json_plugin.register_submission(submission, json_form_options)
res_json = res["api_response"]

self.assertEqual(res_json["data"]["values"], expected_values)

0 comments on commit dae322a

Please sign in to comment.