Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package com.gitrekt.resort.controller;

import com.gitrekt.resort.model.entities.Employee;
import com.gitrekt.resort.model.services.EmployeeService;
import com.gitrekt.resort.model.services.PasswordValidatorUtil;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javax.persistence.EntityNotFoundException;
import org.passay.PasswordData;
import org.passay.RuleResult;
import org.passay.RuleResultDetail;

/**
* Controller class for the dialog in which employees reset their password.
Expand All @@ -20,43 +28,162 @@ public class ResetEmployeePasswordDialogController implements Initializable {
private Button confirmButton;

@FXML
private TextField authorizingManagerIdField;
private TextField newPasswordField;

@FXML
private TextField authorizingManagerPasswordField;
private TextField confirmPasswordField;

@FXML
private TextField confirmEmployeeIdField;
private Label errorLabel;

@FXML
private TextField newPasswordField;
private Label lengthLabel;

@FXML
private TextField confirmPasswordField;
private Label specialCharLabel;

@FXML
private Label mixedCaseLabel;

@FXML
private Label numberLabel;

private Long employeeId;

/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
// Configure text change listeners for the two fields
newPasswordField.setOnKeyPressed(
e -> onNewPasswordFieldUpdated()
);
confirmPasswordField.setOnKeyPressed(e ->
onConfirmPasswordFieldUpdated()
);
}

public void onCancelButtonClicked() {
/**
* Called to initialize the requisite data for the dialog.
*
* @param employeeId The employee id of the employee to reset the password
* for.
*/
public void setEmployeeId(Long employeeId) {
this.employeeId = employeeId;
}

@FXML
private void onCancelButtonClicked() {
Stage dialogStage = (Stage) cancelButton.getScene().getWindow();
dialogStage.close();
}

public void onConfirmButtonClicked() {
// TODO
@FXML
private void onConfirmButtonClicked() {
if(validatePasswords()) {
String password = newPasswordField.getText();
changePassword(password);
closeDialog();
}
}

private void onConfirmPasswordFieldUpdated() {
validatePasswords();
}

public void onConfirmPasswordFieldUpdated() {
// TODO
private void onNewPasswordFieldUpdated() {
validatePasswords();
}

public void onNewPasswordFieldUpdated() {
// TODO
/**
* In addition to determining whether the passwords are valid, this method
* also handles the ui cues that let the user know what is wrong with their
* password. Maybe not the best instance of the SRP, but it's simple enough
* in practice.
*
* @return True if the passwords entered are valid.
*/
private boolean validatePasswords() {
boolean result = true;

String newPassword = newPasswordField.getText();
String matchingPassword = confirmPasswordField.getText();

// Hide any already showing errors
errorLabel.setVisible(false);
lengthLabel.getStyleClass().remove("validationErrorText");
specialCharLabel.getStyleClass().remove("validationErrorText");
numberLabel.getStyleClass().remove("validationErrorText");
mixedCaseLabel.getStyleClass().remove("validationErrorText");

if(newPassword.isEmpty() || matchingPassword.isEmpty()) {
errorLabel.setVisible(true);
errorLabel.setText("Fields cannot be empty");
result = false;
}

if(!newPassword.equals(matchingPassword)) {
errorLabel.setVisible(true);
errorLabel.setText("Passwords don't match");
result = false;
}

RuleResult ruleResult = PasswordValidatorUtil.validator
.validate(new PasswordData(newPassword));

if(!ruleResult.isValid()) {
result = false;
}

// Update the requirements labels
for(RuleResultDetail d : ruleResult.getDetails()) {
String errorCode = d.getErrorCode();
switch(errorCode) {
case "TOO_SHORT":
lengthLabel.getStyleClass().add("validationErrorText");
break;
case "INSUFFICIENT_LOWERCASE":
case "INSUFFICIENT_UPPERCASE":
mixedCaseLabel.getStyleClass().add("validationErrorText");
break;
case "INSUFFICIENT_DIGIT":
numberLabel.getStyleClass().add("validationErrorText");
break;
case "INSUFFICIENT_SPECIAL":
specialCharLabel.getStyleClass().add("validationErrorText");
break;
}
}

return result;
}

/**
* Handles the actual act of changing the user's password.
*
* @param newPassword The password, which should be already validated.
*/
private void changePassword(String newPassword) {
// Ensure that we have an employee to change the password for
if(this.employeeId == null) {
throw new IllegalStateException("Must initialize employeeId");
}

EmployeeService employeeService = new EmployeeService();
Employee employee = employeeService.getEmployeeById(this.employeeId);
try {
employee.setPassword(newPassword);
employeeService.updateEmployee(employee);
} catch (EntityNotFoundException e) {
// TODO
}
}

private void closeDialog() {
Stage dialogStage = (Stage) this.lengthLabel.getScene().getWindow();
dialogStage.close();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ public void initialize(Stage mainStage) {

/**
* @param fxmlPath The path to the FXML file of the screen to switch to.
*
* @return The FXML controller of the new scene.
*/
public void switchToScreen(String fxmlPath) {
public Object switchToScreen(String fxmlPath) {
Parent newScreenRoot;

try {
Expand All @@ -61,6 +63,7 @@ public void switchToScreen(String fxmlPath) {

mainStage.getScene().setRoot(newScreenRoot);
mainStage.setMaximized(true);
return fxmlLoader.getController();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
Expand All @@ -30,6 +32,18 @@ public class StaffAccountsScreenController implements Initializable {
@FXML
private Button addNewEmployeeButton;

@FXML
private TableView staffAccountTableView;

@FXML
private TableColumn idColumn;

@FXML
private TableColumn nameColumn;

@FXML
private TableColumn managerColumn;

private final Image appLogo = new Image("images/Logo.png");

/**
Expand All @@ -53,10 +67,12 @@ public void onRemoveEmployeeButtonClicked() {
public void onResetEmployeePasswordButtonClicked() throws IOException {
Stage dialogStage = new Stage();
dialogStage.getIcons().add(appLogo);
Parent dialogRoot = FXMLLoader.load(
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/fxml/ResetEmployeePasswordDialog.fxml")
);
Parent dialogRoot = loader.load();
Scene resetPasswordDialog = new Scene(dialogRoot);

dialogStage.setScene(resetPasswordDialog);
dialogStage.initModality(Modality.APPLICATION_MODAL);
dialogStage.initOwner(
Expand All @@ -66,6 +82,11 @@ public void onResetEmployeePasswordButtonClicked() throws IOException {
dialogStage.setTitle("Authentication Required");
dialogStage.centerOnScreen();

ResetEmployeePasswordDialogController c;
c = (ResetEmployeePasswordDialogController) loader.getController();
long employeeId = getSelectedEmployeeId();
c.setEmployeeId(employeeId);

dialogStage.show();
}

Expand All @@ -88,4 +109,9 @@ public void onAddNewEmployeeButtonClicked() throws IOException {
dialogStage.show();
}

private long getSelectedEmployeeId() {
// TODO: REPLACE WITH REAL IMPLEMENTATION
return 1L;
}

}
4 changes: 2 additions & 2 deletions src/main/java/com/gitrekt/resort/model/entities/Employee.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public void setManager(boolean isManager) {
this.isManager = isManager;
}

public void setHashedPassword(String hashedPassword){
this.hashedPassword = hashedPassword;
public void setPassword(String plaintextPassword){
encryptPassword(plaintextPassword);
}

private void encryptPassword(String plaintextPassword) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.gitrekt.resort.model.services;

import org.passay.CharacterRule;
import org.passay.EnglishCharacterData;
import org.passay.LengthRule;
import org.passay.PasswordValidator;

public class PasswordValidatorUtil {

public static final PasswordValidator validator = new PasswordValidator(
// 60 is around the max length of BCrypt passwords anyways
new LengthRule(10,60),
new CharacterRule(EnglishCharacterData.UpperCase, 1),
new CharacterRule(EnglishCharacterData.LowerCase, 1),
new CharacterRule(EnglishCharacterData.Digit, 1),
new CharacterRule(EnglishCharacterData.Special, 1)
);

}
45 changes: 10 additions & 35 deletions src/main/resources/fxml/ResetEmployeePasswordDialog.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>

<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="500.0" spacing="10.0" stylesheets="@../fxcss/Master.css" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.gitrekt.resort.controller.ResetEmployeePasswordDialogController">
<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="500.0" spacing="10.0" stylesheets="@../fxcss/Master.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.gitrekt.resort.controller.ResetEmployeePasswordDialogController">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
Expand All @@ -23,33 +22,12 @@
</VBox.margin>
</Label>
<Separator prefWidth="200.0" />
<GridPane hgap="10.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="344.0" minWidth="10.0" prefWidth="338.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<TextField fx:id="authorizingManagerIdField" promptText="Enter authorizing manager employee ID" GridPane.columnIndex="1" />
<PasswordField fx:id="authorizingManagerPasswordField" promptText="Enter authorizing manager password" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="Manager ID:" />
<Label text="Manager Password:" GridPane.rowIndex="1" />
</children>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</GridPane>
<Separator prefWidth="200.0" />
<Label text="Passwords Must Meet the Following Requirements" textFill="WHITE" underline="true" />
<Label fx:id="passwordLengthRequirementLabel" text="More than 8 characters long" textFill="WHITE" />
<Label fx:id="passwordCharactersRequirementLabel" text="Contain at least 1 number or special character" textFill="WHITE" />
<Label fx:id="passwordCaseRequirementLabel" text="Contain mixed case" textFill="WHITE" />
<Label fx:id="lengthLabel" text="More than 8 characters long" textFill="WHITE" />
<Label fx:id="numberLabel" text="Contain at least one number" textFill="WHITE" />
<Label fx:id="specialCharLabel" text="Contain at least 1 special character" textFill="WHITE" />
<Label fx:id="mixedCaseLabel" text="Contain mixed case" textFill="WHITE" />
<Label fx:id="errorLabel" focusTraversable="false" styleClass="validationErrorText" text="Error Text" visible="false" />
<GridPane hgap="10.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
Expand All @@ -58,15 +36,12 @@
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Confirm Employee ID:" />
<TextField fx:id="confirmEmployeeIdField" promptText="Confirm employee ID to change password for" GridPane.columnIndex="1" />
<PasswordField fx:id="newPasswordField" onAction="#onNewPasswordFieldUpdated" promptText="Enter new password" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<PasswordField fx:id="confirmPasswordField" onAction="#onConfirmPasswordFieldUpdated" promptText="Confirm new password" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="New Password:" GridPane.rowIndex="1" />
<Label text="Confirm New Password:" GridPane.rowIndex="2" />
<PasswordField fx:id="newPasswordField" promptText="Enter new password" GridPane.columnIndex="1" />
<PasswordField fx:id="confirmPasswordField" promptText="Confirm new password" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="New Password:" />
<Label text="Confirm New Password:" GridPane.rowIndex="1" />
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
Expand Down