Skip to content
Open
36 changes: 17 additions & 19 deletions src/main/java/org/unilab/uniplan/major/MajorController.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.unilab.uniplan.major.dto.MajorCoursesResponseDto;
import org.unilab.uniplan.major.dto.MajorDto;
import org.unilab.uniplan.major.dto.MajorRequestDto;
import org.unilab.uniplan.major.dto.MajorResponseDto;

Expand All @@ -27,52 +26,51 @@
@Tag(name = "Majors", description = "Manage academic majors (e.g., Informatics, Software Engineering) associated with faculties")
public class MajorController {

private final MajorService majorService;
private final MajorMapper majorMapper;
private final MajorWebFacade majorWebFacade;

@PostMapping
public ResponseEntity<MajorResponseDto> addMajor(@RequestBody @NotNull
public ResponseEntity<Void> createMajor(@RequestBody @NotNull
@Valid final MajorRequestDto majorRequestDTO) {
final MajorDto majorDTO = majorMapper.toInnerDto(majorRequestDTO);
return ResponseEntity.status(HttpStatus.CREATED)
.body(majorMapper.toResponseDto(majorService.createMajor(majorDTO)));
majorWebFacade.createMajor(majorRequestDTO);

return ResponseEntity.status(HttpStatus.CREATED).build();
}

@GetMapping("/{id}")
public ResponseEntity<MajorResponseDto> getMajorById(@PathVariable final UUID id) {
return ResponseEntity.ok(majorMapper.toResponseDto(majorService.findMajorById(id)));
return ResponseEntity.ok(majorWebFacade.getMajorById(id));
}

@GetMapping("/{id}/courses")
public ResponseEntity<MajorCoursesResponseDto> getMajorWithCoursesById(@PathVariable final UUID id) {
return ResponseEntity.ok(majorMapper.toFullResponseDto(majorService.findMajorWithCoursesById(id)));
return ResponseEntity.ok(majorWebFacade.getMajorWithCoursesById(id));
}

@GetMapping("/faculty/{facultyId}")
public List<MajorResponseDto> getMajorsByFacultyId(@PathVariable final UUID facultyId) {
return majorMapper.toResponseDtoList(majorService.findAllMajorByFacultyId(facultyId));
public ResponseEntity<List<MajorResponseDto>> getMajorsByFacultyId(@PathVariable final UUID facultyId) {
return ResponseEntity.ok(majorWebFacade.getMajorsByFacultyId(facultyId));
}

@GetMapping("/faculty/{facultyId}/courses")
public List<MajorCoursesResponseDto> getMajorsWithCoursesByFacultyId(@PathVariable final UUID facultyId) {
return majorMapper.toFullResponseDtoList(majorService.findAllMajorWithCoursesByFacultyId(facultyId));
public ResponseEntity<List<MajorCoursesResponseDto>> getMajorsWithCoursesByFacultyId(@PathVariable final UUID facultyId) {
return ResponseEntity.ok(majorWebFacade.getMajorsWithCoursesByFacultyId(facultyId));
}

@GetMapping
public List<MajorResponseDto> getAllMajors() {
return majorMapper.toResponseDtoList(majorService.findAll());
public ResponseEntity<List<MajorResponseDto>> getAllMajors() {
return ResponseEntity.ok(majorWebFacade.getAllMajors());
}

@PutMapping("/{id}")
public ResponseEntity<MajorResponseDto> updateMajor(@PathVariable final UUID id,
public ResponseEntity<Void> updateMajor(@PathVariable final UUID id,
@RequestBody @NotNull @Valid MajorRequestDto majorRequestDTO) {
final MajorDto majorDTO = majorMapper.toInnerDto(majorRequestDTO);
return ResponseEntity.ok(majorMapper.toResponseDto(majorService.updateMajor(id, majorDTO)));
majorWebFacade.updateMajor(id, majorRequestDTO);
return ResponseEntity.noContent().build();
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteMajor(@PathVariable final UUID id) {
majorService.deleteMajor(id);
majorWebFacade.deleteMajor(id);
return ResponseEntity.noContent().build();
}
}
24 changes: 8 additions & 16 deletions src/main/java/org/unilab/uniplan/major/MajorMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,25 @@
import org.unilab.uniplan.course.CourseMapper;
import org.unilab.uniplan.major.dto.MajorCoursesDto;
import org.unilab.uniplan.major.dto.MajorCoursesResponseDto;
import org.unilab.uniplan.major.dto.MajorDto;
import org.unilab.uniplan.major.dto.MajorRequestDto;
import org.unilab.uniplan.major.dto.MajorResponseDto;

@Mapper(uses = {CourseMapper.class})
public interface MajorMapper {

@Mapping(source = "facultyId", target = "faculty.id")
Major toEntity(MajorDto majorDto);

@Mapping(source = "faculty.id", target = "facultyId")
MajorDto toDto(Major major);

@Mapping(source = "faculty.id", target = "facultyId")
MajorCoursesDto toFullDto(Major major);
Major toEntity(MajorRequestDto majorRequestDto);

@Mapping(source = "facultyId", target = "faculty.id")
void updateEntityFromDto(MajorDto majorDto, @MappingTarget Major major);
void updateEntityFromDto(MajorRequestDto majorRequestDto, @MappingTarget Major major);

@Mapping(target = "id", ignore = true)
MajorDto toInnerDto(MajorRequestDto requestDto);

MajorResponseDto toResponseDto(MajorDto innerDto);
@Mapping(source = "faculty.id", target = "facultyId")
MajorResponseDto toResponseDto(Major major);

List<MajorResponseDto> toResponseDtoList(List<MajorDto> majors);
List<MajorResponseDto> toResponseDtoList(List<Major> majors);

MajorCoursesResponseDto toFullResponseDto(MajorCoursesDto innerDto);
@Mapping(source = "faculty.id", target = "facultyId")
MajorCoursesResponseDto toFullResponseDto(Major major);

List<MajorCoursesResponseDto> toFullResponseDtoList(List<MajorCoursesDto> majors);
List<MajorCoursesResponseDto> toFullResponseDtoList(List<Major> majors);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.unilab.uniplan.faculty.Faculty;

@Repository
public interface MajorRepository extends JpaRepository<Major, UUID> {

List<Major> findAllByFacultyId(UUID facultyId);
List<Major> findAllMajorWithCoursesByFacultyId(UUID facultyId);
}
81 changes: 18 additions & 63 deletions src/main/java/org/unilab/uniplan/major/MajorService.java
Original file line number Diff line number Diff line change
@@ -1,88 +1,43 @@
package org.unilab.uniplan.major;

import org.unilab.uniplan.major.dto.MajorCoursesDto;

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

import jakarta.transaction.Transactional;
import org.unilab.uniplan.common.model.BaseService;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.unilab.uniplan.exception.ResourceNotFoundException;
import org.unilab.uniplan.major.dto.MajorDto;

@Service
@RequiredArgsConstructor
public class MajorService {
public class MajorService implements BaseService<Major> {

private final MajorRepository majorRepository;
private final MajorMapper majorMapper;

@Transactional
public MajorDto createMajor(final MajorDto majorDTO) {
final Major major = majorMapper.toEntity(majorDTO);
return saveEntityAndConvertToDto(major);
}

public MajorDto findMajorById(final UUID id) {
return majorRepository.findById(id)
.map(majorMapper::toDto)
.orElseThrow(() -> new ResourceNotFoundException(
MAJOR_NOT_FOUND.getMessage(String.valueOf(id))));
}

public MajorCoursesDto findMajorWithCoursesById(final UUID id) {
return majorRepository.findById(id)
.map(majorMapper::toFullDto)
.orElseThrow(() -> new ResourceNotFoundException(
MAJOR_NOT_FOUND.getMessage(String.valueOf(id))));
}

public List<MajorDto> findAll() {
return majorRepository.findAll()
.stream().map(majorMapper::toDto).toList();
}

public List<MajorDto> findAllMajorByFacultyId(final UUID facultyId) {
return majorRepository.findAllByFacultyId(facultyId)
.stream()
.map(majorMapper::toDto)
.toList();
@Override
public void save(final Major major) {
majorRepository.save(major);
}

public List<MajorCoursesDto> findAllMajorWithCoursesByFacultyId(final UUID facultyId) {
return majorRepository.findAllByFacultyId(facultyId)
.stream()
.map(majorMapper::toFullDto)
.toList();
@Override
public Optional<Major> getById(final UUID id) {
return majorRepository.findById(id);
}

@Transactional
public MajorDto updateMajor(final UUID id, final MajorDto majorDTO) {
return majorRepository.findById(id).map(existingMajor -> updateEntityAndConvertToDto(
majorDTO,
existingMajor))
.orElseThrow(() -> new ResourceNotFoundException(MAJOR_NOT_FOUND.getMessage(
String.valueOf(id))));
@Override
public List<Major> getAll() {
return majorRepository.findAll();
}

@Transactional
public void deleteMajor(final UUID id) {
final Major major = majorRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException(
MAJOR_NOT_FOUND.getMessage(String.valueOf(id))));
@Override
public void delete(final Major major) {
majorRepository.delete(major);
}

private MajorDto updateEntityAndConvertToDto(final MajorDto dto,
final Major entity) {
majorMapper.updateEntityFromDto(dto, entity);
return saveEntityAndConvertToDto(entity);
public List<Major> findAllMajorByFacultyId(final UUID facultyId) {
return majorRepository.findAllByFacultyId(facultyId);
}

private MajorDto saveEntityAndConvertToDto(final Major entity) {
final Major savedEntity = majorRepository.save(entity);
return majorMapper.toDto(savedEntity);
public List<Major> findAllMajorWithCoursesByFacultyId(final UUID facultyId) {
return majorRepository.findAllMajorWithCoursesByFacultyId(facultyId);
}
}
29 changes: 29 additions & 0 deletions src/main/java/org/unilab/uniplan/major/MajorValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.unilab.uniplan.major;

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.major.dto.MajorRequestDto;

@Component
@RequiredArgsConstructor
public class MajorValidator {

private final FacultyRepository facultyRepository;

public void validate(final MajorRequestDto requestDto) {
validateFacultyExists(requestDto.facultyId());
Comment thread
DjesikaV marked this conversation as resolved.
}

private void validateFacultyExists(final UUID facultyId) {
if (!facultyRepository.existsById(facultyId)) {
throw new ResourceNotFoundException(
FACULTY_NOT_FOUND.getMessage(String.valueOf(facultyId))
);
}
}
}
95 changes: 95 additions & 0 deletions src/main/java/org/unilab/uniplan/major/MajorWebFacade.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.unilab.uniplan.major;

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

import java.util.List;
import java.util.UUID;
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.major.dto.MajorCoursesResponseDto;
import org.unilab.uniplan.major.dto.MajorRequestDto;
import org.unilab.uniplan.major.dto.MajorResponseDto;

@Component
@Slf4j
@RequiredArgsConstructor
public class MajorWebFacade {

private final MajorService majorService;
private final MajorMapper majorMapper;
private final MajorValidator majorValidator;

@Transactional
public void createMajor(final MajorRequestDto requestDto) {
majorValidator.validate(requestDto);

final Major major = majorMapper.toEntity(requestDto);
majorService.save(major);

log.info("Created major with ID: {}", major.getId());
}

@Transactional(readOnly = true)
public List<MajorResponseDto> getAllMajors() {
return majorMapper.toResponseDtoList(majorService.getAll());
}

@Transactional(readOnly = true)
public MajorResponseDto getMajorById(final UUID id) {
final Major major = getMajorOrThrow(id);

return majorMapper.toResponseDto(major);
}

@Transactional
public void updateMajor(final UUID id,
final MajorRequestDto requestDto) {
majorValidator.validate(requestDto);

final Major major = getMajorOrThrow(id);
majorMapper.updateEntityFromDto(requestDto, major);
majorService.save(major);

log.info("Updated major with ID: {}", id);
}

@Transactional
public void deleteMajor(final UUID id) {
final Major major = getMajorOrThrow(id);

majorService.delete(major);

log.info("Deleted major with ID: {}", id);
}

private Major getMajorOrThrow(final UUID id) {
return majorService.getById(id)
.orElseThrow(() -> new ResourceNotFoundException(
MAJOR_NOT_FOUND.getMessage(String.valueOf(id))
));
}

@Transactional(readOnly = true)
public MajorCoursesResponseDto getMajorWithCoursesById(final UUID id) {
final Major major = getMajorOrThrow(id);

return majorMapper.toFullResponseDto(major);
}

@Transactional(readOnly = true)
public List<MajorResponseDto> getMajorsByFacultyId(final UUID facultyId) {
return majorMapper.toResponseDtoList(
majorService.findAllMajorByFacultyId(facultyId)
);
}

@Transactional(readOnly = true)
public List<MajorCoursesResponseDto> getMajorsWithCoursesByFacultyId(final UUID facultyId) {
return majorMapper.toFullResponseDtoList(
majorService.findAllMajorWithCoursesByFacultyId(facultyId)
);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package org.unilab.uniplan.major.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.util.UUID;

public record MajorRequestDto(
@NotNull
@NotNull(message = "Faculty id cannot be null")
UUID facultyId,
@NotNull
@Size(max = 200)
@NotBlank(message = "Major is required")
@Size(max = 200, message = "Major name must be at most 200 characters")
String majorName
) {

Expand Down
Loading
Loading