Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 183 additions & 23 deletions src/main/java/net/dv8tion/jda/api/entities/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@
import net.dv8tion.jda.annotations.ReplaceWith;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.channel.unions.DefaultGuildChannelUnion;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.api.utils.ImageProxy;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.requests.restaction.AuditableRestActionImpl;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.Helpers;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
Expand Down Expand Up @@ -144,8 +151,8 @@ public interface Member extends IMentionable, IPermissionHolder, UserSnowflake

/**
* Whether this Member is in time out.
* <br>While a Member is in time out, all permissions except {@link net.dv8tion.jda.api.Permission#VIEW_CHANNEL VIEW_CHANNEL} and
* {@link net.dv8tion.jda.api.Permission#MESSAGE_HISTORY MESSAGE_HISTORY} are removed from them.
* <br>While a Member is in time out, all permissions except {@link Permission#VIEW_CHANNEL VIEW_CHANNEL} and
* {@link Permission#MESSAGE_HISTORY MESSAGE_HISTORY} are removed from them.
*
* @return True, if this Member is in time out
*/
Expand Down Expand Up @@ -356,6 +363,25 @@ default ImageProxy getEffectiveAvatar()
*/
int getColorRaw();

/**
* The raw {@link MemberFlag flags} bitset for this member.
*
* @return The raw flag bitset
*/
int getFlagsRaw();

/**
* The {@link MemberFlag flags} for this member as an {@link EnumSet}.
* <br>Modifying this set will not update the member, it is a copy of existing flags.
*
* @return The flags
*/
@Nonnull
default EnumSet<MemberFlag> getFlags()
{
return MemberFlag.fromRaw(getFlagsRaw());
}

/**
* Whether this Member can interact with the provided Member
* (kick/ban/etc.)
Expand Down Expand Up @@ -431,7 +457,7 @@ default ImageProxy getEffectiveAvatar()
* <br>This is the channel that the Discord client will default to opening when a Guild is opened for the first time
* after joining the guild.
* <br>The default channel is the channel with the highest position in which the member has
* {@link net.dv8tion.jda.api.Permission#VIEW_CHANNEL Permission.VIEW_CHANNEL} permissions. If this requirement doesn't apply for
* {@link Permission#VIEW_CHANNEL Permission.VIEW_CHANNEL} permissions. If this requirement doesn't apply for
* any channel in the guild, this method returns {@code null}.
*
* @return The {@link DefaultGuildChannelUnion channel} representing the default channel for this member
Expand Down Expand Up @@ -467,7 +493,7 @@ default ImageProxy getEffectiveAvatar()
* Timeframe unit as a {@link TimeUnit} (for example {@code member.ban(7, TimeUnit.DAYS)}).
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#BAN_MEMBERS} permission.
* If the logged in account does not have the {@link Permission#BAN_MEMBERS} permission.
* @throws net.dv8tion.jda.api.exceptions.HierarchyException
* If the logged in account cannot ban the other user due to permission hierarchy position.
* <br>See {@link Member#canInteract(Member)}
Expand Down Expand Up @@ -507,7 +533,7 @@ default AuditableRestAction<Void> ban(int deletionTimeframe, @Nonnull TimeUnit u
* </ul>
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#KICK_MEMBERS} permission.
* If the logged in account does not have the {@link Permission#KICK_MEMBERS} permission.
* @throws net.dv8tion.jda.api.exceptions.HierarchyException
* If the logged in account cannot kick the other member due to permission hierarchy position.
* <br>See {@link Member#canInteract(Member)}
Expand Down Expand Up @@ -544,7 +570,7 @@ default AuditableRestAction<Void> kick()
* The reason for this action or {@code null} if there is no specified reason
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#KICK_MEMBERS} permission.
* If the logged in account does not have the {@link Permission#KICK_MEMBERS} permission.
* @throws net.dv8tion.jda.api.exceptions.HierarchyException
* If the logged in account cannot kick the other member due to permission hierarchy position.
* <br>See {@link Member#canInteract(Member)}
Expand All @@ -570,8 +596,8 @@ default AuditableRestAction<Void> kick(@Nullable String reason)

/**
* Puts this Member in time out in this {@link net.dv8tion.jda.api.entities.Guild Guild} for a specific amount of time.
* <br>While a Member is in time out, all permissions except {@link net.dv8tion.jda.api.Permission#VIEW_CHANNEL VIEW_CHANNEL} and
* {@link net.dv8tion.jda.api.Permission#MESSAGE_HISTORY MESSAGE_HISTORY} are removed from them.
* <br>While a Member is in time out, all permissions except {@link Permission#VIEW_CHANNEL VIEW_CHANNEL} and
* {@link Permission#MESSAGE_HISTORY MESSAGE_HISTORY} are removed from them.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} caused by
* the returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} include the following:
Expand All @@ -589,7 +615,7 @@ default AuditableRestAction<Void> kick(@Nullable String reason)
* The {@link TimeUnit Unit} type of {@code amount}
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#MODERATE_MEMBERS} permission.
* If the logged in account does not have the {@link Permission#MODERATE_MEMBERS} permission.
* @throws IllegalArgumentException
* If any of the following checks are true
* <ul>
Expand All @@ -609,8 +635,8 @@ default AuditableRestAction<Void> timeoutFor(long amount, @Nonnull TimeUnit unit

/**
* Puts this Member in time out in this {@link net.dv8tion.jda.api.entities.Guild Guild} for a specific amount of time.
* <br>While a Member is in time out, all permissions except {@link net.dv8tion.jda.api.Permission#VIEW_CHANNEL VIEW_CHANNEL} and
* {@link net.dv8tion.jda.api.Permission#MESSAGE_HISTORY MESSAGE_HISTORY} are removed from them.
* <br>While a Member is in time out, all permissions except {@link Permission#VIEW_CHANNEL VIEW_CHANNEL} and
* {@link Permission#MESSAGE_HISTORY MESSAGE_HISTORY} are removed from them.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} caused by
* the returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} include the following:
Expand All @@ -626,7 +652,7 @@ default AuditableRestAction<Void> timeoutFor(long amount, @Nonnull TimeUnit unit
* The duration to put this Member in time out for
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#MODERATE_MEMBERS} permission.
* If the logged in account does not have the {@link Permission#MODERATE_MEMBERS} permission.
* @throws IllegalArgumentException
* If any of the following checks are true
* <ul>
Expand All @@ -646,8 +672,8 @@ default AuditableRestAction<Void> timeoutFor(@Nonnull Duration duration)

/**
* Puts this Member in time out in this {@link net.dv8tion.jda.api.entities.Guild Guild} until the specified date.
* <br>While a Member is in time out, all permissions except {@link net.dv8tion.jda.api.Permission#VIEW_CHANNEL VIEW_CHANNEL} and
* {@link net.dv8tion.jda.api.Permission#MESSAGE_HISTORY MESSAGE_HISTORY} are removed from them.
* <br>While a Member is in time out, all permissions except {@link Permission#VIEW_CHANNEL VIEW_CHANNEL} and
* {@link Permission#MESSAGE_HISTORY MESSAGE_HISTORY} are removed from them.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} caused by
* the returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} include the following:
Expand All @@ -663,7 +689,7 @@ default AuditableRestAction<Void> timeoutFor(@Nonnull Duration duration)
* The time this Member will be released from time out
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#MODERATE_MEMBERS} permission.
* If the logged in account does not have the {@link Permission#MODERATE_MEMBERS} permission.
* @throws IllegalArgumentException
* If any of the following checks are true
* <ul>
Expand Down Expand Up @@ -695,7 +721,7 @@ default AuditableRestAction<Void> timeoutUntil(@Nonnull TemporalAccessor tempora
* </ul>
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#MODERATE_MEMBERS} permission.
* If the logged in account does not have the {@link Permission#MODERATE_MEMBERS} permission.
*
* @return {@link net.dv8tion.jda.api.requests.restaction.AuditableRestAction AuditableRestAction}
*/
Expand Down Expand Up @@ -730,7 +756,7 @@ default AuditableRestAction<Void> removeTimeout()
* Whether this {@link net.dv8tion.jda.api.entities.Member Member} should be muted or unmuted.
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#VOICE_DEAF_OTHERS} permission.
* If the logged in account does not have the {@link Permission#VOICE_DEAF_OTHERS} permission.
* @throws java.lang.IllegalStateException
* If the member is not currently connected to a voice channel.
*
Expand Down Expand Up @@ -768,7 +794,7 @@ default AuditableRestAction<Void> mute(boolean mute)
* Whether this {@link net.dv8tion.jda.api.entities.Member Member} should be deafened or undeafened.
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#VOICE_DEAF_OTHERS} permission.
* If the logged in account does not have the {@link Permission#VOICE_DEAF_OTHERS} permission.
* @throws java.lang.IllegalStateException
* If the member is not currently connected to a voice channel.
*
Expand All @@ -788,9 +814,9 @@ default AuditableRestAction<Void> deafen(boolean deafen)
* The nickname is visible to all members of this guild.
*
* <p>To change the nickname for the currently logged in account
* only the Permission {@link net.dv8tion.jda.api.Permission#NICKNAME_CHANGE NICKNAME_CHANGE} is required.
* only the Permission {@link Permission#NICKNAME_CHANGE NICKNAME_CHANGE} is required.
* <br>To change the nickname of <b>any</b> {@link net.dv8tion.jda.api.entities.Member Member} for this {@link net.dv8tion.jda.api.entities.Guild Guild}
* the Permission {@link net.dv8tion.jda.api.Permission#NICKNAME_MANAGE NICKNAME_MANAGE} is required.
* the Permission {@link Permission#NICKNAME_MANAGE NICKNAME_MANAGE} is required.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} caused by
* the returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} include the following:
Expand All @@ -808,9 +834,9 @@ default AuditableRestAction<Void> deafen(boolean deafen)
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* <ul>
* <li>If attempting to set nickname for self and the logged in account has neither {@link net.dv8tion.jda.api.Permission#NICKNAME_CHANGE}
* or {@link net.dv8tion.jda.api.Permission#NICKNAME_MANAGE}</li>
* <li>If attempting to set nickname for another member and the logged in account does not have {@link net.dv8tion.jda.api.Permission#NICKNAME_MANAGE}</li>
* <li>If attempting to set nickname for self and the logged in account has neither {@link Permission#NICKNAME_CHANGE}
* or {@link Permission#NICKNAME_MANAGE}</li>
* <li>If attempting to set nickname for another member and the logged in account does not have {@link Permission#NICKNAME_MANAGE}</li>
* </ul>
* @throws net.dv8tion.jda.api.exceptions.HierarchyException
* If attempting to set nickname for another member and the logged in account cannot manipulate the other user due to permission hierarchy position.
Expand All @@ -826,4 +852,138 @@ default AuditableRestAction<Void> modifyNickname(@Nullable String nickname)
{
return getGuild().modifyNickname(this, nickname);
}

/**
* Updates the flags to the new flag set.
* <br>If any of the flags is not {@link MemberFlag#isModifiable() modifiable}, it is not updated.
*
* <p>Any flags not provided by the set will be disabled, all contained flags will be enabled.
*
* @param newFlags
* The new flags for the member.
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the bot does not have {@link Permission#MODERATE_MEMBERS} in the guild
* @throws IllegalArgumentException
* If {@code null} is provided
*
* @return {@link AuditableRestAction}
*/
@Nonnull
@CheckReturnValue
default AuditableRestAction<Void> modifyFlags(@Nonnull Collection<MemberFlag> newFlags)
{
Checks.noneNull(newFlags, "Flags");
if (!getGuild().getSelfMember().hasPermission(Permission.MODERATE_MEMBERS))
throw new InsufficientPermissionException(getGuild(), Permission.MODERATE_MEMBERS);
int flags = getFlagsRaw();
EnumSet<MemberFlag> updated = Helpers.copyEnumSet(MemberFlag.class, newFlags);
for (MemberFlag flag : MemberFlag.values())
{
if (flag.modifiable)
{
if (updated.contains(flag))
flags |= flag.raw;
else
flags &= ~flag.raw;
}
}

DataObject body = DataObject.empty().put("flags", flags);
Route.CompiledRoute route = Route.Guilds.MODIFY_MEMBER.compile(getGuild().getId(), getId());
return new AuditableRestActionImpl<>(getJDA(), route, body);
}

/**
* Member flags indicating information about the membership state.
*/
enum MemberFlag
{
/**
* The Member has left and rejoined the guild
*/
DID_REJOIN(1, false),
/**
* The Member has completed the onboarding process
*/
COMPLETED_ONBOARDING(1 << 1, false),
/**
* The Member bypasses guild verification requirements
*/
BYPASSES_VERIFICATION(1 << 2, true),
/**
* The Member has started the onboarding process
*/
STARTED_ONBOARDING(1 << 3, false),
;

private final int raw;
private final boolean modifiable;


MemberFlag(int raw, boolean modifiable)
{
this.raw = raw;
this.modifiable = modifiable;
}

/**
* The raw value used by Discord for this flag
*
* @return The raw value
*/
public int getRaw()
{
return raw;
}

/**
* Whether this flag can be modified by the client
*
* @return True, if this flag can be modified
*/
public boolean isModifiable()
{
return modifiable;
}

/**
* The {@link MemberFlag Flags} represented by the provided raw value.
* <br>If the provided raw value is {@code 0} this will return an empty {@link java.util.EnumSet EnumSet}.
*
* @param raw
* The raw value
*
* @return EnumSet containing the flags represented by the provided raw value
*/
@Nonnull
public static EnumSet<MemberFlag> fromRaw(int raw)
{
EnumSet<MemberFlag> flags = EnumSet.noneOf(MemberFlag.class);
for (MemberFlag flag : values())
{
if ((raw & flag.raw) == flag.raw)
flags.add(flag);
}
return flags;
}

/**
* The raw value of the provided {@link MemberFlag Flags}.
* <br>If the provided set is empty this will return {@code 0}.
*
* @param flags
* The flags
*
* @return The raw value of the provided flags
*/
public static int toRaw(@Nonnull Collection<MemberFlag> flags)
{
Checks.noneNull(flags, "Flags");
int raw = 0;
for (MemberFlag flag : flags)
raw |= flag.raw;
return raw;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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 java.util.EnumSet;

/**
* Indicates that the {@link Member#getFlags()} flags for a {@link Member} were updated.
*
* <p>Identifier: {@code flags}
*
* <p><b>Requirements</b><br>
*
* <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 also 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 GuildMemberUpdateFlagsEvent extends GenericGuildMemberUpdateEvent<EnumSet<Member.MemberFlag>>
{
public static final String IDENTIFIER = "flags";

public GuildMemberUpdateFlagsEvent(@Nonnull JDA api, long responseNumber, @Nonnull Member member, @Nonnull EnumSet<Member.MemberFlag> previous)
{
super(api, responseNumber, member, previous, member.getFlags(), IDENTIFIER);
}
}
Loading