diff --git a/pom.xml b/pom.xml index b0f6764..5f7773d 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,11 @@ spring-security-crypto 7.0.2 + + commons-logging + commons-logging + 1.3.5 + diff --git a/src/main/java/edu/group5/app/model/user/User.java b/src/main/java/edu/group5/app/model/user/User.java index e163785..8dd48cd 100644 --- a/src/main/java/edu/group5/app/model/user/User.java +++ b/src/main/java/edu/group5/app/model/user/User.java @@ -1,5 +1,120 @@ package edu.group5.app.model.user; - +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +/** + * User class represents a user in the system. It is an abstract class that will be extended by specific user types such as Donor, Recipient, and Admin. + * Each user has a unique userId, a role that defines their permissions in the system, and personal information such as first name, last name, email, and password hash. + * The constructor validates that all required fields are provided and throws an IllegalArgumentException if any of the fields are null or empty. + * This ensures that the User objects are always in a valid state when created. + * The class also includes a method to verify the user's password + * by comparing the provided plaintext password with the stored hashed password using BCrypt. + * + */ public class User { + private int userId; + private String role; + private String firstName; + private String lastName; + private String email; + private String passwordHash; + + /** + * Constructor for User class. Validates that all required fields + * are provided and throws an IllegalArgumentException if any of the fields are null or empty. + * @param userId the unique identifier for the user, must be a positive integer + * @param role the role of the user (e.g., "Donor", "Recipient", "Admin") + * @param firstName the first name of the user + * @param lastName the last name of the user + * @param email the email address of the user + * @param passwordHash the hashed password of the user, used for authentication purposes + */ + public User(int userId, String role, String firstName, + String lastName, String email, String passwordHash) { + if (userId <= 0) { + throw new IllegalArgumentException("User ID must be positive"); + } + if (role == null || role.trim().isEmpty()) { + throw new IllegalArgumentException("Role cannot be null or empty"); + } + if (firstName == null || firstName.trim().isEmpty()) { + throw new IllegalArgumentException("First name cannot be null or empty"); + } + if (lastName == null || lastName.trim().isEmpty()) { + throw new IllegalArgumentException("Last name cannot be null or empty"); + } + if (email == null || email.trim().isEmpty()) { + throw new IllegalArgumentException("Email cannot be null or empty"); + } + if (passwordHash == null || passwordHash.trim().isEmpty()) { + throw new IllegalArgumentException("Password hash cannot be null or empty"); + } + this.userId = userId; + this.role = role.trim(); + this.firstName = firstName.trim(); + this.lastName = lastName.trim(); + this.email = email.trim(); + this.passwordHash = passwordHash; +} + + /** + * Gets the unique identifier for the user. + * @return the userId of the user + */ + public int getUserId() { + return userId; + } + + /** + * Gets the role of the user, which defines their permissions in the system. + * @return the role of the user + */ + public String getRole() { + return role; + } + /** + * Gets the first name of the user. + * @return the first name of the user + */ + public String getFirstName() { + return firstName; + } + + /** + * Gets the last name of the user. + * @return the last name of the user + */ + public String getLastName() { + return lastName; + } + + /** + * Gets the email address of the user. + * @return the email of the user + */ + public String getEmail() { + return email; + } + + /** + * Gets the hashed password of the user. + * This is used for authentication purposes and should not be exposed in plaintext. + * @return the password hash of the user + */ + public String getPasswordHash() { + return passwordHash; + } + + /** + * Verifies if the provided password matches the stored password hash. + * This method uses BCrypt to compare the plaintext password with the hashed password. + * @param password the plaintext password to verify + * @return true if the password is correct, false otherwise + */ + public boolean verifyPassword(String password) { + if (password == null || password.isEmpty()) { + return false; + } + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + return encoder.matches(password, this.passwordHash); + } } diff --git a/src/test/java/edu/group5/app/control/WrapperTest.java b/src/test/java/edu/group5/app/control/WrapperTest.java new file mode 100644 index 0000000..d626fd7 --- /dev/null +++ b/src/test/java/edu/group5/app/control/WrapperTest.java @@ -0,0 +1,5 @@ +package edu.group5.app.control; + +public class WrapperTest { + +} diff --git a/src/test/java/edu/group5/app/model/donation/DonationTest.java b/src/test/java/edu/group5/app/model/donation/DonationTest.java new file mode 100644 index 0000000..a905209 --- /dev/null +++ b/src/test/java/edu/group5/app/model/donation/DonationTest.java @@ -0,0 +1,5 @@ +package edu.group5.app.model.donation; + +public class DonationTest { + +} diff --git a/src/test/java/edu/group5/app/model/user/UserTest.java b/src/test/java/edu/group5/app/model/user/UserTest.java new file mode 100644 index 0000000..1e7277a --- /dev/null +++ b/src/test/java/edu/group5/app/model/user/UserTest.java @@ -0,0 +1,136 @@ +package edu.group5.app.model.user; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +public class UserTest { + private static final int TEST_USER_ID = 1; + private static final String TEST_ROLE = "Donor"; + private static final String TEST_FIRST_NAME = "John"; + private static final String TEST_LAST_NAME = "Doe"; + private static final String TEST_EMAIL = "john.doe@example.com"; + private static final String TEST_PASSWORD = "password123"; + private static final String TEST_PASSWORD_HASH = new BCryptPasswordEncoder().encode(TEST_PASSWORD); + + private static final int WRONG_USER_ID = -5; + private static final String WRONG_ROLE = ""; + private static final String WRONG_FIRST_NAME = ""; + private static final String WRONG_LAST_NAME = ""; + private static final String WRONG_EMAIL = ""; + private static final String WRONG_PASSWORD_HASH = ""; + + private void constructorTest(int userId, String role, String firstName, String lastName, String email, String passwordHash, boolean negativeTest) { + boolean exceptionThrown = negativeTest; + try { + new User(userId, role, firstName, lastName, email, passwordHash); + } catch (Exception e) { + exceptionThrown = !negativeTest; + } finally { + assertFalse(exceptionThrown); + } + } + + @Test + public void constructorThrowsNoException() { + constructorTest(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH, false); + } + + @Test + public void constructorWithNegativeUserIdThrowsException() { + constructorTest(WRONG_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithEmptyRoleThrowsException() { + constructorTest(TEST_USER_ID, WRONG_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithEmptyFirstNameThrowsException() { + constructorTest(TEST_USER_ID, TEST_ROLE, WRONG_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithEmptyLastNameThrowsException() { + constructorTest(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, WRONG_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithEmptyEmailThrowsException() { + constructorTest(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, WRONG_EMAIL, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithEmptyPasswordHashThrowsException() { + constructorTest(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, WRONG_PASSWORD_HASH, true); + } + + private void getMethodComparer(User user, boolean negativeTest) { + if (user.getUserId() == TEST_USER_ID && + user.getRole().equals(TEST_ROLE) && + user.getFirstName().equals(TEST_FIRST_NAME) && + user.getLastName().equals(TEST_LAST_NAME) && + user.getEmail().equals(TEST_EMAIL) && + user.getPasswordHash() != null) { + assertFalse(negativeTest); + } + } + + @Test + public void getMethodsReturnCorrectInformation() { + User testUser = new User(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH); + getMethodComparer(testUser, false); + } + + @Test + public void verifyPasswordReturnsTrueForCorrectPassword() { + User testUser = new User(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH); + assertTrue(testUser.verifyPassword(TEST_PASSWORD)); + } + + @Test + public void verifyPasswordReturnsFalseForIncorrectPassword() { + User testUser = new User(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH); + assertFalse(testUser.verifyPassword("wrongPassword")); + } + + @Test + public void verifyPasswordReturnsFalseForNullPassword() { + User testUser = new User(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH); + assertFalse(testUser.verifyPassword(null)); + } + + @Test + public void verifyPasswordReturnsFalseForEmptyPassword() { + User testUser = new User(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH); + assertFalse(testUser.verifyPassword("")); + } + + @Test + public void constructorWithNullRoleThrowsException() { + constructorTest(TEST_USER_ID, null, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithNullFirstNameThrowsException() { + constructorTest(TEST_USER_ID, TEST_ROLE, null, TEST_LAST_NAME, TEST_EMAIL, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithNullLastNameThrowsException() { + constructorTest(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, null, TEST_EMAIL, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithNullEmailThrowsException() { + constructorTest(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, null, TEST_PASSWORD_HASH, true); + } + + @Test + public void constructorWithNullPasswordHashThrowsException() { + constructorTest(TEST_USER_ID, TEST_ROLE, TEST_FIRST_NAME, TEST_LAST_NAME, TEST_EMAIL, null, true); + } +} diff --git a/src/test/java/edu/group5/app/utils/UtilitiesTest.java b/src/test/java/edu/group5/app/utils/UtilitiesTest.java new file mode 100644 index 0000000..88aa0c9 --- /dev/null +++ b/src/test/java/edu/group5/app/utils/UtilitiesTest.java @@ -0,0 +1,5 @@ +package edu.group5.app.utils; + +public class UtilitiesTest { + +} diff --git a/src/test/java/edu/group5/app/view/ViewTest.java b/src/test/java/edu/group5/app/view/ViewTest.java new file mode 100644 index 0000000..bd0cd83 --- /dev/null +++ b/src/test/java/edu/group5/app/view/ViewTest.java @@ -0,0 +1,5 @@ +package edu.group5.app.view; + +public class ViewTest { + +}