Début du projet
This commit is contained in:
commit
e7d4e607f6
23 files changed
+4855
No files matched your search
@@ -0,0 +1,170 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { db } = require('../db');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
function requireAuth(req, res, next) {
|
||||
if (req.session && req.session.authenticated) {
|
||||
return next();
|
||||
}
|
||||
res.redirect('/admin/login');
|
||||
}
|
||||
|
||||
router.get('/login', (req, res) => {
|
||||
if (req.session && req.session.authenticated) {
|
||||
return res.redirect('/admin');
|
||||
}
|
||||
res.render('admin/login', { error: null });
|
||||
});
|
||||
|
||||
router.post('/login', (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
const adminUser = process.env.ADMIN_USERNAME || 'admin';
|
||||
const adminPass = process.env.ADMIN_PASSWORD || 'changeme123';
|
||||
|
||||
if (username === adminUser && password === adminPass) {
|
||||
console.log("[DEBUG] Connexion OK")
|
||||
req.session.authenticated = true;
|
||||
req.session.username = username;
|
||||
return req.session.save((err) => {
|
||||
if (err) {
|
||||
console.error('Session save error:', err);
|
||||
}
|
||||
return res.redirect('/admin');
|
||||
});
|
||||
}
|
||||
|
||||
res.render('admin/login', { error: 'Identifiants incorrects' });
|
||||
});
|
||||
|
||||
router.get('/logout', (req, res) => {
|
||||
req.session.destroy(() => {
|
||||
res.redirect('/admin/login');
|
||||
});
|
||||
});
|
||||
|
||||
router.use(requireAuth);
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
const status = req.query.status || 'all';
|
||||
const language = req.query.language || 'all';
|
||||
|
||||
// Filtre langue identique au site public (repli sur la langue de la source)
|
||||
const languageExpr = `COALESCE(language, source_language, 'fr')`;
|
||||
|
||||
const conditions = [];
|
||||
const params = [];
|
||||
|
||||
if (status !== 'all') {
|
||||
conditions.push(`status = ?`);
|
||||
params.push(status);
|
||||
}
|
||||
|
||||
if (language !== 'all') {
|
||||
conditions.push(`${languageExpr} = ?`);
|
||||
params.push(language);
|
||||
}
|
||||
|
||||
const where = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
|
||||
const articles = db
|
||||
.prepare(`SELECT * FROM articles${where} ORDER BY datetime(created_at) DESC`)
|
||||
.all(...params);
|
||||
|
||||
// Stats (filtrées sur la langue sélectionnée)
|
||||
const stats = {};
|
||||
['pending', 'published', 'hidden', 'rejected'].forEach(s => {
|
||||
const statParams = [s];
|
||||
let statQuery = `SELECT COUNT(*) as c FROM articles WHERE status = ?`;
|
||||
if (language !== 'all') {
|
||||
statQuery += ` AND ${languageExpr} = ?`;
|
||||
statParams.push(language);
|
||||
}
|
||||
stats[s] = db.prepare(statQuery).get(...statParams).c;
|
||||
});
|
||||
|
||||
let totalQuery = `SELECT COUNT(*) as c FROM articles`;
|
||||
const totalParams = [];
|
||||
if (language !== 'all') {
|
||||
totalQuery += ` WHERE ${languageExpr} = ?`;
|
||||
totalParams.push(language);
|
||||
}
|
||||
stats.total = db.prepare(totalQuery).get(...totalParams).c;
|
||||
|
||||
// Langues disponibles dans l'ensemble des articles
|
||||
const languages = db
|
||||
.prepare(`SELECT ${languageExpr} as lang, COUNT(*) as c FROM articles GROUP BY lang ORDER BY c DESC, lang`)
|
||||
.all();
|
||||
|
||||
res.render('admin/dashboard', { articles, status, stats, languages, language });
|
||||
});
|
||||
|
||||
router.post('/article/:id/validate', (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { categories, summary } = req.body;
|
||||
|
||||
try {
|
||||
const categoriesJson = categories ? JSON.stringify(categories.split(',').map(c => c.trim()).filter(Boolean)) : null;
|
||||
|
||||
db.prepare(`UPDATE articles SET status='published', categories=COALESCE(?, categories), summary=COALESCE(?, summary), updated_at=datetime('now') WHERE id=?`)
|
||||
.run(categoriesJson, summary || null, id);
|
||||
|
||||
db.prepare(`INSERT INTO activity_log (action, article_id, details) VALUES ('validate', ?, 'Article publié')`).run(id);
|
||||
|
||||
res.redirect(req.get('referer') || '/admin');
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
res.redirect('/admin');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/article/:id/hide', (req, res) => {
|
||||
const { id } = req.params;
|
||||
db.prepare(`UPDATE articles SET status='hidden', updated_at=datetime('now') WHERE id=?`).run(id);
|
||||
db.prepare(`INSERT INTO activity_log (action, article_id, details) VALUES ('hide', ?, 'Article masqué')`).run(id);
|
||||
res.redirect(req.get('referer') || '/admin');
|
||||
});
|
||||
|
||||
router.post('/article/:id/reject', (req, res) => {
|
||||
const { id } = req.params;
|
||||
db.prepare(`UPDATE articles SET status='rejected', updated_at=datetime('now') WHERE id=?`).run(id);
|
||||
db.prepare(`INSERT INTO activity_log (action, article_id, details) VALUES ('reject', ?, 'Article rejeté')`).run(id);
|
||||
res.redirect(req.get('referer') || '/admin');
|
||||
});
|
||||
|
||||
router.post('/article/:id/publish', (req, res) => {
|
||||
const { id } = req.params;
|
||||
db.prepare(`UPDATE articles SET status='published', updated_at=datetime('now') WHERE id=?`).run(id);
|
||||
db.prepare(`INSERT INTO activity_log (action, article_id, details) VALUES ('publish', ?, 'Article republié')`).run(id);
|
||||
res.redirect(req.get('referer') || '/admin');
|
||||
});
|
||||
|
||||
router.post('/article/:id/delete', (req, res) => {
|
||||
const { id } = req.params;
|
||||
db.prepare(`DELETE FROM articles WHERE id=?`).run(id);
|
||||
db.prepare(`INSERT INTO activity_log (action, article_id, details) VALUES ('delete', ?, 'Article supprimé')`).run(id);
|
||||
res.redirect(req.get('referer') || '/admin');
|
||||
});
|
||||
|
||||
router.post('/collect', (req, res) => {
|
||||
const { collect } = require('../../collector/index');
|
||||
collect().then(() => {
|
||||
db.prepare(`INSERT INTO activity_log (action, details) VALUES ('collect', 'Collecte manuelle déclenchée')`).run();
|
||||
res.redirect('/admin?status=pending');
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
res.redirect('/admin');
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/sources', (req, res) => {
|
||||
const sourcesPath = require('path').join(__dirname, '..', '..', 'config', 'sources.json');
|
||||
const sources = JSON.parse(require('fs').readFileSync(sourcesPath, 'utf8'));
|
||||
res.render('admin/sources', { sources });
|
||||
});
|
||||
|
||||
router.get('/log', (req, res) => {
|
||||
const logs = db.prepare(`SELECT * FROM activity_log ORDER BY datetime(created_at) DESC LIMIT 100`).all();
|
||||
res.render('admin/log', { logs });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||