@@ -22,10 +22,12 @@ class SlashContext:
22
22
:ivar subcommand_group: Subcommand group of the command.
23
23
:ivar interaction_id: Interaction ID of the command message.
24
24
:ivar command_id: ID of the command.
25
- :ivar _http: :class:`.http.SlashCommandRequest` of the client.
26
25
:ivar bot: discord.py client.
27
- :ivar logger: Logger instance.
28
- :ivar sent: Whether you sent the initial response.
26
+ :ivar _http: :class:`.http.SlashCommandRequest` of the client.
27
+ :ivar _logger: Logger instance.
28
+ :ivar deffered: Whether the command is current deffered (loading state)
29
+ :ivar _deffered_hidden: Internal var to check that state stays the same
30
+ :ivar responded: Whether you have responded with a message to the interaction.
29
31
:ivar guild_id: Guild ID of the command message. If the command was invoked in DM, then it is ``None``
30
32
:ivar author_id: User ID representing author of the command message.
31
33
:ivar channel_id: Channel ID representing channel of the command message.
@@ -46,8 +48,10 @@ def __init__(self,
46
48
self .command_id = _json ["data" ]["id" ]
47
49
self ._http = _http
48
50
self .bot = _discord
49
- self .logger = logger
50
- self .sent = False
51
+ self ._logger = logger
52
+ self .deffered = False
53
+ self .responded = False
54
+ self ._deffered_hidden = False # To check if the patch to the deffered response matches
51
55
self .guild_id = int (_json ["guild_id" ]) if "guild_id" in _json .keys () else None
52
56
self .author_id = int (_json ["member" ]["user" ]["id" ] if "member" in _json .keys () else _json ["user" ]["id" ])
53
57
self .channel_id = int (_json ["channel_id" ])
@@ -76,39 +80,20 @@ def channel(self) -> typing.Optional[typing.Union[discord.TextChannel, discord.D
76
80
"""
77
81
return self .bot .get_channel (self .channel_id )
78
82
79
- async def respond (self , eat : bool = False ):
83
+ async def defer (self , hidden : bool = False ):
80
84
"""
81
- Sends command invoke response.\n
82
- You should call this first.
85
+ 'Deferes' the response, showing a loading state to the user
83
86
84
- .. note::
85
- - If `eat` is ``False``, there is a chance that ``message`` variable is present.
86
- - While it is recommended to be manually called, this will still be automatically called
87
- if this isn't called but :meth:`.send()` is called.
88
-
89
- :param eat: Whether to eat user's input. Default ``False``.
87
+ :param hidden: Whether the deffered response should be ephemeral . Default ``False``.
90
88
"""
91
- base = {"type" : 2 if eat else 5 }
92
- _task = self .bot .loop .create_task (self ._http .post (base , self .interaction_id , self .__token , True ))
93
- self .sent = True
94
- if not eat and (not self .guild_id or (self .channel and self .channel .permissions_for (self .guild .me ).view_channel )):
95
- with suppress (asyncio .TimeoutError ):
96
- def check (message : discord .Message ):
97
- user_id = self .author_id
98
- is_author = message .author .id == user_id
99
- channel_id = self .channel_id
100
- is_channel = channel_id == message .channel .id
101
- is_user_input = message .type == 20
102
- is_correct_command = message .content .startswith (f"</{ self .name } :{ self .command_id } >" )
103
- return is_author and is_channel and is_user_input and is_correct_command
104
-
105
- self .message = await self .bot .wait_for ("message" , timeout = 3 , check = check )
106
- await _task
107
-
108
- @property
109
- def ack (self ):
110
- """Alias of :meth:`.respond`."""
111
- return self .respond
89
+ if self .deffered or self .responded :
90
+ raise error .AlreadyResponded ("You have already responded to this command!" )
91
+ base = {"type" : 5 }
92
+ if hidden :
93
+ base ["data" ] = {"flags" : 64 }
94
+ self ._deffered_hidden = True
95
+ await self ._http .post_initial_response (base , self .interaction_id , self .__token )
96
+ self .deffered = True
112
97
113
98
async def send (self ,
114
99
content : str = "" , * ,
@@ -129,6 +114,7 @@ async def send(self,
129
114
.. warning::
130
115
- Since Release 1.0.9, this is completely changed. If you are migrating from older version, please make sure to fix the usage.
131
116
- You can't use both ``embed`` and ``embeds`` at the same time, also applies to ``file`` and ``files``.
117
+ - You cannot send files in the initial response
132
118
133
119
:param content: Content of the response.
134
120
:type content: str
@@ -150,15 +136,6 @@ async def send(self,
150
136
:type delete_after: float
151
137
:return: Union[discord.Message, dict]
152
138
"""
153
- if isinstance (content , int ) and 2 <= content <= 5 :
154
- raise error .IncorrectFormat ("`.send` Method is rewritten at Release 1.0.9. Please read the docs and fix all the usages." )
155
- if not self .sent :
156
- self .logger .info (f"At command `{ self .name } `: It is recommended to call `.respond()` first!" )
157
- await self .respond (eat = hidden )
158
- if hidden :
159
- if embeds or embed or files or file :
160
- self .logger .warning ("Embed/File is not supported for `hidden`!" )
161
- return await self .send_hidden (content )
162
139
if embed and embeds :
163
140
raise error .IncorrectFormat ("You can't use both `embed` and `embeds`!" )
164
141
if embed :
@@ -172,6 +149,8 @@ async def send(self,
172
149
raise error .IncorrectFormat ("You can't use both `file` and `files`!" )
173
150
if file :
174
151
files = [file ]
152
+ if delete_after and hidden :
153
+ raise error .IncorrectFormat ("You can't delete a hidden message!" )
175
154
176
155
base = {
177
156
"content" : content ,
@@ -180,30 +159,47 @@ async def send(self,
180
159
"allowed_mentions" : allowed_mentions .to_dict () if allowed_mentions
181
160
else self .bot .allowed_mentions .to_dict () if self .bot .allowed_mentions else {}
182
161
}
183
-
184
- resp = await self ._http .post (base , self .interaction_id , self .__token , files = files )
185
- smsg = model .SlashMessage (state = self .bot ._connection ,
186
- data = resp ,
187
- channel = self .channel or discord .Object (id = self .channel_id ),
188
- _http = self ._http ,
189
- interaction_token = self .__token )
190
- if delete_after :
191
- self .bot .loop .create_task (smsg .delete (delay = delete_after ))
192
- return smsg
193
-
194
- def send_hidden (self , content : str = "" ):
195
- """
196
- Sends hidden response.\n
197
- This is automatically used if you pass ``hidden=True`` at :meth:`.send`.
198
-
199
- .. note::
200
- This is not intended to be manually called. Please use :meth:`.send` instead.
201
-
202
- :param content: Message content.
203
- :return: Coroutine
204
- """
205
- base = {
206
- "content" : content ,
207
- "flags" : 64
208
- }
209
- return self ._http .post (base , self .interaction_id , self .__token )
162
+ if hidden :
163
+ if embeds or files :
164
+ self ._logger .warning ("Embed/File is not supported for `hidden`!" )
165
+ base ["flags" ] = 64
166
+
167
+ initial_message = False
168
+ if not self .responded :
169
+ initial_message = True
170
+ if files :
171
+ raise error .IncorrectFormat ("You cannot send files in the initial response!" )
172
+ if self .deffered :
173
+ if self ._deffered_hidden != hidden :
174
+ self ._logger .warning (
175
+ "Deffered response might not be what you set it to! (hidden / visible) "
176
+ "This is because it was deffered in a different state"
177
+ )
178
+ resp = await self ._http .edit (base , self .__token )
179
+ self .deffered = False
180
+ else :
181
+ json_data = {
182
+ "type" : 4 ,
183
+ "data" : base
184
+ }
185
+ await self ._http .post_initial_response (json_data , self .interaction_id , self .__token )
186
+ if not hidden :
187
+ resp = await self ._http .edit ({}, self .__token )
188
+ else :
189
+ resp = {}
190
+ self .responded = True
191
+ else :
192
+ resp = await self ._http .post_followup (base , self .__token , files = files )
193
+ if not hidden :
194
+ smsg = model .SlashMessage (state = self .bot ._connection ,
195
+ data = resp ,
196
+ channel = self .channel or discord .Object (id = self .channel_id ),
197
+ _http = self ._http ,
198
+ interaction_token = self .__token )
199
+ if delete_after :
200
+ self .bot .loop .create_task (smsg .delete (delay = delete_after ))
201
+ if initial_message :
202
+ self .message = smsg
203
+ return smsg
204
+ else :
205
+ return resp
0 commit comments