Skip to content

Commit 557585b

Browse files
Added CRUD functionality for comments on Request Page
1 parent d3e10c8 commit 557585b

11 files changed

Lines changed: 456 additions & 0 deletions

File tree

pom.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@
109109
<artifactId>spring-boot-starter-aop</artifactId>
110110
</dependency>
111111

112+
<dependency>
113+
<groupId>com.fasterxml.jackson.core</groupId>
114+
<artifactId>jackson-databind</artifactId>
115+
</dependency>
112116
<!-- <dependency>-->
113117
<!-- <groupId>software.amazon.awssdk</groupId>-->
114118
<!-- <artifactId>sqs</artifactId>-->
@@ -120,9 +124,17 @@
120124
<!-- <artifactId>spring-cloud-aws-sqs</artifactId>-->
121125
<!-- <version>3.2.0-M1</version>-->
122126
<!-- </dependency>-->
127+
<dependency>
128+
<groupId>org.mapstruct</groupId>
129+
<artifactId>mapstruct</artifactId>
130+
<version>1.5.5.Final</version>
131+
</dependency>
132+
123133

124134
</dependencies>
125135

136+
137+
126138
<build>
127139
<plugins>
128140
<!-- Maven Shade Plugin -->
@@ -165,6 +177,24 @@
165177
</executions>
166178
</plugin>
167179

180+
<!-- Maven Compiler Plugin -->
181+
<plugin>
182+
<groupId>org.apache.maven.plugins</groupId>
183+
<artifactId>maven-compiler-plugin</artifactId>
184+
<version>3.11.0</version>
185+
<configuration>
186+
<source>17</source>
187+
<target>17</target>
188+
<annotationProcessorPaths>
189+
<path>
190+
<groupId>org.mapstruct</groupId>
191+
<artifactId>mapstruct-processor</artifactId>
192+
<version>1.5.5.Final</version>
193+
</path>
194+
</annotationProcessorPaths>
195+
</configuration>
196+
</plugin>
197+
168198
<!-- Jacoco Plugin -->
169199
<plugin>
170200
<groupId>org.jacoco</groupId>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.sfa.request.controller;
2+
3+
import io.swagger.v3.oas.annotations.tags.Tag;
4+
import jakarta.validation.Valid;
5+
import jakarta.validation.constraints.NotNull;
6+
import lombok.RequiredArgsConstructor;
7+
import org.sfa.request.dto.CommentDTO;
8+
import org.sfa.request.mapper.CommentMapper;
9+
import org.sfa.request.response.SaayamResponse;
10+
import org.sfa.request.service.api.CommentService;
11+
import org.springframework.http.ResponseEntity;
12+
import org.springframework.validation.annotation.Validated;
13+
import org.springframework.web.bind.annotation.*;
14+
15+
@Validated
16+
@RestController
17+
@RequestMapping("/api/v1.0.0/requests/{requesterId}/{requestId}")
18+
@RequiredArgsConstructor
19+
@Tag(name = "Comment", description = "Comment management APIs")
20+
public class CommentController {
21+
private final CommentMapper commentMapper;
22+
private final CommentService commentService;
23+
24+
25+
@GetMapping("/comments/{commentId}")
26+
public ResponseEntity<SaayamResponse<CommentDTO>> getCommentByRequestId(
27+
@PathVariable @NotNull String requestId,
28+
@PathVariable @NotNull Long commentId
29+
){
30+
SaayamResponse<CommentDTO> response = commentService.getCommentById(requestId, commentId);
31+
32+
return ResponseEntity.ok(response);
33+
}
34+
35+
@PostMapping("/comments")
36+
public ResponseEntity<SaayamResponse<CommentDTO>> createComment(
37+
@PathVariable @NotNull String requestId,
38+
@RequestBody @Valid CommentDTO createCommentDTO
39+
) {
40+
SaayamResponse<CommentDTO> response =
41+
commentService.createComment(
42+
requestId, createCommentDTO.getAuthorName(), createCommentDTO.getCommentText());
43+
44+
return ResponseEntity.ok(response);
45+
}
46+
47+
@PutMapping("/comments/{commentId}")
48+
public ResponseEntity<SaayamResponse<CommentDTO>> updateComment(
49+
@PathVariable @NotNull String requestId,
50+
@PathVariable @NotNull Long commentId,
51+
@RequestBody @Valid CommentDTO updateCommentDTO
52+
) {
53+
SaayamResponse<CommentDTO> response =
54+
commentService.updateComment(requestId, commentId, updateCommentDTO.getCommentText());
55+
56+
return ResponseEntity.ok(response);
57+
}
58+
59+
@DeleteMapping("/comments/{commentId}")
60+
public ResponseEntity<SaayamResponse<Void>> deleteComment(
61+
@PathVariable @NotNull Long commentId,
62+
@PathVariable @NotNull String requestId
63+
) {
64+
commentService.deleteComment(requestId, commentId);
65+
66+
return ResponseEntity.noContent().build();
67+
}
68+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.sfa.request.dto;
2+
3+
import jakarta.validation.constraints.NotBlank;
4+
import jakarta.validation.constraints.NotNull;
5+
import jakarta.validation.constraints.Size;
6+
import lombok.AllArgsConstructor;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
@Data
11+
@NoArgsConstructor
12+
@AllArgsConstructor
13+
public class CommentDTO {
14+
15+
@NotNull
16+
private Long commentId;
17+
18+
@NotBlank
19+
@Size(max = 100, message = "Author name should not exceed 100 characters for an entry")
20+
private String authorName;
21+
22+
@NotBlank
23+
@Size(max = 500, message = "Comment text should not exceed 500 characters for one single comment")
24+
private String commentText;
25+
26+
public CommentDTO(String authorName, String commentText) {
27+
this.authorName = authorName;
28+
this.commentText = commentText;
29+
}
30+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.sfa.request.exception.types;
2+
3+
public class ResourceNotFoundException extends RuntimeException {
4+
public ResourceNotFoundException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.sfa.request.mapper;
2+
3+
import org.mapstruct.Mapper;
4+
import org.sfa.request.dto.CommentDTO;
5+
import org.sfa.request.model.entity.Comment;
6+
7+
@Mapper(componentModel = "spring")
8+
public interface CommentMapper {
9+
Comment toEntity(CommentDTO commentDto);
10+
CommentDTO toDTO(Comment comment);
11+
12+
13+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.sfa.request.model.entity;
2+
3+
import jakarta.persistence.*;
4+
import jakarta.validation.constraints.NotBlank;
5+
import jakarta.validation.constraints.Size;
6+
import lombok.AllArgsConstructor;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
@Entity
11+
@Data
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Table(name = "comments")
15+
public class Comment {
16+
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
private Long commentId;
20+
21+
@NotBlank
22+
@Size(max = 100)
23+
@Column(name= "author_name", nullable = false, columnDefinition = "VARCHAR(255)", length = 100)
24+
private String authorName;
25+
26+
@NotBlank
27+
@Size(max = 500)
28+
@Column(name= "comment_text", nullable = false, columnDefinition = "VARCHAR(255)", length = 500)
29+
private String commentText;
30+
31+
@ManyToOne
32+
@JoinColumn(name = "request_id", nullable = false, foreignKey = @ForeignKey(name = "fk_request_id"))
33+
private Request request;
34+
}

src/main/java/org/sfa/request/model/entity/Request.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import java.io.Serializable;
77
import java.time.ZonedDateTime;
8+
import java.util.List;
89

910
/**
1011
* ClassName: Request
@@ -82,6 +83,9 @@ public class Request implements Serializable {
8283
)
8384
private RequestFor requestFor;
8485

86+
@OneToMany(mappedBy = "request", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
87+
private List<Comment> comments;
88+
8589
@Column(name = "city_name", columnDefinition = "VARCHAR(255)")
8690
private String city;
8791

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.sfa.request.repository;
2+
3+
import org.sfa.request.model.entity.Comment;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
import java.util.Optional;
8+
9+
@Repository
10+
public interface CommentRepository extends JpaRepository<Comment, Long> {
11+
Optional<Comment> findByRequestIdAndCommentId(String requestId, Long commentId);
12+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.sfa.request.service.api;
2+
3+
import org.sfa.request.dto.CommentDTO;
4+
import org.sfa.request.response.SaayamResponse;
5+
6+
/**
7+
* ClassName: CommentService
8+
* Package: org.sfa.request.service.api
9+
*/
10+
public interface CommentService {
11+
12+
13+
SaayamResponse<CommentDTO> createComment(String requestId, String authorName, String commentText);
14+
15+
SaayamResponse<CommentDTO> updateComment(String requestId, Long commentId, String commentText);
16+
17+
SaayamResponse<CommentDTO> deleteComment(String requestId, Long commentId);
18+
19+
SaayamResponse<CommentDTO> getCommentById(String requestId, Long commentId);
20+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package org.sfa.request.service.impl;
2+
3+
import org.sfa.request.constant.SaayamStatusCode;
4+
import org.sfa.request.dto.CommentDTO;
5+
import org.sfa.request.exception.types.ResourceNotFoundException;
6+
import org.sfa.request.mapper.CommentMapper;
7+
import org.sfa.request.model.entity.Comment;
8+
import org.sfa.request.repository.CommentRepository;
9+
import org.sfa.request.repository.RequestRepository;
10+
import org.sfa.request.response.SaayamResponse;
11+
import org.sfa.request.service.api.CommentService;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.stereotype.Service;
14+
15+
@Service
16+
public class CommentServiceImpl implements CommentService {
17+
18+
private final CommentRepository commentRepository;
19+
private final CommentMapper commentMapper;
20+
private final RequestRepository requestRepository;
21+
22+
@Autowired
23+
public CommentServiceImpl(CommentRepository commentRepository, CommentMapper commentMapper, RequestRepository requestRepository) {
24+
this.commentRepository = commentRepository;
25+
this.commentMapper = commentMapper;
26+
this.requestRepository = requestRepository;
27+
}
28+
29+
@Override
30+
public SaayamResponse<CommentDTO> createComment(String requestId, String authorName, String commentText) {
31+
boolean requestExistsForComment = requestRepository.existsById(requestId);
32+
if(!requestExistsForComment){
33+
throw new ResourceNotFoundException("Request with id:" + requestId + "not found.");
34+
}
35+
36+
Comment comment = commentMapper.toEntity(new CommentDTO(authorName, commentText));
37+
38+
Comment savedCommentForRequest = commentRepository.save(comment);
39+
40+
CommentDTO commentDTO = commentMapper.toDTO(savedCommentForRequest);
41+
42+
return SaayamResponse.success(
43+
SaayamStatusCode.SUCCESS,
44+
"Comment Created Successfully",
45+
commentDTO);
46+
}
47+
48+
@Override
49+
public SaayamResponse<CommentDTO> updateComment(String requestId, Long commentId, String commentText) {
50+
51+
Comment commentToBeUpdated = commentRepository.findByRequestIdAndCommentId(requestId, commentId).orElseThrow(() ->
52+
new ResourceNotFoundException(
53+
"Comment not found with id:" + commentId
54+
+ "does not belong to request with id:" + requestId));
55+
56+
commentToBeUpdated.setCommentText(commentText);
57+
58+
Comment updateComment = commentRepository.save(commentToBeUpdated);
59+
60+
CommentDTO commentDTO = commentMapper.toDTO(updateComment);
61+
62+
return SaayamResponse.success(
63+
SaayamStatusCode.SUCCESS,
64+
"Comment Content Updated Successfully",
65+
commentDTO);
66+
}
67+
68+
@Override
69+
public SaayamResponse<CommentDTO> deleteComment(String requestId, Long commentId) {
70+
Comment commentToBeDeleted = commentRepository.findByRequestIdAndCommentId(requestId, commentId).orElseThrow(() ->
71+
new ResourceNotFoundException(
72+
"Comment not found with id:" + commentId
73+
+ "does not belong to request with id:" + requestId + "and must already be deleted"));
74+
75+
commentRepository.delete(commentToBeDeleted);
76+
77+
return SaayamResponse.success(
78+
SaayamStatusCode.SUCCESS,
79+
"Comment Deleted Successfully",
80+
null);
81+
}
82+
83+
@Override
84+
public SaayamResponse<CommentDTO> getCommentById(String requestId, Long commentId) {
85+
Comment commentToBeUpdated = commentRepository.findByRequestIdAndCommentId(requestId, commentId).orElseThrow(() ->
86+
new ResourceNotFoundException(
87+
"Comment not found with id:" + commentId
88+
+ "does not belong to request with id:" + requestId));
89+
90+
CommentDTO commentDTO = commentMapper.toDTO(commentToBeUpdated);
91+
92+
return SaayamResponse.success(
93+
SaayamStatusCode.SUCCESS,
94+
"Comment Retrieved Successfully",
95+
commentDTO);
96+
}
97+
}

0 commit comments

Comments
 (0)