updates mailgun webhook loading message data on runtime

This commit is contained in:
paulwer 2024-03-19 12:56:39 +01:00
parent 0aaaf27314
commit 73bcf928e4
4 changed files with 48 additions and 63 deletions

View File

@ -1,47 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Helpers\IngresMail\Transformer;
use App\Services\IngresEmail\IngresEmail;
use App\Utils\TempFile;
use Illuminate\Support\Carbon;
class MailgunInboundWebhookTransformer
{
public function transform($data)
{
$ingresEmail = new IngresEmail();
$ingresEmail->from = $data["sender"]; // TODO: maybe a fallback have to be used to extract email from $data["From"]
$ingresEmail->to = $data["recipient"]; // TODO: maybe a fallback have to be used to extract email from $data["To"]
$ingresEmail->subject = $data["Subject"];
$ingresEmail->body = $data["body-html"];
$ingresEmail->text_body = $data["body-plain"];
$ingresEmail->date = Carbon::createFromTimestamp((int) $data["timestamp"]);
// parse documents as UploadedFile from webhook-data
foreach (json_decode($data["attachments"]) as $attachment) {
// prepare url with credentials before downloading :: https://github.com/mailgun/mailgun.js/issues/24
$url = $attachment->url;
$credentials = config('services.mailgun.domain') . ":" . config('services.mailgun.secret') . "@";
$url = str_replace("http://", "http://" . $credentials, $url);
$url = str_replace("https://", "https://" . $credentials, $url);
// download file and save to tmp dir
$ingresEmail->documents[] = TempFile::UploadedFileFromUrl($url, $attachment->name, $attachment->{"content-type"});
}
return $ingresEmail;
}
}

View File

@ -115,19 +115,24 @@ class MailgunController extends BaseController
{
$input = $request->all();
if (!array_key_exists('recipient', $input) || !array_key_exists('message-url', $input)) {
Log::info('Failed: Message could not be parsed, because required parameters are missing. Please ensure contacting this api-endpoint with a store & notify operation instead of a forward operation!');
return response()->json(['message' => 'Failed. Missing Parameters'], 400);
}
if (!array_key_exists('attachments', $input) || count(json_decode($input['attachments'])) == 0) {
Log::info('Message ignored because of missing attachments. Please ensure contacting this api-endpoint with a store & notify operation instead of a forward operation');
Log::info('Message ignored because of missing attachments. No Actions would have been taken...');
return response()->json(['message' => 'Sucess. Soft Fail. Missing Attachments.'], 200);
}
if (\abs(\time() - (int) $request['timestamp']) > 150) {
if (\abs(\time() - (int) $input['timestamp']) > 150) {
Log::info('Message ignored because of request body is too old.');
return response()->json(['message' => 'Success. Soft Fail. Message too old.'], 200);
}
// @turbo124 TODO: how to check for services.mailgun.webhook_signing_key on company level, when custom credentials are defined
if (\hash_equals(\hash_hmac('sha256', $input['timestamp'] . $input['token'], config('services.mailgun.webhook_signing_key')), $input['signature'])) {
ProcessMailgunInboundWebhook::dispatch($input)->delay(10);
ProcessMailgunInboundWebhook::dispatch($input["recipient"] . "|" . $input["message-url"])->delay(10);
return response()->json(['message' => 'Success'], 201);
}

View File

@ -11,9 +11,11 @@
namespace App\Jobs\Mailgun;
use App\Helpers\IngresMail\Transformer\MailgunInboundWebhookTransformer;
use App\Libraries\MultiDB;
use App\Services\IngresEmail\IngresEmail;
use App\Services\IngresEmail\IngresEmailEngine;
use App\Utils\TempFile;
use Illuminate\Support\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
@ -29,9 +31,9 @@ class ProcessMailgunInboundWebhook implements ShouldQueue
/**
* Create a new job instance.
*
* $input consists of 2 informations: recipient|messageUrl
*/
public function __construct(private array $request)
public function __construct(private string $input)
{
}
@ -43,21 +45,48 @@ class ProcessMailgunInboundWebhook implements ShouldQueue
*/
public function handle()
{
if (!array_key_exists('To', $this->request) || !array_key_exists('attachments', $this->request) || !array_key_exists('timestamp', $this->request) || !array_key_exists('Subject', $this->request) || !(array_key_exists('body-html', $this->request) || array_key_exists('body-plain', $this->request)))
throw new \Exception('invalid body');
$recipient = explode("|", $this->input)[0];
// match company
$company = MultiDB::findAndSetDbByExpenseMailbox($this->request["To"]);
$company = MultiDB::findAndSetDbByExpenseMailbox($recipient);
if (!$company) {
Log::info('unknown Expense Mailbox occured while handling an inbound email from mailgun: ' . $this->request["To"]);
Log::info('unknown Expense Mailbox occured while handling an inbound email from mailgun: ' . $recipient);
return;
}
// prepare
$ingresMail = (new MailgunInboundWebhookTransformer())->transform($this->request);
Log::info(json_encode($ingresMail));
// fetch message from mailgun-api
$mailgun_domain = $company->settings?->email_sending_method === 'client_mailgun' && $company->settings?->mailgun_domain ? $company->settings?->mailgun_domain : config('services.mailgun.domain');
$mailgun_secret = $company->settings?->email_sending_method === 'client_mailgun' && $company->settings?->mailgun_secret ? $company->settings?->mailgun_secret : config('services.mailgun.secret');
$credentials = $mailgun_domain . ":" . $mailgun_secret . "@";
$messageUrl = explode("|", $this->input)[1];
$messageUrl = str_replace("http://", "http://" . $credentials, $messageUrl);
$messageUrl = str_replace("https://", "https://" . $credentials, $messageUrl);
$mail = json_decode(file_get_contents($messageUrl));
// prepare data for ingresEngine
$ingresEmail = new IngresEmail();
$ingresEmail->from = $mail->sender;
$ingresEmail->to = $recipient; // usage of data-input, because we need a single email here
$ingresEmail->subject = $mail->Subject;
$ingresEmail->body = $mail->{"body-html"};
$ingresEmail->text_body = $mail->{"body-plain"};
$ingresEmail->date = Carbon::createFromTimeString($mail->Date);
// parse documents as UploadedFile from webhook-data
foreach ($mail->attachments as $attachment) {
// prepare url with credentials before downloading :: https://github.com/mailgun/mailgun.js/issues/24
$url = $attachment->url;
$url = str_replace("http://", "http://" . $credentials, $url);
$url = str_replace("https://", "https://" . $credentials, $url);
// download file and save to tmp dir
$ingresEmail->documents[] = TempFile::UploadedFileFromUrl($url, $attachment->name, $attachment->{"content-type"});
}
// perform
(new IngresEmailEngine($ingresMail))->handle();
(new IngresEmailEngine($ingresEmail))->handle();
}
}

View File

@ -182,8 +182,6 @@ class IngresEmailEngine
$expense->saveQuietly();
Log::info(json_encode($documents));
$this->saveDocuments($documents, $expense);
event(new ExpenseWasCreated($expense, $expense->company, Ninja::eventVars(null))); // @turbo124 please check, I copied from API-Controller