dogsitters-finder #91
74
server/routers/dogsitters-finder/auth.js
Normal file
74
server/routers/dogsitters-finder/auth.js
Normal file
@ -0,0 +1,74 @@
|
||||
const { Router } = require("express");
|
||||
const hash = require("pbkdf2-password")();
|
||||
const { promisify } = require("node:util");
|
||||
const jwt = require('jsonwebtoken')
|
||||
|
||||
const { getAnswer } = require("../../utils/common");
|
||||
|
||||
const { AuthModel } = require("./model/todo/auth");
|
||||
const { TOKEN_KEY } = require('./const')
|
||||
const { UserModel } = require("./model/todo/user");
|
||||
|
||||
const { requiredValidate } = require('./utils')
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
"/signup",
|
||||
requiredValidate("login", "password", "email"),
|
||||
async (req, res, next) => {
|
||||
const { login, password, email } = req.body
|
||||
|
||||
const user = await AuthModel.findOne({ login });
|
||||
|
||||
if (user) {
|
||||
throw new Error("Пользователь с таким логином уже существует");
|
||||
}
|
||||
|
||||
hash({ password }, async function (err, pass, salt, hash) {
|
||||
if (err) return next(err);
|
||||
|
||||
const user = await UserModel.create({ login, email });
|
||||
await AuthModel.create({ login, hash, salt, userId: user.id });
|
||||
|
||||
res.json(getAnswer(null, { ok: true }))
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
function authenticate(login, pass, cb) {
|
||||
AuthModel.findOne({ login }).populate('userId').exec().then((user) => {
|
||||
if (!user) return cb(null, null)
|
||||
|
||||
hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) {
|
||||
if (err) return cb(err)
|
||||
if (hash === user.hash) return cb(null, user)
|
||||
cb(null, null)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const auth = promisify(authenticate)
|
||||
|
||||
router.post('/signin', requiredValidate('login', 'password'), async (req, res) => {
|
||||
const { login, password } = req.body
|
||||
|
||||
const user = await auth(login, password)
|
||||
|
||||
if (!user) {
|
||||
throw new Error("Неверный логин или пароль")
|
||||
}
|
||||
|
||||
const accessToken = jwt.sign({
|
||||
...JSON.parse(JSON.stringify(user.userId)),
|
||||
}, TOKEN_KEY, {
|
||||
expiresIn: '12h'
|
||||
})
|
||||
|
||||
res.json(getAnswer(null, {
|
||||
user: user.userId,
|
||||
token: accessToken,
|
||||
}))
|
||||
})
|
||||
|
||||
module.exports = router
|
3
server/routers/dogsitters-finder/const.js
Normal file
3
server/routers/dogsitters-finder/const.js
Normal file
@ -0,0 +1,3 @@
|
||||
exports.DSF_AUTH_PASSWD_MODEL_NAME = 'DSF_AUTH_PASSWD'
|
||||
exports.DSF_AUTH_USER_MODEL_NAME = 'DSF_AUTH_USER'
|
||||
exports.DSF_INTERACTION_MODEL_NAME = 'DSF_INTERACTION'
|
@ -66,6 +66,4 @@ router.get("/auth/session", (request, response) => {
|
||||
console.log("token e:", e);
|
||||
return response.status(403).json({ error: "Invalid token" });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
});
|
44
server/routers/dogsitters-finder/model/auth.js
Normal file
44
server/routers/dogsitters-finder/model/auth.js
Normal file
@ -0,0 +1,44 @@
|
||||
const { Schema, model } = require("mongoose");
|
||||
|
||||
const {
|
||||
DSF_AUTH_PASSWD_MODEL_NAME,
|
||||
DSF_AUTH_USER_MODEL_NAME,
|
||||
} = require("../../const");
|
||||
|
||||
const schema = new Schema({
|
||||
login: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true
|
||||
},
|
||||
hash: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
salt: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
userId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: DSF_AUTH_USER_MODEL_NAME
|
||||
},
|
||||
created: {
|
||||
type: Date,
|
||||
default: () => new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
|
||||
schema.set("toJSON", {
|
||||
virtuals: true,
|
||||
versionKey: false,
|
||||
transform: function (doc, ret) {
|
||||
delete ret._id;
|
||||
},
|
||||
});
|
||||
|
||||
schema.virtual("id").get(function () {
|
||||
return this._id.toHexString();
|
||||
});
|
||||
|
||||
exports.AuthModel = model(DSF_AUTH_PASSWD_MODEL_NAME, schema);
|
24
server/routers/dogsitters-finder/model/interaction.js
Normal file
24
server/routers/dogsitters-finder/model/interaction.js
Normal file
@ -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);
|
83
server/routers/dogsitters-finder/model/user.js
Normal file
83
server/routers/dogsitters-finder/model/user.js
Normal file
@ -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);
|
149
server/routers/dogsitters-finder/routes.js
Normal file
149
server/routers/dogsitters-finder/routes.js
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user