/
Webhook.java
427 lines (393 loc) · 14.9 KB
/
Webhook.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/*
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dv8tion.jda.api.entities;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.entities.channel.unions.IWebhookContainerUnion;
import net.dv8tion.jda.api.managers.WebhookManager;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.regex.Pattern;
/**
* An object representing Webhooks in Discord
*
* @since 3.0
*
* @see TextChannel#retrieveWebhooks()
* @see Guild#retrieveWebhooks()
* @see JDA#retrieveWebhookById(String)
*/
public interface Webhook extends ISnowflake
{
/**
* Pattern for a Webhook URL.
*
* <p><b>Groups</b><br>
* <table>
* <caption style="display: none">Javadoc is stupid, this is not a required tag</caption>
* <tr>
* <th>Index</th>
* <th>Name</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>0</td>
* <td>N/A</td>
* <td>The entire link</td>
* </tr>
* <tr>
* <td>1</td>
* <td>id</td>
* <td>The ID of the webhook</td>
* </tr>
* <tr>
* <td>2</td>
* <td>token</td>
* <td>The token of the webhook</td>
* </tr>
* </table>
*
* You can use the names with {@link java.util.regex.Matcher#group(String) Matcher.group(String)}
* and the index with {@link java.util.regex.Matcher#group(int) Matcher.group(int)}.
*/
Pattern WEBHOOK_URL = Pattern.compile("https?://(?:[^\\s.]+\\.)?discord(?:app)?\\.com/api(?:/v\\d+)?/webhooks/(?<id>\\d+)/(?<token>[^\\s/]+)", Pattern.CASE_INSENSITIVE);
/**
* The JDA instance of this Webhook.
*
* @return The current JDA instance of this Webhook
*/
@Nonnull
JDA getJDA();
/**
* The {@link WebhookType} of this webhook.
* <br>Webhooks of type {@link WebhookType#FOLLOWER} don't have a token.
*
* @return The {@link WebhookType}
*/
@Nonnull
WebhookType getType();
/**
* Whether this webhook cannot provide {@link #getChannel()} and {@link #getGuild()}.
* <br>This means that the webhook is not local to this shard's cache and cannot provide full channel/guild references.
*
* @return True, if {@link #getChannel()} and {@link #getGuild()} would throw
*/
boolean isPartial();
/**
* The {@link net.dv8tion.jda.api.entities.Guild Guild} instance
* for this Webhook.
* <br>This is a shortcut for <code>{@link #getChannel()}.getGuild()</code>.
*
* @throws IllegalStateException
* If this webhooks {@link #isPartial() is partial}
*
* @return The current Guild of this Webhook
*/
@Nonnull
Guild getGuild();
/**
* The {@link net.dv8tion.jda.api.entities.channel.attribute.IWebhookContainer channel} instance this Webhook is attached to.
* Webhooks are created on specific channels so that they can interact with that channel.
* With regard to {@link ThreadChannel threads}, Webhooks are attached to their {@link net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer parent channel}
* and then the Webhooks can post to the {@link net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer parent} <i>and</i> the {@link ThreadChannel thread} too.
*
* @throws IllegalStateException
* If this webhooks {@link #isPartial() is partial}
*
* @return The current {@link net.dv8tion.jda.api.entities.channel.attribute.IWebhookContainer channel} that this webhook is attached to.
*/
@Nonnull
//TODO-v5: Should we introduce StandardIWebhookContainer? (IWebhookContainer + StandardGuildChannel)
IWebhookContainerUnion getChannel();
/**
* The owner of this Webhook. This will be null for some Webhooks, such as those retrieved from Audit Logs.
* <br>This requires the member to be cached. You can use {@link #getOwnerAsUser()} to get a reference to the user instead.
*
* @return Possibly-null {@link net.dv8tion.jda.api.entities.Member Member} instance
* representing the owner of this Webhook.
*/
@Nullable
Member getOwner();
/**
* The owner of this Webhook. This will be null for some Webhooks, such as those retrieved from Audit Logs.
* <br>This can be non-null even when {@link #getOwner()} is null. {@link #getOwner()} requires the webhook to be local to this shard and in cache.
*
* @return Possibly-null {@link net.dv8tion.jda.api.entities.User User} instance
* representing the owner of this Webhook.
*/
@Nullable
User getOwnerAsUser();
/**
* The default User for this Webhook.
*
* <p>The {@link net.dv8tion.jda.api.entities.User User} returned is always fake and cannot be interacted with.
* <br>This User is used for all messages posted to the Webhook route (found in {@link #getUrl()}),
* it holds the default references for the message authors of messages by this Webhook.
*
* <p>When {@code POST}ing to a Webhook route the name/avatar of this default user
* can be overridden.
*
* @return A fake {@link net.dv8tion.jda.api.entities.User User} instance
* representing the default webhook user.
*
* @see <a href="https://discord.com/developers/docs/resources/webhook#execute-webhook">Execute Webhook Docs</a>
*/
@Nonnull
User getDefaultUser();
/**
* The name of this Webhook.
* <br>This will be displayed by default as the author name
* of every message by this Webhook.
*
* <p>This is a shortcut for <code>{@link #getDefaultUser()}.getName()</code>.
*
* @return The name of this Webhook
*/
@Nonnull
String getName();
/**
* The execute token for this Webhook.
* <br>This can be used to modify/delete/execute
* this Webhook.
*
* <p><b>Note: Some Webhooks, such as those retrieved from Audit Logs, do not contain a token</b>
*
* @return The execute token for this Webhook
*/
@Nullable
String getToken();
/**
* The {@code POST} route for this Webhook.
* <br>This contains the {@link #getToken() token} and {@link #getId() id}
* of this Webhook. Some Webhooks without tokens (such as those retrieved from Audit Logs)
* will return a URL without a token.
*
* <p>The route returned by this method does not need permission checks
* to be executed.
* <br>It is implied that Webhook messages always have all permissions
* including {@link net.dv8tion.jda.api.Permission#MESSAGE_MENTION_EVERYONE mentioning everyone}.
*
* <p>Webhook executions are limited with 5 requests per second.
* The response contains rate limit headers that should be handled
* by execution frameworks. (<a href="https://discord.com/developers/docs/topics/rate-limits">Learn More</a>)
*
* @return The execution route for this Webhook.
*/
@Nonnull
String getUrl();
/**
* The source channel for a Webhook of type {@link WebhookType#FOLLOWER FOLLOWER}.
*
* @return {@link ChannelReference}
*/
@Nullable
ChannelReference getSourceChannel();
/**
* The source guild for a Webhook of type {@link WebhookType#FOLLOWER FOLLOWER}.
*
* @return {@link GuildReference}
*/
@Nullable
GuildReference getSourceGuild();
/**
* Deletes this Webhook.
*
* <p>The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
* <br>The delete was attempted after the account lost permission to view the channel.</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_PERMISSIONS MISSING_PERMISSIONS}
* <br>The delete was attempted after the account lost {@link net.dv8tion.jda.api.Permission#MANAGE_WEBHOOKS Permission.MANAGE_WEBHOOKS} in
* the channel.</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_WEBHOOK UNKNOWN_WEBHOOK}
* <br>The delete was attempted after the Webhook had already been deleted.</li>
* </ul>
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the Webhook does not have a token, such as the Webhooks retrieved from Audit Logs and the currently
* logged in account does not have {@link net.dv8tion.jda.api.Permission#MANAGE_WEBHOOKS} in this channel.
*
* @return {@link net.dv8tion.jda.api.requests.restaction.AuditableRestAction AuditableRestAction}
* <br>The rest action to delete this Webhook.
*/
@Nonnull
@CheckReturnValue
AuditableRestAction<Void> delete();
/**
* Deletes this Webhook.
*
* <p>The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
* <br>The delete was attempted after the account lost permission to view the channel.</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_PERMISSIONS MISSING_PERMISSIONS}
* <br>The delete was attempted after the account lost {@link net.dv8tion.jda.api.Permission#MANAGE_WEBHOOKS Permission.MANAGE_WEBHOOKS} in
* the channel.</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_WEBHOOK UNKNOWN_WEBHOOK}
* <br>The delete was attempted after the Webhook had already been deleted.</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#INVALID_WEBHOOK_TOKEN INVALID_WEBHOOK_TOKEN}
* <br>If the provided webhook token is not valid.</li>
* </ul>
*
* @param token
* The webhook token (this is not the bot authorization token!)
*
* @throws IllegalArgumentException
* If the provided token is null
*
* @return {@link net.dv8tion.jda.api.requests.restaction.AuditableRestAction AuditableRestAction}
* <br>The rest action to delete this Webhook.
*
* @since 4.0.0
*/
@Nonnull
@CheckReturnValue
AuditableRestAction<Void> delete(@Nonnull String token);
/**
* The {@link WebhookManager WebhookManager} for this Webhook.
* <br>You can modify multiple fields in one request by chaining setters before calling {@link net.dv8tion.jda.api.requests.RestAction#queue() RestAction.queue()}.
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the currently logged in account does not have {@link net.dv8tion.jda.api.Permission#MANAGE_WEBHOOKS Permission.MANAGE_WEBHOOKS}
*
* @return The {@link WebhookManager WebhookManager} for this Webhook
*/
@Nonnull
WebhookManager getManager();
/**
* Partial Webhook which can be {@link #resolve() resolved} to a {@link Webhook}.
*
* @see #resolve()
*/
class WebhookReference implements ISnowflake
{
private final JDA api;
private final long webhookId, channelId;
public WebhookReference(JDA api, long webhookId, long channelId)
{
this.api = api;
this.webhookId = webhookId;
this.channelId = channelId;
}
@Override
public long getIdLong()
{
return webhookId;
}
/**
* The ID for the channel this webhook belongs to
*
* @return The ID for the channel this webhook belongs to
*/
@Nonnull
public String getChannelId()
{
return Long.toUnsignedString(channelId);
}
/**
* The ID for the channel this webhook belongs to
*
* @return The ID for the channel this webhook belongs to
*/
public long getChannelIdLong()
{
return channelId;
}
/**
* Resolves this reference to a {@link Webhook} instance.
* <br>The resulting instance may not provide a {@link #getChannel()} and {@link #getGuild()} due to API limitation.
*
* <p>The resulting webhook can also not be executed because the API does not provide a token.
*
* @return {@link RestAction} - Type: {@link Webhook}
*/
@Nonnull
@CheckReturnValue
public RestAction<Webhook> resolve()
{
Route.CompiledRoute route = Route.Webhooks.GET_WEBHOOK.compile(getId());
return new RestActionImpl<>(api, route,
(response, request) -> request.getJDA().getEntityBuilder().createWebhook(response.getObject(), true));
}
}
/**
* Partial Channel which references the source channel for a follower webhook.
*/
class ChannelReference implements ISnowflake
{
private final long id;
private final String name;
public ChannelReference(long id, String name)
{
this.id = id;
this.name = name;
}
@Override
public long getIdLong()
{
return id;
}
/**
* The source channel's name
*
* @return The channel name
*/
@Nonnull
public String getName()
{
return name;
}
}
/**
* Partial Guild which references the source guild for a follower webhook.
*/
class GuildReference implements ISnowflake
{
private final long id;
private final String name;
public GuildReference(long id, String name)
{
this.id = id;
this.name = name;
}
@Override
public long getIdLong()
{
return id;
}
/**
* The source guild's name
*
* @return The guild name
*/
@Nonnull
public String getName()
{
return name;
}
}
}