From 4cd6c2f67c195180cbc2a4b090ac89a5c5b10557 Mon Sep 17 00:00:00 2001 From: John Niang Date: Wed, 26 Apr 2023 18:50:14 +0800 Subject: [PATCH] Fix the problem of being able to search private posts after making post private (#3859) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind bug /area core /milestone 2.5.x #### What this PR does / why we need it: This PR adds PostVisibleChangedEvent to synchronizing post indices when post visible is changed, whether from public to private or from private to public. #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/3438 #### Special notes for your reviewer: 1. Install Search plugin 2. Create a post 3. Try to search the post 4. Make post private 5. Try to search the post 6. Make post public 7. Try to search the post #### Does this PR introduce a user-facing change? ```release-note 修复隐藏的文章已然能够被搜索到问题 ``` --- .../extension/reconciler/PostReconciler.java | 29 +++++++-- .../event/post/PostVisibleChangedEvent.java | 27 ++++++++ .../app/search/post/PostEventReconciler.java | 61 ++++++++----------- .../reconciler/PostReconcilerTest.java | 6 +- 4 files changed, 80 insertions(+), 43 deletions(-) create mode 100644 application/src/main/java/run/halo/app/event/post/PostVisibleChangedEvent.java diff --git a/application/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java b/application/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java index 2ab6177f8..df279d46d 100644 --- a/application/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java +++ b/application/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java @@ -10,7 +10,7 @@ import java.util.Set; import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; -import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import run.halo.app.content.PostService; @@ -21,6 +21,7 @@ import run.halo.app.core.extension.content.Post; import run.halo.app.core.extension.content.Snapshot; import run.halo.app.event.post.PostPublishedEvent; import run.halo.app.event.post.PostUnpublishedEvent; +import run.halo.app.event.post.PostVisibleChangedEvent; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.ExtensionOperator; import run.halo.app.extension.MetadataUtil; @@ -57,7 +58,7 @@ public class PostReconciler implements Reconciler { private final PostPermalinkPolicy postPermalinkPolicy; private final CounterService counterService; - private final ApplicationContext applicationContext; + private final ApplicationEventPublisher eventPublisher; @Override public Result reconcile(Request request) { @@ -93,7 +94,7 @@ public class PostReconciler implements Reconciler { && Objects.equals(false, post.getSpec().getPublish())) { boolean success = unPublishReconcile(name); if (success) { - applicationContext.publishEvent(new PostUnpublishedEvent(this, name)); + eventPublisher.publishEvent(new PostUnpublishedEvent(this, name)); } return; } @@ -163,7 +164,7 @@ public class PostReconciler implements Reconciler { status.setLastModifyTime(releasedSnapshotOpt.get().getSpec().getLastModifyTime()); client.update(post); - applicationContext.publishEvent(new PostPublishedEvent(this, name)); + eventPublisher.publishEvent(new PostPublishedEvent(this, name)); }); } @@ -231,8 +232,11 @@ public class PostReconciler implements Reconciler { } else { labels.put(Post.DELETED_LABEL, Boolean.FALSE.toString()); } + + fireVisibleChangedEventIfChanged(post); labels.put(Post.VISIBLE_LABEL, Objects.requireNonNullElse(spec.getVisible(), Post.VisibleEnum.PUBLIC).name()); + labels.put(Post.OWNER_LABEL, spec.getOwner()); Instant publishTime = post.getSpec().getPublishTime(); if (publishTime != null) { @@ -254,6 +258,23 @@ public class PostReconciler implements Reconciler { }); } + private void fireVisibleChangedEventIfChanged(Post post) { + var labels = post.getMetadata().getLabels(); + if (labels == null) { + return; + } + var name = post.getMetadata().getName(); + var oldVisibleStr = labels.get(Post.VISIBLE_LABEL); + if (oldVisibleStr != null) { + var oldVisible = Post.VisibleEnum.valueOf(oldVisibleStr); + var expectVisible = post.getSpec().getVisible(); + if (!Objects.equals(oldVisible, expectVisible)) { + eventPublisher.publishEvent( + new PostVisibleChangedEvent(name, oldVisible, expectVisible)); + } + } + } + private void reconcileStatus(String name) { client.fetch(Post.class, name).ifPresent(post -> { final Post oldPost = JsonUtils.deepCopy(post); diff --git a/application/src/main/java/run/halo/app/event/post/PostVisibleChangedEvent.java b/application/src/main/java/run/halo/app/event/post/PostVisibleChangedEvent.java new file mode 100644 index 000000000..4b1355cd1 --- /dev/null +++ b/application/src/main/java/run/halo/app/event/post/PostVisibleChangedEvent.java @@ -0,0 +1,27 @@ +package run.halo.app.event.post; + +import lombok.Data; +import run.halo.app.core.extension.content.Post; + +@Data +public class PostVisibleChangedEvent implements PostEvent { + + private final String postName; + + private final Post.VisibleEnum oldVisible; + + private final Post.VisibleEnum newVisible; + + public PostVisibleChangedEvent(String postName, Post.VisibleEnum oldVisible, + Post.VisibleEnum newVisible) { + this.postName = postName; + this.oldVisible = oldVisible; + this.newVisible = newVisible; + } + + @Override + public String getName() { + return postName; + } + +} diff --git a/application/src/main/java/run/halo/app/search/post/PostEventReconciler.java b/application/src/main/java/run/halo/app/search/post/PostEventReconciler.java index 6b79c5973..320310e97 100644 --- a/application/src/main/java/run/halo/app/search/post/PostEventReconciler.java +++ b/application/src/main/java/run/halo/app/search/post/PostEventReconciler.java @@ -1,10 +1,11 @@ package run.halo.app.search.post; +import static run.halo.app.core.extension.content.Post.VisibleEnum.PUBLIC; + import java.time.Duration; import java.time.Instant; import java.util.List; import java.util.Set; -import java.util.concurrent.CountDownLatch; import lombok.extern.slf4j.Slf4j; import org.springframework.context.SmartLifecycle; import org.springframework.context.event.EventListener; @@ -14,6 +15,7 @@ import run.halo.app.event.post.PostEvent; import run.halo.app.event.post.PostPublishedEvent; import run.halo.app.event.post.PostRecycledEvent; import run.halo.app.event.post.PostUnpublishedEvent; +import run.halo.app.event.post.PostVisibleChangedEvent; import run.halo.app.extension.controller.Controller; import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.DefaultController; @@ -51,21 +53,20 @@ public class PostEventReconciler implements Reconciler, SmartLifecycl @Override public Result reconcile(PostEvent postEvent) { if (postEvent instanceof PostPublishedEvent) { - try { - addPostDoc(postEvent.getName()); - } catch (InterruptedException e) { - throw Exceptions.propagate(e); - } + addPostDoc(postEvent.getName()); } if (postEvent instanceof PostUnpublishedEvent || postEvent instanceof PostRecycledEvent) { - try { + deletePostDoc(postEvent.getName()); + } + if (postEvent instanceof PostVisibleChangedEvent visibleChangedEvent) { + if (PUBLIC.equals(visibleChangedEvent.getOldVisible())) { deletePostDoc(postEvent.getName()); - } catch (InterruptedException e) { - throw Exceptions.propagate(e); + } else if (PUBLIC.equals(visibleChangedEvent.getNewVisible())) { + addPostDoc(postEvent.getName()); } } - return null; + return Result.doNotRetry(); } @Override @@ -95,9 +96,14 @@ public class PostEventReconciler implements Reconciler, SmartLifecycl postEventQueue.addImmediately(recycledEvent); } - void addPostDoc(String postName) throws InterruptedException { - var latch = new CountDownLatch(1); - var disposable = postFinder.getByName(postName) + @EventListener(PostVisibleChangedEvent.class) + public void handlePostVisibleChanged(PostVisibleChangedEvent event) { + postEventQueue.addImmediately(event); + } + + void addPostDoc(String postName) { + postFinder.getByName(postName) + .filter(postVo -> PUBLIC.equals(postVo.getSpec().getVisible())) .map(PostDocUtils::from) .flatMap(postDoc -> extensionGetter.getEnabledExtension(PostSearchService.class) .doOnNext(searchService -> { @@ -108,21 +114,12 @@ public class PostEventReconciler implements Reconciler, SmartLifecycl } }) ) - .doFinally(signalType -> latch.countDown()) - .subscribe(service -> { - }, throwable -> { - throw Exceptions.propagate(throwable); - }); - try { - latch.await(); - } finally { - disposable.dispose(); - } + .then() + .block(); } - void deletePostDoc(String postName) throws InterruptedException { - var latch = new CountDownLatch(1); - var disposable = extensionGetter.getEnabledExtension(PostSearchService.class) + void deletePostDoc(String postName) { + extensionGetter.getEnabledExtension(PostSearchService.class) .doOnNext(searchService -> { try { searchService.removeDocuments(Set.of(postName)); @@ -130,16 +127,8 @@ public class PostEventReconciler implements Reconciler, SmartLifecycl throw Exceptions.propagate(e); } }) - .doFinally(signalType -> latch.countDown()) - .subscribe(service -> { - }, throwable -> { - throw Exceptions.propagate(throwable); - }); - try { - latch.await(); - } finally { - disposable.dispose(); - } + .then() + .block(); } @Override diff --git a/application/src/test/java/run/halo/app/core/extension/reconciler/PostReconcilerTest.java b/application/src/test/java/run/halo/app/core/extension/reconciler/PostReconcilerTest.java index 01e0ef3f4..9cd06b045 100644 --- a/application/src/test/java/run/halo/app/core/extension/reconciler/PostReconcilerTest.java +++ b/application/src/test/java/run/halo/app/core/extension/reconciler/PostReconcilerTest.java @@ -19,7 +19,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEventPublisher; import reactor.core.publisher.Mono; import run.halo.app.content.ContentWrapper; import run.halo.app.content.PostService; @@ -50,7 +50,7 @@ class PostReconcilerTest { private PostService postService; @Mock - private ApplicationContext applicationContext; + private ApplicationEventPublisher eventPublisher; @InjectMocks private PostReconciler postReconciler; @@ -157,7 +157,7 @@ class PostReconcilerTest { verify(client, times(4)).update(captor.capture()); Post value = captor.getValue(); assertThat(value.getStatus().getLastModifyTime()).isEqualTo(lastModifyTime); - verify(applicationContext).publishEvent(any(PostPublishedEvent.class)); + verify(eventPublisher).publishEvent(any(PostPublishedEvent.class)); } @Test