chore: initial commit - baseline before redesign
This commit is contained in:
109
CertReports.Syncfusion/Controllers/ChartController.cs
Normal file
109
CertReports.Syncfusion/Controllers/ChartController.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using CertReports.Syncfusion.Services.Implementations;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Syncfusion.Pdf;
|
||||
using Syncfusion.Pdf.Graphics;
|
||||
|
||||
namespace CertReports.Syncfusion.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// API per la generazione standalone del grafico certificato.
|
||||
/// Richiamabile da qualsiasi progetto esterno.
|
||||
///
|
||||
/// Endpoint:
|
||||
/// GET /api/chart/{isin} → PNG inline
|
||||
/// GET /api/chart/{isin}?format=png → PNG inline
|
||||
/// GET /api/chart/{isin}?format=pdf → PDF inline
|
||||
/// GET /api/chart/{isin}?width=1100&height=700&format=png
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ChartController : ControllerBase
|
||||
{
|
||||
private readonly IChartDataService _chartDataService;
|
||||
private readonly ILogger<ChartController> _logger;
|
||||
|
||||
public ChartController(IChartDataService chartDataService, ILogger<ChartController> logger)
|
||||
{
|
||||
_chartDataService = chartDataService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet("{isin}")]
|
||||
public async Task<IActionResult> GenerateChart(
|
||||
string isin,
|
||||
[FromQuery] int width = 1100,
|
||||
[FromQuery] int height = 700,
|
||||
[FromQuery] string format = "png")
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(isin))
|
||||
return BadRequest("ISIN non valido.");
|
||||
|
||||
// Limiti ragionevoli
|
||||
width = Math.Clamp(width, 400, 2000);
|
||||
height = Math.Clamp(height, 300, 1500);
|
||||
|
||||
try
|
||||
{
|
||||
var chartData = await _chartDataService.GetChartDataAsync(isin);
|
||||
|
||||
if (chartData == null || chartData.Series.Count == 0)
|
||||
{
|
||||
return NotFound(new
|
||||
{
|
||||
status = "KO",
|
||||
message = $"Nessun dato per il grafico di {isin} (meno di 30 prezzi EOD?)."
|
||||
});
|
||||
}
|
||||
|
||||
// Genera PNG
|
||||
byte[] pngBytes = SkiaChartRenderer.RenderToPng(chartData, width, height);
|
||||
|
||||
if (format.Equals("pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Converti in PDF landscape
|
||||
byte[] pdfBytes = WrapPngInPdf(pngBytes);
|
||||
Response.Headers.Append("Content-Disposition", $"inline; filename=chart_{isin}.pdf");
|
||||
return File(pdfBytes, "application/pdf");
|
||||
}
|
||||
|
||||
// Default: PNG
|
||||
Response.Headers.Append("Content-Disposition", $"inline; filename=chart_{isin}.png");
|
||||
return File(pngBytes, "image/png");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Errore generazione chart per ISIN {Isin}", isin);
|
||||
return StatusCode(500, new { status = "KO", message = "Errore nella generazione del grafico." });
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] WrapPngInPdf(byte[] pngBytes)
|
||||
{
|
||||
var doc = new PdfDocument();
|
||||
doc.PageSettings.Size = PdfPageSize.A4;
|
||||
doc.PageSettings.Orientation = PdfPageOrientation.Landscape;
|
||||
doc.PageSettings.Margins.All = 30;
|
||||
|
||||
var page = doc.Pages.Add();
|
||||
var g = page.Graphics;
|
||||
float pw = page.GetClientSize().Width;
|
||||
float ph = page.GetClientSize().Height;
|
||||
|
||||
using var stream = new MemoryStream(pngBytes);
|
||||
var img = new PdfBitmap(stream);
|
||||
|
||||
float ratio = (float)img.Width / img.Height;
|
||||
float dw = pw;
|
||||
float dh = dw / ratio;
|
||||
if (dh > ph) { dh = ph; dw = dh * ratio; }
|
||||
|
||||
float x = (pw - dw) / 2;
|
||||
float y = (ph - dh) / 2;
|
||||
g.DrawImage(img, x, y, dw, dh);
|
||||
|
||||
using var output = new MemoryStream();
|
||||
doc.Save(output);
|
||||
doc.Close(true);
|
||||
return output.ToArray();
|
||||
}
|
||||
}
|
||||
139
CertReports.Syncfusion/Controllers/ReportController.cs
Normal file
139
CertReports.Syncfusion/Controllers/ReportController.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using CertReports.Syncfusion.Helpers;
|
||||
using CertReports.Syncfusion.Services.Interfaces;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CertReports.Syncfusion.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller REST per la generazione dei report certificati.
|
||||
/// Sostituisce la vecchia WebForm ReportFSSiteCrypt.aspx.
|
||||
///
|
||||
/// Endpoint:
|
||||
/// GET /api/report?p={encrypted_isin}
|
||||
/// GET /api/report?alias={alias_id}
|
||||
/// GET /api/report/by-isin/{isin} (uso interno/debug)
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ReportController : ControllerBase
|
||||
{
|
||||
private readonly IReportOrchestrator _orchestrator;
|
||||
private readonly ICertificateDataService _dataService;
|
||||
private readonly CryptoHelper _crypto;
|
||||
private readonly ILogger<ReportController> _logger;
|
||||
|
||||
public ReportController(
|
||||
IReportOrchestrator orchestrator,
|
||||
ICertificateDataService dataService,
|
||||
CryptoHelper crypto,
|
||||
ILogger<ReportController> logger)
|
||||
{
|
||||
_orchestrator = orchestrator;
|
||||
_dataService = dataService;
|
||||
_crypto = crypto;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint principale - compatibile con la vecchia URL.
|
||||
/// Accetta parametri 'p' (ISIN cifrato) o 'alias' (alias ID).
|
||||
/// Restituisce il PDF inline (visualizzabile nel browser).
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GenerateReport(
|
||||
[FromQuery(Name = "p")] string? encryptedIsin = null,
|
||||
[FromQuery(Name = "alias")] string? aliasId = null)
|
||||
{
|
||||
string? isin = null;
|
||||
|
||||
// Risolvi ISIN
|
||||
if (!string.IsNullOrEmpty(encryptedIsin))
|
||||
{
|
||||
try
|
||||
{
|
||||
isin = _crypto.DecryptIsin(encryptedIsin);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Errore nella decodifica ISIN cifrato");
|
||||
return BadRequest("Parametro 'p' non valido.");
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(aliasId))
|
||||
{
|
||||
isin = await _dataService.FindIsinByAliasIdAsync(aliasId);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(isin))
|
||||
{
|
||||
return BadRequest("Specificare il parametro 'p' (ISIN cifrato) o 'alias' (alias ID).");
|
||||
}
|
||||
|
||||
return await GenerateAndReturnPdf(isin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint diretto per ISIN (uso interno / debug).
|
||||
/// In produzione proteggere con autenticazione.
|
||||
/// </summary>
|
||||
[HttpGet("by-isin/{isin}")]
|
||||
public async Task<IActionResult> GenerateReportByIsin(string isin)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(isin) || isin.Length < 12)
|
||||
{
|
||||
return BadRequest("ISIN non valido.");
|
||||
}
|
||||
|
||||
return await GenerateAndReturnPdf(isin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint per download come allegato (content-disposition: attachment)
|
||||
/// </summary>
|
||||
[HttpGet("download")]
|
||||
public async Task<IActionResult> DownloadReport(
|
||||
[FromQuery(Name = "p")] string? encryptedIsin = null,
|
||||
[FromQuery(Name = "alias")] string? aliasId = null)
|
||||
{
|
||||
string? isin = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(encryptedIsin))
|
||||
isin = _crypto.DecryptIsin(encryptedIsin);
|
||||
else if (!string.IsNullOrEmpty(aliasId))
|
||||
isin = await _dataService.FindIsinByAliasIdAsync(aliasId);
|
||||
|
||||
if (string.IsNullOrEmpty(isin))
|
||||
return BadRequest("Specificare il parametro 'p' o 'alias'.");
|
||||
|
||||
try
|
||||
{
|
||||
var pdfBytes = await _orchestrator.GenerateReportAsync(isin);
|
||||
return File(pdfBytes, "application/pdf", $"{isin}.pdf");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Errore generazione report download per ISIN {Isin}", isin);
|
||||
return StatusCode(500, "Errore nella generazione del report.");
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Helper ────────────────────────────────────────────────────────
|
||||
|
||||
private async Task<IActionResult> GenerateAndReturnPdf(string isin)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Richiesta report per ISIN {Isin}", isin);
|
||||
var pdfBytes = await _orchestrator.GenerateReportAsync(isin);
|
||||
|
||||
// Inline: il PDF si apre direttamente nel browser
|
||||
Response.Headers.Append("Content-Disposition", $"inline; filename={isin}.pdf");
|
||||
return File(pdfBytes, "application/pdf");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Errore generazione report per ISIN {Isin}", isin);
|
||||
return StatusCode(500, "Errore nella generazione del report.");
|
||||
}
|
||||
}
|
||||
}
|
||||
47
CertReports.Syncfusion/Controllers/TestController.cs
Normal file
47
CertReports.Syncfusion/Controllers/TestController.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace CertReports.Syncfusion.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class TestController : ControllerBase
|
||||
{
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
public TestController(IConfiguration config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
[HttpGet("db")]
|
||||
public async Task<IActionResult> TestDb()
|
||||
{
|
||||
var connStr = _config.GetConnectionString("CertDb");
|
||||
|
||||
try
|
||||
{
|
||||
await using var conn = new SqlConnection(connStr);
|
||||
await conn.OpenAsync();
|
||||
await using var cmd = new SqlCommand("SELECT 1", conn);
|
||||
var result = await cmd.ExecuteScalarAsync();
|
||||
return Ok(new
|
||||
{
|
||||
status = "OK",
|
||||
result = result?.ToString(),
|
||||
connectionString = connStr?.Replace(_config["ConnectionStrings:CertDb"]?.Split("Password=").LastOrDefault()?.Split(";").FirstOrDefault() ?? "", "***")
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Ok(new
|
||||
{
|
||||
status = "ERRORE",
|
||||
message = ex.Message,
|
||||
innerMessage = ex.InnerException?.Message,
|
||||
connectionString = connStr
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user