Skip to content
35 changes: 13 additions & 22 deletions src/main/java/org/unilab/uniplan/lector/LectorController.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.unilab.uniplan.lector;

import static org.springframework.http.ResponseEntity.ok;

import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
Expand All @@ -18,7 +16,6 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.unilab.uniplan.lector.dto.LectorDto;
import org.unilab.uniplan.lector.dto.LectorRequestDto;
import org.unilab.uniplan.lector.dto.LectorResponseDto;

Expand All @@ -28,39 +25,33 @@
@Tag(name = "Lectors", description = "Manage lecturers with contact information and associated faculties")
public class LectorController {

private final LectorService lectorService;
private final LectorMapper lectorMapper;
private final LectorWebFacade lectorWebFacade;

@PostMapping
public ResponseEntity<LectorResponseDto> createLector(@Valid @NotNull @RequestBody final LectorRequestDto lectorRequestDto) {
final LectorDto lectorDto = lectorService.createLector(lectorMapper.toInternalDto(lectorRequestDto));

return new ResponseEntity<>(lectorMapper.toResponseDto(lectorDto), HttpStatus.CREATED);
public ResponseEntity<Void> createLector(@Valid @NotNull @RequestBody final LectorRequestDto lectorRequestDto) {
lectorWebFacade.createLector(lectorRequestDto);
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@GetMapping
public List<LectorResponseDto> getAllLectors() {
return lectorMapper.toResponseDtoList(lectorService.getAllLectors());
public ResponseEntity<List<LectorResponseDto>> getAllLectors() {
return ResponseEntity.ok(lectorWebFacade.getAllLectors());
}

@GetMapping("/{id}")
public ResponseEntity<LectorResponseDto> getLectorById(@NotNull @PathVariable UUID id) {
final LectorDto lectorDto = lectorService.getLectorById(id);

return ok(lectorMapper.toResponseDto(lectorDto));
public ResponseEntity<LectorResponseDto> getLectorById(@NotNull @PathVariable final UUID id) {
return ResponseEntity.ok(lectorWebFacade.getLectorById(id));
}

@PutMapping("/{id}")
public ResponseEntity<LectorResponseDto> updateLector(@NotNull @PathVariable UUID id, @Valid @NotNull @RequestBody LectorRequestDto lectorRequestDto) {
final LectorDto lectorDto =lectorMapper.toInternalDto(lectorRequestDto);

return ok(lectorMapper.toResponseDto(lectorService.updateLector(id, lectorDto)));
public ResponseEntity<Void> updateLector(@NotNull @PathVariable final UUID id, @Valid @NotNull @RequestBody final LectorRequestDto lectorRequestDto) {
lectorWebFacade.updateLector(id, lectorRequestDto);
return ResponseEntity.noContent().build();
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteLector(@NotNull @PathVariable UUID id) {
lectorService.deleteLector(id);

public ResponseEntity<Void> deleteLector(@NotNull @PathVariable final UUID id) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NotNull is not needed for @PathVariable

lectorWebFacade.deleteLectorById(id);
return ResponseEntity.noContent().build();
}
}
28 changes: 13 additions & 15 deletions src/main/java/org/unilab/uniplan/lector/LectorMapper.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
package org.unilab.uniplan.lector;

import java.util.List;
import java.util.UUID;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.unilab.uniplan.faculty.Faculty;
import org.unilab.uniplan.lector.dto.LectorDto;
import org.unilab.uniplan.lector.dto.LectorRequestDto;
import org.unilab.uniplan.lector.dto.LectorResponseDto;

@Mapper
public interface LectorMapper {

@Mapping(source = "faculty.id", target = "facultyId")
LectorDto toDto(Lector lector);

@Mapping(source = "facultyId", target = "faculty.id")
Lector toEntity(LectorDto lectorDto);
@Mapping(target = "id", ignore = true)
Lector toEntity(LectorRequestDto requestDto);

@Mapping(source = "facultyId", target = "faculty.id")
void updateEntity(LectorDto dto, @MappingTarget Lector entity);
@Mapping(source = "faculty.id", target = "facultyId")
LectorDto toDto(Lector lector);

@Mapping(target = "id", ignore = true)
LectorDto toInternalDto(final LectorRequestDto lectorRequestDto);
@Mapping(source = "facultyId", target = "faculty")
void updateEntity(LectorRequestDto requestDto, @MappingTarget Lector lector);

LectorResponseDto toResponseDto(final LectorDto lectorDto);
@Mapping(source = "faculty.id", target = "facultyId")
LectorResponseDto toResponseDto(Lector lector);

List<LectorDto> toDtos(List<Lector> lectors);
List<LectorResponseDto> toResponseDtoList(List<Lector> lectors);

List<LectorResponseDto> toResponseDtoList(List<LectorDto> lectorDtos);
@Mapping(target = "id", source = "facultyId")
Faculty toFaculty(UUID facultyId);

@Mapping(target = "email", source = "lectorDto.email")
@Mapping(target = "firstName", source = "lectorDto.firstName")
@Mapping(target = "lastName", source = "lectorDto.lastName")
@Mapping(target = "id", ignore = true)
void updateEntityFromDto(final LectorDto lectorDto, @MappingTarget final Lector lector);
}
66 changes: 16 additions & 50 deletions src/main/java/org/unilab/uniplan/lector/LectorService.java
Original file line number Diff line number Diff line change
@@ -1,71 +1,37 @@
package org.unilab.uniplan.lector;

import static org.unilab.uniplan.utils.ErrorConstants.LECTOR_NOT_FOUND;

import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.unilab.uniplan.exception.ResourceNotFoundException;
import org.unilab.uniplan.faculty.FacultyService;
import org.unilab.uniplan.lector.dto.LectorDto;
import org.unilab.uniplan.common.model.BaseService;


@Service
@RequiredArgsConstructor
public class LectorService {
public class LectorService implements BaseService<Lector> {

private final LectorRepository lectorRepository;

private final LectorMapper lectorMapper;

private final FacultyService facultyService;

@Transactional
public LectorDto createLector(LectorDto lectorDto) {
final Lector lector = lectorMapper.toEntity(lectorDto);

return saveEntityAndConvertToDto(lector);
}

public List<LectorDto> getAllLectors() {
final List<Lector> lectors = lectorRepository.findAll();
return lectorMapper.toDtos(lectors);
}

public LectorDto getLectorById(UUID id) {
return lectorRepository.findById(id)
.map(lectorMapper::toDto)
.orElseThrow(() -> new ResourceNotFoundException(LECTOR_NOT_FOUND.getMessage(
String.valueOf(id))));
}

@Transactional
public LectorDto updateLector(UUID id, LectorDto lectorDto) {
return lectorRepository.findById(id)
.map(existingLector -> updateEntityAndConvertToDto(
lectorDto,
existingLector)).orElseThrow(() -> new ResourceNotFoundException(
LECTOR_NOT_FOUND.getMessage(String.valueOf(id))));
@Override
public void save(final Lector entity) {
lectorRepository.save(entity);
}

public void deleteLector(UUID id) {
final Lector lector =lectorRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException(
LECTOR_NOT_FOUND.getMessage(String.valueOf(id))
));
lectorRepository.delete(lector);
@Override
public List<Lector> getAll() {
return lectorRepository.findAll();
}

private LectorDto updateEntityAndConvertToDto(final LectorDto dto,
final Lector entity) {
lectorMapper.updateEntityFromDto(dto, entity);
return saveEntityAndConvertToDto(entity);
@Override
public Optional<Lector> getById(final UUID id) {
return lectorRepository.findById(id);
}

private LectorDto saveEntityAndConvertToDto(final Lector entity) {
final Lector savedEntity = lectorRepository.save(entity);
return lectorMapper.toDto(savedEntity);
@Override
public void delete(final Lector entity) {
lectorRepository.delete(entity);
}
}

24 changes: 24 additions & 0 deletions src/main/java/org/unilab/uniplan/lector/LectorValidator.java
Comment thread
DrDeathDrop marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.unilab.uniplan.lector;

import static org.unilab.uniplan.utils.ErrorConstants.FACULTY_NOT_FOUND;

import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.unilab.uniplan.exception.ResourceNotFoundException;
import org.unilab.uniplan.faculty.FacultyRepository;
import org.unilab.uniplan.lector.dto.LectorRequestDto;

@Component
@RequiredArgsConstructor
public class LectorValidator {

private final FacultyRepository facultyRepository;

public void validate(final LectorRequestDto request) {
final UUID id = request.facultyId();
if (!facultyRepository.existsById(id)) {
throw new ResourceNotFoundException(FACULTY_NOT_FOUND.getMessage(id.toString()));
}
}
}
67 changes: 67 additions & 0 deletions src/main/java/org/unilab/uniplan/lector/LectorWebFacade.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.unilab.uniplan.lector;


import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.unilab.uniplan.exception.ResourceNotFoundException;
import org.unilab.uniplan.lector.dto.LectorRequestDto;
import org.unilab.uniplan.lector.dto.LectorResponseDto;
import java.util.List;
import java.util.UUID;

import static org.unilab.uniplan.utils.ErrorConstants.LECTOR_NOT_FOUND;

@Component
@Slf4j
@RequiredArgsConstructor
public class LectorWebFacade {

private final LectorMapper lectorMapper;
private final LectorService lectorService;
private final LectorValidator lectorValidator;

@Transactional
public void createLector(final LectorRequestDto request) {
final Lector lector = lectorMapper.toEntity(request);
lectorValidator.validate(request);
lectorService.save(lector);
log.info("Lector with id {} has been created", lector.getId());
}

@Transactional(readOnly = true)
public List<LectorResponseDto> getAllLectors() {
return lectorMapper.toResponseDtoList(lectorService.getAll());
}

@Transactional
public LectorResponseDto getLectorById(final UUID id) {
final Lector lector = getLectorOrThrow(id);
return lectorMapper.toResponseDto(lector);
}

private Lector getLectorOrThrow(final UUID id){
return lectorService.getById(id)
.orElseThrow(() -> new ResourceNotFoundException(
LECTOR_NOT_FOUND.getMessage(String.valueOf(id))
));
}

@Transactional
public void updateLector(final UUID id,
final LectorRequestDto request) {
final Lector lector = getLectorOrThrow(id);
lectorMapper.updateEntity(request, lector);
lectorValidator.validate(request);
Comment on lines +55 to +56

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong order, the validation should be first than the updateEntity()

lectorService.save(lector);
log.info("Lector with id {} has been updated", lector.getId());
}

@Transactional
public void deleteLectorById(final UUID id) {
final Lector lector = getLectorOrThrow(id);
lectorService.delete(lector);
log.info("Lector with id {} has been deleted", lector.getId());
}
}
91 changes: 91 additions & 0 deletions src/test/java/org/unilab/uniplan/lector/LectorMapperTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package org.unilab.uniplan.lector;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.unilab.uniplan.faculty.Faculty;
import org.unilab.uniplan.lector.dto.LectorRequestDto;
import org.unilab.uniplan.lector.dto.LectorResponseDto;

class LectorMapperTest {

private final LectorMapper mapper = new LectorMapperImpl();

private UUID facultyId;
private UUID newFacultyId;

private Lector lector;
private LectorRequestDto request;
private LectorRequestDto updateRequest;

@BeforeEach
void setUp() {
facultyId = UUID.randomUUID();
newFacultyId = UUID.randomUUID();

final Faculty faculty = new Faculty();
faculty.setId(facultyId);

lector = new Lector();
lector.setId(UUID.randomUUID());
lector.setFaculty(faculty);
lector.setEmail("i.ivanov@gmail.com");
lector.setFirstName("Ivan");
lector.setLastName("Ivanov");

request = new LectorRequestDto(facultyId, "i.ivanov@gmail.com", "Ivan", "Ivanov");
updateRequest = new LectorRequestDto(newFacultyId, "p.petrov@gmail.com", "Petar", "Petrov");
}

@Test
void toEntity_shouldMapAllFieldsAndIgnoreId_whenRequestDtoIsValid() {
final Lector result = mapper.toEntity(request);

assertThat(result.getFaculty().getId()).isEqualTo(facultyId);
assertThat(result.getEmail()).isEqualTo("i.ivanov@gmail.com");
assertThat(result.getFirstName()).isEqualTo("Ivan");
assertThat(result.getLastName()).isEqualTo("Ivanov");
assertThat(result.getId()).isNull();
}

@Test
void toResponseDto_shouldMapAllFields_whenLectorIsValid() {
final LectorResponseDto result = mapper.toResponseDto(lector);

assertThat(result.id()).isEqualTo(lector.getId());
assertThat(result.facultyId()).isEqualTo(facultyId);
assertThat(result.email()).isEqualTo("i.ivanov@gmail.com");
assertThat(result.firstName()).isEqualTo("Ivan");
assertThat(result.lastName()).isEqualTo("Ivanov");
}

@Test
void updateEntity_shouldReplaceFacultyReference_whenFacultyIdChanges() {
final Faculty originalFaculty = lector.getFaculty();

mapper.updateEntity(updateRequest, lector);

assertThat(lector.getFaculty()).isNotSameAs(originalFaculty);
assertThat(lector.getFaculty().getId()).isEqualTo(newFacultyId);
}

@Test
void updateEntity_shouldUpdatePersonAndEmailFields_whenRequestDtoIsValid() {
mapper.updateEntity(updateRequest, lector);

assertThat(lector.getEmail()).isEqualTo("p.petrov@gmail.com");
assertThat(lector.getFirstName()).isEqualTo("Petar");
assertThat(lector.getLastName()).isEqualTo("Petrov");
}

@Test
void updateEntity_shouldNotChangeId_whenUpdating() {
final UUID id = lector.getId();

mapper.updateEntity(updateRequest, lector);

assertThat(lector.getId()).isEqualTo(id);
}
}
Loading
Loading