-
Notifications
You must be signed in to change notification settings - Fork 59
/
nominateCommand.ts
213 lines (197 loc) · 5.94 KB
/
nominateCommand.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import {
ApplicationCommandOptionType,
ApplicationCommandType,
GuildMember,
PermissionsBitField,
Role,
} from 'discord.js'
import { prisma } from '@/prisma'
import { defineCommand } from '@/types/defineCommand'
export const nominateCommand = defineCommand({
data: {
name: 'nominate',
description: 'Nominates a user for a role',
defaultMemberPermissions: PermissionsBitField.Flags.SendMessages,
type: ApplicationCommandType.ChatInput,
options: [
{
name: 'user',
description: 'The user to nominate',
type: ApplicationCommandOptionType.User,
required: true,
},
{
name: 'role',
description: 'The role to nominate the user for',
type: ApplicationCommandOptionType.Role,
required: true,
},
{
name: 'reason',
description: 'The reason for the nomination',
type: ApplicationCommandOptionType.String,
required: true,
},
],
},
disableAutoDeferReply: true,
execute: async (botContext, interaction) => {
if (!interaction.guild || !interaction.isChatInputCommand()) return
if (!interaction.inCachedGuild()) return
// Get the role from the interaction
const role = interaction.options.getRole('role')
if (!role) throw new Error('No role provided')
// Get the actor from the interaction
const actor = interaction.member
if (!actor) throw new Error('No actor found in the interaction')
// Get the user from the interaction
const nominatedUser = interaction.options.getUser('user')
if (!nominatedUser) throw new Error('No user provided')
// Resolve the member from the user
const nominatedMember = await interaction.guild.members.fetch(
nominatedUser.id,
)
// Get the reason from the interaction
const reason =
interaction.options.getString('reason') ?? 'No reason provided'
// Ensure that the role is enabled
const { runtimeConfiguration } = botContext
const config = runtimeConfiguration.data.nominations.enabledRoles.find(
(role_) => role_.roleId === role.id,
)
if (!config) {
await interaction.reply({
content: `The "${role.name}" role is not enabled for nominations.`,
ephemeral: true,
})
return
}
// Ensure that the user who sent the command has the target role
if (!interaction.member?.roles.cache.has(role.id)) {
await interaction.reply({
content: `You must have the "${role.name}" role to nominate someone for it.`,
ephemeral: true,
})
return
}
// Ensure that the user being nominated does not have the target role
if (nominatedMember.roles.cache.has(role.id)) {
await interaction.reply({
content: `The nominated user already has the "${role.name}" role.`,
ephemeral: true,
})
return
}
// Ensure that the actor haven’t already nominated the user
const existingNomination = await prisma.nomination.findFirst({
where: {
userId: actor.id,
nominatedUserId: nominatedUser.id,
roleId: role.id,
},
})
if (existingNomination) {
if (reason === 'cancel') {
await prisma.nomination.delete({
where: {
id: existingNomination.id,
},
})
await interaction.reply({
content: `You have cancelled your nomination of ${nominatedUser} for the "${role.name}" role.`,
ephemeral: true,
})
await updateNominationMessage(
nominatedMember,
role,
config.nominationsChannelId,
)
return
}
await interaction.reply({
content: `You have already nominated ${nominatedUser} for the "${role.name}" role.`,
ephemeral: true,
})
return
}
await interaction.deferReply()
await prisma.nomination.create({
data: {
userId: actor.id,
nominatedUserId: nominatedUser.id,
reason,
roleId: role.id,
},
})
await interaction.editReply({
content:
`${actor} nominated ${nominatedUser} for the "${role.name}" role.\n` +
`Reason: ${reason}`,
})
await updateNominationMessage(
nominatedMember,
role,
config.nominationsChannelId,
)
},
})
async function updateNominationMessage(
nominatedMember: GuildMember,
role: Role,
channelId: string,
) {
// Delete the existing nomination message
const existingNominationMessage = await prisma.nominationMessage.findFirst({
where: {
nominatedUserId: nominatedMember.id,
roleId: role.id,
},
})
if (existingNominationMessage) {
const channel = nominatedMember.guild.channels.cache.get(channelId)
if (channel?.isTextBased()) {
const message = await channel.messages.fetch(
existingNominationMessage.messageId,
)
if (message) {
await message.delete()
}
}
await prisma.nominationMessage.delete({
where: {
id: existingNominationMessage.id,
},
})
}
// Get the nominations for the user
const nominations = await prisma.nomination.findMany({
where: {
nominatedUserId: nominatedMember.id,
roleId: role.id,
},
})
if (nominations.length === 0) {
return
}
// Generate a new message for the nominations
const countPeople =
nominations.length === 1 ? '1 person' : `${nominations.length} people`
const text: string[] = [
`${nominatedMember} has been nominated for the "${role.name}" role by ${countPeople}`,
]
for (const nomination of nominations) {
text.push(`- <@${nomination.userId}>: ${nomination.reason}`)
}
// Send the message
const channel = nominatedMember.guild.channels.cache.get(channelId)
if (channel?.isTextBased()) {
const message = await channel.send(text.join('\n'))
await prisma.nominationMessage.create({
data: {
nominatedUserId: nominatedMember.id,
roleId: role.id,
messageId: message.id,
},
})
}
}