Skip to content

Commit

Permalink
feat: config manager
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed Aug 27, 2022
1 parent 1b391a9 commit f5fa950
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 49 deletions.
2 changes: 0 additions & 2 deletions GZCTF.Test/ConfigServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ public void TestGetConfigs()
Assert.True(configs.Count > 0);

foreach (var config in configs)
{
output.WriteLine($"{config.ConfigKey,-32}={config.Value}");
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions GZCTF/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ public class AccountController : ControllerBase
private readonly IFileRepository fileService;
private readonly IRecaptchaExtension recaptcha;
private readonly IHostEnvironment environment;
private readonly IOptions<AccountPolicy> accountPolicy;
private readonly IOptionsSnapshot<AccountPolicy> accountPolicy;

public AccountController(
IMailSender _mailSender,
IFileRepository _FileService,
IHostEnvironment _environment,
IRecaptchaExtension _recaptcha,
IOptions<AccountPolicy> _accountPolicy,
IOptionsSnapshot<AccountPolicy> _accountPolicy,
UserManager<UserInfo> _userManager,
SignInManager<UserInfo> _signInManager,
ILogger<AccountController> _logger)
Expand Down
51 changes: 36 additions & 15 deletions GZCTF/Controllers/AdminController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using CTFServer.Models.Request.Admin;
using CTFServer.Models.Request.Teams;
using CTFServer.Repositories.Interface;
using CTFServer.Services.Interface;
using CTFServer.Utils;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -27,51 +28,71 @@ public class AdminController : ControllerBase
private readonly UserManager<UserInfo> userManager;
private readonly ILogRepository logRepository;
private readonly IFileRepository fileService;
private readonly IConfiguration configuration;
private readonly IConfigService configService;
private readonly ITeamRepository teamRepository;
private readonly IGameRepository gameRepository;
private readonly IServiceScopeFactory serviceProvider;
private readonly IServiceProvider serviceProvider;
private readonly IParticipationRepository participationRepository;

public AdminController(UserManager<UserInfo> _userManager,
IFileRepository _FileService,
ILogRepository _logRepository,
IConfiguration _configuration,
IConfigService _configService,
ITeamRepository _teamRepository,
IGameRepository _gameRepository,
IServiceScopeFactory _serviceProvider,
IServiceProvider _serviceProvider,
IParticipationRepository _participationRepository)
{
userManager = _userManager;
fileService = _FileService;
configuration = _configuration;
configService = _configService;
logRepository = _logRepository;
teamRepository = _teamRepository;
gameRepository = _gameRepository;
serviceProvider = _serviceProvider;
participationRepository = _participationRepository;
}

/// <summary>
/// 获取配置
/// </summary>
/// <remarks>
/// 使用此接口获取全局设置,需要Admin权限
/// </remarks>
/// <response code="200">全局配置</response>
/// <response code="401">未授权用户</response>
/// <response code="403">禁止访问</response>
[HttpGet("Config")]
[ProducesResponseType(typeof(GlobalConfig), StatusCodes.Status200OK)]
public IActionResult GetConfigs()
{
GlobalConfig config = new()
{
AccoutPolicy = serviceProvider.GetRequiredService<IOptionsSnapshot<AccountPolicy>>().Value
};

return Ok(config);
}

/// <summary>
/// 更改配置
/// </summary>
/// <remarks>
/// 使用此接口更改全局设置,需要Admin权限
/// </remarks>
/// <response code="200">用户列表</response>
/// <response code="200">更新成功</response>
/// <response code="401">未授权用户</response>
/// <response code="403">禁止访问</response>
[HttpPut("Config")]
[ProducesResponseType(typeof(UserInfoModel[]), StatusCodes.Status200OK)]
public async Task<IActionResult> UpdateConfigs(/*[FromBody] GlobalConfig model*/)
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> UpdateConfigs([FromBody] GlobalConfig model, CancellationToken token)
{
await using var scope = serviceProvider.CreateAsyncScope();

var accountPolicy = scope.ServiceProvider.GetRequiredService<IOptions<AccountPolicy>>();

Console.WriteLine($"Active={accountPolicy.Value.ActiveOnRegister}");
accountPolicy.Value.ActiveOnRegister = false;
Console.WriteLine($"Active={accountPolicy.Value.ActiveOnRegister}");
foreach(var prop in typeof(GlobalConfig).GetProperties())
{
var value = prop.GetValue(model);
if (value is not null)
await configService.SaveConfig(prop.PropertyType, value, token);
}

return Ok();
}
Expand Down
7 changes: 2 additions & 5 deletions GZCTF/Controllers/InfoController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,14 @@ namespace CTFServer.Controllers;
[ApiController]
public class InfoController : ControllerBase
{
private readonly ILogger<InfoController> logger;
private readonly IOptions<AccountPolicy> accountPolicy;
private readonly IOptionsSnapshot<AccountPolicy> accountPolicy;
private readonly INoticeRepository noticeRepository;
private readonly IRecaptchaExtension recaptchaExtension;

public InfoController(INoticeRepository _noticeRepository,
IRecaptchaExtension _recaptchaExtension,
IOptions<AccountPolicy> _accountPolicy,
ILogger<InfoController> _logger)
IOptionsSnapshot<AccountPolicy> _accountPolicy)
{
logger = _logger;
accountPolicy = _accountPolicy;
noticeRepository = _noticeRepository;
recaptchaExtension = _recaptchaExtension;
Expand Down
1 change: 1 addition & 0 deletions GZCTF/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@
builder.Services.AddScoped<ITeamRepository, TeamRepository>();
builder.Services.AddScoped<ILogRepository, LogRepository>();
builder.Services.AddScoped<IFileRepository, FileRepository>();
builder.Services.AddScoped<IConfigService, ConfigService>();

builder.Services.AddChannel<Submission>();
builder.Services.AddHostedService<FlagChecker>();
Expand Down
66 changes: 41 additions & 25 deletions GZCTF/Services/ConfigService.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.ComponentModel;
using CTFServer.Models.Data;
using IdentityModel.OidcClient;
using CTFServer.Services.Interface;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using NPOI.SS.Formula.Functions;
using YamlDotNet.Core.Tokens;

namespace CTFServer.Services;

public class ConfigService : IHostedService
public class ConfigService : IConfigService
{
private readonly ILogger<ConfigService> logger;
private readonly IServiceScopeFactory serviceScopeFactory;
private HashSet<Config> Data = new();
private readonly IConfigurationRoot? configuration;
private readonly AppDbContext context;

public ConfigService(IServiceScopeFactory provider, ILogger<ConfigService> _logger)
public ConfigService(AppDbContext _context,
IConfiguration _configuration)
{
serviceScopeFactory = provider;
logger = _logger;
context = _context;
configuration = _configuration as IConfigurationRoot;
}

private static void GetConfigsInternal(string key, HashSet<Config> configs, Type? type, object? value)
Expand All @@ -44,6 +39,16 @@ private static void GetConfigsInternal(string key, HashSet<Config> configs, Type
}
}

public static HashSet<Config> GetConfigs(Type type, object? value)
{
HashSet<Config> configs = new();

foreach (var item in type.GetProperties())
GetConfigsInternal($"{type.Name}:{item.Name}", configs, item.PropertyType, item.GetValue(value));

return configs;
}

public static HashSet<Config> GetConfigs<T>(T config) where T : class
{
HashSet<Config> configs = new();
Expand All @@ -55,21 +60,32 @@ public static HashSet<Config> GetConfigs<T>(T config) where T : class
return configs;
}

public void SaveConfig<T>(T config) where T : class
{
}
public Task SaveConfig(Type type, object? value, CancellationToken token = default)
=> SaveConfigInternal(GetConfigs(type, value), token);

public Task SaveConfig<T>(T config, CancellationToken token = default) where T : class
=> SaveConfigInternal(GetConfigs(config), token);

public async Task StartAsync(CancellationToken cancellationToken)
private async Task SaveConfigInternal(HashSet<Config> configs, CancellationToken token = default)
{
await using var scope = serviceScopeFactory.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var dbConfigs = await context.Configs.ToDictionaryAsync(c => c.ConfigKey, c => c, token);
foreach (var conf in configs)
{
if (dbConfigs.TryGetValue(conf.ConfigKey, out var dbConf))
{
if (dbConf.Value != conf.Value)
dbConf.Value = conf.Value;
}
else
{
await context.Configs.AddAsync(conf, token);
}
}

var configs = await context.Configs.AsNoTracking().ToListAsync(cancellationToken);
Data = configs.ToHashSet();
await context.SaveChangesAsync(token);
configuration?.Reload();
}

public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;

private static bool IsArrayLikeInterface(Type type)
{
if (!type.IsInterface || !type.IsConstructedGenericType) { return false; }
Expand Down
24 changes: 24 additions & 0 deletions GZCTF/Services/Interface/IConfigService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
namespace CTFServer.Services.Interface;

public interface IConfigService
{
/// <summary>
/// 保存配置对象
/// </summary>
/// <typeparam name="T">选项类型</typeparam>
/// <param name="config">选项对象</param>
/// <param name="token"></param>
/// <returns></returns>
public Task SaveConfig<T>(T config, CancellationToken token = default) where T : class;

/// <summary>
/// 保存配置对象
/// </summary>
/// <param name="type">对象类型</param>
/// <param name="value">对象值</param>
/// <param name="token"></param>
/// <returns></returns>
public Task SaveConfig(Type type, object? value, CancellationToken token = default);
}

0 comments on commit f5fa950

Please sign in to comment.