/
El_Capulco
/
Clinic
Обзор
Документация
Войти
/
El_Capulco
/
Clinic
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
server/src/services/authService.js
161 строка
5 KB
Phofan
Готовый проект
24 мар 2026, 19:09
24 мар 2026, 19:09
4fc54b6
Код
Авторство
О чём код?
import bcrypt from "bcrypt"; import { pool } from "../db/pool.js"; import { HttpError } from "../utils/httpError.js"; const SALT_ROUNDS = 10; export async function login({ name, password }) { if (!name || !password) throw new HttpError(400, "name and password are required"); const [rows] = await pool.query( "SELECT id, name, role, doctor_id, password_hash FROM users WHERE name=? LIMIT 1", [name] ); if (!rows.length) throw new HttpError(401, "Invalid credentials"); const user = rows[0]; const ok = await bcrypt.compare(password, user.password_hash); if (!ok) throw new HttpError(401, "Invalid credentials"); // pending -> логин запрещён до одобрения if (user.role === "pending") throw new HttpError(403, "Account is pending approval"); return user; } export async function getMe(userId) { const [rows] = await pool.query( "SELECT id, name, role, doctor_id FROM users WHERE id=? LIMIT 1", [userId] ); return rows[0] || null; } // Саморегистрация -> pending export async function registerUser({ name, password }) { if (!name || !password) throw new HttpError(400, "name and password are required"); const [exists] = await pool.query("SELECT id FROM users WHERE name=? LIMIT 1", [name]); if (exists.length) throw new HttpError(409, "User already exists"); const passwordHash = await bcrypt.hash(password, SALT_ROUNDS); await pool.query( "INSERT INTO users (id, name, role, doctor_id, password_hash) VALUES (UUID(), ?, 'pending', NULL, ?)", [name, passwordHash] ); const [rows] = await pool.query( "SELECT id, name, role, doctor_id FROM users WHERE name=? ORDER BY created_at DESC LIMIT 1", [name] ); return rows[0]; } // Админ может создавать пользователей сразу с ролью export async function createUser({ name, role, password, doctorId = null }) { if (!name || !role || !password) throw new HttpError(400, "name, role, password are required"); const passwordHash = await bcrypt.hash(password, SALT_ROUNDS); await pool.query( "INSERT INTO users (id, name, role, doctor_id, password_hash) VALUES (UUID(), ?, ?, ?, ?)", [name, role, doctorId, passwordHash] ); const [rows] = await pool.query( "SELECT id, name, role, doctor_id FROM users WHERE name=? ORDER BY created_at DESC LIMIT 1", [name] ); return rows[0]; } // Админ меняет роль пользователю (pending -> registrar/admin/pending) // (doctor теперь назначаем через approveDoctorUser, чтобы создать запись doctors) export async function setUserRole({ userId, role }) { if (!userId || !role) throw new HttpError(400, "userId and role are required"); const allowed = new Set(["admin", "registrar", "pending", "doctor"]); if (!allowed.has(role)) throw new HttpError(400, "Invalid role"); // Если кто-то попытается поставить doctor через этот endpoint — просим использовать approve-doctor if (role === "doctor") { throw new HttpError(400, "Use /users/:id/approve-doctor to assign doctor role"); } const [result] = await pool.query("UPDATE users SET role=?, doctor_id=NULL WHERE id=?", [ role, userId ]); if (result.affectedRows === 0) throw new HttpError(404, "User not found"); const [rows] = await pool.query( "SELECT id, name, role, doctor_id FROM users WHERE id=? LIMIT 1", [userId] ); return rows[0]; } // Список пользователей (для админки), можно фильтровать по роли export async function listUsers({ role } = {}) { const params = []; let where = ""; if (role) { where = "WHERE role=?"; params.push(role); } const [rows] = await pool.query( ` SELECT id, name, role, doctor_id, created_at FROM users ${where} ORDER BY created_at DESC `, params ); return rows; } // Отклонить заявку: удалить только pending export async function deletePendingUser(userId) { if (!userId) throw new HttpError(400, "userId is required"); const [result] = await pool.query("DELETE FROM users WHERE id=? AND role='pending'", [userId]); if (result.affectedRows === 0) { throw new HttpError(404, "Pending user not found"); } return true; } // Назначить doctor: создать запись в doctors и привязать к user // ВАЖНО: предполагается таблица doctors с полями (id AUTO_INCREMENT, fio, specialty, phone, cabinet) export async function approveDoctorUser({ userId, fio, specialty, phone, cabinet }) { if (!userId) throw new HttpError(400, "userId is required"); if (!fio || !specialty) throw new HttpError(400, "fio and specialty are required"); // создаём доктора const [doctorRes] = await pool.query( "INSERT INTO doctors (fio, specialty, phone, cabinet) VALUES (?, ?, ?, ?)", [fio, specialty, phone || null, cabinet || null] ); const doctorId = doctorRes.insertId; // назначаем пользователю роль doctor и привязываем doctor_id const [userRes] = await pool.query("UPDATE users SET role='doctor', doctor_id=? WHERE id=?", [ doctorId, userId ]); if (userRes.affectedRows === 0) throw new HttpError(404, "User not found"); return { doctorId }; }