104 lines
3.4 KiB
JavaScript
104 lines
3.4 KiB
JavaScript
import bcrypt from "bcryptjs";
|
|
import jwt from "jsonwebtoken";
|
|
import db from "./db.js";
|
|
import { JWT_SECRET, JWT_EXPIRES_IN } from "./config.js";
|
|
|
|
function serializeUser(row) {
|
|
if (!row) return null;
|
|
return {
|
|
id: row.id,
|
|
username: row.username,
|
|
name: row.name,
|
|
email: row.email,
|
|
isAdmin: Boolean(row.is_admin),
|
|
createdAt: row.created_at ? new Date(row.created_at).toISOString() : null
|
|
};
|
|
}
|
|
|
|
function signToken(userId) {
|
|
return jwt.sign({ sub: userId }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
|
|
}
|
|
|
|
export async function registerUser({ username, name, email, password }) {
|
|
const passwordHash = await bcrypt.hash(password, 10);
|
|
const [[{ count }]] = await db.query("SELECT COUNT(*) AS count FROM users");
|
|
const isAdmin = count === 0 ? 1 : 0;
|
|
try {
|
|
const [result] = await db.query(
|
|
`INSERT INTO users (username, name, email, password_hash, is_admin) VALUES (?, ?, ?, ?, ?)`,
|
|
[username, name, email, passwordHash, isAdmin]
|
|
);
|
|
const user = await getUserById(result.insertId);
|
|
const token = signToken(user.id);
|
|
return { user, token };
|
|
} catch (error) {
|
|
if (error?.code === "ER_DUP_ENTRY") {
|
|
const message = error.sqlMessage || "Duplicate";
|
|
if (message.includes("username")) {
|
|
error.meta = "USERNAME";
|
|
} else if (message.includes("email")) {
|
|
error.meta = "EMAIL";
|
|
}
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function authenticateUser(identifier, password) {
|
|
const [rows] = await db.query(
|
|
`SELECT * FROM users WHERE username = ? OR email = ? LIMIT 1`,
|
|
[identifier, identifier]
|
|
);
|
|
if (rows.length === 0) {
|
|
const err = new Error("Onjuiste inloggegevens.");
|
|
err.meta = "INVALID_CREDENTIALS";
|
|
throw err;
|
|
}
|
|
const row = rows[0];
|
|
const ok = await bcrypt.compare(password, row.password_hash);
|
|
if (!ok) {
|
|
const err = new Error("Onjuiste inloggegevens.");
|
|
err.meta = "INVALID_CREDENTIALS";
|
|
throw err;
|
|
}
|
|
const user = serializeUser(row);
|
|
const token = signToken(user.id);
|
|
return { user, token };
|
|
}
|
|
|
|
export async function getUserById(id) {
|
|
const [rows] = await db.query(
|
|
`SELECT id, username, name, email, is_admin, created_at FROM users WHERE id = ? LIMIT 1`,
|
|
[id]
|
|
);
|
|
return serializeUser(rows[0]);
|
|
}
|
|
|
|
export async function listUsers() {
|
|
const [rows] = await db.query(
|
|
`SELECT id, username, name, email, is_admin, created_at FROM users ORDER BY created_at ASC`
|
|
);
|
|
return rows.map(serializeUser);
|
|
}
|
|
|
|
export async function adminCreateUser({ username, name, email, password, isAdmin = false }) {
|
|
const passwordHash = await bcrypt.hash(password, 10);
|
|
try {
|
|
const [result] = await db.query(
|
|
`INSERT INTO users (username, name, email, password_hash, is_admin) VALUES (?, ?, ?, ?, ?)`,
|
|
[username, name, email, passwordHash, isAdmin ? 1 : 0]
|
|
);
|
|
return await getUserById(result.insertId);
|
|
} catch (error) {
|
|
if (error?.code === "ER_DUP_ENTRY") {
|
|
const message = error.sqlMessage || "Duplicate";
|
|
if (message.includes("username")) {
|
|
error.meta = "USERNAME";
|
|
} else if (message.includes("email")) {
|
|
error.meta = "EMAIL";
|
|
}
|
|
}
|
|
throw error;
|
|
}
|
|
}
|