diff --git a/backend/src/controllers/poll.controller.js b/backend/src/controllers/poll.controller.js index db18588..1f73e93 100644 --- a/backend/src/controllers/poll.controller.js +++ b/backend/src/controllers/poll.controller.js @@ -1,4 +1,5 @@ import { + addToBookMarkService, createPollService, createVoteService, deletePollService, @@ -86,12 +87,11 @@ export async function deletePollController(req, res) { const reqUser = req.user; const deletedPoll = await deletePollService(reqPollId, reqUser); res.json({ - success : true, - message : "Poll deleted successfully.", - data : deletedPoll - }) - } - catch (err) { + success: true, + message: "Poll deleted successfully.", + data: deletedPoll, + }); + } catch (err) { console.log(err); if (err.statusCode) { res.status(err.statusCode).json({ @@ -107,7 +107,6 @@ export async function deletePollController(req, res) { } } - export const createVoteController = async (req, res) => { try { const reqPollId = req.body.pollId; @@ -115,13 +114,39 @@ export const createVoteController = async (req, res) => { const reqUserId = req.user._id; const vote = await createVoteService(reqPollId, reqUserId, reqOptionId); - + res.json({ - success : true, - message : "Vote created successfully.", - data : vote - }) - } + success: true, + message: "Vote created successfully.", + data: vote, + }); + } catch (err) { + console.log(err); + if (err.statusCode) { + res.status(err.statusCode).json({ + success: false, + message: err.message, + }); + } else { + res.status(500).json({ + success: false, + message: err.message, + }); + } + } +}; + +export const addToBookmarkController = async (req, res) => { + try{ + const reqPollId = req.params.pollId; + const reqUser = req.user; + const {updatedData, message} = await addToBookMarkService(reqPollId, reqUser); + res.json({ + success: true, + message: message, + data : updatedData + }) + } catch (err) { console.log(err); if (err.statusCode) { diff --git a/backend/src/repositories/poll.repo.js b/backend/src/repositories/poll.repo.js index 7f85943..0eb64cf 100644 --- a/backend/src/repositories/poll.repo.js +++ b/backend/src/repositories/poll.repo.js @@ -18,7 +18,10 @@ export async function findPollById(id) { return poll; } catch(err){ - throw err; + throw { + statusCode : 404, + message : "Poll dont exits." + }; } } @@ -57,4 +60,4 @@ export async function updatePollVoteCount(pollId, optionId) { catch(err){ throw err; } -} \ No newline at end of file +} diff --git a/backend/src/repositories/user.repo.js b/backend/src/repositories/user.repo.js index 329d679..aa9ba1e 100644 --- a/backend/src/repositories/user.repo.js +++ b/backend/src/repositories/user.repo.js @@ -1,36 +1,63 @@ -import UserModel from "../models/user.model.js" +import UserModel from "../models/user.model.js"; export const createUser = async (username, email, password) => { - try { - const createdUser = await UserModel.create({ - username, - email, - password - }) + try { + const createdUser = await UserModel.create({ + username, + email, + password, + }); - return createdUser; - } - catch(err) { - throw err - } -} + return createdUser; + } catch (err) { + throw err; + } +}; export async function findUserByEmail(email) { - try{ - const user = await UserModel.findOne({email}); - return user; - } - catch(err){ - throw err; - } + try { + const user = await UserModel.findOne({ email }); + return user; + } catch (err) { + throw err; + } } export async function findUserById(id) { - try{ - const user = await UserModel.findById(id); - return user; + try { + const user = await UserModel.findById(id); + return user; + } catch (err) { + throw err; + } +} + +export async function addPollIdToBookmark(userId, pollId) { + try { + const updatedData = UserModel.findOneAndUpdate( + { _id: userId }, + { $push: { bookmarks: pollId } }, + { new: true } + ); + + return updatedData; + } catch (err) { + throw err; + } +} + + +export async function removePollIdFromBookmark(userId, pollId) { + try { + const updatedData = UserModel.findOneAndUpdate( + { _id: userId }, + { $pull: { bookmarks: pollId } }, + { new: true } + ); + + return updatedData; } - catch(err){ + catch{ throw err; } } \ No newline at end of file diff --git a/backend/src/routes/v1/poll.route.js b/backend/src/routes/v1/poll.route.js index f75e729..a545d8d 100644 --- a/backend/src/routes/v1/poll.route.js +++ b/backend/src/routes/v1/poll.route.js @@ -1,6 +1,6 @@ import express from "express"; import { verifyToken } from "../../middlwares/verifyToken.js"; -import { createPollController, createVoteController, deletePollController, getAllCreatedPollsController, getPollDataController } from "../../controllers/poll.controller.js"; +import { addToBookmarkController, createPollController, createVoteController, deletePollController, getAllCreatedPollsController, getPollDataController } from "../../controllers/poll.controller.js"; import pollDataSchema from "../../validations/pollDataValidation.js"; import validator from "../../validations/validator.js"; import voteSchema from "../../validations/voteValidation.js"; @@ -157,4 +157,27 @@ pollRouter.delete("/delete/:pollId", verifyToken, deletePollController); */ pollRouter.post("/vote", validator(voteSchema), verifyToken, createVoteController); +/** + * @swagger + * /poll/bookmark/{pollId}: + * get: + * summary: Add poll to bookmark + * tags: [Bookmark] + * parameters: + * - in: path + * name: pollId + * schema: + * type: string + * required: true + * description: Poll ID + * responses: + * 200: + * description: Poll added to bookmark successfully + * 401: + * description: Unauthorized + * 500: + * description: Internal server error + * */ +pollRouter.get("/bookmark/:pollId", verifyToken, addToBookmarkController); + export default pollRouter; \ No newline at end of file diff --git a/backend/src/services/poll.service.js b/backend/src/services/poll.service.js index 19b7bc3..61d24a8 100644 --- a/backend/src/services/poll.service.js +++ b/backend/src/services/poll.service.js @@ -1,108 +1,142 @@ import mongoose from "mongoose"; -import { createPollByData, deletePollById, findPollById, findPollsByCreatorId, updatePollVoteCount } from "../repositories/poll.repo.js"; -import { createVote, findVoteByPollIdAndUserId } from "../repositories/vote.repo.js"; +import { + createPollByData, + deletePollById, + findPollById, + findPollsByCreatorId, + updatePollVoteCount, +} from "../repositories/poll.repo.js"; +import { + createVote, + findVoteByPollIdAndUserId, +} from "../repositories/vote.repo.js"; +import { + addPollIdToBookmark, + removePollIdFromBookmark, +} from "../repositories/user.repo.js"; export async function createPollService(title, description, options, userId) { - try { - const optionsData = options.map(option => ({ - name: option, - _id : new mongoose.Types.ObjectId(), - voteCount : 0 - })); + try { + const optionsData = options.map((option) => ({ + name: option, + _id: new mongoose.Types.ObjectId(), + voteCount: 0, + })); - const data = { - title, - description, - options : optionsData, - creatorId: userId - } - const poll = await createPollByData(data); - return poll; - } - catch(err){ - throw err; - } + const data = { + title, + description, + options: optionsData, + creatorId: userId, + }; + const poll = await createPollByData(data); + return poll; + } catch (err) { + throw err; + } } export async function getPollDataService(pollId) { - try { - const poll = await findPollById(pollId); - if (!poll) { - throw { - statusCode: 404, - message: "Poll not found" - } - } - const {creatorId, ...pollData} = poll._doc; - const {username, _id, ...creatorData} = creatorId._doc; - return {pollData, creatorData : {username, _id}}; - } - catch(err){ - throw err; + try { + const poll = await findPollById(pollId); + if (!poll) { + throw { + statusCode: 404, + message: "Poll not found", + }; } + const { creatorId, ...pollData } = poll._doc; + const { username, _id, ...creatorData } = creatorId._doc; + return { pollData, creatorData: { username, _id } }; + } catch (err) { + throw err; + } } export async function getAllCreatedPollsService(id) { - try { - const polls = await findPollsByCreatorId(id); - return polls; - } - catch(err){ - throw err; - } + try { + const polls = await findPollsByCreatorId(id); + return polls; + } catch (err) { + throw err; + } } export async function deletePollService(pollId, user) { - try { - const userId = user._id; - const poll = await findPollById(pollId); - if (!poll) { - throw { - statusCode: 404, - message: "Poll not found" - } - } - console.log(poll?.creatorId._id.toString(), userId.toString(), user); - if (poll.creatorId._id.toString() !== userId.toString()) { - throw { - statusCode: 401, - message: "Unauthorized" - } - } - const deletedPoll = await deletePollById(pollId); - return deletedPoll; + try { + const userId = user._id; + const poll = await findPollById(pollId); + if (!poll) { + throw { + statusCode: 404, + message: "Poll not found", + }; } - - catch(err){ - throw err; + console.log(poll?.creatorId._id.toString(), userId.toString(), user); + if (poll.creatorId._id.toString() !== userId.toString()) { + throw { + statusCode: 401, + message: "Unauthorized", + }; } + const deletedPoll = await deletePollById(pollId); + return deletedPoll; + } catch (err) { + throw err; + } } export async function createVoteService(pollId, userId, optionId) { - try { - // vote already voted - const vote = await findVoteByPollIdAndUserId(pollId, userId); - if (vote) { - throw { - statusCode: 400, - message: "You have already voted on this poll" - } - } - console.log(pollId, userId, optionId); - const poll = await findPollById(pollId); - if (!poll) { - throw { - statusCode: 404, - message: "Poll not found" - } - } - const updatedPollData = await updatePollVoteCount(pollId, optionId); - const createdVote = await createVote(pollId, userId, optionId); - console.log(updatedPollData) - return createVote; - + try { + // vote already voted + const vote = await findVoteByPollIdAndUserId(pollId, userId); + if (vote) { + throw { + statusCode: 400, + message: "You have already voted on this poll", + }; } - catch(err){ - throw err; + console.log(pollId, userId, optionId); + const poll = await findPollById(pollId); + if (!poll) { + throw { + statusCode: 404, + message: "Poll not found", + }; } -} \ No newline at end of file + const updatedPollData = await updatePollVoteCount(pollId, optionId); + const createdVote = await createVote(pollId, userId, optionId); + console.log(updatedPollData); + return createVote; + } catch (err) { + throw err; + } +} + +export async function addToBookMarkService(pollId, user) { + try { + const exits = user?.bookmarks.findIndex((id) => id.toString() == pollId); + const poll = await findPollById(pollId); + if (!poll) { + throw { + statusCode: 404, + message: "Poll dont exits.", + }; + } + let updatedData; + let message; + if (exits == -1) { + updatedData = await addPollIdToBookmark(user._id, poll._id); + message = "Added to bookmark successfully."; + } else { + updatedData = await removePollIdFromBookmark(user._id, poll._id); + message = "Removed from bookmark successfully."; + } + return { + updatedData, + message, + }; + } catch (err) { + throw err; + } +} diff --git a/frontend/src/pages/VotingPage.jsx b/frontend/src/pages/VotingPage.jsx index 8f795dd..cbe506a 100644 --- a/frontend/src/pages/VotingPage.jsx +++ b/frontend/src/pages/VotingPage.jsx @@ -36,7 +36,7 @@ function VotingPage() { mutation.mutate({ pollId, optionId: id }); } - + const chartData = { labels: poll?.data?.pollData?.options.map(option => option.name), datasets: [