Merge pull request 'feature-nxdev' (#21) from feature-nxdev into main
Reviewed-on: #21
This commit is contained in:
commit
1d633c3909
20
backend/IM_API/Aggregate/FriendRequestAggregate.cs
Normal file
20
backend/IM_API/Aggregate/FriendRequestAggregate.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using IM_API.Models;
|
||||
|
||||
namespace IM_API.Aggregate
|
||||
{
|
||||
public class FriendRequestAggregate
|
||||
{
|
||||
public Friend Friend { get; private set; }
|
||||
public FriendRequest FriendRequest { get; private set; }
|
||||
public FriendRequestAggregate() { }
|
||||
public FriendRequestAggregate(Friend friend,FriendRequest friendRequest)
|
||||
{
|
||||
Friend = friend;
|
||||
FriendRequest = friendRequest;
|
||||
}
|
||||
public void Accept(string? remarkName = null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,6 +26,22 @@ namespace IM_API.Configs
|
||||
;
|
||||
//好友信息模型转换
|
||||
CreateMap<Friend, FriendInfoDto>();
|
||||
//好友请求通过后新增好友关系
|
||||
CreateMap<FriendRequest, Friend>()
|
||||
.ForMember(dest => dest.UserId , opt => opt.MapFrom(src => src.RequestUser))
|
||||
.ForMember(dest => dest.FriendId , opt => opt.MapFrom(src => src.ResponseUser))
|
||||
.ForMember(dest => dest.StatusEnum , opt =>opt.MapFrom(src => FriendStatus.Added))
|
||||
.ForMember(dest => dest.RemarkName , opt => opt.MapFrom(src => src.ResponseUserNavigation.NickName))
|
||||
.ForMember(dest => dest.Created , opt => opt.MapFrom(src => DateTime.Now))
|
||||
;
|
||||
//发起好友请求转换请求对象
|
||||
CreateMap<FriendRequestDto, FriendRequest>()
|
||||
.ForMember(dest => dest.RequestUser , opt => opt.MapFrom(src => src.FromUserId))
|
||||
.ForMember(dest => dest.ResponseUser , opt => opt.MapFrom(src => src.ToUserId))
|
||||
.ForMember(dest => dest.Created , opt => opt.MapFrom(src => DateTime.Now))
|
||||
.ForMember(dest => dest.StateEnum , opt => opt.MapFrom(src => FriendRequestState.Pending))
|
||||
.ForMember(dest => dest.Description , opt => opt.MapFrom(src => src.Description))
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ namespace IM_API.Configs
|
||||
services.AddAutoMapper(typeof(MapperConfig));
|
||||
services.AddTransient<IAuthService, AuthService>();
|
||||
services.AddTransient<IUserService, UserService>();
|
||||
services.AddTransient<IFriendSerivce, FriendService>();
|
||||
services.AddSingleton<IJWTService, JWTService>();
|
||||
services.AddSingleton<IRefreshTokenService,RedisRefreshTokenService>();
|
||||
return services;
|
||||
|
||||
114
backend/IM_API/Controllers/FriendController.cs
Normal file
114
backend/IM_API/Controllers/FriendController.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using IM_API.Dtos;
|
||||
using IM_API.Interface.Services;
|
||||
using IM_API.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace IM_API.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class FriendController : ControllerBase
|
||||
{
|
||||
private readonly IFriendSerivce _friendService;
|
||||
private readonly ILogger<FriendController> _logger;
|
||||
public FriendController(IFriendSerivce friendService, ILogger<FriendController> logger)
|
||||
{
|
||||
_friendService = friendService;
|
||||
_logger = logger;
|
||||
}
|
||||
/// <summary>
|
||||
/// 发起好友请求
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Request(FriendRequestDto dto)
|
||||
{
|
||||
var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
int userId = int.Parse(userIdStr);
|
||||
dto.FromUserId = userId;
|
||||
await _friendService.SendFriendRequestAsync(dto);
|
||||
var res = new BaseResponse<object?>();
|
||||
return Ok(res);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取好友请求列表
|
||||
/// </summary>
|
||||
/// <param name="isReceived"></param>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="limit"></param>
|
||||
/// <param name="desc"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Requests(bool isReceived,int page,int limit,bool desc)
|
||||
{
|
||||
var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
int userId = int.Parse(userIdStr);
|
||||
var list = await _friendService.GetFriendRequestListAsync(userId,isReceived,page,limit,desc);
|
||||
var res = new BaseResponse<List<FriendRequest>>(list);
|
||||
return Ok(res);
|
||||
}
|
||||
/// <summary>
|
||||
/// 处理好友请求
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> HandleRequest([FromRoute]int id, [FromBody]FriendRequestHandleDto dto)
|
||||
{
|
||||
await _friendService.HandleFriendRequestAsync(new HandleFriendRequestDto()
|
||||
{
|
||||
RequestId = id,
|
||||
RemarkName = dto.remarkName,
|
||||
Action = dto.action
|
||||
});
|
||||
var res = new BaseResponse<object?>();
|
||||
return Ok(res);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取好友列表
|
||||
/// </summary>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="limit"></param>
|
||||
/// <param name="desc"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> List(int page,int limit,bool desc)
|
||||
{
|
||||
var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
int userId = int.Parse(userIdStr);
|
||||
var list = await _friendService.GetFriendListAsync(userId,page,limit,desc);
|
||||
var res = new BaseResponse<List<FriendInfoDto>>(list);
|
||||
return Ok(res);
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除好友
|
||||
/// </summary>
|
||||
/// <param name="friendId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Delete([FromRoute] int friendId)
|
||||
{
|
||||
//TODO: 这里存在安全问题,当用户传入的id与用户无关时也可以删除成功,待修复。
|
||||
await _friendService.DeleteFriendAsync(friendId);
|
||||
return Ok(new BaseResponse<object?>());
|
||||
}
|
||||
/// <summary>
|
||||
/// 拉黑好友
|
||||
/// </summary>
|
||||
/// <param name="friendId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Block([FromRoute] int friendId)
|
||||
{
|
||||
//TODO: 这里存在安全问题,当用户传入的id与用户无关时也可以拉黑成功,待修复。
|
||||
await _friendService.BlockeFriendAsync(friendId);
|
||||
return Ok(new BaseResponse<object?>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,7 +67,7 @@ namespace IM_API.Controllers
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Find(string username)
|
||||
public async Task<IActionResult> FindByUsername(string username)
|
||||
{
|
||||
var userinfo = await _userService.GetUserInfoByUsernameAsync(username);
|
||||
var res = new BaseResponse<UserInfoDto>(userinfo);
|
||||
|
||||
@ -3,4 +3,5 @@
|
||||
namespace IM_API.Dtos
|
||||
{
|
||||
public record FriendInfoDto(int Id, int UserId,int FriendId,FriendStatus StatusEnum,DateTime Created,string RemarkName,string? Avatar);
|
||||
public record FriendRequestHandleDto(HandleFriendRequestAction action,string? remarkName);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
{
|
||||
public int FromUserId { get; set; }
|
||||
public int ToUserId { get; set; }
|
||||
public string? RemarkName { get; set; }
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,10 @@
|
||||
/// 处理操作
|
||||
/// </summary>
|
||||
public HandleFriendRequestAction Action { get; set; }
|
||||
/// <summary>
|
||||
/// 好友备注名
|
||||
/// </summary>
|
||||
public string? RemarkName { get; set; }
|
||||
}
|
||||
public enum HandleFriendRequestAction
|
||||
{
|
||||
|
||||
@ -27,7 +27,7 @@ namespace IM_API.Interface.Services
|
||||
/// <param name="page"></param>
|
||||
/// <param name="limit"></param>
|
||||
/// <returns></returns>
|
||||
Task<FriendRequest> GetFriendRequestListAsync(int userId,bool isReceived,int page,int limit, bool desc);
|
||||
Task<List<FriendRequest>> GetFriendRequestListAsync(int userId,bool isReceived,int page,int limit, bool desc);
|
||||
/// <summary>
|
||||
/// 处理好友请求
|
||||
/// </summary>
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
using AutoMapper;
|
||||
using IM_API.Dtos;
|
||||
using IM_API.Exceptions;
|
||||
using IM_API.Interface.Services;
|
||||
using IM_API.Models;
|
||||
using IM_API.Tools;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace IM_API.Services
|
||||
@ -17,30 +19,51 @@ namespace IM_API.Services
|
||||
_logger = logger;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public Task<bool> BlockeFriendAsync(int friendId)
|
||||
#region 拉黑好友
|
||||
public async Task<bool> BlockeFriendAsync(int friendId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var friend = await _context.Friends.FirstOrDefaultAsync(x => x.Id == friendId);
|
||||
if (friend == null) throw new BaseException(CodeDefine.FRIEND_RELATION_NOT_FOUND);
|
||||
friend.StatusEnum = FriendStatus.Blocked;
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<bool> BlockFriendByUserIdAsync(int userId, int toUserId)
|
||||
#endregion
|
||||
#region 通过用户id拉黑好友
|
||||
public async Task<bool> BlockFriendByUserIdAsync(int userId, int toUserId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var friend = await _context.Friends.FirstOrDefaultAsync(x => x.UserId == userId && x.FriendId == toUserId);
|
||||
if (friend == null) throw new BaseException(CodeDefine.FRIEND_RELATION_NOT_FOUND);
|
||||
friend.StatusEnum = FriendStatus.Blocked;
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<bool> DeleteFriendAsync(int friendId)
|
||||
#endregion
|
||||
#region 删除好友关系
|
||||
public async Task<bool> DeleteFriendAsync(int friendId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var friend = await _context.Friends.FirstOrDefaultAsync(x => x.Id == friendId);
|
||||
if (friend is null) throw new BaseException(CodeDefine.FRIEND_RELATION_NOT_FOUND);
|
||||
_context.Friends.Remove(friend);
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<bool> DeleteFriendByUserIdAsync(int userId, int toUserId)
|
||||
#endregion
|
||||
#region 通过用户id删除好友关系
|
||||
public async Task<bool> DeleteFriendByUserIdAsync(int userId, int toUserId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var friend = await _context.Friends.FirstOrDefaultAsync(x => x.UserId == userId && x.FriendId == toUserId);
|
||||
if (friend is null) throw new BaseException(CodeDefine.FRIEND_RELATION_NOT_FOUND);
|
||||
_context.Friends.Remove(friend);
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
#region 获取好友列表
|
||||
|
||||
public async Task<List<FriendInfoDto>> GetFriendListAsync(int userId, int page, int limit, bool desc)
|
||||
{
|
||||
var query = _context.Friends.Where(x => x.UserId == userId);
|
||||
var query = _context.Friends.Where(x => x.UserId == userId && x.StatusEnum == FriendStatus.Added);
|
||||
if (desc)
|
||||
{
|
||||
query = query.OrderByDescending(x => x.UserId);
|
||||
@ -48,20 +71,104 @@ namespace IM_API.Services
|
||||
var friendList = await query.Skip((page - 1 * limit)).Take(limit).ToListAsync();
|
||||
return _mapper.Map<List<FriendInfoDto>>(friendList);
|
||||
}
|
||||
|
||||
public Task<FriendRequest> GetFriendRequestListAsync(int userId, bool isReceived, int page, int limit, bool desc)
|
||||
#endregion
|
||||
#region 获取好友请求列表
|
||||
public async Task<List<FriendRequest>> GetFriendRequestListAsync(int userId, bool isReceived, int page, int limit, bool desc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var query = _context.FriendRequests.AsQueryable();
|
||||
//是否为请求方
|
||||
if (isReceived)
|
||||
{
|
||||
query = _context.FriendRequests.Where(x => x.ResponseUser == userId);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = _context.FriendRequests.Where(x => x.RequestUser == userId);
|
||||
}
|
||||
if (desc)
|
||||
{
|
||||
query = query.OrderByDescending(x => x.Id);
|
||||
}
|
||||
var friendRequestList = await query.Skip((page - 1 * limit)).Take(limit).ToListAsync();
|
||||
return friendRequestList;
|
||||
}
|
||||
|
||||
public Task<bool> HandleFriendRequestAsync(HandleFriendRequestDto requestDto)
|
||||
#endregion
|
||||
#region 处理好友请求
|
||||
public async Task<bool> HandleFriendRequestAsync(HandleFriendRequestDto requestDto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
//查询好友请求记录
|
||||
var friendRequest = await _context.FriendRequests
|
||||
.Include(e => e.ResponseUserNavigation)
|
||||
.FirstOrDefaultAsync(x => x.Id == requestDto.RequestId);
|
||||
|
||||
if (friendRequest is null) throw new BaseException(CodeDefine.FRIEND_REQUEST_NOT_FOUND);
|
||||
|
||||
//查询好友关系
|
||||
var friend = await _context.Friends.FirstOrDefaultAsync(
|
||||
x => x.UserId == friendRequest.RequestUser && x.FriendId == friendRequest.ResponseUser
|
||||
);
|
||||
if (friend is null) throw new BaseException(CodeDefine.FRIEND_RELATION_NOT_FOUND);
|
||||
|
||||
public Task<bool> SendFriendRequestAsync(FriendRequestDto friendRequest)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (friend.StatusEnum != FriendStatus.Pending) throw new BaseException(CodeDefine.FRIEND_REQUEST_EXISTS);
|
||||
//处理好友请求操作
|
||||
switch (requestDto.Action)
|
||||
{
|
||||
//拒绝后标记
|
||||
case HandleFriendRequestAction.Reject:
|
||||
friend.StatusEnum = FriendStatus.Declined;
|
||||
friendRequest.StateEnum = FriendRequestState.Declined;
|
||||
break;
|
||||
|
||||
//同意后标记
|
||||
case HandleFriendRequestAction.Accept:
|
||||
friend.StatusEnum = FriendStatus.Added;
|
||||
friendRequest.StateEnum = FriendRequestState.Passed;
|
||||
|
||||
//根据当前好友请求为被申请方添加一条好友记录(注意:好友记录为双向)
|
||||
var ResponseFriend = _mapper.Map<Friend>(friendRequest);
|
||||
if (!string.IsNullOrEmpty(requestDto.RemarkName)) ResponseFriend.RemarkName = requestDto.RemarkName;
|
||||
_context.Friends.Add(ResponseFriend);
|
||||
break;
|
||||
|
||||
//无效操作
|
||||
default:
|
||||
throw new BaseException(CodeDefine.INVALID_ACTION);
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
#region 发起好友请求
|
||||
public async Task<bool> SendFriendRequestAsync(FriendRequestDto dto)
|
||||
{
|
||||
//查询用户是否存在
|
||||
bool isExist = await _context.Users.AnyAsync(x => x.Id == dto.ToUserId);
|
||||
if (!isExist) throw new BaseException(CodeDefine.USER_NOT_FOUND);
|
||||
bool isExistUser2 = await _context.Users.AnyAsync(x => x.Id == dto.FromUserId);
|
||||
if(!isExistUser2) throw new BaseException(CodeDefine.USER_NOT_FOUND);
|
||||
// 检查是否已有好友关系或待处理请求
|
||||
bool alreadyExists = await _context.FriendRequests.AnyAsync(x =>
|
||||
x.RequestUser == dto.FromUserId && x.ResponseUser == dto.ToUserId && x.StateEnum == FriendRequestState.Pending
|
||||
);
|
||||
if (alreadyExists)
|
||||
throw new BaseException(CodeDefine.FRIEND_REQUEST_EXISTS);
|
||||
|
||||
//检查是否被对方拉黑
|
||||
bool isBlocked = await _context.Friends.AnyAsync(x =>
|
||||
x.UserId == dto.FromUserId && x.FriendId == dto.ToUserId && x.StatusEnum == FriendStatus.Blocked
|
||||
);
|
||||
if (isBlocked)
|
||||
throw new BaseException(CodeDefine.FRIEND_REQUEST_REJECTED);
|
||||
|
||||
//生成实体
|
||||
var friendRequst = _mapper.Map<FriendRequest>(dto);
|
||||
var friend = _mapper.Map<Friend>(friendRequst);
|
||||
_context.FriendRequests.Add(friendRequst);
|
||||
_context.Friends.Add(friend);
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +53,10 @@
|
||||
public static CodeDefine FRIEND_REQUEST_REJECTED = new CodeDefine(2103, "好友请求被拒绝");
|
||||
/// <summary>被对方拉黑</summary>
|
||||
public static CodeDefine CANNOT_ADD_FRIEND = new CodeDefine(2104, "无法申请加好友");
|
||||
/// <summary>好友请求不存在</summary>
|
||||
public static CodeDefine FRIEND_REQUEST_NOT_FOUND = new CodeDefine(2105, "好友请求不存在");
|
||||
/// <summary>处理好友请求操作无效</summary>
|
||||
public static CodeDefine INVALID_ACTION = new CodeDefine(2106, "处理好友请求操作无效");
|
||||
|
||||
// 3.5 群聊相关错误(2200 ~ 2299)
|
||||
/// <summary>查询不到群</summary>
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
namespace IM_API
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string? Summary { get; set; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user