Skip to content

Commit

Permalink
Implement per-guild avatars (#1649)
Browse files Browse the repository at this point in the history
  • Loading branch information
RedDaedalus committed Oct 23, 2021
1 parent 7c8a94e commit 6f67977
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 6 deletions.
39 changes: 39 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
*/
public interface Member extends IMentionable, IPermissionHolder
{
/** Template for {@link #getAvatarUrl()}. */
String AVATAR_URL = "https://cdn.discordapp.com/guilds/%s/users/%s/avatars/%s.%s";

/**
* The user wrapped by this Entity.
*
Expand Down Expand Up @@ -207,6 +210,42 @@ public interface Member extends IMentionable, IPermissionHolder
@Nonnull
String getEffectiveName();

/**
* The Discord Id for this member's per guild avatar image.
* If the member has not set a per guild avatar, this will return null.
*
* @return Possibly-null String containing the {@link net.dv8tion.jda.api.entities.Member} per guild avatar id.
*/
@Nullable
String getAvatarId();

/**
* The URL for the member's per guild avatar image.
* If the member has not set a per guild avatar, this will return null.
*
* @return Possibly-null String containing the {@link net.dv8tion.jda.api.entities.Member} per guild avatar url.
*/
@Nullable
default String getAvatarUrl()
{
String avatarId = getAvatarId();
return avatarId == null ? null : String.format(AVATAR_URL, getGuild().getId(), getId(), avatarId, avatarId.startsWith("a_") ? "gif" : "png");
}

/**
* The URL for the member's effective avatar image.
* If they do not have a per guild avatar set, this will return the URL of
* their effective {@link User} avatar.
*
* @return Never-null String containing the {@link net.dv8tion.jda.api.entities.Member} avatar url.
*/
@Nonnull
default String getEffectiveAvatarUrl()
{
String avatarUrl = getAvatarUrl();
return avatarUrl == null ? getUser().getEffectiveAvatarUrl() : avatarUrl;
}

/**
* The roles applied to this Member.
* <br>The roles are ordered based on their position. The highest role being at index 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* 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.events.guild.member.update;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Member;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* Indicates that a {@link net.dv8tion.jda.api.entities.Member Member} updated their {@link net.dv8tion.jda.api.entities.Guild Guild} avatar.
*
* <p>Can be used to retrieve members who change their per guild avatar, triggering guild, the old avatar id and the new avatar id.
*
* <p>Identifier: {@code avatar}
*
* <h2>Requirements</h2>
*
* <p>This event requires the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_MEMBERS GUILD_MEMBERS} intent to be enabled.
* <br>{@link net.dv8tion.jda.api.JDABuilder#createDefault(String) createDefault(String)} and
* {@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disable this by default!
*
* <p>Additionally, this event requires the {@link net.dv8tion.jda.api.utils.MemberCachePolicy MemberCachePolicy}
* to cache the updated members. Discord does not specifically tell us about the updates, but merely tells us the
* member was updated and gives us the updated member object. In order to fire a specific event like this we
* need to have the old member cached to compare against.
*/
public class GuildMemberUpdateAvatarEvent extends GenericGuildMemberUpdateEvent<String>
{
public static final String IDENTIFIER = "avatar";

public GuildMemberUpdateAvatarEvent(@Nonnull JDA api, long responseNumber, @Nonnull Member member, @Nullable String oldAvatarId)
{
super(api, responseNumber, member, oldAvatarId, member.getAvatarId(), IDENTIFIER);
}

/**
* The old avatar id
*
* @return The old avatar id
*/
@Nullable
public String getOldAvatarId()
{
return getOldValue();
}

/**
* The previous avatar url
*
* @return The previous avatar url
*/
@Nullable
public String getOldAvatarUrl() {
return previous == null ? null : String.format(Member.AVATAR_URL, getMember().getGuild().getId(), getMember().getId(), previous, previous.startsWith("a_") ? "gif" : "png");
}

/**
* The new avatar id
*
* @return The new avatar id
*/
@Nullable
public String getNewAvatarId()
{
return getNewValue();
}

/**
* The url of the new avatar
*
* @return The url of the new avatar
*/
@Nullable
public String getNewAvatarUrl() {
return next == null ? null : String.format(Member.AVATAR_URL, getMember().getGuild().getId(), getMember().getId(), next, next.startsWith("a_") ? "gif" : "png");
}
}
6 changes: 2 additions & 4 deletions src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@
import net.dv8tion.jda.api.events.guild.invite.GuildInviteCreateEvent;
import net.dv8tion.jda.api.events.guild.invite.GuildInviteDeleteEvent;
import net.dv8tion.jda.api.events.guild.member.*;
import net.dv8tion.jda.api.events.guild.member.update.GenericGuildMemberUpdateEvent;
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateBoostTimeEvent;
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent;
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdatePendingEvent;
import net.dv8tion.jda.api.events.guild.member.update.*;
import net.dv8tion.jda.api.events.guild.override.GenericPermissionOverrideEvent;
import net.dv8tion.jda.api.events.guild.override.PermissionOverrideCreateEvent;
import net.dv8tion.jda.api.events.guild.override.PermissionOverrideDeleteEvent;
Expand Down Expand Up @@ -364,6 +361,7 @@ public void onGuildMemberRoleRemove(@Nonnull GuildMemberRoleRemoveEvent event) {
//Guild Member Update Events
public void onGuildMemberUpdate(@Nonnull GuildMemberUpdateEvent event) {}
public void onGuildMemberUpdateNickname(@Nonnull GuildMemberUpdateNicknameEvent event) {}
public void onGuildMemberUpdateAvatar(@Nonnull GuildMemberUpdateAvatarEvent event) {}
public void onGuildMemberUpdateBoostTime(@Nonnull GuildMemberUpdateBoostTimeEvent event) {}
public void onGuildMemberUpdatePending(@Nonnull GuildMemberUpdatePendingEvent event) {}

Expand Down
16 changes: 16 additions & 0 deletions src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import net.dv8tion.jda.api.entities.templates.TemplateRole;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent;
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateAvatarEvent;
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateBoostTimeEvent;
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent;
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdatePendingEvent;
Expand Down Expand Up @@ -493,6 +494,8 @@ public MemberImpl createMember(GuildImpl guild, DataObject memberJson, DataObjec
// Create a brand new member
member = new MemberImpl(guild, user);
member.setNickname(memberJson.getString("nick", null));
member.setAvatarId(memberJson.getString("avatar", null));

long epoch = 0;
if (!memberJson.isNull("premium_since"))
{
Expand Down Expand Up @@ -593,6 +596,19 @@ public void updateMember(GuildImpl guild, MemberImpl member, DataObject content,
member, oldNick));
}
}
if (content.hasKey("avatar"))
{
String oldAvatarId = member.getAvatarId();
String newAvatarId = content.getString("avatar", null);
if (!Objects.equals(oldAvatarId, newAvatarId))
{
member.setAvatarId(newAvatarId);
getJDA().handleEvent(
new GuildMemberUpdateAvatarEvent(
getJDA(), responseNumber,
member, oldAvatarId));
}
}
if (content.hasKey("premium_since"))
{
long epoch = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1276,7 +1276,7 @@ public AuditableRestAction<Void> modifyNickname(@Nonnull Member member, String n

Route.CompiledRoute route;
if (member.equals(getSelfMember()))
route = Route.Guilds.MODIFY_SELF_NICK.compile(getId());
route = Route.Guilds.MODIFY_SELF.compile(getId());
else
route = Route.Guilds.MODIFY_MEMBER.compile(getId(), member.getUser().getId());

Expand Down
13 changes: 13 additions & 0 deletions src/main/java/net/dv8tion/jda/internal/entities/MemberImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class MemberImpl implements Member
private GuildImpl guild;
private User user;
private String nickname;
private String avatarId;
private long joinDate, boostDate;
private boolean pending = false;

Expand Down Expand Up @@ -162,6 +163,12 @@ public String getNickname()
return nickname;
}

@Override
public String getAvatarId()
{
return avatarId;
}

@Nonnull
@Override
public String getEffectiveName()
Expand Down Expand Up @@ -349,6 +356,12 @@ public MemberImpl setNickname(String nickname)
return this;
}

public MemberImpl setAvatarId(String avatarId)
{
this.avatarId = avatarId;
return this;
}

public MemberImpl setJoinDate(long joinDate)
{
this.joinDate = joinDate;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/net/dv8tion/jda/internal/requests/Route.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package net.dv8tion.jda.internal.requests;

import net.dv8tion.jda.annotations.ForRemoval;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.Helpers;

Expand Down Expand Up @@ -136,7 +137,7 @@ public static class Guilds
public static final Route MODIFY_MEMBER = new Route(PATCH, "guilds/{guild_id}/members/{user_id}");
public static final Route ADD_MEMBER = new Route(PUT, "guilds/{guild_id}/members/{user_id}");
public static final Route GET_MEMBER = new Route(GET, "guilds/{guild_id}/members/{user_id}");
public static final Route MODIFY_SELF_NICK = new Route(PATCH, "guilds/{guild_id}/members/@me/nick");
public static final Route MODIFY_SELF = new Route(PATCH, "guilds/{guild_id}/members/@me");
public static final Route PRUNABLE_COUNT = new Route(GET, "guilds/{guild_id}/prune");
public static final Route PRUNE_MEMBERS = new Route(POST, "guilds/{guild_id}/prune");
public static final Route GET_WEBHOOKS = new Route(GET, "guilds/{guild_id}/webhooks");
Expand Down

0 comments on commit 6f67977

Please sign in to comment.