1
+ from .slash .http import ModifiedSlashState
1
2
from .errors import InvalidEvent , OutOfValidRange , WrongType
2
3
from .slash .errors import AlreadyDeferred , EphemeralDeletion
3
- from .slash . types import ContextCommand , OptionType , SlashCommand , SlashOption , SlashPermission , SlashSubcommand
4
- from .tools import MISSING , setup_logger , _none
4
+ from .tools import MISSING , setup_logger , _none , get , _default
5
+ from .slash . types import ContextCommand , SlashCommand , SlashOption , SlashPermission , SlashSubcommand
5
6
from .http import BetterRoute , jsonifyMessage , send_files
6
- from .components import ActionRow , Button , Component , LinkButton , SelectMenu , SelectOption , UseableComponent , make_component
7
+ from .components import ActionRow , Button , LinkButton , SelectMenu , SelectOption , UseableComponent , make_component
7
8
8
9
import discord
9
10
from discord .ext .commands import Bot
10
11
from discord .errors import HTTPException
11
12
from discord .state import ConnectionState
12
13
13
- from typing import List , Union , Dict
14
+ from typing import Any , List , Union , Dict
14
15
try :
15
16
from typing import Literal
16
17
except ImportError :
20
21
21
22
22
23
class InteractionType :
23
- PING = Ping = 1
24
- APPLICATION_COMMAND = Command = 2
25
- MESSAGE_COMPONENT = Component = 3
24
+ PING = Ping = 1
25
+ APPLICATION_COMMAND = Command = 2
26
+ MESSAGE_COMPONENT = Component = 3
27
+ APPLICATION_COMMAND_AUTOCOMPLETE = Autocomplete = 4
26
28
27
29
class Interaction ():
28
30
def __init__ (self , state , data , user = None , message = None ) -> None :
29
- self ._state : ConnectionState = state
31
+ self ._state : ModifiedSlashState = state
30
32
31
33
self .deferred : bool = False
32
34
self .responded : bool = False
@@ -88,13 +90,12 @@ async def defer(self, hidden=False):
88
90
logging .error (AlreadyDeferred ())
89
91
return
90
92
91
- body = {"type" : 5 }
92
-
93
+ payload = None
93
94
if hidden is True :
94
- body [ "data" ] = {"flags" : 64 }
95
+ payload = {"flags" : 64 }
95
96
self ._deferred_hidden = True
96
97
97
- await self ._state .http . request ( BetterRoute ( "POST" , f'/interactions/ { self .id } / { self .token } /callback' ), json = body )
98
+ await self ._state .slash_http . respond_to ( self .id , self .token , 5 , payload )
98
99
self .deferred = True
99
100
100
101
async def respond (self , content = MISSING , * , tts = False , embed = MISSING , embeds = MISSING , file = MISSING , files = MISSING , nonce = MISSING ,
@@ -141,10 +142,7 @@ async def respond(self, content=MISSING, *, tts=False, embed=MISSING, embeds=MIS
141
142
"""
142
143
if ninja_mode is True or all (y in [MISSING , False ] for x , y in locals ().items () if x not in ["self" ]):
143
144
try :
144
- route = BetterRoute ("POST" , f'/interactions/{ self .id } /{ self .token } /callback' )
145
- r = await self ._state .http .request (route , json = {
146
- "type" : 6
147
- })
145
+ await self ._state .slash_http .respond_to (self .id , self .token , 6 )
148
146
return
149
147
except HTTPException as x :
150
148
if "value must be one of (4, 5)" in str (x ).lower ():
@@ -169,49 +167,34 @@ async def respond(self, content=MISSING, *, tts=False, embed=MISSING, embeds=MIS
169
167
170
168
171
169
r = None
172
- if not _none ( delete_after ) and hide_message is True :
170
+ if delete_after is not MISSING and hide_message is True :
173
171
raise EphemeralDeletion ()
174
172
175
173
if hide_message :
176
174
payload ["flags" ] = 64
177
-
178
- if (file is not MISSING or files is not MISSING ) and self .deferred is False :
179
- await self .defer (hidden = hide_message )
180
175
181
- if self .deferred is False and hide_message is False :
182
- route = BetterRoute ("POST" , f'/interactions/{ self .id } /{ self .token } /callback' )
183
- r = await self ._state .http .request (route , json = {
184
- "type" : 4 ,
185
- "data" : payload
186
- })
187
- else :
188
- if self .deferred is False and hide_message is True :
189
- await self .defer (hide_message )
176
+ if self .deferred :
190
177
route = BetterRoute ("PATCH" , f'/webhooks/{ self .application_id } /{ self .token } /messages/@original' )
191
178
if file is not MISSING or files is not MISSING :
192
- r = await send_files (route = route , files = [file ] if files is MISSING else files , payload = payload , http = self ._state .http )
179
+ await send_files (route = route , files = [file ] if files is MISSING else files , payload = payload , http = self ._state .http )
193
180
else :
194
- r = await self ._state .http .request (route , json = payload )
181
+ await self ._state .http .request (route , json = payload )
182
+ else :
183
+ await self ._state .slash_http .respond_to (self .id , self .token , 4 , payload , files = [file ] if file is not MISSING else _default (None , files ))
195
184
self .responded = True
196
185
186
+ r = await self ._state .http .request (BetterRoute ("GET" , f"/webhooks/{ self .application_id } /{ self .token } /messages/@original" ))
197
187
if hide_message is True :
198
- msg = EphemeralMessage (state = self ._state , channel = self ._state .get_channel (int (r ["channel_id" ])), data = r , application_id = self .application_id , token = self .token )
199
- if listener is not MISSING :
200
- listener ._start (msg )
201
- return msg
202
-
203
-
204
- if not hide_message :
205
- responseMSG = await self ._state .http .request (BetterRoute ("GET" , f"/webhooks/{ self .application_id } /{ self .token } /messages/@original" ))
206
- msg = await getMessage (self ._state , data = responseMSG , response = False )
207
- if not _none (delete_after ):
208
- await msg .delete (delete_after )
209
- if listener is not MISSING :
210
- listener ._start (msg )
211
- return msg
212
-
188
+ msg = EphemeralMessage (state = self ._state , channel = self .channel , data = r , application_id = self .application_id , token = self .token )
189
+ else :
190
+ msg = await getMessage (self ._state , data = r , response = False )
191
+ if listener is not MISSING :
192
+ listener ._start (msg )
193
+ if not _none (delete_after ):
194
+ await msg .delete (delete_after )
195
+ return msg
213
196
async def send (self , content = None , * , tts = False , embed = MISSING , embeds = MISSING , file = MISSING , files = MISSING , nonce = MISSING ,
214
- allowed_mentions = MISSING , mention_author = MISSING , components = MISSING , listener = MISSING , hidden = False ) -> Union ['Message' , 'EphemeralMessage' ]:
197
+ allowed_mentions = MISSING , mention_author = MISSING , components = MISSING , delete_after = MISSING , listener = MISSING , hidden = False ) -> Union ['Message' , 'EphemeralMessage' ]:
215
198
"""
216
199
Sends a message to the interaction using a webhook
217
200
@@ -237,6 +220,8 @@ async def send(self, content=None, *, tts=False, embed=MISSING, embeds=MISSING,
237
220
Whether the author should be mentioned
238
221
components: List[:class:`~Button` | :class:`~LinkButton` | :class:`~SelectMenu`]
239
222
A list of message components to be included
223
+ delete_after: :class:`float`
224
+ After how many seconds the message should be deleted, only works for non-hiddend messages; default MISSING
240
225
listener: :class:`Listener`
241
226
A component-listener for this message
242
227
hidden: :class:`bool`
@@ -250,7 +235,7 @@ async def send(self, content=None, *, tts=False, embed=MISSING, embeds=MISSING,
250
235
:type: :class:`~Message` | :class:`EphemeralMessage`
251
236
"""
252
237
if self .responded is False :
253
- return await self .respond (content = content , tts = tts , embed = embed , embeds = embeds , file = file , files = files , nonce = nonce , allowed_mentions = allowed_mentions , mention_author = mention_author , components = components , listener = listener , hidden = hidden )
238
+ return await self .respond (content = content , tts = tts , embed = embed , embeds = embeds , file = file , files = files , nonce = nonce , allowed_mentions = allowed_mentions , mention_author = mention_author , components = components , delete_after = delete_after , listener = listener , hidden = hidden )
254
239
255
240
if components is MISSING and listener is not MISSING :
256
241
components = listener .to_components ()
@@ -260,25 +245,48 @@ async def send(self, content=None, *, tts=False, embed=MISSING, embeds=MISSING,
260
245
payload ["flags" ] = 64
261
246
262
247
route = BetterRoute ("POST" , f'/webhooks/{ self .application_id } /{ self .token } ' )
263
-
264
248
if file is not MISSING or files is not MISSING :
265
249
r = await send_files (route = route , files = [file ] if files is MISSING else files , payload = payload , http = self ._state .http )
266
250
else :
267
251
r = await self ._state .http .request (route , json = payload )
268
252
269
253
if hidden is True :
270
- msg = EphemeralMessage (state = self ._state , channel = self ._state .get_channel (r ["channel_id" ]), data = r , application_id = self .application_id , token = self .token )
271
- if listener is not MISSING :
272
- listener . _start ( msg )
273
- msg = await getMessage ( self . _state , r , response = False )
274
-
254
+ msg = EphemeralMessage (state = self ._state , channel = self ._state .get_channel (int ( r ["channel_id" ]) ), data = r , application_id = self .application_id , token = self .token )
255
+ else :
256
+ msg = await getMessage ( self . _state , r , response = False )
257
+ if delete_after is not MISSING :
258
+ await msg . delete ( delete_after )
275
259
if listener is not MISSING :
276
260
listener ._start (msg )
261
+ print (msg )
277
262
return msg
278
263
def _handle_auto_defer (self , auto_defer ):
279
264
self .deferred = auto_defer [0 ]
280
265
self ._deferred_hidden = auto_defer [1 ]
281
266
267
+ class ChoiceGeneratorContext (Interaction ):
268
+ """A class for information that could be needed for generating choices for autocomopletion"""
269
+ def __init__ (self , command , state , data , options , user = None ) -> None :
270
+ Interaction .__init__ (self , state , data , user = user )
271
+ self .focused_option : dict = options [get (options , check = lambda x : options [x ].get ("focused" , False ))]
272
+ """The option for which the choices should be generated"""
273
+ self .value_query : Union [str , int ] = self .focused_option ["value" ]
274
+ """The current 'query' for the value"""
275
+ self .selected_options : Dict [str , Any ] = {options [x ]["name" ]: options [x ]["value" ] for x in options }
276
+ """All the options that were already selected"""
277
+ self .command : Union [SlashedCommand , SlashedCommand , SlashedContext ] = command
278
+ """The slash command for which the choices should be generated"""
279
+
280
+ async def defer (self , * args , ** kwargs ):
281
+ """Cannot defer this type of interaction"""
282
+ raise NotImplementedError ()
283
+ async def respond (self , * args , ** kwargs ):
284
+ """Cannot rerspond to this type of interaction"""
285
+ raise NotImplementedError ()
286
+ async def send (self , * args , ** kwargs ):
287
+ """Cannot send followup message to this type of interaction"""
288
+ raise NotImplementedError ()
289
+
282
290
class ComponentContext (Interaction , UseableComponent ):
283
291
"""A received component"""
284
292
def __init__ (self , state , data , user , message ) -> None :
@@ -370,6 +378,8 @@ async def getMessage(state: ConnectionState, data, response=True):
370
378
The User which pressed the button
371
379
response: :class:`bool`
372
380
Whether the Message returned should be of type `ResponseMessage` or `Message`
381
+ channel: :class:`discord.Messageable`
382
+ An alternative channel that will be used when no channel was found
373
383
374
384
Returns
375
385
-------
@@ -486,7 +496,7 @@ async def edit(self, content=MISSING, *, embed=MISSING, embeds=MISSING, attachme
486
496
data = await self ._state .http .edit_message (self .channel .id , self .id , ** payload )
487
497
self ._update (data )
488
498
489
- if not _none ( delete_after ) :
499
+ if delete_after is not MISSING :
490
500
await self .delete (delay = delete_after )
491
501
492
502
async def disable_action_row (self , row , disable = True ):
0 commit comments