From bb9ce55cb5b55a6aaed2399e39a01d68f2491ce3 Mon Sep 17 00:00:00 2001 From: sowgro Date: Thu, 6 Mar 2025 21:41:39 -0500 Subject: Push current changes (working on documentation and tests) --- .../api/ufundapi/controller/AuthController.java | 25 ++-- .../ufundapi/controller/CupboardController.java | 15 +-- .../api/ufundapi/persistence/CupboardDAO.java | 4 - .../api/ufundapi/persistence/CupboardFileDAO.java | 126 +++++++++++++++++++++ .../api/ufundapi/persistence/CupboardFileDao.java | 126 --------------------- .../api/ufundapi/persistence/UserAuthDAO.java | 17 ++- .../api/ufundapi/persistence/UserAuthFIleDAO.java | 27 +++-- .../api/ufundapi/persistence/UserFileDAO.java | 23 +--- .../ufund/api/ufundapi/service/AuthService.java | 32 +++++- .../api/ufundapi/service/CupboardService.java | 25 ++-- .../ufund/api/ufundapi/service/UserService.java | 2 +- 11 files changed, 231 insertions(+), 191 deletions(-) create mode 100644 ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDAO.java delete mode 100644 ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDao.java (limited to 'ufund-api/src/main/java/com') diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java index 1a545f6..b0390ae 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java @@ -20,8 +20,10 @@ public class AuthController { /** * Attempts to log in as a user - * @param params A map/json object in the format {username: string, password: string} - * @return An api key if the auth was successful, null otherwise + * + * @param params A json object in the format {username: string, password: string} + * @return An api key and status OK if the authentication was successful, + * Status UNAUTHORIZED if the authentication failed and INTERNAL SERVER ERROR otherwise. */ @PostMapping("") public ResponseEntity login(@RequestBody Map params) { @@ -30,19 +32,26 @@ public class AuthController { try { String key = authService.login(username, password); return new ResponseEntity<>(key, HttpStatus.OK); - } catch (IOException ex) { - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } catch (IllegalAccessException e) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); + } catch (IOException ex) { + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } /** - * TODO - * @return + * Logs out the current user + * + * @param key The API sent by the client in the header + * @return OK if the user was successfully logged out, INTERNAL_SERVER_ERROR otherwise. */ @DeleteMapping("") - public ResponseEntity logout() { - return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + public ResponseEntity logout(@RequestHeader("jelly-api-key") String key) { + try { + authService.logout(key); + return new ResponseEntity<>(HttpStatus.OK); + } catch (IOException e) { + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } } } diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java index 6b0bb71..dfcb8a3 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java @@ -40,8 +40,11 @@ public class CupboardController { /** * Creates a Need with the provided object * - * @param need The need to create - * @return OK response and the need if it was successful, INTERNAL_SERVER_ERROR otherwise + * @param params The need to create + * @return OK response and the need if it was successful, + * CONFLICT if another need with the same name exists + * UNPROCESSABLE_ENTITY if the need contains bad data + * INTERNAL_SERVER_ERROR otherwise */ @PostMapping("") public ResponseEntity createNeed(@RequestBody Map params) { @@ -50,10 +53,8 @@ public class CupboardController { Need.GoalType goalType = GoalType.valueOf(params.get("maxGoal")); try { - Need need = cupboardService.createNeed(name, maxGoal, goalType); return new ResponseEntity<>(need, HttpStatus.OK); - } catch (DuplicateKeyException ex) { return new ResponseEntity<>(HttpStatus.CONFLICT); } catch (IllegalArgumentException ex) { @@ -113,10 +114,8 @@ public class CupboardController { * * @param id The id used to locate the {@link Need need} * - * @return ResponseEntity with {@link Need need} object and HTTP status of OK if - * found
+ * @return ResponseEntity with {@link Need need} object and HTTP status of OK if found
* ResponseEntity with HTTP status of NOT_FOUND if not found
- * ResponseEntity with HTTP status of INTERNAL_SERVER_ERROR otherwise */ @GetMapping("/{id}") public ResponseEntity getNeed(@PathVariable int id) { @@ -129,7 +128,6 @@ public class CupboardController { } else { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - } catch (IOException e) { LOG.log(Level.SEVERE, e.getLocalizedMessage()); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); @@ -143,7 +141,6 @@ public class CupboardController { * @param need The need to update * @return OK response and the need if it was successful, or INTERNAL_SERVER_ERROR if there was an issue */ - @PutMapping("") public ResponseEntity updateNeed(@RequestBody Need need) { try { diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardDAO.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardDAO.java index 6baf3e4..c8285a0 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardDAO.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardDAO.java @@ -14,8 +14,6 @@ public interface CupboardDAO { * Retrieves all {@linkplain Need needs} * * @return An array of {@link Need need} objects, may be empty - * - * @throws IOException if an issue with underlying storage */ Need[] getNeeds() throws IOException; @@ -27,8 +25,6 @@ public interface CupboardDAO { * @return a {@link Need need} object with the matching name *
* null if no {@link Need need} with a matching name is found - * - * @throws IOException if an issue with underlying storage */ Need getNeed(int id) throws IOException; diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDAO.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDAO.java new file mode 100644 index 0000000..c4aaca3 --- /dev/null +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDAO.java @@ -0,0 +1,126 @@ +package com.ufund.api.ufundapi.persistence; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ufund.api.ufundapi.model.Need; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.TreeMap; + +@Component +public class CupboardFileDAO implements CupboardDAO { + + private final Map needs; // cache + private final ObjectMapper objectMapper; + private static int nextId; + private final String filename; + + public CupboardFileDAO(@Value("${cupboard.file}") String filename, ObjectMapper objectMapper) throws IOException { + this.filename = filename; + this.objectMapper = objectMapper; + needs = new TreeMap<>(); + load(); // load the heroes from the file + } + + private synchronized static int nextId() { + int id = nextId; + nextId++; + return id; + } + + /** + * Load changes from the json file + * + * @throws IOException Any IO issue with the file + */ + private void load() throws IOException { + needs.clear(); + nextId = 0; + + Need[] needsArray = objectMapper.readValue(new File(filename), Need[].class); + + for (Need need : needsArray) { + needs.put(need.getId(), need); + if (need.getId() > nextId()) { + nextId = need.getId(); + } + } + nextId++; + } + + /** + * Return an array of the needs + * + * @return An array of all the needs + */ + private Need[] getNeedsArray() { + return needs.values().toArray(Need[]::new); + } + + /** + * Saves the needs to json + * + * @return True if the save was successful, false otherwise + * @throws IOException If there was an IO issue saving the file + */ + private boolean save() throws IOException { + Need[] needArray = getNeedsArray(); + + objectMapper.writeValue(new File(filename), needArray); + return true; + } + + @Override + public Need[] getNeeds() { + synchronized (needs) { + return getNeedsArray(); + } + } + + @Override + public Need getNeed(int id) { + synchronized (needs) { + return needs.getOrDefault(id, null); + } + } + + @Override + public Need addNeed(Need need) throws IOException { + synchronized (needs) { + Need newNeed = new Need(need); + newNeed.setID(nextId()); + needs.put(newNeed.getId(), newNeed); + save(); + return newNeed; + } + } + + @Override + public Need updateNeed(Need need) throws IOException { + synchronized (needs) { + if (needs.containsKey(need.getId())) { + needs.put(need.getId(), need); + save(); + return need; + } else { + return null; + } + + } + } + + @Override + public boolean deleteNeed(int id) throws IOException { + synchronized (needs) { + if (needs.containsKey(id)) { + needs.remove(id); + return save(); + } else { + return false; + } + } + } +} \ No newline at end of file diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDao.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDao.java deleted file mode 100644 index 84ea693..0000000 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDao.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.ufund.api.ufundapi.persistence; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.ufund.api.ufundapi.model.Need; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import java.io.File; -import java.io.IOException; -import java.util.Map; -import java.util.TreeMap; - -@Component -public class CupboardFileDao implements CupboardDAO { - - private final Map needs; // cache - private final ObjectMapper objectMapper; - private static int nextId; - private final String filename; - - public CupboardFileDao(@Value("${cupboard.file}") String filename, ObjectMapper objectMapper) throws IOException { - this.filename = filename; - this.objectMapper = objectMapper; - needs = new TreeMap<>(); - load(); // load the heroes from the file - } - - private synchronized static int nextId() { - int id = nextId; - nextId++; - return id; - } - - /** - * Load changes from the json file - * - * @throws IOException Any IO issue with the file - */ - private void load() throws IOException { - needs.clear(); - nextId = 0; - - Need[] needsArray = objectMapper.readValue(new File(filename), Need[].class); - - for (Need need : needsArray) { - needs.put(need.getId(), need); - if (need.getId() > nextId()) { - nextId = need.getId(); - } - } - nextId++; - } - - /** - * Return an array of the needs - * - * @return An array of all the needs - */ - private Need[] getNeedsArray() { - return needs.values().toArray(Need[]::new); - } - - /** - * Saves the needs to json - * - * @return True if the save was successful, false otherwise - * @throws IOException If there was an IO issue saving the file - */ - private boolean save() throws IOException { - Need[] needArray = getNeedsArray(); - - objectMapper.writeValue(new File(filename), needArray); - return true; - } - - @Override - public Need[] getNeeds() { - synchronized (needs) { - return getNeedsArray(); - } - } - - @Override - public Need getNeed(int id) { - synchronized (needs) { - return needs.getOrDefault(id, null); - } - } - - @Override - public Need addNeed(Need need) throws IOException { - synchronized (needs) { - Need newNeed = new Need(need); - newNeed.setID(nextId()); - needs.put(newNeed.getId(), newNeed); - save(); - return newNeed; - } - } - - @Override - public Need updateNeed(Need need) throws IOException { - synchronized (needs) { - if (needs.containsKey(need.getId())) { - needs.put(need.getId(), need); - save(); - return need; - } else { - return null; - } - - } - } - - @Override - public boolean deleteNeed(int id) throws IOException { - synchronized (needs) { - if (needs.containsKey(id)) { - needs.remove(id); - return save(); - } else { - return false; - } - } - } -} \ No newline at end of file diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthDAO.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthDAO.java index 45515b8..355aae4 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthDAO.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthDAO.java @@ -8,16 +8,25 @@ public interface UserAuthDAO { /** * Get a user authentication profile + * * @param key The auth key * @return The authentication profile or null if there was none */ - UserAuth getUserAuth(String key); + UserAuth getUserAuth(String key) throws IOException; /** * Add a user authentication profile + * * @param userAuth The user auth profile to add - * @return True if it was successful - * @throws IOException On any file writing error + * @throws IOException Thrown on any file writing error */ - boolean addUserAuth(UserAuth userAuth) throws IOException; + void addUserAuth(UserAuth userAuth) throws IOException; + + /** + * Remove a user authentication profile + * + * @param key The key of the user auth profile to remove + * @throws IOException Thrown on any file writing error + */ + void removeUserAuth(String key) throws IOException; } diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java index 67918cc..4494939 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java @@ -24,6 +24,11 @@ public class UserAuthFIleDAO implements UserAuthDAO { load(); } + /** + * Loads the data from the file into the map + * + * @throws IOException Thrown if there was an issue reading the file + */ private void load() throws IOException { userAuthMap.clear(); @@ -34,29 +39,35 @@ public class UserAuthFIleDAO implements UserAuthDAO { } } + /** + * Saves the data from the map into the json file + * + * @throws IOException Thrown on any problem writing the file + */ private void save() throws IOException { objectMapper.writeValue(new File(filename), userAuthMap.values()); } - public UserAuth[] getAuthKeys() { + @Override + public UserAuth getUserAuth(String key) { synchronized (userAuthMap) { - return userAuthMap.values().toArray(UserAuth[]::new); + return userAuthMap.get(key); } } @Override - public UserAuth getUserAuth(String key) { + public void addUserAuth(UserAuth userAuth) throws IOException { synchronized (userAuthMap) { - return userAuthMap.get(key); + userAuthMap.put(userAuth.getKey(), userAuth); } + save(); } @Override - public boolean addUserAuth(UserAuth userAuth) throws IOException { + public void removeUserAuth(String key) throws IOException { synchronized (userAuthMap) { - userAuthMap.put(userAuth.getKey(), userAuth); - save(); - return true; + userAuthMap.remove(key); } + save(); } } diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserFileDAO.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserFileDAO.java index dca812b..1ef3032 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserFileDAO.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserFileDAO.java @@ -2,6 +2,7 @@ package com.ufund.api.ufundapi.persistence; import java.io.File; import java.io.IOException; +import java.util.HashMap; import java.util.Map; import java.util.TreeMap; @@ -21,7 +22,7 @@ public class UserFileDAO implements UserDAO { public UserFileDAO(@Value("${users.file}") String filename, ObjectMapper objectMapper) throws IOException { this.filename = filename; this.objectMapper = objectMapper; - users = new TreeMap<>(); + users = new HashMap<>(); load(); // load the users from the file } @@ -47,25 +48,14 @@ public class UserFileDAO implements UserDAO { * @throws IOException If there was an IO issue saving the file */ private boolean save() throws IOException { - User[] userArray = getUserArray(); - - objectMapper.writeValue(new File(filename), userArray); + objectMapper.writeValue(new File(filename), users.values()); return true; } - /** - * Return an array of the needs - * - * @return An array of all the needs - */ - private User[] getUserArray() { - return users.values().toArray(User[]::new); - } - @Override - public User[] getUsers() throws IOException { + public User[] getUsers() { synchronized (users) { - return getUserArray(); + return users.values().toArray(User[]::new); } } @@ -75,10 +65,9 @@ public class UserFileDAO implements UserDAO { * @param username Name of desired user * * @return Desired user, null otherwise - * @throws IOException If there was an IO issue saving the file */ @Override - public User getUser(String username) throws IOException { + public User getUser(String username) { synchronized (users) { return users.getOrDefault(username, null); } diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java index 2e644ee..ac86ff1 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java @@ -17,17 +17,29 @@ public class AuthService { this.userService = userService; } - public UserAuth getUserAuth(String key) { - return userAuthDAO.getUserAuth(key); - } - + /** + * Check if the provided key has access to the provided user. + * + * @param username The username of the user trying to be accessed. + * @param key The api key obtained by the client from logging in. + * @throws IllegalAccessException Thrown if access was denied to the user. + */ public void authenticate(String username, String key) throws IllegalAccessException { - var userAuth = getUserAuth(key); + var userAuth = userAuthDAO.getUserAuth(key); if (userAuth == null || !userAuth.getUsername().equals(username)) { throw new IllegalAccessException("Unauthorized"); } } + /** + * Attempt to log in with the provided credentials + * + * @param username The username of the user + * @param password The password of the user + * @return An API key if the authentication was successful. + * @throws IllegalAccessException Thrown if the username or password was incorrect + * @throws IOException If there was an issue saving the authentication + */ public String login(String username, String password) throws IllegalAccessException, IOException { var usr = userService.getUser(username); if (usr == null || !usr.verifyPassword(password)) { @@ -38,4 +50,14 @@ public class AuthService { return userAuth.getKey(); } + /** + * Logs out the current user + * + * @param key The API key to of the client + * @throws IOException Thrown if there was an error saving the authentication + */ + public void logout(String key) throws IOException { + userAuthDAO.removeUserAuth(key); + } + } diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java index 860a2a8..6052e4f 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java @@ -5,17 +5,17 @@ import java.util.Arrays; import com.ufund.api.ufundapi.model.Need; import com.ufund.api.ufundapi.persistence.CupboardDAO; +import org.springframework.stereotype.Component; +@Component public class CupboardService { private final CupboardDAO cupboardDAO; public class DuplicateKeyException extends Exception { - public DuplicateKeyException(String message) { super(message); } - } public CupboardService(CupboardDAO cupboardDAO) { @@ -57,27 +57,34 @@ public class CupboardService { } /** - * @param id - * @return - * @throws IOException + * Gets a need with the specified ID + * + * @param id the ID of the need + * @return The resulting Need or null if the need was not found */ public Need getNeed(int id) throws IOException { return cupboardDAO.getNeed(id); } /** - * + * Modify a need + * * @param need * @return - * @throws IOException + * @throws IOException Thrown if there was an issue saving the changes */ public Need updateNeed(Need need) throws IOException { return cupboardDAO.updateNeed(need); } + /** + * Delete a need from the cupboard + * + * @param id the ID of the need + * @return True if the need was deleted + * @throws IOException Thrown on any problem removing the need + */ public boolean deleteNeed(int id) throws IOException { return cupboardDAO.deleteNeed(id); } - - } diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java index a545029..6af3897 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java @@ -16,7 +16,7 @@ public class UserService { * * @param userDao The Data Access Object */ - public UserService(UserDAO userDao, AuthService authService) { + public UserService(UserDAO userDao) { this.userDAO = userDao; } -- cgit v1.2.3