diff --git a/app/controllers/comment.js b/app/controllers/comment.js index 2b9aafd..f78bb6b 100644 --- a/app/controllers/comment.js +++ b/app/controllers/comment.js @@ -1,6 +1,7 @@ const HANDLER = require('../utils/response-helper') const HttpStatus = require('http-status-codes') const CommentModel = require('../models/Comment') +const permission = require('../utils/permission') const helper = require('../utils/paginate') module.exports = { @@ -22,14 +23,13 @@ module.exports = { // DELETE COMMENT delete: async (req, res, next) => { const { id } = req.params - const userId = req.user.id.toString() try { const comment = await CommentModel.findById(id) if (!comment) { return res.status(HttpStatus.NOT_FOUND).json({ error: 'No comment exist' }) } // Add rights for admins and moderators as well (TODO) - if (JSON.stringify(comment.userId) !== JSON.stringify(userId)) { + if (!permission.check(req, res, comment.userId)) { return res.status(HttpStatus.FORBIDDEN).json({ message: 'Bad delete request' }) } await CommentModel.findByIdAndRemove(id) @@ -42,7 +42,6 @@ module.exports = { // UPDATE COMMENT update: async (req, res, next) => { const { id } = req.params - const userId = req.user.id.toString() const updates = Object.keys(req.body) const valid = ['content'] const isValidOperation = updates.every((update) => { @@ -57,7 +56,7 @@ module.exports = { return res.status(HttpStatus.NOT_FOUND).json({ error: 'No comment exist' }) } // also add admin or moderator control (TODO) - if (JSON.stringify(comment.userId) !== JSON.stringify(userId)) { + if (!permission.check(req, res, comment.userId)) { return res.status(HttpStatus.BAD_REQUEST).json({ error: 'Wrong update' }) } updates.forEach(update => { diff --git a/app/controllers/event.js b/app/controllers/event.js index da16a39..9246e63 100644 --- a/app/controllers/event.js +++ b/app/controllers/event.js @@ -1,6 +1,7 @@ const Event = require('../models/Event') const HANDLER = require('../utils/response-helper') const HttpStatus = require('http-status-codes') +const permission = require('../utils/permission') const helper = require('../utils/paginate') module.exports = { @@ -23,6 +24,7 @@ module.exports = { if (!event) { return res.status(HttpStatus.BAD_REQUEST).json({ message: 'No post exists' }) } + // check for permission (TODO AFTER PREVIOUS PR MERGED) updates.forEach(update => { event[update] = req.body[update] }) @@ -114,8 +116,11 @@ module.exports = { if (!deleteEvent) { return res.status(HttpStatus.NOT_FOUND).json({ message: 'No Event exists' }) } - await Event.findByIdAndRemove(id) - res.status(HttpStatus.OK).json({ deleteEvent: deleteEvent, message: 'Deleted the event' }) + if (permission.check(req, res, deleteEvent.createdBy)) { + await Event.findByIdAndRemove(id) + return res.status(HttpStatus.OK).json({ deleteEvent: deleteEvent, message: 'Deleted the event' }) + } + return res.status(HttpStatus.BAD_REQUEST).json({ msg: 'Not permitted!' }) } catch (error) { HANDLER.handleError(res, error) } diff --git a/app/controllers/organization.js b/app/controllers/organization.js index 3ff2a53..128b337 100644 --- a/app/controllers/organization.js +++ b/app/controllers/organization.js @@ -2,6 +2,10 @@ const Organization = require('../models/Organisation') const HANDLER = require('../utils/response-helper') const HttpStatus = require('http-status-codes') const helper = require('../utils/uploader') +const User = require('../models/User') +const Project = require('../models/Project') +const Event = require('../models/Event') +const permission = require('../utils/permission') module.exports = { createOrganization: async (req, res, next) => { @@ -20,7 +24,7 @@ module.exports = { updateOrgDetails: async (req, res, next) => { const { id } = req.params const updates = Object.keys(req.body) - const allowedUpdates = ['name', 'description', 'contactInfo', 'image', 'adminInfo', 'moderatorInfo'] + const allowedUpdates = ['name', 'description', 'contactInfo', 'image', 'imgUrl', 'adminInfo', 'moderatorInfo'] const isValidOperation = updates.every((update) => { return allowedUpdates.includes(update) }) @@ -30,6 +34,10 @@ module.exports = { } try { const org = await Organization.findById(id) + // check for permission (ONLY ADMINS CAN UPDATE) + if (!permission.check(req, res)) { + return res.status(HttpStatus.BAD_REQUEST).json({ msg: 'You don\'t have the permission' }) + } updates.forEach(update => { org[update] = req.body[update] }) @@ -46,11 +54,11 @@ module.exports = { getOrgDetailsById: async (req, res, next) => { const { id } = req.params try { - const orgData = await Organization - .findById(id) + const orgData = await Organization.findById(id) .populate('adminInfo', ['name.firstName', 'name.lastName', 'email', 'isAdmin']) .populate('moderatorInfo', ['name.firstName', 'name.lastName', 'email', 'isAdmin']) .sort({ createdAt: -1 }) + .lean() .exec() if (!orgData) { return res.status(HttpStatus.NOT_FOUND).json({ error: 'No such organization exists!' }) @@ -68,7 +76,11 @@ module.exports = { if (!org) { return res.status(HttpStatus.NOT_FOUND).json({ error: 'No such organization exists!' }) } - res.status(HttpStatus.OK).json({ organization: org }) + // check for permission + if (!permission.check(req, res)) { + return res.status(HttpStatus.BAD_REQUEST).json({ msg: 'You don\'t have the permission!' }) + } + return res.status(HttpStatus.OK).json({ organization: org }) } catch (error) { HANDLER.handleError(res, error) } @@ -83,7 +95,7 @@ module.exports = { } org.isArchived = true await org.save() - res.status(HttpStatus.OK).json({ organization: org }) + return res.status(HttpStatus.OK).json({ organization: org }) } catch (error) { HANDLER.handleError(res, error) } @@ -157,5 +169,51 @@ module.exports = { } catch (error) { HANDLER.handleError(res, error) } + }, + getOrgOverView: async (req, res, next) => { + const orgOverView = {} + try { + const org = await Organization.find({}) + if (!org) { + return res.status(HttpStatus.NOT_FOUND).json({ msg: 'No org exists!' }) + } + orgOverView.admins = org[0].adminInfo.length + orgOverView.members = await User.find({}).lean().count() + orgOverView.projects = await Project.find({}).lean().count() + orgOverView.events = await Event.find({}).lean().count() + return res.status(HttpStatus.OK).json({ orgOverView }) + } catch (error) { + HANDLER.handleError(res, error) + } + }, + // SEARCH FUNCTIONALITY + getMembers: async (req, res, next) => { + try { + const { search } = req.query + if (search) { + const regex = search.split(' ') + const member = await User.find({ $or: [{ 'name.firstName': regex }, { 'name.lastName': regex }] }) + .select('name email isAdmin info.about.designation') + .lean() + .sort({ createdAt: -1 }) + .exec() + if (!member) { + return res.status(HttpStatus.OK).json({ msg: 'Member not found!' }) + } + return res.status(HttpStatus.OK).json({ member }) + } else { + const members = await User.find({}) + .select('name email isAdmin info.about.designation') + .lean() + .sort({ createdAt: -1 }) + .exec() + if (members.length === 0) { + return res.status(HttpStatus.OK).json({ msg: 'No members joined yet!' }) + } + return res.status(HttpStatus.OK).json({ members }) + } + } catch (error) { + HANDLER.handleError(res, error) + } } } diff --git a/app/controllers/post.js b/app/controllers/post.js index e6f5578..b174463 100644 --- a/app/controllers/post.js +++ b/app/controllers/post.js @@ -3,6 +3,7 @@ const UserModel = require('../models/User') const HANDLER = require('../utils/response-helper') const HttpStatus = require('http-status-codes') const imgUploadHelper = require('../utils/uploader') +const permission = require('../utils/permission') const helper = require('../utils/paginate') module.exports = { @@ -25,15 +26,13 @@ module.exports = { // DELETE POST delete: async (req, res, next) => { const { id } = req.params - const userId = req.user.id.toString() try { const post = await PostModel.findById(id) if (!post) { return res.status(HttpStatus.NOT_FOUND).json({ message: 'No post exists' }) } - // TODO ADD ADMIN RIGHTS AS WELL - if (JSON.stringify(userId) !== JSON.stringify(post.userId)) { - return res.status(HttpStatus.FORBIDDEN).json({ message: 'Bad delete request' }) + if (!permission.check(req, res, post.userId)) { + return res.status(HttpStatus.BAD_REQUEST).json({ message: 'Bad delete request' }) } await PostModel.findByIdAndRemove(id) res.status(HttpStatus.OK).json({ post: post, msg: 'Deleted!' }) @@ -47,7 +46,6 @@ module.exports = { const { id } = req.params const updates = Object.keys(req.body) const allowedUpdates = ['content', 'imgUrl'] - const userId = req.user.id.toString() const isValidOperation = updates.every((update) => { return allowedUpdates.includes(update) }) @@ -60,7 +58,7 @@ module.exports = { if (!post) { return res.status(HttpStatus.BAD_REQUEST).json({ message: 'No post exists' }) } - if (JSON.stringify(userId) !== JSON.stringify(post.userId)) { + if (!permission.check(req, res, post.userId)) { return res.status(HttpStatus.FORBIDDEN).json({ message: 'Bad update request' }) } updates.forEach(update => { diff --git a/app/controllers/project.js b/app/controllers/project.js index e354788..a5beb1a 100644 --- a/app/controllers/project.js +++ b/app/controllers/project.js @@ -2,6 +2,7 @@ const Project = require('../models/Project') const HANDLER = require('../utils/response-helper') const HttpStatus = require('http-status-codes') const helper = require('../utils/paginate') +const permission = require('../utils/permission') module.exports = { createProject: async (req, res, next) => { @@ -83,10 +84,11 @@ module.exports = { return res.status(HttpStatus.NOT_FOUND).json({ msg: 'No such project exits!' }) } // check if admin or user who created this project - if (project.createdBy === req.user._id.toString() || req.user.isAdmin === true) { + if (permission.check(req, res, project.createdBy)) { await Project.findByIdAndRemove(id) return res.status(HttpStatus.OK).json({ msg: 'Project deleted!' }) } + return res.status(HttpStatus.BAD_REQUEST).json({ msg: 'Not permitted!' }) } catch (error) { HANDLER.handleError(res, error) } diff --git a/app/controllers/user.js b/app/controllers/user.js index eed4310..e035072 100644 --- a/app/controllers/user.js +++ b/app/controllers/user.js @@ -2,9 +2,13 @@ const User = require('../models/User') const jwt = require('jsonwebtoken') const HttpStatus = require('http-status-codes') const emailController = require('./email') +const permission = require('../utils/permission') const HANDLER = require('../utils/response-helper') +const Projects = require('../models/Project') +const Events = require('../models/Event') module.exports = { + // CREATE USER createUser: async (req, res, next) => { const user = new User(req.body) try { @@ -18,21 +22,19 @@ module.exports = { return res.status(HttpStatus.NOT_ACCEPTABLE).json({ error: error }) } }, - + // GET USER PROFILE userProfile: async (req, res, next) => { res.status(HttpStatus.OK).json(req.user) }, + // USER PROFILE UPDATE userProfileUpdate: async (req, res, next) => { const updates = Object.keys(req.body) const allowedUpdates = [ 'name', 'email', - 'password', - 'company', - 'website', - 'location', - 'about' + 'phone', + 'info' ] const isValidOperation = updates.every((update) => { return allowedUpdates.includes(update) @@ -47,12 +49,13 @@ module.exports = { req.user[update] = req.body[update] }) await req.user.save() - res.status(HttpStatus.OK).json({ data: req.user }) + return res.status(HttpStatus.OK).json({ data: req.user }) } catch (error) { - res.status(HttpStatus.BAD_REQUEST).json({ error }) + return res.status(HttpStatus.BAD_REQUEST).json({ error }) } }, + // FORGOT PASSWORD REQUEST forgotPasswordRequest: async (req, res) => { const { email } = req.body try { @@ -71,6 +74,7 @@ module.exports = { } }, + // UPDATE PASSWORD updatePassword: async (req, res) => { const { password, id } = req.body const { token } = req.params @@ -101,20 +105,31 @@ module.exports = { } }, - logout: (req, res, next) => { - res.status(HttpStatus.OK).json({ success: 'ok' }) + // LOGOUT USER + logout: async (req, res, next) => { + try { + req.user.tokens = [] + await req.user.save() + return res.status(HttpStatus.OK).json({ msg: 'User logged out Successfully!' }) + } catch (error) { + HANDLER.handleError(res, error) + } }, + // REMOVE USER userDelete: async (req, res, next) => { try { - await req.user.remove() - res.send({ data: 'user deletion successful', user: req.user }) + if (permission.check(req, res)) { + await req.user.remove() + return res.send({ data: 'user deletion successful', user: req.user }) + } + return res.status(HttpStatus.BAD_REQUEST).json({ msg: 'You don\'t have permission!' }) } catch (error) { - console.log(error) - res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error }) + return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error }) } }, + // USER ACCOUNT ACTIVATION activateAccount: async (req, res, next) => { try { const { token } = req.params @@ -135,12 +150,14 @@ module.exports = { } }, + // GET INVITE LINK getInviteLink: async (req, res, next) => { const token = jwt.sign({ _id: req.user._id, expiry: Date.now() + 24 * 3600 * 1000 }, process.env.JWT_SECRET) const inviteLink = `${req.protocol}://${req.get('host')}/user/invite/${token}` return res.status(HttpStatus.OK).json({ inviteLink: inviteLink }) }, + // PROCESS THE INVITE LINK processInvite: async (req, res, next) => { const { token } = req.params const decodedToken = jwt.verify(token, process.env.JWT_SECRET) @@ -239,6 +256,8 @@ module.exports = { HANDLER.handleError(res, error) } }, + + // BLOCK THE USER blockUser: async (req, res, next) => { const { id } = req.params try { @@ -260,6 +279,8 @@ module.exports = { HANDLER.handleError(res, error) } }, + + // UNBLOCK USER unBlockUser: async (req, res, next) => { const { id } = req.params try { @@ -285,5 +306,18 @@ module.exports = { } catch (error) { HANDLER.handleError(res, error) } + }, + + // GET OVERALL PERSONAL OVERVIEW + getPersonalOverview: async (req, res, next) => { + const userId = req.user._id + const personalOverview = {} + try { + personalOverview.projects = await Projects.find({ createdBy: userId }).estimatedDocumentCount() + personalOverview.events = await Events.find({ createdBy: userId }).estimatedDocumentCount() + return res.status(HttpStatus.OK).json({ personalOverview }) + } catch (error) { + HANDLER.handleError(req, error) + } } } diff --git a/app/models/Organisation.js b/app/models/Organisation.js index 5f2ffcd..8891abe 100644 --- a/app/models/Organisation.js +++ b/app/models/Organisation.js @@ -47,7 +47,7 @@ const orgSchema = new Schema({ } }, image: { - type: Buffer, + data: Buffer, contentType: String }, imgUrl: { diff --git a/app/routes/event.js b/app/routes/event.js index 08854a7..0d0dc02 100644 --- a/app/routes/event.js +++ b/app/routes/event.js @@ -15,6 +15,7 @@ router.get( // get all the events router.get( '/upcoming', + isUnderMaintenance, auth, eventController.UpComingEvents ) @@ -58,6 +59,7 @@ router.delete( // GET ALL EVENT POSTED BY A USER router.get( '/me/all', + isUnderMaintenance, auth, eventController.getAllEventByUser ) diff --git a/app/routes/organisation.js b/app/routes/organisation.js index e3e1167..b69e5d9 100644 --- a/app/routes/organisation.js +++ b/app/routes/organisation.js @@ -54,6 +54,20 @@ router.patch( OrgController.triggerMaintenance ) +// GET ORG OVERVIEW FOR INSIGHT PAGE +router.get( + '/overview/all', + auth, + OrgController.getOrgOverView +) + +// GET MEMBERS FOR INSIGHT PAGE +router.get( + '/members/all', + auth, + OrgController.getMembers +) + // UPDATE THE ORG SETTINGS router.patch( '/:id/settings/update', diff --git a/app/routes/project.js b/app/routes/project.js index 0874eed..178a3f6 100644 --- a/app/routes/project.js +++ b/app/routes/project.js @@ -2,10 +2,12 @@ const express = require('express') const projectController = require('../controllers/project') const router = express.Router() const auth = require('../middleware/auth') +const isUnderMaintenance = require('../middleware/maintenance') // ADD PROJECT router.post( '/', + isUnderMaintenance, auth, projectController.createProject ) @@ -13,6 +15,7 @@ router.post( // GET ALL PROJECTS router.get( '/', + isUnderMaintenance, auth, projectController.getAllProjects ) @@ -20,6 +23,7 @@ router.get( // GET PROJECT BY ID router.get( '/:id', + isUnderMaintenance, auth, projectController.getProjectById ) @@ -27,6 +31,7 @@ router.get( // UPDATE PROJECT INFO router.patch( '/:id', + isUnderMaintenance, auth, projectController.updateProject ) @@ -34,6 +39,7 @@ router.patch( // DELETE PROJECT router.delete( '/:id', + isUnderMaintenance, auth, projectController.deleteProject ) @@ -41,6 +47,7 @@ router.delete( // GET PROJECTS CREATED BY A USER router.get( '/me/all', + isUnderMaintenance, auth, projectController.projectCreatedByUser ) diff --git a/app/routes/user.js b/app/routes/user.js index 66f9679..2d9073f 100644 --- a/app/routes/user.js +++ b/app/routes/user.js @@ -73,9 +73,17 @@ router.delete( userController.userDelete ) +// LOGOUT USER +router.post( + '/logout', + auth, + userController.logout +) + // follow the user router.patch( '/follow', + isUnderMaintenance, auth, userController.addFollowing, userController.addFollower @@ -84,6 +92,7 @@ router.patch( // unFollow the user router.patch( '/unfollow', + isUnderMaintenance, auth, userController.removeFollowing, userController.removeFollower @@ -92,6 +101,7 @@ router.patch( // BLOCK THE USER router.patch( '/block/:id', + isUnderMaintenance, auth, userController.blockUser ) @@ -99,8 +109,17 @@ router.patch( // UNBLOCK THE USER router.patch( '/unblock/:id', + isUnderMaintenance, auth, userController.unBlockUser ) +// GET PERSONAL OVERVIEW +router.get( + '/overview', + isUnderMaintenance, + auth, + userController.getPersonalOverview +) + module.exports = router diff --git a/app/utils/permission.js b/app/utils/permission.js new file mode 100644 index 0000000..f00a933 --- /dev/null +++ b/app/utils/permission.js @@ -0,0 +1,23 @@ +const HANDLER = require('../utils/response-helper') + +module.exports = { + check: async (req, res, creatorId = 0) => { + const userId = req.user.id.toString() + try { + // if user is an admin + if (req.user.isAdmin) { + console.log('user is admin! ') + return true + } + // if user is post/event/project/comment creator + if (JSON.stringify(userId) === JSON.stringify(creatorId)) { + console.log('user is creator!') + return true + } + // else + return false + } catch (error) { + HANDLER.handleError(res, error) + } + } +} diff --git a/app/utils/uploader.js b/app/utils/uploader.js index e892aaa..239abc1 100644 --- a/app/utils/uploader.js +++ b/app/utils/uploader.js @@ -36,10 +36,6 @@ exports.upload = multer({ exports.mapToDb = (req, db) => { const img = fs.readFileSync(req.file.path) - const encodedImage = img.toString('base64') - const image = { - contentType: req.file.mimetype, - image: Buffer.from(encodedImage, 'base64') - } - db.image = image + db.image.data = img + db.image.contentType = 'image/png' } diff --git a/test/user.test.js b/test/user.test.js index 4430ec1..9846440 100644 --- a/test/user.test.js +++ b/test/user.test.js @@ -260,6 +260,16 @@ test('Should validate the invite link token ', async () => { .expect(HttpStatus.OK) }) +/* Logout the user */ +test('Should logout the user ', async (done) => { + await request(app) + .post('/user/logout') + .set('Authorization', `Bearer ${testUser.tokens[0].token}`) + .send() + .expect(HttpStatus.OK) + done() +}) + /* Follow the user */ test('Should follow the user', async (done) => { await request(app)