19 lines
6.2 KiB
PHP
19 lines
6.2 KiB
PHP
<?php
|
|
namespace App\Shared\Geography;
|
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\{DB,Crypt};
|
|
|
|
final class GeographyController
|
|
{
|
|
private function input(Request $r,array $rules):array{$v=$r->validate($rules);abort_if(array_diff(array_keys($r->all()),array_keys($v)),422);return $v;}
|
|
public function catalogue(Request $r){Catalogue::guard();$d=$this->input($r,['parent'=>'nullable|string|max:100','search'=>'nullable|string|max:100','page'=>'sometimes|integer|min:1|max:10000']);return response()->json(Catalogue::page($d))->header('Cache-Control','no-store');}
|
|
public function segments(string $kind,Request $r){Catalogue::guard();$rules=['after'=>'sometimes|integer|min:0'];foreach(Cartography::FIELDS as$f)$rules[$f]=['sometimes','string','regex:/^[A-Za-z0-9]{1,20}$/D'];return response()->json(Segments::page($kind,$this->input($r,$rules)))->header('Cache-Control','no-store');}
|
|
public function segmentScreen(string $kind,Request $r){$this->segments($kind,$r);return response()->view('geography-workspace',['kind'=>$kind,'entityId'=>0,'context'=>$r->session()->get('company_context.token'),'csrf'=>csrf_token()]);}
|
|
public function screen(string $kind,int $id,Request $r,Locations $locations){$locations->run($kind,$id,false,fn()=>null);return response()->view('geography-workspace',['kind'=>$kind,'entityId'=>$id,'context'=>$r->session()->get('company_context.token'),'csrf'=>csrf_token()]);}
|
|
public function show(string $kind,int $id,Locations $locations){return $locations->run($kind,$id,false,function($db,$scope,$entity,$actor,$binding){return Locations::useHost($db,function()use($db,$scope,$entity){$old=Locations::current($db,$scope);return response()->json(['entity'=>$entity,'location'=>$old,'revision'=>Locations::hash([$scope,$entity,$old]),'catalogue_version'=>Catalogue::active()->source_version,'purpose'=>'segmentation']);});});}
|
|
public function history(string $kind,int $id,Request $r,Locations $locations){Catalogue::guard();$d=$this->input($r,['page'=>'sometimes|integer|min:1|max:10000']);return $locations->run($kind,$id,false,fn($db,$scope)=>response()->json($db->table('geo_location_history')->where($scope)->orderByDesc('id')->paginate(15,['id','actor_id','reason','before','after','created_at'],'page',(int)($d['page']??1))->through(function($row){$row->before=json_decode($row->before,true);$row->after=json_decode($row->after,true);return $row;})));}
|
|
public function preview(string $kind,int $id,Request $r,Locations $locations){Catalogue::guard();$d=$this->input($r,['operation_key'=>'required|uuid','revision'=>'required|string|size:64','catalogue_version'=>'required|string|size:64','territory_key'=>'present|nullable|string|max:100','reason'=>'required|string|min:10|max:2000']);$d['operation_key']=strtolower($d['operation_key']);return $locations->run($kind,$id,true,function($db,$scope,$entity,$actor,$binding)use($d){return Locations::useHost($db,function()use($db,$scope,$entity,$actor,$binding,$d){$old=Locations::current($db,$scope);abort_unless(hash_equals(Locations::hash([$scope,$entity,$old]),$d['revision']),409,'O cadastro ou a localização mudou. Confira novamente.');abort_unless(hash_equals(Catalogue::active(true)->source_version,$d['catalogue_version']),409,'O catálogo mudou.');$selection=$d['territory_key']===null?null:Catalogue::selection($d['catalogue_version'],$d['territory_key']);$cut=$d+['scope'=>$scope,'entity'=>$entity,'actor'=>$actor,'binding'=>$binding,'observed'=>time()];return response()->json(['preview'=>Crypt::encryptString(json_encode($cut,JSON_THROW_ON_ERROR)),'impact'=>['entity'=>$entity['name'],'purpose'=>'Localização para segmentação','before'=>$old['selection']??null,'after'=>$selection,'reason'=>$d['reason'],'canonical_address_changed'=>false,'dependent_records_changed'=>false]]);});});}
|
|
public function confirm(string $kind,int $id,Request $r,Locations $locations){Catalogue::guard();$d=$this->input($r,['preview'=>'required|string|max:131072']);try{$cut=json_decode(Crypt::decryptString($d['preview']),true,64,JSON_THROW_ON_ERROR);}catch(\Throwable){abort(409,'Prévia inválida.');}return $locations->run($kind,$id,true,function($db,$scope,$entity,$actor,$binding)use($cut){return Locations::useHost($db,function()use($db,$scope,$entity,$actor,$binding,$cut){abort_unless(($cut['scope']??null)===$scope&&($cut['actor']??null)===$actor&&($cut['binding']??null)===$binding&&is_int($cut['observed']??null)&&$cut['observed']>=time()-600&&$cut['observed']<=time(),409,'A prévia ou o contexto mudou.');$hash=Locations::hash([$scope,$cut['revision'],$cut['catalogue_version'],$cut['territory_key'],$cut['reason']]);$old=$db->table('geo_commands')->where(['tenant_id'=>$scope['tenant_id'],'company_id'=>$scope['company_id'],'actor_id'=>$actor,'operation_key'=>$cut['operation_key']])->first();if($old){abort_unless(hash_equals($old->request_hash,$hash),409,'Chave já usada com outros dados.');return response()->json(json_decode($old->result,true)+['replayed'=>true]);}$before=Locations::current($db,$scope);abort_unless(hash_equals(Locations::hash([$scope,$entity,$before]),$cut['revision']),409,'O cadastro ou a localização mudou desde a conferência.');$state=Catalogue::active(true);abort_unless(hash_equals($state->source_version,$cut['catalogue_version']),409,'O catálogo mudou.');$selection=$cut['territory_key']===null?null:Catalogue::selection($cut['catalogue_version'],$cut['territory_key']);$revision=($before['revision']??0)+1;$values=['revision'=>$revision,'selection'=>$selection===null?null:json_encode($selection,JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR),'actor_id'=>$actor,'reason'=>$cut['reason'],'updated_at'=>now()];$db->table('geo_locations')->updateOrInsert($scope,$values);$after=Locations::current($db,$scope);$db->table('geo_location_history')->insert($scope+['actor_id'=>$actor,'reason'=>$cut['reason'],'before'=>json_encode($before,JSON_THROW_ON_ERROR),'after'=>json_encode($after,JSON_THROW_ON_ERROR),'created_at'=>now()]);$result=['revision'=>$revision,'selection'=>$selection];$db->table('geo_commands')->insert(['tenant_id'=>$scope['tenant_id'],'company_id'=>$scope['company_id'],'actor_id'=>$actor,'operation_key'=>$cut['operation_key'],'request_hash'=>$hash,'result'=>json_encode($result,JSON_THROW_ON_ERROR),'created_at'=>now()]);return response()->json($result+['replayed'=>false],201);});});}
|
|
}
|