diff --git a/src/main/java/school/faang/user_service/controller/SkillController.java b/src/main/java/school/faang/user_service/controller/SkillController.java new file mode 100644 index 0000000000..85bb9691f8 --- /dev/null +++ b/src/main/java/school/faang/user_service/controller/SkillController.java @@ -0,0 +1,43 @@ +package school.faang.user_service.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import school.faang.user_service.dto.skill.SkillCandidateDto; +import school.faang.user_service.dto.skill.SkillDto; +import school.faang.user_service.service.SkillService; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/skills") +@RequiredArgsConstructor +public class SkillController { + private final SkillService skillService; + + @PostMapping + public SkillDto create(@RequestBody SkillDto skill) { + return skillService.create(skill); + } + + @GetMapping(params = "userId") + public List getUserSkills(@RequestParam Long userId) { + return skillService.getUserSkills(userId); + } + + @GetMapping(value = "/offered", params = "userId") + public List getOfferedSkills(@RequestParam long userId) { + return skillService.getOfferedSkills(userId); + } + + @GetMapping(value = "/acquire", params = {"skillId", "userId"}) + public SkillDto acquireSkillFromOffers(@RequestParam long skillId, @RequestParam long userId) { + return skillService.acquireSkillFromOffers(skillId, userId); + } +} diff --git a/src/main/java/school/faang/user_service/dto/skill/SkillCandidateDto.java b/src/main/java/school/faang/user_service/dto/skill/SkillCandidateDto.java new file mode 100644 index 0000000000..7edb0a5674 --- /dev/null +++ b/src/main/java/school/faang/user_service/dto/skill/SkillCandidateDto.java @@ -0,0 +1,11 @@ +package school.faang.user_service.dto.skill; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class SkillCandidateDto { + private SkillDto skill; + private Long offersAmount; +} diff --git a/src/main/java/school/faang/user_service/dto/skill/SkillDto.java b/src/main/java/school/faang/user_service/dto/skill/SkillDto.java new file mode 100644 index 0000000000..83664c3b85 --- /dev/null +++ b/src/main/java/school/faang/user_service/dto/skill/SkillDto.java @@ -0,0 +1,11 @@ +package school.faang.user_service.dto.skill; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class SkillDto { + private Long id; + private String title; +} diff --git a/src/main/java/school/faang/user_service/exception/DataValidationException.java b/src/main/java/school/faang/user_service/exception/DataValidationException.java new file mode 100644 index 0000000000..b7dedd0599 --- /dev/null +++ b/src/main/java/school/faang/user_service/exception/DataValidationException.java @@ -0,0 +1,7 @@ +package school.faang.user_service.exception; + +public class DataValidationException extends RuntimeException { + public DataValidationException(String message) { + super(message); + } +} diff --git a/src/main/java/school/faang/user_service/mapper/SkillMapper.java b/src/main/java/school/faang/user_service/mapper/SkillMapper.java new file mode 100644 index 0000000000..ea55cac1ed --- /dev/null +++ b/src/main/java/school/faang/user_service/mapper/SkillMapper.java @@ -0,0 +1,30 @@ +package school.faang.user_service.mapper; + +import org.mapstruct.Mapper; +import school.faang.user_service.dto.skill.SkillCandidateDto; +import school.faang.user_service.dto.skill.SkillDto; +import school.faang.user_service.entity.Skill; +import school.faang.user_service.entity.UserSkillGuarantee; +import school.faang.user_service.entity.recommendation.SkillOffer; +import school.faang.user_service.repository.UserRepository; + +@Mapper(componentModel = "spring") +public interface SkillMapper { + Skill toEntity(SkillDto skillDto); + + SkillDto toDto(Skill skill); + + default SkillCandidateDto toSkillCandidateDto(SkillDto skillDto, long count) { + return new SkillCandidateDto(skillDto, count); + } + + default UserSkillGuarantee toUserSkillGuarantee(UserRepository userRepository, + SkillOffer offer, + long userId) { + return UserSkillGuarantee.builder() + .user(userRepository.getReferenceById(userId)) + .skill(offer.getSkill()) + .guarantor(offer.getRecommendation().getAuthor()) + .build(); + } +} diff --git a/src/main/java/school/faang/user_service/service/SkillService.java b/src/main/java/school/faang/user_service/service/SkillService.java new file mode 100644 index 0000000000..b467027982 --- /dev/null +++ b/src/main/java/school/faang/user_service/service/SkillService.java @@ -0,0 +1,87 @@ +package school.faang.user_service.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import school.faang.user_service.dto.skill.SkillCandidateDto; +import school.faang.user_service.dto.skill.SkillDto; +import school.faang.user_service.entity.Skill; +import school.faang.user_service.entity.UserSkillGuarantee; +import school.faang.user_service.entity.recommendation.SkillOffer; +import school.faang.user_service.exception.DataValidationException; +import school.faang.user_service.mapper.SkillMapper; +import school.faang.user_service.repository.SkillRepository; +import school.faang.user_service.repository.UserRepository; +import school.faang.user_service.repository.UserSkillGuaranteeRepository; +import school.faang.user_service.repository.recommendation.SkillOfferRepository; + +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class SkillService { + private final SkillRepository skillRepository; + private final SkillMapper skillMapper; + private final SkillOfferRepository offerRepository; + private final UserSkillGuaranteeRepository guaranteeRepository; + private final UserRepository userRepository; + private static final int MIN_SKILL_OFFERS = 3; + + public SkillDto create(SkillDto skill) { + validateSkill(skill); + if (!skillRepository.existsByTitle(skill.getTitle())) { + Skill newSkill = skillRepository.save(skillMapper.toEntity(skill)); + return skillMapper.toDto(newSkill); + } + throw new DataValidationException("Skill " + skill.getTitle() + " already exists!"); + } + + public List getOfferedSkills(long userId) { + return skillRepository.findSkillsOfferedToUser(userId).stream() + .map(skillMapper::toDto) + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) + .entrySet().stream() + .map(entry -> skillMapper.toSkillCandidateDto(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + } + + @Transactional + public SkillDto acquireSkillFromOffers(long skillId, long userId) { + if (skillRepository.findUserSkill(skillId, userId).isPresent()) { + throw new DataValidationException("User already have this skill!"); + } + if (offerRepository.findAllOffersOfSkill(skillId, userId).size() < MIN_SKILL_OFFERS) { + throw new DataValidationException("Not enough skill offers!"); + } + skillRepository.assignSkillToUser(skillId, userId); + for (SkillOffer offer : offerRepository.findAllOffersOfSkill(skillId, userId)) { + UserSkillGuarantee skillGuarantor = + skillMapper.toUserSkillGuarantee(userRepository, offer, userId); + guaranteeRepository.save(skillGuarantor); + } + return skillMapper.toDto(skillRepository.getReferenceById(skillId)); + } + + public List getUserSkills(long userId) { + return skillRepository.findAllByUserId(userId) + .stream() + .map(skillMapper::toDto) + .toList(); + } + + private void validateSkill(SkillDto skill) { + if (Objects.isNull(skill)) { + log.error("The SkillDto submitted in method validateSkill is null!"); + throw new DataValidationException("SkillDto from argument is null!"); + } + if (skill.getTitle() == null || skill.getTitle().isBlank()) { + log.error("The SkillDto submitted to method validateSkill doesn't have a name!"); + throw new DataValidationException("SkillDto has no name!"); + } + } +}