'use strict'; const express = require('express'); const ldapClient = require('./ldapClient'); const requests = require('./requests'); const mailer = require('./mailer'); const adminSettings = require('./adminSettings'); const router = express.Router(); const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const { NAME_RE } = requests; const lastSendAt = new Map(); function errorResponse(res, err) { const status = err.status || 500; res.status(status).json({ success: false, error: err.message || 'Внутренняя ошибка сервера' }); } let takenCache = null; async function getTakenLogins() { if (takenCache && Date.now() - takenCache.at < 30000) return takenCache.logins; const users = await ldapClient.listUsers(); const taken = users.map((u) => u.login).filter(Boolean); const pending = requests.listRequests().pending; for (const r of pending) { if (r.login) taken.push(r.login); } takenCache = { at: Date.now(), logins: taken }; return taken; } router.get('/config', (req, res) => { const settings = adminSettings.getSettings(); res.json({ success: true, config: { phoneRequired: !!settings.phoneRequired, authEnabled: settings.authEnabled !== false } }); }); router.post('/send-code', async (req, res) => { const { email } = req.body || {}; if (!email || !EMAIL_RE.test(String(email))) { return res.status(400).json({ success: false, error: 'Некорректный email' }); } const now = Date.now(); const last = lastSendAt.get(String(email).toLowerCase()); if (last && now - last < 30000) { return res.status(429).json({ success: false, error: 'Код уже отправлен, подождите 30 секунд' }); } try { const { code, codeNumber } = requests.issueCode(email); await mailer.sendVerificationCode(email, code, codeNumber); lastSendAt.set(String(email).toLowerCase(), Date.now()); res.json({ success: true, codeNumber, message: `Код №${codeNumber} отправлен на указанную почту. Введите код из письма с номером ${codeNumber}.` }); } catch (err) { errorResponse(res, err); } }); router.post('/verify-code', (req, res) => { const { email, code } = req.body || {}; try { const record = requests.verifyCode(email, code); res.json({ success: true, emailVerified: !!record.emailVerified }); } catch (err) { errorResponse(res, err); } }); router.post('/submit', async (req, res) => { const surname = String(req.body.surname || '').trim(); const name = String(req.body.name || '').trim(); const patronymic = String(req.body.patronymic || '').trim(); const { email, password, position } = req.body || {}; const phone = req.body.phone; if (!surname || !name) { return res.status(400).json({ success: false, error: 'Фамилия и имя обязательны' }); } if (!NAME_RE.test(surname) || !NAME_RE.test(name) || (patronymic && !NAME_RE.test(patronymic))) { return res.status(400).json({ success: false, error: 'ФИО должно содержать только русские буквы' }); } try { const taken = await getTakenLogins(); const record = requests.submitRequest( { surname, name, patronymic, email, password, phone, position }, taken ); takenCache = null; res.json({ success: true, login: record.login, message: 'Заявка отправлена на рассмотрение администратором' }); } catch (err) { errorResponse(res, err); } }); router.post('/submit-password-change', async (req, res) => { const surname = String(req.body.surname || '').trim(); const name = String(req.body.name || '').trim(); const patronymic = String(req.body.patronymic || '').trim(); const { login, email, password, position } = req.body || {}; const phone = req.body.phone; try { const record = await requests.submitPasswordChangeRequest( { surname, name, patronymic, login, email, password, phone, position } ); res.json({ success: true, login: record.login, message: 'Заявка на смену пароля отправлена на рассмотрение администратором' }); } catch (err) { errorResponse(res, err); } }); module.exports = router;