Track altbody in change-detection so existing campaigns actually re-sync
CI / test (push) Successful in 10s

Campaign/parseCampaign never fetched altbody, so campaignUnchanged()
compared everything except it -- a campaign synced before v0.1.3
(altbody always null) whose content otherwise hasn't changed would be
judged unchanged forever and never get updated with the new altbody,
even though every subsequent sync now intends to send one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 22:13:13 -04:00
parent e238bde036
commit 6227d59eae
3 changed files with 11 additions and 2 deletions
+4
View File
@@ -217,6 +217,10 @@ func attachmentFilename(slug, relPath string, content []byte) string {
func campaignUnchanged(existing *listmonk.Campaign, input listmonk.CampaignInput) bool {
return existing.Subject == input.Subject &&
existing.Body == input.Body &&
// altbody always mirrors body (see CampaignInput.payload) -- comparing
// it here is what catches a campaign synced before that started, whose
// stored altbody is still null even though its body hasn't changed.
existing.AltBody == input.Body &&
existing.FromEmail == input.FromEmail &&
existing.TemplateID == input.TemplateID &&
existing.Type == input.Type &&
+4 -2
View File
@@ -31,6 +31,7 @@ type fakeCampaign struct {
Status string
Subject string
Body string
AltBody string
FromEmail string
TemplateID int
Type string
@@ -138,7 +139,7 @@ func (c fakeCampaign) toJSON() map[string]any {
}
return map[string]any{
"id": c.ID, "name": c.Name, "status": c.Status, "subject": c.Subject,
"body": c.Body, "from_email": c.FromEmail, "template_id": c.TemplateID,
"body": c.Body, "altbody": c.AltBody, "from_email": c.FromEmail, "template_id": c.TemplateID,
"type": c.Type, "tags": c.Tags, "lists": lists, "media": media,
}
}
@@ -155,7 +156,7 @@ func (f *fakeListmonk) createCampaign(w http.ResponseWriter, r *http.Request) {
body := decodeBody(r)
c := fakeCampaign{
ID: f.id(), Name: str(body["name"]), Status: "draft",
Subject: str(body["subject"]), Body: str(body["body"]),
Subject: str(body["subject"]), Body: str(body["body"]), AltBody: str(body["altbody"]),
FromEmail: str(body["from_email"]), TemplateID: toInt(body["template_id"]),
Type: str(body["type"]), Tags: toStrings(body["tags"]),
ListIDs: toInts(body["lists"]), MediaIDs: toInts(body["media"]),
@@ -171,6 +172,7 @@ func (f *fakeListmonk) updateCampaign(w http.ResponseWriter, r *http.Request) {
if f.campaigns[i].ID == id {
f.campaigns[i].Subject = str(body["subject"])
f.campaigns[i].Body = str(body["body"])
f.campaigns[i].AltBody = str(body["altbody"])
f.campaigns[i].FromEmail = str(body["from_email"])
f.campaigns[i].TemplateID = toInt(body["template_id"])
f.campaigns[i].Type = str(body["type"])
+3
View File
@@ -289,6 +289,7 @@ type Campaign struct {
Status string
Subject string
Body string
AltBody string
FromEmail string
TemplateID int
Type string
@@ -381,6 +382,7 @@ func parseCampaign(data []byte) (*Campaign, error) {
Status string `json:"status"`
Subject string `json:"subject"`
Body string `json:"body"`
AltBody string `json:"altbody"`
FromEmail string `json:"from_email"`
TemplateID int `json:"template_id"`
Type string `json:"type"`
@@ -409,6 +411,7 @@ func parseCampaign(data []byte) (*Campaign, error) {
Status: parsed.Status,
Subject: parsed.Subject,
Body: parsed.Body,
AltBody: parsed.AltBody,
FromEmail: parsed.FromEmail,
TemplateID: parsed.TemplateID,
Type: parsed.Type,