Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.provedcode.talent.controller;

import com.provedcode.config.PageProperties;
import com.provedcode.talent.mapper.TalentMapper;
import com.provedcode.talent.model.dto.FullTalentDTO;
import com.provedcode.talent.model.dto.ShortTalentDTO;
import com.provedcode.talent.model.dto.SkillIdDTO;
import com.provedcode.talent.model.request.EditTalent;
import com.provedcode.talent.service.TalentService;
import com.provedcode.user.model.dto.SessionInfoDTO;
Expand All @@ -19,26 +19,23 @@
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/api/v2")
Copy link

Choose a reason for hiding this comment

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

why?

@RequestMapping("/api/")
@Tag(name = "talent", description = "Talent API")
@Validated
public class TalentController {
TalentService talentService;
TalentMapper talentMapper;

@GetAllTalentsApiDoc
@GetMapping("/talents")
@GetMapping("v2/talents")
@Validated
Page<ShortTalentDTO> getTalents(@RequestParam(value = "page", defaultValue = "0") @PositiveOrZero Integer page,
@RequestParam(value = "size", defaultValue = "5") @Min(1) @Max(1000) Integer size) {
Expand All @@ -47,7 +44,7 @@ Page<ShortTalentDTO> getTalents(@RequestParam(value = "page", defaultValue = "0"

@GetTalentApiDoc
@PreAuthorize("hasRole('TALENT')")
@GetMapping("/talents/{id}")
@GetMapping("v2/talents/{id}")
FullTalentDTO getTalent(@PathVariable("id") long id, Authentication authentication) {
log.info("get-talent auth = {}", authentication);
log.info("get-talent auth.name = {}", authentication.getAuthorities());
Expand All @@ -56,7 +53,7 @@ FullTalentDTO getTalent(@PathVariable("id") long id, Authentication authenticati

@PatchEditTalentApiDoc
@PreAuthorize("hasRole('TALENT')")
@PatchMapping("/talents/{talent-id}")
@PatchMapping("v2/talents/{talent-id}")
FullTalentDTO editTalent(@PathVariable("talent-id") long id,
@RequestBody @Valid EditTalent editTalent,
Authentication authentication) {
Expand All @@ -65,8 +62,25 @@ FullTalentDTO editTalent(@PathVariable("talent-id") long id,

@DeleteTalentApiDoc
@PreAuthorize("hasRole('TALENT')")
@DeleteMapping("/talents/{id}")
@DeleteMapping("v2/talents/{id}")
SessionInfoDTO deleteTalent(@PathVariable("id") long id, Authentication authentication) {
return talentService.deleteTalentById(id, authentication);
}

@PreAuthorize("hasRole('TALENT')")
@PostMapping("v4/talents/{talent-id}/skills")
void addSkillOnTalent(@PathVariable("talent-id") long id,
@RequestBody @Valid SkillIdDTO skillIdDTO,
Authentication authentication) {
talentService.addSkillOnTalent(id, skillIdDTO, authentication);
}

@PreAuthorize("hasRole('TALENT')")
@DeleteMapping("v4/talents/{talent-id}/skills/{skill-id}")
void deleteSkillFromTalent(@PathVariable("talent-id") long talentId,
@PathVariable("skill-id") long skillId,
Authentication authentication) {
talentService.deleteSkillFromTalent(talentId, skillId, authentication);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = MappingConstants.ComponentModel.SPRING)
public interface SkillMapper {
SkillDTO skillToSkillDTO(Skills skills);

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import lombok.Builder;

import java.util.List;
import java.util.Set;

@Builder
public record FullTalentDTO(
Expand All @@ -22,7 +23,7 @@ public record FullTalentDTO(
@JsonProperty("additional_info")
String additionalInfo,
String bio,
List<String> talents,
Set<SkillDTO> skills,
@UrlList
List<String> links,
List<String> contacts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import lombok.Builder;

import java.util.List;
import java.util.Set;

@Builder
public record ShortTalentDTO(
Expand All @@ -11,6 +11,6 @@ public record ShortTalentDTO(
String firstName,
String lastName,
String specialization,
List<String> talents
Set<SkillDTO> skills
) {
}
3 changes: 3 additions & 0 deletions src/main/java/com/provedcode/talent/model/dto/SkillDTO.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.provedcode.talent.model.dto;

import lombok.Builder;

@Builder
public record SkillDTO(
Long id,
String skill
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/provedcode/talent/model/dto/SkillIdDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.provedcode.talent.model.dto;

import jakarta.validation.constraints.NotEmpty;

import java.util.List;

public record SkillIdDTO(
@NotEmpty
List<Long> id
) {
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.provedcode.talent.model.dto;

import com.provedcode.talent.model.entity.Skills;
import lombok.Builder;

import java.util.Set;

@Builder
public record SkillsOnProofDTO(
Set<Skills> skills
Set<SkillDTO> skills
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class Talent {
@OneToMany(mappedBy = "talent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<TalentProof> talentProofs = new ArrayList<>();
@ManyToMany
@JoinTable(name = "talent_skills",
@JoinTable(name = "talent_skill",
joinColumns = @JoinColumn(name = "talent_id"),
inverseJoinColumns = @JoinColumn(name = "skill_id"))
private Set<Skills> skills = new LinkedHashSet<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.provedcode.talent.service;

import com.provedcode.talent.mapper.SkillMapper;
import com.provedcode.talent.model.ProofStatus;
import com.provedcode.talent.model.dto.ProofSkillsDTO;
import com.provedcode.talent.model.dto.SkillDTO;
import com.provedcode.talent.model.dto.SkillsOnProofDTO;
import com.provedcode.talent.model.entity.Skills;
import com.provedcode.talent.model.entity.Talent;
Expand All @@ -18,8 +20,10 @@
import org.springframework.web.server.ResponseStatusException;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

import static org.springframework.http.HttpStatus.*;

Expand All @@ -31,6 +35,8 @@ public class ProofSkillsService {
TalentRepository talentRepository;
UserInfoRepository userInfoRepository;
TalentProofRepository talentProofRepository;
SkillMapper skillMapper;


static BiConsumer<Long, UserInfo> isValidUserEditTalent = (talentId, userInfo) -> {
if (!userInfo.getTalent().getId().equals(talentId)) {
Expand Down Expand Up @@ -79,14 +85,15 @@ public SkillsOnProofDTO getAllSkillsOnProof(long talentId, long proofId, Authent
throw new ResponseStatusException(BAD_REQUEST,
"talentId with id = %s and proofId with id = %s do not match".formatted(talentId, proofId));
}

Set<SkillDTO> skills = talentProof.getSkills().stream()
.map(skillMapper::skillToSkillDTO).collect(Collectors.toSet());
if (talentProof.getStatus().equals(ProofStatus.PUBLISHED)) {
return SkillsOnProofDTO.builder().skills(talentProof.getSkills()).build();
return SkillsOnProofDTO.builder().skills(skills).build();
} else if (authentication != null) {
UserInfo userInfo = userInfoRepository.findByLogin(authentication.getName())
.orElseThrow(() -> new ResponseStatusException(NOT_FOUND));
if (userInfo.getTalent().getId().equals(talentProof.getTalent().getId())) {
return SkillsOnProofDTO.builder().skills(talentProof.getSkills()).build();
return SkillsOnProofDTO.builder().skills(skills).build();
} else {
throw new ResponseStatusException(FORBIDDEN, "you can't see proofs in DRAFT and HIDDEN status");
}
Expand Down
85 changes: 66 additions & 19 deletions src/main/java/com/provedcode/talent/service/TalentService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.provedcode.talent.service;

import com.provedcode.config.PageProperties;
import com.provedcode.talent.model.dto.SkillIdDTO;
import com.provedcode.talent.model.entity.*;
import com.provedcode.talent.model.request.EditTalent;
import com.provedcode.talent.repo.SkillsRepository;
import com.provedcode.talent.repo.TalentProofRepository;
import com.provedcode.talent.repo.TalentRepository;
import com.provedcode.talent.utill.ValidateTalentForCompliance;
Expand All @@ -19,11 +21,13 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.*;

@Service
@Slf4j
Expand All @@ -36,6 +40,7 @@ public class TalentService {
UserInfoRepository userInfoRepository;
PageProperties pageProperties;
ValidateTalentForCompliance validateTalentForCompliance;
SkillsRepository skillsRepository;

@Transactional(readOnly = true)
public Page<Talent> getTalentsPage(Integer page, Integer size) {
Expand Down Expand Up @@ -81,10 +86,10 @@ public Talent editTalent(long id, EditTalent editTalent, Authentication authenti
editableTalentDescription.setBio(editTalent.bio());
} else {
editableTalentDescription = TalentDescription.builder()
.additionalInfo(editTalent.additionalInfo())
.bio(editTalent.bio())
.talent(editableTalent)
.build();
.additionalInfo(editTalent.additionalInfo())
.bio(editTalent.bio())
.talent(editableTalent)
.build();
}
editableTalent.setTalentDescription(editableTalentDescription);
}
Expand All @@ -99,27 +104,27 @@ public Talent editTalent(long id, EditTalent editTalent, Authentication authenti
if (editTalent.links() != null) {
editableTalentLinks.clear();
editableTalentLinks.addAll(editTalent.links().stream().map(s -> TalentLink.builder()
.talent(editableTalent)
.link(s)
.build()).toList());
.talent(editableTalent)
.link(s)
.build()).toList());
editableTalent.setTalentLinks(editableTalentLinks);
}
if (editTalent.contacts() != null) {
editableTalentContacts.clear();
editableTalentContacts.addAll(editTalent.contacts().stream().map(s -> TalentContact.builder()
.talent(editableTalent)
.contact(s)
.build()).toList());
.talent(editableTalent)
.contact(s)
.build()).toList());
editableTalent.setTalentContacts(editableTalentContacts);
}
if (editTalent.attachedFiles() != null) {
editableTalentAttachedFiles.clear();
editableTalentAttachedFiles.addAll(editTalent.attachedFiles().stream().map(s -> TalentAttachedFile.builder()
.talent(editableTalent)
.attachedFile(
s)
.build())
.toList());
.talent(editableTalent)
.attachedFile(
s)
.build())
.toList());
editableTalent.setTalentAttachedFiles(editableTalentAttachedFiles);
}
return talentRepository.save(editableTalent);
Expand All @@ -143,8 +148,50 @@ public SessionInfoDTO deleteTalentById(long id, Authentication authentication) {

private void checkEditTalentNull(EditTalent editTalent) {
if (editTalent.firstName() == null && editTalent.lastName() == null && editTalent.image() == null &&
editTalent.specialization() == null && editTalent.additionalInfo() == null && editTalent.bio() == null &&
editTalent.links() == null && editTalent.contacts() == null && editTalent.attachedFiles() == null)
editTalent.specialization() == null && editTalent.additionalInfo() == null && editTalent.bio() == null &&
editTalent.links() == null && editTalent.contacts() == null && editTalent.attachedFiles() == null)
throw new ResponseStatusException(BAD_REQUEST, "you did not provide information to make changes");
}

public void addSkillOnTalent(long id, SkillIdDTO skillIdDTO, Authentication authentication) {
Optional<Talent> talent = talentRepository.findById(id);
Optional<UserInfo> userInfo = userInfoRepository.findByLogin(authentication.getName());
validateTalentForCompliance.userVerification(talent, userInfo, id);
Talent talentObject = talent.get();

Set<Skills> skillsFromRepo = skillIdDTO.id().stream()
.map(element -> skillsRepository.findById(element)
.orElseThrow(() -> new ResponseStatusException(NOT_FOUND,
"Skill with id = %d not found".formatted(element))))
.collect(Collectors.toSet());

Set<Skills> skillsFromProofs = talentObject.getTalentProofs().stream()
.flatMap(talentProof -> talentProof.getSkills().stream())
.collect(Collectors.toSet());

skillsFromRepo.stream()
.filter(skill -> !skillsFromProofs.contains(skill))
.findFirst()
.ifPresent(skill -> {
throw new ResponseStatusException(FORBIDDEN,
"Skill with id = %d not found in talent's proofs".formatted(skill.getId()));
});

skillsFromRepo.stream()
.forEach(skill -> talentObject.getSkills().add(skill));
}

public void deleteSkillFromTalent(long talentId, long skillId, Authentication authentication) {
Optional<Talent> talent = talentRepository.findById(talentId);
Optional<UserInfo> userInfo = userInfoRepository.findByLogin(authentication.getName());
Skills skill = skillsRepository.findById(skillId)
.orElseThrow(() -> new ResponseStatusException(NOT_FOUND,
"Skill with id = %d not found".formatted(skillId)));
validateTalentForCompliance.userVerification(talent, userInfo, talentId);
Talent talentObject = talent.get();
if (!talentObject.getSkills().remove(skill)) {
throw new ResponseStatusException(NOT_FOUND,
"Skill with id = %d not found".formatted(skillId));
}
}
}