From ee834d6198fa3315facd23a734655adf391bb736 Mon Sep 17 00:00:00 2001 From: Miguel Ribeiro Date: Tue, 22 Oct 2024 09:10:53 +0200 Subject: [PATCH] feat: handle webhook payload as string if it is not a json object (#583) --- endpoints/cronjobs/sendnotifications.php | 162 ++++++++++++------ .../testwebhooknotifications.php | 11 +- includes/version.php | 2 +- 3 files changed, 113 insertions(+), 62 deletions(-) diff --git a/endpoints/cronjobs/sendnotifications.php b/endpoints/cronjobs/sendnotifications.php index 3996d8312..693497f2a 100644 --- a/endpoints/cronjobs/sendnotifications.php +++ b/endpoints/cronjobs/sendnotifications.php @@ -276,7 +276,7 @@ return $value !== $emailaddress; }); - foreach($list as $value) { + foreach ($list as $value) { $mail->addCC(trim($value)); } } @@ -536,77 +536,129 @@ // Webhook notifications if enabled if ($webhookNotificationsEnabled) { + // Get webhook payload and turn it into a json object $payload = str_replace("{{days_until}}", $days, $webhook['payload']); $payload_json = json_decode($payload, true); - if ($payload_json === null) { - echo "Error parsing payload JSON
"; - continue; - } + // If the payload is valid json, iterate the object and replace the placeholders with the subscription data (all subscriptions in one payload) + if ($payload_json !== null) { + $subscription_template = $payload_json[$webhook['iterator']]; + $subscriptions = []; - $subscription_template = $payload_json[$webhook['iterator']]; - $subscriptions = []; - - foreach ($notify as $userId => $perUser) { - // Get name of user from household table - $stmt = $db->prepare('SELECT * FROM household WHERE id = :userId'); - $stmt->bindValue(':userId', $userId, SQLITE3_INTEGER); - $result = $stmt->execute(); - $user = $result->fetchArray(SQLITE3_ASSOC); + foreach ($notify as $userId => $perUser) { + // Get name of user from household table + $stmt = $db->prepare('SELECT * FROM household WHERE id = :userId'); + $stmt->bindValue(':userId', $userId, SQLITE3_INTEGER); + $result = $stmt->execute(); + $user = $result->fetchArray(SQLITE3_ASSOC); - if ($user['name']) { - $payer = $user['name']; - } + if ($user['name']) { + $payer = $user['name']; + } - foreach ($perUser as $k => $subscription) { - $temp_subscription = $subscription_template[0]; - - foreach ($temp_subscription as $key => $value) { - if (is_string($value)) { - $temp_subscription[$key] = str_replace("{{subscription_name}}", $subscription['name'], $value); - $temp_subscription[$key] = str_replace("{{subscription_price}}", $subscription['price'], $temp_subscription[$key]); - $temp_subscription[$key] = str_replace("{{subscription_currency}}", $subscription['currency'], $temp_subscription[$key]); - $temp_subscription[$key] = str_replace("{{subscription_category}}", $subscription['category'], $temp_subscription[$key]); - $temp_subscription[$key] = str_replace("{{subscription_payer}}", $subscription['payer'], $temp_subscription[$key]); - $temp_subscription[$key] = str_replace("{{subscription_date}}", $subscription['date'], $temp_subscription[$key]); - $temp_subscription[$key] = str_replace("{{subscription_days_until_payment}}", $subscription['days'], $temp_subscription[$key]); - $temp_subscription[$key] = str_replace("{{subscription_url}}", $subscription['url'], $temp_subscription[$key]); - $temp_subscription[$key] = str_replace("{{subscription_notes}}", $subscription['notes'], $temp_subscription[$key]); + foreach ($perUser as $k => $subscription) { + $temp_subscription = $subscription_template[0]; + + foreach ($temp_subscription as $key => $value) { + if (is_string($value)) { + $temp_subscription[$key] = str_replace("{{subscription_name}}", $subscription['name'], $value); + $temp_subscription[$key] = str_replace("{{subscription_price}}", $subscription['price'], $temp_subscription[$key]); + $temp_subscription[$key] = str_replace("{{subscription_currency}}", $subscription['currency'], $temp_subscription[$key]); + $temp_subscription[$key] = str_replace("{{subscription_category}}", $subscription['category'], $temp_subscription[$key]); + $temp_subscription[$key] = str_replace("{{subscription_payer}}", $subscription['payer'], $temp_subscription[$key]); + $temp_subscription[$key] = str_replace("{{subscription_date}}", $subscription['date'], $temp_subscription[$key]); + $temp_subscription[$key] = str_replace("{{subscription_days_until_payment}}", $subscription['days'], $temp_subscription[$key]); + $temp_subscription[$key] = str_replace("{{subscription_url}}", $subscription['url'], $temp_subscription[$key]); + $temp_subscription[$key] = str_replace("{{subscription_notes}}", $subscription['notes'], $temp_subscription[$key]); + } } + $subscriptions[] = $temp_subscription; + } - $subscriptions[] = $temp_subscription; + } + // remove {{ and }} from the iterator + $payload_iterator = str_replace("{{", "", $webhook['iterator']); + $payload_iterator = str_replace("}}", "", $payload_iterator); + + $payload_json["{{subscriptions}}"] = $subscriptions; + $payload_json[$payload_iterator] = $subscriptions; + unset($payload_json["{{subscriptions}}"]); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $webhook['url']); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $webhook['request_method']); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload_json)); + if (!empty($webhook['headers'])) { + $customheaders = preg_split("/\r\n|\n|\r/", $webhook['headers']); + curl_setopt($ch, CURLOPT_HTTPHEADER, $customheaders); } - } + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - // remove {{ and }} from the iterator - $payload_iterator = str_replace("{{", "", $webhook['iterator']); - $payload_iterator = str_replace("}}", "", $payload_iterator); - - $payload_json["{{subscriptions}}"] = $subscriptions; - $payload_json[$payload_iterator] = $subscriptions; - unset($payload_json["{{subscriptions}}"]); - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $webhook['url']); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $webhook['request_method']); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload_json)); - if (!empty($webhook['headers'])) { - $customheaders = preg_split("/\r\n|\n|\r/", $webhook['headers']); - curl_setopt($ch, CURLOPT_HTTPHEADER, $customheaders); + $response = curl_exec($ch); + curl_close($ch); + + if ($response === false) { + echo "Error sending notifications: " . curl_error($ch) . "
"; + } else { + echo "Webhook Notifications sent
"; + } } - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $response = curl_exec($ch); - curl_close($ch); - if ($response === false) { - echo "Error sending notifications: " . curl_error($ch) . "
"; - } else { - echo "Webhook Notifications sent
"; + // If the payload is not valid json, send it directly as a string, replacing the placeholders with the subscription data (one notification per subscription) + + if ($payload_json === null) { + foreach ($notify as $userId => $perUser) { + // Get name of user from household table + $stmt = $db->prepare('SELECT * FROM household WHERE id = :userId'); + $stmt->bindValue(':userId', $userId, SQLITE3_INTEGER); + $result = $stmt->execute(); + $user = $result->fetchArray(SQLITE3_ASSOC); + + if ($user['name']) { + $payer = $user['name']; + } + + foreach ($perUser as $k => $subscription) { + // Ensure the payload is reset for each subscription + $payload = $webhook['payload']; + $payload = str_replace("{{subscription_name}}", $subscription['name'], $payload); + $payload = str_replace("{{subscription_price}}", $subscription['price'], $payload); + $payload = str_replace("{{subscription_currency}}", $subscription['currency'], $payload); + $payload = str_replace("{{subscription_category}}", $subscription['category'], $payload); + $payload = str_replace("{{subscription_payer}}", $payer, $payload); // Use $payer instead of $subscription['payer'] + $payload = str_replace("{{subscription_date}}", $subscription['date'], $payload); + $payload = str_replace("{{subscription_days_until_payment}}", $subscription['days'], $payload); + $payload = str_replace("{{subscription_url}}", $subscription['url'], $payload); + $payload = str_replace("{{subscription_notes}}", $subscription['notes'], $payload); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $webhook['url']); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $webhook['request_method']); + curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); + if (!empty($webhook['headers'])) { + $customheaders = preg_split("/\r\n|\n|\r/", $webhook['headers']); + curl_setopt($ch, CURLOPT_HTTPHEADER, $customheaders); + } + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $response = curl_exec($ch); + curl_close($ch); + + if ($response === false) { + echo "Error sending notifications: " . curl_error($ch) . "
"; + } else { + echo "Webhook Notification sent
"; + } + + // Delay for 200 milliseconds + usleep(500000); + } + } } } diff --git a/endpoints/notifications/testwebhooknotifications.php b/endpoints/notifications/testwebhooknotifications.php index 221c2fded..8148f620d 100644 --- a/endpoints/notifications/testwebhooknotifications.php +++ b/endpoints/notifications/testwebhooknotifications.php @@ -24,10 +24,6 @@ ]; die(json_encode($response)); } else { - // Set the message parameters - $title = translate('wallos_notification', $i18n); - $message = translate('test_notification', $i18n); - $requestmethod = $data["requestmethod"]; $url = $data["url"]; $payload = $data["payload"]; @@ -47,6 +43,7 @@ // Execute the request $response = curl_exec($ch); + // Close the cURL session curl_close($ch); @@ -54,12 +51,14 @@ if ($response === false) { die(json_encode([ "success" => false, - "message" => translate('notification_failed', $i18n) + "message" => translate('notification_failed', $i18n), + "response" => curl_error($ch) ])); } else { die(json_encode([ "success" => true, - "message" => translate('notification_sent_successfuly', $i18n) + "message" => translate('notification_sent_successfuly', $i18n), + "response" => $response ])); } } diff --git a/includes/version.php b/includes/version.php index 6a16e17f9..e6ab29fe4 100644 --- a/includes/version.php +++ b/includes/version.php @@ -1,3 +1,3 @@ \ No newline at end of file