Repository navigation
Expand file tree
/
Copy pathTextPdfExporter.cs
More file actions
123 lines (109 loc) · 5.2 KB
/
Copy pathTextPdfExporter.cs
File metadata and controls
123 lines (109 loc) · 5.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System.Text;
using BlazorWebForms.Core.Abstractions;
using BlazorWebForms.Core.Models;
using BlazorWebForms.Core.Services;
namespace BlazorWebForms.Infrastructure.SqlServer;
internal sealed class TextPdfExporter(
BlazorWebFormsSqlServerOptions options,
IFormDefinitionSerializer serializer,
IPdfIntegration pdfIntegration) : IPdfExporter
{
public async Task<byte[]> ExportEntryAsync(FormAggregate form, EntryRecord entry, CancellationToken cancellationToken = default)
{
if (!options.EnableTextBasedPdfExporter)
{
throw new InvalidOperationException("Text-based PDF exporter is disabled.");
}
var version = form.Versions.FirstOrDefault(v => v.Id == entry.FormVersionId);
var definition = version is null
? form.DraftDefinition
: serializer.Deserialize(version.DefinitionJson);
var answerRows = BuildAnswerRows(definition, entry)
.Take(Math.Max(1, options.PdfMaxAnswerRows))
.ToList();
var auditRows = entry.ApprovalAuditTrail
.OrderByDescending(audit => audit.OccurredUtc)
.Take(Math.Max(1, options.PdfMaxAuditRows))
.ToList();
var builder = new StringBuilder()
.AppendLine("BLAZOR WEB FORMS EXPORT")
.AppendLine($"Form: {ResolveLocalizedFormTitle(form, definition)}")
.AppendLine($"Description: {ResolveLocalizedFormDescription(form, definition)}")
.AppendLine($"Form version id: {entry.FormVersionId}")
.AppendLine($"Entry: {entry.Id}")
.AppendLine($"Submitted by: {entry.SubmittedBy}")
.AppendLine($"Submitted email: {entry.SubmittedByEmail}")
.AppendLine($"Submitted utc: {entry.SubmittedUtc:O}")
.AppendLine($"Status: {entry.Status}")
.AppendLine($"Branding accent: {definition.Branding.AccentColor}")
.AppendLine($"Branding surface: {definition.Branding.SurfaceColor}")
.AppendLine($"Branding text: {definition.Branding.TextColor}")
.AppendLine();
builder.AppendLine("ANSWERS");
foreach (var answer in answerRows)
{
builder.AppendLine($"{answer}");
}
if (entry.Files.Count > 0)
{
builder.AppendLine();
builder.AppendLine("FILES");
foreach (var file in entry.Files.OrderBy(file => file.FieldId).ThenBy(file => file.FileName))
{
builder.AppendLine($"{file.FieldId}: {file.FileName} ({file.ContentType}, {file.Length} bytes, sha256={file.Sha256})");
}
}
if (entry.ApprovalSteps.Count > 0)
{
builder.AppendLine();
builder.AppendLine("APPROVAL STEPS");
foreach (var step in entry.ApprovalSteps.OrderBy(step => step.Order))
{
builder.AppendLine($"{step.Order}. {step.ApproverName} <{step.ApproverEmail}> - {step.Status}");
}
}
if (auditRows.Count > 0)
{
builder.AppendLine();
builder.AppendLine("APPROVAL AUDIT");
foreach (var audit in auditRows)
{
builder.AppendLine($"{audit.OccurredUtc:O} {audit.Action} by {audit.ActorDisplayName}; reason={audit.Reason}; signature={audit.Signature}");
}
}
var fields = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase)
{
["formName"] = ResolveLocalizedFormTitle(form, definition),
["entryId"] = entry.Id.ToString(),
["status"] = entry.Status.ToString(),
["content"] = builder.ToString()
};
var payload = await pdfIntegration.RenderAsync($"Entry {entry.Id}", fields, cancellationToken);
if (payload.Length > options.PdfMaxBytes)
{
throw new InvalidOperationException($"PDF export exceeded max configured size of {options.PdfMaxBytes} bytes.");
}
return payload;
}
private static IEnumerable<string> BuildAnswerRows(FormDefinition definition, EntryRecord entry)
{
foreach (var section in definition.Sections)
{
var sectionTitle = FormLocalizationResolver.ResolveText(section.Title, section.LocalizedTitles, definition.DefaultCulture, definition.DefaultCulture);
foreach (var field in section.Fields)
{
var label = FormLocalizationResolver.ResolveText(field.Label, field.LocalizedLabels, definition.DefaultCulture, definition.DefaultCulture);
entry.Answers.TryGetValue(field.Id, out var value);
yield return $"[{sectionTitle}] {label} ({field.Id}): {value}";
}
}
}
private static string ResolveLocalizedFormTitle(FormAggregate form, FormDefinition definition)
{
return FormLocalizationResolver.ResolveText(definition.Title, definition.LocalizedTitles, definition.DefaultCulture, definition.DefaultCulture);
}
private static string ResolveLocalizedFormDescription(FormAggregate form, FormDefinition definition)
{
return FormLocalizationResolver.ResolveText(definition.Description, definition.LocalizedDescriptions, definition.DefaultCulture, definition.DefaultCulture);
}
}