Merge pull request 'feature-nxdev' (#20) from feature-nxdev into main

Reviewed-on: #20
This commit is contained in:
西街长安 2025-11-27 16:56:37 +08:00
commit 4c7bdbe9fc
25 changed files with 479 additions and 83 deletions

View File

@ -9,6 +9,23 @@ namespace IM_API.Configs
public MapperConfig()
{
CreateMap<User, UserInfoDto>();
//用户信息更新模型转换
CreateMap<UpdateUserDto, User>()
.ForMember(dest => dest.Updated,opt => opt.MapFrom(src => DateTime.Now))
.ForAllMembers(opts => opts.Condition((src,dest,srcMember) => srcMember != null));
//用户注册模型转换
CreateMap<RegisterRequestDto, User>()
.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<Friend, FriendInfoDto>();
}
}
}

View File

@ -9,6 +9,7 @@ namespace IM_API.Configs
{
services.AddAutoMapper(typeof(MapperConfig));
services.AddTransient<IAuthService, AuthService>();
services.AddTransient<IUserService, UserService>();
services.AddSingleton<IJWTService, JWTService>();
services.AddSingleton<IRefreshTokenService,RedisRefreshTokenService>();
return services;

View File

@ -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<AuthController> _logger;
private readonly IAuthService _authService;
private readonly IUserService _userService;
private readonly IJWTService _jwtService;
private readonly IRefreshTokenService _refreshTokenService;
private readonly IConfiguration _configuration;
public AuthController(ILogger<AuthController> logger, IAuthService authService, IJWTService jwtService, IRefreshTokenService refreshTokenService, IConfiguration configuration)
public AuthController(ILogger<AuthController> 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<IActionResult> Login(LoginRequestDto dto)
@ -33,5 +37,26 @@ namespace IM_API.Controllers
var res = new BaseResponse<LoginDto>(new LoginDto(user.Id,token,refreshToken,expiresAt));
return Ok(res);
}
[HttpPost]
public async Task<IActionResult> Register(RegisterRequestDto dto)
{
var userInfo = await _authService.RegisterAsync(dto);
var res = new BaseResponse<UserInfoDto>(userInfo);
return Ok(res);
}
[HttpPost]
public async Task<IActionResult> Refresh(RefreshDto dto)
{
(bool ok,int userId) = await _refreshTokenService.ValidateRefreshTokenAsync(dto.refreshToken);
if (!ok)
{
var err = new BaseResponse<LoginDto>(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<LoginDto>(new LoginDto(userinfo.Id,token,dto.refreshToken,expiresAt));
return Ok(res);
}
}
}

View File

@ -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<UserController> _logger;
public UserController(IUserService userService, ILogger<UserController> logger)
{
_userService = userService;
_logger = logger;
}
/// <summary>
/// 获取当前用户信息
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Me()
{
var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier);
int userId = int.Parse(userIdStr);
var userinfo = await _userService.GetUserInfoAsync(userId);
var res = new BaseResponse<UserInfoDto>(userinfo);
return Ok(res);
}
/// <summary>
/// 修改用户资料
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> 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<UserInfoDto>(userinfo);
return Ok(res);
}
/// <summary>
/// ID查询用户
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Find(int userId)
{
var userinfo = await _userService.GetUserInfoAsync(userId);
var res = new BaseResponse<UserInfoDto>(userinfo);
return Ok(res);
}
/// <summary>
/// 用户名查询用户
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Find(string username)
{
var userinfo = await _userService.GetUserInfoByUsernameAsync(username);
var res = new BaseResponse<UserInfoDto>(userinfo);
return Ok(res);
}
/// <summary>
/// 重置用户密码
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> 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<object?>());
}
/// <summary>
/// 设置在线状态
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> SetOnlineStatus(OnlineStatusSetDto dto)
{
var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier);
int userId = int.Parse(userIdStr);
await _userService.UpdateOlineStatusAsync(userId, dto.OnlineStatus);
return Ok(new BaseResponse<object?>());
}
}
}

View File

@ -0,0 +1,4 @@
namespace IM_API.Dtos
{
public record RefreshDto(string refreshToken);
}

View File

@ -64,6 +64,15 @@ namespace IM_API.Dtos
Code = code;
Message = message;
}
/// <summary>
/// 接受codedefine对象
/// </summary>
/// <param name="codeDefine"></param>
public BaseResponse(CodeDefine codeDefine)
{
this.Code = codeDefine.Code;
this.Message = codeDefine.Message;
}
public BaseResponse() { }
}
}

View File

@ -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);
}

View File

@ -3,5 +3,7 @@
public class UpdateUserDto
{
public string? NickName { get; set; }
public string? Avatar { get; set; }
}
}

View File

@ -0,0 +1,7 @@
using IM_API.Models;
namespace IM_API.Dtos
{
public record PasswordResetDto(string oldPassword,string Password);
public record OnlineStatusSetDto(UserOnlineStatus OnlineStatus);
}

View File

@ -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在线
/// </summary>
public sbyte OlineStatus { get; set; }
public UserOnlineStatus OnlineStatusEnum { get; set; }
/// <summary>
/// 创建时间
@ -33,6 +34,6 @@ namespace IM_API.Dtos
/// 账户状态
/// (0未激活,1正常,2封禁)
/// </summary>
public sbyte Status { get; set; }
public UserStatus StatusEnum { get; set; }
}
}

View File

@ -1,9 +0,0 @@
using IM_API.Dtos;
namespace IM_API.Interface.Services
{
public interface IDemo
{
TestDto Test();
}
}

View File

@ -12,7 +12,7 @@ namespace IM_API.Interface.Services
/// <param name="page">当前页</param>
/// <param name="limit">分页大小</param>
/// <returns></returns>
Task<List<UserInfoDto>> GetFriendListAsync(int userId,int page,int limit);
Task<List<FriendInfoDto>> GetFriendListAsync(int userId,int page,int limit,bool desc);
/// <summary>
/// 新增好友请求
/// </summary>
@ -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);
Task<FriendRequest> GetFriendRequestListAsync(int userId,bool isReceived,int page,int limit, bool desc);
/// <summary>
/// 处理好友请求
/// </summary>

View File

@ -22,18 +22,18 @@ namespace IM_API.Interface.Services
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
Task<UserInfoDto> UpdateUserAsync(UpdateUserDto dto);
Task<UserInfoDto> UpdateUserAsync(int userId, UpdateUserDto dto);
/// <summary>
/// 重置用户密码
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
Task<bool> ResetPasswordAsync(string password);
Task<bool> ResetPasswordAsync(int userId, string oldPassword, string password);
/// <summary>
/// 更新用户在线状态
/// </summary>
/// <param name="onlineStatus"></param>
/// <returns></returns>
Task<bool> UpdateOlineStatusAsync(UserOnlineStatus onlineStatus);
Task<bool> UpdateOlineStatusAsync(int userId, UserOnlineStatus onlineStatus);
}
}

View File

@ -28,6 +28,16 @@ public partial class Friend
/// </summary>
public DateTime Created { get; set; }
/// <summary>
/// 好友备注名
/// </summary>
public string RemarkName { get; set; } = null!;
/// <summary>
/// 好友头像
/// </summary>
public string? Avatar { get; set; }
public virtual User FriendNavigation { get; set; } = null!;
public virtual User User { get; set; } = null!;

View File

@ -21,6 +21,7 @@ public partial class GroupMember
/// 成员角色0:普通成员,1:管理员,2:群主)
/// </summary>
public sbyte Role { get; set; }
/// <summary>
/// 加入群聊时间
/// </summary>

View File

@ -0,0 +1,99 @@
using Microsoft.EntityFrameworkCore;
namespace IM_API.Models
{
public partial class ImContext
{
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Admin>(entity =>
{
entity.Ignore(e => e.StateEnum);
});
modelBuilder.Entity<User>(entity =>
{
entity.Ignore(e => e.OnlineStatusEnum);
entity.Ignore(e => e.StatusEnum);
entity.HasQueryFilter(e => e.IsDeleted == 0);
});
modelBuilder.Entity<Conversation>(entity =>
{
});
modelBuilder.Entity<Device>(entity =>
{
entity.Ignore(e => e.DtypeEnum);
});
modelBuilder.Entity<File>(entity =>
{
});
modelBuilder.Entity<Friend>(entity =>
{
entity.Ignore(e => e.StatusEnum);
});
modelBuilder.Entity<FriendRequest>(entity =>
{
entity.Ignore(e => e.StateEnum);
});
modelBuilder.Entity<Group>(entity =>
{
entity.Ignore(e => e.StatusEnum);
entity.Ignore(e => e.AllMembersBannedEnum);
entity.Ignore(e => e.AuhorityEnum);
});
modelBuilder.Entity<GroupInvite>(entity =>
{
entity.Ignore(e => e.StateEnum);
});
modelBuilder.Entity<GroupMember>(entity =>
{
entity.Ignore(e => e.RoleEnum);
});
modelBuilder.Entity<GroupRequest>(entity =>
{
entity.Ignore(e => e.StateEnum);
});
modelBuilder.Entity<LoginLog>(entity =>
{
entity.Ignore(e => e.StateEnum);
});
modelBuilder.Entity<Message>(entity =>
{
entity.Ignore(e => e.StateEnum);
entity.Ignore(e => e.MsgTypeEnum);
});
modelBuilder.Entity<Notification>(entity =>
{
});
modelBuilder.Entity<Permission>(entity =>
{
});
modelBuilder.Entity<Permissionarole>(entity =>
{
});
modelBuilder.Entity<Role>(entity =>
{
});
}
}
}

View File

@ -62,7 +62,6 @@ public partial class ImContext : DbContext
modelBuilder.Entity<Admin>(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<Conversation>(entity =>
{
entity.HasKey(e => e.Id).HasName("PRIMARY");
entity
@ -147,7 +145,6 @@ public partial class ImContext : DbContext
modelBuilder.Entity<Device>(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<Friend>(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\n0待通过,1已添加,2已拒绝,3已拉黑")
.HasColumnType("tinyint(4)");
@ -262,7 +264,6 @@ public partial class ImContext : DbContext
modelBuilder.Entity<FriendRequest>(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<Group>(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<GroupInvite>(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<GroupMember>(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<GroupRequest>(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<LoginLog>(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<Message>(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<User>(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("创建时间")

View File

@ -52,6 +52,11 @@ public partial class User
/// </summary>
public sbyte IsDeleted { get; set; }
/// <summary>
/// 用户头像链接
/// </summary>
public string? Avatar { get; set; }
public virtual ICollection<Conversation> Conversations { get; set; } = new List<Conversation>();
public virtual ICollection<Device> Devices { get; set; } = new List<Device>();

View File

@ -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();

View File

@ -35,20 +35,10 @@ namespace IM_API.Services
public async Task<UserInfoDto> 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<User>(dto);
_context.Users.Add(user);
await _context.SaveChangesAsync();
return _mapper.Map<UserInfoDto>(user);

View File

@ -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();
}
}
}

View File

@ -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<FriendService> _logger;
private readonly IMapper _mapper;
public FriendService(ImContext context, ILogger<FriendService> logger, IMapper mapper)
{
_context = context;
_logger = logger;
_mapper = mapper;
}
public Task<bool> BlockeFriendAsync(int friendId)
{
throw new NotImplementedException();
}
public Task<bool> BlockFriendByUserIdAsync(int userId, int toUserId)
{
throw new NotImplementedException();
}
public Task<bool> DeleteFriendAsync(int friendId)
{
throw new NotImplementedException();
}
public Task<bool> DeleteFriendByUserIdAsync(int userId, int toUserId)
{
throw new NotImplementedException();
}
public async Task<List<FriendInfoDto>> 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<List<FriendInfoDto>>(friendList);
}
public Task<FriendRequest> GetFriendRequestListAsync(int userId, bool isReceived, int page, int limit, bool desc)
{
throw new NotImplementedException();
}
public Task<bool> HandleFriendRequestAsync(HandleFriendRequestDto requestDto)
{
throw new NotImplementedException();
}
public Task<bool> SendFriendRequestAsync(FriendRequestDto friendRequest)
{
throw new NotImplementedException();
}
}
}

View File

@ -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<UserService> _logger;
private readonly IMapper _mapper;
public UserService(ImContext imContext,ILogger<UserService> logger,IMapper mapper)
{
this._context = imContext;
this._logger = logger;
this._mapper = mapper;
}
#region
public async Task<UserInfoDto> 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<UserInfoDto>(user);
}
#endregion
#region
public async Task<UserInfoDto> 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<UserInfoDto>(user);
}
#endregion
#region
public async Task<bool> 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<bool> 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<UserInfoDto> 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<UserInfoDto>(user);
}
#endregion
}
}

View File

@ -7,7 +7,7 @@
},
"AllowedHosts": "*",
"Jwt": {
"Key": "change_this_super_secret_key_in_prod",
"Key": "YourSuperSecretKey123456784124214190!",
"Issuer": "IMDemo",
"Audience": "IMClients",
"AccessTokenMinutes": 15,

View File

@ -4,29 +4,32 @@
#### 表说明:储存用户个人信息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| ----------- | ----------- | -------- | -------- | ------- | --------- | ------------------------------------------------ | --------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| Username | VARCHAR(50) | 是 | / | / | 唯一 | 唯一用户名 | admin |
| Password | VARCHAR(50) | 是 | / | / | / | 用户密码 | 123456 |
| NickName | VARCHAR(50) | 是 | / | / | / | 用户昵称 | / |
| OlineStatus | TINYINT | 是 | 0 | / | / | 用户在线状态<br />0默认不在线<br />1在线 | 0 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 账户创建时间 | 2025/9/29 |
| Updated | DATETIME | 否 | / | / | / | 账户修改时间 | 2024/9/29 |
| Status | TINYINT | 是 | 1 | / | / | 账户状态<br />(0未激活,1正常,2封禁) | 1 |
| IsDeleted | TINYINT | 是 | 0 | / | / | 软删除标识<br />0账号正常<br />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 | / | / | 用户在线状态<br />0默认不在线<br />1在线 | 0 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 账户创建时间 | 2025/9/29 |
| Updated | DATETIME | 否 | / | / | / | 账户修改时间 | 2024/9/29 |
| Status | TINYINT | 是 | 1 | / | / | 账户状态<br />(0未激活,1正常,2封禁) | 1 |
| IsDeleted | TINYINT | 是 | 0 | / | / | 软删除标识<br />0账号正常<br />1账号已删除 | 0 |
### 表名Friends
#### 表说明:好友关系映射
| 字段名 | 数据类型 | 是否必填 | 默认值 | 主/外键 | 约束/索引 | 字段说明 | 示例值 |
| -------- | -------- | -------- | -------- | ---------------- | --------- | ------------------------------------------------------------ | --------- |
| Id | INT | 是 | / | 主键 | 索引 | 主键自增 | 1 |
| UserId | INT | 是 | / | 外键Users.Id | 索引 | 用户ID | 1 |
| FriendId | INT | 是 | / | 外键Users.Id | 索引 | 用户2ID | 2 |
| Status | TINYINT | 是 | 0 | / | / | 当前好友关系状态<br />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 | / | / | 当前好友关系状态<br />0待通过,1已添加,2已拒绝,3已拉黑 | 0 |
| Created | DATETIME | 是 | 1970/1/1 | / | / | 好友关系创建时间 | 2025/9/29 |
### 表名Groups