PC-1153 Add /reportmetrics command

This commit is contained in:
Keir Nellyer 2016-10-26 10:28:01 +01:00
parent e4c7e31185
commit 52d001c26e
7 changed files with 385 additions and 12 deletions

View File

@ -34,6 +34,7 @@ import mineplex.core.portal.Portal;
import mineplex.core.punish.Category;
import mineplex.core.punish.Punish;
import mineplex.core.punish.PunishClient;
import mineplex.core.report.data.metrics.ReportMetricsRepository;
import mineplex.core.report.redis.HandlerNotification;
import mineplex.core.report.data.Report;
import mineplex.core.report.data.ReportMessage;
@ -64,7 +65,8 @@ public class ReportManager
private final int _serverWeight;
private final ReportRepository _reportRepository;
private final ReportUserRepository _reportUserRepository;
private final ReportUserRepository _userRepository;
private final ReportMetricsRepository _metricsRepository;
public ReportManager(JavaPlugin plugin, SnapshotManager snapshotManager, CoreClientManager clientManager,
IncognitoManager incognitoManager, Punish punish, Region region, String serverName, int serverWeight)
@ -79,8 +81,8 @@ public class ReportManager
_serverWeight = serverWeight;
_reportRepository = new ReportRepository(this, _plugin.getLogger());
_reportUserRepository = new ReportUserRepository(plugin);
_userRepository = new ReportUserRepository(plugin);
_metricsRepository = new ReportMetricsRepository(_plugin.getLogger());
ServerCommandManager commandManager = ServerCommandManager.getInstance();
ReportRedisManager notificationCallback = new ReportRedisManager(this, _serverName);
@ -101,7 +103,7 @@ public class ReportManager
}
/**
* Gets the {@link ReportRepository} we are using.
* Gets the {@link ReportRepository} this instance is using.
*
* @return the repository
*/
@ -110,6 +112,26 @@ public class ReportManager
return _reportRepository;
}
/**
* Gets the {@link ReportUserRepository} this instance is using.
*
* @return the repository
*/
public ReportUserRepository getUserRepository()
{
return _userRepository;
}
/**
* Gets the {@link ReportMetricsRepository} this instance is using.
*
* @return the repository
*/
public ReportMetricsRepository getMetricsRepository()
{
return _metricsRepository;
}
/**
* Creates a new report or adds to an existing one.
*
@ -595,7 +617,7 @@ public class ReportManager
for (Map.Entry<Integer, ReportMessage> entry : report.getMessages().entrySet())
{
int accountId = entry.getKey();
ReportUser user = _reportUserRepository.getUser(accountId).join();
ReportUser user = _userRepository.getUser(accountId).join();
int categoryReputation = user.getReputation(report.getCategory());
ReportMessage message = entry.getValue();

View File

@ -11,6 +11,7 @@ import mineplex.core.report.command.ReportCommand;
import mineplex.core.report.command.ReportHandleCommand;
import mineplex.core.report.command.ReportInfoCommand;
import mineplex.core.report.command.ReportHistoryCommand;
import mineplex.core.report.command.ReportMetricsCommand;
/**
* Main class for this module, handles initialization and disabling of the module.
@ -38,6 +39,7 @@ public class ReportPlugin extends MiniPlugin
addCommand(new ReportCloseCommand(this));
addCommand(new ReportHistoryCommand(this));
addCommand(new ReportInfoCommand(this));
addCommand(new ReportMetricsCommand(this));
}
@EventHandler

View File

@ -7,23 +7,23 @@ import org.apache.commons.lang3.text.WordUtils;
*/
public enum ReportResultType
{
ACCEPTED(0, false),
DENIED(1, false),
ABUSIVE(2, true),
EXPIRED(3, true);
ACCEPTED((short) 0, false),
DENIED((short) 1, false),
ABUSIVE((short) 2, true),
EXPIRED((short) 3, true);
private final int _id;
private final short _id;
private final boolean _globalStat;
private final String _name;
ReportResultType(int id, boolean globalStat)
ReportResultType(short id, boolean globalStat)
{
_id = id;
_globalStat = globalStat;
_name = WordUtils.capitalizeFully(name().replace('_', ' '));
}
public int getId()
public short getId()
{
return _id;
}

View File

@ -0,0 +1,108 @@
package mineplex.core.report.command;
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.ReportPlugin;
import mineplex.core.report.data.metrics.ReportMetrics;
/**
* Displays various report-related metrics on a player.
*/
public class ReportMetricsCommand extends CommandBase<ReportPlugin>
{
public ReportMetricsCommand(ReportPlugin plugin)
{
super(plugin, Rank.MODERATOR, "reportmetrics");
}
@Override
public void Execute(Player player, String[] args)
{
if (args.length <= 2)
{
int days = 30;
if (args.length >= 1) // has target argument
{
String targetName = args[0];
if (args.length > 1)
{
String daysString = args[1];
try
{
days = Integer.parseInt(daysString);
}
catch (NumberFormatException e)
{
UtilPlayer.message(player, F.main(Plugin.getName(), F.elem(daysString) + C.cRed + " is not a valid number."));
}
}
int finalDays = days;
Plugin.getReportManager().getRepository().getAccountId(targetName).thenAccept(targetIdOptional ->
{
if (targetIdOptional.isPresent())
{
int targetId = targetIdOptional.get();
displayUserMetrics(player, targetName, targetId, finalDays);
}
else
{
UtilPlayer.message(player, F.main(Plugin.getName(), C.cRed + "Player not found."));
}
});
}
else // display global metrics
{
// TODO: do we parse days for global metrics?
UtilPlayer.message(player, F.main("Report Metrics", F.elem("Global Metrics") + " (" + F.elem(days + " days") + ")"));
displayGlobalMetrics(player, days);
}
}
else
{
UtilPlayer.message(player,
F.main(Plugin.getName(), C.cRed + "Invalid Usage: "
+ F.elem("/" + _aliasUsed + " <player> [days]")));
}
}
public void displayGlobalMetrics(Player player, int days)
{
Plugin.getReportManager().getMetricsRepository().getGlobalMetrics(days).thenCompose(
BukkitFuture.accept(globalMetrics ->
{
UtilPlayer.message(player, F.main("Report Metrics", "Submitted: " + F.elem(globalMetrics.getSubmitted())));
UtilPlayer.message(player, F.main("Report Metrics", "Expired: " + F.elem(globalMetrics.getExpired())));
displayMetrics(player, globalMetrics);
}));
}
public void displayUserMetrics(Player player, String targetName, int targetId, int days)
{
Plugin.getReportManager().getMetricsRepository().getUserMetrics(targetId, days).thenCompose(
BukkitFuture.accept(userMetrics ->
{
UtilPlayer.message(player,
F.main("Report Metrics",
F.elem(targetName) + " (" + F.elem(days + " days") + ")"));
displayMetrics(player, userMetrics);
}));
}
public void displayMetrics(Player player, ReportMetrics reportMetrics)
{
UtilPlayer.message(player, F.main("Report Metrics", "Accepted: " + F.elem(reportMetrics.getAccepted())));
UtilPlayer.message(player, F.main("Report Metrics", "Denied: " + F.elem(reportMetrics.getDenied())));
UtilPlayer.message(player, F.main("Report Metrics", "Flagged Abusive: " + F.elem(reportMetrics.getFlagged())));
}
}

View File

@ -0,0 +1,37 @@
package mineplex.core.report.data.metrics;
/**
* Extends the standard report metrics class to hold global-scope metrics.
*/
public class ReportGlobalMetrics extends ReportMetrics
{
private final long _submitted;
private final long _expired;
public ReportGlobalMetrics(long submitted, long expired, long accepted, long denied, long flagged)
{
super(accepted, denied, flagged);
_submitted = submitted;
_expired = expired;
}
/**
* Gets the amount of reports submitted.
*
* @return the amount
*/
public long getSubmitted()
{
return _submitted;
}
/**
* Gets the amount of reports expired.
*
* @return the amount
*/
public long getExpired()
{
return _expired;
}
}

View File

@ -0,0 +1,48 @@
package mineplex.core.report.data.metrics;
/**
* Holds report-related metrics which can be applied to a user or global scope.
*/
public class ReportMetrics
{
private final long _accepted;
private final long _denied;
private final long _flagged;
public ReportMetrics(long accepted, long denied, long flagged)
{
_accepted = accepted;
_denied = denied;
_flagged = flagged;
}
/**
* Gets the amount of reports accepted.
*
* @return the amount
*/
public long getAccepted()
{
return _accepted;
}
/**
* Gets the amount of reports denied.
*
* @return the amount
*/
public long getDenied()
{
return _denied;
}
/**
* Gets the amount of reports flagged (marked as spam).
*
* @return the amount
*/
public long getFlagged()
{
return _flagged;
}
}

View File

@ -0,0 +1,156 @@
package mineplex.core.report.data.metrics;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import mineplex.core.report.ReportResultType;
import mineplex.serverdata.database.DBPool;
/**
* Handles all fetching of report-related metrics.
*/
public class ReportMetricsRepository
{
private static final String GET_GLOBAL_SUBMITTED = "SELECT COUNT(DISTINCT reportReasons.reportId) AS submitted FROM reportReasons\n" +
" WHERE reportReasons.time BETWEEN NOW() - INTERVAL ? DAY AND NOW();";
private static final String GET_GLOBAL_RESULT = "SELECT COUNT(reportResults.reportId) AS amount FROM reportResults\n" +
" WHERE reportResults.resultId = ?\n" +
" AND reportResults.closedTime BETWEEN NOW() - INTERVAL ? DAY AND NOW();";
private static final String GET_USER_RESULT = "SELECT COUNT(reportResults.reportId) AS amount FROM reportResults\n" +
" LEFT JOIN reportHandlers ON reportResults.reportId = reportHandlers.reportId AND reportHandlers.aborted IS FALSE\n" +
" WHERE reportHandlers.handlerId = ?\n" +
" AND reportResults.resultId = ?\n" +
" AND reportResults.closedTime BETWEEN NOW() - INTERVAL ? DAY AND NOW();";
private final Logger _logger;
public ReportMetricsRepository(Logger logger)
{
_logger = logger;
}
public CompletableFuture<ReportGlobalMetrics> getGlobalMetrics(int days)
{
CompletableFuture<ReportGlobalMetrics> future = CompletableFuture.supplyAsync(() ->
{
try (Connection connection = DBPool.getAccount().getConnection())
{
long submitted = getGlobalSubmitted(connection, days);
try (PreparedStatement preparedStatement = connection.prepareStatement(GET_GLOBAL_RESULT))
{
long expired = getGlobalResult(preparedStatement, ReportResultType.EXPIRED, days);
long accepted = getGlobalResult(preparedStatement, ReportResultType.ACCEPTED, days);
long denied = getGlobalResult(preparedStatement, ReportResultType.DENIED, days);
long flagged = getGlobalResult(preparedStatement, ReportResultType.ABUSIVE, days);
return new ReportGlobalMetrics(submitted, expired, accepted, denied, flagged);
}
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
});
future.exceptionally(throwable ->
{
_logger.log(Level.SEVERE, "Error fetching global metrics.", throwable);
return null;
});
return future;
}
private long getGlobalSubmitted(Connection connection, int days) throws SQLException
{
PreparedStatement preparedStatement = connection.prepareStatement(GET_GLOBAL_SUBMITTED);
preparedStatement.setInt(1, days);
try (ResultSet resultSet = preparedStatement.executeQuery())
{
if (resultSet.next())
{
return resultSet.getLong("submitted");
}
else
{
return 0;
}
}
}
private long getGlobalResult(PreparedStatement preparedStatement, ReportResultType resultType, int days) throws SQLException
{
preparedStatement.setShort(1, resultType.getId());
preparedStatement.setInt(2, days);
try (ResultSet resultSet = preparedStatement.executeQuery())
{
if (resultSet.next())
{
return resultSet.getLong("amount");
}
else
{
return 0;
}
}
}
public CompletableFuture<ReportMetrics> getUserMetrics(int accountId, int days)
{
CompletableFuture<ReportMetrics> future = CompletableFuture.supplyAsync(() ->
{
try (Connection connection = DBPool.getAccount().getConnection())
{
try (PreparedStatement preparedStatement = connection.prepareStatement(GET_USER_RESULT))
{
long accepted = getUserResult(preparedStatement, accountId, ReportResultType.ACCEPTED, days);
long denied = getUserResult(preparedStatement, accountId, ReportResultType.DENIED, days);
long flagged = getUserResult(preparedStatement, accountId, ReportResultType.ABUSIVE, days);
return new ReportMetrics(accepted, denied, flagged);
}
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
});
future.exceptionally(throwable ->
{
_logger.log(Level.SEVERE, "Error fetching user metrics.", throwable);
return null;
});
return future;
}
private long getUserResult(PreparedStatement preparedStatement, int accountId, ReportResultType resultType, int days) throws SQLException
{
preparedStatement.setInt(1, accountId);
preparedStatement.setShort(2, resultType.getId());
preparedStatement.setInt(3, days);
try (ResultSet resultSet = preparedStatement.executeQuery())
{
if (resultSet.next())
{
return resultSet.getLong("amount");
}
else
{
return 0;
}
}
}
}