Skip to content

Commit a1e65a9

Browse files
Update server.js
1 parent ad90e95 commit a1e65a9

1 file changed

Lines changed: 53 additions & 42 deletions

File tree

server.js

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ const db = new sqlite3.Database(DB_PATH, (err) => {
9595
db.run(`CREATE TABLE IF NOT EXISTS notifications (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, channelId TEXT NOT NULL, channelName TEXT NOT NULL, channelLogo TEXT, programTitle TEXT NOT NULL, programDesc TEXT, programStart TEXT NOT NULL, programStop TEXT NOT NULL, notificationTime TEXT NOT NULL, programId TEXT NOT NULL, status TEXT DEFAULT 'pending', triggeredAt TEXT, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE)`);
9696
db.run(`CREATE TABLE IF NOT EXISTS push_subscriptions (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, endpoint TEXT UNIQUE NOT NULL, p256dh TEXT NOT NULL, auth TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE)`);
9797

98-
// --- **FIX 1: New table for per-device notification tracking** ---
9998
db.run(`CREATE TABLE IF NOT EXISTS notification_deliveries (
10099
id INTEGER PRIMARY KEY AUTOINCREMENT,
101100
notification_id INTEGER NOT NULL,
@@ -1184,7 +1183,6 @@ app.post('/api/notifications', requireAuth, (req, res) => {
11841183
const notificationId = this.lastID;
11851184
console.log(`[PUSH_API] Notification added successfully for program "${programTitle}" (DB ID: ${notificationId}) for user ${userId}.`);
11861185

1187-
// --- **FIX 2: Create a delivery record for each of the user's devices** ---
11881186
db.all("SELECT id FROM push_subscriptions WHERE user_id = ?", [userId], (subErr, subs) => {
11891187
if (subErr) {
11901188
console.error(`[PUSH_API_ERROR] Could not fetch subscriptions for user ${userId} to create deliveries.`, subErr);
@@ -1206,28 +1204,47 @@ app.post('/api/notifications', requireAuth, (req, res) => {
12061204
);
12071205
});
12081206

1207+
// --- **FIX: Modified `GET /api/notifications` to provide accurate, consolidated status** ---
12091208
app.get('/api/notifications', requireAuth, (req, res) => {
12101209
console.log(`[PUSH_API] Fetching notifications for user ${req.session.userId}.`);
1211-
db.all(`SELECT id, user_id, channelId, channelName, channelLogo, programTitle, programDesc, programStart, programStop, notificationTime as scheduledTime, programId, status, triggeredAt
1212-
FROM notifications
1213-
WHERE user_id = ?
1214-
ORDER BY notificationTime DESC`,
1215-
[req.session.userId],
1216-
(err, rows) => {
1217-
if (err) {
1218-
console.error('[PUSH_API] Error fetching notifications from database:', err);
1219-
return res.status(500).json({ error: 'Could not retrieve notifications.' });
1220-
}
1221-
console.log(`[PUSH_API] Found ${rows.length} notifications for user ${req.session.userId}.`);
1222-
res.json(rows);
1210+
const query = `
1211+
SELECT
1212+
n.id,
1213+
n.user_id,
1214+
n.channelId,
1215+
n.channelName,
1216+
n.channelLogo,
1217+
n.programTitle,
1218+
n.programDesc,
1219+
n.programStart,
1220+
n.programStop,
1221+
n.notificationTime as scheduledTime,
1222+
n.programId,
1223+
-- Determine the overall status based on its deliveries
1224+
CASE
1225+
WHEN (SELECT COUNT(*) FROM notification_deliveries WHERE notification_id = n.id AND status = 'sent') > 0 THEN 'sent'
1226+
WHEN (SELECT COUNT(*) FROM notification_deliveries WHERE notification_id = n.id AND status = 'expired') > 0 THEN 'expired'
1227+
ELSE n.status
1228+
END as status,
1229+
-- Use the latest delivery update time as the triggeredAt time for consistency
1230+
(SELECT MAX(updatedAt) FROM notification_deliveries WHERE notification_id = n.id AND status = 'sent') as triggeredAt
1231+
FROM notifications n
1232+
WHERE n.user_id = ?
1233+
ORDER BY n.notificationTime DESC
1234+
`;
1235+
db.all(query, [req.session.userId], (err, rows) => {
1236+
if (err) {
1237+
console.error('[PUSH_API] Error fetching consolidated notifications from database:', err);
1238+
return res.status(500).json({ error: 'Could not retrieve notifications.' });
12231239
}
1224-
);
1240+
console.log(`[PUSH_API] Found ${rows.length} consolidated notifications for user ${req.session.userId}.`);
1241+
res.json(rows);
1242+
});
12251243
});
12261244

12271245
app.delete('/api/notifications/:id', requireAuth, (req, res) => {
12281246
const { id } = req.params;
12291247
console.log(`[PUSH_API] Deleting notification ID: ${id} for user ${req.session.userId}.`);
1230-
// Deleting from the main `notifications` table will cascade and delete related `notification_deliveries`.
12311248
db.run(`DELETE FROM notifications WHERE id = ? AND user_id = ?`,
12321249
[id, req.session.userId],
12331250
function (err) {
@@ -1414,18 +1431,14 @@ app.delete('/api/multiview/layouts/:id', requireAuth, (req, res) => {
14141431
});
14151432

14161433

1417-
// --- **FIX 3: Rewritten notification checker for multi-device delivery** ---
14181434
async function checkAndSendNotifications() {
14191435
console.log('[PUSH_CHECKER] Running scheduled notification check for all devices.');
14201436
const now = new Date();
14211437
const nowIso = now.toISOString();
14221438

1423-
// --- **FIX 4: 1-day timeout logic** ---
1424-
// Calculate the cutoff time (24 hours ago)
14251439
const timeoutCutoff = new Date(now.getTime() - (24 * 60 * 60 * 1000)).toISOString();
14261440

14271441
try {
1428-
// First, mark any pending deliveries for notifications older than 24 hours as 'expired'.
14291442
db.run(`
14301443
UPDATE notification_deliveries
14311444
SET status = 'expired', updatedAt = ?
@@ -1440,7 +1453,6 @@ async function checkAndSendNotifications() {
14401453
}
14411454
});
14421455

1443-
// Fetch all pending deliveries that are due and not expired.
14441456
const dueDeliveries = await new Promise((resolve, reject) => {
14451457
const query = `
14461458
SELECT
@@ -1465,9 +1477,12 @@ async function checkAndSendNotifications() {
14651477
if (dueDeliveries.length > 0) {
14661478
console.log(`[PUSH_CHECKER] Found ${dueDeliveries.length} due notification deliveries to process.`);
14671479
} else {
1468-
return; // No work to do
1480+
return;
14691481
}
14701482

1483+
// --- **FIX: Decouple main notification status from delivery status** ---
1484+
// We will only update the `notification_deliveries` table. The main `notifications`
1485+
// table status will be derived on-the-fly when requested by the client.
14711486
for (const delivery of dueDeliveries) {
14721487
console.log(`[PUSH_CHECKER] Processing delivery ID ${delivery.delivery_id} for program "${delivery.programTitle}" to subscription ${delivery.subscription_id}.`);
14731488

@@ -1488,26 +1503,22 @@ async function checkAndSendNotifications() {
14881503
keys: { p256dh: delivery.p256dh, auth: delivery.auth }
14891504
};
14901505

1491-
try {
1492-
await webpush.sendNotification(pushSubscription, payload);
1493-
console.log(`[PUSH_CHECKER] Successfully sent notification for delivery ID ${delivery.delivery_id}.`);
1494-
// Mark this specific delivery as 'sent'
1495-
db.run("UPDATE notification_deliveries SET status = 'sent', updatedAt = ? WHERE id = ?", [nowIso, delivery.delivery_id]);
1496-
1497-
} catch (error) {
1498-
console.error(`[PUSH_CHECKER] Error sending notification for delivery ID ${delivery.delivery_id}:`, error.statusCode, error.body || error.message);
1499-
1500-
if (error.statusCode === 410 || error.statusCode === 404) {
1501-
console.log(`[PUSH_CHECKER] Subscription ${delivery.subscription_id} is invalid (410/404). Deleting subscription and marking deliveries as failed.`);
1502-
// Delete the invalid subscription
1503-
db.run("DELETE FROM push_subscriptions WHERE id = ?", [delivery.subscription_id]);
1504-
// Mark all pending deliveries for this subscription as failed to prevent retries
1505-
db.run("UPDATE notification_deliveries SET status = 'failed', updatedAt = ? WHERE subscription_id = ? AND status = 'pending'", [nowIso, delivery.subscription_id]);
1506-
} else {
1507-
// For other errors (e.g., network issues), just mark this attempt as failed. It will be retried.
1508-
db.run("UPDATE notification_deliveries SET status = 'failed', updatedAt = ? WHERE id = ?", [nowIso, delivery.delivery_id]);
1509-
}
1510-
}
1506+
webpush.sendNotification(pushSubscription, payload)
1507+
.then(() => {
1508+
console.log(`[PUSH_CHECKER] Successfully sent notification for delivery ID ${delivery.delivery_id}.`);
1509+
db.run("UPDATE notification_deliveries SET status = 'sent', updatedAt = ? WHERE id = ?", [nowIso, delivery.delivery_id]);
1510+
})
1511+
.catch(error => {
1512+
console.error(`[PUSH_CHECKER] Error sending notification for delivery ID ${delivery.delivery_id}:`, error.statusCode, error.body || error.message);
1513+
1514+
if (error.statusCode === 410 || error.statusCode === 404) {
1515+
console.log(`[PUSH_CHECKER] Subscription ${delivery.subscription_id} is invalid (410/404). Deleting subscription and failing deliveries.`);
1516+
db.run("DELETE FROM push_subscriptions WHERE id = ?", [delivery.subscription_id]);
1517+
db.run("UPDATE notification_deliveries SET status = 'failed', updatedAt = ? WHERE subscription_id = ? AND status = 'pending'", [nowIso, delivery.subscription_id]);
1518+
} else {
1519+
db.run("UPDATE notification_deliveries SET status = 'failed', updatedAt = ? WHERE id = ?", [nowIso, delivery.delivery_id]);
1520+
}
1521+
});
15111522
}
15121523
} catch (error) {
15131524
console.error('[PUSH_CHECKER] Unhandled error in checkAndSendNotifications:', error);

0 commit comments

Comments
 (0)