mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 06:11:45 +00:00
Initial commit — NOMAD (Navigation Organizer for Maps, Activities & Destinations)
Self-hosted travel planner with Express.js, SQLite, React & Tailwind CSS.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
const express = require('express');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const { db } = require('../db/database');
|
||||
const { authenticate, adminOnly } = require('../middleware/auth');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// All admin routes require authentication and admin role
|
||||
router.use(authenticate, adminOnly);
|
||||
|
||||
// GET /api/admin/users
|
||||
router.get('/users', (req, res) => {
|
||||
const users = db.prepare(
|
||||
'SELECT id, username, email, role, maps_api_key, unsplash_api_key, openweather_api_key, created_at, updated_at FROM users ORDER BY created_at DESC'
|
||||
).all();
|
||||
res.json({ users });
|
||||
});
|
||||
|
||||
// PUT /api/admin/users/:id
|
||||
router.put('/users/:id', (req, res) => {
|
||||
const { username, email, role, password } = req.body;
|
||||
const user = db.prepare('SELECT * FROM users WHERE id = ?').get(req.params.id);
|
||||
|
||||
if (!user) return res.status(404).json({ error: 'Benutzer nicht gefunden' });
|
||||
|
||||
if (role && !['user', 'admin'].includes(role)) {
|
||||
return res.status(400).json({ error: 'Ungültige Rolle' });
|
||||
}
|
||||
|
||||
if (username && username !== user.username) {
|
||||
const conflict = db.prepare('SELECT id FROM users WHERE username = ? AND id != ?').get(username, req.params.id);
|
||||
if (conflict) return res.status(409).json({ error: 'Benutzername bereits vergeben' });
|
||||
}
|
||||
if (email && email !== user.email) {
|
||||
const conflict = db.prepare('SELECT id FROM users WHERE email = ? AND id != ?').get(email, req.params.id);
|
||||
if (conflict) return res.status(409).json({ error: 'E-Mail bereits vergeben' });
|
||||
}
|
||||
|
||||
const passwordHash = password ? bcrypt.hashSync(password, 10) : null;
|
||||
|
||||
db.prepare(`
|
||||
UPDATE users SET
|
||||
username = COALESCE(?, username),
|
||||
email = COALESCE(?, email),
|
||||
role = COALESCE(?, role),
|
||||
password_hash = COALESCE(?, password_hash),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?
|
||||
`).run(username || null, email || null, role || null, passwordHash, req.params.id);
|
||||
|
||||
const updated = db.prepare(
|
||||
'SELECT id, username, email, role, created_at, updated_at FROM users WHERE id = ?'
|
||||
).get(req.params.id);
|
||||
|
||||
res.json({ user: updated });
|
||||
});
|
||||
|
||||
// DELETE /api/admin/users/:id
|
||||
router.delete('/users/:id', (req, res) => {
|
||||
if (parseInt(req.params.id) === req.user.id) {
|
||||
return res.status(400).json({ error: 'Eigenes Konto kann nicht gelöscht werden' });
|
||||
}
|
||||
|
||||
const user = db.prepare('SELECT id FROM users WHERE id = ?').get(req.params.id);
|
||||
if (!user) return res.status(404).json({ error: 'Benutzer nicht gefunden' });
|
||||
|
||||
db.prepare('DELETE FROM users WHERE id = ?').run(req.params.id);
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
// GET /api/admin/stats
|
||||
router.get('/stats', (req, res) => {
|
||||
const totalUsers = db.prepare('SELECT COUNT(*) as count FROM users').get().count;
|
||||
const totalTrips = db.prepare('SELECT COUNT(*) as count FROM trips').get().count;
|
||||
const totalPlaces = db.prepare('SELECT COUNT(*) as count FROM places').get().count;
|
||||
const totalPhotos = db.prepare('SELECT COUNT(*) as count FROM photos').get().count;
|
||||
const totalFiles = db.prepare('SELECT COUNT(*) as count FROM trip_files').get().count;
|
||||
|
||||
res.json({ totalUsers, totalTrips, totalPlaces, totalPhotos, totalFiles });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user