1
1
from __future__ import annotations
2
2
3
- from functools import lru_cache
4
3
from typing import TYPE_CHECKING , Annotated , NamedTuple , Optional , Union
5
4
6
5
import asyncpg
14
13
get_partial_ticket ,
15
14
safe_content ,
16
15
)
16
+ from libs .utils .checks import bot_check_permissions
17
17
from libs .utils .embeds import Embed , LoggingEmbed
18
18
19
19
from .config import GuildWebhookDispatcher
20
20
21
21
if TYPE_CHECKING :
22
22
from libs .utils import GuildContext , RoboContext
23
+
23
24
from rodhaj import Rodhaj
24
25
25
26
26
- STAFF_ROLE = 1184257456419913798
27
27
TICKET_EMOJI = "\U0001f3ab " # U+1F3AB Ticket
28
28
29
29
@@ -101,15 +101,6 @@ def add_status_checklist(
101
101
) -> StatusChecklist :
102
102
return self .in_progress_tickets .setdefault (author_id , status )
103
103
104
- #### Determining staff
105
-
106
- @lru_cache (maxsize = 64 )
107
- def get_staff (self , guild : discord .Guild ) -> Optional [list [discord .Member ]]:
108
- mod_role = guild .get_role (STAFF_ROLE )
109
- if mod_role is None :
110
- return None
111
- return [member for member in mod_role .members ]
112
-
113
104
### Conditions for closing tickets
114
105
115
106
async def can_close_ticket (self , ctx : RoboContext ):
@@ -128,22 +119,17 @@ async def can_close_ticket(self, ctx: RoboContext):
128
119
return False
129
120
130
121
async def can_admin_close_ticket (self , ctx : RoboContext ) -> bool :
131
- guild_id = self .bot .transprogrammer_guild_id
132
- guild = self .bot .get_guild (guild_id ) or (await self .bot .fetch_guild (guild_id ))
133
- staff_members = self .get_staff (guild )
134
-
135
- if staff_members is None :
136
- return False
137
-
138
- # TODO: Add the hierarchy system here
139
- staff_ids = [member .id for member in staff_members ]
122
+ # More than likely it will be closed through the threads
123
+ # That means, it must be done in a guild. Thus, we know that
124
+ # it will always be discord.Member
125
+ perms = ctx .channel .permissions_for (ctx .author ) # type: ignore
140
126
from_ticket_channel = (
141
127
isinstance (ctx .channel , discord .Thread )
142
128
and ctx .partial_config is not None
143
129
and ctx .channel .parent_id == ctx .partial_config .ticket_channel_id
144
130
)
145
131
146
- if ctx . author . id in staff_ids and from_ticket_channel is True :
132
+ if perms . manage_threads and from_ticket_channel is True :
147
133
return True
148
134
return False
149
135
@@ -319,10 +305,18 @@ def get_solved_tag(
319
305
320
306
### Feature commands
321
307
308
+ # This command requires the manage_threads permissions for the bot
322
309
@is_ticket_or_dm ()
310
+ @bot_check_permissions (manage_threads = True )
311
+ @commands .cooldown (1 , 20 , commands .BucketType .channel )
323
312
@commands .hybrid_command (name = "close" , aliases = ["solved" , "closed" , "resolved" ])
324
313
async def close (self , ctx : RoboContext ) -> None :
325
- """Closes the thread"""
314
+ """Closes a ticket
315
+
316
+ If someone requests to close the ticket
317
+ and has Manage Threads permissions, then they can
318
+ also close the ticket.
319
+ """
326
320
query = """
327
321
DELETE FROM tickets
328
322
WHERE thread_id = $1 AND owner_id = $2;
@@ -356,7 +350,11 @@ async def close(self, ctx: RoboContext) -> None:
356
350
self .get_ticket_owner_id .cache_invalidate (closed_ticket .id )
357
351
await self .notify_finished_ticket (ctx , owner_id )
358
352
353
+ # 10 command invocations per 12 seconds for each member
354
+ # These values should not be tripped unless someone is spamming
355
+ # https://github.com/Rapptz/RoboDanny/blob/rewrite/cogs/mod.py#L524C9-L524C74
359
356
@is_ticket_thread ()
357
+ @commands .cooldown (10 , 12 , commands .BucketType .member )
360
358
@commands .command (name = "reply" , aliases = ["r" ])
361
359
async def reply (
362
360
self , ctx : GuildContext , * , message : Annotated [str , commands .clean_content ]
0 commit comments