Store a target's settings as columns (closes #543)
check / check (push) Waiting to run

A target's settings move from the per-type JSON string in
targets.config to columns: url, headers, timeout_seconds,
forward_query, archive_expiry and archive_rotation. A column a type
does not use stays empty. headers holds the header map as JSON text
through GORM's JSON serializer, and archive_expiry holds a
time.Duration, 0 meaning never, so nothing that reads a target parses
it. The forms check each setting once, with the same refusals and
messages, and the edit form is filled from the columns, so the
per-type config structs, their parsers and the "could not be read"
branches are gone. A delivery task carries the six settings in place
of the JSON string.

Model: opus-5-5
This commit is contained in:
2026-10-15 19:54:42 +00:00
parent 0cdda43e6c
commit 82bab57dfe
69 changed files with 1404 additions and 2159 deletions
+6 -20
View File
@@ -93,17 +93,6 @@ func (s *tsSink) text(t *testing.T) string {
}
}
func tsSlackConfig(t *testing.T, url string) string {
t.Helper()
data, err := json.Marshal(
delivery.SlackTargetConfig{WebhookURL: url},
)
require.NoError(t, err)
return string(data)
}
// tsSeedEvent writes an event whose CreatedAt is tsEventCreatedAt
// rather than the write time, so an assertion on the rendered
// timestamp cannot pass by accident against "roughly now".
@@ -142,7 +131,7 @@ func tsSeedEvent(
// tsSeedTarget writes the slack target row into the main database.
// The retry path confirms the target still exists before sending.
func tsSeedTarget(
t *testing.T, mainDB *gorm.DB, webhookID, config string,
t *testing.T, mainDB *gorm.DB, webhookID, webhookURL string,
) database.Target {
t.Helper()
@@ -150,7 +139,7 @@ func tsSeedTarget(
WebhookID: webhookID,
Name: "slack-sink",
Type: database.TargetTypeSlack,
Config: config,
URL: webhookURL,
Active: true,
MaxAttempts: 1,
}
@@ -176,7 +165,7 @@ func tsTask(
TargetID: target.ID,
TargetName: target.Name,
TargetType: database.TargetTypeSlack,
TargetConfig: target.Config,
TargetURL: target.URL,
MaxAttempts: 1,
Method: event.Method,
Headers: event.Headers,
@@ -226,8 +215,7 @@ func (c tsCase) run(t *testing.T) (iSetup, database.Delivery, string) {
s := newISetup(t)
sink := newTSSink(t)
cfg := tsSlackConfig(t, sink.URL)
target := tsSeedTarget(t, s.MainDB, s.WebhookID, cfg)
target := tsSeedTarget(t, s.MainDB, s.WebhookID, sink.URL)
event := tsSeedEvent(t, s.WebhookDB, s.WebhookID)
d := iSeedDelivery(
@@ -338,8 +326,7 @@ func TestFormatSlackMessageOverTaskReconstructedEvent(
s := newISetup(t)
cfg := tsSlackConfig(t, tsUndeliverableHook)
target := tsSeedTarget(t, s.MainDB, s.WebhookID, cfg)
target := tsSeedTarget(t, s.MainDB, s.WebhookID, tsUndeliverableHook)
event := tsSeedEvent(t, s.WebhookDB, s.WebhookID)
d := iSeedDelivery(
@@ -410,8 +397,7 @@ func TestEventReconstructionSurvivesAReapedRow(t *testing.T) {
s := newISetup(t)
cfg := tsSlackConfig(t, tsUndeliverableHook)
target := tsSeedTarget(t, s.MainDB, s.WebhookID, cfg)
target := tsSeedTarget(t, s.MainDB, s.WebhookID, tsUndeliverableHook)
event := tsSeedEvent(t, s.WebhookDB, s.WebhookID)
d := iSeedDelivery(