添加项目文件。

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
@@ -0,0 +1,37 @@
using GroupService.Domain.Enums;
namespace GroupService.WebApi.Application.Dtos
{
public class GroupInvitationResponse
{
public Guid Id { get; private set; }
/// <summary>
/// 群聊编号
/// </summary>
public Guid GroupId { get; private set; }
public string GroupAvatar { get; private set; }
public string GroupName { get; private set; }
/// <summary>
/// 被邀请用户
/// </summary>
public Guid UserId { get; private set; }
public string? UserAvatar { get; private set; }
public string UserNickName { get; private set; }
/// <summary>
/// 邀请用户
/// </summary>
public Guid OperatorId { get; private set; }
public string OperatorName { get; private set; }
public string? OperatorAvatar { get; private set; }
/// <summary>
/// 当前状态(0:待被邀请人同意
/// 1:被邀请人已同意)
/// </summary>
public GroupInvitationState State { get; private set; }
public DateTimeOffset Created { get; private set; }
public DateTimeOffset Updated { get; private set; }
}
}
@@ -0,0 +1,26 @@
using GroupService.Domain.Enums;
namespace GroupService.WebApi.Application.Dtos
{
public class GroupMemberResponse
{
public Guid Id { get; private set; }
/// <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; }
public DateTimeOffset Created { get; private set; }
}
}
@@ -0,0 +1,38 @@
using GroupService.Domain.Enums;
namespace GroupService.WebApi.Application.Dtos
{
public class GroupRequestResponse
{
public Guid Id { get; private set; }
/// <summary>
/// 群聊编号
///
/// </summary>
public Guid GroupId { get; private set; }
public string GroupAvatar { get; private set; }
public string GroupName { get; private set; }
/// <summary>
/// 申请人
/// </summary>
public Guid UserId { get; private set; }
public string? UserAvatar { get; private set; }
public string UserNickName { 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; }
/// <summary>
/// 入群附言
/// </summary>
public string Description { get; private set; }
public DateTimeOffset Created { get; private set; }
public DateTimeOffset Updated { get; private set; }
}
}
@@ -0,0 +1,45 @@
using GroupService.Domain.Enums;
namespace GroupService.WebApi.Application.Dtos
{
public class GroupResponse
{
public Guid Id { get; private set; }
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; }
/// <summary>
/// 全员禁言(false允许发言,true全员禁言)
/// </summary>
public bool AllMembersBanned { get; private set; }
/// <summary>
/// 群聊状态
/// (1:正常,2:封禁)
/// </summary>
public GroupState Status { get; private set; }
/// <summary>
/// 群公告
/// </summary>
public string Announcement { get; private set; }
/// <summary>
/// 群头像
/// </summary>
public string? Avatar { get; private set; }
public long MaxSequenceId { get; private set; }
public string LastMessage { get; private set; }
public string LastSenderName { get; private set; }
public DateTimeOffset Created { get; private set; }
public DateTimeOffset Updated { get; private set; }
}
}
@@ -0,0 +1,16 @@
namespace GroupService.WebApi.Application.Dtos
{
public class UserInfoDto
{
public Guid Id { get; set; }
public string UserName { get; set; }
public string NickName { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
public string Region { get; set; }
public string Description { get; set; }
public string? Avatar { get; set; }
public DateTimeOffset CreationTime { get; set; }
public DateTimeOffset? Deletion { get; set; }
}
}
@@ -0,0 +1,24 @@
using GroupService.Domain.Events;
using IM.Commons.IntegrationEvents;
using MassTransit;
using MediatR;
namespace GroupService.WebApi.Application.EventHandler
{
public class GroupBlockHandler : INotificationHandler<GroupBlockedDomainEvent>
{
private readonly IPublishEndpoint endpoint;
public GroupBlockHandler(IPublishEndpoint endpoint)
{
this.endpoint = endpoint;
}
public async Task Handle(GroupBlockedDomainEvent notification, CancellationToken cancellationToken)
{
var groupInfo = notification.Group;
await endpoint.Publish(new GroupBlockEvent(groupInfo.Id, groupInfo.Name,
groupInfo.GroupMaster, groupInfo.Status.ToString(), groupInfo.Avatar));
}
}
}
@@ -0,0 +1,42 @@
using GroupService.Domain.Events;
using GroupService.Domain.IReposities;
using GroupService.Infrastructure;
using GroupService.WebApi.Application.GroupMember;
using GroupService.WebApi.Application.IntegrationServices;
using IM.Commons.IntegrationEvents;
using MassTransit;
using MediatR;
namespace GroupService.WebApi.Application.EventHandler
{
public class GroupCreateHandler : INotificationHandler<GroupCreateDomainEvent>
{
private readonly IPublishEndpoint endpoint;
private readonly IGroupMemberReposity reposity;
private readonly IIdentityIntegrationService service;
private readonly GroupDbContext groupDb;
public GroupCreateHandler(IPublishEndpoint endpoint, IGroupMemberReposity reposity, IIdentityIntegrationService service, GroupDbContext groupDb)
{
this.endpoint = endpoint;
this.reposity = reposity;
this.service = service;
this.groupDb = groupDb;
}
public async Task Handle(GroupCreateDomainEvent notification, CancellationToken cancellationToken)
{
var group = notification.Group;
var userInfo = await service.FindUserByIdAsync(group.GroupMaster);
string nickName = "未知昵称";
if (userInfo.Succeeded)
{
nickName = userInfo.Data.NickName;
}
reposity.Create(new Domain.Entities.GroupMember(group.GroupMaster, group.Id, userInfo.Data.NickName, userInfo.Data.Avatar, Domain.Enums.GroupMemberRole.Master));
await groupDb.SaveChangesAsync();
await endpoint.Publish(new GroupCreateEvent(group.Id, group.Name, group.GroupMaster, group.Avatar));
}
}
}
@@ -0,0 +1,50 @@
using GroupService.Domain.Events;
using GroupService.WebApi.Application.GroupRequest;
using IM.Commons;
using IM.Commons.IntegrationEvents;
using MassTransit;
using MediatR;
namespace GroupService.WebApi.Application.EventHandler
{
public class GroupInvitationEventHandler :
INotificationHandler<GroupInvitationAcceptDomainEvent>
, INotificationHandler<GroupInvitationCreateDomainEvent>
{
private readonly IPublishEndpoint endpoint;
private readonly GroupRequestService requestService;
public GroupInvitationEventHandler(IPublishEndpoint endpoint, GroupRequestService requestService)
{
this.endpoint = endpoint;
this.requestService = requestService;
}
public async Task Handle(GroupInvitationAcceptDomainEvent notification, CancellationToken cancellationToken)
{
var invitation = notification.Invitation;
var res = await requestService.CreateAsync(invitation.GroupId, invitation.UserId,
$"邀请入群"
);
await endpoint.Publish(new GroupInvitationAcceptEvent(invitation.Id, invitation.UserId, invitation.UserProfile.NickName, invitation.UserProfile.Avatar
, invitation.GroupId, invitation.GroupProfile.GroupName, invitation.GroupProfile.Avatar, invitation.OperatorId
, invitation.OperatorProfile.NickName, invitation.OperatorProfile.Avatar
), cancellationToken);
if (!res.Succeeded)
{
throw new EventHandlerException(res.Message);
}
}
public async Task Handle(GroupInvitationCreateDomainEvent notification, CancellationToken cancellationToken)
{
var invitation = notification.Invitation;
await endpoint.Publish(new GroupInvitationCreateEvent(invitation.Id, invitation.UserId, invitation.UserProfile.NickName, invitation.UserProfile.Avatar
, invitation.GroupId, invitation.GroupProfile.GroupName, invitation.GroupProfile.Avatar, invitation.OperatorId
, invitation.OperatorProfile.NickName, invitation.OperatorProfile.Avatar), cancellationToken);
}
}
}
@@ -0,0 +1,25 @@
using GroupService.Domain.Events;
using IM.Commons.IntegrationEvents;
using MassTransit;
using MediatR;
namespace GroupService.WebApi.Application.EventHandler
{
public class GroupMemberJoinedHandler : INotificationHandler<GroupMemberJoinedDomainEvent>
{
private readonly IPublishEndpoint endpoint;
public GroupMemberJoinedHandler(IPublishEndpoint endpoint)
{
this.endpoint = endpoint;
}
public async Task Handle(GroupMemberJoinedDomainEvent notification, CancellationToken cancellationToken)
{
var member = notification.Member;
await endpoint.Publish(new GroupMemberJoinedEvent(member.Id,
member.UserId, member.GroupId, member.GroupNickName, member.Avatar,
member.Role.ToString()), cancellationToken);
}
}
}
@@ -0,0 +1,29 @@
using GroupService.Domain.Events;
using IM.Commons.IntegrationEvents;
using MassTransit;
using MediatR;
namespace GroupService.WebApi.Application.EventHandler
{
public class GroupRequestDeclinedHandler : INotificationHandler<GroupJoinRequestDeclinedDomainEvent>
{
private readonly IPublishEndpoint endpoint;
public GroupRequestDeclinedHandler(IPublishEndpoint endpoint)
{
this.endpoint = endpoint;
}
public async Task Handle(GroupJoinRequestDeclinedDomainEvent notification, CancellationToken cancellationToken)
{
var request = notification.Request;
await endpoint.Publish(new GroupRequestDeclinedEvent(
request.Id, request.GroupId, request.GroupProfile.GroupName,
request.GroupProfile.Avatar, request.UserId,
request.UserProfile.NickName, request.UserProfile.Avatar,
request.OperatorId.Value,request.OperatorName,
request.OperatorAvatar, request.Description,
request.CreationTime, request.ModificationTime.Value));
}
}
}
@@ -0,0 +1,46 @@
using GroupService.Domain.Events;
using GroupService.WebApi.Application.GroupMember;
using IM.Commons;
using IM.Commons.IntegrationEvents;
using MassTransit;
using MediatR;
namespace GroupService.WebApi.Application.EventHandler
{
public class GroupRequestPassedHandler : INotificationHandler<GroupJoinRequestPassedDomainEvent>
{
private readonly IPublishEndpoint endpoint;
private readonly Application.GroupMember.GroupMemberService memberService;
private readonly ILogger<GroupRequestPassedHandler> logger;
public GroupRequestPassedHandler(IPublishEndpoint endpoint,
GroupMemberService memberService, ILogger<GroupRequestPassedHandler> logger)
{
this.endpoint = endpoint;
this.memberService = memberService;
this.logger = logger;
}
public async Task Handle(GroupJoinRequestPassedDomainEvent notification, CancellationToken cancellationToken)
{
var request = notification.Request;
var memberCreateRes = await memberService.CreateAsync(request.GroupId, request.UserId);
await endpoint.Publish(new GroupRequestPassedEvent(request.Id, request.GroupId, request.GroupProfile.GroupName,
request.GroupProfile.Avatar, request.UserId,
request.UserProfile.NickName, request.UserProfile.Avatar,
request.OperatorId.Value, request.OperatorName,
request.OperatorAvatar, request.Description,
request.CreationTime, request.ModificationTime.Value));
if (!memberCreateRes.Succeeded)
{
logger.LogError(memberCreateRes.Message);
throw new EventHandlerException(memberCreateRes.Message);
}
}
}
}
@@ -0,0 +1,32 @@
using GroupService.Domain.IReposities;
using GroupService.Infrastructure;
using IM.Commons.IntegrationEvents;
using MassTransit;
namespace GroupService.WebApi.Application.EventHandler
{
public class MessageCreatedHandler : IConsumer<MsgCreatedEvent>
{
private readonly IGroupReposity reposity;
private readonly GroupDbContext groupDb;
public MessageCreatedHandler(IGroupReposity reposity, GroupDbContext groupDb)
{
this.reposity = reposity;
this.groupDb = groupDb;
}
public async Task Consume(ConsumeContext<MsgCreatedEvent> context)
{
var @event = context.Message;
if(@event.MsgType == "GROUP")
{
var group = await reposity.FindByIdAsync(@event.TargetId);
if (group is null) return;
group.UpdateLastMsg(@event.SequenceId, @event.Content.Fallback, "未知用户");
groupDb.Groups.Update(group);
await groupDb.SaveChangesAsync();
}
}
}
}
@@ -0,0 +1,31 @@
using GroupService.Domain.IReposities;
using GroupService.Infrastructure;
using IM.Commons.IntegrationEvents;
using MassTransit;
namespace GroupService.WebApi.Application.EventHandler
{
public class UserProfileUpdateHandler : IConsumer<UserProfileUpdateEvent>
{
private readonly GroupDbContext db;
private readonly IGroupMemberReposity memberReposity;
public UserProfileUpdateHandler(GroupDbContext db, IGroupMemberReposity memberReposity)
{
this.db = db;
this.memberReposity = memberReposity;
}
public async Task Consume(ConsumeContext<UserProfileUpdateEvent> context)
{
var @event = context.Message;
var members = await memberReposity.FindByUserIdAsync(@event.UserId);
foreach (var member in members)
{
member.UpdateAvatar(@event.Avatar);
}
await db.SaveChangesAsync();
}
}
}
@@ -0,0 +1,14 @@
namespace GroupService.WebApi.Application.Group
{
public class GroupCreateCommand
{
public Guid GroupMasterId { get; private set; }
public string? Name { get; private set; } = "新建群聊";
public GroupCreateCommand(Guid groupMasterId, string? name)
{
GroupMasterId = groupMasterId;
Name = name;
}
}
}
@@ -0,0 +1,18 @@
using AutoMapper;
using GroupService.WebApi.Application.Dtos;
namespace GroupService.WebApi.Application.Group
{
public class GroupMapperConfig : Profile
{
public GroupMapperConfig()
{
CreateMap<Domain.Entities.Group, GroupResponse>()
.ForMember(dest => dest.Created, opt => opt.MapFrom(src => src.CreationTime))
.ForMember(dest => dest.Updated, opt => opt.MapFrom(src => src.ModificationTime))
;
}
}
}
@@ -0,0 +1,43 @@
using AutoMapper;
using GroupService.Domain.IReposities;
using GroupService.WebApi.Application.Dtos;
using IM.Commons;
namespace GroupService.WebApi.Application.Group
{
public class GroupService
{
private readonly IGroupReposity reposity;
private readonly IMapper mapper;
public GroupService(IGroupReposity reposity, IMapper mapper)
{
this.reposity = reposity;
this.mapper = mapper;
}
public async Task<Result<GroupResponse>> CreateAsync(GroupCreateCommand command)
{
var group = new Domain.Entities.Group(command.GroupMasterId, command.Name);
reposity.Create(group);
return Result<GroupResponse>.Success(mapper.Map<GroupResponse>(group));
}
public async Task<Result<List<GroupResponse>>> GetAllAsync(Guid userId)
{
var groups = await reposity.FindByMasterIdAsync(userId);
return Result<List<GroupResponse>>.Success(mapper.Map<List<GroupResponse>>(groups));
}
public async Task<Result<GroupResponse>> GetByIdAsync(Guid groupId)
{
var group = await reposity.FindByIdAsync(groupId);
if (group is null)
{
return Result<GroupResponse>.Fail(ResultCode.GROUP_NOT_FOUND);
}
return Result<GroupResponse>.Success(mapper.Map<GroupResponse>(group));
}
}
}
@@ -0,0 +1,9 @@
namespace GroupService.WebApi.Application.GroupInvitation
{
public record GroupInvitationHandleCommand(Guid InvitationId, Guid UserId, GroupInvitationAction Action);
public enum GroupInvitationAction
{
Accept = 0,
Reject = 1
}
}
@@ -0,0 +1,21 @@
using AutoMapper;
using GroupService.WebApi.Application.Dtos;
namespace GroupService.WebApi.Application.GroupInvitation
{
public class GroupInvitationMapperConfig : Profile
{
public GroupInvitationMapperConfig()
{
CreateMap<Domain.Entities.GroupInvitation, GroupInvitationResponse>()
.ForMember(dest => dest.Created, opt => opt.MapFrom(src => src.CreationTime))
.ForMember(dest => dest.Updated, opt => opt.MapFrom(src => src.ModificationTime))
.ForMember(dest => dest.GroupAvatar, opt => opt.MapFrom(src => src.GroupProfile.Avatar))
.ForMember(dest => dest.GroupName, opt => opt.MapFrom(src => src.GroupProfile.GroupName))
.ForMember(dest => dest.UserNickName, opt => opt.MapFrom(src => src.UserProfile.NickName))
.ForMember(dest => dest.UserAvatar, opt => opt.MapFrom(src => src.UserProfile.Avatar))
.ForMember(dest => dest.OperatorAvatar, opt => opt.MapFrom(src => src.OperatorProfile.Avatar))
.ForMember(dest => dest.OperatorName, opt => opt.MapFrom(src => src.OperatorProfile.NickName));
}
}
}
@@ -0,0 +1,101 @@
using AutoMapper;
using GroupService.Domain.IReposities;
using GroupService.Domain.ValueObjects;
using GroupService.WebApi.Application.Dtos;
using GroupService.WebApi.Application.IntegrationServices;
using IM.Commons;
namespace GroupService.WebApi.Application.GroupInvitation
{
public class GroupInvitationService
{
private readonly IGroupInvitationReposity reposity;
private readonly IGroupMemberReposity memberReposity;
private readonly IIdentityIntegrationService idService;
private readonly IGroupReposity groupReposity;
private readonly IMapper mapper;
public GroupInvitationService(IGroupInvitationReposity reposity, IGroupMemberReposity memberReposity, IIdentityIntegrationService idService, IGroupReposity groupReposity, IMapper mapper)
{
this.reposity = reposity;
this.memberReposity = memberReposity;
this.idService = idService;
this.groupReposity = groupReposity;
this.mapper = mapper;
}
public async Task<Result<GroupInvitationResponse>> CreateAsync(Guid operatorId, Guid userId, Guid groupId)
{
var userRes = await idService.FindUserByIdAsync(userId);
if (!userRes.Succeeded)
{
return Result<GroupInvitationResponse>.Fail(userRes);
}
var operatorInfo = await idService.FindUserByIdAsync(operatorId);
var member = await memberReposity.FindOneByGroupIdAndUserIdAsync(groupId, operatorId);
if (member == null)
{
return Result.Fail<GroupInvitationResponse>(ResultCode.PERMISSION_DENIED);
}
var group = await groupReposity.FindByIdAsync(groupId);
var userProfile = new UserProfile()
{
Avatar = userRes.Data.Avatar,
NickName = userRes.Data.NickName
};
var operatorProfile = new UserProfile()
{
Avatar = operatorInfo.Data.Avatar,
NickName = operatorInfo.Data.NickName
};
var groupProfile = new GroupProfile()
{
Avatar = group.Avatar,
GroupName = group.Name
};
var invitation = new Domain.Entities.GroupInvitation(groupId, groupProfile, userId, userProfile
, operatorId, operatorProfile);
reposity.Create(invitation);
return Result.Success(mapper.Map<GroupInvitationResponse>(invitation));
}
public async Task<Result<object>> HandleAsync(GroupInvitationHandleCommand command)
{
var invitation = await reposity.FindByIdAsync(command.InvitationId);
if (invitation is null || invitation.UserId != command.UserId)
{
return Result.Fail(ResultCode.GROUP_INVITE_EXPIRED);
}
if (command.Action == GroupInvitationAction.Accept)
{
invitation.Accept();
}
else if (command.Action == GroupInvitationAction.Reject)
{
invitation.Reject();
}
return Result.Success();
}
public async Task<Result<GroupInvitationResponse>> GetByIdAsync(Guid id, Guid userId)
{
var invitation = await reposity.FindByIdAsync(id);
if (invitation is null || (invitation.UserId != userId && invitation.OperatorId != userId))
{
return Result.Fail<GroupInvitationResponse>(ResultCode.GROUP_INVITE_EXPIRED);
}
return Result.Success(mapper.Map<GroupInvitationResponse>(invitation));
}
}
}
@@ -0,0 +1,14 @@
using AutoMapper;
using GroupService.WebApi.Application.Dtos;
namespace GroupService.WebApi.Application.GroupMember
{
public class GroupMemberMapperConfig : Profile
{
public GroupMemberMapperConfig()
{
CreateMap<Domain.Entities.GroupMember, GroupMemberResponse>()
.ForMember(dest => dest.Created, opt => opt.MapFrom(src => src.CreationTime));
}
}
}
@@ -0,0 +1,91 @@
using AutoMapper;
using GroupService.Domain;
using GroupService.Domain.IReposities;
using GroupService.WebApi.Application.Dtos;
using GroupService.WebApi.Application.IntegrationServices;
using IM.Commons;
namespace GroupService.WebApi.Application.GroupMember
{
public class GroupMemberService
{
private readonly IGroupMemberReposity reposity;
private readonly IGroupReposity groupReposity;
private readonly GroupMemberDomainService service;
private readonly IIdentityIntegrationService idService;
private IMapper mapper;
public GroupMemberService(IGroupMemberReposity reposity, IGroupReposity groupReposity, GroupMemberDomainService service, IIdentityIntegrationService idService, IMapper mapper)
{
this.reposity = reposity;
this.groupReposity = groupReposity;
this.service = service;
this.idService = idService;
this.mapper = mapper;
}
public async Task<Result<List<GroupMemberResponse>>> GetByGroupIdAsync(Guid groupId)
{
var group = await groupReposity.FindByIdAsync(groupId);
if (group is null)
{
return Result<List<GroupMemberResponse>>.Fail(ResultCode.GROUP_NOT_FOUND);
}
var members = await reposity.FindByGroupIdAsync(groupId);
return Result<List<GroupMemberResponse>>.Success(mapper.Map<List<GroupMemberResponse>>(members.ToList()));
}
public async Task<Result<GroupMemberResponse>> CreateAsync(Guid groupId, Guid userId)
{
var group = await groupReposity.FindByIdAsync(groupId);
if (group is null)
{
return Result<GroupMemberResponse>.Fail(ResultCode.GROUP_NOT_FOUND);
}
var userRes = await idService.FindUserByIdAsync(userId);
if (!userRes.Succeeded)
{
return Result<GroupMemberResponse>.Fail(userRes);
}
var memberRes = await service.CreateAsync(userId, groupId, userRes.Data.NickName, userRes.Data.Avatar);
if (!memberRes.Succeeded)
{
return Result<GroupMemberResponse>.Fail(userRes);
}
return Result<GroupMemberResponse>.Success(mapper.Map<GroupMemberResponse>(memberRes.Data));
}
public async Task<Result<bool>> CheckMemberAsync(Guid groupId, Guid userId)
{
var exist = await reposity.CheckMemberExistAsync(groupId, userId);
return Result.Success(exist);
}
public async Task<Result<object>> DeleteAsync(Guid memberId, Guid operatorId)
{
var member = await reposity.FindByIdAsync(memberId);
if (member is null)
{
return Result.Fail(ResultCode.GROUP_MEMBER_NOT_FOUNT);
}
var operatorMember = await reposity.FindOneByGroupIdAndUserIdAsync(member.GroupId, operatorId);
if (operatorMember is null || operatorMember.Role == Domain.Enums.GroupMemberRole.Normal)
{
return Result.Fail(ResultCode.PERMISSION_DENIED);
}
member.SoftDelete();
return Result.Success();
}
}
}
@@ -0,0 +1,22 @@
using AutoMapper;
using GroupService.Domain.Entities;
using GroupService.WebApi.Application.Dtos;
namespace GroupService.WebApi.Application.GroupRequest
{
public class GroupRequestMapperConfig : Profile
{
public GroupRequestMapperConfig()
{
CreateMap<GroupJoinRequest, GroupRequestResponse>()
.ForMember(dest => dest.Created, opt => opt.MapFrom(src => src.CreationTime))
.ForMember(dest => dest.Updated, opt => opt.MapFrom(src => src.ModificationTime))
.ForMember(dest => dest.GroupAvatar, opt => opt.MapFrom(src => src.GroupProfile.Avatar))
.ForMember(dest => dest.GroupName, opt => opt.MapFrom(src => src.GroupProfile.GroupName))
.ForMember(dest => dest.UserNickName, opt => opt.MapFrom(src => src.UserProfile.NickName))
.ForMember(dest => dest.UserAvatar, opt => opt.MapFrom(src => src.UserProfile.Avatar))
.ForMember(dest => dest.OperatorAvatar, opt => opt.MapFrom(src => src.OperatorAvatar))
.ForMember(dest => dest.OperatorName, opt => opt.MapFrom(src => src.OperatorName));
}
}
}
@@ -0,0 +1,101 @@
using AutoMapper;
using GroupService.Domain.Entities;
using GroupService.Domain.IReposities;
using GroupService.Domain.ValueObjects;
using GroupService.WebApi.Application.Dtos;
using GroupService.WebApi.Application.IntegrationServices;
using IM.Commons;
namespace GroupService.WebApi.Application.GroupRequest
{
public class GroupRequestService
{
private readonly IGroupRequestReposity reposity;
private readonly IGroupReposity groupReposity;
private readonly IMapper mapper;
private readonly IGroupMemberReposity memberReposity;
private readonly IIdentityIntegrationService idService;
public GroupRequestService(IGroupRequestReposity reposity, IGroupReposity groupReposity, IMapper mapper, IGroupMemberReposity memberReposity, IIdentityIntegrationService idService)
{
this.reposity = reposity;
this.groupReposity = groupReposity;
this.mapper = mapper;
this.memberReposity = memberReposity;
this.idService = idService;
}
public async Task<Result<GroupRequestResponse>> CreateAsync(Guid groupId, Guid userId, string? desc)
{
var group = await groupReposity.FindByIdAsync(groupId);
if (group == null)
{
return Result.Fail<GroupRequestResponse>(ResultCode.GROUP_NOT_FOUND);
}
var user = await idService.FindUserByIdAsync(userId);
var groupProfile = new GroupProfile()
{
Avatar = group.Avatar,
GroupName = group.Name
};
var userProfile = new UserProfile()
{
Avatar = user.Data.Avatar,
NickName = user.Data.NickName
};
var request = new GroupJoinRequest(userId,userProfile, groupId, groupProfile, desc);
reposity.Create(request);
if (group.Authority == Domain.Enums.GroupAuthorityType.ANYONE_CAN_JOIN)
{
request.Approve(user.Data.Id, user.Data.NickName, user.Data.Avatar);
}
return Result.Success(mapper.Map<GroupRequestResponse>(request));
}
public async Task<Result<object>> HandleAsync(RequestHandleCommand command)
{
var request = await reposity.FindByIdAsync(command.RequestId);
if (request is null)
{
return Result.Fail<object>(ResultCode.GROUP_REQUEST_NOT_FOUND);
}
var member = await memberReposity.FindOneByGroupIdAndUserIdAsync(request.GroupId, command.UserId);
if (member is null || member.Role == Domain.Enums.GroupMemberRole.Normal)
{
return Result.Fail<object>(ResultCode.PERMISSION_DENIED);
}
if (command.Action == RequestHandleAction.Accept)
{
request.Approve(member.UserId, member.GroupNickName, member.Avatar);
}
else if (command.Action == RequestHandleAction.Reject)
{
request.Decline(member.UserId, member.GroupNickName, member.Avatar);
}
return Result.Success();
}
public async Task<Result<GroupRequestResponse>> GetByIdAsync(Guid id, Guid userId)
{
var request = await reposity.FindByIdAsync(id);
if (request is null || (request.UserId != userId && request.OperatorId != userId))
{
return Result.Fail<GroupRequestResponse>(ResultCode.GROUP_REQUEST_NOT_FOUND);
}
return Result.Success(mapper.Map<GroupRequestResponse>(request));
}
}
}
@@ -0,0 +1,9 @@
namespace GroupService.WebApi.Application.GroupRequest
{
public record RequestHandleCommand(Guid RequestId, Guid UserId, RequestHandleAction Action);
public enum RequestHandleAction
{
Accept = 0,
Reject = 1
}
}
@@ -0,0 +1,46 @@
using GroupService.WebApi.Application.Dtos;
using Grpc.Core;
using IM.Commons;
using IM.Protocols.Grpc.User;
namespace GroupService.WebApi.Application.IntegrationServices
{
public class IDentityIntegrationService : IIdentityIntegrationService
{
private readonly UserInternal.UserInternalClient client;
public IDentityIntegrationService(UserInternal.UserInternalClient client)
{
this.client = client;
}
public async Task<Result<UserInfoDto>> FindUserByIdAsync(Guid id)
{
try
{
var response = await client.GetUserInfoAsyncAsync(new GetUserInfoRequest()
{
UserId = id.ToString()
});
return Result.Success(new UserInfoDto()
{
Avatar = response.Avatar,
CreationTime = response.CreationTime.ToDateTimeOffset(),
Deletion = response.Deletion.ToDateTimeOffset(),
Description = response.Description,
Email = response.Email,
Id = Guid.Parse(response.Id),
NickName = response.NickName,
Phone = response.Phone,
Region = response.Region,
UserName = response.UserName
});
}catch(RpcException e)
{
return Result.Fail<UserInfoDto>(ResultCode.USER_NOT_FOUND);
}
}
}
}
@@ -0,0 +1,10 @@
using GroupService.WebApi.Application.Dtos;
using IM.Commons;
namespace GroupService.WebApi.Application.IntegrationServices
{
public interface IIdentityIntegrationService
{
Task<Result<UserInfoDto>> FindUserByIdAsync(Guid id);
}
}