Skip to content

Commit

Permalink
improved email throttle
Browse files Browse the repository at this point in the history
  • Loading branch information
denisdulici committed Sep 14, 2022
1 parent bf2f839 commit eb3b080
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 41 deletions.
10 changes: 10 additions & 0 deletions app/Exceptions/Common/TooManyEmailsSent.php
@@ -0,0 +1,10 @@
<?php

namespace App\Exceptions\Common;

use Illuminate\Http\Exceptions\ThrottleRequestsException;

class TooManyEmailsSent extends ThrottleRequestsException
{
//
}
24 changes: 7 additions & 17 deletions app/Http/Controllers/Modals/InvoiceEmails.php
Expand Up @@ -7,9 +7,13 @@
use App\Notifications\Sale\Invoice as Notification;
use App\Jobs\Document\SendDocumentAsCustomMail;
use App\Http\Requests\Common\CustomMail as Request;
use Illuminate\Http\JsonResponse;
use App\Traits\Emails;

class InvoiceEmails extends Controller
{
use Emails;

/**
* Instantiate a new controller instance.
*/
Expand All @@ -22,14 +26,7 @@ public function __construct()
$this->middleware('permission:delete-sales-invoices')->only('destroy');
}

/**
* Show the form for creating a new resource.
*
* @param Document $invoice
*
* @return Response
*/
public function create(Document $invoice)
public function create(Document $invoice): JsonResponse
{
$notification = new Notification($invoice, 'invoice_new_customer', true);

Expand Down Expand Up @@ -58,16 +55,9 @@ public function create(Document $invoice)
]);
}

/**
* Store a newly created resource in storage.
*
* @param Request $request
*
* @return Response
*/
public function store(Request $request)
public function store(Request $request): JsonResponse
{
$response = $this->ajaxDispatch(new SendDocumentAsCustomMail($request, 'invoice_new_customer'));
$response = $this->sendEmail(new SendDocumentAsCustomMail($request, 'invoice_new_customer'));

if ($response['success']) {
$invoice = Document::find($request->get('document_id'));
Expand Down
30 changes: 10 additions & 20 deletions app/Http/Controllers/Modals/TransactionEmails.php
Expand Up @@ -8,9 +8,13 @@
use App\Notifications\Banking\Transaction as TransactionNotification;
use App\Jobs\Banking\SendTransactionAsCustomMail;
use App\Http\Requests\Common\CustomMail as Request;
use Illuminate\Http\JsonResponse;
use App\Traits\Emails;

class TransactionEmails extends Controller
{
use Emails;

/**
* Instantiate a new controller instance.
*/
Expand All @@ -23,17 +27,10 @@ public function __construct()
$this->middleware('permission:delete-banking-transactions')->only('destroy');
}

/**
* Show the form for creating a new resource.
*
* @param Transaction $transaction
*
* @return Response
*/
public function create(Transaction $transaction)
{
public function create(Transaction $transaction): JsonResponse
{
$email_template = config('type.transaction.' . $transaction->type . '.email_template');

if (request()->get('email_template')) {
$email_template = request()->get('email_template');
}
Expand All @@ -42,7 +39,7 @@ public function create(Transaction $transaction)
case 'invoice_payment_customer':
$notification = new PaymentReceivedNotification($transaction->document, $transaction, $email_template, true);
break;

default:
$notification = new TransactionNotification($transaction, $email_template, true);
break;
Expand Down Expand Up @@ -73,20 +70,13 @@ public function create(Transaction $transaction)
]);
}

/**
* Store a newly created resource in storage.
*
* @param Request $request
*
* @return Response
*/
public function store(Request $request)
public function store(Request $request): JsonResponse
{
$transaction = Transaction::find($request->get('transaction_id'));

$email_template = config('type.transaction.' . $transaction->type . '.email_template');

$response = $this->ajaxDispatch(new SendTransactionAsCustomMail($request, $email_template));
$response = $this->sendEmail(new SendTransactionAsCustomMail($request, $email_template));

if ($response['success']) {
$route = config('type.transaction.' . $transaction->type . '.route.prefix');
Expand Down
5 changes: 4 additions & 1 deletion app/Providers/Route.php
Expand Up @@ -291,7 +291,10 @@ protected function configureRateLimiting()
});

RateLimiter::for('email', function (Request $request) {
return Limit::perMinute(config('app.throttles.email'));
return [
Limit::perDay(config('app.throttles.email.month'), 30),
Limit::perMinute(config('app.throttles.email.minute')),
];
});
}
}
55 changes: 55 additions & 0 deletions app/Traits/Emails.php
@@ -0,0 +1,55 @@
<?php

namespace App\Traits;

use App\Abstracts\Job;
use App\Exceptions\Common\TooManyEmailsSent;
use App\Traits\Jobs;
use Illuminate\Support\Facades\RateLimiter;

trait Emails
{
use Jobs;

public function sendEmail(Job $job): array
{
// Check if the user has reached the limit of emails per month
$key_per_month = 'email-month:' . user()->id;
$limit_per_month = config('app.throttles.email.month');
$decay_per_month = 60 * 60 * 24 * 30;

$can_send = RateLimiter::attempt($key_per_month, $limit_per_month, fn() => '', $decay_per_month);

if ($can_send) {
// Check if the user has reached the limit of emails per minute
$key_per_minute = 'email-minute:' . user()->id;
$limit_per_minute = config('app.throttles.email.minute');

$can_send = RateLimiter::attempt($key_per_minute, $limit_per_minute, fn() => '');
}

if ($can_send) {
$this->dispatch($job);

$response = [
'success' => true,
'error' => false,
'data' => '',
'message' => '',
];

return $response;
}

$response = [
'success' => false,
'error' => true,
'data' => null,
'message' => 'Too many emails sent!',
];

report(new TooManyEmailsSent('Too many emails sent!'));

return $response;
}
}
5 changes: 4 additions & 1 deletion config/app.php
Expand Up @@ -25,7 +25,10 @@
'throttles' => [
'api' => env('APP_THROTTLES_API', '60'),
'import' => env('APP_THROTTLES_IMPORT', '1'),
'email' => env('APP_THROTTLES_EMAIL', '1'),
'email' => [
'minute' => env('APP_THROTTLES_EMAIL_MINUTE', '3'),
'month' => env('APP_THROTTLES_EMAIL_MONTH', '500'),
],
],

/*
Expand Down
4 changes: 2 additions & 2 deletions routes/admin.php
Expand Up @@ -260,11 +260,11 @@
]);

Route::get('invoices/{invoice}/emails/create', 'Modals\InvoiceEmails@create')->name('invoices.emails.create');
Route::post('invoices/{invoice}/emails', 'Modals\InvoiceEmails@store')->middleware('email')->name('invoices.emails.store');
Route::post('invoices/{invoice}/emails', 'Modals\InvoiceEmails@store')->name('invoices.emails.store');
Route::get('invoices/{invoice}/share/create', 'Modals\InvoiceShare@create')->name('invoices.share.create');

Route::get('transactions/{transaction}/emails/create', 'Modals\TransactionEmails@create')->name('transactions.emails.create');
Route::post('transactions/{transaction}/emails', 'Modals\TransactionEmails@store')->middleware('email')->name('transactions.emails.store');
Route::post('transactions/{transaction}/emails', 'Modals\TransactionEmails@store')->name('transactions.emails.store');
Route::get('transactions/{transaction}/share/create', 'Modals\TransactionShare@create')->name('transactions.share.create');

Route::resource('taxes', 'Modals\Taxes');
Expand Down

0 comments on commit eb3b080

Please sign in to comment.