- Create dedicated ProfanityFilter class with isolated SQLite database - Separate profanity.db from main application database to prevent SQLITE_MISUSE errors - Add comprehensive custom word management (CRUD operations) - Implement advanced profanity detection with leetspeak and pattern matching - Add admin UI for managing custom profanity words - Add extensive test suites for both profanity filter and API routes - Update server.js to use isolated profanity filter - Add proper database initialization and cleanup methods - Support in-memory databases for testing Breaking changes: - Profanity filter now uses separate database file - Updated admin API endpoints for profanity management - Enhanced profanity detection capabilities
108 lines
4.4 KiB
JavaScript
108 lines
4.4 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
|
|
module.exports = (db, profanityFilter) => {
|
|
// Get all active locations (within 48 hours OR persistent)
|
|
router.get('/', (req, res) => {
|
|
console.log('Fetching active locations');
|
|
const fortyEightHoursAgo = new Date(Date.now() - 48 * 60 * 60 * 1000).toISOString();
|
|
|
|
db.all(
|
|
'SELECT * FROM locations WHERE created_at > ? OR persistent = 1 ORDER BY created_at DESC',
|
|
[fortyEightHoursAgo],
|
|
(err, rows) => {
|
|
if (err) {
|
|
console.error('Error fetching locations:', err);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
return;
|
|
}
|
|
console.log(`Fetched ${rows.length} active locations (including persistent)`);
|
|
res.json(rows);
|
|
}
|
|
);
|
|
});
|
|
|
|
// Add a new location
|
|
router.post('/', (req, res) => {
|
|
const { address, latitude, longitude } = req.body;
|
|
let { description } = req.body;
|
|
console.log(`Attempt to add new location: ${address}`);
|
|
|
|
if (!address) {
|
|
console.warn('Failed to add location: Address is required');
|
|
res.status(400).json({ error: 'Address is required' });
|
|
return;
|
|
}
|
|
|
|
// Check for profanity in description and reject if any is found
|
|
if (description && profanityFilter) {
|
|
try {
|
|
const analysis = profanityFilter.analyzeProfanity(description);
|
|
if (analysis.hasProfanity) {
|
|
console.warn(`Submission rejected due to inappropriate language (${analysis.count} word${analysis.count > 1 ? 's' : ''}, severity: ${analysis.severity}) - Original: "${req.body.description}"`);
|
|
|
|
// Reject any submission with profanity
|
|
const wordText = analysis.count === 1 ? 'word' : 'words';
|
|
const detectedWords = analysis.matches.map(m => m.word).join(', ');
|
|
|
|
return res.status(400).json({
|
|
error: 'Submission rejected',
|
|
message: `Your description contains inappropriate language and cannot be posted. Please revise your description to focus on road conditions and keep it professional.\n\nExample: "Multiple vehicles stuck, black ice present" or "Road very slippery, saw 3 accidents"`,
|
|
details: {
|
|
severity: analysis.severity,
|
|
wordCount: analysis.count,
|
|
detectedCategories: [...new Set(analysis.matches.map(m => m.category))]
|
|
}
|
|
});
|
|
}
|
|
} catch (filterError) {
|
|
console.error('Error checking profanity:', filterError);
|
|
// Continue with original description if filter fails
|
|
}
|
|
}
|
|
|
|
db.run(
|
|
'INSERT INTO locations (address, latitude, longitude, description) VALUES (?, ?, ?, ?)',
|
|
[address, latitude, longitude, description],
|
|
function(err) {
|
|
if (err) {
|
|
console.error('Error inserting location:', err);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
return;
|
|
}
|
|
|
|
console.log(`Location added successfully: ${address}`);
|
|
res.json({
|
|
id: this.lastID,
|
|
address,
|
|
latitude,
|
|
longitude,
|
|
description,
|
|
created_at: new Date().toISOString()
|
|
});
|
|
}
|
|
);
|
|
});
|
|
|
|
// Legacy delete route (keeping for backwards compatibility)
|
|
router.delete('/:id', (req, res) => {
|
|
const { id } = req.params;
|
|
|
|
db.run('DELETE FROM locations WHERE id = ?', [id], function(err) {
|
|
if (err) {
|
|
console.error('Error deleting location:', err);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
return;
|
|
}
|
|
|
|
if (this.changes === 0) {
|
|
res.status(404).json({ error: 'Location not found' });
|
|
return;
|
|
}
|
|
|
|
res.json({ message: 'Location deleted successfully' });
|
|
});
|
|
});
|
|
|
|
return router;
|
|
};
|