aboutsummaryrefslogtreecommitdiff
path: root/garage.go
diff options
context:
space:
mode:
authorQuentin <quentin@dufour.io>2023-09-26 06:44:36 +0000
committerQuentin <quentin@dufour.io>2023-09-26 06:44:36 +0000
commit49d8e81fbea0d4703a33e87a807927169a8060ac (patch)
treed0b655454d5e13ed2238060fee27fc0d951d64c8 /garage.go
parent1e75c21b65021da0c3c5a8be9be12114a2327464 (diff)
parent706ff58a6f6608719feda15075d50f978df39c5b (diff)
downloadguichet-49d8e81fbea0d4703a33e87a807927169a8060ac.tar.gz
guichet-49d8e81fbea0d4703a33e87a807927169a8060ac.zip
Merge pull request 'An API for Guichet' (#23) from api into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/guichet/pulls/23
Diffstat (limited to 'garage.go')
-rw-r--r--garage.go242
1 files changed, 144 insertions, 98 deletions
diff --git a/garage.go b/garage.go
index 1ae02e4..c43fd5f 100644
--- a/garage.go
+++ b/garage.go
@@ -2,10 +2,8 @@ package main
import (
"context"
- "errors"
"fmt"
garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
- "github.com/go-ldap/ldap/v3"
"github.com/gorilla/mux"
"log"
"net/http"
@@ -48,7 +46,7 @@ func grgGetKey(accessKey string) (*garage.KeyInfo, error) {
return resp, nil
}
-func grgCreateWebsite(gkey, bucket string) (*garage.BucketInfo, error) {
+func grgCreateBucket(bucket string) (*garage.BucketInfo, error) {
client, ctx := gadmin()
br := garage.NewCreateBucketRequest()
@@ -60,34 +58,40 @@ func grgCreateWebsite(gkey, bucket string) (*garage.BucketInfo, error) {
fmt.Printf("%+v\n", err)
return nil, err
}
+ return binfo, nil
+}
+
+func grgAllowKeyOnBucket(bid, gkey string) (*garage.BucketInfo, error) {
+ client, ctx := gadmin()
// Allow user's key
ar := garage.AllowBucketKeyRequest{
- BucketId: *binfo.Id,
+ BucketId: bid,
AccessKeyId: gkey,
Permissions: *garage.NewAllowBucketKeyRequestPermissions(true, true, true),
}
- binfo, _, err = client.BucketApi.AllowBucketKey(ctx).AllowBucketKeyRequest(ar).Execute()
+ binfo, _, err := client.BucketApi.AllowBucketKey(ctx).AllowBucketKeyRequest(ar).Execute()
if err != nil {
fmt.Printf("%+v\n", err)
return nil, err
}
- // Expose website and set quota
+ return binfo, nil
+}
+
+func allowWebsiteDefault() *garage.UpdateBucketRequestWebsiteAccess {
wr := garage.NewUpdateBucketRequestWebsiteAccess()
wr.SetEnabled(true)
wr.SetIndexDocument("index.html")
wr.SetErrorDocument("error.html")
- qr := garage.NewUpdateBucketRequestQuotas()
- qr.SetMaxSize(1024 * 1024 * 50) // 50MB
- qr.SetMaxObjects(10000) //10k objects
+ return wr
+}
- ur := garage.NewUpdateBucketRequest()
- ur.SetWebsiteAccess(*wr)
- ur.SetQuotas(*qr)
+func grgUpdateBucket(bid string, ur *garage.UpdateBucketRequest) (*garage.BucketInfo, error) {
+ client, ctx := gadmin()
- binfo, _, err = client.BucketApi.UpdateBucket(ctx, *binfo.Id).UpdateBucketRequest(*ur).Execute()
+ binfo, _, err := client.BucketApi.UpdateBucket(ctx, bid).UpdateBucketRequest(*ur).Execute()
if err != nil {
fmt.Printf("%+v\n", err)
return nil, err
@@ -97,155 +101,197 @@ func grgCreateWebsite(gkey, bucket string) (*garage.BucketInfo, error) {
return binfo, nil
}
-func grgGetBucket(bid string) (*garage.BucketInfo, error) {
+func grgAddGlobalAlias(bid, alias string) (*garage.BucketInfo, error) {
client, ctx := gadmin()
- resp, _, err := client.BucketApi.GetBucketInfo(ctx, bid).Execute()
+ resp, _, err := client.BucketApi.PutBucketGlobalAlias(ctx).Id(bid).Alias(alias).Execute()
if err != nil {
- fmt.Printf("%+v\n", err)
+ log.Println(err)
return nil, err
}
return resp, nil
+}
+func grgAddLocalAlias(bid, key, alias string) (*garage.BucketInfo, error) {
+ client, ctx := gadmin()
+
+ resp, _, err := client.BucketApi.PutBucketLocalAlias(ctx).Id(bid).AccessKeyId(key).Alias(alias).Execute()
+ if err != nil {
+ log.Println(err)
+ return nil, err
+ }
+ return resp, nil
}
-func checkLoginAndS3(w http.ResponseWriter, r *http.Request) (*LoginStatus, *garage.KeyInfo, error) {
- login := checkLogin(w, r)
- if login == nil {
- return nil, nil, errors.New("LDAP login failed")
+func grgDelGlobalAlias(bid, alias string) (*garage.BucketInfo, error) {
+ client, ctx := gadmin()
+
+ resp, _, err := client.BucketApi.DeleteBucketGlobalAlias(ctx).Id(bid).Alias(alias).Execute()
+ if err != nil {
+ log.Println(err)
+ return nil, err
}
+ return resp, nil
+}
- keyID := login.UserEntry.GetAttributeValue("garage_s3_access_key")
- if keyID == "" {
- keyPair, err := grgCreateKey(login.Info.Username)
- if err != nil {
- return login, nil, err
- }
- modify_request := ldap.NewModifyRequest(login.Info.DN, nil)
- modify_request.Replace("garage_s3_access_key", []string{*keyPair.AccessKeyId})
- // @FIXME compatibility feature for bagage (SFTP+webdav)
- // you can remove it once bagage will be updated to fetch the key from garage directly
- // or when bottin will be able to dynamically fetch it.
- modify_request.Replace("garage_s3_secret_key", []string{*keyPair.SecretAccessKey})
- err = login.conn.Modify(modify_request)
- return login, keyPair, err
+func grgDelLocalAlias(bid, key, alias string) (*garage.BucketInfo, error) {
+ client, ctx := gadmin()
+
+ resp, _, err := client.BucketApi.DeleteBucketLocalAlias(ctx).Id(bid).AccessKeyId(key).Alias(alias).Execute()
+ if err != nil {
+ log.Println(err)
+ return nil, err
}
- // Note: we could simply return the login info, but LX asked we do not
- // store the secrets in LDAP in the future.
- keyPair, err := grgGetKey(keyID)
- return login, keyPair, err
+ return resp, nil
}
-type keyView struct {
- Status *LoginStatus
- Key *garage.KeyInfo
+func grgGetBucket(bid string) (*garage.BucketInfo, error) {
+ client, ctx := gadmin()
+
+ resp, _, err := client.BucketApi.GetBucketInfo(ctx, bid).Execute()
+ if err != nil {
+ log.Println(err)
+ return nil, err
+ }
+ return resp, nil
+
}
-func handleGarageKey(w http.ResponseWriter, r *http.Request) {
- login, s3key, err := checkLoginAndS3(w, r)
+func grgDeleteBucket(bid string) error {
+ client, ctx := gadmin()
+
+ _, err := client.BucketApi.DeleteBucket(ctx, bid).Execute()
if err != nil {
log.Println(err)
+ }
+ return err
+}
+
+// --- Start page rendering functions
+
+func handleWebsiteConfigure(w http.ResponseWriter, r *http.Request) {
+ user := RequireUserHtml(w, r)
+ if user == nil {
return
}
- view := keyView{Status: login, Key: s3key}
tKey := getTemplate("garage_key.html")
- tKey.Execute(w, &view)
+ tKey.Execute(w, user)
}
-type webListView struct {
- Status *LoginStatus
- Key *garage.KeyInfo
-}
+func handleWebsiteList(w http.ResponseWriter, r *http.Request) {
+ user := RequireUserHtml(w, r)
+ if user == nil {
+ return
+ }
-func handleGarageWebsiteList(w http.ResponseWriter, r *http.Request) {
- login, s3key, err := checkLoginAndS3(w, r)
+ ctrl, err := NewWebsiteController(user)
if err != nil {
- log.Println(err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- view := webListView{Status: login, Key: s3key}
- tWebsiteList := getTemplate("garage_website_list.html")
- tWebsiteList.Execute(w, &view)
+ if len(ctrl.PrettyList) > 0 {
+ http.Redirect(w, r, "/website/inspect/"+ctrl.PrettyList[0], http.StatusFound)
+ } else {
+ http.Redirect(w, r, "/website/new", http.StatusFound)
+ }
+}
+
+type WebsiteNewTpl struct {
+ Ctrl *WebsiteController
+ Err error
}
-func handleGarageWebsiteNew(w http.ResponseWriter, r *http.Request) {
- _, s3key, err := checkLoginAndS3(w, r)
+func handleWebsiteNew(w http.ResponseWriter, r *http.Request) {
+ user := RequireUserHtml(w, r)
+ if user == nil {
+ return
+ }
+
+ ctrl, err := NewWebsiteController(user)
if err != nil {
- log.Println(err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
+ tpl := &WebsiteNewTpl{ctrl, nil}
+
tWebsiteNew := getTemplate("garage_website_new.html")
if r.Method == "POST" {
r.ParseForm()
- log.Println(r.Form)
bucket := strings.Join(r.Form["bucket"], "")
if bucket == "" {
bucket = strings.Join(r.Form["bucket2"], "")
}
- if bucket == "" {
- log.Println("Form empty")
- // @FIXME we need to return the error to the user
- tWebsiteNew.Execute(w, nil)
- return
- }
- binfo, err := grgCreateWebsite(*s3key.AccessKeyId, bucket)
+ view, err := ctrl.Create(bucket)
if err != nil {
- log.Println(err)
- // @FIXME we need to return the error to the user
- tWebsiteNew.Execute(w, nil)
+ tpl.Err = err
+ tWebsiteNew.Execute(w, tpl)
return
}
- http.Redirect(w, r, "/garage/website/b/"+*binfo.Id, http.StatusFound)
+ http.Redirect(w, r, "/website/inspect/"+view.Name.Pretty, http.StatusFound)
return
}
- tWebsiteNew.Execute(w, nil)
+ tWebsiteNew.Execute(w, tpl)
}
-type webInspectView struct {
- Status *LoginStatus
- Key *garage.KeyInfo
- Bucket *garage.BucketInfo
- IndexDoc string
- ErrorDoc string
- MaxObjects int64
- MaxSize int64
- UsedSizePct float64
+type WebsiteInspectTpl struct {
+ Describe *WebsiteDescribe
+ View *WebsiteView
+ Err error
}
-func handleGarageWebsiteInspect(w http.ResponseWriter, r *http.Request) {
- login, s3key, err := checkLoginAndS3(w, r)
- if err != nil {
- log.Println(err)
+func handleWebsiteInspect(w http.ResponseWriter, r *http.Request) {
+ var processErr error
+
+ user := RequireUserHtml(w, r)
+ if user == nil {
return
}
- bucketId := mux.Vars(r)["bucket"]
- binfo, err := grgGetBucket(bucketId)
+ ctrl, err := NewWebsiteController(user)
if err != nil {
- log.Println(err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- wc := binfo.GetWebsiteConfig()
- q := binfo.GetQuotas()
+ bucketName := mux.Vars(r)["bucket"]
- view := webInspectView{
- Status: login,
- Key: s3key,
- Bucket: binfo,
- IndexDoc: (&wc).GetIndexDocument(),
- ErrorDoc: (&wc).GetErrorDocument(),
- MaxObjects: (&q).GetMaxObjects(),
- MaxSize: (&q).GetMaxSize(),
+ if r.Method == "POST" {
+ r.ParseForm()
+ action := strings.Join(r.Form["action"], "")
+ switch action {
+ case "increase_quota":
+ _, processErr = ctrl.Patch(bucketName, &WebsitePatch{Size: &user.Quota.WebsiteSizeBursted})
+ case "delete_bucket":
+ processErr = ctrl.Delete(bucketName)
+ http.Redirect(w, r, "/website", http.StatusFound)
+ return
+ default:
+ processErr = fmt.Errorf("Unknown action")
+ }
+
+ }
+
+ view, err := ctrl.Inspect(bucketName)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
}
+ describe, err := ctrl.Describe()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ tpl := &WebsiteInspectTpl{describe, view, processErr}
+
tWebsiteInspect := getTemplate("garage_website_inspect.html")
- tWebsiteInspect.Execute(w, &view)
+ tWebsiteInspect.Execute(w, &tpl)
}