diff --git a/build.gradle.kts b/build.gradle.kts index 0870213..c2c5d10 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "dev.plex" -version = "1.0-SNAPSHOT" +version = "1.1" description = "Medina" repositories { diff --git a/src/main/java/dev/plex/medina/command/impl/ReportCommand.java b/src/main/java/dev/plex/medina/command/impl/ReportCommand.java index e91c5a0..5352962 100644 --- a/src/main/java/dev/plex/medina/command/impl/ReportCommand.java +++ b/src/main/java/dev/plex/medina/command/impl/ReportCommand.java @@ -46,6 +46,7 @@ public class ReportCommand extends MedinaCommand player.getName(), ZonedDateTime.now(), reason, + false, false); plugin.getSqlReports().addReport(report); diff --git a/src/main/java/dev/plex/medina/command/impl/ReportsCommand.java b/src/main/java/dev/plex/medina/command/impl/ReportsCommand.java index d094f24..72a5321 100644 --- a/src/main/java/dev/plex/medina/command/impl/ReportsCommand.java +++ b/src/main/java/dev/plex/medina/command/impl/ReportsCommand.java @@ -13,19 +13,50 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -@CommandParameters(name = "reports", usage = "/ >", description = "View existing reports on a player", permission = "medina.reports", source = RequiredCommandSource.ANY) +@CommandParameters(name = "reports", usage = "/ [ list | delete | resolve ]", description = "View existing reports on a player", permission = "medina.reports", source = RequiredCommandSource.ANY) public class ReportsCommand extends MedinaCommand { @Override protected Component execute(@NotNull CommandSender sender, @Nullable Player playerSender, @NotNull String[] args) { - if (args.length < 2) + if (args.length == 0) { - return usage(); + plugin.getSqlReports().getUnresolvedReports().whenComplete((reports, ex) -> + { + // we don't want to include deleted reports in the logic + long count = reports.stream() + .filter(report -> !report.isDeleted()) + .count(); + if (count <= 0) + { + send(sender, messageComponent("noUnresolvedReports")); + return; + } + + listUnresolvedReports(sender, reports); + }); + return null; + } + + if (args[0].equalsIgnoreCase("resolve")) + { + if (args.length < 2) + { + return usage(); + } + + int reportId = parseInt(sender, args[1]); + + plugin.getSqlReports().resolveReport(reportId).whenComplete((reports, ex) -> + { + send(sender, messageComponent("resolvedReport", reportId)); + }); + return null; } OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayerIfCached(args[0]); @@ -34,6 +65,11 @@ public class ReportsCommand extends MedinaCommand return messageComponent("playerNotFound"); } + if (args.length == 1) + { + return usage(); + } + switch (args[1].toLowerCase()) { case "list": @@ -54,6 +90,24 @@ public class ReportsCommand extends MedinaCommand return null; } + case "read": + { + if (args.length < 3) + { + return usage(); + } + int reportId = parseInt(sender, args[2]); + plugin.getSqlReports().getReport(reportId).whenComplete((report, ex) -> + { + if (report.isDeleted()) + { + send(sender, messageComponent("reportDoesntExist")); + return; + } + readReport(sender, offlinePlayer, report); + }); + return null; + } case "delete": { if (args.length < 3) @@ -61,7 +115,7 @@ public class ReportsCommand extends MedinaCommand return usage(); } int id = parseInt(sender, args[2]); - plugin.getSqlReports().getReports(id).whenComplete(((report, ex) -> + plugin.getSqlReports().getReport(id).whenComplete(((report, ex) -> { if (report == null) { @@ -108,14 +162,44 @@ public class ReportsCommand extends MedinaCommand send(sender, reportList.get()); } + private void readReport(@NotNull CommandSender sender, OfflinePlayer player, Report report) + { + AtomicReference reportList = new AtomicReference<>(Component.empty()); + Component reportLine = messageComponent("reportPrefix", report.getReportId(), player.getName(), MedinaUtils.useTimezone(report.getTimestamp())); + reportLine = reportLine.append(messageComponent("reportLine", report.getReason())); + reportLine = reportLine.append(Component.newline()); + reportLine = reportLine.append(messageComponent("clickToResolve", report.getReportId())); + reportList.set(reportList.get().append(reportLine)); + send(sender, reportList.get()); + } + + private void listUnresolvedReports(@NotNull CommandSender sender, List reports) + { + AtomicReference reportList = new AtomicReference<>(messageComponent("unresolvedReports")); + for (Report report : reports) + { + if (report.isDeleted()) + { + continue; + } + Component reportLine = messageComponent("reportSummary", report.getReportId(), report.getReporterName(), report.getReportedName()); + reportList.set(reportList.get().append(Component.newline())); + reportList.set(reportList.get().append(reportLine)); + } + send(sender, reportList.get()); + } + @Override public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException { if (args.length == 1 && sender.hasPermission("medina.reports")) { - return MedinaUtils.getPlayerNameList(); + List options = new ArrayList<>(); + options.add("resolve"); + options.addAll(MedinaUtils.getPlayerNameList()); + return options; } - if (args.length == 2 && sender.hasPermission("medina.reports")) + if (args.length == 2 && !args[0].equals("resolve") && sender.hasPermission("medina.reports")) { return List.of("list", "delete"); } diff --git a/src/main/java/dev/plex/medina/data/Report.java b/src/main/java/dev/plex/medina/data/Report.java index a05bd50..a7da742 100644 --- a/src/main/java/dev/plex/medina/data/Report.java +++ b/src/main/java/dev/plex/medina/data/Report.java @@ -33,6 +33,9 @@ public class Report @Getter private final String reason; + @Getter + private final boolean resolved; + @Getter private final boolean deleted; diff --git a/src/main/java/dev/plex/medina/storage/SQLConnection.java b/src/main/java/dev/plex/medina/storage/SQLConnection.java index bee28c1..2531e76 100644 --- a/src/main/java/dev/plex/medina/storage/SQLConnection.java +++ b/src/main/java/dev/plex/medina/storage/SQLConnection.java @@ -56,6 +56,7 @@ public class SQLConnection implements MedinaBase "`reportedName` VARCHAR(18), " + "`timestamp` BIGINT, " + "`reason` VARCHAR(2000), " + + "`resolved` BOOLEAN, " + "`deleted` BOOLEAN, " + "PRIMARY KEY (`reportId`));").execute(); } diff --git a/src/main/java/dev/plex/medina/storage/SQLReports.java b/src/main/java/dev/plex/medina/storage/SQLReports.java index b345d66..401eae8 100644 --- a/src/main/java/dev/plex/medina/storage/SQLReports.java +++ b/src/main/java/dev/plex/medina/storage/SQLReports.java @@ -18,10 +18,12 @@ public class SQLReports implements MedinaBase { private static final String SELECT = "SELECT * FROM `reports` WHERE reportedUUID=?"; private static final String SELECT_ID = "SELECT * FROM `reports` WHERE reportId=?"; - private static final String INSERT = "INSERT INTO `reports` (`reporterUUID`, `reporterName`, `reportedUUID`, `reportedName`, `timestamp`, `reason`, `deleted`) VALUES(?, ?, ?, ?, ?, ?, ?)"; + private static final String SELECT_UNRESOLVED = "SELECT * FROM `reports` WHERE resolved=?"; + private static final String RESOLVE = "UPDATE `reports` SET `resolved`=true WHERE reportId=?"; + private static final String INSERT = "INSERT INTO `reports` (`reporterUUID`, `reporterName`, `reportedUUID`, `reportedName`, `timestamp`, `reason`, `resolved`, `deleted`) VALUES(?, ?, ?, ?, ?, ?, ?, ?)"; private static final String DELETE = "UPDATE `reports` SET `deleted`=true WHERE reportId=? AND reportedUUID=?"; - public CompletableFuture getReports(int reportedId) + public CompletableFuture getReport(int reportedId) { return CompletableFuture.supplyAsync(() -> { @@ -41,6 +43,7 @@ public class SQLReports implements MedinaBase set.getString("reportedName"), ZonedDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("timestamp")), ZoneId.systemDefault()), set.getString("reason"), + set.getBoolean("resolved"), set.getBoolean("deleted")); return report; } @@ -54,6 +57,57 @@ public class SQLReports implements MedinaBase }); } + public CompletableFuture> getUnresolvedReports() + { + return CompletableFuture.supplyAsync(() -> + { + List reports = Lists.newArrayList(); + try (Connection con = plugin.getSqlConnection().getCon()) + { + PreparedStatement statement = con.prepareStatement(SELECT_UNRESOLVED); + statement.setBoolean(1, false); + ResultSet set = statement.executeQuery(); + while (set.next()) + { + Report report = new Report( + set.getInt("reportId"), + UUID.fromString(set.getString("reporterUUID")), + set.getString("reporterName"), + UUID.fromString(set.getString("reportedUUID")), + set.getString("reportedName"), + ZonedDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("timestamp")), ZoneId.systemDefault()), + set.getString("reason"), + set.getBoolean("resolved"), + set.getBoolean("deleted")); + reports.add(report); + } + } + catch (Throwable e) + { + e.printStackTrace(); + return reports; + } + return reports; + }); + } + + public CompletableFuture resolveReport(int reportId) + { + return CompletableFuture.runAsync(() -> + { + try (Connection con = plugin.getSqlConnection().getCon()) + { + PreparedStatement statement = con.prepareStatement(RESOLVE); + statement.setInt(1, reportId); + statement.execute(); + } + catch (Throwable e) + { + e.printStackTrace(); + } + }); + } + public CompletableFuture> getReports(UUID reportedUUID) { return CompletableFuture.supplyAsync(() -> @@ -74,6 +128,7 @@ public class SQLReports implements MedinaBase set.getString("reportedName"), ZonedDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("timestamp")), ZoneId.systemDefault()), set.getString("reason"), + set.getBoolean("resolved"), set.getBoolean("deleted")); reports.add(report); } @@ -120,7 +175,8 @@ public class SQLReports implements MedinaBase statement.setString(4, report.getReportedName()); statement.setLong(5, report.getTimestamp().toInstant().toEpochMilli()); statement.setString(6, report.getReason()); - statement.setBoolean(7, report.isDeleted()); + statement.setBoolean(7, report.isResolved()); + statement.setBoolean(8, report.isDeleted()); statement.execute(); } catch (Throwable e) diff --git a/src/main/java/dev/plex/medina/util/MedinaUtils.java b/src/main/java/dev/plex/medina/util/MedinaUtils.java index d8a0a83..511a6db 100644 --- a/src/main/java/dev/plex/medina/util/MedinaUtils.java +++ b/src/main/java/dev/plex/medina/util/MedinaUtils.java @@ -19,7 +19,7 @@ import java.util.stream.Collectors; public class MedinaUtils implements MedinaBase { private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage(); - private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("MM/dd/yyyy 'at' hh:mm:ss a z"); + private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("MM/dd/yyyy 'at' hh:mm:ss a"); public static Component mmDeserialize(String input) { diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index 8bee0d8..d940741 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -29,7 +29,7 @@ reportHeader: "Player reports for: {0}" # 0 - Report ID # 1 - Author of the note # 2 - Timestamp -reportPrefix: "{0} - Written by: {1} on {2}" +reportPrefix: "{0} - Reported by: {1} on {2}" # 0 - The content of the report reportLine: "# {0}" @@ -44,4 +44,19 @@ reportDoesntExist: "There is no report with this ID belonging to that playe # 2 - The reason for the report notifyReport: "[REPORT] {0} reported {1} for {2}" -cantReportYourself: "You cannot report yourself." \ No newline at end of file +cantReportYourself: "You cannot report yourself." + +# 0 - The report ID +resolvedReport: "Report with ID: {0} has been resolved!" + +unresolvedReports: "--- Unresolved Reports ---" + +# 0 - The report ID +# 1 - The reporter name +# 2 - The reported name +reportSummary: "ID: {0}, {1} reported {2} - Click to view" + +noUnresolvedReports: "There are no unresolved reports." + +# 0 - The report ID +clickToResolve: "Click to resolve" \ No newline at end of file