Skip to content

Commit

Permalink
feat: add author pages for theme-side (halo-dev#2923)
Browse files Browse the repository at this point in the history
#### What type of PR is this?
/kind feature
/area core

#### What this PR does / why we need it:
为主题端新增作者页面
see halo-dev#2837 for more detail
#### Which issue(s) this PR fixes:

Fixes halo-dev#2837

#### Special notes for your reviewer:
/cc @halo-dev/sig-halo 
#### Does this PR introduce a user-facing change?

```release-note
主题端支持作者页面
```
  • Loading branch information
guqing authored Dec 14, 2022
1 parent 3033ceb commit 7a2f5d0
Show file tree
Hide file tree
Showing 17 changed files with 476 additions and 22 deletions.
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.apache.commons.lang3.StringUtils;
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.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;
}
if (user.getStatus() == null) {
user.setStatus(new User.UserStatus());
}
User.UserStatus status = user.getStatus();
String oldPermalink = status.getPermalink();

status.setPermalink(getUserPermalink(user));

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

if (!StringUtils.equals(oldPermalink, status.getPermalink())) {
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

0 comments on commit 7a2f5d0

Please sign in to comment.