feat(pdfengines): new form field autoIndexBookmarks for the merge route

This commit is contained in:
Julien Neuhart
2026-03-06 13:51:51 +01:00
parent 874e78c6cd
commit 59f96358c4
4 changed files with 101 additions and 11 deletions

View File

@@ -409,9 +409,11 @@ func mergeRoute(engine gotenberg.PdfEngine) api.Route {
var inputPaths []string var inputPaths []string
var flatten bool var flatten bool
var autoIndexBookmarks bool
err := form. err := form.
MandatoryPaths([]string{".pdf"}, &inputPaths). MandatoryPaths([]string{".pdf"}, &inputPaths).
Bool("flatten", &flatten, false). Bool("flatten", &flatten, false).
Bool("autoIndexBookmarks", &autoIndexBookmarks, false).
Validate() Validate()
if err != nil { if err != nil {
return fmt.Errorf("validate form data: %w", err) return fmt.Errorf("validate form data: %w", err)
@@ -436,19 +438,36 @@ func mergeRoute(engine gotenberg.PdfEngine) api.Route {
var finalBookmarks []gotenberg.Bookmark var finalBookmarks []gotenberg.Bookmark
if b, ok := bookmarks.([]gotenberg.Bookmark); ok { if b, ok := bookmarks.([]gotenberg.Bookmark); ok {
finalBookmarks = b finalBookmarks = b
} else if b, ok := bookmarks.(map[string][]gotenberg.Bookmark); ok { } else {
offset := 0 bMap, _ := bookmarks.(map[string][]gotenberg.Bookmark)
for _, inputPath := range inputPaths { if bMap != nil || autoIndexBookmarks {
filename := filepath.Base(inputPath) offset := 0
if fileBookmarks, ok := b[filename]; ok { for _, inputPath := range inputPaths {
finalBookmarks = append(finalBookmarks, shiftBookmarks(fileBookmarks, offset)...) filename := filepath.Base(inputPath)
}
pageCount, err := engine.PageCount(ctx, ctx.Log(), inputPath) var fileBookmarks []gotenberg.Bookmark
if err != nil { if bMap != nil {
return fmt.Errorf("get page count of '%s': %w", filename, err) fileBookmarks = bMap[filename]
}
if len(fileBookmarks) == 0 && autoIndexBookmarks {
fb, err := engine.ReadBookmarks(ctx, ctx.Log(), inputPath)
if err != nil {
return fmt.Errorf("read bookmarks of '%s': %w", filename, err)
}
fileBookmarks = fb
}
if len(fileBookmarks) > 0 {
finalBookmarks = append(finalBookmarks, shiftBookmarks(fileBookmarks, offset)...)
}
pageCount, err := engine.PageCount(ctx, ctx.Log(), inputPath)
if err != nil {
return fmt.Errorf("get page count of '%s': %w", filename, err)
}
offset += pageCount
} }
offset += pageCount
} }
} }

View File

@@ -140,6 +140,16 @@ Feature: /forms/pdfengines/merge
""" """
Invalid form data: form field 'bookmarks' is invalid (got 'foo', resulting to unmarshal bookmarks: invalid character 'o' in literal false (expecting 'a')) Invalid form data: form field 'bookmarks' is invalid (got 'foo', resulting to unmarshal bookmarks: invalid character 'o' in literal false (expecting 'a'))
""" """
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| autoIndexBookmarks | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'autoIndexBookmarks' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
@convert @convert
Scenario: POST /forms/pdfengines/merge (PDF/A-1b & PDF/UA-1) Scenario: POST /forms/pdfengines/merge (PDF/A-1b & PDF/UA-1)
@@ -281,6 +291,67 @@ Feature: /forms/pdfengines/merge
} }
""" """
@bookmarks
Scenario: POST /forms/pdfengines/merge (Auto-index Bookmarks)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1_with_bookmarks.pdf | file |
| files | testdata/page_2_with_bookmarks.pdf | file |
| autoIndexBookmarks | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/bookmarks/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": [
{
"title": "Page 1",
"page": 1
},
{
"title": "Page 2",
"page": 2
}
]
}
"""
@bookmarks
Scenario: POST /forms/pdfengines/merge (Auto-index Bookmarks + Bookmarks Map)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2_with_bookmarks.pdf | file |
| bookmarks | {"page_1.pdf":[{"title":"Page 1 Index","page":1}]} | field |
| autoIndexBookmarks | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/bookmarks/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": [
{
"title": "Page 1 Index",
"page": 1
},
{
"title": "Page 2",
"page": 2
}
]
}
"""
@flatten @flatten
Scenario: POST /forms/pdfengines/merge (Flatten) Scenario: POST /forms/pdfengines/merge (Flatten)
Given I have a default Gotenberg container Given I have a default Gotenberg container

Binary file not shown.

Binary file not shown.