import { assertExists } from "https://deno.land/std@0.223.0/assert/assert_exists.ts"; import { Client, EmbedBuilder } from "npm:discord.js"; import { _1d, _1min, wait } from "./utils.ts"; import { fetch_feed_channel, format_devoir_title } from "./lib.ts"; import { Storage } from "./storage.ts"; export async function notification_loop(bot: Client, storage: Storage) { while (true) { const devoirs_to_notify = await get_devoirs_to_notify(storage); await delete_obsolete_notifications(devoirs_to_notify, storage, bot); await create_missing_messages(storage, bot, devoirs_to_notify); await update_existing_notifications(storage, bot); await wait(15 * _1min); } } async function get_devoirs_to_notify(storage: Storage) { const devoirs_to_notify = new Set(); const notification_threshold = 7 * _1d; for await (const [devoir_id, devoir] of storage.devoirs.list()) { const time_left = devoir.date - Date.now(); if (time_left < 0) continue; // TODO : delete devoir. if (time_left > notification_threshold) continue; devoirs_to_notify.add(devoir_id.id); } return devoirs_to_notify; } async function delete_obsolete_notifications(devoirs_to_notify: Set, storage: Storage, bot: Client) { for await (const [notif_id, notif] of storage.notifications.list()) { if (devoirs_to_notify.has(notif.devoir_id)) continue; const feed = await storage.feeds.get({ id: notif.feed_id }); if (feed === null) continue; const feed_channel = await fetch_feed_channel(bot, feed); try { const message = await feed_channel.messages.fetch(notif.message_id); await message.delete(); } catch (_) { /* oki */ } await storage.notifications.delete(notif_id); await storage.feeds.update({ id: notif.feed_id }, (f) => f.notification_ids.delete(notif_id.id)); } } async function create_missing_messages(storage: Storage, bot: Client, devoirs_to_notify: Set) { for await (const [feed_id, feed] of storage.feeds.list()) { const feed_channel = await fetch_feed_channel(bot, feed); // find devoirs needing to create a notification for const devoirs_to_notify_in_feed = new Set(devoirs_to_notify.values()); for (const existing_notification_id of feed.notification_ids.values()) { const notification = await storage.notifications.get({ id: existing_notification_id }); assertExists(notification); devoirs_to_notify_in_feed.delete(notification.devoir_id); } // create notifications for (const devoir_id of devoirs_to_notify_in_feed.values()) { const devoir = await storage.devoirs.get({ id: devoir_id }); if (devoir === null) continue; const embed = new EmbedBuilder() .setTitle(format_devoir_title(devoir)) .setDescription(devoir.description); const message = await feed_channel.send({ embeds: [embed] }); const notification_id = await storage.notifications.add({ devoir_id: devoir_id, message_id: message.id, feed_id: feed_id.id, }); storage.feeds.update(feed_id, (f) => f.notification_ids.add(notification_id.id)); } } } async function update_existing_notifications(storage: Storage, bot: Client) { for await (const [_, notification] of storage.notifications.list()) { const devoir = await storage.devoirs.get({ id: notification.devoir_id }); if (devoir === null) continue; const feed = await storage.feeds.get({ id: notification.feed_id }); if (feed === null) continue; const feed_channel = await fetch_feed_channel(bot, feed); const message = await feed_channel.messages.fetch(notification.message_id); const ms_left = devoir.date - Date.now(); const days_left = Math.floor(ms_left / _1d); const embed = new EmbedBuilder() .setTitle(format_devoir_title(devoir) + ` (${days_left} jours)`) .setDescription(devoir.description) .setColor(0x8888ff); if (days_left <= 5) embed.setColor(0xffd726); if (days_left <= 3) embed.setColor(0xff8b26); if (days_left <= 1) embed.setColor(0xff2626); await message.edit({ embeds: [embed], content: "" }); } }