[0-9a-f-]{36})'; private BackupService $backups; private BackupRepository $repo; private JobService $jobs; public function __construct(BackupService $backups, BackupRepository $repo, JobService $jobs) { $this->backups = $backups; $this->repo = $repo; $this->jobs = $jobs; } public function register(): void { $this->route('/backups', 'GET', fn () => array_map([BackupRepository::class, 'to_api'], $this->repo->ready())); $this->route('/backups', 'POST', fn (\WP_REST_Request $r) => $this->created_job( $this->jobs->create('backup', array_filter([ 'label' => (string) $r->get_param('label'), 'subsite' => (int) $r->get_param('subsite'), 'contents' => $r->get_param('contents'), 'skip_root' => $r->get_param('skip_root'), 'compress' => $r->get_param('compress'), ], static fn ($v) => $v !== null)) )); // The site's root folder, for choosing what of it a backup takes (never on a network). $this->route('/backups/root-items', 'GET', static function () { if (is_multisite()) { return ['items' => [], 'skip' => []]; } $items = RootFiles::items(Groups::roots()); return ['items' => $items, 'skip' => RootFiles::default_skip($items)]; }); $this->route('/backups/' . self::ID, 'DELETE', function (\WP_REST_Request $r) { $this->backups->delete($r['id']); return ['deleted' => true]; }); $this->route('/backups/' . self::ID . '/download', 'GET', function (\WP_REST_Request $r) { $info = $this->backups->download_info($r['id']); Stream::send($info['path'], $info['filename'], (string) $r->get_header('range')); return null; }); $this->route('/backups/' . self::ID . '/restore', 'POST', fn (\WP_REST_Request $r) => $this->created_job( $this->jobs->create('backup_restore', ['backup_id' => $r['id'], 'subsite' => (int) $r->get_param('subsite'), 'new_subsite' => $r->get_param('new_subsite')] + ($r->get_param('server_settings') !== null ? ['server_settings' => $r->get_param('server_settings')] : [])) )); $this->route('/backups/uploads', 'POST', fn (\WP_REST_Request $r) => $this->backups->upload_start( (string) $r->get_param('filename'), (int) $r->get_param('size') )); $this->route('/backups/uploads/' . self::ID, 'POST', fn (\WP_REST_Request $r) => [ 'received' => $this->backups->upload_append($r['id'], (int) $r->get_header('x_relay_offset'), (string) $r->get_body()), ]); $this->route('/backups/uploads/' . self::ID . '/complete', 'POST', fn (\WP_REST_Request $r) => new \WP_REST_Response( BackupRepository::to_api($this->backups->upload_complete($r['id'])), 201 )); $this->route('/backups/uploads/' . self::ID, 'DELETE', function (\WP_REST_Request $r) { $this->backups->upload_abort($r['id']); return ['deleted' => true]; }); } private function created_job(Job $job): \WP_REST_Response { return new \WP_REST_Response($job->to_array(), 201); } }