diff --git a/pom.xml b/pom.xml index 85cb069..409f5d0 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,10 @@ 17 + + org.springframework.boot + spring-boot-starter-mail + org.springdoc diff --git a/src/main/java/com/provedcode/aws/controller/AWSS3BucketController.java b/src/main/java/com/provedcode/aws/controller/AWSS3BucketController.java index 926e991..54bd25f 100644 --- a/src/main/java/com/provedcode/aws/controller/AWSS3BucketController.java +++ b/src/main/java/com/provedcode/aws/controller/AWSS3BucketController.java @@ -21,10 +21,11 @@ public class AWSS3BucketController { @PostSetNewUserImageApiDoc @PreAuthorize("hasRole('TALENT')") - @PostMapping("/image/upload") + @PostMapping("/talents/{talent-id}/image/upload") public void setNewUserImage(@RequestParam("file") MultipartFile file, - Authentication authentication) { - fileService.setNewUserImage(file, authentication); + @PathVariable("talent-id") Long talentId, + Authentication authentication) { + fileService.setNewUserImage(file, talentId, authentication); } @GetAllAWSBucketFilesDevApiDoc diff --git a/src/main/java/com/provedcode/aws/service/FileService.java b/src/main/java/com/provedcode/aws/service/FileService.java index 1c1d9e6..bb771c2 100644 --- a/src/main/java/com/provedcode/aws/service/FileService.java +++ b/src/main/java/com/provedcode/aws/service/FileService.java @@ -16,7 +16,7 @@ public interface FileService { List listAllFiles(); - void setNewUserImage(MultipartFile file, Authentication authentication); + void setNewUserImage(MultipartFile file, Long talentId, Authentication authentication); URL generetePresingedUrlFor7Days(String fileFullPath); } diff --git a/src/main/java/com/provedcode/aws/service/S3Service.java b/src/main/java/com/provedcode/aws/service/S3Service.java index a7a4dc9..5c753ef 100644 --- a/src/main/java/com/provedcode/aws/service/S3Service.java +++ b/src/main/java/com/provedcode/aws/service/S3Service.java @@ -6,6 +6,7 @@ import com.amazonaws.services.s3.model.*; import com.amazonaws.util.IOUtils; import com.provedcode.config.AWSProperties; +import com.provedcode.talent.model.entity.Talent; import com.provedcode.talent.repo.TalentRepository; import com.provedcode.user.model.entity.UserInfo; import com.provedcode.user.repo.UserInfoRepository; @@ -75,7 +76,7 @@ public List listAllFiles() { } @Override - public void setNewUserImage(MultipartFile file, Authentication authentication) { + public void setNewUserImage(MultipartFile file, Long talentId, Authentication authentication) { if (file.isEmpty()) { throw new ResponseStatusException(BAD_REQUEST, "file must be not empty, actual file-size: %s".formatted(file.getSize())); } @@ -84,6 +85,11 @@ public void setNewUserImage(MultipartFile file, Authentication authentication) { } UserInfo user = userInfoRepository.findByLogin(authentication.getName()) .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, "user with login = {%s} not found".formatted(authentication.getName()))); + Talent talent = talentRepository.findById(talentId) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, "talent with id = {%s} not found".formatted(talentId))); + if (!user.getTalent().equals(talent)) { + throw new ResponseStatusException(FORBIDDEN, "You cannot change another talent"); + } try { String fileType = getFileType(file); diff --git a/src/main/java/com/provedcode/config/EmailConfig.java b/src/main/java/com/provedcode/config/EmailConfig.java new file mode 100644 index 0000000..d1a0073 --- /dev/null +++ b/src/main/java/com/provedcode/config/EmailConfig.java @@ -0,0 +1,15 @@ +package com.provedcode.config; + +import lombok.AllArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +@AllArgsConstructor +public class EmailConfig { + private Environment env; + + public String getDefaultEmail() { + return env.getProperty("EMAIL_USER"); + } +} \ No newline at end of file diff --git a/src/main/java/com/provedcode/config/EmailDefaultProps.java b/src/main/java/com/provedcode/config/EmailDefaultProps.java new file mode 100644 index 0000000..f6adf63 --- /dev/null +++ b/src/main/java/com/provedcode/config/EmailDefaultProps.java @@ -0,0 +1,19 @@ +package com.provedcode.config; + +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +@Validated +@ConfigurationProperties(prefix = "default-email") +@Slf4j +public record EmailDefaultProps( + String userDeleted, + String userDeletedSubject +) { + @PostConstruct + void logging() { + log.info("email-default-props = {}", this); + } +} diff --git a/src/main/java/com/provedcode/config/SecurityConfig.java b/src/main/java/com/provedcode/config/SecurityConfig.java index 4459d42..8bfb464 100644 --- a/src/main/java/com/provedcode/config/SecurityConfig.java +++ b/src/main/java/com/provedcode/config/SecurityConfig.java @@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; @@ -59,6 +60,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .requestMatchers(antMatcher("/v3/api-docs/**")).permitAll() // for openAPI .requestMatchers(antMatcher("/swagger-ui/**")).permitAll() // for openAPI .requestMatchers(antMatcher("/swagger-ui.html")).permitAll() // for openAPI + .requestMatchers(antMatcher(HttpMethod.GET, "/api/v5/activate")).permitAll()// for email account recovery .anyRequest().authenticated() ); diff --git a/src/main/java/com/provedcode/config/ServerInfoConfig.java b/src/main/java/com/provedcode/config/ServerInfoConfig.java new file mode 100644 index 0000000..ba483f4 --- /dev/null +++ b/src/main/java/com/provedcode/config/ServerInfoConfig.java @@ -0,0 +1,29 @@ +package com.provedcode.config; + +import lombok.AllArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +@AllArgsConstructor +@Configuration +public class ServerInfoConfig { + private Environment env; + + public String getServerPort() { + return env.getProperty("server.port"); + } + public String getIpAddress() { + InetAddress ip = null; + try { + return ip.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + public String getFullServerAddress() { + return getIpAddress() + ":" + getServerPort(); + } +} diff --git a/src/main/java/com/provedcode/handlers/GlobalControllerAdvice.java b/src/main/java/com/provedcode/handlers/GlobalControllerAdvice.java new file mode 100644 index 0000000..1d59e1d --- /dev/null +++ b/src/main/java/com/provedcode/handlers/GlobalControllerAdvice.java @@ -0,0 +1,33 @@ +package com.provedcode.handlers; + +import com.provedcode.user.model.entity.UserInfo; +import com.provedcode.user.repo.UserInfoRepository; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.server.ResponseStatusException; + +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.NOT_FOUND; + +@ControllerAdvice +@AllArgsConstructor +@Slf4j +public class GlobalControllerAdvice { + UserInfoRepository userInfoRepository; + + @ModelAttribute + public void handleAuthentication(Authentication authentication) { + if (authentication != null) { + String login = authentication.getName(); + UserInfo user = userInfoRepository.findByLogin(login) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "User with login {%s} not found".formatted(login))); + if (Boolean.TRUE.equals(user.getIsLocked())) { + throw new ResponseStatusException(FORBIDDEN, "your account is blocked"); + } + } + } +} diff --git a/src/main/java/com/provedcode/kudos/controller/KudosController.java b/src/main/java/com/provedcode/kudos/controller/KudosController.java index f065d39..78fa3e1 100644 --- a/src/main/java/com/provedcode/kudos/controller/KudosController.java +++ b/src/main/java/com/provedcode/kudos/controller/KudosController.java @@ -36,7 +36,7 @@ KudosAmount getKudosForSponsor(@PathVariable("sponsor-id") long sponsorId, Authe } @GetAmountOfKudosApiDoc - @PreAuthorize("hasRole('TALENT')") + @PreAuthorize("hasAnyRole('TALENT', 'SPONSOR')") @GetMapping("/proofs/{proof-id}/kudos") KudosAmountWithSponsor getProofKudos(@PathVariable("proof-id") long proofId, Authentication authentication) { return kudosService.getProofKudos(proofId, authentication); diff --git a/src/main/java/com/provedcode/kudos/service/KudosService.java b/src/main/java/com/provedcode/kudos/service/KudosService.java index 39ae8b5..793441a 100644 --- a/src/main/java/com/provedcode/kudos/service/KudosService.java +++ b/src/main/java/com/provedcode/kudos/service/KudosService.java @@ -38,156 +38,185 @@ @AllArgsConstructor @Transactional public class KudosService { - KudosRepository kudosRepository; - TalentProofRepository talentProofRepository; - UserInfoRepository userInfoRepository; - SponsorRepository sponsorRepository; - TalentRepository talentRepository; - ProofSkillRepository proofSkillRepository; - SponsorMapper sponsorMapper; - - @Transactional(readOnly = true) - public KudosAmount getKudosForSponsor(long sponsorId, Authentication authentication) { - String login = authentication.getName(); - UserInfo userInfo = userInfoRepository.findByLogin(login) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "User with login = %s not found".formatted(login))); - if (!userInfo.getSponsor().getId().equals(sponsorId)) { - throw new ResponseStatusException(FORBIDDEN, - "Only the account owner can view the number of kudos"); - } - Sponsor sponsor = sponsorRepository.findById(sponsorId).orElseThrow( - () -> new ResponseStatusException(NOT_FOUND, - String.format("Sponsor with id = %d not found", sponsorId))); - return new KudosAmount(sponsor.getAmountKudos()); + KudosRepository kudosRepository; + TalentProofRepository talentProofRepository; + UserInfoRepository userInfoRepository; + SponsorRepository sponsorRepository; + TalentRepository talentRepository; + ProofSkillRepository proofSkillRepository; + SponsorMapper sponsorMapper; + + @Transactional(readOnly = true) + public KudosAmount getKudosForSponsor(long sponsorId, Authentication authentication) { + String login = authentication.getName(); + UserInfo userInfo = userInfoRepository.findByLogin(login) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "User with login = %s not found".formatted( + login))); + if (!userInfo.getSponsor().getId().equals(sponsorId)) { + throw new ResponseStatusException(FORBIDDEN, "Only the account owner can view the number of kudos"); } - - @Transactional(readOnly = true) - public KudosAmountWithSponsor getProofKudos(long proofId, Authentication authentication) { - String login = authentication.getName(); - UserInfo userInfo = userInfoRepository.findByLogin(login) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "User with login = %s not found".formatted(login))); - Talent talent = talentRepository.findById(userInfo.getTalent().getId()) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "Talent with login = %s not found".formatted(login))); - TalentProof talentProof = talentProofRepository.findById(proofId) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "Proof with id = %s not found".formatted(proofId))); - - Long countOfAllKudos = talentProof.getProofSkills() - .stream().flatMap(proofSkills -> proofSkills.getKudos() - .stream().map(Kudos::getAmount)) - .reduce(0L, (prev, next) -> prev + next); - - if (talent.getId().equals(talentProof.getTalent().getId())) { - Map> skillsMap = new HashMap<>(); - talentProof.getProofSkills().forEach(proofSkill -> { // I dnk wtf is this piece of shit, but it - // works. - String skill = proofSkill.getSkill().getSkill(); - Map kudosFromSponsor = talentProof.getProofSkills().stream() - .filter(proofSkills -> proofSkills.getSkill().getSkill().equals(skill)) - .flatMap(proofSkills -> proofSkills.getKudos().stream()) - .collect(Collectors.toMap( - Kudos::getAmount, - proof -> proof.getSponsor() != null - ? sponsorMapper.toDto( - proof.getSponsor()) - : SponsorDTO.builder().build(), - (prev, next) -> next, - HashMap::new)); - skillsMap.put(skill, kudosFromSponsor); - }); - return KudosAmountWithSponsor.builder() - .allKudosOnProof(countOfAllKudos) - .kudosFromSponsor(skillsMap) - .build(); - } else { - return KudosAmountWithSponsor.builder() - .allKudosOnProof(countOfAllKudos) - .kudosFromSponsor(null).build(); - } + Sponsor sponsor = sponsorRepository.findById(sponsorId).orElseThrow( + () -> new ResponseStatusException(NOT_FOUND, + String.format("Sponsor with id = %d not found", sponsorId))); + return new KudosAmount(sponsor.getAmountKudos()); + } + + @Transactional(readOnly = true) + public KudosAmountWithSponsor getProofKudos(long proofId, Authentication authentication) { + String login = authentication.getName(); + UserInfo userInfo = userInfoRepository.findByLogin(login) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "User with login = %s not found".formatted(login))); + TalentProof talentProof = talentProofRepository.findById(proofId) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "Proof with id = %s not found".formatted(proofId))); + + Long countOfAllKudos = talentProof.getProofSkills() + .stream().flatMap(proofSkills -> proofSkills.getKudos() + .stream().map(Kudos::getAmount)) + .reduce(0L, Long::sum); + Map> skillsMap = new HashMap<>(); + + if (userInfo.getSponsor() != null && userInfo.getTalent() == null) { + Sponsor sponsor = sponsorRepository.findById(userInfo.getSponsor().getId()) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "User with login = %s not found".formatted( + login))); + talentProof.getProofSkills().forEach(proofSkill -> { + String skill = proofSkill.getSkill().getSkill(); + Map kudosFromSponsor = talentProof.getProofSkills().stream() + .map(proofSkills -> { + proofSkills.setKudos(proofSkills.getKudos().stream() + .filter(kudos -> sponsor.equals(kudos.getSponsor())).toList()); + return proofSkills; + }) + .filter(proofSkills -> proofSkills.getSkill().getSkill().equals(skill)) + .flatMap(proofSkills -> proofSkills.getKudos().stream()) + .collect(Collectors.toMap( + Kudos::getAmount, + proof -> proof.getSponsor() != null + ? sponsorMapper.toDto(proof.getSponsor()) + : SponsorDTO.builder().build(), + (prev, next) -> next, + HashMap::new)); + skillsMap.put(skill, kudosFromSponsor); + }); + + return KudosAmountWithSponsor.builder() + .allKudosOnProof(countOfAllKudos) + .kudosFromSponsor(skillsMap) + .build(); } - public void addKudosToProof(long proofId, SetAmountKudos amountOfKudoses, Authentication authentication) { - String login = authentication.getName(); - UserInfo userInfo = userInfoRepository.findByLogin(login) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "User with login = %s not found".formatted(login))); - Sponsor sponsor = sponsorRepository.findById(userInfo.getSponsor().getId()).orElseThrow( - () -> new ResponseStatusException(NOT_FOUND, - "Sponsor with login = %s not found".formatted(login))); - TalentProof talentProof = talentProofRepository.findById(proofId) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "Proof with id = %d not found".formatted(proofId))); - if (!talentProof.getStatus().equals(ProofStatus.PUBLISHED)) - throw new ResponseStatusException(FORBIDDEN, - "Proof that was kudosed does not have the PUBLISHED status"); - long obtainedAmount = amountOfKudoses.amount(); - - if (sponsor.getAmountKudos() < obtainedAmount) { - throw new ResponseStatusException(FORBIDDEN, "The sponsor cannot give more kudos than he has"); - } - Long modula = obtainedAmount % talentProof.getProofSkills().size(); - if (modula != 0) { - obtainedAmount -= modula; - } - sponsor.setAmountKudos(sponsor.getAmountKudos() - obtainedAmount); - - Long addKudoses = obtainedAmount / talentProof.getProofSkills().size(); - - talentProof.getProofSkills().forEach(proofSkill -> { - Kudos kudos = Kudos.builder() - .sponsor(sponsor) - .skill(proofSkill) - .amount(addKudoses) - .build(); - proofSkill.getKudos().add(kudosRepository.save(kudos)); - }); + Talent talent = talentRepository.findById(userInfo.getTalent().getId()) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "Talent with login = %s not found".formatted(login))); + if (talent.getId().equals(talentProof.getTalent().getId())) { + talentProof.getProofSkills().forEach(proofSkill -> { // I dnk wtf is this piece of shit, but it works. + String skill = proofSkill.getSkill().getSkill(); + Map kudosFromSponsor = talentProof.getProofSkills().stream() + .filter(proofSkills -> proofSkills.getSkill().getSkill().equals(skill)) + .flatMap(proofSkills -> proofSkills.getKudos().stream()) + .collect(Collectors.toMap( + Kudos::getAmount, + proof -> proof.getSponsor() != null + ? sponsorMapper.toDto(proof.getSponsor()) + : SponsorDTO.builder().build(), + (prev, next) -> next, + HashMap::new)); + skillsMap.put(skill, kudosFromSponsor); + }); + return KudosAmountWithSponsor.builder() + .allKudosOnProof(countOfAllKudos) + .kudosFromSponsor(skillsMap) + .build(); + } else { + return KudosAmountWithSponsor.builder() + .allKudosOnProof(countOfAllKudos) + .kudosFromSponsor(null).build(); } - - public void addKudosToSkill(long proofId, long skillId, SetAmountKudos amountOfKudos, - Authentication authentication) { - String login = authentication.getName(); - UserInfo userInfo = userInfoRepository.findByLogin(login) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "User with login = %s not found".formatted( - login))); - Sponsor sponsor = sponsorRepository.findById(userInfo.getSponsor().getId()).orElseThrow( - () -> new ResponseStatusException(NOT_FOUND, - "Sponsor with login = %s not found".formatted(login))); - TalentProof talentProof = talentProofRepository.findById(proofId) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "Proof with id = %d not found".formatted(proofId))); - if (!talentProof.getStatus().equals(ProofStatus.PUBLISHED)) - throw new ResponseStatusException(FORBIDDEN, - "Skill on proof that was kudosed does not have the PUBLISHED status"); - long obtainedAmount = amountOfKudos.amount(); - if (sponsor.getAmountKudos() < obtainedAmount) { - throw new ResponseStatusException(FORBIDDEN, "The sponsor cannot give more kudos than he has"); - } - sponsor.setAmountKudos(sponsor.getAmountKudos() - obtainedAmount); - ProofSkill proofSkill = talentProof.getProofSkills().stream() - .filter(s -> s.getSkill().getId().equals(skillId)) - .findFirst().orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "Skill with id = %d not found".formatted(skillId))); - kudosRepository.save(Kudos.builder().amount(obtainedAmount).sponsor(sponsor).skill(proofSkill).build()); + } + + public void addKudosToProof(long proofId, SetAmountKudos amountOfKudoses, Authentication authentication) { + String login = authentication.getName(); + UserInfo userInfo = userInfoRepository.findByLogin(login) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "User with login = %s not found".formatted(login))); + Sponsor sponsor = sponsorRepository.findById(userInfo.getSponsor().getId()).orElseThrow( + () -> new ResponseStatusException(NOT_FOUND, + "Sponsor with login = %s not found".formatted(login))); + TalentProof talentProof = talentProofRepository.findById(proofId) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "Proof with id = %d not found".formatted(proofId))); + if (!talentProof.getStatus().equals(ProofStatus.PUBLISHED)) + throw new ResponseStatusException(FORBIDDEN, + "Proof that was kudosed does not have the PUBLISHED status"); + long obtainedAmount = amountOfKudoses.amount(); + + if (sponsor.getAmountKudos() < obtainedAmount) { + throw new ResponseStatusException(FORBIDDEN, "The sponsor cannot give more kudos than he has"); } - - @Transactional(readOnly = true) - public KudosAmount getSkillKudos(long proofId, long skillId) { - TalentProof talentProof = talentProofRepository.findById(proofId) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "Proof with id = %d not found".formatted(proofId))); - if (!talentProof.getStatus().equals(ProofStatus.PUBLISHED)) - throw new ResponseStatusException(FORBIDDEN, - "The skill from the proof that was referred to does not have a PUBLISHED status"); - ProofSkill proofSkill = talentProof.getProofSkills().stream() - .filter(s -> s.getSkill().getId().equals(skillId)) - .findFirst().orElseThrow(() -> new ResponseStatusException(NOT_FOUND, - "Skill with id = %d not found".formatted(skillId))); - List kudos = kudosRepository.findBySkill(proofSkill); - long amountOfKudos = kudos.stream().map(Kudos::getAmount).reduce(0L, Long::sum); - return new KudosAmount(amountOfKudos); + Long modula = obtainedAmount % talentProof.getProofSkills().size(); + if (modula != 0) { + obtainedAmount -= modula; + } + sponsor.setAmountKudos(sponsor.getAmountKudos() - obtainedAmount); + + Long addKudoses = obtainedAmount / talentProof.getProofSkills().size(); + + talentProof.getProofSkills().forEach(proofSkill -> { + Kudos kudos = Kudos.builder() + .sponsor(sponsor) + .skill(proofSkill) + .amount(addKudoses) + .build(); + proofSkill.getKudos().add(kudosRepository.save(kudos)); + }); + } + + public void addKudosToSkill(long proofId, long skillId, SetAmountKudos amountOfKudos, + Authentication authentication) { + String login = authentication.getName(); + UserInfo userInfo = userInfoRepository.findByLogin(login) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "User with login = %s not found".formatted( + login))); + Sponsor sponsor = sponsorRepository.findById(userInfo.getSponsor().getId()).orElseThrow( + () -> new ResponseStatusException(NOT_FOUND, + "Sponsor with login = %s not found".formatted(login))); + TalentProof talentProof = talentProofRepository.findById(proofId) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "Proof with id = %d not found".formatted(proofId))); + if (!talentProof.getStatus().equals(ProofStatus.PUBLISHED)) + throw new ResponseStatusException(FORBIDDEN, + "Skill on proof that was kudosed does not have the PUBLISHED status"); + long obtainedAmount = amountOfKudos.amount(); + if (sponsor.getAmountKudos() < obtainedAmount) { + throw new ResponseStatusException(FORBIDDEN, "The sponsor cannot give more kudos than he has"); } + sponsor.setAmountKudos(sponsor.getAmountKudos() - obtainedAmount); + ProofSkill proofSkill = talentProof.getProofSkills().stream() + .filter(s -> s.getSkill().getId().equals(skillId)) + .findFirst().orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "Skill with id = %d not found".formatted(skillId))); + kudosRepository.save(Kudos.builder().amount(obtainedAmount).sponsor(sponsor).skill(proofSkill).build()); + } + + @Transactional(readOnly = true) + public KudosAmount getSkillKudos(long proofId, long skillId) { + TalentProof talentProof = talentProofRepository.findById(proofId) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "Proof with id = %d not found".formatted(proofId))); + if (!talentProof.getStatus().equals(ProofStatus.PUBLISHED)) + throw new ResponseStatusException(FORBIDDEN, + "The skill from the proof that was referred to does not have a PUBLISHED status"); + ProofSkill proofSkill = talentProof.getProofSkills().stream() + .filter(s -> s.getSkill().getId().equals(skillId)) + .findFirst().orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "Skill with id = %d not found".formatted(skillId))); + List kudos = kudosRepository.findBySkill(proofSkill); + long amountOfKudos = kudos.stream().map(Kudos::getAmount).reduce(0L, Long::sum); + return new KudosAmount(amountOfKudos); + } } diff --git a/src/main/java/com/provedcode/sponsor/controller/SponsorController.java b/src/main/java/com/provedcode/sponsor/controller/SponsorController.java index 39c5bad..09aa4d0 100644 --- a/src/main/java/com/provedcode/sponsor/controller/SponsorController.java +++ b/src/main/java/com/provedcode/sponsor/controller/SponsorController.java @@ -23,13 +23,13 @@ @RestController @AllArgsConstructor @Validated -@RequestMapping("/api/v3") +@RequestMapping("/api") public class SponsorController { SponsorService sponsorService; SponsorMapper sponsorMapper; @GetAllSponsorsApiDoc - @GetMapping("/sponsors") + @GetMapping("/v3/sponsors") Page getSponsors(@RequestParam(value = "page", defaultValue = "0") @PositiveOrZero Integer page, @RequestParam(value = "size", defaultValue = "5") @Min(1) @Max(1000) Integer size) { return sponsorService.getAllSponsors(page, size).map(sponsorMapper::toDto); @@ -37,14 +37,14 @@ Page getSponsors(@RequestParam(value = "page", defaultValue = "0") @ @GetSponsorApiDoc @PreAuthorize("hasRole('SPONSOR')") - @GetMapping("/sponsors/{id}") + @GetMapping("/v3/sponsors/{id}") SponsorDTO getSponsor(@PathVariable("id") long id, Authentication authentication) { return sponsorMapper.toDto(sponsorService.getSponsorById(id, authentication)); } @PatchEditSponsorApiDoc @PreAuthorize("hasRole('SPONSOR')") - @PatchMapping("/sponsors/{id}") + @PatchMapping("/v3/sponsors/{id}") SponsorDTO editSponsor(@PathVariable("id") long id, @RequestBody EditSponsor editSponsor, Authentication authentication) { @@ -53,8 +53,14 @@ SponsorDTO editSponsor(@PathVariable("id") long id, @DeleteSponsorApiDoc @PreAuthorize("hasRole('SPONSOR')") - @DeleteMapping("/sponsors/{id}") + @DeleteMapping("/v3/sponsors/{id}") void deleteSponsor(@PathVariable("id") long id, Authentication authentication) { sponsorService.deleteSponsor(id, authentication); } + + @PreAuthorize("hasRole('SPONSOR')") + @DeleteMapping("/v5/sponsors/{sponsor-id}") + void deactivateSponsor(@PathVariable("sponsor-id") long sponsorId, Authentication authentication) { + sponsorService.deactivateSponsor(sponsorId, authentication); + } } \ No newline at end of file diff --git a/src/main/java/com/provedcode/sponsor/service/SponsorService.java b/src/main/java/com/provedcode/sponsor/service/SponsorService.java index 8beaba7..40bff99 100644 --- a/src/main/java/com/provedcode/sponsor/service/SponsorService.java +++ b/src/main/java/com/provedcode/sponsor/service/SponsorService.java @@ -1,13 +1,20 @@ package com.provedcode.sponsor.service; +import com.provedcode.config.EmailDefaultProps; import com.provedcode.config.PageProperties; +import com.provedcode.config.ServerInfoConfig; import com.provedcode.kudos.model.entity.Kudos; import com.provedcode.sponsor.model.entity.Sponsor; import com.provedcode.sponsor.model.request.EditSponsor; import com.provedcode.sponsor.repository.SponsorRepository; import com.provedcode.sponsor.utill.ValidateSponsorForCompliance; +import com.provedcode.user.model.entity.DeletedUser; import com.provedcode.user.model.entity.UserInfo; +import com.provedcode.user.repo.DeletedUserRepository; import com.provedcode.user.repo.UserInfoRepository; +import com.provedcode.user.service.impl.EmailService; +import com.provedcode.user.util.UsersSchedulerService; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -16,11 +23,13 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Optional; +import java.util.UUID; -import static org.springframework.http.HttpStatus.BAD_REQUEST; -import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.*; @Service @AllArgsConstructor @@ -30,6 +39,10 @@ public class SponsorService { SponsorRepository sponsorRepository; UserInfoRepository userInfoRepository; ValidateSponsorForCompliance validateSponsorForCompliance; + DeletedUserRepository deletedUserRepository; + ServerInfoConfig serverInfoConfig; + EmailService emailService; + EmailDefaultProps emailDefaultProps; @Transactional(readOnly = true) public Page getAllSponsors(Integer page, Integer size) { @@ -76,17 +89,49 @@ public void deleteSponsor(long id, Authentication authentication) { validateSponsorForCompliance.userVerification(sponsor, user, id); Sponsor deletableSponsor = sponsor.get(); + deleteSponsorByUser(user.get(), deletableSponsor); + } + + private void deleteSponsorByUser(UserInfo user, @NotNull Sponsor deletableSponsor) { List kudosList = deletableSponsor.getKudoses().stream().map(i -> { i.setSponsor(null); return i; }).toList(); deletableSponsor.setKudoses(kudosList); - userInfoRepository.delete(user.get()); + userInfoRepository.delete(user); } private void checkEditSponsorNull(EditSponsor editSponsor) { if (editSponsor.firstName() == null && editSponsor.lastName() == null && editSponsor.image() == null && - editSponsor.countOfKudos() == null) + editSponsor.countOfKudos() == null) throw new ResponseStatusException(FORBIDDEN, "you did not provide information to make changes"); } + + public void deactivateSponsor(long sponsorId, Authentication authentication) { + UserInfo user = userInfoRepository.findByLogin(authentication.getName()) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "user with login = %s not found".formatted(authentication.getName()))); + Sponsor sponsor = sponsorRepository.findById(sponsorId) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, + "sponsor with id = %s not found".formatted(sponsorId))); + if (!sponsor.equals(user.getSponsor())) { + throw new ResponseStatusException(FORBIDDEN, "you cannot update/delete another sponsor"); + } + user.setIsLocked(true); + + DeletedUser deletedUser = DeletedUser.builder() + .deletedUser(user) + .timeToDelete(Instant.now().plus(3, ChronoUnit.DAYS)) + .uuidForActivate(UUID.randomUUID().toString()) + .build(); + + String userActivateAccountLink = serverInfoConfig.getFullServerAddress() + + "/api/v5/activate?uuid=" + deletedUser.getUuidForActivate(); + + deletedUserRepository.save(deletedUser); + + emailService.sendEmail(user.getLogin(), + emailDefaultProps.userDeletedSubject(), + emailDefaultProps.userDeleted().formatted(userActivateAccountLink)); + } } \ No newline at end of file diff --git a/src/main/java/com/provedcode/talent/controller/TalentController.java b/src/main/java/com/provedcode/talent/controller/TalentController.java index 3c0b319..157cc17 100644 --- a/src/main/java/com/provedcode/talent/controller/TalentController.java +++ b/src/main/java/com/provedcode/talent/controller/TalentController.java @@ -97,4 +97,11 @@ StatisticsDTO getStatisticsForTalent(@PathVariable("talent-id") long talentId, Authentication authentication) { return talentService.getStatisticsForTalent(talentId, authentication); } + + @PreAuthorize("hasRole('TALENT')") + @DeleteMapping("v5/talents/{talent-id}") + void deactivateTalentById(@PathVariable("talent-id") long talentId, + Authentication authentication) { + talentService.deactivateTalentById(talentId, authentication); + } } \ No newline at end of file diff --git a/src/main/java/com/provedcode/talent/service/TalentService.java b/src/main/java/com/provedcode/talent/service/TalentService.java index d89b82d..e0e8e54 100644 --- a/src/main/java/com/provedcode/talent/service/TalentService.java +++ b/src/main/java/com/provedcode/talent/service/TalentService.java @@ -1,10 +1,11 @@ package com.provedcode.talent.service; +import com.provedcode.config.EmailDefaultProps; import com.provedcode.config.PageProperties; +import com.provedcode.config.ServerInfoConfig; import com.provedcode.kudos.model.entity.Kudos; import com.provedcode.talent.mapper.TalentProofMapper; import com.provedcode.talent.model.dto.ProofDTO; -import com.provedcode.talent.model.dto.SkillDTO; import com.provedcode.talent.model.dto.SkillIdDTO; import com.provedcode.talent.model.dto.StatisticsDTO; import com.provedcode.talent.model.entity.*; @@ -14,9 +15,12 @@ import com.provedcode.talent.repo.TalentRepository; import com.provedcode.talent.utill.ValidateTalentForCompliance; import com.provedcode.user.model.dto.SessionInfoDTO; +import com.provedcode.user.model.entity.DeletedUser; import com.provedcode.user.model.entity.UserInfo; import com.provedcode.user.repo.AuthorityRepository; +import com.provedcode.user.repo.DeletedUserRepository; import com.provedcode.user.repo.UserInfoRepository; +import com.provedcode.user.service.impl.EmailService; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.PositiveOrZero; @@ -29,6 +33,8 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; @@ -47,6 +53,10 @@ public class TalentService { ValidateTalentForCompliance validateTalentForCompliance; SkillsRepository skillsRepository; TalentProofMapper talentProofMapper; + DeletedUserRepository deletedUserRepository; + ServerInfoConfig serverInfoConfig; + EmailService emailService; + EmailDefaultProps emailDefaultProps; @Transactional(readOnly = true) public Page getTalentsPage(Integer page, Integer size) { @@ -143,15 +153,34 @@ public SessionInfoDTO deleteTalentById(long id, Authentication authentication) { validateTalentForCompliance.userVerification(talent, userInfo, id); UserInfo user = userInfo.get(); - Talent entity = talent.get(); - - user.getAuthorities().clear(); userInfoRepository.delete(user); - talentRepository.delete(entity); return new SessionInfoDTO("deleted", "null"); } + public void deactivateTalentById(long id, Authentication authentication) { + Optional talent = talentRepository.findById(id); + Optional userInfo = userInfoRepository.findByLogin(authentication.getName()); + + validateTalentForCompliance.userVerification(talent, userInfo, id); + + UserInfo user = userInfo.get(); + user.setIsLocked(true); + DeletedUser deletedUser = DeletedUser.builder() + .deletedUser(user) + .timeToDelete(Instant.now().plus(3, ChronoUnit.DAYS)) + .uuidForActivate(UUID.randomUUID().toString()) + .build(); + deletedUserRepository.save(deletedUser); + userInfoRepository.save(user); + + String userActivateAccountLink = serverInfoConfig.getFullServerAddress() + "/api/v5/activate?uuid=" + deletedUser.getUuidForActivate(); + + emailService.sendEmail(user.getLogin(), + emailDefaultProps.userDeletedSubject(), + emailDefaultProps.userDeleted().formatted(userActivateAccountLink)); + } + private void checkEditTalentNull(EditTalent editTalent) { if (editTalent.firstName() == null && editTalent.lastName() == null && editTalent.image() == null && editTalent.specialization() == null && editTalent.additionalInfo() == null && editTalent.bio() == null && diff --git a/src/main/java/com/provedcode/user/controller/AuthenticationController.java b/src/main/java/com/provedcode/user/controller/AuthenticationController.java index b30ee13..e25f35b 100644 --- a/src/main/java/com/provedcode/user/controller/AuthenticationController.java +++ b/src/main/java/com/provedcode/user/controller/AuthenticationController.java @@ -1,5 +1,6 @@ package com.provedcode.user.controller; +import com.provedcode.talent.service.TalentService; import com.provedcode.user.model.dto.SponsorRegistrationDTO; import com.provedcode.user.model.dto.TalentRegistrationDTO; import com.provedcode.user.model.dto.UserInfoDTO; @@ -40,4 +41,9 @@ UserInfoDTO register(@RequestBody @Valid TalentRegistrationDTO user) { UserInfoDTO register(@RequestBody @Valid SponsorRegistrationDTO user) { return authenticationService.register(user); } + + @GetMapping("/v5/activate") + void activateAccount(@RequestParam("uuid") String uuid) { + authenticationService.activateAccount(uuid); + } } \ No newline at end of file diff --git a/src/main/java/com/provedcode/user/model/entity/DeletedUser.java b/src/main/java/com/provedcode/user/model/entity/DeletedUser.java new file mode 100644 index 0000000..105f920 --- /dev/null +++ b/src/main/java/com/provedcode/user/model/entity/DeletedUser.java @@ -0,0 +1,25 @@ +package com.provedcode.user.model.entity; + +import jakarta.persistence.*; +import lombok.*; +import lombok.extern.slf4j.Slf4j; + +import java.time.Instant; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Slf4j +@Builder +@Entity +public class DeletedUser { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private Instant timeToDelete; + @OneToOne + @JoinColumn(name = "user_id", referencedColumnName = "id") + private UserInfo deletedUser; + private String uuidForActivate; +} \ No newline at end of file diff --git a/src/main/java/com/provedcode/user/model/entity/UserInfo.java b/src/main/java/com/provedcode/user/model/entity/UserInfo.java index 19dc0da..7250e83 100644 --- a/src/main/java/com/provedcode/user/model/entity/UserInfo.java +++ b/src/main/java/com/provedcode/user/model/entity/UserInfo.java @@ -55,4 +55,7 @@ public class UserInfo { @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "users_authorities", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "authority_id")) private Set authorities = new LinkedHashSet<>(); + + @Column(columnDefinition = "FALSE") + private Boolean isLocked; } \ No newline at end of file diff --git a/src/main/java/com/provedcode/user/repo/DeletedUserRepository.java b/src/main/java/com/provedcode/user/repo/DeletedUserRepository.java new file mode 100644 index 0000000..de3478a --- /dev/null +++ b/src/main/java/com/provedcode/user/repo/DeletedUserRepository.java @@ -0,0 +1,15 @@ +package com.provedcode.user.repo; + +import com.provedcode.user.model.entity.DeletedUser; +import com.provedcode.user.model.entity.UserInfo; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.Optional; + +public interface DeletedUserRepository extends JpaRepository { + @Query("select d from DeletedUser d where d.uuidForActivate = ?1") + Optional findByUUID(String uuidForActivate); + Optional findByUuidForActivate(String uuidForActivate); + +} \ No newline at end of file diff --git a/src/main/java/com/provedcode/user/service/AuthenticationService.java b/src/main/java/com/provedcode/user/service/AuthenticationService.java index 57b7bcd..277af5d 100644 --- a/src/main/java/com/provedcode/user/service/AuthenticationService.java +++ b/src/main/java/com/provedcode/user/service/AuthenticationService.java @@ -9,6 +9,10 @@ public interface AuthenticationService { UserInfoDTO login(String name, Collection authorities); + UserInfoDTO register(TalentRegistrationDTO user); + UserInfoDTO register(SponsorRegistrationDTO user); + + void activateAccount(String uuid); } diff --git a/src/main/java/com/provedcode/user/service/impl/AuthenticationServiceImpl.java b/src/main/java/com/provedcode/user/service/impl/AuthenticationServiceImpl.java index dbcce3e..2adc01f 100644 --- a/src/main/java/com/provedcode/user/service/impl/AuthenticationServiceImpl.java +++ b/src/main/java/com/provedcode/user/service/impl/AuthenticationServiceImpl.java @@ -9,13 +9,14 @@ import com.provedcode.user.model.dto.TalentRegistrationDTO; import com.provedcode.user.model.dto.UserInfoDTO; import com.provedcode.user.model.entity.Authority; +import com.provedcode.user.model.entity.DeletedUser; import com.provedcode.user.model.entity.UserInfo; import com.provedcode.user.repo.AuthorityRepository; +import com.provedcode.user.repo.DeletedUserRepository; import com.provedcode.user.repo.UserInfoRepository; import com.provedcode.user.service.AuthenticationService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.catalina.User; import org.springframework.http.HttpStatus; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.crypto.password.PasswordEncoder; @@ -47,6 +48,7 @@ public class AuthenticationServiceImpl implements AuthenticationService { SponsorRepository sponsorRepository; AuthorityRepository authorityRepository; PasswordEncoder passwordEncoder; + DeletedUserRepository deletedUserRepository; @Transactional(readOnly = true) public UserInfoDTO login(String name, Collection authorities) { @@ -80,6 +82,7 @@ public UserInfoDTO register(TalentRegistrationDTO user) { .login(user.login()) .password(passwordEncoder.encode(user.password())) .authorities(Set.of(authorityRepository.findByAuthority(Role.TALENT).orElseThrow())) + .isLocked(false) .build(); userInfoRepository.save(userInfo); @@ -111,6 +114,7 @@ public UserInfoDTO register(SponsorRegistrationDTO user) { .password(passwordEncoder.encode(user.password())) .authorities( Set.of(authorityRepository.findByAuthority(Role.SPONSOR).orElseThrow())) + .isLocked(false) .build(); userInfoRepository.save(userInfo); @@ -123,6 +127,15 @@ public UserInfoDTO register(SponsorRegistrationDTO user) { return new UserInfoDTO(generateJWTToken(sponsor.getId(), userLogin, userAuthorities).getTokenValue()); } + public void activateAccount(String uuid) { + DeletedUser deletedUser = deletedUserRepository.findByUUID(uuid) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND)); + UserInfo user = deletedUser.getDeletedUser(); + user.setIsLocked(false); + deletedUserRepository.deleteById(deletedUser.getId()); + userInfoRepository.save(user); + } + private Jwt generateJWTToken(Long id, String login, Collection authorities) { log.info("=== POST /login === auth.login = {}", login); log.info("=== POST /login === auth = {}", authorities); diff --git a/src/main/java/com/provedcode/user/service/impl/EmailService.java b/src/main/java/com/provedcode/user/service/impl/EmailService.java new file mode 100644 index 0000000..c497427 --- /dev/null +++ b/src/main/java/com/provedcode/user/service/impl/EmailService.java @@ -0,0 +1,25 @@ +package com.provedcode.user.service.impl; + +import com.provedcode.config.EmailConfig; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Service; + +@Service +@AllArgsConstructor +@Slf4j +public class EmailService { + private JavaMailSender javaMailSender; + private EmailConfig emailConfig; + + public void sendEmail(String to, String subject, String text) { + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom(emailConfig.getDefaultEmail()); + message.setTo(to); + message.setSubject(subject); + message.setText(text); + javaMailSender.send(message); + } +} diff --git a/src/main/java/com/provedcode/user/util/UsersSchedulerService.java b/src/main/java/com/provedcode/user/util/UsersSchedulerService.java new file mode 100644 index 0000000..63285dd --- /dev/null +++ b/src/main/java/com/provedcode/user/util/UsersSchedulerService.java @@ -0,0 +1,64 @@ +package com.provedcode.user.util; + +import com.provedcode.user.repo.DeletedUserRepository; +import com.provedcode.user.repo.UserInfoRepository; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.concurrent.TimeUnit; + +@Service +@EnableScheduling +@AllArgsConstructor +@Transactional +@Slf4j +public class UsersSchedulerService { + UserInfoRepository userInfoRepository; + DeletedUserRepository deletedUsersRepository; + + @Scheduled(timeUnit = TimeUnit.HOURS, fixedRate = 1) + void deleteUser() { + deletedUsersRepository.findAll() + .forEach(userToDelete -> { + if (userToDelete.getTimeToDelete().isAfter(Instant.now())) { + log.info("deleting user: id = {}", userToDelete.getDeletedUser().getId()); + deletedUsersRepository.delete(userToDelete); + userInfoRepository.delete(userToDelete.getDeletedUser()); + } + }); + } + +// @Async +// public void scheduleDeletingMethod(String uuid) { +// try { +// TimeUnit.MINUTES.sleep(3); +// log.info("scheduleDeletingMethod = {}", uuid); +// deletedUsersRepository.findByUUID(uuid) +// .ifPresent(deleted -> { +// deletedUsersRepository.delete(deleted); +// deleteUser(deleted.getDeletedUser()); +// }); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// } +// } +// +// private void deleteUser(UserInfo user) { +// if (user.getSponsor() != null) { +// List kudosList = user.getSponsor().getKudoses().stream().map(i -> { +// i.setSponsor(null); +// return i; +// }).toList(); +// user.getSponsor().setKudoses(kudosList); +// userInfoRepository.delete(user); +// } +// if (user.getTalent() != null) { +// userInfoRepository.delete(user); +// } +// } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f91aa56..d3d2982 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -38,4 +38,14 @@ page-config.default-page-num=0 page-config.default-page-size=5 page-config.default-sort-by=created ## -spring.liquibase.enabled=true \ No newline at end of file +spring.liquibase.enabled=true +## +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username=${EMAIL_USER} +spring.mail.password=${EMAIL_PASSWORD} +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true +# Default email response +default-email.user-deleted=Your account has been suspended, it will be deleted after 24 hours, click on the link to restore it:\n%s\nBest wishes from the test team. +default-email.user-deleted-subject=Your account has been suspended, TestTeam. \ No newline at end of file diff --git a/src/main/resources/db/changelog/changeset/V5/data-V5.sql b/src/main/resources/db/changelog/changeset/V5/data-V5.sql index b897501..2d63889 100644 --- a/src/main/resources/db/changelog/changeset/V5/data-V5.sql +++ b/src/main/resources/db/changelog/changeset/V5/data-V5.sql @@ -5,33 +5,7 @@ insert into authorities (id, authority) values (1, 'TALENT'); insert into authorities (id, authority) values (2, 'SPONSOR'); --- Skill -insert into skills (id, skill) -values (1, 'Java Core'); -insert into skills (id, skill) -values (2, 'Spring Core'); -insert into skills (id, skill) -values (3, 'Spring boot'); -insert into skills (id, skill) -values (4, 'H2 Database'); -insert into skills (id, skill) -values (5, 'Spring Security'); -insert into skills (id, skill) -values (6, 'REST API'); -insert into skills (id, skill) -values (7, 'Git'); -insert into skills (id, skill) -values (8, 'Docker'); -insert into skills (id, skill) -values (9, 'Jira'); -insert into skills (id, skill) -values (10, 'JavaScript Core'); -insert into skills (id, skill) -values (11, 'React'); -insert into skills (id, skill) -values (12, 'Node.js'); -insert into skills (id, skill) -values (13, 'Angular'); + -- Talent -- Serhii Soloviov insert into talents (first_name, last_name, specialization, image) diff --git a/src/main/resources/db/changelog/changeset/V5/deleted-user-schema.sql b/src/main/resources/db/changelog/changeset/V5/deleted-user-schema.sql new file mode 100644 index 0000000..7f19179 --- /dev/null +++ b/src/main/resources/db/changelog/changeset/V5/deleted-user-schema.sql @@ -0,0 +1,14 @@ +--liquibase formatted sql +--changeset Maslyna:5 + +CREATE TABLE deleted_user +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + time_to_delete TIMESTAMP WITHOUT TIME ZONE, + user_id BIGINT, + uuid_for_activate VARCHAR(255), + CONSTRAINT pk_deleteduser PRIMARY KEY (id) +); + +ALTER TABLE deleted_user + ADD CONSTRAINT FK_DELETEDUSER_ON_USER FOREIGN KEY (user_id) REFERENCES users_info (id); \ No newline at end of file diff --git a/src/main/resources/db/changelog/changeset/V5/skills-data.sql b/src/main/resources/db/changelog/changeset/V5/skills-data.sql new file mode 100644 index 0000000..cd7848c --- /dev/null +++ b/src/main/resources/db/changelog/changeset/V5/skills-data.sql @@ -0,0 +1,223 @@ +--liquibase formatted sql +--changeset Maslyna:0 + +-- Skill +insert into skills (id, skill) +values (1, 'Java Core'); +insert into skills (id, skill) +values (2, 'Spring Core'); +insert into skills (id, skill) +values (3, 'Spring boot'); +insert into skills (id, skill) +values (4, 'H2 Database'); +insert into skills (id, skill) +values (5, 'Spring Security'); +insert into skills (id, skill) +values (6, 'REST API'); +insert into skills (id, skill) +values (7, 'Git'); +insert into skills (id, skill) +values (8, 'Docker'); +insert into skills (id, skill) +values (9, 'Jira'); +insert into skills (id, skill) +values (10, 'JavaScript Core'); +insert into skills (id, skill) +values (11, 'React'); +insert into skills (id, skill) +values (12, 'Node.js'); +insert into skills (id, skill) +values (13, 'Angular'); +-- +INSERT INTO skills (id, skill) +VALUES (14, 'Java Development Kit (JDK)'), + (15, 'Servlet API'), + (16, 'JavaServer Pages (JSP)'), + (17, 'JavaServer Faces (JSF)'), + (18, 'Spring Framework'), + (19, 'Hibernate'), + (20, 'Apache Struts'), + (21, 'MySQL'), + (22, 'PostgreSQL'), + (23, 'Oracle'), + (24, 'SQL'), + (25, 'Eclipse'), + (26, 'IntelliJ IDEA'), + (27, 'NetBeans'), + (28, 'Apache Tomcat'), + (29, 'Jetty'), + (30, 'JBoss'), + (31, 'Git'), + (32, 'SVN'), + (33, 'Mercurial'), + (34, 'Algorithms and data structures'), + (35, 'SOAP'), + (36, 'REST'), + (37, 'JSON'), + (38, 'XML'), + (39, 'Multithreading and parallelism'); +INSERT INTO skills (id, skill) +VALUES (40, 'Django'), + (41, 'Flask'), + (42, 'Pyramid'), + (43, 'SQLite'), + (44, 'NoSQL'), + (45, 'MongoDB'), + (46, 'Redis'), + (47, 'BeautifulSoup'), + (48, 'Scrapy'), + (49, 'asyncio'), + (50, 'Twisted'), + (51, 'NumPy'), + (52, 'SciPy'), + (53, 'Pandas'), + (54, 'scikit-learn'), + (55, 'TensorFlow'), + (56, 'PyTorch'), + (57, 'JavaScript'), + (58, 'HTML'), + (59, 'CSS'), + (60, 'DOM'), + (61, 'React'), + (62, 'Angular'), + (63, 'Vue.js'), + (64, 'jQuery'), + (65, 'AJAX'), + (66, 'XSS (Cross-Site Scripting)'), + (67, 'CSRF (Cross-Site Request Forgery)'), + (68, 'Swift'), + (69, 'UIKit'), + (70, 'AppKit'), + (71, 'Core Data'), + (72, 'Core Animation'), + (73, 'Core Location'), + (74, 'Core Graphics'), + (75, 'Storyboards'), + (76, 'Interface Builder'), + (77, 'Auto Layout'), + (78, 'CoreData'), + (79, 'Asynchronous programming'), + (80, 'MVC (Model-View-Controller)'), + (81, 'MVVM (Model-View-ViewModel)'), + (82, 'Clean Architecture'), + (83, 'Kotlin'), + (84, 'Android SDK'), + (85, 'Firebase'), + (86, 'Jenkins'), + (87, 'Docker'), + (88, 'UNIX'), + (89, 'Linux OS'), + (90, 'JPA'), + (91, 'JUnit'), + (92, 'OOP'), + (93, 'PHP'), + (94, 'Microservices'), + (95, 'Azure Service Bus'), + (96, 'Typescript'), + (97, 'WinForms'), + (98, 'Firebase Analytics'), + (99, 'Appsflyer'), + (100, 'Amplitude'); +INSERT INTO skills (id, skill) +VALUES (101, 'Marketing'), + (102, 'Sales'), + (103, 'Content Writing'), + (104, 'Graphic Design'), + (105, 'Video Editing'), + (106, 'Project Management'), + (107, 'Leadership'), + (108, 'Negotiation'), + (109, 'Public Speaking'), + (110, 'Time Management'), + (111, 'Critical Thinking'), + (112, 'Problem Solving'), + (113, 'Customer Service'), + (114, 'Data Analysis'), + (115, 'Financial Planning'), + (116, 'Event Planning'), + (117, 'Foreign Languages'), + (118, 'Photography'), + (119, 'Cooking'), + (120, 'Yoga'), + (121, 'Creative Writing'); +INSERT INTO skills (id, skill) +VALUES (122, 'Leadership Development'), + (123, 'Emotional Intelligence'), + (124, 'Teamwork'), + (125, 'Conflict Resolution'), + (126, 'Decision Making'), + (127, 'Presentation Skills'), + (128, 'Networking'), + (129, 'Research Skills'), + (130, 'Problem-solving'), + (131, 'Analytical Thinking'), + (132, 'Creativity'), + (133, 'Attention to Detail'), + (134, 'Organizational Skills'), + (135, 'Time Management'), + (136, 'Adaptability'), + (137, 'Stress Management'), + (138, 'Interpersonal Skills'), + (139, 'Communication Skills'), + (140, 'Customer Relationship Management'), + (141, 'Sales Techniques'), + (142, 'Market Research'), + (143, 'Digital Marketing'), + (144, 'Social Media Marketing'), + (145, 'Search Engine Optimization'), + (146, 'Content Marketing'), + (147, 'Data Analytics'), + (148, 'Financial Analysis'), + (149, 'Budgeting'), + (150, 'Project Planning'), + (151, 'Quality Assurance'), + (152, 'Risk Management'), + (153, 'Supply Chain Management'), + (154, 'Logistics'), + (155, 'Business Strategy'), + (156, 'Entrepreneurship'), + (157, 'Innovation'), + (158, 'Customer Service'), + (159, 'Hospitality'), + (160, 'Event Management'); +INSERT INTO skills (id, skill) +VALUES (161, 'Teaching'), + (162, 'Tutoring'), + (163, 'Curriculum Development'), + (164, 'Instructional Design'), + (165, 'Classroom Management'), + (166, 'Educational Technology'), + (167, 'Language Teaching'), + (168, 'Music'), + (169, 'Art'), + (170, 'Sports'), + (171, 'Fitness'), + (172, 'Nutrition'), + (173, 'Counseling'), + (174, 'Life Coaching'), + (175, 'Meditation'), + (176, 'Mindfulness'), + (177, 'Research'), + (178, 'Data Entry'), + (179, 'Virtual Assistance'), + (180, 'Project Coordination'), + (181, 'Event Coordination'), + (182, 'Office Management'), + (183, 'Translation'), + (184, 'Transcription'), + (185, 'Proofreading'), + (186, 'Editing'), + (187, 'Copywriting'), + (188, 'Content Creation'), + (189, 'Social Media Management'), + (190, 'Graphic Design'), + (191, 'Video Editing'), + (192, 'Photography'), + (193, 'Web Development'), + (194, 'Mobile App Development'), + (195, 'Game Development'), + (196, 'UI/UX Design'), + (197, 'Product Management'), + (198, 'Agile Methodology'), + (199, 'Scrum'), + (200, 'Lean Manufacturing'); \ No newline at end of file diff --git a/src/main/resources/db/changelog/changeset/V5/user-info-schema-V5.sql b/src/main/resources/db/changelog/changeset/V5/user-info-schema-V5.sql index 97b1109..3028fe7 100644 --- a/src/main/resources/db/changelog/changeset/V5/user-info-schema-V5.sql +++ b/src/main/resources/db/changelog/changeset/V5/user-info-schema-V5.sql @@ -8,6 +8,7 @@ CREATE TABLE users_info ( sponsor_id BIGINT REFERENCES sponsors, login VARCHAR(100) NOT NULL, password VARCHAR(255) NOT NULL, + is_locked BOOLEAN, PRIMARY KEY (id) ); CREATE TABLE authorities ( diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 77eb9b2..49cbdae 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -23,7 +23,12 @@ databaseChangeLog: file: db/changelog/changeset/V5/user-info-schema-V5.sql - include: file: db/changelog/changeset/V5/data-V5.sql + - include: + file: db/changelog/changeset/V5/skills-data.sql - include: file: db/changelog/changeset/V5/dataSkill-V5.sql - include: file: db/changelog/changeset/V5/dataKudos-V5.sql + - include: + file: db/changelog/changeset/V5/deleted-user-schema.sql +