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
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { Client, TextChannel } from 'discord.js'
import process from 'node:process'
import { WARDEN_DUTY_CHANNEL } from '@config/discord'
import { registerClientReadyHandler } from '@events/client-ready/registry'
import { EVENT_PATH } from '@events/index'
import { getChannel } from '@utils/discord'
import { DiscordBaseError } from '@utils/discord/error'
import { getModuleName } from '@utils/io'
import { log } from '@utils/logger'
import cron from 'node-cron'
import { NotifyWaitingCheckin } from '../validators/notify-waiting-checkin'

export class NotifyWaitingCheckinError extends DiscordBaseError {
constructor(message: string, options?: { cause?: unknown }) {
super('NotifyWaitingCheckinError', message, options)
}
}

const moduleName = getModuleName(EVENT_PATH, __filename)

registerClientReadyHandler({
desc: 'Notifies Flamewardens if there are users with check-in status still waiting for review at 22:00 (WIB).',
errorTag: () => `${moduleName}: ${NotifyWaitingCheckin.ERR.UnexpectedNotifyWaitingCheckin}`,
async exec(client: Client) {
try {
cron.schedule('0 22 * * *', async () => {
log.check(NotifyWaitingCheckin.MSG.JobRunning)

const guild = await client.guilds.fetch(process.env.GUILD_ID!)
const wardenDutyChannel = await getChannel(guild, WARDEN_DUTY_CHANNEL) as TextChannel
NotifyWaitingCheckin.assertChannel(wardenDutyChannel)
const checkins = await NotifyWaitingCheckin.getTodayWaitingCheckins(client.prisma)

await NotifyWaitingCheckin.sendOpening(guild.name, wardenDutyChannel)
await NotifyWaitingCheckin.sendList(checkins, wardenDutyChannel)
await NotifyWaitingCheckin.sendClosing(guild.name, wardenDutyChannel)

log.success(NotifyWaitingCheckin.MSG.JobSuccess)
})
}
catch (err) {
if (!(err instanceof DiscordBaseError))
throw err
}
},
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { Checkin } from '@type/checkin'
import { FLAMEWARDEN_ROLE, GRINDER_ROLE } from '@config/discord'
import { getParsedNow } from '@utils/date'
import { DiscordAssert } from '@utils/discord'

export class NotifyWaitingCheckinMessage extends DiscordAssert {
static override readonly ERR = {
...DiscordAssert.ERR,
UnexpectedNotifyWaitingCheckin: '❌ Something went wrong while notifying waiting check-in',
}

static override readonly MSG = {
...DiscordAssert.MSG,
JobRunning: '[JOB] Running notify waiting checkin...',
JobSuccess: '[JOB] Notify waiting checkin finished successfully',
Opening: (guildName: string) => `
Wahai para <@&${FLAMEWARDEN_ROLE}>,
tatkala malam kian mendekat dan waktu hampir beralih hari, ${guildName} mencatat bahwa masih terdapat percikan api yang belum ditakar.
**📜 Laporan Status Api**
Beberapa *check-in* para <@&${GRINDER_ROLE}> masih berada dalam keadaan *WAITING* dan belum memperoleh keputusan hingga saat ini.
**⏳ Waktu Genting**
Apabila nyala tersebut tidak ditinjau sebelum 23:59 WIB,
maka rangkaian api para <@&${GRINDER_ROLE}> terkait berisiko gugur pada pergantian hari.
**⚔️ Tugas Penjagaan**
Demi menjaga keadilan perjalanan dan kesinambungan disiplin,
dimohon para <@&${FLAMEWARDEN_ROLE}> berkenan:
Ⅰ. Meninjau *check-in* yang masih tertunda,
Ⅱ. Menetapkan keputusan dengan bijaksana,
Ⅲ. Atau memberi arahan seperlunya sebelum waktu berganti.
`,
List: (checkin: Checkin) => `
- 🔥 <@${checkin.user!.discord_id}> pada [${getParsedNow(checkin.created_at)}](${checkin.link})
`,
Closing: `
Apabila hingga pergantian hari *check-in* di atas belum ditinjau, maka rangkaian nyala para <@&${GRINDER_ROLE}> terkait berisiko terputus oleh hukum waktu.

Kami mohon kebijaksanaan dan perhatian para <@&${FLAMEWARDEN_ROLE}>,
agar setiap api dinilai dengan adil sebelum malam berganti.

> *"Api bukan sekadar menyala; ia dijaga agar tak padam oleh kelalaian."*
`,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { PrismaClient } from '@generatedDB/client'
import type { Checkin as CheckinType } from '@type/checkin'
import type { TextChannel } from 'discord.js'
import { FLAMEWARDEN_ROLE, GRINDER_ROLE } from '@config/discord'
import { createEmbed } from '@utils/component'
import { DiscordAssert, sendAsBot } from '@utils/discord'
import { DUMMY } from '@utils/placeholder'
import { NotifyWaitingCheckinMessage } from '../messages/notify-waiting-checkin'

export class NotifyWaitingCheckin extends NotifyWaitingCheckinMessage {
static override BASE_PERMS = [
...DiscordAssert.BASE_PERMS,
]

static async sendOpening(guildName: string, wardenDutyChannel: TextChannel) {
const openingEmbed = createEmbed(
`🔥 Maklumat Penjagaan Nyala`,
this.MSG.Opening(guildName),
DUMMY.COLOR,
null,
null,
null,
null,
false,
)
await sendAsBot(null, wardenDutyChannel, {
content: `<@&${FLAMEWARDEN_ROLE}>`,
embeds: [openingEmbed],
allowedMentions: { roles: [FLAMEWARDEN_ROLE, GRINDER_ROLE] },
})
}

static async sendList(checkins: CheckinType[], wardenDutyChannel: TextChannel) {
const list: string[] = []
for (const checkin of checkins) {
list.push(this.MSG.List(checkin))
}
const listEmbed = createEmbed(
`⏳ Daftar Waiting Check-In`,
list.join('\n'),
DUMMY.COLOR,
null,
null,
null,
null,
false,
)
await sendAsBot(null, wardenDutyChannel, {
embeds: [listEmbed],
})
}

static async sendClosing(guildName: string, wardenDutyChannel: TextChannel) {
const closingEmbed = createEmbed(
'🛡️ Amanat Penjagaan',
this.MSG.Closing,
DUMMY.COLOR,
{ text: DUMMY.FOOTER(guildName) },
)
await sendAsBot(null, wardenDutyChannel, {
embeds: [closingEmbed],
allowedMentions: { roles: [FLAMEWARDEN_ROLE, GRINDER_ROLE] },
})
}

static async getTodayWaitingCheckins(prisma: PrismaClient): Promise<CheckinType[]> {
const waitingCheckins = await prisma.checkin.findMany({
where: {
status: 'WAITING',
reviewed_by: null,
created_at: {
gte: new Date(new Date().setHours(0, 0, 0, 0)),
},
},
include: {
user: true,
},
orderBy: { created_at: 'asc' },
}) as CheckinType[]

return waitingCheckins
}
}