refactor: code restructuring

This commit is contained in:
2024-10-07 02:13:35 +03:00
parent de5dc274d7
commit 1c981fb7bf
29 changed files with 57 additions and 56 deletions

View File

@ -0,0 +1,81 @@
using Cronos;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Mirea.Api.Endpoint.Common.Attributes;
using Mirea.Api.Endpoint.Configuration.Model;
using System;
using System.Reflection;
using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Middleware;
public class CacheMaxAgeMiddleware(RequestDelegate next, IServiceProvider serviceProvider)
{
public async Task InvokeAsync(HttpContext context)
{
if (!context.Response.StatusCode.ToString().StartsWith('2'))
{
await next(context);
return;
}
var endpoint = context.GetEndpoint();
var actionDescriptor = endpoint?.Metadata.GetMetadata<Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor>();
if (actionDescriptor == null)
{
await next(context);
return;
}
var controllerType = actionDescriptor.ControllerTypeInfo;
var methodInfo = actionDescriptor.MethodInfo;
var maxAgeAttribute = methodInfo.GetCustomAttribute<CacheMaxAgeAttribute>() ?? controllerType.GetCustomAttribute<CacheMaxAgeAttribute>();
if (maxAgeAttribute == null)
{
await next(context);
return;
}
switch (maxAgeAttribute.MaxAge)
{
case < 0:
{
DateTime? nextDate;
var now = DateTime.UtcNow;
using (var scope = serviceProvider.CreateScope())
{
var updateCronString = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<GeneralConfig>>().Value.ScheduleSettings?.CronUpdateSchedule;
if (string.IsNullOrEmpty(updateCronString) ||
!CronExpression.TryParse(updateCronString, CronFormat.Standard, out var updateCron))
{
await next(context);
return;
}
nextDate = updateCron.GetNextOccurrence(now);
}
if (!nextDate.HasValue)
{
await next(context);
return;
}
context.Response.Headers.CacheControl = "max-age=" + (int)(nextDate.Value - now).TotalSeconds;
break;
}
case > 0:
context.Response.Headers.CacheControl = "max-age=" + maxAgeAttribute.MaxAge;
break;
}
await next(context);
}
}

View File

@ -0,0 +1,60 @@
using FluentValidation;
using Microsoft.AspNetCore.Http;
using Mirea.Api.DataAccess.Application.Common.Exceptions;
using Mirea.Api.Dto.Responses;
using Mirea.Api.Endpoint.Common.Exceptions;
using System;
using System.Text.Json;
using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Middleware;
public class CustomExceptionHandlerMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
try
{
await next(context);
}
catch (Exception exception)
{
await HandleExceptionAsync(context, exception);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var code = StatusCodes.Status500InternalServerError;
var result = string.Empty;
switch (exception)
{
case ValidationException validationException:
code = StatusCodes.Status400BadRequest;
result = JsonSerializer.Serialize(new ErrorResponse()
{
Error = validationException.Message,
Code = code
});
break;
case NotFoundException:
code = StatusCodes.Status404NotFound;
break;
case ControllerArgumentException:
code = StatusCodes.Status400BadRequest;
break;
}
context.Response.ContentType = "application/json";
context.Response.StatusCode = code;
if (string.IsNullOrEmpty(result))
result = JsonSerializer.Serialize(new ErrorResponse()
{
Error = exception.Message,
Code = code
});
return context.Response.WriteAsync(result);
}
}

View File

@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Http;
using Mirea.Api.Security.Common.Interfaces;
using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Middleware;
public class JwtRevocationMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context, IRevokedToken revokedTokenStore)
{
if (context.Request.Headers.ContainsKey("Authorization"))
{
var token = context.Request.Headers.Authorization.ToString().Replace("Bearer ", "");
if (await revokedTokenStore.IsTokenRevokedAsync(token))
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
}
await next(context);
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Http;
using Mirea.Api.Endpoint.Common.Attributes;
using Mirea.Api.Endpoint.Common.Interfaces;
using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Middleware;
public class MaintenanceModeMiddleware(RequestDelegate next, IMaintenanceModeService maintenanceModeService, IMaintenanceModeNotConfigureService maintenanceModeNotConfigureService)
{
private static bool IsIgnoreMaintenanceMode(HttpContext context)
{
var endpoint = context.GetEndpoint();
return endpoint?.Metadata.GetMetadata<MaintenanceModeIgnoreAttribute>() != null;
}
public async Task InvokeAsync(HttpContext context)
{
if (!maintenanceModeService.IsMaintenanceMode && !maintenanceModeNotConfigureService.IsMaintenanceMode || IsIgnoreMaintenanceMode(context))
await next(context);
else
{
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
context.Response.ContentType = "plain/text";
string error;
if (maintenanceModeService.IsMaintenanceMode)
{
context.Response.Headers.RetryAfter = "600";
error = "The service is currently undergoing maintenance. Please try again later.";
}
else
error =
"The service is currently not configured. Go to the setup page if you are an administrator or try again later.";
await context.Response.WriteAsync(error);
}
}
}

View File

@ -1,7 +1,7 @@
using Asp.Versioning;
using Microsoft.Extensions.DependencyInjection;
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
namespace Mirea.Api.Endpoint.Configuration.Core.Startup;
public static class ApiVersioningConfiguration
{

View File

@ -1,9 +1,9 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Mirea.Api.Endpoint.Common.Settings;
using Mirea.Api.Endpoint.Configuration.General.Settings;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Settings;
using Mirea.Api.Endpoint.Configuration.Model;
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
namespace Mirea.Api.Endpoint.Configuration.Core.Startup;
public static class CacheConfiguration
{

View File

@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
namespace Mirea.Api.Endpoint.Configuration.Core.Startup;
public static class EnvironmentConfiguration
{

View File

@ -7,7 +7,7 @@ using Mirea.Api.Security.Common.Interfaces;
using System;
using System.Text;
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
namespace Mirea.Api.Endpoint.Configuration.Core.Startup;
public static class JwtConfiguration
{

View File

@ -2,14 +2,14 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Mirea.Api.Endpoint.Common.Services;
using Mirea.Api.Endpoint.Common.Settings;
using Mirea.Api.Endpoint.Configuration.Model;
using Serilog;
using Serilog.Events;
using Serilog.Filters;
using Serilog.Formatting.Compact;
using System.IO;
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
namespace Mirea.Api.Endpoint.Configuration.Core.Startup;
public static class LoggerConfiguration
{

View File

@ -1,12 +1,12 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Mirea.Api.Endpoint.Common.Services.Security;
using Mirea.Api.Endpoint.Common.Settings;
using Mirea.Api.Endpoint.Configuration.General.Settings;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Settings;
using Mirea.Api.Endpoint.Configuration.Model;
using Mirea.Api.Security;
using Mirea.Api.Security.Common.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
namespace Mirea.Api.Endpoint.Configuration.Core.Startup;
public static class SecureConfiguration
{

View File

@ -9,7 +9,7 @@ using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.IO;
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
namespace Mirea.Api.Endpoint.Configuration.Core.Startup;
public static class SwaggerConfiguration
{

View File

@ -1,6 +0,0 @@
namespace Mirea.Api.Endpoint.Configuration.General.Interfaces;
public interface IIsConfigured
{
bool IsConfigured();
}

View File

@ -0,0 +1,5 @@
namespace Mirea.Api.Endpoint.Common.Interfaces;
public interface ISaveSettings
{
void SaveSetting();
}

View File

@ -0,0 +1,26 @@
using Mirea.Api.Endpoint.Common.Interfaces;
using Mirea.Api.Endpoint.Common.Services;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Mirea.Api.Endpoint.Configuration.Model;
public class Admin : ISaveSettings
{
[JsonIgnore] private const string FileName = "admin.json";
[JsonIgnore]
public static string FilePath => PathBuilder.Combine(FileName);
public required string Username { get; set; }
public required string Email { get; set; }
public required string PasswordHash { get; set; }
public required string Salt { get; set; }
public void SaveSetting()
{
File.WriteAllText(FilePath, JsonSerializer.Serialize(this));
}
}

View File

@ -0,0 +1,34 @@
using Mirea.Api.Endpoint.Common.Interfaces;
using Mirea.Api.Endpoint.Common.Services;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Settings;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Mirea.Api.Endpoint.Configuration.Model;
public class GeneralConfig : ISaveSettings
{
[JsonIgnore] private const string FileName = "Settings.json";
[JsonIgnore]
public static string FilePath => PathBuilder.Combine(FileName);
public DbSettings? DbSettings { get; set; }
public CacheSettings? CacheSettings { get; set; }
public ScheduleSettings? ScheduleSettings { get; set; }
public EmailSettings? EmailSettings { get; set; }
public LogSettings? LogSettings { get; set; }
public string? SecretForwardToken { get; set; }
public void SaveSetting()
{
File.WriteAllText(
FilePath,
JsonSerializer.Serialize(this, new JsonSerializerOptions
{
WriteIndented = true
})
);
}
}

View File

@ -1,6 +1,6 @@
using System;
namespace Mirea.Api.Endpoint.Configuration.General.Attributes;
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Attributes;
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class RequiredSettingsAttribute : Attribute;

View File

@ -0,0 +1,6 @@
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Interfaces;
public interface IIsConfigured
{
bool IsConfigured();
}

View File

@ -1,7 +1,7 @@
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Attributes;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Settings;
[RequiredSettings]
public class CacheSettings : IIsConfigured

View File

@ -1,10 +1,10 @@
using Mirea.Api.DataAccess.Persistence.Common;
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Attributes;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Interfaces;
using System;
using System.Text.Json.Serialization;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Settings;
[RequiredSettings]
public class DbSettings : IIsConfigured

View File

@ -1,6 +1,6 @@
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Settings;
public class EmailSettings : IIsConfigured
{

View File

@ -1,7 +1,7 @@
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Attributes;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Settings;
[RequiredSettings]
public class LogSettings : IIsConfigured

View File

@ -1,10 +1,10 @@
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Attributes;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Settings;
[RequiredSettings]
public class ScheduleSettings : IIsConfigured

View File

@ -1,7 +1,7 @@
using Mirea.Api.Endpoint.Common.Interfaces;
using System;
namespace Mirea.Api.Endpoint.Configuration.General;
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks;
public class SetupTokenService : ISetupToken
{

View File

@ -1,11 +1,11 @@
using Microsoft.Extensions.Options;
using Mirea.Api.Endpoint.Common.Settings;
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Attributes;
using Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Interfaces;
using Mirea.Api.Endpoint.Configuration.Model;
using System;
using System.Reflection;
namespace Mirea.Api.Endpoint.Configuration.General.Validators;
namespace Mirea.Api.Endpoint.Configuration.ConfigurationChecks.Validators;
public class SettingsRequiredValidator
{