// Copyright (C) 2024 Umorpha Systems // SPDX-License-Identifier: AGPL-3.0-or-later package main import ( "encoding/json" "errors" "html/template" "io" "log" "net/http" "os/exec" "sort" ) type Webhooks struct { cfgFile string } func (o *Webhooks) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err := o.serveHTTP(w, r); err != nil { if err.Code != -100 { http.Error(w, err.Error(), err.Code) } if err.Code/100 == 5 { log.Printf("error: %q: %v", r.URL, err) } } } var webhooks = map[string]func(cfg *Webhooks, w http.ResponseWriter, r *http.Request) *_httpError{ "from-gitea": func(cfg *Webhooks, w http.ResponseWriter, r *http.Request) *_httpError { if r.Method != http.MethodPost { return httpError(errors.New("only POST is supported"), http.StatusMethodNotAllowed) } // TODO: Validate API key payloadBytes, err := io.ReadAll(r.Body) if err != nil { return httpError(err, http.StatusBadRequest) } var payload struct { Repository struct { SSHURL string `json:"ssh_url"` CloneURL string `json:"clone_url"` } `json:"repository"` } if err := json.Unmarshal(payloadBytes, &payload); err != nil { return httpError(err, http.StatusBadRequest) } cmd := exec.CommandContext(r.Context(), "eclipse-trigger", "--config="+cfg.cfgFile, "--", payload.Repository.SSHURL, payload.Repository.CloneURL) cmd.Stdout = w cmd.Stderr = w if err := cmd.Run(); err != nil { return httpError(err, http.StatusInternalServerError) } return nil }, } var tmplWebhooks = template.Must(template.ParseFS(tmplFS, "html/pages/webhooks.html.tmpl", "html/lib/*.html.tmpl")) func (o *Webhooks) serveHTTP(w http.ResponseWriter, r *http.Request) *_httpError { if r.URL.Path == "" { if r.Method != http.MethodGet { return httpError(errors.New("only GET is supported"), http.StatusMethodNotAllowed) } names := make([]string, 0, len(webhooks)) for name := range webhooks { names = append(names, name) } sort.Strings(names) if err := tmplWebhooks.Execute(w, map[string]any{"Webhooks": names}); err != nil { return writeOrServerError(err) } } callback := webhooks[r.URL.Path] if callback == nil { return httpNotFound() } return callback(o, w, r) }