aboutsummaryrefslogblamecommitdiff
path: root/website.go
blob: 7e89a412ab61c2676b0b314700cf2f228eb1a145 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                                                                                                                         

                                                                                                                                     

 
 

                       




                                       






















                                                                      
                         




























                                                                         





                                                         



                                                     
                                                      















                                                                          














                                                                                             

                                                                               












                                                          









































                                                                         




























                                                         

                         


                                              











                                                                            
                                       
 
package main

import (
	"fmt"
	"sort"
	"strings"
	garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
)

var (
	ErrWebsiteNotFound = fmt.Errorf("Website not found")
	ErrFetchBucketInfo = fmt.Errorf("Failed to fetch bucket information")
	ErrWebsiteQuotaReached = fmt.Errorf("Can't create additional websites, quota reached")
	ErrEmptyBucketName = fmt.Errorf("You can't create a website with an empty name")
	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 WebsiteId struct {
	Pretty string `json:"name"`
	Internal string `json:"-"`
	Alt []string `json:"alt_name"`
	Expanded bool `json:"expanded"`
	Url string `json:"domain"`

}
func NewWebsiteId(id string, aliases []string) *WebsiteId {
	pretty := id
	var alt []string
	if len(aliases) > 0 {
		pretty = aliases[0]
		alt = aliases[1:]
	}
	expanded := strings.Contains(pretty, ".")

	url := pretty
	if !expanded {
		url = fmt.Sprintf("%s.web.deuxfleurs.fr", pretty)
	}

	return &WebsiteId { pretty, id, alt, expanded, url }
}
func NewWebsiteIdFromBucketInfo(binfo *garage.BucketInfo) *WebsiteId {
	return NewWebsiteId(*binfo.Id, binfo.GlobalAliases)
}

type WebsiteController struct {
	User *LoggedUser 
	WebsiteIdx map[string]*WebsiteId
	PrettyList []string
	WebsiteCount QuotaStat
}

func NewWebsiteController(user *LoggedUser) (*WebsiteController, error) {
	idx := map[string]*WebsiteId{}
	var wlist []string

	keyInfo, err := user.S3KeyInfo()
	if err != nil {
		return nil, err
	}

	for _, bckt := range(keyInfo.Buckets) {
		if len(bckt.GlobalAliases) > 0 {
			wid := NewWebsiteId(*bckt.Id, bckt.GlobalAliases)
			idx[wid.Pretty] = wid
			wlist = append(wlist, wid.Pretty)
		}
	}
	sort.Strings(wlist)

	maxW := user.Quota.WebsiteCount
	quota := NewQuotaStat(int64(len(wlist)), maxW, true)

	return &WebsiteController { user, idx, wlist, quota }, nil
}

type WebsiteDescribe struct {
	AllowedWebsites *QuotaStat `json:"quota"`
	Websites []*WebsiteId `json:"vhosts"`
}

func (w *WebsiteController) Describe() *WebsiteDescribe {
	r := make([]*WebsiteId, 0, len(w.PrettyList))
	for _, k := range w.PrettyList {
		r = append(r, w.WebsiteIdx[k]) 
	}
	return &WebsiteDescribe { &w.WebsiteCount, r }
}

func (w *WebsiteController) Inspect(pretty string) (*WebsiteView, error) {
	website, ok := w.WebsiteIdx[pretty]
	if !ok {
		return nil, ErrWebsiteNotFound
	}

	binfo, err := grgGetBucket(website.Internal)
	if err != nil {
		return nil, ErrFetchBucketInfo
	}

	return NewWebsiteView(binfo), 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) {
	if pretty == "" {
		return nil, ErrEmptyBucketName
	}

	if w.WebsiteCount.IsFull() {
		return nil, ErrWebsiteQuotaReached
	}

	binfo, err := grgCreateBucket(pretty)
	if err != nil {
		return nil, ErrCantCreateBucket
	}

	s3key, err := w.User.S3KeyInfo()
	if err != nil {
		return nil, err
	}

	binfo, err = grgAllowKeyOnBucket(*binfo.Id, *s3key.AccessKeyId)
	if err != nil {
		return nil, ErrCantAllowKey
	}

	qr := w.User.Quota.DefaultWebsiteQuota()
	wr := allowWebsiteDefault()

	ur := garage.NewUpdateBucketRequest()
	ur.SetWebsiteAccess(*wr)
	ur.SetQuotas(*qr)


	binfo, err = grgUpdateBucket(*binfo.Id, ur)
	if err != nil {
		return nil, ErrCantConfigureBucket
	}

	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 `json:"identified_as"`
	Size QuotaStat `json:"quota_size"`
	Files QuotaStat `json:"quota_files"`
}

func NewWebsiteView(binfo *garage.BucketInfo) *WebsiteView {
	q := binfo.GetQuotas()

	wid := NewWebsiteIdFromBucketInfo(binfo)
	size := NewQuotaStat(*binfo.Bytes, (&q).GetMaxSize(), true)
	objects := NewQuotaStat(*binfo.Objects, (&q).GetMaxObjects(), false)
	return &WebsiteView { wid, size, objects }
}

type WebsitePatch struct {
	Size *int64 `json:"quota_size"`
}