From 08287375736a0a57c03b4bd6d9c222dc5567db6e Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Mon, 25 Sep 2023 22:00:46 +0200 Subject: patch and delete with quota are now implemented --- garage.go | 45 +++++++++++--- quotas.go | 71 ++++++++++++++++++++++ templates/garage_website_inspect.html | 34 +++++++++-- templates/garage_website_new.html | 13 +++- website.go | 111 +++++++++++++++++++--------------- 5 files changed, 210 insertions(+), 64 deletions(-) diff --git a/garage.go b/garage.go index 8c8633f..d3d4d38 100644 --- a/garage.go +++ b/garage.go @@ -160,6 +160,16 @@ func grgGetBucket(bid string) (*garage.BucketInfo, error) { } +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) { @@ -193,8 +203,8 @@ func handleWebsiteList(w http.ResponseWriter, r *http.Request) { } type WebsiteNewTpl struct { - ctrl *WebsiteController - err error + Ctrl *WebsiteController + Err error } func handleWebsiteNew(w http.ResponseWriter, r *http.Request) { @@ -209,10 +219,7 @@ func handleWebsiteNew(w http.ResponseWriter, r *http.Request) { return } - tpl := &WebsiteNewTpl{ - ctrl: ctrl, - err: nil, - } + tpl := &WebsiteNewTpl{ctrl, nil} tWebsiteNew := getTemplate("garage_website_new.html") if r.Method == "POST" { @@ -225,23 +232,27 @@ func handleWebsiteNew(w http.ResponseWriter, r *http.Request) { view, err := ctrl.Create(bucket) if err != nil { - tpl.err = err + tpl.Err = err tWebsiteNew.Execute(w, tpl) + return } http.Redirect(w, r, "/website/inspect/"+view.Name.Pretty, http.StatusFound) return } - tWebsiteNew.Execute(w, nil) + tWebsiteNew.Execute(w, tpl) } type WebsiteInspectTpl struct { Ctrl *WebsiteController View *WebsiteView + Err error } func handleWebsiteInspect(w http.ResponseWriter, r *http.Request) { + var processErr error + user := RequireUserHtml(w, r) if user == nil { return @@ -254,6 +265,22 @@ func handleWebsiteInspect(w http.ResponseWriter, r *http.Request) { } bucketName := mux.Vars(r)["bucket"] + + 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 { @@ -261,7 +288,7 @@ func handleWebsiteInspect(w http.ResponseWriter, r *http.Request) { return } - tpl := &WebsiteInspectTpl{ ctrl, view } + tpl := &WebsiteInspectTpl{ ctrl, view, processErr } tWebsiteInspect := getTemplate("garage_website_inspect.html") tWebsiteInspect.Execute(w, &tpl) diff --git a/quotas.go b/quotas.go index 3eec9b8..9a2e426 100644 --- a/quotas.go +++ b/quotas.go @@ -77,3 +77,74 @@ func (q *UserQuota) DefaultWebsiteQuota() *garage.UpdateBucketRequestQuotas { return qr } + +func (q *UserQuota) WebsiteSizeAdjust(sz int64) int64 { + if sz < q.WebsiteSizeDefault { + return q.WebsiteSizeDefault + } else if sz > q.WebsiteSizeBursted { + return q.WebsiteSizeBursted + } else { + return sz + } +} + +func (q *UserQuota) WebsiteObjectAdjust(objs int64) int64 { + if objs > q.WebsiteObjects || objs <= 0 { + return q.WebsiteObjects + } else { + return objs + } +} + +func (q *UserQuota) WebsiteSizeBurstedPretty() string { + return prettyValue(q.WebsiteSizeBursted) +} + +// --- A quota stat we can use +type QuotaStat struct { + Current int64 + Max int64 + Ratio float64 + Burstable bool +} +func NewQuotaStat(current, max int64, burstable bool) QuotaStat { + return QuotaStat { + Current: current, + Max: max, + Ratio: float64(current) / float64(max), + Burstable: burstable, + } +} +func (q *QuotaStat) IsFull() bool { + return q.Current >= q.Max +} +func (q *QuotaStat) Percent() int64 { + return int64(q.Ratio * 100) +} + +func (q *QuotaStat) PrettyCurrent() string { + return prettyValue(q.Current) +} +func (q *QuotaStat) PrettyMax() string { + return prettyValue(q.Max) +} + +func prettyValue(v int64) string { + if v < 1024 { + return fmt.Sprintf("%d octets", v) + } + v = v / 1024 + if v < 1024 { + return fmt.Sprintf("%d kio", v) + } + v = v / 1024 + if v < 1024 { + return fmt.Sprintf("%d Mio", v) + } + v = v / 1024 + if v < 1024 { + return fmt.Sprintf("%d Gio", v) + } + v = v / 1024 + return fmt.Sprintf("%d Tio", v) +} diff --git a/templates/garage_website_inspect.html b/templates/garage_website_inspect.html index d5f48c2..c062ab9 100644 --- a/templates/garage_website_inspect.html +++ b/templates/garage_website_inspect.html @@ -2,15 +2,27 @@ {{define "body"}}
- Nouveau site web Mes identifiants Menu principal
-
-
-
+
+ {{ if .Err }} +
+
{{ .Err.Error }}
+
+ {{ end }} + +
+ + + + + Nouveau site web + + +
{{ $view := .View }} {{ range $wid := .Ctrl.List }} {{ if eq $wid.Internal $view.Name.Internal }} @@ -24,6 +36,11 @@ {{ end }} {{ end }}
+ +

+ {{ .Ctrl.WebsiteCount.Current }} sites créés sur {{ .Ctrl.WebsiteCount.Max }}
+ Jusqu'à {{ .Ctrl.User.Quota.WebsiteSizeBurstedPretty }} par site web +

{{ .View.Name.Url }}

@@ -42,6 +59,15 @@ {{ end }}

+
Actions
+
+
+ + Changer le nom de domaine + +
+
+ {{ if .View.Name.Expanded }}
Vous ne savez pas comment configurer votre nom de domaine ?
diff --git a/templates/garage_website_new.html b/templates/garage_website_new.html index f1cd847..7ee4936 100644 --- a/templates/garage_website_new.html +++ b/templates/garage_website_new.html @@ -3,8 +3,16 @@ {{define "body"}} + +
+
+ {{if .Err}} +
{{ .Err.Error }}
+ {{end}} +
+
diff --git a/website.go b/website.go index c06ccbc..6e86b19 100644 --- a/website.go +++ b/website.go @@ -15,55 +15,11 @@ var ( ErrCantCreateBucket = fmt.Errorf("Can't create this bucket. Maybe another bucket already exists with this name or you have an invalid character") ErrCantAllowKey = fmt.Errorf("Can't allow given key on the target bucket") ErrCantConfigureBucket = fmt.Errorf("Unable to configure the bucket (activating website, adding quotas, etc.)") + ErrBucketDeleteNotEmpty = fmt.Errorf("You must remove all the files before deleting a bucket") + ErrBucketDeleteUnfinishedUpload = fmt.Errorf("You must remove all the unfinished multipart uploads before deleting a bucket") ) -type QuotaStat struct { - Current int64 - Max int64 - Ratio float64 - Burstable bool -} -func NewQuotaStat(current, max int64, burstable bool) QuotaStat { - return QuotaStat { - Current: current, - Max: max, - Ratio: float64(current) / float64(max), - Burstable: burstable, - } -} -func (q *QuotaStat) IsFull() bool { - return q.Current >= q.Max -} -func (q *QuotaStat) Percent() int64 { - return int64(q.Ratio * 100) -} -func (q *QuotaStat) PrettyCurrent() string { - return prettyValue(q.Current) -} -func (q *QuotaStat) PrettyMax() string { - return prettyValue(q.Max) -} - -func prettyValue(v int64) string { - if v < 1024 { - return fmt.Sprintf("%d octets", v) - } - v = v / 1024 - if v < 1024 { - return fmt.Sprintf("%d kio", v) - } - v = v / 1024 - if v < 1024 { - return fmt.Sprintf("%d Mio", v) - } - v = v / 1024 - if v < 1024 { - return fmt.Sprintf("%d Gio", v) - } - v = v / 1024 - return fmt.Sprintf("%d Tio", v) -} type WebsiteId struct { Pretty string @@ -146,8 +102,36 @@ func (w *WebsiteController) Inspect(pretty string) (*WebsiteView, error) { return NewWebsiteView(binfo), nil } -func (w *WebsiteController) Patch(patch *WebsitePatch) (*WebsiteView, error) { - return nil, nil +func (w *WebsiteController) Patch(pretty string, patch *WebsitePatch) (*WebsiteView, error) { + website, ok := w.WebsiteIdx[pretty] + if !ok { + return nil, ErrWebsiteNotFound + } + + binfo, err := grgGetBucket(website.Internal) + if err != nil { + return nil, ErrFetchBucketInfo + } + + // Patch the max size + urQuota := garage.NewUpdateBucketRequestQuotas() + urQuota.SetMaxSize(w.User.Quota.WebsiteSizeAdjust(binfo.Quotas.GetMaxSize())) + urQuota.SetMaxObjects(w.User.Quota.WebsiteObjectAdjust(binfo.Quotas.GetMaxObjects())) + if patch.size != nil { + urQuota.SetMaxSize(w.User.Quota.WebsiteSizeAdjust(*patch.size)) + } + + // Build the update + ur := garage.NewUpdateBucketRequest() + ur.SetQuotas(*urQuota) + + // Call garage + binfo, err = grgUpdateBucket(website.Internal, ur) + if err != nil { + return nil, ErrCantConfigureBucket + } + + return NewWebsiteView(binfo), nil } func (w *WebsiteController) Create(pretty string) (*WebsiteView, error) { @@ -190,6 +174,35 @@ func (w *WebsiteController) Create(pretty string) (*WebsiteView, error) { return NewWebsiteView(binfo), nil } +func (w *WebsiteController) Delete(pretty string) error { + if pretty == "" { + return ErrEmptyBucketName + } + + website, ok := w.WebsiteIdx[pretty] + if !ok { + return ErrWebsiteNotFound + } + + binfo, err := grgGetBucket(website.Internal) + if err != nil { + return ErrFetchBucketInfo + } + + if *binfo.Objects > int64(0) { + return ErrBucketDeleteNotEmpty + } + + if *binfo.UnfinishedUploads > int32(0) { + return ErrBucketDeleteUnfinishedUpload + } + + err = grgDeleteBucket(website.Internal) + return err +} + + + type WebsiteView struct { Name *WebsiteId @@ -207,5 +220,5 @@ func NewWebsiteView(binfo *garage.BucketInfo) *WebsiteView { } type WebsitePatch struct { - size int64 + size *int64 } -- cgit v1.2.3