Merge pull request #245 from Mineplex-LLC/update/report-improvements
Report Feature Improvements
This commit is contained in:
commit
f8010f4ad0
@ -132,15 +132,15 @@ public class SnapshotManager
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
|
||||
public CompletableFuture<Integer> saveReportSnapshot(Report report, Collection<SnapshotMessage> messages)
|
||||
public CompletableFuture<SnapshotMetadata> saveReportSnapshot(Report report, Collection<SnapshotMessage> messages)
|
||||
{
|
||||
return _snapshotRepository
|
||||
.saveReportSnapshot(report, messages)
|
||||
.whenComplete((snapshotId, throwable) ->
|
||||
.whenComplete((snapshotMetadata, throwable) ->
|
||||
{
|
||||
if (throwable == null)
|
||||
{
|
||||
report.setSnapshotId(snapshotId);
|
||||
report.setSnapshotMetadata(snapshotMetadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -0,0 +1,43 @@
|
||||
package mineplex.core.chatsnap;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class SnapshotMetadata
|
||||
{
|
||||
private final int _id;
|
||||
protected String _token = null;
|
||||
protected Integer _creatorId = null;
|
||||
|
||||
public SnapshotMetadata(int id, String token, Integer creatorId)
|
||||
{
|
||||
_id = id;
|
||||
_token = token;
|
||||
_creatorId = creatorId;
|
||||
}
|
||||
|
||||
public SnapshotMetadata(int id, Integer creatorId)
|
||||
{
|
||||
_id = id;
|
||||
_creatorId = creatorId;
|
||||
}
|
||||
|
||||
public SnapshotMetadata(int id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
public int getId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
public Optional<String> getToken()
|
||||
{
|
||||
return Optional.ofNullable(_token);
|
||||
}
|
||||
|
||||
public Optional<Integer> getCreatorId()
|
||||
{
|
||||
return Optional.ofNullable(_creatorId);
|
||||
}
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
package mineplex.core.chatsnap;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@ -20,17 +22,55 @@ import mineplex.serverdata.database.DBPool;
|
||||
*/
|
||||
public class SnapshotRepository
|
||||
{
|
||||
public static String getURL(long reportId)
|
||||
private static final String URL_PREFIX = "http://report.mineplex.com/chatsnap/view.php?token=";
|
||||
|
||||
private static final int TOKEN_CHARS = 8;
|
||||
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
public static String getURL(String token)
|
||||
{
|
||||
return URL_PREFIX + reportId;
|
||||
return URL_PREFIX + token;
|
||||
}
|
||||
|
||||
private static final String URL_PREFIX = "http://report.mineplex.com/chatsnap/view.php?id=";
|
||||
public static String generateToken()
|
||||
{
|
||||
// 6 bits per character, round to nearest byte
|
||||
int byteAmount = (int) Math.ceil((TOKEN_CHARS * 6) / 8.0);
|
||||
byte[] bytes = new byte[byteAmount];
|
||||
SECURE_RANDOM.nextBytes(bytes);
|
||||
|
||||
private static final String INSERT_SNAPSHOT = "INSERT INTO snapshots (creator) VALUES (?);";
|
||||
String token = Base64.getUrlEncoder().encodeToString(bytes);
|
||||
token = replaceDashes(token);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
private static String replaceDashes(String token)
|
||||
{
|
||||
for (int i = 0; i < token.length(); i++)
|
||||
{
|
||||
char originalChar = token.charAt(i);
|
||||
char newChar = originalChar;
|
||||
|
||||
while (newChar == '-')
|
||||
{
|
||||
byte[] replacementBytes = new byte[1];
|
||||
SECURE_RANDOM.nextBytes(replacementBytes);
|
||||
newChar = Base64.getUrlEncoder().encodeToString(replacementBytes).charAt(0);
|
||||
}
|
||||
|
||||
token = token.replaceFirst(String.valueOf(originalChar), String.valueOf(newChar));
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
private static final String INSERT_SNAPSHOT = "INSERT INTO snapshots (token, creator) VALUES (?, ?);";
|
||||
private static final String INSERT_MESSAGE = "INSERT INTO snapshotMessages (senderId, `server`, `time`, message, snapshotType) VALUES (?, ?, ?, ?, ?);";
|
||||
private static final String INSERT_MESSAGE_RECIPIENT = "INSERT INTO snapshotRecipients (messageId, recipientId) VALUES (?, ?);";
|
||||
private static final String INSERT_MESSAGE_MAPPING = "INSERT INTO snapshotMessageMap (snapshotId, messageId) VALUES (?, ?);";
|
||||
private static final String GET_ID_FROM_TOKEN = "SELECT snapshots.id FROM snapshots WHERE snapshots.token = ?;";
|
||||
private static final String GET_METADATA = "SELECT token, creator FROM snapshots WHERE id = ?;";
|
||||
|
||||
private final String _serverName;
|
||||
private final Logger _logger;
|
||||
@ -41,17 +81,17 @@ public class SnapshotRepository
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public CompletableFuture<Integer> saveReportSnapshot(Report report, Collection<SnapshotMessage> messages)
|
||||
public CompletableFuture<SnapshotMetadata> saveReportSnapshot(Report report, Collection<SnapshotMessage> messages)
|
||||
{
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
try (Connection connection = DBPool.getAccount().getConnection())
|
||||
{
|
||||
int snapshotId = report.getSnapshotId().orElseThrow(() ->
|
||||
new IllegalStateException("Report does not have associated snapshot id."));
|
||||
SnapshotMetadata snapshotMetadata = report.getSnapshotMetadata().orElseThrow(() ->
|
||||
new IllegalStateException("Report does not have associated snapshot."));
|
||||
|
||||
insertMessages(snapshotId, messages, connection);
|
||||
return snapshotId;
|
||||
insertMessages(snapshotMetadata.getId(), messages, connection);
|
||||
return snapshotMetadata;
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
@ -60,15 +100,15 @@ public class SnapshotRepository
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Integer> saveSnapshot(Collection<SnapshotMessage> messages)
|
||||
public CompletableFuture<SnapshotMetadata> saveSnapshot(Collection<SnapshotMessage> messages)
|
||||
{
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
try (Connection connection = DBPool.getAccount().getConnection())
|
||||
{
|
||||
int snapshotId = createSnapshot(connection, null);
|
||||
insertMessages(snapshotId, messages, connection);
|
||||
return snapshotId;
|
||||
SnapshotMetadata snapshotMetadata = createSnapshot(connection, null);
|
||||
insertMessages(snapshotMetadata.getId(), messages, connection);
|
||||
return snapshotMetadata;
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
@ -77,7 +117,7 @@ public class SnapshotRepository
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Integer> createSnapshot(Integer creatorAccountId)
|
||||
public CompletableFuture<SnapshotMetadata> createSnapshot(Integer creatorAccountId)
|
||||
{
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
@ -92,17 +132,19 @@ public class SnapshotRepository
|
||||
});
|
||||
}
|
||||
|
||||
private int createSnapshot(Connection connection, Integer creatorAccount) throws SQLException
|
||||
private SnapshotMetadata createSnapshot(Connection connection, Integer creatorAccount) throws SQLException
|
||||
{
|
||||
String token = getUnusedToken(connection);
|
||||
PreparedStatement insertSnapshotStatement = connection.prepareStatement(INSERT_SNAPSHOT, new String[]{"id"});
|
||||
insertSnapshotStatement.setString(1, token);
|
||||
|
||||
if (creatorAccount != null)
|
||||
{
|
||||
insertSnapshotStatement.setInt(1, creatorAccount);
|
||||
insertSnapshotStatement.setInt(2, creatorAccount);
|
||||
}
|
||||
else
|
||||
{
|
||||
insertSnapshotStatement.setNull(1, Types.INTEGER);
|
||||
insertSnapshotStatement.setNull(2, Types.INTEGER);
|
||||
}
|
||||
|
||||
insertSnapshotStatement.execute();
|
||||
@ -111,7 +153,7 @@ public class SnapshotRepository
|
||||
{
|
||||
if (resultSet.next())
|
||||
{
|
||||
return resultSet.getInt(1);
|
||||
return new SnapshotMetadata(resultSet.getInt(1), token, creatorAccount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -120,6 +162,82 @@ public class SnapshotRepository
|
||||
}
|
||||
}
|
||||
|
||||
private String getUnusedToken(Connection connection) throws SQLException
|
||||
{
|
||||
String token;
|
||||
|
||||
do
|
||||
{
|
||||
token = generateToken();
|
||||
}
|
||||
while(getByToken(connection, token).isPresent());
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
private Optional<Integer> getByToken(Connection connection, String token) throws SQLException
|
||||
{
|
||||
try (PreparedStatement statement = connection.prepareStatement(GET_ID_FROM_TOKEN))
|
||||
{
|
||||
statement.setString(1, token);
|
||||
|
||||
try (ResultSet resultSet = statement.executeQuery())
|
||||
{
|
||||
if (resultSet.next())
|
||||
{
|
||||
int snapshotId = resultSet.getInt("id");
|
||||
return Optional.of(snapshotId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<SnapshotMetadata> getSnapshotMetadata(int snapshotId)
|
||||
{
|
||||
CompletableFuture<SnapshotMetadata> future = CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
try (Connection connection = DBPool.getAccount().getConnection())
|
||||
{
|
||||
try (PreparedStatement statement = connection.prepareStatement(GET_METADATA))
|
||||
{
|
||||
statement.setInt(1, snapshotId);
|
||||
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
if (resultSet.next())
|
||||
{
|
||||
String token = resultSet.getString("token");
|
||||
if (resultSet.wasNull()) token = null;
|
||||
|
||||
Integer creatorId = resultSet.getInt("creator");
|
||||
if (resultSet.wasNull()) creatorId = null;
|
||||
|
||||
return new SnapshotMetadata(snapshotId, token, creatorId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
future.exceptionally(throwable ->
|
||||
{
|
||||
_logger.log(Level.SEVERE, "Error whilst getting snapshot metadata for id: " + snapshotId, throwable);
|
||||
return null;
|
||||
});
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
private void insertMessages(int snapshotId, Collection<SnapshotMessage> messages, Connection connection) throws SQLException
|
||||
{
|
||||
try (PreparedStatement insertSnapshotStatement = connection.prepareStatement(INSERT_MESSAGE, new String[]{"id"}))
|
||||
|
@ -10,27 +10,27 @@ public enum ReportCategory
|
||||
/**
|
||||
* Global category, used for representing values which aren't tied to a specific category (such as abusive report statistics).
|
||||
*/
|
||||
GLOBAL(0),
|
||||
GLOBAL((short) 0),
|
||||
|
||||
/**
|
||||
* Hacking category, for reports involving cheats of any sort.
|
||||
*/
|
||||
HACKING(1),
|
||||
HACKING((short) 1),
|
||||
|
||||
/**
|
||||
* Chat Abuse category, for reports involving offensive comments made in chat.
|
||||
*/
|
||||
CHAT_ABUSE(2),
|
||||
CHAT_ABUSE((short) 2),
|
||||
|
||||
/**
|
||||
* Gameplay category, for reports specific to gameplay (such as bug exploits or issues with the map).
|
||||
*/
|
||||
GAMEPLAY(3);
|
||||
GAMEPLAY((short) 3);
|
||||
|
||||
private final int _id;
|
||||
private final short _id;
|
||||
private final String _name;
|
||||
|
||||
ReportCategory(int id)
|
||||
ReportCategory(short id)
|
||||
{
|
||||
_id = id;
|
||||
_name = WordUtils.capitalizeFully(name().replace('_', ' '));
|
||||
@ -41,7 +41,7 @@ public enum ReportCategory
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public int getId()
|
||||
public short getId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import mineplex.core.chatsnap.SnapshotMetadata;
|
||||
import mineplex.core.chatsnap.SnapshotRepository;
|
||||
import mineplex.core.common.jsonchat.ChildJsonMessage;
|
||||
import mineplex.core.common.jsonchat.ClickEvent;
|
||||
@ -80,19 +81,31 @@ public class ReportHandlerTask extends BukkitRunnable
|
||||
.add(prefix + C.cAqua + "Suspect - " + C.cGold + suspectName)
|
||||
.add("\n")
|
||||
.add(prefix + C.cAqua + "Type - " + C.cGold + report.getCategory().getName())
|
||||
.add("\n")
|
||||
.add(prefix + C.cAqua + "Team - " + C.cGold + report.getAssignedTeam().map(ReportTeam::getName).orElse("None"))
|
||||
.add("\n" + prefix + "\n")
|
||||
.add(prefix + C.cGold + report.getMessages().size() + C.cAqua + " total reports")
|
||||
.add("\n")
|
||||
.add(Arrays.stream(getReportReasons(report)).map(s -> prefix + s).collect(Collectors.joining("\n")))
|
||||
.add("\n" + prefix + "\n");
|
||||
|
||||
if (report.getCategory() == ReportCategory.CHAT_ABUSE)
|
||||
Optional<SnapshotMetadata> snapshotMetadataOptional = report.getSnapshotMetadata();
|
||||
|
||||
if (snapshotMetadataOptional.isPresent())
|
||||
{
|
||||
jsonMessage = jsonMessage
|
||||
.add(prefix + C.cAqua + "View chat log")
|
||||
.hover(HoverEvent.SHOW_TEXT, C.cGray + "Opens the chat log in your default browser")
|
||||
.click(ClickEvent.OPEN_URL, SnapshotRepository.getURL(reportId))
|
||||
.add("\n");
|
||||
SnapshotMetadata snapshotMetadata = snapshotMetadataOptional.get();
|
||||
Optional<String> tokenOptional = snapshotMetadata.getToken();
|
||||
|
||||
if (tokenOptional.isPresent())
|
||||
{
|
||||
String token = tokenOptional.get();
|
||||
|
||||
jsonMessage = jsonMessage
|
||||
.add(prefix + C.cAqua + "View chat log")
|
||||
.hover(HoverEvent.SHOW_TEXT, C.cGray + "Opens the chat log in your default browser")
|
||||
.click(ClickEvent.OPEN_URL, SnapshotRepository.getURL(token))
|
||||
.add("\n");
|
||||
}
|
||||
}
|
||||
|
||||
jsonMessage = jsonMessage
|
||||
|
@ -19,6 +19,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import mineplex.core.account.CoreClient;
|
||||
import mineplex.core.account.CoreClientManager;
|
||||
import mineplex.core.chatsnap.SnapshotManager;
|
||||
import mineplex.core.chatsnap.SnapshotMetadata;
|
||||
import mineplex.core.chatsnap.command.PushSnapshotsCommand;
|
||||
import mineplex.core.chatsnap.command.PushSnapshotsHandler;
|
||||
import mineplex.core.command.CommandCenter;
|
||||
@ -148,8 +149,8 @@ public class ReportManager
|
||||
// create snapshot id ahead of time
|
||||
if (category == ReportCategory.CHAT_ABUSE)
|
||||
{
|
||||
int snapshotId = _snapshotManager.getSnapshotRepository().createSnapshot(null).join();
|
||||
report.setSnapshotId(snapshotId);
|
||||
SnapshotMetadata snapshotMetadata = _snapshotManager.getSnapshotRepository().createSnapshot(null).join();
|
||||
report.setSnapshotMetadata(snapshotMetadata);
|
||||
}
|
||||
|
||||
saveReport(report).join();
|
||||
|
@ -6,7 +6,6 @@ import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import mineplex.core.MiniPlugin;
|
||||
import mineplex.core.report.command.ReportAbortCommand;
|
||||
import mineplex.core.report.command.ReportCloseCommand;
|
||||
import mineplex.core.report.command.ReportCommand;
|
||||
import mineplex.core.report.command.ReportHandleCommand;
|
||||
@ -38,7 +37,6 @@ public class ReportPlugin extends MiniPlugin
|
||||
addCommand(new ReportHandleCommand(this));
|
||||
addCommand(new ReportCloseCommand(this));
|
||||
addCommand(new ReportStatsCommand(this));
|
||||
addCommand(new ReportAbortCommand(this));
|
||||
addCommand(new ReportInfoCommand(this));
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,11 @@ public enum ReportTeam
|
||||
_initialPriority = initialPriority;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name();
|
||||
}
|
||||
|
||||
public short getDatabaseId()
|
||||
{
|
||||
return _databaseId;
|
||||
|
@ -1,64 +0,0 @@
|
||||
package mineplex.core.report.command;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import mineplex.core.command.CommandBase;
|
||||
import mineplex.core.common.Rank;
|
||||
import mineplex.core.common.util.BukkitFuture;
|
||||
import mineplex.core.common.util.C;
|
||||
import mineplex.core.common.util.F;
|
||||
import mineplex.core.common.util.UtilPlayer;
|
||||
import mineplex.core.report.ReportManager;
|
||||
import mineplex.core.report.ReportPlugin;
|
||||
import mineplex.core.report.data.Report;
|
||||
|
||||
/**
|
||||
* A command which allows a staff member to abort the report which they are currently handling.
|
||||
* Another staff member may be given this report when executing {@link ReportHandleCommand}.
|
||||
*/
|
||||
public class ReportAbortCommand extends CommandBase<ReportPlugin>
|
||||
{
|
||||
public ReportAbortCommand(ReportPlugin plugin)
|
||||
{
|
||||
super(plugin, Rank.MODERATOR, "reportabort");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void Execute(Player player, String[] args)
|
||||
{
|
||||
if (args == null || args.length == 0)
|
||||
{
|
||||
ReportManager reportManager = Plugin.getReportManager();
|
||||
|
||||
reportManager.getReportHandling(player).whenComplete(BukkitFuture.complete((reportOptional, throwable) ->
|
||||
{
|
||||
if (throwable == null)
|
||||
{
|
||||
if (reportOptional.isPresent())
|
||||
{
|
||||
Report report = reportOptional.get();
|
||||
|
||||
reportManager.abortReport(report).thenApply(BukkitFuture.accept(voidValue ->
|
||||
UtilPlayer.message(player, F.main(ReportManager.getReportPrefix(report),
|
||||
"Report has been aborted and may be handled by another staff member."))));
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), "You aren't currently handling a report."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), C.cRed + "An error occurred, please try again later."));
|
||||
Plugin.getPlugin().getLogger().log(Level.SEVERE, "Error whilst aborting report for player " + player.getName(), throwable);
|
||||
}
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), C.cRed + "Invalid Usage: " + F.elem("/" + _aliasUsed)));
|
||||
}
|
||||
}
|
||||
}
|
@ -6,13 +6,12 @@ import mineplex.core.account.CoreClient;
|
||||
import mineplex.core.account.CoreClientManager;
|
||||
import mineplex.core.command.CommandBase;
|
||||
import mineplex.core.common.Rank;
|
||||
import mineplex.core.common.util.BukkitFuture;
|
||||
import mineplex.core.common.util.C;
|
||||
import mineplex.core.common.util.F;
|
||||
import mineplex.core.common.util.UtilPlayer;
|
||||
import mineplex.core.report.ReportManager;
|
||||
import mineplex.core.report.ReportPlugin;
|
||||
import mineplex.core.report.ui.ReportCategoryPage;
|
||||
import mineplex.core.report.ui.ReportCreatePage;
|
||||
|
||||
/**
|
||||
* The command used by players to create a report.
|
||||
@ -62,7 +61,7 @@ public class ReportCommand extends CommandBase<ReportPlugin>
|
||||
else
|
||||
{
|
||||
CoreClient suspectClient = clientManager.Get(suspect);
|
||||
new ReportCategoryPage(Plugin, reporter, reporterId, suspectClient, reason).openInventory();
|
||||
new ReportCreatePage(Plugin, reporter, reporterId, suspectClient, reason).openInventory();
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -71,7 +70,7 @@ public class ReportCommand extends CommandBase<ReportPlugin>
|
||||
{
|
||||
if (suspectClient != null)
|
||||
{
|
||||
new ReportCategoryPage(Plugin, reporter, reporterId, suspectClient, reason).openInventory();
|
||||
new ReportCreatePage(Plugin, reporter, reporterId, suspectClient, reason).openInventory();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,24 +1,14 @@
|
||||
package mineplex.core.report.command;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import mineplex.core.command.CommandBase;
|
||||
import mineplex.core.common.Rank;
|
||||
import mineplex.core.common.util.BukkitFuture;
|
||||
import mineplex.core.common.util.C;
|
||||
import mineplex.core.common.util.F;
|
||||
import mineplex.core.common.util.UtilPlayer;
|
||||
import mineplex.core.report.ReportManager;
|
||||
import mineplex.core.report.ReportPlugin;
|
||||
import mineplex.core.report.data.Report;
|
||||
import mineplex.core.report.data.ReportRepository;
|
||||
import mineplex.core.report.ui.ReportHandlePage;
|
||||
|
||||
/**
|
||||
* When executed, the user is appointed handler of the most important report in the report queue (if any).
|
||||
@ -36,76 +26,9 @@ public class ReportHandleCommand extends CommandBase<ReportPlugin>
|
||||
{
|
||||
if (args == null || args.length == 0)
|
||||
{
|
||||
ReportManager reportManager = Plugin.getReportManager();
|
||||
ReportRepository reportRepository = reportManager.getReportRepository();
|
||||
int accountId = _commandCenter.GetClientManager().getAccountId(player);
|
||||
|
||||
reportManager.isHandlingReport(player).whenComplete((handlingReport, throwable) ->
|
||||
{
|
||||
if (throwable == null)
|
||||
{
|
||||
if (!handlingReport)
|
||||
{
|
||||
Map<Report, Double> reportPriorities = Collections.synchronizedMap(new HashMap<>());
|
||||
boolean devMode = reportManager.isDevMode(player.getUniqueId());
|
||||
|
||||
// the below fetches the ids of all unhandled reports and gets a Report object for each of these ids
|
||||
// the priority of the report is then calculated and the results placed in a map
|
||||
reportRepository.getUnhandledReports(accountId, devMode).thenCompose(reportRepository::getReports).thenAccept(reports ->
|
||||
CompletableFuture.allOf(reports.stream().map(report ->
|
||||
reportManager.calculatePriority(report).thenAccept(priority ->
|
||||
{
|
||||
if (priority > 0)
|
||||
{
|
||||
reportPriorities.put(report, priority);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mark the report as expired to keep the database clean
|
||||
// and reduce future query time
|
||||
reportManager.expireReport(report);
|
||||
}
|
||||
}
|
||||
)
|
||||
).toArray(CompletableFuture[]::new)).join()
|
||||
).thenApply(aVoid ->
|
||||
{
|
||||
Map.Entry<Report, Double> mostImportant = null;
|
||||
|
||||
for (Map.Entry<Report, Double> entry : reportPriorities.entrySet())
|
||||
{
|
||||
if (mostImportant == null || (double) entry.getValue() > mostImportant.getValue())
|
||||
{
|
||||
mostImportant = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return mostImportant == null ? null : mostImportant.getKey();
|
||||
}).thenCompose(BukkitFuture.accept(report ->
|
||||
{
|
||||
if (report != null)
|
||||
{
|
||||
reportManager.handleReport(report, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), C.cRed + "No report found, report queue is empty."));
|
||||
}
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
Bukkit.getScheduler().runTask(Plugin.getPlugin(), () ->
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), C.cRed + "You are already handling a report.")));
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), C.cRed + "An error occurred, please try again later."));
|
||||
Plugin.getPlugin().getLogger().log(Level.SEVERE, "Error whilst checking for reports being handled by " + player.getName(), throwable);
|
||||
}
|
||||
});
|
||||
ReportHandlePage reportHandlePage = new ReportHandlePage(Plugin, player, accountId);
|
||||
reportHandlePage.openInventory();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,6 +1,5 @@
|
||||
package mineplex.core.report.command;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.google.common.primitives.Longs;
|
||||
@ -32,53 +31,62 @@ public class ReportStatsCommand extends CommandBase<ReportPlugin>
|
||||
if (args != null && args.length == 1)
|
||||
{
|
||||
String playerName = args[0];
|
||||
Player target = Bukkit.getPlayer(playerName);
|
||||
|
||||
if (target != null)
|
||||
Plugin.getReportManager().getReportRepository().getAccountId(playerName).thenAccept(accountIdOptional ->
|
||||
{
|
||||
int accountId = _commandCenter.GetClientManager().getAccountId(target);
|
||||
if (accountIdOptional.isPresent())
|
||||
{
|
||||
int accountId = accountIdOptional.get();
|
||||
|
||||
Plugin.getReportManager().getReportRepository().getAccountStatistics(accountId).thenCompose(BukkitFuture.accept(stats ->
|
||||
stats.keySet().forEach(role ->
|
||||
{
|
||||
long[] idArray = stats.get(role).stream()
|
||||
.sorted((l1, l2) -> Longs.compare(l2, l1))
|
||||
.mapToLong(l -> l)
|
||||
.toArray();
|
||||
int reportCount = idArray.length;
|
||||
|
||||
// don't show handler statistics if user has never handled a report
|
||||
if (role != ReportRole.HANDLER || reportCount > 0)
|
||||
Plugin.getReportManager().getReportRepository().getAccountStatistics(accountId).thenCompose(BukkitFuture.accept(stats ->
|
||||
{
|
||||
// create clickable report ids
|
||||
ChildJsonMessage jsonMessage = new JsonMessage(F.main(Plugin.getName(), ""))
|
||||
.extra(C.mElem);
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), "Report Statistics for " + F.elem(playerName)));
|
||||
|
||||
int displayAmount = 5;
|
||||
|
||||
for (int i = 0; i < displayAmount; i++)
|
||||
for (ReportRole role : ReportRole.values())
|
||||
{
|
||||
long reportId = idArray[i];
|
||||
long[] idArray = stats.get(role).stream()
|
||||
.sorted((l1, l2) -> Longs.compare(l2, l1))
|
||||
.mapToLong(l -> l)
|
||||
.toArray();
|
||||
int reportCount = idArray.length;
|
||||
|
||||
jsonMessage = jsonMessage.add(String.valueOf(reportId))
|
||||
.click(ClickEvent.RUN_COMMAND, "/reportinfo " + reportId);
|
||||
// create clickable report ids
|
||||
ChildJsonMessage jsonMessage = new JsonMessage(F.main(Plugin.getName(), ""))
|
||||
.extra(C.mElem);
|
||||
|
||||
if (reportId != displayAmount)
|
||||
int displayAmount = Math.min(idArray.length, 5);
|
||||
|
||||
if (displayAmount > 0)
|
||||
{
|
||||
jsonMessage = jsonMessage.add(", ");
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < displayAmount; i++)
|
||||
{
|
||||
long reportId = idArray[i];
|
||||
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), F.elem(role.getHumanName()) + " (" + reportCount + ")"));
|
||||
jsonMessage.sendToPlayer(player);
|
||||
jsonMessage = jsonMessage.add(String.valueOf(reportId))
|
||||
.click(ClickEvent.RUN_COMMAND, "/reportinfo " + reportId);
|
||||
|
||||
if (i != displayAmount - 1)
|
||||
{
|
||||
jsonMessage = jsonMessage.add(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonMessage = jsonMessage.add("N/A");
|
||||
}
|
||||
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), F.elem(role.getHumanName()) + " (" + reportCount + ")"));
|
||||
jsonMessage.sendToPlayer(player);
|
||||
}
|
||||
}
|
||||
})
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), C.cRed + "Player not found."));
|
||||
}
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(player, F.main(Plugin.getName(), C.cRed + "Player not found."));
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import mineplex.core.chatsnap.SnapshotMetadata;
|
||||
import mineplex.core.report.ReportCategory;
|
||||
import mineplex.core.report.ReportHandlerTask;
|
||||
import mineplex.core.report.ReportResult;
|
||||
@ -21,7 +22,7 @@ public class Report
|
||||
// set of player account ids and the reason they reported this player
|
||||
private final Map<Integer, ReportMessage> _reportMessages = new HashMap<>();
|
||||
private Integer _handlerId = null;
|
||||
private Integer _snapshotId = null;
|
||||
private SnapshotMetadata _snapshotMetadata = null;
|
||||
private ReportResult _reportResult = null;
|
||||
private ReportTeam _assignedTeam = null;
|
||||
|
||||
@ -89,14 +90,14 @@ public class Report
|
||||
_handlerId = handlerId;
|
||||
}
|
||||
|
||||
public Optional<Integer> getSnapshotId()
|
||||
public Optional<SnapshotMetadata> getSnapshotMetadata()
|
||||
{
|
||||
return Optional.ofNullable(_snapshotId);
|
||||
return Optional.ofNullable(_snapshotMetadata);
|
||||
}
|
||||
|
||||
public void setSnapshotId(Integer snapshotId)
|
||||
public void setSnapshotMetadata(SnapshotMetadata snapshotMetadata)
|
||||
{
|
||||
_snapshotId = snapshotId;
|
||||
_snapshotMetadata = snapshotMetadata;
|
||||
}
|
||||
|
||||
public Optional<ReportResult> getResult()
|
||||
|
@ -30,6 +30,7 @@ import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mysql.jdbc.Statement;
|
||||
import mineplex.core.chatsnap.SnapshotMetadata;
|
||||
import mineplex.core.common.util.UtilTime;
|
||||
import mineplex.core.report.ReportCategory;
|
||||
import mineplex.core.report.ReportManager;
|
||||
@ -53,7 +54,7 @@ public class ReportRepository
|
||||
private static final String SET_REPORT_MESSAGE = "REPLACE INTO reportReasons (reportId, reporterId, reason, `server`, weight, `time`)" +
|
||||
" VALUES (?, ?, ?, ?, ?, ?);";
|
||||
|
||||
private static final String SET_REPORT_HANDLER = "REPLACE INTO reportHandlers (reportId, handlerId)" +
|
||||
private static final String INSERT_REPORT_HANDLER = "INSERT IGNORE INTO reportHandlers (reportId, handlerId)" +
|
||||
" VALUES (?, ?);";
|
||||
|
||||
private static final String SET_REPORT_RESULT = "REPLACE INTO reportResults (reportId, resultId, reason, closedTime)" +
|
||||
@ -77,7 +78,8 @@ public class ReportRepository
|
||||
" LEFT JOIN reportResults ON reports.id = reportResults.reportId\n" +
|
||||
" LEFT JOIN reportHandlers ON reports.id = reportHandlers.reportId\n" +
|
||||
" LEFT JOIN reportReasons ON reports.id = reportReasons.reportId\n" +
|
||||
"WHERE reportResults.reportId IS NULL\n" +
|
||||
"WHERE reports.categoryId = ?\n" +
|
||||
" AND reportResults.reportId IS NULL\n" +
|
||||
" /* Bypass for testing purposes or check player isn't suspect */\n" +
|
||||
" AND (? IS TRUE OR reports.suspectId != ?)\n" +
|
||||
" /* If team is assigned, make sure user is member of team */\n" +
|
||||
@ -122,6 +124,9 @@ public class ReportRepository
|
||||
private static final String GET_ACCOUNT_UUID = "SELECT id, uuid FROM accounts" +
|
||||
" WHERE id IN (%s);";
|
||||
|
||||
private static final String GET_ACCOUNT_ID = "SELECT id, `name` FROM accounts\n" +
|
||||
"WHERE `name` = ?;";
|
||||
|
||||
/** STATISTICS **/
|
||||
|
||||
private static final String STATISTICS_GET_REPORTS_MADE = "SELECT reports.id FROM reports, reportReasons\n" +
|
||||
@ -157,7 +162,7 @@ public class ReportRepository
|
||||
* @param devMode if true, allows various restrictions to be bypassed
|
||||
* @return the ids of unhandled reports the supplied account is allowed to handle
|
||||
*/
|
||||
public CompletableFuture<List<Long>> getUnhandledReports(int accountId, boolean devMode)
|
||||
public CompletableFuture<List<Long>> getUnhandledReports(int accountId, ReportCategory category, boolean devMode)
|
||||
{
|
||||
CompletableFuture<List<Long>> future = CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
@ -166,12 +171,13 @@ public class ReportRepository
|
||||
try (Connection connection = DBPool.getAccount().getConnection())
|
||||
{
|
||||
PreparedStatement preparedStatement = connection.prepareStatement(GET_UNHANDLED_REPORTS);
|
||||
preparedStatement.setBoolean(1, devMode);
|
||||
preparedStatement.setInt(2, accountId);
|
||||
preparedStatement.setShort(1, category.getId());
|
||||
preparedStatement.setBoolean(2, devMode);
|
||||
preparedStatement.setInt(3, accountId);
|
||||
preparedStatement.setInt(4, accountId);
|
||||
preparedStatement.setBoolean(5, devMode);
|
||||
preparedStatement.setInt(6, accountId);
|
||||
preparedStatement.setInt(5, accountId);
|
||||
preparedStatement.setBoolean(6, devMode);
|
||||
preparedStatement.setInt(7, accountId);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
|
||||
while (resultSet.next())
|
||||
@ -333,7 +339,10 @@ public class ReportRepository
|
||||
int snapshotId = resultSet.getInt("snapshotId");
|
||||
if (!resultSet.wasNull())
|
||||
{
|
||||
report.setSnapshotId(snapshotId);
|
||||
SnapshotMetadata snapshotMetadata = _reportManager.getSnapshotManager().getSnapshotRepository()
|
||||
.getSnapshotMetadata(snapshotId).join();
|
||||
|
||||
report.setSnapshotMetadata(snapshotMetadata);
|
||||
}
|
||||
|
||||
int handlerId = resultSet.getInt("handlerId");
|
||||
@ -537,7 +546,7 @@ public class ReportRepository
|
||||
try (Connection connection = DBPool.getAccount().getConnection())
|
||||
{
|
||||
Optional<Long> reportIdOptional = report.getId();
|
||||
Optional<Integer> snapshotIdOptional = report.getSnapshotId();
|
||||
Optional<Integer> snapshotIdOptional = report.getSnapshotMetadata().map(SnapshotMetadata::getId);
|
||||
Optional<ReportTeam> teamOptional = report.getAssignedTeam();
|
||||
long reportId;
|
||||
|
||||
@ -628,7 +637,7 @@ public class ReportRepository
|
||||
Optional<Integer> handlerIdOptional = report.getHandlerId();
|
||||
if (handlerIdOptional.isPresent())
|
||||
{
|
||||
PreparedStatement setReportHandlerStatement = connection.prepareStatement(SET_REPORT_HANDLER);
|
||||
PreparedStatement setReportHandlerStatement = connection.prepareStatement(INSERT_REPORT_HANDLER);
|
||||
setReportHandlerStatement.setLong(1, reportId); // report id
|
||||
setReportHandlerStatement.setInt(2, handlerIdOptional.get()); // handler id
|
||||
setReportHandlerStatement.execute();
|
||||
@ -823,13 +832,17 @@ public class ReportRepository
|
||||
{
|
||||
try (Connection connection = DBPool.getAccount().getConnection())
|
||||
{
|
||||
PreparedStatement preparedStatement = connection.prepareStatement(GET_ACCOUNT_NAME);
|
||||
preparedStatement.setInt(1, accountId);
|
||||
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
if (resultSet.next())
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(GET_ACCOUNT_NAME))
|
||||
{
|
||||
return resultSet.getString("name");
|
||||
preparedStatement.setInt(1, accountId);
|
||||
|
||||
try (ResultSet resultSet = preparedStatement.executeQuery())
|
||||
{
|
||||
if (resultSet.next())
|
||||
{
|
||||
return resultSet.getString("name");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
@ -864,14 +877,18 @@ public class ReportRepository
|
||||
try (Connection connection = DBPool.getAccount().getConnection())
|
||||
{
|
||||
String query = String.format(GET_ACCOUNT_UUID, StringUtils.join(accountIds, ", "));
|
||||
PreparedStatement preparedStatement = connection.prepareStatement(query);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
|
||||
while (resultSet.next())
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(query))
|
||||
{
|
||||
int accountId = resultSet.getInt("id");
|
||||
UUID accountUUID = UUID.fromString(resultSet.getString("uuid"));
|
||||
accountUUIDs.put(accountId, accountUUID);
|
||||
try (ResultSet resultSet = preparedStatement.executeQuery())
|
||||
{
|
||||
while (resultSet.next())
|
||||
{
|
||||
int accountId = resultSet.getInt("id");
|
||||
UUID accountUUID = UUID.fromString(resultSet.getString("uuid"));
|
||||
accountUUIDs.put(accountId, accountUUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
@ -891,4 +908,41 @@ public class ReportRepository
|
||||
return future;
|
||||
}
|
||||
|
||||
public CompletableFuture<Optional<Integer>> getAccountId(String name)
|
||||
{
|
||||
CompletableFuture<Optional<Integer>> future = CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
try (Connection connection = DBPool.getAccount().getConnection())
|
||||
{
|
||||
try (PreparedStatement statement = connection.prepareStatement(GET_ACCOUNT_ID))
|
||||
{
|
||||
statement.setString(1, name);
|
||||
|
||||
try (ResultSet resultSet = statement.executeQuery())
|
||||
{
|
||||
if (resultSet.next())
|
||||
{
|
||||
return Optional.of(resultSet.getInt("id"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
future.exceptionally(throwable ->
|
||||
{
|
||||
_logger.log(Level.SEVERE, "Error whilst fetching id from name: " + name, throwable);
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
return future;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package mineplex.core.report.ui;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import mineplex.core.common.util.C;
|
||||
import mineplex.core.gui.SimpleGuiItem;
|
||||
import mineplex.core.itemstack.ItemBuilder;
|
||||
|
||||
/**
|
||||
* A gui button which when clicked aborts the report the user is currently handling
|
||||
*/
|
||||
public class ReportAbortButton extends SimpleGuiItem
|
||||
{
|
||||
private static final ItemStack ITEM = new ItemBuilder(Material.BEDROCK)
|
||||
.setTitle(C.cRed + "Abort")
|
||||
.addLore("Another member of staff may handle this report instead.")
|
||||
.build();
|
||||
|
||||
private final ReportResultPage _page;
|
||||
|
||||
public ReportAbortButton(ReportResultPage page)
|
||||
{
|
||||
super(ITEM);
|
||||
_page = page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void click(ClickType clickType)
|
||||
{
|
||||
_page.abortReport();
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ import mineplex.core.itemstack.ItemBuilder;
|
||||
import mineplex.core.report.ReportCategory;
|
||||
|
||||
/**
|
||||
* Represents a clickable button in a {@link ReportCategoryPage} which determines the type of infraction a player has committed.
|
||||
* Represents a clickable button in a {@link ReportCreatePage} which determines the type of infraction a player has committed.
|
||||
*/
|
||||
public class ReportCategoryButton extends SimpleGuiItem
|
||||
{
|
||||
@ -39,24 +39,29 @@ public class ReportCategoryButton extends SimpleGuiItem
|
||||
put(ReportCategory.GAMEPLAY, itemGameplay);
|
||||
}};
|
||||
|
||||
private final ReportCategoryPage _reportCategoryPage;
|
||||
private final ReportCategoryCallback _callback;
|
||||
private final ReportCategory _category;
|
||||
|
||||
public ReportCategoryButton(ReportCategoryPage reportCategoryPage, ReportCategory reportCategory)
|
||||
public ReportCategoryButton(ReportCategoryCallback callback, ReportCategory reportCategory)
|
||||
{
|
||||
this(reportCategoryPage, reportCategory, ITEM_STACKS.get(reportCategory));
|
||||
this(callback, reportCategory, ITEM_STACKS.get(reportCategory));
|
||||
}
|
||||
|
||||
public ReportCategoryButton(ReportCategoryPage reportCategoryPage, ReportCategory reportCategory, ItemStack itemStack)
|
||||
public ReportCategoryButton(ReportCategoryCallback callback, ReportCategory reportCategory, ItemStack itemStack)
|
||||
{
|
||||
super(itemStack);
|
||||
_reportCategoryPage = reportCategoryPage;
|
||||
_callback = callback;
|
||||
_category = reportCategory;
|
||||
}
|
||||
|
||||
public ReportCategory getCategory()
|
||||
{
|
||||
return _category;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void click(ClickType clickType)
|
||||
{
|
||||
_reportCategoryPage.addReport(_category);
|
||||
_callback.click(this);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package mineplex.core.report.ui;
|
||||
|
||||
/**
|
||||
* Allows re-use of the {@link ReportCategoryButton} class.
|
||||
*/
|
||||
public interface ReportCategoryCallback
|
||||
{
|
||||
/**
|
||||
* Invoked when a category button is clicked.
|
||||
* @param button The button that was clicked
|
||||
*/
|
||||
void click(ReportCategoryButton button);
|
||||
}
|
@ -5,7 +5,6 @@ import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import mineplex.core.account.CoreClient;
|
||||
import mineplex.core.chatsnap.SnapshotManager;
|
||||
@ -21,7 +20,7 @@ import mineplex.core.report.ReportPlugin;
|
||||
/**
|
||||
* User interface shown to a player when reporting another player.
|
||||
*/
|
||||
public class ReportCategoryPage extends SimpleGui
|
||||
public class ReportCreatePage extends SimpleGui implements ReportCategoryCallback
|
||||
{
|
||||
private final ReportPlugin _plugin;
|
||||
private final Player _reporter;
|
||||
@ -29,7 +28,7 @@ public class ReportCategoryPage extends SimpleGui
|
||||
private final CoreClient _suspect;
|
||||
private final String _reason;
|
||||
|
||||
public ReportCategoryPage(ReportPlugin plugin, Player reporter, int reporterId, CoreClient suspect, String reason)
|
||||
public ReportCreatePage(ReportPlugin plugin, Player reporter, int reporterId, CoreClient suspect, String reason)
|
||||
{
|
||||
super(plugin.getPlugin(), reporter, "Report " + suspect.getName(), 9 * 3);
|
||||
|
||||
@ -51,9 +50,6 @@ public class ReportCategoryPage extends SimpleGui
|
||||
|
||||
public void addReport(ReportCategory category)
|
||||
{
|
||||
_reporter.closeInventory();
|
||||
unregisterListener();
|
||||
|
||||
if (category == ReportCategory.CHAT_ABUSE)
|
||||
{
|
||||
if (hasSentMessage(_suspect.getAccountId()))
|
||||
@ -106,9 +102,10 @@ public class ReportCategoryPage extends SimpleGui
|
||||
});
|
||||
}
|
||||
|
||||
public void unregisterListener()
|
||||
@Override
|
||||
public void click(ReportCategoryButton button)
|
||||
{
|
||||
HandlerList.unregisterAll(this);
|
||||
_reporter.closeInventory();
|
||||
addReport(button.getCategory());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package mineplex.core.report.ui;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import mineplex.core.common.util.BukkitFuture;
|
||||
import mineplex.core.common.util.C;
|
||||
import mineplex.core.common.util.F;
|
||||
import mineplex.core.common.util.UtilPlayer;
|
||||
import mineplex.core.gui.SimpleGui;
|
||||
import mineplex.core.report.ReportCategory;
|
||||
import mineplex.core.report.ReportManager;
|
||||
import mineplex.core.report.ReportPlugin;
|
||||
import mineplex.core.report.data.Report;
|
||||
import mineplex.core.report.data.ReportRepository;
|
||||
|
||||
/**
|
||||
* An interface which allows the user to select the type of report they'd like to handle.
|
||||
*/
|
||||
public class ReportHandlePage extends SimpleGui implements ReportCategoryCallback
|
||||
{
|
||||
private final ReportPlugin _plugin;
|
||||
private final Player _handler;
|
||||
private final int _handlerId;
|
||||
|
||||
public ReportHandlePage(ReportPlugin plugin, Player handler, int handlerId)
|
||||
{
|
||||
super(plugin.getPlugin(), handler, "Report Type Selection", 9 * 3);
|
||||
|
||||
_plugin = plugin;
|
||||
_handler = handler;
|
||||
_handlerId = handlerId;
|
||||
|
||||
buildPage();
|
||||
}
|
||||
|
||||
private void buildPage()
|
||||
{
|
||||
setItem(11, new ReportCategoryButton(this, ReportCategory.HACKING));
|
||||
setItem(13, new ReportCategoryButton(this, ReportCategory.CHAT_ABUSE));
|
||||
setItem(15, new ReportCategoryButton(this, ReportCategory.GAMEPLAY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void click(ReportCategoryButton button)
|
||||
{
|
||||
_handler.closeInventory();
|
||||
handleReport(button.getCategory());
|
||||
}
|
||||
|
||||
public void handleReport(ReportCategory category)
|
||||
{
|
||||
ReportManager reportManager = _plugin.getReportManager();
|
||||
ReportRepository reportRepository = reportManager.getReportRepository();
|
||||
|
||||
reportManager.isHandlingReport(_handler).whenComplete((handlingReport, throwable) ->
|
||||
{
|
||||
if (throwable == null)
|
||||
{
|
||||
if (!handlingReport)
|
||||
{
|
||||
Map<Report, Double> reportPriorities = Collections.synchronizedMap(new HashMap<>());
|
||||
boolean devMode = reportManager.isDevMode(_handler.getUniqueId());
|
||||
|
||||
// the below fetches the ids of all unhandled reports and gets a Report object for each of these ids
|
||||
// the priority of the report is then calculated and the results placed in a map
|
||||
reportRepository.getUnhandledReports(_handlerId, category, devMode).thenCompose(reportRepository::getReports).thenAccept(reports ->
|
||||
CompletableFuture.allOf(reports.stream().map(report ->
|
||||
reportManager.calculatePriority(report).thenAccept(priority ->
|
||||
{
|
||||
if (priority > 0)
|
||||
{
|
||||
reportPriorities.put(report, priority);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mark the report as expired to keep the database clean
|
||||
// and reduce future query time
|
||||
reportManager.expireReport(report);
|
||||
}
|
||||
}
|
||||
)
|
||||
).toArray(CompletableFuture[]::new)).join()
|
||||
).thenApply(aVoid ->
|
||||
{
|
||||
Map.Entry<Report, Double> mostImportant = null;
|
||||
|
||||
for (Map.Entry<Report, Double> entry : reportPriorities.entrySet())
|
||||
{
|
||||
if (mostImportant == null || (double) entry.getValue() > mostImportant.getValue())
|
||||
{
|
||||
mostImportant = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return mostImportant == null ? null : mostImportant.getKey();
|
||||
}).thenCompose(BukkitFuture.accept(report ->
|
||||
{
|
||||
if (report != null)
|
||||
{
|
||||
reportManager.handleReport(report, _handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(_handler, F.main(_plugin.getName(), "No open " + F.elem(category.getName()) + " report(s) found."));
|
||||
}
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
Bukkit.getScheduler().runTask(_plugin.getPlugin(), () ->
|
||||
UtilPlayer.message(_handler, F.main(_plugin.getName(), C.cRed + "You are already handling a report.")));
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(_handler, F.main(_plugin.getName(), C.cRed + "An error occurred, please try again later."));
|
||||
_plugin.getPlugin().getLogger().log(Level.SEVERE, "Error whilst checking for reports being handled by " + _handler.getName(), throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
package mineplex.core.report.ui;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import mineplex.core.common.util.BukkitFuture;
|
||||
import mineplex.core.common.util.C;
|
||||
import mineplex.core.common.util.F;
|
||||
import mineplex.core.common.util.UtilPlayer;
|
||||
import mineplex.core.gui.SimpleGui;
|
||||
@ -18,15 +21,17 @@ import mineplex.core.report.data.Report;
|
||||
*/
|
||||
public class ReportResultPage extends SimpleGui
|
||||
{
|
||||
private ReportManager _reportManager;
|
||||
private Report _report;
|
||||
private String _suspectName;
|
||||
private String _reason;
|
||||
private final ReportPlugin _plugin;
|
||||
private final ReportManager _reportManager;
|
||||
private final Report _report;
|
||||
private final String _suspectName;
|
||||
private final String _reason;
|
||||
|
||||
public ReportResultPage(ReportPlugin reportPlugin, Report report, Player reportCloser, String suspectName, String reason)
|
||||
public ReportResultPage(ReportPlugin plugin, Report report, Player reportCloser, String suspectName, String reason)
|
||||
{
|
||||
super(reportPlugin.getPlugin(), reportCloser, "Close Report", 9 * 4);
|
||||
_reportManager = reportPlugin.getReportManager();
|
||||
super(plugin.getPlugin(), reportCloser, "Close Report", 9 * 4);
|
||||
_plugin = plugin;
|
||||
_reportManager = plugin.getReportManager();
|
||||
_report = report;
|
||||
_suspectName = suspectName;
|
||||
_reason = reason;
|
||||
@ -44,14 +49,13 @@ public class ReportResultPage extends SimpleGui
|
||||
setItem(11, new ReportResultButton(this, ReportResultType.ACCEPTED));
|
||||
setItem(13, new ReportResultButton(this, ReportResultType.DENIED));
|
||||
setItem(15, new ReportResultButton(this, ReportResultType.ABUSIVE));
|
||||
//setItem(34, );
|
||||
setItem(27, new ReportAbortButton(this));
|
||||
setItem(35, new ReportAssignTeamButton(this, ReportTeam.RC));
|
||||
}
|
||||
|
||||
public void closeReport(ReportResultType result)
|
||||
{
|
||||
getPlayer().closeInventory();
|
||||
unregisterListener();
|
||||
ReportResult reportResult = new ReportResult(result, _reason);
|
||||
|
||||
_reportManager.closeReport(_report, getPlayer(), reportResult);
|
||||
@ -60,7 +64,6 @@ public class ReportResultPage extends SimpleGui
|
||||
public void assignTeam(ReportTeam team)
|
||||
{
|
||||
getPlayer().closeInventory();
|
||||
unregisterListener();
|
||||
|
||||
_reportManager.assignTeam(_report, team).thenAccept(aVoid ->
|
||||
UtilPlayer.message(getPlayer(),
|
||||
@ -68,8 +71,32 @@ public class ReportResultPage extends SimpleGui
|
||||
"Report forwarded to " + F.elem(team.name()) + " team")));
|
||||
}
|
||||
|
||||
public void unregisterListener()
|
||||
public void abortReport()
|
||||
{
|
||||
HandlerList.unregisterAll(this);
|
||||
getPlayer().closeInventory();
|
||||
|
||||
_reportManager.getReportHandling(getPlayer()).whenComplete(BukkitFuture.complete((reportOptional, throwable) ->
|
||||
{
|
||||
if (throwable == null)
|
||||
{
|
||||
if (reportOptional.isPresent())
|
||||
{
|
||||
Report report = reportOptional.get();
|
||||
|
||||
_reportManager.abortReport(report).thenApply(BukkitFuture.accept(voidValue ->
|
||||
UtilPlayer.message(getPlayer(), F.main(ReportManager.getReportPrefix(report),
|
||||
"Report has been aborted and may be handled by another staff member."))));
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(getPlayer(), F.main(_plugin.getName(), "You aren't currently handling a report."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UtilPlayer.message(getPlayer(), F.main(_plugin.getName(), C.cRed + "An error occurred, please try again later."));
|
||||
_plugin.getPlugin().getLogger().log(Level.SEVERE, "Error whilst aborting report for player " + getPlayer().getName(), throwable);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,6 @@
|
||||
/** @var Int */
|
||||
private $category;
|
||||
|
||||
/** @var Snapshot */
|
||||
private $snapshot;
|
||||
|
||||
/**
|
||||
* Report constructor.
|
||||
* @param Int $id
|
||||
@ -25,16 +22,14 @@
|
||||
* @param User $suspect
|
||||
* @param UserReport[] $reporters
|
||||
* @param Int $category
|
||||
* @param Snapshot $snapshot
|
||||
*/
|
||||
function __construct($id, $handler, $suspect, $reporters, $category, $snapshot)
|
||||
function __construct($id, $handler, $suspect, $reporters, $category)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->handler = $handler;
|
||||
$this->suspect = $suspect;
|
||||
$this->reporters = $reporters;
|
||||
$this->category = $category;
|
||||
$this->snapshot = $snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,12 +98,4 @@
|
||||
{
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Snapshot
|
||||
*/
|
||||
public function getSnapshot()
|
||||
{
|
||||
return $this->snapshot;
|
||||
}
|
||||
}
|
4
Plugins/Mineplex.ReportSite/sql/snapshot-tokens.sql
Normal file
4
Plugins/Mineplex.ReportSite/sql/snapshot-tokens.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE Account.snapshots ADD token CHAR(8);
|
||||
CREATE UNIQUE INDEX snapshots_token_uindex ON snapshots (token);
|
||||
ALTER TABLE Account.snapshots
|
||||
MODIFY COLUMN creator INT(11) AFTER token;
|
@ -89,7 +89,7 @@
|
||||
function getReport($reportId)
|
||||
{
|
||||
$connection = getConnection("ACCOUNT");
|
||||
$statement = $connection->prepare('SELECT reports.suspectId, reports.categoryId, reports.snapshotId, reportHandlers.handlerId FROM reports
|
||||
$statement = $connection->prepare('SELECT reports.suspectId, reports.categoryId, reportHandlers.handlerId FROM reports
|
||||
LEFT JOIN reportHandlers ON reports.id = reportHandlers.reportId AND reportHandlers.aborted IS FALSE
|
||||
LEFT JOIN reportResults ON reports.id = reportResults.reportId
|
||||
WHERE reports.id = ?;');
|
||||
@ -97,26 +97,20 @@
|
||||
$statement->bind_param('i', $reportId);
|
||||
$statement->execute();
|
||||
$statement->store_result();
|
||||
$statement->bind_result($suspectId, $categoryId, $snapshotId, $handlerId);
|
||||
$statement->bind_result($suspectId, $categoryId, $handlerId);
|
||||
|
||||
if ($statement->fetch())
|
||||
{
|
||||
$suspectUser = getUser($suspectId);
|
||||
$reportReasons = getReporters($reportId);
|
||||
$snapshot = null;
|
||||
$handlerUser = null;
|
||||
|
||||
if (!is_null($snapshotId))
|
||||
{
|
||||
$snapshot = getSnapshot($snapshotId);
|
||||
}
|
||||
|
||||
if (!is_null($handlerId))
|
||||
{
|
||||
$handlerUser = getUser($handlerId);
|
||||
}
|
||||
|
||||
return new Report($reportId, $handlerUser, $suspectUser, $reportReasons, $categoryId, $snapshot);
|
||||
return new Report($reportId, $handlerUser, $suspectUser, $reportReasons, $categoryId);
|
||||
}
|
||||
|
||||
$statement->close();
|
||||
@ -124,7 +118,39 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
function getSnapshot($messageId)
|
||||
/**
|
||||
* @param string $token
|
||||
* @return int|null
|
||||
*/
|
||||
function getSnapshotId($token)
|
||||
{
|
||||
$connection = getConnection('ACCOUNT');
|
||||
$statement = $connection->prepare('SELECT id FROM snapshots WHERE token = ?;');
|
||||
$statement->bind_param('s', $token); // TODO: correct data type
|
||||
$statement->execute();
|
||||
$statement->bind_result($snapshotId);
|
||||
$statement->store_result();
|
||||
$statement->fetch();
|
||||
return $snapshotId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $snapshotId
|
||||
* @return int|null
|
||||
*/
|
||||
function getSnapshotReportId($snapshotId)
|
||||
{
|
||||
$connection = getConnection('ACCOUNT');
|
||||
$statement = $connection->prepare('SELECT id FROM reports WHERE snapshotId = ?;');
|
||||
$statement->bind_param('i', $snapshotId);
|
||||
$statement->execute();
|
||||
$statement->bind_result($reportId);
|
||||
$statement->store_result();
|
||||
$statement->fetch();
|
||||
return $reportId;
|
||||
}
|
||||
|
||||
function getSnapshot($snapshotId)
|
||||
{
|
||||
/** @var $messages Message[] */
|
||||
$messages = array();
|
||||
@ -135,14 +161,14 @@ WHERE snapshotMessageMap.snapshotId = snapshots.id
|
||||
AND snapshotMessages.id = snapshotMessageMap.messageId
|
||||
AND snapshots.id = ?;");
|
||||
|
||||
$statement->bind_param('i', $messageId);
|
||||
$statement->bind_param('i', $snapshotId);
|
||||
$statement->execute();
|
||||
$statement->bind_result($messageId, $senderId, $snapshotType, $server, $time, $message);
|
||||
$statement->bind_result($snapshotId, $senderId, $snapshotType, $server, $time, $message);
|
||||
$statement->store_result();
|
||||
|
||||
while ($statement->fetch())
|
||||
{
|
||||
$recipients = getUsers(getMessageRecipients($messageId));
|
||||
$recipients = getUsers(getMessageRecipients($snapshotId));
|
||||
$message = new Message(getUser($senderId), $recipients, $time, $snapshotType, $message, $server);
|
||||
array_push($messages, $message);
|
||||
}
|
||||
@ -161,20 +187,20 @@ WHERE snapshotMessageMap.snapshotId = snapshots.id
|
||||
}
|
||||
}
|
||||
|
||||
return new Snapshot($messageId, $messages, $snapshotUsers);
|
||||
return new Snapshot($snapshotId, $messages, $snapshotUsers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $messageId
|
||||
* @param $snapshotId
|
||||
* @return Integer[] array
|
||||
*/
|
||||
function getMessageRecipients($messageId)
|
||||
function getMessageRecipients($snapshotId)
|
||||
{
|
||||
$recipientIds = array();
|
||||
$connection = getConnection("ACCOUNT");
|
||||
$statement = $connection->prepare("SELECT recipientId FROM snapshotRecipients WHERE messageId = ?");
|
||||
|
||||
$statement->bind_param('i', $messageId);
|
||||
$statement->bind_param('i', $snapshotId);
|
||||
$statement->execute();
|
||||
$statement->bind_result($recipientId);
|
||||
|
||||
@ -355,38 +381,41 @@ WHERE snapshotMessageMap.snapshotId = snapshots.id
|
||||
return '?' . http_build_query($vars);
|
||||
}
|
||||
|
||||
$validId = isset($_GET['id']);
|
||||
$validToken = isset($_GET['token']);
|
||||
$errorMsg = "";
|
||||
|
||||
$id = null;
|
||||
$token = null;
|
||||
$expanded = null;
|
||||
$report = null;
|
||||
$snapshot = null;
|
||||
$messages = null;
|
||||
|
||||
if ($validId)
|
||||
if ($validToken)
|
||||
{
|
||||
$id = $_GET['id'];
|
||||
$token = $_GET['token'];
|
||||
$expanded = isset($_GET['expanded']) && $_GET['expanded'];
|
||||
$report = getReport($id);
|
||||
$snapshotId = getSnapshotId($token);
|
||||
|
||||
if ($report)
|
||||
if ($snapshotId != null)
|
||||
{
|
||||
$snapshot = $report->getSnapshot();
|
||||
$snapshot = getSnapshot($snapshotId);
|
||||
$messages = $snapshot->getMessages();
|
||||
$reportId = getSnapshotReportId($snapshotId);
|
||||
|
||||
if ($snapshot != null)
|
||||
if ($reportId)
|
||||
{
|
||||
$messages = $snapshot->getMessages();
|
||||
$report = getReport($reportId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$errorMsg = 'No associated snapshot found for report.';
|
||||
$validToken = false;
|
||||
$errorMsg = 'Associated report not found.'; // TODO: Allow snapshots without reports in future
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$validId = false;
|
||||
$errorMsg = "Invalid id.";
|
||||
$validToken = false;
|
||||
$errorMsg = 'Invalid token.';
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -399,7 +428,7 @@ WHERE snapshotMessageMap.snapshotId = snapshots.id
|
||||
<link href='https://fonts.googleapis.com/css?family=Crete+Round' rel='stylesheet' type='text/css'>
|
||||
<link href='https://fonts.googleapis.com/css?family=Oswald' rel='stylesheet' type='text/css'>
|
||||
<title>
|
||||
<?php if ($validId): ?>
|
||||
<?php if ($validToken): ?>
|
||||
Report #<?= $report->getId() ?>
|
||||
<?php else: ?>
|
||||
Report System
|
||||
@ -415,17 +444,17 @@ WHERE snapshotMessageMap.snapshotId = snapshots.id
|
||||
<h1>Report System</h1>
|
||||
</div>
|
||||
<div id="search">
|
||||
<form id="id-input" name="id-input" action="view.php" method="get">
|
||||
<form id="token-input" name="token-input" action="view.php" method="get">
|
||||
<div class="input-group">
|
||||
<input name="id" type="text" class="form-control" placeholder="Enter snapshot id...">
|
||||
<input name="token" type="text" class="form-control" placeholder="Enter snapshot token...">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-secondary" type="submit" form="id-input"><i class="fa fa-search"></i> Search</button>
|
||||
<button class="btn btn-secondary" type="submit" form="token-input"><i class="fa fa-search"></i> Search</button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if ((isset($_GET['id']) && !$validId) || !empty($errorMsg)): ?>
|
||||
<?php if ((isset($_GET['token']) && !$validToken) || !empty($errorMsg)): ?>
|
||||
<div id="content" class="center-block" style="text-align: center; background-color: rgba(204, 34, 42, 0.52);">
|
||||
<p class="error-oh-no" style="font-size: 60px;">What did you do?!?!?</p>
|
||||
<img src="img/shaun.gif" />
|
||||
@ -436,7 +465,7 @@ WHERE snapshotMessageMap.snapshotId = snapshots.id
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php if (!isset($_GET['id'])) exit(); ?>
|
||||
<?php if (!isset($_GET['token'])) exit(); ?>
|
||||
|
||||
<div id="content">
|
||||
<div>
|
||||
|
Loading…
Reference in New Issue
Block a user