133 lines
5.5 KiB
JavaScript
133 lines
5.5 KiB
JavaScript
const assert = require("assert");
|
|
const Database = require("better-sqlite3");
|
|
const {
|
|
accessForUser,
|
|
createEntry,
|
|
ensureTables,
|
|
getEntryBySlug,
|
|
grantPermission,
|
|
listEntries,
|
|
listPermissions,
|
|
listVersions,
|
|
revokePermission,
|
|
restoreVersion,
|
|
searchForAi,
|
|
setEntryWorkflow,
|
|
updateEntry
|
|
} = require("../backend/okf_store");
|
|
const { renderMarkdown } = require("../backend/markdown");
|
|
|
|
const db = new Database(":memory:");
|
|
db.exec(`
|
|
CREATE TABLE user_profiles (
|
|
id TEXT PRIMARY KEY,
|
|
internal_username TEXT NOT NULL UNIQUE,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
);
|
|
`);
|
|
ensureTables(db);
|
|
|
|
const now = Date.now();
|
|
db.prepare("INSERT INTO user_profiles (id, internal_username, created_at, updated_at) VALUES (?, ?, ?, ?)").run("admin-1", "Admin", now, now);
|
|
db.prepare("INSERT INTO user_profiles (id, internal_username, created_at, updated_at) VALUES (?, ?, ?, ?)").run("mod-1", "Mod", now, now);
|
|
db.prepare("INSERT INTO user_profiles (id, internal_username, created_at, updated_at) VALUES (?, ?, ?, ?)").run("user-1", "User", now, now);
|
|
db.prepare("INSERT INTO user_profiles (id, internal_username, created_at, updated_at) VALUES (?, ?, ?, ?)").run("editor-1", "Editor", now, now);
|
|
|
|
const admin = { id: "admin-1", isAdmin: true, isMod: true };
|
|
const mod = { id: "mod-1", isMod: true };
|
|
const user = { id: "user-1" };
|
|
const editor = { id: "editor-1" };
|
|
|
|
grantPermission(db, { user_id: "editor-1", level: "edit", notes: "Trusted writer" }, admin);
|
|
assert.equal(accessForUser(db, editor).canEdit, true);
|
|
assert.equal(listPermissions(db).filter((grant) => !grant.revoked_at).length, 1);
|
|
|
|
const entry = createEntry(db, {
|
|
title: "Currency basics",
|
|
slug: "currency-basics",
|
|
category: "Community",
|
|
tags: "currency, coins",
|
|
aliases: "How do coins, bonuses, and payouts work?\nWhat is currency?",
|
|
summary: "Explains the community currency.",
|
|
user_markdown: "Users earn **coins** through activity.",
|
|
moderator_markdown: "Moderators may help users with missing transaction context.",
|
|
admin_markdown: "Admin-only economy configuration details.",
|
|
ai_facts_markdown: "The primary community currency is coins.",
|
|
source_links: "/commands",
|
|
visibility: "mod",
|
|
status: "published",
|
|
review_state: "approved"
|
|
}, admin);
|
|
|
|
assert.equal(entry.slug, "currency-basics");
|
|
assert.deepEqual(entry.aliases, ["How do coins, bonuses, and payouts work?", "What is currency?"]);
|
|
assert.equal(listEntries(db, {}, user).length, 0);
|
|
assert.equal(listEntries(db, {}, mod).length, 1);
|
|
assert.equal(getEntryBySlug(db, "currency-basics", user), null);
|
|
assert.equal(getEntryBySlug(db, "currency-basics", mod).moderator_markdown.includes("Moderators"), true);
|
|
assert.equal(getEntryBySlug(db, "currency-basics", admin).admin_markdown.includes("Admin-only"), true);
|
|
assert(searchForAi(db, "currency", mod).some((item) => item.facts.includes("Moderators")));
|
|
assert.equal(searchForAi(db, "currency", user).length, 0);
|
|
|
|
const publicEntry = createEntry(db, {
|
|
title: "Public help",
|
|
slug: "public-help",
|
|
category: "Support",
|
|
summary: "Public support answer.",
|
|
user_markdown: "Everyone can read this.",
|
|
admin_markdown: "Admin-only implementation notes.",
|
|
ai_facts_markdown: "Admin AI fact.",
|
|
visibility: "user",
|
|
status: "published",
|
|
review_state: "approved"
|
|
}, admin);
|
|
const publicUserContext = searchForAi(db, "public", user);
|
|
const publicAdminContext = searchForAi(db, "public", admin);
|
|
assert(publicUserContext.some((item) => item.id === publicEntry.id));
|
|
assert.equal(publicUserContext.some((item) => item.facts.includes("Admin-only")), false);
|
|
assert(publicAdminContext.some((item) => item.facts.includes("Admin-only implementation notes.")));
|
|
assert(publicAdminContext.some((item) => item.facts.includes("Admin AI fact.")));
|
|
|
|
const proposed = createEntry(db, {
|
|
title: "Draft from editor",
|
|
slug: "draft-from-editor",
|
|
summary: "Editor draft",
|
|
user_markdown: "Draft content."
|
|
}, editor);
|
|
assert.equal(proposed.status, "draft");
|
|
assert.equal(proposed.review_state, "review_pending");
|
|
assert.equal(listEntries(db, {}, user).some((item) => item.slug === "draft-from-editor"), false);
|
|
assert.equal(listEntries(db, {}, editor, { management: true }).some((item) => item.slug === "draft-from-editor"), true);
|
|
|
|
updateEntry(db, "draft-from-editor", {
|
|
title: "Draft from editor",
|
|
slug: "draft-from-editor",
|
|
summary: "Updated editor draft",
|
|
user_markdown: "Updated draft content.",
|
|
change_note: "Editor update."
|
|
}, editor);
|
|
assert.equal(listVersions(db, proposed.id).length, 2);
|
|
|
|
const restored = restoreVersion(db, proposed.id, 1, admin, "Test restore.");
|
|
assert.equal(restored.summary, "Editor draft");
|
|
assert.equal(restored.user_markdown, "Draft content.");
|
|
assert.equal(listVersions(db, proposed.id).length, 3);
|
|
assert.equal(searchForAi(db, "draft", admin).length, 0);
|
|
|
|
setEntryWorkflow(db, "draft-from-editor", "review", admin);
|
|
setEntryWorkflow(db, "draft-from-editor", "publish", admin);
|
|
assert.equal(getEntryBySlug(db, "draft-from-editor", user).summary, "Editor draft");
|
|
|
|
assert(searchForAi(db, "currency", mod).some((item) => item.slug === "currency-basics"));
|
|
assert.equal(searchForAi(db, "admin-only economy", user).length, 0);
|
|
assert(renderMarkdown("<script>alert(1)</script> **safe**").includes("<script>"));
|
|
assert.equal(renderMarkdown("[bad](javascript:alert(1))").includes("javascript:"), false);
|
|
|
|
const grant = listPermissions(db).find((row) => row.user_id === "editor-1" && !row.revoked_at);
|
|
revokePermission(db, grant.id, admin);
|
|
assert.equal(accessForUser(db, editor).canEdit, false);
|
|
|
|
db.close();
|
|
console.log("OKF plugin verification passed.");
|