route('/settings','GET',$all,fn()=>['locale'=>\ABeCe\Booking\Support\LocaleContext::current(),'timezone'=>wp_timezone()->getName(),'memberships_enabled'=>MembershipModeService::enabled(),'sections'=>['general'=>true,'privacy'=>current_user_can('manage_privacy_options')&¤t_user_can('export_others_personal_data')&¤t_user_can('erase_others_personal_data'),'bookings'=>$this->any($bookingCaps)||current_user_can(Capabilities::MANAGE_CANCELLATION_POLICIES),'booking_rules'=>$this->any($bookingCaps),'cancellation'=>current_user_can(Capabilities::MANAGE_CANCELLATION_POLICIES),'membership'=>\ABeCe\Booking\Edition\Entitlements::current()->has('memberships')&&$this->any($members),'payments'=>$this->any($credit),'calendar'=>$this->any($resources),'location'=>$this->any($resources),'integrations'=>$this->any($resources)]]); $rules=new \ABeCe\Booking\Service\BookingRulesService(new \ABeCe\Booking\Repository\SettingsRepository()); $this->route('/settings/bookings','GET',$bookingCaps,fn()=>$rules->response());$this->route('/settings/bookings','PATCH,PUT',$bookingCaps,function($r)use($rules){$rules->save($this->body($r));return $rules->response();}); $this->route('/settings/general','GET',$all,fn()=>['site_name'=>get_bloginfo('name'),'timezone'=>wp_timezone()->getName(),'locale'=>\ABeCe\Booking\Support\LocaleContext::current()]); $this->route('/settings/membership','GET',$members,fn()=>$this->membership->get());$this->route('/settings/membership','PATCH,PUT',$members,fn($r)=>$this->membership->save($this->body($r))); $this->route('/settings/payments','GET',$credit,fn()=>$this->payments->get());$this->route('/settings/payments','PATCH,PUT',$credit,fn($r)=>$this->payments->save($this->body($r),get_current_user_id())); $this->route('/settings/bank-profiles/preview','POST',$credit,fn($r)=>$this->payments->profiles()->preview($this->body($r),get_current_user_id())); $this->route('/settings/integrations','GET',$resources,fn()=>$this->integration->get());$this->route('/settings/integrations','PATCH,PUT',$resources,fn($r)=>$this->integration->save($this->body($r))); $this->route('/payment-methods','GET',[],fn($r)=>$this->resolve($r,false));$this->route('/admin/payment-methods','GET',[Capabilities::MANAGE_BOOKINGS],fn($r)=>$this->resolve($r,true)); } private function resolve(\WP_REST_Request $r,bool $admin): array { $id=$this->queryId($r->get_param('resource_id'),'resource_id');$currency=$r->get_param('currency');if(!is_string($currency)||!preg_match('/^[A-Z]{3}$/D',$currency))CatalogValidator::invalid('currency',__('Use a three-letter currency code.','abece-booking')); $customer=$admin?$this->queryId($r->get_param('customer_user_id'),'customer_user_id',true):get_current_user_id();if($customer&&!get_userdata($customer))CatalogValidator::invalid('customer_user_id',__('The selected WordPress user does not exist.','abece-booking')); return ['methods'=>$this->methods->methods($id,$currency,$customer,get_current_user_id(),$admin)]; } private function queryId(mixed $value,string $field,bool $nullable=false): ?int { if($value===null&&$nullable)return null; if(!is_scalar($value)||!preg_match('/^[1-9][0-9]*$/D',(string)$value)||false===filter_var($value,FILTER_VALIDATE_INT))CatalogValidator::invalid($field,__('An integer within the allowed range is required.','abece-booking')); return (int)$value; } private function any(array $caps): bool {foreach($caps as $cap)if(current_user_can($cap))return true;return false;} private function permission(array $caps): bool|\WP_Error {if(!is_user_logged_in())return new \WP_Error('abece_booking_login_required',__('Log in to manage your bookings.','abece-booking'),['status'=>401]);if(!$caps||$this->any($caps))return true;return new \WP_Error('abece_booking_forbidden',__('You do not have permission to access this ABeCe Booking page.','abece-booking'),['status'=>403]);} private function route(string $path,string $methods,array $caps,callable $operation): void {register_rest_route(CatalogController::REST_NAMESPACE,$path,['methods'=>$methods,'permission_callback'=>fn()=>$this->permission($caps),'callback'=>function($r)use($operation){try{$response=new \WP_REST_Response($operation($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]);}}]);} 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();} }