From ba2332ecb630667ae9e3113193bc049ee3a3022f Mon Sep 17 00:00:00 2001 From: Tueem Date: Wed, 27 May 2026 22:02:11 +0200 Subject: [PATCH] feat(template): add multiple page support to templates --- internal/routes/download.go | 19 ++++++++++----- pkg/svg/actions/download.go | 26 ++++++++++++++------ pkg/svg/actions/page.go | 13 ++++++++++ pkg/svg/actions/template.go | 47 +++++++++++++++++++++---------------- pkg/svg/storage.go | 7 +++--- 5 files changed, 76 insertions(+), 36 deletions(-) diff --git a/internal/routes/download.go b/internal/routes/download.go index cd26063..c03d048 100644 --- a/internal/routes/download.go +++ b/internal/routes/download.go @@ -17,7 +17,7 @@ type downloadRequest struct { } type downloadResponse struct { - Url string + Urls []string } func DownloadSVG(w http.ResponseWriter, r *http.Request) { @@ -73,16 +73,23 @@ func DownloadSVG(w http.ResponseWriter, r *http.Request) { Keys: request.TemplateKeys, } - filename, err := actions.ProvideFile(&templateParam, &convParam) + filenames, err := actions.ProvideFile(&templateParam, &convParam) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - urlparsed := getPublicUrl(r, filename) - log.Printf("Made %s available as %s\n", id, urlparsed) - response := downloadResponse{ - Url: urlparsed, + + urlsparsed := make([]string, len(filenames)) + for i, filename := range filenames { + urlsparsed[i] = getPublicUrl(r, filename) + log.Printf("Made %s page %d available as %s\n", id, i, urlsparsed[i]) + } + + response := downloadResponse{ + Urls: urlsparsed, + } + w.Header().Add("Content-Type", "application/json") json, err := json.Marshal(response) if err != nil { diff --git a/pkg/svg/actions/download.go b/pkg/svg/actions/download.go index 28c977c..47951c2 100644 --- a/pkg/svg/actions/download.go +++ b/pkg/svg/actions/download.go @@ -3,20 +3,32 @@ package actions import ( "bytes" "log" + "strconv" "tomatentum.net/svg-templater/pkg/format" "tomatentum.net/svg-templater/pkg/svg" ) -func ProvideFile(r *TemplateParameters, conversion *format.ConversionParameters) (string, error) { - templatedSvgblob, err := Template(r) +func ProvideFile(r *TemplateParameters, conversion *format.ConversionParameters) ([]string, error) { + templatedPages, err := Template(r) if err != nil { - return "", err + return nil, err } log.Printf("Converting %s to format %s (w=%d,h=%d)", r.Id, conversion.Format, conversion.Width, conversion.Height) - result, err := format.ConvertByte(templatedSvgblob, *conversion) - if err != nil { - return "", err + filenames := make([]string, len(templatedPages)) + for i, pagedata := range templatedPages { + result, err := format.ConvertByte(pagedata, *conversion) + if err != nil { + return nil, err + } + filenames[i], err = svg.Storage.CreatePublic(bytes.NewReader(result), strconv.Itoa(i+1), conversion.Format) + + if err != nil { + return nil, err + } + log.Printf("Converted %s page %d to format %s (w=%d,h=%d)", r.Id, i, conversion.Format, conversion.Width, conversion.Height) + } - return svg.Storage.CreatePublic(bytes.NewReader(result), conversion.Format) + + return filenames, nil } diff --git a/pkg/svg/actions/page.go b/pkg/svg/actions/page.go index c8a95c9..f427272 100644 --- a/pkg/svg/actions/page.go +++ b/pkg/svg/actions/page.go @@ -3,6 +3,7 @@ package actions import ( "bytes" "fmt" + "io" "log" "regexp" "strconv" @@ -34,6 +35,18 @@ func AddPage(id string, svgbuf []byte) (svg.TemplatePage, error) { return data, nil } +func GetPage(id string, page int) ([]byte, error) { + file, err := svg.Storage.Get(fmt.Sprintf(FILEFORMAT, id, page)) + + if err != nil { + return nil, err + } + + defer file.Close() + + return io.ReadAll(file) +} + func DeletePage(id string, page int) (bool, error) { if success, err := database.DeleteSVGPage(id, page); err != nil || !success { return success, err diff --git a/pkg/svg/actions/template.go b/pkg/svg/actions/template.go index fc74c81..91a7bb6 100644 --- a/pkg/svg/actions/template.go +++ b/pkg/svg/actions/template.go @@ -2,7 +2,6 @@ package actions import ( "errors" - "io" "log" "maps" "regexp" @@ -18,29 +17,42 @@ type TemplateParameters struct { Keys map[string]string } -func Template(r *TemplateParameters) ([]byte, error) { - mapkeys := slices.Collect(maps.Keys(r.Keys)) - ok, err := verifyTemplate(r.Id, mapkeys) +func Template(r *TemplateParameters) ([][]byte, error) { + + data, err := database.GetSpecificSVG(r.Id) + if err != nil { return nil, err } + + mapkeys := slices.Collect(maps.Keys(r.Keys)) + ok, err := verifyTemplate(data, mapkeys) + + if err != nil { + return nil, err + } + if !ok { return nil, errors.New("Template does not exist.") } log.Printf("Replacing keys of %s template\n", r.Id) - reader, err := svg.Storage.Get(r.Id) - if err != nil { - return nil, err + pagesdata := make([][]byte, len(data.Pages)) + + for _, page := range data.Pages { + pagedata, err := GetPage(page.TemplateId, page.Page) + + if err != nil { + return nil, err + } + + replaceAll(&pagedata, r.Keys) + pagesdata[page.Page-1] = pagedata + log.Printf("Finished replacing keys of %s page %d\n", r.Id, page.Page) + } - defer reader.Close() - svgblob, err := io.ReadAll(reader) - if err != nil { - return nil, err - } - replaceAll(&svgblob, r.Keys) log.Printf("Finished replacing keys of %s template\n", r.Id) - return svgblob, nil + return pagesdata, nil } func replaceAll(svgblob *[]byte, keys map[string]string) { @@ -51,12 +63,7 @@ func replaceAll(svgblob *[]byte, keys map[string]string) { })) } -func verifyTemplate(id string, keys []string) (bool, error) { - data, err := database.GetSpecificSVG(id) - if err != nil { - return false, err - } - +func verifyTemplate(data svg.TemplateData, keys []string) (bool, error) { for _, key := range data.AllKeys() { if !slices.Contains(keys, key) { return false, nil diff --git a/pkg/svg/storage.go b/pkg/svg/storage.go index 966338a..5f2aba6 100644 --- a/pkg/svg/storage.go +++ b/pkg/svg/storage.go @@ -2,6 +2,7 @@ package svg import ( "errors" + "fmt" "io" "log" "net/http" @@ -20,7 +21,7 @@ type SvgStorage interface { AddFont(reader io.Reader, format string) error GetFonts() ([]string, error) GetFontsDir() string - CreatePublic(data io.Reader, filetype string) (string, error) + CreatePublic(data io.Reader, suffix string, filetype string) (string, error) GetPublic(path string) (io.ReadCloser, error) GetPublicDir() http.Dir } @@ -86,13 +87,13 @@ func (f FileSvgStorage) List() ([]os.DirEntry, error) { return os.ReadDir(f.basepath) } -func (f FileSvgStorage) CreatePublic(data io.Reader, filetype string) (string, error) { +func (f FileSvgStorage) CreatePublic(data io.Reader, suffix string, filetype string) (string, error) { path := filepath.Join(f.basepath, f.publicSubPath) if err := os.MkdirAll(path, 0755); err != nil { return "", err } - file, err := os.CreateTemp(path, "*."+filetype) + file, err := os.CreateTemp(path, fmt.Sprintf("*-%s."+filetype, suffix)) if err != nil { return "", err }