11"""Contains cog classes for any stats interactions."""
22
33import math
4- import re
54from typing import TYPE_CHECKING
65
76import discord
@@ -83,32 +82,64 @@ async def channel_stats(
8382 The "channel_stats" command sends a graph of the stats about messages sent in the given
8483 channel.
8584 """
86- # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent
87- main_guild : discord .Guild = self .bot .main_guild
85+ if not ctx .channel or not isinstance (
86+ ctx .channel , (discord .TextChannel , discord .DMChannel )
87+ ):
88+ await self .command_send_error (
89+ ctx ,
90+ message = "Channel statistics cannot be sent in this channel." ,
91+ )
92+ return
8893
89- channel_id : int = ctx . channel_id
94+ stats_channel : discord . TextChannel | None
9095
91- if str_channel_id :
92- if not re . fullmatch ( r"\A\d{17,20}\Z" , str_channel_id ):
96+ if not str_channel_id :
97+ if not isinstance ( ctx . channel , discord . TextChannel ):
9398 await self .command_send_error (
94- ctx , message = f"{ str_channel_id !r} is not a valid channel ID."
99+ ctx ,
100+ message = (
101+ "User did not provide a channel ID and the interaction channel "
102+ "is not a text channel."
103+ ),
95104 )
96105 return
106+ stats_channel = ctx .channel
97107
98- channel_id = int (str_channel_id )
108+ if not stats_channel :
109+ try :
110+ channel_id : int = int (str_channel_id )
111+ except ValueError :
112+ await self .command_send_error (
113+ ctx ,
114+ message = "The provided channel ID was not a valid integer." ,
115+ )
116+ return
99117
100- channel : discord .TextChannel | None = discord .utils .get (
101- main_guild .text_channels , id = channel_id
102- )
103- if not channel :
104- await self .command_send_error (
105- ctx , message = f"Text channel with ID { str (channel_id )!r} does not exist."
106- )
107- return
118+ result_channel = ctx .bot .get_channel (channel_id )
119+ if not result_channel :
120+ await self .command_send_error (
121+ ctx ,
122+ message = "The provided channel ID was not valid or could not be found." ,
123+ )
124+ return
125+
126+ if not isinstance (result_channel , discord .TextChannel ):
127+ await self .command_send_error (
128+ ctx ,
129+ message = (
130+ "The provided channel ID relates to a channel type "
131+ "that is not supported."
132+ ),
133+ )
134+ return
135+
136+ stats_channel = result_channel
108137
109138 await ctx .defer (ephemeral = True )
110139
111- message_counts : Mapping [str , int ] = await get_channel_message_counts (channel = channel )
140+ message_counts : Mapping [str , int ] = await get_channel_message_counts (
141+ channel = stats_channel
142+ )
112143
113144 if math .ceil (max (message_counts .values ()) / 15 ) < 1 :
114145 await self .command_send_error (
@@ -128,11 +159,11 @@ async def channel_stats(
128159 amount_of_time_formatter (settings ["STATISTICS_DAYS" ].days , "day" )
129160 } )"""
130161 ),
131- title = f"Most Active Roles in #{ channel .name } " ,
132- filename = f"{ channel .name } _channel_stats.png" ,
162+ title = f"Most Active Roles in #{ stats_channel .name } " ,
163+ filename = f"{ stats_channel .name } _channel_stats.png" ,
133164 description = (
134165 "Bar chart of the number of messages "
135- f"sent by different roles in { channel .mention } ."
166+ f"sent by different roles in { stats_channel .mention } ."
136167 ),
137168 extra_text = (
138169 "Messages sent by members with multiple roles are counted once "
@@ -157,6 +188,26 @@ async def server_stats(self, ctx: "TeXBotApplicationContext") -> None:
157188 main_guild : discord .Guild = self .bot .main_guild
158189 guest_role : discord .Role = await self .bot .guest_role
159190
191+ if not ctx .channel :
192+ await self .command_send_error (
193+ ctx ,
194+ message = (
195+ "Interaction channel was None while attempting to send left member stats."
196+ ),
197+ )
198+ return
199+
200+ if isinstance (
201+ ctx .channel , (discord .VoiceChannel , discord .ForumChannel , discord .CategoryChannel )
202+ ):
203+ await self .command_send_error (
204+ ctx ,
205+ message = (
206+ "Left member stats cannot be sent in a voice, forum, or category channel."
207+ ),
208+ )
209+ return
210+
160211 await ctx .defer (ephemeral = True )
161212
162213 message_counts : Mapping [str , Mapping [str , int ]] = await get_server_message_counts (
@@ -248,6 +299,26 @@ async def user_stats(self, ctx: "TeXBotApplicationContext") -> None:
248299 )
249300 return
250301
302+ if not ctx .channel :
303+ await self .command_send_error (
304+ ctx ,
305+ message = (
306+ "Interaction channel was None while attempting to send left member stats."
307+ ),
308+ )
309+ return
310+
311+ if isinstance (
312+ ctx .channel , (discord .VoiceChannel , discord .ForumChannel , discord .CategoryChannel )
313+ ):
314+ await self .command_send_error (
315+ ctx ,
316+ message = (
317+ "Left member stats cannot be sent in a voice, forum, or category channel."
318+ ),
319+ )
320+ return
321+
251322 await ctx .defer (ephemeral = True )
252323
253324 message_counts : dict [str , int ] = {"Total" : 0 }
@@ -314,6 +385,26 @@ async def left_member_stats(self, ctx: "TeXBotApplicationContext") -> None:
314385 # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent
315386 main_guild : discord .Guild = self .bot .main_guild
316387
388+ if not ctx .channel :
389+ await self .command_send_error (
390+ ctx ,
391+ message = (
392+ "Interaction channel was None while attempting to send left member stats."
393+ ),
394+ )
395+ return
396+
397+ if isinstance (
398+ ctx .channel , (discord .VoiceChannel , discord .ForumChannel , discord .CategoryChannel )
399+ ):
400+ await self .command_send_error (
401+ ctx ,
402+ message = (
403+ "Left member stats cannot be sent in a voice, forum, or category channel."
404+ ),
405+ )
406+ return
407+
317408 await ctx .defer (ephemeral = True )
318409
319410 left_member_counts : dict [str , int ] = {
0 commit comments