
- Refonte complète du design avec système de panneaux latéraux rétractables - Ajout de templates de projets par domaine (recherche, informatique, mathématiques, etc.) - Implémentation système d'export PDF avec Puppeteer - Amélioration de l'API REST avec nouvelles routes d'export et templates - Ajout de JavaScript client pour interactions dynamiques - Configuration environnement étendue pour futures fonctionnalités IA - Amélioration responsive design et expérience utilisateur 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
214 lines
6.3 KiB
JavaScript
214 lines
6.3 KiB
JavaScript
const express = require('express');
|
||
const router = express.Router();
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const { v4: uuidv4 } = require('uuid');
|
||
|
||
// Importer le module d'export
|
||
const exportRouter = require('./export');
|
||
|
||
function modifMd(id, modifications) {
|
||
if (id === undefined) throw new Error('id obligatoire');
|
||
if (!Array.isArray(modifications) || modifications.length === 0) throw new Error('modifications requises');
|
||
|
||
const dataDir = path.resolve(__dirname, '../data');
|
||
const mapPath = path.join(dataDir, 'uuid_map.json');
|
||
if (!fs.existsSync(mapPath)) throw new Error('uuid_map.json inexistant');
|
||
|
||
const map = JSON.parse(fs.readFileSync(mapPath, 'utf8'));
|
||
const uuid = map[id];
|
||
if (!uuid) throw new Error(`Aucun fichier pour l'id ${id}`);
|
||
|
||
const mdPath = path.join(dataDir, `${uuid}.md`);
|
||
if (!fs.existsSync(mdPath)) throw new Error('Fichier markdown inexistant');
|
||
let lignes = fs.readFileSync(mdPath, 'utf8').split('\n');
|
||
|
||
modifications = modifications.slice().sort((a, b) => a.debut - b.debut);
|
||
|
||
let offset = 0;
|
||
for (let m of modifications) {
|
||
let debut = m.debut + offset;
|
||
let fin = m.fin + offset;
|
||
const remplacement = Array.isArray(m.contenu) ? m.contenu : m.contenu.split('\n');
|
||
if (debut < 0 || fin >= lignes.length || debut > fin)
|
||
throw new Error('Plage invalide (début/fin) pour une modification');
|
||
|
||
const avant = lignes.slice(0, debut);
|
||
const apres = lignes.slice(fin + 1);
|
||
lignes = [...avant, ...remplacement, ...apres];
|
||
offset += remplacement.length - (fin - debut + 1);
|
||
}
|
||
|
||
const nouveau = lignes.join('\n');
|
||
fs.writeFileSync(mdPath, nouveau, { encoding: 'utf8', flag: 'w' });
|
||
return { id, uuid, path: mdPath, modifications };
|
||
}
|
||
|
||
|
||
function createMd(markdownContent = "# Titre\nContenu...") {
|
||
const uuid = uuidv4();
|
||
|
||
const dataDir = path.resolve(__dirname, '../data');
|
||
const mdPath = path.join(dataDir, `${uuid}.md`);
|
||
const mapPath = path.join(dataDir, 'uuid_map.json');
|
||
|
||
fs.writeFileSync(mdPath, markdownContent, { encoding: 'utf8', flag: 'w' });
|
||
|
||
let map = {};
|
||
if (fs.existsSync(mapPath)) {
|
||
map = JSON.parse(fs.readFileSync(mapPath, 'utf8'));
|
||
}
|
||
let id = Object.keys(map).at(-1);
|
||
if (id == undefined){
|
||
map[0] = uuid;
|
||
} else {
|
||
id = +id+1
|
||
map[id] = uuid;
|
||
}
|
||
|
||
fs.writeFileSync(mapPath, JSON.stringify(map, null, 2), 'utf8');
|
||
|
||
return { id, uuid, path: mdPath, markdownContent};
|
||
}
|
||
|
||
function readMd(id = undefined) {
|
||
const dataDir = path.resolve(__dirname, '../data');
|
||
const mapPath = path.join(dataDir, 'uuid_map.json');
|
||
|
||
let map = {};
|
||
if (fs.existsSync(mapPath)) {
|
||
map = JSON.parse(fs.readFileSync(mapPath, 'utf8'));
|
||
}
|
||
|
||
if (id !== undefined) {
|
||
const uuid = map[id];
|
||
if (!uuid) {
|
||
throw new Error(`Aucun fichier trouvé pour l'id ${id}`);
|
||
}
|
||
const mdPath = path.join(dataDir, `${uuid}.md`);
|
||
if (!fs.existsSync(mdPath)) {
|
||
throw new Error(`Le fichier ${mdPath} n’existe pas`);
|
||
}
|
||
const markdownContent = fs.readFileSync(mdPath, 'utf8');
|
||
return [{ id, uuid, path: mdPath, markdownContent }];
|
||
} else {
|
||
const results = [];
|
||
for (const [curId, uuid] of Object.entries(map)) {
|
||
const mdPath = path.join(dataDir, `${uuid}.md`);
|
||
if (fs.existsSync(mdPath)) {
|
||
const markdownContent = fs.readFileSync(mdPath, 'utf8');
|
||
results.push({ id: curId, uuid, path: mdPath, markdownContent });
|
||
}
|
||
}
|
||
return results;
|
||
}
|
||
}
|
||
|
||
function updateMd(id, newMarkdownContent) {
|
||
if (id === undefined) throw new Error('id obligatoire');
|
||
const dataDir = path.resolve(__dirname, '../data');
|
||
const mapPath = path.join(dataDir, 'uuid_map.json');
|
||
|
||
if (!fs.existsSync(mapPath)) throw new Error('uuid_map.json inexistant');
|
||
let map = JSON.parse(fs.readFileSync(mapPath, 'utf8'));
|
||
const uuid = map[id];
|
||
if (!uuid) throw new Error(`Aucun fichier trouvé pour l'id ${id}`);
|
||
|
||
const mdPath = path.join(dataDir, `${uuid}.md`);
|
||
if (!fs.existsSync(mdPath)) throw new Error('Le fichier markdown n\'existe pas');
|
||
fs.writeFileSync(mdPath, newMarkdownContent, { encoding: 'utf8', flag: 'w' });
|
||
return { id, uuid, path: mdPath, newMarkdownContent };
|
||
}
|
||
|
||
function deteMd(id) {
|
||
if (id === undefined) throw new Error('id obligatoire');
|
||
const dataDir = path.resolve(__dirname, '../data');
|
||
const mapPath = path.join(dataDir, 'uuid_map.json');
|
||
|
||
if (!fs.existsSync(mapPath)) throw new Error('uuid_map.json inexistant');
|
||
let map = JSON.parse(fs.readFileSync(mapPath, 'utf8'));
|
||
const uuid = map[id];
|
||
if (!uuid) throw new Error(`Aucun fichier trouvé pour l'id ${id}`);
|
||
|
||
const mdPath = path.join(dataDir, `${uuid}.md`);
|
||
if (fs.existsSync(mdPath)) fs.unlinkSync(mdPath);
|
||
delete map[id];
|
||
|
||
fs.writeFileSync(mapPath, JSON.stringify(map, null, 2), 'utf8');
|
||
return { id, deleted: true };
|
||
}
|
||
|
||
// GET /api/journals - Récupérer tous les journaux
|
||
router.get('/journals', (req, res) => {
|
||
res.json({
|
||
success: true,
|
||
data: readMd()
|
||
});
|
||
});
|
||
|
||
// POST /api/journals - Créer un nouveau journal
|
||
router.post('/journals', (req, res) => {
|
||
const { content } = req.body;
|
||
|
||
res.status(201).json({
|
||
success: true,
|
||
data: createMd(content)
|
||
});
|
||
});
|
||
|
||
// GET /api/journals/:id - Récupérer un journal spécifique
|
||
router.get('/journals/:id', (req, res) => {
|
||
const { id } = req.params;
|
||
|
||
res.json({
|
||
success: true,
|
||
data: readMd(id)
|
||
});
|
||
});
|
||
|
||
// PUT /api/journals/:id - Mettre à jour un journal
|
||
router.put('/journals/:id', (req, res) => {
|
||
const { id } = req.params;
|
||
const { content, modifications } = req.body;
|
||
|
||
try {
|
||
let result;
|
||
if (content) {
|
||
// Mise à jour complète du contenu
|
||
result = updateMd(id, content);
|
||
} else if (modifications) {
|
||
// Modifications partielles (pour compatibilité future)
|
||
result = modifMd(id, modifications);
|
||
} else {
|
||
return res.status(400).json({
|
||
success: false,
|
||
error: 'Content ou modifications requis'
|
||
});
|
||
}
|
||
|
||
res.json({
|
||
success: true,
|
||
data: result
|
||
});
|
||
} catch (error) {
|
||
res.status(500).json({
|
||
success: false,
|
||
error: error.message
|
||
});
|
||
}
|
||
});
|
||
|
||
// DELETE /api/journals/:id - Supprimer un journal
|
||
router.delete('/journals/:id', (req, res) => {
|
||
const { id } = req.params;
|
||
|
||
res.json({
|
||
success: true,
|
||
data: deteMd(id)
|
||
});
|
||
});
|
||
|
||
// Intégrer les routes d'export
|
||
router.use('/export', exportRouter);
|
||
|
||
module.exports = router; |