package api import ( "encoding/json" "fmt" "strings" "golang.org/x/exp/slices" ) type SystemSettingName string const ( // SystemSettingServerIDName is the name of server id. SystemSettingServerIDName SystemSettingName = "server-id" // SystemSettingSecretSessionName is the name of secret session. SystemSettingSecretSessionName SystemSettingName = "secret-session" // SystemSettingAllowSignUpName is the name of allow signup setting. SystemSettingAllowSignUpName SystemSettingName = "allow-signup" // SystemSettingIgnoreUpgradeName is the name of ignore upgrade. SystemSettingIgnoreUpgradeName SystemSettingName = "ignore-upgrade" // SystemSettingDisablePublicMemosName is the name of disable public memos setting. SystemSettingDisablePublicMemosName SystemSettingName = "disable-public-memos" // SystemSettingMaxUploadSizeMiBName is the name of max upload size setting. SystemSettingMaxUploadSizeMiBName SystemSettingName = "max-upload-size-mib" // SystemSettingAdditionalStyleName is the name of additional style. SystemSettingAdditionalStyleName SystemSettingName = "additional-style" // SystemSettingAdditionalScriptName is the name of additional script. SystemSettingAdditionalScriptName SystemSettingName = "additional-script" // SystemSettingCustomizedProfileName is the name of customized server profile. SystemSettingCustomizedProfileName SystemSettingName = "customized-profile" // SystemSettingStorageServiceIDName is the name of storage service ID. SystemSettingStorageServiceIDName SystemSettingName = "storage-service-id" // SystemSettingLocalStoragePathName is the name of local storage path. SystemSettingLocalStoragePathName SystemSettingName = "local-storage-path" // SystemSettingOpenAIConfigName is the name of OpenAI config. SystemSettingOpenAIConfigName SystemSettingName = "openai-config" // SystemSettingTelegramRobotToken is the name of Telegram Robot Token. SystemSettingTelegramRobotTokenName SystemSettingName = "telegram-robot-token" ) // CustomizedProfile is the struct definition for SystemSettingCustomizedProfileName system setting item. type CustomizedProfile struct { // Name is the server name, default is `memos` Name string `json:"name"` // LogoURL is the url of logo image. LogoURL string `json:"logoUrl"` // Description is the server description. Description string `json:"description"` // Locale is the server default locale. Locale string `json:"locale"` // Appearance is the server default appearance. Appearance string `json:"appearance"` // ExternalURL is the external url of server. e.g. https://usermemos.com ExternalURL string `json:"externalUrl"` } type OpenAIConfig struct { Key string `json:"key"` Host string `json:"host"` } func (key SystemSettingName) String() string { switch key { case SystemSettingServerIDName: return "server-id" case SystemSettingSecretSessionName: return "secret-session" case SystemSettingAllowSignUpName: return "allow-signup" case SystemSettingIgnoreUpgradeName: return "ignore-upgrade" case SystemSettingDisablePublicMemosName: return "disable-public-memos" case SystemSettingMaxUploadSizeMiBName: return "max-upload-size-mib" case SystemSettingAdditionalStyleName: return "additional-style" case SystemSettingAdditionalScriptName: return "additional-script" case SystemSettingCustomizedProfileName: return "customized-profile" case SystemSettingStorageServiceIDName: return "storage-service-id" case SystemSettingLocalStoragePathName: return "local-storage-path" case SystemSettingOpenAIConfigName: return "openai-config" case SystemSettingTelegramRobotTokenName: return "telegram-robot-token" } return "" } type SystemSetting struct { Name SystemSettingName `json:"name"` // Value is a JSON string with basic value. Value string `json:"value"` Description string `json:"description"` } type SystemSettingUpsert struct { Name SystemSettingName `json:"name"` Value string `json:"value"` Description string `json:"description"` } const systemSettingUnmarshalError = `failed to unmarshal value from system setting "%v"` func (upsert SystemSettingUpsert) Validate() error { switch settingName := upsert.Name; settingName { case SystemSettingServerIDName: return fmt.Errorf("updating %v is not allowed", settingName) case SystemSettingAllowSignUpName: var value bool if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } case SystemSettingIgnoreUpgradeName: var value bool if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } case SystemSettingDisablePublicMemosName: var value bool if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } case SystemSettingMaxUploadSizeMiBName: var value int if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } case SystemSettingAdditionalStyleName: var value string if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } case SystemSettingAdditionalScriptName: var value string if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } case SystemSettingCustomizedProfileName: customizedProfile := CustomizedProfile{ Name: "memos", LogoURL: "", Description: "", Locale: "en", Appearance: "system", ExternalURL: "", } if err := json.Unmarshal([]byte(upsert.Value), &customizedProfile); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } if !slices.Contains(UserSettingLocaleValue, customizedProfile.Locale) { return fmt.Errorf(`invalid locale value for system setting "%v"`, settingName) } if !slices.Contains(UserSettingAppearanceValue, customizedProfile.Appearance) { return fmt.Errorf(`invalid appearance value for system setting "%v"`, settingName) } case SystemSettingStorageServiceIDName: value := DatabaseStorage if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } return nil case SystemSettingLocalStoragePathName: value := "" if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } case SystemSettingOpenAIConfigName: value := OpenAIConfig{} if err := json.Unmarshal([]byte(upsert.Value), &value); err != nil { return fmt.Errorf(systemSettingUnmarshalError, settingName) } case SystemSettingTelegramRobotTokenName: if upsert.Value == "" { return nil } fragments := strings.Split(upsert.Value, ":") if len(fragments) != 2 { return fmt.Errorf(systemSettingUnmarshalError, settingName) } default: return fmt.Errorf("invalid system setting name") } return nil } type SystemSettingFind struct { Name SystemSettingName `json:"name"` }