All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.dronesecurity.userapplication.presentation.reporting.issue.IssuesUIController Maven / Gradle / Ivy

/*
 * Copyright (c) 2021-2022, Mirko Felice & Maxim Derevyanchenko. All rights reserved.
 * Licensed under the MIT license. See LICENSE file in the project root for details.
 */

package io.github.dronesecurity.userapplication.presentation.reporting.issue;

import io.github.dronesecurity.lib.utilities.*;
import io.github.dronesecurity.userapplication.application.reporting.issue.*;
import io.github.dronesecurity.userapplication.application.user.ohs.pl.*;
import io.github.dronesecurity.userapplication.domain.reporting.issue.activeissue.entities.AbstractActiveIssue;
import io.github.dronesecurity.userapplication.domain.reporting.issue.closedissue.entities.ClosedIssue;
import io.github.dronesecurity.userapplication.domain.reporting.issue.createdissue.entities.AbstractCreatedIssue;
import io.github.dronesecurity.userapplication.domain.reporting.issue.openissue.entities.OpenIssue;
import io.github.dronesecurity.userapplication.domain.reporting.issue.visionedissue.entities.VisionedIssue;
import io.github.dronesecurity.userapplication.infrastructure.reporting.issue.serializers.IssueStringHelper;
import io.github.dronesecurity.userapplication.utilities.*;
import io.github.dronesecurity.userapplication.utilities.user.UserAPIHelper;
import io.vertx.core.Future;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.codec.BodyCodec;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.Text;
import javafx.stage.Modality;
import org.apache.commons.text.CaseUtils;
import org.jetbrains.annotations.NotNull;

import java.net.URL;
import java.util.Comparator;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

/**
 * The controller of the issue creation service.
 */
public final class IssuesUIController implements Initializable {

    private static final String ERROR_MESSAGE = "Error connecting to issue information. Please retry.";
    private static final double MIN_WIDTH = 450;
    private static final double MIN_HEIGHT = 300;
    private static final String NEW_ISSUE_FXML = "newIssue.fxml";
    @FXML private TabPane issuesPane;

    // Issue Details visualization nodes
    @FXML private GridPane selectedIssuePane;
    @FXML private Label selectedIssueSubject;
    @FXML private Label issueState;
    @FXML private Label selectedIssueCreationDate;
    @FXML private Label selectedIssueCreationTime;
    @FXML private Label selectedIssueCourier;
    @FXML private Text selectedIssueDetails;
    @FXML private Label selectedIssueDroneId;
    @FXML private Button visionIssueButton;
    @FXML private Button goToClosingPageButton;

    // Open issues list visualization nodes
    @FXML private TableView activeIssuesTable;
    @FXML private TableColumn activeIssuesId;
    @FXML private TableColumn activeIssuesSubject;
    @FXML private TableColumn activeIssuesCourier;
    @FXML private TableColumn activeIssuesDroneId;
    @FXML private TableView closedIssuesTable;
    @FXML private TableColumn closedIssuesId;
    @FXML private TableColumn closedIssuesSubject;
    @FXML private TableColumn closedIssuesCourier;
    @FXML private TableColumn closedIssuesDroneId;

    // Closing issue panel
    @FXML private AnchorPane closingIssuePane;
    @FXML private TextArea solutionTextArea;

    @FXML private Button newIssueButton;
    @FXML private Label solutionLabel;
    @FXML private Text closedIssueSolution;

    private IssueReportService issueReportService;

    private AbstractCreatedIssue currentlySelectedIssue;
    private GenericUser loggedGenericUser;

    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize(final URL location, final ResourceBundle resources) {
        UserAPIHelper.get(UserAPIHelper.Operation.CHECK_LOGGED_USER_ROLE, BodyCodec.json(UserRole.class))
                .onSuccess(res -> this.initLoggedUser(res.body()));

        IssueHelper.initTable(this.activeIssuesTable, this.activeIssuesId, this.activeIssuesSubject,
                this.activeIssuesCourier, this.activeIssuesDroneId, issue -> {
            this.currentlySelectedIssue = issue;
            this.solutionLabel.setVisible(false);
            this.closedIssueSolution.setVisible(false);
            this.closedIssueSolution.setText("");
            this.visionIssueButton.setVisible(this.loggedGenericUser.getRole() == UserRole.MAINTAINER
                    && IssueStringHelper.STATUS_OPEN.equals(issue.getState()));
            this.goToClosingPageButton.setVisible(this.loggedGenericUser.getRole() == UserRole.MAINTAINER
                    && IssueStringHelper.STATUS_VISIONED.equals(issue.getState()));
            this.newIssueButton.setVisible(false);

            this.fillIssueFields();
        });

        IssueHelper.initTable(this.closedIssuesTable, this.closedIssuesId, this.closedIssuesSubject,
                this.closedIssuesCourier, this.closedIssuesDroneId, issue -> {
            this.currentlySelectedIssue = issue;
            this.solutionLabel.setVisible(true);
            this.closedIssueSolution.setVisible(true);
            this.closedIssueSolution.setText(issue.getIssueSolution());
            this.visionIssueButton.setVisible(false);
            this.goToClosingPageButton.setVisible(false);
            this.newIssueButton.setVisible(false);
            this.fillIssueFields();
        });
    }

    @FXML
    private void newIssue() {
        final FXMLLoader loader = new FXMLLoader(IssuesUIController.class.getResource(NEW_ISSUE_FXML));
        FXHelper.initializeWindow(Modality.WINDOW_MODAL, "Create new Issue", loader, MIN_WIDTH, MIN_HEIGHT)
                .ifPresent(stage -> {
                    stage.initOwner(this.issuesPane.getScene().getWindow());
                    stage.setOnHidden(ignored -> this.refreshOpenIssues());
                    stage.showAndWait();
                });
    }

    @FXML
    private void visionIssue() {
        CastHelper.safeCast(this.currentlySelectedIssue, OpenIssue.class).ifPresent(openIssue -> {
            if (this.issueReportService.visionIssue(openIssue.visionIssue())) {
                this.refreshOpenIssues();
                Platform.runLater(() -> {
                    final TableView.TableViewSelectionModel selectionModel =
                            this.activeIssuesTable.getSelectionModel();

                    selectionModel.clearSelection();
                    this.activeIssuesTable.getItems()
                            .filtered(c -> c.getId() == this.currentlySelectedIssue.getId())
                            .stream()
                            .findFirst()
                            .ifPresent(selectionModel::select);
                });
            } else
                DialogUtils.showErrorDialog(ERROR_MESSAGE);
        });
    }

    @FXML
    private void closeIssue() {
        CastHelper.safeCast(this.currentlySelectedIssue, VisionedIssue.class).ifPresent(visionedIssue -> {
            if (this.issueReportService.closeIssue(visionedIssue.closeIssue(this.solutionTextArea.getText()))) {
                Platform.runLater(() -> {
                    this.refreshOpenIssues();
                    this.refreshClosedIssues();
                    this.closedIssuesTable.getItems()
                            .filtered(c -> c.getId().isSameValueAs(this.currentlySelectedIssue.getId()))
                            .stream().findFirst()
                            .ifPresent(issue -> this.closedIssuesTable.getSelectionModel().select(issue));
                });

                this.activeIssuesTable.getSelectionModel().clearSelection();
                this.cancelClosing();
            } else
                DialogUtils.showErrorDialog(ERROR_MESSAGE);
        });
    }

    @FXML
    private void goBackFromOpenIssues() {
        this.selectedIssuePane.setVisible(false);
        this.activeIssuesTable.getSelectionModel().clearSelection();
        this.closedIssuesTable.getSelectionModel().clearSelection();
        this.issuesPane.setVisible(true);
        this.newIssueButton.setVisible(this.loggedGenericUser.getRole() == UserRole.COURIER);
    }

    @FXML
    private void goToClosingPage() {
        this.selectedIssuePane.setVisible(false);
        this.closingIssuePane.setVisible(true);
    }

    @FXML
    private void cancelClosing() {
        this.solutionTextArea.clear();
        this.closingIssuePane.setVisible(false);
        this.selectedIssuePane.setVisible(true);
    }

    private void initLoggedUser(final @NotNull UserRole userRole) {
        final Future loggedUser;
        switch (userRole) {
            case COURIER:
                loggedUser = UserAPIHelper.get(UserAPIHelper.Operation.RETRIEVE_LOGGED_COURIER_IF_PRESENT,
                        BodyCodec.json(GenericUser.class)).map(HttpResponse::body);
                break;
            case MAINTAINER:
                loggedUser = UserAPIHelper.get(
                        UserAPIHelper.Operation.RETRIEVE_LOGGED_MAINTAINER_IF_PRESENT,
                        BodyCodec.json(GenericUser.class)).map(HttpResponse::body);
                break;
            default:
                loggedUser = Future.failedFuture(
                        new IllegalStateException("Unexpected value: " + userRole));
                break;
        }
        loggedUser.onSuccess(res -> {
            this.loggedGenericUser = res;
            this.newIssueButton.setVisible(this.loggedGenericUser.getRole() == UserRole.COURIER);

            if (this.loggedGenericUser.getRole() == UserRole.COURIER) {
                this.issueReportService = new CourierIssueReportService();
                this.activeIssuesTable.getColumns().remove(this.activeIssuesCourier);
                this.closedIssuesTable.getColumns().remove(this.closedIssuesCourier);
            } else {
                this.issueReportService = new MaintainerIssueReportService();
                this.issueReportService.subscribeToNewIssue(this.loggedGenericUser.getUsername(), issue -> {
                        this.refreshOpenIssues();
                        Platform.runLater(() -> DialogUtils.showInfoNotification("You have received a new issue!",
                                this.issuesPane.getScene().getWindow()));
                });
            }
            this.refreshOpenIssues();
            this.refreshClosedIssues();
        });
    }

    private void fillIssueFields() {
        this.selectedIssueSubject.setText(this.currentlySelectedIssue.getSubject());
        this.issueState.setText(CaseUtils.toCamelCase(this.currentlySelectedIssue.getState(), true));
        final String creationInstant = DateHelper.toString(this.currentlySelectedIssue.getReportingDate());
        final int splitIndex = creationInstant.indexOf(':') - 2;
        this.selectedIssueCreationDate.setText(creationInstant.substring(0, splitIndex));
        this.selectedIssueCreationTime.setText(creationInstant.substring(splitIndex));
        this.selectedIssueCourier.setText(this.currentlySelectedIssue.getCourier());
        this.selectedIssueDetails.setText(this.currentlySelectedIssue.getDetails());
        this.selectedIssueDroneId.setText(this.currentlySelectedIssue.getDroneId());

        this.issuesPane.setVisible(false);
        this.selectedIssuePane.setVisible(true);
    }

    private void refreshOpenIssues() {
        IssueHelper.refreshOpenIssues(this.activeIssuesTable, this.loggedGenericUser.getRole() == UserRole.COURIER
                ? this.issueReportService.getActiveIssueReportsForCourier(this.loggedGenericUser.getUsername())
                : this.issueReportService.getActiveIssueReportsForAssignee(this.loggedGenericUser.getUsername()));
    }

    private void refreshClosedIssues() {
        this.closedIssuesTable.setItems(FXCollections.observableList(
                (this.loggedGenericUser.getRole() == UserRole.COURIER
                        ? this.issueReportService.getClosedIssueReportsForCourier(this.loggedGenericUser.getUsername())
                        : this.issueReportService.getClosedIssueReportsForAssignee(this.loggedGenericUser.getUsername())
                )
                .stream()
                .sorted(Comparator.comparingLong(issue -> issue.getId().getId()))
                .collect(Collectors.toList())));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy