Forked from Forthena (PERSONAL/forthena) and retargeted: - NO login, NO LLM: the edition is public and the ranking is deterministic (stories that name Sen. BAM lead; freshest first) — Daniel: no like/dislike or store profile for visitors. - Crawler scoped to BAM: Bing news keyword queries + Inquirer/Rappler fallback wires, with a two-tier relevance gate (named-BAM always; Aquino+legislative-context only from fallback) so op-eds and non-Bam senators are dropped. - Desks: BAM (lead), Gaming, Education, Politics, Energy, PH, Business. - Community board /board: 'Thank you Senator BAM' — nickname-only posts, HTML-stripped, URL-only rejected, IP rate-limited (3/10min, 20/day). - Yellow-gamer theme (Orbitron/Rajdhani/JetBrains Mono, dark + gold, HUD corners), supporter disclaimer in header and footer. - Tests: category/date/relevance/text suites + Mongo board suite + full HTTP e2e (all passing). Infra: 66.181.46.132 (bidaangmamamayan.com), local Mongo 7.0, nginx + certbot TLS, PM2 bama (:3000) + 15-min crawl cron.
41 lines
1.9 KiB
JavaScript
41 lines
1.9 KiB
JavaScript
// Desk registry — the 7-desk tribute era.
|
|
// Verifies lib/categories.js: unique keys, labels, normalize fallback to "bam",
|
|
// and the classifier's ordering (gaming/education/energy before politics/ph).
|
|
import { CATEGORIES, CATEGORY_KEYS, normalizeCategory, sectionName, classifyStory } from "../lib/categories.js";
|
|
|
|
let fails = 0;
|
|
const check = (name, cond, detail = "") => {
|
|
console.log(` ${cond ? "ok " : "FAIL"} ${name}${detail ? " — " + detail : ""}`);
|
|
if (!cond) fails++;
|
|
};
|
|
|
|
console.log("registry:");
|
|
check("7 desks", CATEGORIES.length === 7, `got ${CATEGORIES.length}`);
|
|
check("unique keys", new Set(CATEGORIES.map((c) => c.key)).size === CATEGORIES.length);
|
|
check("keys valid", [...CATEGORY_KEYS].every((k) => /^[a-z-]+$/.test(k)));
|
|
check("every desk has a label", CATEGORIES.every((c) => typeof c.label === "string" && c.label.length > 2));
|
|
|
|
console.log("normalize:");
|
|
check("bam stays bam", normalizeCategory("bam") === "bam");
|
|
check("education stays", normalizeCategory("education") === "education");
|
|
check("junk falls to bam", normalizeCategory("nonsense") === "bam");
|
|
check("null falls to bam", normalizeCategory(null) === "bam");
|
|
check("sectionName of junk is the lead desk", sectionName("??") === "BAM Front");
|
|
|
|
console.log("classify (order matters):");
|
|
const fixtures = [
|
|
["Sen. Bam Aquino, esports runner-up, opens gaming center", "gaming"],
|
|
["Bam Aquino pushes scholarship bill for college students", "education"],
|
|
["Senator backs VAT removal on power system losses", "energy"],
|
|
["Senate committee approves barangay terms bill", "politics"],
|
|
["Pampanga floods hit three towns", "ph"],
|
|
["Aquino joins senate floor vote on trade", "politics"],
|
|
["A story with no keywords at all", "bam"],
|
|
];
|
|
for (const [text, want] of fixtures) {
|
|
check(`"${text.slice(0, 44)}..." -> ${want}`, classifyStory({ title: text }) === want, `got ${classifyStory({ title: text })}`);
|
|
}
|
|
|
|
console.log(fails ? `\n${fails} FAILED` : "\nall passed");
|
|
process.exit(fails ? 1 : 0);
|