111 lines
3.2 KiB
JavaScript
111 lines
3.2 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import dotenv from "dotenv";
|
|
import pg from "pg";
|
|
import bcrypt from "bcryptjs";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
dotenv.config({ path: path.resolve(__dirname, "../../../apps/web/.env") });
|
|
|
|
const { Pool } = pg;
|
|
|
|
function getDatabaseName(connectionString) {
|
|
try {
|
|
const url = new URL(connectionString);
|
|
const name = url.pathname.replace(/^\/+/, "");
|
|
return name ? decodeURIComponent(name) : "";
|
|
} catch {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
function requireAllowedDatabase() {
|
|
if (!process.env.DATABASE_URL)
|
|
throw new Error("DATABASE_URL is required");
|
|
const allowedRaw = process.env.ALLOWED_DB_NAMES;
|
|
if (!allowedRaw)
|
|
throw new Error("ALLOWED_DB_NAMES is required");
|
|
const allowed = allowedRaw
|
|
.split(",")
|
|
.map(value => value.trim().toLowerCase())
|
|
.filter(Boolean);
|
|
if (!allowed.length)
|
|
throw new Error("ALLOWED_DB_NAMES must include at least one database name");
|
|
const dbName = getDatabaseName(process.env.DATABASE_URL);
|
|
if (!dbName)
|
|
throw new Error("DATABASE_URL must include a database name");
|
|
if (!allowed.includes(dbName.toLowerCase()))
|
|
throw new Error(`DATABASE_URL must target an allowed database. Found "${dbName}"`);
|
|
}
|
|
|
|
async function main() {
|
|
requireAllowedDatabase();
|
|
|
|
const sqlPath = path.resolve(__dirname, "../../../docs/seed-ui.sql");
|
|
let sql = fs.readFileSync(sqlPath, "utf8");
|
|
if (!sql.includes("__PASSWORD_HASH__"))
|
|
throw new Error("Seed SQL missing __PASSWORD_HASH__ placeholder");
|
|
|
|
const seedPassword = process.env.SEED_PASSWORD || "FiddyDev123!";
|
|
const passwordHash = await bcrypt.hash(seedPassword, 12);
|
|
sql = sql.replaceAll("__PASSWORD_HASH__", passwordHash);
|
|
|
|
const pool = new Pool({
|
|
connectionString: process.env.DATABASE_URL,
|
|
ssl: process.env.DATABASE_SSL === "false" ? false : { rejectUnauthorized: false }
|
|
});
|
|
|
|
const client = await pool.connect();
|
|
try {
|
|
await client.query("begin");
|
|
await client.query(sql);
|
|
await client.query("commit");
|
|
|
|
const tables = [
|
|
"users",
|
|
"groups",
|
|
"group_members",
|
|
"group_settings",
|
|
"group_join_requests",
|
|
"group_invite_links",
|
|
"group_audit_log",
|
|
"tags",
|
|
"entries",
|
|
"entry_tags",
|
|
"receipts"
|
|
];
|
|
|
|
const counts = {};
|
|
for (const table of tables) {
|
|
const { rows } = await client.query(`select count(*)::int as count from ${table}`);
|
|
counts[table] = rows[0]?.count ?? 0;
|
|
}
|
|
|
|
const { rows: userRows } = await client.query("select email from users order by id");
|
|
const { rows: groupRows } = await client.query("select name from groups order by id");
|
|
|
|
console.log("UI seed complete.");
|
|
console.log("Counts:");
|
|
for (const [table, count] of Object.entries(counts))
|
|
console.log(`- ${table}: ${count}`);
|
|
console.log("Users:");
|
|
for (const row of userRows)
|
|
console.log(`- ${row.email}`);
|
|
console.log("Groups:");
|
|
for (const row of groupRows)
|
|
console.log(`- ${row.name}`);
|
|
} catch (error) {
|
|
await client.query("rollback");
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
} finally {
|
|
client.release();
|
|
await pool.end();
|
|
}
|
|
}
|
|
|
|
main();
|