添加项目文件。

This commit is contained in:
2026-05-09 17:06:30 +08:00
parent c60f5fe117
commit 720ef957d4
378 changed files with 14843 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
using GroupService.Domain.Enums;
using GroupService.Domain.Events;
using IM.DomainCommons;
namespace GroupService.Domain.Entities
{
public class Group : AggregateRootEntity
{
/// <summary>
/// 群聊名称
/// </summary>
public string Name { get; private set; } = "新建群聊";
/// <summary>
/// 群主
/// </summary>
public Guid GroupMaster { get; private set; }
/// <summary>
/// 群权限
/// (0:需管理员同意,1:任意人可加群,2:不允许任何人加入)
/// </summary>
public GroupAuthorityType Authority { get; private set; } = GroupAuthorityType.REQUIRE_CONSENT;
/// <summary>
/// 全员禁言(false允许发言,true全员禁言)
/// </summary>
public bool AllMembersBanned { get; private set; } = false;
/// <summary>
/// 群聊状态
/// (1:正常,2:封禁)
/// </summary>
public GroupState Status { get; private set; } = GroupState.Normal;
/// <summary>
/// 群公告
/// </summary>
public string Announcement { get; private set; } = string.Empty;
/// <summary>
/// 群头像
/// </summary>
public string? Avatar { get; private set; } = "https://ts1.tc.mm.bing.net/th/id/OIP-C.XiB9NHwI57WPmotCbXuwawAAAA?rs=1&pid=ImgDetMain&o=7&rm=3";
public long MaxSequenceId { get; private set; } = 0;
public string LastMessage { get; private set; } = string.Empty;
public string LastSenderName { get; private set; } = string.Empty;
private Group() { }
public Group(Guid groupMaster, string name = "新建群聊")
{
Name = name;
GroupMaster = groupMaster;
AddDomainEvent(new GroupCreateDomainEvent(this));
}
public void setAllMembersBanned(bool isBanned)
{
if (isBanned == AllMembersBanned) return;
AllMembersBanned = isBanned;
AddDomainEvent(new AllMembersBannedDomainEvent(this));
}
public void Ban()
{
Status = GroupState.Blocked;
ModificationTime = DateTime.Now;
AddDomainEvent(new GroupBlockedDomainEvent(this));
}
public void Update(string? name, GroupAuthorityType? groupAuthority, string? announcement, string? avatar)
{
bool isChanged = false;
if (name != null)
{
Name = name;
isChanged = true;
}
if (groupAuthority != null)
{
Authority = groupAuthority.Value;
isChanged = true;
}
if (announcement != null)
{
Announcement = announcement;
isChanged = true;
}
if (avatar != null)
{
Avatar = avatar;
isChanged = true;
}
if (isChanged)
{
ModificationTime = DateTime.Now;
AddDomainEvent(new GroupUpdateDomainEvent(this));
}
}
public void UpdateLastMsg(long maxSequenceId, string lastMsg, string lastSenderName)
{
MaxSequenceId = maxSequenceId;
LastMessage = lastMsg;
LastSenderName = lastSenderName;
}
}
}
@@ -0,0 +1,62 @@
using GroupService.Domain.Enums;
using GroupService.Domain.Events;
using GroupService.Domain.ValueObjects;
using IM.DomainCommons;
namespace GroupService.Domain.Entities
{
public class GroupInvitation : AggregateRootEntity
{
/// <summary>
/// 群聊编号
/// </summary>
public Guid GroupId { get; private set; }
public GroupProfile GroupProfile { get; private set; }
/// <summary>
/// 被邀请用户
/// </summary>
public Guid UserId { get; private set; }
public UserProfile UserProfile { get; private set; }
/// <summary>
/// 邀请用户
/// </summary>
public Guid OperatorId { get; private set; }
public UserProfile OperatorProfile { get; private set; }
/// <summary>
/// 当前状态(0:待被邀请人同意
/// 1:被邀请人已同意)
/// </summary>
public GroupInvitationState State { get; private set; } = GroupInvitationState.Pending;
private GroupInvitation() { }
public GroupInvitation(Guid groupId, GroupProfile groupProfile, Guid userId, UserProfile userProfile, Guid operatorId, UserProfile operatorProfile)
{
GroupId = groupId;
GroupProfile = groupProfile;
UserId = userId;
UserProfile = userProfile;
OperatorId = operatorId;
OperatorProfile = operatorProfile;
AddDomainEvent(new GroupInvitationCreateDomainEvent(this));
}
public void Accept()
{
if (State != GroupInvitationState.Pending) return;
State = GroupInvitationState.Passed;
ModificationTime = DateTime.Now;
AddDomainEvent(new GroupInvitationAcceptDomainEvent(this));
}
public void Reject()
{
if (State != GroupInvitationState.Pending) return;
State = GroupInvitationState.Reject;
ModificationTime = DateTime.Now;
}
}
}
@@ -0,0 +1,74 @@
using GroupService.Domain.Enums;
using GroupService.Domain.Events;
using GroupService.Domain.ValueObjects;
using IM.DomainCommons;
namespace GroupService.Domain.Entities
{
public class GroupJoinRequest : AggregateRootEntity
{
/// <summary>
/// 群聊编号
///
/// </summary>
public Guid GroupId { get; private set; }
public GroupProfile GroupProfile { get; private set; }
/// <summary>
/// 申请人
/// </summary>
public Guid UserId { get; private set; }
public UserProfile UserProfile { get; private set; }
public Guid? OperatorId { get; private set; }
public string? OperatorName { get; private set; }
public string? OperatorAvatar { get; private set; }
/// <summary>
/// 申请状态(0:待管理员同意,1:已拒绝,2:已同意)
/// </summary>
public GroupJoinRequestState State { get; private set; } = GroupJoinRequestState.Pending;
/// <summary>
/// 入群附言
/// </summary>
public string Description { get; private set; } = "申请入群";
private GroupJoinRequest() { }
public GroupJoinRequest(Guid userId, UserProfile user, Guid groupId, GroupProfile group, string? desc)
{
UserId = userId;
GroupId = groupId;
GroupProfile = group;
UserProfile = user;
if (desc is not null && desc.Length > 20)
{
throw new DomainException("入群描述不可超过20字符");
}
Description = desc ?? Description;
}
public void Approve(Guid id, string nickName, string avatar)
{
if (State != GroupJoinRequestState.Pending) return;
State = GroupJoinRequestState.Passed;
OperatorAvatar = avatar;
OperatorId = id;
OperatorName = nickName;
ModificationTime = DateTime.Now;
AddDomainEvent(new GroupJoinRequestPassedDomainEvent(this));
}
public void Decline(Guid id, string nickName, string avatar)
{
if (State != GroupJoinRequestState.Pending) return;
State = GroupJoinRequestState.Declined;
OperatorAvatar = avatar;
OperatorId = id;
OperatorName = nickName;
ModificationTime = DateTime.Now;
AddDomainEvent(new GroupJoinRequestDeclinedDomainEvent(this));
}
}
}
@@ -0,0 +1,53 @@
using GroupService.Domain.Enums;
using GroupService.Domain.Events;
using IM.DomainCommons;
namespace GroupService.Domain.Entities
{
public class GroupMember : AggregateRootEntity
{
/// <summary>
/// 用户编号
/// </summary>
public Guid UserId { get; private set; }
public string GroupNickName { get; private set; }
public string? Avatar { get; private set; }
/// <summary>
/// 群聊编号
/// </summary>
public Guid GroupId { get; private set; }
/// <summary>
/// 成员角色(0:普通成员,1:管理员,2:群主)
/// </summary>
public GroupMemberRole Role { get; private set; }
private GroupMember() { }
public GroupMember(Guid userId, Guid groupId, string groupNickname, string? avatar, GroupMemberRole role = GroupMemberRole.Normal)
{
UserId = userId;
GroupId = groupId;
Role = role;
GroupNickName = groupNickname;
Avatar = avatar;
AddDomainEvent(new GroupMemberJoinedDomainEvent(this));
}
public void UpdateRole(GroupMemberRole role)
{
if (role == Role) return;
Role = role;
}
public void UpdateAvatar(string avatar)
{
Avatar = avatar;
}
public void UpdateGroupNickname(string nickname)
{
GroupNickName = nickname;
}
}
}
@@ -0,0 +1,18 @@
namespace GroupService.Domain.Enums
{
public enum GroupAuthorityType
{
/// <summary>
/// 需管理员同意
/// </summary>
REQUIRE_CONSENT = 0,
/// <summary>
/// 任何人可加入
/// </summary>
ANYONE_CAN_JOIN = 1,
/// <summary>
/// 不允许加入
/// </summary>
NOT_ALLOWED_TO_JOIN = 2
}
}
@@ -0,0 +1,18 @@
namespace GroupService.Domain.Enums
{
public enum GroupInvitationState
{
/// <summary>
/// 待处理
/// </summary>
Pending = 0,
/// <summary>
/// 已同意
/// </summary>
Passed = 1,
/// <summary>
/// 拒绝
/// </summary>
Reject = 2
}
}
@@ -0,0 +1,18 @@
namespace GroupService.Domain.Enums
{
public enum GroupJoinRequestState
{
/// <summary>
/// 待管理员处理
/// </summary>
Pending = 0,
/// <summary>
/// 已拒绝
/// </summary>
Declined = 1,
/// <summary>
/// 已同意
/// </summary>
Passed = 2
}
}
@@ -0,0 +1,18 @@
namespace GroupService.Domain.Enums
{
public enum GroupMemberRole
{
/// <summary>
/// 普通成员
/// </summary>
Normal = 0,
/// <summary>
/// 管理员
/// </summary>
Administrator = 1,
/// <summary>
/// 群主
/// </summary>
Master = 2
}
}
+14
View File
@@ -0,0 +1,14 @@
namespace GroupService.Domain.Enums
{
public enum GroupState
{
/// <summary>
/// 正常
/// </summary>
Normal = 1,
/// <summary>
/// 封禁
/// </summary>
Blocked = 2
}
}
@@ -0,0 +1,7 @@
using GroupService.Domain.Entities;
using MediatR;
namespace GroupService.Domain.Events
{
public record AllMembersBannedDomainEvent(Group Group) : INotification;
}
@@ -0,0 +1,7 @@
using GroupService.Domain.Entities;
using MediatR;
namespace GroupService.Domain.Events
{
public record GroupBlockedDomainEvent(Group Group) : INotification;
}
@@ -0,0 +1,6 @@
using MediatR;
namespace GroupService.Domain.Events
{
public record GroupCreateDomainEvent(Domain.Entities.Group Group) : INotification;
}
@@ -0,0 +1,7 @@
using GroupService.Domain.Entities;
using MediatR;
namespace GroupService.Domain.Events
{
public record GroupInvitationAcceptDomainEvent(GroupInvitation Invitation) : INotification;
}
@@ -0,0 +1,7 @@
using GroupService.Domain.Entities;
using MediatR;
namespace GroupService.Domain.Events
{
public record GroupInvitationCreateDomainEvent(GroupInvitation Invitation) : INotification;
}
@@ -0,0 +1,7 @@
using GroupService.Domain.Entities;
using MediatR;
namespace GroupService.Domain.Events
{
public record GroupJoinRequestDeclinedDomainEvent(GroupJoinRequest Request) : INotification;
}
@@ -0,0 +1,7 @@
using GroupService.Domain.Entities;
using MediatR;
namespace GroupService.Domain.Events
{
public record GroupJoinRequestPassedDomainEvent(GroupJoinRequest Request) : INotification;
}
@@ -0,0 +1,7 @@
using GroupService.Domain.Entities;
using MediatR;
namespace GroupService.Domain.Events
{
public record GroupMemberJoinedDomainEvent(GroupMember Member) : INotification;
}
@@ -0,0 +1,7 @@
using GroupService.Domain.Entities;
using MediatR;
namespace GroupService.Domain.Events
{
public record GroupUpdateDomainEvent(Group Group) : INotification;
}
@@ -0,0 +1,30 @@
using GroupService.Domain.Entities;
using GroupService.Domain.Enums;
using GroupService.Domain.IReposities;
using IM.Commons;
namespace GroupService.Domain
{
public class GroupMemberDomainService
{
private readonly IGroupMemberReposity reposity;
public GroupMemberDomainService(IGroupMemberReposity reposity)
{
this.reposity = reposity;
}
public async Task<Result<GroupMember>> CreateAsync(
Guid userId, Guid groupId, string nickName, string? avatar, GroupMemberRole role = GroupMemberRole.Normal)
{
var exist = await reposity.CheckMemberExistAsync(groupId, userId);
if (exist)
{
return Result<GroupMember>.Fail(ResultCode.ALREADY_IN_GROUP);
}
var groupMember = new GroupMember(userId, groupId, nickName, avatar, role);
groupMember = reposity.Create(groupMember);
return Result<GroupMember>.Success(groupMember);
}
}
}
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\IM.Commons\IM.Commons.csproj" />
<ProjectReference Include="..\DomainCommons\IM.DomainCommons.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,10 @@
using GroupService.Domain.Entities;
namespace GroupService.Domain.IReposities
{
public interface IGroupInvitationReposity
{
void Create(GroupInvitation invitation);
Task<GroupInvitation?> FindByIdAsync(Guid id);
}
}
@@ -0,0 +1,40 @@
using GroupService.Domain.Entities;
namespace GroupService.Domain.IReposities
{
public interface IGroupMemberReposity
{
/// <summary>
/// 通过群ID查询群成员
/// </summary>
/// <param name="groupId"></param>
/// <returns></returns>
Task<IEnumerable<GroupMember>> FindByGroupIdAsync(Guid groupId);
/// <summary>
/// 通过用户ID查询
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<IEnumerable<GroupMember>> FindByUserIdAsync(Guid userId);
/// <summary>
/// 通过群ID和用户ID查询
/// </summary>
/// <param name="groupId"></param>
/// <param name="userId"></param>
/// <returns></returns>
Task<GroupMember?> FindOneByGroupIdAndUserIdAsync(Guid groupId, Guid userId);
/// <summary>
/// 新增群成员
/// </summary>
/// <param name="member"></param>
/// <returns></returns>
GroupMember Create(GroupMember member);
/// <summary>
/// 检查成员是否存在
/// </summary>
/// <param name="userId"></param>
/// <returns>存在返回true,否则返回false</returns>
Task<bool> CheckMemberExistAsync(Guid groupId, Guid userId);
Task<GroupMember?> FindByIdAsync(Guid id);
}
}
@@ -0,0 +1,33 @@
using GroupService.Domain.Entities;
namespace GroupService.Domain.IReposities
{
public interface IGroupReposity
{
/// <summary>
/// 通过群ID查询
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<Group?> FindByIdAsync(Guid id);
/// <summary>
/// 通过群名查询
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<IEnumerable<Group>> FindByNameAsync(string name);
/// <summary>
/// 通过群主ID查询
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<IEnumerable<Group>> FindByMasterIdAsync(Guid userId);
/// <summary>
/// 创建群聊
/// </summary>
/// <param name="group"></param>
/// <returns></returns>
Group Create(Group group);
}
}
@@ -0,0 +1,11 @@
using GroupService.Domain.Entities;
namespace GroupService.Domain.IReposities
{
public interface IGroupRequestReposity
{
void Create(GroupJoinRequest request);
Task<GroupJoinRequest> FindByIdAsync(Guid id);
Task<IEnumerable<GroupJoinRequest?>> FindByGroupIdAsync(Guid groupId);
}
}
@@ -0,0 +1,8 @@
namespace GroupService.Domain.ValueObjects
{
public class GroupProfile
{
public string GroupName { get; set; }
public string Avatar { get; set; }
}
}
@@ -0,0 +1,8 @@
namespace GroupService.Domain.ValueObjects
{
public class UserProfile
{
public string NickName { get; set; }
public string? Avatar { get; set; }
}
}