Privacy settings #60
@@ -955,6 +955,93 @@ const requireAdmin = (req, res, next) => {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
};
|
||||
|
||||
// Middleware to check if user has granted a specific consent category
|
||||
const requireConsent = (category) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
const userId = req.session?.userId;
|
||||
const sessionId = req.sessionID;
|
||||
let consent;
|
||||
if (userId) {
|
||||
consent = await userDbGet('SELECT granted FROM user_consents WHERE user_id = ? AND category = ?', [userId, category]);
|
||||
} else if (sessionId) {
|
||||
consent = await userDbGet('SELECT granted FROM user_consents WHERE session_id = ? AND category = ?', [sessionId, category]);
|
||||
}
|
||||
if (consent && consent.granted) return next();
|
||||
return res.status(403).json({ error: `Consent required: ${category}` });
|
||||
} catch (error) {
|
||||
console.error('Consent check error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// ========== CONSENT MANAGEMENT ==========
|
||||
app.get('/api/consents', async (req, res) => {
|
||||
try {
|
||||
const userId = req.session?.userId;
|
||||
const sessionId = req.sessionID;
|
||||
const categories = ['essential', 'analytics', 'preferences', 'health_data'];
|
||||
const result = {};
|
||||
categories.forEach(c => { result[c] = c === 'essential'; });
|
||||
if (userId) {
|
||||
const rows = await userDbAll('SELECT category, granted FROM user_consents WHERE user_id = ?', [userId]);
|
||||
rows.forEach(r => { result[r.category] = r.granted; });
|
||||
} else if (sessionId) {
|
||||
const rows = await userDbAll('SELECT category, granted FROM user_consents WHERE session_id = ?', [sessionId]);
|
||||
rows.forEach(r => { result[r.category] = r.granted; });
|
||||
}
|
||||
result.essential = true;
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
console.error('Error fetching consents:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/consents', async (req, res) => {
|
||||
try {
|
||||
const userId = req.session?.userId;
|
||||
const sessionId = req.sessionID;
|
||||
const { categories } = req.body;
|
||||
if (!categories || typeof categories !== 'object') {
|
||||
return res.status(400).json({ error: 'categories object required' });
|
||||
}
|
||||
const allowedCategories = ['analytics', 'preferences', 'health_data'];
|
||||
for (const cat of allowedCategories) {
|
||||
if (cat in categories) {
|
||||
const granted = Boolean(categories[cat]);
|
||||
if (userId) {
|
||||
await userDbRun(
|
||||
`INSERT INTO user_consents (user_id, category, granted, updated_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP) ON CONFLICT (user_id, category) DO UPDATE SET granted = ?, updated_at = CURRENT_TIMESTAMP`,
|
||||
[userId, cat, granted, granted]
|
||||
);
|
||||
} else if (sessionId) {
|
||||
await userDbRun(
|
||||
`INSERT INTO user_consents (session_id, category, granted, updated_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP) ON CONFLICT (session_id, category) DO UPDATE SET granted = ?, updated_at = CURRENT_TIMESTAMP`,
|
||||
[sessionId, cat, granted, granted]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return updated consents
|
||||
const result = { essential: true };
|
||||
const cats = ['analytics', 'preferences', 'health_data'];
|
||||
if (userId) {
|
||||
const rows = await userDbAll('SELECT category, granted FROM user_consents WHERE user_id = ?', [userId]);
|
||||
rows.forEach(r => { result[r.category] = r.granted; });
|
||||
} else if (sessionId) {
|
||||
const rows = await userDbAll('SELECT category, granted FROM user_consents WHERE session_id = ?', [sessionId]);
|
||||
rows.forEach(r => { result[r.category] = r.granted; });
|
||||
}
|
||||
cats.forEach(c => { if (!(c in result)) result[c] = false; });
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
console.error('Error saving consents:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== RECENT SEARCHES (database-based) ==========
|
||||
|
||||
const MAX_RECENT = 5;
|
||||
|
||||
Reference in New Issue
Block a user