diff --git a/Makefile b/Makefile index e453227..0d7ad40 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ GOLANG_VERSION=1.24.2 -GOTENBERG_VERSION=8.20.1 +GOTENBERG_VERSION=8.25.0 GOLANGCI_LINT_VERSION=2.1.2 REPO=starwalkn/gotenberg-go-client/v8 diff --git a/baserequest.go b/baserequest.go index fae452d..6a2629b 100644 --- a/baserequest.go +++ b/baserequest.go @@ -13,6 +13,7 @@ type baseRequester interface { customHeaders() map[httpHeader]string formFields() map[formField]string formDocuments() map[string]document.Document + formEmbeds() map[string]document.Document } type baseRequest struct { @@ -105,13 +106,14 @@ func ensureWebhookMethod(method string) string { // this is equivalent to map[string]map[string]string, which this method accepts, but headers map can be nil. // // URLs MUST return a Content-Disposition header with a filename parameter. -func (br *baseRequest) DownloadFrom(downloads map[string]map[string]string) { +func (br *baseRequest) DownloadFrom(downloads map[string]map[string]string, embedded bool) { dfs := make([]downloadFrom, 0, len(downloads)) for url, headers := range downloads { dfs = append(dfs, downloadFrom{ URL: url, ExtraHTTPHeaders: headers, + Embedded: embedded, }) } @@ -126,4 +128,5 @@ func (br *baseRequest) DownloadFrom(downloads map[string]map[string]string) { type downloadFrom struct { URL string `json:"url"` ExtraHTTPHeaders map[string]string `json:"extraHttpHeaders"` + Embedded bool `json:"embedded"` } diff --git a/chromium.go b/chromium.go index 41ac980..f9e0323 100644 --- a/chromium.go +++ b/chromium.go @@ -227,6 +227,11 @@ func (req *chromiumRequest) GenerateTaggedPDF(val bool) { req.fields[fieldChromiumGenerateTaggedPDF] = strconv.FormatBool(val) } +func (req *chromiumRequest) Encrypt(userPassword, ownerPassword string) { + req.fields[fieldUserPassword] = userPassword + req.fields[fieldOwnerPassword] = ownerPassword +} + // ScreenshotWidth Width sets the device screen width in pixels. func (req *chromiumRequest) ScreenshotWidth(width int) { req.fields[fieldScreenshotWidth] = strconv.Itoa(width) diff --git a/fields.go b/fields.go index 9e2232b..8cc5e95 100644 --- a/fields.go +++ b/fields.go @@ -4,8 +4,10 @@ type formField string // Common property. const ( - fieldMetadata formField = "metadata" - fieldDownloadFrom formField = "downloadFrom" + fieldMetadata formField = "metadata" + fieldDownloadFrom formField = "downloadFrom" + fieldUserPassword formField = "userPassword" + fieldOwnerPassword formField = "ownerPassword" ) // URL request property. diff --git a/flatten.go b/flatten.go index 5258fc7..6f561ea 100644 --- a/flatten.go +++ b/flatten.go @@ -3,7 +3,8 @@ package gotenberg import "github.com/starwalkn/gotenberg-go-client/v8/document" type FlattenRequest struct { - pdfs []document.Document + pdfs []document.Document + embeds []document.Document *baseRequest } @@ -28,3 +29,22 @@ func (req *FlattenRequest) formDocuments() map[string]document.Document { return files } + +func (req *FlattenRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range req.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (req *FlattenRequest) Embeds(docs ...document.Document) { + req.embeds = append(req.embeds, docs...) +} + +// Compile-time checks to ensure type implements desired interfaces. +var ( + _ = MultipartRequester(new(FlattenRequest)) +) diff --git a/html.go b/html.go index 3ecec8d..48ecc50 100644 --- a/html.go +++ b/html.go @@ -13,12 +13,18 @@ const ( type HTMLRequest struct { index document.Document assets []document.Document + embeds []document.Document *chromiumRequest } func NewHTMLRequest(index document.Document) *HTMLRequest { - return &HTMLRequest{index, []document.Document{}, newChromiumRequest()} + return &HTMLRequest{ + index: index, + assets: []document.Document{}, + embeds: []document.Document{}, + chromiumRequest: newChromiumRequest(), + } } func (req *HTMLRequest) endpoint() string { @@ -47,6 +53,20 @@ func (req *HTMLRequest) formDocuments() map[string]document.Document { return files } +func (req *HTMLRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range req.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (req *HTMLRequest) Embeds(docs ...document.Document) { + req.embeds = docs +} + // Assets sets assets form files. func (req *HTMLRequest) Assets(assets ...document.Document) { req.assets = assets diff --git a/html_test.go b/html_test.go index 776441c..e2cc082 100644 --- a/html_test.go +++ b/html_test.go @@ -46,8 +46,8 @@ func TestHTML(t *testing.T) { req.PaperSize(A4) req.Margins(NormalMargins) req.Scale(1.5) - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -90,9 +90,9 @@ func TestHTMLScreenshot(t *testing.T) { err = req.Cookies(cks) require.NoError(t, err) - dirPath := t.TempDir() req.Format(JPEG) - dest := fmt.Sprintf("%s/foo.jpeg", dirPath) + + dest := fmt.Sprintf("%s/foo.jpeg", t.TempDir()) err = c.StoreScreenshot(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -117,8 +117,8 @@ func TestHTMLPdfA(t *testing.T) { require.NoError(t, err) req.PdfA(PdfA3b) - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -142,8 +142,8 @@ func TestHTMLPdfUA(t *testing.T) { require.NoError(t, err) req.PdfUA() - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -151,3 +151,47 @@ func TestHTMLPdfUA(t *testing.T) { require.NoError(t, err) assert.True(t, isPDFUA) } + +func TestHTMLEmbeds(t *testing.T) { + c, err := NewClient("http://localhost:3000", http.DefaultClient) + require.NoError(t, err) + + index, err := document.FromPath("index.html", test.HTMLTestFilePath(t, "index.html")) + require.NoError(t, err) + req := NewHTMLRequest(index) + req.Trace("testHTMLEmbeds") + req.UseBasicAuth("foo", "bar") + + var embeds []document.Document + + header, err := document.FromPath("header.html", test.HTMLTestFilePath(t, "header.html")) + require.NoError(t, err) + embeds = append(embeds, header) + footer, err := document.FromPath("footer.html", test.HTMLTestFilePath(t, "footer.html")) + require.NoError(t, err) + embeds = append(embeds, footer) + font, err := document.FromPath("font.woff", test.HTMLTestFilePath(t, "font.woff")) + require.NoError(t, err) + embeds = append(embeds, font) + img, err := document.FromPath("img.gif", test.HTMLTestFilePath(t, "img.gif")) + require.NoError(t, err) + embeds = append(embeds, img) + style, err := document.FromPath("style.css", test.HTMLTestFilePath(t, "style.css")) + require.NoError(t, err) + embeds = append(embeds, style) + + req.Embeds(embeds...) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) + err = c.Store(context.Background(), req, dest) + require.NoError(t, err) + assert.FileExists(t, dest) + + isPDF, err := test.IsPDF(dest) + require.NoError(t, err) + assert.True(t, isPDF) + + hasEmbeds, err := test.HasEmbeds(dest) + require.NoError(t, err) + assert.True(t, hasEmbeds) +} diff --git a/libreoffice.go b/libreoffice.go index 87da8a5..a93f687 100644 --- a/libreoffice.go +++ b/libreoffice.go @@ -10,7 +10,8 @@ const endpointOfficeConvert = "/forms/libreoffice/convert" // LibreOfficeRequest facilitates LibreOffice documents conversion with the Gotenberg API. type LibreOfficeRequest struct { - docs []document.Document + docs []document.Document + embeds []document.Document *baseRequest } @@ -18,6 +19,7 @@ type LibreOfficeRequest struct { func NewLibreOfficeRequest(docs ...document.Document) *LibreOfficeRequest { return &LibreOfficeRequest{ docs: docs, + embeds: []document.Document{}, baseRequest: newBaseRequest(), } } @@ -35,6 +37,20 @@ func (req *LibreOfficeRequest) formDocuments() map[string]document.Document { return files } +func (req *LibreOfficeRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range req.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (req *LibreOfficeRequest) Embeds(docs ...document.Document) { + req.embeds = docs +} + // Password sets the password for opening the source file. func (req *LibreOfficeRequest) Password(password string) { req.fields[fieldOfficePassword] = password @@ -201,6 +217,11 @@ func (req *LibreOfficeRequest) UpdateIndexes(value bool) { req.fields[fieldOfficeUpdateIndexes] = strconv.FormatBool(value) } +func (req *LibreOfficeRequest) Encrypt(userPassword, ownerPassword string) { + req.fields[fieldUserPassword] = userPassword + req.fields[fieldOwnerPassword] = ownerPassword +} + // Compile-time checks to ensure type implements desired interfaces. var ( _ = MultipartRequester(new(LibreOfficeRequest)) diff --git a/libreoffice_test.go b/libreoffice_test.go index de8fa22..68fd592 100644 --- a/libreoffice_test.go +++ b/libreoffice_test.go @@ -23,8 +23,8 @@ func TestLibreOffice(t *testing.T) { req.Trace("testLibreOffice") req.UseBasicAuth("foo", "bar") req.OutputFilename("foo.pdf") - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -62,8 +62,8 @@ func TestLibreOfficeLosslessCompression(t *testing.T) { req.UseBasicAuth("foo", "bar") req.OutputFilename("foo.pdf") req.LosslessImageCompression() - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -85,8 +85,8 @@ func TestLibreOfficeCompression(t *testing.T) { req.Quality(1) req.ReduceImageResolution() req.MaxImageResolution(75) - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -107,8 +107,8 @@ func TestLibreOfficeMultipleWithoutMerge(t *testing.T) { req.Trace("testLibreOfficeMultipleWithoutMerge") req.UseBasicAuth("foo", "bar") req.OutputFilename("foo.zip") - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.zip", dirPath) + + dest := fmt.Sprintf("%s/foo.zip", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -132,8 +132,8 @@ func TestLibreOfficeMultipleWithMerge(t *testing.T) { req.UseBasicAuth("foo", "bar") req.OutputFilename("foo.pdf") req.Merge() - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -157,8 +157,8 @@ func TestLibreOfficePdfA(t *testing.T) { req.UseBasicAuth("foo", "bar") req.OutputFilename("foo.pdf") req.PdfA(PdfA3b) - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -178,8 +178,8 @@ func TestLibreOfficePdfUA(t *testing.T) { req.UseBasicAuth("foo", "bar") req.OutputFilename("foo.pdf") req.PdfUA() - dirPath := t.TempDir() - dest := fmt.Sprintf("%s/foo.pdf", dirPath) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) err = c.Store(context.Background(), req, dest) require.NoError(t, err) assert.FileExists(t, dest) @@ -187,3 +187,31 @@ func TestLibreOfficePdfUA(t *testing.T) { require.NoError(t, err) assert.True(t, isPDFUA) } + +func TestLibreOfficeEmbeds(t *testing.T) { + c, err := NewClient("http://localhost:3000", http.DefaultClient) + require.NoError(t, err) + + doc1, err := document.FromPath("document1.docx", test.LibreOfficeTestFilePath(t, "document.docx")) + require.NoError(t, err) + + req := NewLibreOfficeRequest(doc1) + req.Trace("testLibreOfficeEmbeds") + req.UseBasicAuth("foo", "bar") + req.OutputFilename("foo.pdf") + req.Merge() + + doc2, err := document.FromPath("document2.docx", test.LibreOfficeTestFilePath(t, "document.docx")) + require.NoError(t, err) + + req.Embeds(doc2) + + dest := fmt.Sprintf("%s/foo.pdf", t.TempDir()) + err = c.Store(context.Background(), req, dest) + require.NoError(t, err) + assert.FileExists(t, dest) + + hasEmbeds, err := test.HasEmbeds(dest) + require.NoError(t, err) + assert.True(t, hasEmbeds) +} diff --git a/markdown.go b/markdown.go index 757c58b..fe851f9 100644 --- a/markdown.go +++ b/markdown.go @@ -12,12 +12,19 @@ type MarkdownRequest struct { index document.Document markdowns []document.Document assets []document.Document + embeds []document.Document *chromiumRequest } func NewMarkdownRequest(index document.Document, markdowns ...document.Document) *MarkdownRequest { - return &MarkdownRequest{index, markdowns, []document.Document{}, newChromiumRequest()} + return &MarkdownRequest{ + index: index, + markdowns: markdowns, + assets: []document.Document{}, + embeds: []document.Document{}, + chromiumRequest: newChromiumRequest(), + } } func (req *MarkdownRequest) endpoint() string { @@ -47,6 +54,20 @@ func (req *MarkdownRequest) formDocuments() map[string]document.Document { return files } +func (req *MarkdownRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range req.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (req *MarkdownRequest) Embeds(docs ...document.Document) { + req.embeds = append(req.embeds, docs...) +} + // Assets sets assets form files. func (req *MarkdownRequest) Assets(assets ...document.Document) { req.assets = assets diff --git a/merge.go b/merge.go index df62279..a0edfc0 100644 --- a/merge.go +++ b/merge.go @@ -8,13 +8,18 @@ import ( // MergeRequest facilitates work with PDF files with the Gotenberg API. type MergeRequest struct { - pdfs []document.Document + pdfs []document.Document + embeds []document.Document *baseRequest } func NewMergeRequest(pdfs ...document.Document) *MergeRequest { - return &MergeRequest{pdfs, newBaseRequest()} + return &MergeRequest{ + pdfs: pdfs, + embeds: []document.Document{}, + baseRequest: newBaseRequest(), + } } func (req *MergeRequest) endpoint() string { @@ -31,6 +36,20 @@ func (req *MergeRequest) formDocuments() map[string]document.Document { return files } +func (req *MergeRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range req.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (req *MergeRequest) Embeds(docs ...document.Document) { + req.embeds = append(req.embeds, docs...) +} + // PdfA sets the PDF/A format of the resulting PDF. func (req *MergeRequest) PdfA(pdfa PdfAFormat) { req.fields[fieldMergePdfA] = string(pdfa) @@ -51,6 +70,11 @@ func (req *MergeRequest) Flatten(val bool) { req.fields[fieldMergeFlatten] = strconv.FormatBool(val) } +func (req *MergeRequest) Encrypt(userPassword, ownerPassword string) { + req.fields[fieldUserPassword] = userPassword + req.fields[fieldOwnerPassword] = ownerPassword +} + // Compile-time checks to ensure type implements desired interfaces. var ( _ = MultipartRequester(new(MergeRequest)) diff --git a/metadata_reader.go b/metadata_reader.go index acf8536..490c55f 100644 --- a/metadata_reader.go +++ b/metadata_reader.go @@ -5,7 +5,8 @@ import "github.com/starwalkn/gotenberg-go-client/v8/document" const endpointMetadataRead = "/forms/pdfengines/metadata/read" type ReadMetadataRequest struct { - pdfs []document.Document + pdfs []document.Document + embeds []document.Document *baseRequest } @@ -13,6 +14,7 @@ type ReadMetadataRequest struct { func NewReadMetadataRequest(pdfs ...document.Document) *ReadMetadataRequest { return &ReadMetadataRequest{ pdfs: pdfs, + embeds: []document.Document{}, baseRequest: newBaseRequest(), } } @@ -31,6 +33,25 @@ func (rmd *ReadMetadataRequest) formDocuments() map[string]document.Document { return files } +func (rmd *ReadMetadataRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range rmd.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (rmd *ReadMetadataRequest) Embeds(docs ...document.Document) { + rmd.embeds = append(rmd.embeds, docs...) +} + +func (rmd *ReadMetadataRequest) Encrypt(userPassword, ownerPassword string) { + rmd.fields[fieldUserPassword] = userPassword + rmd.fields[fieldOwnerPassword] = ownerPassword +} + // Compile-time checks to ensure type implements desired interfaces. var ( _ = MultipartRequester(new(ReadMetadataRequest)) diff --git a/metadata_writer.go b/metadata_writer.go index 8ca3cde..5b01c55 100644 --- a/metadata_writer.go +++ b/metadata_writer.go @@ -5,7 +5,8 @@ import "github.com/starwalkn/gotenberg-go-client/v8/document" const endpointMetadataWrite = "/forms/pdfengines/metadata/write" type WriteMetadataRequest struct { - pdfs []document.Document + pdfs []document.Document + embeds []document.Document *baseRequest } @@ -13,6 +14,7 @@ type WriteMetadataRequest struct { func NewWriteMetadataRequest(pdfs ...document.Document) *WriteMetadataRequest { return &WriteMetadataRequest{ pdfs: pdfs, + embeds: []document.Document{}, baseRequest: newBaseRequest(), } } @@ -31,10 +33,29 @@ func (wmd *WriteMetadataRequest) formDocuments() map[string]document.Document { return files } +func (wmd *WriteMetadataRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range wmd.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (wmd *WriteMetadataRequest) Embeds(docs ...document.Document) { + wmd.embeds = append(wmd.embeds, docs...) +} + func (wmd *WriteMetadataRequest) Metadata(md []byte) { wmd.fields[fieldMetadata] = string(md) } +func (wmd *WriteMetadataRequest) Encrypt(userPassword, ownerPassword string) { + wmd.fields[fieldUserPassword] = userPassword + wmd.fields[fieldOwnerPassword] = ownerPassword +} + // Compile-time checks to ensure type implements desired interfaces. var ( _ = MultipartRequester(new(WriteMetadataRequest)) diff --git a/multipart.go b/multipart.go index 82b4cf4..48e5aa9 100644 --- a/multipart.go +++ b/multipart.go @@ -19,7 +19,11 @@ func multipartForm(mr MultipartRequester) (body *bytes.Buffer, contentType strin } }() - if err = addDocuments(writer, mr.formDocuments()); err != nil { + if err = addDocuments(writer, mr.formDocuments(), "files"); err != nil { + return nil, "", err + } + + if err = addDocuments(writer, mr.formEmbeds(), "embeds"); err != nil { return nil, "", err } @@ -40,14 +44,14 @@ func addFormFields(writer *multipart.Writer, formFields map[formField]string) er return nil } -func addDocuments(writer *multipart.Writer, documents map[string]document.Document) error { +func addDocuments(writer *multipart.Writer, documents map[string]document.Document, fieldname string) error { for fname, doc := range documents { in, err := doc.Reader() if err != nil { return fmt.Errorf("getting %s reader: %w", fname, err) } - part, err := writer.CreateFormFile("files", fname) + part, err := writer.CreateFormFile(fieldname, fname) if err != nil { _ = in.Close() diff --git a/split_intervals.go b/split_intervals.go index e808f9f..be2e8fa 100644 --- a/split_intervals.go +++ b/split_intervals.go @@ -7,7 +7,8 @@ import ( ) type SplitIntervalsRequest struct { - pdfs []document.Document + pdfs []document.Document + embeds []document.Document *baseRequest } @@ -18,6 +19,7 @@ func NewSplitIntervalsRequest(pdfs ...document.Document) *SplitIntervalsRequest return &SplitIntervalsRequest{ pdfs: pdfs, + embeds: []document.Document{}, baseRequest: br, } } @@ -36,6 +38,20 @@ func (req *SplitIntervalsRequest) formDocuments() map[string]document.Document { return files } +func (req *SplitIntervalsRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range req.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (req *SplitIntervalsRequest) Embeds(docs ...document.Document) { + req.embeds = append(req.embeds, docs...) +} + // SplitSpan sets the interval for split. func (req *SplitIntervalsRequest) SplitSpan(span int) { req.fields[fieldSplitSpan] = strconv.Itoa(span) @@ -45,3 +61,8 @@ func (req *SplitIntervalsRequest) SplitSpan(span int) { func (req *SplitIntervalsRequest) Flatten(val bool) { req.fields[fieldSplitFlatten] = strconv.FormatBool(val) } + +func (req *SplitIntervalsRequest) Encrypt(userPassword, ownerPassword string) { + req.fields[fieldUserPassword] = userPassword + req.fields[fieldOwnerPassword] = ownerPassword +} diff --git a/split_pages.go b/split_pages.go index c2b0dd5..96ec3e8 100644 --- a/split_pages.go +++ b/split_pages.go @@ -7,7 +7,8 @@ import ( ) type SplitPagesRequest struct { - pdfs []document.Document + pdfs []document.Document + embeds []document.Document *baseRequest } @@ -18,6 +19,7 @@ func NewSplitPagesRequest(pdfs ...document.Document) *SplitPagesRequest { return &SplitPagesRequest{ pdfs: pdfs, + embeds: []document.Document{}, baseRequest: br, } } @@ -36,6 +38,20 @@ func (req *SplitPagesRequest) formDocuments() map[string]document.Document { return files } +func (req *SplitPagesRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range req.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (req *SplitPagesRequest) Embeds(docs ...document.Document) { + req.embeds = append(req.embeds, docs...) +} + // SplitSpan sets the interval for split. func (req *SplitPagesRequest) SplitSpan(span string) { req.fields[fieldSplitSpan] = span @@ -49,3 +65,8 @@ func (req *SplitPagesRequest) SplitUnify(val bool) { func (req *SplitPagesRequest) Flatten(val bool) { req.fields[fieldSplitFlatten] = strconv.FormatBool(val) } + +func (req *SplitPagesRequest) Encrypt(userPassword, ownerPassword string) { + req.fields[fieldUserPassword] = userPassword + req.fields[fieldOwnerPassword] = ownerPassword +} diff --git a/test/testdata/html/font.woff b/test/data/html/font.woff similarity index 100% rename from test/testdata/html/font.woff rename to test/data/html/font.woff diff --git a/test/testdata/html/footer.html b/test/data/html/footer.html similarity index 100% rename from test/testdata/html/footer.html rename to test/data/html/footer.html diff --git a/test/testdata/html/header.html b/test/data/html/header.html similarity index 100% rename from test/testdata/html/header.html rename to test/data/html/header.html diff --git a/test/testdata/html/img.gif b/test/data/html/img.gif similarity index 100% rename from test/testdata/html/img.gif rename to test/data/html/img.gif diff --git a/test/testdata/html/index.html b/test/data/html/index.html similarity index 100% rename from test/testdata/html/index.html rename to test/data/html/index.html diff --git a/test/testdata/html/style.css b/test/data/html/style.css similarity index 100% rename from test/testdata/html/style.css rename to test/data/html/style.css diff --git a/test/testdata/libreoffice/document.docx b/test/data/libreoffice/document.docx similarity index 100% rename from test/testdata/libreoffice/document.docx rename to test/data/libreoffice/document.docx diff --git a/test/testdata/libreoffice/document.rtf b/test/data/libreoffice/document.rtf similarity index 100% rename from test/testdata/libreoffice/document.rtf rename to test/data/libreoffice/document.rtf diff --git a/test/testdata/libreoffice/document.txt b/test/data/libreoffice/document.txt similarity index 100% rename from test/testdata/libreoffice/document.txt rename to test/data/libreoffice/document.txt diff --git a/test/testdata/markdown/font.woff b/test/data/markdown/font.woff similarity index 100% rename from test/testdata/markdown/font.woff rename to test/data/markdown/font.woff diff --git a/test/testdata/markdown/footer.html b/test/data/markdown/footer.html similarity index 100% rename from test/testdata/markdown/footer.html rename to test/data/markdown/footer.html diff --git a/test/testdata/markdown/header.html b/test/data/markdown/header.html similarity index 100% rename from test/testdata/markdown/header.html rename to test/data/markdown/header.html diff --git a/test/testdata/markdown/img.gif b/test/data/markdown/img.gif similarity index 100% rename from test/testdata/markdown/img.gif rename to test/data/markdown/img.gif diff --git a/test/testdata/markdown/index.html b/test/data/markdown/index.html similarity index 100% rename from test/testdata/markdown/index.html rename to test/data/markdown/index.html diff --git a/test/testdata/markdown/paragraph1.md b/test/data/markdown/paragraph1.md similarity index 100% rename from test/testdata/markdown/paragraph1.md rename to test/data/markdown/paragraph1.md diff --git a/test/testdata/markdown/paragraph2.md b/test/data/markdown/paragraph2.md similarity index 100% rename from test/testdata/markdown/paragraph2.md rename to test/data/markdown/paragraph2.md diff --git a/test/testdata/markdown/paragraph3.md b/test/data/markdown/paragraph3.md similarity index 100% rename from test/testdata/markdown/paragraph3.md rename to test/data/markdown/paragraph3.md diff --git a/test/testdata/markdown/style.css b/test/data/markdown/style.css similarity index 100% rename from test/testdata/markdown/style.css rename to test/data/markdown/style.css diff --git a/test/testdata/pdf/gotenberg.pdf b/test/data/pdf/gotenberg.pdf similarity index 100% rename from test/testdata/pdf/gotenberg.pdf rename to test/data/pdf/gotenberg.pdf diff --git a/test/testdata/pdf/gotenberg_bis.pdf b/test/data/pdf/gotenberg_bis.pdf similarity index 100% rename from test/testdata/pdf/gotenberg_bis.pdf rename to test/data/pdf/gotenberg_bis.pdf diff --git a/test/testdata/url/footer.html b/test/data/url/footer.html similarity index 100% rename from test/testdata/url/footer.html rename to test/data/url/footer.html diff --git a/test/testdata/url/header.html b/test/data/url/header.html similarity index 100% rename from test/testdata/url/header.html rename to test/data/url/header.html diff --git a/test/testfunc.go b/test/utils.go similarity index 87% rename from test/testfunc.go rename to test/utils.go index d0bfb96..7df8bc8 100644 --- a/test/testfunc.go +++ b/test/utils.go @@ -19,22 +19,22 @@ import ( "github.com/stretchr/testify/require" ) -// HTMLTestFilePath returns the absolute file path of a file in "html" folder in test/testdata. +// HTMLTestFilePath returns the absolute file path of a file in "html" folder in test/data. func HTMLTestFilePath(t *testing.T, filename string) string { return abs(t, "html", filename) } -// MarkdownTestFilePath returns the absolute file path of a file in "markdown" folder in test/testdata. +// MarkdownTestFilePath returns the absolute file path of a file in "markdown" folder in test/data. func MarkdownTestFilePath(t *testing.T, filename string) string { return abs(t, "markdown", filename) } -// LibreOfficeTestFilePath returns the absolute file path of a file in "libreoffice" folder in test/testdata. +// LibreOfficeTestFilePath returns the absolute file path of a file in "libreoffice" folder in test/data. func LibreOfficeTestFilePath(t *testing.T, filename string) string { return abs(t, "libreoffice", filename) } -// PDFTestFilePath returns the absolute file path of a file in "pdf" folder in test/testdata. +// PDFTestFilePath returns the absolute file path of a file in "pdf" folder in test/data. func PDFTestFilePath(t *testing.T, filename string) string { return abs(t, "pdf", filename) } @@ -44,13 +44,13 @@ func abs(t *testing.T, kind, filename string) string { require.True(t, ok, "got no caller information") if filename == "" { - fpath, err := filepath.Abs(fmt.Sprintf("%s/testdata/%s", path.Dir(gofilename), kind)) + fpath, err := filepath.Abs(fmt.Sprintf("%s/data/%s", path.Dir(gofilename), kind)) require.NoErrorf(t, err, `getting the absolute path of "%s"`, kind) return fpath } - fpath, err := filepath.Abs(fmt.Sprintf("%s/testdata/%s/%s", path.Dir(gofilename), kind, filename)) + fpath, err := filepath.Abs(fmt.Sprintf("%s/data/%s/%s", path.Dir(gofilename), kind, filename)) require.NoErrorf(t, err, `getting the absolute path of "%s"`, filename) return fpath @@ -251,3 +251,26 @@ func IsValidJPEG(path string) (bool, error) { return true, nil } + +//nolint:gochecknoglobals // only for tests +var embedMarkers = [][]byte{ + []byte("/EmbeddedFiles"), + []byte("/Filespec"), + []byte("/FileAttachment"), + []byte("/EF"), +} + +func HasEmbeds(path string) (bool, error) { + data, err := os.ReadFile(path) + if err != nil { + return false, fmt.Errorf("could not read file: %w", err) + } + + for _, m := range embedMarkers { + if bytes.Contains(data, m) { + return true, nil + } + } + + return false, nil +} diff --git a/url.go b/url.go index 524e1d9..6564c71 100644 --- a/url.go +++ b/url.go @@ -9,11 +9,16 @@ const ( // URLRequest facilitates remote URL conversion with the Gotenberg API. type URLRequest struct { + embeds []document.Document + *chromiumRequest } func NewURLRequest(url string) *URLRequest { - req := &URLRequest{newChromiumRequest()} + req := &URLRequest{ + embeds: []document.Document{}, + chromiumRequest: newChromiumRequest(), + } req.fields[fieldURL] = url return req @@ -40,6 +45,20 @@ func (req *URLRequest) formDocuments() map[string]document.Document { return files } +func (req *URLRequest) formEmbeds() map[string]document.Document { + embeds := make(map[string]document.Document) + + for _, embed := range req.embeds { + embeds[embed.Filename()] = embed + } + + return embeds +} + +func (req *URLRequest) Embeds(docs ...document.Document) { + req.embeds = append(req.embeds, docs...) +} + // Compile-time checks to ensure type implements desired interfaces. var ( _ = MultipartRequester(new(URLRequest))