diff --git a/.github/workflows/comment.yaml b/.github/workflows/comment.yaml index 69450074..b296a247 100644 --- a/.github/workflows/comment.yaml +++ b/.github/workflows/comment.yaml @@ -56,7 +56,7 @@ jobs: DB_OPTIONS: serverTimezone=Asia/Shanghai TRACING_PROBABILITY: 0.1 OTLP_ENDPOINT: http://localhost:4318/v1/traces - VOTE_SERVICE_BASE_URL: http://localhost:8081 + VOTE_SERVICE_BASE_URL: http://localhost:5000 USER_SERVICE_BASE_URL: http://localhost:5000 REDIS_HOST: localhost diff --git a/graal/compose.yaml b/graal/compose.yaml index fd7b119d..cff3af93 100644 --- a/graal/compose.yaml +++ b/graal/compose.yaml @@ -59,10 +59,4 @@ services: shauser: image: 'sixwaaaay/shauser:latest-test' ports: - - '5000:5000' - graph: - image: 'sixwaaaay/graph:0.6.0' - ports: - - '8081:8081' - environment: - - 'APP_PORT=8081' \ No newline at end of file + - '5000:5000' \ No newline at end of file diff --git a/graal/pom.xml b/graal/pom.xml index c2e2ffee..efbe011d 100644 --- a/graal/pom.xml +++ b/graal/pom.xml @@ -18,7 +18,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.3 + 3.3.4 io.sixwaaaay @@ -55,6 +55,17 @@ org.springframework.boot spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-jetty io.micrometer @@ -86,6 +97,7 @@ org.projectlombok lombok + 1.18.34 true diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/client/UserClient.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/client/UserClient.java index b80d1ebf..852e1684 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/client/UserClient.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/client/UserClient.java @@ -14,20 +14,20 @@ package io.sixwaaaay.sharingcomment.client; -import io.sixwaaaay.sharingcomment.transmission.GetMultipleUserReply; -import io.sixwaaaay.sharingcomment.transmission.GetUserReply; +import io.sixwaaaay.sharingcomment.domain.User; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.service.annotation.GetExchange; import java.util.Collection; +import java.util.List; public interface UserClient { @GetExchange("/users/{user_id}") - GetUserReply getUser(@PathVariable("user_id") long id, @RequestHeader(value = "Authorization", required = false) String token); + User getUser(@PathVariable("user_id") long id, @RequestHeader(value = "Authorization", required = false) String token); @GetExchange("/users") - GetMultipleUserReply getManyUser(@RequestParam("ids") Collection ids, @RequestHeader(value = "Authorization", required = false) String token); + List getManyUser(@RequestParam("ids") Collection ids, @RequestHeader(value = "Authorization", required = false) String token); } \ No newline at end of file diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/client/UserClientWrapper.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/client/UserClientWrapper.java index e1dbb84d..2048ac9f 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/client/UserClientWrapper.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/client/UserClientWrapper.java @@ -18,12 +18,12 @@ import io.github.resilience4j.decorators.Decorators; import io.github.resilience4j.retry.Retry; import io.github.resilience4j.retry.RetryConfig; -import io.sixwaaaay.sharingcomment.transmission.GetMultipleUserReply; -import io.sixwaaaay.sharingcomment.transmission.GetUserReply; +import io.sixwaaaay.sharingcomment.domain.User; import org.springframework.web.client.HttpClientErrorException; import java.time.Duration; import java.util.Collection; +import java.util.List; public class UserClientWrapper implements UserClient { private final UserClient userClient; @@ -36,7 +36,8 @@ public UserClientWrapper(UserClient userClient) { this.userClient = userClient; var name = "userClient"; - var retryConfig = RetryConfig.custom() + var retryConfig = RetryConfig + .custom() .maxAttempts(3) .waitDuration(Duration.ofMillis(1000)) .ignoreExceptions( @@ -46,7 +47,8 @@ public UserClientWrapper(UserClient userClient) { HttpClientErrorException.Unauthorized.class ).build(); retry = Retry.of(name, retryConfig); - var circuitBreakerConfig = CircuitBreakerConfig.custom() + var circuitBreakerConfig = CircuitBreakerConfig + .custom() .failureRateThreshold(50) .ignoreExceptions( HttpClientErrorException.NotFound.class, @@ -62,8 +64,9 @@ public UserClientWrapper(UserClient userClient) { } @Override - public GetUserReply getUser(long id, String token) { - var getUserReplySupplier = Decorators.ofSupplier(() -> userClient.getUser(id, token)) + public User getUser(long id, String token) { + var getUserReplySupplier = Decorators + .ofSupplier(() -> userClient.getUser(id, token)) .withCircuitBreaker(circuitBreaker) .withRetry(retry) .decorate(); @@ -72,8 +75,9 @@ public GetUserReply getUser(long id, String token) { @Override - public GetMultipleUserReply getManyUser(Collection ids, String token) { - var getManyUserReplySupplier = Decorators.ofSupplier(() -> userClient.getManyUser(ids, token)) + public List getManyUser(Collection ids, String token) { + var getManyUserReplySupplier = Decorators + .ofSupplier(() -> userClient.getManyUser(ids, token)) .withCircuitBreaker(circuitBreaker) .withRetry(retry) .decorate(); diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/client/VoteClient.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/client/VoteClient.java index e52a4d73..7f356763 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/client/VoteClient.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/client/VoteClient.java @@ -14,22 +14,21 @@ package io.sixwaaaay.sharingcomment.client; -import io.sixwaaaay.sharingcomment.transmission.*; -import jakarta.validation.Valid; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.service.annotation.PostExchange; +import java.util.List; -public interface VoteClient { - @PostExchange("/item/add") - VoteReply itemAdd(@Valid @RequestBody VoteReq req); - - @PostExchange("/item/delete") - VoteReply itemDelete(@Valid @RequestBody VoteReq req); - @PostExchange("/item/exists") - VoteExistsReply exists(@Valid @RequestBody VoteExistsReq req); +public interface VoteClient { - @PostExchange("/item/scan") - ScanVotedReply scan(@RequestBody ScanVotedReq req); + /** + * query whether the objectIds(aka commentIds) is liked. + * @param objectIds the id list of the object(aka comment) + * @param token the token of the user + * @return the list of the objectIds which is liked + */ + @PostExchange("/graph/comments/likes") + List queryInLikes(@RequestBody List objectIds, @RequestHeader(value = "Authorization", required = false) String token); } diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/client/VoteClientWrapper.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/client/VoteClientWrapper.java index ed3313df..d6920bbd 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/client/VoteClientWrapper.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/client/VoteClientWrapper.java @@ -18,10 +18,9 @@ import io.github.resilience4j.decorators.Decorators; import io.github.resilience4j.retry.Retry; import io.github.resilience4j.retry.RetryConfig; -import io.sixwaaaay.sharingcomment.transmission.*; import java.time.Duration; -import java.util.Set; +import java.util.List; public class VoteClientWrapper implements VoteClient { @@ -47,39 +46,19 @@ public VoteClientWrapper(VoteClient voteClient) { .waitDuration(Duration.ofMillis(1000)) .build() ); - - @Override - public VoteReply itemAdd(VoteReq req) { - return voteClient.itemAdd(req); - } - - @Override - public VoteReply itemDelete(VoteReq req) { - return voteClient.itemDelete(req); - } - /** - * wrap the exists method with resilience4j circuit breaker and retry - * fallback with an empty set if the circuit breaker is open + * wrap the queryInLikes method with resilience4j circuit breaker and retry + * @param commentIds list of object ids + * @param token user token + * @return list of object ids that user liked */ @Override - public VoteExistsReply exists(VoteExistsReq req) { - var existsReplySupplier = Decorators.ofSupplier(() -> voteClient.exists(req)) + public List queryInLikes(List commentIds, String token) { + var queryInLikesSupplier = Decorators.ofSupplier(() -> voteClient.queryInLikes(commentIds, token)) .withCircuitBreaker(circuitBreaker) .withRetry(retry) - .withFallback(this::fallback) + .withFallback((e) -> List.of()) .decorate(); - return existsReplySupplier.get(); - } - - @Override - public ScanVotedReply scan(ScanVotedReq req) { - return voteClient.scan(req); - } - - private VoteExistsReply fallback(Throwable e) { - var reply = new VoteExistsReply(); - reply.setExists(Set.of()); - return reply; + return queryInLikesSupplier.get(); } } 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 0d7d8541..f35936af 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/controller/CommentController.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/controller/CommentController.java @@ -98,6 +98,12 @@ public Comment createComment(@Valid @RequestBody CommentRequest request) { return comment; } + /** + * delete specified comment + * + * @param id the id of the comment to be deleted + * @param request the request body + */ @DeleteMapping("/{id}") public void deleteComment( @PathVariable("id") Long id, @@ -111,27 +117,4 @@ public void deleteComment( commentService.deleteComment(comment); } - /** - * vote a comment - * - * @param id the id of comment - */ - @PostMapping("/action/like/{id}") - public void voteComment( - @PathVariable long id) { - var userId = Principal.currentUserId(); - commentService.voteComment(userId, id); - } - - /** - * cancel vote a comment - * - * @param id the id of comment - */ - @DeleteMapping("/action/like/{id}") - public void cancelVoteComment( - @PathVariable long id) { - var userId = Principal.currentUserId(); - commentService.cancelVoteComment(userId, id); - } } 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 5d2ffdfd..3f264b06 100644 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/service/CommentService.java +++ b/graal/src/main/java/io/sixwaaaay/sharingcomment/service/CommentService.java @@ -19,8 +19,6 @@ import io.sixwaaaay.sharingcomment.domain.*; import io.sixwaaaay.sharingcomment.repository.CommentRepository; import io.sixwaaaay.sharingcomment.request.Principal; -import io.sixwaaaay.sharingcomment.transmission.VoteExistsReq; -import io.sixwaaaay.sharingcomment.transmission.VoteReq; import io.sixwaaaay.sharingcomment.util.DbContext; import io.sixwaaaay.sharingcomment.util.DbContextEnum; import org.springframework.beans.factory.annotation.Value; @@ -148,26 +146,6 @@ public void deleteComment(Comment comment) { commentRepo.deleteByIdAndUserId(comment.getId(), comment.getUserId()); } - /** - * vote a comment - * - * @param userId the id of the user who is requesting - * @param commentId the id of the comment to be voted - */ - public void voteComment(long userId, long commentId) { - voteClient.itemAdd(new VoteReq(userId, commentId)); - } - - /** - * cancel vote a comment - * - * @param userId the id of the user who is requesting - * @param commentId the id of the comment to be unvoted - */ - public void cancelVoteComment(Long userId, Long commentId) { - voteClient.itemDelete(new VoteReq(userId, commentId)); - } - /** * compose the comment, fill the user info and vote status @@ -178,7 +156,7 @@ private void composeSingleComment(Comment comment) { if (enableUser) { var token = Principal.currentToken(); var user = userClient.getUser(comment.getUserId(), token); - comment.setUser(user.getUser()); + comment.setUser(user); } } @@ -219,7 +197,7 @@ private Map composeCommentAuthor(List comments) { var token = Principal.currentToken(); var users = userClient.getManyUser(userList, token); // covert to map - return users.getUsers().stream().collect(Collectors.toMap(User::getId, identity())); + return users.stream().collect(Collectors.toMap(User::getId, identity())); } /** @@ -235,9 +213,9 @@ private Set composeCommentVoteStatus(List comments, Long userId) } var commentIdList = flatComments(comments).map(Comment::getId).toList(); // check if voted - var voteExistsReply = voteClient.exists(new VoteExistsReq(userId, commentIdList)); + var votedIds = voteClient.queryInLikes(commentIdList, Principal.currentToken()); // convert to set - return voteExistsReply.getExists(); + return Set.copyOf(votedIds); } /** diff --git a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteExistsReq.java b/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteExistsReq.java deleted file mode 100644 index a1dd021f..00000000 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteExistsReq.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.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; - -@Data -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) { - this.type = "user"; - this.targetType = "comment"; - this.subjectId = subjectId; - this.targetIds = 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 deleted file mode 100644 index 9f213e3b..00000000 --- a/graal/src/main/java/io/sixwaaaay/sharingcomment/transmission/VoteReq.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.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; - -@Data - -public class VoteReq { - private String type; - @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) { - this.type = "user"; - this.targetType = "comment"; - this.subjectId = subjectId; - this.targetId = targetId; - } -} diff --git a/graal/src/test/java/io/sixwaaaay/sharingcomment/SharingCommentApplicationTests.java b/graal/src/test/java/io/sixwaaaay/sharingcomment/SharingCommentApplicationTests.java index 1852a3e4..611d2668 100644 --- a/graal/src/test/java/io/sixwaaaay/sharingcomment/SharingCommentApplicationTests.java +++ b/graal/src/test/java/io/sixwaaaay/sharingcomment/SharingCommentApplicationTests.java @@ -118,25 +118,6 @@ public void deleteComments() throws Exception { .andExpect(MockMvcResultMatchers.status().is4xxClientError()); } - @Test - public void voteComment() throws Exception { - var token = jwtUtil.generateToken("n", "1"); - mockMvc.perform(MockMvcRequestBuilders.post("/comments/action/like/1") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer " + token)) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mockMvc.perform(MockMvcRequestBuilders.delete("/comments/action/like/1") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer " + token)) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mockMvc.perform(MockMvcRequestBuilders.delete("/comments/action/like/1") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()); - - } - @Test void testGetUser() {