Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow null user_id and provide partial Webhooks #675

Merged
merged 5 commits into from
May 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 26 additions & 3 deletions src/main/java/net/dv8tion/jda/core/audit/AuditLogEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@
import net.dv8tion.jda.core.entities.Guild;
import net.dv8tion.jda.core.entities.ISnowflake;
import net.dv8tion.jda.core.entities.User;
import net.dv8tion.jda.core.entities.Webhook;
import net.dv8tion.jda.core.entities.impl.GuildImpl;
import net.dv8tion.jda.core.entities.impl.UserImpl;
import net.dv8tion.jda.core.entities.impl.WebhookImpl;
import net.dv8tion.jda.core.utils.Checks;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

/**
* Single entry for an {@link net.dv8tion.jda.core.requests.restaction.pagination.AuditLogPaginationAction
Expand All @@ -41,20 +45,22 @@ public class AuditLogEntry implements ISnowflake
protected final long targetId;
protected final GuildImpl guild;
protected final UserImpl user;
protected final WebhookImpl webhook;
protected final String reason;

protected final Map<String, AuditLogChange> changes;
protected final Map<String, Object> options;
protected final ActionType type;

public AuditLogEntry(ActionType type, long id, long targetId, GuildImpl guild, UserImpl user, String reason,
Map<String, AuditLogChange> changes, Map<String, Object> options)
public AuditLogEntry(ActionType type, long id, long targetId, GuildImpl guild, UserImpl user, WebhookImpl webhook,
String reason, Map<String, AuditLogChange> changes, Map<String, Object> options)
{
this.type = type;
this.id = id;
this.targetId = targetId;
this.guild = guild;
this.user = user;
this.webhook = webhook;
this.reason = reason;
this.changes = changes != null && !changes.isEmpty()
? Collections.unmodifiableMap(changes)
Expand Down Expand Up @@ -93,6 +99,17 @@ public String getTargetId()
{
return Long.toUnsignedString(targetId);
}

/**
* The {@link net.dv8tion.jda.core.entities.Webhook Webhook} that the target id of this audit-log entry refers to
*
* @return Possibly-null Webhook instance
*/
@Nullable
public Webhook getWebhook()
{
return webhook;
}

/**
* The {@link net.dv8tion.jda.core.entities.Guild Guild} this audit-log entry refers to
Expand All @@ -108,8 +125,9 @@ public Guild getGuild()
* The {@link net.dv8tion.jda.core.entities.User User} responsible
* for this action.
*
* @return The User instance
* @return Possibly-null User instance
*/
@Nullable
public User getUser()
{
return user;
Expand All @@ -120,6 +138,7 @@ public User getUser()
*
* @return Possibly-null reason String
*/
@Nullable
public String getReason()
{
return reason;
Expand Down Expand Up @@ -157,6 +176,7 @@ public Map<String, AuditLogChange> getChanges()
*
* @return Possibly-null value corresponding to the specified key
*/
@Nullable
public AuditLogChange getChangeByKey(final AuditLogKey key)
{
return key == null ? null : getChangeByKey(key.getKey());
Expand All @@ -171,6 +191,7 @@ public AuditLogChange getChangeByKey(final AuditLogKey key)
*
* @return Possibly-null value corresponding to the specified key
*/
@Nullable
public AuditLogChange getChangeByKey(final String key)
{
return changes.get(key);
Expand Down Expand Up @@ -231,6 +252,7 @@ public Map<String, Object> getOptions()
*
* @return Possibly-null value corresponding to the specified key
*/
@Nullable
@SuppressWarnings("unchecked")
public <T> T getOptionByName(String name)
{
Expand All @@ -252,6 +274,7 @@ public <T> T getOptionByName(String name)
*
* @return Possibly-null value corresponding to the specified option constant
*/
@Nullable
public <T> T getOption(AuditLogOption option)
{
Checks.notNull(option, "Option");
Expand Down
41 changes: 25 additions & 16 deletions src/main/java/net/dv8tion/jda/core/entities/EntityBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -485,9 +485,9 @@ public void createGuildVoiceStatePass(GuildImpl guildObj, JSONArray voiceStates)
}
}

public User createFakeUser(JSONObject user, boolean modifyCache) { return createUser(user, true, modifyCache); }
public User createUser(JSONObject user) { return createUser(user, false, true); }
private User createUser(JSONObject user, boolean fake, boolean modifyCache)
public UserImpl createFakeUser(JSONObject user, boolean modifyCache) { return createUser(user, true, modifyCache); }
public UserImpl createUser(JSONObject user) { return createUser(user, false, true); }
private UserImpl createUser(JSONObject user, boolean fake, boolean modifyCache)
{
final long id = user.getLong("id");
UserImpl userObj;
Expand Down Expand Up @@ -1157,7 +1157,7 @@ public PermissionOverride createPermissionOverride(JSONObject override, Channel
return permOverride.setAllow(allow).setDeny(deny);
}

public Webhook createWebhook(JSONObject object)
public WebhookImpl createWebhook(JSONObject object)
{
final long id = object.getLong("id");
final long guildId = object.getLong("guild_id");
Expand All @@ -1179,17 +1179,25 @@ public Webhook createWebhook(JSONObject object)
.put("avatar", avatar);
User defaultUser = createFakeUser(fakeUser, false);

JSONObject ownerJson = object.getJSONObject("user");
final long userId = ownerJson.getLong("id");

User owner = api.getUserById(userId);
if (owner == null)
JSONObject ownerJson = object.optJSONObject("user");
User owner = null;

if (ownerJson != null)
{
ownerJson.put("id", userId);
owner = createFakeUser(ownerJson, false);
}
final long userId = ownerJson.getLong("id");

return new WebhookImpl(channel, id).setToken(token).setOwner(channel.getGuild().getMember(owner)).setUser(defaultUser);
owner = api.getUserById(userId);
if (owner == null)
{
ownerJson.put("id", userId);
owner = createFakeUser(ownerJson, false);
}
}

return new WebhookImpl(channel, id)
.setToken(token)
.setOwner(owner == null ? null : channel.getGuild().getMember(owner))
.setUser(defaultUser);
}

public Relationship createRelationship(JSONObject relationshipJson)
Expand Down Expand Up @@ -1366,7 +1374,7 @@ public AuthorizedApplication createAuthorizedApplication(JSONObject object)
return new AuthorizedApplicationImpl(api, authId, description, iconId, id, name, scopes);
}

public AuditLogEntry createAuditLogEntry(GuildImpl guild, JSONObject entryJson, JSONObject userJson)
public AuditLogEntry createAuditLogEntry(GuildImpl guild, JSONObject entryJson, JSONObject userJson, JSONObject webhookJson)
{
final long targetId = Helpers.optLong(entryJson, "target_id", 0);
final long id = entryJson.getLong("id");
Expand All @@ -1375,7 +1383,8 @@ public AuditLogEntry createAuditLogEntry(GuildImpl guild, JSONObject entryJson,
final JSONObject options = entryJson.isNull("options") ? null : entryJson.getJSONObject("options");
final String reason = entryJson.optString("reason", null);

final UserImpl user = (UserImpl) createFakeUser(userJson, false);
final UserImpl user = userJson == null ? null : createFakeUser(userJson, false);
final WebhookImpl webhook = webhookJson == null ? null : createWebhook(webhookJson);
final Set<AuditLogChange> changesList;
final ActionType type = ActionType.from(typeKey);

Expand All @@ -1398,7 +1407,7 @@ public AuditLogEntry createAuditLogEntry(GuildImpl guild, JSONObject entryJson,
CaseInsensitiveMap<String, Object> optionMap = options != null
? new CaseInsensitiveMap<>(options.toMap()) : null;

return new AuditLogEntry(type, id, targetId, guild, user, reason, changeMap, optionMap);
return new AuditLogEntry(type, id, targetId, guild, user, webhook, reason, changeMap, optionMap);
}

public AuditLogChange createAuditLogChange(JSONObject change)
Expand Down
25 changes: 20 additions & 5 deletions src/main/java/net/dv8tion/jda/core/entities/Webhook.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@
import net.dv8tion.jda.webhook.WebhookClientBuilder;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;

/**
* An object representing Webhooks in Discord
*
* @since 3.0
*/
public interface Webhook extends ISnowflake
public interface Webhook extends ISnowflake, IFakeable
{

/**
Expand Down Expand Up @@ -57,11 +58,12 @@ public interface Webhook extends ISnowflake
TextChannel getChannel();

/**
* The owner of this Webhook.
* The owner of this Webhook. This will be null for fake Webhooks, such as those retrieved from Audit Logs.
*
* @return A {@link net.dv8tion.jda.core.entities.Member Member} instance
* representing the owner of this Webhook
* @return Possibly-null {@link net.dv8tion.jda.core.entities.Member Member} instance
* representing the owner of this Webhook.
*/
@Nullable
Member getOwner();

/**
Expand Down Expand Up @@ -96,15 +98,19 @@ public interface Webhook extends ISnowflake
* The execute token for this Webhook.
* <br>This can be used to modify/delete/execute
* this Webhook.
*
* <p><b>Note: Fake 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.
* of this Webhook. Fake 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.
Expand All @@ -122,6 +128,9 @@ public interface Webhook extends ISnowflake
/**
* Deletes this Webhook.
*
* @throws IllegalStateException
* if the Webhook is fake, such as the Webhooks retrieved from Audit Logs
*
* @return {@link net.dv8tion.jda.core.requests.restaction.AuditableRestAction AuditableRestAction}
* <br>The rest action to delete this Webhook.
*/
Expand All @@ -135,6 +144,9 @@ public interface Webhook extends ISnowflake
* @throws net.dv8tion.jda.core.exceptions.InsufficientPermissionException
* If the currently logged in account does not have {@link net.dv8tion.jda.core.Permission#MANAGE_WEBHOOKS Permission.MANAGE_WEBHOOKS}
*
* @throws IllegalStateException
* if the Webhook is fake, such as the Webhooks retrieved from Audit Logs
*
* @return The {@link net.dv8tion.jda.core.managers.WebhookManager WebhookManager} for this Webhook
*/
WebhookManager getManager();
Expand All @@ -160,6 +172,9 @@ public interface Webhook extends ISnowflake
*
* <p><b><u>Remember to close the WebhookClient once you don't need it anymore to free resources!</u></b>
*
* @throws IllegalStateException
* if the Webhook is fake, such as the Webhooks retrieved from Audit Logs
*
* @return The new WebhookClientBuilder
*/
WebhookClientBuilder newClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,15 @@ public String getToken()
@Override
public String getUrl()
{
return Requester.DISCORD_API_PREFIX + "webhooks/" + getId() + "/" + getToken();
return Requester.DISCORD_API_PREFIX + "webhooks/" + getId() + (getToken() == null ? "" : "/" + getToken());
}

@Override
public AuditableRestAction<Void> delete()
{
if (isFake())
throw new IllegalStateException("Fake Webhooks (such as those retrieved from Audit Logs) "
+ "cannot be used for deletion!");
Route.CompiledRoute route = Route.Webhooks.DELETE_TOKEN_WEBHOOK.compile(getId(), token);
return new AuditableRestAction<Void>(getJDA(), route)
{
Expand All @@ -122,6 +125,9 @@ protected void handleResponse(Response response, Request<Void> request)
@Override
public WebhookManager getManager()
{
if (isFake())
throw new IllegalStateException("Fake Webhooks (such as those retrieved from Audit Logs) "
+ "cannot provide a WebhookManager!");
WebhookManager mng = manager;
if (mng == null)
{
Expand Down Expand Up @@ -155,6 +161,9 @@ public net.dv8tion.jda.core.managers.WebhookManagerUpdatable getManagerUpdatable
@Override
public WebhookClientBuilder newClient()
{
if (isFake())
throw new IllegalStateException("Fake Webhooks (such as those retrieved from Audit Logs) "
+ "cannot be used to create a WebhookClient!");
return new WebhookClientBuilder(id, token);
}

Expand All @@ -164,6 +173,12 @@ public long getIdLong()
return id;
}

@Override
public boolean isFake()
{
return token == null;
}

/* -- Impl Setters -- */

public WebhookImpl setOwner(Member member)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import net.dv8tion.jda.core.requests.Request;
import net.dv8tion.jda.core.requests.Response;
import net.dv8tion.jda.core.requests.Route;
import net.dv8tion.jda.core.utils.Helpers;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
Expand Down Expand Up @@ -193,6 +194,7 @@ protected void handleResponse(Response response, Request<List<AuditLogEntry>> re

JSONObject obj = response.getObject();
JSONArray users = obj.getJSONArray("users");
JSONArray webhooks = obj.getJSONArray("webhooks");
JSONArray entries = obj.getJSONArray("audit_log_entries");

List<AuditLogEntry> list = new ArrayList<>(entries.length());
Expand All @@ -204,13 +206,22 @@ protected void handleResponse(Response response, Request<List<AuditLogEntry>> re
JSONObject user = users.getJSONObject(i);
userMap.put(user.getLong("id"), user);
}

TLongObjectMap<JSONObject> webhookMap = new TLongObjectHashMap<>();
for (int i = 0; i < webhooks.length(); i++)
{
JSONObject webhook = webhooks.getJSONObject(i);
webhookMap.put(webhook.getLong("id"), webhook);
}

for (int i = 0; i < entries.length(); i++)
{
try
{
JSONObject entry = entries.getJSONObject(i);
JSONObject user = userMap.get(entry.getLong("user_id"));
AuditLogEntry result = builder.createAuditLogEntry((GuildImpl) guild, entry, user);
JSONObject user = userMap.get(Helpers.optLong(entry, "user_id", 0));
JSONObject webhook = webhookMap.get(Helpers.optLong(entry, "target_id", 0));
AuditLogEntry result = builder.createAuditLogEntry((GuildImpl) guild, entry, user, webhook);
list.add(result);
if (this.useCache)
this.cached.add(result);
Expand Down