Skip to content

Commit

Permalink
Merge branch 'develop' into chore/add-tests-update-endorsement-status
Browse files Browse the repository at this point in the history
  • Loading branch information
Atifsid committed May 4, 2024
2 parents 3fec279 + 88fe526 commit 9b327e1
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
auth ->
auth.requestMatchers("/v1/health")
.permitAll()
.requestMatchers(
request ->
request.getQueryString() != null
&& request.getQueryString().contains("dummyData=true"))
.permitAll()
.requestMatchers(HttpMethod.GET, "/v1/**")
.hasAnyAuthority(UserRole.getAllRoles()) // give read-only access to all
.requestMatchers("/v1/**")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.RDS.skilltree.Config;

import com.RDS.skilltree.utils.UUIDValidationInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private final UUIDValidationInterceptor uuidValidationInterceptor;

@Autowired
public WebMvcConfig(UUIDValidationInterceptor uuidValidationInterceptor) {
this.uuidValidationInterceptor = uuidValidationInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(uuidValidationInterceptor).addPathPatterns("/v1/endorsements");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.persistence.EntityNotFoundException;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import java.io.IOException;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -22,11 +23,25 @@ public class EndorsementController {
private final EndorsementService endorsementService;

@GetMapping(value = "")
public Page<EndorsementModel> getAllEndorsements(
public ResponseEntity<Page<?>> getAllEndorsements(
@RequestParam(name = "offset", defaultValue = "0", required = false) @Min(0) int offset,
@RequestParam(name = "limit", defaultValue = "10", required = false) @Min(1) int limit) {
@RequestParam(name = "limit", defaultValue = "10", required = false) @Min(1) int limit,
@RequestParam(name = "skillID", required = false) String skillID,
@RequestParam(name = "userID", required = false) String userID,
@RequestParam(name = "dummyData", required = false) boolean dummyData)
throws IOException {
PageRequest pageRequest = PageRequest.of(offset, limit);
return endorsementService.getEndorsements(pageRequest);
if (dummyData) {
Page<EndorsementModelFromJSON> pagedEndorsements =
endorsementService.getEndorsementsFromDummyData(pageRequest, skillID, userID);
if (pagedEndorsements.isEmpty()) {
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.ok(pagedEndorsements);
}
} else {
return ResponseEntity.ok(endorsementService.getEndorsements(pageRequest));
}
}

@GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@
import com.RDS.skilltree.Skill.SkillRepository;
import com.RDS.skilltree.User.UserModel;
import com.RDS.skilltree.User.UserRepository;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.EntityNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

Expand All @@ -22,6 +31,13 @@ public class EndorsementServiceImpl implements EndorsementService {
private final UserRepository userRepository;
private final SkillRepository skillRepository;

private final ObjectMapper objectMapper;

@Value("${endorsements.dummmy-data.path}")
private String dummyEndorsementDataPath;

private static final Logger logger = LoggerFactory.getLogger(EndorsementServiceImpl.class);

@Override
public EndorsementDTO getEndorsementById(UUID id) throws IllegalStateException {
Optional<EndorsementModel> endorsementModel = endorsementRepository.findById(id);
Expand All @@ -35,12 +51,65 @@ public Page<EndorsementModel> getEndorsements(PageRequest pageRequest) {
return endorsementRepository.findAll(pageRequest);
}

/* TODO:Dummy JSON code, needs to be changed as part of #103 */
@Override
public Page<EndorsementModelFromJSON> getEndorsementsFromDummyData(
PageRequest pageRequest, String skillID, String userID) throws IOException {

// TODO: temporary stub, implement in followup PR
return null;
try {
List<EndorsementModelFromJSON> endorsementModelFromJSONList = readEndorsementsFromJSON();

if (endorsementModelFromJSONList.isEmpty()) {
return Page.empty(pageRequest);
}

List<EndorsementModelFromJSON> filteredEndorsements =
filterEndorsements(endorsementModelFromJSONList, skillID, userID);
return createPagedEndorsements(filteredEndorsements, pageRequest);
} catch (IOException e) {
logger.error("Error reading endorsements JSON data: {}", e.getMessage());
throw new IOException("Error reading endorsements JSON data", e);
}
}

private List<EndorsementModelFromJSON> readEndorsementsFromJSON() throws IOException {
ClassPathResource resource = new ClassPathResource(dummyEndorsementDataPath);
return objectMapper.readValue(
resource.getInputStream(), new TypeReference<List<EndorsementModelFromJSON>>() {});
}

private List<EndorsementModelFromJSON> filterEndorsements(
List<EndorsementModelFromJSON> endorsements, String skillID, String userID) {
return endorsements.stream()
.filter(endorsement -> isMatchingSkillId(endorsement, skillID))
.filter(endorsement -> isMatchingUserId(endorsement, userID))
.collect(Collectors.toList());
}

private boolean isMatchingSkillId(EndorsementModelFromJSON endorsement, String skillID) {
return skillID == null
|| skillID.isEmpty()
|| endorsement.getSkillId().equals(UUID.fromString(skillID));
}

private boolean isMatchingUserId(EndorsementModelFromJSON endorsement, String userID) {
return userID == null
|| userID.isEmpty()
|| endorsement.getUserID().equals(UUID.fromString(userID));
}

private Page<EndorsementModelFromJSON> createPagedEndorsements(
List<EndorsementModelFromJSON> endorsements, PageRequest pageRequest) {
int startIdx = (int) pageRequest.getOffset();
int totalEndorsements = endorsements.size();

if (startIdx >= totalEndorsements) {
return Page.empty(pageRequest);
}

int endIdx = Math.min(startIdx + pageRequest.getPageSize(), endorsements.size());
List<EndorsementModelFromJSON> currentPageEndorsements = endorsements.subList(startIdx, endIdx);
return new PageImpl<>(currentPageEndorsements, pageRequest, endorsements.size());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.RDS.skilltree.Common.Response.GenericResponse;
import com.RDS.skilltree.Exceptions.EntityAlreadyExistsException;
import com.RDS.skilltree.Exceptions.InvalidParameterException;
import com.RDS.skilltree.Exceptions.NoEntityException;
import jakarta.validation.ConstraintViolationException;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.websocket.AuthenticationException;
Expand Down Expand Up @@ -80,10 +82,16 @@ public ResponseEntity<GenericResponse<Object>> handleException(Exception ex) {
.body(new GenericResponse<>(null, "Something unexpected happened, please try again."));
}

@ExceptionHandler({IllegalArgumentException.class})
public ResponseEntity<GenericResponse<Object>> handleIllegalArgumentException(
IllegalArgumentException ex) {
log.error("IllegalArgumentException - Error : {}", ex.getMessage(), ex);
@ExceptionHandler({InvalidParameterException.class})
public ResponseEntity<GenericResponse<Object>> handleException(InvalidParameterException ex) {
log.error("Exception - Error : {}", ex.getMessage(), ex);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new GenericResponse<>(null, ex.getMessage()));
}

@ExceptionHandler({ConstraintViolationException.class})
public ResponseEntity<GenericResponse<Object>> handleException(ConstraintViolationException ex) {
log.error("Exception - Error : {}", ex.getMessage(), ex);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new GenericResponse<>(null, ex.getMessage()));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
package com.RDS.skilltree.utils;

import com.RDS.skilltree.Exceptions.InvalidParameterException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class UUIDValidationInterceptor implements HandlerInterceptor {

private static final Logger logger = LoggerFactory.getLogger(UUIDValidationInterceptor.class);
private static final Pattern UUID_REGEX =
Pattern.compile(
"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");

@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) {
// Add logic during implementation
String skillID = request.getParameter("skillID");
String userID = request.getParameter("userID");

if (skillID != null && !skillID.isEmpty() && !isValidUUID(skillID)) {
throw new InvalidParameterException("skillID", "Invalid UUID format");
}

if (userID != null && !userID.isEmpty() && !isValidUUID(userID)) {
throw new InvalidParameterException("userID", "Invalid UUID format");
}

return true;
}

private boolean isValidUUID(String uuidString) {

return UUID_REGEX.matcher(uuidString).matches();
}
}
2 changes: 2 additions & 0 deletions skill-tree/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ 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}
# TODO:Dummy JSON code, needs to be changed as part of #103
endorsements.dummmy-data.path=dummy-data/endorsements.json
Loading

0 comments on commit 9b327e1

Please sign in to comment.