const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const userSchema = new mongoose.Schema( { name: { type: String, required: [true, 'Пожалуйста, укажите ваше имя'], trim: true, }, email: { type: String, required: [true, 'Пожалуйста, укажите ваш email'], unique: true, lowercase: true, trim: true, match: [ /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, 'Пожалуйста, укажите корректный email', ], }, password: { type: String, required: [true, 'Пожалуйста, укажите пароль'], minlength: [6, 'Пароль должен быть не менее 6 символов'], select: false, }, dateOfBirth: { type: Date, required: [true, 'Пожалуйста, укажите дату рождения'], }, gender: { type: String, enum: ['male', 'female', 'other'], }, bio: { type: String, trim: true, maxlength: [500, 'Описание не должно превышать 500 символов'], }, photos: [ { url: String, public_id: String, // Добавляем public_id isProfilePhoto: { type: Boolean, default: false }, }, ], location: { city: String, country: String, }, preferences: { gender: { type: String, enum: ['male', 'female', 'other', 'any'], default: 'any' }, ageRange: { min: { type: Number, default: 18 }, max: { type: Number, default: 99 }, }, // Добавляем предпочтения по городу cityPreferences: { sameCity: { type: Boolean, default: true }, // Показывать только из того же города allowedCities: [{ type: String }] // Дополнительные разрешенные города } }, isActive: { type: Boolean, default: true, }, isAdmin: { type: Boolean, default: false, }, lastSeen: { type: Date, default: Date.now, }, // --- НОВЫЕ ПОЛЯ ДЛЯ ЛАЙКОВ, ПРОПУСКОВ И МЭТЧЕЙ --- liked: [{ // Массив ID пользователей, которых лайкнул текущий пользователь type: mongoose.Schema.Types.ObjectId, ref: 'User' // Ссылка на модель User }], passed: [{ // Массив ID пользователей, которых пропустил/дизлайкнул текущий пользователь type: mongoose.Schema.Types.ObjectId, ref: 'User' }], matches: [{ // Массив ID пользователей, с которыми у текущего пользователя взаимный лайк (мэтч) type: mongoose.Schema.Types.ObjectId, ref: 'User' }] // ---------------------------------------------------- }, { timestamps: true, } ); // Middleware pre('save') для хеширования пароля и установки страны по умолчанию userSchema.pre('save', async function (next) { if (!this.isModified('password')) { return next(); } // Если город указан, а страна нет, устанавливаем страну по умолчанию if (this.isModified('location.city') && this.location.city && !this.location.country) { this.location.country = 'Россия'; } const salt = await bcrypt.genSalt(10); this.password = await bcrypt.hash(this.password, salt); next(); }); userSchema.methods.matchPassword = async function (enteredPassword) { return await bcrypt.compare(enteredPassword, this.password); }; // Статический метод для получения устройств пользователя userSchema.statics.findUserDevices = async function(userId) { try { // Получаем сессии и авторизации пользователя const user = await this.findById(userId).select('authHistory devices sessions'); if (!user) return []; // Объединяем все возможные источники устройств let devices = []; // Из истории авторизаций if (user.authHistory && user.authHistory.length > 0) { devices = devices.concat(user.authHistory.map(auth => ({ fingerprint: auth.deviceFingerprint, userAgent: auth.userAgent, ipAddress: auth.ipAddress, lastUsed: auth.timestamp, type: 'auth' }))); } // Из списка устройств if (user.devices && user.devices.length > 0) { devices = devices.concat(user.devices.map(device => ({ fingerprint: device.fingerprint, userAgent: device.userAgent, platform: device.platform, lastUsed: device.lastActive, type: 'device' }))); } // Из активных сессий if (user.sessions && user.sessions.length > 0) { devices = devices.concat(user.sessions.map(session => ({ fingerprint: session.deviceFingerprint, userAgent: session.userAgent, ipAddress: session.ipAddress, lastUsed: session.lastActive, type: 'session' }))); } // Удаляем дубликаты по fingerprint const uniqueDevices = Array.from( devices.reduce((map, device) => { if (device.fingerprint && !map.has(device.fingerprint)) { map.set(device.fingerprint, device); } return map; }, new Map()).values() ); return uniqueDevices; } catch (error) { console.error('Ошибка при поиске устройств пользователя:', error); return []; } }; const User = mongoose.model('User', userSchema); module.exports = User;