diff --git a/api/src/main/java/com/code4ro/nextdoor/core/service/impl/MapperServiceImpl.java b/api/src/main/java/com/code4ro/nextdoor/core/service/impl/MapperServiceImpl.java index 454bc78..d279fe8 100644 --- a/api/src/main/java/com/code4ro/nextdoor/core/service/impl/MapperServiceImpl.java +++ b/api/src/main/java/com/code4ro/nextdoor/core/service/impl/MapperServiceImpl.java @@ -3,6 +3,8 @@ import com.code4ro.nextdoor.core.dto.BaseEntityDto; import com.code4ro.nextdoor.core.entity.BaseEntity; import com.code4ro.nextdoor.core.service.MapperService; +import com.code4ro.nextdoor.emergency.contact.dto.EmergencyContactDto; +import com.code4ro.nextdoor.emergency.contact.entity.EmergencyContact; import com.code4ro.nextdoor.group.dto.GroupDto; import com.code4ro.nextdoor.group.dto.GroupSecurityPolicyDto; import com.code4ro.nextdoor.group.entity.Group; @@ -41,6 +43,9 @@ private void addCustomTypeMaps() { modelMapper.createTypeMap(Group.class, GroupDto.class) .includeBase(BaseEntity.class, BaseEntityDto.class); modelMapper.createTypeMap(GroupSecurityPolicy.class, GroupSecurityPolicyDto.class); + + modelMapper.createTypeMap(EmergencyContact.class, EmergencyContactDto.class); + modelMapper.createTypeMap(EmergencyContactDto.class, EmergencyContact.class); } @Override diff --git a/api/src/main/java/com/code4ro/nextdoor/emergency/contact/controller/EmergencyContactController.java b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/controller/EmergencyContactController.java new file mode 100644 index 0000000..3dc2707 --- /dev/null +++ b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/controller/EmergencyContactController.java @@ -0,0 +1,78 @@ +package com.code4ro.nextdoor.emergency.contact.controller; + +import com.code4ro.nextdoor.core.exception.NextDoorValidationException; +import com.code4ro.nextdoor.emergency.contact.dto.EmergencyContactDto; +import com.code4ro.nextdoor.emergency.contact.service.EmergencyContactService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import java.util.List; +import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +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; + +@RestController +@Api(value = "Emergency Contact CRUD Controller") +@RequestMapping("/api/emergency-contacts") +public class EmergencyContactController { + + private final EmergencyContactService emergencyContactService; + + @Autowired + public EmergencyContactController(EmergencyContactService emergencyContactService) { + this.emergencyContactService = emergencyContactService; + } + + @PostMapping + @ApiOperation(value = "Saves an Emergency Contact") + public ResponseEntity save(@RequestBody EmergencyContactDto emergencyContactDto) { + final EmergencyContactDto savedEmergencyContact = + emergencyContactService.save(emergencyContactDto); + + return new ResponseEntity<>(savedEmergencyContact, HttpStatus.CREATED); + } + + @PutMapping + @ApiOperation(value = "Updates an Emergency Contact") + public ResponseEntity update(@RequestBody EmergencyContactDto emergencyContactDto) { + final EmergencyContactDto savedEmergencyContact = + emergencyContactService.update(emergencyContactDto); + + return ResponseEntity.ok(savedEmergencyContact); + } + + @DeleteMapping("/{id}") + @ApiOperation(value = "Deletes an Emergency Contact by id") + public ResponseEntity deleteById(@PathVariable("id") String id) { + emergencyContactService.deleteById(id); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @GetMapping("/{id}") + @ApiOperation(value = "Gets an Emergency Contact by id") + public ResponseEntity getById(@PathVariable("id") String id) { + Optional emergencyContactDto = + emergencyContactService.findByUUID(id); + + return emergencyContactDto.map(ResponseEntity::ok) + .orElseThrow(() -> new NextDoorValidationException("id.not.found", HttpStatus.NOT_FOUND)); + } + + @GetMapping + @ApiOperation(value = "Gets all Emergency Contacts") + public ResponseEntity> getAll() { + final List emergencyContactDtoList = + emergencyContactService.findAll(); + + return ResponseEntity.ok(emergencyContactDtoList); + } +} diff --git a/api/src/main/java/com/code4ro/nextdoor/emergency/contact/dto/EmergencyContactDto.java b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/dto/EmergencyContactDto.java new file mode 100644 index 0000000..ddcadb0 --- /dev/null +++ b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/dto/EmergencyContactDto.java @@ -0,0 +1,22 @@ +package com.code4ro.nextdoor.emergency.contact.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmergencyContactDto { + private String id; + + private String firstName; + private String surname; + private String email; + private String address; + private String telephoneNumber; +} diff --git a/api/src/main/java/com/code4ro/nextdoor/emergency/contact/entity/EmergencyContact.java b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/entity/EmergencyContact.java new file mode 100644 index 0000000..30c969d --- /dev/null +++ b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/entity/EmergencyContact.java @@ -0,0 +1,26 @@ +package com.code4ro.nextdoor.emergency.contact.entity; + +import com.code4ro.nextdoor.core.entity.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Column; +import javax.persistence.Entity; + +@Entity +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmergencyContact extends BaseEntity { + private String firstName; + private String surname; + @Column(unique = true) + private String email; + private String address; + private String telephoneNumber; +} diff --git a/api/src/main/java/com/code4ro/nextdoor/emergency/contact/repository/EmergencyContactRepository.java b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/repository/EmergencyContactRepository.java new file mode 100644 index 0000000..1826527 --- /dev/null +++ b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/repository/EmergencyContactRepository.java @@ -0,0 +1,8 @@ +package com.code4ro.nextdoor.emergency.contact.repository; + +import com.code4ro.nextdoor.emergency.contact.entity.EmergencyContact; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface EmergencyContactRepository extends JpaRepository { +} diff --git a/api/src/main/java/com/code4ro/nextdoor/emergency/contact/service/EmergencyContactService.java b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/service/EmergencyContactService.java new file mode 100644 index 0000000..8df539e --- /dev/null +++ b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/service/EmergencyContactService.java @@ -0,0 +1,18 @@ +package com.code4ro.nextdoor.emergency.contact.service; + +import com.code4ro.nextdoor.emergency.contact.dto.EmergencyContactDto; +import java.util.List; +import java.util.Optional; + +public interface EmergencyContactService { + + EmergencyContactDto save(EmergencyContactDto emergencyContactDto); + + EmergencyContactDto update(EmergencyContactDto emergencyContactDto); + + void deleteById(String id); + + Optional findByUUID(String id); + + List findAll(); +} diff --git a/api/src/main/java/com/code4ro/nextdoor/emergency/contact/service/impl/EmergencyContactServiceImpl.java b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/service/impl/EmergencyContactServiceImpl.java new file mode 100644 index 0000000..ff5a82f --- /dev/null +++ b/api/src/main/java/com/code4ro/nextdoor/emergency/contact/service/impl/EmergencyContactServiceImpl.java @@ -0,0 +1,72 @@ +package com.code4ro.nextdoor.emergency.contact.service.impl; + +import com.code4ro.nextdoor.core.service.MapperService; +import com.code4ro.nextdoor.emergency.contact.dto.EmergencyContactDto; +import com.code4ro.nextdoor.emergency.contact.entity.EmergencyContact; +import com.code4ro.nextdoor.emergency.contact.repository.EmergencyContactRepository; +import com.code4ro.nextdoor.emergency.contact.service.EmergencyContactService; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class EmergencyContactServiceImpl implements EmergencyContactService { + + private final EmergencyContactRepository emergencyContactRepository; + private final MapperService mapperService; + + @Autowired + public EmergencyContactServiceImpl(EmergencyContactRepository emergencyContactRepository, MapperService mapperService) { + this.emergencyContactRepository = emergencyContactRepository; + this.mapperService = mapperService; + } + + @Override + public EmergencyContactDto save(EmergencyContactDto emergencyContactDto) { + final EmergencyContact emergencyContact = mapperService.map(emergencyContactDto, EmergencyContact.class); + final EmergencyContact emergencyContactDB = emergencyContactRepository.save(emergencyContact); + + return mapperService.map(emergencyContactDB, EmergencyContactDto.class); + } + + @Override + public EmergencyContactDto update(EmergencyContactDto emergencyContactDto) { + return emergencyContactRepository.findById(UUID.fromString(emergencyContactDto.getId())) + .map(emergencyContact -> updateEntityWithDataFromDto(emergencyContact, emergencyContactDto)) + .map(emergencyContactRepository::save) + .map(emergencyContact -> mapperService.map(emergencyContact, EmergencyContactDto.class)) + .orElseGet(() -> save(emergencyContactDto)); + } + + @Override + public void deleteById(String id) { + emergencyContactRepository.deleteById(UUID.fromString(id)); + } + + @Override + public Optional findByUUID(String id) { + return emergencyContactRepository.findById(UUID.fromString(id)) + .map(emergencyContact -> mapperService.map(emergencyContact, EmergencyContactDto.class)); + } + + @Override + public List findAll() { + return emergencyContactRepository.findAll() + .stream() + .map(emergencyContact -> mapperService.map(emergencyContact, EmergencyContactDto.class)) + .collect(Collectors.toList()); + } + + private EmergencyContact updateEntityWithDataFromDto(EmergencyContact emergencyContact, EmergencyContactDto emergencyContactDto) { + emergencyContact.setFirstName(emergencyContactDto.getFirstName()); + emergencyContact.setSurname(emergencyContactDto.getSurname()); + emergencyContact.setEmail(emergencyContactDto.getEmail()); + emergencyContact.setAddress(emergencyContactDto.getAddress()); + emergencyContact.setTelephoneNumber(emergencyContactDto.getTelephoneNumber()); + + return emergencyContact; + } +} diff --git a/api/src/test/java/com/code4ro/nextdoor/emergency/contact/EmergencyContactFactory.java b/api/src/test/java/com/code4ro/nextdoor/emergency/contact/EmergencyContactFactory.java new file mode 100644 index 0000000..3a93d58 --- /dev/null +++ b/api/src/test/java/com/code4ro/nextdoor/emergency/contact/EmergencyContactFactory.java @@ -0,0 +1,33 @@ +package com.code4ro.nextdoor.emergency.contact; + +import com.code4ro.nextdoor.core.RandomObjectFiller; +import com.code4ro.nextdoor.emergency.contact.dto.EmergencyContactDto; +import com.code4ro.nextdoor.emergency.contact.entity.EmergencyContact; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class EmergencyContactFactory { + + public static EmergencyContact createEntity() { + return RandomObjectFiller.createAndFill(EmergencyContact.class); + } + + public static EmergencyContactDto createDto() { + return RandomObjectFiller.createAndFill(EmergencyContactDto.class); + } + + public static List createEntityList() { + return IntStream.range(1, 10) + .boxed() + .map(element -> RandomObjectFiller.createAndFill(EmergencyContact.class)) + .collect(Collectors.toList()); + } + + public static List createDtoList() { + return IntStream.range(1, 10) + .boxed() + .map(element -> RandomObjectFiller.createAndFill(EmergencyContactDto.class)) + .collect(Collectors.toList()); + } +} diff --git a/api/src/test/java/com/code4ro/nextdoor/emergency/contact/EmergencyContactServiceTest.java b/api/src/test/java/com/code4ro/nextdoor/emergency/contact/EmergencyContactServiceTest.java new file mode 100644 index 0000000..8efcb7a --- /dev/null +++ b/api/src/test/java/com/code4ro/nextdoor/emergency/contact/EmergencyContactServiceTest.java @@ -0,0 +1,104 @@ +package com.code4ro.nextdoor.emergency.contact; + +import static com.code4ro.nextdoor.emergency.contact.EmergencyContactFactory.createEntityList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import com.code4ro.nextdoor.core.service.MapperService; +import com.code4ro.nextdoor.emergency.contact.dto.EmergencyContactDto; +import com.code4ro.nextdoor.emergency.contact.entity.EmergencyContact; +import com.code4ro.nextdoor.emergency.contact.repository.EmergencyContactRepository; +import com.code4ro.nextdoor.emergency.contact.service.impl.EmergencyContactServiceImpl; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.junit.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class EmergencyContactServiceTest { + + private static final String ID = "14022837-be98-4457-af25-075d7a136a33"; + + @InjectMocks + private EmergencyContactServiceImpl underTest; + + @Mock + private EmergencyContactRepository emergencyContactRepository; + + @Mock + private MapperService mapperService; + + @Test + @DisplayName("Save emergency contact") + public void testSave() { + final EmergencyContactDto createDto = EmergencyContactFactory.createDto(); + final EmergencyContact entity = EmergencyContactFactory.createEntity(); + + when(mapperService.map(createDto, EmergencyContact.class)).thenReturn(entity); + when(emergencyContactRepository.save(entity)).thenReturn(entity); + when(mapperService.map(entity, EmergencyContactDto.class)).thenReturn(createDto); + + EmergencyContactDto result = underTest.save(createDto); + + verify(emergencyContactRepository).save(entity); + assertThat(result).isNotNull(); + assertThat(result).isEqualTo(createDto); + } + + @Test + @DisplayName("Search and find an emergency contact by UUID") + public void testFindByUUID() { + final EmergencyContactDto dto = EmergencyContactFactory.createDto(); + final EmergencyContact entity = EmergencyContactFactory.createEntity(); + + when(emergencyContactRepository.findById(UUID.fromString(ID))).thenReturn(Optional.of(entity)); + when(mapperService.map(entity, EmergencyContactDto.class)).thenReturn(dto); + + Optional result = underTest.findByUUID(ID); + + verify(emergencyContactRepository).findById(UUID.fromString(ID)); + assertThat(result).isNotNull(); + assertThat(result.get()).isEqualTo(dto); + } + + @Test + @DisplayName("Search an emergency contact by a non existing UUID in DB") + public void testFindByNonExistingUUID() { + when(emergencyContactRepository.findById(UUID.fromString(ID))).thenReturn(Optional.empty()); + + Optional result = underTest.findByUUID(ID); + + verify(emergencyContactRepository).findById(UUID.fromString(ID)); + assertThat(result).isEmpty(); + } + + @Test + @DisplayName("Delete emergency contact by id") + public void testDeleteById() { + doNothing().when(emergencyContactRepository).deleteById(UUID.fromString(ID)); + + underTest.deleteById(ID); + + verify(emergencyContactRepository).deleteById(UUID.fromString(ID)); + } + + @Test + @DisplayName("Find all emergency contacts in database") + public void testFindAll() { + List entityList = createEntityList(); + + when(emergencyContactRepository.findAll()).thenReturn(entityList); + + List result = underTest.findAll(); + + verify(emergencyContactRepository).findAll(); + assertThat(result).isNotEmpty(); + assertThat(result).hasSize(entityList.size()); + } +}