Reworked serialization and store more data in json files for later parsing.

Internally store UUIDs for reports and convert them as needed for display to user.
Many other misc. changes and refactorings.
This commit is contained in:
Keir 2015-12-15 21:30:45 +00:00
parent 50753e30e6
commit 6d9bcb8e66
20 changed files with 530 additions and 350 deletions

View File

@ -1,3 +1,3 @@
Manifest-Version: 1.0
Main-Class: mineplex.chatsnap.ChatSnapManager
Main-Class: mineplex.chatsnap.ReportServer

View File

@ -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");

View File

@ -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;

View File

@ -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<MessageSnapshot>
{
private UUID sender;
private Collection<UUID> recipients;
private String message;
private long time;
public MessageSnapshot(UUID sender, Collection<UUID> recipients, String message)
{
this(sender, recipients, message, System.currentTimeMillis());
}
public MessageSnapshot(UUID sender, Collection<UUID> 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<UUID> 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 +
'}';
}
}

View File

@ -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<MessageSnapshot, Boolean> _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<MessageSnapshot> getSnapshots()
{
// The compareTo method in MessageSnapshot will ensure this in chronological order
Set<MessageSnapshot> 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<MessageSnapshot> getSnapshots(UUID search)
{
Set<MessageSnapshot> 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<MessageSnapshot> snapshots = getSnapshots(playerUUID);
Map<UUID, String> 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<UUID> getUUIDs(Collection<MessageSnapshot> snapshots)
{
// Being a Set ensures no duplicates
Set<UUID> uuids = new HashSet<>();
for (MessageSnapshot messageSnapshot : snapshots)
{
uuids.add(messageSnapshot.getSender());
for (UUID recipient : messageSnapshot.getRecipients())
{
uuids.add(recipient);
}
}
return uuids;
}
private static Map<UUID, String> getUsernames(Collection<UUID> collection)
{
Map<UUID, String> uuidUsernameMap = new HashMap<>();
for (UUID uuid : collection)
{
String username = Bukkit.getOfflinePlayer(uuid).getName();
uuidUsernameMap.put(uuid, username);
}
return uuidUsernameMap;
}
}

View File

@ -0,0 +1,9 @@
package mineplex.core.chatsnap;
/**
* @author iKeirNez
*/
public enum MessageType
{
CHAT, PRIVATE;
}

View File

@ -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<Snapshot>
{
@SerializedName("type")
private MessageType _messageType;
@SerializedName("sender")
private UUID _sender;
@SerializedName("recipients")
private Collection<UUID> _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<UUID> recipients, String message)
{
this(MessageType.CHAT, sender, recipients, message, LocalDateTime.now());
}
public Snapshot(MessageType messageType, UUID sender, Collection<UUID> 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<UUID> 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 +
'}';
}
}

View File

@ -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<Snapshot, Boolean> _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<Snapshot> getSnapshots()
{
// The compareTo method in Snapshot will ensure this in chronological order
Set<Snapshot> 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<Snapshot> getSnapshots(UUID search)
{
Set<Snapshot> matches = new TreeSet<>();
for (Snapshot snapshot : _snapshots.asMap().keySet())
{
if (snapshot.getSender().equals(search) || snapshot.getRecipients().contains(search))
{
matches.add(snapshot);
}
}
return matches;
}
}

View File

@ -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<UUID> getUUIDSet(Set<Player> playerSet)
@ -54,9 +54,9 @@ public class MessageSnapshotPlugin extends MiniPlugin
return uuidSet;
}
public MessageSnapshot getMessageSnap(AsyncPlayerChatEvent e)
public Snapshot getSnapshot(AsyncPlayerChatEvent e)
{
Set<UUID> uuidSet = getUUIDSet(e.getRecipients());
return new MessageSnapshot(e.getPlayer().getUniqueId(), uuidSet, e.getMessage());
return new Snapshot(e.getPlayer().getUniqueId(), uuidSet, e.getMessage());
}
}

View File

@ -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<MessageSnapshotPlugin>
public class ChatCacheCommand extends CommandBase<SnapshotPlugin>
{
public ChatCacheCommand(MessageSnapshotPlugin plugin)
public ChatCacheCommand(SnapshotPlugin plugin)
{
super(plugin, Rank.MODERATOR, "chatcache");
}
@ -42,12 +42,12 @@ public class ChatCacheCommand extends CommandBase<MessageSnapshotPlugin>
public void run()
{
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName);
Set<MessageSnapshot> snaps = Plugin.getMessageSnapshotManager().getSnapshots(offlinePlayer.getUniqueId());
Set<Snapshot> 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());
}
}
});

View File

@ -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<LocalDateTime>
{
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));
}
}

View File

@ -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<Report>
{
@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;
}
}

View File

@ -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<UUID> getUUIDs(Collection<Snapshot> snapshots)
{
// Being a Set ensures no duplicates
Set<UUID> uuids = new HashSet<>();
for (Snapshot snapshot : snapshots)
{
uuids.add(snapshot.getSender());
for (UUID recipient : snapshot.getRecipients())
{
uuids.add(recipient);
}
}
return uuids;
}
public Map<UUID, String> getUsernameMap(Collection<UUID> collection)
{
Map<UUID, String> uuidUsernameMap = new HashMap<>();
for (UUID uuid : collection)
{
String username = Bukkit.getOfflinePlayer(uuid).getName();
uuidUsernameMap.put(uuid, username);
}
return uuidUsernameMap;
}
}

View File

@ -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<String, String> _reportReasons;
public Map<String, String> getReportReasons() { return _reportReasons; }
public Set<String> getReporters() { return _reportReasons.keySet(); }
public void addReporter(String reporter, String reason) { _reportReasons.put(reporter, reason); }
private Map<UUID, String> _reportReasons;
public Map<UUID, String> getReportReasons() { return _reportReasons; }
public Set<UUID> 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)

View File

@ -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<String, Integer> _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<Report>(Region.ALL, Report.class, "reports");
_activeReports = new HashMap<String, Integer>();
@ -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<Snapshot> snapshots = _snapshotManager.getSnapshots(report.getSuspect());
Set<UUID> uuids = getUUIDs(report);
uuids.addAll(publisher.getUUIDs(snapshots));
Map<UUID, String> 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<UUID> getUUIDs(Report report)
{
Set<UUID> 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))

View File

@ -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)
{

View File

@ -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 + " <reason>" + 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<String, String> reportReasons = _report.getReportReasons();
Map<UUID, String> reportReasons = _report.getReportReasons();
String[] output = new String[reportReasons.size()];
int count = 0;
for (Map.Entry<String, String> entry : reportReasons.entrySet())
for (Map.Entry<UUID, String> 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;

View File

@ -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);

View File

@ -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);

View File

@ -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);