110 lines
4.2 KiB
JavaScript
110 lines
4.2 KiB
JavaScript
'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; |