refactor: Migrate backend and frontend architecture from a module-based to an app-based structure.
This commit is contained in:
352
src/backend/Zentral.API/Controllers/AppsController.cs
Normal file
352
src/backend/Zentral.API/Controllers/AppsController.cs
Normal file
@@ -0,0 +1,352 @@
|
||||
using Zentral.API.Services;
|
||||
using Zentral.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Zentral.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller per la gestione delle applicazioni e delle subscription
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class AppsController : ControllerBase
|
||||
{
|
||||
private readonly AppService _appService;
|
||||
private readonly ILogger<AppsController> _logger;
|
||||
|
||||
public AppsController(AppService appService, ILogger<AppsController> logger)
|
||||
{
|
||||
_appService = appService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene tutte le applicazioni disponibili con stato subscription
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<AppDto>>> GetAllApps()
|
||||
{
|
||||
var apps = await _appService.GetAllAppsAsync();
|
||||
return Ok(apps.Select(MapToDto).ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene solo le applicazioni attive (per costruzione menu)
|
||||
/// </summary>
|
||||
[HttpGet("active")]
|
||||
public async Task<ActionResult<List<AppDto>>> GetActiveApps()
|
||||
{
|
||||
var apps = await _appService.GetActiveAppsAsync();
|
||||
return Ok(apps.Select(MapToDto).ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene un'applicazione specifica per codice
|
||||
/// </summary>
|
||||
[HttpGet("{code}")]
|
||||
public async Task<ActionResult<AppDto>> GetApp(string code)
|
||||
{
|
||||
var app = await _appService.GetAppByCodeAsync(code);
|
||||
if (app == null)
|
||||
return NotFound(new { message = $"Applicazione '{code}' non trovata" });
|
||||
|
||||
return Ok(MapToDto(app));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se un'applicazione è abilitata
|
||||
/// </summary>
|
||||
[HttpGet("{code}/enabled")]
|
||||
public async Task<ActionResult<AppStatusDto>> IsAppEnabled(string code)
|
||||
{
|
||||
var app = await _appService.GetAppByCodeAsync(code);
|
||||
if (app == null)
|
||||
return NotFound(new { message = $"Applicazione '{code}' non trovata" });
|
||||
|
||||
var isEnabled = await _appService.IsAppEnabledAsync(code);
|
||||
var hasValidSubscription = await _appService.HasValidSubscriptionAsync(code);
|
||||
|
||||
return Ok(new AppStatusDto
|
||||
{
|
||||
Code = code,
|
||||
IsEnabled = isEnabled,
|
||||
HasValidSubscription = hasValidSubscription,
|
||||
IsCore = app.IsCore,
|
||||
DaysRemaining = app.Subscription?.GetDaysRemaining(),
|
||||
IsExpiringSoon = app.Subscription?.IsExpiringSoon() ?? false
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attiva un'applicazione
|
||||
/// </summary>
|
||||
[HttpPut("{code}/enable")]
|
||||
public async Task<ActionResult<AppSubscriptionDto>> EnableApp(string code, [FromBody] EnableAppRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var subscription = await _appService.EnableAppAsync(
|
||||
code,
|
||||
request.SubscriptionType,
|
||||
request.StartDate,
|
||||
request.EndDate,
|
||||
request.AutoRenew,
|
||||
request.PaidPrice,
|
||||
request.Notes);
|
||||
|
||||
return Ok(MapSubscriptionToDto(subscription));
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disattiva un'applicazione
|
||||
/// </summary>
|
||||
[HttpPut("{code}/disable")]
|
||||
public async Task<ActionResult> DisableApp(string code)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _appService.DisableAppAsync(code);
|
||||
return Ok(new { message = $"Applicazione '{code}' disattivata" });
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene tutte le subscription
|
||||
/// </summary>
|
||||
[HttpGet("subscriptions")]
|
||||
public async Task<ActionResult<List<AppSubscriptionDto>>> GetAllAppSubscriptions()
|
||||
{
|
||||
var subscriptions = await _appService.GetAllSubscriptionsAsync();
|
||||
return Ok(subscriptions.Select(MapSubscriptionToDto).ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggiorna la subscription di un'applicazione
|
||||
/// </summary>
|
||||
[HttpPut("{code}/subscription")]
|
||||
public async Task<ActionResult<AppSubscriptionDto>> UpdateAppSubscription(string code, [FromBody] UpdateAppSubscriptionRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var subscription = await _appService.UpdateSubscriptionAsync(
|
||||
code,
|
||||
request.SubscriptionType,
|
||||
request.EndDate,
|
||||
request.AutoRenew,
|
||||
request.Notes);
|
||||
|
||||
return Ok(MapSubscriptionToDto(subscription));
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rinnova la subscription di un'applicazione
|
||||
/// </summary>
|
||||
[HttpPost("{code}/subscription/renew")]
|
||||
public async Task<ActionResult<AppSubscriptionDto>> RenewAppSubscription(string code, [FromBody] RenewAppSubscriptionRequest? request = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var subscription = await _appService.RenewSubscriptionAsync(code, request?.PaidPrice);
|
||||
return Ok(MapSubscriptionToDto(subscription));
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene le applicazioni in scadenza
|
||||
/// </summary>
|
||||
[HttpGet("expiring")]
|
||||
public async Task<ActionResult<List<AppDto>>> GetExpiringApps([FromQuery] int daysThreshold = 30)
|
||||
{
|
||||
var apps = await _appService.GetExpiringAppsAsync(daysThreshold);
|
||||
return Ok(apps.Select(MapToDto).ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inizializza le applicazioni di default (per setup iniziale)
|
||||
/// </summary>
|
||||
[HttpPost("seed")]
|
||||
public async Task<ActionResult> SeedDefaultApps()
|
||||
{
|
||||
await _appService.SeedDefaultAppsAsync();
|
||||
return Ok(new { message = "Applicazioni di default inizializzate" });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forza il controllo delle subscription scadute
|
||||
/// </summary>
|
||||
[HttpPost("check-expired")]
|
||||
public async Task<ActionResult> CheckExpiredAppSubscriptions()
|
||||
{
|
||||
var count = await _appService.CheckExpiredSubscriptionsAsync();
|
||||
return Ok(new { message = $"Controllate le subscription, {count} applicazioni disattivate per scadenza" });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalida la cache delle applicazioni
|
||||
/// </summary>
|
||||
[HttpPost("invalidate-cache")]
|
||||
public ActionResult InvalidateAppsCache()
|
||||
{
|
||||
_appService.InvalidateCache();
|
||||
return Ok(new { message = "Cache applicazioni invalidata" });
|
||||
}
|
||||
|
||||
#region Mapping
|
||||
|
||||
private static AppDto MapToDto(App app)
|
||||
{
|
||||
return new AppDto
|
||||
{
|
||||
Id = app.Id,
|
||||
Code = app.Code,
|
||||
Name = app.Name,
|
||||
Description = app.Description,
|
||||
Icon = app.Icon,
|
||||
BasePrice = app.BasePrice,
|
||||
MonthlyPrice = app.GetMonthlyPrice(),
|
||||
MonthlyMultiplier = app.MonthlyMultiplier,
|
||||
SortOrder = app.SortOrder,
|
||||
IsCore = app.IsCore,
|
||||
Dependencies = app.GetDependencies().ToList(),
|
||||
RoutePath = app.RoutePath,
|
||||
IsAvailable = app.IsAvailable,
|
||||
IsEnabled = app.IsCore || ((app.Subscription?.IsEnabled ?? false) && (app.Subscription?.IsValid() ?? false)),
|
||||
Subscription = app.Subscription != null ? MapSubscriptionToDto(app.Subscription) : null
|
||||
};
|
||||
}
|
||||
|
||||
private static AppSubscriptionDto MapSubscriptionToDto(AppSubscription subscription)
|
||||
{
|
||||
return new AppSubscriptionDto
|
||||
{
|
||||
Id = subscription.Id,
|
||||
AppId = subscription.AppId,
|
||||
AppCode = subscription.App?.Code,
|
||||
AppName = subscription.App?.Name,
|
||||
IsEnabled = subscription.IsEnabled,
|
||||
SubscriptionType = subscription.SubscriptionType,
|
||||
SubscriptionTypeName = subscription.SubscriptionType.ToString(),
|
||||
StartDate = subscription.StartDate,
|
||||
EndDate = subscription.EndDate,
|
||||
AutoRenew = subscription.AutoRenew,
|
||||
Notes = subscription.Notes,
|
||||
LastRenewalDate = subscription.LastRenewalDate,
|
||||
PaidPrice = subscription.PaidPrice,
|
||||
IsValid = subscription.IsValid(),
|
||||
DaysRemaining = subscription.GetDaysRemaining(),
|
||||
IsExpiringSoon = subscription.IsExpiringSoon()
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region DTOs
|
||||
|
||||
public class AppDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Code { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? Description { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
public decimal BasePrice { get; set; }
|
||||
public decimal MonthlyPrice { get; set; }
|
||||
public decimal MonthlyMultiplier { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsCore { get; set; }
|
||||
public List<string> Dependencies { get; set; } = new();
|
||||
public string? RoutePath { get; set; }
|
||||
public bool IsAvailable { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public AppSubscriptionDto? Subscription { get; set; }
|
||||
}
|
||||
|
||||
public class AppSubscriptionDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int AppId { get; set; }
|
||||
public string? AppCode { get; set; }
|
||||
public string? AppName { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public SubscriptionType SubscriptionType { get; set; }
|
||||
public string SubscriptionTypeName { get; set; } = string.Empty;
|
||||
public DateTime? StartDate { get; set; }
|
||||
public DateTime? EndDate { get; set; }
|
||||
public bool AutoRenew { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
public DateTime? LastRenewalDate { get; set; }
|
||||
public decimal? PaidPrice { get; set; }
|
||||
public bool IsValid { get; set; }
|
||||
public int? DaysRemaining { get; set; }
|
||||
public bool IsExpiringSoon { get; set; }
|
||||
}
|
||||
|
||||
public class AppStatusDto
|
||||
{
|
||||
public string Code { get; set; } = string.Empty;
|
||||
public bool IsEnabled { get; set; }
|
||||
public bool HasValidSubscription { get; set; }
|
||||
public bool IsCore { get; set; }
|
||||
public int? DaysRemaining { get; set; }
|
||||
public bool IsExpiringSoon { get; set; }
|
||||
}
|
||||
|
||||
public class EnableAppRequest
|
||||
{
|
||||
public SubscriptionType SubscriptionType { get; set; } = SubscriptionType.Annual;
|
||||
public DateTime? StartDate { get; set; }
|
||||
public DateTime? EndDate { get; set; }
|
||||
public bool AutoRenew { get; set; }
|
||||
public decimal? PaidPrice { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateAppSubscriptionRequest
|
||||
{
|
||||
public SubscriptionType? SubscriptionType { get; set; }
|
||||
public DateTime? EndDate { get; set; }
|
||||
public bool? AutoRenew { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public class RenewAppSubscriptionRequest
|
||||
{
|
||||
public decimal? PaidPrice { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
Reference in New Issue
Block a user