Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>software.amazon.awssdk</groupId>-->
<!-- <artifactId>sqs</artifactId>-->
Expand All @@ -120,9 +124,17 @@
<!-- <artifactId>spring-cloud-aws-sqs</artifactId>-->
<!-- <version>3.2.0-M1</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>


</dependencies>



<build>
<plugins>
<!-- Maven Shade Plugin -->
Expand Down Expand Up @@ -165,6 +177,24 @@
</executions>
</plugin>

<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

<!-- Jacoco Plugin -->
<plugin>
<groupId>org.jacoco</groupId>
Expand Down
68 changes: 68 additions & 0 deletions src/main/java/org/sfa/request/controller/CommentController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.sfa.request.controller;

import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.sfa.request.dto.CommentDTO;
import org.sfa.request.mapper.CommentMapper;
import org.sfa.request.response.SaayamResponse;
import org.sfa.request.service.api.CommentService;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@Validated
@RestController
@RequestMapping("/api/v1.0.0/requests/{requesterId}/{requestId}")
@RequiredArgsConstructor
@Tag(name = "Comment", description = "Comment management APIs")
public class CommentController {
private final CommentMapper commentMapper;
private final CommentService commentService;


@GetMapping("/comments/{commentId}")
public ResponseEntity<SaayamResponse<CommentDTO>> getCommentByRequestId(
@PathVariable @NotNull String requestId,
@PathVariable @NotNull Long commentId
){
SaayamResponse<CommentDTO> response = commentService.getCommentById(requestId, commentId);

return ResponseEntity.ok(response);
}

@PostMapping("/comments")
public ResponseEntity<SaayamResponse<CommentDTO>> createComment(
@PathVariable @NotNull String requestId,
@RequestBody @Valid CommentDTO createCommentDTO
) {
SaayamResponse<CommentDTO> response =
commentService.createComment(
requestId, createCommentDTO.getAuthorName(), createCommentDTO.getCommentText());

return ResponseEntity.ok(response);
}

@PutMapping("/comments/{commentId}")
public ResponseEntity<SaayamResponse<CommentDTO>> updateComment(
@PathVariable @NotNull String requestId,
@PathVariable @NotNull Long commentId,
@RequestBody @Valid CommentDTO updateCommentDTO
) {
SaayamResponse<CommentDTO> response =
commentService.updateComment(requestId, commentId, updateCommentDTO.getCommentText());

return ResponseEntity.ok(response);
}

@DeleteMapping("/comments/{commentId}")
public ResponseEntity<SaayamResponse<Void>> deleteComment(
@PathVariable @NotNull Long commentId,
@PathVariable @NotNull String requestId
) {
commentService.deleteComment(requestId, commentId);

return ResponseEntity.noContent().build();
}
}
30 changes: 30 additions & 0 deletions src/main/java/org/sfa/request/dto/CommentDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.sfa.request.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommentDTO {

@NotNull
private Long commentId;

@NotBlank
@Size(max = 100, message = "Author name should not exceed 100 characters for an entry")
private String authorName;

@NotBlank
@Size(max = 500, message = "Comment text should not exceed 500 characters for one single comment")
private String commentText;

public CommentDTO(String authorName, String commentText) {
this.authorName = authorName;
this.commentText = commentText;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.sfa.request.exception.types;

public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
13 changes: 13 additions & 0 deletions src/main/java/org/sfa/request/mapper/CommentMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.sfa.request.mapper;

import org.mapstruct.Mapper;
import org.sfa.request.dto.CommentDTO;
import org.sfa.request.model.entity.Comment;

@Mapper(componentModel = "spring")
public interface CommentMapper {
Comment toEntity(CommentDTO commentDto);
CommentDTO toDTO(Comment comment);


}
34 changes: 34 additions & 0 deletions src/main/java/org/sfa/request/model/entity/Comment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.sfa.request.model.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "comments")
public class Comment {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long commentId;

@NotBlank
@Size(max = 100)
@Column(name= "author_name", nullable = false, columnDefinition = "VARCHAR(255)")
private String authorName;

@NotBlank
@Size(max = 500)
@Column(name= "comment_text", nullable = false, columnDefinition = "VARCHAR(255)")
private String commentText;

@ManyToOne
@JoinColumn(name = "request_id", nullable = false, foreignKey = @ForeignKey(name = "fk_request_id"))
private Request request;
}
4 changes: 4 additions & 0 deletions src/main/java/org/sfa/request/model/entity/Request.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.List;

/**
* ClassName: Request
Expand Down Expand Up @@ -82,6 +83,9 @@ public class Request implements Serializable {
)
private RequestFor requestFor;

@OneToMany(mappedBy = "request", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<Comment> comments;

@Column(name = "city_name", columnDefinition = "VARCHAR(255)")
private String city;

Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/sfa/request/repository/CommentRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.sfa.request.repository;

import org.sfa.request.model.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface CommentRepository extends JpaRepository<Comment, Long> {
Optional<Comment> findByRequestIdAndCommentId(String requestId, Long commentId);
}
20 changes: 20 additions & 0 deletions src/main/java/org/sfa/request/service/api/CommentService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.sfa.request.service.api;

import org.sfa.request.dto.CommentDTO;
import org.sfa.request.response.SaayamResponse;

/**
* ClassName: CommentService
* Package: org.sfa.request.service.api
*/
public interface CommentService {


SaayamResponse<CommentDTO> createComment(String requestId, String authorName, String commentText);

SaayamResponse<CommentDTO> updateComment(String requestId, Long commentId, String commentText);

SaayamResponse<CommentDTO> deleteComment(String requestId, Long commentId);

SaayamResponse<CommentDTO> getCommentById(String requestId, Long commentId);
}
97 changes: 97 additions & 0 deletions src/main/java/org/sfa/request/service/impl/CommentServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.sfa.request.service.impl;

import org.sfa.request.constant.SaayamStatusCode;
import org.sfa.request.dto.CommentDTO;
import org.sfa.request.exception.types.ResourceNotFoundException;
import org.sfa.request.mapper.CommentMapper;
import org.sfa.request.model.entity.Comment;
import org.sfa.request.repository.CommentRepository;
import org.sfa.request.repository.RequestRepository;
import org.sfa.request.response.SaayamResponse;
import org.sfa.request.service.api.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CommentServiceImpl implements CommentService {

private final CommentRepository commentRepository;
private final CommentMapper commentMapper;
private final RequestRepository requestRepository;

@Autowired
public CommentServiceImpl(CommentRepository commentRepository, CommentMapper commentMapper, RequestRepository requestRepository) {
this.commentRepository = commentRepository;
this.commentMapper = commentMapper;
this.requestRepository = requestRepository;
}

@Override
public SaayamResponse<CommentDTO> createComment(String requestId, String authorName, String commentText) {
boolean requestExistsForComment = requestRepository.existsById(requestId);
if(!requestExistsForComment){
throw new ResourceNotFoundException("Request with id:" + requestId + "not found.");
}

Comment comment = commentMapper.toEntity(new CommentDTO(authorName, commentText));

Comment savedCommentForRequest = commentRepository.save(comment);

CommentDTO commentDTO = commentMapper.toDTO(savedCommentForRequest);

return SaayamResponse.success(
SaayamStatusCode.SUCCESS,
"Comment Created Successfully",
commentDTO);
}

@Override
public SaayamResponse<CommentDTO> updateComment(String requestId, Long commentId, String commentText) {

Comment commentToBeUpdated = commentRepository.findByRequestIdAndCommentId(requestId, commentId).orElseThrow(() ->
new ResourceNotFoundException(
"Comment not found with id:" + commentId
+ "does not belong to request with id:" + requestId));

commentToBeUpdated.setCommentText(commentText);

Comment updateComment = commentRepository.save(commentToBeUpdated);

CommentDTO commentDTO = commentMapper.toDTO(updateComment);

return SaayamResponse.success(
SaayamStatusCode.SUCCESS,
"Comment Content Updated Successfully",
commentDTO);
}

@Override
public SaayamResponse<CommentDTO> deleteComment(String requestId, Long commentId) {
Comment commentToBeDeleted = commentRepository.findByRequestIdAndCommentId(requestId, commentId).orElseThrow(() ->
new ResourceNotFoundException(
"Comment not found with id:" + commentId
+ "does not belong to request with id:" + requestId + "and must already be deleted"));

commentRepository.delete(commentToBeDeleted);

return SaayamResponse.success(
SaayamStatusCode.SUCCESS,
"Comment Deleted Successfully",
null);
}

@Override
public SaayamResponse<CommentDTO> getCommentById(String requestId, Long commentId) {
Comment commentToBeUpdated = commentRepository.findByRequestIdAndCommentId(requestId, commentId).orElseThrow(() ->
new ResourceNotFoundException(
"Comment not found with id:" + commentId
+ "does not belong to request with id:" + requestId));

CommentDTO commentDTO = commentMapper.toDTO(commentToBeUpdated);

return SaayamResponse.success(
SaayamStatusCode.SUCCESS,
"Comment Retrieved Successfully",
commentDTO);
}
}
Loading