Fix general settings route and req.user references

- Update frontend settings service to use correct /api/admin/settings/general route
- Fix all req.user to req.admin references in adminSettings.js
- Ensures settings can be saved without authentication errors
This commit is contained in:
2025-07-07 15:32:42 +02:00
parent f0768cd31b
commit 971397c338
20 changed files with 716 additions and 127 deletions
+217
View File
@@ -0,0 +1,217 @@
const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs').promises;
const { db, logActivity } = require('../database/db');
const { adminAuth } = require('../middleware/auth');
const { generateThumbnail } = require('../services/imageProcessor');
const router = express.Router();
// Get storage path from environment or default
const getStoragePath = () => process.env.STORAGE_PATH || path.join(__dirname, '../../../storage');
// Configure multer for file uploads
const storage = multer.diskStorage({
destination: async (req, file, cb) => {
const { eventId } = req.params;
const { type = 'individual' } = req.body;
try {
// Get event details
const event = await db('events').where({ id: eventId }).first();
if (!event) {
return cb(new Error('Event not found'));
}
// Create destination path
const photoType = type === 'collage' ? 'collages' : 'individual';
const destPath = path.join(getStoragePath(), 'events/active', event.slug, photoType);
// Ensure directory exists
await fs.mkdir(destPath, { recursive: true });
cb(null, destPath);
} catch (error) {
cb(error);
}
},
filename: (req, file, cb) => {
// Generate unique filename
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
const ext = path.extname(file.originalname);
const name = path.basename(file.originalname, ext);
cb(null, `${name}-${uniqueSuffix}${ext}`);
}
});
const upload = multer({
storage: storage,
limits: {
fileSize: 50 * 1024 * 1024, // 50MB limit
},
fileFilter: (req, file, cb) => {
// Accept images only
const allowedTypes = /jpeg|jpg|png|webp/;
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = allowedTypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb(new Error('Only JPEG, PNG and WebP images are allowed'));
}
}
});
// Upload photos for an event
router.post('/:eventId/upload', adminAuth, upload.array('photos', 20), async (req, res) => {
try {
const { eventId } = req.params;
const { type = 'individual' } = req.body;
// Verify event exists and admin has access
const event = await db('events').where({ id: eventId }).first();
if (!event) {
return res.status(404).json({ error: 'Event not found' });
}
if (!req.files || req.files.length === 0) {
return res.status(400).json({ error: 'No files uploaded' });
}
const uploadedPhotos = [];
// Process each uploaded file
for (const file of req.files) {
try {
// Generate thumbnail
const thumbnailPath = await generateThumbnail(file.path);
// Calculate relative paths
const storagePath = getStoragePath();
const relativePath = path.relative(path.join(storagePath, 'events/active'), file.path);
const relativeThumbPath = thumbnailPath ? path.relative(path.join(storagePath, 'events/active'), thumbnailPath) : null;
// Add to database
const [photoId] = await db('photos').insert({
event_id: eventId,
filename: file.filename,
path: relativePath,
thumbnail_path: relativeThumbPath,
type: type === 'collage' ? 'collage' : 'individual',
size_bytes: file.size
});
uploadedPhotos.push({
id: photoId,
filename: file.filename,
size: file.size,
type
});
} catch (error) {
console.error(`Error processing file ${file.filename}:`, error);
// Continue with other files
}
}
// Log activity
await logActivity('photos_uploaded',
{ count: uploadedPhotos.length, eventName: event.event_name },
eventId,
{ type: 'admin', id: req.admin.id, name: req.admin.username }
);
res.json({
message: `Successfully uploaded ${uploadedPhotos.length} photos`,
photos: uploadedPhotos
});
} catch (error) {
console.error('Error uploading photos:', error);
res.status(500).json({ error: 'Failed to upload photos' });
}
});
// Delete a photo
router.delete('/:eventId/photos/:photoId', adminAuth, async (req, res) => {
try {
const { eventId, photoId } = req.params;
// Get photo details
const photo = await db('photos')
.where({ id: photoId, event_id: eventId })
.first();
if (!photo) {
return res.status(404).json({ error: 'Photo not found' });
}
// Delete physical files
const storagePath = getStoragePath();
const photoPath = path.join(storagePath, 'events/active', photo.path);
try {
await fs.unlink(photoPath);
} catch (error) {
console.error('Error deleting photo file:', error);
}
// Delete thumbnail if exists
if (photo.thumbnail_path) {
const thumbPath = path.join(storagePath, 'events/active', photo.thumbnail_path);
try {
await fs.unlink(thumbPath);
} catch (error) {
console.error('Error deleting thumbnail:', error);
}
}
// Remove from database
await db('photos').where({ id: photoId }).delete();
// Log activity
const event = await db('events').where({ id: eventId }).first();
await logActivity('photo_deleted',
{ filename: photo.filename, eventName: event.event_name },
eventId,
{ type: 'admin', id: req.admin.id, name: req.admin.username }
);
res.json({ message: 'Photo deleted successfully' });
} catch (error) {
console.error('Error deleting photo:', error);
res.status(500).json({ error: 'Failed to delete photo' });
}
});
// Get all photos for an event
router.get('/:eventId/photos', adminAuth, async (req, res) => {
try {
const { eventId } = req.params;
const { type } = req.query;
let query = db('photos').where({ event_id: eventId });
if (type) {
query = query.where({ type });
}
const photos = await query.orderBy('uploaded_at', 'desc');
res.json({
photos: photos.map(photo => ({
id: photo.id,
filename: photo.filename,
url: `/photos/${photo.path}`,
thumbnail_url: photo.thumbnail_path ? `/photos/${photo.thumbnail_path}` : null,
type: photo.type,
size: photo.size_bytes,
uploaded_at: photo.uploaded_at
}))
});
} catch (error) {
console.error('Error fetching photos:', error);
res.status(500).json({ error: 'Failed to fetch photos' });
}
});
module.exports = router;