Files
AI Bot cbf44587aa
Build and Deploy / build-and-push (push) Successful in 1m0s
feat: User management, SMTP email activation and password resets
2026-09-17 08:49:11 +05:30

107 lines
2.9 KiB
JavaScript

const { Pool } = require('pg');
require('dotenv').config();
// Coolify uses DATABASE_URL
// If not set, we can fallback to a local postgres or just let it fail
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
pool.on('error', (err, client) => {
console.error('Unexpected error on idle client', err);
process.exit(-1);
});
const initDB = async () => {
try {
const client = await pool.connect();
console.log('Connected to the PostgreSQL database.');
await client.query(`
CREATE TABLE IF NOT EXISTS profiles (
id TEXT PRIMARY KEY,
email TEXT UNIQUE,
password_hash TEXT,
role TEXT DEFAULT 'user',
api_credits INTEGER DEFAULT 10,
storage_limit_mb INTEGER DEFAULT 500,
is_active BOOLEAN DEFAULT false,
api_keys TEXT
)
`);
// In Postgres, ALTER TABLE ADD COLUMN IF NOT EXISTS requires PG >= 9.6
// So we can catch the error if column exists just like sqlite logic
try {
await client.query(`ALTER TABLE profiles ADD COLUMN is_active BOOLEAN DEFAULT false`);
} catch (err) {
// Ignore if it already exists
}
try {
await client.query(`ALTER TABLE profiles ADD COLUMN api_keys TEXT`);
} catch (err) {
// Ignore if it already exists
}
try {
await client.query(`ALTER TABLE profiles ADD COLUMN activation_token TEXT`);
} catch (err) {
// Ignore if it already exists
}
try {
await client.query(`ALTER TABLE profiles ADD COLUMN reset_token TEXT`);
} catch (err) {
// Ignore if it already exists
}
await client.query(`
CREATE TABLE IF NOT EXISTS projects (
id TEXT PRIMARY KEY,
user_id TEXT REFERENCES profiles(id),
name TEXT,
scene_data TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
client.release();
} catch (err) {
console.error('Error initializing database:', err);
}
};
initDB();
// Wrapper functions to simulate the old sqlite API but backed by pg
const run = async (sql, params = []) => {
// convert ? to $1, $2, etc.
let paramIndex = 1;
const pgSql = sql.replace(/\?/g, () => `$${paramIndex++}`);
const res = await pool.query(pgSql, params);
// `run` in sqlite returns { id: this.lastID, changes: this.changes }
// Postgres doesn't return lastID unless RETURNING is used, but for uuids it doesn't matter.
return { changes: res.rowCount };
};
const get = async (sql, params = []) => {
let paramIndex = 1;
const pgSql = sql.replace(/\?/g, () => `$${paramIndex++}`);
const res = await pool.query(pgSql, params);
return res.rows[0];
};
const all = async (sql, params = []) => {
let paramIndex = 1;
const pgSql = sql.replace(/\?/g, () => `$${paramIndex++}`);
const res = await pool.query(pgSql, params);
return res.rows;
};
module.exports = { db: pool, run, get, all };