feat: add Slack target type for incoming webhook notifications
All checks were successful
check / check (push) Successful in 2m2s

Add a new 'slack' target type that sends webhook events as formatted
messages to any Slack-compatible incoming webhook URL (Slack, Mattermost,
and other compatible services).

Messages include event metadata (method, content type, timestamp, body
size) and the payload pretty-printed in a code block. JSON payloads are
automatically formatted with indentation; non-JSON payloads are shown as
raw text. Large payloads are truncated at 3500 chars.

Changes:
- Add TargetTypeSlack constant to model_target.go
- Add SlackTargetConfig struct and deliverSlack method to delivery engine
- Add FormatSlackMessage (exported) for building Slack message text
- Route slack targets in processDelivery switch
- Handle slack type in HandleTargetCreate with webhook_url config
- Add slack option to source_detail.html target creation form
- Add comprehensive tests (config parsing, message formatting, delivery
  success/failure, routing)
- Update README with slack target documentation
This commit is contained in:
user
2026-03-17 03:35:28 -07:00
parent 1fbcf96581
commit 5f18e7c7bf
6 changed files with 460 additions and 4 deletions

View File

@@ -519,14 +519,14 @@ func (h *Handlers) HandleTargetCreate() http.HandlerFunc {
// Validate target type
switch targetType {
case database.TargetTypeHTTP, database.TargetTypeDatabase, database.TargetTypeLog:
case database.TargetTypeHTTP, database.TargetTypeDatabase, database.TargetTypeLog, database.TargetTypeSlack:
// valid
default:
http.Error(w, "Invalid target type", http.StatusBadRequest)
return
}
// Build config JSON for HTTP targets
// Build config JSON based on target type
var configJSON string
if targetType == database.TargetTypeHTTP {
if url == "" {
@@ -542,6 +542,20 @@ func (h *Handlers) HandleTargetCreate() http.HandlerFunc {
return
}
configJSON = string(configBytes)
} else if targetType == database.TargetTypeSlack {
if url == "" {
http.Error(w, "Webhook URL is required for Slack targets", http.StatusBadRequest)
return
}
cfg := map[string]interface{}{
"webhook_url": url,
}
configBytes, err := json.Marshal(cfg)
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
configJSON = string(configBytes)
}
maxRetries := 0 // default: fire-and-forget (no retries)