Complete yaml conversion test

pull/146/head
johnniang 2019-04-10 11:12:15 +08:00
parent 8a8d55eae1
commit 8054b8f714
6 changed files with 421 additions and 21 deletions

View File

@ -1,5 +1,8 @@
package run.halo.app.model.enums;
import org.springframework.lang.Nullable;
/**
* Data type enum.
*
@ -27,4 +30,22 @@ public enum DataType implements ValueEnum<Integer> {
public Integer getValue() {
return value;
}
/**
* Data type of string.
*
* @param type data type string
* @return corresponding data type, default is `STRING` if the type is missing
*/
public static DataType typeOf(@Nullable Object type) {
if (type != null) {
for (DataType datatype : values()) {
if (datatype.name().equalsIgnoreCase(type.toString())) {
return datatype;
}
}
}
return STRING;
}
}

View File

@ -0,0 +1,40 @@
package run.halo.app.model.enums;
import org.springframework.lang.Nullable;
/**
* Input type enum.
*
* @author johnniang
* @date 4/10/19
*/
public enum InputType {
TEXT,
NUMBER,
RADIO,
SELECT,
TEXTAREA;
/**
* Convert type to input type.
*
* @param type input type
* @return corresponding input type or TEXT if the given type is missing or mismatch
*/
public static InputType typeOf(@Nullable Object type) {
if (type != null) {
for (InputType inputType : values()) {
if (inputType.name().equalsIgnoreCase(type.toString())) {
return inputType;
}
}
}
return TEXT;
}
}

View File

@ -36,7 +36,7 @@ public interface ThemeSettingService {
* @param themeId theme id must not be blank
*/
@Transactional
void save(@Nullable Map<String, String> settings, @NonNull String themeId);
void save(@Nullable Map<String, Object> settings, @NonNull String themeId);
/**
* Lists theme settings by theme id.
@ -54,5 +54,5 @@ public interface ThemeSettingService {
* @return theme setting map
*/
@NonNull
Map<String, String> listAsMapBy(@NonNull String themeId);
Map<String, Object> listAsMapBy(@NonNull String themeId);
}

View File

@ -62,7 +62,7 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
}
@Override
public void save(Map<String, String> settings, String themeId) {
public void save(Map<String, Object> settings, String themeId) {
assertThemeIdHasText(themeId);
if (CollectionUtils.isEmpty(settings)) {
@ -70,7 +70,7 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
}
// Save the settings
settings.forEach((key, value) -> save(key, value, themeId));
settings.forEach((key, value) -> save(key, value.toString(), themeId));
}
@Override
@ -81,7 +81,9 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
}
@Override
public Map<String, String> listAsMapBy(String themeId) {
public Map<String, Object> listAsMapBy(String themeId) {
// TODO Convert to corresponding data type
return ServiceUtils.convertToMap(listBy(themeId), ThemeSetting::getKey, ThemeSetting::getValue);
}

View File

@ -85,13 +85,13 @@ public class ThemeController {
@GetMapping("activation/settings")
@ApiOperation("Lists activated theme settings")
public Map<String, String> listSettingsBy() {
public Map<String, Object> listSettingsBy() {
return themeSettingService.listAsMapBy(themeService.getActivatedThemeId());
}
@PostMapping("activation/settings")
@ApiOperation("Saves theme settings")
public void saveSettingsBy(@RequestBody Map<String, String> settings) {
public void saveSettingsBy(@RequestBody Map<String, Object> settings) {
themeSettingService.save(settings, themeService.getActivatedThemeId());
}
@ -104,7 +104,7 @@ public class ThemeController {
@PostMapping("{themeId}/settings")
@ApiOperation("Saves theme settings")
public void saveSettingsBy(@PathVariable("themeId") String themeId,
@RequestBody Map<String, String> settings) {
@RequestBody Map<String, Object> settings) {
themeSettingService.save(settings, themeId);
}

View File

@ -2,9 +2,14 @@ package run.halo.app.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import lombok.Data;
import org.junit.Test;
import org.springframework.lang.Nullable;
import run.halo.app.model.enums.DataType;
import run.halo.app.model.enums.InputType;
import java.io.IOException;
import java.util.*;
/**
* Yaml test.
@ -21,26 +26,358 @@ public class YamlTest {
@Test
public void readYamlTest() throws IOException {
String yaml = "style:\n" +
" name: Style settings\n" +
String yaml = "sns:\n" +
" label: 社交资料设置\n" +
" items:\n" +
" post_title_lower:\n" +
" name: post_title_lower\n" +
" description: Post title lower\n" +
" rss:\n" +
" name: rss\n" +
" label: RSS\n" +
" type: radio\n" +
" defaultValue: true\n" +
" default: true\n" +
" options:\n" +
" - value: true\n" +
" label: Enabled\n" +
" label: 开启\n" +
" - value: false\n" +
" label: Disabled\n" +
" custom_style:\n" +
" name: custom_style\n" +
" description: Custom style\n" +
" type: textarea\n";
" label: 关闭\n" +
" twitter:\n" +
" name: twitter\n" +
" label: Twitter\n" +
" type: text\n" +
" facebook:\n" +
" name: facebook\n" +
" label: Facebook\n" +
" type: text\n" +
"style:\n" +
" label: 样式设置\n" +
" items:\n" +
" icon:\n" +
" name: icon\n" +
" label: 右上角图标\n" +
" type: text\n" +
" post_title_uppper:\n" +
" name: post_title_uppper\n" +
" label: 文章标题大写\n" +
" type: radio\n" +
" default: true\n" +
" options:\n" +
" - value: true\n" +
" label: 开启\n" +
" - value: false\n" +
" label: 关闭";
Object config = yamlMapper.readValue(yaml, Object.class);
LinkedHashMap config = yamlMapper.readValue(yaml, LinkedHashMap.class);
System.out.println(config.getClass());
System.out.println(jsonMapper.writeValueAsString(config));
}
@Test
@SuppressWarnings("unchecked")
public void readAnotherYamlTest() throws IOException {
String yaml = "sns:\n" +
" label: 社交资料设置\n" +
" items:\n" +
" - name: rss\n" +
" label: RSS\n" +
" type: radio\n" +
" default: true\n" +
" options:\n" +
" - value: true\n" +
" label: 开启\n" +
" - value: false\n" +
" label: 关闭\n" +
" - name: twitter\n" +
" label: Twitter\n" +
" type: text\n" +
" - name: facebook\n" +
" label: Facebook\n" +
" type: text\n" +
" - name: instagram\n" +
" label: Instagram\n" +
" type: text\n" +
"style:\n" +
" label: 样式设置\n" +
" items:\n" +
" - name: icon\n" +
" label: 右上角图标\n" +
" type: text\n" +
" - name: post_title_uppper\n" +
" label: 文章标题大写\n" +
" type: radio\n" +
" default: true\n" +
" options:\n" +
" - value: true\n" +
" label: 开启\n" +
" - value: false\n" +
" label: 关闭\n" +
" - name: blog_title_uppper\n" +
" label: 博客标题大写\n" +
" type: radio\n" +
" default: true\n" +
" options:\n" +
" - value: true\n" +
" label: 开启\n" +
" - value: false\n" +
" label: 关闭\n";
Object config = yamlMapper.readValue(yaml, Object.class);
List<Tab> tabs = handleTabs(config);
System.out.println(config.getClass());
System.out.println(tabs);
System.out.println(jsonMapper.writeValueAsString(config));
}
@Test
public void convertYamlTest() throws IOException {
String yaml = "- name: sns\n" +
" label: 社交资料设置\n" +
" items:\n" +
" - name: rss\n" +
" label: RSS\n" +
" type: radio\n" +
" default: true\n" +
" options:\n" +
" - value: true\n" +
" label: 开启\n" +
" - value: false\n" +
" label: 关闭\n" +
" - name: twitter\n" +
" label: Twitter\n" +
" type: text\n" +
" - name: facebook\n" +
" label: Facebook\n" +
" type: text\n" +
" - name: instagram\n" +
" label: Instagram\n" +
" type: text\n" +
"- name: style\n" +
" label: 样式设置\n" +
" items:\n" +
" - name: icon\n" +
" label: 右上角图标\n" +
" type: text\n" +
" - name: post_title_uppper\n" +
" label: 文章标题大写\n" +
" type: radio\n" +
" default: true\n" +
" options:\n" +
" - value: true\n" +
" label: 开启\n" +
" - value: false\n" +
" label: 关闭\n" +
" - name: blog_title_uppper\n" +
" label: 博客标题大写\n" +
" type: radio\n" +
" default: true\n" +
" options:\n" +
" - value: true\n" +
" label: 开启\n" +
" - value: false\n" +
" label: 关闭";
Object config = yamlMapper.readValue(yaml, Object.class);
List<Tab> tabs = handleTabs(config);
System.out.println(config.getClass());
System.out.print(tabs);
}
@SuppressWarnings("unchecked")
private List<Tab> handleTabs(@Nullable Object config) {
List<Tab> tabs = new LinkedList<>();
if (config instanceof List) {
List configList = (List) config;
// Resolve tab
configList.forEach(tabYaml -> {
// tabYaml should be map
if (!(tabYaml instanceof Map)) {
return;
}
Map tabMap = ((Map) tabYaml);
Tab tab = new Tab();
tab.setName(tabMap.get("name").toString());
tab.setLabel(tabMap.get("label").toString());
// Handle items
tab.setItems(handleItems(tabMap.get("items")));
tabs.add(tab);
});
} else if (config instanceof Map) {
Map configMap = (Map) config;
configMap.forEach((key, value) -> {
// key: tab name
// value: tab property, should be a map
if (!(value instanceof Map)) {
return;
}
Map tabMap = (Map) value;
Tab tab = new Tab();
tab.setName(key.toString());
tab.setLabel(tabMap.get("label").toString());
// Handle items
tab.setItems(handleItems(tabMap.get("items")));
tabs.add(tab);
});
}
return tabs;
}
@SuppressWarnings("unchecked")
private List<Item> handleItems(@Nullable Object items) {
if (items == null) {
return Collections.emptyList();
}
List<Item> result = new LinkedList<>();
if (items instanceof List) {
((List) items).forEach(itemYaml -> {
if (!(itemYaml instanceof Map)) {
return;
}
// Should be Map
Map itemMap = (Map) itemYaml;
// Build item
Item item = new Item();
item.setName(itemMap.get("name").toString());
item.setLabel(itemMap.getOrDefault("label", item.getName()).toString());
item.setDataType(DataType.typeOf(itemMap.get("data_type")));
item.setType(InputType.typeOf(itemMap.get("type")));
item.setDefaultValue(itemMap.get("default"));
// Handle options
item.setOptions(handleOptions(itemMap.get("options")));
// Add item
result.add(item);
});
} else if (items instanceof Map) {
Map itemsMap = (Map) items;
itemsMap.forEach((key, value) -> {
if (!(value instanceof Map)) {
return;
}
Map itemMap = (Map) value;
// key: item name
Item item = new Item();
item.setName(key.toString());
item.setLabel(itemMap.getOrDefault("label", item.getName()).toString());
item.setDataType(DataType.typeOf(itemMap.get("data_type")));
item.setType(InputType.typeOf(itemMap.get("type")));
item.setDefaultValue(itemMap.get("default"));
// Handle options
item.setOptions(handleOptions(itemMap.get("options")));
// Add item
result.add(item);
});
}
return result;
}
@SuppressWarnings("unchecked")
private List<Option> handleOptions(@Nullable Object options) {
if (options == null) {
return Collections.emptyList();
}
List<Option> result = new LinkedList<>();
if (options instanceof List) {
((List) options).forEach(optionYaml -> {
// optionYaml should be Map
if (!(optionYaml instanceof Map)) {
return;
}
Map optionMap = (Map) optionYaml;
// Build option
Option option = new Option();
// TODO Convert the value type
option.setValue(optionMap.get("value"));
option.setLabel(optionMap.get("label").toString());
result.add(option);
});
} else if (options instanceof Map) {
Map optionsMap = (Map) options;
optionsMap.forEach((key, value) -> {
// key: option value
// value: Map that contains option label
if (!(value instanceof Map)) {
return;
}
Map optionMap = (Map) value;
Option option = new Option();
// TODO Convert the value type
option.setValue(key);
option.setLabel(optionMap.get("label").toString());
result.add(option);
});
}
return result;
}
@Data
private class Tab {
private String name;
private String label;
private List<Item> items;
}
@Data
private class Item {
private String name;
private String label;
private InputType type;
private DataType dataType;
private Object defaultValue;
private List<Option> options;
}
@Data
private class Option {
private String label;
private Object value;
}
}