mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-16 19:58:31 +02:00
204 lines
5.9 KiB
JavaScript
204 lines
5.9 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const multer = require('multer');
|
|
const path = require('path');
|
|
const { v4: uuidv4 } = require('uuid');
|
|
const { body, validationResult } = require('express-validator');
|
|
const { db, logger } = require('../config/database');
|
|
const { authMiddleware } = require('../middleware/auth');
|
|
|
|
// Configure multer for image uploads
|
|
const storage = multer.diskStorage({
|
|
destination: 'public/uploads/',
|
|
filename: (req, file, cb) => {
|
|
const uniqueName = `${uuidv4()}${path.extname(file.originalname)}`;
|
|
cb(null, uniqueName);
|
|
}
|
|
});
|
|
|
|
const upload = multer({
|
|
storage,
|
|
limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
|
|
fileFilter: (req, file, cb) => {
|
|
const allowedTypes = /jpeg|jpg|png|gif/;
|
|
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
|
|
const mimetype = allowedTypes.test(file.mimetype);
|
|
if (extname && mimetype) {
|
|
cb(null, true);
|
|
} else {
|
|
cb(new Error('Only image files are allowed'));
|
|
}
|
|
}
|
|
});
|
|
|
|
// Note validation
|
|
const noteValidation = [
|
|
body('title').trim().notEmpty().escape(),
|
|
body('content').trim().optional().escape(),
|
|
body('archived').isBoolean().optional()
|
|
];
|
|
|
|
// Get all notes for user
|
|
router.get('/', authMiddleware, (req, res) => {
|
|
const query = `
|
|
SELECT n.*,
|
|
GROUP_CONCAT(t.id || ':' || t.text || ':' || t.completed) as todos,
|
|
GROUP_CONCAT(i.id || ':' || i.filename) as images
|
|
FROM notes n
|
|
LEFT JOIN todos t ON n.id = t.note_id
|
|
LEFT JOIN images i ON n.id = i.note_id
|
|
WHERE n.user_id = ?
|
|
GROUP BY n.id
|
|
ORDER BY n.created_at DESC
|
|
`;
|
|
|
|
db.all(query, [req.user.id], (err, notes) => {
|
|
if (err) {
|
|
logger.error('Error fetching notes:', err);
|
|
return res.status(500).json({ message: 'Server error' });
|
|
}
|
|
|
|
// Process the results to format todos and images
|
|
const processedNotes = notes.map(note => ({
|
|
...note,
|
|
todos: note.todos ? note.todos.split(',').map(todo => {
|
|
const [id, text, completed] = todo.split(':');
|
|
return { id, text, completed: completed === '1' };
|
|
}) : [],
|
|
images: note.images ? note.images.split(',').map(image => {
|
|
const [id, filename] = image.split(':');
|
|
return { id, filename };
|
|
}) : []
|
|
}));
|
|
|
|
res.json(processedNotes);
|
|
});
|
|
});
|
|
|
|
// Create note
|
|
router.post('/', authMiddleware, noteValidation, (req, res) => {
|
|
const errors = validationResult(req);
|
|
if (!errors.isEmpty()) {
|
|
return res.status(400).json({ errors: errors.array() });
|
|
}
|
|
|
|
const { title, content, todos = [] } = req.body;
|
|
|
|
db.run(
|
|
'INSERT INTO notes (user_id, title, content) VALUES (?, ?, ?)',
|
|
[req.user.id, title, content],
|
|
function(err) {
|
|
if (err) {
|
|
logger.error('Error creating note:', err);
|
|
return res.status(500).json({ message: 'Server error' });
|
|
}
|
|
|
|
const noteId = this.lastID;
|
|
|
|
// Insert todos if any
|
|
if (todos.length > 0) {
|
|
const todoValues = todos.map((todo, index) =>
|
|
`(${noteId}, '${todo.text}', ${todo.completed ? 1 : 0}, ${index})`
|
|
).join(',');
|
|
|
|
db.run(`INSERT INTO todos (note_id, text, completed, position) VALUES ${todoValues}`);
|
|
}
|
|
|
|
res.status(201).json({ id: noteId, title, content, todos: [] });
|
|
}
|
|
);
|
|
});
|
|
|
|
// Update note
|
|
router.put('/:id', authMiddleware, noteValidation, (req, res) => {
|
|
const noteId = req.params.id;
|
|
const { title, content, archived, todos = [] } = req.body;
|
|
|
|
db.run(
|
|
'UPDATE notes SET title = ?, content = ?, archived = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND user_id = ?',
|
|
[title, content, archived ? 1 : 0, noteId, req.user.id],
|
|
function(err) {
|
|
if (err) {
|
|
logger.error('Error updating note:', err);
|
|
return res.status(500).json({ message: 'Server error' });
|
|
}
|
|
|
|
// Update todos
|
|
db.run('DELETE FROM todos WHERE note_id = ?', [noteId], (err) => {
|
|
if (err) {
|
|
logger.error('Error deleting todos:', err);
|
|
return;
|
|
}
|
|
|
|
if (todos.length > 0) {
|
|
const todoValues = todos.map((todo, index) =>
|
|
`(${noteId}, '${todo.text}', ${todo.completed ? 1 : 0}, ${index})`
|
|
).join(',');
|
|
|
|
db.run(`INSERT INTO todos (note_id, text, completed, position) VALUES ${todoValues}`);
|
|
}
|
|
});
|
|
|
|
res.json({ message: 'Note updated successfully' });
|
|
}
|
|
);
|
|
});
|
|
|
|
// Delete note
|
|
router.delete('/:id', authMiddleware, (req, res) => {
|
|
const noteId = req.params.id;
|
|
|
|
db.run('DELETE FROM notes WHERE id = ? AND user_id = ?', [noteId, req.user.id], (err) => {
|
|
if (err) {
|
|
logger.error('Error deleting note:', err);
|
|
return res.status(500).json({ message: 'Server error' });
|
|
}
|
|
|
|
// Cleanup related records
|
|
db.run('DELETE FROM todos WHERE note_id = ?', [noteId]);
|
|
db.run('DELETE FROM images WHERE note_id = ?', [noteId]);
|
|
|
|
res.json({ message: 'Note deleted successfully' });
|
|
});
|
|
});
|
|
|
|
// Upload image
|
|
router.post('/:id/images', authMiddleware, upload.single('image'), (req, res) => {
|
|
if (!req.file) {
|
|
return res.status(400).json({ message: 'No image file provided' });
|
|
}
|
|
|
|
const noteId = req.params.id;
|
|
const filename = req.file.filename;
|
|
|
|
db.run(
|
|
'INSERT INTO images (note_id, filename) VALUES (?, ?)',
|
|
[noteId, filename],
|
|
function(err) {
|
|
if (err) {
|
|
logger.error('Error saving image record:', err);
|
|
return res.status(500).json({ message: 'Server error' });
|
|
}
|
|
res.status(201).json({ id: this.lastID, filename });
|
|
}
|
|
);
|
|
});
|
|
|
|
// Delete image
|
|
router.delete('/:noteId/images/:imageId', authMiddleware, (req, res) => {
|
|
const { noteId, imageId } = req.params;
|
|
|
|
db.run(
|
|
'DELETE FROM images WHERE id = ? AND note_id = ?',
|
|
[imageId, noteId],
|
|
(err) => {
|
|
if (err) {
|
|
logger.error('Error deleting image:', err);
|
|
return res.status(500).json({ message: 'Server error' });
|
|
}
|
|
res.json({ message: 'Image deleted successfully' });
|
|
}
|
|
);
|
|
});
|
|
|
|
module.exports = router; |