Commit Graph

363 Commits (fbca487bcdd8732938b3d440d96dc394599838d2)

Author SHA1 Message Date
Daniel Supernault 22108f8f11
Lint PostImportController 1 week ago
Daniel Supernault 7a98ebfe56
Delete NotificationEpochUpdate.php 2 weeks ago
Your Name 341351c47e Remove sha256 verification from MediaMoveStorageLocalToCloud
original_sha256 is the pre-optimization upload hash and can never match the
optimized local file, so comparing against it is not a valid integrity
check for migration. Drop the --verify-sha256 option and the checksum step
entirely; verify now relies on cloud-object existence and size parity.
2 weeks ago
Your Name 438560415a Revert debug-by-default in MediaMoveStorageLocalToCloud
The cloud migration failure (stale original_sha256 verify) is resolved, so
the temporary default-on debug is no longer needed. Restore --debug to a
bare, off-by-default flag and remove the debugEnabled() string-parsing
helper.
2 weeks ago
Your Name 441a94e731 Make original_sha256 verify opt-in in MediaMoveStorageLocalToCloud
original_sha256 is the hash of the file as originally uploaded, but the
async optimize pipeline (ImageResize/ImageUpdate) rewrites the local file
in place and never updates that column. Verifying the current local bytes
against it made every optimized image fail with sha256_mismatch, so the
migration reported moved=0 and exited 1.

Add a --verify-sha256 flag (off by default) that gates the checksum step.
By default verify relies on cloud-object existence and size parity, which
is the only signal that actually describes the uploaded copy. Add tests
covering both the default (migrates) and opt-in (fails) paths.
2 weeks ago
Your Name b2a068b934 polish 2 weeks ago
Your Name 0c68b6a680 Add failure logging to admin:MediaMoveStorageLocalToCloud and enable debug by default
The scheduled command only surfaced 'exit code 1' with no cause. Add
structured Log::error entries at every failure path (cloud disk
unresolvable/unconfigured, cloud storage disabled, invalid --before-id,
candidate fetch failure, per-media failure with full context, and a
run-level summary when failures occur).

Also make --debug default to true (now a valued option) so production
runs emit verbose routing detail while this is investigated; pass
--debug=false to silence.
2 weeks ago
Your Name a424493420 Replace Str::of() fluent chains with static Str::/native calls
Aligns with the app's dominant convention (171 static Str:: calls vs
24 Str::of() chains). Uses Str::afterLast() for the repeated
"segment after last slash" pattern, Str::matchAll() where a
Collection return is needed, and native explode()/substr() where a
plain array/string suffices.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2 weeks ago
Daniel Supernault 6ddc803ae1
Fix SoftwareUpdate notices 2 weeks ago
Your Name 6496904293 Fix account storage limit not freeing on media deletion (#7169)
users.storage_used only ever grew: uploads incremented it but no deletion
path decremented it, so users hit the account size limit even when their
real media usage was well below it.

- Decrement storage_used in MediaDeletePipeline when media is removed
- Add UserStorageService::increaseStorageUsed / decrementStorageUsed as the
  fast, symmetric hot-path counter updates (floor-based, clamped at zero)
- Refactor the 6 upload call sites to use increaseStorageUsed instead of
  duplicated inline writes (also fixes ceil/floor drift vs the reconciler)
- Add (user_id, size) covering index so per-user SUM(size) is not a full
  table scan (INPLACE/LOCK=NONE, skipped on sqlite)
- Add user:storage:recalculate command to repair affected accounts, with a
  daily --stale=168 scheduled reconciler to correct any drift
- Add regression tests for the pipeline and UserStorageService
2 weeks ago
Your Name e360fab619 Deterministically keep earliest status per uri in dedupe command 2 weeks ago
Your Name 327348be02 Send Pixelfed User-Agent on federated account deletion deliveries 2 weeks ago
Your Name a1724a4b1c Scope reclaim-username profile deletion and fail on surviving orphan 2 weeks ago
Daniel Supernault f37c5fc95c
Add notification gc 2 weeks ago
Daniel Supernault 896342a57f
Update MediaMoveStorageLocalToCloud.php 2 weeks ago
Daniel Supernault 764a98437d
Fix media gc 2 weeks ago
Daniel Supernault 85fec3ac82
Create PruneOldNotifications.php 2 weeks ago
Your Name 042ab0a6e4 Convert optional() to nullsafe operator
Applies patch 2/21 from pixelfed-staging PR #9: replaces optional($x)->y
with $x?->y across 16 files. Pint-clean.
3 weeks ago
Your Name 9db2218ca6 chore: move resources/lang to top-level lang/ per Laravel 9+ convention
- Relocate translation files from resources/lang to lang/ via git mv
- Update PHP references to use the lang_path() helper
- Update crowdin.yml source/translation paths
- Update phpstan.neon translationDirectories
3 weeks ago
Your Name b8ca4da3a6 Add per-file transfer output and --debug detail to MediaMoveStorageLocalToCloud 3 weeks ago
Your Name 6b14b229d1 Fix media storage migration crash when no .env file exists
The media storage migration commands read/parsed the .env file directly to
check and flip PF_ENABLE_CLOUD. In containerized deploys there is no .env on
disk (config is injected via env vars), so updateEnvFile() threw
'file_get_contents(.env): Failed to open stream' and the scheduled command
exited 1.

- Check the live setting via config_cache('pixelfed.cloud_storage') like the
  rest of the app, instead of parsing .env.
- Make the .env write best-effort in ManagesMediaStorageEnv: skip gracefully
  when the file is missing or read-only, and still apply the runtime + DB
  config-cache updates (the load-bearing changes on a hot server).
- Apply the same fix to the sibling unstable:MediaMoveStorageCloudToLocal.
- Add a regression test covering the no-.env container scenario.
3 weeks ago
Shlee 8dafe75567
Merge pull request #6992 from pixelfed/feat/status-inspector-commands
Feat/status inspector commands
3 weeks ago
Your Name 9888923a84 Add status:instance, status:avatar, status:emoji inspector commands
Diagnostic commands mirroring status:statuses/status:media:
- status:instance {id|domain|url|@user@domain}: instance row, moderation
  state (banned/unlisted/auto_cw), sync timestamps, local profile count.
- status:avatar {avatar_id|profile_id} [--check]: avatar row, storage state
  (local/cloud existence), owning profile, optional live HEAD on remote_url.
- status:emoji {id|:shortcode:|filename} [--check]: emoji row, origin
  (local/remote), local file existence, optional live HEAD on image_remote_url.

Also includes the status:post -> status:statuses rename.
3 weeks ago
Your Name 237ed61b5d Rename status:post to status:statuses
Rename command signature (status:post -> status:statuses), class
(StatusPost -> StatusStatuses), and file to match.
3 weeks ago
Your Name d62c589881 Rename media:maintenance to media:filtercleanup
Rename the command signature (media:maintenance -> media:filtercleanup), class
(MediaMaintenance -> MediaFilterCleanup), and file to match. Behavior
unchanged.
3 weeks ago
Your Name 4dfb34de75 Drop live from --status on media:maintenance
Orphaned media never references a live status, so --status only accepts soft
and hard. --profile still accepts live/soft/hard. Removes the now-redundant
live short-circuit and makes valid values per-option.
3 weeks ago
Your Name 4ad6e91ef9 Add --status and --profile state filters to media:maintenance
--status live|soft|hard and --profile live|soft|hard narrow orphaned media by
the lifecycle state of the referenced status/profile row. Filters are applied
at the SQL level (whereExists/whereNotExists on deleted_at) so they compose
correctly with --limit. --status=live short-circuits since orphaned media never
has a live status. Options are validated up front.
3 weeks ago
Your Name 838a6b999c Add TODO.md; enhance media:maintenance with --server filter and state annotations
- TODO.md: capture follow-ups (centralized status media teardown, DM leak fix,
  no-DB-cascade rationale, remote-edit orphaning, media:gc re-check).
- media:maintenance: add --server remote|local|both (default both) to filter
  orphaned media by origin.
- Annotate each row with status state (live/soft-deleted/hard-deleted) next to
  status_id and profile state (live/soft-deleted/hard-deleted) next to
  profile_id, in both dry-run table and verbose run output. States are resolved
  in batched, trashed-aware queries.
3 weeks ago
Your Name 48a1fe5e5e Add verbose output to media:maintenance
With -v, print per-row detail (media_id, original status_id, remote_media,
profile_id, mime, size, path) as each orphaned row is processed instead of the
progress bar, and expand the dry-run table with extra columns. Uses Laravel's
built-in verbosity flag.
3 weeks ago
Your Name 87dad44d09 Add media:maintenance command with orphanedMedia scope
media:maintenance --scope orphanedMedia cleans up media whose status_id
references a status that no longer exists (hard-deleted) or is soft-deleted.
These dangling references predate the delete-path fix and MediaDeletePipeline's
attached guard would otherwise refuse to delete them, leaking files.

Detaches (status_id = null) before dispatching deletion via MediaStorageService,
so the guard sees a genuinely orphaned row. Supports --limit (batched),
--dry-run, and --force. The --scope map is extensible for future routines.
3 weeks ago
Your Name 69869536a1 Fix remote status deletion leaking attached media, add status:media command
MediaDeletePipeline skips deletion when media->status_id is set. status_id has
no FK/cascade, so deleting a status never clears it, and the delete jobs
dispatched by the status-delete paths were always skipped, leaking media files.

Detach media (status_id = null) before dispatching the delete in StatusDelete,
RemoteStatusDelete and DeleteRemoteStatusPipeline, so the row is genuinely
orphaned by the time the guard checks it and the deletion proceeds.

Also adds a status:media diagnostic command that dumps all metadata for a
media id (DB columns, computed URLs, attachment state, parent status including
the dangling status_id case, owner, metadata, and an optional live URL check).
3 weeks ago
Your Name 9214e9680a Add admin:resyncemoji command to re-download remote emoji locally
Adds CustomEmojiService::resync() which re-fetches a remote custom emoji's
media from its origin (image_remote_url) via the SSRF-hardened
SecureMediaFetchService and stores it locally under public/{media_path},
reusing the existing headCheck validation and cache busting.

The admin:resyncemoji command takes a comma-separated list of emoji
filenames, looks each up by media_path, and resyncs remote ones. Supports
--missingonly, --dry-run and --force.
3 weeks ago
Your Name fce75030e0 refactor: simplify storage:maintenance flags and make it quiet by default
- Drop --except (--only already covers task selection)
- Quiet by default; per-root/per-item and summary lines now require -v/--verbose
- Errors are always shown regardless of verbosity
- Document the command in the console README
3 weeks ago
Your Name 8ca3ac4dcc polish 3 weeks ago
Your Name 400f00c5e1 feat: storage:maintenance command + in-flow cleanup of emptied dirs
Replace the remcache GC (GarbageCollectorRemcache / gc:remcache) with a
broader storage:maintenance command that sweeps stale remcache temp files and
recursively removes the random empty directories accumulated under the media,
story, avatar and import trees (--hours/--only/--except/--dry-run), scheduled
daily.

Fix the root causes so flows clean up after themselves rather than relying on
the sweep:
- MediaDeletePipeline removes its own emptied m/_v2 leaf dir
- AvatarOptimize logs the previously-swallowed exception, still cleans up the
  old avatar on failure, and removes the old file's now-empty splayed dir
- AvatarController::deleteAvatar removes the emptied splayed dir
- StoryExpire/StoryDelete remove the story's own emptied leaf dir
- TransformImports removes imports/{userId} once its files are moved out
- StoryFetch cleans up its remcache temp file in a finally block
3 weeks ago
Your Name a81270770c refactor: keep MediaMoveStorageLocalToCloud as a stable admin command
MediaMoveStorageLocalToCloud is stable, so move it back out of the Unstable
namespace: restore App\Console\Commands\Admin\MediaMoveStorageLocalToCloud and
its admin:MediaMoveStorageLocalToCloud signature, and update the scheduler,
README, and feature test. CloudToLocal and CloudToCloud remain under unstable:.
3 weeks ago
Your Name 41c9b8830f refactor: rename MigrateLocalS3MediaURL class and move media move-storage commands to unstable
- Rename App\Console\Commands\Admin\MigrateLocalS3MediaURL to MediaUpdateS3CDNUrl
  (class + filename only; the admin:MigrateLocalS3MediaURL signature is unchanged)
- Move the three MediaMoveStorage{LocalToCloud,CloudToLocal,CloudToCloud} commands
  into App\Console\Commands\Admin\Unstable and change their signatures from
  admin: to unstable:
- Update the scheduler in bootstrap/app.php, the command README, the
  config/filesystems.php reference comment, and the affected feature tests
3 weeks ago
Your Name 40b323bca4 revert: remove emoji local-to-cloud storage changes
Back out all emoji cloud-storage work from staging so it can be reworked and
re-landed separately (the URL resolution flips to cloud on a global config
flag, which created a broken-URL window, and the migration approach needs
revisiting).

Reverts to pre-emoji state:
- CustomEmoji model URL/storage helpers (urlForPath, storageTarget, storeMedia,
  storeMediaFromFile, deleteMedia, url) and callers in ImportEmojis,
  CustomEmojiService, AdminController
- admin custom-emoji blade views back to local /storage URLs
- Remove admin:EmojiMoveStorageLocalToCloud command
- Remove the deploy migration and its scheduler entry

Media (and the already-reverted story) scheduler entries are untouched.
4 weeks ago
Shlee 948da00f0c
Update EmojiMoveStorageLocalToCloud.php 4 weeks ago
Shlee ef8cf16cfa
Merge pull request #6968 from pixelfed/debug/emoji-cloud-migration
perf: async S3 SDK upload path for emoji migration
4 weeks ago
Your Name a0a262f07f perf: async S3 SDK upload path for emoji migration
Process-level workers plateaued at ~7.5 uploads/sec against Fastly Object
Storage because each PUT is high-latency and only a handful ran concurrently.

Add --concurrency=N which uses the AWS SDK CommandPool to keep N PutObject
requests in flight from a single process. A successful PutObject response is
the confirmation (no separate HEAD verify), and the local file is deleted on
success. Commands are yielded lazily so memory stays flat over large runs.

--no-acl escape hatch for S3-compatible stores that reject the ACL header.
4 weeks ago
Shlee 2c0fe5db2f
Merge pull request #6967 from pixelfed/debug/emoji-cloud-migration
feat: add uploads/sec throughput counter to emoji migration
4 weeks ago
Your Name f17a88e16c feat: add uploads/sec throughput counter to emoji migration
- Live 'up/s' rate shown on the progress bar during single-worker runs
- Final summary reports elapsed time and uploads/sec
- Parallel runs tally moved across workers and report aggregate uploads/sec

Makes it easy to compare --workers counts and decide whether async S3
(option 2) is worth pursuing.
4 weeks ago
Shlee 67ae799cb4
Merge pull request #6966 from pixelfed/debug/emoji-cloud-migration
perf: parallelise emoji cloud migration with worker processes
4 weeks ago
Your Name 00564ac221 perf: parallelise emoji cloud migration with worker processes
The migration was ~1-2s/file due to sequential S3 round-trips (HEAD + PUT +
verify HEAD). Speed it up:

- --workers=N spawns N child processes, each handling a strided slice of the
  files (index % N == shard) for real concurrency on the I/O-bound uploads
- --skip-cloud-check skips the upfront HEAD (always upload, idempotent)
- --skip-verify skips the post-upload size re-check
- --offset for manual chunking

Storage/Flysystem has no batch or async upload API, so process-level
concurrency is the pragmatic lever here.
4 weeks ago
Shlee b6e8571009
Merge pull request #6965 from pixelfed/debug/emoji-cloud-migration
fix: skip missing.png in emoji cloud migration
4 weeks ago
Your Name 9e5fcb9a90 fix: skip missing.png in emoji cloud migration
The frontend renders a hardcoded /storage/emoji/missing.png local onerror
fallback for emoji, so that placeholder must stay on local disk. Skip it in
the migration so it is never moved to cloud or deleted locally.
4 weeks ago
Shlee e79d5c828b
Merge pull request #6964 from pixelfed/debug/emoji-cloud-migration
fix: make emoji cloud migration disk-driven + add --debug
4 weeks ago
Your Name 79eef56be0 fix: make emoji cloud migration disk-driven + add --debug
The migration was DB-driven (whereNull('uri')), which excluded federated
emoji whose media is stored locally but have a uri set -> the disk was never
scanned, resulting in moved=0.

- Drive the migration by enumerating local files under public/emoji/ instead
  of a DB query; the local file is the source of truth for what needs moving
- Add --debug to print config, custom_emoji table breakdown, local emoji dir
  contents, and per-file decisions
4 weeks ago
Your Name 9f55f7204c revert: story cloud-migration work
Back out the story local->cloud migration so we can land and verify the
emoji cloud work first, one change at a time.

Reverts:
- 9f110bb74 feat: migrate local story media to cloud storage
- 842681b99 fix: schedule StoryMoveStorageLocalToCloud command

Removes StoryMoveStorageLocalToCloud command, its scheduler entry, and the
StoryExpire explicit-disk changes. Remcache and emoji work are untouched.
Will revisit story once emoji is confirmed.
4 weeks ago