56 lines
4.2 KiB
PHP
56 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace App\Modules\Identity\Http;
|
|
|
|
use App\Shared\Context\{CompanyContext,ModuleNavigation,ModuleRecords};
|
|
use App\Modules\Identity\Services\Permissions;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
final class ModuleRecordsController
|
|
{
|
|
public function index(Request $r,CompanyContext $context,Permissions $permissions)
|
|
{
|
|
$s=$context->identifiers();$out=[];
|
|
$permissions->require($context->userId(),$s['tenant_id'],$s['company_id'],'access.manage');
|
|
foreach(ModuleRecords::AREAS as $area){
|
|
$unit=str_ends_with($area,'_drafts')?$context->unitId():null;
|
|
if(str_ends_with($area,'_drafts')&&!$unit)continue;
|
|
if(!$permissions->has($context->userId(),$s['tenant_id'],$s['company_id'],"$area.view",$unit))continue;
|
|
$rows=DB::table('a_'.$area)->where($s)->where('unit_id',$unit)->orderBy('id')->get(['id','name','version']);
|
|
foreach($rows as $row){
|
|
$row->modules=DB::table('identity_audit')->where($s)->whereIn('action',['module.record.associated','module.record.disassociated'])
|
|
->whereRaw("details::jsonb->>'area' = ?",[$area])->whereRaw("details::jsonb->>'record_id' = ?",[(string)$row->id])
|
|
->orderByDesc('id')->get(['details','action'])->unique(fn($a)=>json_decode($a->details,true)['module_id'])
|
|
->filter(fn($a)=>$a->action==='module.record.associated')->map(fn($a)=>json_decode($a->details,true)['module_id'])->values()->all();
|
|
}
|
|
$out[$area]=$rows;
|
|
}
|
|
return response()->json(['records'=>$out,'modules'=>app(ModuleNavigation::class)->available($context),
|
|
'notice'=>'Registos sem associação explícita permanecem aqui visíveis pelos direitos originais. Associar não altera o registo, a origem ou as permissões.'])->header('Cache-Control','no-store');
|
|
}
|
|
public function associate(Request $r,CompanyContext $context,Permissions $permissions)
|
|
{
|
|
$d=$r->validate(['area'=>'required|in:'.implode(',',ModuleRecords::AREAS),'id'=>'required|integer|min:1','version'=>'required|integer|min:1','module_id'=>'required|string','reason'=>'required|string|min:3|max:500','operation'=>'sometimes|in:associate,remove']);
|
|
abort_if(array_diff(array_keys($r->all()),array_keys($d))!==[],422);
|
|
$s=$context->identifiers();$unit=str_ends_with($d['area'],'_drafts')?$context->unitId():null;
|
|
abort_if(str_ends_with($d['area'],'_drafts')&&!$unit,403);
|
|
DB::transaction(function()use($d,$s,$unit,$context,$permissions){
|
|
DB::table('companies')->where('tenant_id',$s['tenant_id'])->where('id',$s['company_id'])->lockForUpdate()->firstOrFail();
|
|
$permissions->require($context->userId(),$s['tenant_id'],$s['company_id'],'access.manage');
|
|
$permissions->require($context->userId(),$s['tenant_id'],$s['company_id'],$d['area'].'.view',$unit);
|
|
$permissions->require($context->userId(),$s['tenant_id'],$s['company_id'],$d['area'].'.edit',$unit);
|
|
abort_unless(in_array($d['module_id'],array_column(app(ModuleNavigation::class)->available($context),'id'),true),403);
|
|
$row=DB::table('a_'.$d['area'])->where($s)->where('unit_id',$unit)->where('id',$d['id'])->first(['id','version']);
|
|
abort_unless($row,403);
|
|
abort_unless((int)$row->version===(int)$d['version'],409,'O registo mudou. Reabra a consulta antes de decidir a associação.');
|
|
$previous=DB::table('identity_audit')->where($s)->whereIn('action',['module.record.associated','module.record.disassociated'])
|
|
->whereRaw("details::jsonb->>'area' = ?",[$d['area']])->whereRaw("details::jsonb->>'record_id' = ?",[(string)$d['id']])->whereRaw("details::jsonb->>'module_id' = ?",[$d['module_id']])->orderByDesc('id')->value('action');
|
|
$remove=($d['operation']??'associate')==='remove';
|
|
if(($remove&&$previous==='module.record.associated')||(!$remove&&$previous!=='module.record.associated'))
|
|
ModuleRecords::associate($d['area'],$d['id'],$context->userId(),$s+['unit_id'=>$unit],$d['module_id'],$d['reason'],$remove,(int)$row->version);
|
|
});
|
|
return response()->json(['ok'=>true]);
|
|
}
|
|
}
|