-
Notifications
You must be signed in to change notification settings - Fork 59
/
pruneMessagesCommand.ts
145 lines (135 loc) · 4.63 KB
/
pruneMessagesCommand.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
import {
ApplicationCommandType,
ButtonStyle,
ChannelType,
ComponentType,
DiscordAPIError,
GuildTextBasedChannelTypes,
PermissionsBitField,
TextChannel,
} from 'discord.js'
import { defineCommand } from '@/types/defineCommand'
import { isInArray } from '@/utils/typeGuards'
export const pruneMessagesCommand = defineCommand({
data: {
name: 'Prune messages',
type: ApplicationCommandType.Message,
defaultMemberPermissions: PermissionsBitField.Flags.ManageChannels,
dmPermission: false,
},
ephemeral: true,
execute: async (botContext, interaction) => {
if (!interaction.guild || !interaction.isContextMenuCommand()) return
const { log } = botContext
// Fetch reference message by target id
const message = await interaction.channel?.messages.fetch(
interaction.targetId,
)
// Confirmation banner
await interaction.followUp({
content: `Are you sure you want to prune all messages from **${message?.author.username}**?`,
components: [
{
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.Button,
style: ButtonStyle.Primary,
label: 'Yes',
customId: 'yes',
},
{
type: ComponentType.Button,
style: ButtonStyle.Danger,
label: 'No',
customId: 'no',
},
],
},
],
})
try {
// Await button interaction for confirmation
const buttonInteraction =
await interaction.channel?.awaitMessageComponent({
filter: (index) =>
index.customId === 'yes' || index.customId === 'no',
time: 10_000, // Adjust timeout as needed
})
if (buttonInteraction?.customId === 'no') {
// Reply about the cancel action
await interaction.editReply({
content: `Prune message was canceled`,
components: [],
})
return
}
} catch {
await interaction.editReply({
content: 'Confirmation not received within 10 seconds, cancelling',
components: [],
})
return
}
//Discord expects bot to acknowledge the interaction within 3 seconds so reply something first
await interaction.editReply({
content: 'Processing... Please wait a moment.',
components: [],
})
// Delete message in all channel
let numberDeleted = 0
const { client } = botContext
const selectedChannel: GuildTextBasedChannelTypes[] = [
ChannelType.GuildText,
ChannelType.GuildVoice,
ChannelType.GuildStageVoice,
ChannelType.PublicThread,
]
for (const [channelId, channel] of client.channels.cache) {
// Check if the channel type is in the supported text channel array
if (isInArray(channel.type, selectedChannel)) {
//supportedTextChannel only contains TextChannel,we can cast channel to TextChannel without any issues.
const messages = await (channel as TextChannel).messages.fetch()
let userMessages = messages.filter(
(message_) => message_.author.id === message?.author.id,
)
//Filter messages within 2 weeks and delete it all
const duration =
Date.now() - (14 * 24 * 60 * 60 * 1000 - 60 * 60 * 1000) // reduce by 1 hour
userMessages = userMessages.filter(
(message_) => message_.createdTimestamp > duration,
)
if (userMessages.size > 0) {
try {
await (channel as TextChannel).bulkDelete(userMessages)
log.info(
`Deleted ${userMessages.size} messages from ${
interaction.targetId
} in channel ${(channel as TextChannel).name} (${channelId}).`,
)
numberDeleted += userMessages.size
} catch (error) {
log.error('Error deleting messages:', error)
if (error instanceof DiscordAPIError) {
// Reply about the error
//for error 400 : cant occur because the time period has been set for how many days to delete
await interaction.editReply({
content: `Error deleting messages: ${error.message}`,
components: [],
})
if (error.status === 404) {
return
}
}
}
}
}
}
// Tell the user that the messages were successfully pruned
log.info(`Successfully pruned ${numberDeleted} messages.`)
await interaction.editReply({
content: `Successfully prune messages. Number of messages deleted: ${numberDeleted}`,
components: [],
})
},
})