You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
11 KiB
336 lines
11 KiB
using AX.FireTrainingSys.DTOs; |
|
using AX.FireTrainingSys.Models; |
|
using Microsoft.AspNetCore.Authorization; |
|
using Microsoft.AspNetCore.Http; |
|
using Microsoft.AspNetCore.Mvc; |
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
|
using Microsoft.EntityFrameworkCore; |
|
using System; |
|
using System.Collections.Generic; |
|
using System.Diagnostics.CodeAnalysis; |
|
using System.Linq; |
|
using System.Text.RegularExpressions; |
|
using System.Threading.Tasks; |
|
using static BCrypt.Net.BCrypt; |
|
|
|
namespace AX.FireTrainingSys.Controllers |
|
{ |
|
/// <summary> |
|
/// 用户控制器。 |
|
/// </summary> |
|
[Produces("application/json")] |
|
[Route("api/[controller]")] |
|
[ApiVersion("1.0")] |
|
[Authorize(Roles = nameof(RoleType.Admin))] |
|
[ApiController] |
|
public class UsersController : ControllerBase |
|
{ |
|
private readonly DriveDbContext dbContext; |
|
|
|
public UsersController(DriveDbContext dbContext) |
|
{ |
|
this.dbContext = dbContext; |
|
} |
|
|
|
/// <summary> |
|
/// 获得所有用户信息。 |
|
/// </summary> |
|
/// <param name="options">查询条件</param> |
|
/// <returns></returns> |
|
[ProducesResponseType(StatusCodes.Status400BadRequest)] |
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)] |
|
[ProducesResponseType(StatusCodes.Status403Forbidden)] |
|
[ProducesResponseType(StatusCodes.Status200OK)] |
|
[HttpGet] |
|
public async Task<ActionResult<Page<UserInfo>>> Get([FromQuery] UserQueryOptions options) |
|
{ |
|
if (options.PageNumber == default) |
|
options.PageNumber = 1; |
|
|
|
if (options.PageSize == default) |
|
options.PageSize = 10; |
|
|
|
if (options.RoleType == default) |
|
options.RoleType = RoleType.Student; |
|
|
|
var query = dbContext.Users |
|
.Include(e => e.Posts).ThenInclude(e => e.Post) |
|
.AsNoTracking(); |
|
|
|
query = query.Where(e => e.RoleType == options.RoleType); |
|
|
|
if (!string.IsNullOrEmpty(options.Name)) |
|
query = query.Where(e => e.Name.Contains(options.Name)); |
|
|
|
if (!string.IsNullOrEmpty(options.RealName)) |
|
query = query.Where(e => e.RealName.Contains(options.RealName)); |
|
|
|
var count = await query.CountAsync(); |
|
|
|
query = query.OrderByDescending(e => e.CreationTime); |
|
|
|
if (options.PageNumber > 1) |
|
query = query.Skip((options.PageNumber.Value - 1) * options.PageSize.Value); |
|
|
|
query = query.Take(options.PageSize.Value); |
|
|
|
var items = await query.Select(e => e.ToDTO()) |
|
.ToListAsync(); |
|
|
|
var page = new Page<UserInfo> |
|
{ |
|
PageNumber = (int)options.PageNumber, |
|
PageSize = (int)options.PageSize, |
|
TotalPages = (int)Math.Ceiling((double)count / (int)options.PageSize), |
|
TotalCount = count, |
|
Items = items |
|
}; |
|
|
|
return Ok(page); |
|
} |
|
|
|
/// <summary> |
|
/// 创建用户。 |
|
/// </summary> |
|
/// <param name="info">用户信息</param> |
|
/// <returns></returns> |
|
//[ProducesResponseType(ErrorCodes.E610)] |
|
[ProducesResponseType(StatusCodes.Status400BadRequest)] |
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)] |
|
[ProducesResponseType(StatusCodes.Status403Forbidden)] |
|
[ProducesResponseType(StatusCodes.Status201Created)] |
|
[HttpPost] |
|
public async Task<ActionResult<UserInfo>> Post([FromBody] UserInfo info) |
|
{ |
|
if (string.IsNullOrEmpty(info.Name)) |
|
return BadRequest(info); |
|
|
|
if (info.RoleType == RoleType.Teacher) |
|
{ |
|
if (!Regex.IsMatch(info.Name, RegexHelper.Username)) |
|
return BadRequest(info); |
|
} |
|
else if (info.RoleType == RoleType.Student) |
|
{ |
|
if (!Regex.IsMatch(info.Name, RegexHelper.IdentityCard)) |
|
return BadRequest(info); |
|
} |
|
else |
|
return BadRequest(info); |
|
|
|
await using (var transaction = dbContext.Database.BeginTransaction()) |
|
{ |
|
var model = await dbContext.Users |
|
.AsNoTracking() |
|
.Where(e => e.Name == info.Name) |
|
.FirstOrDefaultAsync(); |
|
|
|
if (model != default) |
|
return this.ErrorCode(ErrorCodes.E610); |
|
|
|
model = info.ToModel(); |
|
|
|
//处理多对多关系 |
|
if (info.Posts != default && info.Posts.Any()) |
|
{ |
|
var list = new List<UserPost>(info.Posts.Count); |
|
|
|
foreach (var post in info.Posts) |
|
{ |
|
list.Add(new UserPost |
|
{ |
|
User = model, |
|
PostId = post.Id |
|
}); |
|
} |
|
|
|
dbContext.Set<UserPost>().AddRange(list); |
|
} |
|
|
|
dbContext.Users.Add(model); |
|
|
|
await dbContext.SaveChangesAsync(); |
|
await transaction.CommitAsync(); |
|
|
|
var result = model.ToDTO(); |
|
|
|
return CreatedAtAction(nameof(Post), result); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 修改用户。 |
|
/// </summary> |
|
/// <param name="name">用户帐号(身份证号)</param> |
|
/// <param name="info">用户信息</param> |
|
/// <returns></returns> |
|
//[ProducesResponseType(ErrorCodes.E610)] |
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)] |
|
[ProducesResponseType(StatusCodes.Status403Forbidden)] |
|
[ProducesResponseType(StatusCodes.Status404NotFound)] |
|
[ProducesResponseType(StatusCodes.Status204NoContent)] |
|
[HttpPut("{name}")] |
|
public async Task<Microsoft.AspNetCore.Mvc.ActionResult> Put(string name, [FromBody] UserInfo info) |
|
{ |
|
if (name != info.Name) |
|
return BadRequest($"{nameof(name)} and {nameof(info.Name)} are not equal."); |
|
|
|
if (info.RoleType == RoleType.Admin) |
|
return BadRequest(info); |
|
|
|
await using (var transaction = dbContext.Database.BeginTransaction()) |
|
{ |
|
var model = await dbContext.Users |
|
.Include(e => e.Posts) |
|
.Where(e => e.Name == info.Name) |
|
.FirstOrDefaultAsync(); |
|
|
|
if (model == default) |
|
return NotFound(); |
|
|
|
info.MapTo(model); |
|
|
|
//处理多对多关系 |
|
if (info.Posts != default && info.Posts.Any()) |
|
{ |
|
var posts = model.Posts; |
|
|
|
var list = new List<UserPost>(info.Posts.Count); |
|
|
|
foreach (var post in info.Posts) |
|
{ |
|
list.Add(new UserPost |
|
{ |
|
UserId = model.Id, |
|
PostId = post.Id |
|
}); |
|
} |
|
|
|
var comparer = new UserPostComparer(); |
|
|
|
var removeItems = posts.Except(list, comparer); |
|
var addItems = list.Except(posts, comparer); |
|
|
|
dbContext.Set<UserPost>().RemoveRange(removeItems); |
|
dbContext.Set<UserPost>().AddRange(addItems); |
|
} |
|
|
|
await dbContext.SaveChangesAsync(); |
|
await transaction.CommitAsync(); |
|
|
|
return NoContent(); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 重置密码。 |
|
/// </summary> |
|
/// <param name="name">用户帐号(身份证号)</param> |
|
/// <returns></returns> |
|
[ProducesResponseType(StatusCodes.Status400BadRequest)] |
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)] |
|
[ProducesResponseType(StatusCodes.Status403Forbidden)] |
|
[ProducesResponseType(StatusCodes.Status404NotFound)] |
|
[ProducesResponseType(StatusCodes.Status204NoContent)] |
|
[HttpPut("{name}/ResetPassword")] |
|
public async Task<Microsoft.AspNetCore.Mvc.ActionResult> Put(string name) |
|
{ |
|
var model = await dbContext.Users.FirstOrDefaultAsync(e => e.Name == name); |
|
|
|
if (model == default) |
|
return NotFound(); |
|
|
|
model.ResetPassword(); |
|
|
|
await dbContext.SaveChangesAsync(); |
|
|
|
return NoContent(); |
|
} |
|
|
|
/// <summary> |
|
/// 删除用户。 |
|
/// </summary> |
|
/// <param name="name">用户帐号(身份证号)</param> |
|
/// <returns></returns> |
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)] |
|
[ProducesResponseType(StatusCodes.Status403Forbidden)] |
|
[ProducesResponseType(StatusCodes.Status404NotFound)] |
|
[ProducesResponseType(StatusCodes.Status204NoContent)] |
|
[HttpDelete("{name}")] |
|
public async Task<Microsoft.AspNetCore.Mvc.ActionResult> Delete(string name) |
|
{ |
|
if (name == "admin") |
|
return Forbid(); |
|
|
|
var model = await dbContext.Users |
|
.Where(e => e.Name == name) |
|
.FirstOrDefaultAsync(); |
|
|
|
if (model == default) |
|
return NotFound(); |
|
|
|
model.Deleted = true; |
|
model.Name = $"{model.Name}-{ObjectId.NewId()}"; |
|
|
|
await dbContext.SaveChangesAsync(); |
|
|
|
return NoContent(); |
|
} |
|
} |
|
|
|
internal static partial class Extensions |
|
{ |
|
private const string DefaultPassword = "12345678"; |
|
|
|
public static UserInfo ToDTO(this User model) => new UserInfo |
|
{ |
|
Name = model.Name, |
|
RealName = model.RealName, |
|
RoleType = model.RoleType, |
|
Enabled = model.Enabled, |
|
CreationTime = model.CreationTime.ToLocalTime(), |
|
Posts = model.Posts?.Select(e => e.Post?.ToDTO()).ToList() |
|
}; |
|
|
|
public static ProfileInfo ToDTO2(this User model) => new ProfileInfo |
|
{ |
|
Id = model.Id, |
|
Name = model.Name, |
|
RealName = model.RealName, |
|
RoleType = model.RoleType, |
|
Enabled = model.Enabled, |
|
CreationTime = model.CreationTime.ToLocalTime(), |
|
Posts = model.Posts.Select(e => e.Post?.ToDTO()).ToList() |
|
}; |
|
|
|
public static User ToModel(this UserInfo dto) => new User |
|
{ |
|
Name = dto.Name, |
|
Password = HashPassword(DefaultPassword), |
|
RealName = dto.RealName, |
|
RoleType = dto.RoleType |
|
}; |
|
|
|
//专用于数据同步 |
|
public static User ToModel2(this UserInfo dto) => new User |
|
{ |
|
Name = dto.Name, |
|
Password = HashPassword(DefaultPassword), |
|
RealName = dto.RealName, |
|
RoleType = dto.RoleType, |
|
Enabled = dto.Enabled ?? true |
|
}; |
|
|
|
public static void MapTo(this UserInfo dto, User model) |
|
{ |
|
model.RealName = dto.RealName; |
|
model.RoleType = dto.RoleType; |
|
model.Enabled = dto.Enabled ?? true; |
|
} |
|
|
|
public static void ResetPassword(this User model) |
|
{ |
|
model.Password = HashPassword(DefaultPassword); |
|
} |
|
} |
|
}
|
|
|