mirror of https://github.com/halo-dev/halo
Convert theme setting with type
parent
fe391c93e7
commit
5a7b02c4aa
|
@ -2,6 +2,7 @@ package run.halo.app.handler.theme.config.impl;
|
|||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import run.halo.app.handler.theme.config.ThemeConfigResolver;
|
||||
|
@ -23,6 +24,7 @@ import java.util.Map;
|
|||
* @author johnniang
|
||||
* @date 4/10/19
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class YamlThemeConfigResolverImpl implements ThemeConfigResolver {
|
||||
|
||||
|
@ -109,7 +111,8 @@ public class YamlThemeConfigResolverImpl implements ThemeConfigResolver {
|
|||
|
||||
item.setName(itemMap.get("name").toString());
|
||||
item.setLabel(itemMap.getOrDefault("label", item.getName()).toString());
|
||||
item.setDataType(DataType.typeOf(itemMap.get("data_type")));
|
||||
Object dataType = itemMap.getOrDefault("data-type", itemMap.get("dataType"));
|
||||
item.setDataType(DataType.typeOf(dataType));
|
||||
item.setType(InputType.typeOf(itemMap.get("type")));
|
||||
item.setDefaultValue(itemMap.get("default"));
|
||||
|
||||
|
@ -133,7 +136,8 @@ public class YamlThemeConfigResolverImpl implements ThemeConfigResolver {
|
|||
Item item = new Item();
|
||||
item.setName(key.toString());
|
||||
item.setLabel(itemMap.getOrDefault("label", item.getName()).toString());
|
||||
item.setDataType(DataType.typeOf(itemMap.get("data_type")));
|
||||
Object dataType = itemMap.getOrDefault("data-type", itemMap.get("dataType"));
|
||||
item.setDataType(DataType.typeOf(dataType));
|
||||
item.setType(InputType.typeOf(itemMap.get("type")));
|
||||
item.setDefaultValue(itemMap.get("default"));
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import run.halo.app.model.enums.DataType;
|
|||
import run.halo.app.model.enums.InputType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Theme configuration: item entity
|
||||
|
@ -44,4 +45,17 @@ public class Item {
|
|||
* Item's options, default is empty list
|
||||
*/
|
||||
private List<Option> options;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Item item = (Item) o;
|
||||
return name.equals(item.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import lombok.EqualsAndHashCode;
|
|||
import lombok.ToString;
|
||||
import org.hibernate.annotations.SQLDelete;
|
||||
import org.hibernate.annotations.Where;
|
||||
import run.halo.app.model.enums.DataType;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
|
@ -46,17 +45,10 @@ public class ThemeSetting extends BaseEntity {
|
|||
@Column(name = "theme_id", columnDefinition = "varchar(255) not null")
|
||||
private String themeId;
|
||||
|
||||
@Column(name = "data_type", columnDefinition = "int default 0")
|
||||
private DataType type;
|
||||
|
||||
@Override
|
||||
protected void prePersist() {
|
||||
super.prePersist();
|
||||
|
||||
id = null;
|
||||
|
||||
if (type == null) {
|
||||
type = DataType.STRING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package run.halo.app.model.enums;
|
||||
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Data type enum.
|
||||
|
@ -9,6 +12,7 @@ import org.springframework.lang.Nullable;
|
|||
* @author johnniang
|
||||
* @date 4/9/19
|
||||
*/
|
||||
@Slf4j
|
||||
public enum DataType implements ValueEnum<Integer> {
|
||||
|
||||
STRING(0),
|
||||
|
@ -48,4 +52,34 @@ public enum DataType implements ValueEnum<Integer> {
|
|||
|
||||
return STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts data to corresponding type.
|
||||
*
|
||||
* @param data data to be converted must not be null
|
||||
* @return data with corresponding type
|
||||
*/
|
||||
@NonNull
|
||||
public Object convertTo(@NonNull Object data) {
|
||||
Assert.notNull(data, "Data must not be null");
|
||||
|
||||
try {
|
||||
switch (this) {
|
||||
case STRING:
|
||||
return data.toString();
|
||||
case BOOL:
|
||||
return Boolean.valueOf(data.toString());
|
||||
case LONG:
|
||||
return Long.valueOf(data.toString());
|
||||
case DOUBLE:
|
||||
return Double.valueOf(data.toString());
|
||||
default:
|
||||
return data;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to convert " + data + " to corresponding type: " + this.name(), e);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -245,7 +245,9 @@ public class ThemeServiceImpl implements ThemeService {
|
|||
|
||||
@Override
|
||||
public List<Group> fetchConfig(String themeId) {
|
||||
Assert.hasText(themeId, "Theme name must not be blank");
|
||||
Assert.hasText(themeId, "Theme id must not be blank");
|
||||
|
||||
// TODO Cache the config
|
||||
|
||||
// Get theme property
|
||||
ThemeProperty themeProperty = getThemeOfNonNullBy(themeId);
|
||||
|
|
|
@ -2,17 +2,20 @@ package run.halo.app.service.impl;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import run.halo.app.handler.theme.config.support.Group;
|
||||
import run.halo.app.handler.theme.config.support.Item;
|
||||
import run.halo.app.model.entity.ThemeSetting;
|
||||
import run.halo.app.repository.ThemeSettingRepository;
|
||||
import run.halo.app.service.ThemeService;
|
||||
import run.halo.app.service.ThemeSettingService;
|
||||
import run.halo.app.service.base.AbstractCrudService;
|
||||
import run.halo.app.utils.ServiceUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Theme setting service implementation.
|
||||
|
@ -26,9 +29,13 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
|
|||
|
||||
private final ThemeSettingRepository themeSettingRepository;
|
||||
|
||||
public ThemeSettingServiceImpl(ThemeSettingRepository themeSettingRepository) {
|
||||
private final ThemeService themeService;
|
||||
|
||||
public ThemeSettingServiceImpl(ThemeSettingRepository themeSettingRepository,
|
||||
ThemeService themeService) {
|
||||
super(themeSettingRepository);
|
||||
this.themeSettingRepository = themeSettingRepository;
|
||||
this.themeService = themeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -36,8 +43,14 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
|
|||
Assert.notNull(key, "Setting key must not be null");
|
||||
assertThemeIdHasText(themeId);
|
||||
|
||||
log.debug("Starting saving theme setting key: [{}], value: [{}]", key, value);
|
||||
|
||||
// Find setting by key
|
||||
Optional<ThemeSetting> themeSettingOptional = themeSettingRepository.findByThemeIdAndKey(themeId, key);
|
||||
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return themeSettingRepository.findByThemeIdAndKey(themeId, key)
|
||||
// Delete it
|
||||
return themeSettingOptional
|
||||
.map(setting -> {
|
||||
themeSettingRepository.delete(setting);
|
||||
log.debug("Removed theme setting: [{}]", setting);
|
||||
|
@ -45,15 +58,25 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
|
|||
}).orElse(null);
|
||||
}
|
||||
|
||||
ThemeSetting themeSetting = themeSettingRepository.findByThemeIdAndKey(themeId, key)
|
||||
// Get config item map
|
||||
Map<String, Item> itemMap = getConfigItemMap(themeId);
|
||||
|
||||
// Get item info
|
||||
Item item = itemMap.get(key);
|
||||
|
||||
// Update or create
|
||||
ThemeSetting themeSetting = themeSettingOptional
|
||||
.map(setting -> {
|
||||
log.debug("Updating theme setting: [{}]", setting);
|
||||
setting.setValue(value);
|
||||
log.debug("Updated theme setting: [{}]", setting);
|
||||
return setting;
|
||||
}).orElseGet(() -> {
|
||||
ThemeSetting setting = new ThemeSetting();
|
||||
setting.setKey(key);
|
||||
setting.setValue(value);
|
||||
setting.setThemeId(themeId);
|
||||
log.debug("Creating theme setting: [{}]", setting);
|
||||
return setting;
|
||||
});
|
||||
|
||||
|
@ -82,11 +105,66 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
|
|||
|
||||
@Override
|
||||
public Map<String, Object> listAsMapBy(String themeId) {
|
||||
// Convert to item map(key: item name, value: item)
|
||||
Map<String, Item> itemMap = getConfigItemMap(themeId);
|
||||
|
||||
// Get theme setting
|
||||
List<ThemeSetting> themeSettings = listBy(themeId);
|
||||
|
||||
// TODO Convert to corresponding data type
|
||||
return ServiceUtils.convertToMap(themeSettings, ThemeSetting::getKey, ThemeSetting::getValue);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
// Build settings from user-defined
|
||||
themeSettings.forEach(themeSetting -> {
|
||||
Item item = itemMap.get(themeSetting.getKey());
|
||||
|
||||
|
||||
// Convert data to corresponding data type
|
||||
String key = themeSetting.getKey();
|
||||
|
||||
Object convertedValue = themeSetting.getValue();
|
||||
|
||||
if (item != null) {
|
||||
convertedValue = item.getDataType().convertTo(themeSetting.getValue());
|
||||
log.debug("Converted user-defined data from [{}] to [{}], type: [{}]", themeSetting.getValue(), convertedValue, item.getDataType());
|
||||
}
|
||||
|
||||
result.put(key, convertedValue);
|
||||
});
|
||||
|
||||
// Build settings from pre-defined
|
||||
itemMap.forEach((name, item) -> {
|
||||
log.debug("Name: [{}], item: [{}]", name, item);
|
||||
|
||||
if (item.getDefaultValue() == null || result.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default value
|
||||
Object convertedDefaultValue = item.getDataType().convertTo(item.getDefaultValue());
|
||||
log.debug("Converted pre-defined data from [{}] to [{}], type: [{}]", item.getDefaultValue(), convertedDefaultValue, item.getDataType());
|
||||
|
||||
result.put(name, convertedDefaultValue);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets config item map. (key: item name, value: item)
|
||||
*
|
||||
* @param themeId theme id must not be blank
|
||||
* @return config item map
|
||||
*/
|
||||
private Map<String, Item> getConfigItemMap(@NonNull String themeId) {
|
||||
// Get theme configuration
|
||||
List<Group> groups = themeService.fetchConfig(themeId);
|
||||
|
||||
// Mix all items
|
||||
Set<Item> items = new LinkedHashSet<>();
|
||||
groups.forEach(group -> items.addAll(group.getItems()));
|
||||
|
||||
// Convert to item map(key: item name, value: item)
|
||||
return ServiceUtils.convertToMap(items, Item::getName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,4 +175,5 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
|
|||
private void assertThemeIdHasText(String themeId) {
|
||||
Assert.hasText(themeId, "Theme id must not be null");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -86,24 +86,30 @@ public class ThemeController {
|
|||
return BaseResponse.ok(themeService.fetchConfig(themeService.getActivatedThemeId()));
|
||||
}
|
||||
|
||||
@GetMapping("{themeId}/configurations")
|
||||
@ApiOperation("Fetches theme configuration by theme id")
|
||||
public List<Group> fetchConfig(@PathVariable("themeId") String themeId) {
|
||||
return themeService.fetchConfig(themeId);
|
||||
}
|
||||
|
||||
@GetMapping("activation/settings")
|
||||
@ApiOperation("Lists activated theme settings")
|
||||
public Map<String, Object> listSettingsBy() {
|
||||
return themeSettingService.listAsMapBy(themeService.getActivatedThemeId());
|
||||
}
|
||||
|
||||
@GetMapping("{themeId}/settings")
|
||||
@ApiOperation("Lists theme settings by theme id")
|
||||
public Map<String, Object> listSettingsBy(@PathVariable("themeId") String themeId) {
|
||||
return themeSettingService.listAsMapBy(themeId);
|
||||
}
|
||||
|
||||
@PostMapping("activation/settings")
|
||||
@ApiOperation("Saves theme settings")
|
||||
public void saveSettingsBy(@RequestBody Map<String, Object> settings) {
|
||||
themeSettingService.save(settings, themeService.getActivatedThemeId());
|
||||
}
|
||||
|
||||
@GetMapping("{themeId}/configurations")
|
||||
@ApiOperation("Fetches theme configuration by theme id")
|
||||
public List<Group> fetchConfig(@PathVariable("themeId") String themeId) {
|
||||
return themeService.fetchConfig(themeId);
|
||||
}
|
||||
|
||||
@PostMapping("{themeId}/settings")
|
||||
@ApiOperation("Saves theme settings")
|
||||
public void saveSettingsBy(@PathVariable("themeId") String themeId,
|
||||
|
|
|
@ -5,6 +5,7 @@ sns:
|
|||
name: rss
|
||||
label: RSS
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -58,6 +59,7 @@ style:
|
|||
name: post_title_uppper
|
||||
label: 文章标题大写
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -68,6 +70,7 @@ style:
|
|||
name: blog_title_uppper
|
||||
label: 博客标题大写
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -78,6 +81,7 @@ style:
|
|||
name: avatar_circle
|
||||
label: 圆形头像
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -88,6 +92,7 @@ style:
|
|||
name: hitokoto
|
||||
label: 博客描述开启一言
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: false
|
||||
options:
|
||||
- value: true
|
||||
|
|
|
@ -119,6 +119,7 @@ style:
|
|||
name: background_bing
|
||||
label: Bing 背景
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: false
|
||||
options:
|
||||
- value: true
|
||||
|
@ -130,7 +131,7 @@ style:
|
|||
name: code_pretty
|
||||
label: 代码高亮
|
||||
type: select
|
||||
default: false
|
||||
default: Default
|
||||
options:
|
||||
- value: Default
|
||||
label: Default
|
||||
|
@ -222,6 +223,7 @@ sns-share:
|
|||
name: sns_share_twitter
|
||||
label: 分享到 Twitter
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -233,6 +235,7 @@ sns-share:
|
|||
name: sns_share_facebook
|
||||
label: 分享到 Facebook
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -244,6 +247,7 @@ sns-share:
|
|||
name: sns_share_googleplus
|
||||
label: 分享到 Google +
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -255,6 +259,7 @@ sns-share:
|
|||
name: sns_share_weibo
|
||||
label: 分享到微博
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -266,6 +271,7 @@ sns-share:
|
|||
name: sns_share_linkedin
|
||||
label: 分享到 Linkedin
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -277,6 +283,7 @@ sns-share:
|
|||
name: sns_share_qq
|
||||
label: 分享到 QQ
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -288,6 +295,7 @@ sns-share:
|
|||
name: sns_share_telegram
|
||||
label: 分享到 Telegram
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -302,6 +310,7 @@ other:
|
|||
name: other_js_fade
|
||||
label: 渐显效果
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -313,6 +322,7 @@ other:
|
|||
name: other_js_smoothscroll
|
||||
label: 平滑滚动效果
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -324,6 +334,7 @@ other:
|
|||
name: other_sidebar_archives
|
||||
label: 侧边栏归档
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -335,6 +346,7 @@ other:
|
|||
name: other_sidebar_cates
|
||||
label: 侧边栏分类
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -346,6 +358,7 @@ other:
|
|||
name: other_sidebar_postcount
|
||||
label: 侧边栏文章总数
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
@ -357,6 +370,7 @@ other:
|
|||
name: other_mathjax
|
||||
label: MathJax 插件
|
||||
type: radio
|
||||
data-type: bool
|
||||
default: true
|
||||
options:
|
||||
- value: true
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package run.halo.app.model.enums;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Data type test.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-21
|
||||
*/
|
||||
public class DataTypeTest {
|
||||
|
||||
@Test
|
||||
public void typeOf() {
|
||||
DataType type = DataType.typeOf("bool");
|
||||
System.out.println(type);
|
||||
assertThat(type, equalTo(DataType.BOOL));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue