From e6ccb9bde745e90360bf6752314c6fa915eba369 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 7 Aug 2021 20:56:42 +1000 Subject: [PATCH] Email quota exceeded emails --- app/Console/Kernel.php | 2 +- app/Jobs/Mail/NinjaMailerJob.php | 6 +- app/Jobs/Ninja/AdjustEmailQuota.php | 39 ++++++------ app/Mail/Ninja/EmailQuotaExceeded.php | 60 +++++++++++++++++++ app/Models/Account.php | 23 ++++++- resources/lang/en/texts.php | 2 + .../admin/email_quota_exceeded.blade.php | 7 +++ 7 files changed, 112 insertions(+), 27 deletions(-) create mode 100644 app/Mail/Ninja/EmailQuotaExceeded.php create mode 100644 resources/views/email/admin/email_quota_exceeded.blade.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index a97b90b1730c..10cb1bb3f95c 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -69,7 +69,7 @@ class Kernel extends ConsoleKernel /* Run hosted specific jobs */ if (Ninja::isHosted()) { - $schedule->job(new AdjustEmailQuota)->daily()->withoutOverlapping(); + $schedule->job(new AdjustEmailQuota)->dailyAt('23:00')->withoutOverlapping(); $schedule->job(new SendFailedEmails)->daily()->withoutOverlapping(); $schedule->command('ninja:check-data --database=db-ninja-02')->daily()->withoutOverlapping(); diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php index 21cb877b2590..987e79f65716 100644 --- a/app/Jobs/Mail/NinjaMailerJob.php +++ b/app/Jobs/Mail/NinjaMailerJob.php @@ -72,9 +72,6 @@ class NinjaMailerJob implements ShouldQueue public function handle() { - - if($this->preFlightChecksFail()) - return; /*Set the correct database*/ MultiDB::setDb($this->nmo->company->db); @@ -82,6 +79,9 @@ class NinjaMailerJob implements ShouldQueue /* Serializing models from other jobs wipes the primary key */ $this->company = Company::where('company_key', $this->nmo->company->company_key)->first(); + if($this->preFlightChecksFail()) + return; + /* Set the email driver */ $this->setMailDriver(); diff --git a/app/Jobs/Ninja/AdjustEmailQuota.php b/app/Jobs/Ninja/AdjustEmailQuota.php index c122f0b22784..dec4945673b7 100644 --- a/app/Jobs/Ninja/AdjustEmailQuota.php +++ b/app/Jobs/Ninja/AdjustEmailQuota.php @@ -13,26 +13,18 @@ namespace App\Jobs\Ninja; use App\Libraries\MultiDB; use App\Models\Account; +use App\Utils\Ninja; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Cache; class AdjustEmailQuota implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - const FREE_PLAN_DAILY_QUOTA = 10; - const PRO_PLAN_DAILY_QUOTA = 50; - const ENTERPRISE_PLAN_DAILY_QUOTA = 200; - - const FREE_PLAN_DAILY_CAP = 20; - const PRO_PLAN_DAILY_CAP = 100; - const ENTERPRISE_PLAN_DAILY_CAP = 300; - - const DAILY_MULTIPLIER = 1.1; - /** * Create a new job instance. * @@ -50,22 +42,27 @@ class AdjustEmailQuota implements ShouldQueue */ public function handle() { - if (! config('ninja.db.multi_db_enabled')) { - $this->adjust(); - } else { - //multiDB environment, need to - foreach (MultiDB::$dbs as $db) { - MultiDB::setDB($db); + if(!Ninja::isHosted()) + return; + + //multiDB environment, need to + foreach (MultiDB::$dbs as $db) { + + MultiDB::setDB($db); + + $this->adjust(); - $this->adjust(); - } } + } public function adjust() { - foreach (Account::cursor() as $account) { - //@TODO once we add in the two columns daily_emails_quota daily_emails_sent_ - } + + Account::query()->cursor()->each(function ($account){ + Cache::forget($account->key); + Cache::forget("throttle_notified:{$account->key}"); + }); + } } diff --git a/app/Mail/Ninja/EmailQuotaExceeded.php b/app/Mail/Ninja/EmailQuotaExceeded.php new file mode 100644 index 000000000000..12808cf8a472 --- /dev/null +++ b/app/Mail/Ninja/EmailQuotaExceeded.php @@ -0,0 +1,60 @@ +company = $company; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + $this->settings = $this->company->settings; + $this->logo = $this->company->present()->logo(); + $this->title = ctrans('texts.email_quota_exceeded_subject'); + $this->body = ctrans('texts.email_quota_exceeded_body', ['quota' => $this->company->account->getDailyEmailLimit()]); + $this->whitelabel = $this->company->account->isPaid(); + + return $this->from(config('mail.from.address'), config('mail.from.name')) + ->subject(ctrans('texts.email_quota_exceeded_subject')) + ->view('email.admin.email_quota_exceeded'); + } +} diff --git a/app/Models/Account.php b/app/Models/Account.php index 05b0cb7264f3..76f3e79b0f2a 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -11,14 +11,16 @@ namespace App\Models; +use App\Jobs\Mail\NinjaMailerJob; +use App\Jobs\Mail\NinjaMailerObject; use App\Models\Presenters\AccountPresenter; use App\Utils\Ninja; use App\Utils\Traits\MakesHash; use Carbon\Carbon; use DateTime; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Laracasts\Presenter\PresentableTrait; use Illuminate\Support\Facades\Cache; +use Laracasts\Presenter\PresentableTrait; class Account extends BaseModel { @@ -357,7 +359,24 @@ class Account extends BaseModel if(is_null(Cache::get($this->key))) return false; - return Cache::get($this->key) > $this->getDailyEmailLimit(); + if(Cache::get($this->key) > $this->getDailyEmailLimit()) { + + if(is_null(Cache::get("throttle_notified:{$this->key}"))) { + + $nmo = new NinjaMailerObject; + $nmo->mailable = new MaxCompanies($account->companies()->first()); + $nmo->company = $account->companies()->first(); + $nmo->settings = $account->companies()->first()->settings; + $nmo->to_user = $account->companies()->first()->owner(); + NinjaMailerJob::dispatch($nmo); + + Cache::put("throttle_notified:{$this->key}", true, 60 * 24); + } + + return true; + } + + return false; } } diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index eed12cf3f464..c9cd5d7ffc7c 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -4289,6 +4289,8 @@ $LANG = array( 'back_to' => 'Back to :url', 'stripe_connect_migration_title' => 'Connect your Stripe Account', 'stripe_connect_migration_desc' => 'Invoice Ninja v5 uses Stripe Connect to link your Stripe account to Invoice Ninja. This provides an additional layer of security for your account. Now that you data has migrated, you will need to Authorize Stripe to accept payments in v5.

To do this, navigate to Settings > Online Payments > Configure Gateways. Click on Stripe Connect and then under Settings click Setup Gateway. This will take you to Stripe to authorize Invoice Ninja and on your return your account will be successfully linked!', + 'email_quota_exceeded_subject' => 'Account email quota exceeded.', + 'email_quota_exceeded_body' => 'In a 24 hour period you have sent :quota emails.
We have paused your outbound emails.

Your email quota will reset at 23:00 UTC.', ); return $LANG; diff --git a/resources/views/email/admin/email_quota_exceeded.blade.php b/resources/views/email/admin/email_quota_exceeded.blade.php new file mode 100644 index 000000000000..d63aaaf26850 --- /dev/null +++ b/resources/views/email/admin/email_quota_exceeded.blade.php @@ -0,0 +1,7 @@ +@component('email.template.admin', ['logo' => $logo, 'settings' => $settings]) +
+

{!! $title !!}

+ +

{!! $body !!}

+
+@endcomponent