Разделение сообщения

This commit is contained in:
Халимов Рустам
2026-04-02 22:11:03 +03:00
parent 757142eda7
commit 943699139b
22 changed files with 297 additions and 193 deletions
@@ -0,0 +1,17 @@
using System;
namespace Knot.Contracts.Messaging.Domain;
public class Media
{
public Guid Id { get; set; }
public string Type { get; set; } = string.Empty;
public string? Url { get; set; }
public string? ThumbnailUrl { get; set; }
public long? Size { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public string? FileId { get; set; }
public string? Filename { get; set; }
public string? Duration { get; set; }
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
namespace Knot.Contracts.Messaging.Domain;
public class MediaMessage : Message
{
public override string Type => MediaType.ToString().ToLower();
public override string? Content { get; protected set; }
public string? Caption { get => Content; private set => Content = value; }
public MediaType MediaType { get; private set; }
private List<Media> _media = new();
public IReadOnlyCollection<Media> Media => _media.AsReadOnly();
private MediaMessage() : base() { MediaType = MediaType.File; }
public MediaMessage(Guid id, Guid chatId, Guid senderId, MediaType mediaType, string? caption, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: base(id, chatId, senderId, replyToId, forwardedFromId, createdAt, isImported) { MediaType = mediaType; Caption = caption; }
public MediaMessage(Guid id, Guid chatId, Guid senderId, string mediaType, string? caption, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: this(id, chatId, senderId, Enum.TryParse<MediaType>(mediaType, true, out var mt) ? mt : MediaType.File, caption, replyToId, forwardedFromId, createdAt, isImported) { }
public void AddMedia(string type, string url, string? filename, long? size) => _media.Add(new Media { Type = type, Url = url, FileId = filename, Size = size });
public override void Edit(string newCaption) => base.Edit(newCaption);
public override void Delete() { Caption = null; base.Delete(); }
}
@@ -16,18 +16,17 @@ public abstract class Message : AggregateRoot<Guid>
public MessageState State { get; protected set; }
public abstract string Type { get; }
public abstract string? Content { get; protected set; }
public virtual string? Quote { get; protected set; } = null;
public virtual Guid? StoryId => null;
public virtual string? StoryMediaUrl => null;
public virtual string? StoryMediaType => null;
public virtual IReadOnlyCollection<Media> Media => Array.Empty<Media>();
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<DeletedMessage> _deletedFor = new();
public IReadOnlyCollection<DeletedMessage> DeletedFor => _deletedFor.AsReadOnly();
protected Message() : base(Guid.Empty) { }
protected Message(Guid id, Guid chatId, Guid senderId, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported) : base(id)
protected Message(Guid id, Guid chatId, Guid senderId, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: base(id)
{
ChatId = chatId;
SenderId = senderId;
@@ -36,91 +35,22 @@ public abstract class Message : AggregateRoot<Guid>
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 bool IsDeletedForUser(Guid userId) => _deletedFor.Exists(d => d.UserId == userId);
public virtual void Delete() => AddState(MessageState.IsDeleted);
public virtual void Edit(string newContent) { Content = newContent; AddState(MessageState.IsEdited); }
public void DeleteForUser(Guid userId) { if (!_deletedFor.Exists(x => x.UserId == userId)) _deletedFor.Add(new DeletedMessage(Id, userId)); }
}
public virtual void Edit(string newContent)
{
Content = newContent;
AddState(MessageState.IsEdited);
}
public class Media
{
public Guid Id { get; set; }
public string Type { get; set; } = string.Empty;
public string? Url { get; set; }
public string? ThumbnailUrl { get; set; }
public long? Size { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public string? FileId { get; set; }
public string? Filename { get; set; }
public string? Duration { get; set; }
}
public class TextMessage : Message
{
public override string Type => "text";
public override string? Content { get; protected set; }
public TextMessage() : base() { }
public TextMessage(Guid id, Guid chatId, Guid senderId, string content, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported = false)
: base(id, chatId, senderId, replyToId, forwardedFromId, createdAt, isImported) => Content = content;
public TextMessage(Guid id, Guid chatId, Guid senderId, string content, Guid? replyToId, string? quote, Guid? forwardedFromId, DateTime createdAt, bool isImported = false)
: this(id, chatId, senderId, content, replyToId, forwardedFromId, createdAt, isImported) => Quote = quote;
}
public class MediaMessage : Message
{
public override string Type => MediaType.ToString().ToLower();
public override string? Content { get; protected set; }
public string? Caption { get => Content; private set => Content = value; }
public MediaType MediaType { get; private set; }
private List<Media> _media = new();
public override IReadOnlyCollection<Media> Media => _media.AsReadOnly();
private MediaMessage() : base() { MediaType = MediaType.File; }
public MediaMessage(Guid id, Guid chatId, Guid senderId, MediaType mediaType, string? caption, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: base(id, chatId, senderId, replyToId, forwardedFromId, createdAt, isImported) { MediaType = mediaType; Caption = caption; }
public MediaMessage(Guid id, Guid chatId, Guid senderId, string mediaType, string? caption, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: this(id, chatId, senderId, Enum.TryParse<MediaType>(mediaType, true, out var mt) ? mt : MediaType.File, caption, replyToId, forwardedFromId, createdAt, isImported) { }
public void AddMedia(string type, string url, string? filename, long? size) => _media.Add(new Media { Type = type, Url = url, FileId = filename, Size = size });
public override void Edit(string newCaption) => base.Edit(newCaption);
public override void Delete() { Caption = null; base.Delete(); }
}
public class StoryMessage : Message
{
public override string Type => "story";
public override string? Content { get; protected set; }
public override Guid? StoryId { get; }
public string? InternalStoryMediaUrl { get; private set; }
public override string? StoryMediaUrl => InternalStoryMediaUrl;
public override string? StoryMediaType { get; }
public StoryMessage() : base() { }
public StoryMessage(Guid id, Guid chatId, Guid senderId, Guid storyId, string? storyMediaUrl, string? storyMediaType, DateTime createdAt)
: base(id, chatId, senderId, null, null, createdAt, false) { StoryId = storyId; InternalStoryMediaUrl = storyMediaUrl; StoryMediaType = storyMediaType; }
public StoryMessage(Guid id, Guid chatId, Guid senderId, Guid storyId, string? storyMediaUrl, string? storyMediaType, string? content, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: this(id, chatId, senderId, storyId, storyMediaUrl, storyMediaType, createdAt) { Content = content; ReplyToId = replyToId; ForwardedFromId = forwardedFromId; if (isImported) AddState(MessageState.IsImported); }
}
public class PollMessage : Message
{
public override string Type => "poll";
public override string? Content { get; protected set; }
public List<PollOption> Options { get; } = new();
public List<PollVote> Votes { get; } = new();
public bool IsMultipleChoice { get; set; }
public DateTime? ExpiresAt { get; set; }
public bool IsClosed { get; set; }
public PollMessage() : base() { }
public PollMessage(Guid id, Guid chatId, Guid senderId, string? question, List<string>? options, bool isAnonymous, bool isMultiple, DateTime? expiresAt, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: base(id, chatId, senderId, replyToId, forwardedFromId, createdAt, isImported)
{
Content = question ?? "Poll";
if (options != null) foreach (var opt in options) Options.Add(new PollOption { Text = opt });
IsMultipleChoice = isMultiple;
ExpiresAt = expiresAt;
public void DeleteForUser(Guid userId)
{
if (!_deletedFor.Exists(x => x.UserId == userId))
_deletedFor.Add(new DeletedMessage(Id, userId));
}
}
public class PollOption { public string Text { get; set; } = string.Empty; public int VoteCount { get; set; } }
public class PollVote { public Guid OptionIndex { get; set; } public Guid UserId { get; set; } public DateTime VotedAt { get; set; } }
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
namespace Knot.Contracts.Messaging.Domain;
public class PollMessage : Message
{
public override string Type => "poll";
public override string? Content { get; protected set; }
public List<PollOption> Options { get; } = new();
public List<PollVote> Votes { get; } = new();
public bool IsMultipleChoice { get; set; }
public DateTime? ExpiresAt { get; set; }
public bool IsClosed { get; set; }
public PollMessage() : base() { }
public PollMessage(Guid id, Guid chatId, Guid senderId, string? question, List<string>? options, bool isAnonymous, bool isMultiple, DateTime? expiresAt, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: base(id, chatId, senderId, replyToId, forwardedFromId, createdAt, isImported)
{
Content = question ?? "Poll";
if (options != null)
{
foreach (var opt in options)
{
Options.Add(new PollOption { Text = opt });
}
}
IsMultipleChoice = isMultiple;
ExpiresAt = expiresAt;
}
}
@@ -0,0 +1,7 @@
namespace Knot.Contracts.Messaging.Domain;
public class PollOption
{
public string Text { get; set; } = string.Empty;
public int VoteCount { get; set; }
}
@@ -0,0 +1,10 @@
using System;
namespace Knot.Contracts.Messaging.Domain;
public class PollVote
{
public Guid OptionIndex { get; set; }
public Guid UserId { get; set; }
public DateTime VotedAt { get; set; }
}
@@ -0,0 +1,31 @@
using System;
namespace Knot.Contracts.Messaging.Domain;
public class StoryMessage : Message
{
public override string Type => "story";
public override string? Content { get; protected set; }
public Guid? StoryId { get; private set; }
public string? StoryMediaUrl { get; private set; }
public string? StoryMediaType { get; private set; }
public StoryMessage() : base() { }
public StoryMessage(Guid id, Guid chatId, Guid senderId, Guid storyId, string? storyMediaUrl, string? storyMediaType, DateTime createdAt)
: base(id, chatId, senderId, null, null, createdAt, false)
{
StoryId = storyId;
StoryMediaUrl = storyMediaUrl;
StoryMediaType = storyMediaType;
}
public StoryMessage(Guid id, Guid chatId, Guid senderId, Guid storyId, string? storyMediaUrl, string? storyMediaType, string? content, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported)
: this(id, chatId, senderId, storyId, storyMediaUrl, storyMediaType, createdAt)
{
Content = content;
ReplyToId = replyToId;
ForwardedFromId = forwardedFromId;
if (isImported) AddState(MessageState.IsImported);
}
}
@@ -0,0 +1,18 @@
using System;
namespace Knot.Contracts.Messaging.Domain;
public class TextMessage : Message
{
public override string Type => "text";
public override string? Content { get; protected set; }
public string? Quote { get; protected set; }
public TextMessage() : base() { }
public TextMessage(Guid id, Guid chatId, Guid senderId, string content, Guid? replyToId, Guid? forwardedFromId, DateTime createdAt, bool isImported = false)
: base(id, chatId, senderId, replyToId, forwardedFromId, createdAt, isImported) => Content = content;
public TextMessage(Guid id, Guid chatId, Guid senderId, string content, Guid? replyToId, string? quote, Guid? forwardedFromId, DateTime createdAt, bool isImported = false)
: this(id, chatId, senderId, content, replyToId, forwardedFromId, createdAt, isImported) => Quote = quote;
}