From 0453b9d3d000ea293ce2cbabcb61e74960f9a595 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 8 Dec 2025 16:02:45 +0100 Subject: [PATCH] Updated to submission completed. --- webhook_listener.py | 59 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/webhook_listener.py b/webhook_listener.py index 923d8f3..ae2dc51 100644 --- a/webhook_listener.py +++ b/webhook_listener.py @@ -47,7 +47,10 @@ def signature_required(f): def decorated_function(*args, **kwargs): if DISABLE_VERIFICATION: app.logger.info("Webhook secret verification is DISABLED.") - # ... (rest of signature check logic) + return f(*args, **kwargs) + + # Verify specific to DocuSeal logic usually goes here + # (Assuming your original verification logic was here) return f(*args, **kwargs) return decorated_function @@ -55,32 +58,61 @@ def signature_required(f): @app.route('/webhook/docuseal', methods=['POST']) @signature_required def docuseal_webhook(): - """Main webhook endpoint with advanced filename and audit log control.""" + """Main webhook endpoint handling form.completed and submission.completed.""" app.logger.info(f"Webhook endpoint hit by {request.remote_addr}") json_data = request.get_json() if not json_data: app.logger.error("Received request with invalid or missing JSON body.") return 'Invalid JSON', 400 - if json_data.get('event_type') == 'form.completed': - app.logger.info("Received 'form.completed' event.") - data = json_data.get('data', {}) - submission = data.get('submission', {}) + event_type = json_data.get('event_type') + + # Handle both 'form.completed' (old) and 'submission.completed' (new) + if event_type in ['form.completed', 'submission.completed']: + app.logger.info(f"Received '{event_type}' event.") + data = json_data.get('data', {}) + submission = data.get('submission', {}) # Might be empty in 'submission.completed' + + # --- Extract Submitter Info --- + # 1. Try top-level data (form.completed) submitter_name = data.get('name') submitter_email = data.get('email') + # 2. If null, try extracting from 'submitters' list (submission.completed) + if not submitter_name and not submitter_email: + submitters_list = data.get('submitters', []) + # Priority: Try to find a Name first + for person in submitters_list: + if person.get('name'): + submitter_name = person.get('name') + break + + # If still no name, try to find an Email + if not submitter_name: + for person in submitters_list: + if person.get('email'): + submitter_email = person.get('email') + break + + if submitter_name: + app.logger.info(f"Identified submitter name from list: {submitter_name}") + elif submitter_email: + app.logger.info(f"Identified submitter email from list: {submitter_email}") + urls_to_process = [] - # <-- KEY CHANGE: Conditionally add the audit log URL --> + # --- Handle Audit Log --- if not SKIP_AUDIT_LOG: + # Check submission object first, then data object audit_log_url = submission.get('audit_log_url') or data.get('audit_log_url') if audit_log_url: urls_to_process.append(audit_log_url) else: - app.logger.info("Skipping audit log download as per configuration (SKIP_AUDIT_LOG=true).") + app.logger.info("Skipping audit log download (SKIP_AUDIT_LOG=true).") - # Add all other document URLs + # --- Handle Documents --- + # The structure for documents is identical in both event types for document in data.get('documents', []): if document.get('url'): urls_to_process.append(document.get('url')) @@ -97,7 +129,10 @@ def docuseal_webhook(): download_thread = threading.Thread(target=download_document, args=thread_args) download_thread.start() - return jsonify(status="acknowledged"), 200 + return jsonify(status="acknowledged"), 200 + + app.logger.info(f"Ignored event type: {event_type}") + return jsonify(status="ignored_event_type"), 200 def download_document(url, logger, consume_dir, submitter_name, submitter_email): @@ -114,6 +149,8 @@ def download_document(url, logger, consume_dir, submitter_name, submitter_email) if APPEND_SUBMITTER_INFO: identifier = submitter_name or submitter_email if identifier: + # Clean identifier slightly to be filesystem safe + identifier = "".join([c for c in identifier if c.isalnum() or c in " ._-@"]).strip() prefix = f"{identifier} - " timestamp = "" @@ -148,4 +185,4 @@ def download_document(url, logger, consume_dir, submitter_name, submitter_email) @app.route('/health', methods=['GET']) def health_check(): """A simple health check endpoint.""" - return "OK", 200 + return "OK", 200 \ No newline at end of file