route('/admin/privacy','GET',fn()=>['registration'=>\ABeCe\Booking\Service\RegistrationPrivacyService::overview(),'require_phone'=>(bool)get_option('abece_booking_require_phone',true),'settings'=>$this->retention->settings(),'policy_url'=>get_privacy_policy_url(),'policy_settings_url'=>admin_url('options-privacy.php'),'export_url'=>admin_url('export-personal-data.php'),'erase_url'=>admin_url('erase-personal-data.php'),'reviews'=>$this->reviews(),'audit'=>array_reverse((array)get_option('abece_booking_privacy_cleanup_audit',[])),'next_run'=>wp_next_scheduled('abece_booking_privacy_retention')?:null]); $this->route('/admin/privacy/registration','PATCH',fn($r)=>\ABeCe\Booking\Service\RegistrationPrivacyService::save($this->body($r))); $this->route('/admin/privacy/retention','PATCH',fn($r)=>$this->retention->save($this->body($r))); $this->route('/admin/privacy/preview','POST',function($r){$body=$this->body($r);\ABeCe\Booking\Service\BookingValidator::fields($body,[]);return $this->retention->run(false);}); $this->route('/admin/privacy/cleanup','POST',function($r){$data=$this->body($r);\ABeCe\Booking\Service\BookingValidator::fields($data,['confirmed']);if(($data['confirmed']??false)!==true)throw new CatalogException('abece_booking_privacy_confirmation',__('Confirm that you reviewed the dry run before running cleanup.','abece-booking'),400);return $this->retention->run(true);}); $this->route('/admin/privacy/identity/(?P[1-9][0-9]*)','POST',fn($r)=>$this->identities->approve((int)$r['id'],$this->body($r))); $this->route('/admin/privacy/reviews/(?P[a-f0-9]{64})','POST',fn($r)=>$this->retention->review($r['key'],$this->body($r))); $this->route('/admin/privacy/minimization','PATCH',fn($r)=>$this->retention->minimization($this->body($r))); } private function reviews():array {$reviews=(array)get_option('abece_booking_privacy_reviews',[]);$result=[];foreach($reviews as $key=>$review)$result[]=['key'=>$key]+$review;return $result;} private function route(string $route,string $method,callable $callback):void {register_rest_route(CatalogController::REST_NAMESPACE,$route,['methods'=>$method,'permission_callback'=>function($r)use($method){if(!current_user_can('manage_privacy_options')||!current_user_can('export_others_personal_data')||!current_user_can('erase_others_personal_data'))return new \WP_Error('abece_booking_forbidden',__('You do not have permission to manage privacy requests.','abece-booking'),['status'=>rest_authorization_required_code()]);if($method!=='GET'&&!wp_verify_nonce($r->get_header('X-WP-Nonce'),'wp_rest'))return new \WP_Error('rest_cookie_invalid_nonce',__('The security check failed. Reload the page and try again.','abece-booking'),['status'=>403]);return true;},'callback'=>function($r)use($callback){try{$response=new \WP_REST_Response($callback($r));$response->header('Cache-Control','private, no-store');return $response;}catch(CatalogException $e){return new \WP_Error($e->errorCode,$e->getMessage(),['status'=>$e->status,'field'=>$e->field]);}catch(\Throwable){return new \WP_Error('abece_booking_privacy_processing',__('Privacy processing could not be completed. No technical or personal details are included in this error.','abece-booking'),['status'=>503]);}}]);} private function body(\WP_REST_Request $r):array {if(!is_object(json_decode($r->get_body())))throw new CatalogException('abece_booking_invalid_json',__('A JSON object is required.','abece-booking'),400);return $r->get_json_params();} }