4.1.3
This commit is contained in:
@@ -53,8 +53,11 @@ const setAddress = async (req, res, next) => {
|
||||
if (country) {
|
||||
user.country = { id: country.id, name: country.name_fa || country.name, iso2: country.iso2, slug: country.slug }
|
||||
}
|
||||
user.province = province
|
||||
user.city = city
|
||||
// مثل country بالا — نام فارسی (name_fa) رو ترجیح بده، وگرنه استان/شهر با نام
|
||||
// انگلیسیِ خام (name) ذخیره میشد؛ قبلاً کل داکیومنت خام province/city (که name_fa
|
||||
// جدا داشت ولی field نمایشیِ name همچنان انگلیسی بود) مستقیم ذخیره میشد
|
||||
user.province = { id: province.id, name: province.name_fa || province.name, slug: province.slug }
|
||||
user.city = { id: city.id, name: city.name_fa || city.name, slug: city.slug }
|
||||
user.address = address
|
||||
user.lat = lat
|
||||
user.lng = lng
|
||||
@@ -125,8 +128,11 @@ const updateAddress = async (req, res, next) => {
|
||||
if (country) {
|
||||
user.country = { id: country.id, name: country.name_fa || country.name, iso2: country.iso2, slug: country.slug }
|
||||
}
|
||||
user.province = province
|
||||
user.city = city
|
||||
// مثل country بالا — نام فارسی (name_fa) رو ترجیح بده، وگرنه استان/شهر با نام
|
||||
// انگلیسیِ خام (name) ذخیره میشد؛ قبلاً کل داکیومنت خام province/city (که name_fa
|
||||
// جدا داشت ولی field نمایشیِ name همچنان انگلیسی بود) مستقیم ذخیره میشد
|
||||
user.province = { id: province.id, name: province.name_fa || province.name, slug: province.slug }
|
||||
user.city = { id: city.id, name: city.name_fa || city.name, slug: city.slug }
|
||||
user.address = address
|
||||
user.lat = lat
|
||||
user.lng = lng
|
||||
|
||||
@@ -41,6 +41,49 @@ const setGender = async (req, res, next) => {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setGender
|
||||
// نسخهی PATCH — عیناً همون منطقِ setGender، فقط طبق قراردادِ بقیهی فیلدهای
|
||||
// «مشخصات فردی» (نگاه کنید personalDetailsController.js: set=POST برای ثبتنامِ
|
||||
// اولیه، update=PATCH برای ویرایش از تنظیمات) که settings/edit/gender/page.tsx
|
||||
// باید صداش بزنه، نه POST که مخصوص ویزارد ثبتنامه
|
||||
const updateGender = async (req, res, next) => {
|
||||
try {
|
||||
const token = req.header('Authorization').split(' ')[1]
|
||||
if (!token) return res.status(401).send('Access Denied')
|
||||
const { gender } = req.body
|
||||
if (!gender) {
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: 'اطلاعات ورودی اشتباه است'
|
||||
})
|
||||
}
|
||||
if (!['male', 'female'].includes(gender)) {
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: 'جنسیت معتبر نیست'
|
||||
})
|
||||
}
|
||||
const decodedToken = jwt.verify(token, process.env.APP_SECRET)
|
||||
const user = await UserModel.findById(decodedToken.id)
|
||||
if (!user) {
|
||||
return res.status(404).json({
|
||||
error: true,
|
||||
message: 'کاربری یافت نشد'
|
||||
})
|
||||
}
|
||||
|
||||
user.gender = gender.toLowerCase()
|
||||
await user.save()
|
||||
|
||||
return res.json({
|
||||
message: 'جنسیت با موفقیت بهروزرسانی شد',
|
||||
gender: user.gender
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setGender,
|
||||
updateGender
|
||||
}
|
||||
|
||||
@@ -2,11 +2,118 @@
|
||||
const UserModel = require('../../../models/UserModel')
|
||||
const jwt = require('jsonwebtoken')
|
||||
|
||||
const MARITAL_STATUS_VALUES = ['single', 'divorced']
|
||||
const MARITAL_STATUS_VALUES = ['single', 'divorced', 'widowed', 'not_in_relationship', 'prefer_not_to_say']
|
||||
const RESIDENCE_TYPE_VALUES = ['owner', 'tenant']
|
||||
const VEHICLE_TYPE_VALUES = ['none', 'car', 'motorcycle']
|
||||
const PERSONAL_STYLE_VALUES = ['formal', 'sporty']
|
||||
const INCOME_RANGE_VALUES = ['under_5m', '5m_10m', '10m_20m', 'over_20m']
|
||||
const PERSONAL_STYLE_VALUES = ['casual', 'classic', 'minimal', 'formal', 'street', 'romantic']
|
||||
const INCOME_RANGE_VALUES = [
|
||||
'under_40m', '40m_50m', '50m_60m', '60m_70m', '70m_80m',
|
||||
'80m_90m', '90m_100m', '100m_150m', '150m_200m', 'over_200m'
|
||||
]
|
||||
|
||||
const RELATIONSHIP_GOAL_VALUES = [
|
||||
'friendship',
|
||||
'serious_partner',
|
||||
'marriage_intro',
|
||||
'emotional_relationship',
|
||||
'travel_event_companion',
|
||||
'social_networking',
|
||||
'not_sure'
|
||||
]
|
||||
const SEEKING_GENDER_VALUES = ['female', 'male', 'both', 'not_important']
|
||||
|
||||
const DESIRED_AGE_RANGE_VALUES = ['18_24', '25_30', '31_35', '36_40', '41_50', 'over_50', 'not_important']
|
||||
|
||||
const PERSONALITY_TRAITS_VALUES = [
|
||||
'kind',
|
||||
'loyal',
|
||||
'funny',
|
||||
'calm',
|
||||
'energetic',
|
||||
'responsible',
|
||||
'ambitious',
|
||||
'emotional',
|
||||
'logical',
|
||||
'patient',
|
||||
'honest',
|
||||
'romantic',
|
||||
'independent',
|
||||
'family_oriented',
|
||||
'adventurous',
|
||||
'introvert',
|
||||
'extrovert'
|
||||
]
|
||||
|
||||
const LIFESTYLE_VALUES = [
|
||||
'active_healthy',
|
||||
'homebody_calm',
|
||||
'social_outgoing',
|
||||
'busy_career',
|
||||
'traveler',
|
||||
'night_owl',
|
||||
'early_riser',
|
||||
'minimalist',
|
||||
'luxury_lover'
|
||||
]
|
||||
|
||||
const INTERESTS_VALUES = [
|
||||
'movies_series',
|
||||
'music',
|
||||
'books_reading',
|
||||
'sports',
|
||||
'cooking',
|
||||
'photography',
|
||||
'travel',
|
||||
'nature',
|
||||
'gaming',
|
||||
'art_painting',
|
||||
'fashion',
|
||||
'pets',
|
||||
'dancing',
|
||||
'language_learning'
|
||||
]
|
||||
|
||||
const VALUES_VALUES = [
|
||||
'family',
|
||||
'career_growth',
|
||||
'religion_spirituality',
|
||||
'personal_freedom',
|
||||
'financial_stability',
|
||||
'health_fitness',
|
||||
'personal_growth',
|
||||
'excitement_new_experiences'
|
||||
]
|
||||
|
||||
const RELATIONSHIP_VIEW_VALUES = [
|
||||
'traditional',
|
||||
'modern',
|
||||
'long_term',
|
||||
'friendship_first',
|
||||
'marriage_soon',
|
||||
'friendship_only_for_now'
|
||||
]
|
||||
|
||||
const GEO_PREFERENCE_VALUES = [
|
||||
'same_city_only',
|
||||
'nearby_cities',
|
||||
'whole_province',
|
||||
'whole_iran',
|
||||
'even_abroad',
|
||||
'online_is_fine'
|
||||
]
|
||||
|
||||
const CHILDREN_STATUS_VALUES = ['no_children', 'has_children', 'open_to_children', 'not_now', 'prefer_not_to_say']
|
||||
|
||||
const SMOKING_STATUS_VALUES = ['none', 'sometimes', 'yes', 'doesnt_matter', 'prefer_not_to_say']
|
||||
|
||||
/** Validates a multi-select field: must be an array and every item must be
|
||||
* in `allowedValues` (no cap on how many may be selected). Returns a
|
||||
* Persian error message on failure, or null on success. */
|
||||
function validateMultiSelect (value, allowedValues, errorMessage) {
|
||||
if (!Array.isArray(value)) return errorMessage
|
||||
if (!value.every((item) => allowedValues.includes(item))) return errorMessage
|
||||
return null
|
||||
}
|
||||
|
||||
/** All fields are optional profile-enrichment fields — only the ones present
|
||||
* in the request body are validated/applied, unlike sizes/cooperation-type
|
||||
@@ -54,12 +161,96 @@ function applyPersonalDetails (user, body) {
|
||||
}
|
||||
user.income_range = body.income_range
|
||||
}
|
||||
if (body.moral_traits !== undefined) {
|
||||
user.moral_traits = body.moral_traits
|
||||
}
|
||||
if (body.personal_details_public !== undefined) {
|
||||
user.personal_details_public = Boolean(body.personal_details_public)
|
||||
}
|
||||
if (body.relationship_goal !== undefined) {
|
||||
const error = validateMultiSelect(
|
||||
body.relationship_goal, RELATIONSHIP_GOAL_VALUES,
|
||||
'هدف از آشنایی نامعتبر است'
|
||||
)
|
||||
if (error) return error
|
||||
user.relationship_goal = body.relationship_goal
|
||||
}
|
||||
if (body.seeking_gender !== undefined) {
|
||||
if (body.seeking_gender !== null && !SEEKING_GENDER_VALUES.includes(body.seeking_gender)) {
|
||||
return 'جنسیت مورد نظر نامعتبر است'
|
||||
}
|
||||
user.seeking_gender = body.seeking_gender
|
||||
}
|
||||
if (body.desired_age_range !== undefined) {
|
||||
if (body.desired_age_range !== null && !DESIRED_AGE_RANGE_VALUES.includes(body.desired_age_range)) {
|
||||
return 'بازه سنی مورد نظر نامعتبر است'
|
||||
}
|
||||
user.desired_age_range = body.desired_age_range
|
||||
}
|
||||
if (body.personality_traits !== undefined) {
|
||||
const error = validateMultiSelect(
|
||||
body.personality_traits, PERSONALITY_TRAITS_VALUES,
|
||||
'ویژگیهای شخصیتی نامعتبر است'
|
||||
)
|
||||
if (error) return error
|
||||
user.personality_traits = body.personality_traits
|
||||
}
|
||||
if (body.lifestyle !== undefined) {
|
||||
const error = validateMultiSelect(
|
||||
body.lifestyle, LIFESTYLE_VALUES,
|
||||
'سبک زندگی نامعتبر است'
|
||||
)
|
||||
if (error) return error
|
||||
user.lifestyle = body.lifestyle
|
||||
}
|
||||
if (body.interests !== undefined) {
|
||||
const error = validateMultiSelect(
|
||||
body.interests, INTERESTS_VALUES,
|
||||
'علایق نامعتبر است'
|
||||
)
|
||||
if (error) return error
|
||||
user.interests = body.interests
|
||||
}
|
||||
if (body.values !== undefined) {
|
||||
const error = validateMultiSelect(
|
||||
body.values, VALUES_VALUES,
|
||||
'ارزشها نامعتبر است'
|
||||
)
|
||||
if (error) return error
|
||||
user.values = body.values
|
||||
}
|
||||
if (body.relationship_view !== undefined) {
|
||||
if (body.relationship_view !== null && !RELATIONSHIP_VIEW_VALUES.includes(body.relationship_view)) {
|
||||
return 'دیدگاه نسبت به رابطه نامعتبر است'
|
||||
}
|
||||
user.relationship_view = body.relationship_view
|
||||
}
|
||||
if (body.geo_preference !== undefined) {
|
||||
if (body.geo_preference !== null && !GEO_PREFERENCE_VALUES.includes(body.geo_preference)) {
|
||||
return 'محدوده جغرافیایی مورد نظر نامعتبر است'
|
||||
}
|
||||
user.geo_preference = body.geo_preference
|
||||
}
|
||||
if (body.children_status !== undefined) {
|
||||
const error = validateMultiSelect(
|
||||
body.children_status, CHILDREN_STATUS_VALUES,
|
||||
'وضعیت فرزند نامعتبر است'
|
||||
)
|
||||
if (error) return error
|
||||
user.children_status = body.children_status
|
||||
}
|
||||
if (body.smoking_status !== undefined) {
|
||||
if (body.smoking_status !== null && !SMOKING_STATUS_VALUES.includes(body.smoking_status)) {
|
||||
return 'وضعیت مصرف دخانیات نامعتبر است'
|
||||
}
|
||||
user.smoking_status = body.smoking_status
|
||||
}
|
||||
// فیلد سبکوزن برای ثبت تاریخ تولد از همین اندپوینت (بدون نیاز به شبا/کد ملی که
|
||||
// POST /verify/auth الزامی میکنه) — مثلاً وقتی کاربر فقط سن رو توی «مشخصات فردی»
|
||||
// اضافه میکنه، نه کل احراز هویت بانکی/ملی
|
||||
if (body.birthday !== undefined) {
|
||||
if (body.birthday !== null && Number.isNaN(Date.parse(body.birthday))) {
|
||||
return 'تاریخ تولد نامعتبر است'
|
||||
}
|
||||
user.birthday = body.birthday
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -123,8 +314,19 @@ const updatePersonalDetails = async (req, res, next) => {
|
||||
personal_style: user.personal_style,
|
||||
job: user.job,
|
||||
income_range: user.income_range,
|
||||
moral_traits: user.moral_traits,
|
||||
personal_details_public: user.personal_details_public === true
|
||||
personal_details_public: user.personal_details_public === true,
|
||||
relationship_goal: user.relationship_goal,
|
||||
seeking_gender: user.seeking_gender,
|
||||
desired_age_range: user.desired_age_range,
|
||||
personality_traits: user.personality_traits,
|
||||
lifestyle: user.lifestyle,
|
||||
interests: user.interests,
|
||||
values: user.values,
|
||||
relationship_view: user.relationship_view,
|
||||
geo_preference: user.geo_preference,
|
||||
children_status: user.children_status,
|
||||
smoking_status: user.smoking_status,
|
||||
birthday: user.birthday
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
|
||||
Reference in New Issue
Block a user