|
|
|
package impl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"mime/multipart"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"go.uber.org/fx"
|
|
|
|
|
|
|
|
"github.com/go-sonic/sonic/config"
|
|
|
|
"github.com/go-sonic/sonic/dal"
|
|
|
|
"github.com/go-sonic/sonic/event"
|
|
|
|
"github.com/go-sonic/sonic/model/dto"
|
|
|
|
"github.com/go-sonic/sonic/model/entity"
|
|
|
|
"github.com/go-sonic/sonic/model/property"
|
|
|
|
"github.com/go-sonic/sonic/service"
|
|
|
|
"github.com/go-sonic/sonic/service/theme"
|
|
|
|
"github.com/go-sonic/sonic/util"
|
|
|
|
"github.com/go-sonic/sonic/util/xerr"
|
|
|
|
)
|
|
|
|
|
|
|
|
type themeServiceImpl struct {
|
|
|
|
OptionService service.OptionService
|
|
|
|
Config *config.Config
|
|
|
|
Event event.Bus
|
|
|
|
PropertyScanner theme.PropertyScanner
|
|
|
|
FileScanner theme.FileScanner
|
|
|
|
ThemeFetchers themeFetchers
|
|
|
|
}
|
|
|
|
|
|
|
|
type themeFetchers struct {
|
|
|
|
fx.In
|
|
|
|
MultipartZipThemeFetcher theme.ThemeFetcher `name:"multipartZipThemeFetcher"`
|
|
|
|
GitRepoThemeFetcher theme.ThemeFetcher `name:"gitRepoThemeFetcher"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewThemeService(optionService service.OptionService, config *config.Config, event event.Bus, propertyScanner theme.PropertyScanner, fileScanner theme.FileScanner, themeFetcher themeFetchers) service.ThemeService {
|
|
|
|
return &themeServiceImpl{
|
|
|
|
OptionService: optionService,
|
|
|
|
Config: config,
|
|
|
|
Event: event,
|
|
|
|
PropertyScanner: propertyScanner,
|
|
|
|
FileScanner: fileScanner,
|
|
|
|
ThemeFetchers: themeFetcher,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) GetActivateTheme(ctx context.Context) (*dto.ThemeProperty, error) {
|
|
|
|
activatedThemeID, err := t.OptionService.GetActivatedThemeID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return t.GetThemeByID(ctx, activatedThemeID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) GetThemeByID(ctx context.Context, themeID string) (*dto.ThemeProperty, error) {
|
|
|
|
themeProperty, err := t.PropertyScanner.GetThemeByThemeID(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if themeProperty == nil {
|
|
|
|
return nil, xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg(themeID + " not exist")
|
|
|
|
}
|
|
|
|
activatedThemeID, err := t.OptionService.GetActivatedThemeID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if themeProperty.ID == activatedThemeID {
|
|
|
|
themeProperty.Activated = true
|
|
|
|
}
|
|
|
|
return themeProperty, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) ListAllTheme(ctx context.Context) ([]*dto.ThemeProperty, error) {
|
|
|
|
themes, err := t.PropertyScanner.ListAll(ctx, t.Config.Sonic.ThemeDir)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
activatedThemeID, err := t.OptionService.GetActivatedThemeID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, t := range themes {
|
|
|
|
if t.ID == activatedThemeID {
|
|
|
|
t.Activated = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return themes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) ListThemeFiles(ctx context.Context, themeID string) ([]*dto.ThemeFile, error) {
|
|
|
|
themeProperty, err := t.PropertyScanner.GetThemeByThemeID(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if themeProperty == nil {
|
|
|
|
return nil, xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg(themeID + " not exist")
|
|
|
|
}
|
|
|
|
return t.FileScanner.ListThemeFiles(ctx, themeProperty.ThemePath)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) GetThemeFileContent(ctx context.Context, themeID, absPath string) (string, error) {
|
|
|
|
themeProperty, err := t.PropertyScanner.GetThemeByThemeID(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if themeProperty == nil {
|
|
|
|
return "", xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg(themeID + " not exist")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = t.checkPathValid(themeProperty.ThemePath, absPath); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return t.ReadThemeFile(ctx, absPath)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) ReadThemeFile(ctx context.Context, absPath string) (content string, err error) {
|
|
|
|
file, err := os.Open(absPath)
|
|
|
|
defer func() {
|
|
|
|
cerr := file.Close()
|
|
|
|
if err == nil && cerr != nil {
|
|
|
|
err = xerr.WithStatus(cerr, xerr.StatusInternalServerError).WithMsg("close file err")
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return "", xerr.WithMsg(err, "file not exist").WithStatus(xerr.StatusBadRequest)
|
|
|
|
} else if os.IsPermission(err) {
|
|
|
|
return "", xerr.WithMsg(err, "file permission err").WithStatus(xerr.StatusForbidden)
|
|
|
|
}
|
|
|
|
|
|
|
|
contentBytes, err := io.ReadAll(file)
|
|
|
|
if err != nil {
|
|
|
|
err = xerr.WithMsg(err, "read file error").WithStatus(xerr.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
content = util.BytesToString(contentBytes)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) UpdateThemeFile(ctx context.Context, themeID, absPath, content string) error {
|
|
|
|
themeProperty, err := t.PropertyScanner.GetThemeByThemeID(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if themeProperty == nil {
|
|
|
|
return xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg(themeID + " not exist")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = t.checkPathValid(themeProperty.ThemePath, absPath); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
file, err := os.OpenFile(absPath, os.O_WRONLY, 0)
|
|
|
|
if err != nil {
|
|
|
|
return xerr.WithMsg(err, "open file error")
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
_, err = file.WriteString(content)
|
|
|
|
if err != nil {
|
|
|
|
return xerr.WithMsg(err, "write to file err")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) checkPathValid(themePath, absPath string) error {
|
|
|
|
absPath = filepath.Clean(absPath)
|
|
|
|
if !filepath.IsAbs(absPath) {
|
|
|
|
return xerr.WithMsg(nil, "path error").WithStatus(xerr.StatusForbidden)
|
|
|
|
}
|
|
|
|
if !strings.HasPrefix(absPath, themePath) {
|
|
|
|
return xerr.WithMsg(nil, "path error").WithStatus(xerr.StatusForbidden)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) ListCustomTemplates(ctx context.Context, themeID, prefix string) ([]string, error) {
|
|
|
|
themeProperty, err := t.PropertyScanner.GetThemeByThemeID(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if themeProperty == nil {
|
|
|
|
return nil, xerr.WithMsg(nil, "theme does not exist").WithStatus(xerr.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
files, err := os.ReadDir(themeProperty.ThemePath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerr.WithMsg(err, "read theme files error").WithStatus(xerr.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
result := make([]string, 0)
|
|
|
|
for _, file := range files {
|
|
|
|
if file.IsDir() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
fileName := file.Name()
|
|
|
|
if !strings.HasPrefix(fileName, prefix) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
customName := strings.TrimPrefix(fileName, prefix)
|
|
|
|
customName = strings.TrimSuffix(customName, ".ftl")
|
|
|
|
result = append(result, customName)
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) ActivateTheme(ctx context.Context, themeID string) (*dto.ThemeProperty, error) {
|
|
|
|
err := t.OptionService.Save(ctx, map[string]string{property.Theme.KeyValue: themeID})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
t.Event.Publish(ctx, &event.ThemeActivatedEvent{})
|
|
|
|
return t.GetThemeByID(ctx, themeID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) GetThemeConfig(ctx context.Context, themeID string) ([]*dto.ThemeConfigGroup, error) {
|
|
|
|
themeProperty, err := t.GetThemeByID(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return t.PropertyScanner.ReadThemeConfig(ctx, themeProperty.ThemePath)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) GetThemeSettingMap(ctx context.Context, themeID string) (map[string]interface{}, error) {
|
|
|
|
itemMap, err := t.getThemeConfigItemMap(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return t.getThemeSettingMapByItemMap(ctx, themeID, itemMap)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) GetThemeGroupSettingMap(ctx context.Context, themeID, group string) (map[string]interface{}, error) {
|
|
|
|
themeConfig, err := t.GetThemeConfig(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var groupConfig *dto.ThemeConfigGroup
|
|
|
|
for _, themeGroup := range themeConfig {
|
|
|
|
if themeGroup.Name == group {
|
|
|
|
groupConfig = themeGroup
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if groupConfig == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
itemMap := make(map[string]*dto.ThemeConfigItem)
|
|
|
|
for _, item := range groupConfig.Items {
|
|
|
|
itemMap[item.Name] = item
|
|
|
|
}
|
|
|
|
return t.getThemeSettingMapByItemMap(ctx, themeID, itemMap)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) getThemeSettingMapByItemMap(ctx context.Context, themeID string, itemMap map[string]*dto.ThemeConfigItem) (map[string]interface{}, error) {
|
|
|
|
themeSettingDAL := dal.GetQueryByCtx(ctx).ThemeSetting
|
|
|
|
themeSettings, err := themeSettingDAL.WithContext(ctx).Where(themeSettingDAL.ThemeID.Eq(themeID)).Find()
|
|
|
|
if err != nil {
|
|
|
|
return nil, WrapDBErr(err)
|
|
|
|
}
|
|
|
|
result := make(map[string]interface{})
|
|
|
|
for _, themeSetting := range themeSettings {
|
|
|
|
item, ok := itemMap[themeSetting.SettingKey]
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
value, err := item.DataType.Convert(themeSetting.SettingValue)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerr.WithStatus(err, xerr.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
result[themeSetting.SettingKey] = value
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, item := range itemMap {
|
|
|
|
if _, ok := result[item.Name]; ok || item.DefaultValue == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
result[item.Name] = item.DefaultValue
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) SaveThemeSettings(ctx context.Context, themeID string, settings map[string]interface{}) error {
|
|
|
|
if len(settings) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
itemMap, err := t.getThemeConfigItemMap(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
themeSettingDAL := dal.GetQueryByCtx(ctx).ThemeSetting
|
|
|
|
allThemeSetting, err := themeSettingDAL.WithContext(ctx).Where(themeSettingDAL.ThemeID.Eq(themeID)).Find()
|
|
|
|
if err != nil {
|
|
|
|
return WrapDBErr(err)
|
|
|
|
}
|
|
|
|
allThemeSettingMap := make(map[string]*entity.ThemeSetting, len(allThemeSetting))
|
|
|
|
for _, themeSetting := range allThemeSetting {
|
|
|
|
allThemeSettingMap[themeSetting.SettingKey] = themeSetting
|
|
|
|
}
|
|
|
|
|
|
|
|
toDeleteIDs := make([]int32, 0)
|
|
|
|
toCreate := make([]*entity.ThemeSetting, 0)
|
|
|
|
toUpdate := make([]*entity.ThemeSetting, 0)
|
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
for name, value := range settings {
|
|
|
|
item, ok := itemMap[name]
|
|
|
|
if !ok {
|
|
|
|
return xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg("setting name invalid: " + name)
|
|
|
|
}
|
|
|
|
if themeSetting, ok := allThemeSettingMap[name]; ok {
|
|
|
|
if value == "" {
|
|
|
|
toDeleteIDs = append(toDeleteIDs, themeSetting.ID)
|
|
|
|
} else {
|
|
|
|
valueStr, err := item.DataType.FormatToStr(value)
|
|
|
|
if err != nil {
|
|
|
|
return xerr.WithErrMsgf(err, "value=%s type invalid ,setting name=%s", value, name).WithStatus(xerr.StatusBadRequest)
|
|
|
|
}
|
|
|
|
|
|
|
|
if value != themeSetting.SettingValue {
|
|
|
|
themeSetting.SettingValue = valueStr
|
|
|
|
themeSetting.UpdateTime = util.TimePtr(now)
|
|
|
|
toUpdate = append(toUpdate, themeSetting)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if value != "" {
|
|
|
|
valueStr, err := item.DataType.FormatToStr(value)
|
|
|
|
if err != nil {
|
|
|
|
return xerr.WithErrMsgf(err, "value=%s type invalid ,setting name=%s", value, name).WithStatus(xerr.StatusBadRequest)
|
|
|
|
}
|
|
|
|
toCreate = append(toCreate, &entity.ThemeSetting{SettingKey: name, SettingValue: valueStr, ThemeID: themeID})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = dal.Transaction(ctx, func(txCtx context.Context) error {
|
|
|
|
themeSettingDAL := dal.GetQueryByCtx(txCtx).ThemeSetting
|
|
|
|
_, err := themeSettingDAL.WithContext(txCtx).Where(themeSettingDAL.ID.In(toDeleteIDs...)).Delete()
|
|
|
|
if err != nil {
|
|
|
|
return WrapDBErr(err)
|
|
|
|
}
|
|
|
|
err = themeSettingDAL.WithContext(txCtx).Save(toUpdate...)
|
|
|
|
if err != nil {
|
|
|
|
return WrapDBErr(err)
|
|
|
|
}
|
|
|
|
err = themeSettingDAL.WithContext(txCtx).Create(toCreate...)
|
|
|
|
return WrapDBErr(err)
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
t.Event.Publish(ctx, &event.ThemeUpdateEvent{})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) DeleteThemeSettings(ctx context.Context, themeID string) error {
|
|
|
|
activatedThemeID, err := t.OptionService.GetActivatedThemeID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if activatedThemeID == themeID {
|
|
|
|
return xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg("can not delete the theme being used")
|
|
|
|
}
|
|
|
|
|
|
|
|
themeSettingDAL := dal.GetQueryByCtx(ctx).ThemeSetting
|
|
|
|
_, err = themeSettingDAL.WithContext(ctx).Where(themeSettingDAL.ThemeID.Eq(themeID)).Delete()
|
|
|
|
return WrapDBErr(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) DeleteTheme(ctx context.Context, themeID string, deleteSettings bool) error {
|
|
|
|
activatedThemeID, err := t.OptionService.GetActivatedThemeID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if activatedThemeID == themeID {
|
|
|
|
return xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg("can not delete the theme being used")
|
|
|
|
}
|
|
|
|
if deleteSettings {
|
|
|
|
err = t.DeleteThemeSettings(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
themeProperty, err := t.GetThemeByID(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = os.RemoveAll(themeProperty.ThemePath)
|
|
|
|
if err != nil {
|
|
|
|
return xerr.WithStatus(err, xerr.StatusInternalServerError).WithMsg("delete theme directory err")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) UploadTheme(ctx context.Context, file *multipart.FileHeader) (*dto.ThemeProperty, error) {
|
|
|
|
themeProperty, err := t.ThemeFetchers.MultipartZipThemeFetcher.FetchTheme(ctx, file)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return t.addTheme(ctx, themeProperty)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) UpdateThemeByUpload(ctx context.Context, themeID string, file *multipart.FileHeader) (*dto.ThemeProperty, error) {
|
|
|
|
oldThemeProperty, err := t.GetThemeByID(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
newThemeProperty, err := t.ThemeFetchers.MultipartZipThemeFetcher.FetchTheme(ctx, file)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = os.RemoveAll(oldThemeProperty.ThemePath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerr.WithMsg(err, "delete old theme err").WithStatus(xerr.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
return t.addTheme(ctx, newThemeProperty)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) ReloadTheme(ctx context.Context) error {
|
|
|
|
t.Event.Publish(ctx, &event.ThemeUpdateEvent{})
|
|
|
|
t.Event.Publish(ctx, &event.ThemeFileUpdatedEvent{})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) TemplateExist(ctx context.Context, template string) (bool, error) {
|
|
|
|
activatedThemeID, err := t.OptionService.GetActivatedThemeID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
themeProperty, err := t.GetThemeByID(ctx, activatedThemeID)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return util.FileIsExisted(filepath.Join(themeProperty.ThemePath, template)), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) getThemeConfigItemMap(ctx context.Context, themeID string) (map[string]*dto.ThemeConfigItem, error) {
|
|
|
|
themeConfigGroup, err := t.GetThemeConfig(ctx, themeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
itemMap := make(map[string]*dto.ThemeConfigItem)
|
|
|
|
for _, themeConfig := range themeConfigGroup {
|
|
|
|
for _, item := range themeConfig.Items {
|
|
|
|
itemMap[item.Name] = item
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return itemMap, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) addTheme(ctx context.Context, themeProperty *dto.ThemeProperty) (*dto.ThemeProperty, error) {
|
|
|
|
existTheme, err := t.PropertyScanner.GetThemeByThemeID(ctx, themeProperty.ID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if existTheme != nil {
|
|
|
|
return nil, xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg("theme already exist")
|
|
|
|
}
|
|
|
|
err = util.CopyDir(themeProperty.ThemePath, filepath.Join(t.Config.Sonic.ThemeDir, themeProperty.FolderName))
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerr.WithStatus(err, xerr.StatusBadRequest)
|
|
|
|
}
|
|
|
|
return t.PropertyScanner.ReadThemeProperty(ctx, filepath.Join(t.Config.Sonic.ThemeDir, themeProperty.FolderName))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) Render(ctx context.Context, name string) (string, error) {
|
|
|
|
activatedThemeID, err := t.OptionService.GetActivatedThemeID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return activatedThemeID + "/" + name, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *themeServiceImpl) Fetch(ctx context.Context, themeURL string) (*dto.ThemeProperty, error) {
|
|
|
|
fetchTheme, err := t.ThemeFetchers.GitRepoThemeFetcher.FetchTheme(ctx, themeURL)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg(err.Error())
|
|
|
|
}
|
|
|
|
return t.addTheme(ctx, fetchTheme)
|
|
|
|
}
|