\WP_REST_Server::READABLE, 'callback' => array( __CLASS__, 'get_state' ), 'permission_callback' => $admin, ) ); register_rest_route( self::NS, '/scan', array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( __CLASS__, 'start' ), 'permission_callback' => $admin, 'args' => array( 'target' => array( 'type' => 'string', 'enum' => Scan::TARGETS, 'required' => true, ), 'components' => array( 'type' => 'array', 'items' => array( 'type' => 'string' ), 'required' => true, ), 'check_updates' => array( 'type' => 'boolean', 'default' => true, ), ), ) ); register_rest_route( self::NS, '/scan/step', array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( __CLASS__, 'step' ), 'permission_callback' => $admin, ) ); register_rest_route( self::NS, '/scan/(?Ppause|resume|cancel)', array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( __CLASS__, 'control' ), 'permission_callback' => $admin, ) ); register_rest_route( self::NS, '/findings', array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( __CLASS__, 'get_findings' ), 'permission_callback' => $admin, 'args' => array( 'key' => array( 'type' => 'string', 'required' => true, ), ), ) ); } public static function can_manage() { return current_user_can( Plugin::capability() ); } /** Everything the admin screen renders: PHP versions, installed components, the job and its verdicts. */ public static function state() { $job = Scan::job(); $components = array(); foreach ( Components::all() as $c ) { $update = Updates::available( $c ); $components[] = array( 'key' => $c['key'], 'type' => $c['type'], 'name' => $c['name'], 'version' => $c['version'], 'active' => $c['active'], 'update' => $update ? $update['version'] : '', ); } $out = array( 'php' => array( 'runtime' => PHP_VERSION, 'baseline' => Scan::baseline(), 'targets' => Scan::TARGETS, 'default' => Scan::default_target(), ), 'engine' => Engine::unavailable_reason(), 'components' => $components, 'job' => null, ); if ( $job ) { $rows = Report::rows( $job ); $out['job'] = array( 'id' => $job['id'], 'target' => $job['target'], 'baseline' => $job['baseline'], 'status' => $job['status'], 'check_updates' => $job['check_updates'], 'started_at' => $job['started_at'], 'finished_at' => $job['finished_at'], 'last_step_at' => $job['last_step_at'], 'progress' => self::progress( $job ), 'summary' => Report::summary( $rows ), 'rows' => $rows, ); } return $out; } /** Files of installed code only: an update check adds its files late and would push the bar backwards. */ private static function progress( array $job ) { $total = 0; $done = 0; $current = ''; foreach ( $job['components'] as $i => $c ) { if ( 'update' !== $c['type'] ) { $total += $c['files']; $done += $c['done']; } if ( $i === $job['index'] ) { /* translators: 1: plugin or theme name, 2: version of its update. */ $current = 'update' === $c['type'] ? sprintf( __( '%1$s, update %2$s', 'leaplens' ), $c['name'], $c['version'] ) : $c['name']; } } return array( 'files' => $total, 'done' => min( $done, $total ), 'current' => $current, 'components' => count( $job['components'] ), 'index' => min( $job['index'], count( $job['components'] ) ), ); } public static function get_state() { return rest_ensure_response( self::state() ); } public static function start( \WP_REST_Request $request ) { $job = Scan::start( (array) $request['components'], (string) $request['target'], (bool) $request['check_updates'] ); return is_wp_error( $job ) ? $job : rest_ensure_response( self::state() ); } public static function step() { Scan::step( Scan::budget( self::STEP_BUDGET ) ); return rest_ensure_response( array_merge( self::state(), array( 'busy' => Scan::$busy ) ) ); } public static function control( \WP_REST_Request $request ) { $map = array( 'pause' => 'paused', 'resume' => 'running', 'cancel' => 'cancelled', ); Scan::set_status( $map[ $request['action'] ] ); return rest_ensure_response( self::state() ); } public static function get_findings( \WP_REST_Request $request ) { $job = Scan::job(); if ( ! $job ) { return new \WP_Error( 'leaplens_no_scan', __( 'No scan yet.', 'leaplens' ), array( 'status' => 404 ) ); } $key = (string) $request['key']; foreach ( $job['components'] as $c ) { if ( $c['key'] === $key ) { $found = Scan::findings( $job['id'], $key ); return rest_ensure_response( array( 'key' => $key, 'target' => $job['target'], 'baseline' => $job['baseline'], 'files' => $found['files'], 'truncated' => $found['truncated'], 'skipped' => $c['skipped'], 'failed' => $c['failed'], ) ); } } return new \WP_Error( 'leaplens_unknown', __( 'This component is not part of the last scan.', 'leaplens' ), array( 'status' => 404 ) ); } }