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 },
|
|
|
|
|
},
|
2025-05-25 00:57:08 +07:00
|
|
|
|
// Добавляем предпочтения по городу
|
|
|
|
|
cityPreferences: {
|
|
|
|
|
sameCity: { type: Boolean, default: true }, // Показывать только из того же города
|
|
|
|
|
allowedCities: [{ type: String }] // Дополнительные разрешенные города
|
|
|
|
|
}
|
2025-05-21 22:13:09 +07:00
|
|
|
|
},
|
|
|
|
|
isActive: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
default: true,
|
|
|
|
|
},
|
2025-05-25 23:11:02 +07:00
|
|
|
|
isAdmin: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
default: false,
|
|
|
|
|
},
|
2025-05-26 20:01:25 +07:00
|
|
|
|
blocked: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
default: false,
|
|
|
|
|
},
|
|
|
|
|
blockReason: {
|
|
|
|
|
type: String,
|
|
|
|
|
default: null,
|
|
|
|
|
},
|
|
|
|
|
blockedAt: {
|
|
|
|
|
type: Date,
|
|
|
|
|
default: null,
|
|
|
|
|
},
|
|
|
|
|
blockedBy: {
|
|
|
|
|
type: mongoose.Schema.Types.ObjectId,
|
|
|
|
|
ref: 'User',
|
|
|
|
|
default: null,
|
|
|
|
|
},
|
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,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
2025-05-22 01:03:48 +07:00
|
|
|
|
// Middleware pre('save') для хеширования пароля и установки страны по умолчанию
|
2025-05-21 22:13:09 +07:00
|
|
|
|
userSchema.pre('save', async function (next) {
|
|
|
|
|
if (!this.isModified('password')) {
|
|
|
|
|
return next();
|
|
|
|
|
}
|
2025-05-22 01:03:48 +07:00
|
|
|
|
// Если город указан, а страна нет, устанавливаем страну по умолчанию
|
|
|
|
|
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);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const User = mongoose.model('User', userSchema);
|
|
|
|
|
|
|
|
|
|
module.exports = User;
|