mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 00:22:14 +01:00
feat(chromium): support more units for paper size and margins
This commit is contained in:
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -145,6 +146,91 @@ func (form *FormData) MandatoryDuration(key string, target *time.Duration) *Form
|
||||
return form.mustMandatoryField(key, target)
|
||||
}
|
||||
|
||||
// Inches binds a form field to a float64 variable. It populates an error
|
||||
// if the value cannot be computed back to inches.
|
||||
//
|
||||
// var foo float64
|
||||
//
|
||||
// ctx.FormData().Inches("foo", &foo, 2.0)
|
||||
func (form *FormData) Inches(key string, target *float64, defaultValue float64) *FormData {
|
||||
form.inches(key, target)
|
||||
if *target == -math.MaxFloat64 {
|
||||
*target = defaultValue
|
||||
}
|
||||
return form
|
||||
}
|
||||
|
||||
// MandatoryInches binds a form field to a float64 variable. It populates
|
||||
// an error if the value cannot be computed back to inches, is empty, or the
|
||||
// "key" does not exist.
|
||||
//
|
||||
// var foo float64
|
||||
//
|
||||
// ctx.FormData().MandatoryInches("foo", &foo)
|
||||
func (form *FormData) MandatoryInches(key string, target *float64) *FormData {
|
||||
val, ok := form.values[key]
|
||||
if !ok || val[0] == "" {
|
||||
form.append(
|
||||
fmt.Errorf("form field '%s' is required", key),
|
||||
)
|
||||
return form
|
||||
}
|
||||
return form.inches(key, target)
|
||||
}
|
||||
|
||||
// inches tries to compute a string value to inches.
|
||||
func (form *FormData) inches(key string, target *float64) *FormData {
|
||||
var value string
|
||||
form.mustValue(key, &value, "")
|
||||
|
||||
if value == "" {
|
||||
*target = -math.MaxFloat64
|
||||
return form
|
||||
}
|
||||
|
||||
for _, unit := range []string{"pt", "px", "in", "mm", "cm", "pc"} {
|
||||
if !strings.HasSuffix(value, unit) {
|
||||
continue
|
||||
}
|
||||
|
||||
val, err := strconv.ParseFloat(strings.TrimSuffix(value, unit), 64)
|
||||
if err != nil {
|
||||
form.append(
|
||||
fmt.Errorf("form field '%s' is invalid (got '%s', resulting to %w)", key, value, err),
|
||||
)
|
||||
return form
|
||||
}
|
||||
|
||||
switch unit {
|
||||
case "pt":
|
||||
*target = val * (1.0 / 72.0)
|
||||
case "px":
|
||||
*target = val * (1.0 / 96.0)
|
||||
case "in":
|
||||
*target = val
|
||||
case "mm":
|
||||
*target = val * (1.0 / 25.4)
|
||||
case "cm":
|
||||
*target = val * (1.0 / 2.54)
|
||||
case "pc":
|
||||
*target = val * (1.0 / 6.0)
|
||||
}
|
||||
|
||||
return form
|
||||
}
|
||||
|
||||
val, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
form.append(
|
||||
fmt.Errorf("form field '%s' is invalid (got '%s', resulting to %w)", key, value, err),
|
||||
)
|
||||
return form
|
||||
}
|
||||
|
||||
*target = val
|
||||
return form
|
||||
}
|
||||
|
||||
// Custom helps to define a custom binding function for a form field.
|
||||
//
|
||||
// var foo map[string]string
|
||||
|
||||
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -768,6 +769,333 @@ func TestFormData_MandatoryDuration(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormData_Inches(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
form *FormData
|
||||
defaultValue float64
|
||||
expect float64
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
scenario: "key does not exist, fallback to default zero value",
|
||||
form: &FormData{},
|
||||
defaultValue: 0.0,
|
||||
expect: 0.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does not exist, fallback to default value",
|
||||
form: &FormData{},
|
||||
defaultValue: 2.5,
|
||||
expect: 2.5,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist, but empty value, fallback to default value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 0.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist, value has a unit, but the rest is not float64 compatible",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"foomm",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 0.0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist, but value has no unit and is invalid",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 0.0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist with a pt value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"72pt",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist with a px value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"96px",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist with an in value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"1in",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist with a mm value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"25.4mm",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist with a cm value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"2.54cm",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist with a pc value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"6pc",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "key does exist with no unit in the value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"100",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: 0.0,
|
||||
expect: 100,
|
||||
expectError: false,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
var actual float64
|
||||
|
||||
tc.form.Inches("foo", &actual, tc.defaultValue)
|
||||
|
||||
if fmt.Sprintf("%.1f", actual) != fmt.Sprintf("%.1f", tc.expect) {
|
||||
t.Errorf("expected %.1f but got %.1f", tc.expect, actual)
|
||||
}
|
||||
|
||||
if tc.expectError && tc.form.errors == nil {
|
||||
t.Fatal("expected error but got none", tc.form.errors)
|
||||
}
|
||||
|
||||
if !tc.expectError && tc.form.errors != nil {
|
||||
t.Fatalf("expected no error but got: %v", tc.form.errors)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormData_MandatoryInches(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
form *FormData
|
||||
expect float64
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
scenario: "missing mandatory key",
|
||||
form: &FormData{},
|
||||
expect: 0.0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "mandatory value is empty",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 0.0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "mandatory value has a unit, but the rest is not float64 compatible",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"foomm",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 0.0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "mandatory value has no unit and is invalid",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 0.0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "a pt mandatory value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"72pt",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "a px mandatory value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"96px",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "an in mandatory value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"1in",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "a mm mandatory value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"25.4mm",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "a cm mandatory value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"2.54cm",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "a pc mandatory value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"6pc",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 1.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
scenario: "no unit in the mandatory value",
|
||||
form: &FormData{
|
||||
values: map[string][]string{
|
||||
"foo": {
|
||||
"100",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: 100,
|
||||
expectError: false,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
var actual float64
|
||||
|
||||
tc.form.MandatoryInches("foo", &actual)
|
||||
|
||||
if fmt.Sprintf("%.1f", actual) != fmt.Sprintf("%.1f", tc.expect) {
|
||||
t.Errorf("expected %.1f but got %.1f", tc.expect, actual)
|
||||
}
|
||||
|
||||
if tc.expectError && tc.form.errors == nil {
|
||||
t.Fatal("expected error but got none", tc.form.errors)
|
||||
}
|
||||
|
||||
if !tc.expectError && tc.form.errors != nil {
|
||||
t.Fatalf("expected no error but got: %v", tc.form.errors)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormData_Custom(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
|
||||
Reference in New Issue
Block a user