Files
picpeak/backend/src/routes/adminCategories.js
T
paul 9932621e14 fix: comprehensive boolean compatibility for PostgreSQL and SQLite
- 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>
2025-07-14 21:05:18 +02:00

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;