Refactor membership PDF generation logic to improve maintainability and validation; remove deprecated form filling methods and enhance email notification process. Update membership page styles for better layout and user experience.
This commit is contained in:
105
server/utils/pdf-generator-service.js
Normal file
105
server/utils/pdf-generator-service.js
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* PDF Generator Service - Main service for PDF generation
|
||||
* Clean Code: Facade Pattern, Single Responsibility
|
||||
*/
|
||||
|
||||
import { PDFDocument } from 'pdf-lib'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { fillPdfForm } from './pdf-form-filler.js'
|
||||
|
||||
/**
|
||||
* PDF Generation Result
|
||||
*/
|
||||
export class PDFGenerationResult {
|
||||
constructor(success, pdfBuffer, filename, error = null) {
|
||||
this.success = success
|
||||
this.pdfBuffer = pdfBuffer
|
||||
this.filename = filename
|
||||
this.error = error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PDF Generator Service
|
||||
*/
|
||||
export class PDFGeneratorService {
|
||||
constructor() {
|
||||
this.templatePath = path.join(process.cwd(), 'server', 'templates', 'mitgliedschaft-fillable.pdf')
|
||||
this.fallbackTemplatePath = path.join(process.cwd(), 'server', 'templates', 'Aufnahmeantrag 2025.pdf')
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates PDF from template with form data
|
||||
* @param {Object} data - Form data
|
||||
* @returns {Promise<PDFGenerationResult>} Generation result
|
||||
*/
|
||||
async generateFromTemplate(data) {
|
||||
try {
|
||||
const templatePath = await this.getTemplatePath()
|
||||
const templateBytes = await fs.readFile(templatePath)
|
||||
const pdfDoc = await PDFDocument.load(templateBytes)
|
||||
const form = pdfDoc.getForm()
|
||||
|
||||
// Fill form fields
|
||||
await fillPdfForm(pdfDoc, form, data)
|
||||
|
||||
// Don't flatten form to keep fields editable
|
||||
// form.flatten() makes fields non-editable
|
||||
|
||||
// Generate filename
|
||||
const filename = this.generateFilename(data)
|
||||
|
||||
// Save PDF
|
||||
const pdfBytes = await pdfDoc.save()
|
||||
|
||||
return new PDFGenerationResult(true, Buffer.from(pdfBytes), filename)
|
||||
} catch (error) {
|
||||
console.error('Template PDF generation failed:', error.message)
|
||||
return new PDFGenerationResult(false, null, null, error.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the appropriate template path
|
||||
* @returns {Promise<string>} Template path
|
||||
*/
|
||||
async getTemplatePath() {
|
||||
try {
|
||||
await fs.access(this.templatePath)
|
||||
return this.templatePath
|
||||
} catch (error) {
|
||||
try {
|
||||
await fs.access(this.fallbackTemplatePath)
|
||||
return this.fallbackTemplatePath
|
||||
} catch (fallbackError) {
|
||||
throw new Error('No PDF template found')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates filename for PDF
|
||||
* @param {Object} data - Form data
|
||||
* @returns {string} Filename
|
||||
*/
|
||||
generateFilename(data) {
|
||||
const timestamp = Date.now()
|
||||
const name = `${data.nachname || 'Unbekannt'}_${data.vorname || 'Unbekannt'}`
|
||||
return `beitrittserklärung_${timestamp}.pdf`
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves PDF to file system
|
||||
* @param {Buffer} pdfBuffer - PDF buffer
|
||||
* @param {string} filename - Filename
|
||||
* @param {string} uploadDir - Upload directory
|
||||
* @returns {Promise<string>} File path
|
||||
*/
|
||||
async savePDF(pdfBuffer, filename, uploadDir) {
|
||||
const filePath = path.join(uploadDir, filename)
|
||||
await fs.writeFile(filePath, pdfBuffer)
|
||||
return filePath
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user