diff options
Diffstat (limited to 'ufund-api/src/main')
15 files changed, 406 insertions, 123 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 new file mode 100644 index 0000000..aa27e3f --- /dev/null +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/controller/AuthController.java @@ -0,0 +1,54 @@ +package com.ufund.api.ufundapi.controller; + +import com.ufund.api.ufundapi.model.UserAuth; +import com.ufund.api.ufundapi.persistence.UserAuthDAO; +import com.ufund.api.ufundapi.persistence.UserDAO; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Map; + +@RestController +@RequestMapping("auth") +public class AuthController { +    private final UserDAO userDAO; +    private final UserAuthDAO userAuthDAO; + +    public AuthController(UserDAO userDAO, UserAuthDAO userAuthDAO) { +        this.userDAO = userDAO; +        this.userAuthDAO = userAuthDAO; +    } + +    /** +     * Attempts to log in as a user +     * @param params A map/json object in the format {username: string, password: string} +     * @return An api key if the auth was successful, null otherwise +     */ +    @PostMapping("") +    public ResponseEntity<String> login(@RequestBody Map<String, String> params) { +        String username = params.get("username"); +        String password = params.get("password"); +        try { +            var usr = userDAO.getUser(username); +            if (usr == null || !usr.verifyPassword(password)) { +                return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); +            } +            var userAuth = UserAuth.generate(username); +            userAuthDAO.addUserAuth(userAuth); +            return new ResponseEntity<>(userAuth.getKey(), HttpStatus.OK); +        } catch (IOException ex) { +            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); +        } +    } + +    /** +     * TODO +     * @return +     */ +    @DeleteMapping("") +    public ResponseEntity<Object> logout() { +        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); +    } +} 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 4b2a04d..6b0bb71 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,21 +18,23 @@ 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.service.CupboardService.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;      }      /** @@ -41,16 +44,20 @@ public class CupboardController {       * @return OK response and the need if it was successful, INTERNAL_SERVER_ERROR otherwise       */      @PostMapping("") -    public ResponseEntity<Need> createNeed(@RequestBody Need need) { +    public ResponseEntity<Need> createNeed(@RequestBody Map<String, String> params) { +        String name = params.get("name"); +        int maxGoal = Integer.parseInt(params.get("maxGoal")); +        Need.GoalType goalType = GoalType.valueOf(params.get("maxGoal")); +          try { -            if (need.getMaxGoal() <= 0) { -                return new ResponseEntity<>(HttpStatus.BAD_REQUEST); -            } -            if (need.getMaxGoal() < need.getCurrent()) { -                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);          } @@ -69,7 +76,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()); @@ -93,8 +100,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); @@ -116,7 +123,7 @@ public class CupboardController {          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 { @@ -140,8 +147,12 @@ public class CupboardController {      @PutMapping("")      public ResponseEntity<Need> updateNeed(@RequestBody Need need) {          try { -            need = cupboardDAO.updateNeed(need); -            return new ResponseEntity<>(need, HttpStatus.OK); +            Need updatedNeed = cupboardService.updateNeed(need); +            if (updatedNeed != null) { +                return new ResponseEntity<>(need, HttpStatus.OK); +            } else { +                return new ResponseEntity<>(HttpStatus.NOT_FOUND); +            }          } catch (IOException e) {              return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);          } @@ -156,9 +167,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..aa9598d 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,19 +1,14 @@  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 com.ufund.api.ufundapi.persistence.UserAuthDAO;  import org.springframework.http.HttpStatus;  import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -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.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*;  import com.ufund.api.ufundapi.model.User;  import com.ufund.api.ufundapi.persistence.UserDAO; @@ -21,30 +16,34 @@ import com.ufund.api.ufundapi.persistence.UserDAO;  @RestController  @RequestMapping("users")  public class UserController { -    private static final Logger LOG = Logger.getLogger(CupboardController.class.getName()); +    private static final Logger LOG = Logger.getLogger(UserController.class.getName());      private final UserDAO UserDAO; +    private final UserAuthDAO userAuthDAO;      /**       * Create a user controller to receive REST signals       *       * @param userDAO The Data Access Object       */ -    public UserController(UserDAO userDAO) { +    public UserController(UserDAO userDAO, UserAuthDAO userAuthDAO) {          this.UserDAO = userDAO; +        this.userAuthDAO = userAuthDAO;      }      /**       * Creates a User with the provided object       * -     * @param user The user to create       * @return OK response and the user if it was successful, INTERNAL_SERVER_ERROR       *         otherwise       */      @PostMapping("") -    public ResponseEntity<User> createUser(@RequestBody User user) { +    public ResponseEntity<Boolean> createUser(@RequestBody Map<String, String> params) { +        String username = params.get("username"); +        String password = params.get("password"); +          try { -            if (UserDAO.createUser(user) != null) { -                return new ResponseEntity<>(user, HttpStatus.CREATED); +            if (UserDAO.addUser(User.create(username, password)) != null) { +                return new ResponseEntity<>(true, HttpStatus.CREATED);              } else {                  return new ResponseEntity<>(HttpStatus.CONFLICT);              } @@ -62,14 +61,19 @@ public class UserController {       *         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); + +        var userAuth = userAuthDAO.getUserAuth(key); +        if (userAuth == null || !userAuth.getUsername().equals(username)) { +            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); +        }          try { -            User user = UserDAO.getUser(name); +            User user = UserDAO.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);              } @@ -89,7 +93,13 @@ public class UserController {       *         INTERNAL_SERVER_ERROR if there was an issue       */      @PutMapping("/{name}") -    public ResponseEntity<User> updateUser(@RequestBody User user, @PathVariable String name) { +    public ResponseEntity<User> updateUser(@RequestBody User user, @PathVariable String name, @RequestHeader("jelly-api-key") String key) { + +        var userAuth = userAuthDAO.getUserAuth(key); +        if (userAuth == null || !userAuth.getUsername().equals(user.getUsername())) { +            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); +        } +          try {              user = UserDAO.updateUser(user, name);              if (user != null) { @@ -106,14 +116,20 @@ public class UserController {      /**       * Deletes a user with the desired name       *  -     * @param name The name of the user +     * @param username The name 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<User> deleteUser(@PathVariable String username, @RequestHeader("jelly-api-key") String key) { + +        var userAuth = userAuthDAO.getUserAuth(key); +        if (userAuth == null || !userAuth.getUsername().equals(username)) { +            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); +        } +          try { -            if (UserDAO.deleteUser(name)) { +            if (UserDAO.deleteUser(username)) {                  return new ResponseEntity<>(HttpStatus.OK);              } else {                  return new ResponseEntity<>(HttpStatus.NOT_FOUND); 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..9ca097a 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 @@ -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..1e182a6 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,8 +7,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;  public class User { -    @JsonProperty("name") -    private final String name; +    @JsonProperty("username") +    private final String username;      @JsonProperty("passwordHash")      private int passwordHash;      @JsonProperty("basket") @@ -17,36 +17,35 @@ public class User {      /**       * Create a new user       *  -     * @param name The name of the user +     * @param username The name of the user       */ -    public User(String name) { -        this.name = name; +    public User(String username) { +        this.username = username;          basket = new ArrayList<>();      }      /**       * 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<Need> basket) { +        this.username = username;          this.basket = basket; +        this.passwordHash = passwordHash;      } -    /** -     * 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<>() +        );      } -    public String getName() { -        return name; +    public String getUsername() { +        return username;      }      public boolean verifyPassword(String password) { @@ -65,4 +64,8 @@ public class User {          basket.remove(need);      } +    public User withoutPasswordHash() { +        return new User(this.username, 0, this.basket); +    } +  } 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..6baf3e4 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   *  @@ -20,17 +20,6 @@ public interface CupboardDAO {      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 @@ -54,7 +43,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..84ea693 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 @@ -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..45515b8 --- /dev/null +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthDAO.java @@ -0,0 +1,23 @@ +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); + +    /** +     * Add a user authentication profile +     * @param userAuth The user auth profile to add +     * @return True if it was successful +     * @throws IOException On any file writing error +     */ +    boolean addUserAuth(UserAuth userAuth) 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..67918cc --- /dev/null +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/persistence/UserAuthFIleDAO.java @@ -0,0 +1,62 @@ +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(); +    } + +    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); +        } +    } + +    private void save() throws IOException { +        objectMapper.writeValue(new File(filename), userAuthMap.values()); +    } + +    public UserAuth[] getAuthKeys() { +        synchronized (userAuthMap) { +            return userAuthMap.values().toArray(UserAuth[]::new); +        } +    } + +    @Override +    public UserAuth getUserAuth(String key) { +        synchronized (userAuthMap) { +            return userAuthMap.get(key); +        } +    } + +    @Override +    public boolean addUserAuth(UserAuth userAuth) throws IOException { +        synchronized (userAuthMap) { +            userAuthMap.put(userAuth.getKey(), userAuth); +            save(); +            return true; +        } +    } +} 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..6558ce2 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,7 +44,7 @@ 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} @@ -62,7 +62,7 @@ public interface UserDAO {      /**       * 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 +70,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..54ce74a 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 @@ -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);          }      } @@ -72,15 +72,15 @@ public class UserFileDAO implements UserDAO {      /**       * Return the user with the String name name or null otherwise       *  -     * @param name Name of desired user +     * @param username Name of desired user       *        * @return Desired user, null otherwise       * @throws IOException If there was an IO issue saving the file       */      @Override -    public User getUser(String name) throws IOException { +    public User getUser(String username) throws IOException {          synchronized (users) { -            return users.getOrDefault(name, null); +            return users.getOrDefault(username, null);          }      } @@ -93,16 +93,11 @@ public class UserFileDAO implements UserDAO {       * @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(); +            return res;          }      } @@ -131,16 +126,16 @@ public class UserFileDAO implements UserDAO {      /**       * Delete a user matching the name       *  -     * @param name The name of the user +     * @param username 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..caf1edd --- /dev/null +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/AuthService.java @@ -0,0 +1,5 @@ +package com.ufund.api.ufundapi.service; + +public class AuthService { +     +} 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..860a2a8 --- /dev/null +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/CupboardService.java @@ -0,0 +1,83 @@ +package com.ufund.api.ufundapi.service; + +import java.io.IOException; +import java.util.Arrays; + +import com.ufund.api.ufundapi.model.Need; +import com.ufund.api.ufundapi.persistence.CupboardDAO; + +public class CupboardService { + +    private final CupboardDAO cupboardDAO; + +    public class DuplicateKeyException extends Exception { + +        public DuplicateKeyException(String message) { +            super(message); +        } + +    } + +    public CupboardService(CupboardDAO cupboardDAO) { +        this.cupboardDAO = cupboardDAO; +    } + +    public Need createNeed(String name, int maxGoal, Need.GoalType goalType) throws IOException, DuplicateKeyException { +         +        Need need = new Need(name, goalType, maxGoal); + +        if (need.getMaxGoal() <= 0) { +            throw new IllegalArgumentException("Max Goal must be greater than zero"); +        } else { +            for (Need searchNeed : cupboardDAO.getNeeds()) { +                if (need.getName().equalsIgnoreCase(searchNeed.getName())) { +                    throw new DuplicateKeyException("Duplicate names are not allowed"); +                } +            } +            return cupboardDAO.addNeed(need); +        } +         +    } + +    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  +     */ +    public Need[] searchNeeds(String search) throws IOException { +        return Arrays.stream(cupboardDAO.getNeeds()) +                .filter(i -> i.getName().toLowerCase().contains(search.toLowerCase())) +                .toArray(Need[]::new); +    } + +    /** +     * @param id +     * @return +     * @throws IOException +     */ +    public Need getNeed(int id) throws IOException { +        return cupboardDAO.getNeed(id); +    } + +    /** +     *  +     * @param need +     * @return +     * @throws IOException +     */ +    public Need updateNeed(Need need) throws IOException { +        return cupboardDAO.updateNeed(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..994512d --- /dev/null +++ b/ufund-api/src/main/java/com/ufund/api/ufundapi/service/UserService.java @@ -0,0 +1,5 @@ +package com.ufund.api.ufundapi.service; + +public class UserService { +     +}  | 
