💥 ♻️ Refactor cloud files' references, and loading system

This commit is contained in:
2025-06-01 19:18:23 +08:00
parent 02ae634690
commit 00229fd406
32 changed files with 5204 additions and 582 deletions

View File

@ -22,7 +22,7 @@ public enum PostVisibility
Private
}
public class Post : ModelBase
public class Post : ModelBase, IIdentifiedResource
{
public Guid Id { get; set; }
[MaxLength(1024)] public string? Title { get; set; }
@ -31,7 +31,7 @@ public class Post : ModelBase
public Instant? EditedAt { get; set; }
public Instant? PublishedAt { get; set; }
public PostVisibility Visibility { get; set; } = PostVisibility.Public;
// ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength
public string? Content { get; set; }
@ -44,19 +44,17 @@ public class Post : ModelBase
public int Downvotes { get; set; }
[NotMapped] public Dictionary<string, int> ReactionsCount { get; set; } = new();
public Guid? ThreadedPostId { get; set; }
public Post? ThreadedPost { get; set; }
public Guid? RepliedPostId { get; set; }
public Post? RepliedPost { get; set; }
public Guid? ForwardedPostId { get; set; }
public Post? ForwardedPost { get; set; }
public ICollection<CloudFile> Attachments { get; set; } = new List<CloudFile>();
[Column(TypeName = "jsonb")] public List<CloudFileReferenceObject> Attachments { get; set; } = [];
[JsonIgnore] public NpgsqlTsVector SearchVector { get; set; } = null!;
public Guid PublisherId { get; set; }
public Publisher.Publisher Publisher { get; set; } = null!;
public ICollection<PostReaction> Reactions { get; set; } = new List<PostReaction>();
public ICollection<PostTag> Tags { get; set; } = new List<PostTag>();
public ICollection<PostCategory> Categories { get; set; } = new List<PostCategory>();
@ -64,6 +62,8 @@ public class Post : ModelBase
[JsonIgnore] public bool Empty => Content == null && Attachments.Count == 0 && ForwardedPostId == null;
[NotMapped] public bool IsTruncated = false;
public string ResourceIdentifier => $"post/{Id}";
}
public class PostTag : ModelBase

View File

@ -41,9 +41,7 @@ public class PostController(
.CountAsync();
var posts = await query
.Include(e => e.RepliedPost)
.Include(e => e.ThreadedPost)
.Include(e => e.ForwardedPost)
.Include(e => e.Attachments)
.Include(e => e.Categories)
.Include(e => e.Tags)
.Where(e => e.RepliedPostId == null)
@ -107,9 +105,7 @@ public class PostController(
.CountAsync();
var posts = await db.Posts
.Where(e => e.RepliedPostId == id)
.Include(e => e.ThreadedPost)
.Include(e => e.ForwardedPost)
.Include(e => e.Attachments)
.Include(e => e.Categories)
.Include(e => e.Tags)
.FilterWithVisibility(currentUser, userFriends, isListing: true)
@ -351,7 +347,6 @@ public class PostController(
var post = await db.Posts
.Where(e => e.Id == id)
.Include(e => e.Publisher)
.Include(e => e.Attachments)
.FirstOrDefaultAsync();
if (post is null) return NotFound();

View File

@ -1,4 +1,3 @@
using System.Text.Json;
using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Activity;
using DysonNetwork.Sphere.Localization;
@ -13,6 +12,7 @@ namespace DysonNetwork.Sphere.Post;
public class PostService(
AppDatabase db,
FileService fs,
FileReferenceService fileRefService,
ActivityService act,
IStringLocalizer<NotificationResource> localizer,
NotificationService nty,
@ -57,7 +57,8 @@ public class PostService(
if (attachments is not null)
{
post.Attachments = await db.Files.Where(e => attachments.Contains(e.Id)).ToListAsync();
post.Attachments = (await db.Files.Where(e => attachments.Contains(e.Id)).ToListAsync())
.Select(x => x.ToReferenceObject()).ToList();
// Re-order the list to match the id list places
post.Attachments = attachments
.Select(id => post.Attachments.First(a => a.Id == id))
@ -91,8 +92,20 @@ public class PostService(
db.Posts.Add(post);
await db.SaveChangesAsync();
await fs.MarkUsageRangeAsync(post.Attachments, 1);
await fs.SetUsageRangeAsync(post.Attachments, PostFileUsageIdentifier);
// Create file references for each attachment
if (post.Attachments.Any())
{
var postResourceId = $"post:{post.Id}";
foreach (var file in post.Attachments)
{
await fileRefService.CreateReferenceAsync(
file.Id,
PostFileUsageIdentifier,
postResourceId
);
}
}
await act.CreateNewPostActivity(user, post);
@ -131,8 +144,21 @@ public class PostService(
if (attachments is not null)
{
post.Attachments = (await fs.DiffAndMarkFilesAsync(attachments, post.Attachments)).current;
await fs.DiffAndSetUsageAsync(attachments, PostFileUsageIdentifier);
var postResourceId = $"post:{post.Id}";
// Update resource references using the new file list
await fileRefService.UpdateResourceFilesAsync(
postResourceId,
attachments,
PostFileUsageIdentifier
);
// Update post attachments by getting files from database
var files = await db.Files
.Where(f => attachments.Contains(f.Id))
.ToListAsync();
post.Attachments = files.Select(x => x.ToReferenceObject()).ToList();
}
if (tags is not null)
@ -168,9 +194,13 @@ public class PostService(
public async Task DeletePostAsync(Post post)
{
var postResourceId = $"post:{post.Id}";
// Delete all file references for this post
await fileRefService.DeleteResourceReferencesAsync(postResourceId);
db.Posts.Remove(post);
await db.SaveChangesAsync();
await fs.MarkUsageRangeAsync(post.Attachments, -1);
}
/// <summary>
@ -279,8 +309,7 @@ public class PostService(
[
e.PublisherId,
e.RepliedPost?.PublisherId,
e.ForwardedPost?.PublisherId,
e.ThreadedPost?.PublisherId
e.ForwardedPost?.PublisherId
])
.Where(e => e != null)
.Distinct()
@ -300,13 +329,9 @@ public class PostService(
publishers.TryGetValue(post.RepliedPost.PublisherId, out var repliedPublisher))
post.RepliedPost.Publisher = repliedPublisher;
if (post.ForwardedPost?.PublisherId != null &&
if (post.ForwardedPost?.PublisherId != null &&
publishers.TryGetValue(post.ForwardedPost.PublisherId, out var forwardedPublisher))
post.ForwardedPost.Publisher = forwardedPublisher;
if (post.ThreadedPost?.PublisherId != null &&
publishers.TryGetValue(post.ThreadedPost.PublisherId, out var threadedPublisher))
post.ThreadedPost.Publisher = threadedPublisher;
}
return posts;