93 lines
2.7 KiB
JavaScript
93 lines
2.7 KiB
JavaScript
import mysql from 'mysql2/promise';
|
|
|
|
let pool = null;
|
|
|
|
export function getPool() {
|
|
if (pool) return pool;
|
|
pool = mysql.createPool({
|
|
host: process.env.MYSQL_HOST || 'localhost',
|
|
port: Number(process.env.MYSQL_PORT) || 3306,
|
|
user: process.env.MYSQL_USER || 'root',
|
|
password: process.env.MYSQL_PASSWORD || '',
|
|
database: process.env.MYSQL_DATABASE || 'esp32block',
|
|
waitForConnections: true,
|
|
connectionLimit: 8,
|
|
queueLimit: 0,
|
|
charset: 'utf8mb4',
|
|
});
|
|
return pool;
|
|
}
|
|
|
|
export async function bootstrap() {
|
|
const db = getPool();
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
username VARCHAR(64) NOT NULL UNIQUE,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
role ENUM('student','teacher') NOT NULL DEFAULT 'student',
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
|
`);
|
|
await db.query(`
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
token CHAR(48) PRIMARY KEY,
|
|
user_id INT NOT NULL,
|
|
expires_at DATETIME NOT NULL,
|
|
INDEX idx_sessions_user (user_id),
|
|
CONSTRAINT fk_sessions_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
|
`);
|
|
}
|
|
|
|
export async function findUserByUsername(username) {
|
|
const [rows] = await getPool().query(
|
|
'SELECT id, username, password_hash, role FROM users WHERE username = ? LIMIT 1',
|
|
[username],
|
|
);
|
|
return rows[0] || null;
|
|
}
|
|
|
|
export async function findUserById(id) {
|
|
const [rows] = await getPool().query(
|
|
'SELECT id, username, role FROM users WHERE id = ? LIMIT 1',
|
|
[id],
|
|
);
|
|
return rows[0] || null;
|
|
}
|
|
|
|
export async function createUser({ username, passwordHash, role = 'student' }) {
|
|
const [result] = await getPool().query(
|
|
'INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)',
|
|
[username, passwordHash, role],
|
|
);
|
|
return { id: result.insertId, username, role };
|
|
}
|
|
|
|
export async function createSession({ token, userId, expiresAt }) {
|
|
await getPool().query(
|
|
'INSERT INTO sessions (token, user_id, expires_at) VALUES (?, ?, ?)',
|
|
[token, userId, expiresAt],
|
|
);
|
|
}
|
|
|
|
export async function findSession(token) {
|
|
const [rows] = await getPool().query(
|
|
`SELECT s.token, s.user_id, s.expires_at, u.username, u.role
|
|
FROM sessions s
|
|
JOIN users u ON u.id = s.user_id
|
|
WHERE s.token = ? AND s.expires_at > NOW()
|
|
LIMIT 1`,
|
|
[token],
|
|
);
|
|
return rows[0] || null;
|
|
}
|
|
|
|
export async function deleteSession(token) {
|
|
await getPool().query('DELETE FROM sessions WHERE token = ?', [token]);
|
|
}
|
|
|
|
export async function purgeExpiredSessions() {
|
|
await getPool().query('DELETE FROM sessions WHERE expires_at <= NOW()');
|
|
}
|