package api
import (
"context"
"testing"
"craftdesign.group/quarry/internal/oltp"
"craftdesign.group/quarry/internal/ops"
)
// A rejected submission reaches its author through the listing, with
// the moderator's reason and the text they wrote.
//
// The half of G-118 that survived the first fix. Approval announces
// itself, because the post appears. Rejection announced nothing: the
// row left the listing, the post had never been in the DAG, and the
// reason went to a public modlog the author was never pointed at — so a
// stranger reading that log knew why, and the author did not know it
// had been decided.
//
// The body rides along because the text existed nowhere its author
// could reach. Losing an argument with a moderator is one thing; losing
// the paragraphs is another.
func TestAuthorSeesTheirRejectionAndGetsTheirTextBack(t *testing.T) {
forum := &heldForumStub{staged: []oltp.Staged{
{ID: 1, Kind: "post", Title: "eve's refused post", Author: "eve",
At: "2026-09-19T10:00:00", State: "rejected",
Reason: "off topic", Body: "the paragraphs eve wrote"},
{ID: 2, Kind: "post", Title: "eve's waiting post", Author: "eve",
At: "2026-09-19T11:00:00", State: "pending", Body: "still waiting"},
}}
r := ops.NewRegistry()
if err := RegisterAll(r, Deps{Version: "v", Repos: testRepos(forumTechIndex(t)), Forum: forum}); err != nil {
t.Fatal(err)
}
got, err := r.Invoke(ops.WithUser(context.Background(), "eve"), "forum.list", forumListIn{Repo: "test"})
if err != nil {
t.Fatal(err)
}
held := got.(forumListOut).Held
if len(held) != 2 {
t.Fatalf("FAIL: eve sees %d of her own submissions, want 2: %+v", len(held), held)
}
var rejected, pending *forumHeldOut
for i := range held {
switch held[i].State {
case "rejected":
rejected = &held[i]
case "pending":
pending = &held[i]
}
}
if rejected == nil {
t.Fatalf("FAIL: the rejected submission never reached its author: %+v", held)
}
if rejected.Reason != "off topic" {
t.Errorf("FAIL: the moderator's reason did not reach the author: %q", rejected.Reason)
}
if rejected.Body != "the paragraphs eve wrote" {
t.Errorf("FAIL: the author's text was not handed back: %q", rejected.Body)
}
// A PENDING row carries neither: there is no decision to explain,
// and the author has their own draft. Sending the body back on
// every listing would be a payload nobody asked for.
if pending == nil {
t.Fatalf("FAIL: the waiting submission vanished: %+v", held)
}
if pending.Reason != "" || pending.Body != "" {
t.Errorf("FAIL: a waiting submission carries a reason or a body: %+v", pending)
}
// Still nobody else's, rejections included.
other, err := r.Invoke(ops.WithUser(context.Background(), "jan"), "forum.list", forumListIn{Repo: "test"})
if err != nil {
t.Fatal(err)
}
if h := other.(forumListOut).Held; len(h) != 0 {
t.Errorf("FAIL: jan was shown eve's rejection: %+v", h)
}
}