diff --git a/.github/workflows/comment.yaml b/.github/workflows/comment.yaml index 80509067..cf03dfb8 100644 --- a/.github/workflows/comment.yaml +++ b/.github/workflows/comment.yaml @@ -67,6 +67,7 @@ jobs: flags: comments files: ./graal/target/site/jacoco/jacoco.xml verbose: true + token: ${{ secrets.CODECOV_TOKEN }} release: runs-on: ubuntu-latest diff --git a/graal/init.sql b/graal/init.sql index 53b960cc..8845198c 100644 --- a/graal/init.sql +++ b/graal/init.sql @@ -27,6 +27,7 @@ CREATE TABLE `comments` `created_at` datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)), `reply_count` int NOT NULL DEFAULT '0', `like_count` int NOT NULL DEFAULT '0', + `refer_to` bigint, PRIMARY KEY (`id`), INDEX `finder` (`belong_to`, `reply_to`, `id`) ) ENGINE = InnoDB diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/config/JacksonConfig.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/config/JacksonConfig.java new file mode 100644 index 00000000..70797a8e --- /dev/null +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/config/JacksonConfig.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023-2024 sixwaaaay. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.sixwaaaay.sharingcomment.config; + +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JacksonConfig { + + @Bean + public Jackson2ObjectMapperBuilderCustomizer customizer() { + return builder -> { + builder.serializerByType(Long.class, ToStringSerializer.instance); + builder.serializerByType(Long.TYPE, ToStringSerializer.instance); + }; + } + +} diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/controller/CommentController.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/controller/CommentController.java index 45ad38b0..e1784abe 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/controller/CommentController.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/controller/CommentController.java @@ -23,6 +23,7 @@ import io.sixwaaaay.sharingcomment.service.CommentService; import jakarta.validation.Valid; import lombok.AllArgsConstructor; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; @@ -34,6 +35,7 @@ @RestController @RequestMapping("/comments") @AllArgsConstructor +@Validated public class CommentController { private final CommentService commentService; @@ -64,11 +66,11 @@ public CommentResult getMainCommentList( public ReplyResult getReplyCommentList( @RequestParam("belong_to") Long belongTo, @RequestParam("reply_to") Long replyTo, - @RequestParam("page") Optional id, + @RequestParam(value = "page", defaultValue = "0") long id, @RequestParam(value = "size", defaultValue = "10") Integer size ) { var userId = principal.get().map(Principal::getId).orElse(0L); - return commentService.getReplyCommentList(belongTo, replyTo, id.orElse(0L), size, userId); + return commentService.getReplyCommentList(belongTo, replyTo, id, size, userId); } /** @@ -83,6 +85,7 @@ public Comment createComment(@Valid @RequestBody CommentRequest request) { comment.setUserId(id); // throw exception if principal is empty comment.setBelongTo(request.getBelongTo()); comment.setContent(request.getContent()); + comment.setReferTo(request.getReferTo()); comment.setReplyTo(request.getReplyTo()); var epochSecond = System.currentTimeMillis() / 1000; comment.setCreatedAt(LocalDateTime.ofEpochSecond(epochSecond, 0, ZoneOffset.ofHours(8))); diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/domain/Comment.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/domain/Comment.java index 04c92382..220aff6e 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/domain/Comment.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/domain/Comment.java @@ -68,6 +68,13 @@ public class Comment implements Serializable { @JsonProperty("reply_to") private Long replyTo; + /** + * The unique identifier of the parent comment. + */ + @Column("refer_to") + @JsonProperty("refer_to") + private Long referTo; + /** * The unique identifier of the entity to which this comment belongs. */ diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/request/CommentRequest.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/request/CommentRequest.java index 04d451ff..567295a5 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/request/CommentRequest.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/request/CommentRequest.java @@ -15,6 +15,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotNull; import lombok.Data; import org.hibernate.validator.constraints.Length; @@ -41,6 +42,12 @@ public class CommentRequest { @JsonProperty("reply_to") private Long replyTo; + /** + * The ID of the comment that this comment refers to. + */ + @JsonProperty("refer_to") + private Long referTo; + /** * The ID of the entity to which the comment belongs. * It must be greater than 0. @@ -49,4 +56,12 @@ public class CommentRequest { @Range(min = 1, message = "belong_to must be greater than 0") @JsonProperty("belong_to") private Long belongTo; + + /** + * reply_to and parent_id must be both null or not null at the same time + */ + @AssertTrue(message = "reply_to and refer_to must be both null or not null at the same time") + public boolean isValid() { + return (replyTo == null && referTo == null) || (replyTo != null && referTo != null); + } } diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/service/CommentService.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/service/CommentService.java index eea65b2b..dcd67d73 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/service/CommentService.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/service/CommentService.java @@ -29,6 +29,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; @@ -117,6 +118,8 @@ public CommentResult getMainCommentList(Long belongTo, Long id, Integer size, Lo public ReplyResult getReplyCommentList(Long belongTo, Long replyTo, Long id, Integer size, Long userId) { DbContext.set(DbContextEnum.READ); // set read context var comments = commentRepo.findByBelongToAndReplyToAndIdGreaterThanOrderByIdAsc(belongTo, replyTo, id, Limit.of(size)); + // sort by id asc + comments.sort(Comparator.comparingLong(Comment::getId)); composeComment(comments, userId); var result = new ReplyResult(); result.setComments(comments); diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/ScanVotedReq.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/ScanVotedReq.java index e6825a62..0884f639 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/ScanVotedReq.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/ScanVotedReq.java @@ -14,15 +14,19 @@ package io.sixwaaaay.sharingcomment.transmission; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.sixwaaaay.sharingcomment.util.LongRpcSerializer; import lombok.Data; @Data public class ScanVotedReq { private Integer limit; @JsonProperty("subject_id") + @JsonSerialize(using = LongRpcSerializer.class) private Long subjectId; @JsonProperty("target_type") private String targetType; + @JsonSerialize(using = LongRpcSerializer.class) private Long token; private String type; -} +} \ No newline at end of file diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteExistsReq.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteExistsReq.java index 11721214..a1dd021f 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteExistsReq.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteExistsReq.java @@ -14,6 +14,9 @@ package io.sixwaaaay.sharingcomment.transmission; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.sixwaaaay.sharingcomment.util.ListLongRpcSerializer; +import io.sixwaaaay.sharingcomment.util.LongRpcSerializer; import lombok.Data; import java.util.List; @@ -22,10 +25,12 @@ public class VoteExistsReq { private String type; @JsonProperty("subject_id") + @JsonSerialize(using = LongRpcSerializer.class) private Long subjectId; @JsonProperty("target_type") private String targetType; @JsonProperty("target_ids") + @JsonSerialize(using = ListLongRpcSerializer.class) private List targetIds; public VoteExistsReq(long subjectId, List targetIds) { diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteReq.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteReq.java index db8bb0fa..9f213e3b 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteReq.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteReq.java @@ -14,6 +14,8 @@ package io.sixwaaaay.sharingcomment.transmission; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.sixwaaaay.sharingcomment.util.LongRpcSerializer; import jakarta.validation.constraints.NotNull; import lombok.Data; import org.hibernate.validator.constraints.Range; @@ -25,12 +27,14 @@ public class VoteReq { @NotNull @Range(min = 1, message = "subject_id must be greater than 0") @JsonProperty("subject_id") + @JsonSerialize(using = LongRpcSerializer.class) private Long subjectId; @JsonProperty("target_type") private String targetType; @NotNull @Range(min = 1, message = "target_id must be greater than 0") @JsonProperty("target_id") + @JsonSerialize(using = LongRpcSerializer.class) private Long targetId; public VoteReq(long subjectId, long targetId) { diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/util/ListLongRpcSerializer.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/util/ListLongRpcSerializer.java new file mode 100644 index 00000000..0474b7c7 --- /dev/null +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/util/ListLongRpcSerializer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023-2024 sixwaaaay. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.sixwaaaay.sharingcomment.util; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.util.List; + +public class ListLongRpcSerializer extends JsonSerializer> { + @Override + public void serialize(List value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeStartArray(); + for (var v : value) { + gen.writeNumber(v); + } + gen.writeEndArray(); + } +} diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/util/LongRpcSerializer.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/util/LongRpcSerializer.java new file mode 100644 index 00000000..3dc54e17 --- /dev/null +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/util/LongRpcSerializer.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023-2024 sixwaaaay. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.sixwaaaay.sharingcomment.util; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; + +public class LongRpcSerializer extends JsonSerializer { + @Override + public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeNumber(value); + } +} + diff --git a/graal/src/test/java/io/sixwaaaay/sharingcomment/SharingCommentApplicationTests.java b/graal/src/test/java/io/sixwaaaay/sharingcomment/SharingCommentApplicationTests.java index af5b2f12..99a7ef99 100644 --- a/graal/src/test/java/io/sixwaaaay/sharingcomment/SharingCommentApplicationTests.java +++ b/graal/src/test/java/io/sixwaaaay/sharingcomment/SharingCommentApplicationTests.java @@ -84,7 +84,7 @@ public void getReplyCommentListTest() throws Exception { @Test public void createCommentTest() throws Exception { var token = jwtUtil.generateToken("n", "1111111"); - var json = "{ \"content\": \"This is a test comment\", \"reply_to\": 1, \"belong_to\": 1 }"; + var json = "{ \"content\": \"This is a test comment\", \"reply_to\": 1, \"belong_to\": 1, \"refer_to\": 1 }"; mockMvc.perform(MockMvcRequestBuilders.post("/comments") .content(json) .contentType(MediaType.APPLICATION_JSON)