diff --git a/backend/IM_API/Aggregate/FriendRequestAggregate.cs b/backend/IM_API/Aggregate/FriendRequestAggregate.cs new file mode 100644 index 0000000..a5bfb43 --- /dev/null +++ b/backend/IM_API/Aggregate/FriendRequestAggregate.cs @@ -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) + { + + } + } +} diff --git a/backend/IM_API/Configs/MapperConfig.cs b/backend/IM_API/Configs/MapperConfig.cs index 93bacfd..f3d1036 100644 --- a/backend/IM_API/Configs/MapperConfig.cs +++ b/backend/IM_API/Configs/MapperConfig.cs @@ -26,6 +26,22 @@ namespace IM_API.Configs ; //好友信息模型转换 CreateMap(); + //好友请求通过后新增好友关系 + CreateMap() + .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() + .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)) + ; } } } diff --git a/backend/IM_API/Configs/ServiceCollectionExtensions.cs b/backend/IM_API/Configs/ServiceCollectionExtensions.cs index fcd715d..e24c0e7 100644 --- a/backend/IM_API/Configs/ServiceCollectionExtensions.cs +++ b/backend/IM_API/Configs/ServiceCollectionExtensions.cs @@ -10,6 +10,7 @@ namespace IM_API.Configs services.AddAutoMapper(typeof(MapperConfig)); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddSingleton(); services.AddSingleton(); return services; diff --git a/backend/IM_API/Controllers/FriendController.cs b/backend/IM_API/Controllers/FriendController.cs new file mode 100644 index 0000000..fd2e9b8 --- /dev/null +++ b/backend/IM_API/Controllers/FriendController.cs @@ -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 _logger; + public FriendController(IFriendSerivce friendService, ILogger logger) + { + _friendService = friendService; + _logger = logger; + } + /// + /// 发起好友请求 + /// + /// + /// + [HttpPost] + public async Task 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(); + return Ok(res); + } + /// + /// 获取好友请求列表 + /// + /// + /// + /// + /// + /// + [HttpGet] + public async Task 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); + return Ok(res); + } + /// + /// 处理好友请求 + /// + /// + /// + /// + [HttpPost] + public async Task HandleRequest([FromRoute]int id, [FromBody]FriendRequestHandleDto dto) + { + await _friendService.HandleFriendRequestAsync(new HandleFriendRequestDto() + { + RequestId = id, + RemarkName = dto.remarkName, + Action = dto.action + }); + var res = new BaseResponse(); + return Ok(res); + } + /// + /// 获取好友列表 + /// + /// + /// + /// + /// + [HttpGet] + public async Task 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); + return Ok(res); + } + /// + /// 删除好友 + /// + /// + /// + [HttpPost] + public async Task Delete([FromRoute] int friendId) + { + //TODO: 这里存在安全问题,当用户传入的id与用户无关时也可以删除成功,待修复。 + await _friendService.DeleteFriendAsync(friendId); + return Ok(new BaseResponse()); + } + /// + /// 拉黑好友 + /// + /// + /// + [HttpPost] + public async Task Block([FromRoute] int friendId) + { + //TODO: 这里存在安全问题,当用户传入的id与用户无关时也可以拉黑成功,待修复。 + await _friendService.BlockeFriendAsync(friendId); + return Ok(new BaseResponse()); + } + } +} diff --git a/backend/IM_API/Controllers/UserController.cs b/backend/IM_API/Controllers/UserController.cs index 9d89e57..cbd7ed9 100644 --- a/backend/IM_API/Controllers/UserController.cs +++ b/backend/IM_API/Controllers/UserController.cs @@ -67,7 +67,7 @@ namespace IM_API.Controllers /// /// [HttpGet] - public async Task Find(string username) + public async Task FindByUsername(string username) { var userinfo = await _userService.GetUserInfoByUsernameAsync(username); var res = new BaseResponse(userinfo); diff --git a/backend/IM_API/Dtos/FriendDto.cs b/backend/IM_API/Dtos/FriendDto.cs index 99525c7..e21e06f 100644 --- a/backend/IM_API/Dtos/FriendDto.cs +++ b/backend/IM_API/Dtos/FriendDto.cs @@ -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); } diff --git a/backend/IM_API/Dtos/FriendRequestDto.cs b/backend/IM_API/Dtos/FriendRequestDto.cs index 8990d96..e9c83da 100644 --- a/backend/IM_API/Dtos/FriendRequestDto.cs +++ b/backend/IM_API/Dtos/FriendRequestDto.cs @@ -4,6 +4,7 @@ { public int FromUserId { get; set; } public int ToUserId { get; set; } + public string? RemarkName { get; set; } public string? Description { get; set; } } } diff --git a/backend/IM_API/Dtos/HandleFriendRequestDto.cs b/backend/IM_API/Dtos/HandleFriendRequestDto.cs index 637871d..3b90c04 100644 --- a/backend/IM_API/Dtos/HandleFriendRequestDto.cs +++ b/backend/IM_API/Dtos/HandleFriendRequestDto.cs @@ -10,6 +10,10 @@ /// 处理操作 /// public HandleFriendRequestAction Action { get; set; } + /// + /// 好友备注名 + /// + public string? RemarkName { get; set; } } public enum HandleFriendRequestAction { diff --git a/backend/IM_API/Interface/Services/IFriendSerivce.cs b/backend/IM_API/Interface/Services/IFriendSerivce.cs index 02be835..804cb73 100644 --- a/backend/IM_API/Interface/Services/IFriendSerivce.cs +++ b/backend/IM_API/Interface/Services/IFriendSerivce.cs @@ -27,7 +27,7 @@ namespace IM_API.Interface.Services /// /// /// - Task GetFriendRequestListAsync(int userId,bool isReceived,int page,int limit, bool desc); + Task> GetFriendRequestListAsync(int userId,bool isReceived,int page,int limit, bool desc); /// /// 处理好友请求 /// diff --git a/backend/IM_API/Services/FriendService.cs b/backend/IM_API/Services/FriendService.cs index 8564ebf..de05052 100644 --- a/backend/IM_API/Services/FriendService.cs +++ b/backend/IM_API/Services/FriendService.cs @@ -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 BlockeFriendAsync(int friendId) + #region 拉黑好友 + public async Task 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 BlockFriendByUserIdAsync(int userId, int toUserId) + #endregion + #region 通过用户id拉黑好友 + public async Task 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 DeleteFriendAsync(int friendId) + #endregion + #region 删除好友关系 + public async Task 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 DeleteFriendByUserIdAsync(int userId, int toUserId) + #endregion + #region 通过用户id删除好友关系 + public async Task 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> 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>(friendList); } - - public Task GetFriendRequestListAsync(int userId, bool isReceived, int page, int limit, bool desc) + #endregion + #region 获取好友请求列表 + public async Task> 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 HandleFriendRequestAsync(HandleFriendRequestDto requestDto) + #endregion + #region 处理好友请求 + public async Task 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 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(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 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(dto); + var friend = _mapper.Map(friendRequst); + _context.FriendRequests.Add(friendRequst); + _context.Friends.Add(friend); + await _context.SaveChangesAsync(); + return true; + } + #endregion } } diff --git a/backend/IM_API/Tools/CodeDefine.cs b/backend/IM_API/Tools/CodeDefine.cs index 5ed3bff..5733b58 100644 --- a/backend/IM_API/Tools/CodeDefine.cs +++ b/backend/IM_API/Tools/CodeDefine.cs @@ -53,6 +53,10 @@ public static CodeDefine FRIEND_REQUEST_REJECTED = new CodeDefine(2103, "好友请求被拒绝"); /// 被对方拉黑 public static CodeDefine CANNOT_ADD_FRIEND = new CodeDefine(2104, "无法申请加好友"); + /// 好友请求不存在 + public static CodeDefine FRIEND_REQUEST_NOT_FOUND = new CodeDefine(2105, "好友请求不存在"); + /// 处理好友请求操作无效 + public static CodeDefine INVALID_ACTION = new CodeDefine(2106, "处理好友请求操作无效"); // 3.5 群聊相关错误(2200 ~ 2299) /// 查询不到群 diff --git a/backend/IM_API/WeatherForecast.cs b/backend/IM_API/WeatherForecast.cs deleted file mode 100644 index 57624ef..0000000 --- a/backend/IM_API/WeatherForecast.cs +++ /dev/null @@ -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; } - } -}