diff --git a/.changelog/1265.txt b/.changelog/1265.txt new file mode 100644 index 00000000000..f93fc420a6a --- /dev/null +++ b/.changelog/1265.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +r2_bucket: add support for getting a bucket +``` + +```release-note:breaking-change +r2_bucket: change creation time from string to *time.Time +``` diff --git a/r2_bucket.go b/r2_bucket.go index 08de630e1cd..046438f094b 100644 --- a/r2_bucket.go +++ b/r2_bucket.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/http" + "time" ) var ( @@ -14,8 +15,9 @@ var ( // R2Bucket defines a container for objects stored in R2 Storage. type R2Bucket struct { - Name string `json:"name"` - CreationDate string `json:"creation_date,omitempty"` + Name string `json:"name"` + CreationDate *time.Time `json:"creation_date,omitempty"` + Location string `json:"location,omitempty"` } // R2Buckets represents the map of buckets response from @@ -40,6 +42,16 @@ type ListR2BucketsParams struct { Cursor string `url:"cursor,omitempty"` } +type CreateR2BucketParameters struct { + Name string `json:"name,omitempty"` + LocationHint string `json:"locationHint,omitempty"` +} + +type R2BucketResponse struct { + Result R2Bucket `json:"result"` + Response +} + // ListR2Buckets Lists R2 buckets. func (api *API) ListR2Buckets(ctx context.Context, rc *ResourceContainer, params ListR2BucketsParams) ([]R2Bucket, error) { if rc.Identifier == "" { @@ -61,26 +73,58 @@ func (api *API) ListR2Buckets(ctx context.Context, rc *ResourceContainer, params return r2BucketListResponse.Result.Buckets, nil } -type CreateR2BucketParameters struct { - Name string `json:"name,omitempty"` -} - // CreateR2Bucket Creates a new R2 bucket. // // API reference: https://api.cloudflare.com/#r2-bucket-create-bucket -func (api *API) CreateR2Bucket(ctx context.Context, rc *ResourceContainer, params CreateR2BucketParameters) error { +func (api *API) CreateR2Bucket(ctx context.Context, rc *ResourceContainer, params CreateR2BucketParameters) (R2Bucket, error) { if rc.Identifier == "" { - return ErrMissingAccountID + return R2Bucket{}, ErrMissingAccountID } if params.Name == "" { - return ErrMissingBucketName + return R2Bucket{}, ErrMissingBucketName } uri := fmt.Sprintf("/accounts/%s/r2/buckets", rc.Identifier) - _, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) + res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) + if err != nil { + return R2Bucket{}, err + } - return err + var r2BucketResponse R2BucketResponse + err = json.Unmarshal(res, &r2BucketResponse) + if err != nil { + return R2Bucket{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return r2BucketResponse.Result, nil +} + +// GetR2Bucket Gets an existing R2 bucket. +// +// API reference: https://api.cloudflare.com/#r2-bucket-get-bucket +func (api *API) GetR2Bucket(ctx context.Context, rc *ResourceContainer, bucketName string) (R2Bucket, error) { + if rc.Identifier == "" { + return R2Bucket{}, ErrMissingAccountID + } + + if bucketName == "" { + return R2Bucket{}, ErrMissingBucketName + } + + uri := fmt.Sprintf("/accounts/%s/r2/buckets/%s", rc.Identifier, bucketName) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return R2Bucket{}, err + } + + var r2BucketResponse R2BucketResponse + err = json.Unmarshal(res, &r2BucketResponse) + if err != nil { + return R2Bucket{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return r2BucketResponse.Result, nil } // DeleteR2Bucket Deletes an existing R2 bucket. diff --git a/r2_bucket_test.go b/r2_bucket_test.go index 42168838c8c..ac9b2f96070 100644 --- a/r2_bucket_test.go +++ b/r2_bucket_test.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -32,11 +33,11 @@ func TestR2_ListBuckets(t *testing.T) { } }`) }) - + createDate, _ := time.Parse(time.RFC3339, "2022-06-24T19:58:49.477Z") want := []R2Bucket{ { Name: "example-bucket", - CreationDate: "2022-06-24T19:58:49.477Z", + CreationDate: &createDate, }, } actual, err := client.ListR2Buckets(context.Background(), AccountIdentifier(testAccountID), ListR2BucketsParams{}) @@ -45,6 +46,49 @@ func TestR2_ListBuckets(t *testing.T) { } } +func TestR2_GetBucket(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc(fmt.Sprintf("/accounts/%s/r2/buckets/%s", testAccountID, testBucketName), func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "name": "example-bucket", + "creation_date": "2022-06-24T19:58:49.477Z", + "location": "ENAM" + } +}`) + }) + + _, err := client.GetR2Bucket(context.Background(), AccountIdentifier(""), "") + if assert.Error(t, err) { + assert.Equal(t, ErrMissingAccountID, err) + } + + _, err = client.GetR2Bucket(context.Background(), AccountIdentifier(testAccountID), "") + + if assert.Error(t, err) { + assert.Equal(t, ErrMissingBucketName, err) + } + + createDate, _ := time.Parse(time.RFC3339, "2022-06-24T19:58:49.477Z") + want := R2Bucket{ + Name: testBucketName, + CreationDate: &createDate, + Location: "ENAM", + } + + actual, err := client.GetR2Bucket(context.Background(), AccountIdentifier(testAccountID), testBucketName) + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + func TestR2_CreateBucket(t *testing.T) { setup() defer teardown() @@ -56,22 +100,34 @@ func TestR2_CreateBucket(t *testing.T) { "success": true, "errors": [], "messages": [], - "result": {} + "result": { + "name": "example-bucket", + "creation_date": "2022-06-24T19:58:49.477Z", + "location": "ENAM" + } }`) }) - err := client.CreateR2Bucket(context.Background(), AccountIdentifier(""), CreateR2BucketParameters{}) + _, err := client.CreateR2Bucket(context.Background(), AccountIdentifier(""), CreateR2BucketParameters{}) if assert.Error(t, err) { assert.Equal(t, ErrMissingAccountID, err) } - err = client.CreateR2Bucket(context.Background(), AccountIdentifier(testAccountID), CreateR2BucketParameters{Name: ""}) + _, err = client.CreateR2Bucket(context.Background(), AccountIdentifier(testAccountID), CreateR2BucketParameters{Name: ""}) if assert.Error(t, err) { assert.Equal(t, ErrMissingBucketName, err) } + createDate, _ := time.Parse(time.RFC3339, "2022-06-24T19:58:49.477Z") + want := R2Bucket{ + Name: testBucketName, + CreationDate: &createDate, + Location: "ENAM", + } - err = client.CreateR2Bucket(context.Background(), AccountIdentifier(testAccountID), CreateR2BucketParameters{Name: testBucketName}) - assert.NoError(t, err) + actual, err := client.CreateR2Bucket(context.Background(), AccountIdentifier(testAccountID), CreateR2BucketParameters{Name: testBucketName, LocationHint: "ENAM"}) + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } } func TestR2_DeleteBucket(t *testing.T) {