feat: add entrypoint/target management controls (closes #25)
Add toggle (activate/deactivate) and delete buttons for individual
entrypoints and targets on the webhook detail page. Each action is a
POST form submission with ownership verification.
New routes:
POST /source/{id}/entrypoints/{entrypointID}/delete
POST /source/{id}/entrypoints/{entrypointID}/toggle
POST /source/{id}/targets/{targetID}/delete
POST /source/{id}/targets/{targetID}/toggle
This commit is contained in:
@@ -527,6 +527,144 @@ func (h *Handlers) HandleTargetCreate() http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// HandleEntrypointDelete handles deleting an individual entrypoint.
|
||||
func (h *Handlers) HandleEntrypointDelete() 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")
|
||||
|
||||
// Verify webhook ownership
|
||||
var webhook database.Webhook
|
||||
if err := h.db.DB().Where("id = ? AND user_id = ?", sourceID, userID).First(&webhook).Error; err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete entrypoint (must belong to this webhook)
|
||||
result := h.db.DB().Where("id = ? AND webhook_id = ?", entrypointID, webhook.ID).Delete(&database.Entrypoint{})
|
||||
if result.Error != nil {
|
||||
h.log.Error("failed to delete entrypoint", "error", result.Error)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/source/"+webhook.ID, http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleEntrypointToggle handles toggling the active state of an entrypoint.
|
||||
func (h *Handlers) HandleEntrypointToggle() 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")
|
||||
|
||||
// Verify webhook ownership
|
||||
var webhook database.Webhook
|
||||
if err := h.db.DB().Where("id = ? AND user_id = ?", sourceID, userID).First(&webhook).Error; err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Find the entrypoint
|
||||
var entrypoint database.Entrypoint
|
||||
if err := h.db.DB().Where("id = ? AND webhook_id = ?", entrypointID, webhook.ID).First(&entrypoint).Error; err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Toggle active state
|
||||
entrypoint.Active = !entrypoint.Active
|
||||
if err := h.db.DB().Save(&entrypoint).Error; err != nil {
|
||||
h.log.Error("failed to toggle entrypoint", "error", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/source/"+webhook.ID, http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleTargetDelete handles deleting an individual target.
|
||||
func (h *Handlers) HandleTargetDelete() 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")
|
||||
targetID := chi.URLParam(r, "targetID")
|
||||
|
||||
// Verify webhook ownership
|
||||
var webhook database.Webhook
|
||||
if err := h.db.DB().Where("id = ? AND user_id = ?", sourceID, userID).First(&webhook).Error; err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete target (must belong to this webhook)
|
||||
result := h.db.DB().Where("id = ? AND webhook_id = ?", targetID, webhook.ID).Delete(&database.Target{})
|
||||
if result.Error != nil {
|
||||
h.log.Error("failed to delete target", "error", result.Error)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/source/"+webhook.ID, http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleTargetToggle handles toggling the active state of a target.
|
||||
func (h *Handlers) HandleTargetToggle() 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")
|
||||
targetID := chi.URLParam(r, "targetID")
|
||||
|
||||
// Verify webhook ownership
|
||||
var webhook database.Webhook
|
||||
if err := h.db.DB().Where("id = ? AND user_id = ?", sourceID, userID).First(&webhook).Error; err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Find the target
|
||||
var target database.Target
|
||||
if err := h.db.DB().Where("id = ? AND webhook_id = ?", targetID, webhook.ID).First(&target).Error; err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Toggle active state
|
||||
target.Active = !target.Active
|
||||
if err := h.db.DB().Save(&target).Error; err != nil {
|
||||
h.log.Error("failed to toggle target", "error", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/source/"+webhook.ID, http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
// getUserID extracts the user ID from the session.
|
||||
func (h *Handlers) getUserID(r *http.Request) (string, bool) {
|
||||
sess, err := h.session.Get(r)
|
||||
|
||||
Reference in New Issue
Block a user