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
+30 -11
View File
@@ -409,9 +409,11 @@ func mergeRoute(engine gotenberg.PdfEngine) api.Route {
var inputPaths []string
var flatten bool
var autoIndexBookmarks bool
err := form.
MandatoryPaths([]string{".pdf"}, &inputPaths).
Bool("flatten", &flatten, false).
Bool("autoIndexBookmarks", &autoIndexBookmarks, false).
Validate()
if err != nil {
return fmt.Errorf("validate form data: %w", err)
@@ -436,19 +438,36 @@ func mergeRoute(engine gotenberg.PdfEngine) api.Route {
var finalBookmarks []gotenberg.Bookmark
if b, ok := bookmarks.([]gotenberg.Bookmark); ok {
finalBookmarks = b
} else if b, ok := bookmarks.(map[string][]gotenberg.Bookmark); ok {
offset := 0
for _, inputPath := range inputPaths {
filename := filepath.Base(inputPath)
if fileBookmarks, ok := b[filename]; ok {
finalBookmarks = append(finalBookmarks, shiftBookmarks(fileBookmarks, offset)...)
}
} else {
bMap, _ := bookmarks.(map[string][]gotenberg.Bookmark)
if bMap != nil || autoIndexBookmarks {
offset := 0
for _, inputPath := range inputPaths {
filename := filepath.Base(inputPath)
pageCount, err := engine.PageCount(ctx, ctx.Log(), inputPath)
if err != nil {
return fmt.Errorf("get page count of '%s': %w", filename, err)
var fileBookmarks []gotenberg.Bookmark
if bMap != nil {
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
}
}
@@ -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'))
"""
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
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
Scenario: POST /forms/pdfengines/merge (Flatten)
Given I have a default Gotenberg container
Binary file not shown.
Binary file not shown.