diff --git a/backend/src/db/daos/noteDao.js b/backend/src/db/daos/noteDao.js index 7286cb09..98260813 100644 --- a/backend/src/db/daos/noteDao.js +++ b/backend/src/db/daos/noteDao.js @@ -1,5 +1,6 @@ import Note from "../models/note.js"; import Group from "../models/group.js"; +import { HttpError } from "../../util/error.js"; /** * Checks if a user is in a group @@ -31,7 +32,7 @@ const createNote = async (groupId, title, email, text = "") => { if (role === null) { return null; } - const dbNote = new Note({ title, role, text }); + const dbNote = new Note({ title, role, text, date: new Date() }); await dbNote.save(); const updateQuery = {}; updateQuery[`notes.${role}`] = dbNote.id; @@ -48,19 +49,17 @@ const createNote = async (groupId, title, email, text = "") => { */ const deleteNote = async (noteId, groupId, email) => { const role = await checkRole(groupId, email); - const note = await Note.findById(noteId); - if (note.role !== role) { - return null; - } + const note = await Note.findById(noteId, { role: 1 }).lean(); + if (note?.role !== role) throw new HttpError(403, "Forbidden"); - const updateQuery = { - $pull: { [`notes.${note.role}`]: noteId }, - }; + const updateQuery = { $pull: { [`notes.${note.role}`]: noteId } }; + await Promise.all([ + // remove reference + Group.updateOne({ _id: groupId }, updateQuery), + // remove document + Note.deleteOne({ _id: noteId }), + ]); - // delete note from group - await Group.updateOne({ _id: groupId }, updateQuery); - // delete note from note collection - await note.delete(); return null; }; @@ -94,24 +93,13 @@ const updateNote = async (noteId, updatedNote, groupId, email) => { * @returns list of database note objects */ // I know the group is fetched for twice but this is currently not used anywhere -const retrieveNoteList = async (groupId, email) => { - const dbGroup = await Group.findById(groupId); - const role = await checkRole(groupId, email); - // if user is not in group return null - if (role === null) { - return null; - } - const allNotes = []; - const noteIds = [...dbGroup.notes.values()].flat(); - const dbNotes = await Note.find({ _id: { $in: noteIds } }, [ - "title", - "role", - "date", - "text", - ]); +const retrieveNoteList = async (groupId) => { + const { notes } = await Group.findById(groupId, { notes: 1 }).lean(); + + const noteIds = Object.values(notes).flat(); + const dbNotes = await Note.find({ _id: { $in: noteIds } }, { __v: 0 }); - allNotes.push(...dbNotes); - return allNotes; + return dbNotes; }; /** diff --git a/backend/src/routes/api/note.js b/backend/src/routes/api/note.js index 8b771601..44451044 100644 --- a/backend/src/routes/api/note.js +++ b/backend/src/routes/api/note.js @@ -7,6 +7,8 @@ import { retrieveNote, } from "../../db/daos/noteDao.js"; import auth from "../../middleware/firebaseAuth.js"; +import { handle } from "../../util/error.js"; +import STATUS from "../../util/status.js"; const router = Router(); const HTTP_OK = 200; @@ -14,9 +16,9 @@ const HTTP_OK = 200; router.use(auth); // Retrieve note list -router.get("/retrieveList/:groupId", async (req, res) => { +router.get("/retrieveAll/:groupId", async (req, res) => { const { groupId } = req.params; - const notes = retrieveNoteList(groupId); + const notes = await retrieveNoteList(groupId); res.status(HTTP_OK).json(notes); }); @@ -43,9 +45,12 @@ router.put("/update", async (req, res) => { }); // Delete a note -router.delete("/delete", async (req, res) => { - const { noteId, groupId, email } = req.body; - await deleteNote(noteId, groupId, email); - res.status(HTTP_OK).json("note deleted"); -}); +router.delete( + "/delete", + handle(async (req, res) => { + const { noteId, groupId, email } = req.body; + await deleteNote(noteId, groupId, email); + res.status(STATUS.OK).json("note deleted"); + }) +); export default router; diff --git a/frontend/src/features/playScenario/components/Note/Note.jsx b/frontend/src/features/playScenario/components/Note/Note.jsx deleted file mode 100644 index 07ff605b..00000000 --- a/frontend/src/features/playScenario/components/Note/Note.jsx +++ /dev/null @@ -1,310 +0,0 @@ -import AuthenticationContext from "context/AuthenticationContext"; -import { useAuthDelete, useAuthGet, useAuthPut } from "hooks/crudHooks"; -import { useContext, useEffect, useState } from "react"; -import styles from "./Note.module.scss"; - -export default function Note({ role, noteId, group, refetchGroup }) { - const { user } = useContext(AuthenticationContext); - const [noteContent, setContent] = useState(); - const [title, setTitle] = useState(); - const [date, setDate] = useState(); - const [open, setOpen] = useState(false); - // lock save process while saving - const [save, setSave] = useState(false); - // check if user has same role - const [isRole, setRole] = useState(false); - // show delete confirmation - const [showConfirm, setShowConfirm] = useState(false); - // is the current version of the note saved - const [saved, setSaved] = useState(false); - const { - response: noteData, - loading: noteLoading, - error: noteError, - getRequest: retrieveNoteRequest, - } = useAuthGet(`/api/note/retrieve/${noteId}`); - - const { - response: updateResult, - loading: updateLoading, - error: updateError, - putRequest: updateNoteRequest, - } = useAuthPut("/api/note/update"); - - const { - response: deleteResult, - loading: deleteLoading, - error: deleteError, - deleteRequest: deleteNoteRequest, - } = useAuthDelete(`/api/note/delete`); - - const getRole = () => { - group.users.forEach((userToCheck) => { - if (userToCheck.email === user.email) { - if (userToCheck.role === role) { - setRole(true); - } - } - }); - }; - - const loadNote = async () => { - if (noteData) { - setContent(noteData.text); - setTitle(noteData.title); - if (noteData.date) { - const dateObject = new Date(noteData.date); - setDate(dateObject); - } - } - }; - - async function fetchNote() { - console.log("fetching note"); - await retrieveNoteRequest(); - getRole(); - } - - useEffect(() => { - loadNote(); - }, [noteData]); - - useEffect(() => { - fetchNote(); - }, []); - - const handleContentInput = (e) => { - setSaved(false); - setContent(e.target.value); - }; - - const handleTitleInput = (e) => { - setSaved(false); - setTitle(e.target.value); - }; - - const handleOpen = () => { - setOpen(true); - }; - - const saveNote = async () => { - try { - await updateNoteRequest({ - noteId, - text: noteContent, - title, - groupId: group._id, - email: user.email, - }); - setSaved(true); - } catch (e) { - console.log(e); - throw new Error("Failed to save note"); - } - }; - - const handleSave = async () => { - if (save) return; - setSave(true); - try { - await saveNote(); - await fetchNote(); - } catch (e) { - console.log(e); - } finally { - console.log("note updated"); - setSave(false); - } - }; - - const handleClose = () => { - setOpen(false); - }; - - const deleteNote = async () => { - setShowConfirm(false); - try { - await deleteNoteRequest({ - noteId, - groupId: group._id, - email: user.email, - }); - refetchGroup(); - handleClose(); - } catch (e) { - console.log(e); - } - }; - - const handleDelete = () => { - setShowConfirm(true); - }; - - const handleKeyPress = (e) => { - if (e.key === "Escape") { - handleClose(); - } - }; - - if (noteLoading) { - return ( -
- {noteData?.text || "-"} -
- {/* Date time */} -- Last edit: {date instanceof Date ? date.toLocaleDateString() : "-"} -
-