netgescon-day0/app/Services/Documenti/DocumentoArchivioVisibilityService.php

141 lines
5.5 KiB
PHP

<?php
namespace App\Services\Documenti;
use App\Models\Documento;
use App\Models\DocumentoArchivioCartella;
use App\Models\DocumentoStabile;
use App\Models\User;
use App\Support\StabileContext;
use Illuminate\Database\Eloquent\Builder;
class DocumentoArchivioVisibilityService
{
public function scopeVisibleDocumenti(Builder $query, User $user): Builder
{
$activeStabile = StabileContext::getActiveStabile($user);
if ($activeStabile !== null) {
$query->where('stabile_id', (int) $activeStabile->id);
} elseif (! $user->hasAnyRole(['super-admin', 'admin'])) {
$allowedIds = StabileContext::accessibleStabili($user)
->pluck('id')
->map(fn($value): int => (int) $value)
->all();
if ($allowedIds === []) {
$query->whereRaw('1 = 0');
return $query;
}
$query->whereIn('stabile_id', $allowedIds);
}
return $query->where(function (Builder $documentQuery) use ($user): void {
$documentQuery->whereNull('cartella_archivio_id')
->where(function (Builder $baseVisibility) use ($user): void {
$baseVisibility->whereNull('visibility_scope')
->orWhere('visibility_scope', 'interno')
->orWhere(function (Builder $restricted) use ($user): void {
$this->applyVisibilityConstraint($restricted, $user, 'documenti');
});
})
->orWhereHas('cartellaArchivio', function (Builder $folderQuery) use ($user): void {
$folderQuery->where('is_active', true);
$this->applyVisibilityConstraint($folderQuery, $user, 'documento_archivio_cartelle');
});
});
}
public function scopeVisibleCartelle(Builder $query, User $user, ?int $stabileId = null): Builder
{
if ($stabileId !== null && $stabileId > 0) {
$query->where('stabile_id', $stabileId);
} else {
$activeStabile = StabileContext::getActiveStabile($user);
if ($activeStabile !== null) {
$query->where('stabile_id', (int) $activeStabile->id);
} elseif (! $user->hasAnyRole(['super-admin', 'admin'])) {
$allowedIds = StabileContext::accessibleStabili($user)
->pluck('id')
->map(fn($value): int => (int) $value)
->all();
if ($allowedIds === []) {
$query->whereRaw('1 = 0');
return $query;
}
$query->whereIn('stabile_id', $allowedIds);
}
}
$query->where('is_active', true);
$this->applyVisibilityConstraint($query, $user, 'documento_archivio_cartelle');
return $query;
}
public function canAccessDocumento(User $user, Documento $documento): bool
{
return $this->scopeVisibleDocumenti(Documento::query()->whereKey($documento->getKey()), $user)->exists();
}
public function canAccessDocumentoStabile(User $user, DocumentoStabile $documentoStabile): bool
{
$allowedIds = StabileContext::accessibleStabili($user)
->pluck('id')
->map(fn($value): int => (int) $value)
->all();
return in_array((int) $documentoStabile->stabile_id, $allowedIds, true);
}
private function applyVisibilityConstraint(Builder $query, User $user, string $table): void
{
$roles = $user->getRoleNames()->map(fn($role): string => (string) $role)->values()->all();
$groupLabels = $this->resolveAudienceGroupsForUser($user);
$userId = (int) $user->id;
$query->where(function (Builder $visibilityQuery) use ($table, $roles, $groupLabels, $userId): void {
$visibilityQuery->whereNull($table . '.visibility_scope')
->orWhere($table . '.visibility_scope', 'interno')
->orWhere($table . '.visibility_scope', 'studio')
->orWhere(function (Builder $restrictedQuery) use ($table, $roles, $groupLabels, $userId): void {
$restrictedQuery->where($table . '.visibility_scope', 'restricted')
->where(function (Builder $matchQuery) use ($table, $roles, $groupLabels, $userId): void {
if ($roles !== []) {
foreach ($roles as $role) {
$matchQuery->orWhereJsonContains($table . '.visibility_roles', $role);
}
}
if ($groupLabels !== []) {
foreach ($groupLabels as $groupLabel) {
$matchQuery->orWhereJsonContains($table . '.visibility_groups', $groupLabel);
}
}
$matchQuery->orWhereJsonContains($table . '.allowed_user_ids', $userId);
});
});
});
}
private function resolveAudienceGroupsForUser(User $user): array
{
$groups = [];
if ($user->hasAnyRole(['super-admin', 'admin', 'amministratore'])) {
$groups[] = 'Amministratore';
$groups[] = 'Studio completo';
}
if ($user->hasRole('collaboratore')) {
$groups[] = 'Collaboratori interni';
}
return array_values(array_unique($groups));
}
}