updated pdf renderer to support zipped output
Some checks failed
Tests / Run Go Tests (push) Failing after 1m47s
Some checks failed
Tests / Run Go Tests (push) Failing after 1m47s
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"arbeitszeitmessung/helper"
|
||||
"arbeitszeitmessung/helper/paramParser"
|
||||
"arbeitszeitmessung/models"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
)
|
||||
|
||||
const DE_DATE string = "02.01.2006"
|
||||
const FILE_YEAR_MONTH string = "2006_01"
|
||||
|
||||
func convertDaysToTypst(days []models.IWorkDay, u models.User) ([]typstDay, error) {
|
||||
var typstDays []typstDay
|
||||
@@ -92,17 +94,43 @@ func PDFCreateController(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
output, err := createReports(user, employes, startDate)
|
||||
if err != nil {
|
||||
slog.Warn("Could not create pdf report", slog.Any("Error", err))
|
||||
n := 0
|
||||
for _, e := range employes {
|
||||
if user.IsSuperior(e) {
|
||||
employes[n] = e
|
||||
n++
|
||||
}
|
||||
}
|
||||
employes = employes[:n]
|
||||
|
||||
reportData := createReports(employes, startDate)
|
||||
|
||||
switch pp.ParseStringFallback("output", "render") {
|
||||
case "render":
|
||||
output, err := renderPDFSingle(reportData)
|
||||
if err != nil {
|
||||
slog.Warn("Could not create pdf report", slog.Any("Error", err))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
w.Header().Set("Content-type", "application/pdf")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=Monatsabrechnung_%s", startDate.Format(FILE_YEAR_MONTH)))
|
||||
output.WriteTo(w)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
case "download":
|
||||
panic("Not implemented")
|
||||
pdfReports, err := renderPDFMulti(reportData)
|
||||
if err != nil {
|
||||
slog.Warn("Could not create pdf report", slog.Any("Error", err))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
output, err := zipPfd(pdfReports, &reportData)
|
||||
if err != nil {
|
||||
slog.Warn("Could not create pdf report", slog.Any("Error", err))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
w.Header().Set("Content-type", "application/zip")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachement; filename=Monatsabrechnung_%s", startDate.Format(FILE_YEAR_MONTH)))
|
||||
output.WriteTo(w)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -110,7 +138,7 @@ func PDFCreateController(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func createReports(user models.User, employes []models.User, startDate time.Time) (bytes.Buffer, error) {
|
||||
func createReports(employes []models.User, startDate time.Time) []typstData {
|
||||
startDate = helper.GetFirstOfMonth(startDate)
|
||||
endDate := startDate.AddDate(0, 1, -1)
|
||||
|
||||
@@ -122,7 +150,7 @@ func createReports(user models.User, employes []models.User, startDate time.Time
|
||||
employeData = append(employeData, data)
|
||||
}
|
||||
}
|
||||
return renderPDF(employeData)
|
||||
return employeData
|
||||
}
|
||||
|
||||
func createEmployeReport(employee models.User, startDate, endDate time.Time) (typstData, error) {
|
||||
@@ -158,13 +186,17 @@ func createEmployeReport(employee models.User, startDate, endDate time.Time) (ty
|
||||
OvertimeTotal: "",
|
||||
CurrentTimestamp: time.Now().Format("02.01.2006 - 15:04 Uhr"),
|
||||
}
|
||||
return typstData{Meta: metadata, Days: typstDays}, nil
|
||||
return typstData{Meta: metadata, Days: typstDays, FileName: fmt.Sprintf("%s_%s.pdf", startDate.Format(FILE_YEAR_MONTH), employee.Name)}, nil
|
||||
}
|
||||
|
||||
func renderPDF(data []typstData) (bytes.Buffer, error) {
|
||||
func renderPDFSingle(data []typstData) (bytes.Buffer, error) {
|
||||
var markup bytes.Buffer
|
||||
var output bytes.Buffer
|
||||
|
||||
typstCLI := typst.DockerExec{
|
||||
ContainerName: helper.GetEnv("TYPST_CONTAINER", "arbeitszeitmessung-doc-creator"),
|
||||
}
|
||||
|
||||
if err := typst.InjectValues(&markup, map[string]any{"data": data}); err != nil {
|
||||
return output, err
|
||||
}
|
||||
@@ -179,16 +211,58 @@ func renderPDF(data []typstData) (bytes.Buffer, error) {
|
||||
`)
|
||||
|
||||
// Compile the prepared markup with Typst and write the result it into `output.pdf`.
|
||||
|
||||
typstCLI := typst.DockerExec{
|
||||
ContainerName: helper.GetEnv("TYPST_CONTAINER", "arbeitszeitmessung-doc-creator"),
|
||||
}
|
||||
if err := typstCLI.Compile(&markup, &output, nil); err != nil {
|
||||
return output, err
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func renderPDFMulti(data []typstData) ([]bytes.Buffer, error) {
|
||||
var outputMulti []bytes.Buffer
|
||||
|
||||
typstRender := typst.DockerExec{
|
||||
ContainerName: helper.GetEnv("TYPST_CONTAINER", "arbeitszeitmessung-doc-creator"),
|
||||
}
|
||||
|
||||
for _, d := range data {
|
||||
var markup bytes.Buffer
|
||||
var outputSingle bytes.Buffer
|
||||
if err := typst.InjectValues(&markup, map[string]any{"meta": d.Meta, "days": d.Days}); err != nil {
|
||||
return outputMulti, err
|
||||
}
|
||||
markup.WriteString(`
|
||||
#import "templates/abrechnung.typ": abrechnung
|
||||
#abrechnung(meta, days)
|
||||
`)
|
||||
|
||||
if err := typstRender.Compile(&markup, &outputSingle, nil); err != nil {
|
||||
return outputMulti, err
|
||||
}
|
||||
outputMulti = append(outputMulti, outputSingle)
|
||||
}
|
||||
return outputMulti, nil
|
||||
}
|
||||
|
||||
func zipPfd(pdfReports []bytes.Buffer, reportData *[]typstData) (bytes.Buffer, error) {
|
||||
var zipOutput bytes.Buffer
|
||||
|
||||
zipWriter := zip.NewWriter(&zipOutput)
|
||||
for index, report := range pdfReports {
|
||||
zipFile, err := zipWriter.Create((*reportData)[index].FileName)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
_, err = zipFile.Write(report.Bytes())
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to check the error on Close.
|
||||
err := zipWriter.Close()
|
||||
return zipOutput, err
|
||||
}
|
||||
|
||||
type typstMetadata struct {
|
||||
TimeRange string `json:"time-range"`
|
||||
EmployeeName string `json:"employee-name"`
|
||||
@@ -217,6 +291,7 @@ type typstDay struct {
|
||||
}
|
||||
|
||||
type typstData struct {
|
||||
Meta typstMetadata `json:"meta"`
|
||||
Days []typstDay `json:"days"`
|
||||
Meta typstMetadata `json:"meta"`
|
||||
Days []typstDay `json:"days"`
|
||||
FileName string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user