// Command campaigns drives listmonk's Campaign API from git-authored // Markdown: sync creates/updates draft campaigns from campaigns// // directories, send transitions one to running (the one real send trigger // in this tool), and test previews a campaign's current content without // touching its status. package main import ( "fmt" "log" "os" "strings" "gitea.reground.org/will/eec-campaigns/internal/campaign" "gitea.reground.org/will/eec-campaigns/internal/listmonk" ) func main() { if len(os.Args) < 2 { usage() } lm := listmonk.New( mustEnv("LISTMONK_BASE_URL"), mustEnv("LISTMONK_API_USER"), mustEnv("LISTMONK_API_TOKEN"), ) switch os.Args[1] { case "sync": if len(os.Args) < 3 { fmt.Fprintln(os.Stderr, "usage: campaigns sync PATH") os.Exit(1) } runSync(lm, os.Args[2]) case "send": if len(os.Args) < 3 { fmt.Fprintln(os.Stderr, "usage: campaigns send SLUG") os.Exit(1) } runSend(lm, os.Args[2]) case "test": if len(os.Args) < 4 { fmt.Fprintln(os.Stderr, "usage: campaigns test SLUG EMAIL...") os.Exit(1) } runTest(lm, os.Args[2], os.Args[3:]) case "template": if len(os.Args) < 4 { fmt.Fprintln(os.Stderr, "usage: campaigns template NAME PATH") os.Exit(1) } runTemplate(lm, os.Args[2], os.Args[3]) default: usage() } } func usage() { fmt.Fprintln(os.Stderr, "usage: campaigns ") os.Exit(1) } // runSync's default preview address(es) come from CAMPAIGNS_PREVIEW_EMAIL // (comma-separated), used for any campaign that doesn't set its own // preview_emails in frontmatter. Optional — sync still works with none set, // it just won't auto-preview campaigns that don't specify their own. func runSync(lm *listmonk.Client, path string) { var defaultPreview []string if raw := os.Getenv("CAMPAIGNS_PREVIEW_EMAIL"); raw != "" { for _, addr := range strings.Split(raw, ",") { if addr = strings.TrimSpace(addr); addr != "" { defaultPreview = append(defaultPreview, addr) } } } result, err := campaign.SyncDir(lm, path, defaultPreview) if err != nil { log.Fatalf("sync: %v", err) } log.Printf("synced: %v", result.Synced) log.Printf("unchanged: %v", result.Unchanged) if len(result.Rejected) > 0 { log.Printf("rejected: %v", result.Rejected) } if len(result.PreviewFailed) > 0 { log.Printf("preview send failed: %v", result.PreviewFailed) } if len(result.Rejected) > 0 || len(result.PreviewFailed) > 0 { os.Exit(1) } } func runSend(lm *listmonk.Client, slug string) { camp, err := campaign.Send(lm, slug) if err != nil { log.Fatalf("send: %v", err) } log.Printf("sent: campaign %q (id=%d) is now running", slug, camp.ID) } func runTest(lm *listmonk.Client, slug string, emails []string) { if err := campaign.Test(lm, slug, emails); err != nil { log.Fatalf("test: %v", err) } log.Printf("test: sent preview of %q to %v", slug, emails) } func runTemplate(lm *listmonk.Client, name, path string) { tpl, err := campaign.SyncTemplate(lm, name, path) if err != nil { log.Fatalf("template: %v", err) } log.Printf("template: %q (id=%d) is now the default campaign template", tpl.Name, tpl.ID) } func mustEnv(key string) string { v := os.Getenv(key) if v == "" { log.Fatalf("%s environment variable is required", key) } return v }