添加项目文件。
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
using ContactService.Domain;
|
||||
|
||||
namespace ContactService.WebApi.Application.Dtos
|
||||
{
|
||||
public class FriendRequestResponse
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
/// <summary>
|
||||
/// 申请人
|
||||
/// </summary>
|
||||
public Guid OwnerId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 被申请人
|
||||
/// </summary>
|
||||
public Guid TargetId { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 申请附言
|
||||
/// </summary>
|
||||
public string Description { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 申请状态(0:待通过,1:拒绝,2:同意,3:拉黑)
|
||||
/// </summary>
|
||||
public FriendRequestStatus State { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? RemarkName { get; private set; }
|
||||
public DateTimeOffset CreationTime { get; private set; }
|
||||
public DateTimeOffset? Deletion { get; private set; }
|
||||
|
||||
public DateTimeOffset? ModificationTime { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using ContactService.Domain;
|
||||
|
||||
namespace ContactService.WebApi.Application.Dtos
|
||||
{
|
||||
public class FriendResonse
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public Guid TargetId { get; private set; }
|
||||
public string? Avatar { get; private set; }
|
||||
public string NickName { get; private set; }
|
||||
/// <summary>
|
||||
/// 好友备注名
|
||||
/// </summary>
|
||||
public string? RemarkName { get; private set; }
|
||||
|
||||
public DateTime CreateTime { get; private set; }
|
||||
public DateTime? UpdateTime { get; private set; }
|
||||
public FriendStatus Status { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace ContactService.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,32 @@
|
||||
using ContactService.Domain.Events;
|
||||
using IM.Commons.IntegrationEvents;
|
||||
using MassTransit;
|
||||
using MediatR;
|
||||
|
||||
namespace ContactService.WebApi.Application.EventHandler
|
||||
{
|
||||
public class FriendAddedHandler : INotificationHandler<FriendAddedDomainEvent>
|
||||
{
|
||||
private readonly IPublishEndpoint endpoint;
|
||||
|
||||
public FriendAddedHandler(IPublishEndpoint endpoint)
|
||||
{
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
public async Task Handle(FriendAddedDomainEvent notification, CancellationToken cancellationToken)
|
||||
{
|
||||
await endpoint.Publish(new FriendAddedEvent
|
||||
{
|
||||
OwnerAvatar = notification.Friend.Owner.Avatar,
|
||||
OwnerId = notification.Friend.Owner.Id,
|
||||
OwnerNickName = notification.Friend.Owner.NickName,
|
||||
TargetAvatar = notification.Friend.Target.Avatar,
|
||||
TargetId = notification.Friend.Target.Id,
|
||||
TargetNickName = notification.Friend.Target.NickName,
|
||||
RemarkName = notification.Friend.RemarkName,
|
||||
Status = notification.Friend.Status.ToString(),
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using ContactService.Domain;
|
||||
using ContactService.Domain.Events;
|
||||
using ContactService.Domain.ValueObjects;
|
||||
using ContactService.Infrastructure;
|
||||
using ContactService.WebApi.Application.IntegrationServices;
|
||||
using IM.Commons.IntegrationEvents;
|
||||
using MassTransit;
|
||||
using MediatR;
|
||||
|
||||
namespace ContactService.WebApi.Application.EventHandler
|
||||
{
|
||||
public class FriendRequestStatusUpdateHandler : INotificationHandler<FriendRequestStateUpdateDomainEvent>
|
||||
{
|
||||
private readonly FriendDomainService friendService;
|
||||
private readonly ContactDbContext contactDb;
|
||||
private readonly IPublishEndpoint endpoint;
|
||||
private readonly IIdentityIntegrationService idService;
|
||||
|
||||
public FriendRequestStatusUpdateHandler(FriendDomainService friendService, ContactDbContext contactDb, IPublishEndpoint endpoint, IIdentityIntegrationService idService)
|
||||
{
|
||||
this.friendService = friendService;
|
||||
this.contactDb = contactDb;
|
||||
this.endpoint = endpoint;
|
||||
this.idService = idService;
|
||||
}
|
||||
|
||||
public async Task Handle(FriendRequestStateUpdateDomainEvent notification, CancellationToken cancellationToken)
|
||||
{
|
||||
var @event = notification.Request;
|
||||
if (@event.State == FriendRequestStatus.Passed)
|
||||
{
|
||||
var ownerInfo = await idService.FindUserByIdAsync(@event.OwnerId);
|
||||
var targetInfo = await idService.FindUserByIdAsync(@event.TargetId);
|
||||
|
||||
if (!ownerInfo.Succeeded || !targetInfo.Succeeded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ownerProfile = new UserProfile(ownerInfo.Data.Id, ownerInfo.Data.NickName, ownerInfo.Data.Avatar);
|
||||
var targetProfile = new UserProfile(targetInfo.Data.Id, targetInfo.Data.NickName, targetInfo.Data.Avatar);
|
||||
|
||||
await friendService.CreateAsync(ownerProfile, targetProfile, @event.RemarkName);
|
||||
await friendService.CreateAsync(targetProfile, ownerProfile, notification.AcceptRemarkName);
|
||||
await contactDb.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
await endpoint.Publish(new FriendRequestStateUpdateEvent
|
||||
{
|
||||
CorrelationId = @event.TargetId,
|
||||
Description = @event.Description,
|
||||
OwnerId = @event.OwnerId,
|
||||
RemarkName = @event.RemarkName,
|
||||
State = @event.State.ToString()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using ContactService.Domain;
|
||||
using ContactService.Infrastructure;
|
||||
using IM.Commons.IntegrationEvents;
|
||||
using MassTransit;
|
||||
|
||||
namespace ContactService.WebApi.Application.EventHandler
|
||||
{
|
||||
public class UserProfileUpdateHandler : IConsumer<UserProfileUpdateEvent>
|
||||
{
|
||||
private readonly ContactDbContext contactDb;
|
||||
private readonly IFriendReposity reposity;
|
||||
|
||||
public UserProfileUpdateHandler(ContactDbContext contactDb, IFriendReposity reposity)
|
||||
{
|
||||
this.contactDb = contactDb;
|
||||
this.reposity = reposity;
|
||||
}
|
||||
|
||||
public async Task Consume(ConsumeContext<UserProfileUpdateEvent> context)
|
||||
{
|
||||
var @event = context.Message;
|
||||
var friends = await reposity.FindByTargetAsync(@event.UserId);
|
||||
|
||||
foreach (var friend in friends)
|
||||
{
|
||||
friend.UpdateUserInfo(
|
||||
new Domain.ValueObjects.UserProfile(
|
||||
@event.UserId, @event.Avatar, @event.NickName));
|
||||
}
|
||||
|
||||
await contactDb.SaveChangesAsync();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using AutoMapper;
|
||||
using ContactService.WebApi.Application.Dtos;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace ContactService.WebApi.Application.Friend
|
||||
{
|
||||
public class FriendMapperConfig : Profile
|
||||
{
|
||||
public FriendMapperConfig()
|
||||
{
|
||||
CreateMap<Domain.Entities.Friend, FriendResonse>()
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(dest => dest.Avatar, opt => opt.MapFrom(src => src.Target.Avatar))
|
||||
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status))
|
||||
.ForMember(dest => dest.UpdateTime, opt => opt.MapFrom(src => src.ModificationTime.Value.DateTime))
|
||||
.ForMember(dest => dest.CreateTime, opt => opt.MapFrom(src => src.CreationTime.DateTime))
|
||||
.ForMember(dest => dest.NickName, opt => opt.MapFrom(src => src.Target.NickName))
|
||||
.ForMember(dest => dest.RemarkName, opt => opt.MapFrom(src => src.RemarkName))
|
||||
.ForMember(dest => dest.TargetId, opt => opt.MapFrom(src => src.Target.Id))
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using AutoMapper;
|
||||
using ContactService.Domain;
|
||||
using ContactService.WebApi.Application.Dtos;
|
||||
using ContactService.WebApi.Application.IntegrationServices;
|
||||
using IM.Commons;
|
||||
|
||||
namespace ContactService.WebApi.Application.Friend
|
||||
{
|
||||
public class FriendService
|
||||
{
|
||||
private readonly IFriendReposity reposity;
|
||||
private readonly FriendDomainService service;
|
||||
private readonly IIdentityIntegrationService idService;
|
||||
private readonly IMapper mapper;
|
||||
|
||||
public FriendService(IFriendReposity reposity, FriendDomainService service
|
||||
, IIdentityIntegrationService idService, IMapper mapper
|
||||
)
|
||||
{
|
||||
this.reposity = reposity;
|
||||
this.service = service;
|
||||
this.idService = idService;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<Result<List<FriendResonse>>> GetFriendsByOwnerIdAsync(Guid ownerId)
|
||||
{
|
||||
IEnumerable<Domain.Entities.Friend> friend = await reposity.FindByOwnerAsync(ownerId);
|
||||
return Result<List<FriendResonse>>.Success(mapper.Map<List<FriendResonse>>(friend.ToList()));
|
||||
}
|
||||
|
||||
public async Task<Result<object>> DeleteFriendAsync(Guid userId, Guid friendId)
|
||||
{
|
||||
var friend = await reposity.FindByIdAsync(friendId);
|
||||
if (friend is null)
|
||||
{
|
||||
return Result<object>.Fail(ResultCode.FRIEND_RELATION_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (friend.Owner.Id != userId)
|
||||
{
|
||||
return Result<object>.Fail(ResultCode.FRIEND_RELATION_NOT_FOUND);
|
||||
}
|
||||
|
||||
friend.SoftDelete();
|
||||
|
||||
return Result<object>.Success();
|
||||
}
|
||||
|
||||
public async Task<Result<object>> BlockFriendAsync(Guid userId, Guid friendId)
|
||||
{
|
||||
var friend = await reposity.FindByIdAsync(friendId);
|
||||
if (friend is null)
|
||||
{
|
||||
return Result<object>.Fail(ResultCode.FRIEND_RELATION_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (friend.Owner.Id != userId)
|
||||
{
|
||||
return Result<object>.Fail(ResultCode.PERMISSION_DENIED);
|
||||
}
|
||||
|
||||
friend.Block();
|
||||
return Result<object>.Success();
|
||||
}
|
||||
|
||||
public async Task<Result<bool>> CheckFriendAsync(Guid ownerId, Guid targetId)
|
||||
{
|
||||
var exist = await reposity.CheckOwnerIdAndTargetIdAsync(ownerId, targetId);
|
||||
return Result.Success(exist);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace ContactService.WebApi.Application.FriendRequest
|
||||
{
|
||||
public record CreateFriendRequestCommand
|
||||
{
|
||||
public Guid ownerId { get; private set; }
|
||||
public Guid targetId { get; private set; }
|
||||
public string? description { get; private set; }
|
||||
public string? remarkName { get; private set; }
|
||||
|
||||
public CreateFriendRequestCommand(Guid ownerId, Guid targetId, string? description, string? remarkName)
|
||||
{
|
||||
this.ownerId = ownerId;
|
||||
this.targetId = targetId;
|
||||
this.description = description;
|
||||
this.remarkName = remarkName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using AutoMapper;
|
||||
using ContactService.WebApi.Application.Dtos;
|
||||
|
||||
namespace ContactService.WebApi.Application.FriendRequest
|
||||
{
|
||||
public class FriendRequestConfig : Profile
|
||||
{
|
||||
public FriendRequestConfig()
|
||||
{
|
||||
CreateMap<Domain.Entities.FriendRequest, FriendRequestResponse>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace ContactService.WebApi.Application.FriendRequest
|
||||
{
|
||||
public class FriendRequestHandleCommand
|
||||
{
|
||||
public Guid UserId { get; private set; }
|
||||
public Guid RequestId { get; private set; }
|
||||
public FriendRequestAction Action { get; private set; }
|
||||
public string? RemarkName { get; set; }
|
||||
|
||||
public FriendRequestHandleCommand(Guid userId, Guid requestId, FriendRequestAction action, string? remarkName)
|
||||
{
|
||||
UserId = userId;
|
||||
RequestId = requestId;
|
||||
Action = action;
|
||||
RemarkName = remarkName;
|
||||
}
|
||||
}
|
||||
|
||||
public enum FriendRequestAction
|
||||
{
|
||||
Accpet = 0,
|
||||
Reject = 1,
|
||||
Block = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using AutoMapper;
|
||||
using ContactService.Domain;
|
||||
using ContactService.WebApi.Application.Dtos;
|
||||
using IM.Commons;
|
||||
|
||||
namespace ContactService.WebApi.Application.FriendRequest
|
||||
{
|
||||
public class FriendRequestService
|
||||
{
|
||||
private readonly IFriendRequestReposity reposity;
|
||||
private readonly FriendRequestDomainService service;
|
||||
private readonly IMapper mapper;
|
||||
|
||||
public FriendRequestService(IFriendRequestReposity reposity, FriendRequestDomainService service, IMapper mapper)
|
||||
{
|
||||
this.reposity = reposity;
|
||||
this.service = service;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<Result<FriendRequestResponse>> CreateAsync(CreateFriendRequestCommand command)
|
||||
{
|
||||
var request = await service.CreateAsync(command.ownerId, command.targetId, command.description, command.remarkName);
|
||||
if (!request.Succeeded)
|
||||
{
|
||||
return Result<FriendRequestResponse>.Fail(request);
|
||||
}
|
||||
return Result<FriendRequestResponse>.Success(mapper.Map<FriendRequestResponse>(request.Data));
|
||||
}
|
||||
|
||||
public async Task<Result<FriendRequestResponse>> UpdateStatusAsync(FriendRequestHandleCommand command)
|
||||
{
|
||||
var request = await reposity.FindByIdAsync(command.RequestId);
|
||||
if (request == null)
|
||||
{
|
||||
return Result<FriendRequestResponse>.Fail(ResultCode.FRIEND_REQUEST_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (request.TargetId != command.UserId)
|
||||
{
|
||||
return Result<FriendRequestResponse>.Fail(ResultCode.PERMISSION_DENIED);
|
||||
}
|
||||
|
||||
switch (command.Action)
|
||||
{
|
||||
case FriendRequestAction.Accpet:
|
||||
request.Accept(command.RemarkName);
|
||||
break;
|
||||
case FriendRequestAction.Block:
|
||||
request.Block();
|
||||
break;
|
||||
case FriendRequestAction.Reject:
|
||||
request.Reject();
|
||||
break;
|
||||
default:
|
||||
return Result<FriendRequestResponse>.Fail(ResultCode.PARAMETER_ERROR);
|
||||
}
|
||||
return Result<FriendRequestResponse>.Success(mapper.Map<FriendRequestResponse>(request));
|
||||
}
|
||||
|
||||
public async Task<Result<List<FriendRequestResponse>>> GetByOwnerIdAsync(Guid ownerId)
|
||||
{
|
||||
var requests = await reposity.FindByOwnerIdAsync(ownerId);
|
||||
return Result<List<FriendRequestResponse>>.Success(mapper.Map<List<FriendRequestResponse>>(requests));
|
||||
|
||||
}
|
||||
|
||||
public async Task<Result<List<FriendRequestResponse>>> GetByTargetIdAsync(Guid targetId)
|
||||
{
|
||||
var requests = await reposity.FindByTargetIdAsync(targetId);
|
||||
return Result<List<FriendRequestResponse>>.Success(mapper.Map<List<FriendRequestResponse>>(requests));
|
||||
}
|
||||
|
||||
public async Task<Result<List<FriendRequestResponse>>> GetByTargetIdOrOwnerIdAsync(Guid id)
|
||||
{
|
||||
var requests = await reposity.FindByTargetIdAsync(id);
|
||||
var requests2 = await reposity.FindByOwnerIdAsync(id);
|
||||
return Result<List<FriendRequestResponse>>.Success(mapper.Map<List<FriendRequestResponse>>(requests.Concat(requests2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using ContactService.WebApi.Application.Dtos;
|
||||
using IM.Commons;
|
||||
|
||||
namespace ContactService.WebApi.Application.IntegrationServices
|
||||
{
|
||||
public interface IIdentityIntegrationService
|
||||
{
|
||||
Task<Result<UserInfoDto>> FindUserByIdAsync(Guid id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using ContactService.WebApi.Application.Dtos;
|
||||
using Grpc.Core;
|
||||
using IM.Commons;
|
||||
using IM.Protocols.Grpc.User;
|
||||
|
||||
namespace ContactService.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)
|
||||
{
|
||||
var req = new GetUserInfoRequest()
|
||||
{
|
||||
UserId = id.ToString()
|
||||
};
|
||||
try
|
||||
{
|
||||
var res = await client.GetUserInfoAsyncAsync(req);
|
||||
return Result.Success(new UserInfoDto
|
||||
{
|
||||
Avatar = res.Avatar,
|
||||
CreationTime = res.CreationTime.ToDateTimeOffset(),
|
||||
Deletion = res.Deletion.ToDateTimeOffset(),
|
||||
Description = res.Description,
|
||||
Email = res.Email,
|
||||
Id = Guid.Parse(res.Id),
|
||||
NickName = res.NickName,
|
||||
Phone = res.Phone,
|
||||
Region = res.Region,
|
||||
UserName = res.UserName
|
||||
});
|
||||
}catch(RpcException e)
|
||||
{
|
||||
return Result.Fail<UserInfoDto>(ResultCode.USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user