From 23b7af4408ce4de24c3a35b4f4bb29321dabb351 Mon Sep 17 00:00:00 2001 From: Yash Raj <56453897+yesyash@users.noreply.github.com> Date: Tue, 6 Aug 2024 00:29:24 +0530 Subject: [PATCH] Develop release:v0.1 (#140) * create a model to store user_skill and add remove unused columns in users and skills model * create a model to store user_skill and add/remove unused columns in users and skills model * change id to integer * check if a skill already exists before creating one, make `updated_at` optional in TrackedProperties * remove unit and integration test and remove skill service & skill service implementation * add todo * rename SkillType to SkillTypeEnum * set logging level debug in application-dev instead of application * add todo * remove endorsements list * add reference to user table in skills modal * Build api to create a new endorsement * create api to update an endorsement * remove unused files * remove unused code in endorsement controller * chagne import order * change the skills project structure to match the new one * rename exceptions folder to small case exceptions and create user not found and skill already exists exceptions * create enums folder and move skill type enum to the folder * rename Conifg to config, move generic response and jwtAuthenticationFilter to utils * add api to get all endorsements for a skill using skill id in skillsapi * remove skills package * fix build error * move api to create a endorsement to the new folder structure * add api to update endorsement in apis/endorsements api and remove old Endorsement folder * move health check api to the api folder & metric service inside the services folder * fix formatting * create annotation and aspect to handle authorized roles to an api * add authorizred roles annotation to skillsapi & endorsementsapi class * set authorized role for creating a skill to only superuser * fix formatting * create api to get all skill requests * apply spotless * set endorsement id * run spotlesscheck * remove comments * add super user role check in skills/requests api * build the `skill/requests` api to get all skill requests and their endorsements * fix duplicate data issue when getting all skill requests * improve comment * change data to requests in SkillRequestDto * fix formatting * fix wrong id being set in endorserDetails * fix formatting error * create api to login via rds backend * add permitted paths to security config * fix formatting * change permitted routes to non auth routes * improve the internal server error exception handler by adding time stamp, error message and details * fix formatting * remove user table and use RdsUserViewModel instead * remove auth api and fix logging in update endorsement api * fix formatting * change EndorsementViewModel to use builder pattern * Remove commented code * Change error to info * Refactor: Move post endorsements in skills route (#143) * build api to approve/reject skill request (#144) * build api to approve/reject skill request * fix formatting --------- Co-authored-by: Prakash Co-authored-by: Prakash Choudhary <34452139+prakashchoudhary07@users.noreply.github.com> --- .env.sample | 2 + .../UserAuthenticationToken.java | 10 +- .../java/com/RDS/skilltree/User/UserDRO.java | 49 -------- .../java/com/RDS/skilltree/User/UserDTO.java | 43 ------- .../com/RDS/skilltree/User/UserModel.java | 23 ---- .../RDS/skilltree/User/UserRepository.java | 7 -- .../com/RDS/skilltree/User/UserService.java | 15 --- .../RDS/skilltree/User/UserServiceImpl.java | 70 ----------- .../annotations/AuthorizedRoles.java | 2 +- .../RDS/skilltree/apis/EndorsementsApi.java | 9 +- .../com/RDS/skilltree/apis/SkillsApi.java | 28 ++++- .../aspects/AuthorizedRolesAspect.java | 8 +- .../RDS/skilltree/config/SecurityConfig.java | 33 +++-- .../dtos/CreateEndorsementRequestDto.java | 15 +++ .../dtos/RdsGetUserDetailsResDto.java | 12 ++ .../dtos/SkillRequestActionRequestDto.java | 16 +++ .../{User => enums}/UserRoleEnum.java | 2 +- .../{User => enums}/UserSkillStatusEnum.java | 2 +- .../exceptions/GlobalExceptionHandler.java | 19 +++ .../InternalServerErrorException.java | 7 ++ .../com/RDS/skilltree/models/Endorsement.java | 17 ++- .../JwtUserModel.java => models/JwtUser.java} | 7 +- .../java/com/RDS/skilltree/models/Skill.java | 11 +- .../UserSkills.java} | 20 ++- .../repositories/UserSkillRepository.java | 10 +- .../EndorsementServiceImplementation.java | 115 ++++++++++++------ .../RDS/skilltree/services/SkillService.java | 5 + .../services/SkillServiceImplementation.java | 79 +++++++----- .../services/external/RdsService.java | 4 +- .../external/RdsServiceImplementation.java | 12 +- .../utils/JWTAuthenticationFilter.java | 7 ++ .../viewmodels/AuthSuccessViewModel.java | 12 ++ .../CreateEndorsementViewModel.java | 18 ++- .../viewmodels/CreateSkillViewModel.java | 3 +- .../viewmodels/EndorsementViewModel.java | 20 +-- .../MinimalEndorsementViewModel.java | 18 ++- .../viewmodels/RdsUserViewModel.java | 56 ++++----- .../viewmodels/SkillRequestViewModel.java | 11 +- .../skilltree/viewmodels/UserViewModel.java | 13 +- .../src/main/resources/application.properties | 4 +- 40 files changed, 381 insertions(+), 433 deletions(-) delete mode 100644 skill-tree/src/main/java/com/RDS/skilltree/User/UserDRO.java delete mode 100644 skill-tree/src/main/java/com/RDS/skilltree/User/UserDTO.java delete mode 100644 skill-tree/src/main/java/com/RDS/skilltree/User/UserModel.java delete mode 100644 skill-tree/src/main/java/com/RDS/skilltree/User/UserRepository.java delete mode 100644 skill-tree/src/main/java/com/RDS/skilltree/User/UserService.java delete mode 100644 skill-tree/src/main/java/com/RDS/skilltree/User/UserServiceImpl.java create mode 100644 skill-tree/src/main/java/com/RDS/skilltree/dtos/CreateEndorsementRequestDto.java create mode 100644 skill-tree/src/main/java/com/RDS/skilltree/dtos/RdsGetUserDetailsResDto.java create mode 100644 skill-tree/src/main/java/com/RDS/skilltree/dtos/SkillRequestActionRequestDto.java rename skill-tree/src/main/java/com/RDS/skilltree/{User => enums}/UserRoleEnum.java (95%) rename skill-tree/src/main/java/com/RDS/skilltree/{User => enums}/UserSkillStatusEnum.java (70%) create mode 100644 skill-tree/src/main/java/com/RDS/skilltree/exceptions/InternalServerErrorException.java rename skill-tree/src/main/java/com/RDS/skilltree/{User/JwtUserModel.java => models/JwtUser.java} (52%) rename skill-tree/src/main/java/com/RDS/skilltree/{User/UserSkillsModel.java => models/UserSkills.java} (63%) create mode 100644 skill-tree/src/main/java/com/RDS/skilltree/viewmodels/AuthSuccessViewModel.java diff --git a/.env.sample b/.env.sample index 7f9fd9e3..659928a1 100644 --- a/.env.sample +++ b/.env.sample @@ -4,6 +4,8 @@ MYSQL_DB_PASSWORD=testpassword MYSQL_ROOT_PASSWORD=password DB_DDL_POLICY=update RDS_BACKEND_BASE_URL=http://localhost:3000 +SKILL_TREE_FRONTEND_BASE_URL=https://localhost +SKILL_TREE_BACKEND_BASE_URL=http://localhost:8080 RDS_PUBLIC_KEY="-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg5HrGgKFmH485DXLG4fG 1mKNXceWthXgAozsUGHxLIM3Fa5wU+tLi7tLDZ6LRKo4ZZV2gJJdDqFSNsvn1Uvr diff --git a/skill-tree/src/main/java/com/RDS/skilltree/Authentication/UserAuthenticationToken.java b/skill-tree/src/main/java/com/RDS/skilltree/Authentication/UserAuthenticationToken.java index 5799bfc8..7780b9b4 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/Authentication/UserAuthenticationToken.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/Authentication/UserAuthenticationToken.java @@ -1,7 +1,7 @@ package com.RDS.skilltree.Authentication; -import com.RDS.skilltree.User.JwtUserModel; -import com.RDS.skilltree.User.UserRoleEnum; +import com.RDS.skilltree.enums.UserRoleEnum; +import com.RDS.skilltree.models.JwtUser; import java.util.List; import javax.security.auth.Subject; import org.springframework.security.authentication.AbstractAuthenticationToken; @@ -9,12 +9,12 @@ public class UserAuthenticationToken extends AbstractAuthenticationToken { - private final JwtUserModel user; + private final JwtUser user; public UserAuthenticationToken(String role, String rdsUserId) { super(List.of(new SimpleGrantedAuthority(UserRoleEnum.fromString(role).name()))); - this.user = new JwtUserModel(rdsUserId, UserRoleEnum.fromString(role)); + this.user = new JwtUser(rdsUserId, UserRoleEnum.fromString(role)); setAuthenticated(true); } @@ -24,7 +24,7 @@ public Object getCredentials() { } @Override - public JwtUserModel getPrincipal() { + public JwtUser getPrincipal() { return user; } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserDRO.java b/skill-tree/src/main/java/com/RDS/skilltree/User/UserDRO.java deleted file mode 100644 index 79bd6b2c..00000000 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserDRO.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.RDS.skilltree.User; - -import java.net.URL; -import java.time.Instant; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@AllArgsConstructor -@NoArgsConstructor -@Data -@Builder -public class UserDRO { - private String rdsUserId; - - private String firstName; - - private String lastName; - - private URL imageUrl; - - private UserRoleEnum role; - - public static UserModel toModel(UserDRO user) { - return UserModel.builder() - .rdsUserId(user.getRdsUserId()) - // .role(user.getRole()) - .build(); - } - - public static UserDRO fromModel(UserModel user) { - return UserDRO.builder() - .rdsUserId(user.getRdsUserId()) - // .role(user.getRole()) - .build(); - } - - public static UserModel compareAndUpdateModel(UserModel user, UserDRO userDRO) { - if (userDRO.getRdsUserId() != null) { - user.setRdsUserId(user.getRdsUserId()); - } - // if (userDRO.getRole() != null) { - // user.setRole(user.getRole()); - // } - user.setUpdatedAt(Instant.now()); - return user; - } -} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserDTO.java b/skill-tree/src/main/java/com/RDS/skilltree/User/UserDTO.java deleted file mode 100644 index 87ceb395..00000000 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserDTO.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.RDS.skilltree.User; - -import com.RDS.skilltree.models.Skill; -import java.net.URL; -import java.util.Set; -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class UserDTO { - - private String id; - - private String rdsUserId; - - private String firstName; - - private String lastName; - - private URL imageUrl; - - private UserRoleEnum role; - - private Set skills; - - public static UserDTO toDTO(UserModel user) { - - return UserDTO.builder().id(user.getId()).rdsUserId(user.getRdsUserId()).build(); - } - - public static UserDTO getUsersWithSkills(UserModel user) { - // Set skills = [] - // user.getSkills().stream().map(SkillDTO::toDto).collect(Collectors.toSet()); - - return UserDTO.builder() - .id(user.getId()) - .rdsUserId(user.getRdsUserId()) - // .skills(skills) - // .role(user.getRole()) - .build(); - } -} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserModel.java b/skill-tree/src/main/java/com/RDS/skilltree/User/UserModel.java deleted file mode 100644 index 65f4f8af..00000000 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserModel.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.RDS.skilltree.User; - -import com.RDS.skilltree.utils.TrackedProperties; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import jakarta.persistence.*; -import lombok.*; - -@Entity -@Getter -@Setter -@Builder -@JsonSerialize -@NoArgsConstructor -@AllArgsConstructor -@Table(name = "users") -public class UserModel extends TrackedProperties { - @Id - @Column(name = "id") - private String id; - - @Column(name = "rds_user_id", unique = true) - private String rdsUserId; -} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserRepository.java b/skill-tree/src/main/java/com/RDS/skilltree/User/UserRepository.java deleted file mode 100644 index 6700fd30..00000000 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.RDS.skilltree.User; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface UserRepository extends JpaRepository {} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserService.java b/skill-tree/src/main/java/com/RDS/skilltree/User/UserService.java deleted file mode 100644 index 2115b995..00000000 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserService.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.RDS.skilltree.User; - -import java.util.List; - -public interface UserService { - UserDTO createUser(UserDRO user); - - void updateUser(String id, UserDRO user); - - UserDTO getUserById(String id); - - List getAllUsers(); - - void addSkill(Integer skill, String userId); -} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserServiceImpl.java b/skill-tree/src/main/java/com/RDS/skilltree/User/UserServiceImpl.java deleted file mode 100644 index 1171911a..00000000 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserServiceImpl.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.RDS.skilltree.User; - -import com.RDS.skilltree.exceptions.NoEntityException; -import com.RDS.skilltree.models.Skill; -import com.RDS.skilltree.repositories.SkillRepository; -import jakarta.transaction.Transactional; -import java.util.List; -import java.util.Optional; -import org.springframework.stereotype.Service; - -@Service -public class UserServiceImpl implements UserService { - private final UserRepository userRepository; - private final SkillRepository skillRepository; - - public UserServiceImpl(UserRepository userRepository, SkillRepository skillRepository) { - this.userRepository = userRepository; - this.skillRepository = skillRepository; - } - - @Override - public UserDTO createUser(UserDRO user) { - UserModel userModel = UserDRO.toModel(user); - userRepository.save(userModel); - return UserDTO.toDTO(userModel); - } - - @Override - public void updateUser(String id, UserDRO user) {} - - @Override - public UserDTO getUserById(String id) { - Optional userModel = userRepository.findById(id); - return userModel.map(UserDTO::getUsersWithSkills).orElse(null); - } - - @Override - public List getAllUsers() { - return null; - } - - /** - * updates the user and skill both - * - * @param skillId - * @param userId - */ - @Override - @Transactional - public void addSkill(Integer skillId, String userId) { - Optional userOptional = userRepository.findById(userId); - Optional skillOptional = skillRepository.findById(skillId); - - if (userOptional.isPresent() && skillOptional.isPresent()) { - UserModel userModel = userOptional.get(); - Skill skill = skillOptional.get(); - - // userModel.getSkills().add(skillModel); - // skillModel.getUsers().add(userModel); - - userRepository.save(userModel); - skillRepository.save(skill); - } else { - if (skillOptional.isEmpty()) { - throw new NoEntityException("Skill Id is not passed in the input"); - } - throw new NoEntityException("User with Id doesn't exists"); - } - } -} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/annotations/AuthorizedRoles.java b/skill-tree/src/main/java/com/RDS/skilltree/annotations/AuthorizedRoles.java index 32e798b8..c788b99c 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/annotations/AuthorizedRoles.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/annotations/AuthorizedRoles.java @@ -1,6 +1,6 @@ package com.RDS.skilltree.annotations; -import com.RDS.skilltree.User.UserRoleEnum; +import com.RDS.skilltree.enums.UserRoleEnum; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/skill-tree/src/main/java/com/RDS/skilltree/apis/EndorsementsApi.java b/skill-tree/src/main/java/com/RDS/skilltree/apis/EndorsementsApi.java index c418a5dd..cd3d5212 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/apis/EndorsementsApi.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/apis/EndorsementsApi.java @@ -1,9 +1,8 @@ package com.RDS.skilltree.apis; -import com.RDS.skilltree.User.UserRoleEnum; import com.RDS.skilltree.annotations.AuthorizedRoles; +import com.RDS.skilltree.enums.UserRoleEnum; import com.RDS.skilltree.services.EndorsementService; -import com.RDS.skilltree.viewmodels.CreateEndorsementViewModel; import com.RDS.skilltree.viewmodels.EndorsementViewModel; import com.RDS.skilltree.viewmodels.UpdateEndorsementViewModel; import jakarta.validation.Valid; @@ -21,12 +20,6 @@ public class EndorsementsApi { private final EndorsementService endorsementService; - @PostMapping - public ResponseEntity create( - @Valid @RequestBody CreateEndorsementViewModel endorsement) { - return new ResponseEntity<>(endorsementService.create(endorsement), HttpStatus.CREATED); - } - @PatchMapping("/{id}") public ResponseEntity update( @PathVariable Integer id, @Valid @RequestBody UpdateEndorsementViewModel body) { diff --git a/skill-tree/src/main/java/com/RDS/skilltree/apis/SkillsApi.java b/skill-tree/src/main/java/com/RDS/skilltree/apis/SkillsApi.java index 1a0f65ad..28ba4828 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/apis/SkillsApi.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/apis/SkillsApi.java @@ -1,10 +1,14 @@ package com.RDS.skilltree.apis; -import com.RDS.skilltree.User.UserRoleEnum; import com.RDS.skilltree.annotations.AuthorizedRoles; +import com.RDS.skilltree.dtos.CreateEndorsementRequestDto; +import com.RDS.skilltree.dtos.SkillRequestActionRequestDto; import com.RDS.skilltree.dtos.SkillRequestsDto; +import com.RDS.skilltree.enums.UserRoleEnum; import com.RDS.skilltree.services.EndorsementService; import com.RDS.skilltree.services.SkillService; +import com.RDS.skilltree.utils.GenericResponse; +import com.RDS.skilltree.viewmodels.CreateEndorsementViewModel; import com.RDS.skilltree.viewmodels.CreateSkillViewModel; import com.RDS.skilltree.viewmodels.EndorsementViewModel; import com.RDS.skilltree.viewmodels.SkillViewModel; @@ -12,6 +16,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -35,6 +40,16 @@ public ResponseEntity getAllRequests() { return ResponseEntity.ok(skillService.getAllRequests()); } + @PostMapping("/requests/{skillId}/action") + @AuthorizedRoles({UserRoleEnum.SUPERUSER}) + public ResponseEntity> approveRejectSkillRequest( + @PathVariable(value = "skillId") Integer skillId, + @Valid @RequestBody SkillRequestActionRequestDto skillRequestAction) { + return ResponseEntity.ok( + skillService.approveRejectSkillRequest( + skillId, skillRequestAction.getEndorseId(), skillRequestAction.getAction())); + } + @PostMapping @AuthorizedRoles({UserRoleEnum.SUPERUSER}) public ResponseEntity create(@Valid @RequestBody CreateSkillViewModel skill) { @@ -46,4 +61,15 @@ public ResponseEntity> getEndorsementsBySkillId( @PathVariable(value = "id") Integer skillID) { return ResponseEntity.ok(endorsementService.getAllEndorsementsBySkillId(skillID)); } + + @PostMapping("/{id}/endorsements") + public ResponseEntity create( + @PathVariable(value = "id") Integer skillID, + @Valid @RequestBody CreateEndorsementRequestDto endorsementRequest) { + return new ResponseEntity<>( + endorsementService.create( + CreateEndorsementViewModel.toViewModel( + skillID, endorsementRequest.getEndorseId(), endorsementRequest.getMessage())), + HttpStatus.CREATED); + } } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/aspects/AuthorizedRolesAspect.java b/skill-tree/src/main/java/com/RDS/skilltree/aspects/AuthorizedRolesAspect.java index 65ff6c2f..6505c3c9 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/aspects/AuthorizedRolesAspect.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/aspects/AuthorizedRolesAspect.java @@ -1,9 +1,9 @@ package com.RDS.skilltree.aspects; -import com.RDS.skilltree.User.JwtUserModel; -import com.RDS.skilltree.User.UserRoleEnum; import com.RDS.skilltree.annotations.AuthorizedRoles; +import com.RDS.skilltree.enums.UserRoleEnum; import com.RDS.skilltree.exceptions.ForbiddenException; +import com.RDS.skilltree.models.JwtUser; import java.lang.reflect.Method; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -19,8 +19,8 @@ public class AuthorizedRolesAspect { @Around("@within(authorizedRoles) || @annotation(authorizedRoles)") public Object authorize(ProceedingJoinPoint joinPoint, AuthorizedRoles authorizedRoles) throws Throwable { - JwtUserModel jwtDetails = - (JwtUserModel) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + JwtUser jwtDetails = + (JwtUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); UserRoleEnum role = jwtDetails.getRole(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); diff --git a/skill-tree/src/main/java/com/RDS/skilltree/config/SecurityConfig.java b/skill-tree/src/main/java/com/RDS/skilltree/config/SecurityConfig.java index b01c3b49..520aff3a 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/config/SecurityConfig.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/config/SecurityConfig.java @@ -2,7 +2,7 @@ import com.RDS.skilltree.Authentication.AuthEntryPoint; import com.RDS.skilltree.Authentication.CustomAccessDeniedHandler; -import com.RDS.skilltree.User.UserRoleEnum; +import com.RDS.skilltree.enums.UserRoleEnum; import com.RDS.skilltree.utils.JWTAuthenticationFilter; import java.util.Arrays; import java.util.List; @@ -27,6 +27,8 @@ public class SecurityConfig { private final AuthEntryPoint authEntryPoint; private final CustomAccessDeniedHandler accessDeniedHandler; + public static final List NON_AUTH_ROUTES = List.of("/v1/health", "/v1/auth"); + public SecurityConfig( AuthEntryPoint authEntryPoint, CustomAccessDeniedHandler accessDeniedHandler) { this.authEntryPoint = authEntryPoint; @@ -41,23 +43,18 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { httpSecurityCorsConfigurer -> httpSecurityCorsConfigurer.configurationSource(corsConfigurationSource())) .authorizeHttpRequests( - auth -> - auth.requestMatchers("/v1/health") - .permitAll() - .requestMatchers( - request -> - request.getQueryString() != null - && request.getQueryString().contains("dummyData=true")) - .permitAll() - .requestMatchers(HttpMethod.GET, "/v1/**") - .hasAnyAuthority(UserRoleEnum.getAllRoles()) // give read-only access to all - .requestMatchers("/v1/**") - .hasAnyAuthority( - UserRoleEnum.USER.name(), - UserRoleEnum.MEMBER.name(), - UserRoleEnum.SUPERUSER.name()) - .anyRequest() - .authenticated()) + auth -> { + NON_AUTH_ROUTES.forEach(path -> auth.requestMatchers(path + "/**").permitAll()); + auth.requestMatchers(HttpMethod.GET, "/v1/**") + .hasAnyAuthority(UserRoleEnum.getAllRoles()) // give read-only access to all + .requestMatchers("/v1/**") + .hasAnyAuthority( + UserRoleEnum.USER.name(), + UserRoleEnum.MEMBER.name(), + UserRoleEnum.SUPERUSER.name()) + .anyRequest() + .authenticated(); + }) .exceptionHandling( ex -> ex.accessDeniedHandler(this.accessDeniedHandler) diff --git a/skill-tree/src/main/java/com/RDS/skilltree/dtos/CreateEndorsementRequestDto.java b/skill-tree/src/main/java/com/RDS/skilltree/dtos/CreateEndorsementRequestDto.java new file mode 100644 index 00000000..281e09f1 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/dtos/CreateEndorsementRequestDto.java @@ -0,0 +1,15 @@ +package com.RDS.skilltree.dtos; + +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CreateEndorsementRequestDto { + @NotNull(message = "Message cannot be empty") + private String message; + + @NotNull(message = "user id cannot be null") + private String endorseId; +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/dtos/RdsGetUserDetailsResDto.java b/skill-tree/src/main/java/com/RDS/skilltree/dtos/RdsGetUserDetailsResDto.java new file mode 100644 index 00000000..7f2a765a --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/dtos/RdsGetUserDetailsResDto.java @@ -0,0 +1,12 @@ +package com.RDS.skilltree.dtos; + +import com.RDS.skilltree.viewmodels.RdsUserViewModel; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RdsGetUserDetailsResDto { + private String message; + private RdsUserViewModel user; +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/dtos/SkillRequestActionRequestDto.java b/skill-tree/src/main/java/com/RDS/skilltree/dtos/SkillRequestActionRequestDto.java new file mode 100644 index 00000000..66cf83e4 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/dtos/SkillRequestActionRequestDto.java @@ -0,0 +1,16 @@ +package com.RDS.skilltree.dtos; + +import com.RDS.skilltree.enums.UserSkillStatusEnum; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class SkillRequestActionRequestDto { + @NotNull(message = "user id cannot be null") + private String endorseId; + + @NotNull(message = "Action should not empty") + private UserSkillStatusEnum action; +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserRoleEnum.java b/skill-tree/src/main/java/com/RDS/skilltree/enums/UserRoleEnum.java similarity index 95% rename from skill-tree/src/main/java/com/RDS/skilltree/User/UserRoleEnum.java rename to skill-tree/src/main/java/com/RDS/skilltree/enums/UserRoleEnum.java index 78caeac6..19537b69 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserRoleEnum.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/enums/UserRoleEnum.java @@ -1,4 +1,4 @@ -package com.RDS.skilltree.User; +package com.RDS.skilltree.enums; import java.util.Arrays; diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillStatusEnum.java b/skill-tree/src/main/java/com/RDS/skilltree/enums/UserSkillStatusEnum.java similarity index 70% rename from skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillStatusEnum.java rename to skill-tree/src/main/java/com/RDS/skilltree/enums/UserSkillStatusEnum.java index 79637df6..caa48ac7 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillStatusEnum.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/enums/UserSkillStatusEnum.java @@ -1,4 +1,4 @@ -package com.RDS.skilltree.User; +package com.RDS.skilltree.enums; public enum UserSkillStatusEnum { APPROVED, diff --git a/skill-tree/src/main/java/com/RDS/skilltree/exceptions/GlobalExceptionHandler.java b/skill-tree/src/main/java/com/RDS/skilltree/exceptions/GlobalExceptionHandler.java index c21e447f..e5abe97c 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/exceptions/GlobalExceptionHandler.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/exceptions/GlobalExceptionHandler.java @@ -2,7 +2,10 @@ import com.RDS.skilltree.utils.GenericResponse; import jakarta.validation.ConstraintViolationException; +import java.time.LocalDateTime; +import java.util.HashMap; import java.util.List; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.apache.tomcat.websocket.AuthenticationException; import org.springframework.http.HttpStatus; @@ -135,4 +138,20 @@ public ResponseEntity handleForbiddenException(ForbiddenException ex, WebRequ log.error("Exception - Error : {}", ex.getMessage(), ex); return new ResponseEntity<>(new GenericResponse<>(null, ex.getMessage()), HttpStatus.FORBIDDEN); } + + @ExceptionHandler(InternalServerErrorException.class) + public ResponseEntity handleInternalServerErrorException( + InternalServerErrorException ex, WebRequest request) { + log.error("Internal Server Error", ex); + // Create a more specific error message based on the exception type or cause + String errorMessage = "An unexpected error occurred."; + + // Consider adding more details to the response for debugging + Map errorDetails = new HashMap<>(); + errorDetails.put("timestamp", LocalDateTime.now()); + errorDetails.put("message", errorMessage); + errorDetails.put("details", ex.getMessage()); // Include exception details for debugging + + return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR); + } } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/exceptions/InternalServerErrorException.java b/skill-tree/src/main/java/com/RDS/skilltree/exceptions/InternalServerErrorException.java new file mode 100644 index 00000000..1bdafb12 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/exceptions/InternalServerErrorException.java @@ -0,0 +1,7 @@ +package com.RDS.skilltree.exceptions; + +public class InternalServerErrorException extends RuntimeException { + public InternalServerErrorException(String message) { + super(message); + } +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/models/Endorsement.java b/skill-tree/src/main/java/com/RDS/skilltree/models/Endorsement.java index 9c619b36..935d75b9 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/models/Endorsement.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/models/Endorsement.java @@ -1,16 +1,15 @@ package com.RDS.skilltree.models; -import com.RDS.skilltree.User.UserModel; import com.RDS.skilltree.utils.TrackedProperties; import jakarta.persistence.*; import lombok.*; -@AllArgsConstructor -@NoArgsConstructor @Entity @Builder @Getter @Setter +@AllArgsConstructor +@NoArgsConstructor @Table(name = "endorsements") public class Endorsement extends TrackedProperties { @Id @@ -22,14 +21,12 @@ public class Endorsement extends TrackedProperties { @JoinColumn(name = "skill_id", referencedColumnName = "id") private Skill skill; - @ManyToOne - @JoinColumn(name = "endorse_id", referencedColumnName = "id") - private UserModel endorse; + @Column(name = "endorse_id", nullable = false) + private String endorseId; - @ManyToOne(targetEntity = UserModel.class, cascade = CascadeType.ALL, optional = false) - @JoinColumn(name = "endorser_id", referencedColumnName = "id") - private UserModel endorser; + @Column(name = "endorser_id", nullable = false) + private String endorserId; - @Column(name = "message", nullable = false) + @Column(name = "message", nullable = false, columnDefinition = "TEXT") private String message; } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/JwtUserModel.java b/skill-tree/src/main/java/com/RDS/skilltree/models/JwtUser.java similarity index 52% rename from skill-tree/src/main/java/com/RDS/skilltree/User/JwtUserModel.java rename to skill-tree/src/main/java/com/RDS/skilltree/models/JwtUser.java index 29b92988..5ec4e5fc 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/JwtUserModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/models/JwtUser.java @@ -1,13 +1,14 @@ -package com.RDS.skilltree.User; +package com.RDS.skilltree.models; +import com.RDS.skilltree.enums.UserRoleEnum; import lombok.Getter; @Getter -public class JwtUserModel { +public class JwtUser { private final String rdsUserId; private final UserRoleEnum role; - public JwtUserModel(String rdsUserId, UserRoleEnum role) { + public JwtUser(String rdsUserId, UserRoleEnum role) { this.role = role; this.rdsUserId = rdsUserId; } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/models/Skill.java b/skill-tree/src/main/java/com/RDS/skilltree/models/Skill.java index 48b93981..ef0ae328 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/models/Skill.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/models/Skill.java @@ -1,6 +1,5 @@ package com.RDS.skilltree.models; -import com.RDS.skilltree.User.UserModel; import com.RDS.skilltree.enums.SkillTypeEnum; import com.RDS.skilltree.utils.TrackedProperties; import jakarta.persistence.*; @@ -26,11 +25,9 @@ public class Skill extends TrackedProperties { @Enumerated(value = EnumType.STRING) private SkillTypeEnum type = SkillTypeEnum.ATOMIC; - @ManyToOne - @JoinColumn(name = "created_by", nullable = false) - private UserModel createdBy; + @Column(name = "created_by", nullable = false) + private String createdBy; - @ManyToOne - @JoinColumn(name = "updated_by") - private UserModel updatedBy; + @Column(name = "updated_by") + private String updateBy; } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillsModel.java b/skill-tree/src/main/java/com/RDS/skilltree/models/UserSkills.java similarity index 63% rename from skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillsModel.java rename to skill-tree/src/main/java/com/RDS/skilltree/models/UserSkills.java index a4c1adf6..65358a90 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillsModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/models/UserSkills.java @@ -1,28 +1,25 @@ -package com.RDS.skilltree.User; +package com.RDS.skilltree.models; -import com.RDS.skilltree.models.Skill; +import com.RDS.skilltree.enums.UserSkillStatusEnum; import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.*; -import java.util.UUID; import lombok.*; @Entity @Getter @Setter @Builder -@NoArgsConstructor @AllArgsConstructor +@NoArgsConstructor @Table(name = "user_skills") -public class UserSkillsModel { +public class UserSkills { @Id - @GeneratedValue + @GeneratedValue(strategy = GenerationType.UUID) @Column(name = "id") - private UUID id; + private String id; - @JsonBackReference - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id", nullable = false) - private UserModel user; + @Column(name = "user_id", nullable = false) + private String userId; @JsonBackReference @ManyToOne(fetch = FetchType.LAZY) @@ -31,5 +28,6 @@ public class UserSkillsModel { @Enumerated(EnumType.STRING) @Column(name = "status", nullable = false) + @Builder.Default private UserSkillStatusEnum status = UserSkillStatusEnum.PENDING; } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/repositories/UserSkillRepository.java b/skill-tree/src/main/java/com/RDS/skilltree/repositories/UserSkillRepository.java index d4aeeb41..5dd821ea 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/repositories/UserSkillRepository.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/repositories/UserSkillRepository.java @@ -1,12 +1,12 @@ package com.RDS.skilltree.repositories; -import com.RDS.skilltree.User.UserSkillStatusEnum; -import com.RDS.skilltree.User.UserSkillsModel; +import com.RDS.skilltree.enums.UserSkillStatusEnum; +import com.RDS.skilltree.models.UserSkills; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; -public interface UserSkillRepository extends JpaRepository { - List findByStatus(UserSkillStatusEnum status); +public interface UserSkillRepository extends JpaRepository { + List findByStatus(UserSkillStatusEnum status); - List findByUserIdAndSkillId(String userId, Integer skillId); + List findByUserIdAndSkillId(String userId, Integer skillId); } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java b/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java index 008364cc..b5fd5a10 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java @@ -1,31 +1,33 @@ package com.RDS.skilltree.services; -import com.RDS.skilltree.User.UserModel; -import com.RDS.skilltree.User.UserRepository; -import com.RDS.skilltree.User.UserSkillStatusEnum; -import com.RDS.skilltree.User.UserSkillsModel; +import com.RDS.skilltree.dtos.RdsGetUserDetailsResDto; import com.RDS.skilltree.exceptions.EndorsementNotFoundException; import com.RDS.skilltree.exceptions.SelfEndorsementNotAllowedException; import com.RDS.skilltree.exceptions.SkillNotFoundException; -import com.RDS.skilltree.exceptions.UserNotFoundException; import com.RDS.skilltree.models.Endorsement; +import com.RDS.skilltree.models.JwtUser; import com.RDS.skilltree.models.Skill; +import com.RDS.skilltree.models.UserSkills; import com.RDS.skilltree.repositories.EndorsementRepository; import com.RDS.skilltree.repositories.SkillRepository; import com.RDS.skilltree.repositories.UserSkillRepository; +import com.RDS.skilltree.services.external.RdsService; import com.RDS.skilltree.viewmodels.CreateEndorsementViewModel; import com.RDS.skilltree.viewmodels.EndorsementViewModel; import com.RDS.skilltree.viewmodels.UpdateEndorsementViewModel; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import com.RDS.skilltree.viewmodels.UserViewModel; +import java.util.*; import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class EndorsementServiceImplementation implements EndorsementService { - private final UserRepository userRepository; + private static final Logger log = LoggerFactory.getLogger(EndorsementServiceImplementation.class); + private final RdsService rdsService; private final SkillRepository skillRepository; private final EndorsementRepository endorsementRepository; private final UserSkillRepository userSkillRepository; @@ -33,7 +35,31 @@ public class EndorsementServiceImplementation implements EndorsementService { @Override public List getAllEndorsementsBySkillId(Integer skillId) { List endorsements = endorsementRepository.findBySkillId(skillId); - return endorsements.stream().map(EndorsementViewModel::toViewModel).toList(); + + // store all users data that are a part of this request + Map userDetails = new HashMap<>(); + + return endorsements.stream() + .map( + endorsement -> { + String endorseId = endorsement.getEndorseId(); + String endorserId = endorsement.getEndorserId(); + + if (!userDetails.containsKey(endorseId)) { + RdsGetUserDetailsResDto endorseDetails = + rdsService.getUserDetails(endorsement.getEndorseId()); + userDetails.put(endorseId, UserViewModel.toViewModel(endorseDetails.getUser())); + } + + if (!userDetails.containsKey(endorserId)) { + RdsGetUserDetailsResDto endorserDetails = rdsService.getUserDetails(endorserId); + userDetails.put(endorserId, UserViewModel.toViewModel(endorserDetails.getUser())); + } + + return EndorsementViewModel.toViewModel( + endorsement, userDetails.get(endorseId), userDetails.get(endorserId)); + }) + .toList(); } @Override @@ -43,50 +69,54 @@ public EndorsementViewModel create(CreateEndorsementViewModel endorsementViewMod Integer skillId = endorsementViewModel.getSkillId(); String endorseId = endorsementViewModel.getEndorseId(); - // TODO: Get this from security context once the login api is implemented. - String endorserId = "cf8893a16cee42cc94387a9bd086ed46"; + JwtUser jwtDetails = + (JwtUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + String endorserId = jwtDetails.getRdsUserId(); if (Objects.equals(endorseId, endorserId)) { + log.info( + "Self endorsement not allowed, endorseId: {}, endorserId: {}", endorseId, endorserId); throw new SelfEndorsementNotAllowedException("Self endorsement not allowed"); } Optional skillDetails = skillRepository.findById(skillId); - Optional endorseDetails = userRepository.findById(endorseId); - Optional endorserDetails = userRepository.findById(endorserId); - - if (endorserDetails.isEmpty()) { - throw new UserNotFoundException("Cannot create endorsement for the current user"); - } - - if (endorseDetails.isEmpty()) { - throw new UserNotFoundException("Endorse not found"); - } if (skillDetails.isEmpty()) { - throw new SkillNotFoundException(String.format("Skill id: %s not found", skillId)); + log.info(String.format("Skill id: %s not found", skillId)); + throw new SkillNotFoundException("Skill does not exist"); } - List userSkillEntry = + // Get endorse(person being endorsed) & endorser(person endorsing) details from RDS + RdsGetUserDetailsResDto endorseDetails = rdsService.getUserDetails(endorseId); + RdsGetUserDetailsResDto endorserDetails = rdsService.getUserDetails(endorserId); + + List userSkillEntry = userSkillRepository.findByUserIdAndSkillId(endorseId, skillId); - Endorsement endorsement = new Endorsement(); - endorsement.setMessage(message); - endorsement.setSkill(skillDetails.get()); - endorsement.setEndorse(endorseDetails.get()); - endorsement.setEndorser(endorserDetails.get()); + Endorsement endorsement = + Endorsement.builder() + .skill(skillDetails.get()) + .message(message) + .endorseId(endorseId) + .endorserId(endorserId) + .build(); + // If a skill request is not created then create one + // This is because there is no specific api to create a skill request at the time of writing if (userSkillEntry.isEmpty()) { - UserSkillsModel userSkillsModel = new UserSkillsModel(); - userSkillsModel.setUser(endorseDetails.get()); - userSkillsModel.setSkill(skillDetails.get()); - userSkillsModel.setStatus(UserSkillStatusEnum.PENDING); + UserSkills userSkills = + UserSkills.builder().userId(endorseId).skill(skillDetails.get()).build(); - userSkillRepository.save(userSkillsModel); + userSkillRepository.save(userSkills); } Endorsement newEndorsement = endorsementRepository.save(endorsement); - return EndorsementViewModel.toViewModel(newEndorsement); + return EndorsementViewModel.toViewModel( + newEndorsement, + UserViewModel.toViewModel(endorseDetails.getUser()), + UserViewModel.toViewModel(endorserDetails.getUser())); } @Override @@ -94,8 +124,8 @@ public EndorsementViewModel update(Integer endorsementId, UpdateEndorsementViewM Optional exitingEndorsement = endorsementRepository.findById(endorsementId); if (exitingEndorsement.isEmpty()) { - throw new EndorsementNotFoundException( - String.format("Endorsement with id: %s not found", endorsementId)); + log.info(String.format("Endorsement with id: %s not found", endorsementId)); + throw new EndorsementNotFoundException("Endorsement not found"); } Endorsement endorsement = exitingEndorsement.get(); @@ -105,6 +135,15 @@ public EndorsementViewModel update(Integer endorsementId, UpdateEndorsementViewM endorsement.setMessage(updatedMessage); } - return EndorsementViewModel.toViewModel(endorsementRepository.save(endorsement)); + Endorsement savedEndorsementDetails = endorsementRepository.save(endorsement); + RdsGetUserDetailsResDto endorseDetails = + rdsService.getUserDetails(savedEndorsementDetails.getEndorseId()); + RdsGetUserDetailsResDto endorserDetails = + rdsService.getUserDetails(savedEndorsementDetails.getEndorserId()); + + return EndorsementViewModel.toViewModel( + savedEndorsementDetails, + UserViewModel.toViewModel(endorseDetails.getUser()), + UserViewModel.toViewModel(endorserDetails.getUser())); } } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/SkillService.java b/skill-tree/src/main/java/com/RDS/skilltree/services/SkillService.java index e456ade1..06439ee8 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/SkillService.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/SkillService.java @@ -1,6 +1,8 @@ package com.RDS.skilltree.services; import com.RDS.skilltree.dtos.SkillRequestsDto; +import com.RDS.skilltree.enums.UserSkillStatusEnum; +import com.RDS.skilltree.utils.GenericResponse; import com.RDS.skilltree.viewmodels.CreateSkillViewModel; import com.RDS.skilltree.viewmodels.SkillViewModel; import java.util.List; @@ -11,4 +13,7 @@ public interface SkillService { SkillViewModel create(CreateSkillViewModel skill); SkillRequestsDto getAllRequests(); + + GenericResponse approveRejectSkillRequest( + Integer skillId, String endorseId, UserSkillStatusEnum action); } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/SkillServiceImplementation.java b/skill-tree/src/main/java/com/RDS/skilltree/services/SkillServiceImplementation.java index 8fa7a904..ee900f5a 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/SkillServiceImplementation.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/SkillServiceImplementation.java @@ -1,22 +1,30 @@ package com.RDS.skilltree.services; -import com.RDS.skilltree.User.*; +import com.RDS.skilltree.dtos.RdsGetUserDetailsResDto; import com.RDS.skilltree.dtos.SkillRequestsDto; +import com.RDS.skilltree.enums.UserSkillStatusEnum; +import com.RDS.skilltree.exceptions.NoEntityException; import com.RDS.skilltree.exceptions.SkillAlreadyExistsException; -import com.RDS.skilltree.exceptions.UserNotFoundException; import com.RDS.skilltree.models.Endorsement; +import com.RDS.skilltree.models.JwtUser; import com.RDS.skilltree.models.Skill; +import com.RDS.skilltree.models.UserSkills; import com.RDS.skilltree.repositories.EndorsementRepository; import com.RDS.skilltree.repositories.SkillRepository; import com.RDS.skilltree.repositories.UserSkillRepository; import com.RDS.skilltree.services.external.RdsService; -import com.RDS.skilltree.viewmodels.*; +import com.RDS.skilltree.utils.GenericResponse; +import com.RDS.skilltree.viewmodels.CreateSkillViewModel; +import com.RDS.skilltree.viewmodels.SkillRequestViewModel; +import com.RDS.skilltree.viewmodels.SkillViewModel; +import com.RDS.skilltree.viewmodels.UserViewModel; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; @@ -24,9 +32,9 @@ @Service @RequiredArgsConstructor public class SkillServiceImplementation implements SkillService { + private static final Logger log = LoggerFactory.getLogger(SkillServiceImplementation.class); private final RdsService rdsService; private final SkillRepository skillRepository; - private final UserRepository userRepository; private final UserSkillRepository userSkillRepository; private final EndorsementRepository endorsementRepository; @@ -39,8 +47,7 @@ public List getAll() { @Override public SkillRequestsDto getAllRequests() { - List pendingSkills = - userSkillRepository.findByStatus(UserSkillStatusEnum.PENDING); + List pendingSkills = userSkillRepository.findByStatus(UserSkillStatusEnum.PENDING); // store all users data that are a part of this request Map userDetails = new HashMap<>(); @@ -51,16 +58,16 @@ public SkillRequestsDto getAllRequests() { .map( skill -> { Integer skillId = skill.getSkill().getId(); - String endorseId = skill.getUser().getId(); - String endorseRdsUserId = skill.getUser().getRdsUserId(); + + String endorseId = skill.getUserId(); // Get all endorsement for a specific skill and user Id List endorsements = endorsementRepository.findByEndorseIdAndSkillId(endorseId, skillId); if (!userDetails.containsKey(endorseId)) { - RdsUserViewModel endorseRdsDetails = - rdsService.getUserDetails(endorseRdsUserId); + RdsGetUserDetailsResDto endorseRdsDetails = + rdsService.getUserDetails(endorseId); UserViewModel endorseDetails = getUserModalFromRdsDetails(endorseId, endorseRdsDetails); userDetails.put(endorseId, endorseDetails); @@ -68,12 +75,11 @@ public SkillRequestsDto getAllRequests() { endorsements.forEach( endorsement -> { - String endorserId = endorsement.getEndorser().getId(); - String endorserRdsUserId = endorsement.getEndorser().getRdsUserId(); + String endorserId = endorsement.getEndorserId(); if (!userDetails.containsKey(endorserId)) { - RdsUserViewModel endorserRdsDetails = - rdsService.getUserDetails(endorserRdsUserId); + RdsGetUserDetailsResDto endorserRdsDetails = + rdsService.getUserDetails(endorserId); UserViewModel endorserDetails = getUserModalFromRdsDetails(endorserId, endorserRdsDetails); userDetails.put(endorserId, endorserDetails); @@ -87,19 +93,14 @@ public SkillRequestsDto getAllRequests() { return SkillRequestsDto.toDto(skillRequests, userDetails.values().stream().toList()); } - private static UserViewModel getUserModalFromRdsDetails(String id, RdsUserViewModel rdsDetails) { + private static UserViewModel getUserModalFromRdsDetails( + String id, RdsGetUserDetailsResDto rdsDetails) { String firstName = rdsDetails.getUser().getFirst_name() != null ? rdsDetails.getUser().getFirst_name() : ""; String lastName = rdsDetails.getUser().getLast_name() != null ? rdsDetails.getUser().getLast_name() : ""; - String username = firstName + ' ' + lastName; - - UserViewModel user = new UserViewModel(); - user.setId(id); - user.setName(username); - - return user; + return UserViewModel.builder().id(id).name(firstName + ' ' + lastName).build(); } @Override @@ -109,23 +110,35 @@ public SkillViewModel create(CreateSkillViewModel skill) { String.format("Skill with name %s already exists", skill.getName())); } - JwtUserModel jwtDetails = - (JwtUserModel) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + JwtUser jwtDetails = + (JwtUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - // TODO : user the userId from jwtDetails after the login api is implemented - String userId = "ae7a6673c5574140838f209de4c644fc"; - Optional user = userRepository.findById(userId); - - if (user.isEmpty()) { - throw new UserNotFoundException("unable to create skill for the current user"); - } + RdsGetUserDetailsResDto userDetails = rdsService.getUserDetails(jwtDetails.getRdsUserId()); Skill newSkill = toEntity(skill); - newSkill.setCreatedBy(user.get()); + newSkill.setCreatedBy(userDetails.getUser().getId()); return SkillViewModel.toViewModel(skillRepository.saveAndFlush(newSkill)); } + @Override + public GenericResponse approveRejectSkillRequest( + Integer skillId, String endorseId, UserSkillStatusEnum action) { + List existingSkillRequest = + userSkillRepository.findByUserIdAndSkillId(endorseId, skillId); + + if (existingSkillRequest.isEmpty()) { + log.info("Skill request not found! endorseId: {} and skillId: {}", endorseId, skillId); + throw new NoEntityException("Skill request not found"); + } + + UserSkills updatedSkillRequest = existingSkillRequest.get(0); + updatedSkillRequest.setStatus(action); + + userSkillRepository.save(updatedSkillRequest); + return new GenericResponse<>("Skill {}", action.toString().toLowerCase()); + } + private Skill toEntity(CreateSkillViewModel viewModel) { Skill entity = new Skill(); BeanUtils.copyProperties(viewModel, entity); diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsService.java b/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsService.java index 6166d00d..191b4eb0 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsService.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsService.java @@ -1,7 +1,7 @@ package com.RDS.skilltree.services.external; -import com.RDS.skilltree.viewmodels.RdsUserViewModel; +import com.RDS.skilltree.dtos.RdsGetUserDetailsResDto; public interface RdsService { - RdsUserViewModel getUserDetails(String id); + RdsGetUserDetailsResDto getUserDetails(String id); } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsServiceImplementation.java b/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsServiceImplementation.java index 7885ec9d..8bbb98db 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsServiceImplementation.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsServiceImplementation.java @@ -1,6 +1,7 @@ package com.RDS.skilltree.services.external; -import com.RDS.skilltree.viewmodels.RdsUserViewModel; +import com.RDS.skilltree.dtos.RdsGetUserDetailsResDto; +import com.RDS.skilltree.exceptions.UserNotFoundException; import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,14 +20,13 @@ public class RdsServiceImplementation implements RdsService { private String rdsBackendBaseUrl; @Override - public RdsUserViewModel getUserDetails(String id) { + public RdsGetUserDetailsResDto getUserDetails(String id) { String url = rdsBackendBaseUrl + "/users?id=" + id; - try { - return restTemplate.getForObject(url, RdsUserViewModel.class); + return restTemplate.getForObject(url, RdsGetUserDetailsResDto.class); } catch (RestClientException error) { - log.error("Error calling url: {}, Error : {}", url, error.getMessage()); - throw new RuntimeException("Failed to communicate with RDS backend"); + log.error("Error calling url {}, error: {}", url, error.getMessage()); + throw new UserNotFoundException("Error getting user details"); } } } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/utils/JWTAuthenticationFilter.java b/skill-tree/src/main/java/com/RDS/skilltree/utils/JWTAuthenticationFilter.java index 4d40a8a9..0e130899 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/utils/JWTAuthenticationFilter.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/utils/JWTAuthenticationFilter.java @@ -1,6 +1,7 @@ package com.RDS.skilltree.utils; import com.RDS.skilltree.Authentication.UserAuthenticationToken; +import com.RDS.skilltree.config.SecurityConfig; import io.jsonwebtoken.Claims; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -48,6 +49,12 @@ public void doFilterInternal( filterChain.doFilter(request, response); } + @Override + protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { + String path = request.getRequestURI(); + return SecurityConfig.NON_AUTH_ROUTES.stream().anyMatch(path::startsWith); + } + public String getJWTFromRequest(HttpServletRequest request) { /* check for cookie */ diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/AuthSuccessViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/AuthSuccessViewModel.java new file mode 100644 index 00000000..1d8a9ea2 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/AuthSuccessViewModel.java @@ -0,0 +1,12 @@ +package com.RDS.skilltree.viewmodels; + +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AuthSuccessViewModel { + @NotNull(message = "Message cannot be empty") + private String message; +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateEndorsementViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateEndorsementViewModel.java index 32b3670b..b68fd472 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateEndorsementViewModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateEndorsementViewModel.java @@ -1,18 +1,24 @@ package com.RDS.skilltree.viewmodels; -import jakarta.validation.constraints.NotNull; +import lombok.Builder; import lombok.Getter; import lombok.Setter; @Getter @Setter +@Builder public class CreateEndorsementViewModel { - @NotNull(message = "Message cannot be empty") + private Integer skillId; + private String endorseId; private String message; - @NotNull(message = "user id cannot be null") - private String endorseId; + public static CreateEndorsementViewModel toViewModel( + Integer skillId, String endorseId, String message) { - @NotNull(message = "skill id cannot be null") - private Integer skillId; + return CreateEndorsementViewModel.builder() + .skillId(skillId) + .endorseId(endorseId) + .message(message) + .build(); + } } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateSkillViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateSkillViewModel.java index 8cbba309..b02a96be 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateSkillViewModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateSkillViewModel.java @@ -1,6 +1,5 @@ package com.RDS.skilltree.viewmodels; -import com.RDS.skilltree.User.UserModel; import com.RDS.skilltree.enums.SkillTypeEnum; import jakarta.validation.constraints.NotNull; import lombok.Getter; @@ -15,5 +14,5 @@ public class CreateSkillViewModel { @NotNull(message = "SkillType cannot be empty") private SkillTypeEnum type; - private UserModel createdBy; + private String createdBy; } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/EndorsementViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/EndorsementViewModel.java index a4faad31..bfa7d1a9 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/EndorsementViewModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/EndorsementViewModel.java @@ -1,12 +1,13 @@ package com.RDS.skilltree.viewmodels; import com.RDS.skilltree.models.Endorsement; +import lombok.Builder; import lombok.Getter; import lombok.Setter; -import org.springframework.beans.BeanUtils; @Getter @Setter +@Builder public class EndorsementViewModel { private Integer id; private SkillViewModel skill; @@ -14,14 +15,15 @@ public class EndorsementViewModel { private UserViewModel endorser; private String message; - public static EndorsementViewModel toViewModel(Endorsement endorsement) { - EndorsementViewModel viewModel = new EndorsementViewModel(); - BeanUtils.copyProperties(endorsement, viewModel); + public static EndorsementViewModel toViewModel( + Endorsement endorsement, UserViewModel endorse, UserViewModel endorser) { - viewModel.setSkill(SkillViewModel.toViewModel(endorsement.getSkill())); - viewModel.setEndorser(UserViewModel.toViewModel(endorsement.getEndorser())); - viewModel.setEndorse(UserViewModel.toViewModel(endorsement.getEndorse())); - - return viewModel; + return EndorsementViewModel.builder() + .id(endorsement.getId()) + .skill(SkillViewModel.toViewModel((endorsement.getSkill()))) + .endorse(endorse) + .endorser(endorser) + .message(endorsement.getMessage()) + .build(); } } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/MinimalEndorsementViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/MinimalEndorsementViewModel.java index b6206e46..fb5b9b3a 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/MinimalEndorsementViewModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/MinimalEndorsementViewModel.java @@ -1,11 +1,11 @@ package com.RDS.skilltree.viewmodels; import com.RDS.skilltree.models.Endorsement; +import lombok.Builder; import lombok.Data; -import lombok.NoArgsConstructor; @Data -@NoArgsConstructor +@Builder public class MinimalEndorsementViewModel { private Integer id; private String endorserId; @@ -13,13 +13,11 @@ public class MinimalEndorsementViewModel { private String message; public static MinimalEndorsementViewModel toViewModel(Endorsement endorsement) { - MinimalEndorsementViewModel endorsementViewModel = new MinimalEndorsementViewModel(); - - endorsementViewModel.setId(endorsement.getId()); - endorsementViewModel.setMessage(endorsement.getMessage()); - endorsementViewModel.setEndorsementDate(endorsement.getCreatedAt().toString()); - endorsementViewModel.setEndorserId(endorsement.getEndorser().getId()); - - return endorsementViewModel; + return MinimalEndorsementViewModel.builder() + .id(endorsement.getId()) + .message(endorsement.getMessage()) + .endorserId(endorsement.getEndorserId()) + .endorsementDate(endorsement.getCreatedAt().toString()) + .build(); } } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/RdsUserViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/RdsUserViewModel.java index 76284c89..bc8f2b12 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/RdsUserViewModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/RdsUserViewModel.java @@ -6,38 +6,30 @@ @Getter @Setter public class RdsUserViewModel { - - private String message; - private User user; - - @Getter - @Setter - public static class User { - private String id; - private boolean incomplete_user_details; - private String discord_joined_at; - private String discord_id; - private Roles roles; - private String linkedin_id; - private Picture picture; - private float yoe; - private long github_created_at; - private String github_display_name; - private String github_id; - private String twitter_id; - private String username; - private String github_user_id; - private String first_name; - private String profile_url; - private String website; - private String last_name; - private String company; - private String designation; - private String instagram_id; - private String profile_status; - private long updated_at; - private long created_at; - } + private String id; + private boolean incomplete_user_details; + private String discord_joined_at; + private String discord_id; + private Roles roles; + private String linkedin_id; + private Picture picture; + private float yoe; + private long github_created_at; + private String github_display_name; + private String github_id; + private String twitter_id; + private String username; + private String github_user_id; + private String first_name; + private String profile_url; + private String website; + private String last_name; + private String company; + private String designation; + private String instagram_id; + private String profile_status; + private long updated_at; + private long created_at; @Getter @Setter diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/SkillRequestViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/SkillRequestViewModel.java index 48b433c1..87695b93 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/SkillRequestViewModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/SkillRequestViewModel.java @@ -1,9 +1,8 @@ package com.RDS.skilltree.viewmodels; -import com.RDS.skilltree.User.UserModel; -import com.RDS.skilltree.User.UserSkillsModel; import com.RDS.skilltree.models.Endorsement; import com.RDS.skilltree.models.Skill; +import com.RDS.skilltree.models.UserSkills; import java.util.List; import java.util.stream.Collectors; import lombok.Data; @@ -24,14 +23,14 @@ public SkillRequestViewModel( } public static SkillRequestViewModel toViewModel( - UserSkillsModel userSkillsModel, List endorsements) { - Skill skill = userSkillsModel.getSkill(); - UserModel user = userSkillsModel.getUser(); + UserSkills userSkills, List endorsements) { + Skill skill = userSkills.getSkill(); + String userId = userSkills.getUserId(); return new SkillRequestViewModel( skill.getId(), skill.getName(), - user.getId(), + userId, endorsements.stream() .map(MinimalEndorsementViewModel::toViewModel) .collect(Collectors.toList())); diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/UserViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/UserViewModel.java index d0f28ed3..254c9485 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/UserViewModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/UserViewModel.java @@ -1,23 +1,24 @@ package com.RDS.skilltree.viewmodels; -import com.RDS.skilltree.User.UserModel; +import lombok.Builder; import lombok.Getter; import lombok.Setter; -import org.springframework.beans.BeanUtils; @Getter @Setter +@Builder public class UserViewModel { private String id; private String name; - public static UserViewModel toViewModel(UserModel user) { + public static UserViewModel toViewModel(RdsUserViewModel user) { if (user == null) { return null; } - UserViewModel viewModel = new UserViewModel(); - BeanUtils.copyProperties(user, viewModel); - return viewModel; + return UserViewModel.builder() + .id(user.getId()) + .name(String.format("%s %s", user.getFirst_name(), user.getLast_name())) + .build(); } } diff --git a/skill-tree/src/main/resources/application.properties b/skill-tree/src/main/resources/application.properties index 13e2719b..0cc32ef1 100644 --- a/skill-tree/src/main/resources/application.properties +++ b/skill-tree/src/main/resources/application.properties @@ -11,4 +11,6 @@ management.endpoints.web.exposure.include=health,info,metrics logging.level.root=ERROR # If no value received from env default is dev spring.profiles.active=${SPRING_PROFILES_ACTIVE:dev} -rds.backendBaseUrl=${RDS_BACKEND_BASE_URL} \ No newline at end of file +rds.backendBaseUrl=${RDS_BACKEND_BASE_URL} +skilltree.frontendBaseUrl=${SKILL_TREE_FRONTEND_BASE_URL} +skilltree.backendBaseUrl=${SKILL_TREE_BACKEND_BASE_URL}