mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 16:14:02 +00:00
integrations: Fix Jotform integration by accepting form-data payloads.
This does not add support for files. Fixes part of #32460. Co-authored by: PieterCK <pieterceka123@gmail.com>
This commit is contained in:
@@ -29,6 +29,7 @@ IGNORED_PHRASES = [
|
||||
r"IP",
|
||||
r"JSON",
|
||||
r"Jitsi",
|
||||
r"Jotform",
|
||||
r"Kerberos",
|
||||
r"LinkedIn",
|
||||
r"LDAP",
|
||||
|
@@ -755,7 +755,7 @@ DOC_SCREENSHOT_CONFIG: dict[str, list[BaseScreenshotConfig]] = {
|
||||
"insping": [ScreenshotConfig("website_state_available.json")],
|
||||
"intercom": [ScreenshotConfig("conversation_admin_replied.json")],
|
||||
"jira": [ScreenshotConfig("created_v1.json")],
|
||||
"jotform": [ScreenshotConfig("response.json")],
|
||||
"jotform": [ScreenshotConfig("response.multipart")],
|
||||
"json": [ScreenshotConfig("json_github_push__1_commit.json")],
|
||||
"librato": [ScreenshotConfig("three_conditions_alert.json", payload_as_query_param=True)],
|
||||
"lidarr": [ScreenshotConfig("lidarr_album_grabbed.json")],
|
||||
|
File diff suppressed because one or more lines are too long
93
zerver/webhooks/jotform/fixtures/response.multipart
Normal file
93
zerver/webhooks/jotform/fixtures/response.multipart
Normal file
@@ -0,0 +1,93 @@
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="action"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="webhookURL"
|
||||
|
||||
https://3a95-27-5-198-172.ngrok-free.app/api/v1/external/jotform?api_key=DhXGrkyy2bK2SXMQMXwhs95H4kVVwv2w
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="username"
|
||||
|
||||
UserNiloth
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="formID"
|
||||
|
||||
243231271343446
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="type"
|
||||
|
||||
WEB
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="customParams"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="product"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="formTitle"
|
||||
|
||||
Tutor Appointment Form
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="customTitle"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="submissionID"
|
||||
|
||||
6084250982513018472
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="event"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="documentID"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="teamID"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="subject"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="isSilent"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="customBody"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="rawRequest"
|
||||
|
||||
{"slug":"submit\/243231271343446","jsExecutionTracker":"build-date-1732271172685=>init-started:1732615894703=>validator-called:1732615894706=>validator-mounted-false:1732615894706=>init-complete:1732615894707=>onsubmit-fired:1732615897940=>observerSubmitHandler_received-submit-event:1732615897941=>submit-validation-passed:1732615897942=>observerSubmitHandler_validation-passed-submitting-form:1732615897944","submitSource":"form","buildDate":"1732271172685","uploadServerUrl":"https:\/\/upload.jotform.com\/upload","eventObserver":"1","q3_studentsName":{"first":"Niloth","last":"P"},"q33_typeOf":"Online Tutoring","q34_subjectFor":"Math","q35_grade":"12","q28_appointment":{"implementation":"new","date":"","duration":"60","timezone":"Asia\/Calcutta (GMT+06:30)"},"timeToSubmit":"3","preview":"true","validatedNewRequiredFieldIDs":"{\"new\":1}","path":"\/submit\/243231271343446"}
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="fromTable"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="appID"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="pretty"
|
||||
|
||||
Student's Name:Niloth P, Type of Tutoring:Online Tutoring, Subject for Tutoring:Math, Grade:12
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="unread"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="parent"
|
||||
|
||||
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv
|
||||
Content-Disposition: form-data; name="ip"
|
||||
|
||||
27.51.18.17
|
||||
--------------------------J1JNT4vbVO4FCC1qLG4HSv--
|
@@ -1,4 +1,7 @@
|
||||
from typing_extensions import override
|
||||
|
||||
from zerver.lib.test_classes import WebhookTestCase
|
||||
from zerver.lib.webhooks.common import parse_multipart_string
|
||||
|
||||
|
||||
class JotformHookTests(WebhookTestCase):
|
||||
@@ -7,15 +10,25 @@ class JotformHookTests(WebhookTestCase):
|
||||
WEBHOOK_DIR_NAME = "jotform"
|
||||
|
||||
def test_response(self) -> None:
|
||||
expected_title = "Form"
|
||||
expected_title = "Tutor Appointment Form"
|
||||
expected_message = """
|
||||
* **Name**: Gaurav Pandey
|
||||
* **Address**: Lampgarden-street wolfsquare Bengaluru Karnataka 165578
|
||||
* **Signature**: uploads/gauravguitarrocks/202944822449057/4791133489169827307/4791133489169827307_signature_4.png""".strip()
|
||||
* **Student's Name**: Niloth P
|
||||
* **Type of Tutoring**: Online Tutoring
|
||||
* **Subject for Tutoring**: Math
|
||||
* **Grade**: 12""".strip()
|
||||
|
||||
self.check_webhook(
|
||||
"response",
|
||||
expected_title,
|
||||
expected_message,
|
||||
content_type="application/x-www-form-urlencoded",
|
||||
content_type="multipart/form-data",
|
||||
)
|
||||
|
||||
def test_bad_payload(self) -> None:
|
||||
with self.assertRaisesRegex(AssertionError, "Unable to handle Jotform payload"):
|
||||
self.check_webhook("response")
|
||||
|
||||
@override
|
||||
def get_payload(self, fixture_name: str) -> dict[str, str]:
|
||||
body = self.webhook_fixture_data("jotform", fixture_name, file_type="multipart")
|
||||
return parse_multipart_string(body)
|
||||
|
@@ -1,29 +1,33 @@
|
||||
# Webhooks for external integrations.
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from zerver.decorator import webhook_view
|
||||
from zerver.lib.exceptions import JsonableError
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.typed_endpoint import JsonBodyPayload, typed_endpoint
|
||||
from zerver.lib.validator import WildValue, check_string
|
||||
from zerver.lib.typed_endpoint import typed_endpoint_without_parameters
|
||||
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||
from zerver.models import UserProfile
|
||||
|
||||
|
||||
@webhook_view("Jotform")
|
||||
@typed_endpoint
|
||||
@typed_endpoint_without_parameters
|
||||
def api_jotform_webhook(
|
||||
request: HttpRequest,
|
||||
user_profile: UserProfile,
|
||||
*,
|
||||
payload: JsonBodyPayload[WildValue],
|
||||
) -> HttpResponse:
|
||||
topic_name = payload["formTitle"].tame(check_string)
|
||||
fields = payload["pretty"].tame(check_string).split(", ")
|
||||
payload = request.POST
|
||||
topic_name = payload.get("formTitle")
|
||||
fields = payload.get("pretty", "").split(", ")
|
||||
|
||||
if not topic_name or not fields:
|
||||
raise JsonableError(_("Unable to handle Jotform payload"))
|
||||
|
||||
form_response = ""
|
||||
for field in fields:
|
||||
label, value = field.split(":", 1)
|
||||
# TODO: Add fixtures and tests for question-like fields and files
|
||||
separator = " " if label.endswith("?") else ": "
|
||||
form_response += f"* **{label}**{separator}{value}\n"
|
||||
message = form_response.strip()
|
||||
|
Reference in New Issue
Block a user