organizrr/main.go
2025-04-07 18:19:38 +02:00

247 lines
4.4 KiB
Go

package main
import (
"archive/zip"
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"path/filepath"
"slices"
"time"
"syscall/js"
pdfcpu "github.com/pdfcpu/pdfcpu/pkg/api"
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
)
type Customer struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
type Document struct {
ID string `json:"id"`
Name string `json:"name"`
Blob string `json:"blob"`
}
type CustomerFile struct {
ID string `json:"id"`
Documents []CustomerDocument `json:"documents"`
Suffix string `json:"suffix"`
}
type CustomerDocument struct {
ID string `json:"id"`
SelectedPages []string `json:"selectedPages"`
}
type CreateArchiveInput struct {
Customer Customer `json:"customer"`
Documents []Document `json:"documents"`
Files []CustomerFile `json:"files"`
}
type CreateArchiveResult struct {
ResultArchive *string `json:"resultArchive"`
Error *string `json:"error"`
}
func createArchive(this js.Value, args []js.Value) any {
var input CreateArchiveInput
err := json.Unmarshal([]byte(args[0].String()), &input)
handler := js.FuncOf(func(this js.Value, args []js.Value) any {
var (
resolve = args[0]
reject = args[1]
)
if err != nil {
reject.Invoke(err.Error())
return nil
}
buf := new(bytes.Buffer)
w := zip.NewWriter(buf)
now := time.Now()
filePrefix := fmt.Sprintf("%s_%s_%s", now.Format("2006-01-02_15-04-05"), input.Customer.LastName, input.Customer.FirstName)
var fileNames []string
for _, file := range input.Files {
if len(file.Documents) == 0 {
reject.Invoke("At least one document must be provided")
return nil
}
var document *Document
for _, doc := range input.Documents {
if doc.ID == file.Documents[0].ID {
document = &doc
break
}
}
if document == nil {
reject.Invoke("Couldn't find doc by ID: " + file.Documents[0].ID)
return nil
}
ext := filepath.Ext(document.Name)
fileName := fmt.Sprintf("%s_%s%s", filePrefix, file.Suffix, ext)
i := 1
for slices.Index(fileNames, fileName) != -1 {
fileName = fmt.Sprintf("%s_%s-%d%s", filePrefix, file.Suffix, i, ext)
i++
}
fileNames = append(fileNames, fileName)
f, err := w.Create(fileName)
if err != nil {
reject.Invoke(err.Error())
return nil
}
b, err := base64.StdEncoding.DecodeString(document.Blob)
if err != nil {
reject.Invoke(err.Error())
return nil
}
if ext != ".pdf" {
_, err = f.Write(b)
if err != nil {
reject.Invoke(err.Error())
return nil
}
continue
}
if len(file.Documents) == 1 {
if len(file.Documents[0].SelectedPages) > 0 {
rs := bytes.NewReader(b)
err = pdfcpu.Trim(rs, f, file.Documents[0].SelectedPages, nil)
if err != nil {
reject.Invoke(err.Error())
return nil
}
} else {
_, err = f.Write(b)
if err != nil {
reject.Invoke(err.Error())
return nil
}
}
continue
}
var rsc []io.ReadSeeker
for i := range file.Documents {
var document *Document
for _, doc := range input.Documents {
if doc.ID == file.Documents[i].ID {
document = &doc
break
}
}
if document == nil {
reject.Invoke("Couldn't find doc by ID: " + file.Documents[i].ID)
return nil
}
if i != 0 {
b, err = base64.StdEncoding.DecodeString(document.Blob)
if err != nil {
reject.Invoke(err.Error())
return nil
}
}
var (
rs = bytes.NewReader(b)
)
if len(file.Documents[i].SelectedPages) > 0 {
var (
buf []byte
res = bytes.NewBuffer(buf)
)
err = pdfcpu.Trim(rs, res, file.Documents[i].SelectedPages, nil)
if err != nil {
reject.Invoke(err.Error())
return nil
}
rsc = append(rsc, bytes.NewReader(res.Bytes()))
} else {
rsc = append(rsc, rs)
}
}
pdfcpu.MergeRaw(rsc, f, false, nil)
}
if err = w.Close(); err != nil {
reject.Invoke(err.Error())
return nil
}
resolve.Invoke(base64.StdEncoding.EncodeToString(buf.Bytes()))
return nil
})
promiseConstructor := js.Global().Get("Promise")
return promiseConstructor.New(handler)
}
func init() {
model.ConfigPath = "disable"
}
func main() {
c := make(chan struct{}, 0)
js.Global().Set("createArchive", js.FuncOf(createArchive))
<-c
}