Skip to content

Commit c0a20bd

Browse files
authored
Feat/server booster (#55)
* chore: move grinder greetings into aura channel * chore: remove unnecessary match * chore: just make it clear into getChannel (there are so many channels) * feat: server booster listener * refactor: using `guild.name` instead of Aksaria hard-coded
1 parent 37a86d7 commit c0a20bd

25 files changed

Lines changed: 166 additions & 55 deletions

File tree

src/bot/commands/checkin/handlers/checkin-audit.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { registerCommand } from '@commands/registry'
33
import { AUDIT_FLAME_CHANNEL, FLAMEWARDEN_ROLE } from '@config/discord'
44
import { CHECKIN_AUDIT_ID } from '@events/interaction-create/checkin/handlers/audit-modal'
55
import { createCheckinReviewModal, encodeSnowflake, getCustomId } from '@utils/component'
6-
import { getChannelOrThread, sendReply } from '@utils/discord'
6+
import { getChannel, sendReply } from '@utils/discord'
77
import { DiscordBaseError } from '@utils/discord/error'
88
import { log } from '@utils/logger'
99
import { SlashCommandBuilder } from 'discord.js'
@@ -30,7 +30,7 @@ registerCommand({
3030
if (!interaction.inCachedGuild())
3131
throw new CheckinAuditError(CheckinAudit.ERR.NotGuild)
3232

33-
const channel = await getChannelOrThread(interaction.guild, AUDIT_FLAME_CHANNEL) as TextChannel
33+
const channel = await getChannel(interaction.guild, AUDIT_FLAME_CHANNEL) as TextChannel
3434
CheckinAudit.assertMissPerms(interaction.client.user, channel)
3535
const thread = await CheckinAudit.assertThreadUnderChannel(interaction.guild, interaction.channelId, channel)
3636
CheckinAudit.assertNotArchivedThread(thread)

src/bot/commands/checkin/messages/checkin-status.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ ${checkin.public_id}
7676
✍🏻 **${flamewarden.displayName}'(s) Comment**: ${checkin.comment ?? '-'}
7777
> *"[Api Tuan/Nona](${checkin.link}) <@${userDiscordId}> meredup hari ini, namun belum padam sepenuhnya. Perbaiki, dan nyalakan kembali percikan yang benar."*
7878
`,
79-
LastCheckin: (userDiscordId: string, checkin: Checkin, flamewarden?: GuildMember) => `
79+
LastCheckin: (guildName: string, userDiscordId: string, checkin: Checkin, flamewarden?: GuildMember) => `
8080
Wahai Tuan/Nona <@${userDiscordId}>,
8181
tercatat bahwa rangkaian nyala api Tuan/Nona telah terputus pada pergantian hari sebelumnya.
82-
Namun demikian, percikan terakhir masih tersimpan dalam arsip Aksaria dan dapat ditinjau kembali.
82+
Namun demikian, percikan terakhir masih tersimpan dalam arsip ${guildName} dan dapat ditinjau kembali.
8383
8484
Berikut adalah *check-in* terakhir yang pernah Tuan/Nona torehkan:
8585
🆔 **Check-In ID**:
@@ -99,9 +99,9 @@ ${flamewarden?.displayName
9999
: ''}
100100
> *"[Percikan ini](${checkin.link}) pernah kau titipkan pada api, namun belum sempat ditakar oleh penjaga nyala."*
101101
`,
102-
LastCheckinNote: (checkinLink: string, statusLink: string) => `
102+
LastCheckinNote: (guildName: string, checkinLink: string, statusLink: string) => `
103103
Apabila Tuan/Nona meyakini bahwa [*check-in*](${checkinLink}) belum sempat ditinjau oleh <@&${FLAMEWARDEN_ROLE}>,
104-
maka Aksaria membuka ruang klarifikasi dengan tata cara sebagai berikut:
104+
maka ${guildName} membuka ruang klarifikasi dengan tata cara sebagai berikut:
105105
Ⅰ. Berikan reaksi ❓ pada pesan [*status check-in*](${statusLink}) ini.
106106
Ⅱ. Sebuah *thread* khusus akan tercipta secara otomatis.
107107
Ⅲ. Gunakan *thread* tersebut untuk berkomunikasi dan mengajukan peninjauan kepada <@&${FLAMEWARDEN_ROLE}>.

src/bot/commands/checkin/validators/checkin-status.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class CheckinStatus extends CheckinStatusMessage {
5656
`🧭 Check-In #${checkin.public_id}`,
5757
CheckinStatus.MSG.WaitingCheckin(userDiscordId, checkin),
5858
DUMMY.COLOR,
59-
{ text: DUMMY.FOOTER },
59+
{ text: DUMMY.FOOTER(guild.name) },
6060
)
6161
break
6262
}
@@ -66,7 +66,7 @@ export class CheckinStatus extends CheckinStatusMessage {
6666
`🔥 Check-In #${checkin.public_id}`,
6767
CheckinStatus.MSG.ApprovedCheckin(userDiscordId, flamewarden, checkin),
6868
DUMMY.COLOR,
69-
{ text: DUMMY.FOOTER },
69+
{ text: DUMMY.FOOTER(guild.name) },
7070
)
7171
break
7272
}
@@ -76,7 +76,7 @@ export class CheckinStatus extends CheckinStatusMessage {
7676
`❌ Check-In #${checkin.public_id}`,
7777
CheckinStatus.MSG.RejectedCheckin(userDiscordId, flamewarden, checkin),
7878
DUMMY.COLOR,
79-
{ text: DUMMY.FOOTER },
79+
{ text: DUMMY.FOOTER(guild.name) },
8080
)
8181
break
8282
}
@@ -91,7 +91,7 @@ export class CheckinStatus extends CheckinStatusMessage {
9191
`🧐 Check-In`,
9292
CheckinStatus.MSG.NoCheckin(userDiscordId, checkinStreak),
9393
DUMMY.COLOR,
94-
{ text: DUMMY.FOOTER },
94+
{ text: DUMMY.FOOTER(guild.name) },
9595
)
9696

9797
return { content, embed }
@@ -101,9 +101,9 @@ export class CheckinStatus extends CheckinStatusMessage {
101101
const buttons = this.generateButtons(guild.id, checkin)
102102
embed = createEmbed(
103103
`🕯️ Check-In #${checkin.public_id}`,
104-
CheckinStatus.MSG.LastCheckin(userDiscordId, checkin, flamewarden),
104+
CheckinStatus.MSG.LastCheckin(guild.name, userDiscordId, checkin, flamewarden),
105105
DUMMY.COLOR,
106-
{ text: DUMMY.FOOTER },
106+
{ text: DUMMY.FOOTER(guild.name) },
107107
)
108108

109109
return { content, embed, buttons }

src/bot/commands/embed/handlers/role-grant-create.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ registerCommand({
8787
.setTextInputComponent(
8888
new TextInputBuilder()
8989
.setCustomId('footer')
90-
.setPlaceholder(DUMMY.FOOTER)
91-
.setValue(DUMMY.FOOTER)
90+
.setPlaceholder(DUMMY.FOOTER(interaction.guild.name))
91+
.setValue(DUMMY.FOOTER(interaction.guild.name))
9292
.setStyle(TextInputStyle.Short)
9393
.setRequired(false),
9494
),

src/bot/events/client-ready/jobs/handlers/reset-grinder-roles.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import process from 'node:process'
33
import { GRIND_ASHES_CHANNEL } from '@config/discord'
44
import { registerClientReadyHandler } from '@events/client-ready/registry'
55
import { EVENT_PATH } from '@events/index'
6-
import { getChannelOrThread } from '@utils/discord'
6+
import { getChannel } from '@utils/discord'
77
import { DiscordBaseError } from '@utils/discord/error'
88
import { getModuleName } from '@utils/io'
99
import { log } from '@utils/logger'
@@ -27,7 +27,7 @@ registerClientReadyHandler({
2727
log.check(ResetGrinderRoles.MSG.JobRunning)
2828

2929
const guild = await client.guilds.fetch(process.env.GUILD_ID!)
30-
const channel = await getChannelOrThread(guild, GRIND_ASHES_CHANNEL) as TextChannel
30+
const channel = await getChannel(guild, GRIND_ASHES_CHANNEL) as TextChannel
3131
ResetGrinderRoles.assertChannel(channel)
3232
const users = await ResetGrinderRoles.getUsersWithLatestStreak(client.prisma)
3333

src/bot/events/client-ready/jobs/messages/reset-grinder-roles.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ export class ResetGrinderRolesMessage extends DiscordAssert {
1313
JobRunning: '[JOB] Running daily grinder reset...',
1414
JobSuccess: '[JOB] Grinder daily reset finished successfully',
1515
RemoveGrinderRoleFrom: (member: GuildMember) => `[JOB] Removed Grinder role from ${member.user.tag}`,
16-
GoodBye: (member: GuildMember) => `
16+
GoodBye: (guildName: string, member: GuildMember) => `
1717
# 💔 Nyala Api Tuan/Nona <@${member.id}> Telah Gugur
18-
Tatkala hari telah berganti dan lonceng waktu menunjukkan pergantian malam, tercatat bahwa tiada *check-in* yang sah diterima pada hari yang telah berlalu. Maka, sesuai hukum Aksaria, peran Grinder untuk saat ini harus dilepaskan.
18+
Tatkala hari telah berganti dan lonceng waktu menunjukkan pergantian malam, tercatat bahwa tiada *check-in* yang sah diterima pada hari yang telah berlalu. Maka, sesuai hukum ${guildName}, peran Grinder untuk saat ini harus dilepaskan.
1919
2020
Api bukanlah padam karena kelemahan, melainkan karena ia tak disirami pada waktunya.
2121
2222
Namun jangan berduka, jalan ini selalu terbuka bagi mereka yang bersedia memulai kembali. Apabila Tuan/Nona berkehendak menyalakan api kembali, silakan kembali ke <#${IGNITE_PATH_CHANNEL}> dan bangkitlah dari awal.
2323
24-
*Aksaria menanti mereka yang konsisten.*
24+
*${guildName} menanti mereka yang konsisten.*
2525
`,
2626
GoodByeNotes: `
2727
> Apabila *check-in* Tuan/Nona masih berada dalam status menunggu peninjauan (*waiting*) dan belum memperoleh keputusan hingga mendekati pergantian hari, maka dengan ini disampaikan ketentuan berikut:

src/bot/events/client-ready/jobs/validators/reset-grinder-roles.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export class ResetGrinderRoles extends ResetGrinderRolesMessage {
7979
await sendAsBot(
8080
null,
8181
channel,
82-
{ content: ResetGrinderRoles.MSG.GoodBye(member), components: [button], allowedMentions: { users: [member.id], roles: [] } },
82+
{ content: ResetGrinderRoles.MSG.GoodBye(guild.name, member), components: [button], allowedMentions: { users: [member.id], roles: [] } },
8383
)
8484

8585
log.info(this.MSG.RemoveGrinderRoleFrom(member))

src/bot/events/guild-member-update/grinder-role/handlers/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { TextChannel } from 'discord.js'
2-
import { GRIND_ASHES_CHANNEL, GRINDER_ROLE } from '@config/discord'
2+
import { AURA_FARMING_CHANNEL, GRINDER_ROLE } from '@config/discord'
33
import { registerGuildMemberUpdateHandler } from '@events/guild-member-update/registry'
44
import { EVENT_PATH } from '@events/index'
5-
import { getChannelOrThread, sendAsBot } from '@utils/discord'
5+
import { getChannel, sendAsBot } from '@utils/discord'
66
import { DiscordBaseError } from '@utils/discord/error'
77
import { getModuleName } from '@utils/io'
88
import { GrinderRole } from '../validators'
@@ -18,7 +18,6 @@ const moduleName = getModuleName(EVENT_PATH, __filename)
1818
registerGuildMemberUpdateHandler({
1919
desc: 'Watches grinder role assignment/removal for members on guild member update.',
2020
errorTag: () => `${moduleName}: ${GrinderRole.ERR.UnexpectedGrinderRole}`,
21-
match: (_, newMember) => GrinderRole.isMemberHasRole(newMember, GRINDER_ROLE),
2221
async exec(_, oldMember, newMember) {
2322
try {
2423
if (!newMember.guild)
@@ -27,7 +26,7 @@ registerGuildMemberUpdateHandler({
2726
const newHasGrinderRole = GrinderRole.isMemberHasRole(newMember, GRINDER_ROLE)
2827
const oldHasGrinderRole = GrinderRole.isMemberHasRole(oldMember, GRINDER_ROLE)
2928
if (newHasGrinderRole && !oldHasGrinderRole) {
30-
const channel = await getChannelOrThread(newMember.guild, GRIND_ASHES_CHANNEL) as TextChannel
29+
const channel = await getChannel(newMember.guild, AURA_FARMING_CHANNEL) as TextChannel
3130
GrinderRole.assertChannel(channel)
3231
const button = GrinderRole.generateButton(newMember.guild.id)
3332

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { TextChannel } from 'discord.js'
2+
import { AURA_FARMING_CHANNEL } from '@config/discord'
3+
import { registerGuildMemberUpdateHandler } from '@events/guild-member-update/registry'
4+
import { EVENT_PATH } from '@events/index'
5+
import { getChannel, sendAsBot } from '@utils/discord'
6+
import { DiscordBaseError } from '@utils/discord/error'
7+
import { getModuleName } from '@utils/io'
8+
import { ServerBooster } from '../validators'
9+
10+
export class ServerBoosterError extends DiscordBaseError {
11+
constructor(message: string, options?: { cause?: unknown }) {
12+
super('ServerBoosterError', message, options)
13+
}
14+
}
15+
16+
const moduleName = getModuleName(EVENT_PATH, __filename)
17+
18+
registerGuildMemberUpdateHandler({
19+
desc: 'Watches server booster for members on guild member update.',
20+
errorTag: () => `${moduleName}: ${ServerBooster.ERR.UnexpectedServerBooster}`,
21+
async exec(_, oldMember, newMember) {
22+
try {
23+
if (!newMember.guild)
24+
throw new ServerBoosterError(ServerBooster.ERR.NotGuild)
25+
26+
const wasBoosting = !!oldMember.premiumSince
27+
const isBoosting = !!newMember.premiumSince
28+
29+
const justBoosted = !wasBoosting && isBoosting
30+
if (!justBoosted)
31+
return
32+
33+
const channel = await getChannel(newMember.guild, AURA_FARMING_CHANNEL) as TextChannel
34+
ServerBooster.assertChannel(channel)
35+
36+
const embed = ServerBooster.sayDeeplyThanksTo(newMember)
37+
38+
await sendAsBot(null, channel, {
39+
content: ServerBooster.MSG.SpecialThanks,
40+
embeds: [embed],
41+
})
42+
}
43+
catch (err: any) {
44+
if (!(err instanceof DiscordBaseError))
45+
throw err
46+
}
47+
},
48+
})
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { GuildMember } from 'discord.js'
2+
import { BEARER_LOUNGE_CHANNEL, GRINDER_ROLE } from '@config/discord'
3+
import { createEmbed } from '@utils/component'
4+
import { DiscordAssert } from '@utils/discord'
5+
import { DUMMY } from '@utils/placeholder'
6+
7+
export class ServerBoosterMessage extends DiscordAssert {
8+
static override readonly ERR = {
9+
...DiscordAssert.ERR,
10+
UnexpectedServerBooster: '❌ Something went wrong while managing the server booster',
11+
}
12+
13+
static override readonly MSG = {
14+
...DiscordAssert.MSG,
15+
SpecialThanks: `# ❤️‍🔥 Sebuah Nyala Telah Diperkuat`,
16+
Really: `
17+
Api tidak selalu membesar karena banyak kayu,
18+
kadang karena satu jiwa yang rela memberi nyala!`,
19+
ItMeansALot: (guildName: string, userDiscordId: string, boostCount: number) => `
20+
Tuan/Nona <@${userDiscordId}> telah mempersembahkan aura mereka untuk menguatkan nyala ${guildName} beserta para <@&${GRINDER_ROLE}>🔥!
21+
22+
**✨ Maklumat Anugerah**
23+
- Jumlah *Server Boost* ${guildName} kini bertambah menjadi **\`${boostCount}\`**.
24+
- Tuan/Nona resmi diakui sebagai *Bearer of the Flame*.
25+
- Gerbang khusus ⁠<#${BEARER_LOUNGE_CHANNEL}> kini terbuka bagi Tuan/Nona; sebuah ruang kehormatan untuk para penjaga nyala.
26+
27+
Kami sampaikan terima kasih setinggi-tingginya.
28+
Semoga nyala kebaikan ini kembali pada Tuan/Nona
29+
dalam wujud disiplin, keberkahan, dan pertumbuhan.
30+
`,
31+
}
32+
33+
static sayDeeplyThanksTo(member: GuildMember) {
34+
return createEmbed(
35+
this.MSG.Really,
36+
this.MSG.ItMeansALot(member.guild.name, member.id, member.guild.premiumSubscriptionCount ?? 0),
37+
DUMMY.COLOR,
38+
{ text: DUMMY.FOOTER(member.guild.name) },
39+
{
40+
name: member.user.tag,
41+
iconURL: member.user.displayAvatarURL(),
42+
},
43+
member.user.displayAvatarURL({ size: 512 }),
44+
)
45+
}
46+
}

0 commit comments

Comments
 (0)