From 7853a1911ea112aab581bdbb1370ced965541b95 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 11:19:30 +0200 Subject: [PATCH 01/18] Adapt database structure for UserMessages extension --- database_structure.sql | 14 +++++++++++++- .../model/persistentmodel/DatabaseConnection.java | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/database_structure.sql b/database_structure.sql index 8c1dcf7..b28884d 100644 --- a/database_structure.sql +++ b/database_structure.sql @@ -5,7 +5,8 @@ CREATE TABLE IF NOT EXISTS User_Table( highest_category_id BIGINT, highest_category_rule_id BIGINT, highest_saving_goal_id BIGINT, - highest_payment_request_id BIGINT + highest_payment_request_id BIGINT, + highest_user_message_id BIGINT ); CREATE TABLE IF NOT EXISTS Transaction_Table( @@ -86,3 +87,14 @@ CREATE TABLE IF NOT EXISTS Payment_Request_Transaction( PRIMARY KEY(user_id, payment_request_id, transaction_id) ); +CREATE TABLE IF NOT EXISTS User_Message( + user_id INTEGER, + user_message_id BIGINT, + message TEXT, + date DATETIME, + read BOOLEAN, + type TEXT, + FOREIGN KEY(user_id) REFERENCES User_Table(user_id), + PRIMARY KEY(user_id, user_message_id) +); + diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/DatabaseConnection.java b/src/main/java/nl/utwente/ing/model/persistentmodel/DatabaseConnection.java index d866e74..da4031a 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/DatabaseConnection.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/DatabaseConnection.java @@ -54,8 +54,9 @@ private static void createTables() { " highest_category_id BIGINT,\n" + " highest_category_rule_id BIGINT,\n" + " highest_saving_goal_id BIGINT,\n" + - " highest_payment_request_id BIGINT\n" + - ");" + " highest_payment_request_id BIGINT,\n" + + " highest_user_message_id BIGINT\n" + + ");;" ); statement.executeUpdate( "CREATE TABLE IF NOT EXISTS Transaction_Table(\n" + @@ -136,6 +137,16 @@ private static void createTables() { " FOREIGN KEY(transaction_id) REFERENCES Transaction_Table(transaction_id),\n" + " PRIMARY KEY(user_id, payment_request_id, transaction_id)\n" + ");"); + statement.executeUpdate("CREATE TABLE IF NOT EXISTS User_Message(\n" + + " user_id INTEGER,\n" + + " user_message_id BIGINT,\n" + + " message TEXT,\n" + + " date DATETIME,\n" + + " read BOOLEAN,\n" + + " type TEXT,\n" + + " FOREIGN KEY(user_id) REFERENCES User_Table(user_id),\n" + + " PRIMARY KEY(user_id, user_message_id)\n" + + ");"); statement.close(); connection.setAutoCommit(true); } catch (SQLException e) { From a7f14b31e1b7bfb4eb248180e4b1afff13bba960 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 11:19:51 +0200 Subject: [PATCH 02/18] Write new queries for UserMessages extension --- sql_queries_and_updates.txt | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/sql_queries_and_updates.txt b/sql_queries_and_updates.txt index 9505be3..b01307f 100644 --- a/sql_queries_and_updates.txt +++ b/sql_queries_and_updates.txt @@ -243,6 +243,38 @@ AND pr.payment_request_id = ?; INSERT INTO Payment_Request_Transaction (user_id, transaction_id, payment_request_id) VALUES (?, ?, ?); + increaseHighestUserMessageID(user_id): +UPDATE User_Table +SET highest_user_message_id = highest_user_message_id + 1 +WHERE user_id = ?; + + getHighestUserMessageID(user_id): +SELECT highest_user_message_id +FROM User_Table +WHERE user_id = ?; + + getUserMessage(user_id, user_message_id): +SELECT user_message_id, message, date, read, type +FROM User_Message +WHERE user_id = ? +AND user_message_id = ?; + + createUserMessage(user_id, user_message_id, message, date, type): +INSERT INTO User_Message (user_id, user_message_id, message, date, read, type) +VALUES (?, ?, ?, ?, 0, ?); + + getUnreadUserMessages(user_id): +SELECT user_message_id, message, date, read, type +FROM User_Message +WHERE user_id = ? +AND read = 0; + + setUserMessageRead(user_id, user_message_id): +UPDATE User_Message +SET read = 1 +WHERE user_id = ? +AND user_message_id = ?; + linkTransactionToCategory(user_id, transaction_id, category_id): INSERT INTO Transaction_Category (user_id, transaction_id, category_id) VALUES (?, ?, ?); @@ -272,10 +304,11 @@ AND t.user_id = ? AND t.transaction_id = ?; createNewUser(session_id): -INSERT INTO User_Table (session_id, highest_transaction_id, highest_category_id, highest_category_rule_id, highest_saving_goal_id, highest_payment_request_id) -VALUES (?, 0, 0, 0, 0, 0); +INSERT INTO User_Table (session_id, highest_transaction_id, highest_category_id, highest_category_rule_id, highest_saving_goal_id, highest_payment_request_id, highest_user_message_id) +VALUES (?, 0, 0, 0, 0, 0, 0); getUserID(session_id): SELECT user_id FROM User_Table WHERE session_id = ?; + From 4129b7e8421c79301a74e542f7e922415d8cce65 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 11:20:15 +0200 Subject: [PATCH 03/18] Create UserMessage bean --- .../utwente/ing/model/bean/UserMessage.java | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/main/java/nl/utwente/ing/model/bean/UserMessage.java diff --git a/src/main/java/nl/utwente/ing/model/bean/UserMessage.java b/src/main/java/nl/utwente/ing/model/bean/UserMessage.java new file mode 100644 index 0000000..9e1daf8 --- /dev/null +++ b/src/main/java/nl/utwente/ing/model/bean/UserMessage.java @@ -0,0 +1,132 @@ +package nl.utwente.ing.model.bean; + +/** + * The UserMessage class. + * Used to store information about a UserMessage. + * + * @author Daan Kooij + */ +public class UserMessage { + + private long id; + private String message; + private String date; + private boolean read; + private String type; + + /** + * An empty constructor of PaymentRequest. + * Used by the Spring framework. + */ + public UserMessage() { + + } + + /** + * A constructor of UserMessage. + * + * @param id The ID of the to be created UserMessage. + * @param message The message of the to be created UserMessage. + * @param date The date of the to be created UserMessage. + * @param read The boolean indicating whether the to be created UserMessage is read. + * @param type The type of the to be created UserMessage. + */ + public UserMessage(long id, String message, String date, boolean read, String type) { + this.id = id; + this.message = message; + this.date = date; + this.read = read; + this.type = type; + } + + /** + * Method used to retrieve the ID of UserMessage. + * + * @return The ID of UserMessage. + */ + public long getID() { + return id; + } + + /** + * Method used to update the ID of UserMessage. + * + * @param id The new ID of UserMessage. + */ + public void setID(long id) { + this.id = id; + } + + /** + * Method used to retrieve the message of UserMessage. + * + * @return The message of UserMessage. + */ + public String getMessage() { + return message; + } + + /** + * Method used to update the message of UserMessage. + * + * @param message The new message of UserMessage. + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * Method used to retrieve the date of UserMessage. + * + * @return The date of UserMessage. + */ + public String getDate() { + return date; + } + + /** + * Method used to update the date of UserMessage. + * + * @param date The new date of UserMessage. + */ + public void setDate(String date) { + this.date = date; + } + + /** + * Method used to retrieve the boolean indicating whether UserMessage is read. + * + * @return The boolean indicating whether UserMessage is read. + */ + public boolean getRead() { + return read; + } + + /** + * Method used to update the boolean indicating whether UserMessage is read. + * + * @param read The new boolean indicating whether UserMessage is read. + */ + public void setRead(boolean read) { + this.read = read; + } + + /** + * Method used to retrieve the type of UserMessage. + * + * @return The ID of UserMessage. + */ + public String getType() { + return type; + } + + /** + * Method used to update the type of UserMessage. + * + * @param type The new type of UserMessage. + */ + public void setType(String type) { + this.type = type; + } + +} From eb47b8aa332364f28b3a9a6836d731fe8db5d8a2 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 11:20:41 +0200 Subject: [PATCH 04/18] Adapt CustomORM for UserMessages extension --- .../ing/model/persistentmodel/CustomORM.java | 161 +++++++++++++++++- .../persistentmodel/PersistentModel.java | 4 +- 2 files changed, 159 insertions(+), 6 deletions(-) diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java b/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java index 2e0a8fc..99d5e18 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java @@ -224,6 +224,32 @@ public class CustomORM { public static final String LINK_TRANSACTION_TO_PAYMENT_REQUEST = "INSERT INTO Payment_Request_Transaction (user_id, transaction_id, payment_request_id)\n" + "VALUES (?, ?, ?);"; + public static final String INCREASE_HIGHEST_USER_MESSAGE_ID = + "UPDATE User_Table\n" + + "SET highest_user_message_id = highest_user_message_id + 1\n" + + "WHERE user_id = ?;\n"; + public static final String GET_HIGHEST_USER_MESSAGE_ID = + "SELECT highest_user_message_id\n" + + "FROM User_Table\n" + + "WHERE user_id = ?;"; + public static final String GET_USER_MESSAGE = + "SELECT user_message_id, message, date, read, type\n" + + "FROM User_Message\n" + + "WHERE user_id = ?\n" + + "AND user_message_id = ?;"; + public static final String CREATE_USER_MESSAGE = + "INSERT INTO User_Message (user_id, user_message_id, message, date, read, type)\n" + + "VALUES (?, ?, ?, ?, 0, ?);"; + public static final String GET_UNREAD_USER_MESSAGES = + "SELECT user_message_id, message, date, read, type\n" + + "FROM User_Message\n" + + "WHERE user_id = ?\n" + + "AND read = 0;"; + public static final String SET_USER_MESSAGE_READ = + "UPDATE User_Message\n" + + "SET read = 1\n" + + "WHERE user_id = ?\n" + + "AND user_message_id = ?;"; private static final String LINK_TRANSACTION_TO_CATEGORY = "INSERT INTO Transaction_Category (user_id, transaction_id, category_id)\n" + "VALUES (?, ?, ?);"; @@ -248,9 +274,9 @@ public class CustomORM { "AND t.user_id = ?\n" + "AND t.transaction_id = ?;"; private static final String CREATE_NEW_USER = - "INSERT INTO User_Table (session_id, highest_transaction_id, highest_category_id, " + - "highest_category_rule_id, highest_saving_goal_id, highest_payment_request_id)\n" + - "VALUES (?, 0, 0, 0, 0, 0);"; + "INSERT INTO User_Table (session_id, highest_transaction_id, highest_category_id, highest_category_rule_id, " + + "highest_saving_goal_id, highest_payment_request_id, highest_user_message_id)\n" + + "VALUES (?, 0, 0, 0, 0, 0, 0);"; private static final String GET_USER_ID = "SELECT user_id\n" + "FROM User_Table\n" + @@ -1132,7 +1158,7 @@ public PaymentRequest getPaymentRequest(int userID, long paymentRequestID) { * @param userID The ID of the user to who the to be retrieved PaymentRequest objects belong. * @return An ArrayList of PaymentRequest objects. */ - public ArrayList getPaymentRequest(int userID) { + public ArrayList getPaymentRequests(int userID) { ArrayList paymentRequests = new ArrayList<>(); try { PreparedStatement statement = connection.prepareStatement(GET_PAYMENT_REQUESTS); @@ -1221,6 +1247,133 @@ public void linkTransactionToPaymentRequest(int userID, long transactionID, long } } + /** + * Method used to increase the highestUserMessageID field of a certain user by one in the database. + * + * @param userID The ID of the user whose highestUserMessageID field should be increased. + */ + public void increaseHighestUserMessageID(int userID) { + try { + PreparedStatement statement = connection.prepareStatement(INCREASE_HIGHEST_USER_MESSAGE_ID); + statement.setInt(1, userID); + statement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + /** + * Method used to retrieve the highestUserMessageID field of a certain user from the database. + * + * @param userID The ID of the user whose highestUserMessageID field should be retrieved. + * @return The value of the highestUserMessageID field of the user with userID. + */ + public long getHighestUserMessageID(int userID) { + long highestUserMessageID = -1; + try { + PreparedStatement statement = connection.prepareStatement(GET_HIGHEST_USER_MESSAGE_ID); + statement.setInt(1, userID); + ResultSet rs = statement.executeQuery(); + highestUserMessageID = rs.getLong(1); + } catch (SQLException e) { + e.printStackTrace(); + } + return highestUserMessageID; + } + + /** + * Method used to insert a UserMessage into the database. + * + * @param userID The ID of the user to which this new UserMessage will belong. + * @param userMessage The UserMessage object to be inserted into the database. + */ + public void createUserMessage(int userID, UserMessage userMessage) { + try { + PreparedStatement statement = connection.prepareStatement(CREATE_USER_MESSAGE); + statement.setInt(1, userID); + statement.setLong(2, userMessage.getID()); + statement.setString(3, userMessage.getMessage()); + statement.setString(4, userMessage.getDate()); + statement.setString(5, userMessage.getType()); + statement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + /** + * Method used to retrieve a UserMessage from the database. + * + * @param userID The id of the user from which a UserMessage should be retrieved. + * @param userMessageID The id of the to be retrieved UserMessage. + * @return A UserMessage object containing data retrieved from the database. + */ + public UserMessage getUserMessage(int userID, long userMessageID) { + UserMessage userMessage = null; + try { + PreparedStatement statement = connection.prepareStatement(GET_USER_MESSAGE); + statement.setInt(1, userID); + statement.setLong(2, userMessageID); + ResultSet resultSet = statement.executeQuery(); + + if (resultSet.next()) { + userMessageID = resultSet.getLong(1); + String message = resultSet.getString(2); + String date = resultSet.getString(3); + boolean read = resultSet.getBoolean(4); + String type = resultSet.getString(5); + userMessage = new UserMessage(userMessageID, message, date, read, type); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return userMessage; + } + + /** + * Method used to retrieve a batch of unread UserMessage objects belonging to a certain user from the database. + * + * @param userID The ID of the user to who the to be retrieved UserMessage objects belong. + * @return An ArrayList of UserMessage objects. + */ + public ArrayList getUnreadUserMessages(int userID) { + ArrayList userMessages = new ArrayList<>(); + try { + PreparedStatement statement = connection.prepareStatement(GET_UNREAD_USER_MESSAGES); + statement.setInt(1, userID); + ResultSet resultSet = statement.executeQuery(); + + while (resultSet.next()) { + long userMessageID = resultSet.getLong(1); + String message = resultSet.getString(2); + String date = resultSet.getString(3); + boolean read = resultSet.getBoolean(4); + String type = resultSet.getString(5); + userMessages.add(new UserMessage(userMessageID, message, date, read, type)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return userMessages; + } + + /** + * Method used to indicate that a certain UserMessage of a certain user has been read. + * + * @param userID The ID of the user to which the certain UserMessage belongs. + * @param userMessageID The ID of the UserMessage for which it should be indicated that it is read. + */ + public void setUserMessageFilled(int userID, long userMessageID) { + try { + PreparedStatement statement = connection.prepareStatement(SET_USER_MESSAGE_READ); + statement.setInt(1, userID); + statement.setLong(2, userMessageID); + statement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + /** * Method used to link a Transaction to a Category in the database. * diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java index 40bdf3a..226d1f0 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java @@ -130,7 +130,7 @@ public Transaction postTransaction(String sessionID, String date, float amount, if (transaction.getType().equals("deposit")) { // Check if Transaction answers some Payment Request - List paymentRequests = customORM.getPaymentRequest(userID); + List paymentRequests = customORM.getPaymentRequests(userID); connection.setAutoCommit(false); for (PaymentRequest paymentRequest : paymentRequests) { if (!paymentRequest.getFilled() && transaction.getAmount() == paymentRequest.getAmount() && @@ -661,7 +661,7 @@ public void deleteSavingGoal(String sessionID, long savingGoalID) */ public ArrayList getPaymentRequests(String sessionID) throws InvalidSessionIDException { int userID = this.getUserID(sessionID); - ArrayList paymentRequests = customORM.getPaymentRequest(userID); + ArrayList paymentRequests = customORM.getPaymentRequests(userID); for (PaymentRequest paymentRequest : paymentRequests) { ArrayList transactions = customORM.getTransactionsByPaymentRequest(userID, paymentRequest.getID()); paymentRequest.setTransactions(transactions); From de81a71ea82df069bc50d93c244a4d6a644c7e07 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 11:38:07 +0200 Subject: [PATCH 05/18] Fix faulty method name in CustomORM --- .../java/nl/utwente/ing/model/persistentmodel/CustomORM.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java b/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java index 99d5e18..e0abfbc 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java @@ -1363,7 +1363,7 @@ public ArrayList getUnreadUserMessages(int userID) { * @param userID The ID of the user to which the certain UserMessage belongs. * @param userMessageID The ID of the UserMessage for which it should be indicated that it is read. */ - public void setUserMessageFilled(int userID, long userMessageID) { + public void setUserMessageRead(int userID, long userMessageID) { try { PreparedStatement statement = connection.prepareStatement(SET_USER_MESSAGE_READ); statement.setInt(1, userID); From 4f8f30afbd0b3f531e1571b12551c257b6218bf6 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 11:45:12 +0200 Subject: [PATCH 06/18] Add basic UserMessage functionality to model --- src/main/java/nl/utwente/ing/model/Model.java | 18 +++++++++++- .../persistentmodel/PersistentModel.java | 29 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/main/java/nl/utwente/ing/model/Model.java b/src/main/java/nl/utwente/ing/model/Model.java index a355a93..7027031 100644 --- a/src/main/java/nl/utwente/ing/model/Model.java +++ b/src/main/java/nl/utwente/ing/model/Model.java @@ -243,10 +243,26 @@ void deleteSavingGoal(String sessionID, long savingGoalID) /** * Method used to create a new PaymentRequest for a certain user. * - * @param sessionID The sessionID of the user. + * @param sessionID The sessionID of the user. * @param paymentRequest The PaymentRequest object to be used to create the new PaymentRequest. * @return The PaymentRequest created by this method. */ PaymentRequest postPaymentRequest(String sessionID, PaymentRequest paymentRequest) throws InvalidSessionIDException; + /** + * Method used to retrieve the unread UserMessages belonging to a certain user. + * + * @param sessionID The sessionID of the user. + * @return An ArrayList of UserMessages belonging to the user with sessionID. + */ + ArrayList getUnreadUserMessages(String sessionID) throws InvalidSessionIDException; + + /** + * Method used to indicate that a certain UserMessage of a certain user is read. + * + * @param sessionID The sessionID of the user. + * @param userMessageID The ID of the UserMessage of the certain user that should be marked as read. + */ + void setUserMessageRead(String sessionID, long userMessageID) + throws InvalidSessionIDException, ResourceNotFoundException; } diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java index 226d1f0..c34d8d8 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java @@ -707,6 +707,35 @@ public PaymentRequest postPaymentRequest(String sessionID, PaymentRequest paymen return createdPaymentRequest; } + /** + * Method used to retrieve the unread UserMessages belonging to a certain user. + * + * @param sessionID The sessionID of the user. + * @return An ArrayList of UserMessages belonging to the user with sessionID. + */ + public ArrayList getUnreadUserMessages(String sessionID) throws InvalidSessionIDException { + int userID = this.getUserID(sessionID); + return customORM.getUnreadUserMessages(userID); + } + + /** + * Method used to indicate that a certain UserMessage of a certain user is read. + * + * @param sessionID The sessionID of the user. + * @param userMessageID The ID of the UserMessage of the certain user that should be marked as read. + */ + public void setUserMessageRead(String sessionID, long userMessageID) + throws InvalidSessionIDException, ResourceNotFoundException { + int userID = this.getUserID(sessionID); + + UserMessage userMessage = customORM.getUserMessage(userID, userMessageID); + if (userMessage != null) { + customORM.setUserMessageRead(userID, userMessageID); + } else { + throw new ResourceNotFoundException(); + } + } + /** * Method used to populate a Transaction object with a Category object. * From 7c1d8dc28315b45627c4b9524bdd09fcf074e132 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 11:51:29 +0200 Subject: [PATCH 07/18] Add UserMessage functionality to MainRestController --- .../utwente/ing/api/MainRestController.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/main/java/nl/utwente/ing/api/MainRestController.java b/src/main/java/nl/utwente/ing/api/MainRestController.java index 377ffd6..e17b9df 100644 --- a/src/main/java/nl/utwente/ing/api/MainRestController.java +++ b/src/main/java/nl/utwente/ing/api/MainRestController.java @@ -720,4 +720,50 @@ public ResponseEntity postPaymentRequest(@RequestParam(value = "session_id", def } } + /** + * Method used to retrieve the unread UserMessages belonging to the user issuing the current request. + * + * @param pSessionID The sessionID specified in the request parameters. + * @param hSessionID The sessionID specified in the HTTP header. + * @return A ResponseEntity containing a HTTP status code and either a status message or + * an ArrayList of UserMessages belonging to the user issuing the current request. + */ + @RequestMapping(method = RequestMethod.GET, + value = RestControllerConstants.URI_PREFIX + "/messages") + public ResponseEntity getUnreadUserMessages(@RequestParam(value = "session_id", defaultValue = "") String pSessionID, + @RequestHeader(value = "X-session-ID", defaultValue = "") String hSessionID) { + try { + String sessionID = this.getSessionID(pSessionID, hSessionID); + ArrayList userMessages = model.getUnreadUserMessages(sessionID); + return ResponseEntity.status(200).body(userMessages); + } catch (InvalidSessionIDException e) { + return ResponseEntity.status(401).body("Session ID is missing or invalid"); + } + } + + /** + * Method used to indicate that a certain UserMessage belonging to the user issuing the current request is read. + * + * @param pSessionID The sessionID specified in the request parameters. + * @param hSessionID The sessionID specified in the HTTP header. + * @param userMessageID The userMessageID of the UserMessage for which it is indicated that it is read. + * @return A ResponseEntity containing a HTTP status code and a status message. + */ + @RequestMapping(method = RequestMethod.PUT, + value = RestControllerConstants.URI_PREFIX + "/messages/{userMessageID}") + public ResponseEntity putUserMessageRead(@RequestParam(value = "session_id", defaultValue = "") String pSessionID, + @RequestHeader(value = "X-session-ID", defaultValue = "") String hSessionID, + @PathVariable String userMessageID) { + try { + String sessionID = this.getSessionID(pSessionID, hSessionID); + long userMessageIDLong = Long.parseLong(userMessageID); + model.setUserMessageRead(sessionID, userMessageIDLong); + return ResponseEntity.status(200).body("Successful operation"); + } catch (InvalidSessionIDException e) { + return ResponseEntity.status(401).body("Session ID is missing or invalid"); + } catch (NumberFormatException | ResourceNotFoundException e) { + return ResponseEntity.status(404).body("Resource not found"); + } + } + } From e0ee4962bd619a83514d08226136aeaaac44d965 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 11:58:39 +0200 Subject: [PATCH 08/18] Add helper method to PersistentModel to emit UserMessages --- .../persistentmodel/PersistentModel.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java index c34d8d8..fd27079 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java @@ -471,9 +471,9 @@ public void deleteCategoryRule(String sessionID, long categoryRuleID) * Method used to retrieve balance history information of a certain user in the form of a list of * BalanceCandlesticks. * - * @param sessionID The sessionID of the user. + * @param sessionID The sessionID of the user. * @param intervalPeriod The IntervalPeriod specifying the span of intervals. - * @param amount The amount of intervals for which BalanceCandlesticks should be generated. + * @param amount The amount of intervals for which BalanceCandlesticks should be generated. * @return The balance history information of a certain user in the form of a list of BalanceCandlesticks. */ public ArrayList getBalanceHistory(String sessionID, IntervalPeriod intervalPeriod, int amount) @@ -676,7 +676,7 @@ public ArrayList getPaymentRequests(String sessionID) throws Inv /** * Method used to create a new PaymentRequest for a certain user. * - * @param sessionID The sessionID of the user. + * @param sessionID The sessionID of the user. * @param paymentRequest The PaymentRequest object to be used to create the new PaymentRequest. * @return The PaymentRequest created by this method. */ @@ -736,6 +736,27 @@ public void setUserMessageRead(String sessionID, long userMessageID) } } + /** + * Method used to emit a UserMessage for a certain user. + * + * @param userID The ID of the user for which the UserMessage will be emitted. + * @param type The type of the to be emitted UserMessage. + * @param message The message of the to be emitted UserMessage. + */ + private void emitUserMessage(int userID, String type, String message) { + try { + connection.setAutoCommit(false); + customORM.increaseHighestUserMessageID(userID); + long userMessageID = customORM.getHighestUserMessageID(userID); + connection.commit(); + connection.setAutoCommit(true); + String date = customORM.getCurrentDate(userID); + customORM.createUserMessage(userID, new UserMessage(userMessageID, message, date, false, type)); + } catch (SQLException e) { + e.printStackTrace(); + } + } + /** * Method used to populate a Transaction object with a Category object. * From 9cd812f847cddb22cccd0d534ecaead5e5a9fe7e Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 14:34:30 +0200 Subject: [PATCH 09/18] Add helper queries for UserMessages extension --- sql_queries_and_updates.txt | 23 +++- .../ing/model/persistentmodel/CustomORM.java | 113 ++++++++++++++++-- 2 files changed, 121 insertions(+), 15 deletions(-) diff --git a/sql_queries_and_updates.txt b/sql_queries_and_updates.txt index b01307f..9e9312f 100644 --- a/sql_queries_and_updates.txt +++ b/sql_queries_and_updates.txt @@ -269,12 +269,31 @@ FROM User_Message WHERE user_id = ? AND read = 0; + getAllUserMessages(user_id): +SELECT user_message_id, message, date, read, type +FROM User_Message +WHERE user_id = ?; + setUserMessageRead(user_id, user_message_id): UPDATE User_Message SET read = 1 WHERE user_id = ? AND user_message_id = ?; + getHighestLifetimeBalance(user_id): +SELECT highest_lifetime_balance +FROM User_Table +WHERE user_id = ?; + + updateHighestLifetimeBalance(current_balance, current_balance, user_id): +UPDATE User_Table +SET highest_lifetime_balance = + CASE WHEN ? > highest_lifetime_balance + THEN ? + ELSE highest_lifetime_balance + END +WHERE user_id = ?; + linkTransactionToCategory(user_id, transaction_id, category_id): INSERT INTO Transaction_Category (user_id, transaction_id, category_id) VALUES (?, ?, ?); @@ -304,8 +323,8 @@ AND t.user_id = ? AND t.transaction_id = ?; createNewUser(session_id): -INSERT INTO User_Table (session_id, highest_transaction_id, highest_category_id, highest_category_rule_id, highest_saving_goal_id, highest_payment_request_id, highest_user_message_id) -VALUES (?, 0, 0, 0, 0, 0, 0); +INSERT INTO User_Table (session_id, highest_lifetime_balance, highest_transaction_id, highest_category_id, highest_category_rule_id, highest_saving_goal_id, highest_payment_request_id, highest_user_message_id) +VALUES (?, 0, 0, 0, 0, 0, 0, 0); getUserID(session_id): SELECT user_id diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java b/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java index e0abfbc..fe09102 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java @@ -245,11 +245,27 @@ public class CustomORM { "FROM User_Message\n" + "WHERE user_id = ?\n" + "AND read = 0;"; + public static final String GET_ALL_USER_MESSAGES = + "SELECT user_message_id, message, date, read, type\n" + + "FROM User_Message\n" + + "WHERE user_id = ?;"; public static final String SET_USER_MESSAGE_READ = "UPDATE User_Message\n" + "SET read = 1\n" + "WHERE user_id = ?\n" + "AND user_message_id = ?;"; + public static final String GET_HIGHEST_LIFETIME_BALANCE = + "SELECT highest_lifetime_balance\n" + + "FROM User_Table\n" + + "WHERE user_id = ?;"; + public static final String UPDATE_HIGHEST_LIFETIME_BALANCE = + "UPDATE User_Table\n" + + "SET highest_lifetime_balance = \n" + + " CASE WHEN ? > highest_lifetime_balance \n" + + " THEN ? \n" + + " ELSE highest_lifetime_balance \n" + + " END\n" + + "WHERE user_id = ?;"; private static final String LINK_TRANSACTION_TO_CATEGORY = "INSERT INTO Transaction_Category (user_id, transaction_id, category_id)\n" + "VALUES (?, ?, ?);"; @@ -274,9 +290,10 @@ public class CustomORM { "AND t.user_id = ?\n" + "AND t.transaction_id = ?;"; private static final String CREATE_NEW_USER = - "INSERT INTO User_Table (session_id, highest_transaction_id, highest_category_id, highest_category_rule_id, " + - "highest_saving_goal_id, highest_payment_request_id, highest_user_message_id)\n" + - "VALUES (?, 0, 0, 0, 0, 0, 0);"; + "INSERT INTO User_Table (session_id, highest_lifetime_balance, highest_transaction_id, " + + "highest_category_id, highest_category_rule_id, highest_saving_goal_id, " + + "highest_payment_request_id, highest_user_message_id)\n" + + "VALUES (?, 0, 0, 0, 0, 0, 0, 0);"; private static final String GET_USER_ID = "SELECT user_id\n" + "FROM User_Table\n" + @@ -1102,7 +1119,7 @@ public long getHighestPaymentRequestID(int userID) { /** * Method used to insert a PaymentRequest into the database. * - * @param userID The ID of the user to which this new PaymentRequest will belong. + * @param userID The ID of the user to which this new PaymentRequest will belong. * @param paymentRequest The PaymentRequest object to be inserted into the database. */ public void createPaymentRequest(int userID, PaymentRequest paymentRequest) { @@ -1124,7 +1141,7 @@ public void createPaymentRequest(int userID, PaymentRequest paymentRequest) { /** * Method used to retrieve a PaymentRequest from the database. * - * @param userID The id of the user from which a PaymentRequest should be retrieved. + * @param userID The id of the user from which a PaymentRequest should be retrieved. * @param paymentRequestID The id of the to be retrieved PaymentRequest. * @return A PaymentRequest object containing data retrieved from the database. */ @@ -1184,7 +1201,7 @@ public ArrayList getPaymentRequests(int userID) { /** * Method used to indicate that a certain PaymentRequest of a certain user has been filled. * - * @param userID The ID of the user to which the certain PaymentRequest belongs. + * @param userID The ID of the user to which the certain PaymentRequest belongs. * @param paymentRequestID The ID of the PaymentRequest for which it should be indicated that it is filled. */ public void setPaymentRequestFilled(int userID, long paymentRequestID) { @@ -1202,7 +1219,7 @@ public void setPaymentRequestFilled(int userID, long paymentRequestID) { * Method used to retrieve a batch of Transaction objects belonging to a certain user * and fulfilling a certain PaymentRequest from the database. * - * @param userID The id of the user to who the to be retrieved Transaction objects belong. + * @param userID The id of the user to who the to be retrieved Transaction objects belong. * @param paymentRequestID The ID of the PaymentRequest to which the retrieved Transaction objects belong. * @return An ArrayList of Transaction objects. */ @@ -1231,9 +1248,9 @@ public ArrayList getTransactionsByPaymentRequest(int userID, long p /** * Method used to link a Transaction to a PaymentRequest in the database. * - * @param userID The ID of the user to who the to be linked Transaction and PaymentRequest objects belong. - * @param transactionID The ID of the Transaction that will be linked to a PaymentRequest. - * @param paymentRequestID The ID of the PaymentRequest that will be linked to a Transaction. + * @param userID The ID of the user to who the to be linked Transaction and PaymentRequest objects belong. + * @param transactionID The ID of the Transaction that will be linked to a PaymentRequest. + * @param paymentRequestID The ID of the PaymentRequest that will be linked to a Transaction. */ public void linkTransactionToPaymentRequest(int userID, long transactionID, long paymentRequestID) { try { @@ -1284,7 +1301,7 @@ public long getHighestUserMessageID(int userID) { /** * Method used to insert a UserMessage into the database. * - * @param userID The ID of the user to which this new UserMessage will belong. + * @param userID The ID of the user to which this new UserMessage will belong. * @param userMessage The UserMessage object to be inserted into the database. */ public void createUserMessage(int userID, UserMessage userMessage) { @@ -1304,7 +1321,7 @@ public void createUserMessage(int userID, UserMessage userMessage) { /** * Method used to retrieve a UserMessage from the database. * - * @param userID The id of the user from which a UserMessage should be retrieved. + * @param userID The id of the user from which a UserMessage should be retrieved. * @param userMessageID The id of the to be retrieved UserMessage. * @return A UserMessage object containing data retrieved from the database. */ @@ -1357,10 +1374,37 @@ public ArrayList getUnreadUserMessages(int userID) { return userMessages; } + /** + * Method used to retrieve a batch of UserMessage objects belonging to a certain user from the database. + * + * @param userID The ID of the user to who the to be retrieved UserMessage objects belong. + * @return An ArrayList of UserMessage objects. + */ + public ArrayList getAllUserMessages(int userID) { + ArrayList userMessages = new ArrayList<>(); + try { + PreparedStatement statement = connection.prepareStatement(GET_ALL_USER_MESSAGES); + statement.setInt(1, userID); + ResultSet resultSet = statement.executeQuery(); + + while (resultSet.next()) { + long userMessageID = resultSet.getLong(1); + String message = resultSet.getString(2); + String date = resultSet.getString(3); + boolean read = resultSet.getBoolean(4); + String type = resultSet.getString(5); + userMessages.add(new UserMessage(userMessageID, message, date, read, type)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return userMessages; + } + /** * Method used to indicate that a certain UserMessage of a certain user has been read. * - * @param userID The ID of the user to which the certain UserMessage belongs. + * @param userID The ID of the user to which the certain UserMessage belongs. * @param userMessageID The ID of the UserMessage for which it should be indicated that it is read. */ public void setUserMessageRead(int userID, long userMessageID) { @@ -1374,6 +1418,49 @@ public void setUserMessageRead(int userID, long userMessageID) { } } + /** + * Method user to retrieve the highest lifetime balance of a certain user. + * + * @param userID The ID of the user whose highest lifetime balance will be retrieved. + * @return The highest lifetime balance of the user. + */ + public float getHighestLifetimeBalance(int userID) { + float highestLifetimeBalance = 0; + + try { + PreparedStatement statement = connection.prepareStatement(GET_HIGHEST_LIFETIME_BALANCE); + statement.setInt(1, userID); + ResultSet resultSet = statement.executeQuery(); + if (resultSet.next()) { + highestLifetimeBalance = resultSet.getFloat(1); + } + } catch (SQLException e) { + e.printStackTrace(); + } + + return highestLifetimeBalance; + } + + /** + * Method used to potentially update the highest lifetime balance of a certain user. + * The highest lifetime balance of the user will only be updated if the current balance is higher than the current + * highest lifetime balance. + * + * @param userID The ID of the user whose highest lifetime balance may be updated. + * @param currentBalance The currentBalance of the user. + */ + public void updateHighestLifetimeBalance(int userID, float currentBalance) { + try { + PreparedStatement statement = connection.prepareStatement(UPDATE_HIGHEST_LIFETIME_BALANCE); + statement.setFloat(1, currentBalance); + statement.setFloat(2, currentBalance); + statement.setInt(3, userID); + statement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + /** * Method used to link a Transaction to a Category in the database. * From 29d46127c8d0f21b79f83f8c7ca8850d5ca105cc Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 14:35:46 +0200 Subject: [PATCH 10/18] Add highest_lifetime_balance field to User_Table in database --- database_structure.sql | 1 + .../utwente/ing/model/persistentmodel/DatabaseConnection.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/database_structure.sql b/database_structure.sql index b28884d..9ec7094 100644 --- a/database_structure.sql +++ b/database_structure.sql @@ -1,6 +1,7 @@ CREATE TABLE IF NOT EXISTS User_Table( user_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT, + highest_lifetime_balance FLOAT, highest_transaction_id BIGINT, highest_category_id BIGINT, highest_category_rule_id BIGINT, diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/DatabaseConnection.java b/src/main/java/nl/utwente/ing/model/persistentmodel/DatabaseConnection.java index da4031a..a26e576 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/DatabaseConnection.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/DatabaseConnection.java @@ -50,13 +50,14 @@ private static void createTables() { "CREATE TABLE IF NOT EXISTS User_Table(\n" + " user_id INTEGER PRIMARY KEY AUTOINCREMENT,\n" + " session_id TEXT,\n" + + " highest_lifetime_balance FLOAT,\n" + " highest_transaction_id BIGINT,\n" + " highest_category_id BIGINT,\n" + " highest_category_rule_id BIGINT,\n" + " highest_saving_goal_id BIGINT,\n" + " highest_payment_request_id BIGINT,\n" + " highest_user_message_id BIGINT\n" + - ");;" + ");" ); statement.executeUpdate( "CREATE TABLE IF NOT EXISTS Transaction_Table(\n" + From 87ddbcb16351396d9ea8c77d3c73f178a75d1c6b Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 14:36:33 +0200 Subject: [PATCH 11/18] Change fields that are unnecessarily public to private in CustomORM --- .../ing/model/persistentmodel/CustomORM.java | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java b/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java index fe09102..195079e 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/CustomORM.java @@ -149,70 +149,70 @@ public class CustomORM { "AND description LIKE ?\n" + "AND external_iban LIKE ?\n" + "AND type LIKE ?;"; - public static final String GET_TRANSACTIONS_ASCENDING = + private static final String GET_TRANSACTIONS_ASCENDING = "SELECT transaction_id, date, amount, description, external_iban, type\n" + "FROM Transaction_Table\n" + "WHERE user_id = ?\n" + "ORDER BY date ASC;"; - public static final String GET_CURRENT_DATE = + private static final String GET_CURRENT_DATE = "SELECT date\n" + "FROM Transaction_Table\n" + "WHERE user_id = ?\n" + "ORDER BY date DESC\n" + "LIMIT 1"; - public static final String INCREASE_HIGHEST_SAVING_GOAL_ID = + private static final String INCREASE_HIGHEST_SAVING_GOAL_ID = "UPDATE User_Table\n" + "SET highest_saving_goal_id = highest_saving_goal_id + 1\n" + "WHERE user_id = ?;"; - public static final String GET_HIGHEST_SAVING_GOAL_ID = + private static final String GET_HIGHEST_SAVING_GOAL_ID = "SELECT highest_saving_goal_id\n" + "FROM User_Table\n" + "WHERE user_id = ?;"; - public static final String CREATE_SAVING_GOAL = + private static final String CREATE_SAVING_GOAL = "INSERT INTO Saving_Goal (user_id, saving_goal_id, creation_date, name, goal, " + "save_per_month, min_balance_required)\n" + "VALUES (?, ?, ?, ?, ?, ?, ?);"; - public static final String GET_SAVING_GOAL = + private static final String GET_SAVING_GOAL = "SELECT saving_goal_id, creation_date, deletion_date, name, goal, save_per_month, min_balance_required\n" + "FROM Saving_Goal\n" + "WHERE user_id = ?\n" + "AND saving_goal_id = ?;"; - public static final String DELETE_SAVING_GOAL = + private static final String DELETE_SAVING_GOAL = "UPDATE Saving_Goal\n" + "SET deletion_date = ?\n" + "WHERE user_id = ?\n" + "AND saving_goal_id = ?;"; - public static final String GET_SAVING_GOALS = + private static final String GET_SAVING_GOALS = "SELECT saving_goal_id, creation_date, deletion_date, name, goal, save_per_month, min_balance_required\n" + "FROM Saving_Goal\n" + "WHERE user_id = ?;"; - public static final String INCREASE_HIGHEST_PAYMENT_REQUEST_ID = + private static final String INCREASE_HIGHEST_PAYMENT_REQUEST_ID = "UPDATE User_Table\n" + "SET highest_payment_request_id = highest_payment_request_id + 1\n" + "WHERE user_id = ?;"; - public static final String GET_HIGHEST_PAYMENT_REQUEST_ID = + private static final String GET_HIGHEST_PAYMENT_REQUEST_ID = "SELECT highest_payment_request_id\n" + "FROM User_Table\n" + "WHERE user_id = ?;"; - public static final String CREATE_PAYMENT_REQUEST = + private static final String CREATE_PAYMENT_REQUEST = "INSERT INTO Payment_Request (user_id, payment_request_id, description, due_date, " + "amount, number_of_requests, filled)\n" + "VALUES (?, ?, ?, ?, ?, ?, ?);\n"; - public static final String GET_PAYMENT_REQUEST = + private static final String GET_PAYMENT_REQUEST = "SELECT payment_request_id, description, due_date, amount, number_of_requests, filled\n" + "FROM Payment_Request\n" + "WHERE user_id = ?\n" + "AND payment_request_id = ?;"; - public static final String GET_PAYMENT_REQUESTS = + private static final String GET_PAYMENT_REQUESTS = "SELECT payment_request_id, description, due_date, amount, number_of_requests, filled\n" + "FROM Payment_Request\n" + "WHERE user_id = ?;"; - public static final String SET_PAYMENT_REQUEST_FILLED = + private static final String SET_PAYMENT_REQUEST_FILLED = "UPDATE Payment_Request\n" + "SET filled = 1\n" + "WHERE user_id = ?\n" + "AND payment_request_id = ?;"; - public static final String GET_TRANSACTIONS_BY_PAYMENT_REQUEST = + private static final String GET_TRANSACTIONS_BY_PAYMENT_REQUEST = "SELECT t.transaction_id, t.date, t.amount, t.description, t.external_iban, t.type\n" + "FROM Payment_Request pr, Payment_Request_Transaction prt, Transaction_Table t\n" + "WHERE pr.payment_request_id = prt.payment_request_id\n" + @@ -221,44 +221,44 @@ public class CustomORM { "AND prt.user_id = t.user_id\n" + "AND t.user_id = ?\n" + "AND pr.payment_request_id = ?;"; - public static final String LINK_TRANSACTION_TO_PAYMENT_REQUEST = + private static final String LINK_TRANSACTION_TO_PAYMENT_REQUEST = "INSERT INTO Payment_Request_Transaction (user_id, transaction_id, payment_request_id)\n" + "VALUES (?, ?, ?);"; - public static final String INCREASE_HIGHEST_USER_MESSAGE_ID = + private static final String INCREASE_HIGHEST_USER_MESSAGE_ID = "UPDATE User_Table\n" + "SET highest_user_message_id = highest_user_message_id + 1\n" + "WHERE user_id = ?;\n"; - public static final String GET_HIGHEST_USER_MESSAGE_ID = + private static final String GET_HIGHEST_USER_MESSAGE_ID = "SELECT highest_user_message_id\n" + "FROM User_Table\n" + "WHERE user_id = ?;"; - public static final String GET_USER_MESSAGE = + private static final String GET_USER_MESSAGE = "SELECT user_message_id, message, date, read, type\n" + "FROM User_Message\n" + "WHERE user_id = ?\n" + "AND user_message_id = ?;"; - public static final String CREATE_USER_MESSAGE = + private static final String CREATE_USER_MESSAGE = "INSERT INTO User_Message (user_id, user_message_id, message, date, read, type)\n" + "VALUES (?, ?, ?, ?, 0, ?);"; - public static final String GET_UNREAD_USER_MESSAGES = + private static final String GET_UNREAD_USER_MESSAGES = "SELECT user_message_id, message, date, read, type\n" + "FROM User_Message\n" + "WHERE user_id = ?\n" + "AND read = 0;"; - public static final String GET_ALL_USER_MESSAGES = + private static final String GET_ALL_USER_MESSAGES = "SELECT user_message_id, message, date, read, type\n" + "FROM User_Message\n" + "WHERE user_id = ?;"; - public static final String SET_USER_MESSAGE_READ = + private static final String SET_USER_MESSAGE_READ = "UPDATE User_Message\n" + "SET read = 1\n" + "WHERE user_id = ?\n" + "AND user_message_id = ?;"; - public static final String GET_HIGHEST_LIFETIME_BALANCE = + private static final String GET_HIGHEST_LIFETIME_BALANCE = "SELECT highest_lifetime_balance\n" + "FROM User_Table\n" + "WHERE user_id = ?;"; - public static final String UPDATE_HIGHEST_LIFETIME_BALANCE = + private static final String UPDATE_HIGHEST_LIFETIME_BALANCE = "UPDATE User_Table\n" + "SET highest_lifetime_balance = \n" + " CASE WHEN ? > highest_lifetime_balance \n" + From d35f80976da49721be2797ab5e924ec0eebb856d Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 14:37:24 +0200 Subject: [PATCH 12/18] Create UserMessageEmitter to facilitate easy emission of UserMessages --- .../persistentmodel/UserMessageEmitter.java | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/main/java/nl/utwente/ing/model/persistentmodel/UserMessageEmitter.java diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/UserMessageEmitter.java b/src/main/java/nl/utwente/ing/model/persistentmodel/UserMessageEmitter.java new file mode 100644 index 0000000..69b9f2a --- /dev/null +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/UserMessageEmitter.java @@ -0,0 +1,154 @@ +package nl.utwente.ing.model.persistentmodel; + +import nl.utwente.ing.misc.date.IntervalHelper; +import nl.utwente.ing.model.bean.Transaction; +import nl.utwente.ing.model.bean.UserMessage; + +import java.sql.Connection; +import java.sql.SQLException; +import java.time.LocalDateTime; +import java.util.ArrayList; + +/** + * The UserMessageEmitter class. + * Used to create and emit UserMessages. + * + * @author Daan Kooij + */ +public class UserMessageEmitter { + + private Connection connection; + private CustomORM customORM; + + private static final String EVENT_BALANCE_DROP_BELOW_ZERO = "Balance drop below zero."; + private static final String EVENT_BALANCE_REACH_NEW_HIGH = "Balance reach new high."; + private static final String EVENT_PAYMENT_REQUEST_FILLED = "Payment request filled: "; + private static final String EVENT_PAYMENT_REQUEST_NOT_FILLED = "Payment request not filled: "; + private static final String EVENT_SAVING_GOAL_REACHED = "Saving goal reached: "; + + /** + * The constructor of UserMessageEmitter. + * + * @param connection The database connection. + * @param customORM The CustomORM. + */ + public UserMessageEmitter(Connection connection, CustomORM customORM) { + this.connection = connection; + this.customORM = customORM; + } + + /** + * Method used to emit a UserMessage for a certain user saying that his/her balance dropped below zero. + * + * @param userID The ID of the user for which the UserMessage will be emitted. + */ + public void eventBalanceBelowZero(int userID) { + this.emitUserMessage(userID, "warning", EVENT_BALANCE_DROP_BELOW_ZERO); + } + + /** + * Method used to emit a UserMessage for a certain user saying that his/her balance reached a new high. + * If such a message already exists for the user and is still unread, nothing will be emitted. + * If the Transactions of the user do not span at least three months, nothing will be emitted. + * + * @param userID The ID of the user for which the UserMessage may be emitted. + */ + public void eventBalanceNewHigh(int userID) { + ArrayList userMessages = customORM.getUnreadUserMessages(userID); + for (UserMessage userMessage : userMessages) { + if (userMessage.getMessage().equals(EVENT_BALANCE_REACH_NEW_HIGH)) { + return; + } + } + ArrayList transactions = customORM.getTransactionsAscending(userID); + if (transactions.size() == 0) { + return; + } + + LocalDateTime firstDatePlusThreeMonths = + IntervalHelper.toLocalDateTime(transactions.get(0).getDate()).plusMonths(3); + LocalDateTime currentDate = IntervalHelper.toLocalDateTime(customORM.getCurrentDate(userID)); + if (firstDatePlusThreeMonths.compareTo(currentDate) <= 0) { + this.emitUserMessage(userID, "info", EVENT_BALANCE_REACH_NEW_HIGH); + } + } + + /** + * Method used to emit a UserMessage for a certain user saying that a PaymentRequest has been filled. + * If such a message is already emitted for the same PaymentRequest, nothing will be emitted. + * + * @param userID The ID of the user for which the UserMessage may be emitted. + * @param paymentRequestID The ID of the PaymentRequest for which a UserMessage may be emitted. + * @param paymentRequestName The name of the PaymentRequest for which a UserMessage may be emitted. + */ + public void eventPaymentRequestFilled(int userID, long paymentRequestID, String paymentRequestName) { + String message = EVENT_PAYMENT_REQUEST_FILLED + paymentRequestName + " (ID = " + paymentRequestID + ")."; + ArrayList userMessages = customORM.getAllUserMessages(userID); + for (UserMessage userMessage : userMessages) { + if (userMessage.getMessage().equals(message)) { + return; + } + } + this.emitUserMessage(userID, "info", message); + } + + /** + * Method used to emit a UserMessage for a certain user saying that a PaymentRequest has not been filled in time. + * If such a message is already emitted for the same PaymentRequest, nothing will be emitted. + * + * @param userID The ID of the user for which the UserMessage may be emitted. + * @param paymentRequestID The ID of the PaymentRequest for which a UserMessage may be emitted. + * @param paymentRequestName The name of the PaymentRequest for which a UserMessage may be emitted. + */ + public void eventPaymentRequestNotFilled(int userID, long paymentRequestID, String paymentRequestName) { + String message = EVENT_PAYMENT_REQUEST_NOT_FILLED + paymentRequestName + " (ID = " + paymentRequestID + ")."; + ArrayList userMessages = customORM.getAllUserMessages(userID); + for (UserMessage userMessage : userMessages) { + if (userMessage.getMessage().equals(message)) { + return; + } + } + this.emitUserMessage(userID, "warning", message); + } + + /** + * Method used to emit a UserMessage for a certain user saying that a SavingGoal has been reached. + * If such a message is already emitted for the same SavingGoal, nothing will be emitted. + * + * @param userID The ID of the user for which the UserMessage may be emitted. + * @param savingGoalID The ID of the SavingGoal for which a UserMessage may be emitted. + * @param savingGoalName The name of the SavingGoal for which a UserMessage may be emitted. + */ + public void eventSavingGoalReached(int userID, long savingGoalID, String savingGoalName) { + String message = EVENT_SAVING_GOAL_REACHED + savingGoalName + " (ID = " + savingGoalID + ")."; + ArrayList userMessages = customORM.getAllUserMessages(userID); + for (UserMessage userMessage : userMessages) { + if (userMessage.getMessage().equals(message)) { + return; + } + } + this.emitUserMessage(userID, "info", message); + } + + /** + * Method used to emit a UserMessage for a certain user. + * + * @param userID The ID of the user for which the UserMessage will be emitted. + * @param type The type of the to be emitted UserMessage. + * @param message The message of the to be emitted UserMessage. + */ + private void emitUserMessage(int userID, String type, String message) { + try { + connection.setAutoCommit(false); + customORM.increaseHighestUserMessageID(userID); + long userMessageID = customORM.getHighestUserMessageID(userID); + connection.commit(); + connection.setAutoCommit(true); + String date = customORM.getCurrentDate(userID); + customORM.createUserMessage(userID, new UserMessage(userMessageID, message, date, false, type)); + } catch (SQLException e) { + e.printStackTrace(); + } + } + +} From e8185d6d2c9acea1eb0d384d618b3c543b3e0e54 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 14:37:56 +0200 Subject: [PATCH 13/18] Add String to LocalDateTime conversion method to IntervalHelper --- .../java/nl/utwente/ing/misc/date/IntervalHelper.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java b/src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java index 405d7bb..4e33c8a 100644 --- a/src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java +++ b/src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java @@ -112,4 +112,15 @@ public static int getMonthIdentifier(String dateString) { return (date.getYear() - 1970) * 12 + (date.getMonthValue() - 1); } + /** + * Method used to convert a String object containing a date to a LocalDateTime object containing that date. + * + * @param s The String object containing a date that will be converted to a LocalDateTime object containing that + * date. + * @return The LocalDateTime object containing the date contained in the given String object. + */ + public static LocalDateTime toLocalDateTime(String s) { + return LocalDateTime.parse(s.split("Z")[0]); + } + } From d7f1c8ede93e8782c0796e9b1e85746d4edc536c Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 14:39:36 +0200 Subject: [PATCH 14/18] Let PersistentModel emit UserMessages when appropriate --- .../persistentmodel/PersistentModel.java | 75 +++++++++++++++---- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java index fd27079..6daa779 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java @@ -26,6 +26,7 @@ public class PersistentModel implements Model { private Connection connection; private CustomORM customORM; + private UserMessageEmitter messageEmitter; /** * The constructor of PersistentModel. @@ -34,6 +35,7 @@ public class PersistentModel implements Model { public PersistentModel() { this.connection = DatabaseConnection.getDatabaseConnection(); this.customORM = new CustomORM(connection); + this.messageEmitter = new UserMessageEmitter(connection, customORM); } /** @@ -128,9 +130,9 @@ public Transaction postTransaction(String sessionID, String date, float amount, } this.populateCategory(userID, transaction); + List paymentRequests = customORM.getPaymentRequests(userID); if (transaction.getType().equals("deposit")) { // Check if Transaction answers some Payment Request - List paymentRequests = customORM.getPaymentRequests(userID); connection.setAutoCommit(false); for (PaymentRequest paymentRequest : paymentRequests) { if (!paymentRequest.getFilled() && transaction.getAmount() == paymentRequest.getAmount() && @@ -140,13 +142,50 @@ public Transaction postTransaction(String sessionID, String date, float amount, long numberAnswered = customORM.getTransactionsByPaymentRequest(userID, paymentRequestID).size(); if (numberAnswered >= paymentRequest.getNumber_of_requests()) { customORM.setPaymentRequestFilled(userID, paymentRequestID); + + // User Message Event: Payment Request filled + messageEmitter.eventPaymentRequestFilled(userID, + paymentRequestID, paymentRequest.getDescription()); } break; } } - connection.commit(); - connection.setAutoCommit(true); + if (!connection.getAutoCommit()) { + connection.commit(); + connection.setAutoCommit(true); + } + } + + // Check if PaymentRequests are not filled on due-date + for (PaymentRequest paymentRequest : paymentRequests) { + if (!paymentRequest.getFilled() && IntervalHelper.isSmallerThan(date, paymentRequest.getDue_date())) { + // User Message Event: Payment Request not filled + messageEmitter.eventPaymentRequestNotFilled(userID, + paymentRequest.getID(), paymentRequest.getDescription()); + } + } + + float newBalance = this.getBalance(sessionID); + float oldBalance; + if (type.equals("deposit")) { + oldBalance = newBalance - amount; + } else { + oldBalance = newBalance + amount; + } + + if (oldBalance >= 0 && newBalance < 0) { + // User Message Event: balance drop below zero + messageEmitter.eventBalanceBelowZero(userID); + } + + float oldHighestBalance = customORM.getHighestLifetimeBalance(userID); + customORM.updateHighestLifetimeBalance(userID, newBalance); + float newHighestBalance = customORM.getHighestLifetimeBalance(userID); + if (newHighestBalance > oldHighestBalance) { + // User Message Event: new highest lifetime balance + messageEmitter.eventBalanceNewHigh(userID); } + } catch (SQLException e) { e.printStackTrace(); } @@ -552,6 +591,14 @@ public ArrayList getBalanceHistory(String sessionID, Interva candlesticks.remove(0); + for (SavingGoal savingGoal : savingGoals) { + if (savingGoal.getDeletionDate() != null && + savingGoal.getBalance() >= savingGoal.getGoal()) { + // User Message Event: Saving Goal reached + messageEmitter.eventSavingGoalReached(userID, savingGoal.getId(), savingGoal.getName()); + } + } + return candlesticks; } @@ -736,24 +783,20 @@ public void setUserMessageRead(String sessionID, long userMessageID) } } + /** - * Method used to emit a UserMessage for a certain user. + * Method used to retrieve the current balance of a certain user. * - * @param userID The ID of the user for which the UserMessage will be emitted. - * @param type The type of the to be emitted UserMessage. - * @param message The message of the to be emitted UserMessage. + * @param sessionID The sessionID of the user. + * @return The current balance of the user. */ - private void emitUserMessage(int userID, String type, String message) { + private float getBalance(String sessionID) { try { - connection.setAutoCommit(false); - customORM.increaseHighestUserMessageID(userID); - long userMessageID = customORM.getHighestUserMessageID(userID); - connection.commit(); - connection.setAutoCommit(true); - String date = customORM.getCurrentDate(userID); - customORM.createUserMessage(userID, new UserMessage(userMessageID, message, date, false, type)); - } catch (SQLException e) { + return this.getBalanceHistory(sessionID, IntervalPeriod.HOUR, 1).get(0).getClose(); + } catch (InvalidSessionIDException e) { + // This never happens, because this method will never get called with an invalid session ID. e.printStackTrace(); + return 0; } } From 92f29834ea13f84a10d7e8676ec40a5bd537c7f4 Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 16:37:05 +0200 Subject: [PATCH 15/18] Use date of newest Transaction instead of local date in IntervalHelper --- src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java | 4 ++-- .../nl/utwente/ing/model/persistentmodel/PersistentModel.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java b/src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java index 4e33c8a..f4df1f9 100644 --- a/src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java +++ b/src/main/java/nl/utwente/ing/misc/date/IntervalHelper.java @@ -27,9 +27,9 @@ public class IntervalHelper { * @param amount The amount of intervals to be generated. * @return An array containing LocalDateTime objects representing the requested intervals. */ - public static LocalDateTime[] getIntervals(IntervalPeriod intervalPeriod, int amount) { + public static LocalDateTime[] getIntervals(IntervalPeriod intervalPeriod, int amount, LocalDateTime until) { LocalDateTime[] intervals = new LocalDateTime[amount + 2]; - intervals[amount + 1] = LocalDateTime.now(ZoneOffset.UTC); + intervals[amount + 1] = until; intervals[0] = LocalDateTime.parse("1970-01-01T00:00:00.000"); if (intervalPeriod == IntervalPeriod.YEAR) { diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java index 6daa779..27305f1 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java @@ -519,7 +519,8 @@ public ArrayList getBalanceHistory(String sessionID, Interva throws InvalidSessionIDException { int userID = this.getUserID(sessionID); - LocalDateTime[] intervals = IntervalHelper.getIntervals(intervalPeriod, amount); + LocalDateTime[] intervals = IntervalHelper.getIntervals(intervalPeriod, amount, + IntervalHelper.toLocalDateTime(customORM.getCurrentDate(userID))); ArrayList transactions = customORM.getTransactionsAscending(userID); ArrayList savingGoals = customORM.getSavingGoals(userID); From e83b2b8bd167bd6fcb691db25fffd2de8bc5adbf Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 17:18:29 +0200 Subject: [PATCH 16/18] Fix comparison of dates at emission check of unfilled PaymentRequests --- .../nl/utwente/ing/model/persistentmodel/PersistentModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java index 27305f1..909eefd 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java @@ -158,7 +158,7 @@ public Transaction postTransaction(String sessionID, String date, float amount, // Check if PaymentRequests are not filled on due-date for (PaymentRequest paymentRequest : paymentRequests) { - if (!paymentRequest.getFilled() && IntervalHelper.isSmallerThan(date, paymentRequest.getDue_date())) { + if (!paymentRequest.getFilled() && IntervalHelper.isSmallerThan(paymentRequest.getDue_date(), date)) { // User Message Event: Payment Request not filled messageEmitter.eventPaymentRequestNotFilled(userID, paymentRequest.getID(), paymentRequest.getDescription()); From 3189980193fdf35d8ce4def0f6b1d5167abead8a Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 17:29:50 +0200 Subject: [PATCH 17/18] Fix emission check of SavingGoal reached info messages --- .../nl/utwente/ing/model/persistentmodel/PersistentModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java index 909eefd..cdd52b4 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java @@ -593,7 +593,7 @@ public ArrayList getBalanceHistory(String sessionID, Interva candlesticks.remove(0); for (SavingGoal savingGoal : savingGoals) { - if (savingGoal.getDeletionDate() != null && + if (savingGoal.getDeletionDate() == null && savingGoal.getBalance() >= savingGoal.getGoal()) { // User Message Event: Saving Goal reached messageEmitter.eventSavingGoalReached(userID, savingGoal.getId(), savingGoal.getName()); From 9b5ef09b995ff426cabcd69b9842121dfe34e72c Mon Sep 17 00:00:00 2001 From: Daan Kooij Date: Sun, 5 Aug 2018 18:41:41 +0200 Subject: [PATCH 18/18] Fix calculation of oldBalance in postTransaction method --- .../ing/model/persistentmodel/PersistentModel.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java index cdd52b4..65c71bd 100644 --- a/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java +++ b/src/main/java/nl/utwente/ing/model/persistentmodel/PersistentModel.java @@ -103,6 +103,8 @@ public Transaction postTransaction(String sessionID, String date, float amount, int userID = this.getUserID(sessionID); Transaction transaction = null; try { + float oldBalance = this.getBalance(sessionID); + connection.setAutoCommit(false); customORM.increaseHighestTransactionID(userID); long transactionID = customORM.getHighestTransactionID(userID); @@ -166,12 +168,6 @@ public Transaction postTransaction(String sessionID, String date, float amount, } float newBalance = this.getBalance(sessionID); - float oldBalance; - if (type.equals("deposit")) { - oldBalance = newBalance - amount; - } else { - oldBalance = newBalance + amount; - } if (oldBalance >= 0 && newBalance < 0) { // User Message Event: balance drop below zero