mongoose + tests

This commit is contained in:
Primakov Alexandr Alexandrovich
2024-10-16 11:06:23 +03:00
parent 2cfcd7347b
commit 4b0d9b4dbc
1295 changed files with 4579 additions and 1719 deletions

View File

@@ -0,0 +1,48 @@
const router = require('express').Router()
const jwt = require('jsonwebtoken')
const { JWT_SECRET } = require('./constants')
const { registrationUser, signInUser } = require('./db')
const { requiredFields, responseWrapper } = require('./utils')
router.get('/healthcheck', (req, res) => {
res.send(true)
})
router.post('/registration', requiredFields(['email', 'login', 'password']), async (req, res, next) => {
const { email, login, password, ...rest } = req.body
try {
await registrationUser({
email, login, password, ...rest,
})
res.send(responseWrapper(undefined, {
}))
} catch (e) {
next(e)
}
})
router.post('/sign-in', requiredFields(['email', 'password']), async (req, res, next) => {
const { email, password } = req.body
try {
const user = await signInUser({
email, password,
})
req.session.user = user
const token = jwt.sign({
id: user._id,
}, JWT_SECRET)
res.send(responseWrapper(undefined, {
token, user,
}))
} catch (e) {
next(e)
}
})
module.exports = router

View File

@@ -0,0 +1,30 @@
const JWT_SECRET = `MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDsZZ+2H3Q0uvFh
JohVkLKGUGR0dJRo801QbH/UMQjsuIYPExn4wLHr06ALGb3WQe+hiERthsJu3veV
38AuQ3YHE1mcD5KRwkBflqc+lldp1JyZm8qPO1PLCJBc/553EPV16MbuDdmdxoY5
Uk2X5b3+UVjzDY83Pd9YFa3i42y7wREKj7csTxJPGXGvFDtCgyhhH3vjtd91pCg8
nuXuFShv5HI5S2ffBbxj/p8rjIK+a+DOw2zKEeYN3G5OLCVsmBow76KQZyVmmYAq
Qnlut0s0HbNX8Deo70iib35AEts00ey+2Y5gJh4Lq8tCpSeFlO0mQ13g/jN8jDxu
mnoluhQnAgMBAAECggEARG4KdHLYdacj1maMEpDHTOAapCdXCqZbXAt8WVU0aynj
DJwP6ZUGK+jfrDbwYARINK84d6gJwoRikQzrGblHgjbUurs7R1w+vCzlDtYASc9U
4ZZaZWncEKrS90i7e2X6V/5hD2oM84ITOqabdXv4qpSrtffX3DrZ2yqzYjlJMXPc
VT+qqG8pDEhluJWO+CQBr3L7kk69S1s6ehlVh7OFOvtCXTPfwM23NrwDSRp+kx9x
GikhoPUFZL6FZttJxzgonW10Yi4MvlCNHuWs5F1vfK0b3eG9FsGsvclBd9E0P75i
iQeWG+Ecf81XWaqmaKMvQv5upK0jwEvHBEa6IXhoiQKBgQD+XPv68a8TKlbdg0UY
YYKbs+U/7v0ZcRwkweYTPrhg1cO91nRk8e9OXnD+Boqk2zMojLI9FEF7qf13LY9X
Ue9XikgoDQAIg6bS92FUx5KoyxOnQcDdTenhZZ7dbF0qXn8KBz5EXgPxMVfS3hhk
uZ7PBWbeXtnVyvV+7ymjzX/PDQKBgQDt6wslvUrlLLPDE9bqO+Zi7sYPyQXphRWS
IvG4SisKa0Fo/MCgAP+0hfLBXgl+z+JQFmxpGaZIHikgwI0JA2jQLYdTAcjMiWHn
bxtw+dvOyp8xMjDg0cKuSs798zW1ylGdBvOKMcB4tJK66ahNPoGfd/iVpqkXCCJO
rptTRaODAwKBgDknn58li1ddHiOsCWyPDI/7/jk9dDWxSsefohkU8M0he1g+xeyg
yErtwanywliEwJwN8Ub0NDqbWc7bt+fBC2y6L7iAI0/GdUfWOlKYfYXcC9B7X+Da
TwFMmkPaw5xvm1AfjIhEL9KUac2CBi0r4FlYN2MkIQJ/FmatSsf5twxJAoGBALp8
5E3+pDgi4/zjDjCoJxwhISq6XWH/qTrVHTdhG3+dNrY+eBZy8fvkirW7KiI2fKRe
DzgKnOYmjgJYK7SG8Z9MMKiF24lHnnA0DQRvNTZQaJu9RcbTZJANn1Y7Tzxhi7tT
+Y23FbEHiYPtJrj1Z9FBzp4u9pdRDuMxxhptmY9VAoGANasQyyWaNmJNFqK2OZRk
HhKwV5AXk7Q0F3YbGXOUUmlsQw+wYVtQmyThYESMbS3T9ccjTO1avCDZNcBYnKir
xkMh3KPVALIbolNjaac7TZ+CCu4VL99hCQVerVZqMivXiqmjjioobX3fspQl9nZL
h+adTrBTkdlVVgHE8TNs88Q=`
module.exports = {
JWT_SECRET,
}

View File

@@ -0,0 +1,410 @@
const { v4: uuid } = require('uuid')
const ObjectId = require('mongodb').ObjectID
const { getDB } = require('../../../utils/mongo')
const { _idToId, checkDB, _idToIdArray, filterId } = require('./utils')
let db = null
const USERS_COLL = 'ep_users'
const PROJECTS_COLL = 'ep_all_projects'
const PROJECT_TASKS_COLL = 'ep_projects_tasks'
const PROJECT_MEMBERS_COLL = 'ep_projects_members'
const PROJECT_STATUSES_COLL = 'ep_projects_statuses'
const PROJECT_TYPES_COLL = 'ep_projects_types'
const connect = async () => {
db = await getDB('easy-project')
if (db === null) throw new Error('Нет подключения к базе данных')
}
connect()
const hashPassword = (password, salt = uuid(), salt2 = uuid(), salt3 = uuid()) => ({
password: (password.split('').join(salt) + salt2 + password.split('').join(salt3)).split('-').reverse().join('-'),
salt,
salt2,
salt3,
})
const registrationUser = async ({ email, login, password, ...rest }) => {
checkDB(db)
const usersCollection = db.collection(USERS_COLL)
const userExist = await usersCollection.find({
$or: [{
login,
}, {
email,
}],
}).toArray()
if (userExist.length) {
if (userExist[0].login === login) {
throw new Error('Логин уже занят')
}
if (userExist[0].email === email) {
throw new Error('Email уже занят')
}
}
const { password: hash, salt, salt2, salt3 } = hashPassword(password)
const user = {
salt,
salt2,
salt3,
hash,
login,
email,
...rest,
}
const { insertedId } = await usersCollection.insertOne(user)
user.id = insertedId
}
const signInUser = async ({ email, password }) => {
checkDB(db)
const usersCollection = db.collection(USERS_COLL)
const [userCandidate] = await usersCollection.find({
email,
}).toArray()
if (!userCandidate) {
throw new Error('Email или пароль не корректный')
}
const { salt, salt2, salt3, hash, ...cleanUser } = userCandidate
const { password: hashFromDb } = hashPassword(password, salt, salt2, salt3)
if (hash !== hashFromDb) {
throw new Error('Email или пароль не корректный')
}
return cleanUser
}
const getMyProjects = async (userId) => {
checkDB(db)
const userFilterById = filterId(userId)
const projectCollection = db.collection(PROJECTS_COLL)
const usersCollection = db.collection(USERS_COLL)
let projectList = await projectCollection.find({
$or: [{
userId,
}, {
members: {
$in: [userId],
},
}],
}).toArray()
if (projectList) {
const [userAuthor] = await usersCollection.find(userFilterById).toArray()
for (let index = 0; index < projectList.length; index++) {
projectList[index].author = userAuthor
projectList[index] = _idToId(projectList[index])
}
return projectList
}
return []
}
const deleteProjectById = async (projectId) => {
checkDB(db)
const projectCollection = db.collection(PROJECTS_COLL)
const projectFilterById = filterId(projectId)
const deleted = await projectCollection.deleteOne(projectFilterById)
return deleted
}
const getMyProjectById = async (userId, projectId) => {
checkDB(db)
const projectCollection = db.collection(PROJECTS_COLL)
const usersCollection = db.collection(USERS_COLL)
const userFilterById = filterId(userId)
const [userAuthor] = await usersCollection.find(userFilterById).toArray()
const projectFilter = filterId(projectId)
let [projectMyExist] = await projectCollection.find(projectFilter).toArray()
const members = await usersCollection.find({
_id: {
$in: projectMyExist.members.map((memberId) => new ObjectId(memberId)),
},
}).toArray()
projectMyExist.members = members.map((m) => ({
value: m._id, label: m.email,
}))
projectMyExist.author = userAuthor
projectMyExist = _idToId(projectMyExist)
return projectMyExist
}
const newProject = async ({
title,
code,
userId,
members,
}) => {
checkDB(db)
if (!title || !code) {
throw new Error('Fields can\'t be empty')
}
const projectCollection = db.collection(PROJECTS_COLL)
const project = {
title,
code,
userId,
created: Date.now(),
changed: Date.now(),
changedBy: userId,
taskIndex: 0,
members,
}
await projectCollection.insertOne(project)
return _idToId(project)
}
const updateProject = async ({ projectId, title, code, members }) => {
checkDB(db)
if (!title || !code) {
throw new Error('Fields can\'t be empty')
}
const projectCollection = db.collection(PROJECTS_COLL)
const projectFilterById = filterId(projectId)
const updatedProject = await projectCollection.updateOne(projectFilterById, {
$set: {
title,
code,
changed: Date.now(),
members,
},
})
return updatedProject
}
// TODO: Совмещение projectId с userId ИЛИ поиск по memberIds
const getProjectById = async ({ projectId }) => {
checkDB(db)
const projectFilterById = filterId(projectId)
const projectCollection = db.collection(PROJECTS_COLL)
const [projectExist] = await projectCollection.find(projectFilterById).toArray()
return projectExist
}
const getTaskById = async ({ taskId, userId }) => {
checkDB(db)
if (taskId) {
const userFilterById = filterId(userId)
const taskFilterById = filterId(taskId)
const taskCollection = db.collection(PROJECT_TASKS_COLL)
const usersCollection = db.collection(USERS_COLL)
let [taskExist] = await taskCollection.find(taskFilterById).toArray()
if (taskExist) {
const [userAuthor] = await usersCollection.find(userFilterById).toArray()
taskExist.author = userAuthor
return _idToId(taskExist)
}
}
return {
}
}
const createTask = async ({ taskData, authorId, projectId }) => {
checkDB(db)
const projectCollection = db.collection(PROJECTS_COLL)
const projectFilterById = filterId(projectId)
const [projectExist] = await projectCollection.find(projectFilterById).toArray()
if (!projectExist) {
throw new Error('The project not exists [createTask]')
}
const nextIndex = projectExist.taskIndex + 1
const taskCollection = db.collection(PROJECT_TASKS_COLL)
const { type, status, ...taskRest } = taskData
const task = {
...taskRest,
type: Number(type),
status: Number(status),
changed: Date.now(),
created: Date.now(),
taskIndex: nextIndex,
authorId,
projectId,
}
await projectCollection.updateOne(projectFilterById, {
$set: {
taskIndex: nextIndex,
projectChanged: Date.now(),
},
})
await taskCollection.insertOne(task)
return _idToId(task)
}
const getTaskListByProjectId = async ({ projectId }) => {
checkDB(db)
const projectFilterById = filterId(projectId)
const projectCollection = db.collection(PROJECTS_COLL)
const [projectExist] = await projectCollection.find(projectId).toArray()
if (!projectExist) {
throw new Error('The project not exists [getTaskListByProjectId]')
}
const taskCollection = db.collection(PROJECT_TASKS_COLL)
let taskListCandidate = await taskCollection.find({
projectId,
}).toArray()
// if (taskListCandidate.length > 0) {
// for (let index = 0; index < taskListCandidate.length; index++) {
// // const [userAuthor] = await usersCollection.find(userFilterById).toArray()
// // taskListCandidate[index].author = userAuthor
// projectExist[index] = _idToId(projectExist[index])
// }
// }
taskListCandidate = _idToIdArray(taskListCandidate)
return taskListCandidate
}
const editTask = async ({ taskData, projectId, authorId, taskId }) => {
checkDB(db)
const taskCollection = db.collection(PROJECT_TASKS_COLL)
const projectCollection = db.collection(PROJECTS_COLL)
const taskFilterById = filterId(taskId)
const projectFilterById = filterId(projectId)
const { type, status, ...taskRest } = taskData
const updatedTask = await taskCollection.updateOne(taskFilterById, {
$set: {
type: Number(type),
status: Number(status),
...taskRest,
},
})
await projectCollection.updateOne(projectFilterById, {
$set: {
projectChanged: Date.now(),
},
})
return updatedTask
}
const deleteTaskById = async (taskId) => {
checkDB(db)
const taskCollection = db.collection(PROJECT_TASKS_COLL)
const taskFilterById = filterId(taskId)
const deleted = await taskCollection.deleteOne(taskFilterById)
return deleted
}
const getAllUsers = async () => {
checkDB(db)
const usersCollection = db.collection(USERS_COLL)
let allUsers = await usersCollection.find().toArray()
return _idToIdArray(allUsers)
}
// const getProjectMember = async () => {
// checkDB(db)
// const usersCollection = db.collection(USERS_COLL)
// let allUsers = await usersCollection.find().toArray()
// return _idToIdArray(allUsers)
// }
const updateProjectMembers = async (projectData, members) => {
checkDB(db)
const memberCollection = db.collection(PROJECT_MEMBERS_COLL)
await memberCollection.deleteMany({
projectId: projectData.id,
})
const membersAdd = []
for (let memberIndex = 0; memberIndex < members.length; memberIndex++) {
const member = {
projectId: projectData.id,
memberId: members[memberIndex].value,
}
membersAdd.push(member)
}
const { insertedData } = await memberCollection.insertMany(membersAdd)
return insertedData
}
module.exports = {
connect,
registrationUser,
signInUser,
getMyProjects,
deleteProjectById,
newProject,
createTask,
editTask,
deleteTaskById,
getTaskListByProjectId,
getProjectById,
getMyProjectById,
getTaskById,
updateProject,
getAllUsers,
updateProjectMembers,
}

View File

@@ -0,0 +1,15 @@
const router = require('express').Router()
router.use('/', require('./auth'))
router.use((err, req, res, next) => {
res.status(400).send({
success: false, error: err.message || 'Что-то пошло не так',
})
})
router.use('/projects', require('./projects'))
router.use('/tasks', require('./tasks'))
router.use('/users', require('./users'))
module.exports = router

View File

@@ -0,0 +1,116 @@
const router = require('express').Router()
const { expressjwt: jwt } = require('express-jwt')
const { JWT_SECRET } = require('./constants')
const {
getMyProjects,
newProject,
getProjectById,
updateProject,
getMyProjectById,
deleteProjectById,
updateProjectMembers,
} = require('./db')
const { requiredFields, responseWrapper, _idToId } = require('./utils')
router.get('/healthcheck', (req, res) => {
res.send(true)
})
router.get('/', jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
try {
const projectList = await getMyProjects(req.auth.id)
res.send(responseWrapper(undefined, projectList))
} catch (e) {
next(e)
}
})
router.get('/:projectId', jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
try {
const { projectId } = req.params
const myProject = await getMyProjectById(req.auth.id, projectId)
res.send(responseWrapper(undefined, myProject))
} catch (e) {
next(e)
}
})
router.post('/new', jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
try {
const userId = req.auth.id
const { title, code, members } = req.body
const project = await newProject({
title, code, userId, members,
})
res.send(responseWrapper(undefined, project))
} catch (e) {
next(e)
}
})
router.post('/delete', jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
try {
const userId = req.auth.id
const { projectId } = req.body
const myProject = await getMyProjectById(userId, projectId)
if (myProject) {
const answered = await deleteProjectById(projectId)
if (answered.result.ok) {
res.send(responseWrapper(undefined))
}
}
} catch (e) {
next(e)
}
})
router.post('/edit', jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
try {
const userId = req.auth.id
const { projectId, title, code, members } = req.body
const projectCandidate = await getProjectById({
projectId,
})
if (!projectCandidate) {
throw new Error('The project not exists [project.edit]')
}
await updateProject({
projectId, title, code, members,
})
const updatedProject = await getProjectById({
projectId,
})
const projectSummary = {
oldData: projectCandidate,
newData: updatedProject,
}
res.send(responseWrapper(undefined, projectSummary))
} catch (e) {
next(e)
}
})
module.exports = router

View File

@@ -0,0 +1,137 @@
const router = require('express').Router()
const { expressjwt: jwt } = require('express-jwt')
const ObjectId = require('mongodb').ObjectID
const { JWT_SECRET } = require('./constants')
const { requiredFields, responseWrapper } = require('./utils')
const { createTask, getTaskListByProjectId, getProjectById, editTask, getTaskById, deleteTaskById } = require('./db')
router.get('/healthcheck', (req, res) => {
res.send(true)
})
router.get('/:projectId', jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
const { projectId } = req.params
const taskList = await getTaskListByProjectId({
projectId,
})
res.send(responseWrapper(undefined, taskList))
})
router.get('/:projectId/:taskId', jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
const { projectId, taskId } = req.params
if (projectId && taskId !== undefined && taskId !== 'undefined') {
const userId = req.auth.id
const taskDetail = await getTaskById({
taskId, userId,
})
res.send(responseWrapper(undefined, taskDetail))
} else {
res.send(responseWrapper(undefined, []))
}
})
router.post('/create', requiredFields(['projectId', 'title', 'type', 'status']), jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
try {
const authorId = req.auth.id
const { projectId, ...taskData } = req.body
const taskCandidate = await createTask({
taskData, projectId, authorId,
})
res.send(responseWrapper(undefined, taskCandidate))
} catch (e) {
next(e)
}
})
router.post('/edit', requiredFields(['projectId', 'taskId', 'title', 'type', 'status']), jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
try {
const authorId = req.auth.id
const { projectId, taskId, ...taskData } = req.body
const projectCandidate = await getProjectById({
projectId,
})
if (!projectCandidate) {
throw new Error('The project not exists [task.edit.projectCandidate]')
}
const taskCandidate = await getTaskById({
taskId,
})
if (!taskCandidate) {
throw new Error('The project not exists [task.edit.taskCandidate]')
}
await editTask({
taskData, projectId, authorId, taskId,
})
const updatedTask = await getTaskById({
taskId,
})
const taskSummary = {
oldData: taskCandidate,
newData: updatedTask,
}
res.send(responseWrapper(undefined, taskSummary))
} catch (e) {
next(e)
}
})
router.post('/delete', requiredFields(['projectId', 'taskId']), jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
try {
const authorId = req.auth.id
const { projectId, taskId } = req.body
const projectCandidate = await getProjectById({
projectId,
})
if (!projectCandidate) {
throw new Error('The project not exists [task.edit.projectCandidate]')
}
const taskCandidate = await getTaskById({
taskId,
})
if (!taskCandidate) {
throw new Error('The project not exists [task.edit.taskCandidate]')
}
const answered = await deleteTaskById(taskId)
if (answered.result.ok) {
res.send(responseWrapper(undefined))
}
} catch (e) {
next(e)
}
})
module.exports = router

View File

@@ -0,0 +1,21 @@
const router = require('express').Router()
const { expressjwt: jwt } = require('express-jwt')
const ObjectId = require('mongodb').ObjectID
const { JWT_SECRET } = require('./constants')
const { requiredFields, responseWrapper } = require('./utils')
const { getAllUsers } = require('./db')
router.get('/healthcheck', (req, res) => {
res.send(true)
})
router.get('/getForSelect', jwt({
secret: JWT_SECRET, algorithms: ['HS256'],
}), async (req, res, next) => {
const userList = await getAllUsers()
res.send(responseWrapper(undefined, userList))
})
module.exports = router

View File

@@ -0,0 +1,49 @@
const ObjectId = require('mongodb').ObjectID
const requiredFields = (fields) => (req, res, next) => {
for (const fieldName of fields) {
if (!req.body[fieldName]) {
throw new Error(`Field ${fieldName} does't set`)
}
}
next()
}
const responseWrapper = (error, data, success = true) => ({
error, data, success,
})
const _idToId = (data) => {
const { _id, ...rest } = data
return {
id: _id,
...rest,
}
}
const _idToIdArray = (arrayData, setAuthor = false) => {
let newArray = []
for (let index = 0; index < arrayData.length; index++) {
newArray[index] = _idToId(arrayData[index])
}
return newArray
}
const checkDB = (db) => {
if (db === null) throw new Error('no db connection')
}
const filterId = (id) => ({
_id: new ObjectId(id),
})
module.exports = {
checkDB,
requiredFields,
responseWrapper,
_idToId,
_idToIdArray,
filterId,
}