diff --git a/backend/IM_API/Configs/MapperConfig.cs b/backend/IM_API/Configs/MapperConfig.cs index c4d57e0..93bacfd 100644 --- a/backend/IM_API/Configs/MapperConfig.cs +++ b/backend/IM_API/Configs/MapperConfig.cs @@ -9,6 +9,23 @@ namespace IM_API.Configs public MapperConfig() { CreateMap(); + //用户信息更新模型转换 + CreateMap() + .ForMember(dest => dest.Updated,opt => opt.MapFrom(src => DateTime.Now)) + .ForAllMembers(opts => opts.Condition((src,dest,srcMember) => srcMember != null)); + //用户注册模型转换 + CreateMap() + .ForMember(dest => dest.Username,opt => opt.MapFrom(src => src.Username)) + .ForMember(dest => dest.Password,opt => opt.MapFrom(src => src.Password)) + .ForMember(dest => dest.Avatar,opt => opt.MapFrom(src => "https://ts1.tc.mm.bing.net/th/id/OIP-C.dl0WpkTP6E2J4FnhDC_jHwAAAA?rs=1&pid=ImgDetMain&o=7&rm=3")) + .ForMember(dest => dest.StatusEnum,opt => opt.MapFrom(src => UserStatus.Normal)) + .ForMember(dest => dest.OnlineStatusEnum,opt => opt.MapFrom(src => UserOnlineStatus.Offline)) + .ForMember(dest => dest.NickName,opt => opt.MapFrom(src => src.NickName)) + .ForMember(dest => dest.Created,opt => opt.MapFrom(src => DateTime.Now)) + .ForMember(dest => dest.IsDeleted,opt => opt.MapFrom(src => 0)) + ; + //好友信息模型转换 + CreateMap(); } } } diff --git a/backend/IM_API/Configs/ServiceCollectionExtensions.cs b/backend/IM_API/Configs/ServiceCollectionExtensions.cs index 89e400c..fcd715d 100644 --- a/backend/IM_API/Configs/ServiceCollectionExtensions.cs +++ b/backend/IM_API/Configs/ServiceCollectionExtensions.cs @@ -9,6 +9,7 @@ namespace IM_API.Configs { services.AddAutoMapper(typeof(MapperConfig)); services.AddTransient(); + services.AddTransient(); services.AddSingleton(); services.AddSingleton(); return services; diff --git a/backend/IM_API/Controllers/AuthController.cs b/backend/IM_API/Controllers/AuthController.cs index bca7b5c..5c95072 100644 --- a/backend/IM_API/Controllers/AuthController.cs +++ b/backend/IM_API/Controllers/AuthController.cs @@ -1,6 +1,8 @@ using IM_API.Dtos; using IM_API.Interface.Services; +using IM_API.Tools; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; namespace IM_API.Controllers @@ -11,16 +13,18 @@ namespace IM_API.Controllers { private readonly ILogger _logger; private readonly IAuthService _authService; + private readonly IUserService _userService; private readonly IJWTService _jwtService; private readonly IRefreshTokenService _refreshTokenService; private readonly IConfiguration _configuration; - public AuthController(ILogger logger, IAuthService authService, IJWTService jwtService, IRefreshTokenService refreshTokenService, IConfiguration configuration) + public AuthController(ILogger logger, IAuthService authService, IJWTService jwtService, IRefreshTokenService refreshTokenService, IConfiguration configuration,IUserService userService) { _logger = logger; _authService = authService; _jwtService = jwtService; _refreshTokenService = refreshTokenService; _configuration = configuration; + _userService = userService; } [HttpPost] public async Task Login(LoginRequestDto dto) @@ -33,5 +37,26 @@ namespace IM_API.Controllers var res = new BaseResponse(new LoginDto(user.Id,token,refreshToken,expiresAt)); return Ok(res); } + [HttpPost] + public async Task Register(RegisterRequestDto dto) + { + var userInfo = await _authService.RegisterAsync(dto); + var res = new BaseResponse(userInfo); + return Ok(res); + } + [HttpPost] + public async Task Refresh(RefreshDto dto) + { + (bool ok,int userId) = await _refreshTokenService.ValidateRefreshTokenAsync(dto.refreshToken); + if (!ok) + { + var err = new BaseResponse(CodeDefine.AUTH_FAILED); + return Unauthorized(err); + } + var userinfo = await _userService.GetUserInfoAsync(userId); + (string token,DateTime expiresAt) = _jwtService.CreateAccessTokenForUser(userinfo.Id,userinfo.Username,"user"); + var res = new BaseResponse(new LoginDto(userinfo.Id,token,dto.refreshToken,expiresAt)); + return Ok(res); + } } } diff --git a/backend/IM_API/Controllers/UserController.cs b/backend/IM_API/Controllers/UserController.cs new file mode 100644 index 0000000..9d89e57 --- /dev/null +++ b/backend/IM_API/Controllers/UserController.cs @@ -0,0 +1,103 @@ +using IM_API.Dtos; +using IM_API.Interface.Services; +using IM_API.Tools; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; + +namespace IM_API.Controllers +{ + [Authorize] + [Route("api/[controller]/[action]")] + [ApiController] + public class UserController : ControllerBase + { + private readonly IUserService _userService; + private readonly ILogger _logger; + public UserController(IUserService userService, ILogger logger) + { + _userService = userService; + _logger = logger; + } + /// + /// 获取当前用户信息 + /// + /// + [HttpGet] + public async Task Me() + { + var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier); + int userId = int.Parse(userIdStr); + var userinfo = await _userService.GetUserInfoAsync(userId); + var res = new BaseResponse(userinfo); + return Ok(res); + } + /// + /// 修改用户资料 + /// + /// + /// + [HttpPost] + public async Task Profile(UpdateUserDto dto) + { + var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier); + int userId = int.Parse(userIdStr); + var userinfo = await _userService.UpdateUserAsync(userId,dto); + var res = new BaseResponse(userinfo); + return Ok(res); + + } + /// + /// ID查询用户 + /// + /// + /// + [HttpGet] + public async Task Find(int userId) + { + var userinfo = await _userService.GetUserInfoAsync(userId); + var res = new BaseResponse(userinfo); + return Ok(res); + } + /// + /// 用户名查询用户 + /// + /// + /// + [HttpGet] + public async Task Find(string username) + { + var userinfo = await _userService.GetUserInfoByUsernameAsync(username); + var res = new BaseResponse(userinfo); + return Ok(res); + } + /// + /// 重置用户密码 + /// + /// + /// + [HttpPost] + public async Task ResetPassword(PasswordResetDto dto) + { + var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier); + int userId = int.Parse(userIdStr); + await _userService.ResetPasswordAsync(userId,dto.oldPassword,dto.Password); + return Ok(new BaseResponse()); + } + /// + /// 设置在线状态 + /// + /// + /// + [HttpPost] + public async Task SetOnlineStatus(OnlineStatusSetDto dto) + { + var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier); + int userId = int.Parse(userIdStr); + await _userService.UpdateOlineStatusAsync(userId, dto.OnlineStatus); + return Ok(new BaseResponse()); + } + } +} diff --git a/backend/IM_API/Dtos/AuthDto.cs b/backend/IM_API/Dtos/AuthDto.cs new file mode 100644 index 0000000..73f6d74 --- /dev/null +++ b/backend/IM_API/Dtos/AuthDto.cs @@ -0,0 +1,4 @@ +namespace IM_API.Dtos +{ + public record RefreshDto(string refreshToken); +} diff --git a/backend/IM_API/Dtos/BaseResponse.cs b/backend/IM_API/Dtos/BaseResponse.cs index f75c89b..12a0501 100644 --- a/backend/IM_API/Dtos/BaseResponse.cs +++ b/backend/IM_API/Dtos/BaseResponse.cs @@ -64,6 +64,15 @@ namespace IM_API.Dtos Code = code; Message = message; } + /// + /// 接受codedefine对象 + /// + /// + public BaseResponse(CodeDefine codeDefine) + { + this.Code = codeDefine.Code; + this.Message = codeDefine.Message; + } public BaseResponse() { } } } diff --git a/backend/IM_API/Dtos/FriendDto.cs b/backend/IM_API/Dtos/FriendDto.cs new file mode 100644 index 0000000..99525c7 --- /dev/null +++ b/backend/IM_API/Dtos/FriendDto.cs @@ -0,0 +1,6 @@ +using IM_API.Models; + +namespace IM_API.Dtos +{ + public record FriendInfoDto(int Id, int UserId,int FriendId,FriendStatus StatusEnum,DateTime Created,string RemarkName,string? Avatar); +} diff --git a/backend/IM_API/Dtos/UpdateUserDto.cs b/backend/IM_API/Dtos/UpdateUserDto.cs index 279018d..86e2560 100644 --- a/backend/IM_API/Dtos/UpdateUserDto.cs +++ b/backend/IM_API/Dtos/UpdateUserDto.cs @@ -3,5 +3,7 @@ public class UpdateUserDto { public string? NickName { get; set; } + public string? Avatar { get; set; } + } } diff --git a/backend/IM_API/Dtos/UserDto.cs b/backend/IM_API/Dtos/UserDto.cs new file mode 100644 index 0000000..8d21169 --- /dev/null +++ b/backend/IM_API/Dtos/UserDto.cs @@ -0,0 +1,7 @@ +using IM_API.Models; + +namespace IM_API.Dtos +{ + public record PasswordResetDto(string oldPassword,string Password); + public record OnlineStatusSetDto(UserOnlineStatus OnlineStatus); +} diff --git a/backend/IM_API/Dtos/UserInfoDto.cs b/backend/IM_API/Dtos/UserInfoDto.cs index fff482a..e34bb56 100644 --- a/backend/IM_API/Dtos/UserInfoDto.cs +++ b/backend/IM_API/Dtos/UserInfoDto.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using IM_API.Models; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace IM_API.Dtos @@ -22,7 +23,7 @@ namespace IM_API.Dtos /// 0(默认):不在线 /// 1:在线 /// - public sbyte OlineStatus { get; set; } + public UserOnlineStatus OnlineStatusEnum { get; set; } /// /// 创建时间 @@ -33,6 +34,6 @@ namespace IM_API.Dtos /// 账户状态 /// (0:未激活,1:正常,2:封禁) /// - public sbyte Status { get; set; } + public UserStatus StatusEnum { get; set; } } } diff --git a/backend/IM_API/Interface/Services/IDemo.cs b/backend/IM_API/Interface/Services/IDemo.cs deleted file mode 100644 index 75bf461..0000000 --- a/backend/IM_API/Interface/Services/IDemo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using IM_API.Dtos; - -namespace IM_API.Interface.Services -{ - public interface IDemo - { - TestDto Test(); - } -} diff --git a/backend/IM_API/Interface/Services/IFriendSerivce.cs b/backend/IM_API/Interface/Services/IFriendSerivce.cs index 4f0bfa2..02be835 100644 --- a/backend/IM_API/Interface/Services/IFriendSerivce.cs +++ b/backend/IM_API/Interface/Services/IFriendSerivce.cs @@ -12,7 +12,7 @@ namespace IM_API.Interface.Services /// 当前页 /// 分页大小 /// - Task> GetFriendListAsync(int userId,int page,int limit); + Task> GetFriendListAsync(int userId,int page,int limit,bool desc); /// /// 新增好友请求 /// @@ -27,7 +27,7 @@ namespace IM_API.Interface.Services /// /// /// - Task GetFriendRequestListAsync(int userId,bool isReceived,int page,int limit); + Task GetFriendRequestListAsync(int userId,bool isReceived,int page,int limit, bool desc); /// /// 处理好友请求 /// diff --git a/backend/IM_API/Interface/Services/IUserService.cs b/backend/IM_API/Interface/Services/IUserService.cs index b11f2c3..698606f 100644 --- a/backend/IM_API/Interface/Services/IUserService.cs +++ b/backend/IM_API/Interface/Services/IUserService.cs @@ -22,18 +22,18 @@ namespace IM_API.Interface.Services /// /// /// - Task UpdateUserAsync(UpdateUserDto dto); + Task UpdateUserAsync(int userId, UpdateUserDto dto); /// /// 重置用户密码 /// /// /// - Task ResetPasswordAsync(string password); + Task ResetPasswordAsync(int userId, string oldPassword, string password); /// /// 更新用户在线状态 /// /// /// - Task UpdateOlineStatusAsync(UserOnlineStatus onlineStatus); + Task UpdateOlineStatusAsync(int userId, UserOnlineStatus onlineStatus); } } diff --git a/backend/IM_API/Models/Friend.cs b/backend/IM_API/Models/Friend.cs index 65c5095..11b1221 100644 --- a/backend/IM_API/Models/Friend.cs +++ b/backend/IM_API/Models/Friend.cs @@ -28,6 +28,16 @@ public partial class Friend /// public DateTime Created { get; set; } + /// + /// 好友备注名 + /// + public string RemarkName { get; set; } = null!; + + /// + /// 好友头像 + /// + public string? Avatar { get; set; } + public virtual User FriendNavigation { get; set; } = null!; public virtual User User { get; set; } = null!; diff --git a/backend/IM_API/Models/Groupmember.cs b/backend/IM_API/Models/Groupmember.cs index 0ff8f42..849ea37 100644 --- a/backend/IM_API/Models/Groupmember.cs +++ b/backend/IM_API/Models/Groupmember.cs @@ -21,6 +21,7 @@ public partial class GroupMember /// 成员角色(0:普通成员,1:管理员,2:群主) /// public sbyte Role { get; set; } + /// /// 加入群聊时间 /// diff --git a/backend/IM_API/Models/ImContext.Custom.cs b/backend/IM_API/Models/ImContext.Custom.cs new file mode 100644 index 0000000..dc91a0e --- /dev/null +++ b/backend/IM_API/Models/ImContext.Custom.cs @@ -0,0 +1,99 @@ +using Microsoft.EntityFrameworkCore; + +namespace IM_API.Models +{ + public partial class ImContext + { + partial void OnModelCreatingPartial(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.StateEnum); + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.OnlineStatusEnum); + entity.Ignore(e => e.StatusEnum); + entity.HasQueryFilter(e => e.IsDeleted == 0); + }); + modelBuilder.Entity(entity => + { + + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.DtypeEnum); + }); + + modelBuilder.Entity(entity => + { + + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.StatusEnum); + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.StateEnum); + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.StatusEnum); + entity.Ignore(e => e.AllMembersBannedEnum); + entity.Ignore(e => e.AuhorityEnum); + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.StateEnum); + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.RoleEnum); + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.StateEnum); + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.StateEnum); + }); + + modelBuilder.Entity(entity => + { + entity.Ignore(e => e.StateEnum); + entity.Ignore(e => e.MsgTypeEnum); + }); + + modelBuilder.Entity(entity => + { + + }); + + modelBuilder.Entity(entity => + { + + }); + + modelBuilder.Entity(entity => + { + + }); + + modelBuilder.Entity(entity => + { + + }); + } + } +} diff --git a/backend/IM_API/Models/ImContext.cs b/backend/IM_API/Models/ImContext.cs index b5afb0a..6e6a882 100644 --- a/backend/IM_API/Models/ImContext.cs +++ b/backend/IM_API/Models/ImContext.cs @@ -62,7 +62,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.StateEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -102,7 +101,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -147,7 +145,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.DtypeEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -219,7 +216,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.StatusEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -236,12 +232,18 @@ public partial class ImContext : DbContext entity.Property(e => e.Id) .HasColumnType("int(11)") .HasColumnName("ID"); + entity.Property(e => e.Avatar) + .HasMaxLength(255) + .HasComment("好友头像"); entity.Property(e => e.Created) .HasComment("好友关系创建时间") .HasColumnType("datetime"); entity.Property(e => e.FriendId) .HasComment("用户2ID") .HasColumnType("int(11)"); + entity.Property(e => e.RemarkName) + .HasMaxLength(20) + .HasComment("好友备注名"); entity.Property(e => e.Status) .HasComment("当前好友关系状态\r\n(0:待通过,1:已添加,2:已拒绝,3:已拉黑)") .HasColumnType("tinyint(4)"); @@ -262,7 +264,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.StateEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -306,9 +307,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.StatusEnum); - entity.Ignore(x => x.AllMembersBannedEnum); - entity.Ignore(x => x.AuhorityEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -353,7 +351,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.StateEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -402,7 +399,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.RoleEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -446,7 +442,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.StateEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -488,7 +483,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.StateEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -523,8 +517,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - entity.Ignore(x => x.StateEnum); - entity.Ignore(x => x.MsgTypeEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -689,10 +681,6 @@ public partial class ImContext : DbContext modelBuilder.Entity(entity => { - - // 忽略包装枚举属性 - entity.Ignore(e => e.OnlineStatusEnum); - entity.Ignore(e => e.StatusEnum); entity.HasKey(e => e.Id).HasName("PRIMARY"); entity @@ -707,6 +695,9 @@ public partial class ImContext : DbContext entity.Property(e => e.Id) .HasColumnType("int(11)") .HasColumnName("ID"); + entity.Property(e => e.Avatar) + .HasMaxLength(255) + .HasComment("用户头像链接"); entity.Property(e => e.Created) .HasDefaultValueSql("'1970-01-01 00:00:00'") .HasComment("创建时间") diff --git a/backend/IM_API/Models/User.cs b/backend/IM_API/Models/User.cs index 97a63c5..0f6047d 100644 --- a/backend/IM_API/Models/User.cs +++ b/backend/IM_API/Models/User.cs @@ -52,6 +52,11 @@ public partial class User /// public sbyte IsDeleted { get; set; } + /// + /// 用户头像链接 + /// + public string? Avatar { get; set; } + public virtual ICollection Conversations { get; set; } = new List(); public virtual ICollection Devices { get; set; } = new List(); diff --git a/backend/IM_API/Program.cs b/backend/IM_API/Program.cs index 52e576e..8c2eab4 100644 --- a/backend/IM_API/Program.cs +++ b/backend/IM_API/Program.cs @@ -87,6 +87,15 @@ namespace IM_API return Task.CompletedTask; } }; + + options.Events = new JwtBearerEvents + { + OnAuthenticationFailed = context => + { + Console.WriteLine("Authentication failed: " + context.Exception.Message); + return Task.CompletedTask; + } + }; }); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle @@ -104,8 +113,9 @@ namespace IM_API app.UseHttpsRedirection(); - app.UseAuthorization(); app.UseAuthentication(); + app.UseAuthorization(); + app.MapControllers(); diff --git a/backend/IM_API/Services/AuthService.cs b/backend/IM_API/Services/AuthService.cs index 0746084..d4fd6b4 100644 --- a/backend/IM_API/Services/AuthService.cs +++ b/backend/IM_API/Services/AuthService.cs @@ -35,20 +35,10 @@ namespace IM_API.Services public async Task RegisterAsync(RegisterRequestDto dto) { string username = dto.Username; - string password = dto.Password; - string nickname = dto.NickName; //用户是否存在 bool isExist = await _context.Users.AnyAsync(x => x.Username == username); if (isExist) throw new BaseException(CodeDefine.USER_ALREADY_EXISTS); - User user = new User - { - Username = username, - Password = password, - NickName = nickname, - OnlineStatusEnum = UserOnlineStatus.Offline, - StatusEnum = UserStatus.Normal, - Created = DateTime.Now - }; + User user = _mapper.Map(dto); _context.Users.Add(user); await _context.SaveChangesAsync(); return _mapper.Map(user); diff --git a/backend/IM_API/Services/Demo.cs b/backend/IM_API/Services/Demo.cs deleted file mode 100644 index 4c12ef6..0000000 --- a/backend/IM_API/Services/Demo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using IM_API.Dtos; -using IM_API.Interface.Services; - -namespace IM_API.Services -{ - public class Demo : IDemo - { - public TestDto Test() - { - throw new NotImplementedException(); - } - } -} diff --git a/backend/IM_API/Services/FriendService.cs b/backend/IM_API/Services/FriendService.cs index 0ef256c..8564ebf 100644 --- a/backend/IM_API/Services/FriendService.cs +++ b/backend/IM_API/Services/FriendService.cs @@ -1,10 +1,67 @@ -using IM_API.Models; +using AutoMapper; +using IM_API.Dtos; +using IM_API.Interface.Services; +using IM_API.Models; using Microsoft.EntityFrameworkCore; namespace IM_API.Services { - public class FriendService + public class FriendService : IFriendSerivce { - + private readonly ImContext _context; + private readonly ILogger _logger; + private readonly IMapper _mapper; + public FriendService(ImContext context, ILogger logger, IMapper mapper) + { + _context = context; + _logger = logger; + _mapper = mapper; + } + + public Task BlockeFriendAsync(int friendId) + { + throw new NotImplementedException(); + } + + public Task BlockFriendByUserIdAsync(int userId, int toUserId) + { + throw new NotImplementedException(); + } + + public Task DeleteFriendAsync(int friendId) + { + throw new NotImplementedException(); + } + + public Task DeleteFriendByUserIdAsync(int userId, int toUserId) + { + throw new NotImplementedException(); + } + + public async Task> GetFriendListAsync(int userId, int page, int limit, bool desc) + { + var query = _context.Friends.Where(x => x.UserId == userId); + if (desc) + { + query = query.OrderByDescending(x => x.UserId); + } + 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) + { + throw new NotImplementedException(); + } + + public Task HandleFriendRequestAsync(HandleFriendRequestDto requestDto) + { + throw new NotImplementedException(); + } + + public Task SendFriendRequestAsync(FriendRequestDto friendRequest) + { + throw new NotImplementedException(); + } } } diff --git a/backend/IM_API/Services/UserService.cs b/backend/IM_API/Services/UserService.cs new file mode 100644 index 0000000..0608268 --- /dev/null +++ b/backend/IM_API/Services/UserService.cs @@ -0,0 +1,77 @@ +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 +{ + public class UserService : IUserService + { + private readonly ImContext _context; + private readonly ILogger _logger; + private readonly IMapper _mapper; + public UserService(ImContext imContext,ILogger logger,IMapper mapper) + { + this._context = imContext; + this._logger = logger; + this._mapper = mapper; + } + #region 获取用户信息 + public async Task GetUserInfoAsync(int userId) + { + var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId); + if (user == null) + { + throw new BaseException(CodeDefine.USER_NOT_FOUND); + } + return _mapper.Map(user); + } + #endregion + #region 通过用户名获取用户信息 + public async Task GetUserInfoByUsernameAsync(string username) + { + var user = await _context.Users.FirstOrDefaultAsync(x => x.Username == username); + if (user == null) + { + throw new BaseException(CodeDefine.USER_NOT_FOUND); + } + return _mapper.Map(user); + } + #endregion + #region 重置用户密码 + public async Task ResetPasswordAsync(int userId, string oldPassword, string password) + { + var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId); + if (user is null) throw new BaseException(CodeDefine.USER_NOT_FOUND); + //验证原密码 + if (user.Password != oldPassword) throw new BaseException(CodeDefine.PASSWORD_ERROR); + user.Password = password; + await _context.SaveChangesAsync(); + return true; + } + #endregion + #region 更新用户在线状态 + public async Task UpdateOlineStatusAsync(int userId,UserOnlineStatus onlineStatus) + { + var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId); + if (user is null) throw new BaseException(CodeDefine.USER_NOT_FOUND); + user.OnlineStatusEnum = onlineStatus; + await _context.SaveChangesAsync(); + return true; + } + #endregion + #region 更新用户信息 + public async Task UpdateUserAsync(int userId,UpdateUserDto dto) + { + var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId); + if (user is null) throw new BaseException(CodeDefine.USER_NOT_FOUND); + _mapper.Map(dto,user); + await _context.SaveChangesAsync(); + return _mapper.Map(user); + } + #endregion + } +} diff --git a/backend/IM_API/appsettings.json b/backend/IM_API/appsettings.json index 0b5706a..0ea93f2 100644 --- a/backend/IM_API/appsettings.json +++ b/backend/IM_API/appsettings.json @@ -7,7 +7,7 @@ }, "AllowedHosts": "*", "Jwt": { - "Key": "change_this_super_secret_key_in_prod", + "Key": "YourSuperSecretKey123456784124214190!", "Issuer": "IMDemo", "Audience": "IMClients", "AccessTokenMinutes": 15, diff --git a/docs/数据字典.md b/docs/数据字典.md index 519a51b..b8c4004 100644 --- a/docs/数据字典.md +++ b/docs/数据字典.md @@ -4,29 +4,32 @@ #### 表说明:储存用户个人信息 -| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 | -| ----------- | ----------- | -------- | -------- | ------- | --------- | ------------------------------------------------ | --------- | -| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 | -| Username | VARCHAR(50) | 是 | / | / | 唯一 | 唯一用户名 | admin | -| Password | VARCHAR(50) | 是 | / | / | / | 用户密码 | 123456 | -| NickName | VARCHAR(50) | 是 | / | / | / | 用户昵称 | / | -| OlineStatus | TINYINT | 是 | 0 | / | / | 用户在线状态
0(默认):不在线
1:在线 | 0 | -| Created | DATETIME | 是 | 1970/1/1 | / | / | 账户创建时间 | 2025/9/29 | -| Updated | DATETIME | 否 | / | / | / | 账户修改时间 | 2024/9/29 | -| Status | TINYINT | 是 | 1 | / | / | 账户状态
(0:未激活,1:正常,2:封禁) | 1 | -| IsDeleted | TINYINT | 是 | 0 | / | / | 软删除标识
0:账号正常
1:账号已删除 | 0 | +| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 | +| ----------- | ------------ | -------- | -------- | ------- | --------- | ------------------------------------------------ | ----------------------- | +| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 | +| Username | VARCHAR(50) | 是 | / | / | 唯一 | 唯一用户名 | admin | +| Avatar | VARCHAR(255) | 否 | / | / | / | 用户头像 | https://baidu.com/1.png | +| Password | VARCHAR(50) | 是 | / | / | / | 用户密码 | 123456 | +| NickName | VARCHAR(50) | 是 | / | / | / | 用户昵称 | / | +| OlineStatus | TINYINT | 是 | 0 | / | / | 用户在线状态
0(默认):不在线
1:在线 | 0 | +| Created | DATETIME | 是 | 1970/1/1 | / | / | 账户创建时间 | 2025/9/29 | +| Updated | DATETIME | 否 | / | / | / | 账户修改时间 | 2024/9/29 | +| Status | TINYINT | 是 | 1 | / | / | 账户状态
(0:未激活,1:正常,2:封禁) | 1 | +| IsDeleted | TINYINT | 是 | 0 | / | / | 软删除标识
0:账号正常
1:账号已删除 | 0 | ### 表名:Friends #### 表说明:好友关系映射 -| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 | -| -------- | -------- | -------- | -------- | ---------------- | --------- | ------------------------------------------------------------ | --------- | -| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 | -| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 用户ID | 1 | -| FriendId | INT | 是 | / | 外键(Users.Id) | 索引 | 用户2ID | 2 | -| Status | TINYINT | 是 | 0 | / | / | 当前好友关系状态
(0:待通过,1:已添加,2:已拒绝,3:已拉黑) | 0 | -| Created | DATETIME | 是 | 1970/1/1 | / | / | 好友关系创建时间 | 2025/9/29 | +| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 | +| ---------- | ------------ | -------- | -------- | ---------------- | --------- | ------------------------------------------------------------ | ----------------------- | +| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 | +| UserId | INT | 是 | / | 外键(Users.Id) | 索引 | 用户ID | 1 | +| FriendId | INT | 是 | / | 外键(Users.Id) | 索引 | 用户2ID | 2 | +| RemarkName | VARCHAR(20) | 是 | / | / | / | 好友备注 | 小王 | +| Avatar | VARCHAR(255) | 否 | / | / | / | 好友头像 | https://baidu.com/1.png | +| Status | TINYINT | 是 | 0 | / | / | 当前好友关系状态
(0:待通过,1:已添加,2:已拒绝,3:已拉黑) | 0 | +| Created | DATETIME | 是 | 1970/1/1 | / | / | 好友关系创建时间 | 2025/9/29 | ### 表名:Groups