mirror of https://github.com/halo-dev/halo
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
parent
4fd6353a58
commit
e798866eb7
|
@ -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 static run.halo.app.extension.index.query.QueryFactory.isNull;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
@ -16,6 +17,7 @@ import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.core.extension.User;
|
import run.halo.app.core.extension.User;
|
||||||
import run.halo.app.core.extension.content.Comment;
|
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.core.extension.service.UserService;
|
||||||
import run.halo.app.extension.Extension;
|
import run.halo.app.extension.Extension;
|
||||||
import run.halo.app.extension.ListOptions;
|
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.CounterService;
|
||||||
import run.halo.app.metrics.MeterUtils;
|
import run.halo.app.metrics.MeterUtils;
|
||||||
import run.halo.app.plugin.ExtensionComponentsFinder;
|
import run.halo.app.plugin.ExtensionComponentsFinder;
|
||||||
|
import run.halo.app.security.authorization.AuthorityUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comment service implementation.
|
* Comment service implementation.
|
||||||
|
@ -42,6 +45,7 @@ public class CommentServiceImpl implements CommentService {
|
||||||
|
|
||||||
private final ReactiveExtensionClient client;
|
private final ReactiveExtensionClient client;
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
private final RoleService roleService;
|
||||||
private final ExtensionComponentsFinder extensionComponentsFinder;
|
private final ExtensionComponentsFinder extensionComponentsFinder;
|
||||||
|
|
||||||
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
||||||
|
@ -50,12 +54,14 @@ public class CommentServiceImpl implements CommentService {
|
||||||
public CommentServiceImpl(ReactiveExtensionClient client,
|
public CommentServiceImpl(ReactiveExtensionClient client,
|
||||||
UserService userService, ExtensionComponentsFinder extensionComponentsFinder,
|
UserService userService, ExtensionComponentsFinder extensionComponentsFinder,
|
||||||
SystemConfigurableEnvironmentFetcher environmentFetcher,
|
SystemConfigurableEnvironmentFetcher environmentFetcher,
|
||||||
CounterService counterService) {
|
CounterService counterService, RoleService roleService
|
||||||
|
) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.extensionComponentsFinder = extensionComponentsFinder;
|
this.extensionComponentsFinder = extensionComponentsFinder;
|
||||||
this.environmentFetcher = environmentFetcher;
|
this.environmentFetcher = environmentFetcher;
|
||||||
this.counterService = counterService;
|
this.counterService = counterService;
|
||||||
|
this.roleService = roleService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -113,7 +119,21 @@ public class CommentServiceImpl implements CommentService {
|
||||||
}
|
}
|
||||||
// populate owner from current user
|
// populate owner from current user
|
||||||
return fetchCurrentUser()
|
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 -> {
|
.map(owner -> {
|
||||||
comment.getSpec().setOwner(owner);
|
comment.getSpec().setOwner(owner);
|
||||||
return comment;
|
return comment;
|
||||||
|
|
|
@ -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 static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import lombok.RequiredArgsConstructor;
|
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.User;
|
||||||
import run.halo.app.core.extension.content.Comment;
|
import run.halo.app.core.extension.content.Comment;
|
||||||
import run.halo.app.core.extension.content.Reply;
|
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.core.extension.service.UserService;
|
||||||
import run.halo.app.extension.Extension;
|
import run.halo.app.extension.Extension;
|
||||||
import run.halo.app.extension.ListOptions;
|
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.extension.router.selector.FieldSelector;
|
||||||
import run.halo.app.metrics.CounterService;
|
import run.halo.app.metrics.CounterService;
|
||||||
import run.halo.app.metrics.MeterUtils;
|
import run.halo.app.metrics.MeterUtils;
|
||||||
|
import run.halo.app.security.authorization.AuthorityUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A default implementation of {@link ReplyService}.
|
* A default implementation of {@link ReplyService}.
|
||||||
|
@ -42,6 +45,7 @@ public class ReplyServiceImpl implements ReplyService {
|
||||||
|
|
||||||
private final ReactiveExtensionClient client;
|
private final ReactiveExtensionClient client;
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
private final RoleService roleService;
|
||||||
private final CounterService counterService;
|
private final CounterService counterService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -75,10 +79,24 @@ public class ReplyServiceImpl implements ReplyService {
|
||||||
}
|
}
|
||||||
// populate owner from current user
|
// populate owner from current user
|
||||||
return fetchCurrentUser()
|
return fetchCurrentUser()
|
||||||
.map(user -> {
|
.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));
|
replyToUse.getSpec().setOwner(toCommentOwner(user));
|
||||||
return replyToUse;
|
|
||||||
})
|
})
|
||||||
|
.thenReturn(replyToUse);
|
||||||
|
})
|
||||||
|
)
|
||||||
.switchIfEmpty(
|
.switchIfEmpty(
|
||||||
Mono.error(new IllegalArgumentException("Reply owner must not be null.")));
|
Mono.error(new IllegalArgumentException("Reply owner must not be null.")));
|
||||||
})
|
})
|
||||||
|
|
|
@ -24,6 +24,8 @@ public enum AuthorityUtils {
|
||||||
|
|
||||||
public static final String ANONYMOUS_ROLE_NAME = "anonymous";
|
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.
|
* Converts an array of GrantedAuthority objects to a role set.
|
||||||
*
|
*
|
||||||
|
|
|
@ -10,6 +10,7 @@ import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
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.User;
|
||||||
import run.halo.app.core.extension.content.Comment;
|
import run.halo.app.core.extension.content.Comment;
|
||||||
import run.halo.app.core.extension.content.Post;
|
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.core.extension.service.UserService;
|
||||||
import run.halo.app.extension.ListOptions;
|
import run.halo.app.extension.ListOptions;
|
||||||
import run.halo.app.extension.ListResult;
|
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.CounterService;
|
||||||
import run.halo.app.metrics.MeterUtils;
|
import run.halo.app.metrics.MeterUtils;
|
||||||
import run.halo.app.plugin.ExtensionComponentsFinder;
|
import run.halo.app.plugin.ExtensionComponentsFinder;
|
||||||
|
import run.halo.app.security.authorization.AuthorityUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link CommentServiceImpl}.
|
* Tests for {@link CommentServiceImpl}.
|
||||||
|
@ -65,6 +68,9 @@ class CommentServiceImplTest {
|
||||||
@Mock
|
@Mock
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RoleService roleService;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ExtensionComponentsFinder extensionComponentsFinder;
|
private ExtensionComponentsFinder extensionComponentsFinder;
|
||||||
|
|
||||||
|
@ -90,6 +96,10 @@ class CommentServiceImplTest {
|
||||||
when(client.fetch(eq(User.class), eq("C-owner")))
|
when(client.fetch(eq(User.class), eq("C-owner")))
|
||||||
.thenReturn(Mono.empty());
|
.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);
|
PostCommentSubject postCommentSubject = Mockito.mock(PostCommentSubject.class);
|
||||||
when(extensionComponentsFinder.getExtensions(eq(CommentSubject.class)))
|
when(extensionComponentsFinder.getExtensions(eq(CommentSubject.class)))
|
||||||
.thenReturn(List.of(postCommentSubject));
|
.thenReturn(List.of(postCommentSubject));
|
||||||
|
|
Loading…
Reference in New Issue