55 type ChatInputCommandInteraction ,
66 EmbedBuilder ,
77 GuildMember ,
8+ type Message ,
89 MessageFlags ,
910 PermissionFlagsBits ,
1011 type Role ,
@@ -13,8 +14,8 @@ import {
1314} from 'discord.js' ;
1415import { HOUR , MINUTE , timeToString } from '../../constants/time.js' ;
1516import { config } from '../../env.js' ;
16- import { getPublicChannels } from '../../util/channel.js' ;
1717import { logToChannel } from '../../util/channel-logging.js' ;
18+ import { getPublicChannels } from '../../util/channel.js' ;
1819import { buildCommandString , createCommand } from '../../util/commands.js' ;
1920
2021const DEFAULT_LOOK_BACK_MS = 10 * MINUTE ;
@@ -130,7 +131,7 @@ const getTextChannels = (interaction: ChatInputCommandInteraction) => {
130131 console . error ( 'Interaction is not in a guild' ) ;
131132 return [ ] ;
132133 }
133- const channels = getPublicChannels ( interaction . guild ) . values ( ) ;
134+ const channels = Array . from ( getPublicChannels ( interaction . guild ) . values ( ) ) ;
134135 return [
135136 interaction . channel as TextChannel ,
136137 ...channels . filter ( ( channel ) => channel . id !== interaction . channelId ) ,
@@ -148,26 +149,51 @@ const handleDeleteMessages = async ({
148149} ) => {
149150 let deleted = 0 ;
150151 const failedChannels : string [ ] = [ ] ;
152+
153+ // Collect all target messages from all channels and find the latest timestamp
154+ const channelMessages : Array < {
155+ channel : TextChannel ;
156+ targetMessages : Map < string , Message > ;
157+ } > = [ ] ;
158+ let latestMessageTimestamp = 0 ;
159+
160+ for ( const channel of channels ) {
161+ const targetMessages = new Map < string , Message > ( ) ;
162+
163+ for ( const [ id , message ] of channel . messages . cache ) {
164+ if ( message . author && message . author . id === target . id && message . deletable ) {
165+ targetMessages . set ( id , message ) ;
166+ latestMessageTimestamp = Math . max ( latestMessageTimestamp , message . createdTimestamp ) ;
167+ }
168+ }
169+
170+ if ( targetMessages . size > 0 ) {
171+ channelMessages . push ( { channel, targetMessages } ) ;
172+ }
173+ }
174+
175+ // If no messages found from the target user, return early
176+ if ( latestMessageTimestamp === 0 ) {
177+ return { deleted : 0 , failedChannels : [ ] } ;
178+ }
179+
180+ // Delete messages within the lookback window from the latest message
151181 await Promise . allSettled (
152- channels . map ( async ( channel ) => {
182+ channelMessages . map ( async ( { channel, targetMessages } ) => {
153183 try {
154- const messages = channel . messages . cache ;
155- const targetMessages = messages
156- . filter ( ( message ) => {
157- return (
158- message . author &&
159- message . author . id === target . id &&
160- message . deletable &&
161- Date . now ( ) - message . createdTimestamp < lookBack
162- ) ;
163- } )
164- . map ( ( msg ) => msg . id ) ;
165-
166- if ( targetMessages . length === 0 ) {
184+ const messagesToDelete : string [ ] = [ ] ;
185+
186+ for ( const [ id , message ] of targetMessages ) {
187+ if ( latestMessageTimestamp - message . createdTimestamp < lookBack ) {
188+ messagesToDelete . push ( id ) ;
189+ }
190+ }
191+
192+ if ( messagesToDelete . length === 0 ) {
167193 return ;
168194 }
169- await channel . bulkDelete ( targetMessages , true ) ;
170- deleted += targetMessages . length ;
195+ await channel . bulkDelete ( messagesToDelete , true ) ;
196+ deleted += messagesToDelete . length ;
171197 } catch ( error ) {
172198 console . error ( `Error deleting messages in channel ${ channel . name } :` , error ) ;
173199 failedChannels . push ( channel . id ) ;
0 commit comments