diff --git a/app/Http/Controllers/PostMarkController.php b/app/Http/Controllers/PostMarkController.php index b7a630cb51d1..44227ce9c8f1 100644 --- a/app/Http/Controllers/PostMarkController.php +++ b/app/Http/Controllers/PostMarkController.php @@ -11,6 +11,7 @@ namespace App\Http\Controllers; +use App\Jobs\PostMark\ProcessPostmarkInboundWebhook; use App\Jobs\PostMark\ProcessPostmarkWebhook; use Illuminate\Http\Request; @@ -69,4 +70,49 @@ class PostMarkController extends BaseController return response()->json(['message' => 'Unauthorized'], 403); } + + /** + * Process Postmark Webhook. + * + * + * @OA\Post( + * path="/api/v1/postmark_inbound_webhook", + * operationId="postmarkInboundWebhook", + * tags={"postmark"}, + * summary="Processing inbound webhooks from PostMark", + * description="Adds an credit to the system", + * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Response( + * response=200, + * description="Returns the saved credit object", + * @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Credit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + */ + public function inboundWebhook(Request $request) + { + if ($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('services.postmark.token')) { + ProcessPostmarkInboundWebhook::dispatch($request->all())->delay(10); + + return response()->json(['message' => 'Success'], 200); + } + + return response()->json(['message' => 'Unauthorized'], 403); + } } diff --git a/app/Jobs/PostMark/ProcessPostmarkInboundWebhook.php b/app/Jobs/PostMark/ProcessPostmarkInboundWebhook.php new file mode 100644 index 000000000000..2d2355b234bc --- /dev/null +++ b/app/Jobs/PostMark/ProcessPostmarkInboundWebhook.php @@ -0,0 +1,180 @@ + '', + 'subject' => 'Message not found.', + 'entity' => '', + 'entity_id' => '', + 'events' => [], + ]; + + /** + * Create a new job instance. + * + */ + public function __construct(private array $request) + { + } + + private function getSystemLog(string $message_id): ?SystemLog + { + return SystemLog::query() + ->where('company_id', $this->invitation->company_id) + ->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE) + ->whereJsonContains('log', ['MessageID' => $message_id]) + ->orderBy('id', 'desc') + ->first(); + + } + + private function updateSystemLog(SystemLog $system_log, array $data): void + { + $system_log->log = $data; + $system_log->save(); + } + + /** + * Execute the job. + * + * + * @return void + */ + public function handle() + { + MultiDB::findAndSetDbByCompanyKey($this->request['Tag']); + + // match companies + if (array_key_exists('ToFull', $this->request)) + throw new \Exception('invalid body'); + + $toEmails = []; + foreach ($this->request['ToFull'] as $toEmailEntry) + $toEmails[] = $toEmailEntry['Email']; + + // create expense for each company + $expense = new Expense(); + + $expense->company_id; + } + // { + // "FromName": "Postmarkapp Support", + // "MessageStream": "inbound", + // "From": "support@postmarkapp.com", + // "FromFull": { + // "Email": "support@postmarkapp.com", + // "Name": "Postmarkapp Support", + // "MailboxHash": "" + // }, + // "To": "\"Firstname Lastname\" ", + // "ToFull": [ + // { + // "Email": "yourhash+SampleHash@inbound.postmarkapp.com", + // "Name": "Firstname Lastname", + // "MailboxHash": "SampleHash" + // } + // ], + // "Cc": "\"First Cc\" , secondCc@postmarkapp.com>", + // "CcFull": [ + // { + // "Email": "firstcc@postmarkapp.com", + // "Name": "First Cc", + // "MailboxHash": "" + // }, + // { + // "Email": "secondCc@postmarkapp.com", + // "Name": "", + // "MailboxHash": "" + // } + // ], + // "Bcc": "\"First Bcc\" , secondbcc@postmarkapp.com>", + // "BccFull": [ + // { + // "Email": "firstbcc@postmarkapp.com", + // "Name": "First Bcc", + // "MailboxHash": "" + // }, + // { + // "Email": "secondbcc@postmarkapp.com", + // "Name": "", + // "MailboxHash": "" + // } + // ], + // "OriginalRecipient": "yourhash+SampleHash@inbound.postmarkapp.com", + // "Subject": "Test subject", + // "MessageID": "73e6d360-66eb-11e1-8e72-a8904824019b", + // "ReplyTo": "replyto@postmarkapp.com", + // "MailboxHash": "SampleHash", + // "Date": "Fri, 1 Aug 2014 16:45:32 -04:00", + // "TextBody": "This is a test text body.", + // "HtmlBody": "

This is a test html body.<\/p><\/body><\/html>", + // "StrippedTextReply": "This is the reply text", + // "Tag": "TestTag", + // "Headers": [ + // { + // "Name": "X-Header-Test", + // "Value": "" + // }, + // { + // "Name": "X-Spam-Status", + // "Value": "No" + // }, + // { + // "Name": "X-Spam-Score", + // "Value": "-0.1" + // }, + // { + // "Name": "X-Spam-Tests", + // "Value": "DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_PASS" + // } + // ], + // "Attachments": [ + // { + // "Name": "test.txt", + // "Content": "VGhpcyBpcyBhdHRhY2htZW50IGNvbnRlbnRzLCBiYXNlLTY0IGVuY29kZWQu", + // "ContentType": "text/plain", + // "ContentLength": 45 + // } + // ] + // } +} diff --git a/routes/api.php b/routes/api.php index 4d648054e298..078274348f40 100644 --- a/routes/api.php +++ b/routes/api.php @@ -120,7 +120,7 @@ Route::group(['middleware' => ['throttle:api', 'api_secret_check']], function () Route::post('api/v1/oauth_login', [LoginController::class, 'oauthApiLogin']); }); -Route::group(['middleware' => ['throttle:login','api_secret_check','email_db']], function () { +Route::group(['middleware' => ['throttle:login', 'api_secret_check', 'email_db']], function () { Route::post('api/v1/login', [LoginController::class, 'apiLogin'])->name('login.submit'); Route::post('api/v1/reset_password', [ForgotPasswordController::class, 'sendResetLinkEmail']); }); @@ -324,7 +324,7 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale'] Route::post('reports/user_sales_report', UserSalesReportController::class); Route::post('reports/preview/{hash}', ReportPreviewController::class); Route::post('exports/preview/{hash}', ReportExportController::class); - + Route::post('templates/preview/{hash}', TemplatePreviewController::class); Route::post('search', SearchController::class); @@ -414,6 +414,7 @@ Route::match(['get', 'post'], 'payment_notification_webhook/{company_key}/{compa ->name('payment_notification_webhook'); Route::post('api/v1/postmark_webhook', [PostMarkController::class, 'webhook'])->middleware('throttle:1000,1'); +Route::post('api/v1/postmark_inbound_webhook', [PostMarkController::class, 'inboundWebhook'])->middleware('throttle:1000,1'); Route::get('token_hash_router', [OneTimeTokenController::class, 'router'])->middleware('throttle:500,1'); Route::get('webcron', [WebCronController::class, 'index'])->middleware('throttle:100,1'); Route::post('api/v1/get_migration_account', [HostedMigrationController::class, 'getAccount'])->middleware('guest')->middleware('throttle:100,1');