diff options
Diffstat (limited to 'ufund-api')
15 files changed, 117 insertions, 83 deletions
diff --git a/ufund-api/data/userAuths.json b/ufund-api/data/userAuths.json index e451862..41ff472 100644 --- a/ufund-api/data/userAuths.json +++ b/ufund-api/data/userAuths.json @@ -1,7 +1 @@ -[ -  { -    "key": "eeea7b02-7265-4a26-96de-a8ad1860c533", -    "username": "phil", -    "expiration": "2025-03-31T23:04:47.455490668" -  } -]
\ No newline at end of file +[{"key":"a07ae51f-f80b-4001-95f1-48c11d4917a4","username":"phil","expiration":"2025-04-05T15:04:30.900359001"},{"key":"e14f8ee5-5780-4b9b-bf34-7a41c2bbfcb4","username":"phil","expiration":"2025-04-05T13:46:10.90733016"},{"key":"d7cef571-0f76-49fe-941f-ecbeae69557a","username":"phil","expiration":"2025-04-05T15:14:00.363201102"},{"key":"eeea7b02-7265-4a26-96de-a8ad1860c533","username":"phil","expiration":"2025-03-31T23:04:47.455490668"}]
\ No newline at end of file diff --git a/ufund-api/pom.xml b/ufund-api/pom.xml index ce96d60..d874a29 100644 --- a/ufund-api/pom.xml +++ b/ufund-api/pom.xml @@ -73,8 +73,8 @@  				<artifactId>jacoco-maven-plugin</artifactId>  				<version>${jacoco.version}</version>  				<configuration> -					<destfile>/target/coverage-reports/jacoco-unit.exec</destfile> -					<datafile>/target/coverage-reports/jacoco-unit.exec</datafile> +					<destFile>/target/coverage-reports/jacoco-unit.exec</destFile> +					<dataFile>/target/coverage-reports/jacoco-unit.exec</dataFile>  				</configuration>  				<executions>  					<execution> 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<String> login(@RequestBody Map<String, String> 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<Object> logout() { -        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); +    public ResponseEntity<Object> 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<Need> createNeed(@RequestBody Map<String, String> 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<br> +     * @return ResponseEntity with {@link Need need} object and HTTP status of OK if found<br>       *         ResponseEntity with HTTP status of NOT_FOUND if not found<br> -     *         ResponseEntity with HTTP status of INTERNAL_SERVER_ERROR otherwise       */      @GetMapping("/{id}")      public ResponseEntity<Need> 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<Need> 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       * <br>       * 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 index 84ea693..c4aaca3 100644 --- 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 @@ -11,14 +11,14 @@ import java.util.Map;  import java.util.TreeMap;  @Component -public class CupboardFileDao implements CupboardDAO { +public class CupboardFileDAO implements CupboardDAO {      private final Map<Integer, Need> 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 { +    public CupboardFileDAO(@Value("${cupboard.file}") String filename, ObjectMapper objectMapper) throws IOException {          this.filename = filename;          this.objectMapper = objectMapper;          needs = new TreeMap<>(); 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;      } diff --git a/ufund-api/src/main/resources/application.properties b/ufund-api/src/main/resources/application.properties index a866f98..70cb171 100644 --- a/ufund-api/src/main/resources/application.properties +++ b/ufund-api/src/main/resources/application.properties @@ -3,6 +3,7 @@ server.error.include-message=always  cupboard.file=data/cupboard.json  users.file=data/users.json +authKeys.file=data/userAuths.json  spring.jackson.mapper.auto-detect-getters=false  spring.jackson.mapper.auto-detect-setters=false diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java index 04ce41d..1cc84bf 100644 --- a/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java +++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java @@ -1,7 +1,7 @@  package com.ufund.api.ufundapi.controller;  import com.ufund.api.ufundapi.model.Need; -import com.ufund.api.ufundapi.persistence.CupboardFileDao; +import com.ufund.api.ufundapi.persistence.CupboardFileDAO;  import org.junit.jupiter.api.BeforeEach;  import org.junit.jupiter.api.Test;  import org.springframework.http.HttpStatus; @@ -14,11 +14,11 @@ import static org.mockito.Mockito.when;  public class CupboardControllerTest {      private CupboardController cupboardController; -    private CupboardFileDao mockCupboardDAO; +    private CupboardFileDAO mockCupboardDAO;      @BeforeEach      public void setupCupboardDAO() { -        mockCupboardDAO = mock(CupboardFileDao.class); +        mockCupboardDAO = mock(CupboardFileDAO.class);          cupboardController = new CupboardController(mockCupboardDAO);      } diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDaoTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDAOTest.java index 8aa6fe0..e554f9d 100644 --- a/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDaoTest.java +++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDAOTest.java @@ -13,7 +13,6 @@ import java.io.IOException;  import com.fasterxml.jackson.databind.ObjectMapper;  import com.ufund.api.ufundapi.model.Need; -import com.ufund.api.ufundapi.model.User;  import org.junit.jupiter.api.BeforeEach;  import org.junit.jupiter.api.Tag; @@ -22,8 +21,8 @@ import org.junit.jupiter.api.Test;  import com.ufund.api.ufundapi.model.Need.GoalType;  @Tag("Persistence-tier") -public class CupboardFileDaoTest { -    CupboardFileDao cupboardFileDao; +public class CupboardFileDAOTest { +    CupboardFileDAO cupboardFileDao;      Need[] testNeeds;      ObjectMapper mockObjectMapper; @@ -39,7 +38,7 @@ public class CupboardFileDaoTest {          when(mockObjectMapper              .readValue(new File("doesnt_matter.txt"),Need[].class))                  .thenReturn(testNeeds); -        cupboardFileDao = new CupboardFileDao("doesnt_matter.txt",mockObjectMapper); +        cupboardFileDao = new CupboardFileDAO("doesnt_matter.txt",mockObjectMapper);      }      @Test  | 
