diff --git a/build.gradle b/build.gradle index a89a491..428daaf 100644 --- a/build.gradle +++ b/build.gradle @@ -43,10 +43,16 @@ dependencies { compile group: 'org.springframework.boot', name: 'spring-boot', version: springBootVersion compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion compile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: springBootVersion + compile group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', version: springBootVersion compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-sleuth', version: springSleuthVersion + compile group: 'org.springframework.data', name: 'spring-data-mongodb', version: springMongoDataVersion + compile group: 'org.mongodb', name: 'mongodb-driver-sync', version: javaMongoDriverVersion + compile group: 'com.google.code.gson', name: 'gson', version: gsonVersion + compile group: 'com.google.guava', name: 'guava', version: guavaVersion compile group: 'javax.el', name: 'javax.el-api', version: javaxElApiVersion compile group: 'org.glassfish', name: 'javax.el', version: glassfishVersion providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: javaxServletVersion + annotationProcessor 'org.projectlombok:lombok:1.18.16' tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}", "org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}", "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}" diff --git a/gradle.properties b/gradle.properties index 48be8ce..2baa5dd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,6 +13,10 @@ javaxElApiVersion=3.0.1-b06 glassfishVersion=3.0.0 javaxServletVersion=3.1.0 tomcatVersion=7.0.63 +springMongoDataVersion=3.0.3.RELEASE +javaMongoDriverVersion=4.0.5 +gsonVersion=2.8.6 +guavaVersion=11.0.2 # Version and base tags can be overridden at build time. TechVaultVersion=0.1.0 \ No newline at end of file diff --git a/src/main/java/TechVault/Application.java b/src/main/java/TechVault/Application.java index 7385ead..99a26e6 100644 --- a/src/main/java/TechVault/Application.java +++ b/src/main/java/TechVault/Application.java @@ -2,10 +2,21 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; -@SpringBootApplication -public class Application { +@SpringBootApplication(scanBasePackages="TechVault") +@EnableMongoRepositories(basePackages = "TechVault") +public class Application { public static void main(String[] args) { + System.out.println("Starting Application....."); SpringApplication.run(Application.class, args); } + + @Bean + public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { + return new PersistenceExceptionTranslationPostProcessor(); + } + } \ No newline at end of file diff --git a/src/main/java/TechVault/config/PersistenceConfig.java b/src/main/java/TechVault/config/PersistenceConfig.java new file mode 100644 index 0000000..eb39b0c --- /dev/null +++ b/src/main/java/TechVault/config/PersistenceConfig.java @@ -0,0 +1,45 @@ +package TechVault.config; + +import java.util.Collection; +import java.util.Collections; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration; + +@Configuration +public class PersistenceConfig extends AbstractMongoClientConfiguration { + + @Value("${spring.data.mongodb.database}") + private String dbName; + + @Value("${spring.data.mongodb.uri}") + private String uri; + + @Override + protected String getDatabaseName() { + return dbName; + } + + @Override + public MongoClient mongoClient() { + //"mongodb+srv://prateek:p@cluster0.kf3n4.mongodb.net/TechVault?retryWrites=true&w=majority" + ConnectionString connectionString = new ConnectionString(uri); + MongoClientSettings mongoClientSettings = MongoClientSettings.builder() + .applyConnectionString(connectionString) + .build(); + + return MongoClients.create(mongoClientSettings); + } + + @Override + public Collection getMappingBasePackages() { + return Collections.singleton("TechVault"); + } + +} diff --git a/src/main/java/TechVault/services/comments/CommentService.java b/src/main/java/TechVault/services/comments/CommentService.java new file mode 100644 index 0000000..c19fa7e --- /dev/null +++ b/src/main/java/TechVault/services/comments/CommentService.java @@ -0,0 +1,12 @@ +package TechVault.services.comments; + +import java.util.List; + +import TechVault.services.comments.model.CommentResponse; + +public interface CommentService { + + public List getComments (String contentId); + + public void addComment(String contentId, String parentCommentId, String userName, String comment); +} diff --git a/src/main/java/TechVault/services/comments/CommentServiceImpl.java b/src/main/java/TechVault/services/comments/CommentServiceImpl.java new file mode 100644 index 0000000..a96a93e --- /dev/null +++ b/src/main/java/TechVault/services/comments/CommentServiceImpl.java @@ -0,0 +1,51 @@ +package TechVault.services.comments; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import com.google.common.base.Strings; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import TechVault.services.comments.model.Comment; +import TechVault.services.comments.model.CommentResponse; +import TechVault.services.comments.persistence.CommentDao; + +@Service +public class CommentServiceImpl implements CommentService { + + @Autowired + private CommentDao commentDao; + + @Override + public List getComments(String contentId) { + + List comments = commentDao.getCommentsByBlog(contentId); + Map map = new HashMap<>(); + List result = new ArrayList<>(); + for (Comment comment : comments) { + CommentResponse commentResponse = new CommentResponse(comment); + if (Strings.isNullOrEmpty(comment.getParentCommentId())) { + result.add(commentResponse); + } + map.put(comment.getCommentId(), commentResponse); + } + for (Comment comment : comments) { + if (!Strings.isNullOrEmpty(comment.getParentCommentId())) { + CommentResponse parent = map.get(comment.getParentCommentId()); + parent.getChildComments().add(map.get(comment.getCommentId())); + } + } + return result; + } + + @Override + public void addComment(String contentId, String parentCommentId, String userName, String comment) { + commentDao.addComment(contentId, parentCommentId, userName, comment); + } + +} diff --git a/src/main/java/TechVault/services/comments/controller/CommentController.java b/src/main/java/TechVault/services/comments/controller/CommentController.java new file mode 100644 index 0000000..78d1bd7 --- /dev/null +++ b/src/main/java/TechVault/services/comments/controller/CommentController.java @@ -0,0 +1,70 @@ +package TechVault.services.comments.controller; + +import java.util.List; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import TechVault.services.comments.CommentService; +import TechVault.services.comments.model.CommentResponse; + +@Validated +@RestController +@RequestMapping("comment") +public class CommentController { + private static final Logger LOGGER = LoggerFactory.getLogger(CommentController.class); + + @Autowired + private CommentService commentService; + + /** + * To the the profile of the user corresponding to the user id. + * @return A Response entity which will have all the user details. + */ + @RequestMapping(method = RequestMethod.GET, value = "/{contentId}") + public ResponseEntity getComments(@PathVariable String contentId) { + List comments = null; + try { + comments = commentService.getComments(contentId); + } catch (Exception e) { + LOGGER.error("Unable to get comments ", e); + return new ResponseEntity<>("ERROR", HttpStatus.INTERNAL_SERVER_ERROR); + } + return new ResponseEntity<>(comments, HttpStatus.OK); + } + + /** + * To the the profile of the user corresponding to the user id. + * @return A Response entity which will have all the user details. + */ + @RequestMapping(method = RequestMethod.POST, value = "/postComment", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity postComment(@RequestBody String commentJson) { + + JsonObject commentBody = JsonParser.parseString(commentJson).getAsJsonObject(); + try { + commentService.addComment(commentBody.get("contentId").getAsString(), + commentBody.get("parentCommentId").getAsString(), + commentBody.get("userName").getAsString(), + commentBody.get("comment").getAsString()); + } catch (Exception e) { + LOGGER.error("Error while posting comments", e); + return new ResponseEntity<>("ERROR", HttpStatus.INTERNAL_SERVER_ERROR); + } + return new ResponseEntity<>("SUCCESS", HttpStatus.OK); + } + +} diff --git a/src/main/java/TechVault/services/comments/model/Comment.java b/src/main/java/TechVault/services/comments/model/Comment.java new file mode 100644 index 0000000..ea81c95 --- /dev/null +++ b/src/main/java/TechVault/services/comments/model/Comment.java @@ -0,0 +1,35 @@ +package TechVault.services.comments.model; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +@Document(collection = "comments") +@Builder +@Getter +@Setter +public class Comment { + @Id + private String commentId; + + @Indexed + @Field(name = "contentId") + private String contentId; + + @Field(name = "parentCommentId") + private String parentCommentId; + + @Field(name = "userName") + private String userName; + + @Field(name = "postedTime") + private String postedTime; + + @Field(name = "comment") + private String comment; + +} diff --git a/src/main/java/TechVault/services/comments/model/CommentResponse.java b/src/main/java/TechVault/services/comments/model/CommentResponse.java new file mode 100644 index 0000000..1c1a3e1 --- /dev/null +++ b/src/main/java/TechVault/services/comments/model/CommentResponse.java @@ -0,0 +1,27 @@ +package TechVault.services.comments.model; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +@AllArgsConstructor +public class CommentResponse { + + public CommentResponse (Comment comment ) { + this(comment.getCommentId(), comment.getContentId(), + comment.getUserName(), comment.getPostedTime(), comment.getComment(), + new ArrayList<>()); + } + + private String commentId; + private String contentId; + private String userName; + private String postedTime; + private String comment; + private List childComments; +} diff --git a/src/main/java/TechVault/services/comments/persistence/CommentDao.java b/src/main/java/TechVault/services/comments/persistence/CommentDao.java new file mode 100644 index 0000000..772a55b --- /dev/null +++ b/src/main/java/TechVault/services/comments/persistence/CommentDao.java @@ -0,0 +1,13 @@ +package TechVault.services.comments.persistence; + +import java.util.List; + +import TechVault.services.comments.model.Comment; + +public interface CommentDao { + + public List getCommentsByBlog(String blogUUID); + + public void addComment(String contentId, String parentCommentId, String userName, String comment); + +} diff --git a/src/main/java/TechVault/services/comments/persistence/CommentDaoImpl.java b/src/main/java/TechVault/services/comments/persistence/CommentDaoImpl.java new file mode 100644 index 0000000..8fc6baa --- /dev/null +++ b/src/main/java/TechVault/services/comments/persistence/CommentDaoImpl.java @@ -0,0 +1,42 @@ +package TechVault.services.comments.persistence; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import TechVault.services.comments.model.Comment; + + +@Component +public class CommentDaoImpl implements CommentDao { + + private static final Logger LOGGER = LoggerFactory.getLogger(CommentDaoImpl.class); + private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME; + + @Autowired + private CommentRepository commentRepository; + + @Override + public List getCommentsByBlog(String contentId) { + return commentRepository.findByContentIdOrderByPostedTimeDesc(contentId); + } + + @Override + public void addComment(String contentId, String parentCommentId, String userName, String comment) { + commentRepository.save(Comment.builder() + .parentCommentId(parentCommentId) + .userName(userName) + .contentId(contentId) + .comment(comment) + .postedTime(LocalDateTime.now().format(formatter)) + .build()); + + LOGGER.info("Successfully save comment for user: {} and contentId: {}", userName, contentId); + } + +} diff --git a/src/main/java/TechVault/services/comments/persistence/CommentRepository.java b/src/main/java/TechVault/services/comments/persistence/CommentRepository.java new file mode 100644 index 0000000..56e84cb --- /dev/null +++ b/src/main/java/TechVault/services/comments/persistence/CommentRepository.java @@ -0,0 +1,13 @@ +package TechVault.services.comments.persistence; + +import TechVault.services.comments.model.Comment; + +import java.util.List; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CommentRepository extends MongoRepository { + public List findByContentIdOrderByPostedTimeDesc(String contentId); +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 211105d..7a66560 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,4 @@ #spring.application.name: TechVault -server.port= 8080 \ No newline at end of file +server.port= 8080 +spring.data.mongodb.uri=mongodb+srv://wenqi:p@cluster0.kf3n4.mongodb.net/TechVault?retryWrites=true&w=majority +spring.data.mongodb.database=TechVault \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..cc090c5 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,47 @@ + + + + + + + + + %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable + + + + + + ${LOGS}/spring-boot-logger.log + + %d %p %C{1.} [%t] %m%n + + + + + ${LOGS}/archived/spring-boot-logger-%d{yyyy-MM-dd}.%i.log + + + 10MB + + + + + + + + + + + + + + + + + \ No newline at end of file