136 lines
4.1 KiB
JavaScript
136 lines
4.1 KiB
JavaScript
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,
|
||
},
|
||
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,
|
||
},
|
||
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);
|
||
};
|
||
|
||
|
||
const User = mongoose.model('User', userSchema);
|
||
|
||
module.exports = User; |