From f1126c600a1d11530e7a9989b742fedd75ae427c Mon Sep 17 00:00:00 2001 From: solidprogramming Date: Tue, 10 Sep 2024 13:26:11 +0200 Subject: [PATCH 01/80] [+] Added puppeteersharp for pdf creation #2322 --- roles/ui/files/FWO.UI/FWO.Ui.csproj | 1 + .../FWO.UI/Pages/Reporting/ReportExport.razor | 42 +++++++++++++++---- roles/ui/files/FWO.UI/Program.cs | 5 +++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/roles/ui/files/FWO.UI/FWO.Ui.csproj b/roles/ui/files/FWO.UI/FWO.Ui.csproj index 9a3de6167..9507dad3d 100644 --- a/roles/ui/files/FWO.UI/FWO.Ui.csproj +++ b/roles/ui/files/FWO.UI/FWO.Ui.csproj @@ -9,6 +9,7 @@ + diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor index c7e0382eb..75c4a7118 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor @@ -4,6 +4,10 @@ @using WkHtmlToPdfDotNet @using System.Linq @using FWO.Report.Filter +@using PuppeteerSharp +@using PuppeteerSharp.Media +@using System.IO + @inject ApiConnection apiConnection @inject UserConfig userConfig @@ -159,15 +163,9 @@ } if (ExportPdf) - { - try - { - reportExportFile.Pdf = Convert.ToBase64String(ReportToExport.ToPdf(SelectedPaperKind, PaperSizeWidth, PaperSizeHeight)); - } - catch (KeyNotFoundException) - { - throw new Exception("This paper kind is currently not supported. Please choose another one or \"Custom\" for a custom size."); - } + { + string html = ReportToExport.ExportToHtml(); + reportExportFile.Pdf = await CreatePDFViaPuppeteer(html); } if (ExportCsv) @@ -211,4 +209,30 @@ DisplayMessageInUi(null, userConfig.GetText("export_report"), userConfig.GetText("E1002"), true); } } + + private async Task CreatePDFViaPuppeteer(string html) + { + using IBrowser? browser = await Puppeteer.LaunchAsync(new LaunchOptions + { + Headless = true + }); + + try + { + using IPage page = await browser.NewPageAsync(); + await page.SetContentAsync(html); + + PdfOptions pdfOptions = new PdfOptions() { DisplayHeaderFooter = true, Landscape = true, PrintBackground = true, Format = PaperFormat.A4, MarginOptions = new MarginOptions { Top = "1cm", Bottom = "1cm", Left = "1cm", Right = "1cm" }}; + byte[] pdfData = await page.PdfDataAsync(pdfOptions); + + return Convert.ToBase64String(pdfData); + }catch(Exception) + { + throw new Exception("This paper kind is currently not supported. Please choose another one or \"Custom\" for a custom size."); + return default; + }finally + { + await browser.CloseAsync(); + } + } } diff --git a/roles/ui/files/FWO.UI/Program.cs b/roles/ui/files/FWO.UI/Program.cs index 81bb2c10e..cf9a49c82 100644 --- a/roles/ui/files/FWO.UI/Program.cs +++ b/roles/ui/files/FWO.UI/Program.cs @@ -10,12 +10,17 @@ using Microsoft.AspNetCore.Components.Server.Circuits; using RestSharp; using System.Diagnostics; +using PuppeteerSharp; // Implicitly call static constructor so background lock process is started // (static constructor is only called after class is used in any way) Log.WriteInfo("Startup", "Starting FWO UI Server..."); +Log.WriteInfo("Startup", "Downloading headless Browser..."); +BrowserFetcher? browserFetcher = new(); +await browserFetcher.DownloadAsync(); + var builder = WebApplication.CreateBuilder(args); builder.WebHost.UseWebRoot("wwwroot").UseStaticWebAssets(); From b9234c00195506a6aedd5401cb3d6996c41b553b Mon Sep 17 00:00:00 2001 From: solidprogramming Date: Tue, 10 Sep 2024 13:40:32 +0200 Subject: [PATCH 02/80] [~] Changed the spinner controls to hide it's text --- roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor | 2 +- roles/ui/files/FWO.UI/Pages/Reporting/ReportDownloadPopUp.razor | 2 +- roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor b/roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor index cff6e0e50..e0fa4b403 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor @@ -27,7 +27,7 @@ else {
- Exporting... + Exporting...
} diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/ReportDownloadPopUp.razor b/roles/ui/files/FWO.UI/Pages/Reporting/ReportDownloadPopUp.razor index 372965667..ee19804e1 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/ReportDownloadPopUp.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/ReportDownloadPopUp.razor @@ -9,7 +9,7 @@ @if(Downloading) {
- Exporting... + Exporting...
} else diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor index 75c4a7118..4a8b7d0f6 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor @@ -102,7 +102,7 @@ } else {
- Exporting... + Exporting...
} From 6fc08c4476d89fcc8d399309e22c46f9f8f265fb Mon Sep 17 00:00:00 2001 From: "luca.weidmann@gmx.de" Date: Wed, 11 Sep 2024 13:55:05 +0200 Subject: [PATCH 03/80] [~] Moved the PDF generation with puppeteer to reportbase --- roles/lib/files/FWO.Report/FWO.Report.csproj | 1 + roles/lib/files/FWO.Report/ReportBase.cs | 30 +++++++++++++++++++ roles/ui/files/FWO.UI/FWO.Ui.csproj | 1 - .../FWO.UI/Pages/Reporting/ReportExport.razor | 30 +------------------ 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/roles/lib/files/FWO.Report/FWO.Report.csproj b/roles/lib/files/FWO.Report/FWO.Report.csproj index 9a3a64891..84c581812 100644 --- a/roles/lib/files/FWO.Report/FWO.Report.csproj +++ b/roles/lib/files/FWO.Report/FWO.Report.csproj @@ -8,6 +8,7 @@ + diff --git a/roles/lib/files/FWO.Report/ReportBase.cs b/roles/lib/files/FWO.Report/ReportBase.cs index 31b4de154..149e70ecb 100644 --- a/roles/lib/files/FWO.Report/ReportBase.cs +++ b/roles/lib/files/FWO.Report/ReportBase.cs @@ -5,6 +5,8 @@ using FWO.Config.Api; using System.Text; using WkHtmlToPdfDotNet; +using PuppeteerSharp.Media; +using PuppeteerSharp; namespace FWO.Report { @@ -260,6 +262,34 @@ public virtual byte[] ToPdf(PaperKind paperKind, int width = -1, int height = -1 return converter.Convert(doc); } + public virtual async Task CreatePDFViaPuppeteer(string html) + { + using IBrowser? browser = await Puppeteer.LaunchAsync(new LaunchOptions + { + Headless = true + }); + + try + { + using IPage page = await browser.NewPageAsync(); + await page.SetContentAsync(html); + + PdfOptions pdfOptions = new PdfOptions() { DisplayHeaderFooter = true, Landscape = true, PrintBackground = true, Format = PaperFormat.A4, MarginOptions = new MarginOptions { Top = "1cm", Bottom = "1cm", Left = "1cm", Right = "1cm" } }; + byte[] pdfData = await page.PdfDataAsync(pdfOptions); + + return Convert.ToBase64String(pdfData); + } + catch (Exception) + { + throw new Exception("This paper kind is currently not supported. Please choose another one or \"Custom\" for a custom size."); + return default; + } + finally + { + await browser.CloseAsync(); + } + } + public static string GetIconClass(ObjCategory? objCategory, string? objType) { return objType switch diff --git a/roles/ui/files/FWO.UI/FWO.Ui.csproj b/roles/ui/files/FWO.UI/FWO.Ui.csproj index 9507dad3d..9a3de6167 100644 --- a/roles/ui/files/FWO.UI/FWO.Ui.csproj +++ b/roles/ui/files/FWO.UI/FWO.Ui.csproj @@ -9,7 +9,6 @@ - diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor index 4a8b7d0f6..a3cd1d5cf 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor @@ -4,8 +4,6 @@ @using WkHtmlToPdfDotNet @using System.Linq @using FWO.Report.Filter -@using PuppeteerSharp -@using PuppeteerSharp.Media @using System.IO @@ -165,7 +163,7 @@ if (ExportPdf) { string html = ReportToExport.ExportToHtml(); - reportExportFile.Pdf = await CreatePDFViaPuppeteer(html); + reportExportFile.Pdf = await ReportToExport.CreatePDFViaPuppeteer(html); } if (ExportCsv) @@ -209,30 +207,4 @@ DisplayMessageInUi(null, userConfig.GetText("export_report"), userConfig.GetText("E1002"), true); } } - - private async Task CreatePDFViaPuppeteer(string html) - { - using IBrowser? browser = await Puppeteer.LaunchAsync(new LaunchOptions - { - Headless = true - }); - - try - { - using IPage page = await browser.NewPageAsync(); - await page.SetContentAsync(html); - - PdfOptions pdfOptions = new PdfOptions() { DisplayHeaderFooter = true, Landscape = true, PrintBackground = true, Format = PaperFormat.A4, MarginOptions = new MarginOptions { Top = "1cm", Bottom = "1cm", Left = "1cm", Right = "1cm" }}; - byte[] pdfData = await page.PdfDataAsync(pdfOptions); - - return Convert.ToBase64String(pdfData); - }catch(Exception) - { - throw new Exception("This paper kind is currently not supported. Please choose another one or \"Custom\" for a custom size."); - return default; - }finally - { - await browser.CloseAsync(); - } - } } From 1e9ef5b0b95b4dbf7cc70b2ad34e509f3fb796a5 Mon Sep 17 00:00:00 2001 From: "luca.weidmann@gmx.de" Date: Thu, 12 Sep 2024 12:28:21 +0200 Subject: [PATCH 04/80] [+] Added overloads for pdf creation with puppeteer --- roles/lib/files/FWO.Report/ReportBase.cs | 73 +++++-------------- .../ImportChangeNotifier.cs | 16 +++- .../FWO.Middleware.Server/ReportScheduler.cs | 5 +- .../FWO.UI/Pages/Reporting/ReportExport.razor | 2 +- 4 files changed, 34 insertions(+), 62 deletions(-) diff --git a/roles/lib/files/FWO.Report/ReportBase.cs b/roles/lib/files/FWO.Report/ReportBase.cs index 149e70ecb..e9dcc1001 100644 --- a/roles/lib/files/FWO.Report/ReportBase.cs +++ b/roles/lib/files/FWO.Report/ReportBase.cs @@ -4,7 +4,6 @@ using FWO.Report.Filter; using FWO.Config.Api; using System.Text; -using WkHtmlToPdfDotNet; using PuppeteerSharp.Media; using PuppeteerSharp; @@ -90,9 +89,7 @@ public abstract class ReportBase public ReportData ReportData = new(); protected string htmlExport = ""; - - // Pdf converter - protected static readonly SynchronizedConverter converter = new (new PdfTools()); + public bool GotObjectsInReport { get; protected set; } = false; @@ -214,55 +211,7 @@ public static string ToUtcString(string? timestring) } } - public virtual byte[] ToPdf(PaperKind paperKind, int width = -1, int height = -1) - { - // HTML - if (string.IsNullOrEmpty(htmlExport)) - { - htmlExport = ExportToHtml(); - } - - GlobalSettings globalSettings = new () - { - ColorMode = ColorMode.Color, - Orientation = Orientation.Landscape, - }; - - if (paperKind == PaperKind.Custom) - { - if (width > 0 && height > 0) - { - globalSettings.PaperSize = new PechkinPaperSize(width + "mm", height + "mm"); - } - else - { - throw new Exception("Custom paper size: width or height <= 0"); - } - } - else - { - globalSettings.PaperSize = paperKind; - } - - HtmlToPdfDocument doc = new () - { - GlobalSettings = globalSettings, - Objects = - { - new ObjectSettings() - { - PagesCount = true, - HtmlContent = htmlExport, - WebSettings = { DefaultEncoding = "utf-8" }, - HeaderSettings = { FontSize = 9, Right = "Page [page] of [toPage]", Line = true, Spacing = 2.812 } - } - } - }; - - return converter.Convert(doc); - } - - public virtual async Task CreatePDFViaPuppeteer(string html) + private static async Task CreatePDFViaPuppeteer(string html, PaperFormat format) { using IBrowser? browser = await Puppeteer.LaunchAsync(new LaunchOptions { @@ -274,7 +223,7 @@ public virtual byte[] ToPdf(PaperKind paperKind, int width = -1, int height = -1 using IPage page = await browser.NewPageAsync(); await page.SetContentAsync(html); - PdfOptions pdfOptions = new PdfOptions() { DisplayHeaderFooter = true, Landscape = true, PrintBackground = true, Format = PaperFormat.A4, MarginOptions = new MarginOptions { Top = "1cm", Bottom = "1cm", Left = "1cm", Right = "1cm" } }; + PdfOptions pdfOptions = new PdfOptions() { DisplayHeaderFooter = true, Landscape = true, PrintBackground = true, Format = format, MarginOptions = new MarginOptions { Top = "1cm", Bottom = "1cm", Left = "1cm", Right = "1cm" } }; byte[] pdfData = await page.PdfDataAsync(pdfOptions); return Convert.ToBase64String(pdfData); @@ -282,7 +231,6 @@ public virtual byte[] ToPdf(PaperKind paperKind, int width = -1, int height = -1 catch (Exception) { throw new Exception("This paper kind is currently not supported. Please choose another one or \"Custom\" for a custom size."); - return default; } finally { @@ -290,6 +238,21 @@ public virtual byte[] ToPdf(PaperKind paperKind, int width = -1, int height = -1 } } + public virtual async Task ToPdf(string html, PaperFormat format) + { + return await CreatePDFViaPuppeteer(html, format); + } + + public virtual async Task ToPdf(string html) + { + return await CreatePDFViaPuppeteer(html, PaperFormat.A4); + } + + public virtual async Task ToPdf(PaperFormat format) + { + return await CreatePDFViaPuppeteer(htmlExport, format); + } + public static string GetIconClass(ObjCategory? objCategory, string? objType) { return objType switch diff --git a/roles/middleware/files/FWO.Middleware.Server/ImportChangeNotifier.cs b/roles/middleware/files/FWO.Middleware.Server/ImportChangeNotifier.cs index 4e04a02be..7a820d717 100644 --- a/roles/middleware/files/FWO.Middleware.Server/ImportChangeNotifier.cs +++ b/roles/middleware/files/FWO.Middleware.Server/ImportChangeNotifier.cs @@ -11,7 +11,7 @@ using Newtonsoft.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; -using WkHtmlToPdfDotNet; +using PuppeteerSharp.Media; namespace FWO.Middleware.Server { @@ -175,11 +175,14 @@ private async Task SendEmail() EmailConnection emailConnection = new(globalConfig.EmailServerAddress, globalConfig.EmailPort, globalConfig.EmailTls, globalConfig.EmailUser, decryptedSecret, globalConfig.EmailSenderAddress); MailKitMailer mailer = new(emailConnection); - await mailer.SendAsync(PrepareEmail(), emailConnection, new CancellationToken(), + + MailData? mail = await PrepareEmail(); + + await mailer.SendAsync(mail, emailConnection, new CancellationToken(), globalConfig.ImpChangeNotifyType == (int)ImpChangeNotificationType.HtmlInBody); } - private MailData PrepareEmail() + private async Task PrepareEmail() { string subject = globalConfig.ImpChangeNotifySubject; string body = CreateBody(); @@ -192,7 +195,12 @@ private MailData PrepareEmail() body += changeReport?.ExportToHtml(); break; case (int)ImpChangeNotificationType.PdfAsAttachment: - attachment = CreateAttachment(Convert.ToBase64String(changeReport?.ToPdf(PaperKind.A4) ?? throw new Exception("No Pdf generated.")), GlobalConst.kPdf); + string? pdfData = await changeReport.ToPdf(PaperFormat.A4); + + if (string.IsNullOrWhiteSpace(pdfData)) + throw new Exception("No Pdf generated."); + + attachment = CreateAttachment(pdfData, GlobalConst.kPdf); break; case (int)ImpChangeNotificationType.HtmlAsAttachment: attachment = CreateAttachment(changeReport?.ExportToHtml(), GlobalConst.kHtml); diff --git a/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs b/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs index 441eed8db..3a26e49d6 100644 --- a/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs +++ b/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs @@ -10,6 +10,7 @@ using System.Timers; using WkHtmlToPdfDotNet; using FWO.Config.File; +using PuppeteerSharp.Media; namespace FWO.Middleware.Server { @@ -255,7 +256,7 @@ private static async Task AdaptDeviceFilter(ReportParams reportParams, ApiConnec } } - private static void WriteReportFile(ReportBase report, List fileFormats, ReportFile reportFile) + private static async Task WriteReportFile(ReportBase report, List fileFormats, ReportFile reportFile) { reportFile.Json = report.ExportToJson(); foreach (FileFormat format in fileFormats) @@ -271,7 +272,7 @@ private static void WriteReportFile(ReportBase report, List fileForm break; case GlobalConst.kPdf: - reportFile.Pdf = Convert.ToBase64String(report.ToPdf(PaperKind.A4)); + reportFile.Pdf = await report.ToPdf(PaperFormat.A4); break; case GlobalConst.kJson: diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor index a3cd1d5cf..769039107 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor @@ -163,7 +163,7 @@ if (ExportPdf) { string html = ReportToExport.ExportToHtml(); - reportExportFile.Pdf = await ReportToExport.CreatePDFViaPuppeteer(html); + reportExportFile.Pdf = await ReportToExport.ToPdf(html); } if (ExportCsv) From ed5ac52b4e00cc82821b930b20da142e6ee98d2d Mon Sep 17 00:00:00 2001 From: "luca.weidmann@gmx.de" Date: Thu, 12 Sep 2024 13:28:36 +0200 Subject: [PATCH 05/80] [+] Added custom pdf size for puppeteer --- roles/lib/files/FWO.Report/PaperFormat.cs | 18 +++++++ roles/lib/files/FWO.Report/ReportBase.cs | 49 ++++++++++++++----- .../ImportChangeNotifier.cs | 2 +- .../FWO.Middleware.Server/ReportScheduler.cs | 2 +- .../FWO.UI/Pages/Reporting/ReportExport.razor | 48 +++++++++++------- 5 files changed, 86 insertions(+), 33 deletions(-) create mode 100644 roles/lib/files/FWO.Report/PaperFormat.cs diff --git a/roles/lib/files/FWO.Report/PaperFormat.cs b/roles/lib/files/FWO.Report/PaperFormat.cs new file mode 100644 index 000000000..75d86d0d7 --- /dev/null +++ b/roles/lib/files/FWO.Report/PaperFormat.cs @@ -0,0 +1,18 @@ +namespace FWO.Report +{ + public enum PaperFormat + { + A0, + A1, + A2, + A3, + A4, + A5, + A6, + Letter, + Legal, + Tabloid, + Ledger, + Custom + } +} diff --git a/roles/lib/files/FWO.Report/ReportBase.cs b/roles/lib/files/FWO.Report/ReportBase.cs index e9dcc1001..76c307e4e 100644 --- a/roles/lib/files/FWO.Report/ReportBase.cs +++ b/roles/lib/files/FWO.Report/ReportBase.cs @@ -6,13 +6,14 @@ using System.Text; using PuppeteerSharp.Media; using PuppeteerSharp; +using System.Reflection; namespace FWO.Report { public enum RsbTab { - all = 10, - report = 20, + all = 10, + report = 20, rule = 30, usedObj = 40, @@ -22,8 +23,8 @@ public enum RsbTab public enum ObjCategory { all = 0, - nobj = 1, - nsrv = 2, + nobj = 1, + nsrv = 2, user = 3 } @@ -43,7 +44,7 @@ public enum OutputLocation public abstract class ReportBase { - protected StringBuilder HtmlTemplate = new ($@" + protected StringBuilder HtmlTemplate = new($@" @@ -87,9 +88,11 @@ public abstract class ReportBase protected UserConfig userConfig; public ReportType ReportType; public ReportData ReportData = new(); + public int CustomWidth = 0; + public int CustomHeight = 0; protected string htmlExport = ""; - + public bool GotObjectsInReport { get; protected set; } = false; @@ -159,14 +162,14 @@ protected string GenerateHtmlFrameBase(string title, string filter, DateTime dat HtmlTemplate = HtmlTemplate.Replace("##Filter##", userConfig.GetText("filter") + ": " + filter); HtmlTemplate = HtmlTemplate.Replace("##GeneratedOn##", userConfig.GetText("generated_on")); HtmlTemplate = HtmlTemplate.Replace("##Date##", date.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK")); - if(ReportType.IsChangeReport()) + if (ReportType.IsChangeReport()) { string timeRange = $"{userConfig.GetText("change_time")}: " + $"{userConfig.GetText("from")}: {ToUtcString(Query.QueryVariables["start"]?.ToString())}, " + $"{userConfig.GetText("until")}: {ToUtcString(Query.QueryVariables["stop"]?.ToString())}"; HtmlTemplate = HtmlTemplate.Replace("##Date-of-Config##: ##GeneratedFor##", timeRange); } - else if(ReportType.IsRuleReport() || ReportType == ReportType.Statistics) + else if (ReportType.IsRuleReport() || ReportType == ReportType.Statistics) { HtmlTemplate = HtmlTemplate.Replace("##Date-of-Config##", userConfig.GetText("date_of_config")); HtmlTemplate = HtmlTemplate.Replace("##GeneratedFor##", ToUtcString(Query.ReportTimeString)); @@ -185,7 +188,7 @@ protected string GenerateHtmlFrameBase(string title, string filter, DateTime dat HtmlTemplate = HtmlTemplate.Replace("

##OwnerFilters##

", ""); } - if(deviceFilter != null) + if (deviceFilter != null) { HtmlTemplate = HtmlTemplate.Replace("##OtherFilters##", userConfig.GetText("devices") + ": " + deviceFilter); } @@ -205,13 +208,13 @@ public static string ToUtcString(string? timestring) { return timestring != null ? DateTime.Parse(timestring).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK") : ""; } - catch(Exception) + catch (Exception) { return timestring ?? ""; } } - private static async Task CreatePDFViaPuppeteer(string html, PaperFormat format) + private async Task CreatePDFViaPuppeteer(string html, PaperFormat format) { using IBrowser? browser = await Puppeteer.LaunchAsync(new LaunchOptions { @@ -223,7 +226,9 @@ public static string ToUtcString(string? timestring) using IPage page = await browser.NewPageAsync(); await page.SetContentAsync(html); - PdfOptions pdfOptions = new PdfOptions() { DisplayHeaderFooter = true, Landscape = true, PrintBackground = true, Format = format, MarginOptions = new MarginOptions { Top = "1cm", Bottom = "1cm", Left = "1cm", Right = "1cm" } }; + PuppeteerSharp.Media.PaperFormat? pupformat = GetPuppeteerPaperFormat(format) ?? throw new Exception(); + + PdfOptions pdfOptions = new() { DisplayHeaderFooter = true, Landscape = true, PrintBackground = true, Format = pupformat, MarginOptions = new MarginOptions { Top = "1cm", Bottom = "1cm", Left = "1cm", Right = "1cm" } }; byte[] pdfData = await page.PdfDataAsync(pdfOptions); return Convert.ToBase64String(pdfData); @@ -238,6 +243,26 @@ public static string ToUtcString(string? timestring) } } + private PuppeteerSharp.Media.PaperFormat? GetPuppeteerPaperFormat(PaperFormat format) + { + if (format == PaperFormat.Custom) + return new PuppeteerSharp.Media.PaperFormat(CustomWidth, CustomHeight); + + PropertyInfo[] propertyInfos = typeof(PuppeteerSharp.Media.PaperFormat).GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic); + + PropertyInfo? prop = propertyInfos.SingleOrDefault(_ => _.Name == format.ToString()); + + if (prop == null) + return default; + + PuppeteerSharp.Media.PaperFormat? propFormat = (PuppeteerSharp.Media.PaperFormat)prop.GetValue(null); + + if (propFormat is null) + return default; + + return propFormat; + } + public virtual async Task ToPdf(string html, PaperFormat format) { return await CreatePDFViaPuppeteer(html, format); diff --git a/roles/middleware/files/FWO.Middleware.Server/ImportChangeNotifier.cs b/roles/middleware/files/FWO.Middleware.Server/ImportChangeNotifier.cs index 7a820d717..57f582d0f 100644 --- a/roles/middleware/files/FWO.Middleware.Server/ImportChangeNotifier.cs +++ b/roles/middleware/files/FWO.Middleware.Server/ImportChangeNotifier.cs @@ -195,7 +195,7 @@ private async Task PrepareEmail() body += changeReport?.ExportToHtml(); break; case (int)ImpChangeNotificationType.PdfAsAttachment: - string? pdfData = await changeReport.ToPdf(PaperFormat.A4); + string? pdfData = await changeReport.ToPdf(Report.PaperFormat.A4); if (string.IsNullOrWhiteSpace(pdfData)) throw new Exception("No Pdf generated."); diff --git a/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs b/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs index 3a26e49d6..5d8a8691a 100644 --- a/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs +++ b/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs @@ -272,7 +272,7 @@ private static async Task WriteReportFile(ReportBase report, List fi break; case GlobalConst.kPdf: - reportFile.Pdf = await report.ToPdf(PaperFormat.A4); + reportFile.Pdf = await report.ToPdf(Report.PaperFormat.A4); break; case GlobalConst.kJson: diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor index 769039107..6f3945c9f 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/ReportExport.razor @@ -1,6 +1,7 @@ @using System.Text @using FWO.Report @using FWO.Config.Api +@using System.Reflection @using WkHtmlToPdfDotNet @using System.Linq @using FWO.Report.Filter @@ -10,8 +11,10 @@ @inject ApiConnection apiConnection @inject UserConfig userConfig - + @@ -35,20 +38,20 @@ {
@(userConfig.GetText("page_format")): - - @if (SelectedPaperKind == PaperKind.Custom) + + @if (SelectedPaperFormat == PaperFormat.Custom) {
-
- @(userConfig.GetText("width")) -
- +
+ @(userConfig.GetText("width")) +
+
-
- @(userConfig.GetText("height")) -
- +
+ @(userConfig.GetText("height")) +
+
}
@@ -65,7 +68,7 @@ { } - else + else { ExportCsv = false; @@ -94,11 +97,13 @@