添加项目文件。
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using GroupService.Infrastructure;
|
||||
using GroupService.WebApi.Application.Dtos;
|
||||
using GroupService.WebApi.Application.Group;
|
||||
using IM.ASPNETCore;
|
||||
using IM.Commons;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace GroupService.WebApi.Controllers.Group
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class GroupController : ControllerBase
|
||||
{
|
||||
private readonly Application.Group.GroupService service;
|
||||
|
||||
public GroupController(Application.Group.GroupService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesDefaultResponseType(typeof(Result<List<GroupResponse>>))]
|
||||
public async Task<IActionResult> GetAll()
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.GetAllAsync(Guid.Parse(userId)));
|
||||
}
|
||||
[HttpGet("~/api/[controller]/{userId}")]
|
||||
[ProducesDefaultResponseType(typeof(Result<GroupResponse>))]
|
||||
public async Task<IActionResult> GetOne([FromRoute] Guid userId)
|
||||
{
|
||||
return Ok(await service.GetByIdAsync(userId));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(GroupDbContext))]
|
||||
public async Task<IActionResult> Create(GroupCreateRequest request)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.CreateAsync(new GroupCreateCommand(Guid.Parse(userId), request.Name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace GroupService.WebApi.Controllers.Group
|
||||
{
|
||||
public class GroupCreateRequest
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
|
||||
public class GroupCreateRequestValidator : AbstractValidator<GroupCreateRequest>
|
||||
{
|
||||
public GroupCreateRequestValidator()
|
||||
{
|
||||
RuleFor(r => r.Name)
|
||||
.MaximumLength(20);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using GroupService.Infrastructure;
|
||||
using GroupService.WebApi.Application.GroupInvitation;
|
||||
using IM.ASPNETCore;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace GroupService.WebApi.Controllers.GroupInvitation
|
||||
{
|
||||
[Authorize]
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class GroupInvitationController : ControllerBase
|
||||
{
|
||||
private readonly GroupInvitationService service;
|
||||
|
||||
public GroupInvitationController(GroupInvitationService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(GroupDbContext))]
|
||||
public async Task<IActionResult> Send([FromBody] GroupInvitationRequest request)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.CreateAsync(Guid.Parse(userId), request.UserId, request.GroupId));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Get([FromQuery] Guid invitationId)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.GetByIdAsync(invitationId, Guid.Parse(userId)));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(GroupDbContext))]
|
||||
public async Task<IActionResult> Handle([FromQuery] Guid invitationId, [FromQuery] GroupInvitationAction action)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.HandleAsync(new GroupInvitationHandleCommand(invitationId, Guid.Parse(userId), action)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace GroupService.WebApi.Controllers.GroupInvitation
|
||||
{
|
||||
public class GroupInvitationRequest
|
||||
{
|
||||
public Guid GroupId { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
}
|
||||
|
||||
public class GroupInvitationRequestValidator : AbstractValidator<GroupInvitationRequest>
|
||||
{
|
||||
public GroupInvitationRequestValidator()
|
||||
{
|
||||
RuleFor(r => r.UserId)
|
||||
.NotNull()
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(r => r.GroupId)
|
||||
.NotEmpty()
|
||||
.NotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using GroupService.Infrastructure;
|
||||
using GroupService.WebApi.Application.GroupMember;
|
||||
using IM.ASPNETCore;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace GroupService.WebApi.Controllers.GroupMember
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class GroupMemberController : ControllerBase
|
||||
{
|
||||
private readonly GroupMemberService service;
|
||||
|
||||
public GroupMemberController(GroupMemberService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> CheckMember(Guid userId, Guid groupId)
|
||||
{
|
||||
return Ok(await service.CheckMemberAsync(groupId, userId));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> List(Guid groupId)
|
||||
{
|
||||
return Ok(await service.GetByGroupIdAsync(groupId));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(GroupDbContext))]
|
||||
public async Task<IActionResult> Delete([FromQuery] Guid memberId)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.DeleteAsync(memberId, Guid.Parse(userId)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using GroupService.Infrastructure;
|
||||
using GroupService.WebApi.Application.GroupRequest;
|
||||
using IM.ASPNETCore;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace GroupService.WebApi.Controllers.GroupRequest
|
||||
{
|
||||
[Authorize]
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class GroupRequestController : ControllerBase
|
||||
{
|
||||
private readonly GroupRequestService service;
|
||||
|
||||
public GroupRequestController(GroupRequestService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(GroupDbContext))]
|
||||
public async Task<IActionResult> Send([FromBody] GroupRequestRequest request)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.CreateAsync(request.GroupId, Guid.Parse(userId), request.Desc));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(GroupDbContext))]
|
||||
public async Task<IActionResult> Handle([FromQuery] Guid requestId, [FromQuery] RequestHandleAction action)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.HandleAsync(new RequestHandleCommand(requestId, Guid.Parse(userId), action)));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Find([FromQuery] Guid id)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.GetByIdAsync(id, Guid.Parse(userId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace GroupService.WebApi.Controllers.GroupRequest
|
||||
{
|
||||
public class GroupRequestRequest
|
||||
{
|
||||
public Guid GroupId { get; set; }
|
||||
public string? Desc { get; set; }
|
||||
}
|
||||
|
||||
public class GroupRequestRequestValidator : AbstractValidator<GroupRequestRequest>
|
||||
{
|
||||
public GroupRequestRequestValidator()
|
||||
{
|
||||
RuleFor(r => r.GroupId)
|
||||
.NotEmpty()
|
||||
.NotNull();
|
||||
|
||||
RuleFor(r => r.Desc)
|
||||
.MaximumLength(20)
|
||||
.WithMessage("入群描述不可超过20字符")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using GroupService.Infrastructure;
|
||||
using IM.InitCommon;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
|
||||
namespace ContactService.WebApi
|
||||
{
|
||||
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<GroupDbContext>
|
||||
{
|
||||
public GroupDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
// 1. 复用你写好的配置工厂,提取连接字符串
|
||||
var optionsBuilder = DbContextOptionsBuilderFactory.Create<GroupDbContext>();
|
||||
|
||||
// 2. 🌟 关键补刀:把假的 Mediator 传进去,满足构造函数的要求!
|
||||
return new GroupDbContext(optionsBuilder.Options, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
COPY IM_API_NEW.sln ./
|
||||
|
||||
COPY GroupService.WebApi/GroupService.WebApi.csproj GroupService.WebApi/
|
||||
COPY GroupService.Domain/GroupService.Domain.csproj GroupService.Domain/
|
||||
COPY GroupService.Infrastructure/GroupService.Infrastructure.csproj GroupService.Infrastructure/
|
||||
COPY DomainCommons/IM.DomainCommons.csproj DomainCommons/
|
||||
COPY Infrastructure/IM.Infrastructure.csproj Infrastructure/
|
||||
COPY IM.ASPNETCore/IM.ASPNETCore.csproj IM.ASPNETCore/
|
||||
COPY IM.Commons/IM.Commons.csproj IM.Commons/
|
||||
COPY IM.InitCommon/IM.InitCommon.csproj IM.InitCommon/
|
||||
COPY IM.Jwt/IM.Jwt.csproj IM.Jwt/
|
||||
COPY IM.Protocols/IM.Protocols.csproj IM.Protocols/
|
||||
|
||||
RUN dotnet restore GroupService.WebApi/GroupService.WebApi.csproj
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN dotnet publish GroupService.WebApi/GroupService.WebApi.csproj \
|
||||
-c Release \
|
||||
-o /app/publish \
|
||||
--no-restore
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
|
||||
WORKDIR /app
|
||||
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV ASPNETCORE_URLS=http://+:8080
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
COPY --from=build /app/publish .
|
||||
|
||||
ENTRYPOINT ["dotnet", "GroupService.WebApi.dll"]
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IM.Commons\IM.Commons.csproj" />
|
||||
<ProjectReference Include="..\GroupService.Infrastructure\GroupService.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\IM.ASPNETCore\IM.ASPNETCore.csproj" />
|
||||
<ProjectReference Include="..\IM.InitCommon\IM.InitCommon.csproj" />
|
||||
<ProjectReference Include="..\IM.Protocols\IM.Protocols.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,6 @@
|
||||
@GroupService.WebApi_HostAddress = http://localhost:5070
|
||||
|
||||
GET {{GroupService.WebApi_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
@@ -0,0 +1,27 @@
|
||||
using GroupService.WebApi.Application.GroupInvitation;
|
||||
using GroupService.WebApi.Application.GroupMember;
|
||||
using GroupService.WebApi.Application.GroupRequest;
|
||||
using GroupService.WebApi.Application.IntegrationServices;
|
||||
using IM.Commons;
|
||||
using IM.Protocols.Grpc.User;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace GroupService.WebApi
|
||||
{
|
||||
public class ModuleInit : IModuleInitializer
|
||||
{
|
||||
public void Initialize(IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<WebApi.Application.Group.GroupService>();
|
||||
services.AddScoped<GroupMemberService>();
|
||||
services.AddScoped<GroupRequestService>();
|
||||
services.AddScoped<GroupInvitationService>();
|
||||
services.AddScoped<IIdentityIntegrationService, IDentityIntegrationService>();
|
||||
services.AddGrpcClient<UserInternal.UserInternalClient>((sp, o) =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptionsMonitor<GrpcOptions>>();
|
||||
o.Address = new Uri(options.CurrentValue.IdentityServiceUrl);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
using IM.InitCommon;
|
||||
|
||||
namespace GroupService.WebApi
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.ConfigureDbConfiguration();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
builder.ConfigExtraServices();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseAppDefault();
|
||||
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "http://localhost:5070"
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "https://localhost:7205;http://localhost:5070"
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
},
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:24564",
|
||||
"sslPort": 44370
|
||||
}
|
||||
},
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iissettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:53562/",
|
||||
"sslPort": 44369
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
Reference in New Issue
Block a user