change-vhost #47
5 changed files with 141 additions and 4 deletions
51
garage.go
51
garage.go
|
@ -270,8 +270,9 @@ func handleWebsiteInspect(w http.ResponseWriter, r *http.Request) {
|
||||||
_, processErr = ctrl.Patch(bucketName, &WebsitePatch{Size: &user.Quota.WebsiteSizeBursted})
|
_, processErr = ctrl.Patch(bucketName, &WebsitePatch{Size: &user.Quota.WebsiteSizeBursted})
|
||||||
case "delete_bucket":
|
case "delete_bucket":
|
||||||
processErr = ctrl.Delete(bucketName)
|
processErr = ctrl.Delete(bucketName)
|
||||||
|
if processErr == nil {
|
||||||
http.Redirect(w, r, "/website", http.StatusFound)
|
http.Redirect(w, r, "/website", http.StatusFound)
|
||||||
return
|
}
|
||||||
default:
|
default:
|
||||||
processErr = fmt.Errorf("Unknown action")
|
processErr = fmt.Errorf("Unknown action")
|
||||||
}
|
}
|
||||||
|
@ -295,3 +296,51 @@ func handleWebsiteInspect(w http.ResponseWriter, r *http.Request) {
|
||||||
tWebsiteInspect := getTemplate("garage_website_inspect.html")
|
tWebsiteInspect := getTemplate("garage_website_inspect.html")
|
||||||
tWebsiteInspect.Execute(w, &tpl)
|
tWebsiteInspect.Execute(w, &tpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleWebsiteVhost(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var processErr error
|
||||||
|
|
||||||
|
user := RequireUserHtml(w, r)
|
||||||
|
if user == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl, err := NewWebsiteController(user)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bucketName := mux.Vars(r)["bucket"]
|
||||||
|
|
||||||
|
if r.Method == "POST" {
|
||||||
|
r.ParseForm()
|
||||||
|
|
||||||
|
bucket := strings.Join(r.Form["bucket"], "")
|
||||||
|
if bucket == "" {
|
||||||
|
bucket = strings.Join(r.Form["bucket2"], "")
|
||||||
|
}
|
||||||
|
|
||||||
|
view, processErr := ctrl.Patch(bucketName, &WebsitePatch{Vhost: &bucket})
|
||||||
|
if processErr == nil {
|
||||||
|
http.Redirect(w, r, "/website/inspect/"+view.Name.Pretty, http.StatusFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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}
|
||||||
|
tWebsiteEdit := getTemplate("garage_website_edit.html")
|
||||||
|
tWebsiteEdit.Execute(w, &tpl)
|
||||||
|
}
|
||||||
|
|
1
main.go
1
main.go
|
@ -161,6 +161,7 @@ func server(args []string) {
|
||||||
r.HandleFunc("/website/new", handleWebsiteNew)
|
r.HandleFunc("/website/new", handleWebsiteNew)
|
||||||
r.HandleFunc("/website/configure", handleWebsiteConfigure)
|
r.HandleFunc("/website/configure", handleWebsiteConfigure)
|
||||||
r.HandleFunc("/website/inspect/{bucket}", handleWebsiteInspect)
|
r.HandleFunc("/website/inspect/{bucket}", handleWebsiteInspect)
|
||||||
|
r.HandleFunc("/website/vhost/{bucket}", handleWebsiteVhost)
|
||||||
|
|
||||||
r.HandleFunc("/invite/new_account", handleInviteNewAccount)
|
r.HandleFunc("/invite/new_account", handleInviteNewAccount)
|
||||||
r.HandleFunc("/invite/send_code", handleInviteSendCode)
|
r.HandleFunc("/invite/send_code", handleInviteSendCode)
|
||||||
|
|
72
templates/garage_website_edit.html
Normal file
72
templates/garage_website_edit.html
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
{{define "title"}}Créer un site web |{{end}}
|
||||||
|
|
||||||
|
{{define "body"}}
|
||||||
|
<div class="d-flex">
|
||||||
|
<h4>Modifier le nom de domaine</h4>
|
||||||
|
<a class="ml-auto btn btn-link" href="/website/configure">Mes identifiants</a>
|
||||||
|
<a class="ml-4 btn btn-info" href="/website">Mes sites webs</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{{if .Err}}
|
||||||
|
<div class="alert alert-danger">{{ .Err.Error }}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" id="proto" role="tablist">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" id="dnsint-tab" data-toggle="tab" href="#dnsint" role="tab" aria-controls="dnsint" aria-selected="true">Je n'ai pas de nom de domaine</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" id="dnsext-tab" data-toggle="tab" href="#dnsext" role="tab" aria-controls="dnsext" aria-selected="false">Utiliser mon propre nom de domaine</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content" id="protocols">
|
||||||
|
|
||||||
|
<div class="tab-pane fade show active" id="dnsint" role="tabpanel" aria-labelledby="dnsint-tab">
|
||||||
|
<form method="POST" class="mt-4">
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="bucket">Sous-domaine désiré :</label>
|
||||||
|
<input type="text" id="bucket" name="bucket" placeholder="mon-site" class="form-control" value="" onkeyup="document.getElementById('url').value = `https://${document.getElementById('bucket').value}.web.deuxfleurs.fr`" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="url">Votre site sera accessible à l'URL suivante :</label>
|
||||||
|
<input type="text" id="url" disabled="true" name="url" class="form-control" value="https://mon-site.web.deuxfleurs.fr" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4">
|
||||||
|
<p>La première fois que vous chargerez votre site web, une erreur de certificat sera renvoyée. C'est normal, il faudra patienter quelques minutes le temps que le certificat se génère.</p>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Modifier le nom de domaine</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade show" id="dnsext" role="tabpanel" aria-labelledby="dnsext-tab">
|
||||||
|
<form method="POST" class="mt-4">
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="bucket2">Votre nom de domaine :</label>
|
||||||
|
<input type="text" id="bucket2" name="bucket2" placeholder="example.com" class="form-control" value="" onkeyup="document.getElementById('url2').value = `https://${document.getElementById('bucket2').value}`" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="url2">Votre site sera accessible à l'URL suivante :</label>
|
||||||
|
<input type="text" id="url2" disabled="true" name="url2" class="form-control" value="https://example.com" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>Vous devez éditer votre zone DNS, souvent gérée par votre bureau d'enregistrement, comme Gandi, pour la faire pointer vers Deuxfleurs. Si vous utilisez un sous domaine (eg. <code>site.example.com</code>), une entrée <code>CNAME</code> est appropriée :</p>
|
||||||
|
<pre>site CNAME 3600 garage.deuxfleurs.fr.</pre>
|
||||||
|
<p>Si vous utilisez la racine de votre nom de domaine (eg. <code>example.com</code>, aussi appelée APEX), la solution dépend de votre fournisseur DNS, il vous faudra au choix une entrée <code>ALIAS</code> ou <code>CNAME</code> en fonction de ce que votre fournisseur supporte :</p>
|
||||||
|
<pre>@ ALIAS 3600 garage.deuxfleurs.fr.</pre>
|
||||||
|
<p>La première fois que vous chargerez votre site web, une erreur de certificat sera renvoyée. C'est normal, il faudra patienter quelques minutes le temps que le certificat se génère.</p>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4">
|
||||||
|
<button type="submit" class="btn btn-primary">Modifier le nom de domaine</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
|
@ -63,7 +63,7 @@
|
||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
<div class="btn-group" role="group" aria-label="Actions sur le site web">
|
<div class="btn-group" role="group" aria-label="Actions sur le site web">
|
||||||
<button class="btn btn-secondary" name="action" value="increase_quota">Augmenter le quota</button>
|
<button class="btn btn-secondary" name="action" value="increase_quota">Augmenter le quota</button>
|
||||||
<a class="btn btn-secondary disabled">Changer le nom de domaine</a>
|
<a class="btn btn-secondary" href="/website/vhost/{{ .View.Name.Pretty }}">Changer le nom de domaine</a>
|
||||||
<button class="btn btn-danger" name="action" value="delete_bucket">Supprimer</button>
|
<button class="btn btn-danger" name="action" value="delete_bucket">Supprimer</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
17
website.go
17
website.go
|
@ -17,6 +17,8 @@ var (
|
||||||
ErrCantConfigureBucket = fmt.Errorf("Unable to configure the bucket (activating website, adding quotas, etc.)")
|
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")
|
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")
|
ErrBucketDeleteUnfinishedUpload = fmt.Errorf("You must remove all the unfinished multipart uploads before deleting a bucket")
|
||||||
|
ErrCantChangeVhost = fmt.Errorf("Can't change the vhost to the desired value. Maybe it's already used by someone else or an internal error occured")
|
||||||
|
ErrCantRemoveOldVhost = fmt.Errorf("The new vhost is bound to the bucket but the old one can't be removed, this is an internal error")
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebsiteId struct {
|
type WebsiteId struct {
|
||||||
|
@ -141,12 +143,24 @@ func (w *WebsiteController) Patch(pretty string, patch *WebsitePatch) (*WebsiteV
|
||||||
ur := garage.NewUpdateBucketRequest()
|
ur := garage.NewUpdateBucketRequest()
|
||||||
ur.SetQuotas(*urQuota)
|
ur.SetQuotas(*urQuota)
|
||||||
|
|
||||||
// Call garage
|
// Call garage "update bucket" function
|
||||||
binfo, err = grgUpdateBucket(website.Internal, ur)
|
binfo, err = grgUpdateBucket(website.Internal, ur)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrCantConfigureBucket
|
return nil, ErrCantConfigureBucket
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the alias if the vhost field is set and different
|
||||||
|
if patch.Vhost != nil && *patch.Vhost != "" && *patch.Vhost != pretty {
|
||||||
|
binfo, err = grgAddGlobalAlias(website.Internal, *patch.Vhost)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrCantChangeVhost
|
||||||
|
}
|
||||||
|
binfo, err = grgDelGlobalAlias(website.Internal, pretty)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrCantRemoveOldVhost
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NewWebsiteView(binfo), nil
|
return NewWebsiteView(binfo), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,4 +247,5 @@ func NewWebsiteView(binfo *garage.BucketInfo) *WebsiteView {
|
||||||
|
|
||||||
type WebsitePatch struct {
|
type WebsitePatch struct {
|
||||||
Size *int64 `json:"quota_size"`
|
Size *int64 `json:"quota_size"`
|
||||||
|
Vhost *string `json:"vhost"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue