header('X-Admin-Token', '')); if ($token === '' || $provided === '' || !hash_equals($token, $provided)) { return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); } return null; } public function index(Request $request): JsonResponse { if ($res = $this->authorizeAdmin($request)) { return $res; } $query = Subscription::query()->with('user:id,email,name,tier'); if ($userId = $request->query('user_id')) { $query->where('user_id', (int) $userId); } if ($email = $request->query('email')) { $query->whereHas('user', fn ($q) => $q->where('email', $email)); } if ($status = $request->query('status')) { $query->where('status', (string) $status); } $limit = min(max((int) $request->query('limit', 50), 1), 200); $items = $query->orderByDesc('id')->limit($limit)->get(); return response()->json(['ok' => true, 'items' => $items]); } public function grant(Request $request): JsonResponse { if ($res = $this->authorizeAdmin($request)) { return $res; } $user = $this->resolveUser($request); if (!$user) { return response()->json(['ok' => false, 'error' => 'not_found'], 404); } $plan = (string) $request->input('plan', 'personal'); $status = (string) $request->input('status', 'active'); $provider = (string) $request->input('provider', 'admin'); $providerRef = (string) $request->input('provider_ref', ''); $startedAt = $this->parseDate($request->input('started_at')) ?? now(); $expiresAt = $this->parseDate($request->input('expires_at')); $sub = Subscription::create([ 'user_id' => $user->id, 'plan' => $plan, 'status' => $status, 'provider' => $provider, 'provider_ref' => $providerRef !== '' ? $providerRef : null, 'started_at' => $startedAt, 'expires_at' => $expiresAt, ]); if ($status === 'active') { $user->update(['tier' => 'personal']); $this->keywordQuota->enforceForUser((int) $user->id, 'personal'); } return response()->json(['ok' => true, 'subscription' => $sub]); } public function revoke(Request $request): JsonResponse { if ($res = $this->authorizeAdmin($request)) { return $res; } $id = (int) $request->input('id', 0); $now = now(); if ($id > 0) { $sub = Subscription::find($id); if (!$sub) { return response()->json(['ok' => false, 'error' => 'not_found'], 404); } $sub->update(['status' => 'revoked', 'expires_at' => $now]); $this->syncUserTier($sub->user_id); return response()->json(['ok' => true, 'revoked' => true]); } $user = $this->resolveUser($request); if (!$user) { return response()->json(['ok' => false, 'error' => 'not_found'], 404); } Subscription::where('user_id', $user->id) ->where('status', 'active') ->update(['status' => 'revoked', 'expires_at' => $now]); $this->syncUserTier($user->id); return response()->json(['ok' => true, 'revoked' => true]); } private function resolveUser(Request $request): ?User { if ($userId = $request->input('user_id')) { return User::find((int) $userId); } if ($email = $request->input('email')) { return User::where('email', (string) $email)->first(); } return null; } private function parseDate(mixed $value): ?Carbon { if (!$value) { return null; } try { return Carbon::parse((string) $value); } catch (\Throwable) { return null; } } private function syncUserTier(int $userId): void { $active = Subscription::where('user_id', $userId) ->where('status', 'active') ->where(function ($q): void { $q->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }) ->exists(); User::where('id', $userId)->update([ 'tier' => $active ? 'personal' : 'free', ]); $this->keywordQuota->enforceForUser($userId, $active ? 'personal' : 'free'); if (!$active) { UserApiKey::where('user_id', $userId)->update(['revoked_at' => now()]); } } }