Files
nlcc-itinerary/server/utils/database.ts
2025-10-06 17:20:26 -04:00

195 lines
6.1 KiB
TypeScript

import Database from 'better-sqlite3'
import { join } from 'path'
import bcrypt from 'bcrypt'
let db: Database.Database | null = null
export interface Sermon {
id?: number
slug: string
title: string
date: string
dates?: string
bible_references: string
personal_appliance: string
pastors_challenge: string
worship_songs?: string
created_at?: string
}
export interface User {
id?: number
username: string
password: string
is_admin: number
}
export interface SermonNote {
id?: number
user_id: number
sermon_id: number
notes: string
created_at?: string
updated_at?: string
}
export function getDatabase() {
if (!db) {
const dbPath = join(process.cwd(), 'data', 'sermons.db')
db = new Database(dbPath)
// Create tables if they don't exist
db.exec(`
CREATE TABLE IF NOT EXISTS sermons (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
date TEXT NOT NULL,
dates TEXT,
bible_references TEXT NOT NULL,
personal_appliance TEXT NOT NULL,
pastors_challenge TEXT NOT NULL,
worship_songs TEXT,
archived INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`)
db.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
is_admin INTEGER DEFAULT 0
)
`)
db.exec(`
CREATE TABLE IF NOT EXISTS sermon_notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
sermon_id INTEGER NOT NULL,
notes TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (sermon_id) REFERENCES sermons(id) ON DELETE CASCADE,
UNIQUE(user_id, sermon_id)
)
`)
// Insert default admin user from environment variables with hashed password
const config = useRuntimeConfig()
const adminUsername = config.adminUsername
const adminPassword = config.adminPassword
const userExists = db.prepare('SELECT COUNT(*) as count FROM users WHERE username = ?').get(adminUsername) as { count: number }
if (userExists.count === 0) {
// Hash the password before storing
const saltRounds = 10
const hashedPassword = bcrypt.hashSync(adminPassword, saltRounds)
db.prepare('INSERT INTO users (username, password, is_admin) VALUES (?, ?, 1)').run(adminUsername, hashedPassword)
}
}
return db
}
export function getAllSermons(limit?: number, includeArchived: boolean = false) {
const db = getDatabase()
const whereClause = includeArchived ? '' : 'WHERE archived = 0'
if (limit) {
return db.prepare(`SELECT * FROM sermons ${whereClause} ORDER BY date DESC LIMIT ?`).all(limit) as Sermon[]
}
return db.prepare(`SELECT * FROM sermons ${whereClause} ORDER BY date DESC`).all() as Sermon[]
}
export function getArchivedSermons() {
const db = getDatabase()
return db.prepare('SELECT * FROM sermons WHERE archived = 1 ORDER BY date DESC').all() as Sermon[]
}
export function archiveSermon(id: number) {
const db = getDatabase()
return db.prepare('UPDATE sermons SET archived = 1 WHERE id = ?').run(id)
}
export function getSermonBySlug(slug: string) {
const db = getDatabase()
return db.prepare('SELECT * FROM sermons WHERE slug = ?').get(slug) as Sermon | undefined
}
export function createSermon(sermon: Sermon) {
const db = getDatabase()
const stmt = db.prepare(`
INSERT INTO sermons (slug, title, date, dates, bible_references, personal_appliance, pastors_challenge, worship_songs)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`)
return stmt.run(
sermon.slug,
sermon.title,
sermon.date,
sermon.dates || null,
sermon.bible_references,
sermon.personal_appliance,
sermon.pastors_challenge,
sermon.worship_songs || null
)
}
export function getUserByUsername(username: string) {
const db = getDatabase()
return db.prepare('SELECT * FROM users WHERE username = ?').get(username) as User | undefined
}
export function createUser(username: string, password: string) {
const db = getDatabase()
const saltRounds = 10
const hashedPassword = bcrypt.hashSync(password, saltRounds)
return db.prepare('INSERT INTO users (username, password, is_admin) VALUES (?, ?, 0)').run(username, hashedPassword)
}
export function getAllUsers() {
const db = getDatabase()
return db.prepare('SELECT id, username, is_admin FROM users ORDER BY username').all() as Omit<User, 'password'>[]
}
export function deleteUser(id: number) {
const db = getDatabase()
return db.prepare('DELETE FROM users WHERE id = ?').run(id)
}
export function updateUserRole(id: number, isAdmin: number) {
const db = getDatabase()
return db.prepare('UPDATE users SET is_admin = ? WHERE id = ?').run(isAdmin, id)
}
export function resetUserPassword(id: number, newPassword: string) {
const db = getDatabase()
const saltRounds = 10
const hashedPassword = bcrypt.hashSync(newPassword, saltRounds)
return db.prepare('UPDATE users SET password = ? WHERE id = ?').run(hashedPassword, id)
}
export function getSermonNote(userId: number, sermonId: number) {
const db = getDatabase()
return db.prepare('SELECT * FROM sermon_notes WHERE user_id = ? AND sermon_id = ?').get(userId, sermonId) as SermonNote | undefined
}
export function saveSermonNote(userId: number, sermonId: number, notes: string) {
const db = getDatabase()
const existing = getSermonNote(userId, sermonId)
if (existing) {
return db.prepare('UPDATE sermon_notes SET notes = ?, updated_at = CURRENT_TIMESTAMP WHERE user_id = ? AND sermon_id = ?').run(notes, userId, sermonId)
} else {
return db.prepare('INSERT INTO sermon_notes (user_id, sermon_id, notes) VALUES (?, ?, ?)').run(userId, sermonId, notes)
}
}
export function deleteSermonNote(userId: number, sermonId: number) {
const db = getDatabase()
return db.prepare('DELETE FROM sermon_notes WHERE user_id = ? AND sermon_id = ?').run(userId, sermonId)
}