From 33bdd6980147cecfa0e5521d83d76fd0b2793561 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jan 2026 09:25:21 +1100 Subject: [PATCH] Fixes for throttle middle ware in web.php --- app/DataMapper/QuickbooksSettings.php | 26 +++++++++++++++++++++++++ app/Enum/SyncDirection.php | 1 + app/Transformers/CompanyTransformer.php | 12 ++++++++++-- routes/api.php | 2 +- routes/web.php | 14 ++++++------- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/app/DataMapper/QuickbooksSettings.php b/app/DataMapper/QuickbooksSettings.php index 0225b0a58b..f6feb087f4 100644 --- a/app/DataMapper/QuickbooksSettings.php +++ b/app/DataMapper/QuickbooksSettings.php @@ -67,4 +67,30 @@ class QuickbooksSettings implements Castable 'settings' => $this->settings->toArray(), ]; } + + /** + * Check if this QuickbooksSettings instance represents actual data or is just a default empty object. + * + * @return bool True if this has actual QuickBooks connection data, false if it's just defaults + */ + public function isConfigured(): bool + { + // If accessTokenKey is set, we have a connection + return !empty($this->accessTokenKey); + } + + /** + * Check if this QuickbooksSettings instance is empty (default values only). + * + * @return bool True if this is an empty/default instance + */ + public function isEmpty(): bool + { + return empty($this->accessTokenKey) + && empty($this->refresh_token) + && empty($this->realmID) + && $this->accessTokenExpiresAt === 0 + && $this->refreshTokenExpiresAt === 0 + && empty($this->baseURL); + } } diff --git a/app/Enum/SyncDirection.php b/app/Enum/SyncDirection.php index a36d92bf5a..4d02aa0a3b 100644 --- a/app/Enum/SyncDirection.php +++ b/app/Enum/SyncDirection.php @@ -17,4 +17,5 @@ enum SyncDirection: string case PUSH = 'push'; // only creates and updates records created by Invoice Ninja. case PULL = 'pull'; // creates and updates record from QB. case BIDIRECTIONAL = 'bidirectional'; // creates and updates records created by Invoice Ninja and from QB. + case NONE = 'none'; // no sync. } diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php index a25533030a..cee6ee96ee 100644 --- a/app/Transformers/CompanyTransformer.php +++ b/app/Transformers/CompanyTransformer.php @@ -223,10 +223,18 @@ class CompanyTransformer extends EntityTransformer 'smtp_local_domain' => (string) $company->smtp_local_domain ?? '', 'smtp_verify_peer' => (bool) $company->smtp_verify_peer, 'e_invoice' => $company->e_invoice ?: new \stdClass(), - 'has_quickbooks_token' => $company->quickbooks ? true : false, - 'is_quickbooks_token_active' => $company->quickbooks?->accessTokenKey ?? false, 'legal_entity_id' => $company->legal_entity_id ? (int) $company->legal_entity_id : null, ]; + + // Only include QuickBooks flags if column is not null AND has actual connection data + // This prevents API bloat for users who don't use QuickBooks + $quickbooksRaw = $company->getRawOriginal('quickbooks'); + if (!is_null($quickbooksRaw) && $company->quickbooks->isConfigured()) { + $data['has_quickbooks_token'] = true; + $data['is_quickbooks_token_active'] = (bool) $company->quickbooks->accessTokenKey; + } + + return $data; } private function isLarge(Company $company): bool diff --git a/routes/api.php b/routes/api.php index 2ad89b0998..4f95293b51 100644 --- a/routes/api.php +++ b/routes/api.php @@ -453,7 +453,7 @@ Route::group(['middleware' => ['throttle:api', 'token_auth', 'valid_json','local Route::post('stripe/import_customers', [StripeController::class, 'import'])->middleware('password_protected')->name('stripe.import'); Route::post('stripe/verify', [StripeController::class, 'verify'])->middleware('password_protected')->name('stripe.verify'); - Route::post('stripe/disconnect/{company_gateway_id}', [StripeController::class, 'disconnect'])->middleware('password_protected')->name('stripe.disconnect'); +Route::post('stripe/disconnect/{company_gateway_id}', [StripeController::class, 'disconnect'])->middleware('password_protected')->name('stripe.disconnect'); Route::get('subscriptions/steps', [SubscriptionStepsController::class, 'index']); Route::post('subscriptions/steps/check', [SubscriptionStepsController::class, 'check']); diff --git a/routes/web.php b/routes/web.php index 6592cc7bb9..4cbd90dacd 100644 --- a/routes/web.php +++ b/routes/web.php @@ -21,17 +21,17 @@ use Illuminate\Support\Facades\Route; Route::get('/', [BaseController::class, 'flutterRoute'])->middleware('guest'); Route::get('setup', [SetupController::class, 'index'])->middleware('guest'); -Route::post('setup', [SetupController::class, 'doSetup'])->throttle(10, 1)->middleware('guest'); -Route::get('update', [SetupController::class, 'update'])->throttle(10, 1)->middleware('guest'); +Route::post('setup', [SetupController::class, 'doSetup'])->middleware('throttle:10,1')->middleware('guest'); +Route::get('update', [SetupController::class, 'update'])->middleware('throttle:10,1')->middleware('guest'); -Route::post('setup/check_db', [SetupController::class, 'checkDB'])->throttle(10, 1)->middleware('guest'); -Route::post('setup/check_mail', [SetupController::class, 'checkMail'])->throttle(10, 1)->middleware('guest'); -Route::post('setup/check_pdf', [SetupController::class, 'checkPdf'])->throttle(10, 1)->middleware('guest'); +Route::post('setup/check_db', [SetupController::class, 'checkDB'])->middleware('throttle:10,1')->middleware('guest'); +Route::post('setup/check_mail', [SetupController::class, 'checkMail'])->middleware('throttle:10,1')->middleware('guest'); +Route::post('setup/check_pdf', [SetupController::class, 'checkPdf'])->middleware('throttle:10,1')->middleware('guest'); Route::get('password/reset', [ForgotPasswordController::class, 'showLinkRequestForm'])->middleware('domain_db')->name('password.request'); -Route::post('password/email', [ForgotPasswordController::class, 'sendResetLinkEmail'])->throttle(10, 1)->name('password.email'); +Route::post('password/email', [ForgotPasswordController::class, 'sendResetLinkEmail'])->middleware('throttle:10,1')->name('password.email'); Route::get('password/reset/{token}', [ResetPasswordController::class, 'showResetForm'])->middleware(['domain_db', 'email_db'])->name('password.reset'); -Route::post('password/reset', [ResetPasswordController::class, 'reset'])->throttle(10, 1)->middleware('email_db')->name('password.update'); +Route::post('password/reset', [ResetPasswordController::class, 'reset'])->middleware('throttle:10,1')->middleware('email_db')->name('password.update'); Route::get('auth/{provider}', [LoginController::class, 'redirectToProvider']);