package main import ( //"context" "errors" "encoding/json" garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang" "github.com/gorilla/mux" "log" "net/http" ) type ApiQuotaView struct { files *uint64 size *uint64 } type ApiBucketView struct { global *bool max *ApiQuotaView used *ApiQuotaView } type BucketRequest struct { s3key *garage.KeyInfo bucketName string bucketId string global bool http *http.Request } func handleAPIWebsite(w http.ResponseWriter, r *http.Request) { br, err := buildBucketRequest(w, r) if err != nil { return } if r.Method == http.MethodPatch { patchGarageBucket(w, br) return } if r.Method == http.MethodGet { getGarageBucket(w, br) return } http.Error(w, "This method is not implemented for this endpoint", http.StatusNotImplemented) return } func buildBucketRequest(w http.ResponseWriter, r *http.Request) (*BucketRequest, error) { user := RequireUserApi(w, r) if user == nil { return nil, errors.New("Unable to fetch user") } // FETCH BUCKET ID by iterating over buckets owned by this key bucketName := mux.Vars(r)["bucket"] var bucketId *string var global *bool s3key, err := user.S3KeyInfo() if err != nil { return nil, err } findBucketIdLoop: for _, bucket := range s3key.Buckets { for _, localAlias := range bucket.LocalAliases { if localAlias == bucketName { bucketId = bucket.Id *global = false break findBucketIdLoop } } for _, globalAlias := range bucket.GlobalAliases { if globalAlias == bucketName { bucketId = bucket.Id *global = true break findBucketIdLoop } } } if bucketId == nil || global == nil { http.Error(w, "Bucket not found in this account", http.StatusNotFound) return nil, errors.New("Unable to fetch bucket ID") } return &BucketRequest{ s3key: s3key, bucketName: bucketName, bucketId: *bucketId, global: *global, http: r, }, nil } func patchGarageBucket(w http.ResponseWriter, br *BucketRequest) { var err error // DECODE BODY var queuedChange ApiBucketView decoder := json.NewDecoder(br.http.Body) err = decoder.Decode(&queuedChange) if err != nil { log.Println(err) http.Error(w, "Unable to decode the body", http.StatusBadRequest) return } // SET THE GLOBAL FLAG if queuedChange.global != nil { if *queuedChange.global && !br.global { _, err = grgAddGlobalAlias(br.bucketId, br.bucketName) if err != nil { http.Error(w, "Unable to add the requested name as global alias for this bucket", http.StatusInternalServerError) return } _, err = grgDelLocalAlias(br.bucketId, *br.s3key.AccessKeyId, br.bucketName) if err != nil { http.Error(w, "Unable to remove the local alias for this bucket", http.StatusInternalServerError) return } } else if !*queuedChange.global && br.global { grgAddLocalAlias(br.bucketId, *br.s3key.AccessKeyId, br.bucketName) if err != nil { http.Error(w, "Unable to add the requested name as local alias for this bucket", http.StatusInternalServerError) return } grgDelGlobalAlias(br.bucketId, br.bucketName) if err != nil { http.Error(w, "Unable to remove the global alias for this bucket", http.StatusInternalServerError) return } } } // CHECK IF QUOTA MUST BE ADDED TO THIS BUCKET // VALIDATE IT // --- global --- // 1. can be true, false, or nil (use pointers) // 2. if nil do nothing // 3. if false, throw "not yet implemented" (501) // 4. if true, check that the bucket name does not exist yet in the global namespace, throw "forbidden" (403) // --- quota.size --- // 1. if no quota on the bucket + this field is none, set to 50MB // 2. if lower than 50MB, set to 50MB. If higher than 200MB, set to 200MB // --- quota.files --- // 1. if no quota on the bucket + this field is none, set to 10k // 2. if lower than 10k, set to 10k. If higher than 40k, set to 40k // READ BODY JSON // IF BODY.GLOBAL is not NONE // DO: Add an alias // IF BODY.QUOTA.SIZE is not NONE // DO: Change quota // IF BODY.QUOTA.FILE is not NONE // DO: Change quota getGarageBucket(w, br) } func getGarageBucket(w http.ResponseWriter, br *BucketRequest) { // FETCH AN UPDATED BUCKET VIEW bucket, err := grgGetBucket(br.bucketId) if err != nil { http.Error(w, "Unable to fetch bucket details", http.StatusInternalServerError) return } // BUILD A VIEW log.Println(bucket) }