Backend: Ajout système d'archivage et todos dans cartes

- Migration auto colonne archived (BOOLEAN DEFAULT 0)
- Route GET /api/notes?archived=true/false pour filtrer
- Route PUT /api/notes/:id/archive pour archiver/désarchiver
- Chargement des todos avec chaque note (todos[], todos_count, todos_completed)
- Support filtrage par statut archivé
- Logs archivage/désarchivage
This commit is contained in:
Claude committed 2025-11-11 13:56:10 +00:00
1 parent 95f4d3b50b
commit 40caa7cb35
2 files changed
+60 -6

No files matched your search

+13 -1
View File
@@ -81,7 +81,7 @@ function initDatabase() {
logger.info('✓ Tables de base de données créées avec succès');
// Migration: Ajouter image_filename si elle n'existe pas
// Migrations automatiques
db.all("PRAGMA table_info(notes)", (err, columns) => {
if (err) {
logger.error('Erreur lors de la vérification de la structure de la table notes:', err);
@@ -89,6 +89,7 @@ function initDatabase() {
}
const hasImageFilename = columns.some(col => col.name === 'image_filename');
const hasArchived = columns.some(col => col.name === 'archived');
if (!hasImageFilename) {
logger.info('Migration: Ajout de la colonne image_filename...');
@@ -100,6 +101,17 @@ function initDatabase() {
}
});
}
if (!hasArchived) {
logger.info('Migration: Ajout de la colonne archived...');
db.run('ALTER TABLE notes ADD COLUMN archived BOOLEAN DEFAULT 0', (err) => {
if (err) {
logger.error('Erreur lors de l\'ajout de la colonne archived:', err);
} else {
logger.info('✓ Colonne archived ajoutée avec succès');
}
});
}
});
// Créer l'utilisateur admin par défaut si la table est vide
+47 -5
View File
@@ -39,20 +39,35 @@ const upload = multer({
router.use(authenticateToken);
/**
* GET /api/notes
* GET /api/notes?archived=true/false
* Liste toutes les notes de l'utilisateur
*/
router.get('/', async (req, res) => {
try {
const showArchived = req.query.archived === 'true';
const archivedFilter = showArchived ? 1 : 0;
const notes = await getAll(`
SELECT
n.id, n.title, n.content, n.image_filename,
n.id, n.title, n.content, n.image_filename, n.archived,
n.created_at, n.updated_at,
(SELECT COUNT(*) FROM note_todos WHERE note_id = n.id) as todos_count
(SELECT COUNT(*) FROM note_todos WHERE note_id = n.id) as todos_count,
(SELECT COUNT(*) FROM note_todos WHERE note_id = n.id AND completed = 1) as todos_completed
FROM notes n
WHERE n.user_id = ?
WHERE n.user_id = ? AND n.archived = ?
ORDER BY n.updated_at DESC
`, [req.user.id]);
`, [req.user.id, archivedFilter]);
// Charger les todos pour chaque note
for (const note of notes) {
const todos = await getAll(`
SELECT id, text, completed, position
FROM note_todos
WHERE note_id = ?
ORDER BY position ASC, id ASC
`, [note.id]);
note.todos = todos || [];
}
res.json(notes || []);
} catch (error) {
@@ -179,6 +194,33 @@ router.put('/:id',
}
);
/**
* PUT /api/notes/:id/archive
* Archiver ou désarchiver une note
*/
router.put('/:id/archive', async (req, res) => {
try {
const { archived } = req.body;
// Vérifier que la note appartient à l'utilisateur
const note = await getOne('SELECT id FROM notes WHERE id = ? AND user_id = ?', [req.params.id, req.user.id]);
if (!note) {
return res.status(404).json({ error: 'Note non trouvée' });
}
await runQuery(
'UPDATE notes SET archived = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
[archived ? 1 : 0, req.params.id]
);
logger.info(`Note ${archived ? 'archivée' : 'désarchivée'}: ${req.params.id}`);
res.json({ message: `Note ${archived ? 'archivée' : 'désarchivée'} avec succès`, archived });
} catch (error) {
logger.error('Erreur lors de l\'archivage de la note:', error);
res.status(500).json({ error: 'Erreur serveur' });
}
});
/**
* DELETE /api/notes/:id
* Supprimer une note