feat: comments from users with comment management permission could exempt from review (#5529)

#### What type of PR is this?

/area comment
/area core
/kind improvement

#### What this PR does / why we need it:

> 开启了新评论审核设置,如果是在文章页面登录超级管理员账号进行评论,仍然需要在后台进行审核

#### Which issue(s) this PR fixes:

Fixes #5468 

#### Does this PR introduce a user-facing change?

```release-note
新增评论设置,允许有评论管理权限的用户发布的评论无需审核
```
pull/5568/head
MashiroT 2024-03-22 10:46:06 +08:00 committed by GitHub
parent 4fd6353a58
commit e798866eb7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 6 deletions

View File

@ -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;

View File

@ -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.")));
})

View File

@ -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.
*

View File

@ -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));