Added Exclude Folders & Exclude Prefixes support (#2973)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -31,7 +31,7 @@ import (
|
||||
func Test_AddAccessRuleAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddBucket("testaccessruleadd", false, false, nil, nil)
|
||||
AddBucket("testaccessruleadd", false, nil, nil, nil)
|
||||
|
||||
type args struct {
|
||||
bucket string
|
||||
@@ -111,7 +111,7 @@ func Test_AddAccessRuleAPI(t *testing.T) {
|
||||
func Test_GetAccessRulesAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddBucket("testaccessruleget", false, false, nil, nil)
|
||||
AddBucket("testaccessruleget", false, nil, nil, nil)
|
||||
|
||||
type args struct {
|
||||
bucket string
|
||||
@@ -161,7 +161,7 @@ func Test_GetAccessRulesAPI(t *testing.T) {
|
||||
func Test_DeleteAccessRuleAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddBucket("testaccessruledelete", false, false, nil, nil)
|
||||
AddBucket("testaccessruledelete", false, nil, nil, nil)
|
||||
|
||||
type args struct {
|
||||
prefix string
|
||||
|
||||
@@ -42,14 +42,14 @@ import (
|
||||
type AddBucketOps struct {
|
||||
Name string
|
||||
Locking bool
|
||||
Versioning bool
|
||||
Versioning map[string]interface{}
|
||||
Quota map[string]interface{}
|
||||
Retention map[string]interface{}
|
||||
Endpoint *string
|
||||
UseToken *string
|
||||
}
|
||||
|
||||
func AddBucket(name string, locking, versioning bool, quota, retention map[string]interface{}) (*http.Response, error) {
|
||||
func AddBucket(name string, locking bool, versioning, quota, retention map[string]interface{}) (*http.Response, error) {
|
||||
return AddBucketWithOpts(&AddBucketOps{
|
||||
Name: name,
|
||||
Locking: locking,
|
||||
@@ -142,11 +142,11 @@ func getTokenForEndpoint(endpoint string) string {
|
||||
return loginToken
|
||||
}
|
||||
|
||||
func setupBucket(name string, locking, versioning bool, quota, retention map[string]interface{}, assert *assert.Assertions, expected int) bool {
|
||||
func setupBucket(name string, locking bool, versioning, quota, retention map[string]interface{}, assert *assert.Assertions, expected int) bool {
|
||||
return setupBucketForEndpoint(name, locking, versioning, quota, retention, assert, expected, nil, nil)
|
||||
}
|
||||
|
||||
func setupBucketForEndpoint(name string, locking, versioning bool, quota, retention map[string]interface{}, assert *assert.Assertions, expected int, endpoint, endpointToken *string) bool {
|
||||
func setupBucketForEndpoint(name string, locking bool, versioning, quota, retention map[string]interface{}, assert *assert.Assertions, expected int, endpoint, endpointToken *string) bool {
|
||||
/*
|
||||
The intention of this function is to return either true or false to
|
||||
reduce the code by performing the verification in one place only.
|
||||
@@ -751,7 +751,7 @@ func TestPutObjectsLegalholdStatus(t *testing.T) {
|
||||
status := "enabled"
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(bucketName, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -838,7 +838,7 @@ func TestGetBucketQuota(t *testing.T) {
|
||||
validBucket := "testgetbucketquota"
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(validBucket, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(validBucket, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -915,7 +915,7 @@ func TestPutBucketQuota(t *testing.T) {
|
||||
validBucket := "testputbucketquota"
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(validBucket, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(validBucket, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -974,7 +974,7 @@ func TestListBucketEvents(t *testing.T) {
|
||||
validBucket := "testlistbucketevents"
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(validBucket, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(validBucket, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1032,7 +1032,7 @@ func TestDeleteObjectsRetentionStatus(t *testing.T) {
|
||||
validPrefix := encodeBase64(fileName)
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(bucketName, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1139,7 +1139,7 @@ func TestBucketSetPolicy(t *testing.T) {
|
||||
validBucketName := "testbucketsetpolicy"
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(validBucketName, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(validBucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1200,7 +1200,7 @@ func TestRestoreObjectToASelectedVersion(t *testing.T) {
|
||||
validPrefix := encodeBase64(fileName)
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(bucketName, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1288,7 +1288,7 @@ func TestPutBucketsTags(t *testing.T) {
|
||||
// 1. Create the bucket
|
||||
assert := assert.New(t)
|
||||
validBucketName := "testputbuckettags1"
|
||||
if !setupBucket(validBucketName, false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket(validBucketName, false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1346,7 +1346,7 @@ func TestGetsTheMetadataOfAnObject(t *testing.T) {
|
||||
tags["tag"] = "testputobjecttagbucketonetagone"
|
||||
|
||||
// 1. Create the bucket
|
||||
if !setupBucket(bucketName, false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1417,7 +1417,7 @@ func TestPutObjectsRetentionStatus(t *testing.T) {
|
||||
prefix := encodeBase64(fileName)
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(bucketName, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1515,7 +1515,7 @@ func TestShareObjectOnURL(t *testing.T) {
|
||||
versionID := "null"
|
||||
|
||||
// 1. Create the bucket
|
||||
if !setupBucket(bucketName, false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1589,7 +1589,7 @@ func TestListObjects(t *testing.T) {
|
||||
fileName := "testlistobjecttobucket1.txt"
|
||||
|
||||
// 1. Create the bucket
|
||||
if !setupBucket(bucketName, false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1637,7 +1637,7 @@ func TestDeleteObject(t *testing.T) {
|
||||
numberOfFiles := 2
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket(bucketName, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1703,7 +1703,7 @@ func TestUploadObjectToBucket(t *testing.T) {
|
||||
fileName := "sample.txt"
|
||||
|
||||
// 1. Create the bucket
|
||||
if !setupBucket(bucketName, false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1738,7 +1738,7 @@ func TestDownloadObject(t *testing.T) {
|
||||
}
|
||||
|
||||
// 1. Create the bucket
|
||||
if !setupBucket(bucketName, true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1800,7 +1800,7 @@ func TestDeleteMultipleObjects(t *testing.T) {
|
||||
fileName := "testdeletemultipleobjs"
|
||||
|
||||
// 1. Create a bucket for this particular test
|
||||
if !setupBucket(bucketName, false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1877,7 +1877,7 @@ func TestPutObjectTag(t *testing.T) {
|
||||
versionID := "null"
|
||||
|
||||
// 1. Create the bucket
|
||||
if !setupBucket(bucketName, false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1951,7 +1951,7 @@ func TestBucketRetention(t *testing.T) {
|
||||
retention["mode"] = "compliance"
|
||||
retention["unit"] = "years"
|
||||
retention["validity"] = 2
|
||||
if !setupBucket("setbucketretention1", true, true, nil, retention, assert, 200) {
|
||||
if !setupBucket("setbucketretention1", true, map[string]interface{}{"enabled": true}, nil, retention, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2002,7 +2002,7 @@ func TestBucketInformationGenericErrorResponse(t *testing.T) {
|
||||
|
||||
// 1. Create the bucket
|
||||
assert := assert.New(t)
|
||||
if !setupBucket("bucketinformation2", false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket("bucketinformation2", false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2047,7 +2047,7 @@ func TestBucketInformationSuccessfulResponse(t *testing.T) {
|
||||
|
||||
// 1. Create the bucket
|
||||
assert := assert.New(t)
|
||||
if !setupBucket("bucketinformation1", false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket("bucketinformation1", false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2160,7 +2160,7 @@ func TestListBuckets(t *testing.T) {
|
||||
// 1. Create buckets
|
||||
numberOfBuckets := 3
|
||||
for i := 1; i <= numberOfBuckets; i++ {
|
||||
if !setupBucket("testlistbuckets"+strconv.Itoa(i), false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket("testlistbuckets"+strconv.Itoa(i), false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -2267,7 +2267,7 @@ func TestBucketVersioning(t *testing.T) {
|
||||
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
|
||||
if !setupBucket("test2", true, false, nil, nil, assert, 200) {
|
||||
if !setupBucket("test2", true, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2335,7 +2335,7 @@ func TestSetBucketTags(t *testing.T) {
|
||||
}
|
||||
|
||||
// put bucket
|
||||
if !setupBucket("test4", false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket("test4", false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2402,7 +2402,7 @@ func TestGetBucket(t *testing.T) {
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
|
||||
if !setupBucket("test3", false, false, nil, nil, assert, 200) {
|
||||
if !setupBucket("test3", false, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2455,7 +2455,7 @@ func TestAddBucket(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !setupBucket(tt.args.bucketName, false, false, nil, nil, assert, tt.expectedStatus) {
|
||||
if !setupBucket(tt.args.bucketName, false, nil, nil, nil, assert, tt.expectedStatus) {
|
||||
return
|
||||
}
|
||||
})
|
||||
@@ -3000,7 +3000,7 @@ func TestReturnsTheStatusOfObjectLockingSupportOnTheBucket(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func SetBucketVersioning(bucketName string, versioning bool, endpoint, useToken *string) (*http.Response, error) {
|
||||
func SetBucketVersioning(bucketName string, versioning map[string]interface{}, endpoint, useToken *string) (*http.Response, error) {
|
||||
/*
|
||||
Helper function to set Bucket Versioning
|
||||
*/
|
||||
@@ -3037,7 +3037,7 @@ func TestSetBucketVersioning(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
bucket := "test-set-bucket-versioning"
|
||||
locking := false
|
||||
versioning := true
|
||||
versioning := map[string]interface{}{"enabled": true}
|
||||
|
||||
// 1. Create bucket with versioning as true and locking as false
|
||||
if !setupBucket(bucket, locking, versioning, nil, nil, assert, 200) {
|
||||
@@ -3045,7 +3045,7 @@ func TestSetBucketVersioning(t *testing.T) {
|
||||
}
|
||||
|
||||
// 2. Set versioning as False i.e Suspend versioning
|
||||
response, err := SetBucketVersioning(bucket, false, nil, nil)
|
||||
response, err := SetBucketVersioning(bucket, map[string]interface{}{"enabled": false}, nil, nil)
|
||||
assert.Nil(err)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -3118,12 +3118,11 @@ func TestEnableBucketEncryption(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
bucketName := "test-enable-bucket-encryption"
|
||||
locking := false
|
||||
versioning := false
|
||||
encType := "sse-s3"
|
||||
kmsKeyID := ""
|
||||
|
||||
// 1. Add bucket
|
||||
if !setupBucket(bucketName, locking, versioning, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, locking, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3381,7 +3380,6 @@ func TestBucketLifeCycle(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
bucketName := "test-bucket-life-cycle"
|
||||
locking := false
|
||||
versioning := false
|
||||
ltype := "expiry"
|
||||
prefix := ""
|
||||
tags := ""
|
||||
@@ -3392,7 +3390,7 @@ func TestBucketLifeCycle(t *testing.T) {
|
||||
var noncurrentversionExpirationDays int64
|
||||
|
||||
// 1. Add bucket
|
||||
if !setupBucket(bucketName, locking, versioning, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, locking, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3597,12 +3595,11 @@ func TestAccessRule(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
bucketName := "test-access-rule-bucket"
|
||||
locking := false
|
||||
versioning := false
|
||||
prefix := "prefix"
|
||||
access := "readonly"
|
||||
|
||||
// 1. Add bucket
|
||||
if !setupBucket(bucketName, locking, versioning, nil, nil, assert, 200) {
|
||||
if !setupBucket(bucketName, locking, nil, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3846,16 +3843,16 @@ func TestAddRemoteBucket(t *testing.T) {
|
||||
fmt.Println("targetBucket: ", targetBucket)
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket("source", true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket("source", true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
// 1.1. Create target bucket
|
||||
targetEndpoint := "http://localhost:9092"
|
||||
targetToken := getTokenForEndpoint(targetEndpoint)
|
||||
if !setupBucketForEndpoint(targetBucket, true, true, nil, nil, assert, 200, &targetEndpoint, &targetToken) {
|
||||
if !setupBucketForEndpoint(targetBucket, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200, &targetEndpoint, &targetToken) {
|
||||
log.Println("bucket already exists")
|
||||
}
|
||||
_, err := SetBucketVersioning(targetBucket, false, &targetURL, &targetToken)
|
||||
_, err := SetBucketVersioning(targetBucket, map[string]interface{}{"enabled": false}, &targetURL, &targetToken)
|
||||
if err != nil {
|
||||
log.Println("bucket already has versioning")
|
||||
}
|
||||
@@ -3905,16 +3902,16 @@ func TestDeleteRemoteBucket(t *testing.T) {
|
||||
fmt.Println("targetBucket: ", targetBucket)
|
||||
|
||||
// 1. Create bucket
|
||||
if !setupBucket("deletesource", true, true, nil, nil, assert, 200) {
|
||||
if !setupBucket("deletesource", true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) {
|
||||
return
|
||||
}
|
||||
// 1.1. Create target bucket
|
||||
targetEndpoint := "http://localhost:9092"
|
||||
targetToken := getTokenForEndpoint(targetEndpoint)
|
||||
if !setupBucketForEndpoint(targetBucket, true, true, nil, nil, assert, 200, &targetEndpoint, &targetToken) {
|
||||
if !setupBucketForEndpoint(targetBucket, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200, &targetEndpoint, &targetToken) {
|
||||
log.Println("bucket already exists")
|
||||
}
|
||||
_, err := SetBucketVersioning(targetBucket, false, &targetURL, &targetToken)
|
||||
_, err := SetBucketVersioning(targetBucket, map[string]interface{}{"enabled": false}, &targetURL, &targetToken)
|
||||
if err != nil {
|
||||
log.Println("bucket already has versioning")
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ type MakeBucketRequest struct {
|
||||
Retention *PutBucketRetentionRequest `json:"retention,omitempty"`
|
||||
|
||||
// versioning
|
||||
Versioning bool `json:"versioning,omitempty"`
|
||||
Versioning *SetBucketVersioning `json:"versioning,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this make bucket request
|
||||
@@ -69,6 +69,10 @@ func (m *MakeBucketRequest) Validate(formats strfmt.Registry) error {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateVersioning(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
@@ -122,6 +126,25 @@ func (m *MakeBucketRequest) validateRetention(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MakeBucketRequest) validateVersioning(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.Versioning) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.Versioning != nil {
|
||||
if err := m.Versioning.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("versioning")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("versioning")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this make bucket request based on the context it is used
|
||||
func (m *MakeBucketRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
@@ -134,6 +157,10 @@ func (m *MakeBucketRequest) ContextValidate(ctx context.Context, formats strfmt.
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateVersioning(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
@@ -172,6 +199,22 @@ func (m *MakeBucketRequest) contextValidateRetention(ctx context.Context, format
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MakeBucketRequest) contextValidateVersioning(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Versioning != nil {
|
||||
if err := m.Versioning.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("versioning")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("versioning")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *MakeBucketRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
@@ -34,8 +34,14 @@ import (
|
||||
// swagger:model setBucketVersioning
|
||||
type SetBucketVersioning struct {
|
||||
|
||||
// versioning
|
||||
Versioning bool `json:"versioning,omitempty"`
|
||||
// enabled
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
|
||||
// exclude folders
|
||||
ExcludeFolders bool `json:"excludeFolders,omitempty"`
|
||||
|
||||
// exclude prefixes
|
||||
ExcludePrefixes []string `json:"excludePrefixes"`
|
||||
}
|
||||
|
||||
// Validate validates this set bucket versioning
|
||||
|
||||
@@ -126,7 +126,7 @@ export interface BucketObject {
|
||||
export interface MakeBucketRequest {
|
||||
name: string;
|
||||
locking?: boolean;
|
||||
versioning?: boolean;
|
||||
versioning?: SetBucketVersioning;
|
||||
quota?: SetBucketQuota;
|
||||
retention?: PutBucketRetentionRequest;
|
||||
}
|
||||
@@ -802,7 +802,10 @@ export interface BucketVersioningResponse {
|
||||
}
|
||||
|
||||
export interface SetBucketVersioning {
|
||||
versioning?: boolean;
|
||||
enabled?: boolean;
|
||||
/** @maxLength 10 */
|
||||
excludePrefixes?: string[];
|
||||
excludeFolders?: boolean;
|
||||
}
|
||||
|
||||
export interface BucketObLockingResponse {
|
||||
|
||||
@@ -407,6 +407,7 @@ const BucketSummary = () => {
|
||||
modalOpen={enableVersioningOpen}
|
||||
selectedBucket={bucketName}
|
||||
versioningInfo={versioningInfo}
|
||||
objectLockingEnabled={!!hasObjectLocking}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -581,6 +582,7 @@ const BucketSummary = () => {
|
||||
}
|
||||
onEdit={setBucketVersioning}
|
||||
isLoading={loadingVersioning}
|
||||
disabled={hasObjectLocking}
|
||||
/>
|
||||
|
||||
{versioningInfo?.status === "Enabled" ? (
|
||||
|
||||
@@ -15,32 +15,54 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useState } from "react";
|
||||
import { Box, ConfirmModalIcon } from "mds";
|
||||
import { Box, Button, FormLayout, ModalBox, Switch } from "mds";
|
||||
import { BucketVersioningResponse } from "api/consoleApi";
|
||||
import { api } from "api";
|
||||
import { errorToHandler } from "api/errors";
|
||||
import { setErrorSnackMessage } from "../../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../../store";
|
||||
import VersioningInfo from "../VersioningInfo";
|
||||
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
|
||||
import CSVMultiSelector from "../../Common/FormComponents/CSVMultiSelector/CSVMultiSelector";
|
||||
import { modalStyleUtils } from "../../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
interface IVersioningEventProps {
|
||||
closeVersioningModalAndRefresh: (refresh: boolean) => void;
|
||||
modalOpen: boolean;
|
||||
selectedBucket: string;
|
||||
versioningInfo: BucketVersioningResponse | undefined;
|
||||
objectLockingEnabled: boolean;
|
||||
}
|
||||
|
||||
const parseExcludedPrefixes = (
|
||||
bucketVersioning: BucketVersioningResponse | undefined,
|
||||
) => {
|
||||
const excludedPrefixes = bucketVersioning?.excludedPrefixes;
|
||||
|
||||
if (excludedPrefixes) {
|
||||
return excludedPrefixes.map((item) => item.prefix).join(",");
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
const EnableVersioningModal = ({
|
||||
closeVersioningModalAndRefresh,
|
||||
modalOpen,
|
||||
selectedBucket,
|
||||
versioningInfo = {},
|
||||
objectLockingEnabled,
|
||||
}: IVersioningEventProps) => {
|
||||
const isVersioningEnabled = versioningInfo.status === "Enabled";
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [versioningLoading, setVersioningLoading] = useState<boolean>(false);
|
||||
const [versionState, setVersionState] = useState<boolean>(
|
||||
versioningInfo?.status === "Enabled",
|
||||
);
|
||||
const [excludeFolders, setExcludeFolders] = useState<boolean>(
|
||||
!!versioningInfo?.excludeFolders,
|
||||
);
|
||||
const [excludedPrefixes, setExcludedPrefixes] = useState<string>(
|
||||
parseExcludedPrefixes(versioningInfo),
|
||||
);
|
||||
|
||||
const enableVersioning = () => {
|
||||
if (versioningLoading) {
|
||||
@@ -50,7 +72,11 @@ const EnableVersioningModal = ({
|
||||
|
||||
api.buckets
|
||||
.setBucketVersioning(selectedBucket, {
|
||||
versioning: !isVersioningEnabled,
|
||||
enabled: versionState,
|
||||
excludeFolders: versionState ? excludeFolders : false,
|
||||
excludePrefixes: versionState
|
||||
? excludedPrefixes.split(",").filter((item) => item.trim() !== "")
|
||||
: [],
|
||||
})
|
||||
.then(() => {
|
||||
setVersioningLoading(false);
|
||||
@@ -62,44 +88,76 @@ const EnableVersioningModal = ({
|
||||
});
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setExcludedPrefixes("");
|
||||
setExcludeFolders(false);
|
||||
setVersionState(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
<ModalBox
|
||||
onClose={() => closeVersioningModalAndRefresh(false)}
|
||||
open={modalOpen}
|
||||
title={`Versioning on Bucket`}
|
||||
confirmText={isVersioningEnabled ? "Suspend" : "Enable"}
|
||||
isOpen={modalOpen}
|
||||
isLoading={versioningLoading}
|
||||
titleIcon={<ConfirmModalIcon />}
|
||||
onConfirm={enableVersioning}
|
||||
confirmButtonProps={{
|
||||
variant: "callAction",
|
||||
}}
|
||||
onClose={() => {
|
||||
closeVersioningModalAndRefresh(false);
|
||||
}}
|
||||
confirmationContent={
|
||||
<Box id="alert-dialog-description">
|
||||
Are you sure you want to{" "}
|
||||
<strong>{isVersioningEnabled ? "suspend" : "enable"}</strong>{" "}
|
||||
versioning for this bucket?
|
||||
{isVersioningEnabled && (
|
||||
<Fragment>
|
||||
<br />
|
||||
<br />
|
||||
<strong>File versions won't be automatically deleted.</strong>
|
||||
</Fragment>
|
||||
)}
|
||||
<Box
|
||||
sx={{
|
||||
paddingTop: "20px",
|
||||
}}
|
||||
>
|
||||
{isVersioningEnabled ? (
|
||||
<VersioningInfo versioningState={versioningInfo} />
|
||||
) : null}
|
||||
</Box>
|
||||
>
|
||||
<FormLayout withBorders={false} containerPadding={false}>
|
||||
<Switch
|
||||
id={"activateVersioning"}
|
||||
label={"Versioning Status"}
|
||||
checked={versionState}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setVersionState(e.target.checked);
|
||||
}}
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
/>
|
||||
{versionState && !objectLockingEnabled && (
|
||||
<Fragment>
|
||||
<Switch
|
||||
id={"excludeFolders"}
|
||||
label={"Exclude Folders"}
|
||||
checked={excludeFolders}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setExcludeFolders(e.target.checked);
|
||||
}}
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
/>
|
||||
<CSVMultiSelector
|
||||
elements={excludedPrefixes}
|
||||
label={"Excluded Prefixes"}
|
||||
name={"excludedPrefixes"}
|
||||
onChange={(value: string | string[]) => {
|
||||
let valCh = "";
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
valCh = value.join(",");
|
||||
} else {
|
||||
valCh = value;
|
||||
}
|
||||
setExcludedPrefixes(valCh);
|
||||
}}
|
||||
withBorder={true}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
<Box sx={modalStyleUtils.modalButtonBar}>
|
||||
<Button
|
||||
id={"clear"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
color="primary"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
onClick={enableVersioning}
|
||||
id="saveTag"
|
||||
label={"Save"}
|
||||
/>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</FormLayout>
|
||||
</ModalBox>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box, ValuePair, ActionLink } from "mds";
|
||||
import { ActionLink, Box, ValuePair } from "mds";
|
||||
import { SecureComponent } from "../../../../../common/SecureComponent";
|
||||
|
||||
import EditActionButton from "./EditActionButton";
|
||||
@@ -28,6 +28,7 @@ type EditablePropertyItemProps = {
|
||||
value: any;
|
||||
onEdit: () => void;
|
||||
secureCmpProps?: Record<any, any>;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const SecureAction = ({
|
||||
@@ -61,6 +62,7 @@ const EditablePropertyItem = ({
|
||||
property = null,
|
||||
value = null,
|
||||
onEdit,
|
||||
disabled = false,
|
||||
}: EditablePropertyItemProps) => {
|
||||
return (
|
||||
<Box
|
||||
@@ -84,6 +86,7 @@ const EditablePropertyItem = ({
|
||||
onClick={onEdit}
|
||||
label={value}
|
||||
sx={{ fontWeight: "bold" }}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</SecureAction>
|
||||
}
|
||||
@@ -104,6 +107,7 @@ const EditablePropertyItem = ({
|
||||
height: "16px",
|
||||
},
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</SecureAction>
|
||||
</Box>
|
||||
|
||||
@@ -48,6 +48,8 @@ import SectionTitle from "../../../Common/SectionTitle";
|
||||
import {
|
||||
resetForm,
|
||||
setEnableObjectLocking,
|
||||
setExcludedPrefixes,
|
||||
setExcludeFolders,
|
||||
setIsDirty,
|
||||
setName,
|
||||
setQuota,
|
||||
@@ -77,6 +79,7 @@ import {
|
||||
} from "../../../../../api/consoleApi";
|
||||
import { errorToHandler } from "../../../../../api/errors";
|
||||
import HelpMenu from "../../../HelpMenu";
|
||||
import CSVMultiSelector from "../../../Common/FormComponents/CSVMultiSelector/CSVMultiSelector";
|
||||
|
||||
const ErrorBox = styled.div(({ theme }) => ({
|
||||
color: get(theme, "signalColors.danger", "#C51B3F"),
|
||||
@@ -102,6 +105,12 @@ const AddBucket = () => {
|
||||
const versioningEnabled = useSelector(
|
||||
(state: AppState) => state.addBucket.versioningEnabled,
|
||||
);
|
||||
const excludeFolders = useSelector(
|
||||
(state: AppState) => state.addBucket.excludeFolders,
|
||||
);
|
||||
const excludedPrefixes = useSelector(
|
||||
(state: AppState) => state.addBucket.excludedPrefixes,
|
||||
);
|
||||
const lockingEnabled = useSelector(
|
||||
(state: AppState) => state.addBucket.lockingEnabled,
|
||||
);
|
||||
@@ -346,6 +355,35 @@ const AddBucket = () => {
|
||||
)
|
||||
}
|
||||
/>
|
||||
{versioningEnabled && distributedSetup && !lockingEnabled && (
|
||||
<Fragment>
|
||||
<Switch
|
||||
id={"excludeFolders"}
|
||||
label={"Exclude Folders"}
|
||||
checked={excludeFolders}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(setExcludeFolders(e.target.checked));
|
||||
}}
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
/>
|
||||
<CSVMultiSelector
|
||||
elements={excludedPrefixes}
|
||||
label={"Excluded Prefixes"}
|
||||
name={"excludedPrefixes"}
|
||||
onChange={(value: string | string[]) => {
|
||||
let valCh = "";
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
valCh = value.join(",");
|
||||
} else {
|
||||
valCh = value;
|
||||
}
|
||||
dispatch(setExcludedPrefixes(valCh));
|
||||
}}
|
||||
withBorder={true}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
<Switch
|
||||
value="locking"
|
||||
id="locking"
|
||||
@@ -363,7 +401,11 @@ const AddBucket = () => {
|
||||
label={"Object Locking"}
|
||||
tooltip={
|
||||
lockingAllowed
|
||||
? ""
|
||||
? `${
|
||||
versioningEnabled
|
||||
? "Exclude Folders & Exclude Prefixes options will not be available if this option is enabled."
|
||||
: ""
|
||||
}`
|
||||
: permissionTooltipHelper(
|
||||
[
|
||||
IAM_SCOPES.S3_PUT_BUCKET_VERSIONING,
|
||||
|
||||
@@ -41,13 +41,25 @@ export const addBucketAsync = createAsyncThunk(
|
||||
const retentionValidity = state.addBucket.retentionValidity;
|
||||
const distributedSetup = state.system.distributedSetup;
|
||||
const siteReplicationInfo = state.system.siteReplicationInfo;
|
||||
const excludeFolders = state.addBucket.excludeFolders;
|
||||
const excludedPrefixes = state.addBucket.excludedPrefixes;
|
||||
|
||||
let request: MakeBucketRequest = {
|
||||
name: bucketName,
|
||||
versioning:
|
||||
distributedSetup && !siteReplicationInfo.enabled
|
||||
? versioningEnabled
|
||||
: false,
|
||||
versioning: {
|
||||
enabled:
|
||||
distributedSetup && !siteReplicationInfo.enabled
|
||||
? versioningEnabled
|
||||
: false,
|
||||
excludePrefixes:
|
||||
distributedSetup && !siteReplicationInfo.enabled && !lockingEnabled
|
||||
? excludedPrefixes.split(",").filter((item) => item.trim() !== "")
|
||||
: [],
|
||||
excludeFolders:
|
||||
distributedSetup && !siteReplicationInfo.enabled && !lockingEnabled
|
||||
? excludeFolders
|
||||
: false,
|
||||
},
|
||||
locking: distributedSetup ? lockingEnabled : false,
|
||||
};
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ export interface AddBucketState {
|
||||
retentionUnit: string;
|
||||
retentionValidity: number;
|
||||
navigateTo: string;
|
||||
excludeFolders: boolean;
|
||||
excludedPrefixes: string;
|
||||
}
|
||||
|
||||
const initialState: AddBucketState = {
|
||||
@@ -52,6 +54,8 @@ const initialState: AddBucketState = {
|
||||
retentionUnit: "days",
|
||||
retentionValidity: 180,
|
||||
navigateTo: "",
|
||||
excludeFolders: false,
|
||||
excludedPrefixes: "",
|
||||
};
|
||||
|
||||
export const addBucketsSlice = createSlice({
|
||||
@@ -81,6 +85,12 @@ export const addBucketsSlice = createSlice({
|
||||
state.retentionValidity = 180;
|
||||
}
|
||||
},
|
||||
setExcludeFolders: (state, action: PayloadAction<boolean>) => {
|
||||
state.excludeFolders = action.payload;
|
||||
},
|
||||
setExcludedPrefixes: (state, action: PayloadAction<string>) => {
|
||||
state.excludedPrefixes = action.payload;
|
||||
},
|
||||
setEnableObjectLocking: (state, action: PayloadAction<boolean>) => {
|
||||
state.lockingEnabled = action.payload;
|
||||
},
|
||||
@@ -196,6 +206,8 @@ export const {
|
||||
setRetentionMode,
|
||||
setRetentionUnit,
|
||||
setRetentionValidity,
|
||||
setExcludedPrefixes,
|
||||
setExcludeFolders,
|
||||
} = addBucketsSlice.actions;
|
||||
|
||||
export default addBucketsSlice.reducer;
|
||||
|
||||
@@ -20,16 +20,10 @@ import React, {
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
Fragment,
|
||||
} from "react";
|
||||
import get from "lodash/get";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { InputLabel, Tooltip } from "@mui/material";
|
||||
import { fieldBasic, tooltipHelper } from "../common/styleLibrary";
|
||||
import { AddIcon, HelpIcon } from "mds";
|
||||
import InputBoxWrapper from "../InputBoxWrapper/InputBoxWrapper";
|
||||
import { AddIcon, Box, HelpIcon, InputBox, InputLabel, Tooltip } from "mds";
|
||||
|
||||
interface ICSVMultiSelector {
|
||||
elements: string;
|
||||
@@ -37,37 +31,10 @@ interface ICSVMultiSelector {
|
||||
label: string;
|
||||
tooltip?: string;
|
||||
commonPlaceholder?: string;
|
||||
classes: any;
|
||||
withBorder?: boolean;
|
||||
onChange: (elements: string) => void;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) => {
|
||||
return createStyles({
|
||||
...fieldBasic,
|
||||
...tooltipHelper,
|
||||
inputWithBorder: {
|
||||
border: "1px solid #EAEAEA",
|
||||
padding: 15,
|
||||
height: 150,
|
||||
overflowY: "auto",
|
||||
position: "relative",
|
||||
marginTop: 15,
|
||||
flex: 1,
|
||||
},
|
||||
inputBoxSpacer: {
|
||||
marginBottom: 7,
|
||||
},
|
||||
inputLabel: {
|
||||
...fieldBasic.inputLabel,
|
||||
margin: 0,
|
||||
alignItems: "flex-start",
|
||||
paddingTop: "20px",
|
||||
minWidth: 162,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const CSVMultiSelector = ({
|
||||
elements,
|
||||
name,
|
||||
@@ -76,7 +43,6 @@ const CSVMultiSelector = ({
|
||||
commonPlaceholder = "",
|
||||
onChange,
|
||||
withBorder = false,
|
||||
classes,
|
||||
}: ICSVMultiSelector) => {
|
||||
const [currentElements, setCurrentElements] = useState<string[]>([""]);
|
||||
const bottomList = createRef<HTMLDivElement>();
|
||||
@@ -154,55 +120,65 @@ const CSVMultiSelector = ({
|
||||
|
||||
const inputs = currentElements.map((element, index) => {
|
||||
return (
|
||||
<div
|
||||
className={classes.inputBoxSpacer}
|
||||
<InputBox
|
||||
key={`csv-multi-${name}-${index.toString()}`}
|
||||
>
|
||||
<InputBoxWrapper
|
||||
id={`${name}-${index.toString()}`}
|
||||
label={""}
|
||||
name={`${name}-${index.toString()}`}
|
||||
value={currentElements[index]}
|
||||
onChange={onChangeElement}
|
||||
index={index}
|
||||
key={`csv-${name}-${index.toString()}`}
|
||||
placeholder={commonPlaceholder}
|
||||
overlayIcon={
|
||||
index === currentElements.length - 1 ? <AddIcon /> : null
|
||||
}
|
||||
overlayAction={() => {
|
||||
addEmptyLine(currentElements);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
id={`${name}-${index.toString()}`}
|
||||
label={""}
|
||||
name={`${name}-${index.toString()}`}
|
||||
value={currentElements[index]}
|
||||
onChange={onChangeElement}
|
||||
index={index}
|
||||
placeholder={commonPlaceholder}
|
||||
overlayIcon={index === currentElements.length - 1 ? <AddIcon /> : null}
|
||||
overlayAction={() => {
|
||||
addEmptyLine(currentElements);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.fieldContainer}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
<Fragment>
|
||||
<Box sx={{ display: "flex" }} className={"inputItem"}>
|
||||
<InputLabel
|
||||
sx={{
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
<span>{label}</span>
|
||||
{tooltip !== "" && (
|
||||
<div className={classes.tooltipContainer}>
|
||||
<Tooltip title={tooltip} placement="top-start">
|
||||
<div className={classes.tooltip}>
|
||||
<Box
|
||||
sx={{
|
||||
marginLeft: 5,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
"& .min-icon": {
|
||||
width: 13,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Tooltip tooltip={tooltip} placement="top">
|
||||
<Box className={tooltip}>
|
||||
<HelpIcon />
|
||||
</div>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
</InputLabel>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${withBorder ? classes.inputWithBorder : ""}`}
|
||||
<Box
|
||||
withBorders={withBorder}
|
||||
sx={{
|
||||
width: "100%",
|
||||
overflowY: "auto",
|
||||
height: 150,
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
{inputs}
|
||||
<div ref={bottomList} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
</Box>
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
export default withStyles(styles)(CSVMultiSelector);
|
||||
export default CSVMultiSelector;
|
||||
|
||||
@@ -232,7 +232,7 @@ type MCClient interface {
|
||||
list(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent
|
||||
get(ctx context.Context, opts mc.GetOptions) (io.ReadCloser, *probe.Error)
|
||||
shareDownload(ctx context.Context, versionID string, expires time.Duration) (string, *probe.Error)
|
||||
setVersioning(ctx context.Context, status string) *probe.Error
|
||||
setVersioning(ctx context.Context, status string, excludePrefix []string, excludeFolders bool) *probe.Error
|
||||
}
|
||||
|
||||
// Interface implementation
|
||||
@@ -265,8 +265,8 @@ func (c mcClient) deleteAllReplicationRules(ctx context.Context) *probe.Error {
|
||||
return c.client.RemoveReplication(ctx)
|
||||
}
|
||||
|
||||
func (c mcClient) setVersioning(ctx context.Context, status string) *probe.Error {
|
||||
return c.client.SetVersion(ctx, status, []string{}, false)
|
||||
func (c mcClient) setVersioning(ctx context.Context, status string, excludePrefix []string, excludeFolders bool) *probe.Error {
|
||||
return c.client.SetVersion(ctx, status, excludePrefix, excludeFolders)
|
||||
}
|
||||
|
||||
func (c mcClient) remove(ctx context.Context, isIncomplete, isRemoveBucket, isBypass, forceDelete bool, contentCh <-chan *mc.ClientContent) <-chan mc.RemoveResult {
|
||||
|
||||
@@ -7124,7 +7124,7 @@ func init() {
|
||||
"$ref": "#/definitions/putBucketRetentionRequest"
|
||||
},
|
||||
"versioning": {
|
||||
"type": "boolean"
|
||||
"$ref": "#/definitions/setBucketVersioning"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8195,8 +8195,18 @@ func init() {
|
||||
"setBucketVersioning": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"versioning": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeFolders": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludePrefixes": {
|
||||
"type": "array",
|
||||
"maxLength": 10,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -16257,7 +16267,7 @@ func init() {
|
||||
"$ref": "#/definitions/putBucketRetentionRequest"
|
||||
},
|
||||
"versioning": {
|
||||
"type": "boolean"
|
||||
"$ref": "#/definitions/setBucketVersioning"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -17328,8 +17338,18 @@ func init() {
|
||||
"setBucketVersioning": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"versioning": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeFolders": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludePrefixes": {
|
||||
"type": "array",
|
||||
"maxLength": 10,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -188,8 +188,8 @@ const (
|
||||
)
|
||||
|
||||
// removeBucket deletes a bucket
|
||||
func doSetVersioning(ctx context.Context, client MCClient, state VersionState) error {
|
||||
err := client.setVersioning(ctx, string(state))
|
||||
func doSetVersioning(ctx context.Context, client MCClient, state VersionState, excludePrefix []string, excludeFolders bool) error {
|
||||
err := client.setVersioning(ctx, string(state), excludePrefix, excludeFolders)
|
||||
if err != nil {
|
||||
return err.Cause
|
||||
}
|
||||
@@ -212,11 +212,19 @@ func setBucketVersioningResponse(session *models.Principal, params bucketApi.Set
|
||||
|
||||
versioningState := VersionSuspend
|
||||
|
||||
if params.Body.Versioning {
|
||||
if params.Body.Enabled {
|
||||
versioningState = VersionEnable
|
||||
}
|
||||
|
||||
if err := doSetVersioning(ctx, amcClient, versioningState); err != nil {
|
||||
var excludePrefixes []string
|
||||
|
||||
if params.Body.ExcludePrefixes != nil {
|
||||
excludePrefixes = params.Body.ExcludePrefixes
|
||||
}
|
||||
|
||||
excludeFolders := params.Body.ExcludeFolders
|
||||
|
||||
if err := doSetVersioning(ctx, amcClient, versioningState, excludePrefixes, excludeFolders); err != nil {
|
||||
return ErrorWithContext(ctx, fmt.Errorf("error setting versioning for bucket: %s", err))
|
||||
}
|
||||
return nil
|
||||
@@ -486,8 +494,14 @@ func getMakeBucketResponse(session *models.Principal, params bucketApi.MakeBucke
|
||||
}
|
||||
}()
|
||||
|
||||
versioningEnabled := false
|
||||
|
||||
if br.Versioning != nil && br.Versioning.Enabled {
|
||||
versioningEnabled = true
|
||||
}
|
||||
|
||||
// enable versioning if indicated or retention enabled
|
||||
if br.Versioning || br.Retention != nil {
|
||||
if versioningEnabled || br.Retention != nil {
|
||||
s3Client, err := newS3BucketClient(session, *br.Name, "", getClientIP(params.HTTPRequest))
|
||||
if err != nil {
|
||||
return nil, ErrorWithContext(ctx, err)
|
||||
@@ -496,7 +510,18 @@ func getMakeBucketResponse(session *models.Principal, params bucketApi.MakeBucke
|
||||
// defining the client to be used
|
||||
amcClient := mcClient{client: s3Client}
|
||||
|
||||
if err = doSetVersioning(ctx, amcClient, VersionEnable); err != nil {
|
||||
excludePrefixes := []string{}
|
||||
excludeFolders := false
|
||||
|
||||
if br.Versioning.ExcludeFolders && !br.Locking {
|
||||
excludeFolders = true
|
||||
}
|
||||
|
||||
if br.Versioning.ExcludePrefixes != nil && !br.Locking {
|
||||
excludePrefixes = br.Versioning.ExcludePrefixes
|
||||
}
|
||||
|
||||
if err = doSetVersioning(ctx, amcClient, VersionEnable, excludePrefixes, excludeFolders); err != nil {
|
||||
return nil, ErrorWithContext(ctx, fmt.Errorf("error setting versioning for bucket: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ var (
|
||||
minioSetObjectLockConfigMock func(ctx context.Context, bucketName string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit) error
|
||||
minioGetBucketObjectLockConfigMock func(ctx context.Context, bucketName string) (mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, err error)
|
||||
minioGetObjectLockConfigMock func(ctx context.Context, bucketName string) (lock string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, err error)
|
||||
minioSetVersioningMock func(ctx context.Context, state string) *probe.Error
|
||||
minioSetVersioningMock func(ctx context.Context, state string, excludePrefix []string, excludeFolders bool) *probe.Error
|
||||
minioCopyObjectMock func(ctx context.Context, dst minio.CopyDestOptions, src minio.CopySrcOptions) (minio.UploadInfo, error)
|
||||
minioSetBucketTaggingMock func(ctx context.Context, bucketName string, tags *tags.Tags) error
|
||||
minioRemoveBucketTaggingMock func(ctx context.Context, bucketName string) error
|
||||
@@ -112,8 +112,8 @@ func (mc minioClientMock) copyObject(ctx context.Context, dst minio.CopyDestOpti
|
||||
return minioCopyObjectMock(ctx, dst, src)
|
||||
}
|
||||
|
||||
func (c s3ClientMock) setVersioning(ctx context.Context, state string) *probe.Error {
|
||||
return minioSetVersioningMock(ctx, state)
|
||||
func (c s3ClientMock) setVersioning(ctx context.Context, state string, excludePrefix []string, excludeFolders bool) *probe.Error {
|
||||
return minioSetVersioningMock(ctx, state, excludePrefix, excludeFolders)
|
||||
}
|
||||
|
||||
func (mc minioClientMock) GetBucketTagging(ctx context.Context, bucketName string) (*tags.Tags, error) {
|
||||
@@ -813,9 +813,11 @@ func Test_SetBucketVersioning(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
state VersionState
|
||||
excludePrefix []string
|
||||
excludeFolders bool
|
||||
bucketName string
|
||||
client s3ClientMock
|
||||
setVersioningFunc func(ctx context.Context, state string) *probe.Error
|
||||
setVersioningFunc func(ctx context.Context, state string, excludePrefix []string, excludeFolders bool) *probe.Error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -829,7 +831,36 @@ func Test_SetBucketVersioning(t *testing.T) {
|
||||
state: VersionEnable,
|
||||
bucketName: "test",
|
||||
client: minClient,
|
||||
setVersioningFunc: func(ctx context.Context, state string) *probe.Error {
|
||||
setVersioningFunc: func(ctx context.Context, state string, excludePrefix []string, excludeFolders bool) *probe.Error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Bucket Version with Prefixes Success",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
state: VersionEnable,
|
||||
excludePrefix: []string{"prefix1", "prefix2"},
|
||||
bucketName: "test",
|
||||
client: minClient,
|
||||
setVersioningFunc: func(ctx context.Context, state string, excludePrefix []string, excludeFolders bool) *probe.Error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Bucket Version with Excluded Folders Success",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
state: VersionEnable,
|
||||
excludePrefix: []string{"prefix1", "prefix2"},
|
||||
excludeFolders: true,
|
||||
bucketName: "test",
|
||||
client: minClient,
|
||||
setVersioningFunc: func(ctx context.Context, state string, excludePrefix []string, excludeFolders bool) *probe.Error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
@@ -842,7 +873,7 @@ func Test_SetBucketVersioning(t *testing.T) {
|
||||
state: VersionEnable,
|
||||
bucketName: "test",
|
||||
client: minClient,
|
||||
setVersioningFunc: func(ctx context.Context, state string) *probe.Error {
|
||||
setVersioningFunc: func(ctx context.Context, state string, excludePrefix []string, excludeFolders bool) *probe.Error {
|
||||
return probe.NewError(errors.New(errorMsg))
|
||||
},
|
||||
},
|
||||
@@ -854,7 +885,7 @@ func Test_SetBucketVersioning(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
minioSetVersioningMock = tt.args.setVersioningFunc
|
||||
|
||||
err := doSetVersioning(tt.args.ctx, tt.args.client, tt.args.state)
|
||||
err := doSetVersioning(tt.args.ctx, tt.args.client, tt.args.state, tt.args.excludePrefix, tt.args.excludeFolders)
|
||||
|
||||
fmt.Println(t.Name())
|
||||
fmt.Println("Expected:", tt.expectedError, "Error:", err)
|
||||
|
||||
14
swagger.yml
14
swagger.yml
@@ -3756,7 +3756,7 @@ definitions:
|
||||
locking:
|
||||
type: boolean
|
||||
versioning:
|
||||
type: boolean
|
||||
$ref: "#/definitions/setBucketVersioning"
|
||||
quota:
|
||||
$ref: "#/definitions/setBucketQuota"
|
||||
retention:
|
||||
@@ -4963,8 +4963,16 @@ definitions:
|
||||
setBucketVersioning:
|
||||
type: object
|
||||
properties:
|
||||
versioning:
|
||||
enabled:
|
||||
type: boolean
|
||||
excludePrefixes:
|
||||
type: array
|
||||
maxLength: 10
|
||||
items:
|
||||
type: string
|
||||
excludeFolders:
|
||||
type: boolean
|
||||
|
||||
bucketObLockingResponse:
|
||||
type: object
|
||||
properties:
|
||||
@@ -6154,4 +6162,4 @@ definitions:
|
||||
groups:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
type: string
|
||||
|
||||
Reference in New Issue
Block a user