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.
337 lines
11 KiB
337 lines
11 KiB
2 years ago
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|