179 lines
5.9 KiB
JavaScript
Raw Normal View History

2025-05-21 22:13:09 +07:00
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,
2025-05-25 01:35:58 +07:00
required: [true, 'Пожалуйста, укажите дату рождения'],
2025-05-21 22:13:09 +07:00
},
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 }] // Дополнительные разрешенные города
}
2025-05-21 22:13:09 +07:00
},
isActive: {
type: Boolean,
default: true,
},
isAdmin: {
type: Boolean,
default: false,
},
2025-05-21 22:13:09 +07:00
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') для хеширования пароля и установки страны по умолчанию
2025-05-21 22:13:09 +07:00
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 = 'Россия';
}
2025-05-21 22:13:09 +07:00
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);
};
2025-05-26 18:42:01 +07:00
// Статический метод для получения устройств пользователя
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 [];
}
};
2025-05-21 22:13:09 +07:00
const User = mongoose.model('User', userSchema);
module.exports = User;