From 0d9e2d8974943b5931d2a5cba6d170d70577e699 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Thu, 23 Nov 2023 05:53:51 +0530 Subject: [PATCH 01/12] Adds Get Endorsement End Point Controller Model changes --- .../skilltree/Endorsement/ApiResponse.java | 7 +++ .../Endorsement/EndorsementController.java | 43 +++++++++++++++++ .../skilltree/Endorsement/EndorsementDTO.java | 39 ++++++++++++++++ .../Endorsement/EndorsementModel.java | 6 +-- .../Endorsement/EndorsementService.java | 9 ++++ .../Endorsement/EndorsementServiceImpl.java | 46 +++++++++++++++++++ 6 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java create mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java create mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java create mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementService.java create mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java new file mode 100644 index 00000000..fbe8a212 --- /dev/null +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java @@ -0,0 +1,7 @@ +package com.RDS.skilltree.Endorsement; + +import java.util.Map; + +public record ApiResponse(Map data, int statusCode, String status, String message) { + +} diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java new file mode 100644 index 00000000..0a4e45af --- /dev/null +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java @@ -0,0 +1,43 @@ +package com.RDS.skilltree.Endorsement; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import java.util.Map; +import java.util.UUID; + +@RestController +@RequestMapping("/v1/endorsements") + +public class EndorsementController { + private final EndorsementService endorsementService; + + public EndorsementController(EndorsementService endorsementService) { + this.endorsementService = endorsementService; + } + + @GetMapping("/{id}") + public ResponseEntity getEndorsementById(@PathVariable(value = "id", required = true) String id){ + try { + UUID uuid = UUID.fromString(id); + String message = "Data found successfully"; + Map responseData = endorsementService.getEndorsementAsMap(uuid); + ApiResponse response = new ApiResponse(responseData, HttpStatus.OK.value(),HttpStatus.OK.toString(),message); + return ResponseEntity.ok(response); + } catch (IllegalArgumentException e) { + String message = "Invalid UUID: " + id; + ApiResponse response = new ApiResponse(null, HttpStatus.BAD_REQUEST.value(),HttpStatus.BAD_REQUEST.toString(),message); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } catch (IllegalStateException e) { + String message = e.getMessage(); + ApiResponse response = new ApiResponse(null, HttpStatus.NOT_FOUND.value(),HttpStatus.NOT_FOUND.toString(),message); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + } + } +} + diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java new file mode 100644 index 00000000..72d0cbc2 --- /dev/null +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java @@ -0,0 +1,39 @@ +package com.RDS.skilltree.Endorsement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EndorsementDTO { + private UUID id; + private UUID user; + private UUID skill; + private EndorsementStatus status; + private Instant createdAt; + private Instant updatedAt; + private UUID createdBy; + private UUID updatedBy; + + public static EndorsementDTO toDto(EndorsementModel endorsementModel) { + return EndorsementDTO.builder() + .id(endorsementModel.getId()) + .user(endorsementModel.getUser().getId()) + .skill(endorsementModel.getSkill().getId()) + .status(endorsementModel.getStatus()) + .createdAt(endorsementModel.getCreatedAt()) + .createdBy(endorsementModel.getCreatedBy().getId()) + .updatedAt(endorsementModel.getUpdatedAt()) + .updatedBy(endorsementModel.getUpdatedBy().getId()) + .build(); + } +} diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementModel.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementModel.java index 3668032a..d38a3d6e 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementModel.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementModel.java @@ -4,15 +4,15 @@ import com.RDS.skilltree.User.UserModel; import com.RDS.skilltree.utils.TrackedProperties; import jakarta.persistence.*; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; +import lombok.*; import java.time.Instant; import java.util.UUID; @EqualsAndHashCode(callSuper = true) @Entity +@Builder +@AllArgsConstructor @NoArgsConstructor @Data @Table(name = "endorsements") diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementService.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementService.java new file mode 100644 index 00000000..ff56e374 --- /dev/null +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementService.java @@ -0,0 +1,9 @@ +package com.RDS.skilltree.Endorsement; + +import java.util.Map; +import java.util.UUID; + +public interface EndorsementService { + EndorsementDTO getEndorsementById(UUID id); + Map getEndorsementAsMap(UUID uuid); +} diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java new file mode 100644 index 00000000..fa889517 --- /dev/null +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java @@ -0,0 +1,46 @@ +package com.RDS.skilltree.Endorsement; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +@Service +public class EndorsementServiceImpl implements EndorsementService { + private final EndorsementRepository endorsementRepository; + + public EndorsementServiceImpl(EndorsementRepository endorsementRepository) { + this.endorsementRepository = endorsementRepository; + } + + @Override + public EndorsementDTO getEndorsementById(UUID id) throws IllegalStateException { + Optional endorsementModel = endorsementRepository.findById(id); + + if (endorsementModel.isPresent()) { + return EndorsementDTO.toDto(endorsementModel.get()); + } else { + String errorMessage = "No endorsement with the id " + id + " found"; + throw new IllegalStateException(errorMessage); + } + } + + public Map getEndorsementAsMap(UUID uuid) { + EndorsementDTO endorsementDTO = getEndorsementById(uuid); + + Map endorsementMap = new HashMap<>(); + endorsementMap.put("id", endorsementDTO.getId()); + endorsementMap.put("user", endorsementDTO.getUser()); + endorsementMap.put("skill", endorsementDTO.getSkill()); + endorsementMap.put("status", endorsementDTO.getStatus()); + endorsementMap.put("createdAt", endorsementDTO.getCreatedAt()); + endorsementMap.put("updatedAt", endorsementDTO.getUpdatedAt()); + endorsementMap.put("createdBy", endorsementDTO.getCreatedBy()); + endorsementMap.put("updatedBy", endorsementDTO.getUpdatedBy()); + + return endorsementMap; + } +} From 232d06210bdd6de73e934675a0f0f70ccb933589 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:02:54 +0530 Subject: [PATCH 02/12] Use JSON API Specs format to convert data --- .../Endorsement/EndorsementController.java | 15 +- .../skilltree/Endorsement/EndorsementDTO.java | 35 ++-- .../Endorsement/EndorsementModel.java | 17 +- .../Endorsement/EndorsementService.java | 5 +- .../Endorsement/EndorsementServiceImpl.java | 28 +-- .../Endorsement/JsonApiResponseConverter.java | 164 ++++++++++++++++++ .../EndorsementList/EndorsementListModel.java | 6 +- .../Endorsement/EndorsementServiceTest.java | 73 ++++++++ 8 files changed, 278 insertions(+), 65 deletions(-) create mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java create mode 100644 skill-tree /src/test/java/com/RDS/skilltree/Endorsement/EndorsementServiceTest.java diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java index 0a4e45af..eadcc2ba 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java @@ -1,19 +1,21 @@ package com.RDS.skilltree.Endorsement; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; import java.util.Map; import java.util.UUID; +import static com.RDS.skilltree.Endorsement.JsonApiResponseConverter.convertToHashMap; + @RestController @RequestMapping("/v1/endorsements") - +@Slf4j public class EndorsementController { private final EndorsementService endorsementService; @@ -25,10 +27,10 @@ public EndorsementController(EndorsementService endorsementService) { public ResponseEntity getEndorsementById(@PathVariable(value = "id", required = true) String id){ try { UUID uuid = UUID.fromString(id); - String message = "Data found successfully"; - Map responseData = endorsementService.getEndorsementAsMap(uuid); - ApiResponse response = new ApiResponse(responseData, HttpStatus.OK.value(),HttpStatus.OK.toString(),message); - return ResponseEntity.ok(response); + EndorsementDTO response = endorsementService.getEndorsementById(uuid); + Map responseData = convertToHashMap(response); + return ResponseEntity.ok(responseData); + } catch (IllegalArgumentException e) { String message = "Invalid UUID: " + id; ApiResponse response = new ApiResponse(null, HttpStatus.BAD_REQUEST.value(),HttpStatus.BAD_REQUEST.toString(),message); @@ -40,4 +42,3 @@ public ResponseEntity getEndorsementById(@PathVariable(value = "id", required } } } - diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java index 72d0cbc2..fdaf9ee4 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java @@ -1,39 +1,42 @@ package com.RDS.skilltree.Endorsement; +import com.RDS.skilltree.EndorsementList.EndorsementListModel; +import com.RDS.skilltree.Skill.SkillModel; +import com.RDS.skilltree.User.UserModel; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.*; import java.time.Instant; +import java.util.List; import java.util.UUID; -@Data -@NoArgsConstructor -@AllArgsConstructor +@Getter @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) public class EndorsementDTO { private UUID id; - private UUID user; - private UUID skill; + private UserModel user; + private SkillModel skill; private EndorsementStatus status; private Instant createdAt; private Instant updatedAt; - private UUID createdBy; - private UUID updatedBy; + private UserModel createdBy; + private UserModel updatedBy; + private List endorsersList; public static EndorsementDTO toDto(EndorsementModel endorsementModel) { return EndorsementDTO.builder() .id(endorsementModel.getId()) - .user(endorsementModel.getUser().getId()) - .skill(endorsementModel.getSkill().getId()) + .user(endorsementModel.getUser()) + .skill(endorsementModel.getSkill()) .status(endorsementModel.getStatus()) .createdAt(endorsementModel.getCreatedAt()) - .createdBy(endorsementModel.getCreatedBy().getId()) + .createdBy(endorsementModel.getCreatedBy()) .updatedAt(endorsementModel.getUpdatedAt()) - .updatedBy(endorsementModel.getUpdatedBy().getId()) + .updatedBy(endorsementModel.getUpdatedBy()) + .endorsersList(endorsementModel.getEndorsersList()) .build(); } -} +} \ No newline at end of file diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementModel.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementModel.java index d631bd88..a2cf58db 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementModel.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementModel.java @@ -4,6 +4,7 @@ import com.RDS.skilltree.Skill.SkillModel; import com.RDS.skilltree.User.UserModel; import com.RDS.skilltree.utils.TrackedProperties; +import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.*; import lombok.*; @@ -11,12 +12,11 @@ import java.util.List; import java.util.UUID; -@EqualsAndHashCode(callSuper = true) -@Entity -@Builder @AllArgsConstructor @NoArgsConstructor -@Data +@Entity +@Builder +@Getter @Table(name = "endorsements") public class EndorsementModel extends TrackedProperties { @Id @@ -33,15 +33,10 @@ public class EndorsementModel extends TrackedProperties { private SkillModel skill; @OneToMany(mappedBy = "endorsement") + @JsonManagedReference private List endorsersList = new ArrayList<>(); @Column(name = "endorsement_status") @Enumerated(value = EnumType.STRING) private EndorsementStatus status = EndorsementStatus.PENDING; - - public EndorsementModel(UserModel user, SkillModel skill) { - this.status = EndorsementStatus.PENDING; - this.user = user; - this.skill = skill; - } -} +} \ No newline at end of file diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementService.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementService.java index ff56e374..a2848fd8 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementService.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementService.java @@ -1,9 +1,6 @@ package com.RDS.skilltree.Endorsement; - -import java.util.Map; import java.util.UUID; public interface EndorsementService { EndorsementDTO getEndorsementById(UUID id); - Map getEndorsementAsMap(UUID uuid); -} +} \ No newline at end of file diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java index fa889517..1f2db4d1 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java @@ -1,13 +1,8 @@ package com.RDS.skilltree.Endorsement; - -import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; -import org.springframework.web.server.ResponseStatusException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; +import java.util.*; + @Service public class EndorsementServiceImpl implements EndorsementService { private final EndorsementRepository endorsementRepository; @@ -19,7 +14,6 @@ public EndorsementServiceImpl(EndorsementRepository endorsementRepository) { @Override public EndorsementDTO getEndorsementById(UUID id) throws IllegalStateException { Optional endorsementModel = endorsementRepository.findById(id); - if (endorsementModel.isPresent()) { return EndorsementDTO.toDto(endorsementModel.get()); } else { @@ -27,20 +21,4 @@ public EndorsementDTO getEndorsementById(UUID id) throws IllegalStateException { throw new IllegalStateException(errorMessage); } } - - public Map getEndorsementAsMap(UUID uuid) { - EndorsementDTO endorsementDTO = getEndorsementById(uuid); - - Map endorsementMap = new HashMap<>(); - endorsementMap.put("id", endorsementDTO.getId()); - endorsementMap.put("user", endorsementDTO.getUser()); - endorsementMap.put("skill", endorsementDTO.getSkill()); - endorsementMap.put("status", endorsementDTO.getStatus()); - endorsementMap.put("createdAt", endorsementDTO.getCreatedAt()); - endorsementMap.put("updatedAt", endorsementDTO.getUpdatedAt()); - endorsementMap.put("createdBy", endorsementDTO.getCreatedBy()); - endorsementMap.put("updatedBy", endorsementDTO.getUpdatedBy()); - - return endorsementMap; - } -} +} \ No newline at end of file diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java new file mode 100644 index 00000000..e8c09fdd --- /dev/null +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java @@ -0,0 +1,164 @@ +package com.RDS.skilltree.Endorsement; + +import com.RDS.skilltree.EndorsementList.EndorsementListModel; +import com.RDS.skilltree.Skill.SkillModel; +import com.RDS.skilltree.User.UserModel; + +import java.lang.reflect.Field; +import java.util.*; + +public class JsonApiResponseConverter { + + public static Map convertToHashMap(EndorsementDTO endorsementDTO) { + Map result = new HashMap<>(); + result.put("id", endorsementDTO.getId()); + result.put("type", "endorsement"); + result.put("links", createLinksMap(endorsementDTO.getId().toString())); + result.put("attributes", createAttributesHashMap(endorsementDTO)); + result.put("relationships",createRelationshipsHashMap(endorsementDTO)); + result.put("included",createIncludedList(endorsementDTO)); + + return result; + } + + private static Map createLinksMap(String id) { + Map links = new HashMap<>(); + links.put("self", "/endorsements/" + id); + return links; + } + + private static Map createAttributesHashMap(EndorsementDTO endorsementDTO) { + Map attributes = new HashMap<>(); + attributes.put("status", endorsementDTO.getStatus()); + attributes.put("createdAt", endorsementDTO.getCreatedAt()); + attributes.put("updatedAt", endorsementDTO.getUpdatedAt()); + return attributes; + } + + private static Map createRelationshipsHashMap(EndorsementDTO endorsementDTO) { + Map relationships = new HashMap<>(); + + Map userRelationship = getIdHashmap(endorsementDTO.getUser(),"user"); + relationships.put("user", userRelationship); + + + Map skillRelationship = getIdHashmap(endorsementDTO.getSkill(),"skill"); + relationships.put("skill", skillRelationship); + + Map createdBy = getIdHashmap(endorsementDTO.getCreatedBy(),"user"); + relationships.put("createdBy", createdBy); + + Map updatedBy = getIdHashmap(endorsementDTO.getUpdatedBy(),"user"); + relationships.put("updatedBy", updatedBy); + + List> endorsersList = new ArrayList<>(); + for (EndorsementListModel endorserListModel : endorsementDTO.getEndorsersList()) { + Map data = new HashMap<>(); + data.put("id",endorserListModel.getId()); + data.put("type","endorser"); + endorsersList.add(data); + } + + Map endorseRelationships = new HashMap<>(); + endorseRelationships.put("data",endorsersList); + relationships.put("endorsersList",endorseRelationships); + + return relationships; + } + + private static List> createIncludedList(EndorsementDTO endorsementDTO) { + List> includedList = new ArrayList<>(); + includedList.add(extractSkillsAttributes(endorsementDTO.getSkill())); + includedList.add(extractUsersAttributes(endorsementDTO.getUser())); + for (EndorsementListModel endorserListModel : endorsementDTO.getEndorsersList()) { + includedList.add(extractEndorsementListModelAttributes(endorserListModel)); + } + return includedList; + } + private static Map extractEndorsementListModelAttributes(EndorsementListModel endorsementListModel) { + Map result = new HashMap<>(); + + Map attributes = new HashMap<>(); + attributes.put("type",endorsementListModel.getType()); + attributes.put("deleted",endorsementListModel.isDeleted()); + attributes.put("description",endorsementListModel.getDescription()); + attributes.put("createdAt",endorsementListModel.getCreatedAt()); + attributes.put("updatedAt",endorsementListModel.getUpdatedAt()); + + Map relationships = new HashMap<>(); + relationships.put("endorsersList",getIdHashmap(endorsementListModel.getEndorser(),"user")); + relationships.put("createdBy",getIdHashmap(endorsementListModel.getCreatedBy(),"user")); + relationships.put("updatedBy",getIdHashmap(endorsementListModel.getUpdatedBy(),"user")); + + result.put("id",endorsementListModel.getId()); + result.put("type","EndorsementList"); + result.put("attributes",attributes); + result.put("relationships",relationships); + return result; + } + private static Map extractSkillsAttributes(SkillModel skillModel) { + Map result = new HashMap<>(); + + Map attributes = new HashMap<>(); + attributes.put("name",skillModel.getName()); + attributes.put("type",skillModel.getType()); + attributes.put("createdAt",skillModel.getCreatedAt()); + attributes.put("updatedAt",skillModel.getUpdatedAt()); + attributes.put("isDeleted",skillModel.isDeleted()); + + Map relationships = new HashMap<>(); + relationships.put("createdBy",getIdHashmap(skillModel.getCreatedBy(),"user")); + relationships.put("updatedBy",getIdHashmap(skillModel.getUpdatedBy(),"user")); + + result.put("id",skillModel.getId()); + result.put("type","skill"); + result.put("attributes",attributes); + result.put("relationships",relationships); + + return result; + } + private static Map extractUsersAttributes(UserModel userModel) { + Map result = new HashMap<>(); + + Map attributes = new HashMap<>(); + attributes.put("firstName",userModel.getFirstName()); + attributes.put("lastName",userModel.getLastName()); + attributes.put("rdsUserId",userModel.getRdsUserId()); + attributes.put("role",userModel.getRole()); + attributes.put("imageUrl",userModel.getImageUrl()); + attributes.put("createdAt",userModel.getCreatedAt()); + attributes.put("updatedAt",userModel.getUpdatedAt()); + + Map relationships = new HashMap<>(); + relationships.put("createdBy",getIdHashmap(userModel.getCreatedBy(),"user")); + relationships.put("updatedBy",getIdHashmap(userModel.getUpdatedBy(),"user")); + result.put("id",userModel.getId()); + result.put("type","user"); + result.put("attributes",attributes); + result.put("relationships",relationships); + return result; + } + private static Map getIdHashmap(Object dto, String type) { + Map relationship = new HashMap<>(); + Map data = new HashMap<>(); + try { + if (dto == null) { + data.put("type", type); + data.put("id", null); + } else { + Field idField = dto.getClass().getDeclaredField("id"); + idField.setAccessible(true); + Object id = idField.get(dto); + + data.put("type", type); + data.put("id", id); + + } + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + relationship.put("data", data); + return relationship; + } + +} \ No newline at end of file diff --git a/skill-tree /src/main/java/com/RDS/skilltree/EndorsementList/EndorsementListModel.java b/skill-tree /src/main/java/com/RDS/skilltree/EndorsementList/EndorsementListModel.java index fdf3aa48..837b3b00 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/EndorsementList/EndorsementListModel.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/EndorsementList/EndorsementListModel.java @@ -3,6 +3,7 @@ import com.RDS.skilltree.Endorsement.EndorsementModel; import com.RDS.skilltree.User.UserModel; import com.RDS.skilltree.utils.TrackedProperties; +import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.*; import lombok.Data; import lombok.EqualsAndHashCode; @@ -23,6 +24,7 @@ public class EndorsementListModel extends TrackedProperties { @JoinColumn(name = "endorsement_id", referencedColumnName = "id") @ManyToOne(targetEntity = EndorsementModel.class, cascade = CascadeType.ALL) + @JsonBackReference private EndorsementModel endorsement; @JoinColumn(name = "user_id", referencedColumnName = "id") @@ -40,11 +42,11 @@ public class EndorsementListModel extends TrackedProperties { private EndorsementType type; public EndorsementListModel(EndorsementModel endorsement, UserModel endorser, String description, - EndorsementType type) { + EndorsementType type) { this.endorsement = endorsement; this.endorser = endorser; this.description = description; this.type = type; this.deleted = false; } -} +} \ No newline at end of file diff --git a/skill-tree /src/test/java/com/RDS/skilltree/Endorsement/EndorsementServiceTest.java b/skill-tree /src/test/java/com/RDS/skilltree/Endorsement/EndorsementServiceTest.java new file mode 100644 index 00000000..60d02dd6 --- /dev/null +++ b/skill-tree /src/test/java/com/RDS/skilltree/Endorsement/EndorsementServiceTest.java @@ -0,0 +1,73 @@ +package com.RDS.skilltree.Endorsement; + +import com.RDS.skilltree.Skill.SkillModel; +import com.RDS.skilltree.User.UserModel; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + + +import java.time.Instant; +import java.util.Optional; +import java.util.UUID; + +@RunWith(MockitoJUnitRunner.class) +public class EndorsementServiceTest { + @Mock + private EndorsementRepository endorsementRepository; + + @InjectMocks + @Autowired + private EndorsementServiceImpl underTest; + + @Test + public void itShouldGetEndorsementsById() { + UUID endorsementId = UUID.randomUUID(); + UUID userId = UUID.randomUUID(); + UUID skillId = UUID.randomUUID(); + + UserModel userModel = new UserModel(); + userModel.setId(userId); + SkillModel skillModel = new SkillModel(); + skillModel.setId(skillId); + EndorsementModel endorsementModel = EndorsementModel.builder() + .id(endorsementId) + .user(userModel) + .skill(skillModel) + .build(); + endorsementModel.setCreatedAt(Instant.now()); + endorsementModel.setUpdatedAt(Instant.now()); + endorsementModel.setCreatedBy(userModel); + endorsementModel.setUpdatedBy(userModel); + + // Given + when(endorsementRepository.findById(endorsementId)).thenReturn(Optional.of(endorsementModel)); + + // When + EndorsementDTO result = underTest.getEndorsementById(endorsementId); + + // Then + assertNotNull(result); + assertEquals("The Endorsement Id doesn't matches the expected endorsement Id", endorsementId, result.getId()); + } + + @Test + public void itShouldHandleEndorsementNotFound() { + // Given + UUID nonExistentEndorsementId = UUID.randomUUID(); + when(endorsementRepository.findById(nonExistentEndorsementId)).thenReturn(Optional.empty()); + + // When , Then + assertThatThrownBy(() -> underTest.getEndorsementById(nonExistentEndorsementId)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("No endorsement with the id " + nonExistentEndorsementId + " found"); + } + +} \ No newline at end of file From 5680e235479aced7cad73f479c92e4fcaadc1a78 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Sat, 2 Dec 2023 07:08:48 +0530 Subject: [PATCH 03/12] remove JsonInclude annotation that wasn't being used --- .../main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java | 1 - 1 file changed, 1 deletion(-) diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java index fdaf9ee4..695b3949 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java @@ -14,7 +14,6 @@ @Getter @Builder @JsonIgnoreProperties(ignoreUnknown = true) -@JsonInclude(JsonInclude.Include.NON_NULL) public class EndorsementDTO { private UUID id; private UserModel user; From 11717e2969f03582d163b6bc417a4c3f7f408305 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Sat, 2 Dec 2023 07:18:28 +0530 Subject: [PATCH 04/12] Refactor: Update map structure in convertToHashMap method --- .../Endorsement/JsonApiResponseConverter.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java index e8c09fdd..14f31588 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java @@ -11,13 +11,15 @@ public class JsonApiResponseConverter { public static Map convertToHashMap(EndorsementDTO endorsementDTO) { Map result = new HashMap<>(); - result.put("id", endorsementDTO.getId()); - result.put("type", "endorsement"); - result.put("links", createLinksMap(endorsementDTO.getId().toString())); - result.put("attributes", createAttributesHashMap(endorsementDTO)); - result.put("relationships",createRelationshipsHashMap(endorsementDTO)); - result.put("included",createIncludedList(endorsementDTO)); - + Map dataMap = new HashMap<>(); + + dataMap.put("id", endorsementDTO.getId()); + dataMap.put("type", "endorsement"); + dataMap.put("links", createLinksMap(endorsementDTO.getId().toString())); + dataMap.put("attributes", createAttributesHashMap(endorsementDTO)); + dataMap.put("relationships",createRelationshipsHashMap(endorsementDTO)); + dataMap.put("included",createIncludedList(endorsementDTO)); + result.put("data", dataMap); return result; } From 4e0a2585fb1b651624e93b1b19c7fae1ecdc69f4 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:21:13 +0530 Subject: [PATCH 05/12] Refactor: Resolve comments by Ajey Krishna --- .../skilltree/Endorsement/ApiResponse.java | 2 +- .../Endorsement/EndorsementController.java | 8 ++++++-- .../skilltree/Endorsement/EndorsementDTO.java | 19 ++++++++----------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java index fbe8a212..9a82c66d 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java @@ -2,6 +2,6 @@ import java.util.Map; -public record ApiResponse(Map data, int statusCode, String status, String message) { +public record ApiResponse(T data, int statusCode, String status, String message) { } diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java index eadcc2ba..8b15d712 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java @@ -33,12 +33,16 @@ public ResponseEntity getEndorsementById(@PathVariable(value = "id", required } catch (IllegalArgumentException e) { String message = "Invalid UUID: " + id; - ApiResponse response = new ApiResponse(null, HttpStatus.BAD_REQUEST.value(),HttpStatus.BAD_REQUEST.toString(),message); + ApiResponse response = new ApiResponse<>(null, HttpStatus.BAD_REQUEST.value(),HttpStatus.BAD_REQUEST.toString(),message); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); } catch (IllegalStateException e) { String message = e.getMessage(); - ApiResponse response = new ApiResponse(null, HttpStatus.NOT_FOUND.value(),HttpStatus.NOT_FOUND.toString(),message); + ApiResponse response = new ApiResponse<>(null, HttpStatus.NOT_FOUND.value(),HttpStatus.NOT_FOUND.toString(),message); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + } catch (Exception e) { + String message = e.getMessage(); + ApiResponse response = new ApiResponse<>(null, HttpStatus.BAD_REQUEST.value(),HttpStatus.BAD_REQUEST.toString(),message); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); } } } diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java index 695b3949..1e49fd8e 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java @@ -3,8 +3,8 @@ import com.RDS.skilltree.EndorsementList.EndorsementListModel; import com.RDS.skilltree.Skill.SkillModel; import com.RDS.skilltree.User.UserModel; +import com.RDS.skilltree.utils.TrackedProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; import lombok.*; import java.time.Instant; @@ -14,28 +14,25 @@ @Getter @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class EndorsementDTO { +public class EndorsementDTO extends TrackedProperties { private UUID id; private UserModel user; private SkillModel skill; private EndorsementStatus status; - private Instant createdAt; - private Instant updatedAt; - private UserModel createdBy; - private UserModel updatedBy; private List endorsersList; public static EndorsementDTO toDto(EndorsementModel endorsementModel) { - return EndorsementDTO.builder() + EndorsementDTO endorsementDTO = EndorsementDTO.builder() .id(endorsementModel.getId()) .user(endorsementModel.getUser()) .skill(endorsementModel.getSkill()) .status(endorsementModel.getStatus()) - .createdAt(endorsementModel.getCreatedAt()) - .createdBy(endorsementModel.getCreatedBy()) - .updatedAt(endorsementModel.getUpdatedAt()) - .updatedBy(endorsementModel.getUpdatedBy()) .endorsersList(endorsementModel.getEndorsersList()) .build(); + endorsementDTO.setCreatedAt(endorsementModel.getCreatedAt()); + endorsementDTO.setUpdatedAt(endorsementModel.getUpdatedAt()); + endorsementDTO.setCreatedBy(endorsementModel.getCreatedBy()); + endorsementDTO.setUpdatedBy(endorsementModel.getUpdatedBy()); + return endorsementDTO; } } \ No newline at end of file From c4d12428459b637e9756ad7f0c016a6f997b8ceb Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Tue, 5 Dec 2023 22:55:31 +0530 Subject: [PATCH 06/12] Refactor: Resolve comments by AjeyaK Bhavika and Debanjan --- .../skilltree/Endorsement/ApiResponse.java | 7 - .../Endorsement/EndorsementController.java | 30 ++-- .../Endorsement/EndorsementServiceImpl.java | 8 +- .../Endorsement/JsonApiResponseConverter.java | 166 ------------------ 4 files changed, 15 insertions(+), 196 deletions(-) delete mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java deleted file mode 100644 index 9a82c66d..00000000 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/ApiResponse.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.RDS.skilltree.Endorsement; - -import java.util.Map; - -public record ApiResponse(T data, int statusCode, String status, String message) { - -} diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java index 8b15d712..ee715cc1 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java @@ -1,18 +1,17 @@ package com.RDS.skilltree.Endorsement; +import jakarta.persistence.EntityNotFoundException; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; - -import java.util.Map; import java.util.UUID; -import static com.RDS.skilltree.Endorsement.JsonApiResponseConverter.convertToHashMap; - @RestController @RequestMapping("/v1/endorsements") @Slf4j @@ -25,24 +24,21 @@ public EndorsementController(EndorsementService endorsementService) { @GetMapping("/{id}") public ResponseEntity getEndorsementById(@PathVariable(value = "id", required = true) String id){ + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); try { UUID uuid = UUID.fromString(id); EndorsementDTO response = endorsementService.getEndorsementById(uuid); - Map responseData = convertToHashMap(response); - return ResponseEntity.ok(responseData); - + return ResponseEntity.ok().headers(headers).body(response); } catch (IllegalArgumentException e) { - String message = "Invalid UUID: " + id; - ApiResponse response = new ApiResponse<>(null, HttpStatus.BAD_REQUEST.value(),HttpStatus.BAD_REQUEST.toString(),message); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); - } catch (IllegalStateException e) { - String message = e.getMessage(); - ApiResponse response = new ApiResponse<>(null, HttpStatus.NOT_FOUND.value(),HttpStatus.NOT_FOUND.toString(),message); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + String jsonResponse = "{\"message\": \"" + "Invalid UUID: " + id + "\"}"; + return ResponseEntity.status(HttpStatus.BAD_REQUEST).headers(headers).body(jsonResponse); + } catch (EntityNotFoundException e) { + String jsonResponse = "{\"message\": \"" + e.getMessage() + "\"}"; + return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers).body(jsonResponse); } catch (Exception e) { - String message = e.getMessage(); - ApiResponse response = new ApiResponse<>(null, HttpStatus.BAD_REQUEST.value(),HttpStatus.BAD_REQUEST.toString(),message); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + String jsonResponse = "{\"message\": \"" + "Something went wrong. Please contact admin." + "\"}"; + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(headers).body(jsonResponse); } } } diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java index 1f2db4d1..7bfab991 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java @@ -1,4 +1,5 @@ package com.RDS.skilltree.Endorsement; +import jakarta.persistence.EntityNotFoundException; import org.springframework.stereotype.Service; import java.util.*; @@ -14,11 +15,6 @@ public EndorsementServiceImpl(EndorsementRepository endorsementRepository) { @Override public EndorsementDTO getEndorsementById(UUID id) throws IllegalStateException { Optional endorsementModel = endorsementRepository.findById(id); - if (endorsementModel.isPresent()) { - return EndorsementDTO.toDto(endorsementModel.get()); - } else { - String errorMessage = "No endorsement with the id " + id + " found"; - throw new IllegalStateException(errorMessage); - } + return EndorsementDTO.toDto(endorsementModel.orElseThrow(() -> new EntityNotFoundException("No endorsement with the id " + id + " found"))); } } \ No newline at end of file diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java index 14f31588..e69de29b 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java @@ -1,166 +0,0 @@ -package com.RDS.skilltree.Endorsement; - -import com.RDS.skilltree.EndorsementList.EndorsementListModel; -import com.RDS.skilltree.Skill.SkillModel; -import com.RDS.skilltree.User.UserModel; - -import java.lang.reflect.Field; -import java.util.*; - -public class JsonApiResponseConverter { - - public static Map convertToHashMap(EndorsementDTO endorsementDTO) { - Map result = new HashMap<>(); - Map dataMap = new HashMap<>(); - - dataMap.put("id", endorsementDTO.getId()); - dataMap.put("type", "endorsement"); - dataMap.put("links", createLinksMap(endorsementDTO.getId().toString())); - dataMap.put("attributes", createAttributesHashMap(endorsementDTO)); - dataMap.put("relationships",createRelationshipsHashMap(endorsementDTO)); - dataMap.put("included",createIncludedList(endorsementDTO)); - result.put("data", dataMap); - return result; - } - - private static Map createLinksMap(String id) { - Map links = new HashMap<>(); - links.put("self", "/endorsements/" + id); - return links; - } - - private static Map createAttributesHashMap(EndorsementDTO endorsementDTO) { - Map attributes = new HashMap<>(); - attributes.put("status", endorsementDTO.getStatus()); - attributes.put("createdAt", endorsementDTO.getCreatedAt()); - attributes.put("updatedAt", endorsementDTO.getUpdatedAt()); - return attributes; - } - - private static Map createRelationshipsHashMap(EndorsementDTO endorsementDTO) { - Map relationships = new HashMap<>(); - - Map userRelationship = getIdHashmap(endorsementDTO.getUser(),"user"); - relationships.put("user", userRelationship); - - - Map skillRelationship = getIdHashmap(endorsementDTO.getSkill(),"skill"); - relationships.put("skill", skillRelationship); - - Map createdBy = getIdHashmap(endorsementDTO.getCreatedBy(),"user"); - relationships.put("createdBy", createdBy); - - Map updatedBy = getIdHashmap(endorsementDTO.getUpdatedBy(),"user"); - relationships.put("updatedBy", updatedBy); - - List> endorsersList = new ArrayList<>(); - for (EndorsementListModel endorserListModel : endorsementDTO.getEndorsersList()) { - Map data = new HashMap<>(); - data.put("id",endorserListModel.getId()); - data.put("type","endorser"); - endorsersList.add(data); - } - - Map endorseRelationships = new HashMap<>(); - endorseRelationships.put("data",endorsersList); - relationships.put("endorsersList",endorseRelationships); - - return relationships; - } - - private static List> createIncludedList(EndorsementDTO endorsementDTO) { - List> includedList = new ArrayList<>(); - includedList.add(extractSkillsAttributes(endorsementDTO.getSkill())); - includedList.add(extractUsersAttributes(endorsementDTO.getUser())); - for (EndorsementListModel endorserListModel : endorsementDTO.getEndorsersList()) { - includedList.add(extractEndorsementListModelAttributes(endorserListModel)); - } - return includedList; - } - private static Map extractEndorsementListModelAttributes(EndorsementListModel endorsementListModel) { - Map result = new HashMap<>(); - - Map attributes = new HashMap<>(); - attributes.put("type",endorsementListModel.getType()); - attributes.put("deleted",endorsementListModel.isDeleted()); - attributes.put("description",endorsementListModel.getDescription()); - attributes.put("createdAt",endorsementListModel.getCreatedAt()); - attributes.put("updatedAt",endorsementListModel.getUpdatedAt()); - - Map relationships = new HashMap<>(); - relationships.put("endorsersList",getIdHashmap(endorsementListModel.getEndorser(),"user")); - relationships.put("createdBy",getIdHashmap(endorsementListModel.getCreatedBy(),"user")); - relationships.put("updatedBy",getIdHashmap(endorsementListModel.getUpdatedBy(),"user")); - - result.put("id",endorsementListModel.getId()); - result.put("type","EndorsementList"); - result.put("attributes",attributes); - result.put("relationships",relationships); - return result; - } - private static Map extractSkillsAttributes(SkillModel skillModel) { - Map result = new HashMap<>(); - - Map attributes = new HashMap<>(); - attributes.put("name",skillModel.getName()); - attributes.put("type",skillModel.getType()); - attributes.put("createdAt",skillModel.getCreatedAt()); - attributes.put("updatedAt",skillModel.getUpdatedAt()); - attributes.put("isDeleted",skillModel.isDeleted()); - - Map relationships = new HashMap<>(); - relationships.put("createdBy",getIdHashmap(skillModel.getCreatedBy(),"user")); - relationships.put("updatedBy",getIdHashmap(skillModel.getUpdatedBy(),"user")); - - result.put("id",skillModel.getId()); - result.put("type","skill"); - result.put("attributes",attributes); - result.put("relationships",relationships); - - return result; - } - private static Map extractUsersAttributes(UserModel userModel) { - Map result = new HashMap<>(); - - Map attributes = new HashMap<>(); - attributes.put("firstName",userModel.getFirstName()); - attributes.put("lastName",userModel.getLastName()); - attributes.put("rdsUserId",userModel.getRdsUserId()); - attributes.put("role",userModel.getRole()); - attributes.put("imageUrl",userModel.getImageUrl()); - attributes.put("createdAt",userModel.getCreatedAt()); - attributes.put("updatedAt",userModel.getUpdatedAt()); - - Map relationships = new HashMap<>(); - relationships.put("createdBy",getIdHashmap(userModel.getCreatedBy(),"user")); - relationships.put("updatedBy",getIdHashmap(userModel.getUpdatedBy(),"user")); - result.put("id",userModel.getId()); - result.put("type","user"); - result.put("attributes",attributes); - result.put("relationships",relationships); - return result; - } - private static Map getIdHashmap(Object dto, String type) { - Map relationship = new HashMap<>(); - Map data = new HashMap<>(); - try { - if (dto == null) { - data.put("type", type); - data.put("id", null); - } else { - Field idField = dto.getClass().getDeclaredField("id"); - idField.setAccessible(true); - Object id = idField.get(dto); - - data.put("type", type); - data.put("id", id); - - } - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - } - relationship.put("data", data); - return relationship; - } - -} \ No newline at end of file From 73716abd80cae28fecdeb2baa263941c98b12c37 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Tue, 5 Dec 2023 23:02:23 +0530 Subject: [PATCH 07/12] Refactor: Remove empty file --- .../com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/JsonApiResponseConverter.java deleted file mode 100644 index e69de29b..00000000 From c5779944c0aff30f502f7c605b8d5cd3528f3abf Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Thu, 14 Dec 2023 06:23:31 +0530 Subject: [PATCH 08/12] Added required args constructor and removed redundant lines from tests --- .../skilltree/Endorsement/EndorsementController.java | 6 ++---- .../skilltree/Endorsement/EndorsementServiceImpl.java | 6 ++---- .../skilltree/Endorsement/EndorsementServiceTest.java | 11 ++--------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java index ee715cc1..edd3be10 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java @@ -1,6 +1,7 @@ package com.RDS.skilltree.Endorsement; import jakarta.persistence.EntityNotFoundException; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -15,13 +16,10 @@ @RestController @RequestMapping("/v1/endorsements") @Slf4j +@RequiredArgsConstructor public class EndorsementController { private final EndorsementService endorsementService; - public EndorsementController(EndorsementService endorsementService) { - this.endorsementService = endorsementService; - } - @GetMapping("/{id}") public ResponseEntity getEndorsementById(@PathVariable(value = "id", required = true) String id){ HttpHeaders headers = new HttpHeaders(); diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java index 7bfab991..70e199d7 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementServiceImpl.java @@ -1,17 +1,15 @@ package com.RDS.skilltree.Endorsement; import jakarta.persistence.EntityNotFoundException; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.*; @Service +@RequiredArgsConstructor public class EndorsementServiceImpl implements EndorsementService { private final EndorsementRepository endorsementRepository; - public EndorsementServiceImpl(EndorsementRepository endorsementRepository) { - this.endorsementRepository = endorsementRepository; - } - @Override public EndorsementDTO getEndorsementById(UUID id) throws IllegalStateException { Optional endorsementModel = endorsementRepository.findById(id); diff --git a/skill-tree /src/test/java/com/RDS/skilltree/Endorsement/EndorsementServiceTest.java b/skill-tree /src/test/java/com/RDS/skilltree/Endorsement/EndorsementServiceTest.java index 60d02dd6..6d8d8d92 100644 --- a/skill-tree /src/test/java/com/RDS/skilltree/Endorsement/EndorsementServiceTest.java +++ b/skill-tree /src/test/java/com/RDS/skilltree/Endorsement/EndorsementServiceTest.java @@ -33,10 +33,8 @@ public void itShouldGetEndorsementsById() { UUID userId = UUID.randomUUID(); UUID skillId = UUID.randomUUID(); - UserModel userModel = new UserModel(); - userModel.setId(userId); - SkillModel skillModel = new SkillModel(); - skillModel.setId(skillId); + UserModel userModel = UserModel.builder().id(userId).build(); + SkillModel skillModel = SkillModel.builder().id(skillId).build(); EndorsementModel endorsementModel = EndorsementModel.builder() .id(endorsementId) .user(userModel) @@ -47,24 +45,19 @@ public void itShouldGetEndorsementsById() { endorsementModel.setCreatedBy(userModel); endorsementModel.setUpdatedBy(userModel); - // Given when(endorsementRepository.findById(endorsementId)).thenReturn(Optional.of(endorsementModel)); - // When EndorsementDTO result = underTest.getEndorsementById(endorsementId); - // Then assertNotNull(result); assertEquals("The Endorsement Id doesn't matches the expected endorsement Id", endorsementId, result.getId()); } @Test public void itShouldHandleEndorsementNotFound() { - // Given UUID nonExistentEndorsementId = UUID.randomUUID(); when(endorsementRepository.findById(nonExistentEndorsementId)).thenReturn(Optional.empty()); - // When , Then assertThatThrownBy(() -> underTest.getEndorsementById(nonExistentEndorsementId)) .isInstanceOf(IllegalStateException.class) .hasMessageContaining("No endorsement with the id " + nonExistentEndorsementId + " found"); From 8291aae36b610f0cbfb79e67f1c50df8e89bb5ad Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:37:07 +0530 Subject: [PATCH 09/12] convert the models to respective DTO's --- .../RDS/skilltree/Endorsement/EndorsementDTO.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java index 1e49fd8e..31947610 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementDTO.java @@ -1,13 +1,11 @@ package com.RDS.skilltree.Endorsement; import com.RDS.skilltree.EndorsementList.EndorsementListModel; -import com.RDS.skilltree.Skill.SkillModel; -import com.RDS.skilltree.User.UserModel; +import com.RDS.skilltree.Skill.SkillDTO; +import com.RDS.skilltree.User.UserDTO; import com.RDS.skilltree.utils.TrackedProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.*; - -import java.time.Instant; import java.util.List; import java.util.UUID; @@ -16,16 +14,16 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class EndorsementDTO extends TrackedProperties { private UUID id; - private UserModel user; - private SkillModel skill; + private UserDTO user; + private SkillDTO skill; private EndorsementStatus status; private List endorsersList; public static EndorsementDTO toDto(EndorsementModel endorsementModel) { EndorsementDTO endorsementDTO = EndorsementDTO.builder() .id(endorsementModel.getId()) - .user(endorsementModel.getUser()) - .skill(endorsementModel.getSkill()) + .user(UserDTO.toDTO(endorsementModel.getUser())) + .skill(SkillDTO.toDto(endorsementModel.getSkill())) .status(endorsementModel.getStatus()) .endorsersList(endorsementModel.getEndorsersList()) .build(); From 7c1a2f675425903e7bb56e3ca348114bfa5edb4f Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Thu, 14 Dec 2023 11:30:17 +0530 Subject: [PATCH 10/12] Defined types to maintain a consistent format for the Api response --- .../Endorsement/EndorsementController.java | 15 +++++++-------- .../Endorsement/EndorsementResponse.java | 12 ++++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementResponse.java diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java index edd3be10..0eed3d2a 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java @@ -21,22 +21,21 @@ public class EndorsementController { private final EndorsementService endorsementService; @GetMapping("/{id}") - public ResponseEntity getEndorsementById(@PathVariable(value = "id", required = true) String id){ + public ResponseEntity> getEndorsementById(@PathVariable(value = "id", required = true) String id){ HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); try { UUID uuid = UUID.fromString(id); EndorsementDTO response = endorsementService.getEndorsementById(uuid); - return ResponseEntity.ok().headers(headers).body(response); + return ResponseEntity.ok().headers(headers).body(new EndorsementResponse(response, "Data retrieved successfully")); } catch (IllegalArgumentException e) { - String jsonResponse = "{\"message\": \"" + "Invalid UUID: " + id + "\"}"; - return ResponseEntity.status(HttpStatus.BAD_REQUEST).headers(headers).body(jsonResponse); + String message = "Invalid UUID: " + id; + return ResponseEntity.status(HttpStatus.BAD_REQUEST).headers(headers).body(new EndorsementResponse(null, message)); } catch (EntityNotFoundException e) { - String jsonResponse = "{\"message\": \"" + e.getMessage() + "\"}"; - return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers).body(jsonResponse); + return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers).body(new EndorsementResponse(null, e.getMessage())); } catch (Exception e) { - String jsonResponse = "{\"message\": \"" + "Something went wrong. Please contact admin." + "\"}"; - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(headers).body(jsonResponse); + String message = "Something went wrong. Please contact admin."; + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(headers).body(new EndorsementResponse(null, message)); } } } diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementResponse.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementResponse.java new file mode 100644 index 00000000..6d755a2b --- /dev/null +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementResponse.java @@ -0,0 +1,12 @@ +package com.RDS.skilltree.Endorsement; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class EndorsementResponse { + private T data; + private String message; +} From 80e33aac1ce28614e831b74cf0f4951592b2104b Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Thu, 14 Dec 2023 22:31:28 +0530 Subject: [PATCH 11/12] Resolve comments by vikhyat --- .../Common/Response/GenericResponse.java | 15 +++++++++++++++ .../Endorsement/EndorsementController.java | 16 +++++++--------- .../Endorsement/EndorsementResponse.java | 12 ------------ 3 files changed, 22 insertions(+), 21 deletions(-) create mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Common/Response/GenericResponse.java delete mode 100644 skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementResponse.java diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Common/Response/GenericResponse.java b/skill-tree /src/main/java/com/RDS/skilltree/Common/Response/GenericResponse.java new file mode 100644 index 00000000..0e932fee --- /dev/null +++ b/skill-tree /src/main/java/com/RDS/skilltree/Common/Response/GenericResponse.java @@ -0,0 +1,15 @@ +package com.RDS.skilltree.Common.Response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class GenericResponse { + private T data; + private String message; +} diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java index 0eed3d2a..4b052b84 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementController.java @@ -1,9 +1,9 @@ package com.RDS.skilltree.Endorsement; +import com.RDS.skilltree.Common.Response.GenericResponse; import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -20,22 +20,20 @@ public class EndorsementController { private final EndorsementService endorsementService; - @GetMapping("/{id}") - public ResponseEntity> getEndorsementById(@PathVariable(value = "id", required = true) String id){ - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); + @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> getEndorsementById(@PathVariable(value = "id", required = true) String id){ try { UUID uuid = UUID.fromString(id); EndorsementDTO response = endorsementService.getEndorsementById(uuid); - return ResponseEntity.ok().headers(headers).body(new EndorsementResponse(response, "Data retrieved successfully")); + return ResponseEntity.ok().body(new GenericResponse(response, "Data retrieved successfully")); } catch (IllegalArgumentException e) { String message = "Invalid UUID: " + id; - return ResponseEntity.status(HttpStatus.BAD_REQUEST).headers(headers).body(new EndorsementResponse(null, message)); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new GenericResponse(null, message)); } catch (EntityNotFoundException e) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers).body(new EndorsementResponse(null, e.getMessage())); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new GenericResponse(null, e.getMessage())); } catch (Exception e) { String message = "Something went wrong. Please contact admin."; - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(headers).body(new EndorsementResponse(null, message)); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new GenericResponse(null, message)); } } } diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementResponse.java b/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementResponse.java deleted file mode 100644 index 6d755a2b..00000000 --- a/skill-tree /src/main/java/com/RDS/skilltree/Endorsement/EndorsementResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.RDS.skilltree.Endorsement; - -import lombok.*; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class EndorsementResponse { - private T data; - private String message; -} From 0c295cde1cc77fa6f72080fc121bacf5d1e9dad1 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Fri, 15 Dec 2023 06:17:00 +0530 Subject: [PATCH 12/12] Adds @JsonInclude(JsonInclude.Include.NON_NULL) to improve response class by excluding null fields --- .../java/com/RDS/skilltree/Common/Response/GenericResponse.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/skill-tree /src/main/java/com/RDS/skilltree/Common/Response/GenericResponse.java b/skill-tree /src/main/java/com/RDS/skilltree/Common/Response/GenericResponse.java index 0e932fee..ee31959f 100644 --- a/skill-tree /src/main/java/com/RDS/skilltree/Common/Response/GenericResponse.java +++ b/skill-tree /src/main/java/com/RDS/skilltree/Common/Response/GenericResponse.java @@ -1,5 +1,6 @@ package com.RDS.skilltree.Common.Response; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -9,6 +10,7 @@ @Setter @NoArgsConstructor @AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) public class GenericResponse { private T data; private String message;