diff --git a/Plugins/Mineplex.ChatSnapManager/src/META-INF/MANIFEST.MF b/Plugins/Mineplex.ChatSnapManager/src/META-INF/MANIFEST.MF index b5d0a64ef..a745c0202 100644 --- a/Plugins/Mineplex.ChatSnapManager/src/META-INF/MANIFEST.MF +++ b/Plugins/Mineplex.ChatSnapManager/src/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ Manifest-Version: 1.0 -Main-Class: mineplex.chatsnap.ChatSnapManager +Main-Class: mineplex.chatsnap.ReportServer diff --git a/Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/JedisPubSubHandler.java b/Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/JedisPubSubHandler.java index c1feff9a8..6e4355c7d 100644 --- a/Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/JedisPubSubHandler.java +++ b/Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/JedisPubSubHandler.java @@ -35,7 +35,7 @@ public class JedisPubSubHandler extends JedisPubSub @Override public void onMessage(String channel, String dataString) { - if (channel.equals(ChatSnapManager.CHANNEL_DEPLOY)) + if (channel.equals(ReportServer.CHANNEL_DEPLOY)) { JsonObject data = _gson.fromJson(dataString, JsonObject.class); String token = data.get("token").getAsString(); @@ -53,7 +53,7 @@ public class JedisPubSubHandler extends JedisPubSub e.printStackTrace(); } } - else if (channel.equals(ChatSnapManager.CHANNEL_DESTROY)) + else if (channel.equals(ReportServer.CHANNEL_DESTROY)) { // dataString = token File target = new File(_directory, dataString + ".json"); diff --git a/Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/ChatSnapManager.java b/Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/ReportServer.java similarity index 85% rename from Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/ChatSnapManager.java rename to Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/ReportServer.java index 69e7f72d2..792bccab8 100644 --- a/Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/ChatSnapManager.java +++ b/Plugins/Mineplex.ChatSnapManager/src/mineplex/chatsnap/ReportServer.java @@ -9,21 +9,21 @@ import redis.clients.jedis.JedisPoolConfig; /** * @author iKeirNez */ -public class ChatSnapManager +public class ReportServer { public static final String CHANNEL_DEPLOY = "chatsnap:deploy"; public static final String CHANNEL_DESTROY = "chatsnap:destroy"; public static void main(String[] args) { - new ChatSnapManager(new JedisPool(new JedisPoolConfig(), "10.3.203.80", 6379)); // TODO is this okay? + new ReportServer(new JedisPool(new JedisPoolConfig(), "10.3.203.80", 6379)); // TODO is this okay? System.out.println("Started."); } private JedisPool _jedisPool; private File dataDirectory = new File("data"); - public ChatSnapManager(JedisPool jedisPool) + public ReportServer(JedisPool jedisPool) { _jedisPool = jedisPool; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshot.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshot.java deleted file mode 100644 index 0a78dcf1f..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshot.java +++ /dev/null @@ -1,91 +0,0 @@ -package mineplex.core.chatsnap; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -import org.bukkit.ChatColor; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Represents a message sent by a player. - * @author iKeirNez - */ -public class MessageSnapshot implements Comparable -{ - private UUID sender; - private Collection recipients; - private String message; - private long time; - - public MessageSnapshot(UUID sender, Collection recipients, String message) - { - this(sender, recipients, message, System.currentTimeMillis()); - } - - public MessageSnapshot(UUID sender, Collection recipients, String message, long time) - { - this.sender = checkNotNull(sender); - this.recipients = checkNotNull(recipients); - this.message = checkNotNull(message); - this.time = checkNotNull(time); - } - - public UUID getSender() - { - return sender; - } - - public String getMessage() - { - return message; - } - - public Set getRecipients() - { - return new HashSet<>(recipients); - } - - public long getTime() - { - return time; - } - - @Override - public int compareTo(MessageSnapshot o) - { - return Long.compare(getTime(), o.getTime()); - } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MessageSnapshot that = (MessageSnapshot) o; - return time == that.time && - Objects.equals(sender, that.sender) && - Objects.equals(recipients, that.recipients) && - Objects.equals(message, that.message); - } - - @Override - public int hashCode() - { - return Objects.hash(sender, recipients, message, time); - } - - @Override - public String toString() - { - return "MessageSnapshot{" + - "sender=" + sender + - ", recipients=" + recipients + - ", message='" + ChatColor.stripColor(message) + '\'' + - ", time=" + time + - '}'; - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshotManager.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshotManager.java deleted file mode 100644 index 573379471..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshotManager.java +++ /dev/null @@ -1,181 +0,0 @@ -package mineplex.core.chatsnap; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import org.bukkit.Bukkit; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import mineplex.serverdata.Utility; -import mineplex.serverdata.servers.ServerManager; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; - -/** - * Handles temporary storage of {@link MessageSnapshot} instances. - * @author iKeirNez - */ -public class MessageSnapshotManager -{ - private static final String URL_PREFIX = "http://chatsnap.mineplex.com/"; - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - - public static final String CHANNEL_DEPLOY = "chatsnap:deploy"; - public static final String CHANNEL_DESTROY = "chatsnap:destroy"; - - public static String getChatLogUrl(String token) - { - return URL_PREFIX + token; - } - - // There aren't any List or Set caching implementations - // For an easy work around, we store values as the Key - // For the value we just use some dummy object - // I went with Boolean as it's the smallest data type - private final Cache _snapshots = CacheBuilder.newBuilder() - .concurrencyLevel(4) - .expireAfterWrite(30, TimeUnit.MINUTES) - .build(); - - private JedisPool _jedisPool; - - public MessageSnapshotManager() - { - _jedisPool = Utility.generatePool(ServerManager.getMasterConnection()); // TODO is this the best way? - } - - /** - * Keeps a snapshot in memory temporarily (30 minutes) and then discards it. - * During this time, other modules (such as the Report module) can access it for their own use. - * - * @param messageSnapshot the snapshot to temporarily store - */ - public void cacheSnapshot(MessageSnapshot messageSnapshot) - { - _snapshots.put(messageSnapshot, true); - } - - /** - * Gets all currently stored snapshots. - * The set is in chronological order of the time the message was sent. - * - * @return a set containing all snapshots - */ - public Set getSnapshots() - { - // The compareTo method in MessageSnapshot will ensure this in chronological order - Set snapshots = new TreeSet<>(); - snapshots.addAll(_snapshots.asMap().keySet()); - return snapshots; - } - - /** - * Gets all instances of {@link MessageSnapshot} which involve a particular user. - * The user may be the sender or recipient of a message. - * - * @param search the user to search for snaps involved in - * @return the snaps that the user is involved in - */ - public Set getSnapshots(UUID search) - { - Set matches = new TreeSet<>(); - - for (MessageSnapshot messageSnapshot : _snapshots.asMap().keySet()) - { - if (messageSnapshot.getSender().equals(search) || messageSnapshot.getRecipients().contains(search)) - { - matches.add(messageSnapshot); - } - } - - return matches; - } - - public void publishChatLog(String token, UUID playerUUID) - { - Set snapshots = getSnapshots(playerUUID); - Map uuidUsernameMap = getUsernames(getUUIDs(snapshots)); - - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("token", token); - jsonObject.addProperty("time_generated", System.currentTimeMillis()); - jsonObject.add("snapshots", GSON.toJsonTree(snapshots)); - jsonObject.add("usernames", GSON.toJsonTree(uuidUsernameMap)); - String json = GSON.toJson(jsonObject); - - try (Jedis jedis = _jedisPool.getResource()) - { - jedis.publish(CHANNEL_DEPLOY, json); - } - - /*try - { - File dir = new File("data"); - dir.mkdir(); - File file = new File(dir, playerUUID + "-" + token + ".json"); - file.createNewFile(); - BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); - bufferedWriter.write(json); - bufferedWriter.close(); - } - catch (IOException e) - { - e.printStackTrace(); - }*/ - } - - public void unpublishChatLog(String token) - { - try (Jedis jedis = _jedisPool.getResource()) - { - jedis.publish(CHANNEL_DESTROY, token); - } - } - - private static Set getUUIDs(Collection snapshots) - { - // Being a Set ensures no duplicates - Set uuids = new HashSet<>(); - - for (MessageSnapshot messageSnapshot : snapshots) - { - uuids.add(messageSnapshot.getSender()); - - for (UUID recipient : messageSnapshot.getRecipients()) - { - uuids.add(recipient); - } - } - - return uuids; - } - - private static Map getUsernames(Collection collection) - { - Map uuidUsernameMap = new HashMap<>(); - - for (UUID uuid : collection) - { - String username = Bukkit.getOfflinePlayer(uuid).getName(); - uuidUsernameMap.put(uuid, username); - } - - return uuidUsernameMap; - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageType.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageType.java new file mode 100644 index 000000000..d328b3038 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageType.java @@ -0,0 +1,9 @@ +package mineplex.core.chatsnap; + +/** + * @author iKeirNez + */ +public enum MessageType +{ + CHAT, PRIVATE; +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/Snapshot.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/Snapshot.java new file mode 100644 index 000000000..a20bb86f0 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/Snapshot.java @@ -0,0 +1,120 @@ +package mineplex.core.chatsnap; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.ChatColor; + +import com.google.gson.annotations.SerializedName; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a message sent by a player. + * @author iKeirNez + */ +public class Snapshot implements Comparable +{ + @SerializedName("type") + private MessageType _messageType; + + @SerializedName("sender") + private UUID _sender; + + @SerializedName("recipients") + private Collection _recipients; + + @SerializedName("message") + private String _message; + + @SerializedName("time") + private LocalDateTime _time; + + public Snapshot(UUID sender, UUID recipient, String message) + { + this(MessageType.PRIVATE, sender, Collections.singletonList(recipient), message, LocalDateTime.now()); + } + + public Snapshot(UUID sender, Collection recipients, String message) + { + this(MessageType.CHAT, sender, recipients, message, LocalDateTime.now()); + } + + public Snapshot(MessageType messageType, UUID sender, Collection recipients, String message, LocalDateTime time) + { + _messageType = messageType; + _sender = checkNotNull(sender); + _recipients = checkNotNull(recipients); + _message = checkNotNull(message); + _time = checkNotNull(time); + + if (messageType == MessageType.PRIVATE && recipients.size() > 1) + { + throw new IllegalArgumentException("Snapshot type PRIVATE may not have more than 1 recipient."); + } + } + + public MessageType getMessageType() + { + return _messageType; + } + + public UUID getSender() + { + return _sender; + } + + public String getMessage() + { + return _message; + } + + public Set getRecipients() + { + return new HashSet<>(_recipients); + } + + public LocalDateTime getSentTime() + { + return _time; + } + + @Override + public int compareTo(Snapshot o) + { + return getSentTime().compareTo(o.getSentTime()); + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Snapshot that = (Snapshot) o; + return _time == that._time && + Objects.equals(_sender, that._sender) && + Objects.equals(_recipients, that._recipients) && + Objects.equals(_message, that._message); + } + + @Override + public int hashCode() + { + return Objects.hash(_sender, _recipients, _message, _time); + } + + @Override + public String toString() + { + return "Snapshot{" + + "sender=" + _sender + + ", recipients=" + _recipients + + ", message='" + ChatColor.stripColor(_message) + '\'' + + ", created=" + _time + + '}'; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/SnapshotManager.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/SnapshotManager.java new file mode 100644 index 000000000..1dfac2f1d --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/SnapshotManager.java @@ -0,0 +1,80 @@ +package mineplex.core.chatsnap; + +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import mineplex.core.chatsnap.publishing.SnapshotPublisher; + +/** + * Handles temporary storage of {@link Snapshot} instances. + * @author iKeirNez + */ +public class SnapshotManager +{ + // There aren't any List or Set caching implementations + // For an easy work around, we store values as the Key + // For the value we just use some dummy object + // I went with Boolean as it's the smallest data type + private final Cache _snapshots = CacheBuilder.newBuilder() + .concurrencyLevel(4) + .expireAfterWrite(30, TimeUnit.MINUTES) + .build(); + + private final SnapshotPublisher _publisher = new SnapshotPublisher(); + + public SnapshotPublisher getPublisher() + { + return _publisher; + } + + /** + * Keeps a snapshot in memory temporarily (30 minutes) and then discards it. + * During this time, other modules (such as the Report module) can access it for their own use. + * + * @param snapshot the snapshot to temporarily store + */ + public void cacheSnapshot(Snapshot snapshot) + { + _snapshots.put(snapshot, true); + } + + /** + * Gets all currently stored snapshots. + * The set is in chronological order of the time the message was sent. + * + * @return a set containing all snapshots + */ + public Set getSnapshots() + { + // The compareTo method in Snapshot will ensure this in chronological order + Set snapshots = new TreeSet<>(); + snapshots.addAll(_snapshots.asMap().keySet()); + return snapshots; + } + + /** + * Gets all instances of {@link Snapshot} which involve a particular user. + * The user may be the sender or recipient of a message. + * + * @param search the user to search for snaps involved in + * @return the snaps that the user is involved in + */ + public Set getSnapshots(UUID search) + { + Set matches = new TreeSet<>(); + + for (Snapshot snapshot : _snapshots.asMap().keySet()) + { + if (snapshot.getSender().equals(search) || snapshot.getRecipients().contains(search)) + { + matches.add(snapshot); + } + } + + return matches; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshotPlugin.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/SnapshotPlugin.java similarity index 62% rename from Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshotPlugin.java rename to Plugins/Mineplex.Core/src/mineplex/core/chatsnap/SnapshotPlugin.java index ad996cf09..541eb2923 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/MessageSnapshotPlugin.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/SnapshotPlugin.java @@ -16,19 +16,19 @@ import mineplex.core.chatsnap.commands.ChatCacheCommand; /** * @author iKeirNez */ -public class MessageSnapshotPlugin extends MiniPlugin +public class SnapshotPlugin extends MiniPlugin { - private final MessageSnapshotManager _messageSnapshotManager; + private final SnapshotManager _snapshotManager; - public MessageSnapshotPlugin(JavaPlugin plugin, MessageSnapshotManager messageSnapshotManager) + public SnapshotPlugin(JavaPlugin plugin, SnapshotManager snapshotManager) { super("ChatSnap", plugin); - _messageSnapshotManager = messageSnapshotManager; + _snapshotManager = snapshotManager; } - public MessageSnapshotManager getMessageSnapshotManager() + public SnapshotManager getSnapshotManager() { - return _messageSnapshotManager; + return _snapshotManager; } @Override @@ -40,7 +40,7 @@ public class MessageSnapshotPlugin extends MiniPlugin @EventHandler(priority = EventPriority.MONITOR) public void onPlayerChat(AsyncPlayerChatEvent e) { - _messageSnapshotManager.cacheSnapshot(getMessageSnap(e)); + _snapshotManager.cacheSnapshot(getSnapshot(e)); } public Set getUUIDSet(Set playerSet) @@ -54,9 +54,9 @@ public class MessageSnapshotPlugin extends MiniPlugin return uuidSet; } - public MessageSnapshot getMessageSnap(AsyncPlayerChatEvent e) + public Snapshot getSnapshot(AsyncPlayerChatEvent e) { Set uuidSet = getUUIDSet(e.getRecipients()); - return new MessageSnapshot(e.getPlayer().getUniqueId(), uuidSet, e.getMessage()); + return new Snapshot(e.getPlayer().getUniqueId(), uuidSet, e.getMessage()); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/commands/ChatCacheCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/commands/ChatCacheCommand.java index 11b41d759..9c51ecac7 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/commands/ChatCacheCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/commands/ChatCacheCommand.java @@ -6,8 +6,8 @@ import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; -import mineplex.core.chatsnap.MessageSnapshotPlugin; -import mineplex.core.chatsnap.MessageSnapshot; +import mineplex.core.chatsnap.SnapshotPlugin; +import mineplex.core.chatsnap.Snapshot; import mineplex.core.command.CommandBase; import mineplex.core.common.Rank; import mineplex.core.common.util.F; @@ -17,9 +17,9 @@ import mineplex.core.common.util.UtilPlayer; * Displays what chat messages we have cached for a player. * @author iKeirNez */ -public class ChatCacheCommand extends CommandBase +public class ChatCacheCommand extends CommandBase { - public ChatCacheCommand(MessageSnapshotPlugin plugin) + public ChatCacheCommand(SnapshotPlugin plugin) { super(plugin, Rank.MODERATOR, "chatcache"); } @@ -42,12 +42,12 @@ public class ChatCacheCommand extends CommandBase public void run() { OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName); - Set snaps = Plugin.getMessageSnapshotManager().getSnapshots(offlinePlayer.getUniqueId()); + Set snaps = Plugin.getSnapshotManager().getSnapshots(offlinePlayer.getUniqueId()); - for (MessageSnapshot messageSnapshot : snaps) + for (Snapshot snapshot : snaps) { // TODO: show sender name - caller.sendMessage(messageSnapshot.getMessage()); + caller.sendMessage(snapshot.getMessage()); } } }); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/LocalDateTimeSerializer.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/LocalDateTimeSerializer.java new file mode 100644 index 000000000..5a9366c14 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/LocalDateTimeSerializer.java @@ -0,0 +1,33 @@ +package mineplex.core.chatsnap.publishing; + +import java.lang.reflect.Type; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +/** + * @author iKeirNez + */ +public class LocalDateTimeSerializer implements JsonSerializer +{ + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; + + private ZoneId _zoneId; + + public LocalDateTimeSerializer(ZoneId zoneId) + { + _zoneId = zoneId; + } + + @Override + public JsonElement serialize(LocalDateTime localDateTime, Type type, JsonSerializationContext jsonSerializationContext) + { + return new JsonPrimitive(localDateTime.atZone(_zoneId).toLocalDateTime().truncatedTo(ChronoUnit.SECONDS).format(FORMATTER)); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/ReportSerializer.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/ReportSerializer.java new file mode 100644 index 000000000..8e14cbb78 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/ReportSerializer.java @@ -0,0 +1,32 @@ +package mineplex.core.chatsnap.publishing; + +import java.lang.reflect.Type; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import mineplex.core.report.Report; + +/** + * @author iKeirNez + */ +public class ReportSerializer implements JsonSerializer +{ + @Override + public JsonElement serialize(Report report, Type type, JsonSerializationContext jsonSerializationContext) + { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("id", report.getReportId()); + jsonObject.addProperty("serverName", report.getServerName()); + + if (report.getHandler() != null) + { + jsonObject.addProperty("handler", report.getHandler().toString()); + } + + jsonObject.addProperty("suspect", report.getSuspect().toString()); + jsonObject.add("reporters", jsonSerializationContext.serialize(report.getReportReasons())); + return jsonObject; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/SnapshotPublisher.java b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/SnapshotPublisher.java new file mode 100644 index 000000000..6dbca2174 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/chatsnap/publishing/SnapshotPublisher.java @@ -0,0 +1,132 @@ +package mineplex.core.chatsnap.publishing; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.Bukkit; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.FieldNamingStrategy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import mineplex.core.chatsnap.Snapshot; +import mineplex.core.report.Report; +import mineplex.serverdata.Utility; +import mineplex.serverdata.servers.ServerManager; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; + +/** + * @author iKeirNez + */ +public class SnapshotPublisher +{ + private static final ZoneId ZONE_ID = ZoneId.of("US/Central"); + private static final Gson GSON = new GsonBuilder() + .setPrettyPrinting() + .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer(ZONE_ID)) + .registerTypeAdapter(Report.class, new ReportSerializer()) + .create(); + + public static ZoneId getZoneId() + { + return ZONE_ID; + } + + public static Gson getGson() + { + return GSON; + } + + public static String getURL(String token) + { + return URL_PREFIX + token; + } + + private static final String URL_PREFIX = "http://chatsnap.mineplex.com/"; + public static final String CHANNEL_DEPLOY = "chatsnap:deploy"; + public static final String CHANNEL_DESTROY = "chatsnap:destroy"; + + private JedisPool _jedisPool; + + public SnapshotPublisher() + { + _jedisPool = Utility.generatePool(ServerManager.getMasterConnection()); // TODO is this the best way? + } + + public void publishChatLog(String token, JsonObject jsonObject) + { + jsonObject.addProperty("token", token); + String json = GSON.toJson(jsonObject); + + /*try (Jedis jedis = _jedisPool.getResource()) + { + jedis.publish(CHANNEL_DEPLOY, json); + }*/ + + try + { + File dir = new File("data"); + dir.mkdir(); + File file = new File(dir, token + ".json"); + file.createNewFile(); + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); + bufferedWriter.write(json); + bufferedWriter.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + public void unpublishChatLog(String token) + { + try (Jedis jedis = _jedisPool.getResource()) + { + jedis.publish(CHANNEL_DESTROY, token); + } + } + + public Set getUUIDs(Collection snapshots) + { + // Being a Set ensures no duplicates + Set uuids = new HashSet<>(); + + for (Snapshot snapshot : snapshots) + { + uuids.add(snapshot.getSender()); + + for (UUID recipient : snapshot.getRecipients()) + { + uuids.add(recipient); + } + } + + return uuids; + } + + public Map getUsernameMap(Collection collection) + { + Map uuidUsernameMap = new HashMap<>(); + + for (UUID uuid : collection) + { + String username = Bukkit.getOfflinePlayer(uuid).getName(); + uuidUsernameMap.put(uuid, username); + } + + return uuidUsernameMap; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/report/Report.java b/Plugins/Mineplex.Core/src/mineplex/core/report/Report.java index 049eb92ea..6d28313d7 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/report/Report.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/report/Report.java @@ -3,6 +3,7 @@ package mineplex.core.report; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.TimeUnit; import mineplex.serverdata.data.Data; @@ -19,18 +20,18 @@ public class Report implements Data private String _serverName; public String getServerName() { return _serverName; } - private String _playerName; - public String getPlayerName() { return _playerName; } + private UUID _suspect; + public UUID getSuspect() { return _suspect; } // Set of player names and the reason they reported this player - private Map _reportReasons; - public Map getReportReasons() { return _reportReasons; } - public Set getReporters() { return _reportReasons.keySet(); } - public void addReporter(String reporter, String reason) { _reportReasons.put(reporter, reason); } + private Map _reportReasons; + public Map getReportReasons() { return _reportReasons; } + public Set getReporters() { return _reportReasons.keySet(); } + public void addReporter(UUID reporter, String reason) { _reportReasons.put(reporter, reason); } - private String _handler = null; - public void setHandler(String handler) { _handler = handler; } - public String getHandler() { return _handler; } + private UUID _handler = null; + public void setHandler(UUID handler) { _handler = handler; } + public UUID getHandler() { return _handler; } private ReportCategory _category; public ReportCategory getCategory() { return _category; } @@ -40,10 +41,10 @@ public class Report implements Data private String _token = null; - public Report(int reportId, String playerName, String serverName, ReportCategory category) + public Report(int reportId, UUID suspect, String serverName, ReportCategory category) { _reportId = reportId; - _playerName = playerName; + _suspect = suspect; _serverName = serverName; _reportReasons = new HashMap<>(); _category = category; @@ -78,7 +79,7 @@ public class Report implements Data * * @return the full token */ - public String getChatSnapToken() + public String getUniqueToken() { // since we don't always use this, only generate a token when we need it if (_token == null) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/report/ReportManager.java b/Plugins/Mineplex.Core/src/mineplex/core/report/ReportManager.java index db5c0ed31..a842e4c08 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/report/ReportManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/report/ReportManager.java @@ -1,17 +1,19 @@ package mineplex.core.report; +import java.time.LocalDateTime; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import mineplex.core.account.CoreClient; -import mineplex.core.chatsnap.MessageSnapshot; -import mineplex.core.chatsnap.MessageSnapshotManager; +import mineplex.core.chatsnap.Snapshot; +import mineplex.core.chatsnap.SnapshotManager; +import mineplex.core.chatsnap.publishing.SnapshotPublisher; import mineplex.core.command.CommandCenter; import mineplex.core.common.Rank; import mineplex.core.common.jsonchat.ClickEvent; @@ -32,11 +34,11 @@ import mineplex.serverdata.commands.ServerCommandManager; import mineplex.serverdata.data.DataRepository; import mineplex.serverdata.redis.RedisDataRepository; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.plugin.java.JavaPlugin; -import mineplex.serverdata.servers.ServerManager; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.exceptions.JedisConnectionException; @@ -58,7 +60,7 @@ public class ReportManager { private JavaPlugin _javaPlugin; private PreferencesManager _preferencesManager; private StatsManager _statsManager; - private MessageSnapshotManager _messageSnapshotManager; + private SnapshotManager _snapshotManager; private String _serverName; // Holds active/open reports in a synchronized database. @@ -71,12 +73,12 @@ public class ReportManager { private Map _activeReports; public ReportManager(JavaPlugin javaPlugin, PreferencesManager preferencesManager, StatsManager statsManager, - MessageSnapshotManager messageSnapshotManager, String serverName) + SnapshotManager snapshotManager, String serverName) { _javaPlugin = javaPlugin; _preferencesManager = preferencesManager; _statsManager = statsManager; - _messageSnapshotManager = messageSnapshotManager; + _snapshotManager = snapshotManager; _serverName = serverName; _reportRepository = new RedisDataRepository(Region.ALL, Report.class, "reports"); _activeReports = new HashMap(); @@ -98,13 +100,14 @@ public class ReportManager { removeReport(reportId); int closerId = reportCloser != null ? getPlayerAccount(reportCloser).getAccountId() : -1; - String playerName = report.getPlayerName(); - int playerId = getPlayerAccount(playerName).getAccountId(); + String suspectName = Bukkit.getOfflinePlayer(report.getSuspect()).getName(); + int playerId = getPlayerAccount(suspectName).getAccountId(); _reportSqlRepository.logReport(reportId, playerId, _serverName, closerId, result, reason); // Update the reputation/profiles of all reporters on this closing report. - for (String reporterName : report.getReporters()) + for (UUID reporterUUID : report.getReporters()) { + String reporterName = Bukkit.getOfflinePlayer(reporterUUID).getName(); incrementStat(reporterName, result); } @@ -116,12 +119,12 @@ public class ReportManager { reportCloser.getName(), reason, result.toDisplayMessage() + C.mBody))); CommandCenter.Instance.OnPlayerCommandPreprocess( - new PlayerCommandPreprocessEvent(reportCloser, "/punish " + playerName + " " + reason)); + new PlayerCommandPreprocessEvent(reportCloser, "/punish " + suspectName + " " + reason)); } if (report.getCategory() == ReportCategory.CHAT_ABUSE) // only chat abuse reports have chat logs published { - _messageSnapshotManager.unpublishChatLog(report.getChatSnapToken()); + _snapshotManager.getPublisher().unpublishChatLog(report.getUniqueToken()); } } } @@ -136,7 +139,7 @@ public class ReportManager { reportHandler.sendMessage(F.main(getReportPrefix(reportId), String.format("%s is already handling this report.", report.getHandler()))); } else { String handlerName = reportHandler.getName(); - report.setHandler(handlerName); + report.setHandler(reportHandler.getUniqueId()); saveReport(report); sendStaffNotification(F.main(getReportPrefix(reportId), String.format("%s is handling this report.", handlerName))); @@ -180,12 +183,12 @@ public class ReportManager { if (report != null && report.getCategory() == category) { - report.addReporter(reporter.getName(), reason); + report.addReporter(reporter.getUniqueId(), reason); } else { - report = new Report(generateReportId(), reportedPlayer.getName(), _serverName, category); - report.addReporter(reporter.getName(), reason); + report = new Report(generateReportId(), reportedPlayer.getUniqueId(), _serverName, category); + report.addReporter(reporter.getUniqueId(), reason); _activeReports.put(reportedPlayer.getName().toLowerCase(), report.getReportId()); } @@ -193,17 +196,19 @@ public class ReportManager { saveReport(report); // only start notifying staff when - if (/*report.getReporters().size() >= category.getNotifyThreshold()*/true) + if (/*report.getReporters().size() >= category.getNotifyThreshold()*/true) // TODO REMVOE { - _messageSnapshotManager.publishChatLog(report.getChatSnapToken(), reportedPlayer.getUniqueId()); + publishChatAbuse(report); + int reportId = report.getReportId(); String prefix = getReportPrefix(reportId); + String suspectName = Bukkit.getOfflinePlayer(report.getSuspect()).getName(); // Report #2 > iKeirNez - Flying around in arcade game (Hacking) // Report #2 > Reported by Chiss. // Report #2 > 5 total reporter(s). JsonMessage message = new JsonMessage(F.main(prefix, String.format("%s - %s (%s)", - C.cGoldB + report.getPlayerName() + C.mBody, + C.cGoldB + suspectName + C.mBody, reason, C.cGoldB + report.getCategory().getTitle() + C.mBody)) + "\n" + F.main(prefix, String.format("Reported by %s.", reporter.getName())) @@ -230,6 +235,39 @@ public class ReportManager { return null; } + public void publishChatAbuse(Report report) + { + SnapshotPublisher publisher = _snapshotManager.getPublisher(); + Gson gson = SnapshotPublisher.getGson(); + Set snapshots = _snapshotManager.getSnapshots(report.getSuspect()); + Set uuids = getUUIDs(report); + uuids.addAll(publisher.getUUIDs(snapshots)); + + Map usernameMap = publisher.getUsernameMap(uuids); + + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("timezone", SnapshotPublisher.getZoneId().getId()); + jsonObject.add("generated", gson.toJsonTree(LocalDateTime.now())); + jsonObject.add("report", gson.toJsonTree(report)); + jsonObject.add("snapshots", gson.toJsonTree(snapshots)); + jsonObject.add("usernames", gson.toJsonTree(usernameMap)); + + publisher.publishChatLog(report.getUniqueToken(), jsonObject); + } + + private Set getUUIDs(Report report) + { + Set uuids = new HashSet<>(report.getReporters()); + uuids.add(report.getSuspect()); + + if (report.getHandler() != null) + { + uuids.add(report.getHandler()); + } + + return uuids; + } + public void onPlayerJoin(Player player) { if (hasActiveReport(player)) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/report/command/ReportNotificationCallback.java b/Plugins/Mineplex.Core/src/mineplex/core/report/command/ReportNotificationCallback.java index ca4e25bbb..e584cb957 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/report/command/ReportNotificationCallback.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/report/command/ReportNotificationCallback.java @@ -1,5 +1,7 @@ package mineplex.core.report.command; +import java.util.UUID; + import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.entity.Player; @@ -33,11 +35,11 @@ public class ReportNotificationCallback implements CommandCallback if (report != null) { - String handlerName = report.getHandler(); + UUID handlerUUID = report.getHandler(); - if (handlerName != null) + if (handlerUUID != null) { - Player handler = Bukkit.getPlayerExact(handlerName); + Player handler = Bukkit.getPlayer(handlerUUID); if (handler != null) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/report/task/ReportHandlerMessageTask.java b/Plugins/Mineplex.Core/src/mineplex/core/report/task/ReportHandlerMessageTask.java index 05ef69d9b..4dab83eec 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/report/task/ReportHandlerMessageTask.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/report/task/ReportHandlerMessageTask.java @@ -1,10 +1,13 @@ package mineplex.core.report.task; import java.util.Map; +import java.util.UUID; +import org.bukkit.Bukkit; import org.bukkit.scheduler.BukkitRunnable; -import mineplex.core.chatsnap.MessageSnapshotManager; +import mineplex.core.chatsnap.SnapshotManager; +import mineplex.core.chatsnap.publishing.SnapshotPublisher; import mineplex.core.common.jsonchat.ClickEvent; import mineplex.core.common.jsonchat.JsonMessage; import mineplex.core.common.util.C; @@ -38,15 +41,17 @@ public class ReportHandlerMessageTask extends BukkitRunnable if (_reportManager.isActiveReport(reportId)) { Report report = _reportManager.getReport(reportId); + String suspectName = Bukkit.getOfflinePlayer(_report.getSuspect()).getName(); + JsonMessage jsonMessage = new JsonMessage(BORDER + "\n" + C.cAqua + "Reviewing Ticket " + C.cGold + "#" + reportId + "\n\n" + C.cPurple + StringUtils.join(getReportReasons(), "\n" + C.cPurple) + "\n\n" - + C.cAqua + "Suspect: " + C.cGold + _report.getPlayerName() + + C.cAqua + "Suspect: " + C.cGold + suspectName + "\n" - + (_report.hasChatSnapToken() ? C.cAqua + "Chat Log: " + C.cGold + MessageSnapshotManager.getChatLogUrl(_report.getChatSnapToken()) + "\n" : "") + + (_report.hasChatSnapToken() ? C.cAqua + "Chat Log: " + C.cGold + SnapshotPublisher.getURL(_report.getUniqueToken()) + "\n" : "") + "\n" + C.cAqua + "Type " + C.cGold + "/reportclose " + reportId + " " + C.cAqua + " to close this report." + BORDER).click(ClickEvent.SUGGEST_COMMAND, "/reportclose " + reportId); @@ -62,14 +67,15 @@ public class ReportHandlerMessageTask extends BukkitRunnable public String[] getReportReasons() { - Map reportReasons = _report.getReportReasons(); + Map reportReasons = _report.getReportReasons(); String[] output = new String[reportReasons.size()]; int count = 0; - for (Map.Entry entry : reportReasons.entrySet()) + for (Map.Entry entry : reportReasons.entrySet()) { + String reporterName = Bukkit.getOfflinePlayer(entry.getKey()).getName(); // triple backslashes so this translates to valid JSON - output[count++] = "\\\"" + entry.getValue() + "\\\" - " + entry.getKey(); + output[count++] = "\\\"" + entry.getValue() + "\\\" - " + reporterName; } return output; diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java index 2920bbaa0..99115e295 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java @@ -12,8 +12,8 @@ import mineplex.core.achievement.AchievementManager; import mineplex.core.antihack.AntiHack; import mineplex.core.blockrestore.BlockRestore; import mineplex.core.chat.Chat; -import mineplex.core.chatsnap.MessageSnapshotManager; -import mineplex.core.chatsnap.MessageSnapshotPlugin; +import mineplex.core.chatsnap.SnapshotManager; +import mineplex.core.chatsnap.SnapshotPlugin; import mineplex.core.command.CommandCenter; import mineplex.core.donation.DonationManager; import mineplex.core.explosion.Explosion; @@ -118,9 +118,9 @@ public class Clans extends JavaPlugin new Explosion(this, blockRestore); new FriendManager(this, _clientManager, preferenceManager, portal); new InventoryManager(this, _clientManager); - MessageSnapshotManager messageSnapshotManager = new MessageSnapshotManager(); - new MessageSnapshotPlugin(this, messageSnapshotManager); - new ReportPlugin(this, new ReportManager(this, preferenceManager, statsManager, messageSnapshotManager, serverStatusManager.getCurrentServerName())); + SnapshotManager snapshotManager = new SnapshotManager(); + new SnapshotPlugin(this, snapshotManager); + new ReportPlugin(this, new ReportManager(this, preferenceManager, statsManager, snapshotManager, serverStatusManager.getCurrentServerName())); // Enable custom-gear related managers PacketHandler packetHandler = new PacketHandler(this); diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java index 6f76b5882..06269aab9 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java @@ -12,8 +12,8 @@ import mineplex.core.antihack.AntiHack; import mineplex.core.aprilfools.AprilFoolsManager; import mineplex.core.blockrestore.BlockRestore; import mineplex.core.chat.Chat; -import mineplex.core.chatsnap.MessageSnapshotManager; -import mineplex.core.chatsnap.MessageSnapshotPlugin; +import mineplex.core.chatsnap.SnapshotManager; +import mineplex.core.chatsnap.SnapshotPlugin; import mineplex.core.command.CommandCenter; import mineplex.core.creature.Creature; import mineplex.core.disguise.DisguiseManager; @@ -68,7 +68,6 @@ import mineplex.minecraft.game.classcombat.shop.ClassCombatShop; import mineplex.minecraft.game.classcombat.shop.ClassShopManager; import mineplex.minecraft.game.core.IRelation; import mineplex.minecraft.game.core.combat.CombatManager; -import mineplex.minecraft.game.core.condition.ConditionManager; import mineplex.minecraft.game.core.damage.DamageManager; import mineplex.minecraft.game.core.fire.Fire; @@ -157,9 +156,9 @@ public class Hub extends JavaPlugin implements IRelation } }); new GlobalPacketManager(this, clientManager, serverStatusManager, inventoryManager, donationManager, petManager, statsManager, giveawayManager); - MessageSnapshotManager messageSnapshotManager = new MessageSnapshotManager(); - new MessageSnapshotPlugin(this, messageSnapshotManager); - new ReportPlugin(this, new ReportManager(this, preferenceManager, statsManager, messageSnapshotManager, serverStatusManager.getCurrentServerName())); + SnapshotManager snapshotManager = new SnapshotManager(); + new SnapshotPlugin(this, snapshotManager); + new ReportPlugin(this, new ReportManager(this, preferenceManager, statsManager, snapshotManager, serverStatusManager.getCurrentServerName())); //new Replay(this, packetHandler); AprilFoolsManager.Initialize(this, clientManager, disguiseManager); diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java index 2038a165f..09b133a25 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java @@ -8,8 +8,8 @@ import org.bukkit.plugin.java.JavaPlugin; import mineplex.core.FoodDupeFix; import mineplex.core.PacketsInteractionFix; -import mineplex.core.chatsnap.MessageSnapshotManager; -import mineplex.core.chatsnap.MessageSnapshotPlugin; +import mineplex.core.chatsnap.SnapshotManager; +import mineplex.core.chatsnap.SnapshotPlugin; import mineplex.core.giveaway.GiveawayManager; import mineplex.core.globalpacket.GlobalPacketManager; import net.minecraft.server.v1_8_R3.BiomeBase; @@ -135,9 +135,9 @@ public class Arcade extends JavaPlugin FriendManager friendManager = new FriendManager(this, _clientManager, preferenceManager, portal); Chat chat = new Chat(this, _clientManager, preferenceManager, achievementManager, serverStatusManager.getCurrentServerName()); new MessageManager(this, _clientManager, preferenceManager, ignoreManager, punish, friendManager, chat); - MessageSnapshotManager messageSnapshotManager = new MessageSnapshotManager(); - new MessageSnapshotPlugin(this, messageSnapshotManager); - new ReportPlugin(this, new ReportManager(this, preferenceManager, statsManager, messageSnapshotManager, serverStatusManager.getCurrentServerName())); + SnapshotManager snapshotManager = new SnapshotManager(); + new SnapshotPlugin(this, snapshotManager); + new ReportPlugin(this, new ReportManager(this, preferenceManager, statsManager, snapshotManager, serverStatusManager.getCurrentServerName())); BlockRestore blockRestore = new BlockRestore(this);