femto-backend/Femto.Modules.Blog/Domain/Posts/Post.cs
2025-08-10 21:21:40 +02:00

72 lines
2.3 KiB
C#

using System.Text.Json;
using Femto.Common.Domain;
using Femto.Modules.Blog.Domain.Posts.Events;
using Femto.Modules.Blog.Emoji;
namespace Femto.Modules.Blog.Domain.Posts;
internal class Post : Entity
{
public Guid Id { get; private set; }
public Guid AuthorId { get; private set; }
public string Content { get; private set; } = null!;
public IList<PostMedia> Media { get; private set; }
public IList<PostReaction> Reactions { get; private set; } = [];
public IList<PostComment> Comments { get; private set; } = [];
public bool IsPublic { get; private set; }
public DateTimeOffset PostedOn { get; private set; }
private string PossibleReactionsJson { get; set; } = null!;
public IEnumerable<string> PossibleReactions
{
get => JsonSerializer.Deserialize<IEnumerable<string>>(this.PossibleReactionsJson)!;
init => PossibleReactionsJson = JsonSerializer.Serialize(value);
}
private Post() { }
public Post(Guid authorId, string content, IList<PostMedia> media, bool isPublic)
{
this.Id = Guid.CreateVersion7();
this.AuthorId = authorId;
this.Content = content;
this.Media = media;
this.PossibleReactions = AllEmoji.GetRandomEmoji(5);
this.PostedOn = DateTimeOffset.UtcNow;
this.IsPublic = isPublic;
this.AddDomainEvent(new PostCreated(this));
}
public void AddReaction(Guid reactorId, string emoji)
{
if (!this.PossibleReactions.Contains(emoji))
return;
if (this.Reactions.Any(r => r.AuthorId == reactorId && r.Emoji == emoji))
return;
this.Reactions.Add(new PostReaction(reactorId, this.Id, emoji));
}
public void RemoveReaction(Guid reactorId, string emoji)
{
this.Reactions = this
.Reactions.Where(r => r.AuthorId != reactorId || r.Emoji != emoji)
.ToList();
}
public void AddComment(Guid authorId, string content)
{
// XXX just ignore empty comments for now. we may want to upgrade this to an error
// but it is probably suitable to just consider it a no-op
if (string.IsNullOrWhiteSpace(content))
return;
this.Comments.Add(new PostComment(authorId, content));
}
}