Deleting a post, editing media out, replacing an avatar or a header, and removing a whole root deleted no file: every one stayed on disk and publicly served from /media/files with a year-long immutable cache, its row orphaned. Now every upload is a row, profile pictures too (Kind avatar or header, ProfileOfAvatarId), and each of those acts trashes what it held, as does an upload never posted for a day and a dropped scheduled post. A trashed row is marked in one conditional update (an upload attached meanwhile is left alone), its files move into media-trash, beside the media root and outside what /media/files serves, and the janitor deletes them a day later. Nothing is deleted for looking unused. Along the way: a profile picture that isn't an image, or can't be read, answers 422 instead of being silently ignored with a 200; a removed root's scheduled posts are dropped, so nothing of it publishes later; media rows get indexes (they had none), and the janitor's first pass comes five minutes after boot instead of an hour. `PrivaPub admin media audit [--fix]` compares the disk with the database. With --fix (as www-data) it gives the pictures personas show today a row, and trashes media of deleted posts or personas, rows whose files are missing, and files nothing holds: the leftovers of every deletion until now. MediaLifecycleTests covers each act, that the trash is never served, and the audit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
34 lines
1.2 KiB
C#
34 lines
1.2 KiB
C#
using MongoDB.Entities;
|
|
|
|
namespace PrivaPub.Models.Media
|
|
{
|
|
public class MediaAttachment : Entity
|
|
{
|
|
public string OwnerAvatarId { get; set; }
|
|
public string PostId { get; set; }
|
|
public string Kind { get; set; }
|
|
public string ContentType { get; set; }
|
|
public string FilePath { get; set; }
|
|
public string PreviewPath { get; set; }
|
|
public long Size { get; set; }
|
|
public string Description { get; set; }
|
|
public string Blurhash { get; set; }
|
|
public int? Width { get; set; }
|
|
public int? Height { get; set; }
|
|
public float[] Focus { get; set; }
|
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
public DateTime? AttachedAt { get; set; }
|
|
public string ScheduledStatusId { get; set; }//kept for a scheduled post until it is published or dropped
|
|
public string ProfileOfAvatarId { get; set; }//a persona's avatar or header (Kind "avatar" or "header"), never a post's
|
|
// set once nothing holds it any more (its post deleted, edited out, replaced, its root removed, never posted): its
|
|
// files move out of what /media/files serves at once, and the janitor deletes them after a grace
|
|
public DateTime? TrashedAt { get; set; }
|
|
public string TrashReason { get; set; }
|
|
}
|
|
|
|
public class MediaSecret : Entity
|
|
{
|
|
public string Key { get; set; }
|
|
}
|
|
}
|