diff --git a/src/main/java/net/dv8tion/jda/api/Permission.java b/src/main/java/net/dv8tion/jda/api/Permission.java index 313a4fbd3d..22e99f903d 100644 --- a/src/main/java/net/dv8tion/jda/api/Permission.java +++ b/src/main/java/net/dv8tion/jda/api/Permission.java @@ -87,6 +87,7 @@ public enum Permission VOICE_START_ACTIVITIES( 39, true, true, "Use Activities"), VOICE_USE_SOUNDBOARD( 42, true, true, "Use Soundboard"), VOICE_USE_EXTERNAL_SOUNDS(45, true, true, "Use External Sounds"), + VOICE_SET_STATUS( 48, true, true, "Set Voice Channel Status"), // Stage Channel Permissions REQUEST_TO_SPEAK( 32, true, true, "Request to Speak"), diff --git a/src/main/java/net/dv8tion/jda/api/audit/ActionType.java b/src/main/java/net/dv8tion/jda/api/audit/ActionType.java index 32efb8933e..ba216cc69c 100644 --- a/src/main/java/net/dv8tion/jda/api/audit/ActionType.java +++ b/src/main/java/net/dv8tion/jda/api/audit/ActionType.java @@ -18,6 +18,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.ScheduledEvent; +import net.dv8tion.jda.api.entities.channel.attribute.IVoiceStatusChannel; import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji; @@ -635,6 +636,27 @@ public enum ActionType */ AUTO_MODERATION_MEMBER_TIMEOUT( 145, TargetType.MEMBER), + /** + * A user updated the {@link IVoiceStatusChannel#getStatus() status} of a voice channel. + * + *

Possible Keys
+ *

+ */ + VOICE_CHANNEL_STATUS_UPDATE(192, TargetType.CHANNEL), + + /** + * A user removed the {@link IVoiceStatusChannel#getStatus() status} of a voice channel. + * + *

Possible Keys
+ *

+ */ + VOICE_CHANNEL_STATUS_DELETE(193, TargetType.CHANNEL), + UNKNOWN(-1, TargetType.UNKNOWN); private final int key; diff --git a/src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java b/src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java index e4e6831ed6..7b1522aac9 100644 --- a/src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java +++ b/src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java @@ -240,6 +240,14 @@ public enum AuditLogKey */ CHANNEL_TOPIC("topic"), + /** + * Change of the {@link VoiceChannel#getStatus() VoiceChannel.getStatus()} value. + *
Only for {@link ChannelType#VOICE ChannelType.VOICE} + * + *

Expected type: String + */ + CHANNEL_VOICE_STATUS("status"), + /** * Change of the {@link ISlowmodeChannel#getSlowmode()} value. * diff --git a/src/main/java/net/dv8tion/jda/api/entities/channel/ChannelField.java b/src/main/java/net/dv8tion/jda/api/entities/channel/ChannelField.java index 681c1d15a0..4b069e77f7 100644 --- a/src/main/java/net/dv8tion/jda/api/entities/channel/ChannelField.java +++ b/src/main/java/net/dv8tion/jda/api/entities/channel/ChannelField.java @@ -168,6 +168,14 @@ public enum ChannelField * @see VoiceChannel#getUserLimit() */ USER_LIMIT("userlimit", AuditLogKey.CHANNEL_USER_LIMIT), + /** + * The status of the channel. + * + *

Limited to {@link VoiceChannel Voice Channels}. + * + * @see VoiceChannel#getStatus() + */ + VOICE_STATUS("status", AuditLogKey.CHANNEL_VOICE_STATUS), //Thread Specific diff --git a/src/main/java/net/dv8tion/jda/api/entities/channel/attribute/IVoiceStatusChannel.java b/src/main/java/net/dv8tion/jda/api/entities/channel/attribute/IVoiceStatusChannel.java new file mode 100644 index 0000000000..47195b4eb4 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/entities/channel/attribute/IVoiceStatusChannel.java @@ -0,0 +1,68 @@ +/* + * 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.channel.attribute; + +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.channel.Channel; +import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; + +import javax.annotation.CheckReturnValue; +import javax.annotation.Nonnull; + +/** + * Channel with a modifiable voice status. + *
This can be used to indicate what is going on to people outside the channel. + */ +public interface IVoiceStatusChannel extends Channel +{ + /** The maximum length of a voice status {@value} */ + int MAX_STATUS_LENGTH = 500; + + /** + * The current voice channel status. + *
This can be configured by users who are connected + * and have the {@link net.dv8tion.jda.api.Permission#VOICE_SET_STATUS set voice channel status} permission. + * + * @return The current voice channel status, or empty string if unset + */ + @Nonnull + String getStatus(); + + /** + * Change the current voice channel status. + *
This can be configured by users who are connected + * and have the {@link net.dv8tion.jda.api.Permission#VOICE_SET_STATUS set voice channel status} permission. + * + * @param status + * The new status, or empty to unset + * + * @throws IllegalArgumentException + * If the status is null or longer than {@value #MAX_STATUS_LENGTH} characters + * @throws net.dv8tion.jda.api.exceptions.MissingAccessException + * If the currently logged in account does not have {@link Permission#VIEW_CHANNEL Permission.VIEW_CHANNEL} in this channel + * @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException + *

+ * + * @return {@link AuditableRestAction} + */ + @Nonnull + @CheckReturnValue + AuditableRestAction modifyStatus(@Nonnull String status); +} diff --git a/src/main/java/net/dv8tion/jda/api/entities/channel/concrete/VoiceChannel.java b/src/main/java/net/dv8tion/jda/api/entities/channel/concrete/VoiceChannel.java index 7c18c463b5..d1c957c62c 100644 --- a/src/main/java/net/dv8tion/jda/api/entities/channel/concrete/VoiceChannel.java +++ b/src/main/java/net/dv8tion/jda/api/entities/channel/concrete/VoiceChannel.java @@ -19,6 +19,7 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.channel.attribute.IAgeRestrictedChannel; import net.dv8tion.jda.api.entities.channel.attribute.ISlowmodeChannel; +import net.dv8tion.jda.api.entities.channel.attribute.IVoiceStatusChannel; import net.dv8tion.jda.api.entities.channel.attribute.IWebhookContainer; import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; @@ -47,7 +48,7 @@ * @see JDA#getVoiceChannelsByName(String, boolean) * @see JDA#getVoiceChannelById(long) */ -public interface VoiceChannel extends StandardGuildChannel, GuildMessageChannel, AudioChannel, IWebhookContainer, IAgeRestrictedChannel, ISlowmodeChannel +public interface VoiceChannel extends StandardGuildChannel, GuildMessageChannel, AudioChannel, IWebhookContainer, IAgeRestrictedChannel, ISlowmodeChannel, IVoiceStatusChannel { /** * The maximum limit you can set with {@link VoiceChannelManager#setUserLimit(int)}. ({@value}) diff --git a/src/main/java/net/dv8tion/jda/api/events/channel/update/ChannelUpdateVoiceStatusEvent.java b/src/main/java/net/dv8tion/jda/api/events/channel/update/ChannelUpdateVoiceStatusEvent.java new file mode 100644 index 0000000000..de172cb414 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/events/channel/update/ChannelUpdateVoiceStatusEvent.java @@ -0,0 +1,44 @@ +/* + * 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.channel.update; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.channel.Channel; +import net.dv8tion.jda.api.entities.channel.ChannelField; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; + +import javax.annotation.Nonnull; + +/** + * Indicates that a {@link Channel Channel's} voice channel status has been updated. + * + *

Can be used to retrieve the old status and the new one. + * + *

Limited to {@link VoiceChannel VoiceChannels}. + * + * @see VoiceChannel#getStatus() + */ +public class ChannelUpdateVoiceStatusEvent extends GenericChannelUpdateEvent +{ + public static final ChannelField FIELD = ChannelField.VOICE_STATUS; + public static final String IDENTIFIER = FIELD.getFieldName(); + + public ChannelUpdateVoiceStatusEvent(@Nonnull JDA api, long responseNumber, Channel channel, String oldValue, String newValue) + { + super(api, responseNumber, channel, FIELD, oldValue, newValue); + } +} diff --git a/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java b/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java index aa26bce27c..3df7247bae 100644 --- a/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java +++ b/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java @@ -212,6 +212,7 @@ public void onChannelUpdateDefaultReaction(@Nonnull ChannelUpdateDefaultReaction public void onChannelUpdateDefaultSortOrder(@Nonnull ChannelUpdateDefaultSortOrderEvent event) {} public void onChannelUpdateDefaultLayout(@Nonnull ChannelUpdateDefaultLayoutEvent event) {} public void onChannelUpdateTopic(@Nonnull ChannelUpdateTopicEvent event) {} + public void onChannelUpdateVoiceStatus(@Nonnull ChannelUpdateVoiceStatusEvent event) {} public void onChannelUpdateType(@Nonnull ChannelUpdateTypeEvent event) {} public void onChannelUpdateUserLimit(@Nonnull ChannelUpdateUserLimitEvent event) {} public void onChannelUpdateArchived(@Nonnull ChannelUpdateArchivedEvent event) {} diff --git a/src/main/java/net/dv8tion/jda/api/requests/Route.java b/src/main/java/net/dv8tion/jda/api/requests/Route.java index e28e1ca5e1..f15462924c 100644 --- a/src/main/java/net/dv8tion/jda/api/requests/Route.java +++ b/src/main/java/net/dv8tion/jda/api/requests/Route.java @@ -203,6 +203,7 @@ public static class Channels public static final Route CREATE_PERM_OVERRIDE = new Route(PUT, "channels/{channel_id}/permissions/{permoverride_id}"); public static final Route MODIFY_PERM_OVERRIDE = new Route(PUT, "channels/{channel_id}/permissions/{permoverride_id}"); public static final Route DELETE_PERM_OVERRIDE = new Route(DELETE, "channels/{channel_id}/permissions/{permoverride_id}"); + public static final Route SET_STATUS = new Route(PUT, "channels/{channel_id}/voice-status"); public static final Route SEND_TYPING = new Route(POST, "channels/{channel_id}/typing"); public static final Route GET_PERMISSIONS = new Route(GET, "channels/{channel_id}/permissions"); diff --git a/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java b/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java index 09b06f2ad8..cae8badde5 100644 --- a/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java +++ b/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java @@ -1219,6 +1219,7 @@ public VoiceChannel createVoiceChannel(GuildImpl guild, DataObject json, long gu .setParentCategory(json.getLong("parent_id", 0)) .setLatestMessageIdLong(json.getLong("last_message_id", 0)) .setName(json.getString("name")) + .setStatus(json.getString("status", "")) .setPosition(json.getInt("position")) .setUserLimit(json.getInt("user_limit")) .setNSFW(json.getBoolean("nsfw")) diff --git a/src/main/java/net/dv8tion/jda/internal/entities/channel/concrete/VoiceChannelImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/channel/concrete/VoiceChannelImpl.java index a9f3148599..b59ac14014 100644 --- a/src/main/java/net/dv8tion/jda/internal/entities/channel/concrete/VoiceChannelImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/entities/channel/concrete/VoiceChannelImpl.java @@ -26,8 +26,11 @@ import net.dv8tion.jda.api.entities.channel.concrete.Category; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; import net.dv8tion.jda.api.managers.channel.concrete.VoiceChannelManager; +import net.dv8tion.jda.api.requests.Route; +import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.requests.restaction.ChannelAction; import net.dv8tion.jda.api.utils.MiscUtil; +import net.dv8tion.jda.api.utils.data.DataObject; import net.dv8tion.jda.internal.entities.GuildImpl; import net.dv8tion.jda.internal.entities.channel.middleman.AbstractStandardGuildChannelImpl; import net.dv8tion.jda.internal.entities.channel.mixin.attribute.IAgeRestrictedChannelMixin; @@ -36,6 +39,7 @@ import net.dv8tion.jda.internal.entities.channel.mixin.middleman.AudioChannelMixin; import net.dv8tion.jda.internal.entities.channel.mixin.middleman.GuildMessageChannelMixin; import net.dv8tion.jda.internal.managers.channel.concrete.VoiceChannelManagerImpl; +import net.dv8tion.jda.internal.requests.restaction.AuditableRestActionImpl; import net.dv8tion.jda.internal.utils.Checks; import javax.annotation.Nonnull; @@ -55,6 +59,7 @@ public class VoiceChannelImpl extends AbstractStandardGuildChannelImpl connectedMembers = MiscUtil.newLongMap(); private String region; + private String status = ""; private long latestMessageId; private int bitrate; private int userLimit; @@ -162,6 +167,29 @@ public VoiceChannelManager getManager() return new VoiceChannelManagerImpl(this); } + @Nonnull + @Override + public String getStatus() + { + return status; + } + + @Nonnull + @Override + public AuditableRestAction modifyStatus(@Nonnull String status) + { + Checks.notLonger(status, MAX_STATUS_LENGTH, "Voice Status"); + checkCanAccessChannel(); + if (this.equals(getGuild().getSelfMember().getVoiceState().getChannel())) + checkPermission(Permission.VOICE_SET_STATUS); + else + checkCanManage(); + + Route.CompiledRoute route = Route.Channels.SET_STATUS.compile(getId()); + DataObject body = DataObject.empty().put("status", status.isEmpty() ? null : status); + return new AuditableRestActionImpl<>(api, route, body); + } + @Override public TLongObjectMap getConnectedMembersMap() { @@ -210,6 +238,12 @@ public VoiceChannelImpl setLatestMessageIdLong(long latestMessageId) return this; } + public VoiceChannelImpl setStatus(String status) + { + this.status = status; + return this; + } + // -- Abstract Hooks -- @Override diff --git a/src/main/java/net/dv8tion/jda/internal/handle/VoiceChannelStatusUpdateHandler.java b/src/main/java/net/dv8tion/jda/internal/handle/VoiceChannelStatusUpdateHandler.java new file mode 100644 index 0000000000..a366e038f0 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/internal/handle/VoiceChannelStatusUpdateHandler.java @@ -0,0 +1,60 @@ +/* + * 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.internal.handle; + +import net.dv8tion.jda.api.events.channel.update.ChannelUpdateVoiceStatusEvent; +import net.dv8tion.jda.api.utils.data.DataObject; +import net.dv8tion.jda.internal.JDAImpl; +import net.dv8tion.jda.internal.entities.channel.concrete.VoiceChannelImpl; + +public class VoiceChannelStatusUpdateHandler extends SocketHandler +{ + public VoiceChannelStatusUpdateHandler(JDAImpl api) + { + super(api); + } + + @Override + protected Long handleInternally(DataObject content) + { + long guildId = content.getUnsignedLong("guild_id"); + if (getJDA().getGuildSetupController().isLocked(guildId)) + return guildId; + + long id = content.getUnsignedLong("id"); + VoiceChannelImpl channel = (VoiceChannelImpl) getJDA().getVoiceChannelsView().getElementById(id); + + if (channel == null) + { + EventCache.LOG.debug("Caching VOICE_CHANNEL_STATUS_UPDATE for uncached channel. ID: {}", id); + getJDA().getEventCache().cache(EventCache.Type.CHANNEL, id, responseNumber, allContent, this::handle); + return null; + } + + String newStatus = content.getString("status", ""); + if (!newStatus.equals(channel.getStatus())) + { + String oldStatus = channel.getStatus(); + channel.setStatus(newStatus); + api.handleEvent( + new ChannelUpdateVoiceStatusEvent( + api, responseNumber, + channel, oldStatus, newStatus)); + } + return null; + } +} diff --git a/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java b/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java index aa02b8e52e..6225bc0463 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java @@ -1416,6 +1416,7 @@ protected void setupHandlers() handlers.put("USER_UPDATE", new UserUpdateHandler(api)); handlers.put("VOICE_SERVER_UPDATE", new VoiceServerUpdateHandler(api)); handlers.put("VOICE_STATE_UPDATE", new VoiceStateUpdateHandler(api)); + handlers.put("VOICE_CHANNEL_STATUS_UPDATE", new VoiceChannelStatusUpdateHandler(api)); // Unused events handlers.put("CHANNEL_PINS_ACK", nopHandler);