OneConversorTemplate/OnlyOneAccessTemplate/Controllers/ModuleManagementController.cs
2025-06-08 18:49:54 -03:00

326 lines
12 KiB
C#

using Microsoft.AspNetCore.Mvc;
using OnlyOneAccessTemplate.Services;
using OnlyOneAccessTemplate.Models;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Http.Extensions;
namespace OnlyOneAccessTemplate.Controllers
{
[Route("api/module-management")]
[ApiController]
public class ModuleManagementController : ControllerBase
{
private readonly IModuleService _moduleService;
private readonly ILogger<ModuleManagementController> _logger;
private readonly IConfiguration _configuration;
public ModuleManagementController(
IModuleService moduleService,
ILogger<ModuleManagementController> logger,
IConfiguration configuration)
{
_moduleService = moduleService;
_logger = logger;
_configuration = configuration;
}
[HttpPost("register")]
public async Task<IActionResult> RegisterModule([FromBody] ModuleRegistrationRequest request)
{
try
{
_logger.LogInformation("Registrando novo módulo: {ModuleId}", request.ModuleId);
// Verificar se módulo já existe
var existing = await _moduleService.GetModuleConfigAsync(request.ModuleId);
if (existing != null)
{
return BadRequest(new { success = false, message = "Módulo já existe" });
}
// Testar conectividade com o módulo
var healthUrl = $"{request.BaseUrl.TrimEnd('/')}/{request.HealthEndpoint?.TrimStart('/') ?? "api/converter/health"}";
var isHealthy = await TestModuleHealth(healthUrl);
// Gerar API Key
var apiKey = GenerateApiKey();
// Criar configuração
var moduleConfig = new ModuleConfig
{
ModuleId = request.ModuleId,
Name = request.Name,
Url = $"{request.BaseUrl.TrimEnd('/')}/modules/{request.ModuleId}",
RequestBy = request.ModuleId,
IsActive = request.AutoActivate.HasValue && request.AutoActivate.Value && isHealthy,
CacheMinutes = request.CacheMinutes ?? 5,
// Proxy Configuration
UseProxy = true,
ProxyEndpoint = $"/api/modules/{request.ModuleId}",
ProxyMappings = new Dictionary<string, string>
{
["convert"] = $"{request.BaseUrl}/api/converter/convert",
["config"] = $"{request.BaseUrl}/api/converter/config",
["health"] = $"{request.BaseUrl}/api/converter/health"
},
// Security
ApiKey = apiKey,
AllowedOrigins = request.AllowedOrigins ?? new List<string> { Request.GetDisplayUrl() },
RateLimitPerMinute = request.RateLimitPerMinute ?? 60,
// Menu
MenuTitle = request.MenuTitle ?? request.Name,
MenuDescription = request.MenuDescription,
MenuIcon = request.MenuIcon ?? "fas fa-exchange-alt",
MenuCategory = request.MenuCategory ?? "Conversores",
MenuOrder = request.MenuOrder ?? 0,
ShowInMenu = request.ShowInMenu ?? true,
// SEO
SeoTitles = request.SeoTitles ?? new Dictionary<string, string>(),
SeoDescriptions = request.SeoDescriptions ?? new Dictionary<string, string>(),
SeoKeywords = request.SeoKeywords ?? new Dictionary<string, string>(),
// Technical
HealthEndpoint = request.HealthEndpoint ?? "/api/converter/health",
HealthCheckIntervalMinutes = request.HealthCheckIntervalMinutes ?? 5,
AutoStart = request.AutoActivate ?? true,
Version = request.Version ?? "1.0.0",
IsHealthy = isHealthy,
LastHealthCheck = DateTime.UtcNow,
// Developer
DeveloperName = request.DeveloperName,
DeveloperEmail = request.DeveloperEmail,
Repository = request.Repository,
Documentation = request.Documentation,
// Headers
Headers = new Dictionary<string, string>
{
["X-API-Key"] = apiKey,
["User-Agent"] = "ConvertIt-MainApp/1.0"
}
};
await _moduleService.SaveModuleConfigAsync(moduleConfig);
_logger.LogInformation("Módulo {ModuleId} registrado com sucesso", request.ModuleId);
return Ok(new
{
success = true,
message = "Módulo registrado com sucesso",
moduleId = request.ModuleId,
apiKey = apiKey,
proxyEndpoint = moduleConfig.ProxyEndpoint,
isHealthy = isHealthy,
isActive = moduleConfig.IsActive
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao registrar módulo {ModuleId}", request.ModuleId);
return StatusCode(500, new { success = false, message = ex.Message });
}
}
[HttpGet("modules")]
public async Task<IActionResult> ListModules()
{
try
{
var modules = await _moduleService.GetAllActiveModulesAsync();
var result = modules.Select(m => new
{
moduleId = m.ModuleId,
name = m.Name,
isActive = m.IsActive,
isHealthy = m.IsHealthy,
lastHealthCheck = m.LastHealthCheck,
version = m.Version,
menuTitle = m.MenuTitle,
menuCategory = m.MenuCategory,
showInMenu = m.ShowInMenu,
developerName = m.DeveloperName,
proxyEndpoint = m.ProxyEndpoint
});
return Ok(new { success = true, modules = result });
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao listar módulos");
return StatusCode(500, new { success = false, message = ex.Message });
}
}
[HttpPost("modules/{moduleId}/toggle")]
public async Task<IActionResult> ToggleModule(string moduleId)
{
try
{
var module = await _moduleService.GetModuleConfigAsync(moduleId);
if (module == null)
{
return NotFound(new { success = false, message = "Módulo não encontrado" });
}
module.IsActive = !module.IsActive;
module.UpdatedAt = DateTime.UtcNow;
await _moduleService.SaveModuleConfigAsync(module);
_logger.LogInformation("Módulo {ModuleId} {Status}", moduleId,
module.IsActive ? "ativado" : "desativado");
return Ok(new
{
success = true,
moduleId = moduleId,
isActive = module.IsActive,
message = $"Módulo {(module.IsActive ? "ativado" : "desativado")} com sucesso"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao alternar módulo {ModuleId}", moduleId);
return StatusCode(500, new { success = false, message = ex.Message });
}
}
[HttpPost("modules/{moduleId}/health-check")]
public async Task<IActionResult> CheckModuleHealth(string moduleId)
{
try
{
var module = await _moduleService.GetModuleConfigAsync(moduleId);
if (module == null)
{
return NotFound(new { success = false, message = "Módulo não encontrado" });
}
var healthUrl = $"{GetBaseUrl(module.Url)}{module.HealthEndpoint}";
var isHealthy = await TestModuleHealth(healthUrl);
module.IsHealthy = isHealthy;
module.LastHealthCheck = DateTime.UtcNow;
await _moduleService.SaveModuleConfigAsync(module);
return Ok(new
{
success = true,
moduleId = moduleId,
isHealthy = isHealthy,
lastCheck = module.LastHealthCheck,
healthUrl = healthUrl
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao verificar saúde do módulo {ModuleId}", moduleId);
return StatusCode(500, new { success = false, message = ex.Message });
}
}
[HttpDelete("modules/{moduleId}")]
public async Task<IActionResult> UnregisterModule(string moduleId)
{
try
{
var module = await _moduleService.GetModuleConfigAsync(moduleId);
if (module == null)
{
return NotFound(new { success = false, message = "Módulo não encontrado" });
}
// Aqui você implementaria a remoção (dependendo de como está armazenado)
// Por enquanto, vamos apenas desativar
module.IsActive = false;
module.UpdatedAt = DateTime.UtcNow;
await _moduleService.SaveModuleConfigAsync(module);
_logger.LogInformation("Módulo {ModuleId} desregistrado", moduleId);
return Ok(new
{
success = true,
message = "Módulo desregistrado com sucesso"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao desregistrar módulo {ModuleId}", moduleId);
return StatusCode(500, new { success = false, message = ex.Message });
}
}
private async Task<bool> TestModuleHealth(string healthUrl)
{
try
{
using var client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(10);
var response = await client.GetAsync(healthUrl);
return response.IsSuccessStatusCode;
}
catch
{
return false;
}
}
private string GenerateApiKey()
{
using var rng = RandomNumberGenerator.Create();
var bytes = new byte[32];
rng.GetBytes(bytes);
return Convert.ToBase64String(bytes);
}
private string GetBaseUrl(string fullUrl)
{
var uri = new Uri(fullUrl);
return $"{uri.Scheme}://{uri.Host}:{uri.Port}";
}
}
public class ModuleRegistrationRequest
{
public string ModuleId { get; set; } = "";
public string Name { get; set; } = "";
public string BaseUrl { get; set; } = "";
public bool? AutoActivate { get; set; } = true;
public int? CacheMinutes { get; set; } = 5;
public List<string>? AllowedOrigins { get; set; }
public int? RateLimitPerMinute { get; set; } = 60;
// Menu
public string? MenuTitle { get; set; }
public string? MenuDescription { get; set; }
public string? MenuIcon { get; set; }
public string? MenuCategory { get; set; }
public int? MenuOrder { get; set; }
public bool? ShowInMenu { get; set; } = true;
// SEO
public Dictionary<string, string>? SeoTitles { get; set; }
public Dictionary<string, string>? SeoDescriptions { get; set; }
public Dictionary<string, string>? SeoKeywords { get; set; }
// Technical
public string? HealthEndpoint { get; set; }
public int? HealthCheckIntervalMinutes { get; set; }
public string? Version { get; set; }
// Developer
public string? DeveloperName { get; set; }
public string? DeveloperEmail { get; set; }
public string? Repository { get; set; }
public string? Documentation { get; set; }
}
}