implemented report repository

This commit is contained in:
Elias Müller 2024-12-05 23:02:15 +01:00
parent 0276763a8d
commit 6b2a323a9c
6 changed files with 117 additions and 152 deletions

View File

@ -74,6 +74,7 @@ public abstract class HttpRepository extends Repository {
private ReqResp<String> sendHttp(HttpRequest request) { private ReqResp<String> sendHttp(HttpRequest request) {
try(HttpClient client = HttpClient.newHttpClient()) { try(HttpClient client = HttpClient.newHttpClient()) {
this.validateThread();
HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
return new ReqResp<>(httpResponse.statusCode(), httpResponse.body()); return new ReqResp<>(httpResponse.statusCode(), httpResponse.body());
} catch(IOException | InterruptedException e) { } catch(IOException | InterruptedException e) {

View File

@ -1,6 +1,8 @@
package eu.mhsl.craftattack.spawn.api.client; package eu.mhsl.craftattack.spawn.api.client;
import com.google.gson.Gson; import com.google.gson.Gson;
import eu.mhsl.craftattack.spawn.Main;
import org.bukkit.Bukkit;
import java.net.URI; import java.net.URI;
@ -12,4 +14,8 @@ public abstract class Repository {
this.basePath = basePath; this.basePath = basePath;
this.gson = new Gson(); this.gson = new Gson();
} }
protected void validateThread() {
if(Bukkit.isPrimaryThread()) Main.logger().warning("Repository was called synchronously!");
}
} }

View File

@ -2,7 +2,6 @@ package eu.mhsl.craftattack.spawn.api.client.repositories;
import eu.mhsl.craftattack.spawn.api.client.HttpRepository; import eu.mhsl.craftattack.spawn.api.client.HttpRepository;
import eu.mhsl.craftattack.spawn.api.client.ReqResp; import eu.mhsl.craftattack.spawn.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.appliances.report.Report;
import eu.mhsl.craftattack.spawn.util.api.ApiUtil; import eu.mhsl.craftattack.spawn.util.api.ApiUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -15,22 +14,44 @@ public class ReportRepository extends HttpRepository {
super(ApiUtil.getBaseUri(), ApiUtil::withAuthorizationSecret); super(ApiUtil.getBaseUri(), ApiUtil::withAuthorizationSecret);
} }
public record ReportData(@NotNull UUID reporter, @Nullable UUID reported, String reason) { public record ReportCreationInfo(@NotNull UUID reporter, @Nullable UUID reported, String reason) {
} }
public record ReportDataResponse(@NotNull String url) { public record ReportUrl(@NotNull String url) {
} }
public record ReportsResponse(List<ReportInfo> from_self, Object to_self) { public record PlayerReports(
List<Report> from_self,
Object to_self
) {
public record Report(
@Nullable Reporter reported,
@NotNull String subject,
boolean draft,
@NotNull String status,
@NotNull String url
) {
public record Reporter(
@NotNull String username,
@NotNull String uuid
) {
}
}
} }
public record ReportInfo(Reporter reported, @NotNull String subject, boolean draft, @NotNull String status, @NotNull String url) { public ReqResp<PlayerReports> queryReports(UUID player) {
return this.get(
"report",
(parameters) -> parameters.addParameter("uuid", player.toString()),
PlayerReports.class
);
} }
public record Reporter(@NotNull String username, @NotNull String uuid) { public ReqResp<ReportUrl> createReport(ReportCreationInfo data) {
} return this.post(
"report",
public ReqResp<ReportsResponse> queryReports(UUID player) { data,
return this.get("reports", (builder) -> builder.addParameter("token", "asd"), input, SendReportResponse.class); ReportUrl.class
);
} }
} }

View File

@ -18,12 +18,13 @@ public class WhitelistRepository extends HttpRepository {
String lastname, String lastname,
Long banned_until, Long banned_until,
Long outlawed_until Long outlawed_until
) {} ) {
}
public ReqResp<UserData> getUserData(UUID userId) { public ReqResp<UserData> getUserData(UUID userId) {
return this.get( return this.get(
"user", "user",
uriBuilder -> uriBuilder.addParameter("uuid", userId.toString()), parameters -> parameters.addParameter("uuid", userId.toString()),
UserData.class UserData.class
); );
} }

View File

@ -1,7 +1,8 @@
package eu.mhsl.craftattack.spawn.appliances.report; package eu.mhsl.craftattack.spawn.appliances.report;
import com.google.gson.Gson;
import eu.mhsl.craftattack.spawn.Main; import eu.mhsl.craftattack.spawn.Main;
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.api.client.repositories.ReportRepository;
import eu.mhsl.craftattack.spawn.appliance.Appliance; import eu.mhsl.craftattack.spawn.appliance.Appliance;
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@ -10,22 +11,14 @@ import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.apache.http.client.utils.URIBuilder;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
public class Report extends Appliance { public class Report extends Appliance {
public static Component helpText() { public static Component helpText() {
@ -38,163 +31,51 @@ public class Report extends Appliance {
.build(); .build();
} }
private URI apiEndpoint;
private String apiSecret;
public Report() { public Report() {
super("report"); super("report");
} }
private record Request(@NotNull UUID reporter, @Nullable UUID reported, String reason) {
}
private record ReportResponse(@NotNull String url) {
}
private record ReportsResponse(List<ReportInfo> from_self, Object to_self) {
}
private record ReportInfo(Reporter reported, @NotNull String subject, boolean draft, @NotNull String status, @NotNull String url) {
}
private record Reporter(@NotNull String username, @NotNull String uuid) {
}
public void reportToUnknown(@NotNull Player issuer) { public void reportToUnknown(@NotNull Player issuer) {
Request request = new Request(issuer.getUniqueId(), null, ""); ReportRepository.ReportCreationInfo request = new ReportRepository.ReportCreationInfo(issuer.getUniqueId(), null, "");
this.issueReport(issuer, request); this.createReport(issuer, request);
} }
public void reportToKnown(@NotNull Player issuer, @NotNull String targetUsername, @Nullable String reason) { public void reportToKnown(@NotNull Player issuer, @NotNull String targetUsername, @Nullable String reason) {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(targetUsername); OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(targetUsername);
if(issuer.getUniqueId().equals(offlinePlayer.getUniqueId())) { if(issuer.getUniqueId().equals(offlinePlayer.getUniqueId())) {
issuer.sendMessage( issuer.sendMessage(Component.text("Du kannst dich nicht selbst reporten.", NamedTextColor.RED));
Component.text("Du kannst dich nicht selbst reporten.").color(NamedTextColor.RED)
);
return; return;
} }
Request request = new Request(issuer.getUniqueId(), offlinePlayer.getUniqueId(), Optional.ofNullable(reason).orElse("")); ReportRepository.ReportCreationInfo request = new ReportRepository.ReportCreationInfo(
this.issueReport(issuer, request); issuer.getUniqueId(),
} offlinePlayer.getUniqueId(),
Optional.ofNullable(reason).orElse("")
public void requestReports(Player issuer) {
URIBuilder uriBuilder = new URIBuilder(this.apiEndpoint);
uriBuilder.addParameter("secret", apiSecret);
uriBuilder.addParameter("uuid", issuer.getUniqueId().toString());
try(HttpClient client = HttpClient.newHttpClient()) {
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(uriBuilder.build())
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());
this.printReports(issuer, httpResponse);
} catch (IOException | InterruptedException | URISyntaxException e) {
issuer.sendMessage(
Component.text("Internal server description: " + e.getMessage()).color(NamedTextColor.RED)
);
throw new RuntimeException(e);
}
}
private void issueReport(Player issuer, Request reportRequest) {
URIBuilder uriBuilder = new URIBuilder(this.apiEndpoint);
uriBuilder.addParameter("secret", apiSecret);
try(HttpClient client = HttpClient.newHttpClient()) {
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(uriBuilder.build())
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(new Gson().toJson(reportRequest)))
.build();
HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());
this.printResultMessage(issuer, httpResponse);
} catch(IOException | InterruptedException | URISyntaxException e) {
issuer.sendMessage(
Component.text("Internal server description: " + e.getMessage()).color(NamedTextColor.RED)
);
throw new RuntimeException(e);
}
}
private void printReports(Player issuer, HttpResponse<String> httpResponse) {
if(httpResponse.statusCode() != 200) {
Main.logger().warning("Failed to request Reports: " + httpResponse.statusCode());
issuer.sendMessage(
Component.text()
.append(Component.text("Interner Serverfehler beim abfragen der Reports.", NamedTextColor.RED))
.appendNewline()
.append(Component.text("Bitte melde dich bei einem Admin!", NamedTextColor.RED))
);
return;
}
List<ReportInfo> reports = new Gson().fromJson(httpResponse.body(), ReportsResponse.class).from_self;
reports.removeIf(reportInfo -> reportInfo.draft);
if(reports.isEmpty()) {
issuer.sendMessage(
Component.text()
.append(Component.text("Du hast noch niemanden reportet.", NamedTextColor.RED))
.appendNewline()
.append(Component.text("Um jemanden zu melden, nutze /report", NamedTextColor.GRAY))
);
return;
}
ComponentBuilder<TextComponent, TextComponent.Builder> component = Component.text();
component.append(
Component.newline()
.append(Component.text("Von dir erstellte Reports: ", NamedTextColor.GOLD))
.appendNewline()
); );
this.createReport(issuer, request);
reports.forEach(reportInfo -> {
component.append(
Component.text()
.append(Component.text(" - ", NamedTextColor.WHITE))
.append(Component.text(reportInfo.reported.username, NamedTextColor.WHITE))
.append(Component.text(String.format(": %s", reportInfo.subject), NamedTextColor.GRAY))
.clickEvent(ClickEvent.openUrl(reportInfo.url))
.hoverEvent(HoverEvent.showText(Component.text("Klicke, um den Report einzusehen.", NamedTextColor.GOLD)))
);
component.appendNewline();
});
issuer.sendMessage(component.build());
} }
private void printResultMessage(Player issuer, HttpResponse<String> httpResponse) { private void createReport(Player issuer, ReportRepository.ReportCreationInfo reportRequest) {
switch(httpResponse.statusCode()) { ReqResp<ReportRepository.ReportUrl> createdReport = this.queryRepository(ReportRepository.class)
.createReport(reportRequest);
switch(createdReport.status()) {
case 201: case 201:
ReportResponse createdReport = new Gson().fromJson(httpResponse.body(), ReportResponse.class);
issuer.sendMessage( issuer.sendMessage(
Component.text() Component.text()
.append(Component.text("\\/".repeat(20), NamedTextColor.DARK_GRAY)) .append(Component.text("\\/".repeat(20), NamedTextColor.DARK_GRAY))
.appendNewline() .appendNewline()
.appendNewline() .append(Component.text("⚠ Der Report muss über den folgenden Link fertiggestellt werden!", NamedTextColor.GOLD))
.append(Component.text("!!! Report hier fertigstellen !!!", NamedTextColor.GOLD))
.appendNewline() .appendNewline()
.appendNewline() .appendNewline()
.append( .append(
Component Component
.text(" > Hier klicken < ", NamedTextColor.GREEN) .text(createdReport.data().url(), NamedTextColor.GRAY) // URL mit Weltkugel-Emoji
.hoverEvent(HoverEvent.showText(Component.text(createdReport.url).color(NamedTextColor.GREEN))) .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, createdReport.data().url()))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, createdReport.url))
) )
.appendNewline() .appendNewline()
.appendNewline() .appendNewline()
.append( .append(Component.text("Ohne das Fertigstellen des Reports wird dieser nicht bearbeitet!", NamedTextColor.DARK_RED))
Component
.text(createdReport.url, NamedTextColor.GRAY)
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, createdReport.url))
)
.appendNewline()
.appendNewline() .appendNewline()
.append(Component.text("/\\".repeat(20), NamedTextColor.DARK_GRAY)) .append(Component.text("/\\".repeat(20), NamedTextColor.DARK_GRAY))
); );
@ -213,7 +94,7 @@ public class Report extends Appliance {
case 401: case 401:
default: default:
Main.logger().warning("Failed to request Report: " + httpResponse.statusCode()); Main.logger().warning("Failed to request Report: " + createdReport.status());
issuer.sendMessage( issuer.sendMessage(
Component.text() Component.text()
.append(Component.text("Interner Serverfehler beim anlegen des Reports.", NamedTextColor.RED)) .append(Component.text("Interner Serverfehler beim anlegen des Reports.", NamedTextColor.RED))
@ -224,6 +105,61 @@ public class Report extends Appliance {
} }
} }
public void queryReports(Player issuer) {
ReqResp<ReportRepository.PlayerReports> userReports = this.queryRepository(ReportRepository.class)
.queryReports(issuer.getUniqueId());
if(userReports.status() != 200) {
Main.logger().warning("Failed to request Reports: " + userReports.status());
issuer.sendMessage(
Component.text()
.append(Component.text("Interner Serverfehler beim abfragen der Reports.", NamedTextColor.RED))
.appendNewline()
.append(Component.text("Bitte melde dich bei einem Admin!", NamedTextColor.RED))
);
return;
}
List<ReportRepository.PlayerReports.Report> reports = userReports
.data()
.from_self()
.stream()
.filter(report -> !report.draft())
.toList()
.reversed();
if(reports.isEmpty()) {
issuer.sendMessage(
Component.text()
.append(Component.text("Du hast noch niemanden reportet.", NamedTextColor.RED))
.appendNewline()
.append(Component.text("Um jemanden zu melden, nutze /report", NamedTextColor.GRAY))
);
return;
}
ComponentBuilder<TextComponent, TextComponent.Builder> component = Component.text()
.append(Component.newline())
.append(Component.text("Von dir erstellte Reports: ", NamedTextColor.GOLD))
.appendNewline();
reports.forEach(report -> {
component
.append(Component.text(" - ", NamedTextColor.WHITE))
.append(
report.reported() != null
? Component.text(report.reported().username(), NamedTextColor.WHITE)
: Component.text("Unbekannt", NamedTextColor.YELLOW)
)
.append(Component.text(String.format(": %s", report.subject()), NamedTextColor.GRAY))
.clickEvent(ClickEvent.openUrl(report.url()))
.hoverEvent(HoverEvent.showText(Component.text("Klicke, um den Report einzusehen.", NamedTextColor.GOLD)));
component.appendNewline();
});
issuer.sendMessage(component.build());
}
@Override @Override
@NotNull @NotNull
protected List<ApplianceCommand<?>> commands() { protected List<ApplianceCommand<?>> commands() {

View File

@ -14,6 +14,6 @@ public class ReportsCommand extends ApplianceCommand.PlayerChecked<Report> {
@Override @Override
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
sender.sendMessage(ComponentUtil.pleaseWait()); sender.sendMessage(ComponentUtil.pleaseWait());
getAppliance().requestReports(getPlayer()); getAppliance().queryReports(getPlayer());
} }
} }