moved settings under models and added settings dao helpers
This commit is contained in:
parent
d8963c6fc3
commit
8c9b657132
|
@ -127,7 +127,7 @@ func TestSettingsSet(t *testing.T) {
|
||||||
`"twitchAuth":{`,
|
`"twitchAuth":{`,
|
||||||
`"secret":"******"`,
|
`"secret":"******"`,
|
||||||
`"clientSecret":"******"`,
|
`"clientSecret":"******"`,
|
||||||
`"appName":"Acme"`,
|
`"appName":"acme_test"`,
|
||||||
},
|
},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
"OnModelBeforeUpdate": 1,
|
"OnModelBeforeUpdate": 1,
|
||||||
|
|
11
core/app.go
11
core/app.go
|
@ -6,6 +6,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/daos"
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
|
"github.com/pocketbase/pocketbase/models/settings"
|
||||||
"github.com/pocketbase/pocketbase/tools/filesystem"
|
"github.com/pocketbase/pocketbase/tools/filesystem"
|
||||||
"github.com/pocketbase/pocketbase/tools/hook"
|
"github.com/pocketbase/pocketbase/tools/hook"
|
||||||
"github.com/pocketbase/pocketbase/tools/mailer"
|
"github.com/pocketbase/pocketbase/tools/mailer"
|
||||||
|
@ -47,7 +48,7 @@ type App interface {
|
||||||
IsDebug() bool
|
IsDebug() bool
|
||||||
|
|
||||||
// Settings returns the loaded app settings.
|
// Settings returns the loaded app settings.
|
||||||
Settings() *Settings
|
Settings() *settings.Settings
|
||||||
|
|
||||||
// Cache returns the app internal cache store.
|
// Cache returns the app internal cache store.
|
||||||
Cache() *store.Store[any]
|
Cache() *store.Store[any]
|
||||||
|
@ -79,6 +80,14 @@ type App interface {
|
||||||
// App event hooks
|
// App event hooks
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
// OnBeforeBootstrap hook is triggered before initializing the base
|
||||||
|
// application resources (eg. before db open and initial settings load).
|
||||||
|
OnBeforeBootstrap() *hook.Hook[*BootstrapEvent]
|
||||||
|
|
||||||
|
// OnAfterBootstrap hook is triggered after initializing the base
|
||||||
|
// application resources (eg. after db open and initial settings load).
|
||||||
|
OnAfterBootstrap() *hook.Hook[*BootstrapEvent]
|
||||||
|
|
||||||
// OnBeforeServe hook is triggered before serving the internal router (echo),
|
// OnBeforeServe hook is triggered before serving the internal router (echo),
|
||||||
// allowing you to adjust its options and attach new routes.
|
// allowing you to adjust its options and attach new routes.
|
||||||
OnBeforeServe() *hook.Hook[*ServeEvent]
|
OnBeforeServe() *hook.Hook[*ServeEvent]
|
||||||
|
|
93
core/base.go
93
core/base.go
|
@ -1,10 +1,8 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
@ -15,10 +13,10 @@ import (
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/daos"
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
"github.com/pocketbase/pocketbase/models"
|
||||||
|
"github.com/pocketbase/pocketbase/models/settings"
|
||||||
"github.com/pocketbase/pocketbase/tools/filesystem"
|
"github.com/pocketbase/pocketbase/tools/filesystem"
|
||||||
"github.com/pocketbase/pocketbase/tools/hook"
|
"github.com/pocketbase/pocketbase/tools/hook"
|
||||||
"github.com/pocketbase/pocketbase/tools/mailer"
|
"github.com/pocketbase/pocketbase/tools/mailer"
|
||||||
"github.com/pocketbase/pocketbase/tools/security"
|
|
||||||
"github.com/pocketbase/pocketbase/tools/store"
|
"github.com/pocketbase/pocketbase/tools/store"
|
||||||
"github.com/pocketbase/pocketbase/tools/subscriptions"
|
"github.com/pocketbase/pocketbase/tools/subscriptions"
|
||||||
)
|
)
|
||||||
|
@ -34,14 +32,16 @@ type BaseApp struct {
|
||||||
|
|
||||||
// internals
|
// internals
|
||||||
cache *store.Store[any]
|
cache *store.Store[any]
|
||||||
settings *Settings
|
settings *settings.Settings
|
||||||
db *dbx.DB
|
db *dbx.DB
|
||||||
dao *daos.Dao
|
dao *daos.Dao
|
||||||
logsDB *dbx.DB
|
logsDB *dbx.DB
|
||||||
logsDao *daos.Dao
|
logsDao *daos.Dao
|
||||||
subscriptionsBroker *subscriptions.Broker
|
subscriptionsBroker *subscriptions.Broker
|
||||||
|
|
||||||
// serve event hooks
|
// app event hooks
|
||||||
|
onBeforeBootstrap *hook.Hook[*BootstrapEvent]
|
||||||
|
onAfterBootstrap *hook.Hook[*BootstrapEvent]
|
||||||
onBeforeServe *hook.Hook[*ServeEvent]
|
onBeforeServe *hook.Hook[*ServeEvent]
|
||||||
|
|
||||||
// dao event hooks
|
// dao event hooks
|
||||||
|
@ -125,10 +125,12 @@ func NewBaseApp(dataDir string, encryptionEnv string, isDebug bool) *BaseApp {
|
||||||
isDebug: isDebug,
|
isDebug: isDebug,
|
||||||
encryptionEnv: encryptionEnv,
|
encryptionEnv: encryptionEnv,
|
||||||
cache: store.New[any](nil),
|
cache: store.New[any](nil),
|
||||||
settings: NewSettings(),
|
settings: settings.New(),
|
||||||
subscriptionsBroker: subscriptions.NewBroker(),
|
subscriptionsBroker: subscriptions.NewBroker(),
|
||||||
|
|
||||||
// serve event hooks
|
// app event hooks
|
||||||
|
onBeforeBootstrap: &hook.Hook[*BootstrapEvent]{},
|
||||||
|
onAfterBootstrap: &hook.Hook[*BootstrapEvent]{},
|
||||||
onBeforeServe: &hook.Hook[*ServeEvent]{},
|
onBeforeServe: &hook.Hook[*ServeEvent]{},
|
||||||
|
|
||||||
// dao event hooks
|
// dao event hooks
|
||||||
|
@ -210,6 +212,12 @@ func NewBaseApp(dataDir string, encryptionEnv string, isDebug bool) *BaseApp {
|
||||||
// Bootstrap initializes the application
|
// Bootstrap initializes the application
|
||||||
// (aka. create data dir, open db connections, load settings, etc.)
|
// (aka. create data dir, open db connections, load settings, etc.)
|
||||||
func (app *BaseApp) Bootstrap() error {
|
func (app *BaseApp) Bootstrap() error {
|
||||||
|
event := &BootstrapEvent{app}
|
||||||
|
|
||||||
|
if err := app.OnBeforeBootstrap().Trigger(event); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// clear resources of previous core state (if any)
|
// clear resources of previous core state (if any)
|
||||||
if err := app.ResetBootstrapState(); err != nil {
|
if err := app.ResetBootstrapState(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -228,10 +236,13 @@ func (app *BaseApp) Bootstrap() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// we don't check for an error because the db migrations may
|
// we don't check for an error because the db migrations may have not been executed yet
|
||||||
// have not been executed yet.
|
|
||||||
app.RefreshSettings()
|
app.RefreshSettings()
|
||||||
|
|
||||||
|
if err := app.OnAfterBootstrap().Trigger(event); err != nil && app.IsDebug() {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +306,7 @@ func (app *BaseApp) IsDebug() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings returns the loaded app settings.
|
// Settings returns the loaded app settings.
|
||||||
func (app *BaseApp) Settings() *Settings {
|
func (app *BaseApp) Settings() *settings.Settings {
|
||||||
return app.settings
|
return app.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,75 +360,41 @@ func (app *BaseApp) NewFilesystem() (*filesystem.System, error) {
|
||||||
// RefreshSettings reinitializes and reloads the stored application settings.
|
// RefreshSettings reinitializes and reloads the stored application settings.
|
||||||
func (app *BaseApp) RefreshSettings() error {
|
func (app *BaseApp) RefreshSettings() error {
|
||||||
if app.settings == nil {
|
if app.settings == nil {
|
||||||
app.settings = NewSettings()
|
app.settings = settings.New()
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptionKey := os.Getenv(app.EncryptionEnv())
|
encryptionKey := os.Getenv(app.EncryptionEnv())
|
||||||
|
|
||||||
param, err := app.Dao().FindParamByKey(models.ParamAppSettings)
|
storedSettings, err := app.Dao().FindSettings(encryptionKey)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// no settings were previously stored
|
// no settings were previously stored
|
||||||
if param == nil {
|
if storedSettings == nil {
|
||||||
return app.Dao().SaveParam(models.ParamAppSettings, app.settings, encryptionKey)
|
return app.Dao().SaveSettings(app.settings, encryptionKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the settings from the stored param into the app ones
|
// load the settings from the stored param into the app ones
|
||||||
// ---
|
if err := app.settings.Merge(storedSettings); err != nil {
|
||||||
newSettings := NewSettings()
|
|
||||||
|
|
||||||
// try first without decryption
|
|
||||||
plainDecodeErr := json.Unmarshal(param.Value, newSettings)
|
|
||||||
|
|
||||||
// failed, try to decrypt
|
|
||||||
if plainDecodeErr != nil {
|
|
||||||
// load without decrypt has failed and there is no encryption key to use for decrypt
|
|
||||||
if encryptionKey == "" {
|
|
||||||
return errors.New("Failed to load the stored app settings (missing or invalid encryption key).")
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrypt
|
|
||||||
decrypted, decryptErr := security.Decrypt(string(param.Value), encryptionKey)
|
|
||||||
if decryptErr != nil {
|
|
||||||
return decryptErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode again
|
|
||||||
decryptedDecodeErr := json.Unmarshal(decrypted, newSettings)
|
|
||||||
if decryptedDecodeErr != nil {
|
|
||||||
return decryptedDecodeErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := app.settings.Merge(newSettings); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
afterMergeRaw, err := json.Marshal(app.settings)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if
|
|
||||||
// save because previously the settings weren't stored encrypted
|
|
||||||
(plainDecodeErr == nil && encryptionKey != "") ||
|
|
||||||
// or save because there are new fields after the merge
|
|
||||||
!bytes.Equal(param.Value, afterMergeRaw) {
|
|
||||||
saveErr := app.Dao().SaveParam(models.ParamAppSettings, app.settings, encryptionKey)
|
|
||||||
if saveErr != nil {
|
|
||||||
return saveErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Serve event hooks
|
// App event hooks
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (app *BaseApp) OnBeforeBootstrap() *hook.Hook[*BootstrapEvent] {
|
||||||
|
return app.onBeforeBootstrap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *BaseApp) OnAfterBootstrap() *hook.Hook[*BootstrapEvent] {
|
||||||
|
return app.onAfterBootstrap
|
||||||
|
}
|
||||||
|
|
||||||
func (app *BaseApp) OnBeforeServe() *hook.Hook[*ServeEvent] {
|
func (app *BaseApp) OnBeforeServe() *hook.Hook[*ServeEvent] {
|
||||||
return app.onBeforeServe
|
return app.onBeforeServe
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package core_test
|
package core_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pocketbase/pocketbase/models"
|
"github.com/pocketbase/pocketbase/models"
|
||||||
|
@ -32,7 +31,7 @@ func TestBaseAppRefreshSettings(t *testing.T) {
|
||||||
t.Fatalf("Expected new settings to be persisted, got %v", err)
|
t.Fatalf("Expected new settings to be persisted, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// change the db entry and refresh the app settings
|
// change the db entry and refresh the app settings (ensure that there was no db update)
|
||||||
param.Value = types.JsonRaw([]byte(`{"example": 123}`))
|
param.Value = types.JsonRaw([]byte(`{"example": 123}`))
|
||||||
if err := app.Dao().SaveParam(param.Key, param.Value); err != nil {
|
if err := app.Dao().SaveParam(param.Key, param.Value); err != nil {
|
||||||
t.Fatalf("Failed to update the test settings: %v", err)
|
t.Fatalf("Failed to update the test settings: %v", err)
|
||||||
|
@ -41,21 +40,9 @@ func TestBaseAppRefreshSettings(t *testing.T) {
|
||||||
if err := app.RefreshSettings(); err != nil {
|
if err := app.RefreshSettings(); err != nil {
|
||||||
t.Fatalf("Failed to refresh the app settings: %v", err)
|
t.Fatalf("Failed to refresh the app settings: %v", err)
|
||||||
}
|
}
|
||||||
testEventCalls(t, app, map[string]int{
|
testEventCalls(t, app, nil)
|
||||||
"OnModelBeforeUpdate": 1,
|
|
||||||
"OnModelAfterUpdate": 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
// make sure that the newly merged settings were actually saved
|
// try to refresh again without doing any changes
|
||||||
newParam, err := app.Dao().FindParamByKey(models.ParamAppSettings)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to fetch new settings param: %v", err)
|
|
||||||
}
|
|
||||||
if bytes.Equal(param.Value, newParam.Value) {
|
|
||||||
t.Fatalf("Expected the new refreshed settings to be different, got: \n%v", string(newParam.Value))
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to refresh again and ensure that there was no db update
|
|
||||||
app.ResetEventCalls()
|
app.ResetEventCalls()
|
||||||
if err := app.RefreshSettings(); err != nil {
|
if err := app.RefreshSettings(); err != nil {
|
||||||
t.Fatalf("Failed to refresh the app settings without change: %v", err)
|
t.Fatalf("Failed to refresh the app settings without change: %v", err)
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/pocketbase/pocketbase/daos"
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
"github.com/pocketbase/pocketbase/models"
|
||||||
"github.com/pocketbase/pocketbase/models/schema"
|
"github.com/pocketbase/pocketbase/models/schema"
|
||||||
|
"github.com/pocketbase/pocketbase/models/settings"
|
||||||
"github.com/pocketbase/pocketbase/tools/mailer"
|
"github.com/pocketbase/pocketbase/tools/mailer"
|
||||||
"github.com/pocketbase/pocketbase/tools/search"
|
"github.com/pocketbase/pocketbase/tools/search"
|
||||||
"github.com/pocketbase/pocketbase/tools/subscriptions"
|
"github.com/pocketbase/pocketbase/tools/subscriptions"
|
||||||
|
@ -15,6 +16,10 @@ import (
|
||||||
// Serve events data
|
// Serve events data
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
type BootstrapEvent struct {
|
||||||
|
App App
|
||||||
|
}
|
||||||
|
|
||||||
type ServeEvent struct {
|
type ServeEvent struct {
|
||||||
App App
|
App App
|
||||||
Router *echo.Echo
|
Router *echo.Echo
|
||||||
|
@ -68,13 +73,13 @@ type RealtimeSubscribeEvent struct {
|
||||||
|
|
||||||
type SettingsListEvent struct {
|
type SettingsListEvent struct {
|
||||||
HttpContext echo.Context
|
HttpContext echo.Context
|
||||||
RedactedSettings *Settings
|
RedactedSettings *settings.Settings
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingsUpdateEvent struct {
|
type SettingsUpdateEvent struct {
|
||||||
HttpContext echo.Context
|
HttpContext echo.Context
|
||||||
OldSettings *Settings
|
OldSettings *settings.Settings
|
||||||
NewSettings *Settings
|
NewSettings *settings.Settings
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package daos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/models"
|
||||||
|
"github.com/pocketbase/pocketbase/models/settings"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FindSettings returns and decode the serialized app settings param value.
|
||||||
|
//
|
||||||
|
// The method will first try to decode the param value without decryption.
|
||||||
|
// If it fails and optEncryptionKey is set, it will try again by first
|
||||||
|
// decrypting the value and then decode it again.
|
||||||
|
//
|
||||||
|
// Returns an error if it fails to decode the stored serialized param value.
|
||||||
|
func (dao *Dao) FindSettings(optEncryptionKey ...string) (*settings.Settings, error) {
|
||||||
|
param, err := dao.FindParamByKey(models.ParamAppSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := settings.New()
|
||||||
|
|
||||||
|
// try first without decryption
|
||||||
|
plainDecodeErr := json.Unmarshal(param.Value, result)
|
||||||
|
|
||||||
|
// failed, try to decrypt
|
||||||
|
if plainDecodeErr != nil {
|
||||||
|
var encryptionKey string
|
||||||
|
if len(optEncryptionKey) > 0 && optEncryptionKey[0] != "" {
|
||||||
|
encryptionKey = optEncryptionKey[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// load without decrypt has failed and there is no encryption key to use for decrypt
|
||||||
|
if encryptionKey == "" {
|
||||||
|
return nil, errors.New("failed to load the stored app settings - missing or invalid encryption key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt
|
||||||
|
decrypted, decryptErr := security.Decrypt(string(param.Value), encryptionKey)
|
||||||
|
if decryptErr != nil {
|
||||||
|
return nil, decryptErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode again
|
||||||
|
decryptedDecodeErr := json.Unmarshal(decrypted, result)
|
||||||
|
if decryptedDecodeErr != nil {
|
||||||
|
return nil, decryptedDecodeErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveSettings persists the specified settings configuration.
|
||||||
|
//
|
||||||
|
// If optEncryptionKey is set, then the stored serialized value will be encrypted with it.
|
||||||
|
func (dao *Dao) SaveSettings(newSettings *settings.Settings, optEncryptionKey ...string) error {
|
||||||
|
return dao.SaveParam(models.ParamAppSettings, newSettings, optEncryptionKey...)
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package daos_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/tests"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSaveAndFindSettings(t *testing.T) {
|
||||||
|
app, _ := tests.NewTestApp()
|
||||||
|
defer app.Cleanup()
|
||||||
|
|
||||||
|
encryptionKey := security.PseudorandomString(32)
|
||||||
|
|
||||||
|
// change unencrypted app settings
|
||||||
|
app.Settings().Meta.AppName = "save_unencrypted"
|
||||||
|
if err := app.Dao().SaveSettings(app.Settings()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the change was persisted
|
||||||
|
s1, err := app.Dao().FindSettings()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to fetch settings: %v", err)
|
||||||
|
}
|
||||||
|
if s1.Meta.AppName != "save_unencrypted" {
|
||||||
|
t.Fatalf("Expected settings to be changed with app name %q, got \n%v", "save_unencrypted", s1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make another change but this time provide an encryption key
|
||||||
|
app.Settings().Meta.AppName = "save_encrypted"
|
||||||
|
if err := app.Dao().SaveSettings(app.Settings(), encryptionKey); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to fetch the settings without encryption key (should fail)
|
||||||
|
if s2, err := app.Dao().FindSettings(); err == nil {
|
||||||
|
t.Fatalf("Expected FindSettings to fail without an encryption key, got \n%v", s2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try again but this time with an encryption key
|
||||||
|
s3, err := app.Dao().FindSettings(encryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to fetch settings with an encryption key %s: %v", encryptionKey, err)
|
||||||
|
}
|
||||||
|
if s3.Meta.AppName != "save_encrypted" {
|
||||||
|
t.Fatalf("Expected settings to be changed with app name %q, got \n%v", "save_encrypted", s3)
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,12 +6,12 @@ import (
|
||||||
|
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/daos"
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
"github.com/pocketbase/pocketbase/models/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SettingsUpsert is a [core.Settings] upsert (create/update) form.
|
// SettingsUpsert is a [settings.Settings] upsert (create/update) form.
|
||||||
type SettingsUpsert struct {
|
type SettingsUpsert struct {
|
||||||
*core.Settings
|
*settings.Settings
|
||||||
|
|
||||||
app core.App
|
app core.App
|
||||||
dao *daos.Dao
|
dao *daos.Dao
|
||||||
|
@ -55,16 +55,10 @@ func (form *SettingsUpsert) Submit(interceptors ...InterceptorFunc) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptionKey := os.Getenv(form.app.EncryptionEnv())
|
|
||||||
|
|
||||||
return runInterceptors(func() error {
|
return runInterceptors(func() error {
|
||||||
saveErr := form.dao.SaveParam(
|
encryptionKey := os.Getenv(form.app.EncryptionEnv())
|
||||||
models.ParamAppSettings,
|
if err := form.dao.SaveSettings(form.Settings, encryptionKey); err != nil {
|
||||||
form.Settings,
|
return err
|
||||||
encryptionKey,
|
|
||||||
)
|
|
||||||
if saveErr != nil {
|
|
||||||
return saveErr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicitly trigger old logs deletion
|
// explicitly trigger old logs deletion
|
||||||
|
@ -73,7 +67,7 @@ func (form *SettingsUpsert) Submit(interceptors ...InterceptorFunc) error {
|
||||||
)
|
)
|
||||||
|
|
||||||
if form.Settings.Logs.MaxDays == 0 {
|
if form.Settings.Logs.MaxDays == 0 {
|
||||||
// reclaim deleted logs disk space
|
// no logs are allowed -> reclaim preserved disk space after the previous delete operation
|
||||||
form.app.LogsDao().Vacuum()
|
form.app.LogsDao().Vacuum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/mails/templates"
|
"github.com/pocketbase/pocketbase/mails/templates"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
"github.com/pocketbase/pocketbase/models"
|
||||||
|
"github.com/pocketbase/pocketbase/models/settings"
|
||||||
"github.com/pocketbase/pocketbase/tokens"
|
"github.com/pocketbase/pocketbase/tokens"
|
||||||
"github.com/pocketbase/pocketbase/tools/mailer"
|
"github.com/pocketbase/pocketbase/tools/mailer"
|
||||||
)
|
)
|
||||||
|
@ -20,17 +21,15 @@ func SendRecordPasswordReset(app core.App, authRecord *models.Record) error {
|
||||||
|
|
||||||
mailClient := app.NewMailClient()
|
mailClient := app.NewMailClient()
|
||||||
|
|
||||||
settings := app.Settings()
|
subject, body, err := resolveEmailTemplate(app, token, app.Settings().Meta.ResetPasswordTemplate)
|
||||||
|
|
||||||
subject, body, err := resolveEmailTemplate(app, token, settings.Meta.ResetPasswordTemplate)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
message := &mailer.Message{
|
message := &mailer.Message{
|
||||||
From: mail.Address{
|
From: mail.Address{
|
||||||
Name: settings.Meta.SenderName,
|
Name: app.Settings().Meta.SenderName,
|
||||||
Address: settings.Meta.SenderAddress,
|
Address: app.Settings().Meta.SenderAddress,
|
||||||
},
|
},
|
||||||
To: mail.Address{Address: authRecord.Email()},
|
To: mail.Address{Address: authRecord.Email()},
|
||||||
Subject: subject,
|
Subject: subject,
|
||||||
|
@ -64,17 +63,15 @@ func SendRecordVerification(app core.App, authRecord *models.Record) error {
|
||||||
|
|
||||||
mailClient := app.NewMailClient()
|
mailClient := app.NewMailClient()
|
||||||
|
|
||||||
settings := app.Settings()
|
subject, body, err := resolveEmailTemplate(app, token, app.Settings().Meta.VerificationTemplate)
|
||||||
|
|
||||||
subject, body, err := resolveEmailTemplate(app, token, settings.Meta.VerificationTemplate)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
message := &mailer.Message{
|
message := &mailer.Message{
|
||||||
From: mail.Address{
|
From: mail.Address{
|
||||||
Name: settings.Meta.SenderName,
|
Name: app.Settings().Meta.SenderName,
|
||||||
Address: settings.Meta.SenderAddress,
|
Address: app.Settings().Meta.SenderAddress,
|
||||||
},
|
},
|
||||||
To: mail.Address{Address: authRecord.Email()},
|
To: mail.Address{Address: authRecord.Email()},
|
||||||
Subject: subject,
|
Subject: subject,
|
||||||
|
@ -108,17 +105,15 @@ func SendRecordChangeEmail(app core.App, record *models.Record, newEmail string)
|
||||||
|
|
||||||
mailClient := app.NewMailClient()
|
mailClient := app.NewMailClient()
|
||||||
|
|
||||||
settings := app.Settings()
|
subject, body, err := resolveEmailTemplate(app, token, app.Settings().Meta.ConfirmEmailChangeTemplate)
|
||||||
|
|
||||||
subject, body, err := resolveEmailTemplate(app, token, settings.Meta.ConfirmEmailChangeTemplate)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
message := &mailer.Message{
|
message := &mailer.Message{
|
||||||
From: mail.Address{
|
From: mail.Address{
|
||||||
Name: settings.Meta.SenderName,
|
Name: app.Settings().Meta.SenderName,
|
||||||
Address: settings.Meta.SenderAddress,
|
Address: app.Settings().Meta.SenderAddress,
|
||||||
},
|
},
|
||||||
To: mail.Address{Address: newEmail},
|
To: mail.Address{Address: newEmail},
|
||||||
Subject: subject,
|
Subject: subject,
|
||||||
|
@ -149,13 +144,11 @@ func SendRecordChangeEmail(app core.App, record *models.Record, newEmail string)
|
||||||
func resolveEmailTemplate(
|
func resolveEmailTemplate(
|
||||||
app core.App,
|
app core.App,
|
||||||
token string,
|
token string,
|
||||||
emailTemplate core.EmailTemplate,
|
emailTemplate settings.EmailTemplate,
|
||||||
) (subject string, body string, err error) {
|
) (subject string, body string, err error) {
|
||||||
settings := app.Settings()
|
|
||||||
|
|
||||||
subject, rawBody, _ := emailTemplate.Resolve(
|
subject, rawBody, _ := emailTemplate.Resolve(
|
||||||
settings.Meta.AppName,
|
app.Settings().Meta.AppName,
|
||||||
settings.Meta.AppUrl,
|
app.Settings().Meta.AppUrl,
|
||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,10 @@ package templates
|
||||||
const AdminPasswordResetBody = `
|
const AdminPasswordResetBody = `
|
||||||
{{define "content"}}
|
{{define "content"}}
|
||||||
<p>Hello,</p>
|
<p>Hello,</p>
|
||||||
|
|
||||||
<p>Follow this link to reset your admin password for {{.AppName}}.</p>
|
<p>Follow this link to reset your admin password for {{.AppName}}.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a class="btn" href="{{.ActionUrl}}" target="_blank" rel="noopener">Reset password</a>
|
<a class="btn" href="{{.ActionUrl}}" target="_blank" rel="noopener">Reset password</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p><i>If you did not request to reset your password, please ignore this email and the link will expire on its own.</i></p>
|
<p><i>If you did not request to reset your password, please ignore this email and the link will expire on its own.</i></p>
|
||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -45,8 +45,8 @@ type Settings struct {
|
||||||
TwitchAuth AuthProviderConfig `form:"twitchAuth" json:"twitchAuth"`
|
TwitchAuth AuthProviderConfig `form:"twitchAuth" json:"twitchAuth"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSettings creates and returns a new default Settings instance.
|
// New creates and returns a new default Settings instance.
|
||||||
func NewSettings() *Settings {
|
func New() *Settings {
|
||||||
return &Settings{
|
return &Settings{
|
||||||
Meta: MetaConfig{
|
Meta: MetaConfig{
|
||||||
AppName: "Acme",
|
AppName: "Acme",
|
||||||
|
@ -170,11 +170,11 @@ func (s *Settings) Merge(other *Settings) error {
|
||||||
|
|
||||||
// Clone creates a new deep copy of the current settings.
|
// Clone creates a new deep copy of the current settings.
|
||||||
func (s *Settings) Clone() (*Settings, error) {
|
func (s *Settings) Clone() (*Settings, error) {
|
||||||
settings := &Settings{}
|
clone := &Settings{}
|
||||||
if err := settings.Merge(s); err != nil {
|
if err := clone.Merge(s); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return settings, nil
|
return clone, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RedactClone creates a new deep copy of the current settings,
|
// RedactClone creates a new deep copy of the current settings,
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package settings
|
||||||
|
|
||||||
// Common settings placeholder tokens
|
// Common settings placeholder tokens
|
||||||
const (
|
const (
|
|
@ -1,4 +1,4 @@
|
||||||
package core_test
|
package settings_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -7,12 +7,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/models/settings"
|
||||||
"github.com/pocketbase/pocketbase/tools/auth"
|
"github.com/pocketbase/pocketbase/tools/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSettingsValidate(t *testing.T) {
|
func TestSettingsValidate(t *testing.T) {
|
||||||
s := core.NewSettings()
|
s := settings.New()
|
||||||
|
|
||||||
// set invalid settings data
|
// set invalid settings data
|
||||||
s.Meta.AppName = ""
|
s.Meta.AppName = ""
|
||||||
|
@ -87,10 +87,10 @@ func TestSettingsValidate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsMerge(t *testing.T) {
|
func TestSettingsMerge(t *testing.T) {
|
||||||
s1 := core.NewSettings()
|
s1 := settings.New()
|
||||||
s1.Meta.AppUrl = "old_app_url"
|
s1.Meta.AppUrl = "old_app_url"
|
||||||
|
|
||||||
s2 := core.NewSettings()
|
s2 := settings.New()
|
||||||
s2.Meta.AppName = "test"
|
s2.Meta.AppName = "test"
|
||||||
s2.Logs.MaxDays = 123
|
s2.Logs.MaxDays = 123
|
||||||
s2.Smtp.Host = "test"
|
s2.Smtp.Host = "test"
|
||||||
|
@ -144,7 +144,7 @@ func TestSettingsMerge(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsClone(t *testing.T) {
|
func TestSettingsClone(t *testing.T) {
|
||||||
s1 := core.NewSettings()
|
s1 := settings.New()
|
||||||
|
|
||||||
s2, err := s1.Clone()
|
s2, err := s1.Clone()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -173,7 +173,7 @@ func TestSettingsClone(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsRedactClone(t *testing.T) {
|
func TestSettingsRedactClone(t *testing.T) {
|
||||||
s1 := core.NewSettings()
|
s1 := settings.New()
|
||||||
s1.Meta.AppName = "test123" // control field
|
s1.Meta.AppName = "test123" // control field
|
||||||
s1.Smtp.Password = "test123"
|
s1.Smtp.Password = "test123"
|
||||||
s1.Smtp.Tls = true
|
s1.Smtp.Tls = true
|
||||||
|
@ -213,7 +213,7 @@ func TestSettingsRedactClone(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNamedAuthProviderConfigs(t *testing.T) {
|
func TestNamedAuthProviderConfigs(t *testing.T) {
|
||||||
s := core.NewSettings()
|
s := settings.New()
|
||||||
|
|
||||||
s.GoogleAuth.ClientId = "google_test"
|
s.GoogleAuth.ClientId = "google_test"
|
||||||
s.FacebookAuth.ClientId = "facebook_test"
|
s.FacebookAuth.ClientId = "facebook_test"
|
||||||
|
@ -256,17 +256,17 @@ func TestNamedAuthProviderConfigs(t *testing.T) {
|
||||||
|
|
||||||
func TestTokenConfigValidate(t *testing.T) {
|
func TestTokenConfigValidate(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config core.TokenConfig
|
config settings.TokenConfig
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
// zero values
|
// zero values
|
||||||
{
|
{
|
||||||
core.TokenConfig{},
|
settings.TokenConfig{},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
// invalid data
|
// invalid data
|
||||||
{
|
{
|
||||||
core.TokenConfig{
|
settings.TokenConfig{
|
||||||
Secret: strings.Repeat("a", 5),
|
Secret: strings.Repeat("a", 5),
|
||||||
Duration: 4,
|
Duration: 4,
|
||||||
},
|
},
|
||||||
|
@ -274,7 +274,7 @@ func TestTokenConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid secret but invalid duration
|
// valid secret but invalid duration
|
||||||
{
|
{
|
||||||
core.TokenConfig{
|
settings.TokenConfig{
|
||||||
Secret: strings.Repeat("a", 30),
|
Secret: strings.Repeat("a", 30),
|
||||||
Duration: 63072000 + 1,
|
Duration: 63072000 + 1,
|
||||||
},
|
},
|
||||||
|
@ -282,7 +282,7 @@ func TestTokenConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid data
|
// valid data
|
||||||
{
|
{
|
||||||
core.TokenConfig{
|
settings.TokenConfig{
|
||||||
Secret: strings.Repeat("a", 30),
|
Secret: strings.Repeat("a", 30),
|
||||||
Duration: 100,
|
Duration: 100,
|
||||||
},
|
},
|
||||||
|
@ -305,22 +305,22 @@ func TestTokenConfigValidate(t *testing.T) {
|
||||||
|
|
||||||
func TestSmtpConfigValidate(t *testing.T) {
|
func TestSmtpConfigValidate(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config core.SmtpConfig
|
config settings.SmtpConfig
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
// zero values (disabled)
|
// zero values (disabled)
|
||||||
{
|
{
|
||||||
core.SmtpConfig{},
|
settings.SmtpConfig{},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
// zero values (enabled)
|
// zero values (enabled)
|
||||||
{
|
{
|
||||||
core.SmtpConfig{Enabled: true},
|
settings.SmtpConfig{Enabled: true},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
// invalid data
|
// invalid data
|
||||||
{
|
{
|
||||||
core.SmtpConfig{
|
settings.SmtpConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Host: "test:test:test",
|
Host: "test:test:test",
|
||||||
Port: -10,
|
Port: -10,
|
||||||
|
@ -329,7 +329,7 @@ func TestSmtpConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid data
|
// valid data
|
||||||
{
|
{
|
||||||
core.SmtpConfig{
|
settings.SmtpConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
Port: 100,
|
Port: 100,
|
||||||
|
@ -354,22 +354,22 @@ func TestSmtpConfigValidate(t *testing.T) {
|
||||||
|
|
||||||
func TestS3ConfigValidate(t *testing.T) {
|
func TestS3ConfigValidate(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config core.S3Config
|
config settings.S3Config
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
// zero values (disabled)
|
// zero values (disabled)
|
||||||
{
|
{
|
||||||
core.S3Config{},
|
settings.S3Config{},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
// zero values (enabled)
|
// zero values (enabled)
|
||||||
{
|
{
|
||||||
core.S3Config{Enabled: true},
|
settings.S3Config{Enabled: true},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
// invalid data
|
// invalid data
|
||||||
{
|
{
|
||||||
core.S3Config{
|
settings.S3Config{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Endpoint: "test:test:test",
|
Endpoint: "test:test:test",
|
||||||
},
|
},
|
||||||
|
@ -377,7 +377,7 @@ func TestS3ConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid data (url endpoint)
|
// valid data (url endpoint)
|
||||||
{
|
{
|
||||||
core.S3Config{
|
settings.S3Config{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Endpoint: "https://localhost:8090",
|
Endpoint: "https://localhost:8090",
|
||||||
Bucket: "test",
|
Bucket: "test",
|
||||||
|
@ -389,7 +389,7 @@ func TestS3ConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid data (hostname endpoint)
|
// valid data (hostname endpoint)
|
||||||
{
|
{
|
||||||
core.S3Config{
|
settings.S3Config{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Endpoint: "example.com",
|
Endpoint: "example.com",
|
||||||
Bucket: "test",
|
Bucket: "test",
|
||||||
|
@ -415,36 +415,36 @@ func TestS3ConfigValidate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMetaConfigValidate(t *testing.T) {
|
func TestMetaConfigValidate(t *testing.T) {
|
||||||
invalidTemplate := core.EmailTemplate{
|
invalidTemplate := settings.EmailTemplate{
|
||||||
Subject: "test",
|
Subject: "test",
|
||||||
ActionUrl: "test",
|
ActionUrl: "test",
|
||||||
Body: "test",
|
Body: "test",
|
||||||
}
|
}
|
||||||
|
|
||||||
noPlaceholdersTemplate := core.EmailTemplate{
|
noPlaceholdersTemplate := settings.EmailTemplate{
|
||||||
Subject: "test",
|
Subject: "test",
|
||||||
ActionUrl: "http://example.com",
|
ActionUrl: "http://example.com",
|
||||||
Body: "test",
|
Body: "test",
|
||||||
}
|
}
|
||||||
|
|
||||||
withPlaceholdersTemplate := core.EmailTemplate{
|
withPlaceholdersTemplate := settings.EmailTemplate{
|
||||||
Subject: "test",
|
Subject: "test",
|
||||||
ActionUrl: "http://example.com" + core.EmailPlaceholderToken,
|
ActionUrl: "http://example.com" + settings.EmailPlaceholderToken,
|
||||||
Body: "test" + core.EmailPlaceholderActionUrl,
|
Body: "test" + settings.EmailPlaceholderActionUrl,
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config core.MetaConfig
|
config settings.MetaConfig
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
// zero values
|
// zero values
|
||||||
{
|
{
|
||||||
core.MetaConfig{},
|
settings.MetaConfig{},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
// invalid data
|
// invalid data
|
||||||
{
|
{
|
||||||
core.MetaConfig{
|
settings.MetaConfig{
|
||||||
AppName: strings.Repeat("a", 300),
|
AppName: strings.Repeat("a", 300),
|
||||||
AppUrl: "test",
|
AppUrl: "test",
|
||||||
SenderName: strings.Repeat("a", 300),
|
SenderName: strings.Repeat("a", 300),
|
||||||
|
@ -457,7 +457,7 @@ func TestMetaConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// invalid data (missing required placeholders)
|
// invalid data (missing required placeholders)
|
||||||
{
|
{
|
||||||
core.MetaConfig{
|
settings.MetaConfig{
|
||||||
AppName: "test",
|
AppName: "test",
|
||||||
AppUrl: "https://example.com",
|
AppUrl: "https://example.com",
|
||||||
SenderName: "test",
|
SenderName: "test",
|
||||||
|
@ -470,7 +470,7 @@ func TestMetaConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid data
|
// valid data
|
||||||
{
|
{
|
||||||
core.MetaConfig{
|
settings.MetaConfig{
|
||||||
AppName: "test",
|
AppName: "test",
|
||||||
AppUrl: "https://example.com",
|
AppUrl: "https://example.com",
|
||||||
SenderName: "test",
|
SenderName: "test",
|
||||||
|
@ -498,17 +498,17 @@ func TestMetaConfigValidate(t *testing.T) {
|
||||||
|
|
||||||
func TestEmailTemplateValidate(t *testing.T) {
|
func TestEmailTemplateValidate(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
emailTemplate core.EmailTemplate
|
emailTemplate settings.EmailTemplate
|
||||||
expectedErrors []string
|
expectedErrors []string
|
||||||
}{
|
}{
|
||||||
// require values
|
// require values
|
||||||
{
|
{
|
||||||
core.EmailTemplate{},
|
settings.EmailTemplate{},
|
||||||
[]string{"subject", "actionUrl", "body"},
|
[]string{"subject", "actionUrl", "body"},
|
||||||
},
|
},
|
||||||
// missing placeholders
|
// missing placeholders
|
||||||
{
|
{
|
||||||
core.EmailTemplate{
|
settings.EmailTemplate{
|
||||||
Subject: "test",
|
Subject: "test",
|
||||||
ActionUrl: "test",
|
ActionUrl: "test",
|
||||||
Body: "test",
|
Body: "test",
|
||||||
|
@ -517,10 +517,10 @@ func TestEmailTemplateValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid data
|
// valid data
|
||||||
{
|
{
|
||||||
core.EmailTemplate{
|
settings.EmailTemplate{
|
||||||
Subject: "test",
|
Subject: "test",
|
||||||
ActionUrl: "test" + core.EmailPlaceholderToken,
|
ActionUrl: "test" + settings.EmailPlaceholderToken,
|
||||||
Body: "test" + core.EmailPlaceholderActionUrl,
|
Body: "test" + settings.EmailPlaceholderActionUrl,
|
||||||
},
|
},
|
||||||
[]string{},
|
[]string{},
|
||||||
},
|
},
|
||||||
|
@ -549,17 +549,17 @@ func TestEmailTemplateValidate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEmailTemplateResolve(t *testing.T) {
|
func TestEmailTemplateResolve(t *testing.T) {
|
||||||
allPlaceholders := core.EmailPlaceholderActionUrl + core.EmailPlaceholderToken + core.EmailPlaceholderAppName + core.EmailPlaceholderAppUrl
|
allPlaceholders := settings.EmailPlaceholderActionUrl + settings.EmailPlaceholderToken + settings.EmailPlaceholderAppName + settings.EmailPlaceholderAppUrl
|
||||||
|
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
emailTemplate core.EmailTemplate
|
emailTemplate settings.EmailTemplate
|
||||||
expectedSubject string
|
expectedSubject string
|
||||||
expectedBody string
|
expectedBody string
|
||||||
expectedActionUrl string
|
expectedActionUrl string
|
||||||
}{
|
}{
|
||||||
// no placeholders
|
// no placeholders
|
||||||
{
|
{
|
||||||
emailTemplate: core.EmailTemplate{
|
emailTemplate: settings.EmailTemplate{
|
||||||
Subject: "subject:",
|
Subject: "subject:",
|
||||||
Body: "body:",
|
Body: "body:",
|
||||||
ActionUrl: "/actionUrl////",
|
ActionUrl: "/actionUrl////",
|
||||||
|
@ -570,7 +570,7 @@ func TestEmailTemplateResolve(t *testing.T) {
|
||||||
},
|
},
|
||||||
// with placeholders
|
// with placeholders
|
||||||
{
|
{
|
||||||
emailTemplate: core.EmailTemplate{
|
emailTemplate: settings.EmailTemplate{
|
||||||
ActionUrl: "/actionUrl////" + allPlaceholders,
|
ActionUrl: "/actionUrl////" + allPlaceholders,
|
||||||
Subject: "subject:" + allPlaceholders,
|
Subject: "subject:" + allPlaceholders,
|
||||||
Body: "body:" + allPlaceholders,
|
Body: "body:" + allPlaceholders,
|
||||||
|
@ -583,8 +583,8 @@ func TestEmailTemplateResolve(t *testing.T) {
|
||||||
),
|
),
|
||||||
expectedSubject: fmt.Sprintf(
|
expectedSubject: fmt.Sprintf(
|
||||||
"subject:%s%s%s%s",
|
"subject:%s%s%s%s",
|
||||||
core.EmailPlaceholderActionUrl,
|
settings.EmailPlaceholderActionUrl,
|
||||||
core.EmailPlaceholderToken,
|
settings.EmailPlaceholderToken,
|
||||||
"name_test",
|
"name_test",
|
||||||
"url_test",
|
"url_test",
|
||||||
),
|
),
|
||||||
|
@ -622,22 +622,22 @@ func TestEmailTemplateResolve(t *testing.T) {
|
||||||
|
|
||||||
func TestLogsConfigValidate(t *testing.T) {
|
func TestLogsConfigValidate(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config core.LogsConfig
|
config settings.LogsConfig
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
// zero values
|
// zero values
|
||||||
{
|
{
|
||||||
core.LogsConfig{},
|
settings.LogsConfig{},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
// invalid data
|
// invalid data
|
||||||
{
|
{
|
||||||
core.LogsConfig{MaxDays: -10},
|
settings.LogsConfig{MaxDays: -10},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
// valid data
|
// valid data
|
||||||
{
|
{
|
||||||
core.LogsConfig{MaxDays: 1},
|
settings.LogsConfig{MaxDays: 1},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -657,22 +657,22 @@ func TestLogsConfigValidate(t *testing.T) {
|
||||||
|
|
||||||
func TestAuthProviderConfigValidate(t *testing.T) {
|
func TestAuthProviderConfigValidate(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config core.AuthProviderConfig
|
config settings.AuthProviderConfig
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
// zero values (disabled)
|
// zero values (disabled)
|
||||||
{
|
{
|
||||||
core.AuthProviderConfig{},
|
settings.AuthProviderConfig{},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
// zero values (enabled)
|
// zero values (enabled)
|
||||||
{
|
{
|
||||||
core.AuthProviderConfig{Enabled: true},
|
settings.AuthProviderConfig{Enabled: true},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
// invalid data
|
// invalid data
|
||||||
{
|
{
|
||||||
core.AuthProviderConfig{
|
settings.AuthProviderConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
ClientId: "",
|
ClientId: "",
|
||||||
ClientSecret: "",
|
ClientSecret: "",
|
||||||
|
@ -684,7 +684,7 @@ func TestAuthProviderConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid data (only the required)
|
// valid data (only the required)
|
||||||
{
|
{
|
||||||
core.AuthProviderConfig{
|
settings.AuthProviderConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
ClientId: "test",
|
ClientId: "test",
|
||||||
ClientSecret: "test",
|
ClientSecret: "test",
|
||||||
|
@ -693,7 +693,7 @@ func TestAuthProviderConfigValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
// valid data (fill all fields)
|
// valid data (fill all fields)
|
||||||
{
|
{
|
||||||
core.AuthProviderConfig{
|
settings.AuthProviderConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
ClientId: "test",
|
ClientId: "test",
|
||||||
ClientSecret: "test",
|
ClientSecret: "test",
|
||||||
|
@ -722,12 +722,12 @@ func TestAuthProviderConfigSetupProvider(t *testing.T) {
|
||||||
provider := auth.NewGithubProvider()
|
provider := auth.NewGithubProvider()
|
||||||
|
|
||||||
// disabled config
|
// disabled config
|
||||||
c1 := core.AuthProviderConfig{Enabled: false}
|
c1 := settings.AuthProviderConfig{Enabled: false}
|
||||||
if err := c1.SetupProvider(provider); err == nil {
|
if err := c1.SetupProvider(provider); err == nil {
|
||||||
t.Errorf("Expected error, got nil")
|
t.Errorf("Expected error, got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
c2 := core.AuthProviderConfig{
|
c2 := settings.AuthProviderConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
ClientId: "test_ClientId",
|
ClientId: "test_ClientId",
|
||||||
ClientSecret: "test_ClientSecret",
|
ClientSecret: "test_ClientSecret",
|
Binary file not shown.
Loading…
Reference in New Issue