diff --git a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/endpoint/OwnerEndpoint.java b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/endpoint/OwnerEndpoint.java index 52cda7f..54db7ba 100644 --- a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/endpoint/OwnerEndpoint.java +++ b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/endpoint/OwnerEndpoint.java @@ -43,7 +43,7 @@ public class OwnerEndpoint { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public OwnerDto addHorse(@RequestBody OwnerDto owner) { + public OwnerDto addOwner(@RequestBody OwnerDto owner) { LOGGER.info("POST " + BASE_URL); try { Owner ownerEntity = ownerMapper.dtoToEntity(owner); @@ -58,4 +58,27 @@ public class OwnerEndpoint { "Something went wrong during the communication with the database"); } } + + @PutMapping(value = "/{id}") + @ResponseStatus(HttpStatus.OK) + public OwnerDto updateOwner(@PathVariable("id") Long id, @RequestBody OwnerDto owner) { + LOGGER.info("PUT " + BASE_URL + "/{}", id); + try { + Owner ownerEntity = ownerMapper.dtoToEntity(owner); + ownerEntity.setId(id); + return ownerMapper.entityToDto((ownerService.updateOwner(ownerEntity))); + } catch (ValidationException e) { + LOGGER.error(e.getMessage()); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Error during updating owner with id " + id + ": " + e.getMessage()); + } catch (DataAccessException e) { + LOGGER.error(e.getMessage()); + throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, + "Something went wrong during the communication with the database"); + } catch (NotFoundException e) { + LOGGER.error(e.getMessage()); + throw new ResponseStatusException(HttpStatus.NOT_FOUND, + "The requested owner could not be found"); + } + } } diff --git a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/OwnerDao.java b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/OwnerDao.java index 820e757..f2aefb5 100644 --- a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/OwnerDao.java +++ b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/OwnerDao.java @@ -4,6 +4,8 @@ import at.ac.tuwien.sepm.assignment.individual.entity.Owner; import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException; import org.springframework.dao.DataAccessException; +import java.io.IOException; + public interface OwnerDao { /** @@ -16,9 +18,15 @@ public interface OwnerDao { /** * @param owner that specifies the owner to add - * @return the newly created horse + * @return the newly created owner * @throws DataAccessException will be thrown if something goes wrong during the database access. */ Owner addOwner(Owner owner); + /** + * @param owner that specifies the new owner values alongside with the id of the owner to update + * @return the updated owner + * @throws DataAccessException will be thrown if something goes wrong during the database access. + */ + Owner updateOwner(Owner owner) throws DataAccessException; } diff --git a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/impl/OwnerJdbcDao.java b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/impl/OwnerJdbcDao.java index d435af5..edeb9e7 100644 --- a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/impl/OwnerJdbcDao.java +++ b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/impl/OwnerJdbcDao.java @@ -7,6 +7,7 @@ import java.lang.invoke.MethodHandles; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Types; import java.time.LocalDateTime; import java.util.List; import org.slf4j.Logger; @@ -84,6 +85,44 @@ public class OwnerJdbcDao implements OwnerDao { } } + @Override + public Owner updateOwner(Owner owner) throws DataAccessException { + LOGGER.trace("Update owner {}", owner.toString()); + String sql = "UPDATE " + TABLE_NAME + " SET name=?, updated_at=? WHERE id=?"; + + try { + if(owner.getId() == null || owner.getId() == 0) + throw new DataIntegrityViolationException("Horse Id missing or 0"); + + this.validateOwner(owner); + + Owner oldOwner = findOneById(owner.getId()); + + LocalDateTime currentTime = LocalDateTime.now(); + + owner.setUpdatedAt(currentTime); + + int changes = jdbcTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(sql); + + ps.setString(1, owner.getName()); + ps.setObject(2, owner.getUpdatedAt()); + ps.setObject(3, owner.getId()); + return ps; + }); + + if (changes == 0) + throw new DataAccessException("Updating owner failed, no rows affected") {}; + + owner.setCreatedAt(oldOwner.getCreatedAt()); + + return owner; + } catch(DataAccessException e) { + // We are doing this in order to not change the exception type + throw new DataAccessException("Updating records failed", e) {}; + } + } + private void validateOwner(Owner owner) throws DataIntegrityViolationException { if(owner.getName() == null || owner.getName().isEmpty()) throw new DataIntegrityViolationException("Required parameters for owner missing"); diff --git a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/service/OwnerService.java b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/service/OwnerService.java index b22677a..a053393 100644 --- a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/service/OwnerService.java +++ b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/service/OwnerService.java @@ -5,6 +5,8 @@ import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException; import at.ac.tuwien.sepm.assignment.individual.util.ValidationException; import org.springframework.dao.DataAccessException; +import java.io.IOException; + public interface OwnerService { @@ -20,8 +22,15 @@ public interface OwnerService { * @param owner to create * @return the new owner * @throws ValidationException will be thrown if something goes wrong during verification. - * @throws DataAccessException will be thrown if the horse could not be saved in the database. + * @throws DataAccessException will be thrown if the owner could not be saved in the database. */ Owner addOwner(Owner owner) throws ValidationException, DataAccessException; + /** + * @param owner that specifies the new owner values alongside with the id of the owner to update + * @return the updated owner + * @throws ValidationException will be thrown if something goes wrong during verification. + * @throws DataAccessException will be thrown if the owner could not be saved in the database. + */ + Owner updateOwner(Owner owner) throws ValidationException, DataAccessException; } diff --git a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/service/impl/SimpleOwnerService.java b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/service/impl/SimpleOwnerService.java index 3dd7345..b38b970 100644 --- a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/service/impl/SimpleOwnerService.java +++ b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/service/impl/SimpleOwnerService.java @@ -37,4 +37,11 @@ public class SimpleOwnerService implements OwnerService { this.validator.validateNewOwner(owner); return ownerDao.addOwner(owner); } + + @Override + public Owner updateOwner(Owner owner) throws ValidationException, DataAccessException { + LOGGER.trace("updateOwner({})", owner); + this.validator.validateUpdateOwner(owner); + return ownerDao.updateOwner(owner); + } } diff --git a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/util/Validator.java b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/util/Validator.java index febe9df..20c5c8a 100644 --- a/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/util/Validator.java +++ b/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/util/Validator.java @@ -21,6 +21,12 @@ public class Validator { } public void validateUpdateOwner(Owner owner) throws ValidationException { + if(owner.getId() == null || owner.getId() == 0) { + throw new ValidationException("Owner Id cannot be null or 0"); + } + if(owner.getName() == null || owner.getName().isEmpty()) { + throw new ValidationException("Required value for owner missing: name"); + } } public void validateNewHorse(Horse horse) throws ValidationException { diff --git a/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/integration/OwnerEndpointTest.java b/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/integration/OwnerEndpointTest.java index 584867d..8bc5830 100644 --- a/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/integration/OwnerEndpointTest.java +++ b/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/integration/OwnerEndpointTest.java @@ -38,5 +38,29 @@ public class OwnerEndpointTest { assertEquals(response.getStatusCode(), HttpStatus.CREATED); assertEquals(newOwner.getName(), response.getBody().getName()); } + + @Test + @DisplayName("Updating a owner with the correct parameters will return 200 and the new OwnerDto") + public void updatingNewOwner_correctParameters_shouldReturnStatus200AndOwner() { + OwnerDto newOwner = new OwnerDto("Chad"); + + // Create a new owner + HttpEntity request = new HttpEntity<>(newOwner); + ResponseEntity response = REST_TEMPLATE + .exchange(BASE_URL + port + OWNER_URL, HttpMethod.POST, request, OwnerDto.class); + + // Update the owner + newOwner.setId(response.getBody().getId()); + newOwner.setName("Gigachad"); + + request = new HttpEntity<>(newOwner); + response = REST_TEMPLATE + .exchange(BASE_URL + port + OWNER_URL + '/' + newOwner.getId(), HttpMethod.PUT, request, OwnerDto.class); + + // Compare everything except timestamps + assertEquals(response.getStatusCode(), HttpStatus.OK); + assertEquals(newOwner.getId(), response.getBody().getId()); + assertEquals(newOwner.getName(), response.getBody().getName()); + } } diff --git a/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/unit/persistence/OwnerDaoTestBase.java b/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/unit/persistence/OwnerDaoTestBase.java index ccf5501..8e51be4 100644 --- a/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/unit/persistence/OwnerDaoTestBase.java +++ b/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/unit/persistence/OwnerDaoTestBase.java @@ -10,6 +10,9 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; +import java.io.IOException; +import java.sql.Date; + public abstract class OwnerDaoTestBase { @Autowired @@ -31,9 +34,40 @@ public abstract class OwnerDaoTestBase { } @Test - @DisplayName("Adding a new horse with the incorrect parameters should throw DataAccessException") + @DisplayName("Adding a new owner with the incorrect parameters should throw DataAccessException") public void addingNewOwner_incorrectParameters_shouldThrowDataAccess() { Owner newOwner = new Owner(""); assertThrows(DataAccessException.class, () -> ownerDao.addOwner(newOwner)); } + + @Test + @DisplayName("Updating a owner with the correct parameters should return the owner") + public void updatingOwner_correctParameters_shouldReturnOwner() throws IOException { + // Create owner + Owner newOwner = new Owner("Chad"); + Owner savedOwner = ownerDao.addOwner(newOwner); + + // Update owner + newOwner.setId(savedOwner.getId()); + newOwner.setName("Gigachad"); + Owner updatedOwner = ownerDao.updateOwner(newOwner); + + // Compare everything except updated timestamp + assertEquals(updatedOwner.getId(), newOwner.getId()); + assertEquals(updatedOwner.getName(), newOwner.getName()); + assertEquals(updatedOwner.getCreatedAt(), newOwner.getCreatedAt()); + } + + @Test + @DisplayName("Updating a owner with the incorrect parameters should throw DataAccessException") + public void updatingOwner_incorrectParameters_shouldThrowDataAccess() { + // Create owner + Owner newOwner = new Owner("Chad"); + Owner savedOwner = ownerDao.addOwner(newOwner); + + // Update owner + newOwner.setId(savedOwner.getId()); + newOwner.setName(""); + assertThrows(DataAccessException.class, () -> ownerDao.updateOwner(newOwner)); + } } diff --git a/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/unit/service/OwnerServiceTest.java b/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/unit/service/OwnerServiceTest.java index fb73b96..0de9a44 100644 --- a/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/unit/service/OwnerServiceTest.java +++ b/backend/src/test/java/at/ac/tuwien/sepm/assignment/individual/unit/service/OwnerServiceTest.java @@ -36,4 +36,35 @@ public class OwnerServiceTest { Owner newOwner = new Owner(""); assertThrows(ValidationException.class, () -> ownerService.addOwner(newOwner)); } + + @Test + @DisplayName("Updating a owner with the correct parameters will return the new owner") + public void updatingOwner_correctParameters_shouldReturnOwner() { + // Create owner + Owner newOwner = new Owner("Chad"); + Owner savedOwner = ownerService.addOwner(newOwner); + + // Update owner + newOwner.setId(savedOwner.getId()); + newOwner.setName("Chad"); + Owner updatedOwner = ownerService.updateOwner(newOwner); + + // Compare everything except updated timestamp + assertEquals(updatedOwner.getId(), newOwner.getId()); + assertEquals(updatedOwner.getName(), newOwner.getName()); + assertEquals(updatedOwner.getCreatedAt(), newOwner.getCreatedAt()); + } + + @Test + @DisplayName("Updating a owner with the incorrect parameters will return the new owner") + public void updatingOwner_incorrectParameters_shouldThrowValidation() { + // Create owner + Owner newOwner = new Owner("Chad"); + Owner savedOwner = ownerService.addOwner(newOwner); + + // Update owner + newOwner.setId(savedOwner.getId()); + newOwner.setName(""); + assertThrows(ValidationException.class, () -> ownerService.updateOwner(newOwner)); + } }