aboutsummaryrefslogtreecommitdiff
path: root/ufund-api
diff options
context:
space:
mode:
authorGunther6070 <haydenhartman10@yahoo.com>2025-03-17 23:12:49 -0400
committerGunther6070 <haydenhartman10@yahoo.com>2025-03-17 23:12:49 -0400
commit5b6c20479fbb6ed0cabbbc88b42280c5a7dbd22c (patch)
tree16f93b3ce3b40de1e550f3824f60ca3aac632265 /ufund-api
parent7a5c5073e9e410b3ccc3ab7902a0d6f558277c7d (diff)
parent2b847078b7af4ade35461b8af52352bc88994be3 (diff)
downloadJellySolutions-5b6c20479fbb6ed0cabbbc88b42280c5a7dbd22c.tar.gz
JellySolutions-5b6c20479fbb6ed0cabbbc88b42280c5a7dbd22c.tar.bz2
JellySolutions-5b6c20479fbb6ed0cabbbc88b42280c5a7dbd22c.zip
Merge branch 'main' into funding_basket
Diffstat (limited to 'ufund-api')
-rw-r--r--ufund-api/data/cupboard.json4
-rw-r--r--ufund-api/data/userAuths.json1
-rw-r--r--ufund-api/data/users.json15
-rw-r--r--ufund-api/pom.xml6
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/DuplicateKeyException.java7
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java62
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/controller/CupboardController.java74
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/controller/UserController.java81
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java15
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/model/User.java66
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/model/UserAuth.java43
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardDAO.java21
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDAO.java (renamed from ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/CupboardFileDao.java)27
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthDAO.java32
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java73
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserDAO.java21
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserFileDAO.java88
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java70
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java109
-rw-r--r--ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java72
-rw-r--r--ufund-api/src/main/resources/application.properties2
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/controller/AuthControllerTest.java104
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/controller/CupboardControllerTest.java114
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/controller/UserControllerTest.java191
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java25
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java50
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDAOTest.java (renamed from ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/CupboardFileDaoTest.java)58
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserAuthFileDAOTest.java63
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserFileDAOTest.java51
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/service/AuthServiceTest.java110
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java197
-rw-r--r--ufund-api/src/test/java/com/ufund/api/ufundapi/service/UserServiceTest.java126
32 files changed, 1572 insertions, 406 deletions
diff --git a/ufund-api/data/cupboard.json b/ufund-api/data/cupboard.json
index bb7ec03..abc2293 100644
--- a/ufund-api/data/cupboard.json
+++ b/ufund-api/data/cupboard.json
@@ -1,3 +1 @@
-[
- {"name":"Money for coral","id":1,"maxGoal":100.0,"type":"MONETARY","filterAttributes":null,"Current":0.0}
-] \ No newline at end of file
+[{"name":"Jellyfish Hats","id":26,"maxGoal":10.0,"type":"MONETARY","filterAttributes":["#savethejellyfish","Clothing","Storefront"],"current":0.0},{"name":"Pollution Re-Filtering","id":27,"maxGoal":1.0E7,"type":"MONETARY","filterAttributes":["Cleanup","Donations","Third-Party"],"current":0.0},{"name":"Coral re-re-habilitation","id":28,"maxGoal":10000.0,"type":"MONETARY","filterAttributes":["Preservation","#savethecoral","#helloPhil"],"current":0.0}] \ No newline at end of file
diff --git a/ufund-api/data/userAuths.json b/ufund-api/data/userAuths.json
new file mode 100644
index 0000000..fea8a6f
--- /dev/null
+++ b/ufund-api/data/userAuths.json
@@ -0,0 +1 @@
+[{"key":"e48872fa-b89f-494a-b681-11a809d32ff4","username":"phil","expiration":"2025-04-14T17:20:23.265745224"},{"key":"31fcbc15-9902-41d2-8d6f-5b0e40ebddd2","username":"phil","expiration":"2025-04-14T16:45:41.082560826"},{"key":"3fdd4e7e-bc59-4e3a-ba5c-177d0833022a","username":"sowgro","expiration":"2025-04-14T18:35:26.42935739"},{"key":"13d12a6d-6825-4c1d-8b22-ba960de140b8","username":"phil","expiration":"2025-04-14T17:20:58.531711142"},{"key":"a07ae51f-f80b-4001-95f1-48c11d4917a4","username":"phil","expiration":"2025-04-05T15:04:30.900359001"},{"key":"cc49c007-fd36-4828-b8fa-f5b85ad0676d","username":"phil","expiration":"2025-04-14T16:46:12.80566798"},{"key":"da61796e-402a-4a80-88ae-7607a37989a4","username":"phil","expiration":"2025-04-14T17:07:10.618039573"},{"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":"125a4847-3a1c-4834-961f-7f96e997f92e","username":"sowgro","expiration":"2025-04-14T18:35:38.922687686"},{"key":"3fc557b6-0306-4779-9b74-b7292a5cf1cc","username":"phil","expiration":"2025-04-14T16:06:08.564069822"},{"key":"77392d17-6e0c-45ec-857d-6595a55ddd97","username":"phil","expiration":"2025-04-14T16:06:48.335542315"},{"key":"eeea7b02-7265-4a26-96de-a8ad1860c533","username":"phil","expiration":"2025-03-31T23:04:47.455490668"},{"key":"e121c7c6-e534-4fde-8a78-4f175e9db9c8","username":"phil","expiration":"2025-04-14T17:23:23.218442063"},{"key":"af38add5-b100-4b96-9ffb-5afaccd59979","username":"adf","expiration":"2025-04-14T18:18:47.670506361"},{"key":"2aeaab28-99c9-4b45-bdef-82096c70945e","username":"phil","expiration":"2025-04-14T17:19:48.552121268"},{"key":"58e4e2a2-3a36-4fd6-8bb1-ad0831664d01","username":"phil","expiration":"2025-04-12T23:17:42.638952959"},{"key":"4df8bb43-f597-49ca-863a-6e0da5280d79","username":"phil","expiration":"2025-04-14T01:13:53.799331844"},{"key":"ad6d92d4-c496-407c-823a-edaa386e67ed","username":"phil","expiration":"2025-04-14T17:07:36.032623002"},{"key":"718be1e2-cfc7-44a6-b3c6-965684d1d0a9","username":"adf","expiration":"2025-04-14T18:35:58.888847176"},{"key":"85319427-4603-4a16-af33-2e9525dda8c0","username":"phil","expiration":"2025-04-14T00:39:34.952183453"},{"key":"f5f53053-ef5e-4850-93a0-3dc20646f78b","username":"sowgro","expiration":"2025-04-14T18:11:29.438554549"},{"key":"efc531fb-ab24-4d5a-a2f5-7f4ede74819f","username":"phil","expiration":"2025-04-13T19:41:51.017327545"},{"key":"f1d6a110-4232-4ef3-b6ec-9a2962664158","username":"phil","expiration":"2025-04-14T17:23:40.834526839"}] \ No newline at end of file
diff --git a/ufund-api/data/users.json b/ufund-api/data/users.json
index 4e98a14..8543a55 100644
--- a/ufund-api/data/users.json
+++ b/ufund-api/data/users.json
@@ -1 +1,14 @@
-[{"name":"steve","password":null}] \ No newline at end of file
+[
+ {
+ "username": "phil",
+ "passwordHash": -1054080181,
+ "basket": [],
+ "type": "HELPER"
+ },
+ {
+ "username": "admin",
+ "passwordHash": 92668751,
+ "basket": [],
+ "type": "MANAGER"
+ }
+] \ No newline at end of file
diff --git a/ufund-api/pom.xml b/ufund-api/pom.xml
index ce96d60..d2e8fb8 100644
--- a/ufund-api/pom.xml
+++ b/ufund-api/pom.xml
@@ -73,8 +73,10 @@
<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>
+ <!-- not sure what these were supposed to do, but 'datafile' is not a
+ configuration key for jacoco, and changing it to 'dataFile' breaks the build -->
+ <!-- <datafile>/target/coverage-reports/jacoco-unit.exec</datafile>-->
+ <!-- <datafile>/target/coverage-reports/jacoco-unit.exec</datafile>-->
</configuration>
<executions>
<execution>
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/DuplicateKeyException.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/DuplicateKeyException.java
new file mode 100644
index 0000000..69ce6c0
--- /dev/null
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/DuplicateKeyException.java
@@ -0,0 +1,7 @@
+package com.ufund.api.ufundapi;
+
+public class DuplicateKeyException extends Exception {
+ public DuplicateKeyException(String message) {
+ super(message);
+ }
+}
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
new file mode 100644
index 0000000..b46d4ee
--- /dev/null
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java
@@ -0,0 +1,62 @@
+package com.ufund.api.ufundapi.controller;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.ufund.api.ufundapi.service.AuthService;
+
+@RestController
+@RequestMapping("auth")
+public class AuthController {
+ private final AuthService authService;
+
+ public AuthController(AuthService authService) {
+ this.authService = authService;
+ }
+
+ /**
+ * Attempts to log in as a user
+ *
+ * @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) {
+ String username = params.get("username");
+ String password = params.get("password");
+ try {
+ String key = authService.login(username, password);
+ return new ResponseEntity<>(key, HttpStatus.OK);
+ } catch (IllegalAccessException e) {
+ return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
+ } catch (IOException ex) {
+ return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * 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(@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 faaa98a..9592490 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
@@ -1,6 +1,7 @@
package com.ufund.api.ufundapi.controller;
import java.io.IOException;
+import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -17,37 +18,48 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ufund.api.ufundapi.model.Need;
-import com.ufund.api.ufundapi.persistence.CupboardDAO;
+import com.ufund.api.ufundapi.model.Need.GoalType;
+import com.ufund.api.ufundapi.service.CupboardService;
+import com.ufund.api.ufundapi.DuplicateKeyException;
@RestController
@RequestMapping("cupboard")
public class CupboardController {
private static final Logger LOG = Logger.getLogger(CupboardController.class.getName());
- private final CupboardDAO cupboardDAO;
+ private final CupboardService cupboardService;
/**
* Create a cupboard controller to receive REST signals
*
- * @param cupboardDAO The Data Access Object
+ * @param cupboardService The Data Access Object
*/
- public CupboardController(CupboardDAO cupboardDAO) {
- this.cupboardDAO = cupboardDAO;
+ public CupboardController(CupboardService cupboardService) {
+ this.cupboardService = cupboardService;
}
/**
* 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 Need need) {
+ public ResponseEntity<Need> createNeed(@RequestBody Map<String, Object> params) {
+ System.out.println(params);
+ String name = (String) params.get("name");
+ int maxGoal = (int) params.get("maxGoal");
+ Need.GoalType goalType = GoalType.valueOf((String) params.get("type"));
+
try {
- if (need.getMaxGoal() <= 0) {
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
- }
- cupboardDAO.createNeed(need);
+ Need need = cupboardService.createNeed(name, maxGoal, goalType);
return new ResponseEntity<>(need, HttpStatus.OK);
+ } catch (DuplicateKeyException ex) {
+ return new ResponseEntity<>(HttpStatus.CONFLICT);
+ } catch (IllegalArgumentException ex) {
+ return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY);
} catch (IOException ex) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
@@ -66,7 +78,7 @@ public class CupboardController {
LOG.info("GET /needs");
try {
- Need[] needs = cupboardDAO.getNeeds();
+ Need[] needs = cupboardService.getNeeds();
return new ResponseEntity<>(needs, HttpStatus.OK);
} catch (IOException e) {
LOG.log(Level.SEVERE, e.getLocalizedMessage());
@@ -90,8 +102,8 @@ public class CupboardController {
LOG.info("GET /need/?name="+name);
try {
- Need[] needArray = cupboardDAO.findNeeds(name);
- return new ResponseEntity<>(needArray, HttpStatus.OK);
+ Need[] needs = cupboardService.searchNeeds(name);
+ return new ResponseEntity<>(needs, HttpStatus.OK);
} catch (IOException e) {
LOG.log(Level.SEVERE,e.getLocalizedMessage());
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
@@ -103,23 +115,20 @@ 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) {
LOG.log(Level.INFO, "GET /need/{0}", id);
try {
- Need need = cupboardDAO.getNeed(id);
+ Need need = cupboardService.getNeed(id);
if (need != null) {
return new ResponseEntity<>(need, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
-
} catch (IOException e) {
LOG.log(Level.SEVERE, e.getLocalizedMessage());
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
@@ -133,13 +142,20 @@ 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) {
+ @PutMapping("/{id}")
+ public ResponseEntity<Need> updateNeed(@RequestBody Need need, @PathVariable int id) {
try {
- need = cupboardDAO.updateNeed(need);
- return new ResponseEntity<>(need, HttpStatus.OK);
- } catch (IOException e) {
+ Need updatedNeed = cupboardService.updateNeed(need, id);
+ if (updatedNeed != null) {
+ return new ResponseEntity<>(need, HttpStatus.OK);
+ } else {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+ } catch (IOException ex) {
+ ex.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@@ -153,9 +169,9 @@ public class CupboardController {
@DeleteMapping("/{id}")
public ResponseEntity<Need> deleteNeed(@PathVariable int id) {
try {
- if (cupboardDAO.getNeed(id) != null) {
- cupboardDAO.deleteNeed(id);
- return new ResponseEntity<>(HttpStatus.OK);
+ Need need = cupboardService.getNeed(id);
+ if (cupboardService.deleteNeed(id)) {
+ return new ResponseEntity<>(need, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/UserController.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/UserController.java
index 4e5f156..adf17a1 100644
--- a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/UserController.java
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/UserController.java
@@ -1,6 +1,8 @@
package com.ufund.api.ufundapi.controller;
import java.io.IOException;
+import java.security.InvalidParameterException;
+import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -12,43 +14,47 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import com.ufund.api.ufundapi.DuplicateKeyException;
import com.ufund.api.ufundapi.model.User;
-import com.ufund.api.ufundapi.persistence.UserDAO;
+import com.ufund.api.ufundapi.service.AuthService;
+import com.ufund.api.ufundapi.service.UserService;
@RestController
@RequestMapping("users")
public class UserController {
- private static final Logger LOG = Logger.getLogger(CupboardController.class.getName());
- private final UserDAO UserDAO;
+ private static final Logger LOG = Logger.getLogger(UserController.class.getName());
+ private final UserService userService;
+ private final AuthService authService;
- /**
- * Create a user controller to receive REST signals
- *
- * @param userDAO The Data Access Object
- */
- public UserController(UserDAO userDAO) {
- this.UserDAO = userDAO;
+ public UserController(UserService userService, AuthService authService) {
+ this.userService = userService;
+ this.authService = authService;
}
/**
* Creates a User with the provided object
- *
- * @param user The user to create
+ * @param params A map consisting of the parameters for a user
* @return OK response and the user if it was successful, INTERNAL_SERVER_ERROR
* otherwise
*/
@PostMapping("")
- public ResponseEntity<User> createUser(@RequestBody User user) {
+ public ResponseEntity<User> createUser(@RequestBody Map<String, String> params) {
+ String username = params.get("username");
+ String password = params.get("password");
+
try {
- if (UserDAO.createUser(user) != null) {
+ User user = userService.createUser(username, password);
+ if (user != null) {
return new ResponseEntity<>(user, HttpStatus.CREATED);
} else {
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
-
+ } catch (DuplicateKeyException ex) {
+ return new ResponseEntity<>(HttpStatus.CONFLICT);
} catch (IOException ex) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
@@ -57,23 +63,27 @@ public class UserController {
/**
* Responds to the GET request for a {@linkplain User user} for the given id
*
+ * @param username The name of the user
+ * @param key The authentication key of the user
* @return ResponseEntity with {@link User user} 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("/{name}")
- public ResponseEntity<User> getUser(@PathVariable String name) {
- LOG.log(Level.INFO, "GET /user/{0}", name);
+ @GetMapping("/{username}")
+ public ResponseEntity<User> getUser(@PathVariable String username, @RequestHeader("jelly-api-key") String key) {
+ LOG.log(Level.INFO, "GET /user/{0}", username);
try {
- User user = UserDAO.getUser(name);
+ authService.authenticate(username, key);
+ User user = userService.getUser(username);
if (user != null) {
- return new ResponseEntity<>(user, HttpStatus.OK);
+ return new ResponseEntity<>(user.withoutPasswordHash(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
-
+ } catch (IllegalAccessException ex) {
+ return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
} catch (IOException e) {
LOG.log(Level.SEVERE, e.getLocalizedMessage());
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
@@ -84,42 +94,53 @@ public class UserController {
/**
* Updates a User with the provided one
*
- * @param user The user to update
+ * @param user The user to update
+ * @param username The name of the user
+ * @param key The authentication key of the user
* @return OK response and the user if it was successful, or
* INTERNAL_SERVER_ERROR if there was an issue
*/
- @PutMapping("/{name}")
- public ResponseEntity<User> updateUser(@RequestBody User user, @PathVariable String name) {
+ @PutMapping("/{username}")
+ public ResponseEntity<User> updateUser(@RequestBody User user, @PathVariable String username, @RequestHeader("jelly-api-key") String key) {
try {
- user = UserDAO.updateUser(user, name);
+ authService.authenticate(username, key);
+ user = userService.updateUser(user, username);
if (user != null) {
return new ResponseEntity<>(user, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
-
+ } catch (InvalidParameterException ex) {
+ return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} catch (IOException e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ } catch (IllegalAccessException e) {
+ return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
}
/**
* Deletes a user with the desired name
*
- * @param name The name of the user
+ * @param username The name of the user
+ * @param key The authentication key of the user
* @return OK if the user was deleted, NOT_FOUND if the user was not found, or
* INTERNAL_SERVER_ERROR if an error occurred
*/
- @DeleteMapping("/{name}")
- public ResponseEntity<User> deleteUser(@PathVariable String name) {
+ @DeleteMapping("/{username}")
+ public ResponseEntity<Boolean> deleteUser(@PathVariable String username, @RequestHeader("jelly-api-key") String key) {
+
try {
- if (UserDAO.deleteUser(name)) {
+ authService.authenticate(username, key);
+ if (userService.deleteUser(username)) {
return new ResponseEntity<>(HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
} catch (IOException e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ } catch (IllegalAccessException e) {
+ return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
}
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java
index 2611357..c0e9214 100644
--- a/ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/model/Need.java
@@ -14,7 +14,7 @@ public class Need {
@JsonProperty("filterAttributes") private String[] filterAttributes;
@JsonProperty("type") final private GoalType type;
@JsonProperty("maxGoal") private double maxGoal;
- @JsonProperty("Current") private double current;
+ @JsonProperty("current") private double current;
/**
* Create a new need
@@ -32,6 +32,19 @@ public class Need {
}
/**
+ * Create a new need
+ *
+ * @param name The name of the need
+ * @param maxGoal The maximum goal for this need
+ * @param type The type of need (monetary, physical)
+ */
+ public Need(String name, GoalType type, double maxGoal) {
+ this.name = name;
+ this.type = type;
+ this.maxGoal = maxGoal;
+ }
+
+ /**
* Create a deep copy of another need
*
* @param other The need to copy from
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/model/User.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/model/User.java
index 59f4c46..f08f9f0 100644
--- a/ufund-api/src/main/java/com/ufund/api/ufundapi/model/User.java
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/model/User.java
@@ -7,46 +7,40 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class User {
- @JsonProperty("name")
- private final String name;
- @JsonProperty("passwordHash")
- private int passwordHash;
- @JsonProperty("basket")
- private final List<Need> basket;
-
- /**
- * Create a new user
- *
- * @param name The name of the user
- */
- public User(String name) {
- this.name = name;
- basket = new ArrayList<>();
+ public enum UserType {
+ HELPER,
+ MANAGER
}
+ @JsonProperty("username") private final String username;
+ @JsonProperty("passwordHash") private int passwordHash;
+ @JsonProperty("basket") private final List<Integer> basket;
+ @JsonProperty("type") private final UserType type;
+
/**
* Create a new user
*
- * @param name The name of the user
+ * @param username The name of the user
* @param basket A basket to copy from
*/
- public User(@JsonProperty("name") String name, @JsonProperty("basket") List<Need> basket) {
- this.name = name;
+ public User(@JsonProperty("username") String username, @JsonProperty("passwordHash") int passwordHash, @JsonProperty("basket") List<Integer> basket, @JsonProperty("type") UserType userType) {
+ this.username = username;
this.basket = basket;
+ this.passwordHash = passwordHash;
+ this.type = userType;
}
- /**
- * Create a deep copy of another user
- *
- * @param other The user to copy from
- */
- public User(User other) {
- this.name = other.name;
- this.basket = other.basket;
+ public static User create(String username, String password) {
+ return new User(
+ username,
+ password.hashCode(),
+ new ArrayList<>(),
+ UserType.HELPER
+ );
}
- public String getName() {
- return name;
+ public String getUsername() {
+ return username;
}
public boolean verifyPassword(String password) {
@@ -54,15 +48,23 @@ public class User {
}
public void addToBasket(Need need) {
- basket.add(need);
+ basket.add(need.getId());
}
- public Need[] getBasketNeeds() {
- return basket.toArray(Need[]::new);
+ public Integer[] getBasketNeeds() {
+ return basket.toArray(Integer[]::new);
}
public void removeBasketNeed(Need need) {
- basket.remove(need);
+ basket.remove(need.getId());
+ }
+
+ public User withoutPasswordHash() {
+ return new User(this.username, 0, this.basket, this.type);
+ }
+
+ public UserType getType() {
+ return type;
}
}
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/model/UserAuth.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/model/UserAuth.java
new file mode 100644
index 0000000..1c11a28
--- /dev/null
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/model/UserAuth.java
@@ -0,0 +1,43 @@
+package com.ufund.api.ufundapi.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+public class UserAuth {
+ @JsonProperty("key") String key;
+ @JsonProperty("username") String username;
+ @JsonProperty("expiration") LocalDateTime expiration;
+
+ public UserAuth(@JsonProperty("key") String key, @JsonProperty("username") String username, @JsonProperty("expiration") LocalDateTime expiration) {
+ this.key = key;
+ this.expiration = expiration;
+ this.username = username;
+ }
+
+ /**
+ * Generate a new user authentication profile
+ * @param username the username the key will belong to
+ * @return The new user authentication profile
+ */
+ public static UserAuth generate(String username) {
+ return new UserAuth(
+ UUID.randomUUID().toString(),
+ username,
+ LocalDateTime.now().plusDays(30)
+ );
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public LocalDateTime getExpiration() {
+ return expiration;
+ }
+}
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 1435410..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
@@ -1,9 +1,9 @@
package com.ufund.api.ufundapi.persistence;
-import com.ufund.api.ufundapi.model.Need;
-
import java.io.IOException;
+import com.ufund.api.ufundapi.model.Need;
+
/**
* Defines the interface for Need object persistence
*
@@ -14,23 +14,10 @@ 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;
/**
- * Finds all {@linkplain Need needs} whose name contains the given text
- *
- * @param targetName The text to match against
- *
- * @return An array of {@link Need needs} whose names contains the given text, may be empty
- *
- * @throws IOException if an issue with underlying storage
- */
- Need[] findNeeds(String targetName) throws IOException;
-
- /**
* Retrieves a {@linkplain Need need} with the given name
*
* @param id The ID of the {@link Need need} to get
@@ -38,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;
@@ -54,7 +39,7 @@ public interface CupboardDAO {
*
* @throws IOException if an issue with underlying storage
*/
- Need createNeed(Need need) throws IOException;
+ Need addNeed(Need need) throws IOException;
/**
* Updates and saves a {@linkplain Need need}
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 81ee7c0..521acae 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,18 +11,18 @@ 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<>();
- load(); // load the heroes from the file
+ load();
}
private synchronized static int nextId() {
@@ -61,18 +61,6 @@ public class CupboardFileDao implements CupboardDAO {
}
/**
- * Returns an array of needs filtered by a search
- *
- * @param search The search substring
- * @return The requested array
- */
- private Need[] getNeedsArray(String search) {
- return needs.values().stream()
- .filter(i -> i.getName().toLowerCase().contains(search.toLowerCase()))
- .toArray(Need[]::new);
- }
-
- /**
* Saves the needs to json
*
* @return True if the save was successful, false otherwise
@@ -93,13 +81,6 @@ public class CupboardFileDao implements CupboardDAO {
}
@Override
- public Need[] findNeeds(String targetName) {
- synchronized (needs) {
- return getNeedsArray(targetName);
- }
- }
-
- @Override
public Need getNeed(int id) {
synchronized (needs) {
return needs.getOrDefault(id, null);
@@ -107,7 +88,7 @@ public class CupboardFileDao implements CupboardDAO {
}
@Override
- public Need createNeed(Need need) throws IOException {
+ public Need addNeed(Need need) throws IOException {
synchronized (needs) {
Need newNeed = new Need(need);
newNeed.setID(nextId());
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
new file mode 100644
index 0000000..355aae4
--- /dev/null
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthDAO.java
@@ -0,0 +1,32 @@
+package com.ufund.api.ufundapi.persistence;
+
+import com.ufund.api.ufundapi.model.UserAuth;
+
+import java.io.IOException;
+
+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) throws IOException;
+
+ /**
+ * Add a user authentication profile
+ *
+ * @param userAuth The user auth profile to add
+ * @throws IOException Thrown on any file writing error
+ */
+ 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
new file mode 100644
index 0000000..1fc1e92
--- /dev/null
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java
@@ -0,0 +1,73 @@
+package com.ufund.api.ufundapi.persistence;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ufund.api.ufundapi.model.UserAuth;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class UserAuthFIleDAO implements UserAuthDAO {
+
+ private final Map<String, UserAuth> userAuthMap;
+ private final ObjectMapper objectMapper;
+ private final String filename;
+
+ public UserAuthFIleDAO(ObjectMapper objectMapper, @Value("${authKeys.file}") String filename) throws IOException {
+ this.userAuthMap = new HashMap<>();
+ this.objectMapper = objectMapper;
+ this.filename = filename;
+ 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();
+
+ UserAuth[] userAuthKeysArray = objectMapper.readValue(new File(filename), UserAuth[].class);
+
+ for (UserAuth userAuth : userAuthKeysArray) {
+ userAuthMap.put(userAuth.getKey(), userAuth);
+ }
+ }
+
+ /**
+ * 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());
+ }
+
+ @Override
+ public UserAuth getUserAuth(String key) {
+ synchronized (userAuthMap) {
+ return userAuthMap.get(key);
+ }
+ }
+
+ @Override
+ public void addUserAuth(UserAuth userAuth) throws IOException {
+ synchronized (userAuthMap) {
+ userAuthMap.put(userAuth.getKey(), userAuth);
+ save();
+ }
+ }
+
+ @Override
+ public void removeUserAuth(String key) throws IOException {
+ synchronized (userAuthMap) {
+ userAuthMap.remove(key);
+ save();
+ }
+ }
+}
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserDAO.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserDAO.java
index d456abc..29d46cf 100644
--- a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserDAO.java
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserDAO.java
@@ -21,17 +21,17 @@ public interface UserDAO {
User[] getUsers() throws IOException;
/**
- * Retrieves a {@linkplain User user} with the given name
+ * Retrieves a {@linkplain User user} with the given username
*
- * @param id The ID of the {@link User user} to get
+ * @param username The ID of the {@link User user} to get
*
- * @return a {@link User user} object with the matching name
+ * @return a {@link User user} object with the matching username
* <br>
- * null if no {@link User user} with a matching name is found
+ * null if no {@link User user} with a matching username is found
*
* @throws IOException if an issue with underlying storage
*/
- User getUser(String name) throws IOException;
+ User getUser(String username) throws IOException;
/**
* Creates and saves a {@linkplain User user}
@@ -44,25 +44,24 @@ public interface UserDAO {
*
* @throws IOException if an issue with underlying storage
*/
- User createUser(User user) throws IOException;
+ User addUser(User user) throws IOException;
/**
* Updates and saves a {@linkplain User user}
*
- * @param newUser {@link User user} object to be updated and saved
- * @param name {@link String name} name of object to be updated
+ * @param user {@link User user} object to be updated and saved
*
* @return updated {@link User user} if successful, null if
* {@link User user} could not be found
*
* @throws IOException if underlying storage cannot be accessed
*/
- User updateUser(User newUser, String name) throws IOException;
+ User updateUser(User user) throws IOException;
/**
* Deletes a {@linkplain User user} with the given id
*
- * @param id The id of the {@link User user}
+ * @param username The id of the {@link User user}
*
* @return true if the {@link User user} was deleted
* <br>
@@ -70,5 +69,5 @@ public interface UserDAO {
*
* @throws IOException if underlying storage cannot be accessed
*/
- boolean deleteUser(String name) throws IOException;
+ boolean deleteUser(String username) throws IOException;
}
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 18eec18..f17f8f2 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,8 +2,8 @@ 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;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -21,7 +21,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
}
@@ -36,7 +36,7 @@ public class UserFileDAO implements UserDAO {
User[] usersArray = objectMapper.readValue(new File(filename), User[].class);
for (User user : usersArray) {
- users.put(user.getName(), user);
+ users.put(user.getUsername(), user);
}
}
@@ -47,100 +47,54 @@ 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);
}
}
- /**
- * Return the user with the String name name or null otherwise
- *
- * @param name 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 name) throws IOException {
+ public User getUser(String username) {
synchronized (users) {
- return users.getOrDefault(name, null);
+ return users.getOrDefault(username, null);
}
}
- /**
- * Create a User user
- *
- * @param user User to create
- *
- * @return Desired created user
- * @throws IOException If there was an IO issue saving the file
- */
@Override
- public User createUser(User user) throws IOException {
+ public User addUser(User user) throws IOException {
synchronized (users) {
- if (getUser(user.getName()) == null) {
- User newUser = new User(user);
- users.put(newUser.getName(), newUser);
- save();
- return newUser;
- } else {
- return null;
+ var res = users.putIfAbsent(user.getUsername(), user);
+ save();
+ if (res == null) {
+ return user;
}
+ return res;
}
}
- /**
- * Update a user that matches the supplied name
- *
- * @param name The name of the user
- * @param newUser New user data
- *
- * @return Desired user, null otherwise
- * @throws IOException If there was an IO issue saving the file
- */
@Override
- public User updateUser(User newUser, String name) throws IOException {
+ public User updateUser(User user) throws IOException {
synchronized (users) {
- if (users.containsKey(name)) {
- users.put(name, newUser);
+ if (users.containsKey(user.getUsername())) {
+ users.put(user.getUsername(), user);
save();
- return newUser;
+ return user;
} else {
return null;
}
}
}
- /**
- * Delete a user matching the name
- *
- * @param name The name of the user
- *
- * @return True if deleted, false otherwise
- * @throws IOException If there was an IO issue saving the file
- */
@Override
- public boolean deleteUser(String name) throws IOException {
+ public boolean deleteUser(String username) throws IOException {
synchronized (users) {
- if (users.containsKey(name)) {
- users.remove(name);
+ if (users.containsKey(username)) {
+ users.remove(username);
return save();
} else {
return false;
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
new file mode 100644
index 0000000..87a16a6
--- /dev/null
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java
@@ -0,0 +1,70 @@
+package com.ufund.api.ufundapi.service;
+
+import com.ufund.api.ufundapi.model.User;
+import com.ufund.api.ufundapi.model.UserAuth;
+import com.ufund.api.ufundapi.persistence.UserAuthDAO;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+@Component
+public class AuthService {
+
+ private final UserAuthDAO userAuthDAO;
+ private final UserService userService;
+
+ public AuthService(UserAuthDAO userAuthDAO, UserService userService) {
+ this.userAuthDAO = userAuthDAO;
+ this.userService = userService;
+ }
+
+ /**
+ * Check if the provided key has access to the provided user.
+ *
+ * @param targetUsername The targetUsername 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 targetUsername, String key) throws IllegalAccessException, IOException {
+ var userAuth = userAuthDAO.getUserAuth(key);
+ if (userAuth == null) {
+ throw new IllegalAccessException("Unauthenticated");
+ }
+//
+// var username = userAuth.getUsername();
+// var userType = userService.getUser(username).getType();
+// if (!username.equals(targetUsername) && userType != User.UserType.MANAGER) {
+// 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)) {
+ throw new IllegalAccessException("Unauthorized");
+ }
+ var userAuth = UserAuth.generate(username);
+ userAuthDAO.addUserAuth(userAuth);
+ 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
new file mode 100644
index 0000000..2398745
--- /dev/null
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java
@@ -0,0 +1,109 @@
+package com.ufund.api.ufundapi.service;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.springframework.stereotype.Component;
+
+import com.ufund.api.ufundapi.DuplicateKeyException;
+import com.ufund.api.ufundapi.model.Need;
+import com.ufund.api.ufundapi.persistence.CupboardDAO;
+
+@Component
+public class CupboardService {
+
+ private final CupboardDAO cupboardDAO;
+
+ public CupboardService(CupboardDAO cupboardDAO) {
+ this.cupboardDAO = cupboardDAO;
+ }
+
+ /**
+ * Creates a new Need
+ *
+ * @param name The name of the need to create
+ * @param maxGoal The max goal of the new need
+ * @param goalType The goal type of the new need
+ * @return The need that was created
+ * @throws IOException Thrown if there was any issue saving the data
+ * @throws DuplicateKeyException If there already exists a need with the same name
+ */
+ public Need createNeed(String name, double maxGoal, Need.GoalType goalType) throws IOException, DuplicateKeyException {
+
+ if (maxGoal <= 0) {
+ throw new IllegalArgumentException("Max Goal must be greater than zero");
+ }
+
+ for (Need searchNeed : cupboardDAO.getNeeds()) {
+ if (searchNeed.getName().equalsIgnoreCase(name)) {
+ throw new DuplicateKeyException("Duplicate names are not allowed");
+ }
+ }
+
+ Need need = new Need(name, goalType, maxGoal);
+ return cupboardDAO.addNeed(need);
+
+ }
+
+ /**
+ * Get all the needs in the cupboard
+ *
+ * @return An array containing all needs
+ * @throws IOException Thrown if there was any issue saving the data
+ */
+ public Need[] getNeeds() throws IOException {
+ return cupboardDAO.getNeeds();
+ }
+
+ /**
+ * Returns an array of needs filtered by a search
+ *
+ * @param search The search substring
+ * @return The requested array
+ * @throws IOException Thrown if there was any issue saving the data
+ */
+ public Need[] searchNeeds(String search) throws IOException {
+ return Arrays.stream(cupboardDAO.getNeeds())
+ .filter(i -> i.getName().toLowerCase().contains(search.toLowerCase()))
+ .toArray(Need[]::new);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Updates a need
+ *
+ * @param id The ID of the need to update
+ * @param need The need object to set (note: the ID is ignored)
+ * @return The updated need object
+ * @throws IOException Thrown if there was an issue saving the changes
+ */
+ public Need updateNeed(Need need, int id) throws IOException {
+ if (need.getId() != id) {
+ throw new IllegalArgumentException("ID in URL and body must match");
+ }
+ if (need.getMaxGoal() <= 0) {
+ throw new IllegalArgumentException("Goal must be greater than 0");
+ }
+ 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
new file mode 100644
index 0000000..935ee72
--- /dev/null
+++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java
@@ -0,0 +1,72 @@
+package com.ufund.api.ufundapi.service;
+
+import java.io.IOException;
+
+import com.ufund.api.ufundapi.DuplicateKeyException;
+import com.ufund.api.ufundapi.model.User;
+import com.ufund.api.ufundapi.persistence.UserDAO;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserService {
+
+ private final UserDAO userDAO;
+
+ public UserService(UserDAO userDao) {
+ this.userDAO = userDao;
+ }
+
+ /**
+ * Creates a new user
+ *
+ * @param username The username of the user
+ * @param password The password of the user
+ * @return The created user object
+ * @throws IOException Thrown on any problem saving the file
+ */
+ public User createUser(String username, String password) throws IOException, DuplicateKeyException {
+ if (userDAO.getUser(username) != null) {
+ throw new DuplicateKeyException("A user with this name already exists");
+ }
+ User user = User.create(username, password);
+ return userDAO.addUser(user);
+ }
+
+ /**
+ * Gets a user with the given username
+ *
+ * @param username The username of the user
+ * @return The user object with that username
+ * @throws IOException If there was any problem saving the file
+ */
+ public User getUser(String username) throws IOException {
+ return userDAO.getUser(username);
+ }
+
+ /**
+ * Updates a user
+ *
+ * @param user The ID of the user to update
+ * @param username The user object to set (note: the ID is ignored)
+ * @return The updated user object
+ * @throws IOException Thrown if there was any issue saving the data
+ */
+ public User updateUser(User user, String username) throws IOException {
+ if (!user.getUsername().equals(username)) {
+ throw new IllegalArgumentException("ID in URL and body must match");
+ }
+ return userDAO.updateUser(user);
+ }
+
+ /**
+ * Deletes a user
+ *
+ * @param username The username of the user to delete
+ * @return True if the user was deleted
+ * @throws IOException Thrown if there was any issue saving the data
+ */
+ public boolean deleteUser(String username) throws IOException {
+ return userDAO.deleteUser(username);
+ }
+
+}
diff --git a/ufund-api/src/main/resources/application.properties b/ufund-api/src/main/resources/application.properties
index a866f98..c742063 100644
--- a/ufund-api/src/main/resources/application.properties
+++ b/ufund-api/src/main/resources/application.properties
@@ -1,8 +1,8 @@
-# rename to application.properties
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/AuthControllerTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/AuthControllerTest.java
new file mode 100644
index 0000000..3d4637d
--- /dev/null
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/AuthControllerTest.java
@@ -0,0 +1,104 @@
+package com.ufund.api.ufundapi.controller;
+
+import java.io.IOException;
+import java.util.Map;
+import static java.util.Map.entry;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import static org.mockito.ArgumentMatchers.any;
+import org.mockito.Mockito;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import com.ufund.api.ufundapi.service.AuthService;
+
+@RequestMapping("auth")
+public class AuthControllerTest {
+
+ private AuthController authController;
+ private AuthService mockAuthService;
+ private Map<String, String> authMap;
+
+ @BeforeEach
+ private void setupAuthController() {
+ mockAuthService = mock(AuthService.class);
+ authController = new AuthController(mockAuthService);
+
+ authMap = Map.ofEntries(
+ entry("Bob", "123")
+ );
+ }
+
+ @Test
+ public void testLogin() throws IllegalAccessException, IOException {
+ // Setup
+ String key = "123";
+
+ // Mock
+ when(mockAuthService.login(any(), any())).thenReturn(key);
+
+ // Invoke
+ ResponseEntity<String> response = authController.login(authMap);
+
+ // Analyze
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ assertEquals(key, response.getBody());
+ }
+
+ @Test
+ public void testLoginUnauthorized() throws IllegalAccessException, IOException {
+ // Mock
+ when(mockAuthService.login(any(), any())).thenThrow(IllegalAccessException.class);
+
+ // Invoke
+ ResponseEntity<String> response = authController.login(authMap);
+
+ // Analyze
+ assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
+ }
+
+ @Test
+ public void testLoginIOException() throws IllegalAccessException, IOException {
+ // Mock
+ when(mockAuthService.login(any(), any())).thenThrow(IOException.class);
+
+ // Invoke
+ ResponseEntity<String> response = authController.login(authMap);
+
+ // Analyze
+ assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+ }
+
+ @Test
+ public void testLogout() throws IllegalAccessException, IOException {
+ // Setup
+ String key = "123";
+
+ // Invoke
+ ResponseEntity<Object> response = authController.logout(key);
+
+ // Analyze
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ }
+
+ @Test
+ public void testLogoutIOException() throws IllegalAccessException, IOException {
+ // Setup
+ String key = "123";
+
+ // Mock
+ doThrow(new IOException()).when(mockAuthService).logout(key);
+
+ // Invoke
+ ResponseEntity<Object> response = authController.logout(key);
+
+ // Analyze
+ assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
+ }
+}
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 839c518..94f93cb 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,6 +1,8 @@
package com.ufund.api.ufundapi.controller;
import java.io.IOException;
+import java.util.Map;
+import static java.util.Map.entry;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -11,54 +13,74 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.springframework.http.HttpStatus;
+import com.ufund.api.ufundapi.DuplicateKeyException;
import com.ufund.api.ufundapi.model.Need;
-import com.ufund.api.ufundapi.persistence.CupboardFileDao;
+import com.ufund.api.ufundapi.model.Need.GoalType;
+import com.ufund.api.ufundapi.service.CupboardService;
public class CupboardControllerTest {
private CupboardController cupboardController;
- private CupboardFileDao mockCupboardDAO;
+ private CupboardService mockCupboardService;
@BeforeEach
public void setupCupboardDAO() {
- mockCupboardDAO = mock(CupboardFileDao.class);
- cupboardController = new CupboardController(mockCupboardDAO);
+ mockCupboardService = mock(CupboardService.class);
+ cupboardController = new CupboardController(mockCupboardService);
}
@Test
- public void createNeed() throws IOException {
- var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.createNeed(need)).thenReturn(need);
+ public void createNeed() throws IOException, DuplicateKeyException {
+ String name = "Test";
+ int maxGoal = 100;
+ GoalType type = Need.GoalType.MONETARY;
+ var need = new Need(name, type, maxGoal);
+ when(mockCupboardService.createNeed(name, maxGoal, type)).thenReturn(need);
+
- var res = cupboardController.createNeed(need);
+ Map<String, Object> needMap = Map.ofEntries(
+ entry("name", "Test"),
+ entry("maxGoal", 100),
+ entry("type", "MONETARY")
+ );
+
+ var res = cupboardController.createNeed(needMap);
assertEquals(HttpStatus.OK, res.getStatusCode());
assertEquals(need, res.getBody());
}
@Test
- public void createNeedBadMaxGoal() throws IOException {
- var need = new Need("Name", 1, -100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.createNeed(need)).thenReturn(need);
+ public void createNeedBadMaxGoal() throws IOException, DuplicateKeyException {
+ when(mockCupboardService.createNeed("Name", -100, Need.GoalType.MONETARY)).thenThrow(new IllegalArgumentException());
+
+ Map<String, Object> needMap = Map.ofEntries(
+ entry("name", "Name"),
+ entry("maxGoal", -100),
+ entry("type", "MONETARY"));
- var res = cupboardController.createNeed(need);
+ var res = cupboardController.createNeed(needMap);
- assertEquals(HttpStatus.BAD_REQUEST, res.getStatusCode());
+ assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, res.getStatusCode());
}
@Test
- public void createNeedIOException() throws IOException {
- var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.createNeed(need)).thenThrow(new IOException());
+ public void createNeedIOException() throws IOException, DuplicateKeyException {
+ when(mockCupboardService.createNeed("Name", 100, Need.GoalType.MONETARY)).thenThrow(new IOException());
+
+ Map<String, Object> needMap = Map.ofEntries(
+ entry("name", "Name"),
+ entry("maxGoal", 100),
+ entry("type", "MONETARY"));
- var res = cupboardController.createNeed(need);
+ var res = cupboardController.createNeed(needMap);
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, res.getStatusCode());
}
@Test
- public void getNeeds() {
+ public void getNeeds() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.getNeeds()).thenReturn(new Need[]{need});
+ when(mockCupboardService.getNeeds()).thenReturn(new Need[]{need});
var res = cupboardController.getNeeds();
@@ -67,9 +89,8 @@ public class CupboardControllerTest {
}
@Test
- public void getNeedsIOException() {
- var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.getNeeds()).thenThrow(new IOException());
+ public void getNeedsIOException() throws IOException {
+ when(mockCupboardService.getNeeds()).thenThrow(new IOException());
var res = cupboardController.getNeeds();
@@ -77,8 +98,8 @@ public class CupboardControllerTest {
}
@Test
- public void getNeedsEmpty() {
- when(mockCupboardDAO.getNeeds()).thenReturn(new Need[]{});
+ public void getNeedsEmpty() throws IOException {
+ when(mockCupboardService.getNeeds()).thenReturn(new Need[]{});
var res = cupboardController.getNeeds();
@@ -87,9 +108,9 @@ public class CupboardControllerTest {
}
@Test
- public void searchNeeds() {
+ public void searchNeeds() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.findNeeds("Na")).thenReturn(new Need[]{need});
+ when(mockCupboardService.searchNeeds("Na")).thenReturn(new Need[]{need});
var res = cupboardController.searchNeeds("Na");
@@ -98,9 +119,8 @@ public class CupboardControllerTest {
}
@Test
- public void searchNeedsIOException() {
- var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.findNeeds("Na")).thenThrow(new IOException());
+ public void searchNeedsIOException() throws IOException {
+ when(mockCupboardService.searchNeeds("Na")).thenThrow(new IOException());
var res = cupboardController.searchNeeds("Na");
@@ -108,8 +128,8 @@ public class CupboardControllerTest {
}
@Test
- public void searchNeedsEmpty() {
- when(mockCupboardDAO.findNeeds("Na")).thenReturn(new Need[]{});
+ public void searchNeedsEmpty() throws IOException {
+ when(mockCupboardService.searchNeeds("Na")).thenReturn(new Need[]{});
var res = cupboardController.searchNeeds("Na");
@@ -118,9 +138,9 @@ public class CupboardControllerTest {
}
@Test
- public void getNeed() {
+ public void getNeed() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.getNeed(need.getId())).thenReturn(need);
+ when(mockCupboardService.getNeed(need.getId())).thenReturn(need);
var res = cupboardController.getNeed(need.getId());
@@ -129,9 +149,9 @@ public class CupboardControllerTest {
}
@Test
- public void getNeedIOException() {
+ public void getNeedIOException() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.getNeed(need.getId())).thenThrow(new IOException());
+ when(mockCupboardService.getNeed(need.getId())).thenThrow(new IOException());
var res = cupboardController.getNeed(need.getId());
@@ -139,9 +159,9 @@ public class CupboardControllerTest {
}
@Test
- public void getNeedFail() {
+ public void getNeedFail() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.getNeed(need.getId())).thenReturn(null);
+ when(mockCupboardService.getNeed(need.getId())).thenReturn(null);
var res = cupboardController.getNeed(need.getId());
@@ -152,9 +172,9 @@ public class CupboardControllerTest {
@Test
public void updateNeeds() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.updateNeed(need)).thenReturn(need);
+ when(mockCupboardService.updateNeed(need, 1)).thenReturn(need);
- var res = cupboardController.updateNeed(need);
+ var res = cupboardController.updateNeed(need, 1);
assertEquals(HttpStatus.OK, res.getStatusCode());
assertEquals(need, res.getBody());
@@ -163,9 +183,9 @@ public class CupboardControllerTest {
@Test
public void updateNeedsIOException() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.updateNeed(need)).thenThrow(new IOException());
+ when(mockCupboardService.updateNeed(need, 1)).thenThrow(new IOException());
- var res = cupboardController.updateNeed(need);
+ var res = cupboardController.updateNeed(need, 1);
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, res.getStatusCode());
}
@@ -173,8 +193,8 @@ public class CupboardControllerTest {
@Test
public void deleteNeed() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.getNeed(1)).thenReturn(need);
- when(mockCupboardDAO.deleteNeed(1)).thenReturn(true);
+ when(mockCupboardService.getNeed(1)).thenReturn(need);
+ when(mockCupboardService.deleteNeed(1)).thenReturn(true);
var res = cupboardController.deleteNeed(1);
@@ -183,8 +203,8 @@ public class CupboardControllerTest {
@Test
public void deleteNeedFail() throws IOException {
- when(mockCupboardDAO.getNeed(1)).thenReturn(null);
- when(mockCupboardDAO.deleteNeed(1)).thenReturn(false);
+ when(mockCupboardService.getNeed(1)).thenReturn(null);
+ when(mockCupboardService.deleteNeed(1)).thenReturn(false);
var res = cupboardController.deleteNeed(1);
@@ -194,8 +214,8 @@ public class CupboardControllerTest {
@Test
public void deleteNeedIOException() throws IOException {
var need = new Need("Name", 1, 100, Need.GoalType.MONETARY);
- when(mockCupboardDAO.getNeed(1)).thenReturn(need);
- when(mockCupboardDAO.deleteNeed(1)).thenThrow(new IOException());
+ when(mockCupboardService.getNeed(1)).thenReturn(need);
+ when(mockCupboardService.deleteNeed(1)).thenThrow(new IOException());
var res = cupboardController.deleteNeed(1);
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/UserControllerTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/UserControllerTest.java
index 681f47c..b6367ad 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/UserControllerTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/controller/UserControllerTest.java
@@ -1,8 +1,12 @@
package com.ufund.api.ufundapi.controller;
import java.io.IOException;
+import java.security.InvalidParameterException;
+import java.util.Map;
+import static java.util.Map.entry;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@@ -12,82 +16,111 @@ import static org.mockito.Mockito.when;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import com.ufund.api.ufundapi.DuplicateKeyException;
import com.ufund.api.ufundapi.model.User;
-import com.ufund.api.ufundapi.persistence.UserFileDAO;
+import com.ufund.api.ufundapi.model.UserAuth;
+import com.ufund.api.ufundapi.service.AuthService;
+import com.ufund.api.ufundapi.service.UserService;
@Tag("Controller-tier")
public class UserControllerTest {
private UserController userController;
- private UserFileDAO mockUserDAO;
+ private AuthService mockAuthService;
+ private UserService mockUserService;
+ private Map<String, String> userMap;
@BeforeEach
public void setupUserController() {
- mockUserDAO = mock(UserFileDAO.class);
- userController = new UserController(mockUserDAO);
-
+ mockUserService = mock(UserService.class);
+ mockAuthService = mock(AuthService.class);
+ userController = new UserController(mockUserService, mockAuthService);
+ userMap = Map.ofEntries(
+ entry("username", "Test"),
+ entry("password", "Pass")
+ );
}
@Test
public void testGetUser() throws IOException { // getUser may throw IOException
// Setup
String username = "Test";
- User user = new User(username);
+ User user = User.create(username, "pass");
+ String key = UserAuth.generate(username).getKey( );
// When the same id is passed in, our mock User DAO will return the User object
- when(mockUserDAO.getUser(username)).thenReturn(user);
+ when(mockUserService.getUser(username)).thenReturn(user);
+
// Invoke
- ResponseEntity<User> response = userController.getUser(username);
+ ResponseEntity<User> response = userController.getUser(username, key);
// Analyze
assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(user, response.getBody());
+ assertNotNull(response.getBody());
+ assertEquals(user.getUsername(), response.getBody().getUsername());
}
@Test
public void testGetUserNotFound() throws Exception { // createUser may throw IOException
// Setup
String username = "Test";
- // When the same id is passed in, our mock User DAO will return null, simulating
+ String key = UserAuth.generate(username).getKey();
+ // When the same id is passed in, our mock User service will return null, simulating
// no User found
- when(mockUserDAO.getUser(username)).thenReturn(null);
+ when(mockUserService.getUser(username)).thenReturn(null);
+
// Invoke
- ResponseEntity<User> response = userController.getUser(username);
+ ResponseEntity<User> response = userController.getUser(username, key);
// Analyze
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
}
@Test
+ public void testGetUserUnauthorized() throws Exception { // createUser may throw IOException
+ // Setup
+ String username = "Test";
+ String key = UserAuth.generate(username).getKey();
+ // When getUser is called on the Mock User service, throw an IOException
+ // doThrow(new IllegalAccessException()).when(mockUserService).getUser(username);
+ doThrow(new IllegalAccessException()).when(mockAuthService).authenticate(username, key);
+
+ // Invoke
+ ResponseEntity<User> response = userController.getUser(username, key);
+
+ // Analyze
+ assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
+ }
+
+ @Test
public void testGetUserHandleException() throws Exception { // createUser may throw IOException
// Setup
String username = "Test";
- // When getUser is called on the Mock User DAO, throw an IOException
- doThrow(new IOException()).when(mockUserDAO).getUser(username);
+ String key = UserAuth.generate(username).getKey();
+ // When getUser is called on the Mock User service, throw an IOException
+ doThrow(new IOException()).when(mockUserService).getUser(username);
// Invoke
- ResponseEntity<User> response = userController.getUser(username);
+ ResponseEntity<User> response = userController.getUser(username, key);
// Analyze
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
}
- /*****************************************************************
- * The following tests will fail until all userController methods
- * are implemented.
- ****************************************************************/
-
@Test
- public void testCreateUser() throws IOException { // createUser may throw IOException
+ public void testCreateUser() throws IOException, DuplicateKeyException { // createUser may throw IOException
// Setup
String username = "Test";
- User user = new User(username);
+ String password = "Pass";
+ User user = User.create(username, "pass");
// when createUser is called, return true simulating successful
// creation and save
- when(mockUserDAO.createUser(user)).thenReturn(user);
+ when(mockUserService.createUser(username, password)).thenReturn(user);
+
+
// Invoke
- ResponseEntity<User> response = userController.createUser(user);
+ ResponseEntity<User> response = userController.createUser(userMap);
// Analyze
assertEquals(HttpStatus.CREATED, response.getStatusCode());
@@ -95,32 +128,52 @@ public class UserControllerTest {
}
@Test
- public void testCreateUserFailed() throws IOException { // createUser may throw IOException
+ public void testCreateUserFailed() throws IOException, DuplicateKeyException { // createUser may throw IOException
// Setup
String username = "Test";
- User user = new User(username);
+ String password = "Pass";
// when createUser is called, return false simulating failed
// creation and save
- when(mockUserDAO.createUser(user)).thenReturn(null);
+ when(mockUserService.createUser(username, password)).thenReturn(null);
+
+
// Invoke
- ResponseEntity<User> response = userController.createUser(user);
+ ResponseEntity<User> response = userController.createUser(userMap);
// Analyze
assertEquals(HttpStatus.CONFLICT, response.getStatusCode());
}
@Test
- public void testCreateUserHandleException() throws IOException { // createUser may throw IOException
+ public void testCreateUserDuplicate() throws IOException, DuplicateKeyException { // createUser may throw IOException
// Setup
String username = "Test";
- User user = new User(username);
+ String password = "Pass";
+ // when createUser is called, return false simulating failed
+ // creation and save
+ when(mockUserService.createUser(username, password)).thenThrow(DuplicateKeyException.class);
- // When createUser is called on the Mock User DAO, throw an IOException
- doThrow(new IOException()).when(mockUserDAO).createUser(user);
+ // Invoke
+ ResponseEntity<User> response = userController.createUser(userMap);
+
+ // Analyze
+ assertEquals(HttpStatus.CONFLICT, response.getStatusCode());
+ }
+
+ @Test
+ public void testCreateUserHandleException() throws IOException, DuplicateKeyException { // createUser may throw IOException
+ // Setup
+ String username = "Test";
+ String password = "Pass";
+
+ // When createUser is called on the Mock User service, throw an IOException
+ doThrow(new IOException()).when(mockUserService).createUser(username, password);
+
+
// Invoke
- ResponseEntity<User> response = userController.createUser(user);
+ ResponseEntity<User> response = userController.createUser(userMap);
// Analyze
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
@@ -130,13 +183,14 @@ public class UserControllerTest {
public void testUpdateUser() throws IOException { // updateUser may throw IOException
// Setup
String username = "Test";
- User user = new User("Bob");
+ User user = User.create(username, "pass");
+ String key = UserAuth.generate(username).getKey();
// when updateUser is called, return true simulating successful
// update and save
- when(mockUserDAO.updateUser(user, username)).thenReturn(user);
+ when(mockUserService.updateUser(user, username)).thenReturn(user);
// Invoke
- ResponseEntity<User> response = userController.updateUser(user, username);
+ ResponseEntity<User> response = userController.updateUser(user, username, key);
// Analyze
assertEquals(HttpStatus.OK, response.getStatusCode());
@@ -147,42 +201,62 @@ public class UserControllerTest {
public void testUpdateUserFailed() throws IOException { // updateUser may throw IOException
// Setup
String username = "Test";
- User user = new User("Bob");
+ User user = User.create(username, "pass");
+ String key = UserAuth.generate(username).getKey();
// when updateUser is called, return true simulating successful
// update and save
- when(mockUserDAO.updateUser(user, username)).thenReturn(null);
+ when(mockUserService.updateUser(user, username)).thenReturn(null);
// Invoke
- ResponseEntity<User> response = userController.updateUser(user, username);
+ ResponseEntity<User> response = userController.updateUser(user, username, key);
// Analyze
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
}
@Test
- public void testUpdateUserHandleException() throws IOException { // updateUser may throw IOException
+ public void testUpdateUserInvalidParameter() throws IOException { // updateUser may throw IOException
// Setup
String username = "Test";
- User user = new User("Bob");
+ User user = User.create(username, "pass");
+ String key = UserAuth.generate(username).getKey();
// When updateUser is called on the Mock User DAO, throw an IOException
- doThrow(new IOException()).when(mockUserDAO).updateUser(user, username);
+ doThrow(new IOException()).when(mockUserService).updateUser(user, username);
// Invoke
- ResponseEntity<User> response = userController.updateUser(user, username);
+ ResponseEntity<User> response = userController.updateUser(user, username, key);
// Analyze
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
}
@Test
+ public void testUpdateUserUnauthorized() throws IOException, IllegalAccessException { // updateUser may throw IOException
+ // Setup
+ String username = "Test";
+ User user = User.create(username, "pass");
+ String key = UserAuth.generate(username).getKey();
+ // When updateUser is called on the Mock User service, throw a Invalid Parameter exception
+ // exception
+ doThrow(new IllegalAccessException()).when(mockAuthService).authenticate(username, key);
+
+ // Invoke
+ ResponseEntity<User> response = userController.updateUser(user, username, key);
+
+ // Analyze
+ assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
+ }
+
+ @Test
public void testDeleteUser() throws IOException { // deleteUser may throw IOException
// Setup
String username = "Test";
+ String key = UserAuth.generate(username).getKey();
// when deleteUser is called return true, simulating successful deletion
- when(mockUserDAO.deleteUser(username)).thenReturn(true);
+ when(mockUserService.deleteUser(username)).thenReturn(true);
// Invoke
- ResponseEntity<User> response = userController.deleteUser(username);
+ ResponseEntity<Boolean> response = userController.deleteUser(username, key);
// Analyze
assertEquals(HttpStatus.OK, response.getStatusCode());
@@ -192,11 +266,12 @@ public class UserControllerTest {
public void testDeleteUserNotFound() throws IOException { // deleteUser may throw IOException
// Setup
String username = "Test";
+ String key = UserAuth.generate(username).getKey();
// when deleteUser is called return false, simulating failed deletion
- when(mockUserDAO.deleteUser(username)).thenReturn(false);
+ when(mockUserService.deleteUser(username)).thenReturn(false);
// Invoke
- ResponseEntity<User> response = userController.deleteUser(username);
+ ResponseEntity<Boolean> response = userController.deleteUser(username, key);
// Analyze
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
@@ -206,14 +281,30 @@ public class UserControllerTest {
public void testDeleteUserHandleException() throws IOException { // deleteUser may throw IOException
// Setup
String username = "Test";
- // When deleteUser is called on the Mock User DAO, throw an IOException
- doThrow(new IOException()).when(mockUserDAO).deleteUser(username);
+ String key = UserAuth.generate(username).getKey();
+ // When deleteUser is called on the Mock User service, throw an IOException
+ doThrow(new IOException()).when(mockUserService).deleteUser(username);
// Invoke
- ResponseEntity<User> response = userController.deleteUser(username);
+ ResponseEntity<Boolean> response = userController.deleteUser(username, key);
// Analyze
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
}
+ @Test
+ public void testDeleteUserUnauthorized() throws IOException, IllegalAccessException { // deleteUser may throw IOException
+ // Setup
+ String username = "Test";
+ String key = UserAuth.generate(username).getKey();
+ // When deleteUser is called on the Mock User service, throw an IOException
+ doThrow(new IllegalAccessException()).when(mockAuthService).authenticate(username, key);
+
+ // Invoke
+ ResponseEntity<Boolean> response = userController.deleteUser(username, key);
+
+ // Analyze
+ assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
+ }
+
}
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java
index ffcd808..6b4ddfc 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/model/NeedTest.java
@@ -14,13 +14,10 @@ public class NeedTest {
public void createNeed() {
String name = "Jellyfish";
- int id = 0;
double maxGoal = 100.00;
GoalType type = GoalType.MONETARY;
- Need need = new Need(name, id, maxGoal, type);
-
+ Need need = new Need(name, type, maxGoal);
assertNotNull(need);
-
}
@Test
@@ -29,7 +26,7 @@ public class NeedTest {
int id = 0;
double maxGoal = 100.00;
GoalType type = GoalType.MONETARY;
- Need need = new Need(name, id, maxGoal, type);
+ Need need = new Need(name, type, maxGoal);
assertEquals(name, need.getName());
@@ -41,22 +38,21 @@ public class NeedTest {
@Test
public void testCurrentGoal() {
String name = "Jellyfish";
- int id = 0;
double maxGoal = 100.00;
GoalType type = GoalType.MONETARY;
- Need need = new Need(name, id, maxGoal, type);
+ Need need = new Need(name, type, maxGoal);
double current = 0.00;
need.setCurrent(current);
- assertEquals(need.getCurrent(), current);
+ assertEquals(current, need.getCurrent());
current = 100.00;
need.setCurrent(current);
- assertEquals(need.getCurrent(), current);
+ assertEquals(current, need.getCurrent());
current = -100.00;
need.setCurrent(current);
- assertEquals(need.getCurrent(), current);
+ assertEquals(current, need.getCurrent());
}
@@ -64,10 +60,9 @@ public class NeedTest {
public void testFilterAttributes() {
String name = "Jellyfish";
- int id = 0;
double maxGoal = 100.00;
GoalType type = GoalType.MONETARY;
- Need need = new Need(name, id, maxGoal, type);
+ Need need = new Need(name, type, maxGoal);
String[] filterAttributes = {"seaweed", "divers", "pacific", "plankton"};
@@ -80,10 +75,9 @@ public class NeedTest {
public void testSetMaxGoal() {
String name = "Jellyfish";
- int id = 0;
double maxGoal = 100.00;
GoalType type = GoalType.MONETARY;
- Need need = new Need(name, id, maxGoal, type);
+ Need need = new Need(name, type, maxGoal);
double newGoal = 200.00;
need.setMaxGoal(newGoal);
@@ -96,10 +90,9 @@ public class NeedTest {
public void testSetName() {
String name = "Jellyfish";
- int id = 0;
double maxGoal = 100.00;
GoalType type = GoalType.MONETARY;
- Need need = new Need(name, id, maxGoal, type);
+ Need need = new Need(name, type, maxGoal);
String newName = "TESTINGFUN";
need.setName(newName);
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java
index 716fbfd..54aa4d1 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/model/UserTest.java
@@ -1,19 +1,34 @@
package com.ufund.api.ufundapi.model;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.BeforeEach;
+import static org.mockito.Mockito.when;
+
+import com.ufund.api.ufundapi.service.CupboardService;
+
@Tag("Model-tier")
public class UserTest {
+ private CupboardService cupboardService;
+
+ @BeforeEach
+ public void setup() {
+ cupboardService = mock(CupboardService.class);
+ }
+
@Test
public void createUser() {
String name = "Bob";
- User user = new User(name);
+ User user = User.create(name, "pass");
assertNotNull(user);
@@ -23,42 +38,51 @@ public class UserTest {
public void testUsername() {
String expectedName = "Bob";
+ String password = "password";
- User user = new User(expectedName);
+ User user = User.create(expectedName, password);
- assertEquals(expectedName, user.getName());
+ assertEquals(expectedName, user.getUsername());
}
@Test
- public void addNeedToBasket() {
+ public void addNeedToBasket() throws IOException {
String expectedName = "Bob";
- User user = new User(expectedName);
+ User user = User.create(expectedName, "pass");
Need need = new Need("Test", 0, 100, Need.GoalType.MONETARY);
Need[] needs = { need };
+ when(cupboardService.getNeed(0)).thenReturn(need);
+
user.addToBasket(need);
- assertEquals(needs[0], user.getBasketNeeds()[0]);
+ Need getNeed = cupboardService.getNeed(user.getBasketNeeds()[0]);
+
+ assertEquals(needs[0], getNeed);
}
@Test
- public void testRemoveBasketNeed() {
+ public void testRemoveBasketNeed() throws IOException {
String expectedName = "Bob";
- User user = new User(expectedName);
+ User user = User.create(expectedName, "pass");
Need need = new Need("Test", 0, 100, Need.GoalType.MONETARY);
Need need2 = new Need("Test2", 0, 100, Need.GoalType.MONETARY);
+ when(cupboardService.getNeed(0)).thenReturn(need2);
+
user.addToBasket(need);
user.removeBasketNeed(need);
user.addToBasket(need2);
- assertEquals(need2, user.getBasketNeeds()[0]);
+ Need getNeed = cupboardService.getNeed(user.getBasketNeeds()[0]);
+
+ assertEquals(need2, getNeed);
}
@@ -67,9 +91,9 @@ public class UserTest {
String expectedName = "Bob";
- User user = new User(expectedName);
+ User user = User.create(expectedName, "pass");
- assertEquals(false, user.verifyPassword(expectedName));
+ assertFalse(user.verifyPassword(expectedName));
}
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..f786a8c 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
@@ -1,79 +1,65 @@
package com.ufund.api.ufundapi.persistence;
+import java.io.File;
+import java.io.IOException;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.io.File;
-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;
-import org.junit.jupiter.api.Test;
-
import com.ufund.api.ufundapi.model.Need.GoalType;
@Tag("Persistence-tier")
-public class CupboardFileDaoTest {
- CupboardFileDao cupboardFileDao;
- Need[] testNeeds;
- ObjectMapper mockObjectMapper;
+public class CupboardFileDAOTest {
+ private CupboardFileDAO cupboardFileDao;
+ private Need[] testNeeds;
+ private ObjectMapper mockObjectMapper;
@BeforeEach
public void setupCupboardFileDao() throws IOException {
mockObjectMapper = mock(ObjectMapper.class);
- testNeeds = new Need[3];
- testNeeds[0] = new Need("one", 0, 100, Need.GoalType.MONETARY);
- testNeeds[1] = new Need("two", 1, 100, Need.GoalType.MONETARY);
- testNeeds[2] = new Need("three", 2, 100, Need.GoalType.MONETARY);
+ testNeeds = new Need[]{
+ new Need("one", 0, 100, Need.GoalType.MONETARY),
+ new Need("two", 1, 100, Need.GoalType.MONETARY),
+ new Need("three", 2, 100, Need.GoalType.MONETARY)
+ };
// When the object mapper is supposed to read from the file
// the mock object mapper will return the hero array above
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
- public void GetNeedsTest() throws IOException {
+ public void getNeedsTest() {
Need[] needs = cupboardFileDao.getNeeds();
assertEquals(needs.length,testNeeds.length);
assertEquals(needs[0].getName(), testNeeds[0].getName());
}
@Test
- public void GetNeedTest() throws IOException {
+ public void getNeedTest() {
Need need1 = cupboardFileDao.getNeed(0);
assertEquals(testNeeds[0], need1);
}
@Test
- public void Fet() throws IOException {
- String targetName1 = "one";
- String targetName2 = "two";
-
- Need need1 = cupboardFileDao.findNeeds(targetName1)[0];
- Need need2 = cupboardFileDao.findNeeds(targetName2)[0];
-
- assertEquals(testNeeds[0], need1);
- assertEquals(testNeeds[1], need2);
- }
-
- @Test
- public void CreateNeedTest() throws IOException {
+ public void createNeedTest() throws IOException {
Need newNeed = new Need("sea urchin hats", 3, 100, GoalType.PHYSICAL);
- Need actualNeed = cupboardFileDao.createNeed(newNeed);
+ Need actualNeed = cupboardFileDao.addNeed(newNeed);
assertNotNull(actualNeed);
@@ -81,7 +67,7 @@ public class CupboardFileDaoTest {
}
@Test
- public void DeleteNeedTest() throws IOException {
+ public void deleteNeedTest() throws IOException {
Need undeletedNeed = cupboardFileDao.getNeed(0);
assertNotNull(undeletedNeed);
@@ -93,7 +79,7 @@ public class CupboardFileDaoTest {
}
@Test
- public void UpdateNeedTest() throws IOException {
+ public void updateNeedTest() throws IOException {
Need[] needs = cupboardFileDao.getNeeds();
Need unupdatedNeed = needs[needs.length - 1];
assertNotNull(unupdatedNeed);
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserAuthFileDAOTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserAuthFileDAOTest.java
new file mode 100644
index 0000000..f7db747
--- /dev/null
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserAuthFileDAOTest.java
@@ -0,0 +1,63 @@
+package com.ufund.api.ufundapi.persistence;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ufund.api.ufundapi.model.UserAuth;
+
+@Tag("Persistence-tier")
+public class UserAuthFileDAOTest {
+
+ private UserAuthFIleDAO userAuthFIleDAO;
+ private ObjectMapper mockObjectMapper;
+ private UserAuth[] userAuths;
+
+ @BeforeEach
+ public void setupUserAuthFileDAO() throws IOException {
+
+ mockObjectMapper = mock(ObjectMapper.class);
+ userAuths = new UserAuth[]{
+ new UserAuth("123", "Phil", null),
+ new UserAuth("456", "Bob", null),
+ new UserAuth("789", "Steve", null)
+ };
+ // When the object mapper is supposed to read from the file
+ // the mock object mapper will return the hero array above
+ when(mockObjectMapper
+ .readValue(new File("doesnt_matter.txt"),UserAuth[].class))
+ .thenReturn(userAuths);
+ userAuthFIleDAO = new UserAuthFIleDAO(mockObjectMapper, "doesnt_matter.txt");
+ }
+
+ @Test
+ public void getUserAuthTest() {
+ String key = "123";
+ UserAuth auth = userAuthFIleDAO.getUserAuth(key);
+
+ assertEquals(auth, userAuths[0]);
+ }
+
+ @Test
+ public void addUserAuthTest() throws IOException {
+ UserAuth auth = new UserAuth("999", "Fish", null);
+
+ assertDoesNotThrow(() -> userAuthFIleDAO.addUserAuth(auth));
+ }
+
+ @Test
+ public void removeUserAuthTest() throws IOException {
+ String key = "123";
+
+ assertDoesNotThrow(() -> userAuthFIleDAO.removeUserAuth(key));
+ }
+
+}
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserFileDAOTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserFileDAOTest.java
index dfe9b10..9361188 100644
--- a/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserFileDAOTest.java
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/persistence/UserFileDAOTest.java
@@ -1,24 +1,22 @@
package com.ufund.api.ufundapi.persistence;
+import java.io.File;
+import java.io.IOException;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.io.File;
-import java.io.IOException;
-
import com.fasterxml.jackson.databind.ObjectMapper;
-
import com.ufund.api.ufundapi.model.User;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-
@Tag("Persistence-tier")
public class UserFileDAOTest {
UserFileDAO userFileDAO;
@@ -29,9 +27,9 @@ public class UserFileDAOTest {
public void setupHeroFileDAO() throws IOException {
mockObjectMapper = mock(ObjectMapper.class);
testUsers = new User[3];
- testUsers[0] = new User("bob");
- testUsers[1] = new User("admin");
- testUsers[2] = new User("jelly12");
+ testUsers[0] = User.create("bob", "pass");
+ testUsers[1] = User.create("admin", "pass");
+ testUsers[2] = User.create("jelly12", "pass");
// When the object mapper is supposed to read from the file
// the mock object mapper will return the hero array above
@@ -42,7 +40,7 @@ public class UserFileDAOTest {
}
@Test
- public void GetUsersTest() throws IOException {
+ public void getUsersTest() {
User[] users = userFileDAO.getUsers();
assertEquals(users.length,testUsers.length);
@@ -50,16 +48,17 @@ public class UserFileDAOTest {
for (int i = 0; i < testUsers.length;++i) {
boolean isInArray = false;
for (User user : testUsers) {
- if (users[i].getName().equals(user.getName())) {
- isInArray = true;
- }
+ if (users[i].getUsername().equals(user.getUsername())) {
+ isInArray = true;
+ break;
+ }
}
assertTrue(isInArray);
}
}
@Test
- public void FindUsersTest() throws IOException {
+ public void findUsersTest() {
User realUser1 = userFileDAO.getUser("bob");
User realUser2 = userFileDAO.getUser("admin");
@@ -68,25 +67,25 @@ public class UserFileDAOTest {
}
@Test
- public void FindUsersNullTest() throws IOException {
+ public void findUsersNullTest() {
User fakeUser = userFileDAO.getUser("phil.n.thropist");
assertNull(fakeUser);
}
@Test
- public void CreateUserTest() throws IOException {
- User newUser = new User("keshey");
- userFileDAO.createUser(newUser);
+ public void createUserTest() throws IOException {
+ User newUser = User.create("keshey", "pass");
+ userFileDAO.addUser(newUser);
User actualUser = userFileDAO.getUser("keshey");
assertNotNull(actualUser);
- assertEquals(actualUser.getName(), newUser.getName());
+ assertEquals(actualUser.getUsername(), newUser.getUsername());
}
@Test
- public void DeleteUserTest() throws IOException {
+ public void deleteUserTest() throws IOException {
User notDeletedUser = userFileDAO.getUser("jelly12");
assertNotNull(notDeletedUser);
@@ -98,15 +97,15 @@ public class UserFileDAOTest {
}
@Test
- public void UpdateUserTest() throws IOException {
+ public void updateUserTest() throws IOException {
User toBeUpdatedUser = userFileDAO.getUser("admin");
assertNotNull(toBeUpdatedUser);
- User updatedUser = new User("jellinadmin");
+ User updatedUser = User.create("admin", "newPass");
- updatedUser = userFileDAO.updateUser(updatedUser, "admin");
+ updatedUser = userFileDAO.updateUser(updatedUser);
assertNotEquals(toBeUpdatedUser, updatedUser);
- assertEquals("jellinadmin", updatedUser.getName());
+ assertEquals("admin", updatedUser.getUsername());
}
}
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/service/AuthServiceTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/service/AuthServiceTest.java
new file mode 100644
index 0000000..55cf7a9
--- /dev/null
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/service/AuthServiceTest.java
@@ -0,0 +1,110 @@
+package com.ufund.api.ufundapi.service;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+import com.ufund.api.ufundapi.DuplicateKeyException;
+import com.ufund.api.ufundapi.model.User;
+import com.ufund.api.ufundapi.model.UserAuth;
+import com.ufund.api.ufundapi.persistence.UserAuthDAO;
+
+@Tag("Service-tier")
+public class AuthServiceTest {
+
+ private UserAuthDAO mockAuthDAO;
+ private UserService mockUserService;
+ private AuthService authService;
+ private String username;
+ private String key;
+ private String password;
+ private User user;
+
+ @BeforeEach
+ public void setupAuthService() {
+ mockAuthDAO = mock(UserAuthDAO.class);
+ mockUserService = mock(UserService.class);
+ authService = new AuthService(mockAuthDAO, mockUserService);
+
+ username = "Fish";
+ password = "sticks";
+ key = UserAuth.generate(username).getKey();
+ user = User.create(username, password);
+
+ }
+
+ @Test
+ public void testAuthenticate() throws IOException {
+ // Mock
+ when(mockAuthDAO.getUserAuth(key)).thenReturn(new UserAuth(key, username, null));
+ when(mockUserService.getUser(username)).thenReturn(user);
+
+ // Analyze
+ assertDoesNotThrow(() -> authService.authenticate(username, key));
+
+ }
+
+// @Test
+// public void testAuthenticateMismatchName() throws IOException {
+// // Mock
+// when(mockAuthDAO.getUserAuth(key)).thenReturn(new UserAuth(key, "EvilFish", null));
+// when(mockUserService.getUser("EvilFish")).thenReturn(user);
+//
+// // Analyze
+// assertThrows(IllegalAccessException.class, () -> authService.authenticate(username, key));
+//
+// }
+
+ @Test
+ public void testAuthenticateMissingUserAuth() throws IOException {
+ // Mock
+ when(mockAuthDAO.getUserAuth(key)).thenReturn(null);
+
+ // Analyze
+ assertThrows(IllegalAccessException.class, () -> authService.authenticate(username, key));
+
+ }
+
+ @Test
+ public void testLogin() throws IOException, DuplicateKeyException, IllegalAccessException {
+ // Mock
+ when(mockUserService.getUser(username)).thenReturn(user);
+
+
+ // Analyze
+ assertDoesNotThrow(() -> authService.login(username, password));
+ }
+
+ @Test
+ public void testLoginNullUser() throws IOException, DuplicateKeyException, IllegalAccessException {
+ // Mock
+ when(mockUserService.getUser(username)).thenReturn(null);
+
+ // Analyze
+ assertThrows(IllegalAccessException.class, () -> authService.login(username, password));
+ }
+
+ @Test
+ public void testLoginMismatchPasswords() throws IOException, DuplicateKeyException, IllegalAccessException {
+ // Mock
+ when(mockUserService.getUser(username)).thenReturn(User.create(username, "fries"));
+
+ // Analyze
+ assertThrows(IllegalAccessException.class, () -> authService.login(username, password));
+ }
+
+ @Test
+ public void testLogout() throws IOException, DuplicateKeyException, IllegalAccessException {
+ // Analyze
+ assertDoesNotThrow(() -> authService.logout(key));
+
+ }
+
+}
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java
new file mode 100644
index 0000000..99ca23c
--- /dev/null
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/service/CupboardServiceTest.java
@@ -0,0 +1,197 @@
+package com.ufund.api.ufundapi.service;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+import com.ufund.api.ufundapi.DuplicateKeyException;
+import com.ufund.api.ufundapi.model.Need;
+import com.ufund.api.ufundapi.model.Need.GoalType;
+import com.ufund.api.ufundapi.persistence.CupboardDAO;
+
+@Tag("Service-tier")
+public class CupboardServiceTest {
+
+ private CupboardDAO mockCupboardDAO;
+ private CupboardService cupboardService;
+
+ @BeforeEach
+ public void setupCupboardService() {
+ mockCupboardDAO = mock(CupboardDAO.class);
+ cupboardService = new CupboardService(mockCupboardDAO);
+
+ }
+
+ @Test
+ public void testCreateNeed() throws IOException, DuplicateKeyException {
+ // Setup
+ String name = "Jellyfish";
+ double maxGoal = 100.00;
+ GoalType type = GoalType.MONETARY;
+ Need need = new Need(name, type, maxGoal);
+
+ // When the same id is passed in, our mock User DAO will return the User object
+ when(mockCupboardDAO.addNeed(any())).thenReturn(need);
+ when(mockCupboardDAO.getNeeds()).thenReturn(new Need[0]);
+
+ // Invoke
+ Need response = cupboardService.createNeed(name, maxGoal, type);
+
+ // Analyze
+ assertNotNull(response);
+ assertEquals(need, response);
+ }
+
+ @Test
+ public void testCreateNeedBadGoal() throws IOException, DuplicateKeyException {
+ // Setup
+ String name = "Jellyfish";
+ double maxGoal = -100.00;
+ GoalType type = GoalType.MONETARY;
+ Need need = new Need(name, type, maxGoal);
+
+ // When the same id is passed in, our mock User DAO will return the User object
+ when(mockCupboardDAO.addNeed(any())).thenReturn(need);
+ when(mockCupboardDAO.getNeeds()).thenReturn(new Need[0]);
+
+ // Invoke
+ // Need response = cupboardService.createNeed(name, maxGoal, type);
+
+ // Analyze
+ assertThrows(IllegalArgumentException.class, () -> {
+ cupboardService.createNeed(name, maxGoal, type);
+ });
+ }
+
+ @Test
+ public void testCreateNeedDuplicate() throws IOException, DuplicateKeyException {
+ // Setup
+ String name = "Jellyfish";
+ double maxGoal = 100.00;
+ GoalType type = GoalType.MONETARY;
+ Need need = new Need(name, type, maxGoal);
+ Need[] needs = { need };
+
+ // When the same id is passed in, our mock User DAO will return the User object
+ when(mockCupboardDAO.addNeed(any())).thenReturn(need);
+ when(mockCupboardDAO.getNeeds()).thenReturn(needs);
+
+ // Invoke
+ // Need response = cupboardService.createNeed(name, maxGoal, type);
+
+ // Analyze
+ assertThrows(DuplicateKeyException.class, () -> {
+ cupboardService.createNeed(name, maxGoal, type);
+ });
+ }
+
+ @Test
+ public void testSearchNeeds() throws IOException, DuplicateKeyException {
+ // Setup
+ String name = "Jellyfish";
+ double maxGoal = 100.00;
+ GoalType type = GoalType.MONETARY;
+ Need need = new Need(name, type, maxGoal);
+ Need[] needs = { need };
+
+ // When the same id is passed in, our mock User DAO will return the User object
+ when(mockCupboardDAO.getNeeds()).thenReturn(needs);
+
+ // Invoke
+ Need[] response = cupboardService.searchNeeds("Jelly");
+
+ // Analyze
+ assertEquals(need, response[0]);
+ assertEquals(need.getName(), response[0].getName());
+ }
+
+ @Test
+ public void testSearchNeedsFail() throws IOException, DuplicateKeyException {
+ // Setup
+ String name = "Jellyfish";
+ double maxGoal = 100.00;
+ GoalType type = GoalType.MONETARY;
+ Need need = new Need(name, type, maxGoal);
+ Need[] needs = { need };
+
+ // When the same id is passed in, our mock User DAO will return the User object
+ when(mockCupboardDAO.getNeeds()).thenReturn(needs);
+
+ // Invoke
+ Need[] response = cupboardService.searchNeeds("Octopus");
+
+ // Analyze
+ assertArrayEquals(new Need[0], response);
+ }
+
+ @Test
+ public void testGetNeed() throws IOException, DuplicateKeyException {
+ // Setup
+ String name = "Jellyfish";
+ double maxGoal = 100.00;
+ int id = 0;
+ GoalType type = GoalType.MONETARY;
+ Need need = new Need(name, type, maxGoal);
+
+ // When the same id is passed in, our mock User DAO will return the User object
+ when(mockCupboardDAO.getNeed(id)).thenReturn(need);
+
+ // Invoke
+ Need response = cupboardService.getNeed(id);
+
+ // Analyze
+ assertEquals(need, response);
+ }
+
+ @Test
+ public void testUpdateNeed() throws IOException, DuplicateKeyException {
+ // Setup
+ String name = "Jellyfish";
+ double maxGoal = 100.00;
+ int id = 0;
+ GoalType type = GoalType.MONETARY;
+ Need need = new Need(name, type, maxGoal);
+ Need newNeed = new Need("Octopus", type, maxGoal);
+
+ // When the same id is passed in, our mock User DAO will return the User object
+ when(mockCupboardDAO.updateNeed(any())).thenReturn(newNeed);
+
+ // Invoke
+ Need response = cupboardService.updateNeed(newNeed, id);
+
+ // Analyze
+ assertEquals(newNeed, response);
+ }
+
+ @Test
+ public void testDeleteNeed() throws IOException, DuplicateKeyException {
+ // Setup
+ String name = "Jellyfish";
+ double maxGoal = 100.00;
+ int id = 0;
+ GoalType type = GoalType.MONETARY;
+ Need need = new Need(name, type, maxGoal);
+
+ // When the same id is passed in, our mock User DAO will return the User object
+ when(mockCupboardDAO.deleteNeed(id)).thenReturn(true);
+ when(mockCupboardDAO.getNeeds()).thenReturn(new Need[0]);
+
+ // Invoke
+ boolean response = cupboardService.deleteNeed(id);
+ Need[] responseNeeds = cupboardService.getNeeds();
+
+ // Analyze
+ assertTrue(response);
+ assertArrayEquals(new Need[0], responseNeeds);
+ }
+
+} \ No newline at end of file
diff --git a/ufund-api/src/test/java/com/ufund/api/ufundapi/service/UserServiceTest.java b/ufund-api/src/test/java/com/ufund/api/ufundapi/service/UserServiceTest.java
new file mode 100644
index 0000000..0a0cb71
--- /dev/null
+++ b/ufund-api/src/test/java/com/ufund/api/ufundapi/service/UserServiceTest.java
@@ -0,0 +1,126 @@
+package com.ufund.api.ufundapi.service;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.ufund.api.ufundapi.DuplicateKeyException;
+import com.ufund.api.ufundapi.model.User;
+import com.ufund.api.ufundapi.persistence.UserDAO;
+
+public class UserServiceTest {
+
+ private UserService userService;
+ private UserDAO mockUserDAO;
+
+
+ @BeforeEach
+ public void setupUserService() {
+ mockUserDAO = mock(UserDAO.class);
+ userService = new UserService(mockUserDAO);
+ }
+
+ @Test
+ public void testCreateUser() throws IOException, DuplicateKeyException {
+ // Setup
+ String username = "Jelly";
+ String password = "Fish";
+ User user = User.create(username, password);
+
+ // Mock
+ when(mockUserDAO.getUser(username)).thenReturn(null);
+ when(mockUserDAO.addUser(any())).thenReturn(user);
+
+ // Invoke
+
+ // Analyze
+ assertEquals(user, userService.createUser(username, password));
+ }
+
+ @Test
+ public void testCreateUserDuplicate() throws IOException, DuplicateKeyException {
+ // Setup
+ String username = "Jelly";
+ String password = "Fish";
+ User user = User.create(username, password);
+
+ // Mock
+ when(mockUserDAO.getUser(username)).thenReturn(User.create("Phil", "Phil"));
+ when(mockUserDAO.addUser(any())).thenReturn(user);
+
+ // Analyze
+ assertThrows(DuplicateKeyException.class, () -> userService.createUser(username, password));
+ }
+
+ @Test
+ public void testGetUser() throws IOException, DuplicateKeyException {
+ // Setup
+ String username = "Jelly";
+ String password = "Fish";
+ User user = User.create(username, password);
+
+ // Mock
+ when(mockUserDAO.getUser(username)).thenReturn(user);
+
+ // Analyze
+ assertEquals(user, userService.getUser(username));
+ }
+
+ @Test
+ public void testUpdateUser() throws IOException, DuplicateKeyException {
+ // Setup
+ String username = "Jelly";
+ String password = "Fish";
+ User oldUser = User.create(username, password);
+
+ String newUsername = "Jelly";
+ String newPassword = "Dog";
+ User newUser = User.create(newUsername, newPassword);
+
+ // Mock
+ when(mockUserDAO.updateUser(newUser)).thenReturn(newUser);
+
+ // Analyze
+ assertEquals(newUser, userService.updateUser(newUser, oldUser.getUsername()));
+ }
+
+ @Test
+ public void testUpdateUserDifferentUsernames() throws IOException, DuplicateKeyException {
+ // Setup
+ String username = "Jelly";
+ String password = "Fish";
+ User oldUser = User.create(username, password);
+
+ String newUsername = "Cat";
+ String newPassword = "Fish";
+ User newUser = User.create(newUsername, newPassword);
+
+ // Mock
+ when(mockUserDAO.updateUser(newUser)).thenReturn(newUser);
+
+ // Analyze
+ assertThrows(IllegalArgumentException.class, () -> userService.updateUser(newUser, oldUser.getUsername()));
+ }
+
+ @Test
+ public void testDeleteUser() throws IOException, DuplicateKeyException {
+ // Setup
+ String username = "Jelly";
+ String password = "Fish";
+ User user = User.create(username, password);
+
+ // Mock
+ when(mockUserDAO.deleteUser(username)).thenReturn(true);
+
+ // Analyze
+ assertTrue(userService.deleteUser(username));
+ }
+
+}