2025-05-21 22:13:09 +07:00
|
|
|
|
// Контроллер аутентификации
|
|
|
|
|
const User = require('../models/User');
|
|
|
|
|
const jwt = require('jsonwebtoken');
|
2025-05-25 22:36:17 +07:00
|
|
|
|
const profanityFilter = require('../utils/profanityFilter');
|
2025-05-21 22:13:09 +07:00
|
|
|
|
|
|
|
|
|
// Вспомогательная функция для генерации JWT
|
|
|
|
|
const generateToken = (id) => {
|
|
|
|
|
return jwt.sign({ id }, process.env.JWT_SECRET, {
|
|
|
|
|
expiresIn: '30d',
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// @desc Регистрация нового пользователя
|
|
|
|
|
// @route POST /api/auth/register
|
|
|
|
|
// @access Public
|
|
|
|
|
const registerUser = async (req, res, next) => {
|
|
|
|
|
try {
|
2025-05-25 20:47:11 +07:00
|
|
|
|
const { name, email, password, dateOfBirth, gender, city } = req.body;
|
2025-05-21 22:13:09 +07:00
|
|
|
|
|
|
|
|
|
console.log('Начало регистрации пользователя с email:', email);
|
|
|
|
|
|
2025-05-25 01:35:58 +07:00
|
|
|
|
if (!name || !email || !password || !dateOfBirth) {
|
2025-05-21 22:13:09 +07:00
|
|
|
|
res.status(400);
|
2025-05-25 01:35:58 +07:00
|
|
|
|
throw new Error('Пожалуйста, заполните все обязательные поля: имя, email, пароль и дату рождения.');
|
2025-05-21 22:13:09 +07:00
|
|
|
|
}
|
2025-05-25 20:47:11 +07:00
|
|
|
|
|
|
|
|
|
// Проверяем наличие города
|
|
|
|
|
if (!city) {
|
|
|
|
|
res.status(400);
|
|
|
|
|
throw new Error('Пожалуйста, выберите город.');
|
|
|
|
|
}
|
2025-05-21 22:13:09 +07:00
|
|
|
|
|
2025-05-25 22:36:17 +07:00
|
|
|
|
// Проверка имени на наличие запрещенных слов
|
2025-05-26 01:28:53 +07:00
|
|
|
|
if (await profanityFilter.isProfane(name)) {
|
2025-05-25 22:36:17 +07:00
|
|
|
|
res.status(400);
|
|
|
|
|
throw new Error('Имя содержит запрещённые слова. Пожалуйста, используйте другое имя.');
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-25 02:29:07 +07:00
|
|
|
|
// Проверка возраста (минимум 14 лет)
|
|
|
|
|
const birthDate = new Date(dateOfBirth);
|
|
|
|
|
const today = new Date();
|
|
|
|
|
let age = today.getFullYear() - birthDate.getFullYear();
|
|
|
|
|
const monthDiff = today.getMonth() - birthDate.getMonth();
|
|
|
|
|
|
|
|
|
|
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
|
|
|
|
age--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (age < 14) {
|
|
|
|
|
res.status(400);
|
|
|
|
|
throw new Error('Для регистрации необходим возраст не менее 14 лет.');
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-21 22:13:09 +07:00
|
|
|
|
const normalizedEmail = email.toLowerCase();
|
|
|
|
|
console.log('Нормализованный email для поиска:', normalizedEmail);
|
|
|
|
|
|
|
|
|
|
const userExists = await User.findOne({ email: normalizedEmail });
|
|
|
|
|
|
|
|
|
|
if (userExists) {
|
|
|
|
|
console.log('Пользователь с таким email уже существует');
|
|
|
|
|
res.status(400);
|
|
|
|
|
throw new Error('Пользователь с таким email уже существует.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Создание нового пользователя...');
|
|
|
|
|
const user = await User.create({
|
|
|
|
|
name,
|
|
|
|
|
email: normalizedEmail,
|
|
|
|
|
password,
|
|
|
|
|
dateOfBirth,
|
|
|
|
|
gender,
|
2025-05-25 20:47:11 +07:00
|
|
|
|
location: {
|
|
|
|
|
city: city,
|
|
|
|
|
country: 'Россия' // Устанавливаем страну по умолчанию
|
|
|
|
|
}
|
2025-05-21 22:13:09 +07:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('Пользователь создан успешно:', user ? 'Да' : 'Нет', 'ID:', user ? user._id : 'N/A');
|
|
|
|
|
|
|
|
|
|
if (user) {
|
|
|
|
|
res.status(201).json({
|
|
|
|
|
_id: user._id,
|
|
|
|
|
name: user.name,
|
|
|
|
|
email: user.email,
|
|
|
|
|
token: generateToken(user._id),
|
|
|
|
|
message: 'Пользователь успешно зарегистрирован!'
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
res.status(400);
|
|
|
|
|
throw new Error('Неверные данные пользователя. Не удалось создать пользователя.');
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Ошибка при регистрации:', error.message);
|
|
|
|
|
if (!res.statusCode || res.statusCode < 400) {
|
|
|
|
|
res.status(400);
|
|
|
|
|
}
|
|
|
|
|
res.json({ message: error.message, stack: process.env.NODE_ENV === 'production' ? null : error.stack });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// @desc Аутентификация пользователя и получение токена (Вход)
|
|
|
|
|
// @route POST /api/auth/login
|
|
|
|
|
// @access Public
|
|
|
|
|
const loginUser = async (req, res, next) => {
|
|
|
|
|
try {
|
|
|
|
|
const { email, password } = req.body;
|
|
|
|
|
|
2025-05-25 23:15:46 +07:00
|
|
|
|
console.log('Попытка входа с email/логином:', email);
|
2025-05-21 22:13:09 +07:00
|
|
|
|
|
|
|
|
|
if (!email || !password) {
|
|
|
|
|
res.status(400);
|
|
|
|
|
throw new Error('Пожалуйста, укажите email и пароль.');
|
2025-05-26 12:05:51 +07:00
|
|
|
|
} // Проверяем наличие специального логина для администратора
|
2025-05-25 23:15:46 +07:00
|
|
|
|
if (email === 'admin') {
|
2025-05-26 12:11:18 +07:00
|
|
|
|
// Для логина "admin" проверяем аккаунт admin@example.com
|
|
|
|
|
console.log('Попытка входа с административным логином через "admin"');
|
|
|
|
|
const user = await User.findOne({ email: 'admin@example.com' }).select('+password');
|
2025-05-25 23:15:46 +07:00
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
console.log('Административный аккаунт не найден в базе данных');
|
2025-05-26 12:05:51 +07:00
|
|
|
|
console.log('Создание административного аккаунта...');
|
|
|
|
|
|
|
|
|
|
try {
|
2025-05-26 12:11:18 +07:00
|
|
|
|
// Если админ не найден, создаем его с валидным email
|
2025-05-26 12:05:51 +07:00
|
|
|
|
const adminUser = new User({
|
|
|
|
|
name: 'Администратор',
|
2025-05-26 12:11:18 +07:00
|
|
|
|
email: 'admin@example.com', // Используем валидный email
|
2025-05-26 12:05:51 +07:00
|
|
|
|
password: 'admin124', // Пароль будет хеширован pre-save hook
|
|
|
|
|
dateOfBirth: new Date('1990-01-01'),
|
|
|
|
|
gender: 'other',
|
|
|
|
|
isActive: true,
|
|
|
|
|
isAdmin: true,
|
|
|
|
|
location: {
|
|
|
|
|
city: 'Admin',
|
|
|
|
|
country: 'System'
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await adminUser.save();
|
|
|
|
|
console.log('Административный аккаунт создан успешно');
|
|
|
|
|
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
_id: adminUser._id,
|
|
|
|
|
name: adminUser.name,
|
|
|
|
|
email: adminUser.email,
|
|
|
|
|
isAdmin: true,
|
|
|
|
|
token: generateToken(adminUser._id),
|
|
|
|
|
message: 'Административный аккаунт создан. Вход выполнен успешно!'
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
} catch (adminError) {
|
|
|
|
|
console.error('Ошибка при создании админ-аккаунта:', adminError);
|
|
|
|
|
res.status(401);
|
|
|
|
|
throw new Error('Неверный логин или пароль. Не удалось создать админа автоматически.');
|
|
|
|
|
}
|
2025-05-25 23:15:46 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!user.password) {
|
|
|
|
|
console.error('Ошибка: Пароль не загружен из базы данных для административного аккаунта');
|
|
|
|
|
res.status(500);
|
|
|
|
|
throw new Error('Внутренняя ошибка сервера при проверке учетных данных.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Проверка пароля для административного аккаунта...');
|
|
|
|
|
const isMatch = await user.matchPassword(password);
|
|
|
|
|
console.log('Результат проверки пароля:', isMatch ? 'Успешно' : 'Неверный пароль');
|
|
|
|
|
|
|
|
|
|
if (isMatch) {
|
2025-05-26 12:05:51 +07:00
|
|
|
|
// Обновляем дату последнего входа
|
|
|
|
|
user.lastSeen = new Date();
|
|
|
|
|
await user.save();
|
|
|
|
|
|
2025-05-25 23:15:46 +07:00
|
|
|
|
res.status(200).json({
|
|
|
|
|
_id: user._id,
|
|
|
|
|
name: user.name,
|
|
|
|
|
email: user.email,
|
|
|
|
|
isAdmin: user.isAdmin || false,
|
|
|
|
|
token: generateToken(user._id),
|
|
|
|
|
message: 'Вход выполнен успешно!'
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
res.status(401);
|
|
|
|
|
throw new Error('Неверный логин или пароль.');
|
|
|
|
|
}
|
|
|
|
|
return;
|
2025-05-26 12:17:22 +07:00
|
|
|
|
} // Перед проверкой обычных пользователей, проверим наличие админа с email
|
2025-05-26 12:05:51 +07:00
|
|
|
|
if (email === 'admin@example.com') {
|
|
|
|
|
console.log('Попытка входа с email администратора: admin@example.com');
|
2025-05-26 12:17:22 +07:00
|
|
|
|
// Проверяем наличие админа с email admin@example.com
|
|
|
|
|
const adminUser = await User.findOne({ email: 'admin@example.com' }).select('+password');
|
2025-05-26 12:05:51 +07:00
|
|
|
|
|
|
|
|
|
if (adminUser && await adminUser.matchPassword(password)) {
|
2025-05-26 12:17:22 +07:00
|
|
|
|
console.log('Успешный вход через email администратора');
|
2025-05-26 12:05:51 +07:00
|
|
|
|
// Обновляем дату последнего входа
|
|
|
|
|
adminUser.lastSeen = new Date();
|
|
|
|
|
await adminUser.save();
|
|
|
|
|
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
_id: adminUser._id,
|
|
|
|
|
name: adminUser.name,
|
|
|
|
|
email: adminUser.email,
|
|
|
|
|
isAdmin: true,
|
|
|
|
|
token: generateToken(adminUser._id),
|
|
|
|
|
message: 'Вход выполнен успешно!'
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-25 23:15:46 +07:00
|
|
|
|
// Для обычных пользователей продолжаем проверку email
|
2025-05-21 22:13:09 +07:00
|
|
|
|
const normalizedEmail = email.toLowerCase();
|
|
|
|
|
console.log('Нормализованный email для поиска:', normalizedEmail);
|
|
|
|
|
|
|
|
|
|
const user = await User.findOne({ email: normalizedEmail }).select('+password');
|
|
|
|
|
|
|
|
|
|
console.log('Найден пользователь:', user ? 'Да' : 'Нет');
|
|
|
|
|
console.log('Пользователь содержит пароль:', user && user.password ? 'Да' : 'Нет');
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
console.log('Пользователь не найден в базе данных');
|
|
|
|
|
res.status(401);
|
|
|
|
|
throw new Error('Неверный email или пароль.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!user.password) {
|
|
|
|
|
console.error('Ошибка: Пароль не загружен из базы данных');
|
|
|
|
|
res.status(500);
|
|
|
|
|
throw new Error('Внутренняя ошибка сервера при проверке учетных данных.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Проверка пароля...');
|
|
|
|
|
const isMatch = await user.matchPassword(password);
|
|
|
|
|
console.log('Результат проверки пароля:', isMatch ? 'Успешно' : 'Неверный пароль');
|
|
|
|
|
|
2025-05-25 23:11:02 +07:00
|
|
|
|
// Проверка если аккаунт неактивен (заблокирован)
|
|
|
|
|
if (isMatch && !user.isActive && !user.isAdmin) {
|
2025-05-26 19:50:52 +07:00
|
|
|
|
console.log('[AuthController] Пользователь заблокирован, но создаем токен для восстановления сессии');
|
|
|
|
|
|
|
|
|
|
// Создаем токен для последующего восстановления сессии после разблокировки
|
|
|
|
|
const restorationToken = generateToken(user._id);
|
|
|
|
|
|
|
|
|
|
// Обновляем дату последнего входа даже для заблокированного пользователя
|
|
|
|
|
user.lastSeen = new Date();
|
|
|
|
|
await user.save();
|
|
|
|
|
|
2025-05-25 23:11:02 +07:00
|
|
|
|
res.status(403);
|
2025-05-26 19:50:52 +07:00
|
|
|
|
const error = new Error('Ваш аккаунт заблокирован. Пожалуйста, обратитесь в поддержку.');
|
|
|
|
|
error.blocked = true;
|
|
|
|
|
error.userId = user._id;
|
|
|
|
|
error.restorationToken = restorationToken; // Добавляем токен для восстановления
|
|
|
|
|
error.userName = user.name;
|
|
|
|
|
throw error;
|
2025-05-25 23:11:02 +07:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-21 22:13:09 +07:00
|
|
|
|
if (isMatch) {
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
_id: user._id,
|
|
|
|
|
name: user.name,
|
|
|
|
|
email: user.email,
|
2025-05-25 23:11:02 +07:00
|
|
|
|
isAdmin: user.isAdmin || false, // Добавляем информацию о правах администратора
|
2025-05-21 22:13:09 +07:00
|
|
|
|
token: generateToken(user._id),
|
|
|
|
|
message: 'Вход выполнен успешно!'
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
res.status(401);
|
|
|
|
|
throw new Error('Неверный email или пароль.');
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Ошибка при входе:', error.message);
|
|
|
|
|
if (!res.statusCode || res.statusCode < 400) {
|
|
|
|
|
res.status(401);
|
|
|
|
|
}
|
2025-05-26 19:50:52 +07:00
|
|
|
|
|
|
|
|
|
// Специальная обработка для заблокированных аккаунтов
|
|
|
|
|
if (error.blocked && error.restorationToken) {
|
|
|
|
|
return res.json({
|
|
|
|
|
message: error.message,
|
|
|
|
|
blocked: true,
|
|
|
|
|
userId: error.userId,
|
|
|
|
|
restorationToken: error.restorationToken,
|
|
|
|
|
userName: error.userName,
|
|
|
|
|
stack: process.env.NODE_ENV === 'production' ? null : error.stack
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-21 22:13:09 +07:00
|
|
|
|
res.json({ message: error.message, stack: process.env.NODE_ENV === 'production' ? null : error.stack });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// @desc Получение данных профиля текущего пользователя
|
|
|
|
|
// @route GET /api/auth/me
|
|
|
|
|
// @access Private
|
|
|
|
|
const getMe = async (req, res, next) => {
|
|
|
|
|
try {
|
|
|
|
|
if (!req.user) {
|
|
|
|
|
res.status(404);
|
|
|
|
|
throw new Error('Пользователь не найден.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
_id: req.user._id,
|
|
|
|
|
name: req.user.name,
|
|
|
|
|
email: req.user.email,
|
|
|
|
|
dateOfBirth: req.user.dateOfBirth,
|
|
|
|
|
gender: req.user.gender,
|
|
|
|
|
bio: req.user.bio,
|
|
|
|
|
photos: req.user.photos,
|
|
|
|
|
location: req.user.location,
|
|
|
|
|
preferences: req.user.preferences,
|
2025-05-25 23:30:52 +07:00
|
|
|
|
isAdmin: req.user.isAdmin || false, // Добавляем информацию об административных правах
|
2025-05-21 22:13:09 +07:00
|
|
|
|
createdAt: req.user.createdAt,
|
|
|
|
|
updatedAt: req.user.updatedAt,
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Ошибка при получении данных пользователя:', error.message);
|
|
|
|
|
if (!res.statusCode || res.statusCode < 400) {
|
|
|
|
|
res.status(500);
|
|
|
|
|
}
|
|
|
|
|
res.json({ message: error.message, stack: process.env.NODE_ENV === 'production' ? null : error.stack });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Экспортируем все функции
|
|
|
|
|
module.exports = {
|
|
|
|
|
registerUser,
|
|
|
|
|
loginUser,
|
|
|
|
|
getMe
|
|
|
|
|
};
|