Files
Verde-Web/app/Http/Middleware/ResolveTenant.php

79 lines
2.5 KiB
PHP

<?php
namespace App\Http\Middleware;
use App\Models\Tenant;
use App\Models\User;
use App\Tenancy\Tenancy;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Resolves the current tenant from the request and sets it via Tenancy.
*
* Resolution order:
* 1. X-Tenant-Code header (typed by user before login, kept in cookie)
* 2. X-Tenant-Id header (uuid; admin tools sometimes prefer this)
* 3. Authenticated user's tenant_id (after login the bearer token
* guarantees scope, even if header is missing)
*
* If a header is present but maps to no tenant, returns 404 — the
* client can then prompt for a different LGU code.
*
* super_admin users bypass header resolution and aren't auto-scoped,
* letting them read across tenants.
*/
class ResolveTenant
{
public function handle(Request $request, Closure $next): Response
{
$headerCode = $request->header('X-Tenant-Code');
$headerId = $request->header('X-Tenant-Id');
$tenant = null;
if ($headerCode) {
$tenant = Tenant::where('code', strtoupper((string) $headerCode))->first();
if (! $tenant) {
\Log::info("ResolveTenant: Header code not found: {$headerCode}");
return response()->json([
'success' => false,
'data' => null,
'message' => "Unknown LGU code: {$headerCode}",
'errors' => null,
'meta' => null,
], 404);
}
} elseif ($headerId) {
$tenant = Tenant::where('uuid', $headerId)->first();
if (! $tenant) {
\Log::info("ResolveTenant: Header ID not found: {$headerId}");
}
}
// Fall back to the authenticated user's tenant.
if (! $tenant) {
$user = $request->user();
if ($user instanceof User && $user->tenant_id) {
$tenant = Tenant::find($user->tenant_id);
}
}
if ($tenant) {
if ($tenant->status !== Tenant::STATUS_ACTIVE) {
return response()->json([
'success' => false,
'data' => null,
'message' => "LGU '{$tenant->name}' is not currently active.",
'errors' => null,
'meta' => null,
], 403);
}
Tenancy::setCurrent($tenant);
}
return $next($request);
}
}