check / check (push) Waiting to run
`internal/handlers/source_management.go` had grown to about 2,370 lines holding the webhook, event log, entrypoint and target handlers, so unrelated units had to wait on each other to touch it. It is split, as pure code movement, into files named for what they hold: `webhook_list.go`, `webhook_create.go`, `webhook_detail.go`, `webhook_edit.go`, `webhook_delete.go`, `event_log.go`, `entrypoint.go`, `target_create.go`, `target_delete.go`, `target_toggle.go` and `shared.go`. No function body, signature, comment or behaviour changed. The README's file tree and log-line caveat, and one middleware comment, name the new files. Model: opus-5-5
170 lines
3.9 KiB
Go
170 lines
3.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi"
|
|
"github.com/google/uuid"
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
)
|
|
|
|
// HandleEntrypointCreate handles adding a new entrypoint.
|
|
func (h *Handlers) HandleEntrypointCreate() http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
userID, ok := h.getUserID(r)
|
|
if !ok {
|
|
http.Redirect(
|
|
w, r, "/pages/login", http.StatusSeeOther,
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
sourceID := chi.URLParam(r, "sourceID")
|
|
|
|
var webhook database.Webhook
|
|
|
|
err := h.db.DB().Where(
|
|
"id = ? AND user_id = ?", sourceID, userID,
|
|
).First(&webhook).Error
|
|
if err != nil {
|
|
h.renderError(w, r, http.StatusNotFound)
|
|
|
|
return
|
|
}
|
|
|
|
// The body size cap is enforced by the MaxBodySize
|
|
// middleware, which runs before CSRF parses the form.
|
|
err = r.ParseForm()
|
|
if err != nil {
|
|
h.renderError(w, r, http.StatusBadRequest)
|
|
|
|
return
|
|
}
|
|
|
|
description := r.PostFormValue("description")
|
|
|
|
entrypoint := &database.Entrypoint{
|
|
WebhookID: webhook.ID,
|
|
Path: uuid.New().String(),
|
|
Description: description,
|
|
Active: true,
|
|
}
|
|
|
|
err = h.db.DB().Create(entrypoint).Error
|
|
if err != nil {
|
|
h.serverError(w, r, "failed to create entrypoint", err)
|
|
|
|
return
|
|
}
|
|
|
|
http.Redirect(
|
|
w, r, withNotice("/hook/"+webhook.ID, entrypointAdded),
|
|
http.StatusSeeOther,
|
|
)
|
|
}
|
|
}
|
|
|
|
// HandleEntrypointEdit handles changing an entrypoint's description.
|
|
// It writes only the description column, so the entrypoint keeps its
|
|
// URL, and an activate or deactivate saved since the page was shown
|
|
// is not undone.
|
|
func (h *Handlers) HandleEntrypointEdit() http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
userID, ok := h.getUserID(r)
|
|
if !ok {
|
|
http.Redirect(
|
|
w, r, "/pages/login", http.StatusSeeOther,
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
sourceID := chi.URLParam(r, "sourceID")
|
|
entrypointID := chi.URLParam(r, "entrypointID")
|
|
|
|
var webhook database.Webhook
|
|
|
|
err := h.db.DB().Where(
|
|
"id = ? AND user_id = ?", sourceID, userID,
|
|
).First(&webhook).Error
|
|
if err != nil {
|
|
h.renderError(w, r, http.StatusNotFound)
|
|
|
|
return
|
|
}
|
|
|
|
// The body size cap is enforced by the MaxBodySize
|
|
// middleware, which runs before CSRF parses the form.
|
|
err = r.ParseForm()
|
|
if err != nil {
|
|
h.renderError(w, r, http.StatusBadRequest)
|
|
|
|
return
|
|
}
|
|
|
|
result := h.db.DB().Model(&database.Entrypoint{}).Where(
|
|
"id = ? AND webhook_id = ?", entrypointID, webhook.ID,
|
|
).Update("description", r.PostFormValue("description"))
|
|
if result.Error != nil {
|
|
h.serverError(
|
|
w, r, "failed to edit entrypoint", result.Error,
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
// The id came from the URL and may name another webhook's
|
|
// entrypoint, which this webhook does not have.
|
|
if result.RowsAffected == 0 {
|
|
h.renderError(w, r, http.StatusNotFound)
|
|
|
|
return
|
|
}
|
|
|
|
http.Redirect(
|
|
w, r, withNotice("/hook/"+webhook.ID, entrypointSaved),
|
|
http.StatusSeeOther,
|
|
)
|
|
}
|
|
}
|
|
|
|
// HandleEntrypointDelete handles deleting an entrypoint.
|
|
func (h *Handlers) HandleEntrypointDelete() http.HandlerFunc {
|
|
return h.deleteChildResource(
|
|
"entrypointID", &database.Entrypoint{},
|
|
"failed to delete entrypoint",
|
|
nil,
|
|
entrypointDeleted,
|
|
)
|
|
}
|
|
|
|
// HandleEntrypointToggle handles toggling an entrypoint's
|
|
// active state.
|
|
func (h *Handlers) HandleEntrypointToggle() http.HandlerFunc {
|
|
return h.toggleChildResource(
|
|
"entrypointID",
|
|
func(webhookID, childID string) (bool, error) {
|
|
var ep database.Entrypoint
|
|
|
|
err := h.db.DB().Where(
|
|
"id = ? AND webhook_id = ?",
|
|
childID, webhookID,
|
|
).First(&ep).Error
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
// Only the active column: saving the whole row would
|
|
// write back the description read above over an edit
|
|
// saved since.
|
|
active := !ep.Active
|
|
|
|
return active, h.db.DB().Model(&ep).
|
|
Update("active", active).Error
|
|
},
|
|
"failed to toggle entrypoint",
|
|
entrypointActivated, entrypointDeactivated,
|
|
)
|
|
}
|