This commit is contained in:
106
backend/src/routes/folder.js
Normal file
106
backend/src/routes/folder.js
Normal file
@@ -0,0 +1,106 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
const Campaign = require('../models/Campaign');
|
||||
const Folder = require('../models/Folder');
|
||||
const Note = require('../models/Note');
|
||||
|
||||
async function userOwnsCampaign(campaignId, userId) {
|
||||
const campaign = await Campaign.findOne({ _id: campaignId, createdBy: userId }).lean();
|
||||
return Boolean(campaign);
|
||||
}
|
||||
|
||||
router.get('/list', async (req, res) => {
|
||||
try {
|
||||
const { campaign } = req.query;
|
||||
if (!campaign) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
const hasAccess = await userOwnsCampaign(campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: 'error', msg: 'unauthorized' });
|
||||
|
||||
const folders = await Folder.find({ campaign })
|
||||
.select('_id name date')
|
||||
.sort({ date: -1 })
|
||||
.lean();
|
||||
|
||||
res.json({ status: 'ok', folders });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/create', async (req, res) => {
|
||||
try {
|
||||
const { name, campaign } = req.body;
|
||||
if (!name || !campaign) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
const hasAccess = await userOwnsCampaign(campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: 'error', msg: 'unauthorized' });
|
||||
|
||||
const newFolder = new Folder({
|
||||
name: name.trim(),
|
||||
campaign
|
||||
});
|
||||
await newFolder.save();
|
||||
res.json({ status: 'ok', folder: newFolder });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/delete', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.body;
|
||||
if (!id) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
const folder = await Folder.findById(id);
|
||||
if (!folder) return res.json({ status: 'error', msg: 'errors.notfound' });
|
||||
|
||||
const hasAccess = await userOwnsCampaign(folder.campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: 'error', msg: 'unauthorized' });
|
||||
|
||||
async function moveRecursive(folderId) {
|
||||
const subfolders = await Folder.find({ parentFolder: folderId }).select('_id').lean();
|
||||
await Note.updateMany(
|
||||
{ folder: folderId },
|
||||
{ $set: { folder: null, date: Date.now() } }
|
||||
);
|
||||
await Folder.deleteOne({ _id: folderId });
|
||||
for (const sub of subfolders) {
|
||||
await moveRecursive(sub._id);
|
||||
}
|
||||
}
|
||||
|
||||
await moveRecursive(id);
|
||||
|
||||
res.json({ status: 'ok' });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/rename', async (req, res) => {
|
||||
try {
|
||||
const { id, name } = req.body;
|
||||
if (!id || !name) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
const folder = await Folder.findById(id);
|
||||
if (!folder) return res.json({ status: 'error', msg: 'errors.notfound' });
|
||||
|
||||
const hasAccess = await userOwnsCampaign(folder.campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: 'error', msg: 'unauthorized' });
|
||||
|
||||
folder.name = name.trim();
|
||||
await folder.save();
|
||||
|
||||
res.json({ status: 'ok', folder });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -1,8 +1,9 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
const Campaign = require("../models/Campaign");
|
||||
const Note = require("../models/Note");
|
||||
const Campaign = require('../models/Campaign');
|
||||
const Note = require('../models/Note');
|
||||
const Folder = require('../models/Folder');
|
||||
|
||||
async function userOwnsCampaign(campaignId, userId) {
|
||||
const campaign = await Campaign.findOne({ _id: campaignId, createdBy: userId }).lean();
|
||||
@@ -12,74 +13,115 @@ async function userOwnsCampaign(campaignId, userId) {
|
||||
router.get('/list', async (req, res) => {
|
||||
try {
|
||||
const { campaign } = req.query;
|
||||
if (!campaign) return res.json({ status: "error", msg: "errors.missing-data" });
|
||||
if (!campaign) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
const hasAccess = await userOwnsCampaign(campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: "error", msg: "unauthorized" });
|
||||
if (!hasAccess) return res.json({ status: 'error', msg: 'unauthorized' });
|
||||
|
||||
const notes = await Note.find({ campaign })
|
||||
.select('_id title content date campaign')
|
||||
const folders = await Folder.find({ campaign })
|
||||
.select('_id name date')
|
||||
.sort({ date: -1 })
|
||||
.lean();
|
||||
|
||||
res.json({ status: "ok", notes });
|
||||
const rootNotes = await Note.find({ campaign, folder: null })
|
||||
.select('_id title content date')
|
||||
.sort({ date: -1 })
|
||||
.lean();
|
||||
|
||||
res.json({ status: 'ok', folders, notes: rootNotes });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: "error", msg: "errors.internal" });
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/subfolder/list', async (req, res) => {
|
||||
try {
|
||||
const { campaign, folder } = req.query;
|
||||
if (!campaign || !folder) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
const hasAccess = await userOwnsCampaign(campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: 'error', msg: 'unauthorized' });
|
||||
|
||||
// Verify folder belongs to campaign
|
||||
const folderDoc = await Folder.findOne({ _id: folder, campaign }).lean();
|
||||
if (!folderDoc) return res.json({ status: 'error', msg: 'errors.notfound' });
|
||||
|
||||
const subfolders = await Folder.find({ campaign, parentFolder: folder })
|
||||
.select('_id name date')
|
||||
.sort({ date: -1 })
|
||||
.lean();
|
||||
|
||||
const notes = await Note.find({ campaign, folder: folder })
|
||||
.select('_id title content date')
|
||||
.sort({ date: -1 })
|
||||
.lean();
|
||||
|
||||
res.json({ status: 'ok', subfolders, notes });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/create', async (req, res) => {
|
||||
try {
|
||||
const { title, content, campaign } = req.body;
|
||||
const hasAccess = await userOwnsCampaign(campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: "error", msg: "unauthorized" });
|
||||
const { title, content, campaign, folder } = req.body;
|
||||
if (!title || !campaign) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
const newNote = new Note({
|
||||
title,
|
||||
content,
|
||||
campaign
|
||||
});
|
||||
const hasAccess = await userOwnsCampaign(campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: 'error', msg: 'unauthorized' });
|
||||
|
||||
let effectiveFolder = null;
|
||||
if (folder) {
|
||||
const folderDoc = await Folder.findOne({ _id: folder, campaign }).lean();
|
||||
if (!folderDoc) return res.json({ status: 'error', msg: 'errors.notfound' });
|
||||
effectiveFolder = folder;
|
||||
}
|
||||
|
||||
const newNote = new Note({ title, content, campaign, folder: effectiveFolder });
|
||||
await newNote.save();
|
||||
res.json({ status: "ok", note: newNote });
|
||||
res.json({ status: 'ok', note: newNote });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: "error", msg: "errors.internal" });
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/update', async (req, res) => {
|
||||
try {
|
||||
const { id, title, content } = req.body;
|
||||
const note = await Note.findById(id);
|
||||
if (!note) return res.json({ status: "error", msg: "errors.notfound" });
|
||||
const hasAccess = await userOwnsCampaign(note.campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: "error", msg: "unauthorized" });
|
||||
const { id, title, content, folder } = req.body;
|
||||
if (!id) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
if(title) note.title = title;
|
||||
note.content = content;
|
||||
note.date = Date.now();
|
||||
const note = await Note.findById(id);
|
||||
if (!note) return res.json({ status: 'error', msg: 'errors.notfound' });
|
||||
|
||||
const hasAccess = await userOwnsCampaign(note.campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: 'error', msg: 'unauthorized' });
|
||||
|
||||
if (title !== undefined) note.title = title;
|
||||
if (content !== undefined) note.content = content;
|
||||
if (folder !== undefined) note.folder = folder;
|
||||
await note.save();
|
||||
res.json({ status: "ok", note });
|
||||
res.json({ status: 'ok', note });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: "error", msg: "errors.internal" });
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/delete', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.body;
|
||||
const note = await Note.findById(id);
|
||||
if (!note) return res.json({ status: "error", msg: "errors.notfound" });
|
||||
const hasAccess = await userOwnsCampaign(note.campaign, req.user.id);
|
||||
if (!hasAccess) return res.json({ status: "error", msg: "unauthorized" });
|
||||
if (!id) return res.json({ status: 'error', msg: 'errors.missing-data' });
|
||||
|
||||
await note.remove();
|
||||
res.json({ status: "ok" });
|
||||
const result = await Note.deleteOne({ _id: id });
|
||||
if (result.deletedCount === 0) return res.json({ status: 'error', msg: 'errors.notfound' });
|
||||
|
||||
res.json({ status: 'ok' });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.json({ status: "error", msg: "errors.internal" });
|
||||
res.json({ status: 'error', msg: 'errors.internal' });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user