using System; using System.Collections.Generic; using Knot.Shared.Kernel; using MongoDB.Bson.Serialization.Attributes; namespace Knot.Modules.Messaging.Domain; /// /// Абстрактная база агрегата Сообщение. /// [BsonDiscriminator(RootClass = true)] [BsonKnownTypes(typeof(TextMessage), typeof(MediaMessage), typeof(StoryMessage), typeof(PollMessage))] public abstract class Message : AggregateRoot { // ================== Базовые поля ================== public Guid ChatId { get; protected set; } public Guid SenderId { get; protected set; } public DateTime CreatedAt { get; protected set; } public long SequenceId { get; protected set; } public void SetSequenceId(long sequenceId) { SequenceId = sequenceId; } // ================== Опциональные метаданные (общего назначения) ================== public Guid? ReplyToId { get; protected set; } public Guid? ForwardedFromId { get; protected set; } // ================== Флаги ================== public MessageState State { get; protected set; } // ================== Абстрактные / Виртуальные свойства ================== public abstract string Type { get; } public abstract string? Content { get; protected set; } public bool IsEdited => HasState(MessageState.IsEdited); public bool IsDeleted => HasState(MessageState.IsDeleted); public bool IsDeletedForUser(Guid userId) => _deletedFor.Exists(d => d.UserId == userId); // ================== Связанные коллекции (общего назначения) ================== protected List _deletedFor = new(); public IReadOnlyCollection DeletedFor => _deletedFor.AsReadOnly(); // ================== Инфраструктурный конструктор EF ================== protected Message() : base(Guid.Empty) { } protected Message( Guid id, Guid chatId, Guid senderId, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported) : base(id) { ChatId = chatId; SenderId = senderId; ReplyToId = replyToId; ForwardedFromId = forwardedFromId; CreatedAt = createdAt; if (isImported) AddState(MessageState.IsImported); } // ================== Управление Состоянием ================== public void AddState(MessageState state) => State |= state; public void RemoveState(MessageState state) => State &= ~state; public bool HasState(MessageState state) => (State & state) == state; // ================== Общие операции ================== public virtual void Delete() { AddState(MessageState.IsDeleted); RaiseDomainEvent(new MessageDeletedDomainEvent(Id, ChatId)); } public virtual void Edit(string newContent) { Content = newContent; AddState(MessageState.IsEdited); RaiseDomainEvent(new MessageEditedDomainEvent(Id, ChatId, newContent)); } public void DeleteForUser(Guid userId) { if (!_deletedFor.Exists(x => x.UserId == userId)) { _deletedFor.Add(new DeletedMessage(Id, userId)); } } }