restruct files

This commit is contained in:
paulwer 2023-12-14 16:40:43 +01:00
parent a6f9275144
commit 8d6925afd3
10 changed files with 395 additions and 9 deletions

View File

@ -0,0 +1,19 @@
<?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\Mail;
interface BaseMailbox
{
public function getUnprocessedEmails();
public function moveProcessed();
public function moveFailed();
}

View File

@ -15,11 +15,7 @@ use Ddeboer\Imap\MessageInterface;
use Ddeboer\Imap\Server;
use Ddeboer\Imap\SearchExpression;
use Ddeboer\Imap\Search\Date\Since;
use Ddeboer\Imap\Search\Flag\Unflagged;
/**
* GmailTransport.
*/
class ImapMailbox
{
private $server;
@ -43,10 +39,6 @@ class ImapMailbox
$thirtyDaysAgo = $today->sub(new \DateInterval('P30D'));
$search->addCondition(new Since($thirtyDaysAgo));
// not flagged with IN-PARSED
$search->addCondition(new Unflagged());
return $mailbox->getMessages($search);
}

View File

@ -0,0 +1,57 @@
<?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\Mail;
use Ddeboer\Imap\MessageInterface;
use Ddeboer\Imap\Server;
use Ddeboer\Imap\SearchExpression;
use Ddeboer\Imap\Search\Date\Since;
/**
* TODO
*/
class Pop3Mailbox implements BaseMailbox
{
private $server;
public $connection;
public function __construct(string $server, string $port, string $user, string $password)
{
$this->server = new Server($server, $port != '' ? $port : null);
$this->connection = $this->server->authenticate($user, $password);
}
public function getUnprocessedEmails()
{
$mailbox = $this->connection->getMailbox('INBOX');
$search = new SearchExpression();
// not older than 30days
$today = new \DateTimeImmutable();
$thirtyDaysAgo = $today->sub(new \DateInterval('P30D'));
$search->addCondition(new Since($thirtyDaysAgo));
return $mailbox->getMessages($search);
}
public function moveProcessed(MessageInterface $mail)
{
return $mail->move($this->connection->getMailbox('PROCESSED'));
}
public function moveFailed(MessageInterface $mail)
{
return $mail->move($this->connection->getMailbox('FAILED'));
}
}

View File

@ -0,0 +1,20 @@
<?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\Mail\Webhook;
interface BaseWebhookHandler
{
public function process()
{
}
}

View File

@ -0,0 +1,22 @@
<?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\Mail\Webhook\Maigun;
use App\Helpers\Mail\Webhook\BaseWebhookHandler;
interface MailgunWebhookHandler extends BaseWebhookHandler
{
public function process()
{
}
}

View File

@ -0,0 +1,22 @@
<?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\Mail\Webhook\Postmark;
use App\Helpers\Mail\Webhook\BaseWebhookHandler;
interface PostmarkWebhookHandler extends BaseWebhookHandler
{
public function process()
{
}
}

View File

@ -0,0 +1,72 @@
<?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\Http\Controllers;
use App\Jobs\Mailgun\ProcessMailgunInboundWebhook;
use Illuminate\Http\Request;
/**
* Class PostMarkController.
*/
class MailgunController extends BaseController
{
private $invitation;
public function __construct()
{
}
/**
* 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')) {
ProcessMailgunInboundWebhook::dispatch($request->all())->delay(10);
return response()->json(['message' => 'Success'], 200);
}
return response()->json(['message' => 'Unauthorized'], 403);
}
}

View File

@ -17,7 +17,7 @@ use App\Events\Expense\ExpenseWasCreated;
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
use App\Events\Payment\PaymentWasEmailedAndFailed;
use App\Factory\ExpenseFactory;
use App\Helpers\Mail\ImapMailbox;
use App\Helpers\Mail\Mailbox\Imap\ImapMailbox;
use App\Jobs\Util\SystemLogger;
use App\Libraries\Google\Google;
use App\Libraries\MultiDB;

View File

@ -0,0 +1,180 @@
<?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\Jobs\PostMark;
use App\DataMapper\Analytics\Mail\EmailBounce;
use App\DataMapper\Analytics\Mail\EmailSpam;
use App\Jobs\Util\SystemLogger;
use App\Libraries\MultiDB;
use App\Models\CreditInvitation;
use App\Models\Expense;
use App\Models\InvoiceInvitation;
use App\Models\PurchaseOrderInvitation;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoiceInvitation;
use App\Models\SystemLog;
use App\Notifications\Ninja\EmailSpamNotification;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Postmark\PostmarkClient;
use Turbo124\Beacon\Facades\LightLogs;
class ProcessMailgunInboundWebhook implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
public $invitation;
private $entity;
private array $default_response = [
'recipients' => '',
'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\" <yourhash+SampleHash@inbound.postmarkapp.com>",
// "ToFull": [
// {
// "Email": "yourhash+SampleHash@inbound.postmarkapp.com",
// "Name": "Firstname Lastname",
// "MailboxHash": "SampleHash"
// }
// ],
// "Cc": "\"First Cc\" <firstcc@postmarkapp.com>, secondCc@postmarkapp.com>",
// "CcFull": [
// {
// "Email": "firstcc@postmarkapp.com",
// "Name": "First Cc",
// "MailboxHash": ""
// },
// {
// "Email": "secondCc@postmarkapp.com",
// "Name": "",
// "MailboxHash": ""
// }
// ],
// "Bcc": "\"First Bcc\" <firstbcc@postmarkapp.com>, 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": "<html><body><p>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
// }
// ]
// }
}

View File

@ -388,6 +388,7 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
// Route::post('hooks', [SubscriptionController::class, 'subscribe'])->name('hooks.subscribe');
// Route::delete('hooks/{subscription_id}', [SubscriptionController::class, 'unsubscribe'])->name('hooks.unsubscribe');
Route::post('stripe/update_payment_methods', [StripeController::class, 'update'])->middleware('password_protected')->name('stripe.update');
Route::post('stripe/import_customers', [StripeController::class, 'import'])->middleware('password_protected')->name('stripe.import');
@ -415,6 +416,7 @@ Route::match(['get', 'post'], 'payment_notification_webhook/{company_key}/{compa
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::post('api/v1/mailgun_inbound_webhook', [MailgunController::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');