change-vhost #47

Merged
quentin merged 2 commits from change-vhost into main 2023-10-17 16:34:13 +00:00
5 changed files with 142 additions and 5 deletions

View file

@ -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)
}

View file

@ -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)

View 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}}

View file

@ -48,7 +48,7 @@
<h5 class="mt-3">Quotas</h5> <h5 class="mt-3">Quotas</h5>
<div class="progress mt-3"> <div class="progress mt-3">
<div class="progress-bar" role="progressbar" aria-valuenow="{{ .View.Size.Current }}" aria-valuemin="0" aria-valuemax="{{ .View.Size.Max }}" style="width: {{ .View.Size.Percent }}%; min-width: 2em;"> <div class="progress-bar" role="progressbar" aria-valuenow="{{ .View.Size.Current }}" aria-valuemin="0" aria-valuemax="{{ .View.Size.Max }}" style="width: {{ .View.Size.Percent }}%; min-width: 2em;">
{{ .View.Size.Ratio }}% {{ .View.Size.Percent }}%
</div> </div>
</div> </div>
@ -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>

View file

@ -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"`
} }