From 938bd48fff19b9f9546eee7c6bb24a52d195ce37 Mon Sep 17 00:00:00 2001 From: Julya Shapaeva Date: Sat, 8 Feb 2025 13:15:02 +0300 Subject: [PATCH] Fix dogsitters backend --- server/routers/dogsitters-finder/const.js | 2 + .../dogsitters-finder/model/interaction.js | 24 +++ .../routers/dogsitters-finder/model/user.js | 83 ++++++++++ server/routers/dogsitters-finder/routes.js | 149 ++++++++++++++++++ 4 files changed, 258 insertions(+) create mode 100644 server/routers/dogsitters-finder/const.js create mode 100644 server/routers/dogsitters-finder/model/interaction.js create mode 100644 server/routers/dogsitters-finder/model/user.js create mode 100644 server/routers/dogsitters-finder/routes.js diff --git a/server/routers/dogsitters-finder/const.js b/server/routers/dogsitters-finder/const.js new file mode 100644 index 0000000..f10d344 --- /dev/null +++ b/server/routers/dogsitters-finder/const.js @@ -0,0 +1,2 @@ +exports.DSF_AUTH_USER_MODEL_NAME = 'DSF_AUTH_USER' +exports.DSF_INTERACTION_MODEL_NAME = 'DSF_INTERACTION' diff --git a/server/routers/dogsitters-finder/model/interaction.js b/server/routers/dogsitters-finder/model/interaction.js new file mode 100644 index 0000000..95f202b --- /dev/null +++ b/server/routers/dogsitters-finder/model/interaction.js @@ -0,0 +1,24 @@ +const { Schema, model } = require("mongoose"); + +const { DSF_AUTH_USER_MODEL_NAME, DSF_INTERACTION_MODEL_NAME } = require("../../const"); + +const interactionSchema = new Schema({ + owner_id: { + type: Schema.Types.ObjectId, + ref: DSF_AUTH_USER_MODEL_NAME, + required: true + }, + dogsitter_id: { + type: Schema.Types.ObjectId, + ref: DSF_AUTH_USER_MODEL_NAME, + required: true + }, + timestamp: { + type: Date, + default: Date.now + } +}); + +interactionSchema.index({ owner_id: 1, dogsitter_id: 1 }); + +module.exports.Interaction = model(DSF_INTERACTION_MODEL_NAME, interactionSchema); \ No newline at end of file diff --git a/server/routers/dogsitters-finder/model/user.js b/server/routers/dogsitters-finder/model/user.js new file mode 100644 index 0000000..889c946 --- /dev/null +++ b/server/routers/dogsitters-finder/model/user.js @@ -0,0 +1,83 @@ +const { Schema, model } = require("mongoose"); + +const { DSF_AUTH_USER_MODEL_NAME } = require("../../const"); + +const userSchema = new Schema({ + phone_number: { + type: String, + required: true, + unique: true, + match: /^\+?\d{10,15}$/ + }, + first_name: { + type: String, + required: true, + trim: true + }, + second_name: { + type: String, + required: true, + trim: true + }, + role: { + type: String, + enum: ["dogsitter", "owner"], + required: true + }, + location: { + type: String, + required: function() { + return this.role === "dogsitter"; + } + }, + price: { + type: Number, + min: 0, + required: function() { + return this.role === "dogsitter"; + } + }, + about_me: { + type: String, + maxlength: 500 + }, + rating: { + type: Number, + min: 0, + max: 5, + default: 0 + }, + ratings: { + type: [Number], + default: [], + validate: { + validator: function(arr) { + return arr.every(v => v >= 0 && v <= 5); + }, + message: "Рейтинг должен быть в диапазоне от 0 до 5!" + } + }, + tg: { + type: String, + match: /^[a-zA-Z0-9_]{5,32}$/ + }, + created: { + type: Date, + default: Date.now + } +}); + +userSchema.virtual("id").get(function() { + return this._id.toHexString(); +}); + +userSchema.set("toJSON", { + virtuals: true, + versionKey: false, + transform: function(doc, ret) { + delete ret._id; + delete ret.__v; + } +}); + +module.exports.User = model(DSF_AUTH_USER_MODEL_NAME, userSchema); \ No newline at end of file diff --git a/server/routers/dogsitters-finder/routes.js b/server/routers/dogsitters-finder/routes.js new file mode 100644 index 0000000..f82bc47 --- /dev/null +++ b/server/routers/dogsitters-finder/routes.js @@ -0,0 +1,149 @@ +const { Router } = require('express') +const { expressjwt } = require('express-jwt') + +const { getAnswer } = require('../../utils/common') +const { User, Interaction } = require('./model') +const { TOKEN_KEY } = require('./const') +const { requiredValidate } = require('./utils') + +const router = Router() + +// Получение списка пользователей +router.get('/users', async (req, res) => { + + const users = await User.find() + .select('-__v -ratings -phone_number') + .lean() + + console.log('get users successfull') + + res.send(getAnswer(null, users)) +}) + +// Получение конкретного пользователя +router.get('/dogsitter-viewing', async (req, res) => { + const { userId } = req.params + + const user = await User.findById(userId) + .select('-__v -ratings') + .lean() + + if (!user) { + return res.status(404).send(getAnswer(new Error('Пользователь не найден'))) + } + + res.send(getAnswer(null, user)) +}) + +router.use(expressjwt({ secret: TOKEN_KEY, algorithms: ['HS256'] })) + +// Добавление оценки пользователю +router.post('/dogsitter-viewing/rating', requiredValidate('value'), async (req, res) => { + const { userId } = req.params + const { value } = req.body + const authUserId = req.auth.id + + try { + const user = await User.findById(userId) + if (!user) throw new Error('Пользователь не найден') + if (user.role !== 'dogsitter') throw new Error('Нельзя оценивать этого пользователя') + if (user.id === authUserId) throw new Error('Нельзя оценивать самого себя') + + user.ratings.push(Number(value)) + user.rating = user.ratings.reduce((a, b) => a + b, 0) / user.ratings.length + + const updatedUser = await user.save() + + res.send(getAnswer(null, { + id: updatedUser.id, + rating: updatedUser.rating.toFixed(1), + totalRatings: updatedUser.ratings.length + })) + + } catch (error) { + res.status(400).send(getAnswer(error)) + } +}) + +// Обновление информации пользователя +router.patch('/users', async (req, res) => { + const { userId } = req.params + const updates = req.body + + try { + const user = await User.findByIdAndUpdate(userId, updates, { new: true }) + .select('-__v -ratings') + + if (!user) throw new Error('Пользователь не найден') + res.send(getAnswer(null, user)) + + } catch (error) { + res.status(400).send(getAnswer(error)) + } +}) + +// Создание объекта взаимодействия +router.post('/interactions', + expressjwt({ secret: TOKEN_KEY, algorithms: ['HS256'] }), + requiredValidate('dogsitter_id'), + async (req, res) => { + try { + const { dogsitter_id } = req.body + const owner_id = req.auth.id // ID из JWT токена + + // Проверка существования пользователей + const [owner, dogsitter] = await Promise.all([ + User.findById(owner_id), + User.findById(dogsitter_id) + ]) + + if (!owner || owner.role !== 'owner') { + throw new Error('Владелец не найден или имеет неверную роль') + } + + if (!dogsitter || dogsitter.role !== 'dogsitter') { + throw new Error('Догситтер не найден или имеет неверную роль') + } + + // Создание взаимодействия + const interaction = await Interaction.create({ + owner_id, + dogsitter_id + }) + + res.send(getAnswer(null, { + id: interaction.id, + timestamp: interaction.timestamp + })) + + } catch (error) { + res.status(400).send(getAnswer(error)) + } + } +) + +router.get('/interactions/check', async (req, res) => { + const { owner_id, dogsitter_id } = req.query; + + if (!owner_id || !dogsitter_id) { + return res.status(400).send(getAnswer('Missing owner_id or dogsitter_id')); + } + + try { + // Поиск взаимодействий по owner_id и dogsitter_id + const interactions = await Interaction.find({ owner_id, dogsitter_id }) + .select('-__v') // Выбираем только нужные поля + .lean(); + + if (interactions.length === 0) { + return res.status(404).send(getAnswer('No interactions found')); + } + + res.send(getAnswer(null, interactions)); + } catch (error) { + console.error('Error checking interactions:', error); + res.status(500).send(getAnswer('Internal Server Error')); + } +}); + +module.exports = router \ No newline at end of file -- 2.45.2