9932621e14
- Add formatBoolean() usage to all boolean database queries - Fix 36 boolean comparisons across 18 backend files - Ensure compatibility between SQLite (0/1) and PostgreSQL (true/false) - Update all WHERE clauses and UPDATE operations with boolean values This completes the database compatibility fixes for production deployment. All boolean operations now work correctly with both database systems. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
185 lines
5.4 KiB
JavaScript
185 lines
5.4 KiB
JavaScript
const express = require('express');
|
|
const { body, validationResult } = require('express-validator');
|
|
const { db, logActivity } = require('../database/db');
|
|
const { formatBoolean } = require('../utils/dbCompat');
|
|
const { adminAuth } = require('../middleware/auth-enhanced-v2');
|
|
const router = express.Router();
|
|
|
|
// Get all global categories
|
|
router.get('/global', adminAuth, async (req, res) => {
|
|
try {
|
|
const categories = await db('photo_categories')
|
|
.where('is_global', formatBoolean(true))
|
|
.orderBy('name', 'asc');
|
|
|
|
res.json(categories);
|
|
} catch (error) {
|
|
console.error('Error fetching categories:', error);
|
|
res.status(500).json({ error: 'Failed to fetch categories' });
|
|
}
|
|
});
|
|
|
|
// Get categories for a specific event (global + event-specific)
|
|
router.get('/event/:eventId', adminAuth, async (req, res) => {
|
|
try {
|
|
const { eventId } = req.params;
|
|
|
|
const categories = await db('photo_categories')
|
|
.where(function() {
|
|
this.where('is_global', formatBoolean(true))
|
|
.orWhere('event_id', eventId);
|
|
})
|
|
.orderBy('is_global', 'desc')
|
|
.orderBy('name', 'asc');
|
|
|
|
res.json(categories);
|
|
} catch (error) {
|
|
console.error('Error fetching event categories:', error);
|
|
res.status(500).json({ error: 'Failed to fetch categories' });
|
|
}
|
|
});
|
|
|
|
// Create a new category
|
|
router.post('/', adminAuth, [
|
|
body('name').notEmpty().withMessage('Category name is required'),
|
|
body('slug').optional(),
|
|
body('is_global').optional().isBoolean(),
|
|
body('event_id').optional().isInt()
|
|
], async (req, res) => {
|
|
try {
|
|
const errors = validationResult(req);
|
|
if (!errors.isEmpty()) {
|
|
return res.status(400).json({ errors: errors.array() });
|
|
}
|
|
|
|
const { name, slug, is_global = true, event_id = null } = req.body;
|
|
|
|
// Generate slug if not provided
|
|
const categorySlug = slug || name.toLowerCase()
|
|
.replace(/[^\w\s-]/g, '')
|
|
.replace(/\s+/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.trim();
|
|
|
|
// Check if slug already exists for this scope
|
|
const existing = await db('photo_categories')
|
|
.where('slug', categorySlug)
|
|
.where(function() {
|
|
if (is_global) {
|
|
this.where('is_global', formatBoolean(true));
|
|
} else {
|
|
this.where('event_id', event_id);
|
|
}
|
|
})
|
|
.first();
|
|
|
|
if (existing) {
|
|
return res.status(400).json({ error: 'Category with this slug already exists' });
|
|
}
|
|
|
|
// Create category
|
|
const insertResult = await db('photo_categories').insert({
|
|
name,
|
|
slug: categorySlug,
|
|
is_global,
|
|
event_id: is_global ? null : event_id
|
|
}).returning('id');
|
|
|
|
const categoryId = insertResult[0]?.id || insertResult[0];
|
|
|
|
const category = await db('photo_categories').where('id', categoryId).first();
|
|
|
|
// Log activity
|
|
await logActivity('category_created',
|
|
{ categoryName: name, isGlobal: is_global },
|
|
event_id,
|
|
{ type: 'admin', id: req.admin.id, name: req.admin.username }
|
|
);
|
|
|
|
res.json(category);
|
|
} catch (error) {
|
|
console.error('Error creating category:', error);
|
|
res.status(500).json({ error: 'Failed to create category' });
|
|
}
|
|
});
|
|
|
|
// Update a category
|
|
router.put('/:id', adminAuth, [
|
|
body('name').notEmpty().withMessage('Category name is required')
|
|
], async (req, res) => {
|
|
try {
|
|
const errors = validationResult(req);
|
|
if (!errors.isEmpty()) {
|
|
return res.status(400).json({ errors: errors.array() });
|
|
}
|
|
|
|
const { id } = req.params;
|
|
const { name } = req.body;
|
|
|
|
const category = await db('photo_categories').where('id', id).first();
|
|
if (!category) {
|
|
return res.status(404).json({ error: 'Category not found' });
|
|
}
|
|
|
|
await db('photo_categories')
|
|
.where('id', id)
|
|
.update({
|
|
name,
|
|
slug: name.toLowerCase()
|
|
.replace(/[^\w\s-]/g, '')
|
|
.replace(/\s+/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.trim()
|
|
});
|
|
|
|
const updated = await db('photo_categories').where('id', id).first();
|
|
|
|
// Log activity
|
|
await logActivity('category_updated',
|
|
{ categoryName: name },
|
|
category.event_id,
|
|
{ type: 'admin', id: req.admin.id, name: req.admin.username }
|
|
);
|
|
|
|
res.json(updated);
|
|
} catch (error) {
|
|
console.error('Error updating category:', error);
|
|
res.status(500).json({ error: 'Failed to update category' });
|
|
}
|
|
});
|
|
|
|
// Delete a category
|
|
router.delete('/:id', adminAuth, async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
const category = await db('photo_categories').where('id', id).first();
|
|
if (!category) {
|
|
return res.status(404).json({ error: 'Category not found' });
|
|
}
|
|
|
|
// Check if category has photos
|
|
const photoCount = await db('photos').where('category_id', id).count('id as count').first();
|
|
if (photoCount.count > 0) {
|
|
return res.status(400).json({
|
|
error: 'Cannot delete category with photos. Please reassign photos first.'
|
|
});
|
|
}
|
|
|
|
await db('photo_categories').where('id', id).delete();
|
|
|
|
// Log activity
|
|
await logActivity('category_deleted',
|
|
{ categoryName: category.name },
|
|
category.event_id,
|
|
{ type: 'admin', id: req.admin.id, name: req.admin.username }
|
|
);
|
|
|
|
res.json({ message: 'Category deleted successfully' });
|
|
} catch (error) {
|
|
console.error('Error deleting category:', error);
|
|
res.status(500).json({ error: 'Failed to delete category' });
|
|
}
|
|
});
|
|
|
|
module.exports = router; |