validator for ExpenseMailbox property

This commit is contained in:
paulwer 2023-12-15 18:15:55 +01:00
parent dd9727a701
commit 36279be694
10 changed files with 471 additions and 352 deletions

View File

@ -11,10 +11,17 @@
namespace App\Helpers\Mail\Webhook; namespace App\Helpers\Mail\Webhook;
use App\Models\Company;
interface BaseWebhookHandler interface BaseWebhookHandler
{ {
public function process() public function process()
{ {
} }
protected function matchCompany(string $email)
{
return Company::where("expense_mailbox", $email)->first();
}
} }

View File

@ -11,12 +11,21 @@
namespace App\Helpers\Mail\Webhook\Postmark; namespace App\Helpers\Mail\Webhook\Postmark;
use App\Factory\ExpenseFactory;
use App\Helpers\Mail\Webhook\BaseWebhookHandler; use App\Helpers\Mail\Webhook\BaseWebhookHandler;
interface PostmarkWebhookHandler extends BaseWebhookHandler interface PostmarkWebhookHandler extends BaseWebhookHandler
{ {
public function process() public function process($data)
{ {
$email = '';
$company = $this->matchCompany($email);
if (!$company)
return false;
$expense = ExpenseFactory::create($company->id, $company->owner()->id);
} }
} }

View File

@ -13,6 +13,7 @@ namespace App\Http\Requests\Company;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\Http\ValidationRules\Company\ValidCompanyQuantity; use App\Http\ValidationRules\Company\ValidCompanyQuantity;
use App\Http\ValidationRules\Company\ValidExpenseMailbox;
use App\Http\ValidationRules\Company\ValidSubdomain; use App\Http\ValidationRules\Company\ValidSubdomain;
use App\Http\ValidationRules\ValidSettingsRule; use App\Http\ValidationRules\ValidSettingsRule;
use App\Models\Company; use App\Models\Company;
@ -55,6 +56,8 @@ class StoreCompanyRequest extends Request
} }
} }
$rules['expense_mailbox'] = new ValidExpenseMailbox($this->company->key, $this->company->account->isPaid() && $this->company->account->plan == 'enterprise'); // @turbo124 check if this is right
return $rules; return $rules;
} }

View File

@ -13,6 +13,7 @@ namespace App\Http\Requests\Company;
use App\DataMapper\CompanySettings; use App\DataMapper\CompanySettings;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\Http\ValidationRules\Company\ValidExpenseMailbox;
use App\Http\ValidationRules\Company\ValidSubdomain; use App\Http\ValidationRules\Company\ValidSubdomain;
use App\Http\ValidationRules\ValidSettingsRule; use App\Http\ValidationRules\ValidSettingsRule;
use App\Utils\Ninja; use App\Utils\Ninja;
@ -67,6 +68,8 @@ class UpdateCompanyRequest extends Request
$rules['subdomain'] = ['nullable', 'regex:/^[a-zA-Z0-9.-]+[a-zA-Z0-9]$/', new ValidSubdomain()]; $rules['subdomain'] = ['nullable', 'regex:/^[a-zA-Z0-9.-]+[a-zA-Z0-9]$/', new ValidSubdomain()];
} }
$rules['expense_mailbox'] = new ValidExpenseMailbox($this->company->key, $this->company->account->isPaid() && $this->company->account->plan == 'enterprise'); // @turbo124 check if this is right
return $rules; return $rules;
} }

View File

@ -0,0 +1,64 @@
<?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\ValidationRules\Company;
use App\Libraries\MultiDB;
use App\Utils\Ninja;
use Illuminate\Contracts\Validation\Rule;
/**
* Class ValidCompanyQuantity.
*/
class ValidExpenseMailbox implements Rule
{
private $validated_schema = false;
private $company_key = false;
private $isEnterprise = false;
public function __construct(string $company_key, bool $isEnterprise = false)
{
$this->company_key = $company_key;
$this->isEnterprise = $isEnterprise;
}
public function passes($attribute, $value)
{
if (empty($value)) {
return true;
}
// early return, if we dont have any additional validation
if (!config('ninja.inbound_expense.webhook.mailbox_schema') && !(Ninja::isHosted() && config('ninja.inbound_expense.webhook.mailbox_schema_enterprise'))) {
$this->validated_schema = true;
return MultiDB::checkExpenseMailboxAvailable($value);
}
// Validate Schema
$validated = !config('ninja.inbound_expense.webhook.mailbox_schema') || (preg_match(config('ninja.inbound_expense.webhook.mailbox_schema'), $value) && (!config('ninja.inbound_expense.webhook.mailbox_schema_hascompanykey') || str_contains($value, $this->company_key))) ? true : false;
$validated_enterprise = !config('ninja.inbound_expense.webhook.mailbox_schema_enterprise') || (Ninja::isHosted() && $this->isEnterprise && preg_match(config('ninja.inbound_expense.webhook.mailbox_schema_enterprise'), $value));
if (!$validated && !$validated_enterprise)
return false;
$this->validated_schema = true;
return MultiDB::checkExpenseMailboxAvailable($value);
}
/**
* @return string
*/
public function message()
{
return $this->validated_schema ? ctrans('texts.expense_mailbox_taken') : ctrans('texts.expense_mailbox_invalid');
}
}

View File

@ -71,6 +71,8 @@ class MultiDB
'socket', 'socket',
]; ];
private static $protected_expense_mailboxes = [];
/** /**
* @return array * @return array
*/ */
@ -105,6 +107,32 @@ class MultiDB
return true; return true;
} }
public static function checkExpenseMailboxAvailable($expense_mailbox): bool
{
if (!config('ninja.db.multi_db_enabled')) {
return Company::where("expense_mailbox", $expense_mailbox)->withTrashed()->exists();
}
if (in_array($expense_mailbox, self::$protected_expense_mailboxes)) {
return false;
}
$current_db = config('database.default');
foreach (self::$dbs as $db) {
if (Company::on($db)->where("expense_mailbox", $expense_mailbox)->withTrashed()->exists()) {
self::setDb($current_db);
return false;
}
}
self::setDb($current_db);
return true;
}
public static function checkUserEmailExists($email): bool public static function checkUserEmailExists($email): bool
{ {
if (!config('ninja.db.multi_db_enabled')) { if (!config('ninja.db.multi_db_enabled')) {

View File

@ -204,6 +204,7 @@ class CompanyTransformer extends EntityTransformer
'invoice_task_project_header' => (bool) $company->invoice_task_project_header, 'invoice_task_project_header' => (bool) $company->invoice_task_project_header,
'invoice_task_item_description' => (bool) $company->invoice_task_item_description, 'invoice_task_item_description' => (bool) $company->invoice_task_item_description,
'origin_tax_data' => $company->origin_tax_data ?: new \stdClass, 'origin_tax_data' => $company->origin_tax_data ?: new \stdClass,
'expense_mailbox' => $company->expense_mailbox,
]; ];
} }

View File

@ -238,7 +238,9 @@ return [
], ],
'webhook' => [ 'webhook' => [
'mailbox_template' => env('INBOUND_EXPENSE_WEBHOOK_MAILBOXTEMPLATE', null), 'mailbox_template' => env('INBOUND_EXPENSE_WEBHOOK_MAILBOXTEMPLATE', null),
'mailbox_template_enterprise' => env('INBOUND_EXPENSE_WEBHOOK_MAILBOXTEMPLATE_ENTERPRISE', '{{input}}@expense.invoicing.co'), 'mailbox_schema' => env('INBOUND_EXPENSE_WEBHOOK_MAILBOX_SCHEMA', null),
'mailbox_schema_hascompanykey' => env('INBOUND_EXPENSE_WEBHOOK_MAILBOX_SCHEMA_HASCOMPANYKEY', false),
'mailbox_schema_enterprise' => env('INBOUND_EXPENSE_WEBHOOK_MAILBOX_SCHEMA_ENTERPRISE', '.*@expense\.invoicing\.co$'),
], ],
], ],
]; ];

View File

@ -2534,6 +2534,8 @@ $lang = array(
'local_storage_required' => 'Error: local storage is not available.', 'local_storage_required' => 'Error: local storage is not available.',
'your_password_reset_link' => 'Your Password Reset Link', 'your_password_reset_link' => 'Your Password Reset Link',
'subdomain_taken' => 'The subdomain is already in use', 'subdomain_taken' => 'The subdomain is already in use',
'expense_mailbox_taken' => 'The mailbox is already in use',
'expense_mailbox_invalid' => 'The mailbox does not match the required schema',
'client_login' => 'Client Login', 'client_login' => 'Client Login',
'converted_amount' => 'Converted Amount', 'converted_amount' => 'Converted Amount',
'default' => 'Default', 'default' => 'Default',