Files
jobtrackingapp/JobTrackerApi/Services/PlaywrightCvPdfExporter.cs

67 lines
2.4 KiB
C#

using Microsoft.Playwright;
namespace JobTrackerApi.Services;
public sealed record CvPdfArtifact(string FileName, string StoragePath, byte[] Bytes);
public interface ICvPdfExporter
{
Task<CvPdfArtifact> ExportAsync(TailoredCvRenderResult renderResult, CancellationToken cancellationToken);
}
public sealed class PlaywrightCvPdfExporter : ICvPdfExporter
{
private readonly AppPaths _paths;
private readonly ILogger<PlaywrightCvPdfExporter> _logger;
public PlaywrightCvPdfExporter(AppPaths paths, ILogger<PlaywrightCvPdfExporter> logger)
{
_paths = paths;
_logger = logger;
}
public async Task<CvPdfArtifact> ExportAsync(TailoredCvRenderResult renderResult, CancellationToken cancellationToken)
{
var now = DateTimeOffset.UtcNow;
var folder = Path.Combine(_paths.CvExportsRoot, now.ToString("yyyyMMdd"));
Directory.CreateDirectory(folder);
var fileName = string.IsNullOrWhiteSpace(renderResult.SuggestedFileName)
? $"tailored-cv-{now:yyyyMMddHHmmss}.pdf"
: renderResult.SuggestedFileName;
var storagePath = Path.Combine(folder, fileName);
try
{
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
Headless = true,
});
var page = await browser.NewPageAsync();
await page.SetContentAsync(renderResult.Html, new PageSetContentOptions
{
WaitUntil = WaitUntilState.Load,
});
var bytes = await page.PdfAsync(new PagePdfOptions
{
Format = "A4",
PrintBackground = true,
Margin = new()
{
Top = "0",
Right = "0",
Bottom = "0",
Left = "0",
}
});
await File.WriteAllBytesAsync(storagePath, bytes, cancellationToken);
return new CvPdfArtifact(fileName, storagePath, bytes);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to export CV PDF to {Path}", storagePath);
throw new InvalidOperationException("CV PDF export is unavailable. Ensure Chromium is installed for Playwright on this machine.", ex);
}
}
}