refactor: the structure of finders vo (#2400)

#### What type of PR is this?
/kind improvement
/area core
/milestone 2.0

#### What this PR does / why we need it:
统一主题端 VO 的结构 
#### Which issue(s) this PR fixes:
Fixes #2394

#### Special notes for your reviewer:
how to test it?
通过主题端调用 finder 方法来验证

/cc @halo-dev/sig-halo 
#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/2402/head
guqing 2022-09-09 17:44:11 +08:00 committed by GitHub
parent 1d73228b1f
commit 9dc7bc1729
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 327 additions and 393 deletions

View File

@ -2,6 +2,7 @@ package run.halo.app.theme.dialect;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thymeleaf.context.ITemplateContext; import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.model.IModel; import org.thymeleaf.model.IModel;
@ -35,7 +36,7 @@ public class PostTemplateHeadProcessor implements TemplateHeadProcessor {
.map(template -> (String) context.getVariable(POST_NAME_VARIABLE)) .map(template -> (String) context.getVariable(POST_NAME_VARIABLE))
.map(postFinder::getByName) .map(postFinder::getByName)
.doOnNext(postVo -> { .doOnNext(postVo -> {
List<Map<String, String>> htmlMetas = postVo.getHtmlMetas(); List<Map<String, String>> htmlMetas = postVo.getSpec().getHtmlMetas();
String metaHtml = headMetaBuilder(htmlMetas); String metaHtml = headMetaBuilder(htmlMetas);
IModelFactory modelFactory = context.getModelFactory(); IModelFactory modelFactory = context.getModelFactory();
model.add(modelFactory.createText(metaHtml)); model.add(modelFactory.createText(metaHtml));
@ -44,6 +45,9 @@ public class PostTemplateHeadProcessor implements TemplateHeadProcessor {
} }
private String headMetaBuilder(List<Map<String, String>> htmlMetas) { private String headMetaBuilder(List<Map<String, String>> htmlMetas) {
if (htmlMetas == null) {
return StringUtils.EMPTY;
}
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (Map<String, String> htmlMeta : htmlMetas) { for (Map<String, String> htmlMeta : htmlMetas) {
sb.append("<meta"); sb.append("<meta");

View File

@ -76,14 +76,15 @@ public class CategoryFinderImpl implements CategoryFinder {
public List<CategoryTreeVo> listAsTree() { public List<CategoryTreeVo> listAsTree() {
List<CategoryVo> categoryVos = listAll(); List<CategoryVo> categoryVos = listAll();
Map<String, CategoryVo> nameIdentityMap = categoryVos.stream() Map<String, CategoryVo> nameIdentityMap = categoryVos.stream()
.collect(Collectors.toMap(CategoryVo::getName, Function.identity())); .collect(Collectors.toMap(categoryVo -> categoryVo.getMetadata().getName(),
Function.identity()));
Map<String, CategoryTreeVo> treeVoMap = new HashMap<>(); Map<String, CategoryTreeVo> treeVoMap = new HashMap<>();
// populate parentName // populate parentName
categoryVos.forEach(categoryVo -> { categoryVos.forEach(categoryVo -> {
final String parentName = categoryVo.getName(); final String parentName = categoryVo.getMetadata().getName();
treeVoMap.putIfAbsent(parentName, CategoryTreeVo.from(categoryVo)); treeVoMap.putIfAbsent(parentName, CategoryTreeVo.from(categoryVo));
List<String> children = categoryVo.getChildren(); List<String> children = categoryVo.getSpec().getChildren();
if (CollectionUtils.isEmpty(children)) { if (CollectionUtils.isEmpty(children)) {
return; return;
} }
@ -91,7 +92,7 @@ public class CategoryFinderImpl implements CategoryFinder {
CategoryVo childrenVo = nameIdentityMap.get(childrenName); CategoryVo childrenVo = nameIdentityMap.get(childrenName);
CategoryTreeVo treeVo = CategoryTreeVo.from(childrenVo); CategoryTreeVo treeVo = CategoryTreeVo.from(childrenVo);
treeVo.setParentName(parentName); treeVo.setParentName(parentName);
treeVoMap.putIfAbsent(treeVo.getName(), treeVo); treeVoMap.putIfAbsent(treeVo.getMetadata().getName(), treeVo);
}); });
}); });
nameIdentityMap.clear(); nameIdentityMap.clear();
@ -102,7 +103,7 @@ public class CategoryFinderImpl implements CategoryFinder {
Map<String, List<CategoryTreeVo>> nameIdentityMap = list.stream() Map<String, List<CategoryTreeVo>> nameIdentityMap = list.stream()
.filter(item -> item.getParentName() != null) .filter(item -> item.getParentName() != null)
.collect(Collectors.groupingBy(CategoryTreeVo::getParentName)); .collect(Collectors.groupingBy(CategoryTreeVo::getParentName));
list.forEach(node -> node.setChildren(nameIdentityMap.get(node.getName()))); list.forEach(node -> node.setChildren(nameIdentityMap.get(node.getMetadata().getName())));
return list.stream() return list.stream()
.filter(v -> v.getParentName() == null) .filter(v -> v.getParentName() == null)
.collect(Collectors.toList()); .collect(Collectors.toList());

View File

@ -35,7 +35,7 @@ public class MenuFinderImpl implements MenuFinder {
@Override @Override
public MenuVo getByName(String name) { public MenuVo getByName(String name) {
return listAsTree().stream() return listAsTree().stream()
.filter(menu -> menu.getName().equals(name)) .filter(menu -> menu.getMetadata().getName().equals(name))
.findAny() .findAny()
.orElse(null); .orElse(null);
} }
@ -63,10 +63,15 @@ public class MenuFinderImpl implements MenuFinder {
List<MenuItemVo> menuItemVos = populateParentName(listAllMenuItem()); List<MenuItemVo> menuItemVos = populateParentName(listAllMenuItem());
List<MenuItemVo> treeList = listToTree(menuItemVos); List<MenuItemVo> treeList = listToTree(menuItemVos);
Map<String, MenuItemVo> nameItemRootNodeMap = treeList.stream() Map<String, MenuItemVo> nameItemRootNodeMap = treeList.stream()
.collect(Collectors.toMap(MenuItemVo::getName, Function.identity())); .collect(Collectors.toMap(item -> item.getMetadata().getName(), Function.identity()));
return listAll().stream() return listAll().stream()
.map(menuVo -> { .map(menuVo -> {
List<MenuItemVo> menuItems = menuVo.getMenuItemNames().stream() LinkedHashSet<String> menuItemNames = menuVo.getSpec().getMenuItems();
if (menuItemNames == null) {
return menuVo.withMenuItems(List.of());
}
List<MenuItemVo> menuItems = menuItemNames.stream()
.map(nameItemRootNodeMap::get) .map(nameItemRootNodeMap::get)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(); .toList();
@ -79,7 +84,7 @@ public class MenuFinderImpl implements MenuFinder {
Map<String, List<MenuItemVo>> nameIdentityMap = list.stream() Map<String, List<MenuItemVo>> nameIdentityMap = list.stream()
.filter(item -> item.getParentName() != null) .filter(item -> item.getParentName() != null)
.collect(Collectors.groupingBy(MenuItemVo::getParentName)); .collect(Collectors.groupingBy(MenuItemVo::getParentName));
list.forEach(node -> node.setChildren(nameIdentityMap.get(node.getName()))); list.forEach(node -> node.setChildren(nameIdentityMap.get(node.getMetadata().getName())));
// clear map to release memory // clear map to release memory
nameIdentityMap.clear(); nameIdentityMap.clear();
return list.stream() return list.stream()
@ -101,28 +106,30 @@ public class MenuFinderImpl implements MenuFinder {
static List<MenuItemVo> populateParentName(List<MenuItemVo> menuItemVos) { static List<MenuItemVo> populateParentName(List<MenuItemVo> menuItemVos) {
Map<String, MenuItemVo> nameIdentityMap = menuItemVos.stream() Map<String, MenuItemVo> nameIdentityMap = menuItemVos.stream()
.collect(Collectors.toMap(MenuItemVo::getName, Function.identity())); .collect(Collectors.toMap(menuItem -> menuItem.getMetadata().getName(),
Function.identity()));
Map<String, MenuItemVo> treeVoMap = new HashMap<>(); Map<String, MenuItemVo> treeVoMap = new HashMap<>();
// populate parentName // populate parentName
menuItemVos.forEach(menuItemVo -> { menuItemVos.forEach(menuItemVo -> {
final String parentName = menuItemVo.getName(); final String parentName = menuItemVo.getMetadata().getName();
treeVoMap.putIfAbsent(parentName, menuItemVo); treeVoMap.putIfAbsent(parentName, menuItemVo);
LinkedHashSet<String> children = menuItemVo.getChildrenNames(); LinkedHashSet<String> children = menuItemVo.getSpec().getChildren();
if (CollectionUtils.isEmpty(children)) { if (CollectionUtils.isEmpty(children)) {
return; return;
} }
children.forEach(childrenName -> { children.forEach(childrenName -> {
MenuItemVo childrenVo = nameIdentityMap.get(childrenName); MenuItemVo childrenVo = nameIdentityMap.get(childrenName);
childrenVo.setParentName(parentName); childrenVo.setParentName(parentName);
treeVoMap.putIfAbsent(childrenVo.getName(), childrenVo); treeVoMap.putIfAbsent(childrenVo.getMetadata().getName(), childrenVo);
}); });
}); });
// clear map to release memory // clear map to release memory
nameIdentityMap.clear(); nameIdentityMap.clear();
Function<MenuItemVo, Integer> priorityCmp = menuItem -> menuItem.getSpec().getPriority();
return treeVoMap.values() return treeVoMap.values()
.stream() .stream()
.sorted(Comparator.comparing(MenuItemVo::getPriority)) .sorted(Comparator.comparing(priorityCmp))
.toList(); .toList();
} }
} }

View File

@ -1,39 +0,0 @@
package run.halo.app.theme.finders.vo;
import java.util.List;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
/**
* Base class for category value object.
*
* @author guqing
* @since 2.0.0
*/
@Getter
@ToString
@SuperBuilder
public class BaseCategoryVo {
String name;
String displayName;
String slug;
String description;
String cover;
String template;
Integer priority;
String permalink;
List<String> posts;
public int getPostCount() {
return posts == null ? 0 : posts.size();
}
}

View File

@ -1,26 +0,0 @@
package run.halo.app.theme.finders.vo;
import java.util.Map;
import lombok.experimental.SuperBuilder;
import run.halo.app.core.extension.Comment;
@SuperBuilder
public class BaseCommentVo {
String name;
String raw;
String content;
Comment.CommentOwner owner;
String userAgent;
Integer priority;
Boolean top;
Boolean allowNotification;
Map<String, String> annotations;
}

View File

@ -1,61 +0,0 @@
package run.halo.app.theme.finders.vo;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import run.halo.app.core.extension.Post;
/**
* a base entity for post.
*
* @author guqing
* @since 2.0.0
*/
@Data
@ToString
@SuperBuilder
public abstract class BasePostVo {
String name;
String title;
String slug;
String owner;
String template;
String cover;
Boolean published;
Instant publishTime;
Boolean pinned;
Boolean allowComment;
Post.VisibleEnum visible;
Integer version;
Integer priority;
String excerpt;
List<Map<String, String>> htmlMetas;
String permalink;
List<Contributor> contributors;
Map<String, String> annotations;
static <T> List<T> nullSafe(List<T> t) {
return Objects.requireNonNullElse(t, List.of());
}
}

View File

@ -1,12 +1,13 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.List; import java.util.List;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import run.halo.app.core.extension.Category; import run.halo.app.core.extension.Category;
import run.halo.app.extension.MetadataOperator;
/** /**
* A tree vo for {@link Category}. * A tree vo for {@link Category}.
@ -15,10 +16,16 @@ import run.halo.app.core.extension.Category;
* @since 2.0.0 * @since 2.0.0
*/ */
@Data @Data
@SuperBuilder @Builder
@ToString(callSuper = true) @ToString
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode
public class CategoryTreeVo extends BaseCategoryVo { public class CategoryTreeVo {
private MetadataOperator metadata;
private Category.CategorySpec spec;
private Category.CategoryStatus status;
private List<CategoryTreeVo> children; private List<CategoryTreeVo> children;
@ -33,14 +40,10 @@ public class CategoryTreeVo extends BaseCategoryVo {
public static CategoryTreeVo from(CategoryVo category) { public static CategoryTreeVo from(CategoryVo category) {
Assert.notNull(category, "The category must not be null"); Assert.notNull(category, "The category must not be null");
return CategoryTreeVo.builder() return CategoryTreeVo.builder()
.name(category.getName()) .metadata(category.getMetadata())
.displayName(category.getDisplayName()) .spec(category.getSpec())
.slug(category.getSlug()) .status(category.getStatus())
.description(category.getDescription()) .children(List.of())
.cover(category.getCover())
.template(category.getTemplate())
.priority(category.getPriority())
.permalink(category.getPermalink())
.build(); .build();
} }
} }

View File

@ -1,10 +1,10 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.List; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
import lombok.experimental.SuperBuilder;
import run.halo.app.core.extension.Category; import run.halo.app.core.extension.Category;
import run.halo.app.extension.MetadataOperator;
/** /**
* A value object for {@link Category}. * A value object for {@link Category}.
@ -13,11 +13,15 @@ import run.halo.app.core.extension.Category;
* @since 2.0.0 * @since 2.0.0
*/ */
@Value @Value
@SuperBuilder @Builder
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode
public class CategoryVo extends BaseCategoryVo { public class CategoryVo {
List<String> children; MetadataOperator metadata;
Category.CategorySpec spec;
Category.CategoryStatus status;
/** /**
* Convert {@link Category} to {@link CategoryVo}. * Convert {@link Category} to {@link CategoryVo}.
@ -26,17 +30,10 @@ public class CategoryVo extends BaseCategoryVo {
* @return category value object * @return category value object
*/ */
public static CategoryVo from(Category category) { public static CategoryVo from(Category category) {
Category.CategorySpec spec = category.getSpec();
return CategoryVo.builder() return CategoryVo.builder()
.name(category.getMetadata().getName()) .metadata(category.getMetadata())
.displayName(spec.getDisplayName()) .spec(category.getSpec())
.slug(spec.getSlug()) .status(category.getStatus())
.description(spec.getDescription())
.cover(spec.getCover())
.template(spec.getTemplate())
.priority(spec.getPriority())
.children(spec.getChildren())
.permalink(category.getStatusOrDefault().getPermalink())
.build(); .build();
} }
} }

View File

@ -1,9 +1,10 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
import lombok.experimental.SuperBuilder;
import run.halo.app.core.extension.Comment; import run.halo.app.core.extension.Comment;
import run.halo.app.extension.MetadataOperator;
/** /**
* A value object for {@link Comment}. * A value object for {@link Comment}.
@ -12,11 +13,13 @@ import run.halo.app.core.extension.Comment;
* @since 2.0.0 * @since 2.0.0
*/ */
@Value @Value
@SuperBuilder @Builder
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode
public class CommentVo extends BaseCommentVo { public class CommentVo {
Comment.CommentSubjectRef subjectRef; MetadataOperator metadata;
Comment.CommentSpec spec;
/** /**
* Convert {@link Comment} to {@link CommentVo}. * Convert {@link Comment} to {@link CommentVo}.
@ -25,18 +28,9 @@ public class CommentVo extends BaseCommentVo {
* @return a value object for {@link Comment} * @return a value object for {@link Comment}
*/ */
public static CommentVo from(Comment comment) { public static CommentVo from(Comment comment) {
Comment.CommentSpec spec = comment.getSpec();
return CommentVo.builder() return CommentVo.builder()
.name(comment.getMetadata().getName()) .metadata(comment.getMetadata())
.subjectRef(spec.getSubjectRef()) .spec(comment.getSpec())
.raw(spec.getRaw())
.content(spec.getContent())
.owner(spec.getOwner())
.userAgent(spec.getUserAgent())
.priority(spec.getPriority())
.top(spec.getTop())
.allowNotification(spec.getAllowNotification())
.annotations(comment.getMetadata().getAnnotations())
.build(); .build();
} }
} }

View File

@ -1,6 +1,7 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import lombok.Builder; import lombok.Builder;
import lombok.ToString;
import lombok.Value; import lombok.Value;
import run.halo.app.core.extension.Snapshot; import run.halo.app.core.extension.Snapshot;
@ -11,6 +12,7 @@ import run.halo.app.core.extension.Snapshot;
* @since 2.0.0 * @since 2.0.0
*/ */
@Value @Value
@ToString
@Builder @Builder
public class ContentVo { public class ContentVo {

View File

@ -1,6 +1,7 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import lombok.Builder; import lombok.Builder;
import lombok.ToString;
import lombok.Value; import lombok.Value;
import run.halo.app.core.extension.User; import run.halo.app.core.extension.User;
@ -11,6 +12,7 @@ import run.halo.app.core.extension.User;
* @since 2.0.0 * @since 2.0.0
*/ */
@Value @Value
@ToString
@Builder @Builder
public class Contributor { public class Contributor {
String name; String name;

View File

@ -1,10 +1,11 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.ToString;
import run.halo.app.core.extension.MenuItem; import run.halo.app.core.extension.MenuItem;
import run.halo.app.extension.MetadataOperator;
/** /**
* A value object for {@link MenuItem}. * A value object for {@link MenuItem}.
@ -13,23 +14,20 @@ import run.halo.app.core.extension.MenuItem;
* @since 2.0.0 * @since 2.0.0
*/ */
@Data @Data
@ToString
@Builder @Builder
public class MenuItemVo { public class MenuItemVo {
String name; MetadataOperator metadata;
String parentName; MenuItem.MenuItemSpec spec;
String displayName; MenuItem.MenuItemStatus status;
String href;
Integer priority;
LinkedHashSet<String> childrenNames;
List<MenuItemVo> children; List<MenuItemVo> children;
String parentName;
/** /**
* Convert {@link MenuItem} to {@link MenuItemVo}. * Convert {@link MenuItem} to {@link MenuItemVo}.
* *
@ -39,11 +37,10 @@ public class MenuItemVo {
public static MenuItemVo from(MenuItem menuItem) { public static MenuItemVo from(MenuItem menuItem) {
MenuItem.MenuItemStatus status = menuItem.getStatus(); MenuItem.MenuItemStatus status = menuItem.getStatus();
return MenuItemVo.builder() return MenuItemVo.builder()
.name(menuItem.getMetadata().getName()) .metadata(menuItem.getMetadata())
.priority(menuItem.getSpec().getPriority()) .spec(menuItem.getSpec())
.childrenNames(menuItem.getSpec().getChildren()) .status(status)
.displayName(status.getDisplayName()) .children(List.of())
.href(status.getHref())
.build(); .build();
} }
} }

View File

@ -1,12 +1,12 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import lombok.Builder; import lombok.Builder;
import lombok.ToString;
import lombok.Value; import lombok.Value;
import lombok.With; import lombok.With;
import run.halo.app.core.extension.Menu; import run.halo.app.core.extension.Menu;
import run.halo.app.extension.MetadataOperator;
/** /**
* A value object for {@link Menu}. * A value object for {@link Menu}.
@ -15,15 +15,13 @@ import run.halo.app.core.extension.Menu;
* @since 2.0.0 * @since 2.0.0
*/ */
@Value @Value
@ToString
@Builder @Builder
public class MenuVo { public class MenuVo {
String name; MetadataOperator metadata;
String displayName; Menu.Spec spec;
@JsonIgnore
LinkedHashSet<String> menuItemNames;
@With @With
List<MenuItemVo> menuItems; List<MenuItemVo> menuItems;
@ -36,9 +34,9 @@ public class MenuVo {
*/ */
public static MenuVo from(Menu menu) { public static MenuVo from(Menu menu) {
return builder() return builder()
.name(menu.getMetadata().getName()) .metadata(menu.getMetadata())
.displayName(menu.getSpec().getDisplayName()) .spec(menu.getSpec())
.menuItemNames(menu.getSpec().getMenuItems()) .menuItems(List.of())
.build(); .build();
} }
} }

View File

@ -1,11 +1,13 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.List; import java.util.List;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder; import lombok.ToString;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import run.halo.app.core.extension.Post; import run.halo.app.core.extension.Post;
import run.halo.app.extension.MetadataOperator;
/** /**
* A value object for {@link Post}. * A value object for {@link Post}.
@ -14,15 +16,24 @@ import run.halo.app.core.extension.Post;
* @since 2.0.0 * @since 2.0.0
*/ */
@Data @Data
@SuperBuilder @Builder
@EqualsAndHashCode(callSuper = true) @ToString
public class PostVo extends BasePostVo { @EqualsAndHashCode
public class PostVo {
ContentVo content; private MetadataOperator metadata;
List<CategoryVo> categories; private Post.PostSpec spec;
List<TagVo> tags; private Post.PostStatus status;
private ContentVo content;
private List<CategoryVo> categories;
private List<TagVo> tags;
private List<Contributor> contributors;
/** /**
* Convert {@link Post} to {@link PostVo}. * Convert {@link Post} to {@link PostVo}.
@ -35,25 +46,11 @@ public class PostVo extends BasePostVo {
Post.PostSpec spec = post.getSpec(); Post.PostSpec spec = post.getSpec();
Post.PostStatus postStatus = post.getStatusOrDefault(); Post.PostStatus postStatus = post.getStatusOrDefault();
return PostVo.builder() return PostVo.builder()
.name(post.getMetadata().getName()) .metadata(post.getMetadata())
.annotations(post.getMetadata().getAnnotations()) .spec(spec)
.title(spec.getTitle()) .status(postStatus)
.cover(spec.getCover())
.allowComment(spec.getAllowComment())
.categories(List.of()) .categories(List.of())
.tags(List.of()) .tags(List.of())
.owner(spec.getOwner())
.pinned(spec.getPinned())
.slug(spec.getSlug())
.htmlMetas(nullSafe(spec.getHtmlMetas()))
.published(spec.getPublished())
.publishTime(spec.getPublishTime())
.priority(spec.getPriority())
.version(spec.getVersion())
.visible(spec.getVisible())
.template(spec.getTemplate())
.permalink(postStatus.getPermalink())
.excerpt(postStatus.getExcerpt())
.contributors(List.of()) .contributors(List.of())
.content(new ContentVo(null, null)) .content(new ContentVo(null, null))
.build(); .build();

View File

@ -1,9 +1,11 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.Value; import lombok.Value;
import lombok.experimental.SuperBuilder;
import run.halo.app.core.extension.Reply; import run.halo.app.core.extension.Reply;
import run.halo.app.extension.MetadataOperator;
/** /**
* A value object for {@link Reply}. * A value object for {@link Reply}.
@ -12,13 +14,14 @@ import run.halo.app.core.extension.Reply;
* @since 2.0.0 * @since 2.0.0
*/ */
@Value @Value
@SuperBuilder @Builder
@EqualsAndHashCode(callSuper = true) @ToString
public class ReplyVo extends BaseCommentVo { @EqualsAndHashCode
public class ReplyVo {
String commentName; MetadataOperator metadata;
String quoteReply; Reply.ReplySpec spec;
/** /**
* Convert {@link Reply} to {@link ReplyVo}. * Convert {@link Reply} to {@link ReplyVo}.
@ -29,17 +32,8 @@ public class ReplyVo extends BaseCommentVo {
public static ReplyVo from(Reply reply) { public static ReplyVo from(Reply reply) {
Reply.ReplySpec spec = reply.getSpec(); Reply.ReplySpec spec = reply.getSpec();
return ReplyVo.builder() return ReplyVo.builder()
.name(reply.getMetadata().getName()) .metadata(reply.getMetadata())
.commentName(spec.getCommentName()) .spec(spec)
.quoteReply(spec.getQuoteReply())
.raw(spec.getRaw())
.content(spec.getContent())
.owner(spec.getOwner())
.userAgent(spec.getUserAgent())
.priority(spec.getPriority())
.top(spec.getTop())
.allowNotification(spec.getAllowNotification())
.annotations(reply.getMetadata().getAnnotations())
.build(); .build();
} }
} }

View File

@ -1,12 +1,13 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.List; import java.util.List;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import run.halo.app.core.extension.SinglePage; import run.halo.app.core.extension.SinglePage;
import run.halo.app.extension.MetadataOperator;
/** /**
* A value object for {@link SinglePage}. * A value object for {@link SinglePage}.
@ -15,12 +16,20 @@ import run.halo.app.core.extension.SinglePage;
* @since 2.0.0 * @since 2.0.0
*/ */
@Data @Data
@SuperBuilder @Builder
@ToString(callSuper = true) @ToString
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode
public class SinglePageVo extends BasePostVo { public class SinglePageVo {
ContentVo content; private MetadataOperator metadata;
private SinglePage.SinglePageSpec spec;
private SinglePage.SinglePageStatus status;
private ContentVo content;
private List<Contributor> contributors;
/** /**
* Convert {@link SinglePage} to {@link SinglePageVo}. * Convert {@link SinglePage} to {@link SinglePageVo}.
@ -33,23 +42,9 @@ public class SinglePageVo extends BasePostVo {
SinglePage.SinglePageSpec spec = singlePage.getSpec(); SinglePage.SinglePageSpec spec = singlePage.getSpec();
SinglePage.SinglePageStatus pageStatus = singlePage.getStatus(); SinglePage.SinglePageStatus pageStatus = singlePage.getStatus();
return SinglePageVo.builder() return SinglePageVo.builder()
.name(singlePage.getMetadata().getName()) .metadata(singlePage.getMetadata())
.annotations(singlePage.getMetadata().getAnnotations()) .spec(spec)
.title(spec.getTitle()) .status(pageStatus)
.cover(spec.getCover())
.allowComment(spec.getAllowComment())
.owner(spec.getOwner())
.pinned(spec.getPinned())
.slug(spec.getSlug())
.htmlMetas(nullSafe(spec.getHtmlMetas()))
.published(spec.getPublished())
.publishTime(spec.getPublishTime())
.priority(spec.getPriority())
.version(spec.getVersion())
.visible(spec.getVisible())
.template(spec.getTemplate())
.permalink(pageStatus.getPermalink())
.excerpt(pageStatus.getExcerpt())
.contributors(List.of()) .contributors(List.of())
.content(new ContentVo(null, null)) .content(new ContentVo(null, null))
.build(); .build();

View File

@ -1,10 +1,9 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.List;
import java.util.Map;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import run.halo.app.core.extension.Tag; import run.halo.app.core.extension.Tag;
import run.halo.app.extension.MetadataOperator;
/** /**
* A value object for {@link Tag}. * A value object for {@link Tag}.
@ -13,21 +12,11 @@ import run.halo.app.core.extension.Tag;
@Builder @Builder
public class TagVo { public class TagVo {
String name; MetadataOperator metadata;
String displayName; Tag.TagSpec spec;
String slug; Tag.TagStatus status;
String color;
String cover;
String permalink;
List<String> posts;
Map<String, String> annotations;
/** /**
* Convert {@link Tag} to {@link TagVo}. * Convert {@link Tag} to {@link TagVo}.
@ -39,14 +28,9 @@ public class TagVo {
Tag.TagSpec spec = tag.getSpec(); Tag.TagSpec spec = tag.getSpec();
Tag.TagStatus status = tag.getStatusOrDefault(); Tag.TagStatus status = tag.getStatusOrDefault();
return TagVo.builder() return TagVo.builder()
.name(tag.getMetadata().getName()) .metadata(tag.getMetadata())
.displayName(spec.getDisplayName()) .spec(spec)
.slug(spec.getSlug()) .status(status)
.color(spec.getColor())
.cover(spec.getCover())
.permalink(status.getPermalink())
.posts(status.getPosts())
.annotations(tag.getMetadata().getAnnotations())
.build(); .build();
} }
} }

View File

@ -26,6 +26,8 @@ import org.thymeleaf.templateresolver.StringTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource; import org.thymeleaf.templateresource.StringTemplateResource;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import run.halo.app.core.extension.Post;
import run.halo.app.extension.Metadata;
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.infra.SystemSetting; import run.halo.app.infra.SystemSetting;
import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.DefaultTemplateEnum;
@ -113,9 +115,13 @@ class HaloProcessorDialectTest {
List<Map<String, String>> htmlMetas = new ArrayList<>(); List<Map<String, String>> htmlMetas = new ArrayList<>();
htmlMetas.add(ImmutableSortedMap.of("name", "post-meta-V1", "content", "post-meta-V1")); htmlMetas.add(ImmutableSortedMap.of("name", "post-meta-V1", "content", "post-meta-V1"));
htmlMetas.add(ImmutableSortedMap.of("name", "post-meta-V2", "content", "post-meta-V2")); htmlMetas.add(ImmutableSortedMap.of("name", "post-meta-V2", "content", "post-meta-V2"));
Post.PostSpec postSpec = new Post.PostSpec();
postSpec.setHtmlMetas(htmlMetas);
Metadata metadata = new Metadata();
metadata.setName("fake-post");
PostVo postVo = PostVo.builder() PostVo postVo = PostVo.builder()
.htmlMetas(htmlMetas) .spec(postSpec)
.name("fake-post").build(); .metadata(metadata).build();
when(postFinder.getByName(eq("fake-post"))).thenReturn(postVo); when(postFinder.getByName(eq("fake-post"))).thenReturn(postVo);
String result = templateEngine.process("post", context); String result = templateEngine.process("post", context);

View File

@ -50,20 +50,27 @@ class CategoryFinderImplTest {
when(client.fetch(eq(Category.class), eq("hello"))) when(client.fetch(eq(Category.class), eq("hello")))
.thenReturn(Mono.just(category())); .thenReturn(Mono.just(category()));
CategoryVo categoryVo = categoryFinder.getByName("hello"); CategoryVo categoryVo = categoryFinder.getByName("hello");
categoryVo.getMetadata().setCreationTimestamp(null);
JSONAssert.assertEquals(""" JSONAssert.assertEquals("""
{ {
"name": "hello", "metadata": {
"displayName": "displayName-1", "name": "hello",
"slug": "slug-1", "annotations": {
"description": "description-1", "K1": "V1"
"cover": "cover-1", }
"template": "template-1", },
"priority": 0, "spec": {
"children": [ "displayName": "displayName-1",
"C1", "slug": "slug-1",
"C2" "description": "description-1",
], "cover": "cover-1",
"postCount": 0 "template": "template-1",
"priority": 0,
"children": [
"C1",
"C2"
]
}
} }
""", """,
JsonUtils.objectToJson(categoryVo), JsonUtils.objectToJson(categoryVo),
@ -80,7 +87,7 @@ class CategoryFinderImplTest {
.thenReturn(Mono.just(categories)); .thenReturn(Mono.just(categories));
ListResult<CategoryVo> list = categoryFinder.list(1, 10); ListResult<CategoryVo> list = categoryFinder.list(1, 10);
assertThat(list.getItems()).hasSize(3); assertThat(list.getItems()).hasSize(3);
assertThat(list.get().map(CategoryVo::getName).toList()) assertThat(list.get().map(categoryVo -> categoryVo.getMetadata().getName()).toList())
.isEqualTo(List.of("c3", "c2", "hello")); .isEqualTo(List.of("c3", "c2", "hello"));
} }

View File

@ -54,72 +54,135 @@ class MenuFinderImplTest {
List<MenuVo> menuVos = menuFinder.listAsTree(); List<MenuVo> menuVos = menuFinder.listAsTree();
JSONAssert.assertEquals(""" JSONAssert.assertEquals("""
[ [
{ {
"name": "D", "metadata": {
"displayName": "D", "name": "D"
"menuItems": [ },
{ "spec": {
"name": "E", "displayName": "D",
"priority": 0, "menuItems": [
"childrenNames": [ "E"
"A", ]
"C" },
], "menuItems": [
"children": [ {
{ "metadata": {
"name": "A", "name": "E"
"parentName": "E", },
"priority": 0, "spec": {
"childrenNames": [ "displayName": "E",
"B" "priority": 0,
], "children": [
"children": [ "A",
{ "C"
"name": "B", ]
"parentName": "A", },
"priority": 0 "status": {},
} "children": [
] {
}, "metadata": {
{ "name": "A"
"name": "C", },
"parentName": "E", "spec": {
"priority": 0 "displayName": "A",
} "priority": 0,
] "children": [
} "B"
] ]
}, },
{ "status": {},
"name": "X", "children": [
"displayName": "X", {
"menuItems": [ "metadata": {
{ "name": "B"
"name": "G", },
"priority": 0 "spec": {
} "displayName": "B",
] "priority": 0
}, },
{ "status": {},
"name": "Y", "parentName": "A"
"displayName": "Y", }
"menuItems": [ ],
{ "parentName": "E"
"name": "F", },
"priority": 0, {
"childrenNames": [ "metadata": {
"H" "name": "C"
], },
"children": [ "spec": {
{ "displayName": "C",
"name": "H", "priority": 0
"parentName": "F", },
"priority": 0 "status": {},
} "parentName": "E"
] }
} ]
] }
} ]
},
{
"metadata": {
"name": "X"
},
"spec": {
"displayName": "X",
"menuItems": [
"G"
]
},
"menuItems": [
{
"metadata": {
"name": "G"
},
"spec": {
"displayName": "G",
"priority": 0
},
"status": {}
}
]
},
{
"metadata": {
"name": "Y"
},
"spec": {
"displayName": "Y",
"menuItems": [
"F"
]
},
"menuItems": [
{
"metadata": {
"name": "F"
},
"spec": {
"displayName": "F",
"priority": 0,
"children": [
"H"
]
},
"status": {},
"children": [
{
"metadata": {
"name": "H"
},
"spec": {
"displayName": "H",
"priority": 0
},
"status": {},
"parentName": "F"
}
]
}
]
}
] ]
""", """,
JsonUtils.objectToJson(menuVos), JsonUtils.objectToJson(menuVos),

View File

@ -48,21 +48,28 @@ class TagFinderImplTest {
when(client.fetch(eq(Tag.class), eq("t1"))) when(client.fetch(eq(Tag.class), eq("t1")))
.thenReturn(Mono.just(tag(1))); .thenReturn(Mono.just(tag(1)));
TagVo tagVo = tagFinder.getByName("t1"); TagVo tagVo = tagFinder.getByName("t1");
tagVo.getMetadata().setCreationTimestamp(null);
JSONAssert.assertEquals(""" JSONAssert.assertEquals("""
{ {
"name": "t1", "metadata": {
"displayName": "displayName-1", "name": "t1",
"slug": "slug-1", "annotations": {
"color": "color-1", "K1": "V1"
"cover": "cover-1", }
"permalink": "permalink-1", },
"posts": [ "spec": {
"p1", "displayName": "displayName-1",
"p2" "slug": "slug-1",
], "color": "color-1",
"annotations": { "cover": "cover-1"
"K1": "V1" },
} "status": {
"permalink": "permalink-1",
"posts": [
"p1",
"p2"
]
}
} }
""", """,
JsonUtils.objectToJson(tagVo), JsonUtils.objectToJson(tagVo),
@ -78,7 +85,9 @@ class TagFinderImplTest {
); );
List<TagVo> tags = tagFinder.listAll(); List<TagVo> tags = tagFinder.listAll();
assertThat(tags).hasSize(3); assertThat(tags).hasSize(3);
assertThat(tags.stream().map(TagVo::getName).collect(Collectors.toList())) assertThat(tags.stream()
.map(tag -> tag.getMetadata().getName())
.collect(Collectors.toList()))
.isEqualTo(List.of("t3", "t2", "t1")); .isEqualTo(List.of("t3", "t2", "t1"));
} }