Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
ruibaby committed May 21, 2024
2 parents dcd8f2f + 248d075 commit 74bb432
Show file tree
Hide file tree
Showing 15 changed files with 12,680 additions and 12,153 deletions.
8 changes: 4 additions & 4 deletions .github/actions/setup-env/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ inputs:
node-version:
description: Node.js version.
required: false
default: "18"
default: "20"

pnpm-version:
description: pnpm version.
required: false
default: "8"
default: "9"

java-version:
description: Java version.
Expand All @@ -29,8 +29,8 @@ runs:
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'pnpm'
cache-dependency-path: 'ui/pnpm-lock.yaml'
cache: "pnpm"
cache-dependency-path: "ui/pnpm-lock.yaml"

- name: Setup JDK
uses: actions/setup-java@v4
Expand Down
4 changes: 4 additions & 0 deletions api-docs/openapi/v3_0/aggregated.json
Original file line number Diff line number Diff line change
Expand Up @@ -13221,6 +13221,10 @@
"logo": {
"type": "string"
},
"priority": {
"type": "integer",
"format": "int32"
},
"settingRef": {
"$ref": "#/components/schemas/SettingRef"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
public class AuthProvider extends AbstractExtension {

public static final String AUTH_BINDING_LABEL = "auth.halo.run/auth-binding";

public static final String PRIVILEGED_LABEL = "auth.halo.run/privileged";

@Schema(requiredMode = REQUIRED)
Expand Down Expand Up @@ -52,6 +52,8 @@ public static class AuthProviderSpec {

private String unbindUrl;

private int priority;

@Schema(requiredMode = NOT_REQUIRED)
private SettingRef settingRef;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package run.halo.app.extension.router;

import static org.springframework.data.domain.Sort.Order.asc;
import static org.springframework.data.domain.Sort.Order.desc;
import static run.halo.app.extension.Comparators.compareCreationTimestamp;
import static run.halo.app.extension.Comparators.compareName;
import static run.halo.app.extension.Comparators.nullsComparator;
Expand Down Expand Up @@ -40,7 +42,10 @@ public SortableRequest(ServerWebExchange exchange) {
implementation = String.class,
example = "metadata.creationTimestamp,desc"))
public Sort getSort() {
return SortResolver.defaultInstance.resolve(exchange);
return SortResolver.defaultInstance.resolve(exchange)
.and(Sort.by(desc("metadata.creationTimestamp"),
asc("metadata.name"))
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@
import static run.halo.app.extension.index.query.QueryFactory.and;
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.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
import static run.halo.app.security.authorization.AuthorityUtils.COMMENT_MANAGEMENT_ROLE_NAME;
import static run.halo.app.security.authorization.AuthorityUtils.authoritiesToRoles;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.domain.Sort;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;
Expand All @@ -25,7 +30,6 @@
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;
import run.halo.app.extension.ListResult;
import run.halo.app.extension.PageRequest;
Expand All @@ -34,7 +38,6 @@
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}.
Expand All @@ -54,56 +57,100 @@ public class ReplyServiceImpl implements ReplyService {
@Override
public Mono<Reply> create(String commentName, Reply reply) {
return client.get(Comment.class, commentName)
.map(comment -> {
// Boolean allowNotification = reply.getSpec().getAllowNotification();
// TODO send notification if allowNotification is true
reply.getSpec().setCommentName(commentName);
if (reply.getSpec().getTop() == null) {
reply.getSpec().setTop(false);
}
if (reply.getSpec().getPriority() == null) {
reply.getSpec().setPriority(0);
}
if (reply.getSpec().getCreationTime() == null) {
reply.getSpec().setCreationTime(Instant.now());
}
if (reply.getSpec().getApproved() == null) {
reply.getSpec().setApproved(false);
}
if (BooleanUtils.isTrue(reply.getSpec().getApproved())
&& reply.getSpec().getApprovedTime() == null) {
.flatMap(comment -> prepareReply(commentName, reply)
.flatMap(client::create)
.flatMap(createdReply -> {
var quotedReply = createdReply.getSpec().getQuoteReply();
if (StringUtils.isBlank(quotedReply)) {
return Mono.just(createdReply);
}
return approveReply(quotedReply)
.thenReturn(createdReply);
})
.flatMap(createdReply -> approveComment(comment)
.thenReturn(createdReply)
)
);
}

private Mono<Comment> approveComment(Comment comment) {
UnaryOperator<Comment> updateFunc = commentToUpdate -> {
commentToUpdate.getSpec().setApproved(true);
commentToUpdate.getSpec().setApprovedTime(Instant.now());
return commentToUpdate;
};
return client.update(updateFunc.apply(comment))
.onErrorResume(OptimisticLockingFailureException.class,
e -> updateCommentWithRetry(comment.getMetadata().getName(), updateFunc));
}

private Mono<Void> approveReply(String replyName) {
return Mono.defer(() -> client.fetch(Reply.class, replyName)
.flatMap(reply -> {
reply.getSpec().setApproved(true);
reply.getSpec().setApprovedTime(Instant.now());
}
return reply;
})
.flatMap(replyToUse -> {
if (replyToUse.getSpec().getOwner() != null) {
return Mono.just(replyToUse);
}
// populate owner from current user
return fetchCurrentUser()
.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.")));
})
.flatMap(client::create);
return client.update(reply);
})
)
.retryWhen(Retry.backoff(8, Duration.ofMillis(100))
.filter(OptimisticLockingFailureException.class::isInstance))
.then();
}

private Mono<Comment> updateCommentWithRetry(String name, UnaryOperator<Comment> updateFunc) {
return Mono.defer(() -> client.get(Comment.class, name)
.map(updateFunc)
.flatMap(client::update)
)
.retryWhen(Retry.backoff(8, Duration.ofMillis(100))
.filter(OptimisticLockingFailureException.class::isInstance));
}

private Mono<Reply> prepareReply(String commentName, Reply reply) {
reply.getSpec().setCommentName(commentName);
if (reply.getSpec().getTop() == null) {
reply.getSpec().setTop(false);
}
if (reply.getSpec().getPriority() == null) {
reply.getSpec().setPriority(0);
}
if (reply.getSpec().getCreationTime() == null) {
reply.getSpec().setCreationTime(Instant.now());
}
if (reply.getSpec().getApproved() == null) {
reply.getSpec().setApproved(false);
}
if (BooleanUtils.isTrue(reply.getSpec().getApproved())
&& reply.getSpec().getApprovedTime() == null) {
reply.getSpec().setApprovedTime(Instant.now());
}

var steps = new ArrayList<Publisher<?>>();
var approveItMono = hasCommentManagePermission()
.filter(Boolean::booleanValue)
.doOnNext(hasPermission -> {
reply.getSpec().setApproved(true);
reply.getSpec().setApprovedTime(Instant.now());
});
steps.add(approveItMono);

var populateOwnerMono = fetchCurrentUser()
.switchIfEmpty(
Mono.error(new IllegalArgumentException("Reply owner must not be null.")))
.doOnNext(user -> reply.getSpec().setOwner(toCommentOwner(user)));
if (reply.getSpec().getOwner() == null) {
steps.add(populateOwnerMono);
}
return Mono.when(steps).thenReturn(reply);
}

Mono<Boolean> hasCommentManagePermission() {
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.flatMap(authentication -> {
var roles = authoritiesToRoles(authentication.getAuthorities());
return roleService.contains(roles, Set.of(COMMENT_MANAGEMENT_ROLE_NAME));
});
}

@Override
Expand Down Expand Up @@ -197,19 +244,6 @@ private Mono<OwnerInfo> getOwnerInfo(Reply reply) {
"Unsupported owner kind: " + owner.getKind());
}

Predicate<Reply> getReplyPredicate(ReplyQuery query) {
Predicate<Reply> predicate = reply -> true;
if (query.getCommentName() != null) {
predicate = predicate.and(
reply -> query.getCommentName().equals(reply.getSpec().getCommentName()));
}

Predicate<Extension> labelAndFieldSelectorPredicate =
labelAndFieldSelectorToPredicate(query.getLabelSelector(),
query.getFieldSelector());
return predicate.and(labelAndFieldSelectorPredicate);
}

private Comment.CommentOwner toCommentOwner(User user) {
Comment.CommentOwner owner = new Comment.CommentOwner();
owner.setKind(User.KIND);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public Mono<String> resolve(Subscription.Subscriber subscriber) {
return Mono.fromSupplier(() -> getEmail(subscriber));
}
return client.fetch(User.class, subscriber.getName())
.filter(user -> user.getSpec().isEmailVerified())
.mapNotNull(user -> user.getSpec().getEmail());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public Mono<AuthProvider> disable(String name) {
public Mono<List<ListedAuthProvider>> listAll() {
return client.list(AuthProvider.class, provider ->
provider.getMetadata().getDeletionTimestamp() == null,
Comparator.comparing(item -> item.getMetadata().getCreationTimestamp())
defaultComparator()
)
.map(this::convertTo)
.collectList()
Expand Down Expand Up @@ -105,6 +105,12 @@ Flux<UserConnection> listMyConnections() {
);
}

private static Comparator<AuthProvider> defaultComparator() {
return Comparator.comparing((AuthProvider item) -> item.getSpec().getPriority())
.thenComparing(item -> item.getMetadata().getName())
.thenComparing(item -> item.getMetadata().getCreationTimestamp());
}

private Mono<ConfigMap> updateAuthProviderEnabled(Consumer<Set<String>> consumer) {
return client.fetch(ConfigMap.class, SystemSetting.SYSTEM_CONFIG)
.switchIfEmpty(Mono.defer(() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ void testResolve() {
user.getMetadata().setName("fake-user");
user.setSpec(new User.UserSpec());
user.getSpec().setEmail("test@halo.run");
user.getSpec().setEmailVerified(false);
when(client.fetch(eq(User.class), eq("fake-user"))).thenReturn(Mono.just(user));

subscriber.setName("fake-user");
subscriberEmailResolver.resolve(subscriber)
.as(StepVerifier::create)
.verifyComplete();

user.getSpec().setEmailVerified(true);
when(client.fetch(eq(User.class), eq("fake-user"))).thenReturn(Mono.just(user));

subscriber.setName("fake-user");
Expand Down
2 changes: 1 addition & 1 deletion ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
## 开发环境运行

```bash
npm install -g pnpm@8
npm install -g pnpm@9
```

```bash
Expand Down
Loading

0 comments on commit 74bb432

Please sign in to comment.