feat(authorization): implement WebsiteExtra management with controller, request, resource, service, routes, middleware, and tests
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Tenant\Controllers\AdminApp;
|
||||
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Tenant\Requests\AdminApp\UpdateWebsiteExtrasRequest;
|
||||
use App\Domains\Tenant\Resources\AdminApp\WebsiteExtrasResource;
|
||||
use App\Domains\Tenant\Services\TenantInformationService;
|
||||
use App\Domains\Tenant\Services\WebsiteExtraService;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class WebsiteExtraController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected WebsiteExtraService $websiteExtraService,
|
||||
protected TenantInformationService $tenantInformationService,
|
||||
) {}
|
||||
|
||||
public function show(Request $request): WebsiteExtrasResource
|
||||
{
|
||||
return WebsiteExtrasResource::make(
|
||||
$this->loadTenant($request->user())
|
||||
);
|
||||
}
|
||||
|
||||
public function update(UpdateWebsiteExtrasRequest $request): WebsiteExtrasResource
|
||||
{
|
||||
$tenant = $request->user()->tenant()->firstOrFail();
|
||||
|
||||
$this->websiteExtraService->replaceForTenant(
|
||||
$tenant,
|
||||
$request->validated('extras', [])
|
||||
);
|
||||
|
||||
return WebsiteExtrasResource::make(
|
||||
$this->loadTenant($request->user())
|
||||
);
|
||||
}
|
||||
|
||||
private function loadTenant(User $user): Tenant
|
||||
{
|
||||
$tenant = $user->tenant()->firstOrFail();
|
||||
|
||||
return $this->tenantInformationService->load($tenant, [
|
||||
'websiteType.extras',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Tenant\Requests\AdminApp;
|
||||
|
||||
use App\Domains\Tenant\Services\WebsiteExtraService;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateWebsiteExtrasRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return app(WebsiteExtraService::class)->requestRules(
|
||||
$this->user()?->tenant?->website_type_code
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Tenant\Resources\AdminApp;
|
||||
|
||||
use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
* @mixin Tenant
|
||||
*/
|
||||
class WebsiteExtrasResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
$websiteExtras = $this->websiteExtras->keyBy(
|
||||
fn ($extra) => $extra->websiteTypeExtra->nombre
|
||||
);
|
||||
|
||||
return [
|
||||
'website_type' => $this->websiteType ? [
|
||||
'codigo' => $this->websiteType->codigo,
|
||||
'nombre' => $this->websiteType->nombre,
|
||||
] : null,
|
||||
'definitions' => $this->websiteType?->extras
|
||||
->mapWithKeys(fn ($definition) => [
|
||||
$definition->nombre => [
|
||||
'descripcion' => $definition->descripcion,
|
||||
'is_required' => $definition->is_required,
|
||||
'request_rules' => $definition->config_schema['request_rules'] ?? [],
|
||||
],
|
||||
]) ?? [],
|
||||
'extras' => $websiteExtras->mapWithKeys(fn ($extra) => [
|
||||
$extra->websiteTypeExtra->nombre => $this->formatConfig(
|
||||
$extra->resolvedConfig(),
|
||||
fn (Attachment $attachment): string => $attachment->key
|
||||
),
|
||||
]),
|
||||
'resolved_extras' => $websiteExtras->mapWithKeys(fn ($extra) => [
|
||||
$extra->websiteTypeExtra->nombre => $this->formatConfig(
|
||||
$extra->resolvedConfig(),
|
||||
fn (Attachment $attachment): string => $attachment->getTemporaryUrl(1440)
|
||||
),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
private function formatConfig(mixed $value, callable $formatAttachment): mixed
|
||||
{
|
||||
if ($value instanceof Attachment) {
|
||||
return $formatAttachment($value);
|
||||
}
|
||||
|
||||
if (! is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return array_map(
|
||||
fn (mixed $item): mixed => $this->formatConfig($item, $formatAttachment),
|
||||
$value
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Tenant\Models\WebsiteType;
|
||||
use App\Domains\Tenant\Models\WebsiteTypeExtra;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
@@ -118,6 +119,21 @@ class WebsiteExtraService
|
||||
$tenant->unsetRelation('websiteExtras');
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all configured extras for a tenant.
|
||||
*
|
||||
* @param array<string, mixed> $extras
|
||||
*/
|
||||
public function replaceForTenant(Tenant $tenant, array $extras): void
|
||||
{
|
||||
DB::transaction(function () use ($tenant, $extras): void {
|
||||
$tenant->websiteExtras()->delete();
|
||||
$this->createForTenant($tenant, $extras);
|
||||
});
|
||||
|
||||
$tenant->unsetRelation('websiteExtras');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, WebsiteTypeExtra>
|
||||
*/
|
||||
|
||||
13
app/Domains/Tenant/routes/adminapp.php
Normal file
13
app/Domains/Tenant/routes/adminapp.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
use App\Domains\Tenant\Controllers\AdminApp\WebsiteExtraController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('v1/adminapp/tenant')
|
||||
->middleware(['auth:sanctum', 'adminapp.tenant'])
|
||||
->group(function (): void {
|
||||
Route::get('website-extras', [WebsiteExtraController::class, 'show'])
|
||||
->name('adminapp.tenant.website-extras.show');
|
||||
Route::put('website-extras', [WebsiteExtraController::class, 'update'])
|
||||
->name('adminapp.tenant.website-extras.update');
|
||||
});
|
||||
@@ -8,3 +8,5 @@ Route::get('tenants/bootstrap/{dominio}', BootstrapTenantController::class)
|
||||
->where('dominio', '.*');
|
||||
|
||||
Route::apiResource('tenants', TenantController::class);
|
||||
|
||||
require __DIR__.'/adminapp.php';
|
||||
|
||||
30
app/Http/Middleware/EnsureAdminAppTenant.php
Normal file
30
app/Http/Middleware/EnsureAdminAppTenant.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use Closure;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class EnsureAdminAppTenant
|
||||
{
|
||||
/**
|
||||
* Ensure the authenticated user is an AdminApp user bound to a tenant.
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
if (
|
||||
! $user
|
||||
|| $user->rol_codigo !== RoleCode::AdminApp->value
|
||||
|| ! $user->tenant_codigo
|
||||
) {
|
||||
throw new AuthorizationException;
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user