Add background PDF generation for published document versions
Move PDF generation from synchronous publish flow to a background polling job. Published versions with file_id IS NULL are picked up by the job, which generates the PDF, uploads to S3, and links the file. Export PDF now serves stored files for published versions (with optional signature page and watermark) and generates on the fly for drafts. Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -44,6 +44,9 @@ var (
|
||||
//go:embed transfer_impact_assessments_template.html
|
||||
transferImpactAssessmentsTemplateContent string
|
||||
|
||||
//go:embed signature_page_template.html
|
||||
signaturePageTemplateContent string
|
||||
|
||||
templateFuncs = template.FuncMap{
|
||||
"now": func() time.Time { return time.Now() },
|
||||
"eq": func(a, b any) bool { return a == b },
|
||||
@@ -183,6 +186,8 @@ var (
|
||||
dataProtectionImpactAssessmentsTemplate = template.Must(template.New("dataProtectionImpactAssessments").Funcs(templateFuncs).Parse(dataProtectionImpactAssessmentsTemplateContent))
|
||||
|
||||
transferImpactAssessmentsTemplate = template.Must(template.New("transferImpactAssessments").Funcs(templateFuncs).Parse(transferImpactAssessmentsTemplateContent))
|
||||
|
||||
signaturePageTemplate = template.Must(template.New("signaturePage").Funcs(templateFuncs).Parse(signaturePageTemplateContent))
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -210,6 +215,11 @@ type (
|
||||
RequestedAt time.Time
|
||||
}
|
||||
|
||||
SignaturePageData struct {
|
||||
Signatures []SignatureData
|
||||
Landscape bool
|
||||
}
|
||||
|
||||
ProcessingActivityTableData struct {
|
||||
CompanyName string
|
||||
CompanyHorizontalLogoBase64 string
|
||||
@@ -399,6 +409,15 @@ func RenderHTML(data DocumentData) ([]byte, error) {
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func RenderSignaturePageHTML(data SignaturePageData) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := signaturePageTemplate.Execute(&buf, data); err != nil {
|
||||
return nil, fmt.Errorf("cannot execute signature page template: %w", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func RenderProcessingActivitiesTableHTML(data ProcessingActivityTableData) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := processingActivitiesTemplate.Execute(&buf, data); err != nil {
|
||||
|
||||
97
pkg/docgen/signature_page_template.html
Normal file
97
pkg/docgen/signature_page_template.html
Normal file
@@ -0,0 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
@page {
|
||||
size: {{- if .Landscape}} A4 landscape {{- else}} A4 {{- end}};
|
||||
margin: 1in;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
line-height: 1.5;
|
||||
color: #1a1a1a;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.signatures-title {
|
||||
font-size: 13pt;
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.signatures-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 9pt;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.signatures-table th,
|
||||
.signatures-table td {
|
||||
padding: 6px 8px;
|
||||
text-align: left;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.signatures-table th {
|
||||
background: #f5f5f5;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.signature-signed {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.signature-requested {
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2 class="signatures-title">Document Signatures</h2>
|
||||
<table class="signatures-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Signatory</th>
|
||||
<th>Status</th>
|
||||
<th>Requested Date</th>
|
||||
<th>Signed Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{- range .Signatures}}
|
||||
<tr>
|
||||
<td>{{.SignedBy}}</td>
|
||||
<td>
|
||||
{{- if eq (string .State) "SIGNED"}}
|
||||
<span class="signature-signed">{{string .State}}</span>
|
||||
{{- else}}
|
||||
<span class="signature-requested">{{string .State}}</span>
|
||||
{{- end}}
|
||||
</td>
|
||||
<td>{{.RequestedAt.Format "Jan 2, 2006"}}</td>
|
||||
<td>
|
||||
{{- if .SignedAt}}
|
||||
{{.SignedAt.Format "Jan 2, 2006"}}
|
||||
{{- else}}
|
||||
-
|
||||
{{- end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{- end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user