Self-hosted multi-platform broadcast newsroom for activist collectives: publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style column wall with hostile-content-safe rendering, live control room with Auto Director, bridged chat governance with polls and quorum, distributed sandboxed transcode workers, encrypted content-addressed archive, monthly analytics. MIT licensed. See README.md and docs/.
12 lines
1.1 KiB
TypeScript
12 lines
1.1 KiB
TypeScript
import type { Pool } from "pg";
|
|
/** No runtime DDL: code refuses an incomplete or incorrectly privileged schema. */
|
|
export async function assertPublishingSchema(pool: Pool): Promise<void> {
|
|
const result = await pool.query<{ ready: boolean }>(`SELECT
|
|
EXISTS (SELECT 1 FROM schema_migrations WHERE name = '019_publishing_integration.sql')
|
|
AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'publishing_attempts' AND column_name = 'first_dispatch_started_at')
|
|
AND (SELECT count(*) = 2 AND bool_and(relrowsecurity AND relforcerowsecurity) FROM pg_class WHERE oid IN ('publishing_attempts'::regclass, 'publishing_receipts'::regclass))
|
|
AND NOT EXISTS (SELECT 1 FROM pg_index WHERE indrelid IN ('publishing_attempts'::regclass, 'publishing_receipts'::regclass) AND NOT indisvalid)
|
|
AND current_user = 'sp_app'
|
|
AND NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = current_user AND (rolsuper OR rolbypassrls)) AS ready`);
|
|
if (result.rows[0]?.ready !== true) throw new Error("PUBLISHING_SCHEMA_NOT_READY");
|
|
}
|