Merge branch 'master' of github.com:akaunting/akaunting
This commit is contained in:
commit
8ef6f743bd
10
app/Exceptions/Common/TooManyEmailsSent.php
Normal file
10
app/Exceptions/Common/TooManyEmailsSent.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions\Common;
|
||||
|
||||
use Illuminate\Http\Exceptions\ThrottleRequestsException;
|
||||
|
||||
class TooManyEmailsSent extends ThrottleRequestsException
|
||||
{
|
||||
//
|
||||
}
|
@ -7,9 +7,13 @@ use App\Models\Document\Document;
|
||||
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.
|
||||
*/
|
||||
@ -22,14 +26,7 @@ class InvoiceEmails extends Controller
|
||||
$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);
|
||||
|
||||
@ -58,16 +55,9 @@ class InvoiceEmails extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'));
|
||||
|
@ -8,9 +8,13 @@ use App\Notifications\Portal\PaymentReceived as PaymentReceivedNotification;
|
||||
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.
|
||||
*/
|
||||
@ -23,14 +27,7 @@ class TransactionEmails extends Controller
|
||||
$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');
|
||||
|
||||
@ -73,20 +70,13 @@ class TransactionEmails extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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');
|
||||
|
@ -134,6 +134,10 @@ class Kernel extends HttpKernel
|
||||
'import' => [
|
||||
'throttle:import',
|
||||
],
|
||||
|
||||
'email' => [
|
||||
'throttle:email',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -289,5 +289,12 @@ class Route extends Provider
|
||||
RateLimiter::for('import', function (Request $request) {
|
||||
return Limit::perMinute(config('app.throttles.import'));
|
||||
});
|
||||
|
||||
RateLimiter::for('email', function (Request $request) {
|
||||
return [
|
||||
Limit::perDay(config('app.throttles.email.month'), 30),
|
||||
Limit::perMinute(config('app.throttles.email.minute')),
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
55
app/Traits/Emails.php
Normal file
55
app/Traits/Emails.php
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -25,6 +25,10 @@ return [
|
||||
'throttles' => [
|
||||
'api' => env('APP_THROTTLES_API', '60'),
|
||||
'import' => env('APP_THROTTLES_IMPORT', '1'),
|
||||
'email' => [
|
||||
'minute' => env('APP_THROTTLES_EMAIL_MINUTE', '3'),
|
||||
'month' => env('APP_THROTTLES_EMAIL_MONTH', '500'),
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|
@ -139,6 +139,9 @@
|
||||
if (button.getAttribute("data-menu") !== menuRef && iconButton.children[0].textContent != "cancel") {
|
||||
button.children[0].textContent = button.children[0].getAttribute("name");
|
||||
button.children[0].classList.remove("active"); // inactive icon
|
||||
|
||||
let split_id = button.children[0].id.split("-cancel");
|
||||
button.children[0].id = split_id[0];
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -148,6 +151,7 @@
|
||||
if (menu.classList.contains(menuRef) && iconButton.children[0].textContent != "cancel") {
|
||||
iconButton.children[0].textContent = "cancel";
|
||||
iconButton.children[0].classList.add("active");
|
||||
iconButton.children[0].id += "-cancel";
|
||||
|
||||
menu.classList.remove("ltr:-left-80", "rtl:-right-80");
|
||||
menu.classList.add("ltr:left-14", "rtl:right-14");
|
||||
@ -177,6 +181,9 @@
|
||||
iconButton.children[0].textContent = icon;
|
||||
iconButton.children[0].classList.remove("active");
|
||||
|
||||
let split_id = iconButton.children[0].id.split("-cancel");
|
||||
iconButton.children[0].id = split_id[0];
|
||||
|
||||
menu.classList.add("ltr:-left-80", "rtl:-right-80");
|
||||
menu.classList.remove("ltr:left-14", "rtl:right-14");
|
||||
|
||||
@ -242,6 +249,7 @@
|
||||
|
||||
settings_icon_html.children[0].textContent = "cancel";
|
||||
settings_icon_html.children[0].classList.add("active");
|
||||
settings_icon_html.children[0].id += "-cancel";
|
||||
|
||||
toggleButton.classList.add("invisible");
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
<link rel="stylesheet" href="{{ asset('public/vendor/quicksand/css/quicksand.css?v=' . version('short')) }}" type="text/css">
|
||||
|
||||
<!-- Css -->
|
||||
<link rel="stylesheet" href="{{ asset('public/css//third_party/swiper-bundle.min.css?v=' . version('short')) }}" type="text/css">
|
||||
<link rel="stylesheet" href="{{ asset('public/css/element.css?v=' . version('short')) }}" type="text/css">
|
||||
<link rel="stylesheet" href="{{ asset('public/css/app.css?v=' . version('short')) }}" type="text/css">
|
||||
|
||||
|
@ -122,6 +122,9 @@
|
||||
if (button.getAttribute("data-menu") !== menuRef && iconButton.children[0].textContent != "cancel") {
|
||||
button.children[0].textContent = button.children[0].getAttribute("name");
|
||||
button.children[0].classList.remove("active"); // inactive icon
|
||||
|
||||
let split_id = button.children[0].id.split("-cancel");
|
||||
button.children[0].id = split_id[0];
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -131,6 +134,7 @@
|
||||
if (menu.classList.contains(menuRef) && iconButton.children[0].textContent != "cancel") {
|
||||
iconButton.children[0].textContent = "cancel";
|
||||
iconButton.children[0].classList.add("active");
|
||||
iconButton.children[0].id += "-cancel";
|
||||
|
||||
menu.classList.remove("ltr:-left-80", "rtl:-right-80");
|
||||
menu.classList.add("ltr:left-14", "rtl:right-14");
|
||||
@ -155,6 +159,9 @@
|
||||
iconButton.children[0].textContent = icon;
|
||||
iconButton.children[0].classList.remove("active");
|
||||
|
||||
let split_id = iconButton.children[0].id.split("-cancel");
|
||||
iconButton.children[0].id = split_id[0];
|
||||
|
||||
menu.classList.add("ltr:-left-80", "rtl:-right-80");
|
||||
menu.classList.remove("ltr:left-14", "rtl:right-14");
|
||||
mainContent.classList.remove("hidden");
|
||||
|
@ -26,6 +26,7 @@
|
||||
<link rel="stylesheet" href="{{ asset('public/vendor/quicksand/css/quicksand.css?v=' . version('short')) }}" type="text/css">
|
||||
|
||||
<!-- Css -->
|
||||
<link rel="stylesheet" href="{{ asset('public/css//third_party/swiper-bundle.min.css?v=' . version('short')) }}" type="text/css">
|
||||
<link rel="stylesheet" href="{{ asset('public/css/element.css?v=' . version('short')) }}" type="text/css">
|
||||
<link rel="stylesheet" href="{{ asset('public/css/app.css?v=' . version('short')) }}" type="text/css">
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
<div class="swiper-slide">
|
||||
<x-tabs.nav
|
||||
id="{{ $name }}"
|
||||
@click="onChangePaymentMethodSigned('{{ $key }}')"
|
||||
@click="onChangePaymentMethod('{{ $key }}')"
|
||||
>
|
||||
<div class="w-24 truncate">
|
||||
{{ $name }}
|
||||
|
@ -259,9 +259,13 @@ Route::group(['as' => 'modals.', 'prefix' => 'modals'], function () {
|
||||
'middleware' => ['date.format', 'money', 'dropzone']
|
||||
]);
|
||||
|
||||
Route::resource('transactions/{transaction}/emails', 'Modals\TransactionEmails', ['names' => 'transactions.emails']);
|
||||
Route::resource('transactions/{transaction}/share', 'Modals\TransactionShare', ['names' => 'transactions.share']);
|
||||
Route::resource('invoices/{invoice}/emails', 'Modals\InvoiceEmails', ['names' => 'invoices.emails']);
|
||||
Route::resource('invoices/{invoice}/share', 'Modals\InvoiceShare', ['names' => 'invoices.share']);
|
||||
Route::get('invoices/{invoice}/emails/create', 'Modals\InvoiceEmails@create')->name('invoices.emails.create');
|
||||
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')->name('transactions.emails.store');
|
||||
Route::get('transactions/{transaction}/share/create', 'Modals\TransactionShare@create')->name('transactions.share.create');
|
||||
|
||||
Route::resource('taxes', 'Modals\Taxes');
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user