From b2b791b3650b43c1c6224762c37038f4187abc4b Mon Sep 17 00:00:00 2001 From: Gabe Kangas Date: Mon, 25 Apr 2022 14:10:20 -0700 Subject: [PATCH] Migrate forbidden and suggested usernames list to string slice. Closes #1873 --- core/data/config.go | 29 ++++++++----------- core/data/configEntry.go | 7 +++++ core/data/data.go | 32 +-------------------- core/data/datastoreMigrations.go | 49 ++++++++++++++++++++++++++++++++ core/data/migrations.go | 33 +++++++++++++++++++++ core/data/persistence.go | 2 ++ core/data/types.go | 15 ++++++++++ 7 files changed, 119 insertions(+), 48 deletions(-) create mode 100644 core/data/datastoreMigrations.go diff --git a/core/data/config.go b/core/data/config.go index b63c84d64..c421e5cf6 100644 --- a/core/data/config.go +++ b/core/data/config.go @@ -630,44 +630,39 @@ func FindHighestVideoQualityIndex(qualities []models.StreamOutputVariant) int { // GetForbiddenUsernameList will return the blocked usernames as a comma separated string. func GetForbiddenUsernameList() []string { - usernameString, err := _datastore.GetString(blockedUsernamesKey) + usernames, err := _datastore.GetStringSlice(blockedUsernamesKey) if err != nil { return config.DefaultForbiddenUsernames } - if usernameString == "" { + if len(usernames) == 0 { return config.DefaultForbiddenUsernames } - blocklist := strings.Split(usernameString, ",") - - return blocklist + return usernames } // SetForbiddenUsernameList set the username blocklist as a comma separated string. func SetForbiddenUsernameList(usernames []string) error { - usernameListString := strings.Join(usernames, ",") - return _datastore.SetString(blockedUsernamesKey, usernameListString) + return _datastore.SetStringSlice(blockedUsernamesKey, usernames) } -// GetSuggestedUsernamesList will return the suggested usernames as a comma separated string. -// If the number of suggested usernames is smaller than 10, the number pool is not used (see code in the CreateAnonymousUser function). +// GetSuggestedUsernamesList will return the suggested usernames. +// If the number of suggested usernames is smaller than 10, the number pool is +// not used (see code in the CreateAnonymousUser function). func GetSuggestedUsernamesList() []string { - usernameString, err := _datastore.GetString(suggestedUsernamesKey) + usernames, err := _datastore.GetStringSlice(suggestedUsernamesKey) - if err != nil || usernameString == "" { + if err != nil || len(usernames) == 0 { return []string{} } - suggestionList := strings.Split(usernameString, ",") - - return suggestionList + return usernames } -// SetSuggestedUsernamesList sets the username suggestion list as a comma separated string. +// SetSuggestedUsernamesList sets the username suggestion list. func SetSuggestedUsernamesList(usernames []string) error { - usernameListString := strings.Join(usernames, ",") - return _datastore.SetString(suggestedUsernamesKey, usernameListString) + return _datastore.SetStringSlice(suggestedUsernamesKey, usernames) } // GetServerInitTime will return when the server was first setup. diff --git a/core/data/configEntry.go b/core/data/configEntry.go index 6e4afb17d..c33f0310a 100644 --- a/core/data/configEntry.go +++ b/core/data/configEntry.go @@ -12,6 +12,13 @@ type ConfigEntry struct { Value interface{} } +func (c *ConfigEntry) getStringSlice() ([]string, error) { + decoder := c.getDecoder() + var result []string + err := decoder.Decode(&result) + return result, err +} + func (c *ConfigEntry) getString() (string, error) { decoder := c.getDecoder() var result string diff --git a/core/data/data.go b/core/data/data.go index e4f0d504b..1abd512bd 100644 --- a/core/data/data.go +++ b/core/data/data.go @@ -108,7 +108,7 @@ func SetupPersistence(file string) error { // is database schema outdated? if version < schemaVersion { - if err := migrateDatabase(db, version, schemaVersion); err != nil { + if err := migrateDatabaseSchema(db, version, schemaVersion); err != nil { return err } } @@ -126,33 +126,3 @@ func SetupPersistence(file string) error { return nil } - -func migrateDatabase(db *sql.DB, from, to int) error { - log.Printf("Migrating database from version %d to %d", from, to) - dbBackupFile := filepath.Join(config.BackupDirectory, fmt.Sprintf("owncast-v%d.bak", from)) - utils.Backup(db, dbBackupFile) - for v := from; v < to; v++ { - log.Tracef("Migration step from %d to %d\n", v, v+1) - switch v { - case 0: - migrateToSchema1(db) - case 1: - migrateToSchema2(db) - case 2: - migrateToSchema3(db) - case 3: - migrateToSchema4(db) - case 4: - migrateToSchema5(db) - default: - log.Fatalln("missing database migration step") - } - } - - _, err := db.Exec("UPDATE config SET value = ? WHERE key = ?", to, "version") - if err != nil { - return err - } - - return nil -} diff --git a/core/data/datastoreMigrations.go b/core/data/datastoreMigrations.go new file mode 100644 index 000000000..9165b6384 --- /dev/null +++ b/core/data/datastoreMigrations.go @@ -0,0 +1,49 @@ +package data + +import ( + "strings" + + log "github.com/sirupsen/logrus" +) + +const ( + datastoreValuesVersion = 1 + datastoreValueVersionKey = "DATA_STORE_VERSION" +) + +func migrateDatastoreValues(datastore *Datastore) { + currentVersion, _ := _datastore.GetNumber(datastoreValueVersionKey) + + for v := currentVersion; v < datastoreValuesVersion; v++ { + log.Tracef("Migration datastore values from %d to %d\n", int(v), int(v+1)) + switch v { + case 0: + migrateToDatastoreValues1(datastore) + default: + log.Fatalln("missing datastore values migration step") + } + } + if err := _datastore.SetNumber(datastoreValueVersionKey, datastoreValuesVersion); err != nil { + log.Errorln("error setting datastore value version:", err) + } +} + +func migrateToDatastoreValues1(datastore *Datastore) { + // Migrate the forbidden usernames to be a slice instead of a string. + forbiddenUsernamesString, _ := datastore.GetString(blockedUsernamesKey) + if forbiddenUsernamesString != "" { + forbiddenUsernamesSlice := strings.Split(forbiddenUsernamesString, ",") + if err := datastore.SetStringSlice(blockedUsernamesKey, forbiddenUsernamesSlice); err != nil { + log.Errorln("error migrating blocked username list:", err) + } + } + + // Migrate the suggested usernames to be a slice instead of a string. + suggestedUsernamesString, _ := datastore.GetString(suggestedUsernamesKey) + if suggestedUsernamesString != "" { + suggestedUsernamesSlice := strings.Split(suggestedUsernamesString, ",") + if err := datastore.SetStringSlice(suggestedUsernamesKey, suggestedUsernamesSlice); err != nil { + log.Errorln("error migrating suggested username list:", err) + } + } +} diff --git a/core/data/migrations.go b/core/data/migrations.go index b1b54d476..3366294cf 100644 --- a/core/data/migrations.go +++ b/core/data/migrations.go @@ -2,13 +2,46 @@ package data import ( "database/sql" + "fmt" + "path/filepath" "time" + "github.com/owncast/owncast/config" "github.com/owncast/owncast/utils" log "github.com/sirupsen/logrus" "github.com/teris-io/shortid" ) +func migrateDatabaseSchema(db *sql.DB, from, to int) error { + log.Printf("Migrating database from version %d to %d", from, to) + dbBackupFile := filepath.Join(config.BackupDirectory, fmt.Sprintf("owncast-v%d.bak", from)) + utils.Backup(db, dbBackupFile) + for v := from; v < to; v++ { + log.Tracef("Migration step from %d to %d\n", v, v+1) + switch v { + case 0: + migrateToSchema1(db) + case 1: + migrateToSchema2(db) + case 2: + migrateToSchema3(db) + case 3: + migrateToSchema4(db) + case 4: + migrateToSchema5(db) + default: + log.Fatalln("missing database migration step") + } + } + + _, err := db.Exec("UPDATE config SET value = ? WHERE key = ?", to, "version") + if err != nil { + return err + } + + return nil +} + // nolint:cyclop func migrateToSchema5(db *sql.DB) { // Create the access tokens table. diff --git a/core/data/persistence.go b/core/data/persistence.go index f8bf57bbe..3d1c81888 100644 --- a/core/data/persistence.go +++ b/core/data/persistence.go @@ -147,6 +147,8 @@ func (ds *Datastore) Setup() { if hasSetInitDate, _ := GetServerInitTime(); hasSetInitDate == nil || !hasSetInitDate.Valid { _ = SetServerInitTime(time.Now()) } + + migrateDatastoreValues(_datastore) } // Reset will delete all config entries in the datastore and start over. diff --git a/core/data/types.go b/core/data/types.go index 75e85cb3d..0da6c26c6 100644 --- a/core/data/types.go +++ b/core/data/types.go @@ -1,5 +1,20 @@ package data +// GetStringSlice will return the string slice value for a key. +func (ds *Datastore) GetStringSlice(key string) ([]string, error) { + configEntry, err := ds.Get(key) + if err != nil { + return []string{}, err + } + return configEntry.getStringSlice() +} + +// SetStringSlice will set the string slice value for a key. +func (ds *Datastore) SetStringSlice(key string, value []string) error { + configEntry := ConfigEntry{key, value} + return ds.Save(configEntry) +} + // GetString will return the string value for a key. func (ds *Datastore) GetString(key string) (string, error) { configEntry, err := ds.Get(key)