添加项目文件。
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<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="..\ContactService.Domain\ContactService.Domain.csproj" />
|
||||
<ProjectReference Include="..\ContactService.Infrastructure\ContactService.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,7 @@
|
||||
@ContactService.WebApi_HostAddress = http://localhost:5294
|
||||
|
||||
GET {{ContactService.WebApi_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
###
|
||||
|
||||
GET {{ContactService.WebApi_HostAddress}}
|
||||
@@ -0,0 +1,55 @@
|
||||
using ContactService.Infrastructure;
|
||||
using ContactService.WebApi.Application.Dtos;
|
||||
using ContactService.WebApi.Application.Friend;
|
||||
using IM.ASPNETCore;
|
||||
using IM.Commons;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace ContactService.WebApi.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class FriendController : ControllerBase
|
||||
{
|
||||
private readonly FriendService service;
|
||||
|
||||
public FriendController(FriendService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesDefaultResponseType(typeof(Result<FriendResonse>))]
|
||||
public async Task<IActionResult> List()
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
var friends = await service.GetFriendsByOwnerIdAsync(Guid.Parse(userId));
|
||||
return Ok(friends);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(ContactDbContext))]
|
||||
public async Task<IActionResult> Delete([FromQuery] Guid friendId)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.DeleteFriendAsync(Guid.Parse(userId), friendId));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(ContactDbContext))]
|
||||
public async Task<IActionResult> Block([FromQuery] Guid friendId)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.BlockFriendAsync(Guid.Parse(userId), friendId));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> CheckFriend(Guid userId, Guid targetId)
|
||||
{
|
||||
return Ok(await service.CheckFriendAsync(userId, targetId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace ContactService.WebApi.Controllers
|
||||
{
|
||||
public class FriendRequestAddRequest
|
||||
{
|
||||
public Guid TargetId { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? RemarkName { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class FriendRequestAddRequestValidator : AbstractValidator<FriendRequestAddRequest>
|
||||
{
|
||||
public FriendRequestAddRequestValidator()
|
||||
{
|
||||
RuleFor(r => r.TargetId)
|
||||
.NotEmpty()
|
||||
.NotNull()
|
||||
;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using ContactService.Infrastructure;
|
||||
using ContactService.WebApi.Application.Dtos;
|
||||
using ContactService.WebApi.Application.FriendRequest;
|
||||
using IM.ASPNETCore;
|
||||
using IM.Commons;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace ContactService.WebApi.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class FriendRequestController : ControllerBase
|
||||
{
|
||||
private readonly FriendRequestService service;
|
||||
|
||||
public FriendRequestController(FriendRequestService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(ContactDbContext))]
|
||||
[ProducesDefaultResponseType(typeof(Result<FriendRequestResponse?>))]
|
||||
public async Task<IActionResult> Add(FriendRequestAddRequest request)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.CreateAsync(new CreateFriendRequestCommand(Guid.Parse(userId), request.TargetId, request.Description, request.RemarkName)));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[UnitOfWork(typeof(ContactDbContext))]
|
||||
public async Task<IActionResult> Handle(FriendRequestHandleRequest request)
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.UpdateStatusAsync(new FriendRequestHandleCommand(Guid.Parse(userId), request.RequestId, request.Action,request.RemarkName)));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> List()
|
||||
{
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Ok(await service.GetByTargetIdOrOwnerIdAsync(Guid.Parse(userId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using ContactService.WebApi.Application.FriendRequest;
|
||||
using FluentValidation;
|
||||
|
||||
namespace ContactService.WebApi.Controllers
|
||||
{
|
||||
public class FriendRequestHandleRequest
|
||||
{
|
||||
public Guid RequestId { get; set; }
|
||||
public FriendRequestAction Action { get; set; }
|
||||
public string? RemarkName { get; set; }
|
||||
}
|
||||
|
||||
public class FriendRequestHandleRequestValidator : AbstractValidator<FriendRequestHandleRequest>
|
||||
{
|
||||
public FriendRequestHandleRequestValidator()
|
||||
{
|
||||
RuleFor(r => r.RequestId)
|
||||
.NotEmpty()
|
||||
.NotNull();
|
||||
|
||||
When(w => w.Action == FriendRequestAction.Accpet, () =>
|
||||
{
|
||||
RuleFor(r => r.RemarkName)
|
||||
.NotEmpty()
|
||||
.NotNull();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using ContactService.Infrastructure;
|
||||
using IM.InitCommon;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
|
||||
namespace ContactService.WebApi
|
||||
{
|
||||
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ContactDbContext>
|
||||
{
|
||||
public ContactDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
// 1. 复用你写好的配置工厂,提取连接字符串
|
||||
var optionsBuilder = DbContextOptionsBuilderFactory.Create<ContactDbContext>();
|
||||
|
||||
// 2. 🌟 关键补刀:把假的 Mediator 传进去,满足构造函数的要求!
|
||||
return new ContactDbContext(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 ContactService.WebApi/ContactService.WebApi.csproj ContactService.WebApi/
|
||||
COPY ContactService.Domain/ContactService.Domain.csproj ContactService.Domain/
|
||||
COPY ContactService.Infrastructure/ContactService.Infrastructure.csproj ContactService.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 ContactService.WebApi/ContactService.WebApi.csproj
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN dotnet publish ContactService.WebApi/ContactService.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", "ContactService.WebApi.dll"]
|
||||
@@ -0,0 +1,24 @@
|
||||
using ContactService.WebApi.Application.Friend;
|
||||
using ContactService.WebApi.Application.FriendRequest;
|
||||
using ContactService.WebApi.Application.IntegrationServices;
|
||||
using IM.Commons;
|
||||
using IM.Protocols.Grpc.User;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ContactService.WebApi
|
||||
{
|
||||
public class ModuleInit : IModuleInitializer
|
||||
{
|
||||
public void Initialize(IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<FriendService>();
|
||||
services.AddScoped<FriendRequestService>();
|
||||
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,42 @@
|
||||
|
||||
using IM.InitCommon;
|
||||
|
||||
namespace ContactService.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();
|
||||
|
||||
builder.Services.AddAllGrpcServer();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseAppDefault();
|
||||
|
||||
|
||||
app.MapControllers();
|
||||
app.MapAllGrpcServer();
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "http://localhost:5294"
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "https://localhost:7242;http://localhost:5294"
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
},
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:46536",
|
||||
"sslPort": 44317
|
||||
}
|
||||
},
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iissettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:53560/",
|
||||
"sslPort": 44389
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using ContactService.WebApi.Application.Friend;
|
||||
using Grpc.Core;
|
||||
using IM.Protocols.Grpc.Contact;
|
||||
|
||||
namespace ContactService.WebApi.Services
|
||||
{
|
||||
public class ContactintegrationService: ContactInternal.ContactInternalBase
|
||||
{
|
||||
private readonly Application.Friend.FriendService friendService;
|
||||
|
||||
public ContactintegrationService(FriendService friendService)
|
||||
{
|
||||
this.friendService = friendService;
|
||||
}
|
||||
|
||||
public override async Task<CheckFriendshipResponse> CheckFriendship(CheckFriendshipRequest request, ServerCallContext context)
|
||||
{
|
||||
var response = new CheckFriendshipResponse();
|
||||
var res = await friendService.CheckFriendAsync(
|
||||
Guid.Parse(request.OwnerId),
|
||||
Guid.Parse(request.TargetId)
|
||||
);
|
||||
|
||||
if(res.Succeeded && res.Data)
|
||||
{
|
||||
response.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.Checked = false;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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