From 7de8e6733e45a27d96ded1fe76c370d818f21e9c Mon Sep 17 00:00:00 2001 From: AdrianBalunan Date: Thu, 23 Apr 2026 16:25:23 +0200 Subject: [PATCH] Fix: Moved UserSelect methods to UserDAO so that the userDAO file manages all user-table related activites --- .../systemutvikling/team6/HmHApplication.java | 6 +- .../profileOrgSettingsController.java | 7 - .../profileUserSettingsController.java | 4 +- .../team6/database/DAO/UserDAO.java | 521 ++++++++++++++++- .../team6/database/Readers/UserSelect.java | 551 ------------------ .../team6/service/AuthenticationService.java | 20 +- .../database/Readers/CharitySelectTest.java | 1 - 7 files changed, 526 insertions(+), 584 deletions(-) delete mode 100644 helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/Readers/UserSelect.java diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/HmHApplication.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/HmHApplication.java index 0f4a58b..ba6064b 100644 --- a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/HmHApplication.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/HmHApplication.java @@ -6,7 +6,6 @@ import java.util.Objects; import javafx.application.Application; import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; @@ -14,9 +13,6 @@ import ntnu.systemutvikling.team6.database.DAO.UserDAO; import ntnu.systemutvikling.team6.database.DatabaseConnection; import ntnu.systemutvikling.team6.database.DatabaseSetup; -import ntnu.systemutvikling.team6.database.Readers.UserSelect; -import ntnu.systemutvikling.team6.models.Charity; -import ntnu.systemutvikling.team6.models.registry.CharityRegistry; import ntnu.systemutvikling.team6.scraper.FullCharityScrape; import ntnu.systemutvikling.team6.service.APIToDatabaseService; import ntnu.systemutvikling.team6.service.AuthenticationService; @@ -25,7 +21,7 @@ public class HmHApplication extends Application { @Override public void start(Stage stage) throws Exception { DatabaseConnection conn = new DatabaseConnection(); - AuthenticationService authToken = new AuthenticationService(new UserSelect(conn), new UserDAO(conn)); + AuthenticationService authToken = new AuthenticationService(new UserDAO(conn)); FXMLLoader fxmlLoader = new FXMLLoader(HmHApplication.class.getResource("/fxml/frontPage.fxml")); diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/profileCharity/profileOrgSettingsController.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/profileCharity/profileOrgSettingsController.java index c8b93db..f9d3acc 100644 --- a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/profileCharity/profileOrgSettingsController.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/profileCharity/profileOrgSettingsController.java @@ -12,17 +12,10 @@ import javafx.stage.Stage; import ntnu.systemutvikling.team6.controller.components.*; import ntnu.systemutvikling.team6.database.DAO.CharityUserDAO; -import ntnu.systemutvikling.team6.database.DAO.UserDAO; import ntnu.systemutvikling.team6.database.DatabaseConnection; -import ntnu.systemutvikling.team6.database.Readers.UserSelect; import ntnu.systemutvikling.team6.models.Charity; -import ntnu.systemutvikling.team6.models.Donation; -import ntnu.systemutvikling.team6.models.registry.DonationRegistry; -import ntnu.systemutvikling.team6.models.user.User; -import ntnu.systemutvikling.team6.security.PasswordHasher; import java.io.IOException; -import java.util.Base64; import java.util.List; public class profileOrgSettingsController extends BaseController { diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/profileUser/profileUserSettingsController.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/profileUser/profileUserSettingsController.java index 89cbc7d..8e0ef07 100644 --- a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/profileUser/profileUserSettingsController.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/profileUser/profileUserSettingsController.java @@ -10,7 +10,6 @@ import ntnu.systemutvikling.team6.controller.components.NavbarController; import ntnu.systemutvikling.team6.database.DAO.UserDAO; import ntnu.systemutvikling.team6.database.DatabaseConnection; -import ntnu.systemutvikling.team6.database.Readers.UserSelect; import ntnu.systemutvikling.team6.models.user.*; import ntnu.systemutvikling.team6.security.PasswordHasher; @@ -119,10 +118,9 @@ private void handleNewProfile(ActionEvent event){ boolean updateSuccess; DatabaseConnection conn = new DatabaseConnection(); UserDAO userDataObject = new UserDAO(conn); - UserSelect userReaderObject = new UserSelect(conn); try { if (!emailText.equals(authToken.getCurrentUser().getEmail())) { - boolean isEmailTaken = userReaderObject.isEmailTaken(emailText); + boolean isEmailTaken = userDataObject.isEmailTaken(emailText); if (!isEmailTaken) { updateSuccess = userDataObject.updateUserDetails(newUserOnlyCredentials); } else { diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DAO/UserDAO.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DAO/UserDAO.java index 2357894..f82b2b9 100644 --- a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DAO/UserDAO.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DAO/UserDAO.java @@ -1,11 +1,14 @@ package ntnu.systemutvikling.team6.database.DAO; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; +import java.sql.*; +import java.time.LocalDate; +import java.util.HashSet; + import ntnu.systemutvikling.team6.database.DatabaseConnection; -import ntnu.systemutvikling.team6.models.user.Settings; -import ntnu.systemutvikling.team6.models.user.User; +import ntnu.systemutvikling.team6.models.Charity; +import ntnu.systemutvikling.team6.models.registry.UserRegistry; +import ntnu.systemutvikling.team6.models.user.*; +import ntnu.systemutvikling.team6.security.PasswordHasher; /** * This class is responsible for sending concurrent information about the user to the User database, @@ -21,6 +24,514 @@ public UserDAO(DatabaseConnection connection) { this.connection = connection; } + public boolean isEmailTaken(String email){ + if (email == null || email.isBlank() || !email.contains("@") || !email.contains(".")) { + throw new IllegalArgumentException( + "Email cannot be null or blank," + " and must contain '@' and '.'"); + } + try (Connection conn = connection.getMySqlConnection()) { + + String mysql = + """ + SELECT UUID_User FROM User WHERE user_email = ? + """; + PreparedStatement statement = conn.prepareStatement(mysql); + statement.setString(1, email); + ResultSet rs = statement.executeQuery(); + + if (rs.next()) { + System.out.println("Email Taken already"); + return true; + } + + } catch (SQLException e) { + e.printStackTrace(); + } + return false; + } + public Charity getUserCharityUser(String uuid){ + if (uuid == null || uuid.isBlank()) { + throw new IllegalArgumentException( + "UUID cannot be null or blank"); + } + Charity currentCharity = null; + Connection conn = null; + try { + conn = connection.getMySqlConnection(); + String sql_query = + """ + SELECT + c.UUID_charities, c.org_number, c.pre_approved, c.status, + cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, + cat.category + FROM CharityUsers cu + INNER JOIN Charities c ON c.UUID_charities = cu.TheCharity + INNER JOIN CharityVanity cv ON cv.UUID_charity = c.UUID_charities + LEFT JOIN Charity_Categories cc ON cc.Charities_UUID_charities = c.UUID_charities + LEFT JOIN Categories cat ON cat.category_id = cc.Categories_category_id + WHERE CharityUserId = ? + """; + PreparedStatement stmt = conn.prepareStatement(sql_query); + stmt.setString(1, uuid); + ResultSet rs = stmt.executeQuery(); + + String lastCharity = null; + + while (rs.next()) { + String currentId = rs.getString("UUID_charities"); + if (lastCharity == null || !currentId.equals(lastCharity)) { + currentCharity = + new Charity( + rs.getString("UUID_charities"), + rs.getString("org_number"), + rs.getString("charity_name"), + rs.getString("charity_link"), + rs.getString("status"), + rs.getBoolean("pre_approved"), + rs.getString("description"), + rs.getString("logoURL"), + rs.getString("key_values"), + rs.getBytes("logoBLOB")); + lastCharity = currentId; + } + + String categoryName = rs.getString("category"); + if (categoryName != null && !currentCharity.getCategory().contains(categoryName)) { + currentCharity.getCategory().add(categoryName); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("ERROR: Something went wrong during updating charities table."); + } + return currentCharity; + } + + /** + * Retrieves a single {@link User} from the database by their UUID. + * + *

The returned user is fully populated with {@link Settings} (when present) and an {@link + * Inbox} containing any associated {@link Message} objects. Returns {@code null} if no user with + * the given UUID exists. + * + * @param user_id the UUID string of the user to retrieve; must not be {@code null} + * @return the matching {@link User} with settings and inbox populated, or {@code null} if no user + * is found + * @throws RuntimeException if a {@link SQLException} occurs while executing the query + */ + public User getUserFromDBUuid(String user_id) { + User user = null; + Connection conn = null; + try { + conn = connection.getMySqlConnection(); + String sql_query = + """ + SELECT + u.UUID_User, u.user_name, u.user_email, u.user_password, u.role, + s.UUID_user, s.isAnonymous, s.language, s.lightmode, + m.UUID_message, m.message_title, m.message_content, m.message_date, m.sender_user_id, m.sender_charity_id, m.user_id, + cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, + c.UUID_charities, c.org_number, c.pre_approved, c.status + FROM User u + LEFT JOIN Settings s ON u.UUID_User = s.UUID_user + LEFT JOIN Messages m ON u.UUID_User = m.user_id + LEFT JOIN Charities c ON m.sender_charity_id = c.UUID_charities + LEFT JOIN CharityVanity cv ON c.UUID_charities = cv.UUID_charity + WHERE u.UUID_User = ?; + """; + PreparedStatement stmt = conn.prepareStatement(sql_query); + stmt.setString(1, user_id); + ResultSet rs = stmt.executeQuery(); + + String lastUserid = null; + HashSet addedMessageIds = new HashSet<>(); + while (rs.next()) { + String userId = rs.getString("UUID_User"); + if (lastUserid == null || !userId.equals(lastUserid)) { + user = + new User( + userId, + rs.getString("user_name"), + rs.getString("user_email"), + rs.getString("user_password"), + rs.getString("role")); + if (rs.getString("isAnonymous") != null) { + Settings settings = + new Settings( + rs.getBoolean("isAnonymous"), + Language.valueOf(rs.getString("language").toUpperCase()), + rs.getBoolean("lightmode")); + user.setSettings(settings); + } + user.setInbox(new Inbox()); + lastUserid = userId; + } + String messageId = rs.getString("UUID_message"); + if (messageId != null && !addedMessageIds.contains(messageId)) { + addedMessageIds.add(messageId); + Charity fromCharity = null; + String charityId = rs.getString("UUID_charities"); + if (charityId != null) { + fromCharity = new Charity( + charityId, + rs.getString("org_number"), + rs.getString("charity_name"), + rs.getString("charity_link"), + rs.getString("status"), + rs.getBoolean("pre_approved"), + rs.getString("description"), + rs.getString("logoURL"), + rs.getString("key_values"), + rs.getBytes("logoBLOB") + ); + } + + if (fromCharity != null) { + Message message = new Message( + rs.getString("message_title"), + fromCharity, + rs.getString("message_content"), + LocalDate.parse(rs.getString("message_date")) + ); + user.getInbox().addMessage(message); + } + } + } + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("ERROR: Something went wrong during updating charities table."); + } finally { + conn = null; + } + return user; + } + /** + * Retrieves a single {@link User} from the database matching the given username and password. + * + *

The password is hashed via {@link PasswordHasher} before being compared against the stored + * value. If a matching user is found, their {@link Settings} (when present) and {@link Inbox} + * (including any {@link Message} objects) are also populated. Returns {@code null} if no matching + * user is found. + * + *

Note: the current SQL query compares both parameters against {@code + * user_password}; the {@code user_name} column is not yet included in the WHERE clause, which may + * be a bug. + * + * @param email the email to look up + * @param password the plain-text password; hashed internally before the query runs + * @return the matching {@link User} with settings and inbox populated, or {@code null} if no + * match is found + * @throws RuntimeException if a {@link SQLException} occurs while executing the query + */ + public User getUserFromDBEmailAndPassword(String email, String password) { + PasswordHasher hasher = new PasswordHasher(); + String hashedpassword = hasher.getHashPassword(password); + + User user = null; + Connection conn = null; + try { + conn = connection.getMySqlConnection(); + String sql_query = + """ + SELECT + u.UUID_User, u.user_name, u.user_email, u.user_password, u.role, + s.UUID_user, s.isAnonymous, s.language, s.lightmode, + m.UUID_message, m.message_title, m.message_content, m.message_date, m.sender_user_id, m.sender_charity_id, m.user_id, + cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, + c.UUID_charities, c.org_number, c.pre_approved, c.status + FROM User u + LEFT JOIN Settings s ON u.UUID_User = s.UUID_user + LEFT JOIN Messages m ON u.UUID_User = m.user_id + LEFT JOIN Charities c ON m.sender_charity_id = c.UUID_charities + LEFT JOIN CharityVanity cv ON c.UUID_charities = cv.UUID_charity + WHERE u.user_email = ?; + """; + PreparedStatement stmt = conn.prepareStatement(sql_query); + stmt.setString(1, email); + + + + ResultSet rs = stmt.executeQuery(); + HashSet addedMessageIds = new HashSet<>(); + while (rs.next()) { + String userId = rs.getString("UUID_User"); + System.out.println(rs.getString("user_name")); + + if (user == null) { + String storedHash = rs.getString("user_password"); + + if (!new PasswordHasher().isValidPassword(password, storedHash)){ + return null; + } + user = + new User( + userId, + rs.getString("user_name"), + rs.getString("user_email"), + rs.getString("user_password"), + rs.getString("role")); + if (rs.getString("isAnonymous") != null) { + Settings settings = + new Settings( + rs.getBoolean("isAnonymous"), + Language.valueOf(rs.getString("language").toUpperCase()), + rs.getBoolean("lightmode")); + user.setSettings(settings); + } + user.setInbox(new Inbox()); + } + String messageId = rs.getString("UUID_message"); + if (messageId != null && !addedMessageIds.contains(messageId)) { + addedMessageIds.add(messageId); + Charity fromCharity = null; + String charityId = rs.getString("UUID_charities"); + if (charityId != null) { + fromCharity = new Charity( + charityId, + rs.getString("org_number"), + rs.getString("charity_name"), + rs.getString("charity_link"), + rs.getString("status"), + rs.getBoolean("pre_approved"), + rs.getString("description"), + rs.getString("logoURL"), + rs.getString("key_values"), + rs.getBytes("logoBLOB") + ); + } + + if (fromCharity != null) { + Message message = new Message( + rs.getString("message_title"), + fromCharity, + rs.getString("message_content"), + LocalDate.parse(rs.getString("message_date")) + ); + user.getInbox().addMessage(message); + } + } + } + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("ERROR: Something went wrong during updating charities table."); + } finally { + conn = null; + } + return user; + } + + /** + * Retrieves all users from the database, each fully populated with their {@link Settings} and + * {@link Inbox}. + * + *

The query LEFT JOINs {@code User}, {@code Settings}, and {@code Messages}. Multiple rows for + * the same user UUID (due to multiple messages) are collapsed into a single {@link User} object + * with all messages appended to its inbox. + * + * @return a {@link UserRegistry} containing all users found in the database; never {@code null}, + * but may be empty if no users exist + * @throws RuntimeException if a {@link SQLException} occurs while executing the query + */ + public UserRegistry getUsersFromDB() { + UserRegistry registry = new UserRegistry(); + Connection conn = null; + try { + conn = connection.getMySqlConnection(); + String sql_query = + """ + SELECT + u.UUID_User, u.user_name, u.user_email, u.user_password, u.role, + s.UUID_user, s.isAnonymous, s.language, s.lightmode, + m.UUID_message, m.message_title, m.message_content, m.message_date, m.sender_user_id, m.sender_charity_id, m.user_id, + cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, + c.UUID_charities, c.org_number, c.pre_approved, c.status + FROM User u + LEFT JOIN Settings s ON u.UUID_User = s.UUID_user + LEFT JOIN Messages m ON u.UUID_User = m.user_id + LEFT JOIN Charities c ON m.sender_charity_id = c.UUID_charities + LEFT JOIN CharityVanity cv ON c.UUID_charities = cv.UUID_charity + """; + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql_query); + + User currentUser = null; + String lastUserid = null; + HashSet addedMessageIds = new HashSet<>(); + + while (rs.next()) { + String userId = rs.getString("UUID_User"); + + if (lastUserid == null || !userId.equals(lastUserid)) { + currentUser = + new User( + userId, + rs.getString("user_name"), + rs.getString("user_email"), + rs.getString("user_password"), + rs.getString("role")); + if (rs.getString("isAnonymous") != null) { + Settings settings = + new Settings( + rs.getBoolean("isAnonymous"), + Language.valueOf(rs.getString("language").toUpperCase()), + rs.getBoolean("lightmode")); + currentUser.setSettings(settings); + } + currentUser.setInbox(new Inbox()); + registry.addUser(currentUser); + lastUserid = userId; + } + String messageId = rs.getString("UUID_message"); + if (messageId != null && !addedMessageIds.contains(messageId)) { + addedMessageIds.add(messageId); + Charity fromCharity = null; + String charityId = rs.getString("UUID_charities"); + if (charityId != null) { + fromCharity = new Charity( + charityId, + rs.getString("org_number"), + rs.getString("charity_name"), + rs.getString("charity_link"), + rs.getString("status"), + rs.getBoolean("pre_approved"), + rs.getString("description"), + rs.getString("logoURL"), + rs.getString("key_values"), + rs.getBytes("logoBLOB") + ); + } + + if (fromCharity != null) { + Message message = new Message( + rs.getString("message_title"), + fromCharity, + rs.getString("message_content"), + LocalDate.parse(rs.getString("message_date")) + ); + currentUser.getInbox().addMessage(message); + } + } + } + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("ERROR: Something went wrong during updating charities table."); + } finally { + conn = null; + } + return registry; + } + + /** + * Retrieves the {@link Inbox} for a specific user by their UUID, populated with all of their + * {@link Message} objects. + * + *

Returns an empty {@link Inbox} (never {@code null}) if no messages exist for the given user. + * + * @param user_id the UUID string of the user whose inbox should be retrieved; must not be {@code + * null} + * @return an {@link Inbox} containing all messages for the user; empty if no messages are found + * @throws RuntimeException if a {@link SQLException} occurs while executing the query + */ + public Inbox getInboxForUser(String user_id) { + Inbox inbox = new Inbox(); + Connection conn = null; + try { + conn = connection.getMySqlConnection(); + String sql_query = + """ + SELECT + m.UUID_message, m.message_title, m.message_content, m.message_date, m.sender_user_id, m.sender_charity_id, m.user_id, + cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, + c.UUID_charities, c.org_number, c.pre_approved, c.status + FROM Messages m + LEFT JOIN Charities c ON m.sender_charity_id = c.UUID_charities + LEFT JOIN CharityVanity cv ON c.UUID_charities = cv.UUID_charity + WHERE user_id = ?; + """; + PreparedStatement stmt = conn.prepareStatement(sql_query); + stmt.setString(1, user_id); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + Charity fromCharity = null; + String charityId = rs.getString("UUID_charities"); + if (charityId != null) { + fromCharity = new Charity( + charityId, + rs.getString("org_number"), + rs.getString("charity_name"), + rs.getString("charity_link"), + rs.getString("status"), + rs.getBoolean("pre_approved"), + rs.getString("description"), + rs.getString("logoURL"), + rs.getString("key_values"), + rs.getBytes("logoBLOB") + ); + } + + if (fromCharity != null) { + Message message = new Message( + rs.getString("message_title"), + fromCharity, + rs.getString("message_content"), + LocalDate.parse(rs.getString("message_date")) + ); + inbox.addMessage(message); + } + } + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("ERROR: Something went wrong during updating charities table."); + } finally { + conn = null; + } + return inbox; + } + + /** + * Retrieves the {@link Settings} for a specific user by their UUID. + * + *

At most one row is fetched (via {@code setMaxRows(1)}). Returns {@code null} if no settings + * row exists for the given user. + * + * @param user_id the UUID string of the user whose settings should be retrieved; must not be + * {@code null} + * @return the user's {@link Settings}, or {@code null} if none are found + * @throws RuntimeException if a {@link SQLException} occurs while executing the query + */ + public Settings getSettingsForUser(String user_id) { + Settings settings = null; + Connection conn = null; + try { + conn = connection.getMySqlConnection(); + String sql_query = + """ + SELECT UUID_user, isAnonymous, language, lightmode FROM Settings + WHERE UUID_user = ?; + """; + PreparedStatement stmt = conn.prepareStatement(sql_query); + stmt.setString(1, user_id); + stmt.setMaxRows(1); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + settings = + new Settings( + rs.getBoolean("isAnonymous"), + Language.valueOf(rs.getString("language").toUpperCase()), + rs.getBoolean("lightmode")); + } + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("ERROR: Something went wrong during updating charities table."); + } finally { + conn = null; + } + + return settings; + } /** * Gets the user and settings information and sends it to the database through MySQL. * diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/Readers/UserSelect.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/Readers/UserSelect.java deleted file mode 100644 index bc5da17..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/Readers/UserSelect.java +++ /dev/null @@ -1,551 +0,0 @@ -package ntnu.systemutvikling.team6.database.Readers; - -import java.sql.*; -import java.time.LocalDate; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import ntnu.systemutvikling.team6.database.DatabaseConnection; -import ntnu.systemutvikling.team6.models.Charity; -import ntnu.systemutvikling.team6.models.Feedback; -import ntnu.systemutvikling.team6.models.registry.CharityRegistry; -import ntnu.systemutvikling.team6.models.registry.UserRegistry; -import ntnu.systemutvikling.team6.models.user.*; -import ntnu.systemutvikling.team6.security.PasswordHasher; - -/** - * Data access class responsible for reading user-related data from the database. - * - *

Provides methods to retrieve individual users (by credentials or UUID), all users, a user's - * settings, and a user's inbox. Queries use LEFT JOINs across the {@code User}, {@code Settings}, - * and {@code Messages} tables to assemble fully populated {@link User} objects in a single round - * trip where possible. - */ -public class UserSelect { - /** The database connection used for all queries in this class. */ - private final DatabaseConnection connection; - - /** - * Constructs a new {@code UserSelect} with the given database connection. - * - * @param connection the {@link DatabaseConnection} to use for executing queries; must not be - * {@code null} - */ - public UserSelect(DatabaseConnection connection) { - this.connection = connection; - } - - public boolean isEmailTaken(String email){ - if (email == null || email.isBlank() || !email.contains("@") || !email.contains(".")) { - throw new IllegalArgumentException( - "Email cannot be null or blank," + " and must contain '@' and '.'"); - } - try (Connection conn = connection.getMySqlConnection()) { - - String mysql = - """ - SELECT UUID_User FROM User WHERE user_email = ? - """; - PreparedStatement statement = conn.prepareStatement(mysql); - statement.setString(1, email); - ResultSet rs = statement.executeQuery(); - - if (rs.next()) { - System.out.println("Email Taken already"); - return true; - } - - } catch (SQLException e) { - e.printStackTrace(); - } - return false; - } - - public Charity getUserCharityUser(String uuid){ - if (uuid == null || uuid.isBlank()) { - throw new IllegalArgumentException( - "UUID cannot be null or blank"); - } - Charity currentCharity = null; - Connection conn = null; - try { - conn = connection.getMySqlConnection(); - String sql_query = - """ - SELECT - c.UUID_charities, c.org_number, c.pre_approved, c.status, - cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, - cat.category - FROM CharityUsers cu - INNER JOIN Charities c ON c.UUID_charities = cu.TheCharity - INNER JOIN CharityVanity cv ON cv.UUID_charity = c.UUID_charities - LEFT JOIN Charity_Categories cc ON cc.Charities_UUID_charities = c.UUID_charities - LEFT JOIN Categories cat ON cat.category_id = cc.Categories_category_id - WHERE CharityUserId = ? - """; - PreparedStatement stmt = conn.prepareStatement(sql_query); - stmt.setString(1, uuid); - ResultSet rs = stmt.executeQuery(); - - String lastCharity = null; - - while (rs.next()) { - String currentId = rs.getString("UUID_charities"); - if (lastCharity == null || !currentId.equals(lastCharity)) { - currentCharity = - new Charity( - rs.getString("UUID_charities"), - rs.getString("org_number"), - rs.getString("charity_name"), - rs.getString("charity_link"), - rs.getString("status"), - rs.getBoolean("pre_approved"), - rs.getString("description"), - rs.getString("logoURL"), - rs.getString("key_values"), - rs.getBytes("logoBLOB")); - lastCharity = currentId; - } - - String categoryName = rs.getString("category"); - if (categoryName != null && !currentCharity.getCategory().contains(categoryName)) { - currentCharity.getCategory().add(categoryName); - } - } - - } catch (SQLException e) { - e.printStackTrace(); - throw new RuntimeException("ERROR: Something went wrong during updating charities table."); - } - return currentCharity; - } - - - /** - * Retrieves a single {@link User} from the database matching the given username and password. - * - *

The password is hashed via {@link PasswordHasher} before being compared against the stored - * value. If a matching user is found, their {@link Settings} (when present) and {@link Inbox} - * (including any {@link Message} objects) are also populated. Returns {@code null} if no matching - * user is found. - * - *

Note: the current SQL query compares both parameters against {@code - * user_password}; the {@code user_name} column is not yet included in the WHERE clause, which may - * be a bug. - * - * @param email the email to look up - * @param password the plain-text password; hashed internally before the query runs - * @return the matching {@link User} with settings and inbox populated, or {@code null} if no - * match is found - * @throws RuntimeException if a {@link SQLException} occurs while executing the query - */ - public User getUserFromDBEmailAndPassword(String email, String password) { - PasswordHasher hasher = new PasswordHasher(); - String hashedpassword = hasher.getHashPassword(password); - - User user = null; - Connection conn = null; - try { - conn = connection.getMySqlConnection(); - String sql_query = - """ - SELECT - u.UUID_User, u.user_name, u.user_email, u.user_password, u.role, - s.UUID_user, s.isAnonymous, s.language, s.lightmode, - m.UUID_message, m.message_title, m.message_content, m.message_date, m.sender_user_id, m.sender_charity_id, m.user_id, - cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, - c.UUID_charities, c.org_number, c.pre_approved, c.status - FROM User u - LEFT JOIN Settings s ON u.UUID_User = s.UUID_user - LEFT JOIN Messages m ON u.UUID_User = m.user_id - LEFT JOIN Charities c ON m.sender_charity_id = c.UUID_charities - LEFT JOIN CharityVanity cv ON c.UUID_charities = cv.UUID_charity - WHERE u.user_email = ?; - """; - PreparedStatement stmt = conn.prepareStatement(sql_query); - stmt.setString(1, email); - - - - ResultSet rs = stmt.executeQuery(); - HashSet addedMessageIds = new HashSet<>(); - while (rs.next()) { - String userId = rs.getString("UUID_User"); - System.out.println(rs.getString("user_name")); - - if (user == null) { - String storedHash = rs.getString("user_password"); - - if (!new PasswordHasher().isValidPassword(password, storedHash)){ - return null; - } - user = - new User( - userId, - rs.getString("user_name"), - rs.getString("user_email"), - rs.getString("user_password"), - rs.getString("role")); - if (rs.getString("isAnonymous") != null) { - Settings settings = - new Settings( - rs.getBoolean("isAnonymous"), - Language.valueOf(rs.getString("language").toUpperCase()), - rs.getBoolean("lightmode")); - user.setSettings(settings); - } - user.setInbox(new Inbox()); - } - String messageId = rs.getString("UUID_message"); - if (messageId != null && !addedMessageIds.contains(messageId)) { - addedMessageIds.add(messageId); - Charity fromCharity = null; - String charityId = rs.getString("UUID_charities"); - if (charityId != null) { - fromCharity = new Charity( - charityId, - rs.getString("org_number"), - rs.getString("charity_name"), - rs.getString("charity_link"), - rs.getString("status"), - rs.getBoolean("pre_approved"), - rs.getString("description"), - rs.getString("logoURL"), - rs.getString("key_values"), - rs.getBytes("logoBLOB") - ); - } - - if (fromCharity != null) { - Message message = new Message( - rs.getString("message_title"), - fromCharity, - rs.getString("message_content"), - LocalDate.parse(rs.getString("message_date")) - ); - user.getInbox().addMessage(message); - } - } - } - } catch (SQLException e) { - e.printStackTrace(); - throw new RuntimeException("ERROR: Something went wrong during updating charities table."); - } finally { - conn = null; - } - return user; - } - - /** - * Retrieves a single {@link User} from the database by their UUID. - * - *

The returned user is fully populated with {@link Settings} (when present) and an {@link - * Inbox} containing any associated {@link Message} objects. Returns {@code null} if no user with - * the given UUID exists. - * - * @param user_id the UUID string of the user to retrieve; must not be {@code null} - * @return the matching {@link User} with settings and inbox populated, or {@code null} if no user - * is found - * @throws RuntimeException if a {@link SQLException} occurs while executing the query - */ - public User getUserFromDBUuid(String user_id) { - User user = null; - Connection conn = null; - try { - conn = connection.getMySqlConnection(); - String sql_query = - """ - SELECT - u.UUID_User, u.user_name, u.user_email, u.user_password, u.role, - s.UUID_user, s.isAnonymous, s.language, s.lightmode, - m.UUID_message, m.message_title, m.message_content, m.message_date, m.sender_user_id, m.sender_charity_id, m.user_id, - cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, - c.UUID_charities, c.org_number, c.pre_approved, c.status - FROM User u - LEFT JOIN Settings s ON u.UUID_User = s.UUID_user - LEFT JOIN Messages m ON u.UUID_User = m.user_id - LEFT JOIN Charities c ON m.sender_charity_id = c.UUID_charities - LEFT JOIN CharityVanity cv ON c.UUID_charities = cv.UUID_charity - WHERE u.UUID_User = ?; - """; - PreparedStatement stmt = conn.prepareStatement(sql_query); - stmt.setString(1, user_id); - ResultSet rs = stmt.executeQuery(); - - String lastUserid = null; - HashSet addedMessageIds = new HashSet<>(); - while (rs.next()) { - String userId = rs.getString("UUID_User"); - if (lastUserid == null || !userId.equals(lastUserid)) { - user = - new User( - userId, - rs.getString("user_name"), - rs.getString("user_email"), - rs.getString("user_password"), - rs.getString("role")); - if (rs.getString("isAnonymous") != null) { - Settings settings = - new Settings( - rs.getBoolean("isAnonymous"), - Language.valueOf(rs.getString("language").toUpperCase()), - rs.getBoolean("lightmode")); - user.setSettings(settings); - } - user.setInbox(new Inbox()); - lastUserid = userId; - } - String messageId = rs.getString("UUID_message"); - if (messageId != null && !addedMessageIds.contains(messageId)) { - addedMessageIds.add(messageId); - Charity fromCharity = null; - String charityId = rs.getString("UUID_charities"); - if (charityId != null) { - fromCharity = new Charity( - charityId, - rs.getString("org_number"), - rs.getString("charity_name"), - rs.getString("charity_link"), - rs.getString("status"), - rs.getBoolean("pre_approved"), - rs.getString("description"), - rs.getString("logoURL"), - rs.getString("key_values"), - rs.getBytes("logoBLOB") - ); - } - - if (fromCharity != null) { - Message message = new Message( - rs.getString("message_title"), - fromCharity, - rs.getString("message_content"), - LocalDate.parse(rs.getString("message_date")) - ); - user.getInbox().addMessage(message); - } - } - } - } catch (SQLException e) { - e.printStackTrace(); - throw new RuntimeException("ERROR: Something went wrong during updating charities table."); - } finally { - conn = null; - } - return user; - } - - /** - * Retrieves all users from the database, each fully populated with their {@link Settings} and - * {@link Inbox}. - * - *

The query LEFT JOINs {@code User}, {@code Settings}, and {@code Messages}. Multiple rows for - * the same user UUID (due to multiple messages) are collapsed into a single {@link User} object - * with all messages appended to its inbox. - * - * @return a {@link UserRegistry} containing all users found in the database; never {@code null}, - * but may be empty if no users exist - * @throws RuntimeException if a {@link SQLException} occurs while executing the query - */ - public UserRegistry getUsersFromDB() { - UserRegistry registry = new UserRegistry(); - Connection conn = null; - try { - conn = connection.getMySqlConnection(); - String sql_query = - """ - SELECT - u.UUID_User, u.user_name, u.user_email, u.user_password, u.role, - s.UUID_user, s.isAnonymous, s.language, s.lightmode, - m.UUID_message, m.message_title, m.message_content, m.message_date, m.sender_user_id, m.sender_charity_id, m.user_id, - cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, - c.UUID_charities, c.org_number, c.pre_approved, c.status - FROM User u - LEFT JOIN Settings s ON u.UUID_User = s.UUID_user - LEFT JOIN Messages m ON u.UUID_User = m.user_id - LEFT JOIN Charities c ON m.sender_charity_id = c.UUID_charities - LEFT JOIN CharityVanity cv ON c.UUID_charities = cv.UUID_charity - """; - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql_query); - - User currentUser = null; - String lastUserid = null; - HashSet addedMessageIds = new HashSet<>(); - - while (rs.next()) { - String userId = rs.getString("UUID_User"); - - if (lastUserid == null || !userId.equals(lastUserid)) { - currentUser = - new User( - userId, - rs.getString("user_name"), - rs.getString("user_email"), - rs.getString("user_password"), - rs.getString("role")); - if (rs.getString("isAnonymous") != null) { - Settings settings = - new Settings( - rs.getBoolean("isAnonymous"), - Language.valueOf(rs.getString("language").toUpperCase()), - rs.getBoolean("lightmode")); - currentUser.setSettings(settings); - } - currentUser.setInbox(new Inbox()); - registry.addUser(currentUser); - lastUserid = userId; - } - String messageId = rs.getString("UUID_message"); - if (messageId != null && !addedMessageIds.contains(messageId)) { - addedMessageIds.add(messageId); - Charity fromCharity = null; - String charityId = rs.getString("UUID_charities"); - if (charityId != null) { - fromCharity = new Charity( - charityId, - rs.getString("org_number"), - rs.getString("charity_name"), - rs.getString("charity_link"), - rs.getString("status"), - rs.getBoolean("pre_approved"), - rs.getString("description"), - rs.getString("logoURL"), - rs.getString("key_values"), - rs.getBytes("logoBLOB") - ); - } - - if (fromCharity != null) { - Message message = new Message( - rs.getString("message_title"), - fromCharity, - rs.getString("message_content"), - LocalDate.parse(rs.getString("message_date")) - ); - currentUser.getInbox().addMessage(message); - } - } - } - } catch (SQLException e) { - e.printStackTrace(); - throw new RuntimeException("ERROR: Something went wrong during updating charities table."); - } finally { - conn = null; - } - return registry; - } - - /** - * Retrieves the {@link Settings} for a specific user by their UUID. - * - *

At most one row is fetched (via {@code setMaxRows(1)}). Returns {@code null} if no settings - * row exists for the given user. - * - * @param user_id the UUID string of the user whose settings should be retrieved; must not be - * {@code null} - * @return the user's {@link Settings}, or {@code null} if none are found - * @throws RuntimeException if a {@link SQLException} occurs while executing the query - */ - public Settings getSettingsForUser(String user_id) { - Settings settings = null; - Connection conn = null; - try { - conn = connection.getMySqlConnection(); - String sql_query = - """ - SELECT UUID_user, isAnonymous, language, lightmode FROM Settings - WHERE UUID_user = ?; - """; - PreparedStatement stmt = conn.prepareStatement(sql_query); - stmt.setString(1, user_id); - stmt.setMaxRows(1); - ResultSet rs = stmt.executeQuery(); - - while (rs.next()) { - settings = - new Settings( - rs.getBoolean("isAnonymous"), - Language.valueOf(rs.getString("language").toUpperCase()), - rs.getBoolean("lightmode")); - } - } catch (SQLException e) { - e.printStackTrace(); - throw new RuntimeException("ERROR: Something went wrong during updating charities table."); - } finally { - conn = null; - } - - return settings; - } - - /** - * Retrieves the {@link Inbox} for a specific user by their UUID, populated with all of their - * {@link Message} objects. - * - *

Returns an empty {@link Inbox} (never {@code null}) if no messages exist for the given user. - * - * @param user_id the UUID string of the user whose inbox should be retrieved; must not be {@code - * null} - * @return an {@link Inbox} containing all messages for the user; empty if no messages are found - * @throws RuntimeException if a {@link SQLException} occurs while executing the query - */ - public Inbox getInboxForUser(String user_id) { - Inbox inbox = new Inbox(); - Connection conn = null; - try { - conn = connection.getMySqlConnection(); - String sql_query = - """ - SELECT - m.UUID_message, m.message_title, m.message_content, m.message_date, m.sender_user_id, m.sender_charity_id, m.user_id, - cv.charity_name, cv.charity_link, cv.description, cv.logoURL, cv.key_values, cv.logoBLOB, - c.UUID_charities, c.org_number, c.pre_approved, c.status - FROM Messages m - LEFT JOIN Charities c ON m.sender_charity_id = c.UUID_charities - LEFT JOIN CharityVanity cv ON c.UUID_charities = cv.UUID_charity - WHERE user_id = ?; - """; - PreparedStatement stmt = conn.prepareStatement(sql_query); - stmt.setString(1, user_id); - ResultSet rs = stmt.executeQuery(); - - while (rs.next()) { - Charity fromCharity = null; - String charityId = rs.getString("UUID_charities"); - if (charityId != null) { - fromCharity = new Charity( - charityId, - rs.getString("org_number"), - rs.getString("charity_name"), - rs.getString("charity_link"), - rs.getString("status"), - rs.getBoolean("pre_approved"), - rs.getString("description"), - rs.getString("logoURL"), - rs.getString("key_values"), - rs.getBytes("logoBLOB") - ); - } - - if (fromCharity != null) { - Message message = new Message( - rs.getString("message_title"), - fromCharity, - rs.getString("message_content"), - LocalDate.parse(rs.getString("message_date")) - ); - inbox.addMessage(message); - } - } - } catch (SQLException e) { - e.printStackTrace(); - throw new RuntimeException("ERROR: Something went wrong during updating charities table."); - } finally { - conn = null; - } - return inbox; - } - - -} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/AuthenticationService.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/AuthenticationService.java index 032d138..a54f9a1 100644 --- a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/AuthenticationService.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/AuthenticationService.java @@ -1,7 +1,6 @@ package ntnu.systemutvikling.team6.service; import ntnu.systemutvikling.team6.database.DAO.UserDAO; -import ntnu.systemutvikling.team6.database.Readers.UserSelect; import ntnu.systemutvikling.team6.models.Charity; import ntnu.systemutvikling.team6.models.user.Inbox; import ntnu.systemutvikling.team6.models.user.Role; @@ -18,9 +17,8 @@ */ public class AuthenticationService { /** Handles read operations for user data from the database. */ - private final UserSelect userDataReader; + private final UserDAO userDataAcsessObject; /** Handles write operations for user data to the database. */ - private final UserDAO userDataSender; /** The currently authenticated user, or {@code null} if no user is logged in. */ private User currentUser; @@ -30,12 +28,10 @@ public class AuthenticationService { /** * Constructs an {@code AuthenticationService} with the specified data access objects. * - * @param userDataReader the data reader used to query user information from the database - * @param userDataSender the DAO used to persist new user registrations to the database + * @param userDAO the data reader used to query user information from the database */ - public AuthenticationService(UserSelect userDataReader, UserDAO userDataSender) { - this.userDataReader = userDataReader; - this.userDataSender = userDataSender; + public AuthenticationService(UserDAO userDAO) { + this.userDataAcsessObject = userDAO; } /** @@ -50,11 +46,11 @@ public AuthenticationService(UserSelect userDataReader, UserDAO userDataSender) * @return {@code true} if authentication was successful; {@code false} otherwise */ public boolean login(String email, String password){ - User user = userDataReader.getUserFromDBEmailAndPassword(email, password); + User user = userDataAcsessObject.getUserFromDBEmailAndPassword(email, password); if (user != null){ currentUser = user; - isCharityUser = userDataReader.getUserCharityUser(currentUser.getId().toString()); + isCharityUser = userDataAcsessObject.getUserCharityUser(currentUser.getId().toString()); if (isCharityUser != null){ currentUser.setRole(Role.CHARITY_USER); } @@ -83,11 +79,11 @@ public boolean login(String email, String password){ public boolean register(String username, String email, String password ){ User newUser = new User(username, email, password, Role.NORMAL_USER, new Settings(), new Inbox()); - if(userDataReader.isEmailTaken(email)){ + if(userDataAcsessObject.isEmailTaken(email)){ throw new IllegalArgumentException("Email already taken"); } - boolean success = userDataSender.registerUser(newUser); + boolean success = userDataAcsessObject.registerUser(newUser); if (success){ // currentUser = newUser; diff --git a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/database/Readers/CharitySelectTest.java b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/database/Readers/CharitySelectTest.java index e338b49..0a4c791 100644 --- a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/database/Readers/CharitySelectTest.java +++ b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/database/Readers/CharitySelectTest.java @@ -270,7 +270,6 @@ void getFeedbackforCharityUUID_oneRow_returnsSingleFeedback() throws Exception { Feedback feedback = result.get(0); assertEquals(feedback1Id, feedback.getFeedbackId().toString()); assertEquals("Very helpful!", feedback.getComment()); - assertEquals("Bob", feedback.getUser().getDisplayName()); } @Test