mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-16 12:22:17 +01:00
feat(exiftool): refactor read write metadata
This commit is contained in:
@@ -78,7 +78,7 @@ func FormDataChromiumOptions(ctx *api.Context) (*api.FormData, Options) {
|
||||
}
|
||||
|
||||
if value != "screen" && value != "print" {
|
||||
return fmt.Errorf("wrong value, expected either 'screen', 'print' or empty")
|
||||
return errors.New("wrong value, expected either 'screen', 'print' or empty")
|
||||
}
|
||||
|
||||
emulatedMediaType = value
|
||||
@@ -233,16 +233,14 @@ func FormDataChromiumPdfFormats(form *api.FormData) gotenberg.PdfFormats {
|
||||
}
|
||||
}
|
||||
|
||||
// FormDataMetadata creates metadata object from the form data.
|
||||
func FormDataMetadata(form *api.FormData) map[string]interface{} {
|
||||
// FormDataPdfMetadata creates metadata object from the form data.
|
||||
func FormDataPdfMetadata(form *api.FormData) map[string]interface{} {
|
||||
var metadata map[string]interface{}
|
||||
|
||||
form.Custom("metadata", func(value string) error {
|
||||
metadata = map[string]interface{}{}
|
||||
if len(value) > 0 {
|
||||
err := json.Unmarshal([]byte(value), &metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("unmarshal metadata: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -260,7 +258,7 @@ func convertUrlRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
ctx := c.Get("context").(*api.Context)
|
||||
form, options := FormDataChromiumPdfOptions(ctx)
|
||||
pdfFormats := FormDataChromiumPdfFormats(form)
|
||||
metadata := FormDataMetadata(form)
|
||||
metadata := FormDataPdfMetadata(form)
|
||||
|
||||
var url string
|
||||
err := form.
|
||||
@@ -270,7 +268,7 @@ func convertUrlRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("validate form data: %w", err)
|
||||
}
|
||||
|
||||
err = convertUrl(ctx, chromium, engine, url, pdfFormats, options, metadata)
|
||||
err = convertUrl(ctx, chromium, engine, url, options, pdfFormats, metadata)
|
||||
if err != nil {
|
||||
return fmt.Errorf("convert URL to PDF: %w", err)
|
||||
}
|
||||
@@ -320,7 +318,7 @@ func convertHtmlRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
ctx := c.Get("context").(*api.Context)
|
||||
form, options := FormDataChromiumPdfOptions(ctx)
|
||||
pdfFormats := FormDataChromiumPdfFormats(form)
|
||||
metadata := FormDataMetadata(form)
|
||||
metadata := FormDataPdfMetadata(form)
|
||||
|
||||
var inputPath string
|
||||
err := form.
|
||||
@@ -331,7 +329,7 @@ func convertHtmlRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("file://%s", inputPath)
|
||||
err = convertUrl(ctx, chromium, engine, url, pdfFormats, options, metadata)
|
||||
err = convertUrl(ctx, chromium, engine, url, options, pdfFormats, metadata)
|
||||
if err != nil {
|
||||
return fmt.Errorf("convert HTML to PDF: %w", err)
|
||||
}
|
||||
@@ -382,7 +380,7 @@ func convertMarkdownRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
ctx := c.Get("context").(*api.Context)
|
||||
form, options := FormDataChromiumPdfOptions(ctx)
|
||||
pdfFormats := FormDataChromiumPdfFormats(form)
|
||||
metadata := FormDataMetadata(form)
|
||||
metadata := FormDataPdfMetadata(form)
|
||||
|
||||
var (
|
||||
inputPath string
|
||||
@@ -402,7 +400,7 @@ func convertMarkdownRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
|
||||
return fmt.Errorf("transform markdown file(s) to HTML: %w", err)
|
||||
}
|
||||
|
||||
err = convertUrl(ctx, chromium, engine, url, pdfFormats, options, metadata)
|
||||
err = convertUrl(ctx, chromium, engine, url, options, pdfFormats, metadata)
|
||||
if err != nil {
|
||||
return fmt.Errorf("convert markdown to PDF: %w", err)
|
||||
}
|
||||
@@ -526,7 +524,7 @@ func markdownToHtml(ctx *api.Context, inputPath string, markdownPaths []string)
|
||||
return fmt.Sprintf("file://%s", inputPath), nil
|
||||
}
|
||||
|
||||
func convertUrl(ctx *api.Context, chromium Api, engine gotenberg.PdfEngine, url string, pdfFormats gotenberg.PdfFormats, options PdfOptions, metadata map[string]interface{}) error {
|
||||
func convertUrl(ctx *api.Context, chromium Api, engine gotenberg.PdfEngine, url string, options PdfOptions, pdfFormats gotenberg.PdfFormats, metadata map[string]interface{}) error {
|
||||
outputPath := ctx.GeneratePath(".pdf")
|
||||
|
||||
err := chromium.Pdf(ctx, ctx.Log(), url, outputPath, options)
|
||||
@@ -584,7 +582,7 @@ func convertUrl(ctx *api.Context, chromium Api, engine gotenberg.PdfEngine, url
|
||||
|
||||
// Writes and potentially overrides metadata entries, if any.
|
||||
if len(metadata) > 0 {
|
||||
err = engine.WriteMetadata(ctx, ctx.Log(), outputPath, metadata)
|
||||
err = engine.WriteMetadata(ctx, ctx.Log(), metadata, outputPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("write metadata: %w", err)
|
||||
}
|
||||
|
||||
@@ -399,6 +399,57 @@ func TestFormDataChromiumPdfFormats(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormDataPdfMetadata(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
ctx *api.ContextMock
|
||||
expectedMetadata map[string]interface{}
|
||||
}{
|
||||
{
|
||||
scenario: "no metadata form field",
|
||||
ctx: &api.ContextMock{Context: new(api.Context)},
|
||||
expectedMetadata: nil,
|
||||
},
|
||||
{
|
||||
scenario: "invalid metadata form field",
|
||||
ctx: func() *api.ContextMock {
|
||||
ctx := &api.ContextMock{Context: new(api.Context)}
|
||||
ctx.SetValues(map[string][]string{
|
||||
"metadata": {
|
||||
"foo",
|
||||
},
|
||||
})
|
||||
return ctx
|
||||
}(),
|
||||
expectedMetadata: nil,
|
||||
},
|
||||
{
|
||||
scenario: "valid metadata form field",
|
||||
ctx: func() *api.ContextMock {
|
||||
ctx := &api.ContextMock{Context: new(api.Context)}
|
||||
ctx.SetValues(map[string][]string{
|
||||
"metadata": {
|
||||
"{\"foo\":\"bar\"}",
|
||||
},
|
||||
})
|
||||
return ctx
|
||||
}(),
|
||||
expectedMetadata: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
tc.ctx.SetLogger(zap.NewNop())
|
||||
actual := FormDataPdfMetadata(tc.ctx.Context.FormData())
|
||||
|
||||
if !reflect.DeepEqual(actual, tc.expectedMetadata) {
|
||||
t.Fatalf("expected %+v but got: %+v", tc.expectedMetadata, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertUrlRoute(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
@@ -1223,8 +1274,8 @@ func TestConvertUrl(t *testing.T) {
|
||||
ctx *api.ContextMock
|
||||
api Api
|
||||
engine gotenberg.PdfEngine
|
||||
pdfFormats gotenberg.PdfFormats
|
||||
options PdfOptions
|
||||
pdfFormats gotenberg.PdfFormats
|
||||
metadata map[string]interface{}
|
||||
expectError bool
|
||||
expectHttpError bool
|
||||
@@ -1331,7 +1382,7 @@ func TestConvertUrl(t *testing.T) {
|
||||
expectOutputPathsCount: 0,
|
||||
},
|
||||
{
|
||||
scenario: "error from PDF engine",
|
||||
scenario: "PDF engine convert error",
|
||||
ctx: &api.ContextMock{Context: new(api.Context)},
|
||||
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
|
||||
return nil
|
||||
@@ -1339,14 +1390,14 @@ func TestConvertUrl(t *testing.T) {
|
||||
engine: &gotenberg.PdfEngineMock{ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
|
||||
return errors.New("foo")
|
||||
}},
|
||||
pdfFormats: gotenberg.PdfFormats{PdfA: "foo"},
|
||||
options: DefaultPdfOptions(),
|
||||
pdfFormats: gotenberg.PdfFormats{PdfA: "foo"},
|
||||
expectError: true,
|
||||
expectHttpError: false,
|
||||
expectOutputPathsCount: 0,
|
||||
},
|
||||
{
|
||||
scenario: "success with pdfa form field",
|
||||
scenario: "success with PDF formats",
|
||||
ctx: &api.ContextMock{Context: new(api.Context)},
|
||||
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
|
||||
return nil
|
||||
@@ -1354,12 +1405,29 @@ func TestConvertUrl(t *testing.T) {
|
||||
engine: &gotenberg.PdfEngineMock{ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
|
||||
return nil
|
||||
}},
|
||||
pdfFormats: gotenberg.PdfFormats{PdfA: gotenberg.PdfA1b},
|
||||
options: DefaultPdfOptions(),
|
||||
pdfFormats: gotenberg.PdfFormats{PdfA: gotenberg.PdfA1b},
|
||||
expectError: false,
|
||||
expectHttpError: false,
|
||||
expectOutputPathsCount: 1,
|
||||
},
|
||||
{
|
||||
scenario: "PDF engine write metadata error",
|
||||
ctx: &api.ContextMock{Context: new(api.Context)},
|
||||
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
|
||||
return nil
|
||||
}},
|
||||
engine: &gotenberg.PdfEngineMock{WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
|
||||
return errors.New("foo")
|
||||
}},
|
||||
options: DefaultPdfOptions(),
|
||||
metadata: map[string]interface{}{
|
||||
"Creator": "foo",
|
||||
"Producer": "bar",
|
||||
},
|
||||
expectError: true,
|
||||
expectHttpError: false,
|
||||
},
|
||||
{
|
||||
scenario: "cannot add output paths",
|
||||
ctx: func() *api.ContextMock {
|
||||
@@ -1381,38 +1449,16 @@ func TestConvertUrl(t *testing.T) {
|
||||
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
|
||||
return nil
|
||||
}},
|
||||
options: DefaultPdfOptions(),
|
||||
expectError: false,
|
||||
expectHttpError: false,
|
||||
expectOutputPathsCount: 1,
|
||||
},
|
||||
{
|
||||
scenario: "error with metadata write",
|
||||
ctx: &api.ContextMock{Context: new(api.Context)},
|
||||
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
|
||||
return nil
|
||||
}},
|
||||
engine: &gotenberg.PdfEngineMock{WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string, newMetadata map[string]interface{}) error {
|
||||
return fmt.Errorf("error writing metadata to %s: %w", "foo.pdf", errors.New("foo"))
|
||||
}},
|
||||
options: DefaultPdfOptions(),
|
||||
metadata: map[string]interface{}{
|
||||
"Creator": "foo",
|
||||
"Producer": "bar",
|
||||
engine: &gotenberg.PdfEngineMock{
|
||||
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
|
||||
return nil
|
||||
},
|
||||
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
expectHttpError: false,
|
||||
},
|
||||
{
|
||||
scenario: "success with metadata write",
|
||||
ctx: &api.ContextMock{Context: new(api.Context)},
|
||||
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
|
||||
return nil
|
||||
}},
|
||||
engine: &gotenberg.PdfEngineMock{WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string, newMetadata map[string]interface{}) error {
|
||||
return nil
|
||||
}},
|
||||
options: DefaultPdfOptions(),
|
||||
options: DefaultPdfOptions(),
|
||||
pdfFormats: gotenberg.PdfFormats{PdfA: gotenberg.PdfA1b},
|
||||
metadata: map[string]interface{}{
|
||||
"Creator": "foo",
|
||||
"Producer": "bar",
|
||||
@@ -1424,7 +1470,7 @@ func TestConvertUrl(t *testing.T) {
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
tc.ctx.SetLogger(zap.NewNop())
|
||||
err := convertUrl(tc.ctx.Context, tc.api, tc.engine, "", tc.pdfFormats, tc.options, tc.metadata)
|
||||
err := convertUrl(tc.ctx.Context, tc.api, tc.engine, "", tc.options, tc.pdfFormats, tc.metadata)
|
||||
|
||||
if tc.expectError && err == nil {
|
||||
t.Fatal("expected error but got none", err)
|
||||
|
||||
Reference in New Issue
Block a user