NewFromEnv now falls back to DISCOURSE_KEY when DISCOURSE_API_KEY
is unset (the explicit name still wins), matching the shorter
DISCOURSE_URL/DISCOURSE_KEY convention used across the MOPAC fleet
scripts. Behavioral test proves both the alias and the precedence
against the fake server.
Part of Redmine 507 (Discourse Go client).
Client.SendMessage(title, raw, targets) creates a private-message
topic by posting to /posts.json with target_usernames /
target_group_names / target_emails (comma-joined on the wire, as
Discourse expects, never JSON arrays) instead of a category. The
result reuses the topic ids type, so URL() renders the PM link.
Local validation requires title, body and at least one target;
undeliverable recipients surface as the typed ErrForbidden class.
Fake-server tests assert the wire shape and the recorded recipients.
Part of Redmine 507 (Discourse Go client): PM delivery is how the
495 pipeline pings humans that a briefing has landed.
Client.Search(term, page) url-encodes the term (operators like
@user / #category / order:latest pass through) and decodes the four
hit groups Discourse returns: posts (with blurb and highlighted
topic title), topics, users and categories. Empty term is rejected
locally with ErrInvalidRequest; server failures keep the typed
error classes. Fake-server tests cover encoding, parsing and the
403 path.
Part of Redmine 507 (Discourse Go client): search is how the 495
briefing pipeline finds landing spots and prior threads.
v0 landed with a few misaligned struct tags and fields; gofmt -l
flagged categories.go, topics.go, discourse_test.go and the smoke
fake. Alignment only, no behavior change, so the tree passes the
gofmt gate cleanly.
Covers the MOPAC briefing/report surface (Redmine 495 Part A): category
list/create (create needs the admin-scoped key; current key 403s, typed
as ErrForbidden), topic create/list/latest/get, post create/update/get,
current-user identity probe, and a Do() JSON passthrough so unmodeled
endpoints need no client release. Key is env/constructor-only, never a
flag, never logged; errors classify via errors.Is. Fake-server unit
tests + containerized end-to-end smoke (redaction sweep included); live
reads verified against community.turnsys.com.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2