diff --git a/application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java b/application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java index dc2f33439..b4a0a2257 100644 --- a/application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java +++ b/application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java @@ -5,6 +5,7 @@ import static run.halo.app.extension.index.query.QueryFactory.equal; import static run.halo.app.extension.index.query.QueryFactory.isNull; import java.time.Instant; +import java.util.Set; import java.util.function.Function; import org.apache.commons.lang3.BooleanUtils; import org.springframework.data.domain.Sort; @@ -16,6 +17,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.core.extension.User; import run.halo.app.core.extension.content.Comment; +import run.halo.app.core.extension.service.RoleService; import run.halo.app.core.extension.service.UserService; import run.halo.app.extension.Extension; import run.halo.app.extension.ListOptions; @@ -30,6 +32,7 @@ import run.halo.app.infra.exception.AccessDeniedException; import run.halo.app.metrics.CounterService; import run.halo.app.metrics.MeterUtils; import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.security.authorization.AuthorityUtils; /** * Comment service implementation. @@ -42,6 +45,7 @@ public class CommentServiceImpl implements CommentService { private final ReactiveExtensionClient client; private final UserService userService; + private final RoleService roleService; private final ExtensionComponentsFinder extensionComponentsFinder; private final SystemConfigurableEnvironmentFetcher environmentFetcher; @@ -50,12 +54,14 @@ public class CommentServiceImpl implements CommentService { public CommentServiceImpl(ReactiveExtensionClient client, UserService userService, ExtensionComponentsFinder extensionComponentsFinder, SystemConfigurableEnvironmentFetcher environmentFetcher, - CounterService counterService) { + CounterService counterService, RoleService roleService + ) { this.client = client; this.userService = userService; this.extensionComponentsFinder = extensionComponentsFinder; this.environmentFetcher = environmentFetcher; this.counterService = counterService; + this.roleService = roleService; } @Override @@ -113,7 +119,21 @@ public class CommentServiceImpl implements CommentService { } // populate owner from current user return fetchCurrentUser() - .map(this::toCommentOwner) + .flatMap(currentUser -> ReactiveSecurityContextHolder.getContext() + .flatMap(securityContext -> { + var authentication = securityContext.getAuthentication(); + var roles = AuthorityUtils.authoritiesToRoles( + authentication.getAuthorities()); + return roleService.contains(roles, + Set.of(AuthorityUtils.COMMENT_MANAGEMENT_ROLE_NAME)) + .doOnNext(result -> { + if (result) { + comment.getSpec().setApproved(true); + comment.getSpec().setApprovedTime(Instant.now()); + } + }) + .thenReturn(toCommentOwner(currentUser)); + })) .map(owner -> { comment.getSpec().setOwner(owner); return comment; diff --git a/application/src/main/java/run/halo/app/content/comment/ReplyServiceImpl.java b/application/src/main/java/run/halo/app/content/comment/ReplyServiceImpl.java index 2594d5b99..9b6c8d198 100644 --- a/application/src/main/java/run/halo/app/content/comment/ReplyServiceImpl.java +++ b/application/src/main/java/run/halo/app/content/comment/ReplyServiceImpl.java @@ -6,6 +6,7 @@ import static run.halo.app.extension.index.query.QueryFactory.isNull; import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate; import java.time.Instant; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import lombok.RequiredArgsConstructor; @@ -19,6 +20,7 @@ import reactor.core.publisher.Mono; import run.halo.app.core.extension.User; import run.halo.app.core.extension.content.Comment; import run.halo.app.core.extension.content.Reply; +import run.halo.app.core.extension.service.RoleService; import run.halo.app.core.extension.service.UserService; import run.halo.app.extension.Extension; import run.halo.app.extension.ListOptions; @@ -29,6 +31,7 @@ import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.router.selector.FieldSelector; import run.halo.app.metrics.CounterService; import run.halo.app.metrics.MeterUtils; +import run.halo.app.security.authorization.AuthorityUtils; /** * A default implementation of {@link ReplyService}. @@ -42,6 +45,7 @@ public class ReplyServiceImpl implements ReplyService { private final ReactiveExtensionClient client; private final UserService userService; + private final RoleService roleService; private final CounterService counterService; @Override @@ -75,10 +79,24 @@ public class ReplyServiceImpl implements ReplyService { } // populate owner from current user return fetchCurrentUser() - .map(user -> { - replyToUse.getSpec().setOwner(toCommentOwner(user)); - return replyToUse; - }) + .flatMap(user -> + ReactiveSecurityContextHolder.getContext() + .flatMap(securityContext -> { + var authentication = securityContext.getAuthentication(); + var roles = AuthorityUtils.authoritiesToRoles( + authentication.getAuthorities()); + return roleService.contains(roles, + Set.of(AuthorityUtils.COMMENT_MANAGEMENT_ROLE_NAME)) + .doOnNext(result -> { + if (result) { + reply.getSpec().setApproved(true); + reply.getSpec().setApprovedTime(Instant.now()); + } + replyToUse.getSpec().setOwner(toCommentOwner(user)); + }) + .thenReturn(replyToUse); + }) + ) .switchIfEmpty( Mono.error(new IllegalArgumentException("Reply owner must not be null."))); }) diff --git a/application/src/main/java/run/halo/app/security/authorization/AuthorityUtils.java b/application/src/main/java/run/halo/app/security/authorization/AuthorityUtils.java index fce28a677..941595cab 100644 --- a/application/src/main/java/run/halo/app/security/authorization/AuthorityUtils.java +++ b/application/src/main/java/run/halo/app/security/authorization/AuthorityUtils.java @@ -24,6 +24,8 @@ public enum AuthorityUtils { public static final String ANONYMOUS_ROLE_NAME = "anonymous"; + public static final String COMMENT_MANAGEMENT_ROLE_NAME = "role-template-manage-comments"; + /** * Converts an array of GrantedAuthority objects to a role set. * diff --git a/application/src/test/java/run/halo/app/content/comment/CommentServiceImplTest.java b/application/src/test/java/run/halo/app/content/comment/CommentServiceImplTest.java index 47078eb80..e0c9d06fb 100644 --- a/application/src/test/java/run/halo/app/content/comment/CommentServiceImplTest.java +++ b/application/src/test/java/run/halo/app/content/comment/CommentServiceImplTest.java @@ -10,6 +10,7 @@ import static org.mockito.Mockito.when; import java.util.List; import java.util.Map; +import java.util.Set; import org.json.JSONException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -33,6 +34,7 @@ import run.halo.app.core.extension.Counter; import run.halo.app.core.extension.User; import run.halo.app.core.extension.content.Comment; import run.halo.app.core.extension.content.Post; +import run.halo.app.core.extension.service.RoleService; import run.halo.app.core.extension.service.UserService; import run.halo.app.extension.ListOptions; import run.halo.app.extension.ListResult; @@ -46,6 +48,7 @@ import run.halo.app.infra.utils.JsonUtils; import run.halo.app.metrics.CounterService; import run.halo.app.metrics.MeterUtils; import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.security.authorization.AuthorityUtils; /** * Tests for {@link CommentServiceImpl}. @@ -65,6 +68,9 @@ class CommentServiceImplTest { @Mock private UserService userService; + @Mock + private RoleService roleService; + @Mock private ExtensionComponentsFinder extensionComponentsFinder; @@ -90,6 +96,10 @@ class CommentServiceImplTest { when(client.fetch(eq(User.class), eq("C-owner"))) .thenReturn(Mono.empty()); + when(roleService.contains(Set.of("USER"), + Set.of(AuthorityUtils.COMMENT_MANAGEMENT_ROLE_NAME))) + .thenReturn(Mono.just(false)); + PostCommentSubject postCommentSubject = Mockito.mock(PostCommentSubject.class); when(extensionComponentsFinder.getExtensions(eq(CommentSubject.class))) .thenReturn(List.of(postCommentSubject));