PluginProbe ʕ •ᴥ•ʔ
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback / trunk
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback vtrunk
5.1.3 5.1.2 5.1.1 5.1 5.0 trunk 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.2.0 3.2.1 3.22 3.22.1 3.22.2 3.22.3 3.22.4 3.22.5 3.22.6 3.3.0 3.3.1 3.3.2 3.3.2.1 3.3.2.2 3.3.3 3.30 3.31 3.32 3.4 3.4.1 3.4.3 3.4.4 3.5 3.5.1 3.6 3.6.1 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.9.6 3.9.6.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.4
atarim-visual-collaboration / third-party / backup / jetbackup / class-avcf-abilities-jetbackup-queue.php
atarim-visual-collaboration / third-party / backup / jetbackup Last commit date
class-avcf-abilities-jetbackup-backups.php 3 days ago class-avcf-abilities-jetbackup-destinations.php 2 weeks ago class-avcf-abilities-jetbackup-jobs.php 2 weeks ago class-avcf-abilities-jetbackup-queue.php 3 days ago class-avcf-abilities-jetbackup-restore-point.php 3 days ago class-avcf-abilities-jetbackup-restore.php 3 days ago class-avcf-abilities-jetbackup-schedules.php 2 weeks ago class-avcf-abilities-jetbackup-settings.php 2 weeks ago class-avcf-abilities-jetbackup-system.php 2 weeks ago class-avcf-jetbackup-detector.php 2 weeks ago class-avcf-jetbackup-helpers.php 3 days ago
class-avcf-abilities-jetbackup-queue.php
325 lines
1 <?php
2 /**
3 * JetBackup — Queue, Downloads & Alerts ability cluster.
4 *
5 * Namespaced atarim/jetbackup-* over JetBackup's queue/download/alert AJAX Calls:
6 * list queue items, abort / start-over / clear-completed queue items,
7 * run the queue, list / delete downloads, list / clear alerts.
8 *
9 * (get-queue-item lives in the restore cluster since that's its primary use.)
10 *
11 * Gated by manage_options; delete-download requires confirm:true. Built on
12 * JetBackup 3.1.23.x; not runtime-tested here.
13 *
14 * @package atarim-visual-collaboration
15 */
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 class AVCF_Abilities_JetBackup_Queue extends AVCF_Abilities_Base {
22
23 /** @var AVCF_JetBackup_Detector */
24 private $detector;
25
26 public function __construct() {
27 $this->detector = new AVCF_JetBackup_Detector();
28 }
29
30 public function register() {
31 if ( ! $this->detector->avcf_jetbackup_is_available() ) {
32 return;
33 }
34 $this->register_list_queue_items();
35 $this->register_abort_queue_item();
36 $this->register_start_over_queue_item();
37 $this->register_clear_completed_queue_items();
38 $this->register_run_queue();
39 $this->register_list_downloads();
40 $this->register_delete_download();
41 $this->register_list_alerts();
42 $this->register_clear_alerts();
43 }
44
45 /* ------------------------------ shared ----------------------------- */
46
47 private function ro_meta() {
48 return [ 'mcp' => [ 'public' => true, 'type' => 'tool' ], 'annotations' => [ 'readonly' => true, 'destructive' => false, 'idempotent' => true ] ];
49 }
50 private function write_meta( $d = false ) {
51 return [ 'mcp' => [ 'public' => true, 'type' => 'tool' ], 'annotations' => [ 'readonly' => false, 'destructive' => (bool) $d, 'idempotent' => false ] ];
52 }
53 public function can() {
54 return AVCF_JetBackup_Helpers::can_manage();
55 }
56 private function out_schema() {
57 return [
58 'type' => 'object',
59 'properties' => [
60 'success' => [ 'type' => 'boolean' ],
61 'message' => [ 'type' => 'string' ],
62 'data' => [ 'type' => 'object' ],
63 ],
64 'required' => [ 'success', 'message' ],
65 ];
66 }
67 private function pagination_schema() {
68 return [
69 'type' => 'object',
70 'properties' => [
71 'skip' => [ 'type' => 'integer', 'minimum' => 0, 'default' => 0 ],
72 'limit' => [ 'type' => 'integer', 'minimum' => 1, 'maximum' => 100, 'default' => 50 ],
73 ],
74 'additionalProperties' => false,
75 ];
76 }
77 private function id_schema( $desc ) {
78 return [
79 'type' => 'object',
80 'properties' => [ 'id' => [ 'type' => 'integer', 'minimum' => 1, 'description' => $desc ] ],
81 'required' => [ 'id' ],
82 'additionalProperties' => false,
83 ];
84 }
85 private function no_input_schema() {
86 return [ 'type' => 'object', 'properties' => new \stdClass(), 'additionalProperties' => false ];
87 }
88 private function missing_id( $what ) {
89 return [ 'success' => false, 'message' => sprintf( 'Missing id (%s).', $what ), 'data' => [] ];
90 }
91
92 /* -------------------------- list-queue-items ------------------------ */
93
94 private function register_list_queue_items() {
95 $self = $this;
96 wp_register_ability( 'atarim/jetbackup-list-queue-items', [
97 'label' => 'List JetBackup Queue Items',
98 'category' => 'atarim',
99 'description' => 'List JetBackup queue items — running and recent backup/restore/download/etc. tasks (paginated). Optional skip, limit (1-100, default 50).',
100 'input_schema' => $this->pagination_schema(),
101 'output_schema' => $this->out_schema(),
102 'execute_callback' => function( $input = [] ) {
103 return AVCF_JetBackup_Helpers::invoke( 'ListQueueItems', AVCF_JetBackup_Helpers::paginate( (array) $input ) );
104 },
105 'permission_callback' => function() use ( $self ) { return $self->can(); },
106 'meta' => $this->ro_meta(),
107 ] );
108 }
109
110 /* -------------------------- abort-queue-item ------------------------ */
111
112 private function register_abort_queue_item() {
113 $self = $this;
114 wp_register_ability( 'atarim/jetbackup-abort-queue-item', [
115 'label' => 'Abort JetBackup Queue Item',
116 'category' => 'atarim',
117 'description' => 'Abort (cancel) a running or pending queue item by id.',
118 'input_schema' => $this->id_schema( 'Queue item id to abort.' ),
119 'output_schema' => $this->out_schema(),
120 'execute_callback' => function( $input = [] ) {
121 $input = (array) $input;
122 if ( empty( $input['id'] ) ) { return $this->missing_id( 'queue item id to abort' ); }
123 return AVCF_JetBackup_Helpers::invoke( 'AbortQueueItem', AVCF_JetBackup_Helpers::id_payload( $input ) );
124 },
125 'permission_callback' => function() use ( $self ) { return $self->can(); },
126 'meta' => $this->write_meta( false ),
127 ] );
128 }
129
130 /* ------------------------ start-over-queue-item --------------------- */
131
132 private function register_start_over_queue_item() {
133 $self = $this;
134 wp_register_ability( 'atarim/jetbackup-start-over-queue-item', [
135 'label' => 'Restart JetBackup Queue Item',
136 'category' => 'atarim',
137 'description' => 'Restart a queue item from the beginning by id (e.g. retry a failed task).',
138 'input_schema' => $this->id_schema( 'Queue item id to restart.' ),
139 'output_schema' => $this->out_schema(),
140 'execute_callback' => function( $input = [] ) {
141 $input = (array) $input;
142 if ( empty( $input['id'] ) ) { return $this->missing_id( 'queue item id to restart' ); }
143 return AVCF_JetBackup_Helpers::invoke( 'StartOverQueueItem', AVCF_JetBackup_Helpers::id_payload( $input ) );
144 },
145 'permission_callback' => function() use ( $self ) { return $self->can(); },
146 'meta' => $this->write_meta( false ),
147 ] );
148 }
149
150 /* -------------------- clear-completed-queue-items ------------------- */
151
152 private function register_clear_completed_queue_items() {
153 $self = $this;
154 wp_register_ability( 'atarim/jetbackup-clear-completed-queue-items', [
155 'label' => 'Clear Completed JetBackup Queue Items',
156 'category' => 'atarim',
157 'description' => 'Clear all completed items from the JetBackup queue.',
158 'input_schema' => $this->no_input_schema(),
159 'output_schema' => $this->out_schema(),
160 'execute_callback' => function( $input = [] ) {
161 return AVCF_JetBackup_Helpers::invoke( 'ClearCompletedQueueItems', [] );
162 },
163 'permission_callback' => function() use ( $self ) { return $self->can(); },
164 'meta' => $this->write_meta( false ),
165 ] );
166 }
167
168 /* ------------------------------ run-queue --------------------------- */
169
170 /**
171 * JetBackup queues a backup and relies on a host cron to start it, so on a
172 * site with no cron the queue never moves and nothing gated on a restore
173 * point can proceed. Its own ExecuteCron AJAX call refuses outside WP-CLI
174 * (`if(!$this->isCLI() || !Helper::isWPCli()) throw ...`), so the cron entry
175 * point is called directly instead.
176 *
177 * Verified against JetBackup 3.1.x from a web request: Cron::main() is
178 * public static, takes no arguments, registers its own fatal-error shutdown
179 * handler so a queue item killed by max_execution_time is retried rather
180 * than corrupted, and returns normally. Two preconditions come with it.
181 * Cron::canRun() refuses unless JetBackup's Automation "crons" setting is
182 * enabled (it defaults to enabled), which is checked up front so the caller
183 * gets an actionable message. And the constructor takes an flock, so a
184 * second call while a tick is still running throws CronException code 501 —
185 * that means the work is in progress, not that it failed, so it is reported
186 * alongside the queue state instead of as an error.
187 */
188 private function register_run_queue() {
189 $self = $this;
190 wp_register_ability( 'atarim/jetbackup-run-queue', [
191 'label' => 'Run JetBackup Queue',
192 'category' => 'atarim',
193 'description' => 'Advance the JetBackup queue by one tick, for sites with no host cron driving it. Runs synchronously and does the archiving, so the request may time out while a backup is written — that is not a failure, and neither is a reply saying a tick is already running. Poll jetbackup-list-queue-items, or call this again, until the item completes. Returns the queue state after the tick.',
194 'input_schema' => $this->no_input_schema(),
195 'output_schema' => $this->out_schema(),
196 'execute_callback' => function( $input = [] ) use ( $self ) {
197 return $self->run_queue_tick();
198 },
199 'permission_callback' => function() use ( $self ) { return $self->can(); },
200 'meta' => $this->write_meta( false ),
201 ] );
202 }
203
204 public function run_queue_tick() {
205 if ( ! class_exists( '\\JetBackup\\Cron\\Cron' ) || ! method_exists( '\\JetBackup\\Cron\\Cron', 'main' ) ) {
206 return [
207 'success' => false,
208 'message' => 'JetBackup cron entry point unavailable on this JetBackup version.',
209 'data' => [],
210 ];
211 }
212
213 $message = 'Queue tick completed.';
214
215 try {
216 if ( ! \JetBackup\Factory::getSettingsAutomation()->isCronsEnabled() ) {
217 return [
218 'success' => false,
219 'message' => 'JetBackup crons are disabled in its Automation settings, so the queue cannot be advanced from a web request. Enable crons in JetBackup and retry.',
220 'data' => [],
221 ];
222 }
223
224 \JetBackup\Cron\Cron::main();
225 } catch ( \Throwable $e ) {
226 if ( 501 !== (int) $e->getCode() ) {
227 return [
228 'success' => false,
229 'message' => $e->getMessage() ? $e->getMessage() : 'JetBackup queue tick failed.',
230 'data' => [],
231 ];
232 }
233 $message = 'A queue tick is already running; its progress is below.';
234 }
235
236 $queue = AVCF_JetBackup_Helpers::invoke( 'ListQueueItems', AVCF_JetBackup_Helpers::paginate( [] ) );
237 $queue['message'] = trim( $message . ' ' . (string) ( isset( $queue['message'] ) ? $queue['message'] : '' ) );
238
239 return $queue;
240 }
241
242 /* --------------------------- list-downloads ------------------------- */
243
244 private function register_list_downloads() {
245 $self = $this;
246 wp_register_ability( 'atarim/jetbackup-list-downloads', [
247 'label' => 'List JetBackup Downloads',
248 'category' => 'atarim',
249 'description' => 'List prepared backup downloads (from jetbackup-download-backup), paginated. Optional skip, limit (1-100, default 50).',
250 'input_schema' => $this->pagination_schema(),
251 'output_schema' => $this->out_schema(),
252 'execute_callback' => function( $input = [] ) {
253 return AVCF_JetBackup_Helpers::invoke( 'ListDownloads', AVCF_JetBackup_Helpers::paginate( (array) $input ) );
254 },
255 'permission_callback' => function() use ( $self ) { return $self->can(); },
256 'meta' => $this->ro_meta(),
257 ] );
258 }
259
260 /* --------------------------- delete-download ------------------------ */
261
262 private function register_delete_download() {
263 $self = $this;
264 wp_register_ability( 'atarim/jetbackup-delete-download', [
265 'label' => 'Delete JetBackup Download',
266 'category' => 'atarim',
267 'description' => 'Delete a prepared download by id. Destructive: requires confirm:true.',
268 'input_schema' => [
269 'type' => 'object',
270 'properties' => [
271 'id' => [ 'type' => 'integer', 'minimum' => 1, 'description' => 'Download id to delete.' ],
272 'confirm' => [ 'type' => 'boolean', 'description' => 'Must be true to proceed.' ],
273 ],
274 'required' => [ 'id' ],
275 'additionalProperties' => false,
276 ],
277 'output_schema' => $this->out_schema(),
278 'execute_callback' => function( $input = [] ) {
279 $input = (array) $input;
280 if ( empty( $input['id'] ) ) { return $this->missing_id( 'download id to delete' ); }
281 if ( ! AVCF_JetBackup_Helpers::confirmed( $input ) ) { return AVCF_JetBackup_Helpers::confirm_required_response( 'delete download' ); }
282 return AVCF_JetBackup_Helpers::invoke( 'DeleteDownload', AVCF_JetBackup_Helpers::id_payload( $input ) );
283 },
284 'permission_callback' => function() use ( $self ) { return $self->can(); },
285 'meta' => $this->write_meta( true ),
286 ] );
287 }
288
289 /* ---------------------------- list-alerts --------------------------- */
290
291 private function register_list_alerts() {
292 $self = $this;
293 wp_register_ability( 'atarim/jetbackup-list-alerts', [
294 'label' => 'List JetBackup Alerts',
295 'category' => 'atarim',
296 'description' => 'List JetBackup alerts/notifications (paginated). Optional skip, limit (1-100, default 50).',
297 'input_schema' => $this->pagination_schema(),
298 'output_schema' => $this->out_schema(),
299 'execute_callback' => function( $input = [] ) {
300 return AVCF_JetBackup_Helpers::invoke( 'ListAlerts', AVCF_JetBackup_Helpers::paginate( (array) $input ) );
301 },
302 'permission_callback' => function() use ( $self ) { return $self->can(); },
303 'meta' => $this->ro_meta(),
304 ] );
305 }
306
307 /* ---------------------------- clear-alerts -------------------------- */
308
309 private function register_clear_alerts() {
310 $self = $this;
311 wp_register_ability( 'atarim/jetbackup-clear-alerts', [
312 'label' => 'Clear JetBackup Alerts',
313 'category' => 'atarim',
314 'description' => 'Clear all JetBackup alerts.',
315 'input_schema' => $this->no_input_schema(),
316 'output_schema' => $this->out_schema(),
317 'execute_callback' => function( $input = [] ) {
318 return AVCF_JetBackup_Helpers::invoke( 'ClearAlerts', [] );
319 },
320 'permission_callback' => function() use ( $self ) { return $self->can(); },
321 'meta' => $this->write_meta( false ),
322 ] );
323 }
324 }
325