namespace = 'agenticdaisy-firewall/v1'; $this->rest_base = 'ledger'; } /** * Register routes. */ public function register_routes(): void { register_rest_route( 'agenticdaisy-firewall/v1', '/' . $this->rest_base . '/(?P\d+)/undo', array( array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'undo_item' ), 'permission_callback' => array( $this, 'permissions_check' ), 'args' => array( 'id' => array( 'type' => 'integer', 'required' => true, 'minimum' => 1, 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', ), ), ), ) ); register_rest_route( 'agenticdaisy-firewall/v1', '/' . $this->rest_base . '/(?P\d+)/revision', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_revision' ), 'permission_callback' => array( $this, 'permissions_check' ), 'args' => array( 'id' => array( 'type' => 'integer', 'required' => true, 'minimum' => 1, 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', ), ), ), ) ); } /** * GET the revision recording what an action changed (AF-12.11). * * On demand rather than on every listing: finding it costs a query per * row, and a page of twenty would pay it twenty times for a link most * readers never follow. * * @param WP_REST_Request $request Request. */ public function get_revision( $request ): WP_REST_Response { $revision_id = $this->rollback->change_revision_id( (int) $request->get_param( 'id' ) ); return new WP_REST_Response( array( 'revision_id' => $revision_id, // Core's own diff screen. Absence is ordinary: revisions can // be disabled, trimmed, or never written for this action. 'link' => null === $revision_id ? null : admin_url( 'revision.php?revision=' . $revision_id ), ), 200 ); } /** * Admin capability gate; never __return_true (checklist ยง1.14). * * @param WP_REST_Request $request Request. * @return true|\WP_Error */ public function permissions_check( $request ) { if ( current_user_can( 'manage_options' ) ) { return true; } return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to undo agent actions.', 'agentic-daisy-ai-agent-firewall' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Execute the rollback. * * @param WP_REST_Request $request Request. * @return WP_REST_Response|\WP_Error */ public function undo_item( $request ) { $result = $this->rollback->undo( (int) $request->get_param( 'id' ), new DateTimeImmutable( 'now' ) ); if ( $result instanceof \WP_Error ) { return $result; } return new WP_REST_Response( array( 'status' => 'undone', 'result' => $result, ), 200 ); } }