Skip to content

Commit

Permalink
feat(chat): add message deletion feature
Browse files Browse the repository at this point in the history
Closes #12
  • Loading branch information
Silthus committed Nov 17, 2021
1 parent 1b367e2 commit a7b20bc
Show file tree
Hide file tree
Showing 18 changed files with 366 additions and 70 deletions.
12 changes: 8 additions & 4 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ Supercharge the Minecraft Chat Experience of your Players!
* [Installation](#installation)
* [Configuration](#configuration)
* [Commands](#commands)
* [Player Commands](#player-commands)
* [Admin Commands](#admin-commands)
* [Player Commands](#player-commands)
* [Admin Commands](#admin-commands)
* [Permissions](#permissions)
* [Channel Permissions](#channel-permissions)
* [Channel Permissions](#channel-permissions)
* [Plugin Integrations](#plugin-integrations)
* [PlaceholderAPI Support](#placeholderapi-support)
* [PlaceholderAPI Support](#placeholderapi-support)
* [Frequently Asked Questions](#frequently-asked-questions)
* [Are HEX colors supported?](#are-hex-colors-supported)

## Installation

Expand Down Expand Up @@ -61,6 +63,8 @@ e.g. clicking on a channel will set the channel as active*. However, here are th
| `schat.player.channel.leave` | Allows the player to leave channels. |
| `schat.player.channel.quickmessage` | Enables the player to send quick messages (`/ch <channel> <message>`) to channels he is allowed to write in. |
| `schat.player.directmessage` | Allows the player to send direct messages (`/dm <player> <message>`) to other players. |
| `schat.message.select` | Allows selecting chat messages for moderation or editing. |
| `schat.message.delete` | Allows deleting chat messages. |
| `schat.admin` | This permission groups all admin permissions nested under the `schat.admin.*` permissions. OPs get this by default. |
| `schat.admin.reload` | Allows performing the `/schat reload` command to reload the plugin. |

Expand Down
14 changes: 12 additions & 2 deletions src/main/java/net/silthus/chat/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public final class Constants {
public static final String PERMISSION_PLAYER_CHANNEL_LEAVE = "schat.player.channel.leave";
public static final String PERMISSION_PLAYER_CHANNEL_QUICKMESSAGE = "schat.player.channel.quickmessage";
public static final String PERMISSION_PLAYER_DIRECT_MESSAGE = "schat.player.directmessage";
public static final String PERMISSION_SELECT_MESSAGE = "schat.message.select";
public static final String PERMISSION_MESSAGE_DELETE = "schat.message.delete";
public static final String PERMISSION_ADMIN_RELOAD = "schat.admin.reload";

public static class Targets {
Expand Down Expand Up @@ -84,12 +86,18 @@ public static class Commands {
public static final String LEAVE_CHANNEL = "leave-channel";
public static final String INVALID_CONVERSATION = "invalid-conversation";
public static final String PLUGIN_RELOADED = "plugin-reloaded";
public static final String SELECTED_MESSAGE = "message.selected";
public static final String DELETED_MESSAGE = "message.deleted";
public static final String DESELECTED_MESSAGE = "message.deselected";
public static final String DELETE_MESSAGE_BUTTON = "message.delete-button";
public static final String DESELECT_MESSAGE_BUTTON = "message.deselect-button";

}

public static class Formats {

public static final String BASE_KEY = "formats";
public static final String PLAYER_CLICK = "player.click-to-send";
public static final String SELECT_MESSAGE = "message.select-to-moderate";
}
}

Expand Down Expand Up @@ -130,7 +138,9 @@ public static class Commands {
public static final Function<Conversation, String> LEAVE_CHANNEL = conversation -> "/schat channel leave " + conversation.getUniqueId();
public static final Function<Conversation, String> JOIN_CONVERSATION = conversation -> "/schat conversations set-active " + conversation.getUniqueId();
public static final Function<Conversation, String> LEAVE_CONVERSATION = conversation -> "/schat conversations leave " + conversation.getUniqueId();
public static final Function<ChatSource, String> PRIVATE_MESSAGE = source -> "/schat directmessage send " + source.getUniqueId();
public static final Function<ChatSource, String> PRIVATE_MESSAGE = source -> "/schat message send " + source.getUniqueId();
public static final Function<Message, String> SELECT_MESSAGE = message -> "/schat message select " + message.getId();
public static final Function<Message, String> DELETE_MESSAGE = message -> "/schat message delete " + message.getId();
}

public static class BungeeCord {
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/net/silthus/chat/SChat.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package net.silthus.chat;

import co.aikar.commands.InvalidCommandArgument;
import co.aikar.commands.MessageKeys;
import co.aikar.commands.PaperCommandManager;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
Expand Down Expand Up @@ -240,6 +241,7 @@ private void setupCommands() {
registerChatterContext(commandManager);
registerChannelContext(commandManager);
registerConversationContext(commandManager);
registerMessageContext(commandManager);

registerChannelCompletion(commandManager);
registerChatterCompletion(commandManager);
Expand Down Expand Up @@ -292,6 +294,20 @@ private void registerConversationContext(PaperCommandManager commandManager) {
commandManager.getCommandContexts().registerContext(Conversation.class, context -> getConversationManager().getConversation(UUID.fromString(context.popFirstArg())));
}

private void registerMessageContext(PaperCommandManager commandManager) {
commandManager.getCommandContexts().registerIssuerAwareContext(Message.class, context -> {
try {
final Chatter chatter = Chatter.of(context.getPlayer());
final Optional<Message> optionalMessage = chatter.getMessage(UUID.fromString(context.popFirstArg()));
if (optionalMessage.isEmpty())
throw new InvalidCommandArgument(MessageKeys.UNKNOWN_COMMAND);
return optionalMessage.get();
} catch (IllegalArgumentException e) {
throw new InvalidCommandArgument(MessageKeys.INVALID_SYNTAX);
}
});
}

private void registerChannelCompletion(PaperCommandManager commandManager) {
commandManager.getCommandCompletions().registerAsyncCompletion("channels", context ->
getChannelRegistry().getChannels().stream()
Expand Down
92 changes: 73 additions & 19 deletions src/main/java/net/silthus/chat/commands/SChatCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,24 @@
import co.aikar.commands.MessageType;
import co.aikar.commands.annotation.*;
import co.aikar.locales.MessageKey;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.silthus.chat.AccessDeniedException;
import net.silthus.chat.Conversation;
import net.silthus.chat.Message;
import net.silthus.chat.SChat;
import net.silthus.chat.*;
import net.silthus.chat.config.Language;
import net.silthus.chat.conversations.Channel;
import net.silthus.chat.identities.Chatter;
import org.jetbrains.annotations.NotNull;

import static net.kyori.adventure.text.event.ClickEvent.runCommand;
import static net.silthus.chat.Constants.*;
import static net.silthus.chat.Constants.Language.Commands.*;

@CommandAlias("schat")
@CommandPermission(PERMISSION_PLAYER_COMMANDS)
public class SChatCommands extends BaseCommand {

static MessageKey key(String key) {
return MessageKey.of(Language.Commands.BASE_KEY + "." + key);
return MessageKey.of(BASE_KEY + "." + key);
}

private final SChat plugin;
Expand All @@ -52,7 +54,7 @@ public SChatCommands(SChat plugin) {
@CommandPermission(PERMISSION_ADMIN_RELOAD)
public void reload() {
plugin.reload();
success(Language.Commands.PLUGIN_RELOADED);
success(PLUGIN_RELOADED);
}

@Subcommand("conversations")
Expand All @@ -62,7 +64,7 @@ public class ConversationCommands extends BaseCommand {
@CommandPermission(PERMISSION_PLAYER_CHANNEL_JOIN)
public void setActive(@Flags("self") Chatter chatter, Conversation conversation) {
if (!chatter.getConversations().contains(conversation)) {
throw new ConditionFailedException(key(Language.Commands.INVALID_CONVERSATION));
throw new ConditionFailedException(key(INVALID_CONVERSATION));
}
chatter.setActiveConversation(conversation);
chatter.updateView();
Expand All @@ -72,7 +74,7 @@ public void setActive(@Flags("self") Chatter chatter, Conversation conversation)
@CommandPermission(PERMISSION_PLAYER_CHANNEL_LEAVE)
private void leave(@Flags("self") Chatter chatter, Conversation conversation) {
if (!chatter.getConversations().contains(conversation)) {
throw new ConditionFailedException(key(Language.Commands.INVALID_CONVERSATION));
throw new ConditionFailedException(key(INVALID_CONVERSATION));
}
chatter.unsubscribe(conversation);
chatter.updateView();
Expand All @@ -81,7 +83,6 @@ private void leave(@Flags("self") Chatter chatter, Conversation conversation) {

@Subcommand("channel|ch")
@CommandAlias("channel")
@CommandPermission(PERMISSION_PLAYER_CHANNEL_COMMANDS)
public class ChannelCommands extends BaseCommand {

@Subcommand("join")
Expand All @@ -91,11 +92,11 @@ public class ChannelCommands extends BaseCommand {
public void join(@Flags("self") Chatter chatter, Channel channel) {
try {
chatter.join(channel);
success(Language.Commands.JOINED_CHANNEL, "{channel}", getChannelName(channel));
success(JOINED_CHANNEL, "{channel}", getChannelName(channel));
chatter.updateView();
} catch (AccessDeniedException e) {
error(Language.Commands.ACCESS_TO_CHANNEL_DENIED, "{channel}", getChannelName(channel));
throw new ConditionFailedException(key(Language.Commands.ACCESS_TO_CHANNEL_DENIED), "{channel}", getChannelName(channel));
error(ACCESS_TO_CHANNEL_DENIED, "{channel}", getChannelName(channel));
throw new ConditionFailedException(key(ACCESS_TO_CHANNEL_DENIED), "{channel}", getChannelName(channel));
}
}

Expand All @@ -105,7 +106,7 @@ public void join(@Flags("self") Chatter chatter, Channel channel) {
@CommandPermission(PERMISSION_PLAYER_CHANNEL_LEAVE)
public void leave(@Flags("self") Chatter chatter, Channel channel) {
chatter.unsubscribe(channel);
success(Language.Commands.LEAVE_CHANNEL, "{channel}", getChannelName(channel));
success(LEAVE_CHANNEL, "{channel}", getChannelName(channel));
chatter.updateView();
}

Expand All @@ -117,22 +118,22 @@ public void quickMessage(@Flags("self") Chatter chatter, Channel channel, String
if (chatter.canSendMessage(channel)) {
Message.message(chatter, message).to(channel).send();
} else {
error(Language.Commands.SEND_TO_CHANNEL_DENIED, "{channel}", getChannelName(channel));
throw new ConditionFailedException(key(Language.Commands.SEND_TO_CHANNEL_DENIED), "{channel}", getChannelName(channel));
error(SEND_TO_CHANNEL_DENIED, "{channel}", getChannelName(channel));
throw new ConditionFailedException(key(SEND_TO_CHANNEL_DENIED), "{channel}", getChannelName(channel));
}
}
}

@Subcommand("directmessage")
@CommandPermission(PERMISSION_PLAYER_DIRECT_MESSAGE)
@Subcommand("message")
public class DirectMessageCommands extends BaseCommand {

@Subcommand("send")
@CommandAlias("m|tell|msg|message|w|dm|pm|qm")
@CommandCompletion("@chatters *")
@CommandPermission(PERMISSION_PLAYER_DIRECT_MESSAGE)
public void directMessage(@Flags("self") Chatter source, Chatter target, @Optional String message) {
if (source.equals(target))
throw new ConditionFailedException(key(Language.Commands.CANNOT_SEND_TO_SELF));
throw new ConditionFailedException(key(CANNOT_SEND_TO_SELF));

if (message != null) {
source.message(message).to(target).send();
Expand All @@ -141,6 +142,47 @@ public void directMessage(@Flags("self") Chatter source, Chatter target, @Option
source.updateView();
}
}

@Subcommand("select")
@CommandPermission(PERMISSION_SELECT_MESSAGE)
public void select(@Flags("self") Chatter chatter, Message message) {
final Boolean messageIsSelected = chatter.getView().selectedMessage()
.map(msg -> msg.equals(message)).orElse(false);
if (messageIsSelected) {
deselectMessage(chatter);
sender().sendActionBar(lang(DESELECTED_MESSAGE));
} else {
chatter.getView().selectedMessage(message);
chatter.getView().footer(deleteButton(message).append(abortButton(message)));
sender().sendActionBar(lang(SELECTED_MESSAGE));
}
chatter.updateView();
}

@Subcommand("delete")
@CommandPermission(PERMISSION_MESSAGE_DELETE)
public void delete(@Flags("self") Chatter chatter, Message message) {
deselectMessage(chatter);
message.delete();
sender().sendActionBar(lang(DELETED_MESSAGE));
}

private void deselectMessage(@Flags("self") Chatter chatter) {
chatter.getView().selectedMessage(null);
chatter.getView().footer(null);
}

@NotNull
private Component deleteButton(Message message) {
if (getCurrentCommandIssuer().hasPermission(PERMISSION_MESSAGE_DELETE))
return lang(DELETE_MESSAGE_BUTTON).clickEvent(runCommand(Commands.DELETE_MESSAGE.apply(message)));
return Component.empty();
}

@NotNull
private Component abortButton(Message message) {
return lang(DESELECT_MESSAGE_BUTTON).clickEvent(runCommand(Commands.SELECT_MESSAGE.apply(message)));
}
}

private String getChannelName(Channel channel) {
Expand All @@ -154,4 +196,16 @@ private void success(String key, String... replacements) {
private void error(String key, String... replacements) {
getCurrentCommandIssuer().sendMessage(MessageType.ERROR, key(key), replacements);
}

private Audience sender() {
return plugin.getAudiences().sender(getCurrentCommandIssuer().getIssuer());
}

private Component lang(String key) {
return lang().get(key);
}

private Language lang() {
return plugin.language().section(Constants.Language.Commands.BASE_KEY);
}
}
5 changes: 5 additions & 0 deletions src/main/java/net/silthus/chat/config/Language.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.silthus.chat.Constants;
import org.bukkit.configuration.ConfigurationSection;

import java.util.Locale;
Expand All @@ -44,6 +45,10 @@ public Language(ConfigurationSection config, Locale locale) {
this.locale = locale;
}

public Language commands() {
return section(Constants.Language.Commands.BASE_KEY);
}

public Language section(String key) {
final ConfigurationSection section = config.getConfigurationSection(key);
if (section == null) return new Language(config.createSection(key), locale);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ public void removeTarget(@NonNull ChatTarget target) {

@Override
public boolean deleteMessage(Message message) {
if (super.deleteMessage(message)) {
final boolean deleted = super.deleteMessage(message);
if (deleted)
getTargets().forEach(target -> target.deleteMessage(message));
return true;
}
return false;
return deleted;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ private void deleteMessageFromUnreadMessages(Message message) {

protected abstract void processMessage(Message message);

public Optional<Message> getMessage(UUID messageId) {
return receivedMessages.stream().filter(message -> message.getId().equals(messageId)).findFirst();
}

@Override
public Message getLastReceivedMessage() {
if (receivedMessages.isEmpty()) return null;
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/net/silthus/chat/identities/Chatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ public Optional<Player> getPlayer() {
return Optional.ofNullable(Bukkit.getPlayer(getUniqueId()));
}

@Override
public boolean deleteMessage(Message message) {
final boolean deleted = super.deleteMessage(message);
if (deleted)
updateView();
return deleted;
}

public void updateView() {
getPlayer().ifPresent(view::sendTo);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,10 @@ public void sendConversation(Conversation conversation) {

@Override
public boolean deleteMessage(Message message) {
if (super.deleteMessage(message)) {
final boolean deleted = super.deleteMessage(message);
if (deleted)
sendPluginMessage(forwardToAllServers(DELETE_MESSAGE), json(new MessageDto(message)));
return true;
}
return false;
return deleted;
}

@Override
Expand Down
Loading

0 comments on commit a7b20bc

Please sign in to comment.