reworked household and exemption dialogs

This commit is contained in:
MineTec committed 2026-10-14 17:16:13 +02:00
1 parent 974c5c5200
commit 7bd1e13660
1 file changed
+65 -23
@@ -51,7 +51,7 @@ final class BanEvasionDialogs {
private record CaseView(BanEvasionRepository.CaseDetails details, Map<UUID, BanState> banStates, Map<UUID, Long> households) { private record CaseView(BanEvasionRepository.CaseDetails details, Map<UUID, BanState> banStates, Map<UUID, Long> households) {
} }
private record LinksView(String name, List<BanEvasionRepository.Link> links, List<String> networks) { private record LinksView(String name, List<BanEvasionRepository.Link> links, List<String> networks, @Nullable Long household) {
} }
private final BanEvasion appliance; private final BanEvasion appliance;
@@ -120,15 +120,19 @@ final class BanEvasionDialogs {
this.appliance.loadFor(admin, () -> this.appliance.query(connection -> new LinksView( this.appliance.loadFor(admin, () -> this.appliance.query(connection -> new LinksView(
this.appliance.repository().nameOf(connection, uuid), this.appliance.repository().nameOf(connection, uuid),
this.appliance.repository().linksOf(connection, uuid, LINK_LIMIT), this.appliance.repository().linksOf(connection, uuid, LINK_LIMIT),
this.appliance.repository().recentNetworks(connection, uuid, RECENT_NETWORKS) this.appliance.repository().recentNetworks(connection, uuid, RECENT_NETWORKS),
this.appliance.repository().householdsOf(connection, List.of(uuid)).get(uuid)
)), view -> { )), view -> {
List<Component> lines = new ArrayList<>(); List<Component> lines = new ArrayList<>();
if(view.household() != null) lines.add(Component.text(view.name() + " gehört zu Haushalt #" + view.household() + "."));
if(view.links().isEmpty()) lines.add(Component.text("Kein anderer Account hat je einen Anschluss mit " + view.name() + " geteilt.")); if(view.links().isEmpty()) lines.add(Component.text("Kein anderer Account hat je einen Anschluss mit " + view.name() + " geteilt."));
view.links().forEach(link -> lines.add(Component.text(String.format("%s – %d Einträge an gemeinsamen Anschlüssen, %s bis %s%s", view.links().forEach(link -> lines.add(Component.text(String.format("%s – %d Einträge an gemeinsamen Anschlüssen, %s bis %s%s",
link.name(), link.sharedAttempts(), TIME.format(link.firstAt()), TIME.format(link.lastAt()), link.name(), link.sharedAttempts(), TIME.format(link.firstAt()), TIME.format(link.lastAt()),
link.caseId() == null ? "" : " · Fall #" + link.caseId())))); link.caseId() == null ? "" : " · Fall #" + link.caseId()))));
List<ActionButton> buttons = new ArrayList<>(); List<ActionButton> buttons = new ArrayList<>();
if(view.household() != null)
buttons.add(button("Haushalt #" + view.household(), player -> this.openHousehold(player, view.household())));
view.links().stream() view.links().stream()
.filter(link -> link.caseId() != null) .filter(link -> link.caseId() != null)
.forEach(link -> buttons.add(button("Fall #" + link.caseId() + ": " + link.name(), player -> this.openCase(player, link.caseId(), false)))); .forEach(link -> buttons.add(button("Fall #" + link.caseId() + ": " + link.name(), player -> this.openCase(player, link.caseId(), false))));
@@ -160,34 +164,72 @@ final class BanEvasionDialogs {
void openExemptions(Player admin) { void openExemptions(Player admin) {
Instant now = Instant.now(); Instant now = Instant.now();
this.appliance.loadFor(admin, () -> this.appliance.query(connection -> this.appliance.repository().activeExemptions(connection, now)), exemptions -> { this.appliance.loadFor(admin, () -> this.appliance.query(connection -> this.appliance.repository().activeExemptions(connection, now)), exemptions -> {
List<Component> lines = new ArrayList<>(); Component body = Component.text(exemptions.isEmpty()
if(exemptions.isEmpty()) lines.add(Component.text("Keine aktiven IP-Ausnahmen.")); ? "Keine aktiven IP-Ausnahmen."
exemptions.forEach(exemption -> lines.add(Component.text(String.format("%s · %s bis %s · %s%s", : exemptions.size() + " aktive IP-Ausnahmen, zuerst endende oben.");
exemption.network(), TIME.format(exemption.validFrom()), TIME.format(exemption.validUntil()),
exemption.createdByName() == null ? "?" : exemption.createdByName(),
exemption.note() == null ? "" : " · " + exemption.note()))));
List<ActionButton> buttons = new ArrayList<>(); List<ActionButton> buttons = new ArrayList<>();
exemptions.forEach(exemption -> buttons.add(button("Beenden: " + exemption.network(), player -> this.endExemption(player, exemption)))); exemptions.forEach(exemption -> buttons.add(button(
String.format("%s bis %s%s", Networks.mask(exemption.network()), TIME.format(exemption.validUntil()),
exemption.note() == null ? "" : " · " + exemption.note()),
player -> this.openExemption(player, exemption))));
buttons.add(button("Zur Fallliste", player -> this.openList(player, CaseStatus.OPEN))); buttons.add(button("Zur Fallliste", player -> this.openList(player, CaseStatus.OPEN)));
show(admin, "IP-Ausnahmen", lines(lines), List.of(), buttons); show(admin, "IP-Ausnahmen", body, List.of(), buttons);
}); });
} }
private void openExemption(Player admin, BanEvasionRepository.Exemption exemption) {
Component body = lines(List.of(
Component.text("Anschluss: " + exemption.network()),
Component.text("Gültig: " + TIME.format(exemption.validFrom()) + " bis " + TIME.format(exemption.validUntil())),
Component.text("Angelegt von: " + (exemption.createdByName() == null ? "?" : exemption.createdByName())),
Component.text("Notiz: " + (exemption.note() == null ? "–" : exemption.note()))
));
show(admin, "IP-Ausnahme", body, List.of(), List.of(
button("Jetzt beenden", player -> this.endExemption(player, exemption)),
button("Zurück", this::openExemptions)
));
}
void openHouseholds(Player admin) { void openHouseholds(Player admin) {
this.appliance.loadFor(admin, () -> this.appliance.query(this.appliance.repository()::listHouseholds), households -> { this.appliance.loadFor(admin, () -> this.appliance.query(this.appliance.repository()::listHouseholds), households -> {
String text = households.isEmpty() ? "Keine Haushalte." : households.size() + " Haushalte, neueste zuerst.";
if(households.size() > LIST_LIMIT)
text += " Gezeigt werden die neuesten " + LIST_LIMIT + " – ältere über /accountLinks <spieler> finden.";
List<ActionButton> buttons = new ArrayList<>();
households.stream().limit(LIST_LIMIT).forEach(household -> buttons.add(button(
"#" + household.id() + ": " + household.members().stream().map(BanEvasionRepository.Member::name).collect(Collectors.joining(", ")),
player -> this.openHousehold(player, household.id()))));
buttons.add(button("Zur Fallliste", player -> this.openList(player, CaseStatus.OPEN)));
show(admin, "Haushalte", Component.text(text), List.of(), buttons);
});
}
private record HouseholdView(BanEvasionRepository.Household household, Map<UUID, BanState> banStates) {
}
void openHousehold(Player admin, long householdId) {
this.appliance.loadFor(admin, () -> {
BanEvasionRepository.Household household = this.appliance.query(connection -> this.appliance.repository().household(connection, householdId));
if(household == null) return null;
return new HouseholdView(household, this.appliance.banStates(household.members().stream().map(BanEvasionRepository.Member::uuid).toList()));
}, view -> {
if(view == null) {
admin.sendMessage(Component.text("Haushalt #" + householdId + " gibt es nicht (mehr).", NamedTextColor.GRAY));
this.openHouseholds(admin);
return;
}
BanEvasionRepository.Household household = view.household();
List<Component> lines = new ArrayList<>(); List<Component> lines = new ArrayList<>();
if(households.isEmpty()) lines.add(Component.text("Keine Haushalte.")); lines.add(Component.text("Angelegt " + TIME.format(household.createdAt()) + " von "
households.forEach(household -> lines.add(Component.text(String.format("#%d: %s%s", + (household.createdByName() == null ? "?" : household.createdByName())));
household.id(), lines.add(Component.text("Notiz: " + (household.note() == null ? "–" : household.note())));
household.members().stream().map(BanEvasionRepository.Member::name).collect(Collectors.joining(", ")), lines.add(Component.empty());
household.note() == null ? "" : " · " + household.note())))); household.members().forEach(member -> lines.add(accountLine(member.name(), view.banStates().get(member.uuid()), null)));
List<ActionButton> buttons = new ArrayList<>(); List<ActionButton> buttons = new ArrayList<>();
households.forEach(household -> household.members().forEach(member -> household.members().forEach(member -> buttons.add(button("Entfernen: " + member.name(), player -> this.removeMember(player, householdId, member))));
buttons.add(button("Aus #" + household.id() + " entfernen: " + member.name(), player -> this.removeMember(player, member))))); buttons.add(button("Zurück", this::openHouseholds));
buttons.add(button("Zur Fallliste", player -> this.openList(player, CaseStatus.OPEN))); show(admin, "Haushalt #" + householdId, lines(lines), List.of(), buttons);
show(admin, "Haushalte", lines(lines), List.of(), buttons);
}); });
} }
@@ -290,13 +332,13 @@ final class BanEvasionDialogs {
}); });
} }
private void removeMember(Player admin, BanEvasionRepository.Member member) { private void removeMember(Player admin, long householdId, BanEvasionRepository.Member member) {
this.appliance.loadFor(admin, () -> this.appliance.query(connection -> { this.appliance.loadFor(admin, () -> this.appliance.query(connection -> {
this.appliance.repository().removeFromHousehold(connection, member.uuid()); this.appliance.repository().removeFromHousehold(connection, member.uuid());
return true; return true;
}), done -> { }), done -> {
Main.logger().info(String.format("BanEvasion: %s removed from household by %s", member.name(), admin.getName())); Main.logger().info(String.format("BanEvasion: %s removed from household #%d by %s", member.name(), householdId, admin.getName()));
this.openHouseholds(admin); this.openHousehold(admin, householdId);
}); });
} }