yatra-x-feedback / src /controllers /feedback.controller.js
imkrish's picture
Upload folder using huggingface_hub
54d9dcb verified
Raw History Blame Contribute Delete
4.65 kB
'use strict';
const { v4: uuidv4 } = require('uuid');
const { getPool } = require('../db');
/**
* Create a new feedback event (PostgreSQL)
*/
async function createFeedbackEvent(req, res) {
const {
event_type,
session_id,
user_hash,
context = {},
itinerary_snapshot = [],
modifications = [],
reward = 0
} = req.body;
// Validation
if (!event_type) {
return res.status(400).json({
error: { message: 'event_type is required' }
});
}
const validEventTypes = [
'plan_saved', 'plan_completed', 'rating_positive',
'poi_added', 'plan_abandoned', 'poi_removed',
'rating_negative', 'poi_reordered', 'poi_swapped', 'session_start'
];
if (!validEventTypes.includes(event_type)) {
return res.status(400).json({
error: { message: `Invalid event_type. Must be one of: ${validEventTypes.join(', ')}` }
});
}
try {
const pool = getPool();
if (!pool) {
return res.status(503).json({ error: { message: 'Database not available' } });
}
const id = uuidv4();
const query = `
INSERT INTO feedback_events
(id, event_type, session_id, user_hash, context, itinerary_snapshot, modifications, reward, created_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW())
`;
const params = [
id,
event_type,
session_id || null,
user_hash || null,
JSON.stringify(context),
JSON.stringify(itinerary_snapshot),
JSON.stringify(modifications),
reward
];
await pool.query(query, params);
res.status(201).json({
data: { id, event_type, session_id, reward },
message: 'Feedback event recorded successfully'
});
} catch (err) {
console.error('Error creating feedback event:', err);
res.status(500).json({ error: { message: 'Failed to record feedback event' } });
}
}
/**
* List feedback events with optional filters (PostgreSQL)
*/
async function listFeedbackEvents(req, res) {
const { event_type, session_id, limit = 100, offset = 0 } = req.query;
try {
const pool = getPool();
if (!pool) {
return res.status(503).json({ error: { message: 'Database not available' } });
}
let query = 'SELECT * FROM feedback_events WHERE 1=1';
const params = [];
let paramCounter = 1;
if (event_type) {
query += ` AND event_type = $${paramCounter++}`;
params.push(event_type);
}
if (session_id) {
query += ` AND session_id = $${paramCounter++}`;
params.push(session_id);
}
query += ` ORDER BY created_at DESC LIMIT $${paramCounter++} OFFSET $${paramCounter++}`;
params.push(Math.min(parseInt(limit), 1000), parseInt(offset));
const result = await pool.query(query, params);
res.json({ data: result.rows });
} catch (err) {
console.error('Error listing feedback events:', err);
res.status(500).json({ error: { message: 'Failed to list feedback events' } });
}
}
/**
* Get aggregated statistics for a POI (PostgreSQL)
*/
async function getPOIStats(req, res) {
const { poi_id } = req.params;
if (!poi_id) {
return res.status(400).json({ error: { message: 'poi_id is required' } });
}
try {
const pool = getPool();
if (!pool) {
return res.status(503).json({ error: { message: 'Database not available' } });
}
// PostgreSQL JSONB search or simple LIKE on TEXT
const query = `
SELECT event_type, reward, modifications
FROM feedback_events
WHERE itinerary_snapshot::text LIKE $1
`;
const result = await pool.query(query, [`%${poi_id}%`]);
const events = result.rows;
const stats = {
poi_id,
times_suggested: events.length,
times_saved: events.filter(e => e.event_type === 'plan_saved').length,
times_removed: events.filter(e => {
if (e.event_type !== 'poi_removed') return false;
const mods = typeof e.modifications === 'string' ? JSON.parse(e.modifications) : e.modifications;
return Array.isArray(mods) && mods.some(m => m.poi_id === poi_id);
}).length,
avg_reward: events.length > 0
? (events.reduce((sum, e) => sum + parseFloat(e.reward), 0) / events.length).toFixed(2)
: 0,
save_rate: 0
};
if (stats.times_suggested > 0) {
stats.save_rate = (stats.times_saved / stats.times_suggested).toFixed(2);
}
res.json({ data: stats });
} catch (err) {
console.error('Error getting POI stats:', err);
res.status(500).json({ error: { message: 'Failed to get POI stats' } });
}
}
module.exports = {
createFeedbackEvent,
listFeedbackEvents,
getPOIStats
};