Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 50 additions & 7 deletions src/services/attendee/attendee-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,26 +433,69 @@ attendeeRouter.patch(
const payload = res.locals.payload;
const userId = payload.userId;

const { tags } = AttendeeTagsUpdateValidator.parse(req.body);
const { tags: newTags } = AttendeeTagsUpdateValidator.parse(req.body);

// Check if the user exists in the database
const { data: user } = await SupabaseDB.ATTENDEES.select("tags")
.eq("userId", userId)
.maybeSingle()
.throwOnError();

const [userData, notificationData] = await Promise.all([
SupabaseDB.ATTENDEES.select("tags")
.eq("userId", userId)
.maybeSingle()
.throwOnError(),
SupabaseDB.NOTIFICATIONS.select("deviceId")
.eq("userId", userId)
.maybeSingle()
.throwOnError(),
]);

const user = userData.data;
const deviceId = notificationData.data?.deviceId;

if (!user) {
return res
.status(StatusCodes.NOT_FOUND)
.json({ error: "UserNotFound" });
}

const oldTags = user.tags || [];

if (deviceId) {
const tagsToSubscribe = newTags.filter(
(tag) => !oldTags.includes(tag)
);
const tagsToUnsubscribe = oldTags.filter(
(tag) => !newTags.includes(tag)
);
const subscribePromises = tagsToSubscribe.map((tag) => {
const topicName = `tag_${tag.replace(/[^a-zA-Z0-9-_.~%]/g, "_")}`;
return getFirebaseAdmin()
.messaging()
.subscribeToTopic(deviceId, topicName);
});

const unsubscribePromises = tagsToUnsubscribe.map((tag) => {
const topicName = `tag_${tag.replace(/[^a-zA-Z0-9-_.~%]/g, "_")}`;
return getFirebaseAdmin()
.messaging()
.unsubscribeFromTopic(deviceId, topicName);
});

Promise.all([...subscribePromises, ...unsubscribePromises]).catch(
(error) => {
console.error(
`Failed to sync FCM topics for user ${userId}:`,
error
);
}
);
}

// Update the tags
await SupabaseDB.ATTENDEES.update({ tags })
await SupabaseDB.ATTENDEES.update({ tags: newTags })
.eq("userId", userId)
.throwOnError();

return res.status(StatusCodes.OK).json({ tags });
return res.status(StatusCodes.OK).json({ tags: newTags });
}
);

Expand Down
11 changes: 11 additions & 0 deletions src/services/notifications/notifications-router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ describe("/notifications", () => {
`event_Test_Event`,
currentDayTopic,
"food_wave_1",
"tag_AI",
"tag_Art_Media",
"tag_Autonomous_Vehicles",
"tag_Career_Readiness",
"tag_Company_Talk",
"tag_Cybersecurity",
"tag_Ethics",
"tag_HCI",
"tag_Interactive_Events",
"tag_Networking",
"tag_Research",
].sort();

expect(response.body.topics).toEqual(expectedTopics);
Expand Down
47 changes: 46 additions & 1 deletion src/services/notifications/notifications-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ notificationsRouter.post(
.messaging()
.subscribeToTopic(notificationEnrollmentData.deviceId, "allUsers");

// Get their tags
const { data: attendee } = await SupabaseDB.ATTENDEES.select("tags")
.eq("userId", userId)
.maybeSingle()
.throwOnError();

// enroll them in a topic for the tags
if (attendee?.tags && attendee.tags.length > 0) {
const userTags = attendee.tags;
const subscriptionPromises = userTags.map((tag) => {
const topicName = `tag_${tag.replace(/[^a-zA-Z0-9-_.~%]/g, "_")}`;
return getFirebaseAdmin()
.messaging()
.subscribeToTopic(
notificationEnrollmentData.deviceId,
topicName
);
});
await Promise.all(subscriptionPromises);
}

return res.status(StatusCodes.CREATED).json(notificationEnrollmentData);
}
);
Expand Down Expand Up @@ -164,8 +185,32 @@ notificationsRouter.get(
await SupabaseDB.CUSTOM_TOPICS.select("topicName").throwOnError();
const customTopics =
customTopicsData.map((topic) => topic.topicName) ?? [];

const hardcodedTags = [
"Career Readiness",
"AI",
"Research",
"Interactive Events",
"HCI",
"Ethics",
"Art/Media",
"Autonomous Vehicles",
"Networking",
"Company Talk",
"Cybersecurity",
];

const tagTopics = hardcodedTags.map(
(tag) => `tag_${tag.replace(/[^a-zA-Z0-9-_.~%]/g, "_")}`
);

const allTopics = [
...new Set([...staticTopics, ...eventTopics, ...customTopics]),
...new Set([
...staticTopics,
...eventTopics,
...customTopics,
...tagTopics,
]),
];
return res.status(StatusCodes.OK).send({ topics: allTopics.sort() });
}
Expand Down