Self-service password reset
This commit is contained in:
@@ -21,9 +21,20 @@ export interface User {
|
||||
id?: number
|
||||
username: string
|
||||
password: string
|
||||
email?: string
|
||||
first_name?: string
|
||||
last_name?: string
|
||||
is_admin: number
|
||||
}
|
||||
|
||||
export interface PasswordResetCode {
|
||||
id?: number
|
||||
email: string
|
||||
code: string
|
||||
expires_at: string
|
||||
created_at?: string
|
||||
}
|
||||
|
||||
export interface SermonNote {
|
||||
id?: number
|
||||
user_id: number
|
||||
@@ -60,10 +71,23 @@ export function getDatabase() {
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
email TEXT,
|
||||
first_name TEXT,
|
||||
last_name TEXT,
|
||||
is_admin INTEGER DEFAULT 0
|
||||
)
|
||||
`)
|
||||
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS password_reset_codes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
email TEXT NOT NULL,
|
||||
code TEXT NOT NULL,
|
||||
expires_at DATETIME NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`)
|
||||
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS sermon_notes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -143,16 +167,48 @@ export function getUserByUsername(username: string) {
|
||||
return db.prepare('SELECT * FROM users WHERE username = ?').get(username) as User | undefined
|
||||
}
|
||||
|
||||
export function createUser(username: string, password: string) {
|
||||
export function createUser(username: string, password: string, email?: string, firstName?: string, lastName?: 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)
|
||||
return db.prepare('INSERT INTO users (username, password, email, first_name, last_name, is_admin) VALUES (?, ?, ?, ?, ?, 0)')
|
||||
.run(username, hashedPassword, email || null, firstName || null, lastName || null)
|
||||
}
|
||||
|
||||
export function getUserByEmail(email: string) {
|
||||
const db = getDatabase()
|
||||
return db.prepare('SELECT * FROM users WHERE email = ?').get(email) as User | undefined
|
||||
}
|
||||
|
||||
export function createPasswordResetCode(email: string, code: string, expiresAt: string) {
|
||||
const db = getDatabase()
|
||||
// Delete any existing codes for this email
|
||||
db.prepare('DELETE FROM password_reset_codes WHERE email = ?').run(email)
|
||||
return db.prepare('INSERT INTO password_reset_codes (email, code, expires_at) VALUES (?, ?, ?)')
|
||||
.run(email, code, expiresAt)
|
||||
}
|
||||
|
||||
export function getPasswordResetCode(email: string, code: string) {
|
||||
const db = getDatabase()
|
||||
return db.prepare('SELECT * FROM password_reset_codes WHERE email = ? AND code = ? AND expires_at > datetime("now")')
|
||||
.get(email, code) as PasswordResetCode | undefined
|
||||
}
|
||||
|
||||
export function deletePasswordResetCode(email: string) {
|
||||
const db = getDatabase()
|
||||
return db.prepare('DELETE FROM password_reset_codes WHERE email = ?').run(email)
|
||||
}
|
||||
|
||||
export function resetPasswordByEmail(email: string, newPassword: string) {
|
||||
const db = getDatabase()
|
||||
const saltRounds = 10
|
||||
const hashedPassword = bcrypt.hashSync(newPassword, saltRounds)
|
||||
return db.prepare('UPDATE users SET password = ? WHERE email = ?').run(hashedPassword, email)
|
||||
}
|
||||
|
||||
export function getAllUsers() {
|
||||
const db = getDatabase()
|
||||
return db.prepare('SELECT id, username, is_admin FROM users ORDER BY username').all() as Omit<User, 'password'>[]
|
||||
return db.prepare('SELECT id, username, email, first_name, last_name, is_admin FROM users ORDER BY username').all() as Omit<User, 'password'>[]
|
||||
}
|
||||
|
||||
export function deleteUser(id: number) {
|
||||
|
||||
Reference in New Issue
Block a user