mirror of https://github.com/halo-dev/halo
feat: create a configmap based on the setting definition when installing a theme (#2440)
#### What type of PR is this? /kind improvement /area core /milestone 2.0 #### What this PR does / why we need it: - 安装主题后通过读取主题 Setting 模型中的默认值初始化一个 ConfigMap - 修改了 Setting 模型的 spec 结构(多了一层 forms 嵌套),配置示例如下: ```yaml apiVersion: v1alpha1 kind: Setting metadata: name: theme-anatole-setting spec: forms: - group: basic label: 基本设置 formSchema: - $formkit: select name: sidebar_width label: 侧边栏宽度 options: "20%": 20% "30%": 30% "40%": 40% "50%": 50% value: "40%" ``` #### Which issue(s) this PR fixes: Fixes #2414 #### Special notes for your reviewer: /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? ```release-note None ```pull/2456/head
parent
cda6402780
commit
95b7a273f8
|
@ -21,17 +21,25 @@ public class Setting extends AbstractExtension {
|
|||
|
||||
public static final String KIND = "Setting";
|
||||
|
||||
@Schema(required = true, minLength = 1)
|
||||
private List<SettingSpec> spec;
|
||||
@Schema(required = true)
|
||||
private SettingSpec spec;
|
||||
|
||||
@Data
|
||||
public static class SettingSpec {
|
||||
|
||||
@Schema(required = true, minLength = 1)
|
||||
private List<SettingForm> forms;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SettingForm {
|
||||
|
||||
@Schema(required = true)
|
||||
private String group;
|
||||
|
||||
private String label;
|
||||
|
||||
@Schema(required = true)
|
||||
private List<Object> formSchema;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,26 @@
|
|||
package run.halo.app.core.extension.reconciler;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import run.halo.app.core.extension.Setting;
|
||||
import run.halo.app.core.extension.Theme;
|
||||
import run.halo.app.extension.ConfigMap;
|
||||
import run.halo.app.extension.ExtensionClient;
|
||||
import run.halo.app.extension.Metadata;
|
||||
import run.halo.app.extension.controller.Reconciler;
|
||||
import run.halo.app.extension.controller.Reconciler.Request;
|
||||
import run.halo.app.infra.exception.ThemeUninstallException;
|
||||
import run.halo.app.infra.properties.HaloProperties;
|
||||
import run.halo.app.infra.utils.JsonUtils;
|
||||
import run.halo.app.theme.ThemePathPolicy;
|
||||
|
||||
/**
|
||||
|
@ -36,10 +46,77 @@ public class ThemeReconciler implements Reconciler<Request> {
|
|||
if (isDeleted(theme)) {
|
||||
reconcileThemeDeletion(theme);
|
||||
}
|
||||
themeSettingDefaultConfig(theme);
|
||||
});
|
||||
return new Result(false, null);
|
||||
}
|
||||
|
||||
private void themeSettingDefaultConfig(Theme theme) {
|
||||
if (StringUtils.isBlank(theme.getSpec().getSettingName())) {
|
||||
return;
|
||||
}
|
||||
final String userDefinedConfigMapName = theme.getSpec().getConfigMapName();
|
||||
|
||||
final String newConfigMapName = UUID.randomUUID().toString();
|
||||
if (StringUtils.isBlank(userDefinedConfigMapName)) {
|
||||
client.fetch(Theme.class, theme.getMetadata().getName())
|
||||
.ifPresent(themeToUse -> {
|
||||
Theme oldTheme = JsonUtils.deepCopy(themeToUse);
|
||||
themeToUse.getSpec().setConfigMapName(newConfigMapName);
|
||||
if (!oldTheme.equals(themeToUse)) {
|
||||
client.update(themeToUse);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final String configMapNameToUse =
|
||||
StringUtils.defaultIfBlank(userDefinedConfigMapName, newConfigMapName);
|
||||
|
||||
boolean existConfigMap = client.fetch(ConfigMap.class, configMapNameToUse)
|
||||
.isPresent();
|
||||
if (existConfigMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
client.fetch(Setting.class, theme.getSpec().getSettingName())
|
||||
.ifPresent(setting -> {
|
||||
Map<String, String> data = settingDefinedDefaultValueMap(setting);
|
||||
if (CollectionUtils.isEmpty(data)) {
|
||||
return;
|
||||
}
|
||||
ConfigMap configMap = new ConfigMap();
|
||||
configMap.setMetadata(new Metadata());
|
||||
configMap.getMetadata().setName(configMapNameToUse);
|
||||
configMap.setData(data);
|
||||
client.create(configMap);
|
||||
});
|
||||
}
|
||||
|
||||
Map<String, String> settingDefinedDefaultValueMap(Setting setting) {
|
||||
final String defaultValueField = "value";
|
||||
final String nameField = "name";
|
||||
List<Setting.SettingForm> forms = setting.getSpec().getForms();
|
||||
if (CollectionUtils.isEmpty(forms)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> data = new LinkedHashMap<>();
|
||||
for (Setting.SettingForm form : forms) {
|
||||
String group = form.getGroup();
|
||||
Map<String, JsonNode> groupValue = form.getFormSchema().stream()
|
||||
.map(o -> JsonUtils.DEFAULT_JSON_MAPPER.convertValue(o, JsonNode.class))
|
||||
.filter(jsonNode -> jsonNode.isObject() && jsonNode.has(nameField)
|
||||
&& jsonNode.has(defaultValueField))
|
||||
.map(jsonNode -> {
|
||||
String name = jsonNode.findValue(nameField).asText();
|
||||
JsonNode value = jsonNode.findValue(defaultValueField);
|
||||
return Map.entry(name, value);
|
||||
})
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
data.put(group, JsonUtils.objectToJson(groupValue));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private void reconcileThemeDeletion(Theme theme) {
|
||||
deleteThemeFiles(theme);
|
||||
// delete theme setting form
|
||||
|
|
|
@ -12,10 +12,11 @@ kind: Setting
|
|||
metadata:
|
||||
name: local-policy-template-setting
|
||||
spec:
|
||||
- group: default
|
||||
label: Default
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
name: location
|
||||
label: 存储位置
|
||||
help: ~/halo-next/attachments 下的子目录
|
||||
forms:
|
||||
- group: default
|
||||
label: Default
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
name: location
|
||||
label: 存储位置
|
||||
help: ~/halo-next/attachments 下的子目录
|
||||
|
|
|
@ -3,130 +3,131 @@ kind: Setting
|
|||
metadata:
|
||||
name: system
|
||||
spec:
|
||||
- group: basic
|
||||
label: 基本设置
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
label: "站点标题"
|
||||
name: title
|
||||
validation: required
|
||||
- $formkit: text
|
||||
label: "站点副标题"
|
||||
name: subtitle
|
||||
validation: required
|
||||
- $formkit: text
|
||||
label: Logo
|
||||
name: logo
|
||||
- $formkit: text
|
||||
label: Favicon
|
||||
name: favicon
|
||||
- group: user
|
||||
label: 用户设置
|
||||
formSchema:
|
||||
- $formkit: checkbox
|
||||
label: "是否公开注册"
|
||||
value: false
|
||||
name: allowRegistration
|
||||
validation: required
|
||||
- $formkit: text
|
||||
label: "默认角色"
|
||||
name: defaultRole
|
||||
validation: required
|
||||
- group: routeRules
|
||||
label: 主题模板路由设置
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
label: "分类页路由前缀"
|
||||
value: "categories"
|
||||
name: categories
|
||||
validation: required | alphanumeric
|
||||
- $formkit: text
|
||||
label: "标签页路由前缀"
|
||||
value: "tags"
|
||||
name: tags
|
||||
validation: required | alphanumeric
|
||||
- $formkit: text
|
||||
label: "归档页路由前缀"
|
||||
value: "archives"
|
||||
name: archives
|
||||
validation: required | alphanumeric
|
||||
- $formkit: select
|
||||
label: "文章详情页访问规则"
|
||||
value: "/archives/{slug}"
|
||||
options:
|
||||
- /archives/{slug}
|
||||
- /archives/{name}
|
||||
- /?p={name}
|
||||
- /?p={slug}
|
||||
- /{year:\d{4}}/{slug}
|
||||
- /{year:\d{4}}/{month:\d{2}}/{slug}
|
||||
- /{year:\d{4}}/{month:\d{2}}/{day:\d{2}}/{slug}
|
||||
name: post
|
||||
validation: required
|
||||
- group: post
|
||||
label: 文章设置
|
||||
formSchema:
|
||||
- $formkit: select
|
||||
label: "列表排序方式"
|
||||
name: sortOrder
|
||||
value: "publishTime"
|
||||
options:
|
||||
visitCount: "浏览量"
|
||||
publishTime: "发布时间"
|
||||
updateTime: "更新时间"
|
||||
validation: required
|
||||
- $formkit: number
|
||||
label: "列表显示条数"
|
||||
name: pageSize
|
||||
value: 10
|
||||
min: 1
|
||||
max: 100
|
||||
validation: required
|
||||
- $formkit: checkbox
|
||||
label: "新文章审核"
|
||||
value: false
|
||||
name: review
|
||||
help: "用户发布文章是否需要管理员审核"
|
||||
- group: seo
|
||||
label: SEO 设置
|
||||
formSchema:
|
||||
- $formkit: checkbox
|
||||
name: blockSpiders
|
||||
label: "屏蔽搜索引擎"
|
||||
value: false
|
||||
- $formkit: textarea
|
||||
name: keywords
|
||||
label: "站点关键词"
|
||||
- $formkit: textarea
|
||||
name: description
|
||||
label: "站点描述"
|
||||
- group: comment
|
||||
label: 评论设置
|
||||
formSchema:
|
||||
- $formkit: checkbox
|
||||
name: enable
|
||||
value: true
|
||||
label: "启用评论"
|
||||
- $formkit: checkbox
|
||||
name: requireReviewForNew
|
||||
value: true
|
||||
label: "新评论审核"
|
||||
- $formkit: checkbox
|
||||
name: systemUserOnly
|
||||
value: true
|
||||
label: "仅允许注册用户评论"
|
||||
- group: codeInjection
|
||||
label: 代码注入
|
||||
formSchema:
|
||||
- $formkit: textarea
|
||||
label: "全局 head"
|
||||
name: globalHead
|
||||
help: "插入代码到所有页面的 head 标签部分"
|
||||
- $formkit: textarea
|
||||
label: "内容页 head"
|
||||
name: contentHead
|
||||
help: "插入代码到文章页面和自定义页面的 head 标签部分"
|
||||
- $formkit: textarea
|
||||
label: "页脚"
|
||||
name: footer
|
||||
help: "插入代码到所有页面的页脚部分"
|
||||
forms:
|
||||
- group: basic
|
||||
label: 基本设置
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
label: "站点标题"
|
||||
name: title
|
||||
validation: required
|
||||
- $formkit: text
|
||||
label: "站点副标题"
|
||||
name: subtitle
|
||||
validation: required
|
||||
- $formkit: text
|
||||
label: Logo
|
||||
name: logo
|
||||
- $formkit: text
|
||||
label: Favicon
|
||||
name: favicon
|
||||
- group: user
|
||||
label: 用户设置
|
||||
formSchema:
|
||||
- $formkit: checkbox
|
||||
label: "是否公开注册"
|
||||
value: false
|
||||
name: allowRegistration
|
||||
validation: required
|
||||
- $formkit: text
|
||||
label: "默认角色"
|
||||
name: defaultRole
|
||||
validation: required
|
||||
- group: routeRules
|
||||
label: 主题模板路由设置
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
label: "分类页路由前缀"
|
||||
value: "categories"
|
||||
name: categories
|
||||
validation: required | alphanumeric
|
||||
- $formkit: text
|
||||
label: "标签页路由前缀"
|
||||
value: "tags"
|
||||
name: tags
|
||||
validation: required | alphanumeric
|
||||
- $formkit: text
|
||||
label: "归档页路由前缀"
|
||||
value: "archives"
|
||||
name: archives
|
||||
validation: required | alphanumeric
|
||||
- $formkit: select
|
||||
label: "文章详情页访问规则"
|
||||
value: "/archives/{slug}"
|
||||
options:
|
||||
- /archives/{slug}
|
||||
- /archives/{name}
|
||||
- /?p={name}
|
||||
- /?p={slug}
|
||||
- /{year:\d{4}}/{slug}
|
||||
- /{year:\d{4}}/{month:\d{2}}/{slug}
|
||||
- /{year:\d{4}}/{month:\d{2}}/{day:\d{2}}/{slug}
|
||||
name: post
|
||||
validation: required
|
||||
- group: post
|
||||
label: 文章设置
|
||||
formSchema:
|
||||
- $formkit: select
|
||||
label: "列表排序方式"
|
||||
name: sortOrder
|
||||
value: "publishTime"
|
||||
options:
|
||||
visitCount: "浏览量"
|
||||
publishTime: "发布时间"
|
||||
updateTime: "更新时间"
|
||||
validation: required
|
||||
- $formkit: number
|
||||
label: "列表显示条数"
|
||||
name: pageSize
|
||||
value: 10
|
||||
min: 1
|
||||
max: 100
|
||||
validation: required
|
||||
- $formkit: checkbox
|
||||
label: "新文章审核"
|
||||
value: false
|
||||
name: review
|
||||
help: "用户发布文章是否需要管理员审核"
|
||||
- group: seo
|
||||
label: SEO 设置
|
||||
formSchema:
|
||||
- $formkit: checkbox
|
||||
name: blockSpiders
|
||||
label: "屏蔽搜索引擎"
|
||||
value: false
|
||||
- $formkit: textarea
|
||||
name: keywords
|
||||
label: "站点关键词"
|
||||
- $formkit: textarea
|
||||
name: description
|
||||
label: "站点描述"
|
||||
- group: comment
|
||||
label: 评论设置
|
||||
formSchema:
|
||||
- $formkit: checkbox
|
||||
name: enable
|
||||
value: true
|
||||
label: "启用评论"
|
||||
- $formkit: checkbox
|
||||
name: requireReviewForNew
|
||||
value: true
|
||||
label: "新评论审核"
|
||||
- $formkit: checkbox
|
||||
name: systemUserOnly
|
||||
value: true
|
||||
label: "仅允许注册用户评论"
|
||||
- group: codeInjection
|
||||
label: 代码注入
|
||||
formSchema:
|
||||
- $formkit: textarea
|
||||
label: "全局 head"
|
||||
name: globalHead
|
||||
help: "插入代码到所有页面的 head 标签部分"
|
||||
- $formkit: textarea
|
||||
label: "内容页 head"
|
||||
name: contentHead
|
||||
help: "插入代码到文章页面和自定义页面的 head 标签部分"
|
||||
- $formkit: textarea
|
||||
label: "页脚"
|
||||
name: footer
|
||||
help: "插入代码到所有页面的页脚部分"
|
||||
|
|
|
@ -27,24 +27,25 @@ class SettingTest {
|
|||
metadata:
|
||||
name: setting-name
|
||||
spec:
|
||||
- group: basic
|
||||
label: 基本设置
|
||||
formSchema:
|
||||
- $el: h1
|
||||
children: Register
|
||||
- $formkit: text
|
||||
help: This will be used for your account.
|
||||
label: Email
|
||||
name: email
|
||||
validation: required|email
|
||||
- group: sns
|
||||
label: 社交资料
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
help: This will be used for your theme.
|
||||
label: color
|
||||
name: color
|
||||
validation: required
|
||||
forms:
|
||||
- group: basic
|
||||
label: 基本设置
|
||||
formSchema:
|
||||
- $el: h1
|
||||
children: Register
|
||||
- $formkit: text
|
||||
help: This will be used for your account.
|
||||
label: Email
|
||||
name: email
|
||||
validation: required|email
|
||||
- group: sns
|
||||
label: 社交资料
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
help: This will be used for your theme.
|
||||
label: color
|
||||
name: color
|
||||
validation: required
|
||||
""";
|
||||
List<Unstructured> unstructureds =
|
||||
new YamlUnstructuredLoader(new InMemoryResource(settingYaml)).load();
|
||||
|
@ -55,43 +56,45 @@ class SettingTest {
|
|||
assertThat(setting).isNotNull();
|
||||
JSONAssert.assertEquals("""
|
||||
{
|
||||
"spec": [
|
||||
{
|
||||
"group": "basic",
|
||||
"label": "基本设置",
|
||||
"formSchema": [
|
||||
{
|
||||
"$el": "h1",
|
||||
"children": "Register"
|
||||
},
|
||||
{
|
||||
"$formkit": "text",
|
||||
"help": "This will be used for your account.",
|
||||
"label": "Email",
|
||||
"name": "email",
|
||||
"validation": "required|email"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "sns",
|
||||
"label": "社交资料",
|
||||
"formSchema": [
|
||||
{
|
||||
"$formkit": "text",
|
||||
"help": "This will be used for your theme.",
|
||||
"label": "color",
|
||||
"name": "color",
|
||||
"validation": "required"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"apiVersion": "v1alpha1",
|
||||
"kind": "Setting",
|
||||
"metadata": {
|
||||
"name": "setting-name"
|
||||
}
|
||||
"spec": {
|
||||
"forms": [
|
||||
{
|
||||
"group": "basic",
|
||||
"label": "基本设置",
|
||||
"formSchema": [
|
||||
{
|
||||
"$el": "h1",
|
||||
"children": "Register"
|
||||
},
|
||||
{
|
||||
"$formkit": "text",
|
||||
"help": "This will be used for your account.",
|
||||
"label": "Email",
|
||||
"name": "email",
|
||||
"validation": "required|email"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "sns",
|
||||
"label": "社交资料",
|
||||
"formSchema": [
|
||||
{
|
||||
"$formkit": "text",
|
||||
"help": "This will be used for your theme.",
|
||||
"label": "color",
|
||||
"name": "color",
|
||||
"validation": "required"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"apiVersion": "v1alpha1",
|
||||
"kind": "Setting",
|
||||
"metadata": {
|
||||
"name": "setting-name"
|
||||
}
|
||||
}
|
||||
""",
|
||||
JsonUtils.objectToJson(setting), false);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package run.halo.app.core.extension.reconciler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
@ -11,21 +12,28 @@ import java.io.IOException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import run.halo.app.core.extension.Setting;
|
||||
import run.halo.app.core.extension.Theme;
|
||||
import run.halo.app.extension.ConfigMap;
|
||||
import run.halo.app.extension.ExtensionClient;
|
||||
import run.halo.app.extension.Metadata;
|
||||
import run.halo.app.extension.controller.Reconciler;
|
||||
import run.halo.app.infra.properties.HaloProperties;
|
||||
import run.halo.app.infra.utils.JsonUtils;
|
||||
import run.halo.app.theme.ThemePathPolicy;
|
||||
|
||||
/**
|
||||
|
@ -64,8 +72,9 @@ class ThemeReconcilerTest {
|
|||
Files.createDirectory(testWorkDir);
|
||||
when(haloProperties.getWorkDir()).thenReturn(testWorkDir);
|
||||
|
||||
ThemeReconciler themeReconciler = new ThemeReconciler(extensionClient, haloProperties);
|
||||
ThemePathPolicy themePathPolicy = new ThemePathPolicy(testWorkDir);
|
||||
final ThemeReconciler themeReconciler =
|
||||
new ThemeReconciler(extensionClient, haloProperties);
|
||||
final ThemePathPolicy themePathPolicy = new ThemePathPolicy(testWorkDir);
|
||||
|
||||
Theme theme = new Theme();
|
||||
Metadata metadata = new Metadata();
|
||||
|
@ -93,10 +102,127 @@ class ThemeReconcilerTest {
|
|||
|
||||
themeReconciler.reconcile(new Reconciler.Request(metadata.getName()));
|
||||
|
||||
verify(extensionClient, times(1)).fetch(eq(Theme.class), eq(metadata.getName()));
|
||||
verify(extensionClient, times(1)).fetch(eq(Setting.class), eq(themeSpec.getSettingName()));
|
||||
verify(extensionClient, times(2)).fetch(eq(Theme.class), eq(metadata.getName()));
|
||||
verify(extensionClient, times(2)).fetch(eq(Setting.class), eq(themeSpec.getSettingName()));
|
||||
|
||||
assertThat(Files.exists(testWorkDir)).isTrue();
|
||||
assertThat(Files.exists(defaultThemePath)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void themeSettingDefaultValue() throws IOException, JSONException {
|
||||
Path testWorkDir = tempDirectory.resolve("reconcile-setting-value");
|
||||
Files.createDirectory(testWorkDir);
|
||||
when(haloProperties.getWorkDir()).thenReturn(testWorkDir);
|
||||
|
||||
final ThemeReconciler themeReconciler =
|
||||
new ThemeReconciler(extensionClient, haloProperties);
|
||||
|
||||
Theme theme = new Theme();
|
||||
Metadata metadata = new Metadata();
|
||||
metadata.setName("theme-test");
|
||||
theme.setMetadata(metadata);
|
||||
theme.setKind(Theme.KIND);
|
||||
theme.setApiVersion("theme.halo.run/v1alpha1");
|
||||
Theme.ThemeSpec themeSpec = new Theme.ThemeSpec();
|
||||
themeSpec.setSettingName(null);
|
||||
theme.setSpec(themeSpec);
|
||||
|
||||
when(extensionClient.fetch(eq(Theme.class), eq(metadata.getName())))
|
||||
.thenReturn(Optional.of(theme));
|
||||
Reconciler.Result reconcile =
|
||||
themeReconciler.reconcile(new Reconciler.Request(metadata.getName()));
|
||||
assertThat(reconcile.reEnqueue()).isFalse();
|
||||
verify(extensionClient, times(1)).fetch(eq(Theme.class), eq(metadata.getName()));
|
||||
|
||||
// setting exists
|
||||
themeSpec.setSettingName("theme-test-setting");
|
||||
when(extensionClient.fetch(eq(ConfigMap.class), any()))
|
||||
.thenReturn(Optional.of(Mockito.mock(ConfigMap.class)));
|
||||
assertThat(theme.getSpec().getConfigMapName()).isNull();
|
||||
ArgumentCaptor<Theme> captor = ArgumentCaptor.forClass(Theme.class);
|
||||
themeReconciler.reconcile(new Reconciler.Request(metadata.getName()));
|
||||
verify(extensionClient, times(3))
|
||||
.fetch(eq(Theme.class), eq(metadata.getName()));
|
||||
verify(extensionClient, times(1))
|
||||
.update(captor.capture());
|
||||
Theme value = captor.getValue();
|
||||
assertThat(value.getSpec().getConfigMapName()).isNotNull();
|
||||
|
||||
// populate setting name and configMap name and configMap not exists
|
||||
themeSpec.setSettingName("theme-test-setting");
|
||||
themeSpec.setConfigMapName("theme-test-configmap");
|
||||
when(extensionClient.fetch(eq(ConfigMap.class), any()))
|
||||
.thenReturn(Optional.empty());
|
||||
when(extensionClient.fetch(eq(Setting.class), eq(themeSpec.getSettingName())))
|
||||
.thenReturn(Optional.of(getFakeSetting()));
|
||||
themeReconciler.reconcile(new Reconciler.Request(metadata.getName()));
|
||||
verify(extensionClient, times(1))
|
||||
.fetch(eq(Setting.class), eq(themeSpec.getSettingName()));
|
||||
ArgumentCaptor<ConfigMap> configMapCaptor = ArgumentCaptor.forClass(ConfigMap.class);
|
||||
verify(extensionClient, times(1)).create(any(ConfigMap.class));
|
||||
verify(extensionClient, times(1)).create(configMapCaptor.capture());
|
||||
ConfigMap defaultValueConfigMap = configMapCaptor.getValue();
|
||||
Map<String, String> data = defaultValueConfigMap.getData();
|
||||
JSONAssert.assertEquals("""
|
||||
{
|
||||
"sns": "{\\"email\\":\\"example@exmple.com\\"}"
|
||||
}
|
||||
""",
|
||||
JsonUtils.objectToJson(data),
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingDefinedDefaultValueMap() throws JSONException {
|
||||
Setting setting = getFakeSetting();
|
||||
when(haloProperties.getWorkDir()).thenReturn(tempDirectory);
|
||||
Map<String, String> map = new ThemeReconciler(extensionClient, haloProperties)
|
||||
.settingDefinedDefaultValueMap(setting);
|
||||
JSONAssert.assertEquals("""
|
||||
{
|
||||
"sns": "{\\"email\\":\\"example@exmple.com\\"}"
|
||||
}
|
||||
""",
|
||||
JsonUtils.objectToJson(map),
|
||||
true);
|
||||
}
|
||||
|
||||
private static Setting getFakeSetting() {
|
||||
String settingJson = """
|
||||
{
|
||||
"apiVersion": "v1alpha1",
|
||||
"kind": "Setting",
|
||||
"metadata": {
|
||||
"name": "theme-default-setting"
|
||||
},
|
||||
"spec": {
|
||||
"forms": [{
|
||||
"formSchema": [
|
||||
{
|
||||
"$el": "h1",
|
||||
"children": "Register"
|
||||
},
|
||||
{
|
||||
"$formkit": "text",
|
||||
"label": "Email",
|
||||
"name": "email",
|
||||
"value": "example@exmple.com"
|
||||
},
|
||||
{
|
||||
"$formkit": "password",
|
||||
"label": "Password",
|
||||
"name": "password",
|
||||
"validation": "required|length:5,16",
|
||||
"value": null
|
||||
}
|
||||
],
|
||||
"group": "sns",
|
||||
"label": "社交资料"
|
||||
}]
|
||||
}
|
||||
}
|
||||
""";
|
||||
return JsonUtils.jsonToObject(settingJson, Setting.class);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue