V 0.0.1 添加软件的基础配置

This commit is contained in:
lq1405 2024-10-18 12:44:12 +08:00
parent b2ea31de40
commit 3927fd21b5
17 changed files with 506 additions and 60 deletions

View File

@ -0,0 +1,11 @@
namespace LMS.Common.Dictionary;
public class AllOptions
{
public static readonly Dictionary<string, List<string>> AllOptionsRequestQuery = new()
{
{ "all", [] },
{ "tts", ["EdgeTTsRoles"] },
{ "software", ["LaitoolHomePage", "LaitoolNotice", "LaitoolUpdateContent","LaitoolVersion"]}
};
}

View File

@ -0,0 +1,11 @@
namespace LMS.Common.Dictionary;
public class SimpleOptions
{
public static readonly Dictionary<string, List<string>> SimpleOptionsRequestQuery = new()
{
{ "ttsrole", ["EdgeTTsRoles"] },
{ "laitoolinfo", ["LaitoolHomePage", "LaitoolNotice", "LaitoolUpdateContent", "LaitoolVersion"] },
};
}

View File

@ -0,0 +1,8 @@
namespace LMS.Common.Enum;
public enum OptionTypeEnum
{
String = 1,
JSON = 2,
Number = 3,
}

View File

@ -193,6 +193,13 @@ namespace LMS.Common.Enums
RoleHasUser = 9004,
#endregion
#region
[Result(ResponseString.DataNotExist)]
[Description("没有找到指定的配置项")]
FindOptionsFail = 10001,
#endregion
}
}
}

View File

@ -28,6 +28,8 @@ namespace LMS.DAO
public DbSet<RsaKeys> RsaKeys { get; set; }
public DbSet<Options> Options { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

View File

@ -0,0 +1,61 @@
using LMS.Common.Enum;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace LMS.Repository.DB;
public class Options
{
[Key]
public required string Key { get; set; } = string.Empty;
/// <summary>
/// Value of the option这个值是一个json字符串
/// </summary>
public string? Value { get; set; } = string.Empty;
public OptionTypeEnum Type { get; set; } = OptionTypeEnum.String;
// 写一个字段映射Value判断是不是json字符串是的话就解析成对象
[NotMapped]
public object? ValueObject
{
get
{
if (string.IsNullOrEmpty(Value))
{
return Value;
}
if (Type == OptionTypeEnum.JSON)
{
return JsonConvert.DeserializeObject(Value ?? "{}");
}
if (Type == OptionTypeEnum.Number)
{
return Convert.ToDouble(Value);
}
return Value;
}
set
{
if (value == null)
{
Value = string.Empty;
return;
}
if (Type == OptionTypeEnum.JSON)
{
Value = JsonConvert.SerializeObject(value);
}
else
{
Value = value.ToString();
}
}
}
}

View File

@ -0,0 +1,16 @@
using LMS.Common.Enum;
using System.ComponentModel.DataAnnotations;
namespace LMS.Repository.DTO;
public class OptionsDto
{
public required string Key { get; set; } = string.Empty;
/// <summary>
/// Value of the option这个值是一个json字符串
/// </summary>
public string? Value { get; set; }
public OptionTypeEnum Type { get; set; } = OptionTypeEnum.String;
}

View File

@ -12,6 +12,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
namespace LMS.Repository.Options;
public class ModofyOptionsModel
{
[Required]
public required string Key { get; set; }
[Required]
public string Value { get; set; } = string.Empty;
}

View File

@ -1,4 +1,5 @@
using AutoMapper;
using LMS.Repository.DB;
using LMS.Repository.DTO;
using LMS.Repository.DTO.UserDto;
using LMS.Repository.Models.DB;
@ -26,6 +27,9 @@ namespace Lai_server.Configuration
CreateMap<User, UserDto>();
CreateMap<User, UserBaseDto>();
CreateMap<Options, OptionsDto>();
}
}
}

View File

@ -1,8 +1,11 @@
using LMS.DAO;
using LMS.Repository.DB;
using LMS.Repository.Models.DB;
using LMS.Tools.Extensions;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using LMS.Common.Enum;
using System.Threading;
using static LMS.Common.Enums.ResponseCodeEnum;
namespace LMS.service.Configuration.InitConfiguration;
@ -14,18 +17,19 @@ namespace LMS.service.Configuration.InitConfiguration;
public class DatabaseConfiguration(IServiceProvider serviceProvider) : IHostedService
{
private readonly IServiceProvider _serviceProvider = serviceProvider;
public async Task StartAsync(CancellationToken cancellationToken)
/// <summary>
/// 检查用户和角色是否创建,如果没有则创建超级管理员和默认角色
/// </summary>
/// <param name="context">数据库上下文</param>
/// <param name="userManager">用户管理器</param>
/// <param name="roleManager">角色管理器</param>
/// <param name="cancellationToken">取消令牌</param>
private static async Task CheckUserAndRoleNotCreat(ApplicationDbContext context, UserManager<User> userManager, RoleManager<Role> roleManager, CancellationToken cancellationToken)
{
using var scope = _serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<Role>>();
using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
try
{
// 判断数据库中是不是超级管理员,没有创建一个
// 要是没有用户,默认没有
User? user = await dbContext.Users.FirstOrDefaultAsync(x => x.UserName == "admin", cancellationToken: cancellationToken);
// 判断数据库中是否存在超级管理员,如果不存在则创建一个
// 如果没有用户,默认没有超级管理员
User? user = await context.Users.FirstOrDefaultAsync(x => x.UserName == "admin", cancellationToken: cancellationToken);
if (user != null)
{
return;
@ -77,11 +81,56 @@ public class DatabaseConfiguration(IServiceProvider serviceProvider) : IHostedSe
Console.WriteLine(indentiyResult.Succeeded);
}
}
// 判断判断admin是不是超级管理员不是的话添加
// 判断admin是否为超级管理员如果不是添加
if (!await userManager.IsInRoleAsync(admin, "Super Admin"))
{
await userManager.AddToRoleAsync(admin, "Super Admin");
}
}
/// <summary>
/// 检查所有的配置项,没有的话,创建
/// </summary>
/// <param name="dbContext"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private static async Task CheckOptionsNotCreat(ApplicationDbContext dbContext, CancellationToken cancellationToken)
{
List<Options> optionsKeyValue = [
new Options { Key = "EdgeTTsRoles", Value = "[]", Type = OptionTypeEnum.JSON },
new Options { Key = "LaitoolHomePage", Value = string.Empty, Type = OptionTypeEnum.String },
new Options { Key = "LaitoolUpdateContent", Value = string.Empty, Type = OptionTypeEnum.String },
new Options { Key = "LaitoolNotice", Value = string.Empty, Type = OptionTypeEnum.String },
new Options { Key = "LaitoolVersion", Value = string.Empty, Type = OptionTypeEnum.String },
];
// 遍历所有的配置项,如果没有则添加
foreach (var item in optionsKeyValue)
{
Options? options = await dbContext.Options.FirstOrDefaultAsync(x => x.Key == item.Key, cancellationToken: cancellationToken);
if (options == null)
{
await dbContext.Options.AddAsync(item, cancellationToken);
}
}
}
public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<Role>>();
using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
try
{
// 检查用户和角色是否创建
await CheckUserAndRoleNotCreat(dbContext, userManager, roleManager, cancellationToken);
// 检查 是不是有配置项,没有的化添加
await CheckOptionsNotCreat(dbContext, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
await transaction.CommitAsync(cancellationToken);
}
catch (Exception ex)

View File

@ -26,6 +26,7 @@ namespace Lai_server.Configuration
services.AddScoped<PremissionValidationService>();
services.AddScoped<RoleService>();
services.AddScoped<UserService>();
services.AddScoped<OptionsService>();
// 注入 DAO

View File

@ -0,0 +1,72 @@
using LMS.Repository.DB;
using LMS.Repository.DTO;
using LMS.Repository.Options;
using LMS.service.Service;
using LMS.Tools.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using static LMS.Common.Enums.ResponseCodeEnum;
namespace LMS.service.Controllers
{
/// <summary>
/// Laitool 的配置项控制器
/// </summary>
/// <param name="optionsService"></param>
[Route("lms/[controller]/[action]")]
[ApiController]
public class LaitoolOptionsController(OptionsService optionsService) : ControllerBase
{
private readonly OptionsService _optionsService = optionsService;
#region
/// <summary>
/// 获取简单的配置项,无需权限
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("{optionsKey}")]
public async Task<ActionResult<APIResponseModel<List<OptionsDto>>>> GetSimpleOptions(string optionsKey)
{
return await _optionsService.GetSimpleOptions(optionsKey);
}
#endregion
#region
[HttpGet("{optionsKey}")]
[Authorize]
public async Task<ActionResult<APIResponseModel<List<OptionsDto>>>> GetAllOptions(string optionsKey)
{
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
return await _optionsService.GetAllOptions(optionsKey, userId);
}
#endregion
#region
[HttpPost]
[Authorize]
public async Task<ActionResult<APIResponseModel<string>>> ModifyOptions([FromBody] List<ModofyOptionsModel> model)
{
if (!ModelState.IsValid)
{
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
}
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
return await _optionsService.ModifyOptions(model, userId);
}
#endregion
//[HttpPost]
//[Authorize]
//public async Task<ActionResult<APIResponseModel<Options>>> GetOptions([FromBody] OptionsRequestModel request)
//{
// return await _optionsService.GetOptions(request);
//}
}
}

View File

@ -1,10 +1,9 @@
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
namespace LMS.service.Controllers
{
[Route("lms/[controller]/[action]")]
public class SoftWareController : Controller
public class SoftWareController : ControllerBase
{
//public Index()
//{

View File

@ -12,7 +12,6 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">

View File

@ -0,0 +1,163 @@
using AutoMapper;
using LMS.Common.Dictionary;
using LMS.DAO;
using LMS.Repository.DB;
using LMS.Repository.DTO;
using LMS.Repository.DTO.UserDto;
using LMS.Repository.Models.DB;
using LMS.Repository.Options;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using static LMS.Common.Enums.ResponseCodeEnum;
namespace LMS.service.Service
{
public class OptionsService(ApplicationDbContext context, UserManager<User> userManager, IMapper mapper)
{
private readonly ApplicationDbContext _context = context;
private readonly UserManager<User> _userManager = userManager;
private readonly IMapper _mapper = mapper;
#region
/// <summary>
/// 获取简单的配置项,无需权限
/// </summary>
/// <param name="optionsKey">配置项键</param>
/// <returns>API响应模型</returns>
internal async Task<ActionResult<APIResponseModel<List<OptionsDto>>>> GetSimpleOptions(string optionsKey)
{
try
{
if (!SimpleOptions.SimpleOptionsRequestQuery.TryGetValue(optionsKey, out List<string>? value))
{
return APIResponseModel<List<OptionsDto>>.CreateErrorResponseModel(ResponseCode.ParameterError);
}
// 从数据库中获取配置项
List<Options> options = await _context.Options.Where(x => value.Contains(x.Key)).ToListAsync();
if (options == null || options.Count <= 0)
{
return APIResponseModel<List<OptionsDto>>.CreateErrorResponseModel(ResponseCode.FindOptionsFail);
}
else
{
List<OptionsDto> optionsDto = options.Select(x => _mapper.Map<OptionsDto>(x)).ToList();
return APIResponseModel<List<OptionsDto>>.CreateSuccessResponseModel(optionsDto);
}
}
catch (Exception ex)
{
return APIResponseModel<List<OptionsDto>>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
}
}
#endregion
#region
/// <summary>
/// 获取所有的配置项,需要管理员权限
/// </summary>
/// <param name="requestUserId">请求用户ID</param>
/// <returns>API响应模型</returns>
internal async Task<ActionResult<APIResponseModel<List<OptionsDto>>>> GetAllOptions(string optionsKey, long requestUserId)
{
try
{
User? user = await _userManager.FindByIdAsync(requestUserId.ToString());
if (user == null)
{
return APIResponseModel<List<OptionsDto>>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
}
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Admin") || await _userManager.IsInRoleAsync(user, "Super Admin");
// 判断用户是不是管理员
if (!isAdminOrSuperAdmin)
{
return APIResponseModel<List<OptionsDto>>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
}
IQueryable<Options> query = _context.Options;
if (optionsKey != "all")
{
List<string> optionsKeyName = [];
if (AllOptions.AllOptionsRequestQuery.TryGetValue(optionsKey, out List<string>? value))
{
optionsKeyName = value;
}
else
{
return APIResponseModel<List<OptionsDto>>.CreateErrorResponseModel(ResponseCode.ParameterError);
}
query = query.Where(x => optionsKeyName.Contains(x.Key));
}
List<Options> options = await query.ToListAsync();
List<OptionsDto> optionsDto = options.Select(x => new OptionsDto
{
Key = x.Key,
Value = x.Value,
Type = x.Type,
}).ToList();
return APIResponseModel<List<OptionsDto>>.CreateSuccessResponseModel(optionsDto);
}
catch (Exception ex)
{
return APIResponseModel<List<OptionsDto>>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
}
}
#endregion
#region
/// <summary>
/// 修改配置项
/// </summary>
/// <param name="models">要修改的配置项模型列表</param>
/// <param name="userId">用户ID</param>
/// <returns>API响应模型</returns>
internal async Task<ActionResult<APIResponseModel<string>>> ModifyOptions(List<ModofyOptionsModel> models, long userId)
{
using var transaction = await _context.Database.BeginTransactionAsync();
try
{
User? user = await _userManager.FindByIdAsync(userId.ToString());
if (user == null)
{
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
}
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Admin") || await _userManager.IsInRoleAsync(user, "Super Admin");
// 判断用户是不是管理员
if (!isAdminOrSuperAdmin)
{
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
}
// 开始修改配置项
for (int i = 0; i < models.Count; i++)
{
ModofyOptionsModel model = models[i];
Options? options = await _context.Options.FirstOrDefaultAsync(x => x.Key == model.Key);
if (options == null)
{
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindOptionsFail);
}
options.Value = model.Value;
_context.Options.Update(options);
}
await _context.SaveChangesAsync();
await transaction.CommitAsync();
return APIResponseModel<string>.CreateSuccessResponseModel("修改成功");
}
catch (Exception ex)
{
await transaction.RollbackAsync();
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
}
}
#endregion
}
}

30
SQL/v0.0.1/Options.sql Normal file
View File

@ -0,0 +1,30 @@
/*
Navicat Premium Dump SQL
Source Server : 亿
Source Server Type : MySQL
Source Server Version : 80018 (8.0.18)
Source Host : yisurds-66dc0b453c05d4.rds.ysydb1.com:14080
Source Schema : LMS_TEST
Target Server Type : MySQL
Target Server Version : 80018 (8.0.18)
File Encoding : 65001
Date: 17/10/2024 21:42:59
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for Options
-- ----------------------------
CREATE TABLE IF NOT EXISTS `Options` (
`Key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`Value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL,
`Type` int(11) NOT NULL,
PRIMARY KEY (`Key`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;