diff --git a/pom.xml b/pom.xml index 7842f29..1e6b667 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.faforever faf-moderator-client - 0.5.3 + 0.5.5 jar faf-moderator-client @@ -23,7 +23,7 @@ UTF-8 1.8 - 046b482571d8b29b35c68249586e41f1b9e44857 + 98d878df4c19853d93b2d58269ac83a5897e1145 1.1 1.6 0.8 diff --git a/src/main/java/com/faforever/moderatorclient/api/JsonApiErrorHandler.java b/src/main/java/com/faforever/moderatorclient/api/JsonApiErrorHandler.java index 8cc56ab..45a1641 100644 --- a/src/main/java/com/faforever/moderatorclient/api/JsonApiErrorHandler.java +++ b/src/main/java/com/faforever/moderatorclient/api/JsonApiErrorHandler.java @@ -4,14 +4,19 @@ import com.faforever.commons.api.dto.ApiException; import com.github.jasminb.jsonapi.exceptions.ResourceParseException; import com.github.jasminb.jsonapi.models.errors.Errors; +import com.google.common.base.Charsets; +import com.google.common.io.CharStreams; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.client.DefaultResponseErrorHandler; import java.io.IOException; +import java.io.InputStreamReader; @Component +@Slf4j public class JsonApiErrorHandler extends DefaultResponseErrorHandler { private final JsonApiMessageConverter jsonApiMessageConverter; @@ -21,6 +26,8 @@ public JsonApiErrorHandler(JsonApiMessageConverter jsonApiMessageConverter) { @Override public void handleError(ClientHttpResponse response) throws IOException { + log.warn("Api call returned with error code '{}' and body '{}'", response.getStatusCode(), CharStreams.toString(new InputStreamReader(response.getBody(), Charsets.UTF_8))); + if (response.getStatusCode() == HttpStatus.UNPROCESSABLE_ENTITY) { try { jsonApiMessageConverter.readInternal(Errors.class, response); diff --git a/src/main/java/com/faforever/moderatorclient/api/domain/BanService.java b/src/main/java/com/faforever/moderatorclient/api/domain/BanService.java index 0e721e9..401fca8 100644 --- a/src/main/java/com/faforever/moderatorclient/api/domain/BanService.java +++ b/src/main/java/com/faforever/moderatorclient/api/domain/BanService.java @@ -1,16 +1,13 @@ package com.faforever.moderatorclient.api.domain; import com.faforever.commons.api.dto.BanInfo; -import com.faforever.commons.api.dto.BanRevokeData; -import com.faforever.commons.api.dto.Player; import com.faforever.commons.api.elide.ElideNavigator; import com.faforever.commons.api.elide.ElideNavigatorOnCollection; import com.faforever.commons.api.elide.ElideNavigatorOnId; import com.faforever.moderatorclient.api.FafApiCommunicationService; import com.faforever.moderatorclient.mapstruct.BanInfoMapper; -import com.faforever.moderatorclient.mapstruct.BanRevokeDataMapper; import com.faforever.moderatorclient.ui.domain.BanInfoFX; -import com.faforever.moderatorclient.ui.domain.BanRevokeDataFX; +import com.google.common.collect.ImmutableMap; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; @@ -24,33 +21,21 @@ public class BanService { private final BanInfoMapper banInfoMapper; - private final BanRevokeDataMapper banRevokeDataMapper; private final FafApiCommunicationService fafApi; - public BanService(BanInfoMapper banInfoMapper, BanRevokeDataMapper banRevokeDataMapper, FafApiCommunicationService fafApi) { + public BanService(BanInfoMapper banInfoMapper, FafApiCommunicationService fafApi) { this.banInfoMapper = banInfoMapper; - this.banRevokeDataMapper = banRevokeDataMapper; this.fafApi = fafApi; } public BanInfo patchBanInfo(@NotNull BanInfoFX banInfoFX) { BanInfo banInfo = banInfoMapper.map(banInfoFX); log.debug("Patching BanInfo of id: ", banInfo.getId()); + banInfo.setAuthor(null); + banInfo.setPlayer(null); return fafApi.patch(ElideNavigator.of(BanInfo.class).id(banInfo.getId()), banInfo); } - public BanRevokeData revokeBan(@NotNull BanRevokeDataFX banRevokeDataFX) { - BanRevokeData banRevokeData = banRevokeDataMapper.map(banRevokeDataFX); - log.debug("Revoking ban with id: ", banRevokeData.getBan().getId()); - banRevokeData.setAuthor(fafApi.getSelfPlayer()); - ElideNavigatorOnCollection navigator = ElideNavigator.of(Player.class) - .id(banRevokeData.getBan().getId()) - .navigateRelationship(BanRevokeData.class, "banRevokeData") - .collection(); - - return (BanRevokeData) fafApi.post(navigator, banRevokeData); - } - public String createBan(@NotNull BanInfoFX banInfoFX) { BanInfo banInfo = banInfoMapper.map(banInfoFX); log.debug("Creating ban"); @@ -58,14 +43,17 @@ public String createBan(@NotNull BanInfoFX banInfoFX) { return fafApi.post(ElideNavigator.of(BanInfo.class).collection(), banInfo).getId(); } - public CompletableFuture> getAllBans() { + public CompletableFuture> getLatestBans() { return CompletableFuture.supplyAsync(() -> { - List banInfos = fafApi.getAll(ElideNavigator.of(BanInfo.class) + List banInfos = fafApi.getPage(ElideNavigator.of(BanInfo.class) .collection() .addIncludeOnCollection("player") .addIncludeOnCollection("author") - .addIncludeOnCollection("banRevokeData") - .addIncludeOnCollection("banRevokeData.author") + .addIncludeOnCollection("revokeAuthor") + .addSortingRule("createTime", false), + 100, + 1, + ImmutableMap.of() ); return banInfos.stream().map(banInfoMapper::map).collect(Collectors.toList()); }); @@ -79,4 +67,21 @@ public BanInfoFX getBanInfoById(String banInfoId) { .addIncludeOnId("author"); return banInfoMapper.map(fafApi.getOne(navigator)); } + + public void updateBan(BanInfo banInfoUpdate) { + log.debug("Update for ban id: " + banInfoUpdate.getId()); + ElideNavigatorOnId navigator = ElideNavigator.of(BanInfo.class) + .id(banInfoUpdate.getId()); + + fafApi.patch(navigator, banInfoUpdate); + } + + public List getBanInfoByBannedPlayerNameContains(String name) { + ElideNavigatorOnCollection navigator = ElideNavigator.of(BanInfo.class) + .collection() + .addFilter(ElideNavigator.qBuilder().string("player.login").eq("*" + name + "*")) + .addIncludeOnCollection("player") + .addIncludeOnCollection("author"); + return banInfoMapper.mapToFX(fafApi.getAll(navigator)); + } } diff --git a/src/main/java/com/faforever/moderatorclient/api/domain/UserService.java b/src/main/java/com/faforever/moderatorclient/api/domain/UserService.java index e6edf41..ea76784 100644 --- a/src/main/java/com/faforever/moderatorclient/api/domain/UserService.java +++ b/src/main/java/com/faforever/moderatorclient/api/domain/UserService.java @@ -60,8 +60,7 @@ private ElideNavigatorOnCollection addModeratorInclud .addIncludeOnCollection(variablePrefix + "avatarAssignments.avatar") .addIncludeOnCollection(variablePrefix + "bans") .addIncludeOnCollection(variablePrefix + "bans.author") - .addIncludeOnCollection(variablePrefix + "bans.banRevokeData") - .addIncludeOnCollection(variablePrefix + "bans.banRevokeData.author"); + .addIncludeOnCollection(variablePrefix + "bans.revokeAuthor"); } public List findLatestRegistrations() { diff --git a/src/main/java/com/faforever/moderatorclient/mapstruct/BanInfoMapper.java b/src/main/java/com/faforever/moderatorclient/mapstruct/BanInfoMapper.java index c6a85ff..97bb1c6 100644 --- a/src/main/java/com/faforever/moderatorclient/mapstruct/BanInfoMapper.java +++ b/src/main/java/com/faforever/moderatorclient/mapstruct/BanInfoMapper.java @@ -7,7 +7,7 @@ import java.util.List; -@Mapper(uses = {JavaFXMapper.class, BanRevokeDataMapper.class, PlayerMapper.class, CycleAvoidingMappingContext.class}) +@Mapper(uses = {JavaFXMapper.class, PlayerMapper.class, CycleAvoidingMappingContext.class}) public abstract class BanInfoMapper { @Mapping(target = "duration", ignore = true) @Mapping(target = "banStatus", ignore = true) diff --git a/src/main/java/com/faforever/moderatorclient/mapstruct/BanRevokeDataMapper.java b/src/main/java/com/faforever/moderatorclient/mapstruct/BanRevokeDataMapper.java deleted file mode 100644 index 164648d..0000000 --- a/src/main/java/com/faforever/moderatorclient/mapstruct/BanRevokeDataMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.faforever.moderatorclient.mapstruct; - -import com.faforever.commons.api.dto.BanRevokeData; -import com.faforever.moderatorclient.ui.domain.BanRevokeDataFX; -import org.mapstruct.Mapper; - -import java.util.List; - -@Mapper(uses = {JavaFXMapper.class, BanInfoMapper.class, PlayerMapper.class}) -public interface BanRevokeDataMapper { - BanRevokeDataFX map(BanRevokeData dto); - - BanRevokeData map(BanRevokeDataFX fxBean); - - List map(List dtoList); -} diff --git a/src/main/java/com/faforever/moderatorclient/ui/BanInfoController.java b/src/main/java/com/faforever/moderatorclient/ui/BanInfoController.java index 8d60d19..b080a99 100644 --- a/src/main/java/com/faforever/moderatorclient/ui/BanInfoController.java +++ b/src/main/java/com/faforever/moderatorclient/ui/BanInfoController.java @@ -1,17 +1,21 @@ package com.faforever.moderatorclient.ui; import com.faforever.commons.api.dto.BanDurationType; +import com.faforever.commons.api.dto.BanInfo; import com.faforever.commons.api.dto.BanLevel; import com.faforever.moderatorclient.api.FafApiCommunicationService; import com.faforever.moderatorclient.api.domain.BanService; import com.faforever.moderatorclient.mapstruct.PlayerMapper; import com.faforever.moderatorclient.ui.domain.BanInfoFX; -import com.faforever.moderatorclient.ui.domain.BanRevokeDataFX; import com.faforever.moderatorclient.ui.domain.PlayerFX; import javafx.fxml.FXML; -import javafx.scene.control.*; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.RadioButton; +import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; import javafx.stage.Stage; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -54,9 +58,13 @@ public class BanInfoController implements Controller { public RadioButton globalBanRadioButton; public Button revokeButton; public Label userLabel; + public Label banIsRevokedNotice; + public TextField revocationTimeTextField; + public VBox revokeOptions; @Getter private BanInfoFX banInfo; private Consumer postedListener; + private Runnable onBanRevoked; public BanInfoController(FafApiCommunicationService fafApi, BanService banService, PlayerMapper playerMapper) { this.fafApi = fafApi; @@ -64,6 +72,11 @@ public BanInfoController(FafApiCommunicationService fafApi, BanService banServic this.playerMapper = playerMapper; } + public void addRevokedListener(Runnable listener) { + this.onBanRevoked = listener; + } + + public void addPostedListener(Consumer listener) { this.postedListener = listener; } @@ -75,12 +88,24 @@ public Pane getRoot() { @FXML public void initialize() { + banIsRevokedNotice.managedProperty().bind(banIsRevokedNotice.visibleProperty()); + } + + public void onRevokeTimeTextChanged() { + revocationTimeTextField.setStyle("-fx-text-fill: green"); + try { + DateTimeFormatter.ISO_LOCAL_DATE_TIME.parse(revocationTimeTextField.getText()); + } catch (Exception e) { + revocationTimeTextField.setStyle("-fx-text-fill: red"); + } } public void setBanInfo(BanInfoFX banInfo) { this.banInfo = banInfo; if (banInfo.getId() != null) { + revokeOptions.setDisable(false); + affectedUserTextField.setText(banInfo.getPlayer().representationProperty().get()); Optional.ofNullable(banInfo.getAuthor()).ifPresent(author -> banAuthorTextField.setText(author.representationProperty().get())); banReasonTextField.setText(banInfo.getReason()); @@ -92,14 +117,19 @@ public void setBanInfo(BanInfoFX banInfo) { temporaryBanRadioButton.setSelected(banInfo.getDuration() == BanDurationType.TEMPORARY); Optional.ofNullable(banInfo.getExpiresAt()).ifPresent(offsetDateTime -> untilTextField.setText(offsetDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME))); - if (banInfo.getBanRevokeData() != null) { - revocationReasonTextField.setText(banInfo.getBanRevokeData().getReason()); - revocationAuthorTextField.setText(banInfo.getBanRevokeData().getAuthor().toString()); + if (banInfo.getRevokeTime() != null) { + banIsRevokedNotice.setVisible(true); + revocationReasonTextField.setText(banInfo.getRevokeReason()); + revocationTimeTextField.setText(banInfo.getRevokeTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + revocationAuthorTextField.setText(banInfo.getRevokeAuthor() == null ? "" : banInfo.getRevokeAuthor().getLogin()); + } else { + revocationTimeTextField.setText(OffsetDateTime.now().atZoneSameInstant(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); } chatOnlyBanRadioButton.setSelected(banInfo.getLevel() == BanLevel.CHAT); globalBanRadioButton.setSelected(banInfo.getLevel() == BanLevel.GLOBAL); } else { + PlayerFX player = banInfo.getPlayer(); if (player != null) { affectedUserTextField.setText(player.representationProperty().get()); @@ -188,23 +218,43 @@ private boolean validate() { public void onRevoke() { Assert.notNull(banInfo, "You can't revoke if banInfo is null."); - + List errors = new ArrayList<>(); String revocationReason = revocationReasonTextField.getText(); if (StringUtils.isBlank(revocationReason)) { - new Alert(Alert.AlertType.ERROR, "The reason of revocation must not be empty", ButtonType.OK).showAndWait(); + errors.add("The reason of revocation must not be empty."); + } + OffsetDateTime revokeTime = null; + try { + revokeTime = OffsetDateTime.of(LocalDateTime.parse(revocationTimeTextField.getText(), DateTimeFormatter.ISO_LOCAL_DATE_TIME), ZoneOffset.UTC); + } catch (Exception e) { + log.debug("Revoke time invalid", e); + errors.add("Invalid date for revocation."); + } + + if (!errors.isEmpty()) { + ViewHelper.errorDialog("Could not revoke", + errors.stream().collect(Collectors.joining("\n"))); return; } log.debug("Revoking ban id '{}' with reason: {}", banInfo.getId(), revocationReason); - BanRevokeDataFX banRevokeData = new BanRevokeDataFX() - .setBan(banInfo) - .setAuthor(playerMapper.map(fafApi.getSelfPlayer())) - .setReason(revocationReason); + banInfo.setRevokeAuthor(playerMapper.map(fafApi.getSelfPlayer())); + banInfo.setRevokeReason(revocationReason); + banInfo.setRevokeTime(revokeTime); + banInfo.setUpdateTime(OffsetDateTime.now()); - banService.revokeBan(banRevokeData); + BanInfo banInfoUpdate = new BanInfo(); + banInfoUpdate.setId(banInfo.getId()); + banInfoUpdate.setRevokeReason(revocationReason); + banInfoUpdate.setRevokeTime(revokeTime); + + banService.updateBan(banInfoUpdate); + if (onBanRevoked != null) { + onBanRevoked.run(); + } close(); } diff --git a/src/main/java/com/faforever/moderatorclient/ui/BansController.java b/src/main/java/com/faforever/moderatorclient/ui/BansController.java index a54437f..c3d6e22 100644 --- a/src/main/java/com/faforever/moderatorclient/ui/BansController.java +++ b/src/main/java/com/faforever/moderatorclient/ui/BansController.java @@ -4,6 +4,7 @@ import com.faforever.moderatorclient.api.domain.BanService; import com.faforever.moderatorclient.ui.domain.BanInfoFX; import javafx.application.Platform; +import javafx.beans.InvalidationListener; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; @@ -17,7 +18,9 @@ import org.springframework.stereotype.Component; import javax.inject.Inject; -import java.util.function.Predicate; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; @Component @Slf4j @@ -31,8 +34,10 @@ public class BansController implements Controller { public RadioButton banIdRadioButton; public TableView banTableView; public CheckBox onlyActiveCheckBox; - private FilteredList filteredItemList; + public Button editBanButton; + private FilteredList filteredList; private ObservableList itemList; + private boolean inSearchMode = false; @Inject public BansController(UiService uiService, BanService banService) { @@ -48,33 +53,27 @@ public HBox getRoot() { @FXML public void initialize() { itemList = FXCollections.observableArrayList(); - filteredItemList = new FilteredList<>(itemList); - SortedList sortedItemList = new SortedList<>(filteredItemList); + filteredList = new FilteredList<>(itemList); + SortedList sortedItemList = new SortedList<>(filteredList); sortedItemList.comparatorProperty().bind(banTableView.comparatorProperty()); ViewHelper.buildBanTableView(banTableView, sortedItemList, true); - onRefreshBans(); - setUpFilter(); + onRefreshLatestBans(); + playerRadioButton.setUserData((Supplier>) () -> banService.getBanInfoByBannedPlayerNameContains(filter.getText())); + banIdRadioButton.setUserData((Supplier>) () -> Collections.singletonList(banService.getBanInfoById(filter.getText()))); + editBanButton.disableProperty().bind(banTableView.getSelectionModel().selectedItemProperty().isNull()); + InvalidationListener onlyActiveBansChangeListener = (observable) -> + filteredList.setPredicate(banInfoFX -> !onlyActiveCheckBox.isSelected() || banInfoFX.getBanStatus() == BanStatus.BANNED); + onlyActiveCheckBox.selectedProperty().addListener(onlyActiveBansChangeListener); + onlyActiveBansChangeListener.invalidated(onlyActiveCheckBox.selectedProperty()); } - private void setUpFilter() { - banIdRadioButton.setUserData((Predicate) o -> activeFilter(o) && o.getId().toLowerCase().contains(filter.getText().toLowerCase())); - playerRadioButton.setUserData((Predicate) o -> activeFilter(o) && o.getPlayer().getLogin().toLowerCase().contains(filter.getText().toLowerCase())); - filterGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> renewFilter()); - filter.textProperty().addListener((observable, oldValue, newValue) -> renewFilter()); - onlyActiveCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> renewFilter()); - renewFilter(); - } - - private void renewFilter() { - Predicate predicate = (Predicate) filterGroup.getSelectedToggle().getUserData(); - filteredItemList.setPredicate(predicate::test); - } - - public void onRefreshBans() { - banService.getAllBans().thenAccept(banInfoFXES -> Platform.runLater(() -> itemList.setAll(banInfoFXES))).exceptionally(throwable -> { + public void onRefreshLatestBans() { + banService.getLatestBans().thenAccept(banInfoFXES -> Platform.runLater(() -> itemList.setAll(banInfoFXES))).exceptionally(throwable -> { log.error("error loading bans", throwable); return null; }); + filter.clear(); + inSearchMode = false; } public void editBan() { @@ -90,7 +89,13 @@ public void editBan() { private void openBanDialog(BanInfoFX banInfoFX, boolean isNew) { BanInfoController banInfoController = uiService.loadFxml("ui/banInfo.fxml"); banInfoController.setBanInfo(banInfoFX); - banInfoController.addPostedListener(banInfoFX1 -> onRefreshBans()); + banInfoController.addPostedListener(banInfoFX1 -> { + if (inSearchMode) { + onSearch(); + return; + } + onRefreshLatestBans(); + }); Stage banInfoDialog = new Stage(); banInfoDialog.setTitle(isNew ? "Apply new ban" : "Edit ban"); @@ -102,7 +107,9 @@ public void addBan() { openBanDialog(new BanInfoFX(), true); } - private boolean activeFilter(BanInfoFX banInfoFX) { - return !onlyActiveCheckBox.isSelected() || banInfoFX.getBanStatus() == BanStatus.BANNED; + public void onSearch() { + List banInfoFXES = ((Supplier>) filterGroup.getSelectedToggle().getUserData()).get(); + itemList.setAll(banInfoFXES); + inSearchMode = true; } } diff --git a/src/main/java/com/faforever/moderatorclient/ui/LadderMapVoteGenerationFormController.java b/src/main/java/com/faforever/moderatorclient/ui/LadderMapVoteGenerationFormController.java index 4144a7d..0b778f4 100644 --- a/src/main/java/com/faforever/moderatorclient/ui/LadderMapVoteGenerationFormController.java +++ b/src/main/java/com/faforever/moderatorclient/ui/LadderMapVoteGenerationFormController.java @@ -20,9 +20,9 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; @@ -171,8 +171,9 @@ private void getDefaultChoices(int questionID, int count) { private String generateMapDescriptionHTML(MapVersion mapVersion) { String formattedHtml; try { - URL resource = getClass().getClassLoader().getResource("media/map_description_template.html"); - String htmlTemplate = new String(Files.readAllBytes(Paths.get(resource.toURI()))); + InputStream resourceAsStream = getClass().getResourceAsStream("/media/map_description_template.html"); + BufferedReader reader = new BufferedReader(new InputStreamReader(resourceAsStream)); + String htmlTemplate = reader.lines().collect(Collectors.joining("\n")); formattedHtml = htmlTemplate.replaceAll("\\{map-player-count}", String.valueOf(mapVersion.getMaxPlayers())); formattedHtml = formattedHtml.replaceAll("\\{preview-source}", mapVersion.getThumbnailUrlLarge().toString()); diff --git a/src/main/java/com/faforever/moderatorclient/ui/MainController.java b/src/main/java/com/faforever/moderatorclient/ui/MainController.java index 23282c7..7fc80e8 100644 --- a/src/main/java/com/faforever/moderatorclient/ui/MainController.java +++ b/src/main/java/com/faforever/moderatorclient/ui/MainController.java @@ -1,6 +1,7 @@ package com.faforever.moderatorclient.ui; import com.faforever.moderatorclient.api.event.FafApiFailGetEvent; +import com.faforever.moderatorclient.api.event.FafApiFailModifyEvent; import com.faforever.moderatorclient.ui.main_window.*; import javafx.application.Platform; import javafx.scene.Scene; @@ -117,13 +118,13 @@ private void initDomainBlacklistTab() { private void initBanTab() { bansController = uiService.loadFxml("ui/main_window/bans.fxml"); banTab.setContent(bansController.getRoot()); - initLoading(banTab, bansController::onRefreshBans); + initLoading(banTab, bansController::onRefreshLatestBans); } private void initTutorialTab() { tutorialController = uiService.loadFxml("ui/main_window/tutorial.fxml"); tutorialTab.setContent(tutorialController.getRoot()); - initLoading(tutorialTab, tutorialController::onRefreshTutorials); + initLoading(tutorialTab, tutorialController::onRefreshCategorys); } private void initMessagesTab() { @@ -162,4 +163,10 @@ public void onFafApiGetFailed(FafApiFailGetEvent event) { Platform.runLater(() -> ViewHelper.exceptionDialog("Querying data from API failed", MessageFormat.format("Something went wrong while fetching data of type ''{0}'' from the API. The related controls are shown empty instead now. You can proceed without causing any harm, but it is likely that some operations will not work and/or the error will pop up again.\n\nPlease contact the maintainer and give him the details from the box below.", event.getEntityClass().getSimpleName()), event.getCause(), Optional.of(event.getUrl()))); } + + @EventListener + public void onFafApiGetFailed(FafApiFailModifyEvent event) { + Platform.runLater(() -> + ViewHelper.exceptionDialog("Sending updated data to API failed", MessageFormat.format("Something went wrong while sending data of type ''{0}'' to the API. The related change was not saved. You might wanna try again. Please check if the data you entered is valid. \n\nPlease contact the maintainer and give him the details from the box below.", event.getEntityClass().getSimpleName()), event.getCause(), Optional.of(event.getUrl()))); + } } \ No newline at end of file diff --git a/src/main/java/com/faforever/moderatorclient/ui/ViewHelper.java b/src/main/java/com/faforever/moderatorclient/ui/ViewHelper.java index 2deacf2..d918f69 100644 --- a/src/main/java/com/faforever/moderatorclient/ui/ViewHelper.java +++ b/src/main/java/com/faforever/moderatorclient/ui/ViewHelper.java @@ -10,7 +10,6 @@ import com.faforever.moderatorclient.mapstruct.VotingSubjectFX; import com.faforever.moderatorclient.ui.domain.*; import javafx.beans.binding.Bindings; -import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; @@ -245,41 +244,32 @@ public static void buildBanTableView(TableView tableView, ObservableL extractors.put(authorColumn, banInfoFX -> banInfoFX.getAuthor().getLogin()); TableColumn revokeReasonColumn = new TableColumn<>("Revocation Reason"); - revokeReasonColumn.setCellValueFactory(o -> { - ObjectProperty banRevokeProperty = o.getValue().banRevokeDataProperty(); - return Bindings.createStringBinding(() -> { - if (banRevokeProperty.get() != null) { - return banRevokeProperty.get().reasonProperty().get(); - } else { - return ""; - } - }, - banRevokeProperty); - }); + revokeReasonColumn.setCellValueFactory(o -> o.getValue().revokeReasonProperty()); revokeReasonColumn.setMinWidth(250); tableView.getColumns().add(revokeReasonColumn); - extractors.put(revokeReasonColumn, banInfoFX -> banInfoFX.getBanRevokeData() == null ? null : banInfoFX.getBanRevokeData().getReason()); + extractors.put(revokeReasonColumn, BanInfoFX::getRevokeReason); TableColumn revokeAuthorColumn = new TableColumn<>("Revocation Author"); - revokeAuthorColumn.setCellValueFactory(o -> { - BanRevokeDataFX banRevokeData = o.getValue().getBanRevokeData(); - if (banRevokeData != null) { - return banRevokeData.getAuthor().representationProperty(); - } else { - return null; - } - } - ); + revokeAuthorColumn.setCellValueFactory(o -> Bindings.createStringBinding(() -> { + PlayerFX revokeAuthor = o.getValue().getRevokeAuthor(); + return revokeAuthor == null ? null : revokeAuthor.getLogin(); + }, o.getValue().revokeAuthorProperty())); revokeAuthorColumn.setMinWidth(150); tableView.getColumns().add(revokeAuthorColumn); - extractors.put(revokeAuthorColumn, banInfoFX -> banInfoFX.getBanRevokeData() == null ? null : banInfoFX.getBanRevokeData().getAuthor().getLogin()); + extractors.put(revokeAuthorColumn, banInfoFX -> banInfoFX.getRevokeAuthor() == null ? null : banInfoFX.getRevokeAuthor().getLogin()); + + TableColumn revocationAtColumn = new TableColumn<>("Revocation at"); + revocationAtColumn.setCellValueFactory(o -> o.getValue().revokeTimeProperty()); + revocationAtColumn.setMinWidth(180); + tableView.getColumns().add(revocationAtColumn); + extractors.put(revocationAtColumn, BanInfoFX::getRevokeTime); TableColumn changeTimeColumn = new TableColumn<>("Created Time"); changeTimeColumn.setCellValueFactory(new PropertyValueFactory<>("createTime")); changeTimeColumn.setMinWidth(180); tableView.getColumns().add(changeTimeColumn); - TableColumn updateTimeColumn = new TableColumn<>("Update (Revoke) Time"); + TableColumn updateTimeColumn = new TableColumn<>("Update Time"); updateTimeColumn.setCellValueFactory(new PropertyValueFactory<>("updateTime")); updateTimeColumn.setMinWidth(180); tableView.getColumns().add(updateTimeColumn); diff --git a/src/main/java/com/faforever/moderatorclient/ui/domain/BanInfoFX.java b/src/main/java/com/faforever/moderatorclient/ui/domain/BanInfoFX.java index 611d9fb..96f8fa4 100644 --- a/src/main/java/com/faforever/moderatorclient/ui/domain/BanInfoFX.java +++ b/src/main/java/com/faforever/moderatorclient/ui/domain/BanInfoFX.java @@ -19,7 +19,9 @@ public class BanInfoFX extends AbstractEntityFX { private final ObjectProperty level; private final ObjectProperty duration; private final ObjectProperty banStatus; - private final ObjectProperty banRevokeData; + private final StringProperty revokeReason; + private final ObjectProperty revokeAuthor; + private final ObjectProperty revokeTime; public BanInfoFX() { player = new SimpleObjectProperty<>(); @@ -27,7 +29,10 @@ public BanInfoFX() { reason = new SimpleStringProperty(); expiresAt = new SimpleObjectProperty<>(); level = new SimpleObjectProperty<>(); - banRevokeData = new SimpleObjectProperty<>(); + + revokeAuthor = new SimpleObjectProperty<>(); + revokeReason = new SimpleStringProperty(); + revokeTime = new SimpleObjectProperty<>(); duration = new SimpleObjectProperty<>(); duration.bind(Bindings.createObjectBinding(() -> expiresAt.get() == null ? BanDurationType.PERMANENT : BanDurationType.TEMPORARY, expiresAt)); @@ -35,15 +40,17 @@ public BanInfoFX() { banStatus = new SimpleObjectProperty<>(); banStatus.bind( Bindings.createObjectBinding(() -> { - if (banRevokeData.get() != null) { + if (getRevokeTime() != null && getRevokeTime().isBefore(OffsetDateTime.now())) { return BanStatus.DISABLED; - } else if (duration.get() == BanDurationType.PERMANENT) { + } + if (getDuration() == BanDurationType.PERMANENT) { return BanStatus.BANNED; - } else { - return expiresAt.get().isAfter(OffsetDateTime.now()) ? BanStatus.BANNED : BanStatus.EXPIRED; } + return getExpiresAt().isAfter(OffsetDateTime.now()) + ? BanStatus.BANNED + : BanStatus.EXPIRED; }, - banRevokeData, duration, expiresAt) + revokeTime, duration, expiresAt) ); } @@ -128,16 +135,39 @@ public ObjectProperty banStatusProperty() { return banStatus; } - public BanRevokeDataFX getBanRevokeData() { - return banRevokeData.get(); + public String getRevokeReason() { + return revokeReason.get(); } - public BanInfoFX setBanRevokeData(BanRevokeDataFX banRevokeData) { - this.banRevokeData.set(banRevokeData); - return this; + public void setRevokeReason(String revokeReason) { + this.revokeReason.set(revokeReason); + } + + public StringProperty revokeReasonProperty() { + return revokeReason; + } + + public PlayerFX getRevokeAuthor() { + return revokeAuthor.get(); + } + + public void setRevokeAuthor(PlayerFX revokeAuthor) { + this.revokeAuthor.set(revokeAuthor); + } + + public ObjectProperty revokeAuthorProperty() { + return revokeAuthor; + } + + public OffsetDateTime getRevokeTime() { + return revokeTime.get(); + } + + public void setRevokeTime(OffsetDateTime revokeTime) { + this.revokeTime.set(revokeTime); } - public ObjectProperty banRevokeDataProperty() { - return banRevokeData; + public ObjectProperty revokeTimeProperty() { + return revokeTime; } } diff --git a/src/main/java/com/faforever/moderatorclient/ui/domain/BanRevokeDataFX.java b/src/main/java/com/faforever/moderatorclient/ui/domain/BanRevokeDataFX.java deleted file mode 100644 index b325e03..0000000 --- a/src/main/java/com/faforever/moderatorclient/ui/domain/BanRevokeDataFX.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.faforever.moderatorclient.ui.domain; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; - -public class BanRevokeDataFX extends AbstractEntityFX { - private final ObjectProperty ban; - private final StringProperty reason; - private final ObjectProperty author; - - public BanRevokeDataFX() { - ban = new SimpleObjectProperty<>(); - reason = new SimpleStringProperty(); - author = new SimpleObjectProperty<>(); - } - - public BanInfoFX getBan() { - return ban.get(); - } - - public BanRevokeDataFX setBan(BanInfoFX ban) { - this.ban.set(ban); - return this; - } - - public ObjectProperty banProperty() { - return ban; - } - - public String getReason() { - return reason.get(); - } - - public BanRevokeDataFX setReason(String reason) { - this.reason.set(reason); - return this; - } - - public StringProperty reasonProperty() { - return reason; - } - - public PlayerFX getAuthor() { - return author.get(); - } - - public BanRevokeDataFX setAuthor(PlayerFX author) { - this.author.set(author); - return this; - } - - public ObjectProperty authorProperty() { - return author; - } -} diff --git a/src/main/java/com/faforever/moderatorclient/ui/main_window/RecentActivityController.java b/src/main/java/com/faforever/moderatorclient/ui/main_window/RecentActivityController.java index aec9c9b..9a5bae4 100644 --- a/src/main/java/com/faforever/moderatorclient/ui/main_window/RecentActivityController.java +++ b/src/main/java/com/faforever/moderatorclient/ui/main_window/RecentActivityController.java @@ -63,6 +63,7 @@ private void addBan(PlayerFX playerFX) { banInfo.setPlayer(playerFX); banInfoController.setBanInfo(banInfo); banInfoController.addPostedListener(banInfoFX -> refresh()); + banInfoController.addRevokedListener(this::refresh); Stage banInfoDialog = new Stage(); banInfoDialog.setTitle("Apply new ban"); banInfoDialog.setScene(new Scene(banInfoController.getRoot())); diff --git a/src/main/java/com/faforever/moderatorclient/ui/voting/VotingSubjectAddController.java b/src/main/java/com/faforever/moderatorclient/ui/voting/VotingSubjectAddController.java index 5a2f81a..8eacedf 100644 --- a/src/main/java/com/faforever/moderatorclient/ui/voting/VotingSubjectAddController.java +++ b/src/main/java/com/faforever/moderatorclient/ui/voting/VotingSubjectAddController.java @@ -51,8 +51,8 @@ public Pane getRoot() { @FXML public void initialize() { - beginTimeTextField.setPromptText(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())); - endTimeTextField.setPromptText(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())); + beginTimeTextField.setPromptText(OffsetDateTime.now().atZoneSameInstant(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + endTimeTextField.setPromptText(OffsetDateTime.now().atZoneSameInstant(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); } diff --git a/src/main/resources/ui/banInfo.fxml b/src/main/resources/ui/banInfo.fxml index 1846e03..cbf0b1a 100644 --- a/src/main/resources/ui/banInfo.fxml +++ b/src/main/resources/ui/banInfo.fxml @@ -5,7 +5,7 @@ + xmlns="http://javafx.com/javafx/8.0.171" fx:controller="com.faforever.moderatorclient.ui.BanInfoController"> @@ -17,11 +17,11 @@ - - + + - - - - - - - - + + + - -