Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add author pages for theme-side #2923

Merged
merged 10 commits into from
Dec 14, 2022
2 changes: 2 additions & 0 deletions src/main/java/run/halo/app/core/extension/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public static class UserStatus {

private Instant lastLoginAt;

private String permalink;

private List<LoginHistory> loginHistories;

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,113 @@
package run.halo.app.core.extension.reconciler;

import java.util.HashSet;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import run.halo.app.content.permalinks.ExtensionLocator;
import run.halo.app.core.extension.User;
import run.halo.app.extension.ExtensionClient;
import run.halo.app.extension.GroupVersionKind;
import run.halo.app.extension.controller.Controller;
import run.halo.app.extension.controller.ControllerBuilder;
import run.halo.app.extension.controller.Reconciler;
import run.halo.app.extension.controller.Reconciler.Request;
import run.halo.app.infra.AnonymousUserConst;
import run.halo.app.infra.ExternalUrlSupplier;
import run.halo.app.infra.utils.JsonUtils;
import run.halo.app.infra.utils.PathUtils;
import run.halo.app.theme.router.PermalinkIndexDeleteCommand;
import run.halo.app.theme.router.PermalinkIndexUpdateCommand;

@Slf4j
@Component
@AllArgsConstructor
public class UserReconciler implements Reconciler<Request> {

private static final String FINALIZER_NAME = "user-protection";
private final ExtensionClient client;

public UserReconciler(ExtensionClient client) {
this.client = client;
}
private final ApplicationEventPublisher eventPublisher;
private final ExternalUrlSupplier externalUrlSupplier;

@Override
public Result reconcile(Request request) {
//TODO Add reconciliation logic here for User extension.
client.fetch(User.class, request.name()).ifPresent(user -> {
if (user.getMetadata().getDeletionTimestamp() != null) {
cleanUpResourcesAndRemoveFinalizer(request.name());
return;
}

addFinalizerIfNecessary(user);
updatePermalink(request.name());
});
return new Result(false, null);
}

private void updatePermalink(String name) {
client.fetch(User.class, name).ifPresent(user -> {
if (AnonymousUserConst.isAnonymousUser(name)) {
// anonymous user is not allowed to have permalink
return;
}

final User oldUser = JsonUtils.deepCopy(user);
guqing marked this conversation as resolved.
Show resolved Hide resolved
if (user.getStatus() == null) {
user.setStatus(new User.UserStatus());
}
User.UserStatus status = user.getStatus();
status.setPermalink(getUserPermalink(user));

ExtensionLocator extensionLocator = getExtensionLocator(name);
eventPublisher.publishEvent(
new PermalinkIndexUpdateCommand(this, extensionLocator, status.getPermalink()));

if (!user.equals(oldUser)) {
client.update(user);
}
});
}

private static ExtensionLocator getExtensionLocator(String name) {
return new ExtensionLocator(GroupVersionKind.fromExtension(User.class), name,
name);
}

private String getUserPermalink(User user) {
return externalUrlSupplier.get()
.resolve(PathUtils.combinePath("authors", user.getMetadata().getName()))
.normalize().toString();
}

private void addFinalizerIfNecessary(User oldUser) {
Set<String> finalizers = oldUser.getMetadata().getFinalizers();
if (finalizers != null && finalizers.contains(FINALIZER_NAME)) {
return;
}
client.fetch(User.class, oldUser.getMetadata().getName())
.ifPresent(user -> {
Set<String> newFinalizers = user.getMetadata().getFinalizers();
if (newFinalizers == null) {
newFinalizers = new HashSet<>();
user.getMetadata().setFinalizers(newFinalizers);
}
newFinalizers.add(FINALIZER_NAME);
client.update(user);
});
}

private void cleanUpResourcesAndRemoveFinalizer(String userName) {
client.fetch(User.class, userName).ifPresent(user -> {
eventPublisher.publishEvent(
new PermalinkIndexDeleteCommand(this, getExtensionLocator(userName)));

if (user.getMetadata().getFinalizers() != null) {
user.getMetadata().getFinalizers().remove(FINALIZER_NAME);
}
client.update(user);
});
}

@Override
public Controller setupWith(ControllerBuilder builder) {
return builder
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/run/halo/app/infra/AnonymousUserConst.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ public interface AnonymousUserConst {
String PRINCIPAL = "anonymousUser";

String Role = "anonymous";

static boolean isAnonymousUser(String principal) {
return PRINCIPAL.equals(principal);
}
}
4 changes: 3 additions & 1 deletion src/main/java/run/halo/app/theme/DefaultTemplateEnum.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public enum DefaultTemplateEnum {

TAGS("tags"),

SINGLE_PAGE("page");
SINGLE_PAGE("page"),

AUTHOR("author");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.User;
import run.halo.app.theme.finders.vo.Contributor;
import run.halo.app.theme.finders.vo.ContributorVo;

/**
* A finder for {@link User}.
*/
public interface ContributorFinder {

Mono<Contributor> getContributor(String name);
Mono<ContributorVo> getContributor(String name);

Flux<Contributor> getContributors(List<String> names);
Flux<ContributorVo> getContributors(List<String> names);
}
3 changes: 3 additions & 0 deletions src/main/java/run/halo/app/theme/finders/PostFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ Mono<ListResult<ListedPostVo>> listByCategory(@Nullable Integer page, @Nullable
Mono<ListResult<ListedPostVo>> listByTag(@Nullable Integer page, @Nullable Integer size,
String tag);

Mono<ListResult<ListedPostVo>> listByOwner(@Nullable Integer page, @Nullable Integer size,
String owner);

Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size);

Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size, String year);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.theme.finders.ContributorFinder;
import run.halo.app.theme.finders.Finder;
import run.halo.app.theme.finders.vo.Contributor;
import run.halo.app.theme.finders.vo.ContributorVo;

/**
* A default implementation of {@link ContributorFinder}.
Expand All @@ -25,13 +25,13 @@ public ContributorFinderImpl(ReactiveExtensionClient client) {
}

@Override
public Mono<Contributor> getContributor(String name) {
public Mono<ContributorVo> getContributor(String name) {
return client.fetch(User.class, name)
.map(Contributor::from);
.map(ContributorVo::from);
}

@Override
public Flux<Contributor> getContributors(List<String> names) {
public Flux<ContributorVo> getContributors(List<String> names) {
if (names == null) {
return Flux.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ public Mono<ListResult<ListedPostVo>> listByTag(Integer page, Integer size, Stri
post -> contains(post.getSpec().getTags(), tag), defaultComparator());
}

@Override
public Mono<ListResult<ListedPostVo>> listByOwner(Integer page, Integer size, String owner) {
return listPost(page, size,
post -> post.getSpec().getOwner().equals(owner), defaultComparator());
}

@Override
public Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size) {
return archives(page, size, null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
@Value
@ToString
@Builder
public class Contributor {
public class ContributorVo {
String name;

String displayName;
Expand All @@ -23,17 +23,22 @@ public class Contributor {

String bio;

String permalink;

/**
* Convert {@link User} to {@link Contributor}.
* Convert {@link User} to {@link ContributorVo}.
*
* @param user user extension
* @return contributor value object
*/
public static Contributor from(User user) {
public static ContributorVo from(User user) {
User.UserStatus status = user.getStatus();
String permalink = (status == null ? "" : status.getPermalink());
return builder().name(user.getMetadata().getName())
.displayName(user.getSpec().getDisplayName())
.avatar(user.getSpec().getAvatar())
.bio(user.getSpec().getBio())
.permalink(permalink)
.build();
}
}
4 changes: 2 additions & 2 deletions src/main/java/run/halo/app/theme/finders/vo/ListedPostVo.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ public class ListedPostVo {

private List<TagVo> tags;

private List<Contributor> contributors;
private List<ContributorVo> contributors;

private Contributor owner;
private ContributorVo owner;

private StatsVo stats;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public class ListedSinglePageVo {

private StatsVo stats;

private List<Contributor> contributors;
private List<ContributorVo> contributors;

private Contributor owner;
private ContributorVo owner;

/**
* Convert {@link SinglePage} to {@link ListedSinglePageVo}.
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/run/halo/app/theme/finders/vo/UserVo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package run.halo.app.theme.finders.vo;

import java.util.List;
import lombok.Builder;
import lombok.Value;
import org.apache.commons.lang3.ObjectUtils;
import run.halo.app.core.extension.User;
import run.halo.app.extension.MetadataOperator;
import run.halo.app.infra.utils.JsonUtils;

@Value
@Builder
public class UserVo {
MetadataOperator metadata;

User.UserSpec spec;

User.UserStatus status;

/**
* Converts to {@link UserVo} from {@link User}.
*
* @param user user extension
* @return user value object.
*/
public static UserVo from(User user) {
User.UserStatus statusCopy =
JsonUtils.deepCopy(ObjectUtils.defaultIfNull(user.getStatus(), new User.UserStatus()));
statusCopy.setLoginHistories(List.of());
statusCopy.setLastLoginAt(null);

User.UserSpec userSpecCopy = JsonUtils.deepCopy(user.getSpec());
userSpecCopy.setPassword("[PROTECTED]");
return UserVo.builder()
.metadata(user.getMetadata())
.spec(userSpecCopy)
.status(statusCopy)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ private SystemSetting.ThemeRouteRules getPermalinkRules() {
public String getPattern(DefaultTemplateEnum defaultTemplateEnum) {
SystemSetting.ThemeRouteRules permalinkRules = getPermalinkRules();
return switch (defaultTemplateEnum) {
case INDEX, SINGLE_PAGE -> null;
case INDEX, SINGLE_PAGE, AUTHOR -> null;
case POST -> permalinkRules.getPost();
case ARCHIVES -> permalinkRules.getArchives();
case CATEGORY, CATEGORIES -> permalinkRules.getCategories();
Expand Down
Loading