PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.12
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.12
1.1.12 1.1.11 1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 All 36 releases
← All changes | includes/desktop-files/stored-files-store.php +107 -154 0.9.8 → 1.1.12 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode — stored-files store (real per-user file storage).
3 + * OpenStation — stored-files store (real per-user file storage).
4 4 *
5 5 * Backs the `upload` file type. One row per uploaded file in
6 6 * `{$wpdb->prefix}desktop_mode_stored_files`; the bytes live flat on
7 7 * disk under `uploads/desktop-mode-files/<owner_id>/<disk_name>`.
@@ -24,11 +24,11 @@
24 24 * "references, not copies" rule: for `upload` placements the
25 25 * placement OWNS the entity. Soft-trash keeps the bytes; when the
26 26 * owner's last placement of a file is permanently removed, the row,
27 27 * the bytes, and every recipient placement are purged (see
28 - * {@see desktop_mode_stored_files_handle_unplaced()}).
28 + * {@see openstation_stored_files_handle_unplaced()}).
29 29 *
30 - * @package WPDesktopMode
30 + * @package OpenStation
31 31 */
32 32
33 33 defined( 'ABSPATH' ) || exit;
34 34
@@ -35,14 +35,19 @@
35 35 /**
36 36 * Absolute path of the storage base dir (no trailing slash), or of
37 37 * a user's subdirectory when `$user_id` is given. Purely a path
38 38 * computation — nothing is created; see
39 - * {@see desktop_mode_stored_files_ensure_dir()}.
39 + * {@see openstation_stored_files_ensure_dir()}.
40 40 *
41 + * The `desktop-mode-files` segment is the pre-rebrand spelling and is
42 + * frozen: users' uploaded bytes already live there. Renaming it points
43 + * the plugin at an empty directory while every stored file stays on
44 + * disk, unreachable. The mismatch with the function name is deliberate.
45 + *
41 46 * @param int $user_id Optional. Owner whose subdirectory to return.
42 47 * @return string
43 48 */
44 -function desktop_mode_stored_files_dir( $user_id = 0 ) {
49 +function openstation_stored_files_dir( $user_id = 0 ) {
45 50 $uploads = wp_get_upload_dir();
46 51 $base = trailingslashit( $uploads['basedir'] ) . 'desktop-mode-files';
47 52 /**
48 53 * Filters the storage base directory. Sites that can write
@@ -49,9 +54,9 @@
49 54 * outside the webroot can point this somewhere safer entirely.
50 55 *
51 56 * @param string $base Absolute path, no trailing slash.
52 57 */
53 - $base = (string) apply_filters( 'desktop_mode_stored_files_base_dir', $base );
58 + $base = (string) apply_filters( 'openstation_stored_files_base_dir', $base );
54 59 if ( (int) $user_id > 0 ) {
55 60 return $base . '/' . (int) $user_id;
56 61 }
57 62 return $base;
@@ -64,17 +69,17 @@
64 69 *
65 70 * @param int $user_id Owner.
66 71 * @return string|WP_Error
67 72 */
68 -function desktop_mode_stored_files_ensure_dir( $user_id ) {
73 +function openstation_stored_files_ensure_dir( $user_id ) {
69 74 $user_id = (int) $user_id;
70 75 if ( $user_id <= 0 ) {
71 - return new WP_Error( 'desktop_mode_stored_files_invalid_user', __( 'A user id is required.', 'desktop-mode' ), array( 'status' => 400 ) );
76 + return new WP_Error( 'openstation_stored_files_invalid_user', __( 'A user id is required.', 'desktop-mode' ), array( 'status' => 400 ) );
72 77 }
73 - $base = desktop_mode_stored_files_dir();
74 - $dir = desktop_mode_stored_files_dir( $user_id );
78 + $base = openstation_stored_files_dir();
79 + $dir = openstation_stored_files_dir( $user_id );
75 80 if ( ! wp_mkdir_p( $dir ) ) {
76 - return new WP_Error( 'desktop_mode_stored_files_mkdir_failed', __( 'Could not create the storage directory.', 'desktop-mode' ), array( 'status' => 500 ) );
81 + return new WP_Error( 'openstation_stored_files_mkdir_failed', __( 'Could not create the storage directory.', 'desktop-mode' ), array( 'status' => 500 ) );
77 82 }
78 83
79 84 // Protection files in the base. `Require all denied` alone 500s
80 85 // on Apache 2.2 and `Deny from all` alone is ignored on pure
@@ -111,9 +116,9 @@
111 116 *
112 117 * @param string $disk_name Candidate.
113 118 * @return bool
114 119 */
115 -function desktop_mode_stored_files_valid_disk_name( $disk_name ) {
120 +function openstation_stored_files_valid_disk_name( $disk_name ) {
116 121 return (bool) preg_match( '/^[a-f0-9-]{16,64}$/', (string) $disk_name );
117 122 }
118 123
119 124 /**
@@ -124,17 +129,17 @@
124 129 *
125 130 * @param array $row Normalized stored-file row.
126 131 * @return string|null
127 132 */
128 -function desktop_mode_stored_file_path( $row ) {
133 +function openstation_stored_file_path( $row ) {
129 134 if ( ! is_array( $row ) || empty( $row['owner_id'] ) || empty( $row['disk_name'] ) ) {
130 135 return null;
131 136 }
132 - if ( ! desktop_mode_stored_files_valid_disk_name( $row['disk_name'] ) ) {
137 + if ( ! openstation_stored_files_valid_disk_name( $row['disk_name'] ) ) {
133 138 return null;
134 139 }
135 - $base = desktop_mode_stored_files_dir();
136 - $path = desktop_mode_stored_files_dir( (int) $row['owner_id'] ) . '/' . $row['disk_name'];
140 + $base = openstation_stored_files_dir();
141 + $path = openstation_stored_files_dir( (int) $row['owner_id'] ) . '/' . $row['disk_name'];
137 142
138 143 // realpath() fails on not-yet-existing leaves; canonicalize the
139 144 // parent instead and re-attach the (regex-validated) leaf.
140 145 $real_parent = realpath( dirname( $path ) );
@@ -157,13 +162,41 @@
157 162 * @param int $owner_id Owner.
158 163 * @param array $args `display_name`, `disk_name`, `size_bytes`, `mime`.
159 164 * @return int|WP_Error Row id.
160 165 */
161 -function desktop_mode_stored_files_create( $owner_id, $args ) {
166 +function openstation_stored_files_create( $owner_id, $args ) {
167 + $id = openstation_stored_files_locked(
168 + static function () use ( $owner_id, $args ) {
169 + return openstation_stored_files_create_locked( $owner_id, $args );
170 + }
171 + );
172 + if ( ! is_wp_error( $id ) ) {
173 + /**
174 + * Fires after a stored-file row is created (bytes are already
175 + * on disk at this point).
176 + *
177 + * @param int $id Stored-file id.
178 + * @param int $owner_id Owner.
179 + */
180 + do_action( 'openstation_stored_file_created', $id, (int) $owner_id );
181 +
182 + }
183 + return $id;
184 +}
185 +
186 +/**
187 + * Insert a stored-file row while holding the reconciliation lock.
188 + *
189 + * @internal
190 + * @param int $owner_id Owner.
191 + * @param array $args Stored-file attributes.
192 + * @return int|WP_Error
193 + */
194 +function openstation_stored_files_create_locked( $owner_id, $args ) {
162 195 global $wpdb;
163 196 $owner_id = (int) $owner_id;
164 197 if ( $owner_id <= 0 ) {
165 - return new WP_Error( 'desktop_mode_stored_files_invalid_user', __( 'A user id is required.', 'desktop-mode' ), array( 'status' => 400 ) );
198 + return new WP_Error( 'openstation_stored_files_invalid_user', __( 'A user id is required.', 'desktop-mode' ), array( 'status' => 400 ) );
166 199 }
167 200 $args = wp_parse_args(
168 201 $args,
169 202 array(
@@ -172,10 +205,10 @@
172 205 'size_bytes' => 0,
173 206 'mime' => '',
174 207 )
175 208 );
176 - if ( ! desktop_mode_stored_files_valid_disk_name( $args['disk_name'] ) ) {
177 - return new WP_Error( 'desktop_mode_stored_files_bad_disk_name', __( 'Invalid storage name.', 'desktop-mode' ), array( 'status' => 400 ) );
209 + if ( ! openstation_stored_files_valid_disk_name( $args['disk_name'] ) ) {
210 + return new WP_Error( 'openstation_stored_files_bad_disk_name', __( 'Invalid storage name.', 'desktop-mode' ), array( 'status' => 400 ) );
178 211 }
179 212 $display = sanitize_file_name( wp_strip_all_tags( (string) $args['display_name'] ) );
180 213 if ( '' === $display ) {
181 214 $display = __( 'file', 'desktop-mode' );
@@ -180,10 +213,10 @@
180 213 if ( '' === $display ) {
181 214 $display = __( 'file', 'desktop-mode' );
182 215 }
183 216
184 - $tables = desktop_mode_files_table_names();
185 - $now = desktop_mode_files_now_ms();
217 + $tables = openstation_files_table_names();
218 + $now = openstation_files_now_ms();
186 219 $ok = $wpdb->insert(
187 220 $tables['stored_files'],
188 221 array(
189 222 'owner_id' => $owner_id,
@@ -196,21 +229,12 @@
196 229 ),
197 230 array( '%d', '%s', '%s', '%d', '%s', '%d', '%d' )
198 231 );
199 232 if ( false === $ok ) {
200 - return new WP_Error( 'desktop_mode_stored_files_insert_failed', __( 'Failed to record the uploaded file.', 'desktop-mode' ), array( 'status' => 500 ) );
233 + return new WP_Error( 'openstation_stored_files_insert_failed', __( 'Failed to record the uploaded file.', 'desktop-mode' ), array( 'status' => 500 ) );
201 234 }
202 235 $id = (int) $wpdb->insert_id;
203 236
204 - /**
205 - * Fires after a stored-file row is created (bytes are already
206 - * on disk at this point).
207 - *
208 - * @param int $id Stored-file id.
209 - * @param int $owner_id Owner.
210 - */
211 - do_action( 'desktop_mode_stored_file_created', $id, $owner_id );
212 -
213 237 return $id;
214 238 }
215 239
216 240 /**
@@ -218,15 +242,15 @@
218 242 *
219 243 * @param int $file_id Row id.
220 244 * @return array|null
221 245 */
222 -function desktop_mode_stored_files_get( $file_id ) {
246 +function openstation_stored_files_get( $file_id ) {
223 247 global $wpdb;
224 248 $file_id = (int) $file_id;
225 249 if ( $file_id <= 0 ) {
226 250 return null;
227 251 }
228 - $tables = desktop_mode_files_table_names();
252 + $tables = openstation_files_table_names();
229 253 $row = $wpdb->get_row(
230 254 $wpdb->prepare( "SELECT * FROM {$tables['stored_files']} WHERE id = %d", $file_id ),
231 255 ARRAY_A
232 256 );
@@ -232,9 +256,9 @@
232 256 );
233 257 if ( ! $row ) {
234 258 return null;
235 259 }
236 - return desktop_mode_stored_files_normalize_row( $row );
260 + return openstation_stored_files_normalize_row( $row );
237 261 }
238 262
239 263 /**
240 264 * Coerce wpdb's stringly-typed row. Internal helper.
@@ -243,9 +267,9 @@
243 267 *
244 268 * @param array $row Raw wpdb row.
245 269 * @return array
246 270 */
247 -function desktop_mode_stored_files_normalize_row( $row ) {
271 +function openstation_stored_files_normalize_row( $row ) {
248 272 return array(
249 273 'id' => (int) $row['id'],
250 274 'owner_id' => (int) $row['owner_id'],
251 275 'display_name' => (string) $row['display_name'],
@@ -265,20 +289,20 @@
265 289 * @param int $file_id Row id.
266 290 * @param string $name New display name.
267 291 * @return true|WP_Error
268 292 */
269 -function desktop_mode_stored_files_rename( $file_id, $name ) {
293 +function openstation_stored_files_rename( $file_id, $name ) {
270 294 global $wpdb;
271 - $row = desktop_mode_stored_files_get( $file_id );
295 + $row = openstation_stored_files_get( $file_id );
272 296 if ( ! $row ) {
273 - return new WP_Error( 'desktop_mode_stored_files_not_found', __( 'Stored file not found.', 'desktop-mode' ), array( 'status' => 404 ) );
297 + return new WP_Error( 'openstation_stored_files_not_found', __( 'Stored file not found.', 'desktop-mode' ), array( 'status' => 404 ) );
274 298 }
275 299 $name = sanitize_file_name( wp_strip_all_tags( (string) $name ) );
276 300 if ( '' === $name ) {
277 - return new WP_Error( 'desktop_mode_stored_files_bad_name', __( 'A file name is required.', 'desktop-mode' ), array( 'status' => 400 ) );
301 + return new WP_Error( 'openstation_stored_files_bad_name', __( 'A file name is required.', 'desktop-mode' ), array( 'status' => 400 ) );
278 302 }
279 - $tables = desktop_mode_files_table_names();
280 - $now = desktop_mode_files_now_ms();
303 + $tables = openstation_files_table_names();
304 + $now = openstation_files_now_ms();
281 305 $wpdb->update(
282 306 $tables['stored_files'],
283 307 array(
284 308 'display_name' => $name,
@@ -309,9 +333,9 @@
309 333 * @param int $file_id Stored-file id.
310 334 * @param string $new_name New display name.
311 335 * @param string $old_name Previous display name.
312 336 */
313 - do_action( 'desktop_mode_stored_file_renamed', (int) $row['id'], $name, (string) $row['display_name'] );
337 + do_action( 'openstation_stored_file_renamed', (int) $row['id'], $name, (string) $row['display_name'] );
314 338
315 339 return true;
316 340 }
317 341
@@ -326,39 +350,39 @@
326 350 * @param int $user_id Acting user.
327 351 * @param array $row Placement row.
328 352 * @return bool
329 353 */
330 -function desktop_mode_stored_files_gate_trash( $can, $user_id, $row ) {
354 +function openstation_stored_files_gate_trash( $can, $user_id, $row ) {
331 355 if ( ! is_array( $row ) || 'upload' !== (string) ( $row['file_type'] ?? '' ) ) {
332 356 return $can;
333 357 }
334 - $stored = desktop_mode_stored_files_get( (int) $row['file_ref'] );
358 + $stored = openstation_stored_files_get( (int) $row['file_ref'] );
335 359 if ( ! $stored ) {
336 360 return $can; // Dangling tile — normal rules, so it stays cleanable.
337 361 }
338 362 return (int) $stored['owner_id'] === (int) $user_id;
339 363 }
340 -add_filter( 'desktop_mode_files_user_can_trash_placement', 'desktop_mode_stored_files_gate_trash', 20, 3 );
364 +add_filter( 'openstation_files_user_can_trash_placement', 'openstation_stored_files_gate_trash', 20, 3 );
341 365
342 366 /**
343 367 * Delete a stored file: bytes first, then the row. Does NOT touch
344 368 * placements — callers that need the full cascade go through
345 - * {@see desktop_mode_stored_files_purge()}.
369 + * {@see openstation_stored_files_purge()}.
346 370 *
347 371 * @param int $file_id Row id.
348 372 * @return true|WP_Error
349 373 */
350 -function desktop_mode_stored_files_delete( $file_id ) {
374 +function openstation_stored_files_delete( $file_id ) {
351 375 global $wpdb;
352 - $row = desktop_mode_stored_files_get( $file_id );
376 + $row = openstation_stored_files_get( $file_id );
353 377 if ( ! $row ) {
354 - return new WP_Error( 'desktop_mode_stored_files_not_found', __( 'Stored file not found.', 'desktop-mode' ), array( 'status' => 404 ) );
378 + return new WP_Error( 'openstation_stored_files_not_found', __( 'Stored file not found.', 'desktop-mode' ), array( 'status' => 404 ) );
355 379 }
356 - $path = desktop_mode_stored_file_path( $row );
380 + $path = openstation_stored_file_path( $row );
357 381 if ( $path && file_exists( $path ) ) {
358 382 wp_delete_file( $path );
359 383 }
360 - $tables = desktop_mode_files_table_names();
384 + $tables = openstation_files_table_names();
361 385 $wpdb->delete( $tables['stored_files'], array( 'id' => (int) $row['id'] ), array( '%d' ) );
362 386
363 387 /**
364 388 * Fires after a stored file (row + bytes) is deleted.
@@ -365,9 +389,9 @@
365 389 *
366 390 * @param int $file_id Stored-file id.
367 391 * @param array $row The row as it was before deletion.
368 392 */
369 - do_action( 'desktop_mode_stored_file_deleted', (int) $row['id'], $row );
393 + do_action( 'openstation_stored_file_deleted', (int) $row['id'], $row );
370 394
371 395 return true;
372 396 }
373 397
@@ -378,16 +402,16 @@
378 402 *
379 403 * @param int $file_id Row id.
380 404 * @return true|WP_Error
381 405 */
382 -function desktop_mode_stored_files_purge( $file_id ) {
406 +function openstation_stored_files_purge( $file_id ) {
383 407 global $wpdb;
384 408 $file_id = (int) $file_id;
385 - $row = desktop_mode_stored_files_get( $file_id );
409 + $row = openstation_stored_files_get( $file_id );
386 410 if ( ! $row ) {
387 - return new WP_Error( 'desktop_mode_stored_files_not_found', __( 'Stored file not found.', 'desktop-mode' ), array( 'status' => 404 ) );
411 + return new WP_Error( 'openstation_stored_files_not_found', __( 'Stored file not found.', 'desktop-mode' ), array( 'status' => 404 ) );
388 412 }
389 - $tables = desktop_mode_files_table_names();
413 + $tables = openstation_files_table_names();
390 414
391 415 // Remaining placements (trashed included — the file is going
392 416 // away for good, a recycle-bin restore must not resurrect a
393 417 // tile pointing at deleted bytes).
@@ -400,9 +424,9 @@
400 424 )
401 425 );
402 426 foreach ( (array) $placement_ids as $pid ) {
403 427 $wpdb->delete( $tables['placements'], array( 'id' => (int) $pid ), array( '%d' ) );
404 - desktop_mode_files_write_tombstone( 'placement', (int) $pid );
428 + openstation_files_write_tombstone( 'placement', (int) $pid );
405 429 }
406 430
407 431 // File shares (target_type='file'). The shares table keys the
408 432 // target id on the historically-named `folder_id` column.
@@ -414,9 +438,9 @@
414 438 ),
415 439 array( '%s', '%d' )
416 440 );
417 441
418 - return desktop_mode_stored_files_delete( $file_id );
442 + return openstation_stored_files_delete( $file_id );
419 443 }
420 444
421 445 /**
422 446 * Sum of stored bytes for one owner.
@@ -423,11 +447,11 @@
423 447 *
424 448 * @param int $owner_id Owner.
425 449 * @return int
426 450 */
427 -function desktop_mode_stored_files_total_bytes( $owner_id ) {
451 +function openstation_stored_files_total_bytes( $owner_id ) {
428 452 global $wpdb;
429 - $tables = desktop_mode_files_table_names();
453 + $tables = openstation_files_table_names();
430 454 return (int) $wpdb->get_var(
431 455 $wpdb->prepare(
432 456 "SELECT COALESCE( SUM( size_bytes ), 0 ) FROM {$tables['stored_files']} WHERE owner_id = %d",
433 457 (int) $owner_id
@@ -442,9 +466,9 @@
442 466 *
443 467 * @param int $user_id User.
444 468 * @return int
445 469 */
446 -function desktop_mode_stored_files_user_quota_bytes( $user_id ) {
470 +function openstation_stored_files_user_quota_bytes( $user_id ) {
447 471 /**
448 472 * Filters the per-user storage quota in bytes. Return 0 for
449 473 * unlimited.
450 474 *
@@ -450,9 +474,9 @@
450 474 *
451 475 * @param int $quota Quota in bytes. Default 0 (unlimited).
452 476 * @param int $user_id User being checked.
453 477 */
454 - return max( 0, (int) apply_filters( 'desktop_mode_stored_files_user_quota_bytes', 0, (int) $user_id ) );
478 + return max( 0, (int) apply_filters( 'openstation_stored_files_user_quota_bytes', 0, (int) $user_id ) );
455 479 }
456 480
457 481 /**
458 482 * Capability required to upload. Defaults to WordPress's own
@@ -460,15 +484,15 @@
460 484 * roles loosen via the filter.
461 485 *
462 486 * @return string
463 487 */
464 -function desktop_mode_stored_files_upload_capability() {
488 +function openstation_stored_files_upload_capability() {
465 489 /**
466 490 * Filters the capability required to upload desktop files.
467 491 *
468 492 * @param string $capability Default 'upload_files'.
469 493 */
470 - return (string) apply_filters( 'desktop_mode_stored_files_upload_capability', 'upload_files' );
494 + return (string) apply_filters( 'openstation_stored_files_upload_capability', 'upload_files' );
471 495 }
472 496
473 497 /**
474 498 * Access resolver: can `$user_id` read (view / download) this
@@ -483,9 +507,9 @@
483 507 * @param int $file_id Stored-file id.
484 508 * @param int $user_id Viewer.
485 509 * @return bool
486 510 */
487 -function desktop_mode_stored_file_user_can_read( $file_id, $user_id ) {
511 +function openstation_stored_file_user_can_read( $file_id, $user_id ) {
488 512 global $wpdb;
489 513 $file_id = (int) $file_id;
490 514 $user_id = (int) $user_id;
491 515 if ( $file_id <= 0 || $user_id <= 0 ) {
@@ -490,9 +514,9 @@
490 514 $user_id = (int) $user_id;
491 515 if ( $file_id <= 0 || $user_id <= 0 ) {
492 516 return false;
493 517 }
494 - $row = desktop_mode_stored_files_get( $file_id );
518 + $row = openstation_stored_files_get( $file_id );
495 519 if ( ! $row ) {
496 520 return false;
497 521 }
498 522 if ( (int) $row['owner_id'] === $user_id ) {
@@ -499,16 +523,16 @@
499 523 return true;
500 524 }
501 525
502 526 // Accepted direct file share.
503 - if ( function_exists( 'desktop_mode_stored_file_share_state' ) ) {
504 - if ( 'accepted' === desktop_mode_stored_file_share_state( $file_id, $user_id ) ) {
527 + if ( function_exists( 'openstation_stored_file_share_state' ) ) {
528 + if ( 'accepted' === openstation_stored_file_share_state( $file_id, $user_id ) ) {
505 529 return true;
506 530 }
507 531 }
508 532
509 533 // Read+ capability on a folder containing a live placement.
510 - $tables = desktop_mode_files_table_names();
534 + $tables = openstation_files_table_names();
511 535 $parents = $wpdb->get_col(
512 536 $wpdb->prepare(
513 537 "SELECT DISTINCT parent_id FROM {$tables['placements']}
514 538 WHERE file_type = %s AND file_ref = %s
@@ -517,11 +541,11 @@
517 541 'upload',
518 542 (string) $file_id
519 543 )
520 544 );
521 - if ( function_exists( 'desktop_mode_folder_share_user_capability' ) ) {
545 + if ( function_exists( 'openstation_folder_share_user_capability' ) ) {
522 546 foreach ( (array) $parents as $parent_id ) {
523 - if ( 'none' !== desktop_mode_folder_share_user_capability( (int) $parent_id, $user_id ) ) {
547 + if ( 'none' !== openstation_folder_share_user_capability( (int) $parent_id, $user_id ) ) {
524 548 return true;
525 549 }
526 550 }
527 551 }
@@ -534,9 +558,9 @@
534 558 * @param int $file_id Stored-file id.
535 559 * @param int $user_id Viewer.
536 560 * @param array $row Stored-file row.
537 561 */
538 - return (bool) apply_filters( 'desktop_mode_stored_file_can_read', false, $file_id, $user_id, $row );
562 + return (bool) apply_filters( 'openstation_stored_file_can_read', false, $file_id, $user_id, $row );
539 563 }
540 564
541 565 /**
542 566 * Placement-removal listener — the deletion contract.
@@ -551,15 +575,15 @@
551 575 *
552 576 * @param int $placement_id Removed placement id.
553 577 * @param array $row The removed row.
554 578 */
555 -function desktop_mode_stored_files_handle_unplaced( $placement_id, $row ) {
579 +function openstation_stored_files_handle_unplaced( $placement_id, $row ) {
556 580 global $wpdb;
557 581 if ( ! is_array( $row ) || 'upload' !== (string) ( $row['file_type'] ?? '' ) ) {
558 582 return;
559 583 }
560 584 $file_id = (int) $row['file_ref'];
561 - $file = desktop_mode_stored_files_get( $file_id );
585 + $file = openstation_stored_files_get( $file_id );
562 586 if ( ! $file ) {
563 587 return;
564 588 }
565 589 if ( (int) $row['owner_id'] !== (int) $file['owner_id'] ) {
@@ -564,9 +588,9 @@
564 588 }
565 589 if ( (int) $row['owner_id'] !== (int) $file['owner_id'] ) {
566 590 return; // A recipient's tile went away; bytes stay.
567 591 }
568 - $tables = desktop_mode_files_table_names();
592 + $tables = openstation_files_table_names();
569 593 $remaining = (int) $wpdb->get_var(
570 594 $wpdb->prepare(
571 595 "SELECT COUNT(*) FROM {$tables['placements']}
572 596 WHERE file_type = %s AND file_ref = %s AND owner_id = %d",
@@ -577,85 +601,14 @@
577 601 );
578 602 if ( $remaining > 0 ) {
579 603 return;
580 604 }
581 - desktop_mode_stored_files_purge( $file_id );
605 + openstation_stored_files_purge( $file_id );
582 606 }
583 -add_action( 'desktop_mode_file_unplaced', 'desktop_mode_stored_files_handle_unplaced', 10, 2 );
607 +add_action( 'openstation_file_unplaced', 'openstation_stored_files_handle_unplaced', 10, 2 );
584 608
585 -/**
586 - * Daily reconciliation sweep, both directions:
587 - *
588 - * a) Rows with no placement at all (crashed uploads, interrupted
589 - * purges) older than the grace period → delete row + bytes.
590 - * b) Bytes on disk with no matching row (interrupted deletes)
591 - * whose mtime is older than the grace period → delete bytes.
592 - *
593 - * Rows whose bytes are missing are left alone — `exists()` still
594 - * renders the tile so the user can see and remove it.
595 - */
596 -function desktop_mode_stored_files_reconcile() {
597 - global $wpdb;
598 - $tables = desktop_mode_files_table_names();
599 - $grace = DAY_IN_SECONDS;
600 609
601 - // a) Placement-less rows past grace.
602 - $cutoff_ms = desktop_mode_files_now_ms() - ( $grace * 1000 );
603 - $orphans = $wpdb->get_col(
604 - $wpdb->prepare(
605 - "SELECT sf.id FROM {$tables['stored_files']} sf
606 - LEFT JOIN {$tables['placements']} p
607 - ON p.file_type = 'upload'
608 - AND p.file_ref = CAST( sf.id AS CHAR )
609 - WHERE p.id IS NULL
610 - AND sf.created_at_ms < %d",
611 - $cutoff_ms
612 - )
613 - );
614 - foreach ( (array) $orphans as $orphan_id ) {
615 - desktop_mode_stored_files_delete( (int) $orphan_id );
616 - }
617 610
618 - // b) Row-less bytes past grace. The flat layout makes this a
619 - // two-level scan: <base>/<user_id>/<disk_name>.
620 - $base = desktop_mode_stored_files_dir();
621 - if ( ! is_dir( $base ) ) {
622 - return;
623 - }
624 - $user_dirs = glob( $base . '/*', GLOB_ONLYDIR );
625 - foreach ( (array) $user_dirs as $user_dir ) {
626 - $owner_id = (int) basename( $user_dir );
627 - if ( $owner_id <= 0 ) {
628 - continue;
629 - }
630 - $known = $wpdb->get_col(
631 - $wpdb->prepare(
632 - "SELECT disk_name FROM {$tables['stored_files']} WHERE owner_id = %d",
633 - $owner_id
634 - )
635 - );
636 - $known_set = array_flip( array_map( 'strval', (array) $known ) );
637 - $entries = glob( $user_dir . '/*' );
638 - foreach ( (array) $entries as $entry ) {
639 - $name = basename( $entry );
640 - if ( 'index.php' === $name || ! is_file( $entry ) ) {
641 - continue;
642 - }
643 - if ( isset( $known_set[ $name ] ) ) {
644 - continue;
645 - }
646 - if ( ! desktop_mode_stored_files_valid_disk_name( $name ) ) {
647 - continue; // Not ours — leave foreign files alone.
648 - }
649 - $mtime = (int) filemtime( $entry );
650 - if ( $mtime > 0 && ( time() - $mtime ) > $grace ) {
651 - wp_delete_file( $entry );
652 - }
653 - }
654 - }
655 -}
656 -add_action( 'desktop_mode_files_daily_prune', 'desktop_mode_stored_files_reconcile' );
657 -
658 611 /**
659 612 * When a WordPress user is deleted, purge their stored files (rows,
660 613 * bytes, shares, recipient placements) and remove their directory.
661 614 *
@@ -660,22 +613,22 @@
660 613 * bytes, shares, recipient placements) and remove their directory.
661 614 *
662 615 * @param int $user_id Deleted user id.
663 616 */
664 -function desktop_mode_stored_files_handle_deleted_user( $user_id ) {
617 +function openstation_stored_files_handle_deleted_user( $user_id ) {
665 618 global $wpdb;
666 619 $user_id = (int) $user_id;
667 620 if ( $user_id <= 0 ) {
668 621 return;
669 622 }
670 - $tables = desktop_mode_files_table_names();
623 + $tables = openstation_files_table_names();
671 624 $ids = $wpdb->get_col(
672 625 $wpdb->prepare( "SELECT id FROM {$tables['stored_files']} WHERE owner_id = %d", $user_id )
673 626 );
674 627 foreach ( (array) $ids as $file_id ) {
675 - desktop_mode_stored_files_purge( (int) $file_id );
628 + openstation_stored_files_purge( (int) $file_id );
676 629 }
677 - $dir = desktop_mode_stored_files_dir( $user_id );
630 + $dir = openstation_stored_files_dir( $user_id );
678 631 if ( is_dir( $dir ) ) {
679 632 $index = $dir . '/index.php';
680 633 if ( file_exists( $index ) ) {
681 634 wp_delete_file( $index );
@@ -683,5 +636,5 @@
683 636 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir
684 637 @rmdir( $dir ); // Only succeeds when empty — leftovers are the sweep's job.
685 638 }
686 639 }
687 -add_action( 'deleted_user', 'desktop_mode_stored_files_handle_deleted_user' );
640 +add_action( 'deleted_user', 'openstation_stored_files_handle_deleted_user' );