store = $store ?? new AcknowledgementStore(); $this->analysis = $analysis ?? new AnalysisStore(); } public function registerRoutes(): void { register_rest_route( 'intellilanz/v1', '/acknowledge', array( array( 'methods' => 'POST', 'callback' => array( $this, 'acknowledge' ), 'permission_callback' => array( $this, 'permissionsCheck' ) ), array( 'methods' => 'DELETE', 'callback' => array( $this, 'clear' ), 'permission_callback' => array( $this, 'permissionsCheck' ) ), ) ); } public function permissionsCheck(): bool { return current_user_can( 'manage_options' ); } public function acknowledge( $request ) { if ( ! $this->permissionsCheck() ) { return $this->error( 'intellilanz_forbidden', __( 'You cannot acknowledge this finding.', 'intellilanz' ), rest_authorization_required_code() ); } $key = $this->key( $request ); $severity = $this->severity( $key ); if ( $key === '' || $severity === null ) { return $this->error( 'intellilanz_invalid_finding', __( 'The requested finding is invalid.', 'intellilanz' ), 400 ); } $days = $request->get_param( 'snooze_days' ); $days = $days === null || $days === '' ? null : (int) $days; if ( $days !== null && ( $days < 1 || $days > 3650 ) ) { return $this->error( 'intellilanz_invalid_snooze', __( 'The snooze duration is invalid.', 'intellilanz' ), 400 ); } return $this->response( array( 'finding_key' => $key, 'acknowledgement' => $this->store->acknowledge( $key, $severity, $days, get_current_user_id() ) ) ); } public function clear( $request ) { if ( ! $this->permissionsCheck() ) { return $this->error( 'intellilanz_forbidden', __( 'You cannot clear this acknowledgement.', 'intellilanz' ), rest_authorization_required_code() ); } $key = $this->key( $request ); if ( $key === '' ) { return $this->error( 'intellilanz_invalid_finding', __( 'The requested finding is invalid.', 'intellilanz' ), 400 ); } $this->store->clear( $key ); return $this->response( array( 'finding_key' => $key, 'acknowledged' => false ) ); } private function key( $request ): string { $key = is_object( $request ) && is_callable( array( $request, 'get_param' ) ) ? sanitize_text_field( (string) $request->get_param( 'finding_key' ) ) : ''; return preg_match( '/^[a-z0-9_.:-]{3,240}$/i', $key ) ? $key : ''; } private function severity( string $key ): ?int { $analysis = $this->analysis->get(); if ( $analysis === null ) { return null; } foreach ( $analysis['site_health'] as $result ) { if ( ( $result['finding_key'] ?? '' ) === $key ) { return array( 'good' => 0, 'recommended' => 2, 'critical' => 3 )[ $result['effective_status'] ?? $result['native_status'] ?? '' ] ?? 1; } } foreach ( $analysis['graph']['nodes'] as $node ) { $metadata = (array) ( $node['metadata'] ?? array() ); $health = (array) ( $metadata['health'] ?? array() ); foreach ( (array) ( $health['findings'] ?? array() ) as $finding ) { if ( ( $finding['finding_key'] ?? '' ) === $key ) { return (int) ( $finding['severity'] ?? $node['severity'] ?? 0 ); } } } return null; } private function response( array $data ): \WP_REST_Response { $response = new \WP_REST_Response( $data, 200 ); $response->header( 'Cache-Control', 'no-store, private' ); return $response; } private function error( string $code, string $message, int $status ): \WP_Error { return new \WP_Error( $code, $message, array( 'status' => $status ) ); } }