From 0edb03943b90f71ddae2fa18f1da51f4ed9b7d25 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 18:22:00 +1000 Subject: [PATCH 1/5] Updates for PRedis --- .../Middleware/ThrottleRequestsWithPredis.php | 33 ++++++++++++------- app/Jobs/RecurringInvoice/SendRecurring.php | 4 +-- app/Providers/RouteServiceProvider.php | 19 +++++------ app/Services/Template/TemplateService.php | 2 +- composer.lock | 22 ++++++------- 5 files changed, 45 insertions(+), 35 deletions(-) diff --git a/app/Http/Middleware/ThrottleRequestsWithPredis.php b/app/Http/Middleware/ThrottleRequestsWithPredis.php index 365cdad1929d..30388163d103 100644 --- a/app/Http/Middleware/ThrottleRequestsWithPredis.php +++ b/app/Http/Middleware/ThrottleRequestsWithPredis.php @@ -4,15 +4,15 @@ namespace App\Http\Middleware; use Closure; use Illuminate\Cache\RateLimiter; +use Illuminate\Contracts\Redis\Factory as Redis; use Illuminate\Redis\Limiters\DurationLimiter; -use Illuminate\Routing\Middleware\ThrottleRequests; -class ThrottleRequestsWithPredis extends ThrottleRequests +class ThrottleRequestsWithPredis extends \Illuminate\Routing\Middleware\ThrottleRequests { /** * The Redis factory implementation. * - * @var \Illuminate\Redis\Connections\Connection + * @var \Illuminate\Contracts\Redis\Factory */ protected $redis; @@ -34,13 +34,17 @@ class ThrottleRequestsWithPredis extends ThrottleRequests * Create a new request throttler. * * @param \Illuminate\Cache\RateLimiter $limiter + * @param \Illuminate\Contracts\Redis\Factory $redis * @return void */ - public function __construct(RateLimiter $limiter) + public function __construct(RateLimiter $limiter, Redis $redis) { parent::__construct($limiter); $this->redis = \Illuminate\Support\Facades\Redis::connection('sentinel-cache'); + + // $this->redis = $redis; + } /** @@ -56,7 +60,7 @@ class ThrottleRequestsWithPredis extends ThrottleRequests protected function handleRequest($request, Closure $next, array $limits) { foreach ($limits as $limit) { - if ($this->tooManyAttempts($limit->key, $limit->maxAttempts, $limit->decayMinutes)) { + if ($this->tooManyAttempts($limit->key, $limit->maxAttempts, $limit->decaySeconds)) { throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback); } } @@ -79,16 +83,13 @@ class ThrottleRequestsWithPredis extends ThrottleRequests * * @param string $key * @param int $maxAttempts - * @param int $decayMinutes + * @param int $decaySeconds * @return mixed */ - protected function tooManyAttempts($key, $maxAttempts, $decayMinutes) + protected function tooManyAttempts($key, $maxAttempts, $decaySeconds) { $limiter = new DurationLimiter( - $this->redis, - $key, - $maxAttempts, - $decayMinutes * 60 + $this->getRedisConnection(), $key, $maxAttempts, $decaySeconds ); return tap(! $limiter->acquire(), function () use ($key, $limiter) { @@ -121,4 +122,14 @@ class ThrottleRequestsWithPredis extends ThrottleRequests { return $this->decaysAt[$key] - $this->currentTime(); } + + /** + * Get the Redis connection that should be used for throttling. + * + * @return \Illuminate\Redis\Connections\Connection + */ + protected function getRedisConnection() + { + return $this->redis; + } } diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index a856539a642a..6874e2e980c0 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -176,8 +176,8 @@ class SendRecurring implements ShouldQueue private function createRecurringInvitations($invoice): Invoice { if ($this->recurring_invoice->invitations->count() == 0) { - $this->recurring_invoice->service()->createInvitations()->save(); - $this->recurring_invoice = $this->recurring_invoice->fresh(); + $this->recurring_invoice = $this->recurring_invoice->service()->createInvitations()->save(); + // $this->recurring_invoice = $this->recurring_invoice->fresh(); } $this->recurring_invoice->invitations->each(function ($recurring_invitation) use ($invoice) { diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 8b447788b7be..4a86a210f6ce 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -11,17 +11,16 @@ namespace App\Providers; -use App\Http\Middleware\ThrottleRequestsWithPredis; -use App\Models\Scheduler; use App\Utils\Ninja; +use App\Models\Scheduler; +use Illuminate\Http\Request; use App\Utils\Traits\MakesHash; +use Illuminate\Support\Facades\Route; use Illuminate\Cache\RateLimiting\Limit; +use Illuminate\Support\Facades\RateLimiter; +use App\Http\Middleware\ThrottleRequestsWithPredis; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; -use Illuminate\Http\Request; -use Illuminate\Routing\Middleware\ThrottleRequests; -use Illuminate\Support\Facades\RateLimiter; -use Illuminate\Support\Facades\Route; class RouteServiceProvider extends ServiceProvider { @@ -36,11 +35,11 @@ class RouteServiceProvider extends ServiceProvider { parent::boot(); - if (Ninja::isHosted() && !config('ninja.testvars.travis')) { + // if (Ninja::isHosted() && !config('ninja.testvars.travis')) { app('router')->aliasMiddleware('throttle', ThrottleRequestsWithPredis::class); - } else { - app('router')->aliasMiddleware('throttle', ThrottleRequests::class); - } + // } else { + // app('router')->aliasMiddleware('throttle', ThrottleRequests::class); + // } Route::bind('task_scheduler', function ($value) { if (is_numeric($value)) { diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index 6e945840edb1..c511409993ca 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -482,7 +482,7 @@ class TemplateService default => $processed = [], }; - nlog(json_encode($processed)); + // nlog(json_encode($processed)); return $processed; diff --git a/composer.lock b/composer.lock index c5427c1227ac..e194aaba1e31 100644 --- a/composer.lock +++ b/composer.lock @@ -16665,23 +16665,23 @@ }, { "name": "nunomaduro/collision", - "version": "v8.3.0", + "version": "v8.4.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "b49f5b2891ce52726adfd162841c69d4e4c84229" + "reference": "e7d1aa8ed753f63fa816932bbc89678238843b4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/b49f5b2891ce52726adfd162841c69d4e4c84229", - "reference": "b49f5b2891ce52726adfd162841c69d4e4c84229", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/e7d1aa8ed753f63fa816932bbc89678238843b4a", + "reference": "e7d1aa8ed753f63fa816932bbc89678238843b4a", "shasum": "" }, "require": { "filp/whoops": "^2.15.4", "nunomaduro/termwind": "^2.0.1", "php": "^8.2.0", - "symfony/console": "^7.1.2" + "symfony/console": "^7.1.3" }, "conflict": { "laravel/framework": "<11.0.0 || >=12.0.0", @@ -16689,13 +16689,13 @@ }, "require-dev": { "larastan/larastan": "^2.9.8", - "laravel/framework": "^11.16.0", - "laravel/pint": "^1.16.2", - "laravel/sail": "^1.30.2", + "laravel/framework": "^11.19.0", + "laravel/pint": "^1.17.1", + "laravel/sail": "^1.31.0", "laravel/sanctum": "^4.0.2", "laravel/tinker": "^2.9.0", - "orchestra/testbench-core": "^9.2.1", - "pestphp/pest": "^2.34.9 || ^3.0.0", + "orchestra/testbench-core": "^9.2.3", + "pestphp/pest": "^2.35.0 || ^3.0.0", "sebastian/environment": "^6.1.0 || ^7.0.0" }, "type": "library", @@ -16758,7 +16758,7 @@ "type": "patreon" } ], - "time": "2024-07-16T22:41:01+00:00" + "time": "2024-08-03T15:32:23+00:00" }, { "name": "phar-io/manifest", From 689fe9218d2b9520bba3e44224def219543a7052 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 18:28:27 +1000 Subject: [PATCH 2/5] Roll back routeserviceprovider changes --- app/Providers/RouteServiceProvider.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 4a86a210f6ce..4f447463c7bb 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -35,11 +35,11 @@ class RouteServiceProvider extends ServiceProvider { parent::boot(); - // if (Ninja::isHosted() && !config('ninja.testvars.travis')) { + if (Ninja::isHosted() && !config('ninja.testvars.travis')) { app('router')->aliasMiddleware('throttle', ThrottleRequestsWithPredis::class); - // } else { - // app('router')->aliasMiddleware('throttle', ThrottleRequests::class); - // } + } else { + app('router')->aliasMiddleware('throttle', ThrottleRequests::class); + } Route::bind('task_scheduler', function ($value) { if (is_numeric($value)) { From 7e986b82c764e7fa6de61a6a61a8575659ab47b1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 18:46:37 +1000 Subject: [PATCH 3/5] Add includes --- app/Providers/RouteServiceProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 4f447463c7bb..6421b53ca446 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -19,6 +19,7 @@ use Illuminate\Support\Facades\Route; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Support\Facades\RateLimiter; use App\Http\Middleware\ThrottleRequestsWithPredis; +use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; From d69d465abf28e16129e476be10e3cea1d2911ebc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 20:21:30 +1000 Subject: [PATCH 4/5] Fixes for recurring invoice queries --- app/Jobs/Cron/RecurringInvoicesCron.php | 43 ++++++++++--------------- app/Jobs/Util/QuoteReminderJob.php | 16 ++++----- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/app/Jobs/Cron/RecurringInvoicesCron.php b/app/Jobs/Cron/RecurringInvoicesCron.php index b9c30656a5c8..f295ea6e446b 100644 --- a/app/Jobs/Cron/RecurringInvoicesCron.php +++ b/app/Jobs/Cron/RecurringInvoicesCron.php @@ -48,12 +48,12 @@ class RecurringInvoicesCron Auth::logout(); if (! config('ninja.db.multi_db_enabled')) { - $recurring_invoices = RecurringInvoice::query()->where('recurring_invoices.status_id', RecurringInvoice::STATUS_ACTIVE) - ->where('recurring_invoices.is_deleted', false) - ->where('recurring_invoices.remaining_cycles', '!=', '0') - ->whereNotNull('recurring_invoices.next_send_date') - ->whereNull('recurring_invoices.deleted_at') - ->where('recurring_invoices.next_send_date', '<=', now()->toDateTimeString()) + $recurring_invoices = RecurringInvoice::query()->where('status_id', RecurringInvoice::STATUS_ACTIVE) + ->where('is_deleted', false) + ->where('remaining_cycles', '!=', '0') + ->whereNotNull('next_send_date') + ->whereNull('deleted_at') + ->where('next_send_date', '<=', now()->toDateTimeString()) ->whereHas('client', function ($query) { $query->where('is_deleted', 0) ->where('deleted_at', null); @@ -87,27 +87,18 @@ class RecurringInvoicesCron foreach (MultiDB::$dbs as $db) { MultiDB::setDB($db); - $recurring_invoices = RecurringInvoice::query()->where('recurring_invoices.status_id', RecurringInvoice::STATUS_ACTIVE) - ->where('recurring_invoices.is_deleted', false) - ->where('recurring_invoices.remaining_cycles', '!=', '0') - ->whereNull('recurring_invoices.deleted_at') - ->whereNotNull('recurring_invoices.next_send_date') - ->where('recurring_invoices.next_send_date', '<=', now()->toDateTimeString()) - // ->whereHas('client', function ($query) { - // $query->where('is_deleted', 0) - // ->where('deleted_at', null); - // }) - // ->whereHas('company', function ($query) { - // $query->where('is_disabled', 0); - // }) - ->leftJoin('clients', function ($join) { - $join->on('recurring_invoices.client_id', '=', 'clients.id') - ->where('clients.is_deleted', 0) - ->whereNull('clients.deleted_at'); + $recurring_invoices = RecurringInvoice::query()->where('status_id', RecurringInvoice::STATUS_ACTIVE) + ->where('is_deleted', false) + ->where('remaining_cycles', '!=', '0') + ->whereNull('deleted_at') + ->whereNotNull('next_send_date') + ->where('next_send_date', '<=', now()->toDateTimeString()) + ->whereHas('client', function ($query) { + $query->where('is_deleted', 0) + ->where('deleted_at', null); }) - ->leftJoin('companies', function ($join) { - $join->on('recurring_invoices.company_id', '=', 'companies.id') - ->where('companies.is_disabled', 0); + ->whereHas('company', function ($query) { + $query->where('is_disabled', 0); }) ->with('company') ->cursor(); diff --git a/app/Jobs/Util/QuoteReminderJob.php b/app/Jobs/Util/QuoteReminderJob.php index fdebf50198c7..a583062df824 100644 --- a/app/Jobs/Util/QuoteReminderJob.php +++ b/app/Jobs/Util/QuoteReminderJob.php @@ -61,10 +61,10 @@ class QuoteReminderJob implements ShouldQueue nrlog("Sending quote reminders on ".now()->format('Y-m-d h:i:s')); Quote::query() - ->where('quotes.is_deleted', 0) - ->whereIn('quotes.status_id', [Invoice::STATUS_SENT]) - ->whereNull('quotes.deleted_at') - ->where('quotes.next_send_date', '<=', now()->toDateTimeString()) + ->where('is_deleted', 0) + ->whereIn('status_id', [Invoice::STATUS_SENT]) + ->whereNull('deleted_at') + ->where('next_send_date', '<=', now()->toDateTimeString()) ->whereHas('client', function ($query) { $query->where('is_deleted', 0) ->where('deleted_at', null); @@ -88,10 +88,10 @@ class QuoteReminderJob implements ShouldQueue nrlog("Sending quote reminders on db {$db} ".now()->format('Y-m-d h:i:s')); Quote::query() - ->where('quotes.is_deleted', 0) - ->whereIn('quotes.status_id', [Invoice::STATUS_SENT]) - ->whereNull('quotes.deleted_at') - ->where('quotes.next_send_date', '<=', now()->toDateTimeString()) + ->where('is_deleted', 0) + ->whereIn('status_id', [Invoice::STATUS_SENT]) + ->whereNull('deleted_at') + ->where('next_send_date', '<=', now()->toDateTimeString()) ->whereHas('client', function ($query) { $query->where('is_deleted', 0) ->where('deleted_at', null); From dea57e07809f79268b3e2f75c08892315ff18dc6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 08:37:21 +1000 Subject: [PATCH 5/5] Fixes for recurring invoice queries --- VERSION.txt | 2 +- app/Http/Controllers/ExportController.php | 4 ++-- app/Jobs/Company/CompanyExport.php | 2 +- config/ninja.php | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index b62d8ef8ec05..21a04bbf2c42 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.10.17 \ No newline at end of file +5.10.18 \ No newline at end of file diff --git a/app/Http/Controllers/ExportController.php b/app/Http/Controllers/ExportController.php index d182e613057d..0aea27594fe8 100644 --- a/app/Http/Controllers/ExportController.php +++ b/app/Http/Controllers/ExportController.php @@ -59,9 +59,9 @@ class ExportController extends BaseController /** @var \App\Models\User $user */ $user = auth()->user(); - $hash = Str::uuid(); + $hash = Str::uuid()->toString(); $url = \Illuminate\Support\Facades\URL::temporarySignedRoute('protected_download', now()->addHour(), ['hash' => $hash]); - Cache::put($hash, $url, now()->addHour()); + Cache::put($hash, $url, 3600); CompanyExport::dispatch($user->getCompany(), $user, $hash); diff --git a/app/Jobs/Company/CompanyExport.php b/app/Jobs/Company/CompanyExport.php index 3885c05e7df3..9cc901cdf240 100644 --- a/app/Jobs/Company/CompanyExport.php +++ b/app/Jobs/Company/CompanyExport.php @@ -695,7 +695,7 @@ class CompanyExport implements ShouldQueue $url = Cache::get($this->hash); - Cache::put($this->hash, $storage_path, now()->addHour()); + Cache::put($this->hash, $storage_path, 3600); App::forgetInstance('translator'); $t = app('translator'); diff --git a/config/ninja.php b/config/ninja.php index a1fe742fc8dc..1881afbb4e3a 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.10.17'), - 'app_tag' => env('APP_TAG', '5.10.17'), + 'app_version' => env('APP_VERSION', '5.10.18'), + 'app_tag' => env('APP_TAG', '5.10.18'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false),