From 2c07fba86e326c4ae84dce17ba85de4aa6678d0e Mon Sep 17 00:00:00 2001 From: Yomna Date: Mon, 18 Sep 2023 13:20:29 +0300 Subject: [PATCH 1/2] #123_Create_Followup_Crud_Api --- .../example/demo/config/SecurityConfig.java | 3 +- .../com/example/demo/entity/Application.java | 6 +- .../com/example/demo/entity/Candidate.java | 2 +- .../com/example/demo/entity/Document.java | 4 ++ .../com/example/demo/entity/FollowUp.java | 28 +++++++++ .../java/com/example/demo/entity/Vacancy.java | 2 +- .../demo/repository/FollowUpRepository.java | 28 +++++++++ .../demo/repository/InterviewRepository.java | 3 + .../demo/repository/PositionRepository.java | 3 +- .../demo/repository/TopicLevelRepository.java | 3 +- .../rest/controller/FollowUpController.java | 46 ++++++++++++++ .../example/demo/rest/dto/FollowUpDto.java | 14 +++++ .../example/demo/rest/dto/InterviewDto.java | 5 +- .../example/demo/rest/dto/PositionDto.java | 2 + .../example/demo/rest/dto/TopicLevelDto.java | 5 ++ .../com/example/demo/rest/dto/TopicsDto.java | 6 ++ .../rest/entitymapper/DocumentMapper.java | 2 +- .../rest/entitymapper/FollowUpMapper.java | 60 ++++++++++++++++++ .../demo/rest/handler/FollowUpHandler.java | 63 +++++++++++++++++++ .../example/demo/security/TokenProvider.java | 1 + .../example/demo/service/FollowUpService.java | 38 +++++++++++ .../example/demo/service/PositionService.java | 2 + .../example/demo/utils/HibernateUtils.java | 22 +++++++ .../src/main/resources/application.properties | 4 +- .../db/changelog/2022/08/01-01-changelog.xml | 26 ++++++++ .../db/changelog/2022/08/01-02-changelog.xml | 31 +++++++++ .../db/changelog/2022/08/01-03-changelog.xml | 13 ++++ .../db/changelog/2022/08/01-04-changelog.xml | 46 ++++++++++++++ .../src/main/resources/db/root-changelog.xml | 5 ++ 29 files changed, 460 insertions(+), 13 deletions(-) create mode 100644 back-end/src/main/java/com/example/demo/entity/FollowUp.java create mode 100644 back-end/src/main/java/com/example/demo/repository/FollowUpRepository.java create mode 100644 back-end/src/main/java/com/example/demo/rest/controller/FollowUpController.java create mode 100644 back-end/src/main/java/com/example/demo/rest/dto/FollowUpDto.java create mode 100644 back-end/src/main/java/com/example/demo/rest/entitymapper/FollowUpMapper.java create mode 100644 back-end/src/main/java/com/example/demo/rest/handler/FollowUpHandler.java create mode 100644 back-end/src/main/java/com/example/demo/service/FollowUpService.java create mode 100644 back-end/src/main/java/com/example/demo/utils/HibernateUtils.java create mode 100644 back-end/src/main/resources/db/changelog/2022/08/01-01-changelog.xml create mode 100644 back-end/src/main/resources/db/changelog/2022/08/01-02-changelog.xml create mode 100644 back-end/src/main/resources/db/changelog/2022/08/01-03-changelog.xml create mode 100644 back-end/src/main/resources/db/changelog/2022/08/01-04-changelog.xml diff --git a/back-end/src/main/java/com/example/demo/config/SecurityConfig.java b/back-end/src/main/java/com/example/demo/config/SecurityConfig.java index 545002d2..e12a77da 100644 --- a/back-end/src/main/java/com/example/demo/config/SecurityConfig.java +++ b/back-end/src/main/java/com/example/demo/config/SecurityConfig.java @@ -38,7 +38,8 @@ protected void configure(HttpSecurity http) throws Exception { http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.authorizeRequests().antMatchers("/auth/**").permitAll(); http.authorizeRequests().antMatchers("/v3/api-docs/*", "/v3/api-docs", "/swagger-ui.html", "/swagger-ui/*").permitAll(); - http.authorizeRequests().anyRequest().authenticated(); + //http.authorizeRequests().anyRequest().authenticated(); + http.authorizeRequests().antMatchers("/authenticate").permitAll(); http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } diff --git a/back-end/src/main/java/com/example/demo/entity/Application.java b/back-end/src/main/java/com/example/demo/entity/Application.java index df302b3a..e0922608 100644 --- a/back-end/src/main/java/com/example/demo/entity/Application.java +++ b/back-end/src/main/java/com/example/demo/entity/Application.java @@ -9,16 +9,16 @@ @Entity public class Application extends JPAEntity { - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "VACANCY_ID") private Vacancy vacancy; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "CANDIDATE_ID") private Candidate candidate; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "QUESTION_ID") private Question question; diff --git a/back-end/src/main/java/com/example/demo/entity/Candidate.java b/back-end/src/main/java/com/example/demo/entity/Candidate.java index 2b6783f9..ab5e03f7 100644 --- a/back-end/src/main/java/com/example/demo/entity/Candidate.java +++ b/back-end/src/main/java/com/example/demo/entity/Candidate.java @@ -25,7 +25,7 @@ public class Candidate extends JPAEntity { @Column private Integer documentId; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "position_id") private Position position; diff --git a/back-end/src/main/java/com/example/demo/entity/Document.java b/back-end/src/main/java/com/example/demo/entity/Document.java index 72c84f54..80bde2f6 100644 --- a/back-end/src/main/java/com/example/demo/entity/Document.java +++ b/back-end/src/main/java/com/example/demo/entity/Document.java @@ -3,11 +3,15 @@ import com.example.demo.entity.common.JPAEntity; import com.example.demo.support.DocumentType; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import javax.persistence.*; @Data @Entity +@EqualsAndHashCode(of = "id", callSuper = false) +@ToString(of = "id", callSuper = false) public class Document extends JPAEntity { @Column diff --git a/back-end/src/main/java/com/example/demo/entity/FollowUp.java b/back-end/src/main/java/com/example/demo/entity/FollowUp.java new file mode 100644 index 00000000..bfc4ef51 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/entity/FollowUp.java @@ -0,0 +1,28 @@ +package com.example.demo.entity; + +import com.example.demo.entity.common.JPAEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.persistence.*; +import java.sql.Date; +import java.time.LocalDateTime; + +@Data +@Entity +@EqualsAndHashCode(of = "id", callSuper = false) +@ToString(of = "id", callSuper = false) +@Table(name = "followUp") +public class FollowUp extends JPAEntity { + @Column(name = "date") + private Date date; + + @Column(name = "description") + private String description; + + @ManyToOne + @JoinColumn(name = "interviewId") + private Interview interview; + +} \ No newline at end of file diff --git a/back-end/src/main/java/com/example/demo/entity/Vacancy.java b/back-end/src/main/java/com/example/demo/entity/Vacancy.java index 420a8f54..6a7d46fd 100644 --- a/back-end/src/main/java/com/example/demo/entity/Vacancy.java +++ b/back-end/src/main/java/com/example/demo/entity/Vacancy.java @@ -23,7 +23,7 @@ public class Vacancy extends JPAEntity { private LocalDateTime expireDate; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "position_id") private Position position; diff --git a/back-end/src/main/java/com/example/demo/repository/FollowUpRepository.java b/back-end/src/main/java/com/example/demo/repository/FollowUpRepository.java new file mode 100644 index 00000000..59a63966 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/repository/FollowUpRepository.java @@ -0,0 +1,28 @@ +package com.example.demo.repository; + + +import com.example.demo.entity.FollowUp; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface FollowUpRepository extends JpaRepository { + + + + + @Query(value = "SELECT f FROM FollowUp f JOIN FETCH f.interview WHERE f.id = :id") + Optional findById(@Param("id") Integer id); + + @Query(value = " SELECT f FROM FollowUp f JOIN FETCH f.interview WHERE f.interview.id= :interviewId", + countQuery = "SELECT COUNT(f) FROM FollowUp f WHERE f.interview.id= :interviewId") + Page findAllByInterview(@Param(value = "interviewId") Integer interviewId, Pageable pageable); + +} diff --git a/back-end/src/main/java/com/example/demo/repository/InterviewRepository.java b/back-end/src/main/java/com/example/demo/repository/InterviewRepository.java index 434b4e9c..24884a38 100644 --- a/back-end/src/main/java/com/example/demo/repository/InterviewRepository.java +++ b/back-end/src/main/java/com/example/demo/repository/InterviewRepository.java @@ -2,6 +2,9 @@ import com.example.demo.entity.Interview; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +@Repository public interface InterviewRepository extends JpaRepository { + } diff --git a/back-end/src/main/java/com/example/demo/repository/PositionRepository.java b/back-end/src/main/java/com/example/demo/repository/PositionRepository.java index 6dcc8e70..886c8cce 100644 --- a/back-end/src/main/java/com/example/demo/repository/PositionRepository.java +++ b/back-end/src/main/java/com/example/demo/repository/PositionRepository.java @@ -2,7 +2,8 @@ import com.example.demo.entity.Position; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; - +@Repository public interface PositionRepository extends JpaRepository { } diff --git a/back-end/src/main/java/com/example/demo/repository/TopicLevelRepository.java b/back-end/src/main/java/com/example/demo/repository/TopicLevelRepository.java index 50ced108..96df4df2 100644 --- a/back-end/src/main/java/com/example/demo/repository/TopicLevelRepository.java +++ b/back-end/src/main/java/com/example/demo/repository/TopicLevelRepository.java @@ -3,7 +3,8 @@ import com.example.demo.entity.TopicLevel; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; - +@Repository public interface TopicLevelRepository extends JpaRepository { } diff --git a/back-end/src/main/java/com/example/demo/rest/controller/FollowUpController.java b/back-end/src/main/java/com/example/demo/rest/controller/FollowUpController.java new file mode 100644 index 00000000..7f85a013 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/rest/controller/FollowUpController.java @@ -0,0 +1,46 @@ +package com.example.demo.rest.controller; + +import com.example.demo.entity.FollowUp; +import com.example.demo.rest.dto.EmployeeDto; +import com.example.demo.rest.dto.FollowUpDto; +import com.example.demo.rest.handler.FollowUpHandler; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/followUp") +@AllArgsConstructor +@Tag(name = "followUp", description = "REST API for followUp") +public class FollowUpController { + private FollowUpHandler followUpHandler; + + @GetMapping("/{id}") + @Operation(summary = "Get followUp By Id") + public ResponseEntity getById(@PathVariable(value = "id") Integer id) { + return followUpHandler.getById(id); + } + + @GetMapping("/{id}/followUp-interview") + @Operation(summary = "get All interview by FollowUp") + public ResponseEntity getInterviews(@PathVariable(value = "id") Integer id, @RequestParam(value = "page", defaultValue = "0") Integer page, + @RequestParam(value = "size", defaultValue = "10") Integer size) { + return followUpHandler.getAllByInterview(id, page, size);} + + @PostMapping + @Operation(summary = "Add New followUp") + public ResponseEntity save(@RequestBody FollowUpDto dto) { + return followUpHandler.save(dto); + } + + + + @DeleteMapping("/{id}") + @Operation(summary = "Delete A followUp") + public ResponseEntity delete(@PathVariable Integer id) { + return followUpHandler.delete(id); + } + +} diff --git a/back-end/src/main/java/com/example/demo/rest/dto/FollowUpDto.java b/back-end/src/main/java/com/example/demo/rest/dto/FollowUpDto.java new file mode 100644 index 00000000..ae0bca05 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/rest/dto/FollowUpDto.java @@ -0,0 +1,14 @@ +package com.example.demo.rest.dto; +import com.example.demo.rest.dto.common.RestDto; +import lombok.Data; + +import java.sql.Date; +import java.time.LocalDateTime; +import java.util.LinkedHashSet; +import java.util.Set; +@Data +public class FollowUpDto extends RestDto { + private Date date; + private String description; + private InterviewDto interview; +} diff --git a/back-end/src/main/java/com/example/demo/rest/dto/InterviewDto.java b/back-end/src/main/java/com/example/demo/rest/dto/InterviewDto.java index 19b48101..ae41847f 100644 --- a/back-end/src/main/java/com/example/demo/rest/dto/InterviewDto.java +++ b/back-end/src/main/java/com/example/demo/rest/dto/InterviewDto.java @@ -4,16 +4,17 @@ import com.example.demo.entity.Employee; import com.example.demo.entity.Topics; import com.example.demo.rest.dto.common.RestDto; +import lombok.Data; import java.sql.Date; import java.util.LinkedHashSet; import java.util.Set; - +@Data public class InterviewDto extends RestDto { private Date date; private String evaluation; private Boolean status; private Set topicses = new LinkedHashSet<>(); - private Employee employee; + private EmployeeDto employee; private Set applications = new LinkedHashSet<>(); } diff --git a/back-end/src/main/java/com/example/demo/rest/dto/PositionDto.java b/back-end/src/main/java/com/example/demo/rest/dto/PositionDto.java index c398477e..97bfa284 100644 --- a/back-end/src/main/java/com/example/demo/rest/dto/PositionDto.java +++ b/back-end/src/main/java/com/example/demo/rest/dto/PositionDto.java @@ -10,4 +10,6 @@ public class PositionDto extends RestDto { private String name; private String description; + private CompanyDto company; + } diff --git a/back-end/src/main/java/com/example/demo/rest/dto/TopicLevelDto.java b/back-end/src/main/java/com/example/demo/rest/dto/TopicLevelDto.java index 5887b952..8fccbf58 100644 --- a/back-end/src/main/java/com/example/demo/rest/dto/TopicLevelDto.java +++ b/back-end/src/main/java/com/example/demo/rest/dto/TopicLevelDto.java @@ -1,11 +1,16 @@ package com.example.demo.rest.dto; +import com.example.demo.entity.Topics; import com.example.demo.rest.dto.common.RestDto; import lombok.Data; +import java.util.LinkedHashSet; +import java.util.Set; + @Data public class TopicLevelDto extends RestDto { private String describtion; + private PositionDto position; } diff --git a/back-end/src/main/java/com/example/demo/rest/dto/TopicsDto.java b/back-end/src/main/java/com/example/demo/rest/dto/TopicsDto.java index fc4a4310..ca96cae4 100644 --- a/back-end/src/main/java/com/example/demo/rest/dto/TopicsDto.java +++ b/back-end/src/main/java/com/example/demo/rest/dto/TopicsDto.java @@ -3,8 +3,14 @@ import com.example.demo.rest.dto.common.RestDto; import lombok.Data; +import java.util.LinkedHashSet; +import java.util.Set; + @Data public class TopicsDto extends RestDto { private String name; private String description; + private PositionDto position; + private Set topicLevels = new LinkedHashSet<>(); + } diff --git a/back-end/src/main/java/com/example/demo/rest/entitymapper/DocumentMapper.java b/back-end/src/main/java/com/example/demo/rest/entitymapper/DocumentMapper.java index d882908a..02991f17 100644 --- a/back-end/src/main/java/com/example/demo/rest/entitymapper/DocumentMapper.java +++ b/back-end/src/main/java/com/example/demo/rest/entitymapper/DocumentMapper.java @@ -9,7 +9,7 @@ import java.util.Base64; import java.util.List; -@Mapper(componentModel = "spring") +@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.IGNORE) public abstract class DocumentMapper { // @Mappings({@Mapping(source = "content", target = "content", ignore = true) }) diff --git a/back-end/src/main/java/com/example/demo/rest/entitymapper/FollowUpMapper.java b/back-end/src/main/java/com/example/demo/rest/entitymapper/FollowUpMapper.java new file mode 100644 index 00000000..cf48362e --- /dev/null +++ b/back-end/src/main/java/com/example/demo/rest/entitymapper/FollowUpMapper.java @@ -0,0 +1,60 @@ +package com.example.demo.rest.entitymapper; +import com.example.demo.entity.FollowUp; + +import com.example.demo.entity.Interview; +import com.example.demo.rest.dto.FollowUpDto; +import com.example.demo.rest.dto.InterviewDto; +import com.example.demo.rest.entitymapper.common.JPAEntityMapper; +import com.example.demo.service.InterviewService; +import com.example.demo.utils.HibernateUtils; +import org.mapstruct.*; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.IGNORE) + +public abstract class FollowUpMapper { + @Autowired + private InterviewMapper interviewMapper; + @Autowired + private InterviewService interviewService; + + + @Mappings({ + @Mapping(source = "interview", target = "interview", ignore = true) + }) + + public abstract FollowUpDto toDto(FollowUp followUp); + + public abstract List toDto(List followUps); + + + @AfterMapping + public void toDtoAfterMapping(FollowUp entity, @MappingTarget FollowUpDto dto) { + if (HibernateUtils.isConvertible(entity.getInterview())) { + dto.setInterview(interviewMapper.toDto(entity.getInterview())); + } + + + } + @InheritInverseConfiguration + public abstract FollowUp toEntity(FollowUpDto followUpDto); + + public abstract List toEntity(List list); + @AfterMapping + public void toEntityAfterMapping(FollowUpDto dto, @MappingTarget FollowUp entity) { + if (dto.getInterview() != null) { + entity.setInterview(interviewService.getById(dto.getInterview().getId()).get()); + } + + + } + @InheritInverseConfiguration + public abstract FollowUp updateEntityFromDto(FollowUpDto dto, @MappingTarget FollowUp entity); + + + + + +} \ No newline at end of file diff --git a/back-end/src/main/java/com/example/demo/rest/handler/FollowUpHandler.java b/back-end/src/main/java/com/example/demo/rest/handler/FollowUpHandler.java new file mode 100644 index 00000000..aa3f266b --- /dev/null +++ b/back-end/src/main/java/com/example/demo/rest/handler/FollowUpHandler.java @@ -0,0 +1,63 @@ +package com.example.demo.rest.handler; + +import com.example.demo.entity.FollowUp; +import com.example.demo.entity.Interview; +import com.example.demo.rest.dto.FollowUpDto; +import com.example.demo.rest.dto.InterviewDto; +import com.example.demo.rest.dto.common.PaginatedResultDto; +import com.example.demo.rest.entitymapper.EmployeeMapper; +import com.example.demo.rest.entitymapper.FollowUpMapper; +import com.example.demo.rest.entitymapper.common.PaginationMapper; +import com.example.demo.rest.exception.ResourceNotFoundException; +import com.example.demo.service.EmployeeService; +import com.example.demo.service.FollowUpService; +import lombok.AllArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.net.URI; +import java.util.List; + +@Component +@AllArgsConstructor +public class FollowUpHandler { + + @Autowired + private FollowUpService followUpService; + @Autowired + private FollowUpMapper followUpMapper; + private PaginationMapper paginationMapper; + public ResponseEntity save(FollowUpDto dto) { + FollowUp followUp = followUpMapper.toEntity(dto); + followUpService.save(followUp); + FollowUpDto followUpDto = followUpMapper.toDto(followUp); + return ResponseEntity.created(URI.create("/FollowUp/" + followUp.getId())).body(followUpDto); + } + public ResponseEntity getById(Integer id){ + FollowUp followUp = followUpService.getById(id). + orElseThrow(() -> new ResourceNotFoundException(FollowUp.class.getSimpleName(), id)); + FollowUpDto followUpDto = followUpMapper.toDto(followUp); + return ResponseEntity.ok(followUpDto); + } + + public ResponseEntity delete(Integer id){ + FollowUp followUp = followUpService.getById(id). + orElseThrow(() -> new ResourceNotFoundException(FollowUp.class.getSimpleName(), id)); + followUpService.delete(followUp); + return ResponseEntity.noContent().build(); + } + + + public ResponseEntity getAllByInterview(Integer interviewId, Integer page, Integer size) { + Page followUpPage = followUpService.getAllByInterview(interviewId, page, size); + List followUpDtoList = followUpMapper.toDto(followUpPage.getContent()); + PaginatedResultDto paginatedResultDto = new PaginatedResultDto<>(); + paginatedResultDto.setData(followUpDtoList); + paginatedResultDto.setPagination(paginationMapper.toPaginationDto(followUpPage)); + return ResponseEntity.ok(paginatedResultDto); + } + +} + diff --git a/back-end/src/main/java/com/example/demo/security/TokenProvider.java b/back-end/src/main/java/com/example/demo/security/TokenProvider.java index d290e519..9b8f7bbc 100644 --- a/back-end/src/main/java/com/example/demo/security/TokenProvider.java +++ b/back-end/src/main/java/com/example/demo/security/TokenProvider.java @@ -58,6 +58,7 @@ public boolean validateToken(String token) { } catch (ExpiredJwtException ex) { log.error("JWT expired: {}", ex.getMessage()); } catch (IllegalArgumentException ex) { + log.error("Token is null, empty or only whitespace: {}", ex.getMessage()); } catch (MalformedJwtException ex) { log.error("JWT is invalid: {}", ex.getMessage()); diff --git a/back-end/src/main/java/com/example/demo/service/FollowUpService.java b/back-end/src/main/java/com/example/demo/service/FollowUpService.java new file mode 100644 index 00000000..dbd96975 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/service/FollowUpService.java @@ -0,0 +1,38 @@ +package com.example.demo.service; + +import com.example.demo.entity.Answer; +import com.example.demo.entity.FollowUp; +import com.example.demo.repository.AnswerRepository; +import com.example.demo.repository.FollowUpRepository; +import lombok.AllArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; + +import java.util.Optional; +@Service +@AllArgsConstructor +public class FollowUpService { + + private FollowUpRepository followUpRepository; + + + + public Optional getById(Integer id){ + return followUpRepository.findById(id); + } + + public FollowUp save(FollowUp followUp) { + return followUpRepository.save(followUp); + } + + + public Page getAllByInterview(Integer interviewId, Integer page, Integer size) { + return followUpRepository.findAllByInterview(interviewId, PageRequest.of(page, size)); + } + + public void delete(FollowUp followUp) { + + followUpRepository.delete(followUp); + } +} diff --git a/back-end/src/main/java/com/example/demo/service/PositionService.java b/back-end/src/main/java/com/example/demo/service/PositionService.java index 1e74f78b..002ade67 100644 --- a/back-end/src/main/java/com/example/demo/service/PositionService.java +++ b/back-end/src/main/java/com/example/demo/service/PositionService.java @@ -4,6 +4,7 @@ import com.example.demo.entity.Position; import com.example.demo.repository.PositionRepository; +import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -12,6 +13,7 @@ import java.util.Optional; @Service +@AllArgsConstructor public class PositionService { @Autowired PositionRepository positionRepository; diff --git a/back-end/src/main/java/com/example/demo/utils/HibernateUtils.java b/back-end/src/main/java/com/example/demo/utils/HibernateUtils.java new file mode 100644 index 00000000..961bcbe0 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/utils/HibernateUtils.java @@ -0,0 +1,22 @@ +package com.example.demo.utils; + +import org.hibernate.Hibernate; + +import java.util.List; +import java.util.Set; + +public class HibernateUtils { + public static boolean isConvertible(Set set) { + if (set == null) + return false; + return Hibernate.isInitialized(set); + } + + public static boolean isConvertible(List list) { + return Hibernate.isInitialized(list); + } + + public static boolean isConvertible(Object obj) { + return Hibernate.isInitialized(obj); + } +} diff --git a/back-end/src/main/resources/application.properties b/back-end/src/main/resources/application.properties index d333a820..c841f6e4 100644 --- a/back-end/src/main/resources/application.properties +++ b/back-end/src/main/resources/application.properties @@ -1,9 +1,9 @@ spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto=none spring.jpa.hibernate.show-sql=true -spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.url=jdbc:postgresql://localhost:5432/Candi-Meter spring.datasource.username=postgres -spring.datasource.password=root +spring.datasource.password=12345 spring.liquibase.change-log=classpath:db/root-changelog.xml spring.doc.swagger-ui.path=/swagger-ui.html spring.servlet.multipart.enabled=true diff --git a/back-end/src/main/resources/db/changelog/2022/08/01-01-changelog.xml b/back-end/src/main/resources/db/changelog/2022/08/01-01-changelog.xml new file mode 100644 index 00000000..8d7a57b4 --- /dev/null +++ b/back-end/src/main/resources/db/changelog/2022/08/01-01-changelog.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/back-end/src/main/resources/db/changelog/2022/08/01-02-changelog.xml b/back-end/src/main/resources/db/changelog/2022/08/01-02-changelog.xml new file mode 100644 index 00000000..9ec145ca --- /dev/null +++ b/back-end/src/main/resources/db/changelog/2022/08/01-02-changelog.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/back-end/src/main/resources/db/changelog/2022/08/01-03-changelog.xml b/back-end/src/main/resources/db/changelog/2022/08/01-03-changelog.xml new file mode 100644 index 00000000..95bef2a2 --- /dev/null +++ b/back-end/src/main/resources/db/changelog/2022/08/01-03-changelog.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/back-end/src/main/resources/db/changelog/2022/08/01-04-changelog.xml b/back-end/src/main/resources/db/changelog/2022/08/01-04-changelog.xml new file mode 100644 index 00000000..4b62ea2b --- /dev/null +++ b/back-end/src/main/resources/db/changelog/2022/08/01-04-changelog.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/back-end/src/main/resources/db/root-changelog.xml b/back-end/src/main/resources/db/root-changelog.xml index 4a3b1ede..a2996f78 100644 --- a/back-end/src/main/resources/db/root-changelog.xml +++ b/back-end/src/main/resources/db/root-changelog.xml @@ -12,6 +12,11 @@ + + + + + From e358b2ab11146015bc55112e92a0bf929e98928c Mon Sep 17 00:00:00 2001 From: Yomna Date: Wed, 25 Oct 2023 10:23:54 +0300 Subject: [PATCH 2/2] #122_Edit_Vacancy_Table --- back-end/pom.xml | 99 ++++++++-------- .../demo/config/SecurityAuditorAware.java | 29 +++++ .../example/demo/config/SecurityConfig.java | 62 ---------- .../demo/config/WebSecurityConfig.java | 109 ++++++++++++++++++ .../java/com/example/demo/entity/Vacancy.java | 13 +++ .../demo/repository/UserRepository.java | 7 +- .../demo/repository/VacancyRepository.java | 13 ++- .../demo/rest/controller/UserController.java | 11 ++ .../com/example/demo/rest/dto/VacancyDto.java | 8 ++ .../demo/rest/entitymapper/VacancyMapper.java | 73 +++++++++++- .../demo/rest/handler/VacancyHandler.java | 18 +++ .../example/demo/security/AuthController.java | 30 +++-- .../example/demo/security/AuthHandler.java | 89 ++++++++++---- .../com/example/demo/security/CookieUtil.java | 37 ++++++ .../security/CustomUserDetailsService.java | 48 ++++++++ .../demo/security/LoginRequestDto.java | 19 +++ .../demo/security/LoginResponseDto.java | 17 +++ ...quest.java => RefreshTokenRequestDto.java} | 2 +- .../RestAuthenticationEntryPoint.java | 13 ++- .../security/TokenAuthenticationFilter.java | 62 +++++++--- .../example/demo/security/TokenProvider.java | 53 +++++---- .../com/example/demo/security/UserDto.java | 16 +++ .../example/demo/service/VacancyService.java | 4 + .../src/main/resources/application.properties | 15 --- back-end/src/main/resources/application.yaml | 28 +++++ .../db/changelog/2022/08/01-05-changelog.xml | 28 +++++ .../db/changelog/2022/08/01-06-changelog.xml | 23 ++++ .../src/main/resources/db/root-changelog.xml | 2 + 28 files changed, 724 insertions(+), 204 deletions(-) create mode 100644 back-end/src/main/java/com/example/demo/config/SecurityAuditorAware.java delete mode 100644 back-end/src/main/java/com/example/demo/config/SecurityConfig.java create mode 100644 back-end/src/main/java/com/example/demo/config/WebSecurityConfig.java create mode 100644 back-end/src/main/java/com/example/demo/security/CookieUtil.java create mode 100644 back-end/src/main/java/com/example/demo/security/CustomUserDetailsService.java create mode 100644 back-end/src/main/java/com/example/demo/security/LoginRequestDto.java create mode 100644 back-end/src/main/java/com/example/demo/security/LoginResponseDto.java rename back-end/src/main/java/com/example/demo/security/{RefreshTokenRequest.java => RefreshTokenRequestDto.java} (84%) create mode 100644 back-end/src/main/java/com/example/demo/security/UserDto.java delete mode 100644 back-end/src/main/resources/application.properties create mode 100644 back-end/src/main/resources/application.yaml create mode 100644 back-end/src/main/resources/db/changelog/2022/08/01-05-changelog.xml create mode 100644 back-end/src/main/resources/db/changelog/2022/08/01-06-changelog.xml diff --git a/back-end/pom.xml b/back-end/pom.xml index cb737f53..924a828c 100644 --- a/back-end/pom.xml +++ b/back-end/pom.xml @@ -22,10 +22,10 @@ 3.6.0 8 8 + 0.11.5 - org.springframework.boot @@ -47,6 +47,17 @@ + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot spring-boot-starter-web @@ -74,16 +85,17 @@ liquibase-core + + org.springdoc + springdoc-openapi-ui + ${org.springdoc.version} + + org.projectlombok lombok true - - org.springdoc - springdoc-openapi-ui - 1.6.4 - org.springframework.boot spring-boot-starter-test @@ -95,77 +107,77 @@ test - - - - + org.mapstruct mapstruct 1.4.2.Final - - io.swagger.core.v3 - swagger-models - 2.1.11 - - - io.swagger.core.v3 - swagger-annotations - 2.1.11 - - org.postgresql postgresql runtime + + + org.springframework.boot spring-boot-starter-log4j2 - - org.springframework.boot - spring-boot-starter-security - compile - - - org.springframework.boot - spring-boot-starter-logging - - + com.lmax + disruptor + 3.4.0 + + + io.jsonwebtoken jjwt-api - 0.11.5 + ${io.jsonwebtoken.version} io.jsonwebtoken jjwt-impl - 0.11.5 + ${io.jsonwebtoken.version} + runtime io.jsonwebtoken jjwt-jackson - 0.11.5 + ${io.jsonwebtoken.version} + runtime + + + - org.liquibase - liquibase-maven-plugin - 4.5.0 + org.passay + passay + 1.3.1 + + + + + + net.sf.jasperreports + jasperreports + 6.20.0 + + - + - org.springframework.boot spring-boot-maven-plugin @@ -174,10 +186,10 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + ${org.apache.maven.plugins.version} - 1.8 - 1.8 + ${java.version} + ${java.version} org.projectlombok @@ -189,13 +201,10 @@ mapstruct-processor ${org.mapstruct.version} - - - \ No newline at end of file diff --git a/back-end/src/main/java/com/example/demo/config/SecurityAuditorAware.java b/back-end/src/main/java/com/example/demo/config/SecurityAuditorAware.java new file mode 100644 index 00000000..3b569618 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/config/SecurityAuditorAware.java @@ -0,0 +1,29 @@ +package com.example.demo.config; + +import lombok.extern.log4j.Log4j2; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.AuditorAware; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; + +import java.util.Optional; + +@Configuration +@Log4j2 +public class SecurityAuditorAware implements AuditorAware { + @Override + public Optional getCurrentAuditor() { + Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + if (principal instanceof User) { + User user = (User) principal; + log.debug("Current Auditor {}", user.getUsername()); + return Optional.of(user.getUsername()); + } else { + log.debug("Current Auditor {}", principal); + return Optional.of(principal); + } + + + } +} diff --git a/back-end/src/main/java/com/example/demo/config/SecurityConfig.java b/back-end/src/main/java/com/example/demo/config/SecurityConfig.java deleted file mode 100644 index e12a77da..00000000 --- a/back-end/src/main/java/com/example/demo/config/SecurityConfig.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.example.demo.config; - -import com.example.demo.security.RestAuthenticationEntryPoint; -import com.example.demo.security.SecurityUserService; -import com.example.demo.security.TokenAuthenticationFilter; -import lombok.AllArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@Configuration -@EnableWebSecurity -@AllArgsConstructor -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - private final SecurityUserService securityUserService; - - private final TokenAuthenticationFilter tokenAuthenticationFilter; - - private final RestAuthenticationEntryPoint restAuthenticationEntryPoint; - - - - @Override - protected void configure(HttpSecurity http) throws Exception { - - - http.csrf().disable().exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint); - http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); - http.authorizeRequests().antMatchers("/auth/**").permitAll(); - http.authorizeRequests().antMatchers("/v3/api-docs/*", "/v3/api-docs", "/swagger-ui.html", "/swagger-ui/*").permitAll(); - //http.authorizeRequests().anyRequest().authenticated(); - http.authorizeRequests().antMatchers("/authenticate").permitAll(); - http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); - } - - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(securityUserService).passwordEncoder(passwordEncoder()); - } - - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { - return authenticationConfiguration.getAuthenticationManager(); - } - - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } -} diff --git a/back-end/src/main/java/com/example/demo/config/WebSecurityConfig.java b/back-end/src/main/java/com/example/demo/config/WebSecurityConfig.java new file mode 100644 index 00000000..7cb452f6 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/config/WebSecurityConfig.java @@ -0,0 +1,109 @@ +package com.example.demo.config; +import com.example.demo.security.CustomUserDetailsService; +import com.example.demo.security.RestAuthenticationEntryPoint; +import com.example.demo.security.TokenAuthenticationFilter; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import java.util.List; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +@RequiredArgsConstructor +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + private final CustomUserDetailsService customUserDetailsService; + + private final RestAuthenticationEntryPoint restAuthenticationEntryPoint; + + @Value("${app.allowed-origins}") + private List allowedOrigins; + + @Override + public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { + authenticationManagerBuilder.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder()); + } + + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public TokenAuthenticationFilter authenticationJwtTokenFilter() { + return new TokenAuthenticationFilter(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + + http.cors().configurationSource(corsConfigurationSource()).and().csrf().disable().exceptionHandling() + .authenticationEntryPoint(restAuthenticationEntryPoint); + http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + http.authorizeRequests().antMatchers("/auth/**").permitAll() + + .antMatchers(HttpMethod.POST,"/interview").hasRole("EMPLOYEE") + .antMatchers(HttpMethod.GET,"/interview/*").hasRole("EMPLOYEE") + .antMatchers(HttpMethod.PUT,"/interview/*").hasRole("EMPLOYEE") + .antMatchers(HttpMethod.DELETE,"/interview/*").hasRole("EMPLOYEE") + .antMatchers(HttpMethod.GET,"/user/current/vacancy").hasRole("EMPLOYEE") + + + // All Permissions + + .antMatchers("/employee/**", "/vacancy/**","/role/**").hasRole("ADMIN") + .antMatchers("/vacancy/**").hasRole("EMPLOYEE"); + + + + //for swagger + http.authorizeRequests().antMatchers("/v3/api-docs/*", "/v3/api-docs", "/swagger-ui.html", "/swagger-ui/*").permitAll(); + http.authorizeRequests().anyRequest().authenticated(); + http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); + } + + + @Override + public void configure(WebSecurity web) throws Exception { + + } + + @Bean + CorsConfigurationSource corsConfigurationSource() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues(); + corsConfiguration.setAllowedOrigins(allowedOrigins); + corsConfiguration.setAllowCredentials(true); + corsConfiguration.addAllowedMethod(HttpMethod.PUT); + corsConfiguration.addAllowedMethod(HttpMethod.DELETE); + corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS); + corsConfiguration.addAllowedMethod(HttpMethod.PATCH); + source.registerCorsConfiguration("/**", corsConfiguration); + return source; + } + + +} diff --git a/back-end/src/main/java/com/example/demo/entity/Vacancy.java b/back-end/src/main/java/com/example/demo/entity/Vacancy.java index 6a7d46fd..bbda503b 100644 --- a/back-end/src/main/java/com/example/demo/entity/Vacancy.java +++ b/back-end/src/main/java/com/example/demo/entity/Vacancy.java @@ -27,5 +27,18 @@ public class Vacancy extends JPAEntity { @JoinColumn(name = "position_id") private Position position; + @Column(name = "vacancies") + private String vacancies; + + @Column(name = "post_date", updatable = false) + private LocalDateTime postDate; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_by") + private User postBy; + + + + } \ No newline at end of file diff --git a/back-end/src/main/java/com/example/demo/repository/UserRepository.java b/back-end/src/main/java/com/example/demo/repository/UserRepository.java index c49dee3b..41621276 100644 --- a/back-end/src/main/java/com/example/demo/repository/UserRepository.java +++ b/back-end/src/main/java/com/example/demo/repository/UserRepository.java @@ -3,12 +3,17 @@ import com.example.demo.entity.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; import java.util.Optional; -//@Repository +@Repository public interface UserRepository extends JpaRepository { @Query("SELECT u FROM User u WHERE u.username = :username") Optional findUserByUsername(String username); + + @Query(value = "Select u FROM User u LEFT JOIN FETCH u.roles WHERE u.username= :userName ") + Optional findRolesByUserName(@Param("userName") String userName); } diff --git a/back-end/src/main/java/com/example/demo/repository/VacancyRepository.java b/back-end/src/main/java/com/example/demo/repository/VacancyRepository.java index e1a06843..8d985d65 100644 --- a/back-end/src/main/java/com/example/demo/repository/VacancyRepository.java +++ b/back-end/src/main/java/com/example/demo/repository/VacancyRepository.java @@ -1,8 +1,19 @@ package com.example.demo.repository; import com.example.demo.entity.Vacancy; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository -public interface VacancyRepository extends JpaRepository{} +public interface VacancyRepository extends JpaRepository{ + + + + @Query(value = "SELECT v from Vacancy v JOIN FETCH v.postBy as A WHERE A.username= :userName", + countQuery = "SELECT count(v) FROM Vacancy v WHERE v.postBy.username= :userName ") + Page getVacationsByUser(@Param("userName") String userName, Pageable pageable); +} diff --git a/back-end/src/main/java/com/example/demo/rest/controller/UserController.java b/back-end/src/main/java/com/example/demo/rest/controller/UserController.java index 00b659cd..64c599f8 100644 --- a/back-end/src/main/java/com/example/demo/rest/controller/UserController.java +++ b/back-end/src/main/java/com/example/demo/rest/controller/UserController.java @@ -1,7 +1,9 @@ package com.example.demo.rest.controller; +import com.example.demo.entity.Vacancy; import com.example.demo.rest.dto.UserDto; import com.example.demo.rest.handler.UserHandler; +import com.example.demo.rest.handler.VacancyHandler; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; @@ -14,6 +16,7 @@ @Tag(name = "user", description = "REST API for user") public class UserController { private final UserHandler userHandler; + private VacancyHandler vacancyHandler; @GetMapping @Operation(summary = "Get All Users Paged") @@ -45,4 +48,12 @@ public ResponseEntity delete(@PathVariable Integer id) { public ResponseEntity update(@PathVariable Integer id,@RequestBody UserDto usersDto) { return userHandler.update(id, usersDto); } + //----------------------------------Vacancy---------------------------------------------------- + + @GetMapping("/current/vacancy") + @Operation(summary = "get all Vacancies that posted by user ", description = "this API to get all Vacancies that posted by user in pages") + public ResponseEntity getAllByUserName(@RequestParam(value = "page", defaultValue = "0") Integer page, + @RequestParam(value = "size", defaultValue = "10") Integer size) { + return vacancyHandler.getAllByUser(page, size); + } } diff --git a/back-end/src/main/java/com/example/demo/rest/dto/VacancyDto.java b/back-end/src/main/java/com/example/demo/rest/dto/VacancyDto.java index 11c1030c..81bcca81 100644 --- a/back-end/src/main/java/com/example/demo/rest/dto/VacancyDto.java +++ b/back-end/src/main/java/com/example/demo/rest/dto/VacancyDto.java @@ -13,4 +13,12 @@ public class VacancyDto extends RestDto { private LocalDateTime expireDate; private PositionDto position; + + private String vacancies; + + private LocalDateTime postDate; + + private UserDto postBy; + + } diff --git a/back-end/src/main/java/com/example/demo/rest/entitymapper/VacancyMapper.java b/back-end/src/main/java/com/example/demo/rest/entitymapper/VacancyMapper.java index 23db19c5..a8a7bee7 100644 --- a/back-end/src/main/java/com/example/demo/rest/entitymapper/VacancyMapper.java +++ b/back-end/src/main/java/com/example/demo/rest/entitymapper/VacancyMapper.java @@ -3,8 +3,75 @@ import com.example.demo.entity.Vacancy; import com.example.demo.rest.dto.VacancyDto; import com.example.demo.rest.entitymapper.common.JPAEntityMapper; -import org.mapstruct.Mapper; +import com.example.demo.service.PositionService; +import com.example.demo.service.UserService; +import com.example.demo.utils.HibernateUtils; +import org.mapstruct.*; +import org.springframework.beans.factory.annotation.Autowired; + + +import java.util.List; + + +@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public abstract class VacancyMapper { + + + @Autowired + private PositionMapper positionMapper; + @Autowired + private PositionService positionService; + @Autowired + private UserMapper userMapper; + @Autowired + private UserService userService; + + + + @Mappings({ + @Mapping(source = "position", target = "position", ignore = true), + @Mapping(source = "postBy", target = "postBy", ignore = true), + + + }) + + public abstract VacancyDto toDto(Vacancy vacancy); + + public abstract List toDto(List vacancies); + + @AfterMapping + public void toDtoAfterMapping(Vacancy entity, @MappingTarget VacancyDto dto) { + if (HibernateUtils.isConvertible(entity.getPosition())) { + dto.setPosition(positionMapper.toDto(entity.getPosition())); + } + if (HibernateUtils.isConvertible(entity.getPostBy())) { + dto.setPostBy(userMapper.toDto(entity.getPostBy())); + } + + + } + @InheritInverseConfiguration + public abstract Vacancy toEntity(VacancyDto billDetailsDto); + + public abstract List toEntity(List list); + @AfterMapping + public void toEntityAfterMapping(VacancyDto dto, @MappingTarget Vacancy entity) { + if (dto.getPosition() != null) { + entity.setPosition(positionService.getById(dto.getPosition().getId()).get()); + } + + if (dto.getPostBy() != null) { + entity.setPostBy(userService.getById(dto.getPostBy().getId()).get()); + } + + + } + @InheritInverseConfiguration + public abstract Vacancy updateEntityFromDto(VacancyDto billDetailsDto, @MappingTarget Vacancy billDetails); + + + + +} -@Mapper(componentModel = "spring") -public interface VacancyMapper extends JPAEntityMapper {} diff --git a/back-end/src/main/java/com/example/demo/rest/handler/VacancyHandler.java b/back-end/src/main/java/com/example/demo/rest/handler/VacancyHandler.java index c0880b77..87b970cd 100644 --- a/back-end/src/main/java/com/example/demo/rest/handler/VacancyHandler.java +++ b/back-end/src/main/java/com/example/demo/rest/handler/VacancyHandler.java @@ -3,18 +3,24 @@ import com.example.demo.entity.Vacancy; import com.example.demo.rest.dto.VacancyDto; import com.example.demo.rest.dto.common.PaginatedResultDto; +import com.example.demo.rest.entitymapper.UserMapper; import com.example.demo.rest.entitymapper.VacancyMapper; import com.example.demo.rest.entitymapper.common.PaginationMapper; import com.example.demo.rest.exception.ResourceNotFoundException; +import com.example.demo.service.UserService; import com.example.demo.service.VacancyService; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; + +import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Component; import java.net.URI; import java.util.List; +import java.util.Optional; @Component @AllArgsConstructor @@ -23,6 +29,8 @@ public class VacancyHandler { private VacancyService vacancyService; private VacancyMapper vacancyMapper; private PaginationMapper paginationMapper; + private UserService userService; + private UserMapper userMapper; public ResponseEntity getAll(Integer page, Integer size) { Page vacancyPage = vacancyService.getAll(page, size); @@ -61,4 +69,14 @@ public ResponseEntity delete(Integer id){ vacancyService.delete(vacancy); return ResponseEntity.noContent().build(); } + + public ResponseEntity getAllByUser(Integer page, Integer size) { + String userName = SecurityContextHolder.getContext().getAuthentication().getName(); + Page vacancies = vacancyService.getByUser(userName, page, size); + List vacancyDtoList = vacancyMapper.toDto(vacancies.getContent()); + PaginatedResultDto paginatedResultDto = new PaginatedResultDto<>(); + paginatedResultDto.setData(vacancyDtoList); + paginatedResultDto.setPagination(paginationMapper.toPaginationDto(vacancies)); + return ResponseEntity.ok(paginatedResultDto); + } } \ No newline at end of file diff --git a/back-end/src/main/java/com/example/demo/security/AuthController.java b/back-end/src/main/java/com/example/demo/security/AuthController.java index c6690b71..3964e473 100644 --- a/back-end/src/main/java/com/example/demo/security/AuthController.java +++ b/back-end/src/main/java/com/example/demo/security/AuthController.java @@ -11,6 +11,11 @@ import javax.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.web.bind.annotation.*; + @RestController @RequestMapping("/auth") @AllArgsConstructor @@ -18,21 +23,24 @@ @Log4j2 public class AuthController { + private AuthHandler authHandler; - private final AuthHandler authHandler; + @PostMapping(value = "/login") + public ResponseEntity login(@Valid @RequestBody LoginRequestDto loginRequest) { + //TODO:add encryption/decryption + return authHandler.login(loginRequest); + } - @PostMapping("/login") - public ResponseEntity login(@Valid @RequestBody AuthRequest authRequest) - { - return authHandler.login(authRequest); + @PostMapping(value = "/refresh") + public ResponseEntity refreshToken(@RequestBody RefreshTokenRequestDto refreshToken) { + return authHandler.refresh(refreshToken); } - @PostMapping("/refresh") - public ResponseEntity login(@Valid @RequestBody RefreshTokenRequest refreshTokenRequest) - { - return authHandler.refresh(refreshTokenRequest.getRefreshToken()); + @GetMapping(value = "/user-info") + @PreAuthorize("isAuthenticated()") + public ResponseEntity getUserInfo(@AuthenticationPrincipal UserDetails userDetails) { + return authHandler.getUserInfo(userDetails); } - - } + diff --git a/back-end/src/main/java/com/example/demo/security/AuthHandler.java b/back-end/src/main/java/com/example/demo/security/AuthHandler.java index 9682749c..eda890fb 100644 --- a/back-end/src/main/java/com/example/demo/security/AuthHandler.java +++ b/back-end/src/main/java/com/example/demo/security/AuthHandler.java @@ -1,5 +1,6 @@ package com.example.demo.security; +import com.example.demo.rest.handler.UserHandler; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.http.HttpStatus; @@ -13,47 +14,91 @@ import java.util.HashMap; import java.util.Map; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.util.Set; + @Component @RequiredArgsConstructor @Log4j2 public class AuthHandler { - private final AuthenticationManager authenticationManager; + private final TokenProvider tokenProvider; - public ResponseEntity login(AuthRequest authRequest) - { - Authentication authentication= authenticationManager - .authenticate(new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())); - SecurityContextHolder.getContext().setAuthentication(authentication); + private final CookieUtil cookieUtil; - String accessToken = tokenProvider.generateToken(authRequest.getUsername(),TokenType.ACCESS_TOKEN); - String refreshToken = tokenProvider.generateToken(authRequest.getUsername(),TokenType.REFRESH_TOKEN); - Map tokens = new HashMap<>(); - tokens.put("access token", accessToken); - tokens.put("refresh token", refreshToken); + @Value("${app.jwt.token.expiration-in-ms}") + private Long tokenExpirationMillis; - return ResponseEntity.ok(tokens); + @Value("${app.jwt.refresh.expiration-in-ms}") + private Long refreshTokenExpirationMillis; + +// private UsersService usersService; + + @Autowired + private UserHandler userHandler; + + + public ResponseEntity login(LoginRequestDto loginRequest) { + log.info("start login for user {}", loginRequest.getUsername()); + Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())); + SecurityContextHolder.getContext().setAuthentication(authentication); + log.info("create cookies for user {}", loginRequest.getUsername()); + HttpHeaders responseHeaders = new HttpHeaders(); + String accessToken = tokenProvider.generateAccessToken(loginRequest.getUsername()); + String refreshToken = tokenProvider.generateRefreshToken(loginRequest.getUsername()); + addAccessTokenCookie(responseHeaders, accessToken); + addRefreshTokenCookie(responseHeaders, refreshToken); + return ResponseEntity.ok().body(new LoginResponseDto(accessToken, refreshToken)); } - public ResponseEntity refresh(String refreshToken) { - boolean refreshTokenValid = tokenProvider.validateToken(refreshToken); + + public ResponseEntity refresh(RefreshTokenRequestDto dto) { + Boolean refreshTokenValid = tokenProvider.validateToken(dto.getRefreshToken()); if (!refreshTokenValid) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - String currentUsername = tokenProvider.getUsernameFromToken(refreshToken); + String currentUsername = tokenProvider.getUsernameFromToken(dto.getRefreshToken()); - String newAccessToken = tokenProvider.generateToken(currentUsername,TokenType.ACCESS_TOKEN); - String newRefreshToken = tokenProvider.generateToken(currentUsername,TokenType.REFRESH_TOKEN); + String newAccessToken = tokenProvider.generateAccessToken(currentUsername); + HttpHeaders responseHeaders = new HttpHeaders(); + addAccessTokenCookie(responseHeaders, newAccessToken); - Map tokens = new HashMap<>(); - tokens.put("access token", newAccessToken); - tokens.put("refresh token", newRefreshToken); + return ResponseEntity.ok().body(new LoginResponseDto(newAccessToken, dto.getRefreshToken())); + } - return ResponseEntity.ok(tokens); + + public ResponseEntity getUserInfo(UserDetails userDetails) { + UserDto userDto = UserDto.builder().username(userDetails.getUsername()).authorities((Set) userDetails.getAuthorities()).build(); + + return ResponseEntity.ok(userDto); + } + + private void addAccessTokenCookie(HttpHeaders httpHeaders, String token) { + httpHeaders.add(HttpHeaders.SET_COOKIE, cookieUtil.createAccessTokenCookie(token, tokenExpirationMillis).toString()); } -} + private void deleteAccessTokenCookie(HttpHeaders httpHeaders) { + httpHeaders.add(HttpHeaders.SET_COOKIE, cookieUtil.deleteAccessTokenCookie().toString()); + } + private void addRefreshTokenCookie(HttpHeaders httpHeaders, String token) { + httpHeaders.add(HttpHeaders.SET_COOKIE, cookieUtil.createRefreshTokenCookie(token, refreshTokenExpirationMillis).toString()); + } +} \ No newline at end of file diff --git a/back-end/src/main/java/com/example/demo/security/CookieUtil.java b/back-end/src/main/java/com/example/demo/security/CookieUtil.java new file mode 100644 index 00000000..79da7a3d --- /dev/null +++ b/back-end/src/main/java/com/example/demo/security/CookieUtil.java @@ -0,0 +1,37 @@ +package com.example.demo.security; + +import org.springframework.http.HttpCookie; +import org.springframework.http.ResponseCookie; +import org.springframework.stereotype.Component; + +@Component +public class CookieUtil { + + public HttpCookie createAccessTokenCookie(String token, Long duration) { + //TODO:add encryption/decryption + //TODO:add secure= true + return ResponseCookie.from("accessToken", token) + .maxAge(duration / 1000) + .httpOnly(true) + .path("/") + .build(); + } + + public HttpCookie createRefreshTokenCookie(String token, Long duration) { + //TODO:add encryption/decryption + //TODO:add secure= true + return ResponseCookie.from("refreshToken", token) + .maxAge(duration / 1000) + .httpOnly(true) + .path("/") + .build(); + } + + public HttpCookie deleteAccessTokenCookie() { + return ResponseCookie.from("accessToken", null) + .maxAge(0) + .httpOnly(true) + .path("/") + .build(); + } +} diff --git a/back-end/src/main/java/com/example/demo/security/CustomUserDetailsService.java b/back-end/src/main/java/com/example/demo/security/CustomUserDetailsService.java new file mode 100644 index 00000000..c2dfa36a --- /dev/null +++ b/back-end/src/main/java/com/example/demo/security/CustomUserDetailsService.java @@ -0,0 +1,48 @@ +package com.example.demo.security; + +import com.example.demo.entity.User; +import com.example.demo.repository.UserRepository; +import lombok.AllArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@AllArgsConstructor +@Log4j2 +public class CustomUserDetailsService implements UserDetailsService { + + private UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + log.info("load user by username"); + User user = userRepository.findRolesByUserName(username) + .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username)); + + if (user.getRoles().isEmpty()) { + throw new AccessDeniedException("User Doesn't have any Roles."); + } + + List authorities = user.getRoles().stream() + .map(role -> new SimpleGrantedAuthority(role.getName())) + .collect(Collectors.toList()); + return org.springframework.security.core.userdetails.User + .withUsername(username) + .password(user.getPassword()) + .authorities(authorities) + .accountExpired(false) + .accountLocked(false) + .credentialsExpired(false) + .disabled(false) + .build(); + } +} diff --git a/back-end/src/main/java/com/example/demo/security/LoginRequestDto.java b/back-end/src/main/java/com/example/demo/security/LoginRequestDto.java new file mode 100644 index 00000000..0e68cc20 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/security/LoginRequestDto.java @@ -0,0 +1,19 @@ +package com.example.demo.security; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +@Data +public class LoginRequestDto { + + @NotBlank(message = "username is mandatory") + @Size(max = 100, message = "username's max length allowed is 100 characters") + private String username; + + @NotBlank(message = "password is mandatory") + @Size(max = 100, message = "password's max length allowed is 100 characters") + private String password; + +} diff --git a/back-end/src/main/java/com/example/demo/security/LoginResponseDto.java b/back-end/src/main/java/com/example/demo/security/LoginResponseDto.java new file mode 100644 index 00000000..5b4d9ea5 --- /dev/null +++ b/back-end/src/main/java/com/example/demo/security/LoginResponseDto.java @@ -0,0 +1,17 @@ +package com.example.demo.security; + +import lombok.Data; + +@Data +public class LoginResponseDto { + private String accessToken; + private String refreshToken; + + public LoginResponseDto(String accessToken, String refreshToken) { + this.accessToken = accessToken; + this.refreshToken = refreshToken; + } + + public LoginResponseDto() { + } +} \ No newline at end of file diff --git a/back-end/src/main/java/com/example/demo/security/RefreshTokenRequest.java b/back-end/src/main/java/com/example/demo/security/RefreshTokenRequestDto.java similarity index 84% rename from back-end/src/main/java/com/example/demo/security/RefreshTokenRequest.java rename to back-end/src/main/java/com/example/demo/security/RefreshTokenRequestDto.java index 68479513..b6228fb9 100644 --- a/back-end/src/main/java/com/example/demo/security/RefreshTokenRequest.java +++ b/back-end/src/main/java/com/example/demo/security/RefreshTokenRequestDto.java @@ -5,7 +5,7 @@ import javax.validation.constraints.NotBlank; @Data -public class RefreshTokenRequest { +public class RefreshTokenRequestDto { @NotBlank(message = "refresh token is mandatory") private String refreshToken; diff --git a/back-end/src/main/java/com/example/demo/security/RestAuthenticationEntryPoint.java b/back-end/src/main/java/com/example/demo/security/RestAuthenticationEntryPoint.java index f35cacb1..feb8c1e7 100644 --- a/back-end/src/main/java/com/example/demo/security/RestAuthenticationEntryPoint.java +++ b/back-end/src/main/java/com/example/demo/security/RestAuthenticationEntryPoint.java @@ -1,6 +1,8 @@ package com.example.demo.security; import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; @@ -11,11 +13,14 @@ import java.io.IOException; @Component -@Log4j2 public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { + private static final Logger logger = LoggerFactory.getLogger(RestAuthenticationEntryPoint.class); + @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { - log.error("Unauthorized error: {}", authException.getMessage()); + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { + logger.error("Unauthorized error: {}", authException.getMessage()); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized :D :D :D "); } -} + +} \ No newline at end of file diff --git a/back-end/src/main/java/com/example/demo/security/TokenAuthenticationFilter.java b/back-end/src/main/java/com/example/demo/security/TokenAuthenticationFilter.java index 40898fbb..db5ed917 100644 --- a/back-end/src/main/java/com/example/demo/security/TokenAuthenticationFilter.java +++ b/back-end/src/main/java/com/example/demo/security/TokenAuthenticationFilter.java @@ -2,54 +2,86 @@ import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @AllArgsConstructor @Log4j2 -@Component public class TokenAuthenticationFilter extends OncePerRequestFilter { - private final TokenProvider tokenProvider; - private final SecurityUserService securityUserService; + @Autowired + private TokenProvider tokenProvider; + @Autowired + private UserDetailsService customUserDetailsService; + + + public TokenAuthenticationFilter() { + } @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { try { - log.info("validate token"); - String jwt = getJwtToken(request); + String jwt = getJwtToken(httpServletRequest, false); if (tokenProvider.validateToken(jwt)) { - log.info("token is valid ! "); String username = tokenProvider.getUsernameFromToken(jwt); - UserDetails userDetails = securityUserService.loadUserByUsername(username); + UserDetails userDetails = customUserDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); - authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest)); SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (Exception ex) { - log.error("error in validating token", ex); + ex.printStackTrace(); } - filterChain.doFilter(request, response); + filterChain.doFilter(httpServletRequest, httpServletResponse); + } + + private String getJwtFromRequest(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + String accessToken = bearerToken.substring(7); + if (accessToken == null) return null; + + // return SecurityCipher.decrypt(accessToken); + return accessToken; + } + return null; } - private String getJwtToken(HttpServletRequest request) { - String header = request.getHeader("Authorization"); - if (header != null && header.startsWith("Bearer")) - return header.replace("Bearer ", ""); + private String getJwtFromCookie(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + for (Cookie cookie : cookies) { + if ("accessToken".equals(cookie.getName())) { + String accessToken = cookie.getValue(); + if (accessToken == null) return null; + + // return SecurityCipher.decrypt(accessToken); + return accessToken; + } + } return null; } + + private String getJwtToken(HttpServletRequest request, boolean fromCookie) { + if (fromCookie) return getJwtFromCookie(request); + + return getJwtFromRequest(request); + } } diff --git a/back-end/src/main/java/com/example/demo/security/TokenProvider.java b/back-end/src/main/java/com/example/demo/security/TokenProvider.java index 9b8f7bbc..d93c811e 100644 --- a/back-end/src/main/java/com/example/demo/security/TokenProvider.java +++ b/back-end/src/main/java/com/example/demo/security/TokenProvider.java @@ -5,40 +5,46 @@ import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import java.security.Key; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; @Component -@Log4j2 public class TokenProvider { + private final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256); @Value("${app.jwt.token.expiration-in-ms}") private Long tokenExpirationMillis; - @Value("${app.jwt.refresh.expiration-in-ms}") private Long refreshTokenExpirationMillis; - private final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256); - - public String generateToken(String subject,TokenType tokenType) { - - Long expireTime =(tokenType == TokenType.ACCESS_TOKEN) ? tokenExpirationMillis : refreshTokenExpirationMillis; - - + public String generateAccessToken(String subject) { Date now = new Date(); - long duration = now.getTime() + expireTime; + Long duration = now.getTime() + tokenExpirationMillis; Date expiryDate = new Date(duration); + String token = Jwts.builder() + .setSubject(subject) + .setIssuedAt(now) + .setExpiration(expiryDate) + .signWith(key) + .compact(); + return token; + } - - return Jwts.builder() + public String generateRefreshToken(String subject) { + Date now = new Date(); + Long duration = now.getTime() + refreshTokenExpirationMillis; + Date expiryDate = new Date(duration); + String token = Jwts.builder() .setSubject(subject) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(key) .compact(); + return token; } public String getUsernameFromToken(String token) { @@ -53,23 +59,22 @@ public LocalDateTime getExpiryDateFromToken(String token) { public boolean validateToken(String token) { try { + if (!StringUtils.hasText(token)) + return false; Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); return true; - } catch (ExpiredJwtException ex) { - log.error("JWT expired: {}", ex.getMessage()); - } catch (IllegalArgumentException ex) { - - log.error("Token is null, empty or only whitespace: {}", ex.getMessage()); + } catch (SignatureException ex) { + ex.printStackTrace(); } catch (MalformedJwtException ex) { - log.error("JWT is invalid: {}", ex.getMessage()); + ex.printStackTrace(); + } catch (ExpiredJwtException ex) { + ex.printStackTrace(); } catch (UnsupportedJwtException ex) { - log.error("JWT is not supported: {}", ex.getMessage()); + ex.printStackTrace(); + } catch (IllegalArgumentException ex) { + ex.printStackTrace(); } - return false; - - } - - } + diff --git a/back-end/src/main/java/com/example/demo/security/UserDto.java b/back-end/src/main/java/com/example/demo/security/UserDto.java new file mode 100644 index 00000000..2b6f278c --- /dev/null +++ b/back-end/src/main/java/com/example/demo/security/UserDto.java @@ -0,0 +1,16 @@ +package com.example.demo.security; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.security.core.GrantedAuthority; + +import java.util.Set; + +@Builder +@Getter +public class UserDto { + + private String username; + private Set authorities; + +} diff --git a/back-end/src/main/java/com/example/demo/service/VacancyService.java b/back-end/src/main/java/com/example/demo/service/VacancyService.java index d6da76e6..3c67e671 100644 --- a/back-end/src/main/java/com/example/demo/service/VacancyService.java +++ b/back-end/src/main/java/com/example/demo/service/VacancyService.java @@ -38,4 +38,8 @@ public void delete(Vacancy vacancy) { public Optional getById(Integer id) { return vacancyRepository.findById(id); } + + public Page getByUser(String userName, Integer page, Integer size) { + return vacancyRepository.getVacationsByUser(userName, PageRequest.of(page, size)); + } } \ No newline at end of file diff --git a/back-end/src/main/resources/application.properties b/back-end/src/main/resources/application.properties deleted file mode 100644 index c841f6e4..00000000 --- a/back-end/src/main/resources/application.properties +++ /dev/null @@ -1,15 +0,0 @@ -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect -spring.jpa.hibernate.ddl-auto=none -spring.jpa.hibernate.show-sql=true -spring.datasource.url=jdbc:postgresql://localhost:5432/Candi-Meter -spring.datasource.username=postgres -spring.datasource.password=12345 -spring.liquibase.change-log=classpath:db/root-changelog.xml -spring.doc.swagger-ui.path=/swagger-ui.html -spring.servlet.multipart.enabled=true -spring.servlet.multipart.file-size-threshold=2KB -spring.servlet.multipart.max-file-size=200MB -spring.servlet.multipart.max-request-size=200MB - -app.jwt.token.expiration-in-ms=30000 -app.jwt.refresh.expiration-in-ms=60000 \ No newline at end of file diff --git a/back-end/src/main/resources/application.yaml b/back-end/src/main/resources/application.yaml new file mode 100644 index 00000000..240492df --- /dev/null +++ b/back-end/src/main/resources/application.yaml @@ -0,0 +1,28 @@ + +server: + port: 8085 +spring: + jpa: + hibernate: + ddl-auto: none + show-sql: true + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://localhost:5432/Candi-Meter + username: postgres + password: 12345 + liquibase: + change-log: classpath:db/root-changelog.xml + + +app: + allowed-origins: + http://41.32.3.215:8085/,http://localhost:4200 + + jwt: + token: + expiration-in-ms: 86400000 + refresh: + expiration-in-ms: 108000000 + secret: my-very-secret-key + diff --git a/back-end/src/main/resources/db/changelog/2022/08/01-05-changelog.xml b/back-end/src/main/resources/db/changelog/2022/08/01-05-changelog.xml new file mode 100644 index 00000000..4bf68369 --- /dev/null +++ b/back-end/src/main/resources/db/changelog/2022/08/01-05-changelog.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/back-end/src/main/resources/db/changelog/2022/08/01-06-changelog.xml b/back-end/src/main/resources/db/changelog/2022/08/01-06-changelog.xml new file mode 100644 index 00000000..a656fcb7 --- /dev/null +++ b/back-end/src/main/resources/db/changelog/2022/08/01-06-changelog.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/back-end/src/main/resources/db/root-changelog.xml b/back-end/src/main/resources/db/root-changelog.xml index a2996f78..60f3f966 100644 --- a/back-end/src/main/resources/db/root-changelog.xml +++ b/back-end/src/main/resources/db/root-changelog.xml @@ -16,6 +16,8 @@ + +