service = $service; } public function register_routes(): void { register_rest_route( RunController::NAMESPACE, '/runs/(?P[0-9a-fA-F-]{36})/findings/(?P[0-9a-fA-F-]{36})/decision', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'change' ), 'permission_callback' => array( $this, 'authorize' ), 'args' => array( 'decision' => array( 'type' => 'string', 'enum' => array( 'active', 'acknowledged', 'suppressed' ), 'required' => true, ), 'reason' => array( 'type' => 'string', 'maxLength' => ManualCommentSanitizer::MAX_INPUT_BYTES, 'default' => '', ), ), ) ); } /** * @param WP_REST_Request> $request Request. * @return WP_REST_Response|WP_Error */ public function change( WP_REST_Request $request ) { try { $acknowledgement = $this->service->change( (string) $request->get_param( 'uuid' ), (string) $request->get_param( 'finding_uuid' ), (string) $request->get_param( 'decision' ), (string) $request->get_param( 'reason' ), get_current_user_id() ); } catch ( InvalidArgumentException $exception ) { return $this->error( 'invalid', 400 ); } catch ( StorageException $exception ) { return $this->error( 'not_found', 404 ); } catch ( \Throwable $exception ) { return $this->error( 'failed', 500 ); } return new WP_REST_Response( array( 'acknowledgement' => $acknowledgement ), 200 ); } /** * @param WP_REST_Request> $request Request. * @return true|WP_Error */ public function authorize( WP_REST_Request $request ) { if ( ! current_user_can( 'manage_options' ) ) { return new WP_Error( 'px320_audit_forbidden', __( 'You are not allowed to manage site audits.', '320px-site-audit' ), array( 'status' => 403 ) ); } $nonce = $request->get_header( 'X-WP-Nonce' ); if ( ! is_string( $nonce ) || false === wp_verify_nonce( $nonce, 'wp_rest' ) ) { return new WP_Error( 'px320_audit_invalid_nonce', __( 'The audit request could not be verified. Refresh the page and try again.', '320px-site-audit' ), array( 'status' => 403 ) ); } return true; } private function error( string $reason, int $status ): WP_Error { return new WP_Error( 'px320_audit_finding_decision_' . $reason, 'failed' === $reason ? __( 'The local report decision could not be saved safely. Nothing was sent outside this site.', '320px-site-audit' ) : __( 'The report decision is not valid for this completed finding.', '320px-site-audit' ), array( 'status' => $status ) ); } }