From 7e9122eaf442f0ea4cd2f2eecf1dfea1c8e7f7fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Falc=C3=B3n?= Date: Wed, 17 Jun 2026 16:12:51 +0200 Subject: [PATCH] feat(integration-requests): let the admin bypass limits and auto-approve (#551) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What The user matching \`ADMIN_EMAIL\` curates the integration-requests board, so they get special treatment: - **No monthly cap** — \`actionsRemaining()\` reports a full quota for the admin, so neither the backend checks nor the frontend buttons ever gate them. - **Auto-approved proposals** — requests created by the admin are stored as \`approved\` instead of \`pending\`, skipping moderation. ## How - New \`User::isAdmin()\` helper, mirroring \`isDemoAccount()\`, comparing against \`config('mail.admin_email')\` (already wired to \`ADMIN_EMAIL\`). - \`IntegrationRequestController::actionsRemaining()\` early-returns the limit for the admin. - \`IntegrationRequestController::store()\` sets \`status\` to \`Approved\` for the admin. ## Tests - Added a feature test covering the admin bypassing the monthly limit and auto-approval. All 16 \`IntegrationRequestTest\` tests pass. --- .../IntegrationRequestController.php | 12 +++++++++- app/Models/User.php | 5 ++++ tests/Feature/IntegrationRequestTest.php | 23 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/IntegrationRequestController.php b/app/Http/Controllers/IntegrationRequestController.php index acc1c18a..5acffc91 100644 --- a/app/Http/Controllers/IntegrationRequestController.php +++ b/app/Http/Controllers/IntegrationRequestController.php @@ -40,7 +40,11 @@ class IntegrationRequestController extends Controller return $this->limitReachedResponse(); } - $integrationRequest = $user->integrationRequests()->create($request->only(['name', 'url'])); + $integrationRequest = $user->integrationRequests()->create([ + ...$request->only(['name', 'url']), + // The admin curates the board, so their proposals skip moderation. + 'status' => $user->isAdmin() ? IntegrationRequestStatus::Approved : IntegrationRequestStatus::Pending, + ]); $integrationRequest->votes()->create(['user_id' => $user->id]); return $this->payload($user, 201); @@ -96,6 +100,12 @@ class IntegrationRequestController extends Controller private function actionsRemaining(User $user): int { + // The admin has no monthly cap; report a full quota so neither the + // backend checks nor the frontend buttons ever gate them. + if ($user->isAdmin()) { + return self::MONTHLY_ACTION_LIMIT; + } + $start = now()->startOfMonth(); $used = $user->integrationRequests()->where('created_at', '>=', $start)->count() diff --git a/app/Models/User.php b/app/Models/User.php index cdc0cf63..c9be818b 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -304,6 +304,11 @@ class User extends Authenticatable implements HasLocalePreference, MustVerifyEma return $this->email === config('app.demo.email'); } + public function isAdmin(): bool + { + return $this->email === config('mail.admin_email'); + } + public function preferredLocale(): string { return $this->locale ?? 'en'; diff --git a/tests/Feature/IntegrationRequestTest.php b/tests/Feature/IntegrationRequestTest.php index aaa97d33..246625ce 100644 --- a/tests/Feature/IntegrationRequestTest.php +++ b/tests/Feature/IntegrationRequestTest.php @@ -108,6 +108,29 @@ test('a user cannot exceed the monthly action limit', function () { ->assertStatus(422); }); +test('the admin bypasses the monthly limit and their requests are auto-approved', function () { + config(['mail.admin_email' => 'admin@whisper.test']); + $admin = User::factory()->create(['email' => 'admin@whisper.test']); + IntegrationRequest::factory()->count(5)->create(['user_id' => $admin->id]); + + $this->actingAs($admin) + ->postJson('/integration-requests', ['name' => 'Revolut', 'url' => 'https://revolut.com']) + ->assertCreated() + ->assertJsonPath('actionsRemaining', 3); + + $this->assertDatabaseHas('integration_requests', [ + 'user_id' => $admin->id, + 'name' => 'Revolut', + 'status' => IntegrationRequestStatus::Approved->value, + ]); + + $other = IntegrationRequest::factory()->approved()->create(); + + $this->actingAs($admin) + ->postJson("/integration-requests/{$other->id}/vote") + ->assertOk(); +}); + test('removing a vote is allowed even at the monthly limit', function () { $user = User::factory()->create(); $request = IntegrationRequest::factory()->approved()->create();