Skip to content

Commit dd2e2e7

Browse files
fix notifs (#359)
* Fix notification logic * console.log(oopsies
1 parent 0558c1c commit dd2e2e7

File tree

9 files changed

+161
-55
lines changed

9 files changed

+161
-55
lines changed

src/controllers/DelaysController.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ const router = express.Router();
66
router.get("/alerts", async (req, res) => {
77
try {
88
const alerts = await AlertsUtils.getAlertsData();
9-
res.status(200).json(alerts);
9+
res.status(200).json({
10+
success: true,
11+
data: alerts,
12+
});
1013
} catch (error) {
1114
console.error("Error fetching alerts:", error.message);
1215
res.status(500).json({ error: "Failed to fetch alerts" });
@@ -32,7 +35,11 @@ router.post("/delays", async (req, res) => {
3235
})
3336
);
3437

35-
res.status(200).json(delays);
38+
res.status(200).json({
39+
success: true,
40+
data: allStops,
41+
});
42+
3643
} catch (error) {
3744
res.status(500).json({ error: error.message });
3845
}

src/controllers/RouteController.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ router.post('/route', async (req, res) => {
5454
AnalyticsUtils.assignRouteIdsAndCache(routes);
5555

5656
// Send the sectioned routes as the response
57-
res.json(sectionedRoutes);
57+
res.status(200).json({
58+
success: true,
59+
data: sectionedRoutes,
60+
});
5861
} catch (error) {
5962
LogUtils.logErr(error, req.body, 'Error processing route request');
6063
res.status(500).json({ error: 'Failed to process the route request' });

src/controllers/RouteReportingController.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ router.get('/closestBus', async (req, res) => {
1212
} = req.body;
1313

1414
const closestBus = await RouteReportingUtils.getClosestBus(routeId, start);
15-
res.status(200).json(closestBus);
15+
res.status(200).json({
16+
success: true,
17+
data: closestBus,
18+
});
1619
} catch (error) {
1720
LogUtils.logErr(error, req.body, 'Error fetching closest bus');
1821
res.status(500).json({ error: 'Failed to fetch closest bus' });
@@ -29,7 +32,10 @@ router.post('/reports', async (req, res) => {
2932
} = req.body;
3033

3134
const report = await RouteReportingUtils.insertReport(vehicleId, congestionLevel, deviceToken, timestamp);
32-
res.status(200).json(report);
35+
res.status(200).json({
36+
success: true,
37+
data: report,
38+
});
3339
} catch (error) {
3440
LogUtils.logErr(error, req.body, 'Error inserting report');
3541
res.status(500).json({ error: 'Failed to insert report' });
@@ -40,7 +46,10 @@ router.get('/reports/:vehicleId', async (req, res) => {
4046
try {
4147
const { vehicleId } = req.params;
4248
const reports = await RouteReportingUtils.fetchReportsByBus(vehicleId);
43-
res.status(200).json(reports);
49+
res.status(200).json({
50+
success: true,
51+
data: reports,
52+
});
4453
} catch (error) {
4554
LogUtils.logErr(error, req.params, 'Error fetching reports by vehicleId');
4655
res.status(500).json({ error: 'Failed to fetch reports by vehicleId' });

src/controllers/StopsController.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ const router = express.Router();
77
router.get("/allStops", async (req, res) => {
88
try {
99
const allStops = await AllStopUtils.getAllStops();
10-
res.status(200).json(allStops);
10+
res.status(200).json({
11+
success: true,
12+
data: allStops,
13+
});
1114
} catch (error) {
1215
console.error("Error fetching all stops:", error.message);
1316
res.status(500).json({ error: "Failed to fetch all stops" });

src/controllers/TrackingController.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ router.post("/tracking", async (req, res) => {
1616
const trackingResponse = await RealtimeFeedUtilsV3.getTrackingResponse(
1717
data
1818
);
19-
20-
res.status(200).json(trackingResponse);
19+
20+
res.status(200).json({
21+
success: true,
22+
data: trackingResponse,
23+
});
2124
} catch (error) {
2225
res.status(500).json({ error: error.message });
2326
}

src/data/notifRequests.json

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,57 @@
1-
{}
1+
{
2+
"t776-bFA1-slD": {
3+
"1512": [
4+
"d5yOxYOS8UakmiJWNFX2Nr:APA91bGb6PSrXFd4vmD7XQN3vALrZEwTWXf2z9HeEMOXrYtNj0psn5qO_-zv0VLsPpuZYdFMXi3YSkJ2FTnJV75Fc7LNw01GGJTFzf9CWf-W-f6r9c7oKsXEVfqjz8k-BkXnTTqQhG2d"
5+
]
6+
},
7+
"t854-b1F57-slC": {
8+
"1328": [
9+
"diiwsV-LXkL-vFTrMLczKh:APA91bFVvviZuN0JvnDgawDbae2RYr2-FX3yjQrf0khhB7_7d1mhODigsCC8bZrdmdFM-Wx8yeVnSOJZnS9UACYm4VNGB0bMT_2LzYuIolKSD9xPn240pu4"
10+
]
11+
},
12+
"t840-b1F59-slC": {
13+
"1328": [
14+
"diiwsV-LXkL-vFTrMLczKh:APA91bFVvviZuN0JvnDgawDbae2RYr2-FX3yjQrf0khhB7_7d1mhODigsCC8bZrdmdFM-Wx8yeVnSOJZnS9UACYm4VNGB0bMT_2LzYuIolKSD9xPn240pu4"
15+
]
16+
},
17+
"t898-b1F57-slC": {
18+
"1533": [
19+
"diiwsV-LXkL-vFTrMLczKh:APA91bFVvviZuN0JvnDgawDbae2RYr2-FX3yjQrf0khhB7_7d1mhODigsCC8bZrdmdFM-Wx8yeVnSOJZnS9UACYm4VNGB0bMT_2LzYuIolKSD9xPn240pu4"
20+
]
21+
},
22+
"t868-b1F59-slC": {
23+
"1534": [
24+
"diiwsV-LXkL-vFTrMLczKh:APA91bFVvviZuN0JvnDgawDbae2RYr2-FX3yjQrf0khhB7_7d1mhODigsCC8bZrdmdFM-Wx8yeVnSOJZnS9UACYm4VNGB0bMT_2LzYuIolKSD9xPn240pu4"
25+
]
26+
},
27+
"t8CF-b1F4A-slC": {
28+
"1343": [
29+
"de-EtLrD6Ub1sEK8dSm1jr:APA91bEU9KIQElzFZefk6KRhQ0ADcVflRp3MHhWrLBZa8DTIHVLac1wQTVYfZ5wTRfKOWGpxFFnKWyTunYJKLOC54bP3n5YPyCyHhje7skYx4y673pJXcbI"
30+
]
31+
},
32+
"t908-b1F59-slC": {},
33+
"t91C-b1F57-slC": {},
34+
"t930-b1F59-slC": {},
35+
"t960-b1F4B-slC": {},
36+
"tC-b1F57-slC": {},
37+
"t20-b1F59-slC": {},
38+
"t13-b1F4B-slC": {},
39+
"t14-b1F59-slC": {},
40+
"t28-b1F57-slC": {},
41+
"t31-b1F4B-slC": {
42+
"1531": [
43+
"de-EtLrD6Ub1sEK8dSm1jr:APA91bEU9KIQElzFZefk6KRhQ0ADcVflRp3MHhWrLBZa8DTIHVLac1wQTVYfZ5wTRfKOWGpxFFnKWyTunYJKLOC54bP3n5YPyCyHhje7skYx4y673pJXcbI"
44+
]
45+
},
46+
"t7D0-b1F4B-slD": {},
47+
"t7DC-b1F57-slD": {},
48+
"t7DA-b1F5B-slD": {},
49+
"t804-b1F57-slD": {},
50+
"t7DF-b1F44-slD": {},
51+
"t898-b1F4B-slD": {},
52+
"t86D-b1F44-slD": {},
53+
"t8A4-b1F57-slD": {},
54+
"t898-b1F57-slD": {},
55+
"t8C0-b1F57-slD": {},
56+
"t8C9-b1F4B-slD": {}
57+
}

src/index.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,35 @@ import RealtimeFeedUtilsV3 from "./utils/RealtimeFeedUtilsV3.js";
1616

1717
import admin from "firebase-admin";
1818
import swaggerUi from "swagger-ui-express";
19-
import swaggerDoc from "./swagger.json" with { type: "json" };
19+
import fs from "fs";
20+
const swaggerDoc = JSON.parse(
21+
fs.readFileSync(new URL("./swagger.json", import.meta.url))
22+
);
23+
2024
import AlertsUtils from "./utils/AlertsUtils.js";
2125
import AllStopUtils from "./utils/AllStopUtils.js";
2226
import GTFSUtils from "./utils/GTFSUtils.js";
2327

24-
2528
const app = express();
2629
const port = process.env.PORT;
2730

2831
app.use(express.json());
2932

30-
app.use('/api/v1/', delayRoutes);
33+
app.use("/api/v1/", delayRoutes);
3134

32-
app.use('/api/v3/', routeRoutes);
35+
app.use("/api/v3/", routeRoutes);
3336

34-
app.use('/api/v3/', trackingRoutes);
37+
app.use("/api/v3/", trackingRoutes);
3538

36-
app.use('/api/v2/', searchRoutes);
39+
app.use("/api/v3/", searchRoutes);
3740

38-
app.use('/api/v1/', stopsRoutes);
41+
app.use("/api/v1/", stopsRoutes);
3942

40-
app.use('/api/v1/', notifRoutes);
43+
app.use("/api/v1/", notifRoutes);
4144

42-
app.use('/api/v1/', reportingRoutes);
45+
app.use("/api/v1/", reportingRoutes);
4346

44-
app.use('/api/v1/', ecosystemRoutes);
47+
app.use("/api/v1/", ecosystemRoutes);
4548

4649
// Setup Swagger docs
4750
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDoc));

src/utils/NotificationUtils.js

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { fileURLToPath } from "url";
44
import fs from "fs";
55
import path from "path";
66
import RealtimeFeedUtilsV3 from "./RealtimeFeedUtilsV3.js";
7+
import LogUtils from "./LogUtils.js";
78

89
const __filename = fileURLToPath(import.meta.url);
910
const __dirname = path.dirname(__filename);
@@ -59,54 +60,86 @@ function deleteDelayNotification(tripID, stopID, deviceToken) {
5960

6061
function sendNotifications() {
6162
const rtfData = RealtimeFeedUtilsV3.getRTFData();
62-
63+
6364
if (!rtfData) {
64-
// no real-time data available yet
6565
return;
6666
}
67-
67+
68+
const tokensToDelete = [];
69+
6870
for (const id in rtfData) {
6971
if (id in notifRequests) {
7072
for (const stopID in notifRequests[id]) {
7173
if (stopID in rtfData[id]["stopUpdates"]) {
72-
for (const deviceToken of notifRequests[id][stopID]) {
73-
sendNotification(
74-
deviceToken,
75-
`The bus on ${rtfData[id]["routeId"]} is delayed`,
76-
"testBody"
77-
);
74+
//only send a notification if there is a delay
75+
if (rtfData[id]["stopUpdates"][stopID] > 0) {
76+
for (const deviceToken of notifRequests[id][stopID]) {
77+
const notifData = {
78+
title: "Delay Notification",
79+
body: `The bus on ${rtfData[id]["routeId"]} is delayed`,
80+
};
81+
82+
sendNotification(deviceToken, notifData);
83+
84+
tokensToDelete.push({ id, stopID, deviceToken });
85+
}
7886
}
7987
}
8088
}
8189
}
8290
}
91+
92+
for (const { id, stopID, deviceToken } of tokensToDelete) {
93+
if (
94+
notifRequests[id] &&
95+
notifRequests[id][stopID] &&
96+
Array.isArray(notifRequests[id][stopID])
97+
) {
98+
notifRequests[id][stopID] = notifRequests[id][stopID].filter(
99+
(token) => token !== deviceToken
100+
);
101+
if (notifRequests[id][stopID].length === 0) {
102+
delete notifRequests[id][stopID];
103+
}
104+
}
105+
}
106+
83107
saveNotifs();
84108
}
85109

86-
function sendNotification(deviceToken, data, notification) {
110+
async function sendNotification(deviceToken, notif) {
87111
const message = {
88-
data: {
89-
data,
90-
notification,
91-
},
92112
token: deviceToken,
113+
notification: {
114+
title: notif.title,
115+
body: notif.body,
116+
},
93117
};
118+
94119
if (!message.token) {
95120
throw new Error("Invalid device token");
96121
}
97-
getMessaging()
98-
.send(message)
99-
.then((response) => {
100-
console.log(response);
101-
});
122+
123+
try {
124+
const response = await getMessaging()
125+
.send(message)
126+
.then((response) => {
127+
LogUtils.log({ message: response });
128+
console.log(response);
129+
});
130+
131+
console.log("Notification sent successfully:", response);
132+
} catch (error) {
133+
console.error("Error sending notification:", error.code, error.message);
134+
}
102135
}
103136

104137
function waitForDeparture(deviceToken, startTime) {
105138
const startDate = new Date(parseInt(startTime) * 1000 - 60000 * 10);
106139

107140
const notifData = {
108-
data: "You should board your bus in 10 minutes",
109-
notification: "Bording Reminder",
141+
body: "You should board your bus in 10 minutes",
142+
title: "Bording Reminder",
110143
};
111144

112145
const job = schedule.scheduleJob(startDate, () => {
@@ -121,13 +154,14 @@ function waitForDeparture(deviceToken, startTime) {
121154
}
122155

123156
function cancelDeparture(deviceToken, startTime) {
124-
const startDate = new Date(parseInt(startTime) * 1000 - 60000 * 10);
157+
let startDate = new Date(parseInt(startTime) * 1000 - 60000 * 10);
158+
startDate = startDate.toString();
125159

126160
if (deviceToken in departures) {
127161
if (startDate in departures[deviceToken]) {
128162
if (departures[deviceToken][startDate]) {
129163
departures[deviceToken][startDate].cancel();
130-
console.log("Job canceled.");
164+
LogUtils.log({ message: "job canceled" });
131165
}
132166
}
133167
}

src/utils/RealtimeFeedUtilsV3.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,13 @@ function getVehicleData() {
146146
*
147147
*/
148148
async function getTrackingResponse(requestData) {
149-
LogUtils.log({ message: "getTrackingResponse: entering function" });
150149
const vehicles = getVehicleData();
151150

152151
const trackingInformation = requestData
153152
.map((data) => {
154153
const { routeId, tripId } = data;
155154
const vehicleData = getVehicleInformation(routeId, tripId, vehicles);
156155
if (!vehicleData) {
157-
LogUtils.log({ message: "getVehicleResponse: noData", vehicleData });
158156
return null;
159157
}
160158
return vehicleData;
@@ -203,22 +201,12 @@ function getVehicleInformation(routeId, tripId, vehicles) {
203201
// vehicles param ensures the vehicle tracking information doesn't update in
204202
// the middle of execution
205203
if (!routeId || !tripId || !vehicles) {
206-
LogUtils.log({
207-
category: "getVehicleInformation NULL",
208-
routeId,
209-
tripId,
210-
});
211204
return null;
212205
}
213206
const vehicleData = Object.values(vehicles).find(
214207
(v) => v.routeId === routeId && v.tripId === tripId
215208
);
216209
if (!vehicleData) {
217-
LogUtils.log({
218-
category: "getVehicleInformation no data",
219-
routeId,
220-
tripId,
221-
});
222210
return {
223211
case: "noData",
224212
latitude: 0,

0 commit comments

Comments
 (0)