Fix TestCampaign sending only subscribers, failing listmonk validation
CI / test (push) Successful in 9s

listmonk's /api/campaigns/:id/test handler binds the request into the
same campReq struct create/update use and validates it in full, so a
request with only {"subscribers": [...]} fails with "Invalid length
for name" before subscribers is ever read. TestCampaign now sends the
campaign's full CampaignInput alongside subscribers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 21:51:20 -04:00
parent 7eea2b1a8b
commit 39d02303c7
4 changed files with 33 additions and 8 deletions
+26 -5
View File
@@ -297,6 +297,23 @@ type Campaign struct {
MediaIDs []int
}
// AsInput converts a fetched Campaign back into the CampaignInput shape,
// for callers (e.g. Test) that need to re-send a campaign's current fields
// against an endpoint that validates the full campaign body.
func (camp *Campaign) AsInput() CampaignInput {
return CampaignInput{
Name: camp.Name,
Subject: camp.Subject,
FromEmail: camp.FromEmail,
TemplateID: camp.TemplateID,
Type: camp.Type,
Tags: camp.Tags,
ListIDs: camp.ListIDs,
Body: camp.Body,
MediaIDs: camp.MediaIDs,
}
}
// CampaignInput is what sync.go builds from a campaign's frontmatter+body to
// create or update a listmonk campaign.
type CampaignInput struct {
@@ -482,14 +499,18 @@ func (c *Client) SetCampaignStatus(id int, status string) error {
}
// TestCampaign sends a preview of the campaign's current content to the
// given addresses without touching its status. Request field confirmed
// against knadh/listmonk's actual handler source (cmd/campaigns.go's
// campReq.SubscriberEmails, json tag "subscribers").
func (c *Client) TestCampaign(id int, emails []string) error {
// given addresses without touching its status. listmonk's test-send handler
// binds the request into the same campReq struct create/update use and
// validates it in full, so the campaign's other fields (in particular a
// non-empty "name") must be sent alongside "subscribers" — a request with
// just {"subscribers": [...]} fails listmonk's own validation with "Invalid
// length for name" before the "subscribers" field is ever looked at.
func (c *Client) TestCampaign(id int, in CampaignInput, emails []string) error {
if len(emails) == 0 {
return nil
}
payload := map[string]any{"subscribers": emails}
payload := in.payload()
payload["subscribers"] = emails
respBody, status, err := c.do(http.MethodPost, fmt.Sprintf("/api/campaigns/%d/test", id), payload)
if err != nil {
return fmt.Errorf("sending test for campaign %d: %w", id, err)