diff options
Diffstat (limited to '')
12 files changed, 334 insertions, 155 deletions
diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java index b46d4ee..82b2c67 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java @@ -2,6 +2,8 @@ package com.ufund.api.ufundapi.controller;  import java.io.IOException;  import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger;  import org.springframework.http.HttpStatus;  import org.springframework.http.ResponseEntity; @@ -17,6 +19,7 @@ import com.ufund.api.ufundapi.service.AuthService;  @RestController  @RequestMapping("auth")  public class AuthController { +    private static final Logger LOG = Logger.getLogger(AuthController.class.getName());      private final AuthService authService;      public AuthController(AuthService authService) { @@ -32,15 +35,18 @@ public class AuthController {       */      @PostMapping("")      public ResponseEntity<String> login(@RequestBody Map<String, String> params) { +        LOG.log(Level.INFO, "POST /auth body={0}", 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 (IllegalAccessException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.UNAUTHORIZED);          } catch (IOException ex) { -            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } @@ -52,11 +58,13 @@ public class AuthController {       */      @DeleteMapping("")      public ResponseEntity<Object> logout(@RequestHeader("jelly-api-key") String key) { +        LOG.log(Level.INFO, "DELETE /auth key={0}", key);          try {              authService.logout(key);              return new ResponseEntity<>(HttpStatus.OK); -        } catch (IOException e) { -            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +        } catch (IOException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), 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 36ae341..12fb0a9 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 @@ -13,6 +13,7 @@ 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.RequestParam;  import org.springframework.web.bind.annotation.RestController; @@ -20,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;  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.service.AuthService;  import com.ufund.api.ufundapi.service.CupboardService;  @RestController @@ -27,14 +29,16 @@ import com.ufund.api.ufundapi.service.CupboardService;  public class CupboardController {      private static final Logger LOG = Logger.getLogger(CupboardController.class.getName());      private final CupboardService cupboardService; +    private final AuthService authService;      /**       * Create a cupboard controller to receive REST signals       *       * @param cupboardService The Data Access Object       */ -    public CupboardController(CupboardService cupboardService) { +    public CupboardController(CupboardService cupboardService, AuthService authService) {          this.cupboardService = cupboardService; +        this.authService = authService;      }      /** @@ -47,21 +51,33 @@ public class CupboardController {       *         INTERNAL_SERVER_ERROR otherwise       */      @PostMapping("") -    public ResponseEntity<Need> createNeed(@RequestBody Map<String, Object> params) { -        System.out.println(params); +    public ResponseEntity<Object> createNeed(@RequestBody Map<String, Object> params, @RequestHeader("jelly-api-key") String key) { +        LOG.log(Level.INFO, "POST /cupboard body={0}", params); +          String name = (String) params.get("name"); -        double maxGoal = (double) params.get("maxGoal"); +        String image = (String) params.get("image"); +        String location = (String) params.get("location"); +        double maxGoal = ((Number) params.get("maxGoal")).doubleValue(); +        boolean urgent = (Boolean) params.get("urgent"); +        String description = (String) params.get("description");          Need.GoalType goalType = GoalType.valueOf((String) params.get("type"));          try { -            Need need = cupboardService.createNeed(name, maxGoal, goalType); +            authService.keyHasAccessToCupboard(key); +            Need need = cupboardService.createNeed(name, image, location, maxGoal, goalType, urgent, description);              return new ResponseEntity<>(need, HttpStatus.OK);          } catch (DuplicateKeyException ex) { -            return new ResponseEntity<>(HttpStatus.CONFLICT); +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.CONFLICT);          } catch (IllegalArgumentException ex) { -            return new ResponseEntity<>(HttpStatus.BAD_REQUEST); +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); +        } catch (IllegalAccessException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.UNAUTHORIZED);          } catch (IOException ex) { -            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } @@ -74,39 +90,39 @@ public class CupboardController {       *         ResponseEntity with HTTP status of INTERNAL_SERVER_ERROR otherwise       */      @GetMapping("") -    public ResponseEntity<Need[]> getNeeds() { -        LOG.info("GET /needs"); +    public ResponseEntity<Object> getNeeds() { +        LOG.info("GET /cupboard");          try {              Need[] needs = cupboardService.getNeeds();              return new ResponseEntity<>(needs, HttpStatus.OK); -        } catch (IOException e) { -            LOG.log(Level.SEVERE, e.getLocalizedMessage()); -            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +        } catch (IOException ex) { +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      }       /** -     * Responds to the GET request for all {@linkplain Need need} whose name contains -     * the text in name -     *  -     * @param name The name parameter which contains the text used to find the {@link Need need} -     *  -     * @return ResponseEntity with array of {@link Need need} objects (may be empty) and -     * HTTP status of OK<br> -     * ResponseEntity with HTTP status of INTERNAL_SERVER_ERROR otherwise -     * <p> -     */ +      * Responds to the GET request for all {@linkplain Need need} whose name contains +      * the text in name +      * +      * @param name The name parameter which contains the text used to find the {@link Need need} +      * +      * @return ResponseEntity with array of {@link Need need} objects (may be empty) and +      * HTTP status of OK<br> +      * ResponseEntity with HTTP status of INTERNAL_SERVER_ERROR otherwise +      * <p> +      */      @GetMapping("/") -    public ResponseEntity<Need[]> searchNeeds(@RequestParam String name) { -        LOG.info("GET /need/?name="+name); +    public ResponseEntity<Object> searchNeeds(@RequestParam String name) { +        LOG.info("GET /cupboard/?name="+name);          try {              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); +        } catch (IOException ex) { +            LOG.log(Level.SEVERE,ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } @@ -119,8 +135,8 @@ public class CupboardController {       *         ResponseEntity with HTTP status of NOT_FOUND if not found<br>       */      @GetMapping("/{id}") -    public ResponseEntity<Need> getNeed(@PathVariable int id) { -        LOG.log(Level.INFO, "GET /need/{0}", id); +    public ResponseEntity<Object> getNeed(@PathVariable int id) { +        LOG.log(Level.INFO, "GET /cupboard/{0}", id);          try {              Need need = cupboardService.getNeed(id); @@ -129,9 +145,9 @@ public class CupboardController {              } else {                  return new ResponseEntity<>(HttpStatus.NOT_FOUND);              } -        } catch (IOException e) { -            LOG.log(Level.SEVERE, e.getLocalizedMessage()); -            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +        } catch (IOException ex) { +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } @@ -143,9 +159,10 @@ public class CupboardController {       * @return OK response and the need if it was successful, or INTERNAL_SERVER_ERROR if there was an issue       */      @PutMapping("/{id}") -    public ResponseEntity<Need> updateNeed(@RequestBody Need need, @PathVariable int id) { -        LOG.log(Level.INFO, "Updating need: " + need); +    public ResponseEntity<Object> updateNeed(@RequestBody Need need, @PathVariable int id, @RequestHeader("jelly-api-key") String key) { +        LOG.log(Level.INFO, "PUT /cupboard/{0} body={1}", of(id, need));          try { +            authService.keyHasAccessToCupboard(key);              Need updatedNeed = cupboardService.updateNeed(need, id);              if (updatedNeed != null) {                  return new ResponseEntity<>(need, HttpStatus.OK); @@ -153,11 +170,41 @@ public class CupboardController {                  return new ResponseEntity<>(HttpStatus.NOT_FOUND);              }          } catch (IllegalArgumentException ex) { -            ex.printStackTrace(); -            return new ResponseEntity<>(HttpStatus.BAD_REQUEST); +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); +        } catch (IllegalAccessException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.UNAUTHORIZED); +        } catch (IOException ex) { +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); +        } +    } + +    /** +     * Checks out a need by checkoutAmount +     * +     * @param data JSON object with parameters needID and amount +     * @param key  Key used to authenticate user +     * @return OK if successful, other statuses if failure +     */ +    @PutMapping("/checkout") +    public ResponseEntity<Object> checkoutNeeds(@RequestBody Map<String, Integer> data, @RequestHeader("jelly-api-key") String key) { +        int needID = data.get("needID"); +        int checkoutAmount = data.get("amount"); +        LOG.log(Level.INFO, "PUT /need/checkout body={0}", data); +        try { +            cupboardService.checkoutNeed(needID, checkoutAmount, key); +            return new ResponseEntity<>(HttpStatus.OK); +        } catch (IllegalArgumentException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); +        } catch (IllegalAccessException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.UNAUTHORIZED);          } catch (IOException ex) { -            ex.printStackTrace(); -            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } @@ -168,17 +215,27 @@ public class CupboardController {       * @return OK if the need was deleted, NOT_FOUND if the need was not found, or INTERNAL_SERVER_ERROR if an error occurred      */      @DeleteMapping("/{id}") -    public ResponseEntity<Need> deleteNeed(@PathVariable int id) { +    public ResponseEntity<Object> deleteNeed(@PathVariable int id, @RequestHeader("jelly-api-key") String key) { +        LOG.log(Level.INFO, "DELETE /cupboard/{0}", id);          try { +            authService.keyHasAccessToCupboard(key);              Need need = cupboardService.getNeed(id);              if (cupboardService.deleteNeed(id)) {                  return new ResponseEntity<>(need, HttpStatus.OK);              } else {                  return new ResponseEntity<>(HttpStatus.NOT_FOUND); -            }  -        } catch (IOException e) { -            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +            } +        } catch (IllegalAccessException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.UNAUTHORIZED); +        } catch (IOException ex) { +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } +    private Object[] of(Object ...params) { +        return params; +    } +  } 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 dfaad3a..a34e891 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,7 +1,6 @@  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; @@ -42,7 +41,8 @@ public class UserController {       *         otherwise       */      @PostMapping("") -    public ResponseEntity<User> createUser(@RequestBody Map<String, String> params) { +    public ResponseEntity<Object> createUser(@RequestBody Map<String, String> params) { +        LOG.log(Level.INFO, "POST /users body={0}", params);          String username = params.get("username");          String password = params.get("password"); @@ -54,9 +54,11 @@ public class UserController {                  return new ResponseEntity<>(HttpStatus.CONFLICT);              }          } catch (DuplicateKeyException ex) { -            return new ResponseEntity<>(HttpStatus.CONFLICT); +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.CONFLICT);          } catch (IOException ex) { -            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } @@ -71,11 +73,11 @@ public class UserController {       *         ResponseEntity with HTTP status of INTERNAL_SERVER_ERROR otherwise       */      @GetMapping("/{username}") -    public ResponseEntity<User> getUser(@PathVariable String username, @RequestHeader("jelly-api-key") String key) { -        LOG.log(Level.INFO, "GET /user/{0}", username); +    public ResponseEntity<Object> getUser(@PathVariable String username, @RequestHeader("jelly-api-key") String key) { +        LOG.log(Level.INFO, "GET /user/{0} key={1}", of(username, key));          try { -            authService.authenticate(username, key); +            authService.keyHasAccessToUser(username, key);              User user = userService.getUser(username);              if (user != null) {                  return new ResponseEntity<>(user.withoutPasswordHash(), HttpStatus.OK); @@ -83,10 +85,11 @@ public class UserController {                  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); +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.UNAUTHORIZED); +        } catch (IOException ex) { +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } @@ -101,24 +104,26 @@ public class UserController {       *         INTERNAL_SERVER_ERROR if there was an issue       */      @PutMapping("/{username}") -    public ResponseEntity<User> updateUser(@RequestBody User user, @PathVariable String username, @RequestHeader("jelly-api-key") String key) { -        LOG.log(Level.INFO,"PUT: " + user + " " + username + " " + key.toString()); +    public ResponseEntity<Object> updateUser(@RequestBody User user, @PathVariable String username, @RequestHeader("jelly-api-key") String key) { +        LOG.log(Level.INFO,"PUT /users/{0} body={1} key={2}", of(username, user, key));          try { -            //authService.authenticate(username, key); +            authService.keyHasAccessToUser(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); -        // } +        } catch (IllegalArgumentException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); +        } catch (IllegalAccessException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.UNAUTHORIZED); +        } catch (IOException ex) { +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); +        }      }      /** @@ -130,20 +135,27 @@ public class UserController {       *         INTERNAL_SERVER_ERROR if an error occurred       */      @DeleteMapping("/{username}") -    public ResponseEntity<Boolean> deleteUser(@PathVariable String username, @RequestHeader("jelly-api-key") String key) { +    public ResponseEntity<Object> deleteUser(@PathVariable String username, @RequestHeader("jelly-api-key") String key) { +        LOG.log(Level.INFO, "DELETE /users/{0} id={1}", of(username, key));          try { -            authService.authenticate(username, key); +            authService.keyHasAccessToUser(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); +        } catch (IllegalAccessException ex) { +            LOG.log(Level.WARNING, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.UNAUTHORIZED); +        } catch (IOException ex) { +            LOG.log(Level.SEVERE, ex.getLocalizedMessage()); +            return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);          }      } +    private Object[] of(Object ...params) { +        return params; +    } +  } 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 c0e9214..9b6170b 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 @@ -10,38 +10,57 @@ public class Need {      }      @JsonProperty("name") private String name; +    @JsonProperty("image") private String image; +    @JsonProperty("location") private String location;      @JsonProperty("id") private int id;      @JsonProperty("filterAttributes") private String[] filterAttributes;      @JsonProperty("type") final private GoalType type;      @JsonProperty("maxGoal") private double maxGoal; +    @JsonProperty("urgent") private boolean urgent;      @JsonProperty("current") private double current; +    @JsonProperty("description") private String description;      /** -     * Create a new need +     * Create a new need, used by the controller       *       * @param name The name of the need +     * @param location The physical location of the need       * @param id The unique ID of the need       * @param maxGoal The maximum goal for this need       * @param type The type of need (monetary, physical) +     * @param urgent The urgency of the need +     * @param description The description of the need       */ -    public Need(@JsonProperty("name") String name, @JsonProperty("id") int id, @JsonProperty("maxGoal") double maxGoal, GoalType type) { +    public Need(@JsonProperty("name") String name, @JsonProperty("image") String image, @JsonProperty("location") String location, @JsonProperty("id") int id, @JsonProperty("maxGoal") double maxGoal, @JsonProperty("type") GoalType type, @JsonProperty("urgent") boolean urgent, @JsonProperty("Description") String description) {          this.id = id; +        this.image = image; +        this.location = location;          this.name = name;          this.maxGoal = maxGoal;          this.type = type; +        this.urgent = urgent; +        this.description = description;      }      /**       * Create a new need       *       * @param name    The name of the need +     * @param image   The image representation of the need +     * @param location The location of the need       * @param maxGoal The maximum goal for this need       * @param type    The type of need (monetary, physical) +     * @param urgent The urgency of the need +     * @param description The description of the need       */ -    public Need(String name, GoalType type, double maxGoal) { +    public Need(String name, String image, String location, double maxGoal, GoalType type, boolean urgent, String description) {          this.name = name; +        this.image = image; +        this.location = location;          this.type = type;          this.maxGoal = maxGoal; +        this.urgent = urgent; +        this.description = description;      }      /** @@ -51,11 +70,15 @@ public class Need {       */      public Need(Need other) {          this.name = other.name; +        this.image = other.image; +        this.location = other.location;          this.id = other.id;          this.filterAttributes = other.filterAttributes;          this.type = other.type;          this.maxGoal = other.maxGoal;          this.current = other.current; +        this.urgent = other.urgent; +        this.description = other.description;      }      public String getName() { @@ -82,10 +105,15 @@ public class Need {          return current;      } +      public void setCurrent(double current) {          this.current = current;      } +    public void incrementCurrent(double incrementAmount) { +        this.current += incrementAmount; +    } +      public void setFilterAttributes(String[] filterAttributes) {          this.filterAttributes = filterAttributes;      } 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 6de1a8a..58b62df 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 @@ -12,18 +12,23 @@ public class User {          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; +    @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 username   The name of the user -     * @param basket A basket to copy from +     * @param username The name of the user +     * @param basket   A basket to copy from       */ -    public User(@JsonProperty("username") String username, @JsonProperty("passwordHash") int passwordHash, @JsonProperty("basket") List<Integer> basket, @JsonProperty("type") UserType userType) { +    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; @@ -35,30 +40,46 @@ public class User {                  username,                  password.hashCode(),                  new ArrayList<>(), -                UserType.HELPER -        ); +                UserType.HELPER);      }      public String getUsername() {          return username;      } +    /** +     * Verifies if the provided password's hash is the same as the user's actual +     * hash +     *  +     * @param password The password to check if valid +     * @return True or false depending on if it's equal +     */      public boolean verifyPassword(String password) {          return password.hashCode() == passwordHash;      } +    /** +     * Adds a need's ID to a user's basket +     *  +     * @param need The need to add +     */      public void addToBasket(Need need) {          basket.add(need.getId());      } -    public Integer[] getNeeds() { +    public Integer[] getBasket() {          return basket.toArray(Integer[]::new);      } -    public boolean removeBasketNeed(Integer needID) { -        return basket.remove(needID); +    public void removeBasketNeed(Integer needID) { +        basket.remove(needID);      } +    /** +     * Returns a user without a password hash for security purposes +     *  +     * @return new User with empty password hash +     */      public User withoutPasswordHash() {          return new User(this.username, 0, this.basket, this.type);      } @@ -71,6 +92,7 @@ public class User {          this.passwordHash = other.passwordHash;      } +    @Override      public String toString() {          return this.username + "; basket: " + this.basket + "; type:" + this.type + "; hash: " + this.passwordHash;      } 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 index 1c11a28..78dccec 100644 --- 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 @@ -1,10 +1,10 @@  package com.ufund.api.ufundapi.model; -import com.fasterxml.jackson.annotation.JsonProperty; -  import java.time.LocalDateTime;  import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonProperty; +  public class UserAuth {      @JsonProperty("key") String key;      @JsonProperty("username") String username; @@ -12,12 +12,13 @@ public class UserAuth {      public UserAuth(@JsonProperty("key") String key, @JsonProperty("username") String username, @JsonProperty("expiration") LocalDateTime expiration) {          this.key = key; -        this.expiration = expiration;          this.username = username; +        this.expiration = expiration;      }      /**       * Generate a new user authentication profile +     *        * @param username the username the key will belong to       * @return The new user authentication profile       */ 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 521acae..7efda83 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 @@ -1,15 +1,16 @@  package com.ufund.api.ufundapi.persistence; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.ufund.api.ufundapi.model.Need; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -  import java.io.File;  import java.io.IOException;  import java.util.Map;  import java.util.TreeMap; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ufund.api.ufundapi.model.Need; +  @Component  public class CupboardFileDAO implements CupboardDAO { @@ -52,31 +53,20 @@ public class CupboardFileDAO implements CupboardDAO {      }      /** -     * Return an array of the needs -     * -     * @return An array of all the needs -     */ -    private Need[] getNeedsArray() { -        return needs.values().toArray(Need[]::new); -    } - -    /**       * Saves the needs to json       * -     * @return True if the save was successful, false otherwise       * @throws IOException If there was an IO issue saving the file       */ -    private boolean save() throws IOException { -        Need[] needArray = getNeedsArray(); +    private void save() throws IOException { +        Need[] needArray = needs.values().toArray(Need[]::new);          objectMapper.writeValue(new File(filename), needArray); -        return true;      }      @Override      public Need[] getNeeds() {          synchronized (needs) { -            return getNeedsArray(); +            return needs.values().toArray(Need[]::new);          }      } @@ -117,7 +107,8 @@ public class CupboardFileDAO implements CupboardDAO {          synchronized (needs) {              if (needs.containsKey(id)) {                  needs.remove(id); -                return save(); +                save(); +                return true;              } else {                  return false;              } diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java index 1fc1e92..24a426b 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java @@ -1,15 +1,17 @@  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.time.LocalDateTime;  import java.util.HashMap;  import java.util.Map; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ufund.api.ufundapi.model.UserAuth; +  @Component  public class UserAuthFIleDAO implements UserAuthDAO { @@ -35,7 +37,9 @@ public class UserAuthFIleDAO implements UserAuthDAO {          UserAuth[] userAuthKeysArray = objectMapper.readValue(new File(filename), UserAuth[].class);          for (UserAuth userAuth : userAuthKeysArray) { -            userAuthMap.put(userAuth.getKey(), userAuth); +            if (userAuth.getExpiration().isAfter(LocalDateTime.now())) { +                userAuthMap.put(userAuth.getKey(), userAuth); +            }          }      } 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 6e900aa..ec94da8 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,9 +2,9 @@ package com.ufund.api.ufundapi.persistence;  import java.io.File;  import java.io.IOException; -import java.util.ArrayList;  import java.util.HashMap;  import java.util.Map; +import java.util.Objects;  import org.springframework.beans.factory.annotation.Value;  import org.springframework.stereotype.Component; @@ -44,12 +44,10 @@ public class UserFileDAO implements UserDAO {      /**       * Saves the needs to json       * -     * @return True if the save was successful, false otherwise       * @throws IOException If there was an IO issue saving the file       */ -    private boolean save() throws IOException { +    private void save() throws IOException {          objectMapper.writeValue(new File(filename), users.values()); -        return true;      }      @Override @@ -82,17 +80,8 @@ public class UserFileDAO implements UserDAO {      public User updateUser(User user) throws IOException {          synchronized (users) {              if (users.containsKey(user.getUsername())) { -                // var old = users.put(user.getUsername(), user); -                // user.copyPassword(old); -                if (user.getNeeds() == null || user.getType() == null) { -                    User oldData = users.get(user.getUsername()); -                    User crutch = new User(oldData.getUsername(), 0, new ArrayList<Integer>(), oldData.getType()); -                    crutch.copyPassword(oldData); -                    users.put(user.getUsername(), crutch); -                } else { -                    var old = users.put(user.getUsername(), user); -                    user.copyPassword(old); -                } +                var old = users.put(user.getUsername(), user); +                user.copyPassword(Objects.requireNonNull(old));                  save();                  return user;              } else { @@ -106,7 +95,8 @@ public class UserFileDAO implements UserDAO {          synchronized (users) {              if (users.containsKey(username)) {                  users.remove(username); -                return save(); +                save(); +                return true;              } 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 index 87a16a6..cdce80d 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java @@ -1,11 +1,12 @@  package com.ufund.api.ufundapi.service; +import java.io.IOException; + +import org.springframework.stereotype.Component; +  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 { @@ -24,18 +25,51 @@ public class AuthService {       * @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. +     * @throws IOException Thrown on a file writing issue +     */ +    public void keyHasAccessToUser(String targetUsername, String key) throws IllegalAccessException, IOException { +        var userAuth = userAuthDAO.getUserAuth(key); +        if (userAuth == null) { +            throw new IllegalAccessException("Invalid authentication key"); +        } + +       var username = userAuth.getUsername(); +       var userType = userService.getUser(username).getType(); +       if (!username.equals(targetUsername) && userType != User.UserType.MANAGER) { +           throw new IllegalAccessException("Provided key does not grant access to perform the requested operation"); +       } +    } + +    /** +     * Check if the provided key is valid +     * @param key The api key obtained by the client from logging in. +     * @throws IllegalAccessException Thrown if access was denied to the user. +     * @throws IOException Thrown on a file writing issue +     */ +    public void keyIsValid(String key) throws IOException, IllegalAccessException { +        var userAuth = userAuthDAO.getUserAuth(key); +        if (userAuth == null) { +            throw new IllegalAccessException("Invalid authentication key"); +        } +    } + +    /** +     * Check if the provided key has access to edit the cupboard +     * @param key The api key obtained by the client from logging in. +     * @throws IllegalAccessException Thrown if access was denied to the user. +     * @throws IOException Thrown on a file writing issue       */ -    public void authenticate(String targetUsername, String key) throws IllegalAccessException, IOException { +    public void keyHasAccessToCupboard(String key) throws IOException, IllegalAccessException {          var userAuth = userAuthDAO.getUserAuth(key);          if (userAuth == null) { -            throw new IllegalAccessException("Unauthenticated"); +            throw new IllegalAccessException("Invalid authentication key"); +        } + +        var username = userAuth.getUsername(); +        var userType = userService.getUser(username).getType(); +        if (userType != User.UserType.MANAGER) { +            throw new IllegalAccessException("Provided key does not grant access to perform the requested operation");          } -// -//        var username = userAuth.getUsername(); -//        var userType = userService.getUser(username).getType(); -//        if (!username.equals(targetUsername) && userType != User.UserType.MANAGER) { -//            throw new IllegalAccessException("Unauthorized"); -//        }      }      /** @@ -50,7 +84,7 @@ public class AuthService {      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"); +            throw new IllegalAccessException("Incorrect username or password");          }          var userAuth = UserAuth.generate(username);          userAuthDAO.addUserAuth(userAuth); diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java index 2398745..993e7c1 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java @@ -3,6 +3,7 @@ package com.ufund.api.ufundapi.service;  import java.io.IOException;  import java.util.Arrays; +import org.springframework.context.annotation.Lazy;  import org.springframework.stereotype.Component;  import com.ufund.api.ufundapi.DuplicateKeyException; @@ -13,8 +14,10 @@ import com.ufund.api.ufundapi.persistence.CupboardDAO;  public class CupboardService {      private final CupboardDAO cupboardDAO; +    final AuthService authService; -    public CupboardService(CupboardDAO cupboardDAO) { +    public CupboardService(@Lazy AuthService authService, CupboardDAO cupboardDAO) { +        this.authService = authService;          this.cupboardDAO = cupboardDAO;      } @@ -22,16 +25,22 @@ public class CupboardService {       * Creates a new Need       *       * @param name The name of the need to create +     * @param image The image representation of the need to create +     * @param location The location of the new need       * @param maxGoal The max goal of the new need       * @param goalType The goal type of the new need +     * @param urgent The urgency of the new need +     * @param description The description 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 { +    public Need createNeed(String name, String image, String location, double maxGoal, Need.GoalType goalType, boolean urgent, String description) throws IOException, DuplicateKeyException {          if (maxGoal <= 0) {              throw new IllegalArgumentException("Max Goal must be greater than zero"); +        } else if (goalType.equals(Need.GoalType.PHYSICAL) && maxGoal % 1 != 0) { +            throw new IllegalArgumentException("Cannot have non whole number value for physical goal");          }          for (Need searchNeed : cupboardDAO.getNeeds()) { @@ -40,7 +49,7 @@ public class CupboardService {              }          } -        Need need = new Need(name, goalType, maxGoal); +        Need need = new Need(name, image, location, maxGoal, goalType, urgent, description);          return cupboardDAO.addNeed(need);      } @@ -92,11 +101,30 @@ public class CupboardService {          }          if (need.getMaxGoal() <= 0) {              throw new IllegalArgumentException("Goal must be greater than 0"); +        } else if (need.getType().equals(Need.GoalType.PHYSICAL) && need.getMaxGoal() % 1 != 0) { +            throw new IllegalArgumentException("Cannot have non whole number value for physical goal");          }          return cupboardDAO.updateNeed(need);      }      /** +     * Checks out a need with the desired amount +     *  +     * @param id The ID of the need to update +     * @param checkoutAmount The amount to update the need by +     * @throws IOException If there is an error reading the file +     * @throws IllegalAccessException If the user has insufficient permission +    */ +    public void checkoutNeed(int id, double checkoutAmount, String key) throws IOException, IllegalAccessException { +        if (checkoutAmount <= 0) { +            throw new IllegalArgumentException("Amount must be greater than 0"); +        } +        authService.keyIsValid(key); +        Need need = cupboardDAO.getNeed(id); +        need.incrementCurrent(checkoutAmount); +    } + +    /**       * Delete a need from the cupboard       *       * @param id the ID of the need @@ -104,6 +132,7 @@ public class CupboardService {       * @throws IOException Thrown on any problem removing the need       */      public boolean deleteNeed(int id) throws IOException { +                  return cupboardDAO.deleteNeed(id);      }  } diff --git a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java index caf9f4c..6e27f50 100644 --- a/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java @@ -12,7 +12,7 @@ import com.ufund.api.ufundapi.persistence.UserDAO;  public class UserService {      private final UserDAO userDAO; -    private final CupboardService cupboardService; +    final CupboardService cupboardService;      public UserService(UserDAO userDao, CupboardService cupboardService) {          this.userDAO = userDao; @@ -44,7 +44,10 @@ public class UserService {       */      public User getUser(String username) throws IOException {          User user = userDAO.getUser(username); -        for (int needId : user.getNeeds()) { +        if (user == null) { +            return null; +        } +        for (int needId : user.getBasket()) {              if (cupboardService.getNeed(needId) == null) {                  user.removeBasketNeed(needId);              } @@ -55,7 +58,7 @@ public class UserService {      /**       * Updates a user       * -     * @param user The ID of the user to update +     * @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 @@ -77,5 +80,5 @@ public class UserService {      public boolean deleteUser(String username) throws IOException {          return userDAO.deleteUser(username);      } -     +  }  | 
