147 lines
4.2 KiB
C#
147 lines
4.2 KiB
C#
using Knot.Shared.Kernel;
|
|
|
|
namespace Knot.Contracts.Conversations.Domain;
|
|
|
|
public sealed record ChatCreatedDomainEvent(Chat Chat) : IDomainEvent;
|
|
public sealed record ChatMemberAddedDomainEvent(Guid ChatId, Guid UserId) : IDomainEvent;
|
|
|
|
/// <summary>
|
|
/// Тип чата: личный или групповой.
|
|
/// </summary>
|
|
public enum ChatType
|
|
{
|
|
Personal,
|
|
Group,
|
|
Favorites
|
|
}
|
|
|
|
/// <summary>
|
|
/// Роль участника в чате.
|
|
/// </summary>
|
|
public static class ChatRole
|
|
{
|
|
public const string Owner = "owner";
|
|
public const string Admin = "admin";
|
|
public const string Member = "member";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Сущность чата (Агрегат).
|
|
/// </summary>
|
|
public sealed class Chat : AggregateRoot<Guid>
|
|
{
|
|
public ChatType Type { get; private set; }
|
|
public string? Name { get; private set; }
|
|
public string? Description { get; private set; }
|
|
public string? Avatar { get; private set; }
|
|
public DateTime CreatedAt { get; private set; }
|
|
public long LastMessageSequenceId { get; private set; }
|
|
|
|
private readonly List<ChatMember> _members = new();
|
|
public IReadOnlyCollection<ChatMember> Members => _members.AsReadOnly();
|
|
|
|
private Chat(Guid id, ChatType type, string? name, string? avatar, string? description = null) : base(id)
|
|
{
|
|
Type = type;
|
|
Name = name;
|
|
Avatar = avatar;
|
|
Description = description;
|
|
CreatedAt = DateTime.UtcNow;
|
|
}
|
|
|
|
public static Chat CreatePersonal()
|
|
{
|
|
var chat = new Chat(Guid.NewGuid(), ChatType.Personal, null, null);
|
|
chat.RaiseDomainEvent(new ChatCreatedDomainEvent(chat));
|
|
return chat;
|
|
}
|
|
|
|
public static Chat CreateGroup(string name, string? avatar = null)
|
|
{
|
|
var chat = new Chat(Guid.NewGuid(), ChatType.Group, name, avatar);
|
|
chat.RaiseDomainEvent(new ChatCreatedDomainEvent(chat));
|
|
return chat;
|
|
}
|
|
|
|
public static Chat Create(string? name, ChatType type, string? avatar = null, string? description = null)
|
|
{
|
|
var chat = new Chat(Guid.NewGuid(), type, name, avatar, description);
|
|
chat.RaiseDomainEvent(new ChatCreatedDomainEvent(chat));
|
|
return chat;
|
|
}
|
|
|
|
public void AddMember(Guid userId, string role = "member")
|
|
{
|
|
if (_members.Any(m => m.UserId == userId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_members.Add(new ChatMember(Id, userId, role));
|
|
RaiseDomainEvent(new ChatMemberAddedDomainEvent(Id, userId));
|
|
}
|
|
|
|
public void RemoveMember(Guid userId)
|
|
{
|
|
var member = _members.FirstOrDefault(m => m.UserId == userId);
|
|
if (member != null)
|
|
{
|
|
_members.Remove(member);
|
|
}
|
|
}
|
|
|
|
public void UpdateName(string name) => Name = name;
|
|
|
|
public void UpdateDescription(string? description) => Description = description;
|
|
|
|
public void UpdateAvatar(string? avatarUrl) => Avatar = avatarUrl;
|
|
|
|
public long IncrementSequenceId()
|
|
{
|
|
return ++LastMessageSequenceId;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Участник чата.
|
|
/// </summary>
|
|
public sealed class ChatMember : Entity<Guid>
|
|
{
|
|
public Guid ChatId { get; private set; }
|
|
public Guid UserId { get; private set; }
|
|
public string Role { get; private set; }
|
|
public DateTime JoinedAt { get; private set; }
|
|
public bool IsPinned { get; private set; }
|
|
public bool IsMuted { get; private set; }
|
|
|
|
public Guid? LastReadMessageId { get; private set; }
|
|
public long LastReadSequenceId { get; private set; }
|
|
public Guid? LastDeliveredMessageId { get; private set; }
|
|
|
|
private ChatMember() : base(Guid.Empty) { Role = "member"; }
|
|
|
|
internal ChatMember(Guid chatId, Guid userId, string role) : base(Guid.NewGuid())
|
|
{
|
|
ChatId = chatId;
|
|
UserId = userId;
|
|
Role = role;
|
|
JoinedAt = DateTime.UtcNow;
|
|
}
|
|
|
|
public void TogglePin() => IsPinned = !IsPinned;
|
|
|
|
public void UpdateReadCursor(Guid messageId, long sequenceId)
|
|
{
|
|
if (sequenceId > LastReadSequenceId)
|
|
{
|
|
LastReadMessageId = messageId;
|
|
LastReadSequenceId = sequenceId;
|
|
}
|
|
}
|
|
|
|
public void UpdateDeliveredCursor(Guid messageId)
|
|
{
|
|
LastDeliveredMessageId = messageId;
|
|
}
|
|
}
|