Keep listed published rules public and guest-claim rules unlisted, with semantic document markup and share chrome that stays clickable.
Guest publishes remain share-by-link but stay out of the catalog and sitemap, and their pages send noindex until claimed. The published-rule view now uses heading and list markup matching Markdown export, and top banners sit below the header so Share is not covered. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
77b0ec8ad8
commit
1445cb7e1e
27 files changed
+524
-86
No files matched your search
@@ -95,6 +95,8 @@ describe("GET /api/rules/[id]", () => {
|
||||
document: { sections: [] },
|
||||
createdAt: new Date("2026-01-01T00:00:00Z"),
|
||||
updatedAt: new Date("2026-01-02T00:00:00Z"),
|
||||
userId: "user-1",
|
||||
claimTokenHash: null,
|
||||
};
|
||||
findUniqueMock.mockResolvedValueOnce(row);
|
||||
const res = await GET(
|
||||
@@ -103,16 +105,47 @@ describe("GET /api/rules/[id]", () => {
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = (await res.json()) as {
|
||||
rule: { id: string; title: string; summary: string | null };
|
||||
rule: {
|
||||
id: string;
|
||||
title: string;
|
||||
summary: string | null;
|
||||
isListed: boolean;
|
||||
};
|
||||
viewerIsOwner: boolean;
|
||||
};
|
||||
expect(body.rule.id).toBe("rule-1");
|
||||
expect(body.rule.title).toBe("Mutual Aid Mondays");
|
||||
expect(body.rule.summary).toBe("A grassroots community in Denver.");
|
||||
expect(body.rule.isListed).toBe(true);
|
||||
expect(body.viewerIsOwner).toBe(false);
|
||||
expect(findUniqueMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("marks guest-claim rules as unlisted without exposing the claim token", async () => {
|
||||
isDatabaseConfiguredMock.mockReturnValue(true);
|
||||
findUniqueMock.mockResolvedValueOnce({
|
||||
id: "guest-1",
|
||||
title: "Unlisted",
|
||||
summary: null,
|
||||
document: {},
|
||||
createdAt: new Date("2026-01-01T00:00:00Z"),
|
||||
updatedAt: new Date("2026-01-02T00:00:00Z"),
|
||||
userId: null,
|
||||
claimTokenHash: "secret-hash",
|
||||
});
|
||||
const res = await GET(
|
||||
new NextRequest("https://x.test/api/rules/guest-1"),
|
||||
makeContext("guest-1"),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = (await res.json()) as {
|
||||
rule: { isListed: boolean; claimTokenHash?: unknown; userId?: unknown };
|
||||
};
|
||||
expect(body.rule.isListed).toBe(false);
|
||||
expect(body.rule).not.toHaveProperty("claimTokenHash");
|
||||
expect(body.rule).not.toHaveProperty("userId");
|
||||
});
|
||||
|
||||
it("returns viewerIsOwner true when the signed-in user owns the rule", async () => {
|
||||
isDatabaseConfiguredMock.mockReturnValue(true);
|
||||
getSessionUserMock.mockResolvedValue({ id: "user-1", email: "a@b.c" });
|
||||
|
||||
Reference in new issue
Block a user