Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
04ca52a
Db repo (#31)
LordRenDS Mar 20, 2023
1d52efb
Updated TalentController
Maslyna Mar 21, 2023
badfc53
Created TalentExceptionHandler
Maslyna Mar 21, 2023
2fb0942
Updated TalentController: Added new endpoint `GET(/talents/{id})`, th…
Maslyna Mar 21, 2023
775886e
Refactored project structure
Maslyna Mar 21, 2023
3a393b4
Merge pull request #32 from ProvedCode/tasks-3-6
Maslyna Mar 21, 2023
9180e5f
BUGFIX: `BeanDefinitionStoreException: Failed to parse configuration …
Maslyna Mar 22, 2023
73b787f
user-story-1 (#35)
Maslyna Mar 24, 2023
a4145af
bugfix (#36)
Maslyna Mar 25, 2023
8b174a6
Add WebConfig (#48)
LordRenDS Mar 26, 2023
520855d
Add @CrossOrigin to TalentController (#50)
LordRenDS Mar 26, 2023
f340825
Delete WebConfig (#52)
LordRenDS Mar 26, 2023
efaac0b
data.sql Update
Maslyna Mar 26, 2023
4c15848
Edit data.sql and schema.sql
LordRenDS Mar 26, 2023
a21a15a
Edit UserInfo: add user_id and @NotNull, @NotEmpty validations
LordRenDS Mar 26, 2023
e220c32
Edit UserInfo: add @Builder, @AllArgsConstructor, @NoArgsConstructor
LordRenDS Mar 26, 2023
41fad81
commit 1
Maslyna Mar 27, 2023
dd96682
commit 2
Maslyna Mar 27, 2023
a987949
BugFix
Maslyna Mar 27, 2023
94c1325
commit 3
Maslyna Mar 27, 2023
51775bd
Edit UserAuthorityRepository, AuthenticationController, SecurityConfi…
LordRenDS Mar 27, 2023
11b01cc
Create trash in AuthenticationController
LordRenDS Mar 27, 2023
e40af7f
Code refactor
Maslyna Mar 28, 2023
e007bc8
BugFix: don`t ask me
Maslyna Mar 28, 2023
83c8ee9
Add enum Role, add findByAuthority to AuthorityRepository, do some re…
LordRenDS Mar 28, 2023
762e05d
Refactored code
Maslyna Mar 28, 2023
2b007f5
Refactored code
Maslyna Mar 28, 2023
4c60386
bugfix
Maslyna Mar 29, 2023
4026ba3
update 3
Maslyna Mar 29, 2023
49f0374
Updated TalentController
Maslyna Mar 21, 2023
bac76b1
Created TalentExceptionHandler
Maslyna Mar 21, 2023
5b43ebb
Updated TalentController: Added new endpoint `GET(/talents/{id})`, th…
Maslyna Mar 21, 2023
fd423cb
Refactored project structure
Maslyna Mar 21, 2023
6be5930
BUGFIX: `BeanDefinitionStoreException: Failed to parse configuration …
Maslyna Mar 22, 2023
13a2c93
user-story-1 (#35)
Maslyna Mar 24, 2023
223034d
bugfix (#36)
Maslyna Mar 25, 2023
797a82a
Add WebConfig (#48)
LordRenDS Mar 26, 2023
d854051
Delete WebConfig (#52)
LordRenDS Mar 26, 2023
c2937ed
data.sql Update
Maslyna Mar 26, 2023
f23a050
Edit data.sql and schema.sql
LordRenDS Mar 26, 2023
e5411a0
Edit UserInfo: add user_id and @NotNull, @NotEmpty validations
LordRenDS Mar 26, 2023
01b271f
Edit UserInfo: add @Builder, @AllArgsConstructor, @NoArgsConstructor
LordRenDS Mar 26, 2023
27cf835
commit 1
Maslyna Mar 27, 2023
0cc1196
commit 2
Maslyna Mar 27, 2023
2663abe
BugFix
Maslyna Mar 27, 2023
b386b4e
commit 3
Maslyna Mar 27, 2023
1fe33bf
Edit UserAuthorityRepository, AuthenticationController, SecurityConfi…
LordRenDS Mar 27, 2023
2cee94b
Create trash in AuthenticationController
LordRenDS Mar 27, 2023
cf52e96
Code refactor
Maslyna Mar 28, 2023
0751137
BugFix: don`t ask me
Maslyna Mar 28, 2023
9ac9993
Add enum Role, add findByAuthority to AuthorityRepository, do some re…
LordRenDS Mar 28, 2023
8c7ec93
Refactored code
Maslyna Mar 28, 2023
a4133f5
Refactored code
Maslyna Mar 28, 2023
232e24b
bugfix
Maslyna Mar 29, 2023
dceead3
update 3
Maslyna Mar 29, 2023
82fe360
Merge remote-tracking branch 'origin/code_revision' into code_revision
LordRenDS Mar 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/com/provedcode/config/InitConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.provedcode.config;

import com.provedcode.user.mapper.UserInfoMapper;
import com.provedcode.user.repo.UserInfoRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@AllArgsConstructor
public class InitConfig implements CommandLineRunner {
UserInfoRepository userInfoRepository;
PasswordEncoder passwordEncoder;
UserInfoMapper userInfoMapper;

@Override
public void run(String... args) throws Exception {
// TODO: Method to change passwords for already created users from data.sql
userInfoRepository.saveAll(
userInfoRepository.findAll().stream()
.map(i -> {
i.setPassword(passwordEncoder.encode(i.getPassword()));
return i;
}).toList());
}
}
84 changes: 81 additions & 3 deletions src/main/java/com/provedcode/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
package com.provedcode.config;

import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.provedcode.user.mapper.UserInfoMapper;
import com.provedcode.user.repo.UserInfoRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.web.SecurityFilterChain;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;

import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;

Expand All @@ -19,11 +43,65 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
http.authorizeHttpRequests(c -> c
.requestMatchers("/actuator/health").permitAll() // for DevOps
.requestMatchers(antMatcher("/h2/**")).permitAll()
.requestMatchers(antMatcher("/api/**")).permitAll()
.anyRequest().denyAll()
.requestMatchers(antMatcher("/api/talents/**")).permitAll()
.anyRequest().authenticated()
);
http.csrf().disable().headers().frameOptions().disable();

http.httpBasic(Customizer.withDefaults());
http.csrf().disable().headers().disable();

http.sessionManagement().sessionCreationPolicy(STATELESS);

http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.exceptionHandling(c -> c
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
.accessDeniedHandler(new BearerTokenAccessDeniedHandler())
);

return http.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public KeyPair keyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
}

@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthorityPrefix("");

JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}

@Bean
UserDetailsService userDetailsService(
UserInfoRepository repository,
UserInfoMapper mapper
) {
return login -> repository.findByLogin(login)
.map(mapper::toUserDetails)
.orElseThrow(() -> new UsernameNotFoundException(login + " not found"));
}

@Bean
JwtDecoder jwtDecoder(KeyPair keyPair) {
return NimbusJwtDecoder.withPublicKey((RSAPublicKey) keyPair.getPublic()).build();
}

@Bean
JwtEncoder jwtEncoder(KeyPair keyPair) {
var jwk = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic()).privateKey(keyPair.getPrivate()).build();
var jwkSet = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwkSet);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@ControllerAdvice
public class TalentExceptionHandler {
@ExceptionHandler(ResponseStatusException.class)
private ResponseEntity responseStatusExceptionHandler(ResponseStatusException exception) {
private ResponseEntity<?> responseStatusExceptionHandler(ResponseStatusException exception) {
return ResponseEntity.status(exception.getStatusCode()).body(exception.getBody());
}
}
13 changes: 9 additions & 4 deletions src/main/java/com/provedcode/talent/TalentController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@
import com.provedcode.talent.model.dto.ShortTalentDTO;
import com.provedcode.talent.service.TalentService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

@Slf4j
@RestController
@AllArgsConstructor
@CrossOrigin(origins = "*", allowedHeaders = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT,
RequestMethod.DELETE})
@CrossOrigin(origins = "*", allowedHeaders = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
@RequestMapping("/api")
public class TalentController {
TalentService talentService;

@GetMapping("/api/talents/{id}")
@PreAuthorize("hasRole('TALENT')")
@GetMapping("/talents/{id}")
FullTalentDTO getTalent(@PathVariable("id") long id) {
return talentService.getTalentById(id);
}

@GetMapping("/api/talents")
@GetMapping("/talents")
@ResponseStatus(HttpStatus.OK)
Page<ShortTalentDTO> getTalents(@RequestParam(value = "page") Optional<Integer> page,
@RequestParam(value = "size") Optional<Integer> size) {
return talentService.getTalentsPage(page, size);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,32 @@ public class TalentMapperImpl implements TalentMapper {
@Override
public ShortTalentDTO talentToShortTalentDTO(Talent talent) {
return ShortTalentDTO.builder()
.id(talent.getId())
.image(talent.getImage())
.firstname(talent.getFirstName())
.lastname(talent.getLastName())
.specialization(talent.getSpecialization())
.skills(talent.getTalentSkills().stream().map(TalentSkill::getSkill).toList())
.build();
.id(talent.getId())
.image(talent.getImage())
.firstName(talent.getFirstName())
.lastName(talent.getLastName())
.specialization(talent.getSpecialization())
.skills(talent.getTalentSkills().stream().map(TalentSkill::getSkill).toList())
.build();
}

@Override
public FullTalentDTO talentToFullTalentDTO(Talent talent) {
return FullTalentDTO.builder()
.id(talent.getId())
.firstname(talent.getFirstName())
.lastname(talent.getLastName())
.bio(talent.getTalentDescription().getBio())
.additionalInfo(talent.getTalentDescription().getAdditionalInfo())
.image(talent.getImage())
.specialization(talent.getSpecialization())
.links(talent.getTalentLinks().stream().map(TalentLink::getLink).toList())
.contacts(talent.getTalentContacts().stream().map(TalentContact::getContact).toList())
.skills(talent.getTalentSkills().stream().map(TalentSkill::getSkill).toList())
.attachedFiles(talent.getTalentAttachedFiles().stream().map(TalentAttachedFile::getAttachedFile).toList())
.build();
.id(talent.getId())
.firstName(talent.getFirstName())
.lastName(talent.getLastName())
.bio(talent.getTalentDescription() != null ? talent.getTalentDescription().getBio() : null)
.additionalInfo(talent.getTalentDescription() != null ? talent.getTalentDescription()
.getAdditionalInfo() : null)
.image(talent.getImage())
.specialization(talent.getSpecialization())
.links(talent.getTalentLinks().stream().map(TalentLink::getLink).toList())
.contacts(talent.getTalentContacts().stream().map(TalentContact::getContact).toList())
.skills(talent.getTalentSkills().stream().map(TalentSkill::getSkill).toList())
.attachedFiles(
talent.getTalentAttachedFiles().stream().map(TalentAttachedFile::getAttachedFile)
.toList())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
@Builder
public record FullTalentDTO (
Long id,
String firstname,
String lastname,
String firstName,
String lastName,
String image,
String specialization,
String additionalInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
public record ShortTalentDTO(
Long id,
String image,
String firstname,
String lastname,
String firstName,
String lastName,
String specialization,
List<String> skills
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,4 @@ public class Talent {
private List<TalentContact> talentContacts = new ArrayList<>();
@OneToMany(fetch = FetchType.EAGER, mappedBy = "talent", orphanRemoval = true)
private List<TalentAttachedFile> talentAttachedFiles = new ArrayList<>();

}
Original file line number Diff line number Diff line change
@@ -1,52 +1,54 @@
package com.provedcode.talent.service.impl;

import com.provedcode.config.PageProperties;
import com.provedcode.talent.service.TalentService;
import com.provedcode.talent.mapper.TalentMapper;
import com.provedcode.talent.model.dto.FullTalentDTO;
import com.provedcode.talent.model.dto.ShortTalentDTO;
import com.provedcode.talent.model.entity.Talent;
import com.provedcode.talent.repo.TalentRepository;
import com.provedcode.talent.service.TalentService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

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

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

@Service
@Slf4j
@AllArgsConstructor
@Transactional
public class TalentServiceImpl implements TalentService {
TalentMapper talentMapper;
TalentRepository talentRepository;
PageProperties pageProperties;

@Override
@Transactional(readOnly = true)
public Page<ShortTalentDTO> getTalentsPage(Optional<Integer> page, Optional<Integer> size) {
if (page.orElse(pageProperties.defaultPageNum()) < 0) {
throw new ResponseStatusException(BAD_REQUEST, "'page' query parameter must be greater than or equal to 0");
}
if (size.orElse(pageProperties.defaultPageSize()) <= 0) {
throw new ResponseStatusException(BAD_REQUEST, "'size' query parameter must be greater than or equal to 1");
}
return talentRepository.findAll(PageRequest.of(page.orElse(pageProperties.defaultPageNum()), size.orElse(pageProperties.defaultPageSize())))
.map(talentMapper::talentToShortTalentDTO);
return talentRepository.findAll(PageRequest.of(page.orElse(pageProperties.defaultPageNum()),
size.orElse(pageProperties.defaultPageSize())))
.map(talentMapper::talentToShortTalentDTO);

}

@Override
@Transactional(readOnly = true)
public FullTalentDTO getTalentById(long id) {
Optional<Talent> talent = talentRepository.findById(id);
if (talent.isEmpty()){
if (talent.isEmpty()) {
throw new ResponseStatusException(NOT_FOUND, String.format("talent with id = %d not found", id));
}
return talentMapper.talentToFullTalentDTO(talent.get());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.provedcode.user.controller;

import com.provedcode.user.model.dto.RegistrationDTO;
import com.provedcode.user.model.dto.SessionInfoDTO;
import com.provedcode.user.service.AuthenticationService;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

@RestController
@AllArgsConstructor
@Slf4j
@RequestMapping("/api/talents")
@CrossOrigin(origins = "*", allowedHeaders = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
public class AuthenticationController {
AuthenticationService authenticationService;

@PostMapping("/login")
SessionInfoDTO login(Authentication authentication) {
return authenticationService.login(authentication.getName(), authentication.getAuthorities());
}

@PostMapping("/register")
@ResponseStatus(HttpStatus.OK)
SessionInfoDTO register(@RequestBody @Valid RegistrationDTO user) {
return authenticationService.register(user);
}

}
8 changes: 8 additions & 0 deletions src/main/java/com/provedcode/user/mapper/UserInfoMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.provedcode.user.mapper;

import com.provedcode.user.model.entity.UserInfo;
import org.springframework.security.core.userdetails.UserDetails;

public interface UserInfoMapper {
UserDetails toUserDetails(UserInfo user);
}
Loading