Skip to content

Commit

Permalink
Merge pull request #10 from foomo/feature/uploads
Browse files Browse the repository at this point in the history
feat: file uploads API support
  • Loading branch information
cvidmar authored Oct 23, 2024
2 parents 1728e2a + fa68cfe commit 1c01bf5
Show file tree
Hide file tree
Showing 17 changed files with 124 additions and 104 deletions.
8 changes: 4 additions & 4 deletions api_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (service *APIKeyService) List(ctx context.Context, spaceID string) *Collect
path := fmt.Sprintf("/spaces/%s%s/api_keys", spaceID, getEnvPath(service.c))
method := http.MethodGet

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return &Collection{}
}
Expand All @@ -76,7 +76,7 @@ func (service *APIKeyService) Get(ctx context.Context, spaceID, apiKeyID string)
path := fmt.Sprintf("/spaces/%s%s/api_keys/%s", spaceID, getEnvPath(service.c), apiKeyID)
method := http.MethodGet

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -107,7 +107,7 @@ func (service *APIKeyService) Upsert(ctx context.Context, spaceID string, apiKey
method = "POST"
}

req, err := service.c.newRequest(ctx, method, path, nil, bytes.NewReader(bytesArray))
req, err := service.c.newRequest(ctx, method, path, nil, bytes.NewReader(bytesArray), nil)
if err != nil {
return err
}
Expand All @@ -122,7 +122,7 @@ func (service *APIKeyService) Delete(ctx context.Context, spaceID string, apiKey
path := fmt.Sprintf("/spaces/%s%s/api_keys/%s", spaceID, getEnvPath(service.c), apiKey.Sys.ID)
method := http.MethodDelete

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return err
}
Expand Down
18 changes: 8 additions & 10 deletions asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type File struct {
ContentType string `json:"contentType,omitempty"`
URL string `json:"url,omitempty"`
UploadURL string `json:"upload,omitempty"`
UploadFrom *Upload `json:"uploadFrom,omitempty"`
Detail *FileDetail `json:"details,omitempty"`
}

Expand Down Expand Up @@ -76,7 +77,7 @@ func (service *AssetsService) List(ctx context.Context, spaceID string) *Collect
path := fmt.Sprintf("/spaces/%s%s/assets", spaceID, getEnvPath(service.c))
method := http.MethodGet

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return &Collection{}
}
Expand All @@ -98,7 +99,7 @@ func (service *AssetsService) Get(ctx context.Context, spaceID, assetID string,

method := http.MethodGet

req, err := service.c.newRequest(ctx, method, path, query, nil)
req, err := service.c.newRequest(ctx, method, path, query, nil, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -167,7 +168,7 @@ func (service *AssetsService) Upsert(ctx context.Context, spaceID string, asset
method = "POST"
}

req, err := service.c.newRequest(ctx, method, path, nil, bytes.NewReader(bytesArray))
req, err := service.c.newRequest(ctx, method, path, nil, bytes.NewReader(bytesArray), nil)
if err != nil {
return err
}
Expand All @@ -182,7 +183,7 @@ func (service *AssetsService) Delete(ctx context.Context, spaceID string, asset
path := fmt.Sprintf("/spaces/%s%s/assets/%s", spaceID, getEnvPath(service.c), asset.Sys.ID)
method := http.MethodDelete

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return err
}
Expand All @@ -198,13 +199,10 @@ func (service *AssetsService) Process(ctx context.Context, spaceID string, asset
var locale string
for k := range asset.Fields.Title {
locale = k
if asset.Fields.File[k].UploadURL == "" {
continue
}
path := fmt.Sprintf("/spaces/%s%s/assets/%s/files/%s/process", spaceID, getEnvPath(service.c), asset.Sys.ID, locale)
method := http.MethodPut

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return err
}
Expand All @@ -224,7 +222,7 @@ func (service *AssetsService) Publish(ctx context.Context, spaceID string, asset
path := fmt.Sprintf("/spaces/%s%s/assets/%s/published", spaceID, getEnvPath(service.c), asset.Sys.ID)
method := http.MethodPut

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return err
}
Expand All @@ -240,7 +238,7 @@ func (service *AssetsService) Unpublish(ctx context.Context, spaceID string, ass
path := fmt.Sprintf("/spaces/%s%s/assets/%s/published", spaceID, getEnvPath(service.c), asset.Sys.ID)
method := http.MethodDelete

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (col *Collection) GetAll() (*Collection, error) {
return nil, errNext
}
allItems = append(allItems, col.Items...)
if uint16(len(col.Items)) < col.Limit {
if len(col.Items) < int(col.Limit) {
break
}
}
Expand Down
4 changes: 2 additions & 2 deletions collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func TestNewCollection(t *testing.T) {
Filename: "error-notResolvable.json",
})

req, err := c.newRequest(context.TODO(), http.MethodGet, "/", url.Values{}, nil)
req, err := c.newRequest(context.TODO(), http.MethodGet, "/", url.Values{}, nil, nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -92,7 +92,7 @@ func TestNewCollection(t *testing.T) {
Filename: "error-nameUnknown.json",
})

req, err := c.newRequest(context.TODO(), http.MethodGet, "/", url.Values{}, nil)
req, err := c.newRequest(context.TODO(), http.MethodGet, "/", url.Values{}, nil, nil)
if err != nil {
t.Fatal(err)
}
Expand Down
12 changes: 6 additions & 6 deletions content_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func (ct *ContentType) GetVersion() int {
func (service *ContentTypesService) List(ctx context.Context, spaceID string) *Collection {
path := fmt.Sprintf("/spaces/%s%s/content_types", spaceID, getEnvPath(service.c))

req, err := service.c.newRequest(ctx, http.MethodGet, path, nil, nil)
req, err := service.c.newRequest(ctx, http.MethodGet, path, nil, nil, nil)
if err != nil {
return nil
}
Expand All @@ -312,7 +312,7 @@ func (service *ContentTypesService) List(ctx context.Context, spaceID string) *C
func (service *ContentTypesService) Get(ctx context.Context, spaceID, contentTypeID string) (*ContentType, error) {
path := fmt.Sprintf("/spaces/%s%s/content_types/%s", spaceID, getEnvPath(service.c), contentTypeID)

req, err := service.c.newRequest(ctx, http.MethodGet, path, nil, nil)
req, err := service.c.newRequest(ctx, http.MethodGet, path, nil, nil, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -343,7 +343,7 @@ func (service *ContentTypesService) Upsert(ctx context.Context, spaceID string,
method = "POST"
}

req, err := service.c.newRequest(ctx, method, path, nil, bytes.NewReader(bytesArray))
req, err := service.c.newRequest(ctx, method, path, nil, bytes.NewReader(bytesArray), nil)
if err != nil {
return err
}
Expand All @@ -358,7 +358,7 @@ func (service *ContentTypesService) Delete(ctx context.Context, spaceID string,
path := fmt.Sprintf("/spaces/%s%s/content_types/%s", spaceID, getEnvPath(service.c), ct.Sys.ID)
method := http.MethodDelete

req, err := service.c.newRequest(ctx, method, path, nil, nil)
req, err := service.c.newRequest(ctx, method, path, nil, nil, nil)
if err != nil {
return err
}
Expand All @@ -373,7 +373,7 @@ func (service *ContentTypesService) Delete(ctx context.Context, spaceID string,
func (service *ContentTypesService) Activate(ctx context.Context, spaceID string, ct *ContentType) error {
path := fmt.Sprintf("/spaces/%s%s/content_types/%s/published", spaceID, getEnvPath(service.c), ct.Sys.ID)

req, err := service.c.newRequest(ctx, http.MethodPut, path, nil, nil)
req, err := service.c.newRequest(ctx, http.MethodPut, path, nil, nil, nil)
if err != nil {
return err
}
Expand All @@ -388,7 +388,7 @@ func (service *ContentTypesService) Activate(ctx context.Context, spaceID string
func (service *ContentTypesService) Deactivate(ctx context.Context, spaceID string, ct *ContentType) error {
path := fmt.Sprintf("/spaces/%s%s/content_types/%s/published", spaceID, getEnvPath(service.c), ct.Sys.ID)

req, err := service.c.newRequest(ctx, http.MethodDelete, path, nil, nil)
req, err := service.c.newRequest(ctx, http.MethodDelete, path, nil, nil, nil)
if err != nil {
return err
}
Expand Down
24 changes: 12 additions & 12 deletions content_type_field_validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,24 +106,24 @@ func (v *FieldValidationDimension) UnmarshalJSON(data []byte) error {
if width, ok := dimensionData["width"].(map[string]interface{}); ok {
v.Width = &MinMax{}

if min, ok := width["min"].(float64); ok {
v.Width.Min = min
if minimum, ok := width["min"].(float64); ok {
v.Width.Min = minimum
}

if max, ok := width["min"].(float64); ok {
v.Width.Max = max
if maximum, ok := width["min"].(float64); ok {
v.Width.Max = maximum
}
}

if height, ok := dimensionData["height"].(map[string]interface{}); ok {
v.Height = &MinMax{}

if min, ok := height["min"].(float64); ok {
v.Height.Min = min
if minimum, ok := height["min"].(float64); ok {
v.Height.Min = minimum
}

if max, ok := height["max"].(float64); ok {
v.Height.Max = max
if maximum, ok := height["max"].(float64); ok {
v.Height.Max = maximum
}
}

Expand Down Expand Up @@ -193,17 +193,17 @@ func (v *FieldValidationDate) UnmarshalJSON(data []byte) error {

v.Range = &DateMinMax{}

if min, ok := dateRangeData["min"].(string); ok {
minDate, err := time.Parse("2006-01-02T03:04:05", min)
if minimum, ok := dateRangeData["min"].(string); ok {
minDate, err := time.Parse("2006-01-02T03:04:05", minimum)
if err != nil {
return err
}

v.Range.Min = minDate
}

if max, ok := dateRangeData["max"].(string); ok {
maxDate, err := time.Parse("2006-01-02T03:04:05", max)
if maximum, ok := dateRangeData["max"].(string); ok {
maxDate, err := time.Parse("2006-01-02T03:04:05", maximum)
if err != nil {
return err
}
Expand Down
12 changes: 6 additions & 6 deletions content_type_field_validations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,16 @@ func TestFieldValidationDate(t *testing.T) {
var err error

layout := "2006-01-02T03:04:05"
min := time.Now()
max := time.Now()
minimum := time.Now()
maximum := time.Now()

minStr := min.Format(layout)
maxStr := max.Format(layout)
minStr := minimum.Format(layout)
maxStr := maximum.Format(layout)

validation := &FieldValidationDate{
Range: &DateMinMax{
Min: min,
Max: max,
Min: minimum,
Max: maximum,
},
ErrorMessage: "error message",
}
Expand Down
8 changes: 4 additions & 4 deletions content_type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,10 +756,10 @@ func TestContentTypeFieldTypeMedia(t *testing.T) {
// size validation
validationSize := validations[2].(map[string]interface{})
sizeData := validationSize["assetFileSize"].(map[string]interface{})
min := int(sizeData["min"].(float64))
max := int(sizeData["max"].(float64))
assert.Equal(t, 30, min)
assert.Equal(t, 400, max)
minimum := int(sizeData["min"].(float64))
maximum := int(sizeData["max"].(float64))
assert.Equal(t, 30, minimum)
assert.Equal(t, 400, maximum)

w.WriteHeader(http.StatusCreated)
_, _ = fmt.Fprintln(w, readTestData(t, "content_type.json"))
Expand Down
29 changes: 25 additions & 4 deletions contentful.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"net/http"
"net/http/httputil"
"net/url"
"path"
"strconv"
"strings"
"time"

"github.com/aoliveti/curling"
Expand All @@ -24,6 +26,7 @@ type Contentful struct {
QueryParams map[string]string
Headers map[string]string
BaseURL string
UploadURL string
Environment string

Spaces *SpacesService
Expand All @@ -33,6 +36,7 @@ type Contentful struct {
Entries *EntriesService
Locales *LocalesService
Tags *TagsService
Upload *UploadService
Webhooks *WebhooksService
}

Expand All @@ -59,7 +63,8 @@ func NewCMA(token string) *Contentful {
"Content-Type": "application/vnd.contentful.management.v1+json",
"X-Contentful-User-Agent": fmt.Sprintf("sdk contentful.go/%s", Version),
},
BaseURL: "https://api.contentful.com",
BaseURL: "https://api.contentful.com",
UploadURL: "https://upload.contentful.com",
}

c.Spaces = &SpacesService{c: c}
Expand All @@ -68,6 +73,7 @@ func NewCMA(token string) *Contentful {
c.ContentTypes = &ContentTypesService{c: c}
c.Entries = &EntriesService{c: c}
c.Tags = &TagsService{c: c}
c.Upload = &UploadService{c: c}
c.Locales = &LocalesService{c: c}
c.Webhooks = &WebhooksService{c: c}

Expand Down Expand Up @@ -153,8 +159,20 @@ func (c *Contentful) SetBaseURL(baseURL string) *Contentful {
return c
}

func (c *Contentful) newRequest(ctx context.Context, method, path string, query url.Values, body io.Reader) (*http.Request, error) {
u, err := url.Parse(c.BaseURL)
func (c *Contentful) newRequest(ctx context.Context, method, requestPath string, query url.Values, body io.Reader, additionalHeaders map[string]string) (*http.Request, error) {
if idx := strings.Index(requestPath, "?"); idx != -1 {
requestPath = requestPath[:idx]
}
cleanUrl := path.Clean(requestPath)

Check warning on line 166 in contentful.go

View workflow job for this annotation

GitHub Actions / test

var-naming: var cleanUrl should be cleanURL (revive)
_, lastSegment := path.Split(cleanUrl)
var u *url.URL
var err error
switch lastSegment {
case "uploads":
u, err = url.Parse(c.UploadURL)
default:
u, err = url.Parse(c.BaseURL)
}
if err != nil {
return nil, err
}
Expand All @@ -164,7 +182,7 @@ func (c *Contentful) newRequest(ctx context.Context, method, path string, query
query.Set(key, value)
}

u.Path = u.Path + path
u.Path = u.Path + requestPath
u.RawQuery = query.Encode()

req, err := http.NewRequestWithContext(ctx, method, u.String(), body)
Expand All @@ -176,6 +194,9 @@ func (c *Contentful) newRequest(ctx context.Context, method, path string, query
for key, value := range c.Headers {
req.Header.Set(key, value)
}
for key, value := range additionalHeaders {
req.Header.Set(key, value)
}

return req, nil
}
Expand Down
6 changes: 3 additions & 3 deletions contentful_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func TestNewRequest(t *testing.T) {
expectedURL.Path = path
expectedURL.RawQuery = query.Encode()

req, err := c.newRequest(context.TODO(), method, path, query, nil)
req, err := c.newRequest(context.TODO(), method, path, query, nil, nil)
require.NoError(t, err)
assert.Equal(t, "Bearer "+CMAToken, req.Header.Get("Authorization"))
assert.Equal(t, "application/vnd.contentful.management.v1+json", req.Header.Get("Content-Type"))
Expand All @@ -206,7 +206,7 @@ func TestNewRequest(t *testing.T) {
}
body, err := json.Marshal(bodyData)
require.NoError(t, err)
req, err = c.newRequest(context.TODO(), method, path, query, bytes.NewReader(body))
req, err = c.newRequest(context.TODO(), method, path, query, bytes.NewReader(body), nil)
require.NoError(t, err)
assert.Equal(t, "Bearer "+CMAToken, req.Header.Get("Authorization"))
assert.Equal(t, "application/vnd.contentful.management.v1+json", req.Header.Get("Content-Type"))
Expand Down Expand Up @@ -241,7 +241,7 @@ func TestHandleError(t *testing.T) {
errResponseReader := bytes.NewReader(marshaled)
errResponseReadCloser := io.NopCloser(errResponseReader)

req, err := c.newRequest(context.TODO(), method, path, query, nil)
req, err := c.newRequest(context.TODO(), method, path, query, nil, nil)
require.NoError(t, err)
responseHeaders := http.Header{}
responseHeaders.Add("X-Contentful-Request-Id", requestID)
Expand Down
Loading

0 comments on commit 1c01bf5

Please sign in to comment.