From 34c450d2e67a5381b95bdec8ec7bd1c1dfb23abd Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 08:54:36 -0800 Subject: [PATCH 01/10] add to db --- pkg/database/migrations.go | 10 ++++++++++ pkg/database/realm.go | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/database/migrations.go b/pkg/database/migrations.go index 9017c097f..5dd7d58f4 100644 --- a/pkg/database/migrations.go +++ b/pkg/database/migrations.go @@ -1801,6 +1801,16 @@ func (db *Database) getMigrations(ctx context.Context) *gormigrate.Gormigrate { return nil }, }, + { + ID: "00075-AddAlternateSMSTemplates", + Migrate: func(tx *gorm.DB) error { + sql := `ALTER TABLE realms ADD COLUMN IF NOT EXISTS alternate_sms_templates text[]` + return tx.Exec(sql).Error + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("ALTER TABLE realms DROP COLUMN IF EXISTS alternate_sms_templates").Error + }, + }, }) } diff --git a/pkg/database/realm.go b/pkg/database/realm.go index da44c277a..644e1bcbb 100644 --- a/pkg/database/realm.go +++ b/pkg/database/realm.go @@ -140,7 +140,8 @@ type Realm struct { LongCodeDuration DurationSeconds `gorm:"type:bigint; not null; default: 86400"` // default 24h // SMS configuration - SMSTextTemplate string `gorm:"type:text; not null; default: 'This is your Exposure Notifications Verification code: [longcode] Expires in [longexpires] hours'"` + SMSTextTemplate string `gorm:"type:text; not null; default: 'This is your Exposure Notifications Verification code: [longcode] Expires in [longexpires] hours'"` + SMSTextAlternateTemplates pq.StringArray `gorm:"column:alternate_sms_templates; type:text[];"` // SMSCountry is an optional field to hint the default phone picker country // code. From 85d56d2ca9cab89a169d4b801c8df4c3177bfdb0 Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 08:59:35 -0800 Subject: [PATCH 02/10] include labels --- pkg/database/migrations.go | 25 ++++++++++++++++++++++--- pkg/database/realm.go | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/pkg/database/migrations.go b/pkg/database/migrations.go index 5dd7d58f4..77bf826f6 100644 --- a/pkg/database/migrations.go +++ b/pkg/database/migrations.go @@ -1804,11 +1804,30 @@ func (db *Database) getMigrations(ctx context.Context) *gormigrate.Gormigrate { { ID: "00075-AddAlternateSMSTemplates", Migrate: func(tx *gorm.DB) error { - sql := `ALTER TABLE realms ADD COLUMN IF NOT EXISTS alternate_sms_templates text[]` - return tx.Exec(sql).Error + sqls := []string{ + "ALTER TABLE realms ADD COLUMN IF NOT EXISTS alternate_sms_templates text[]", + "ALTER TABLE realms ADD COLUMN IF NOT EXISTS alternate_sms_labels varchar(50)[]", + } + + for _, sql := range sqls { + if err := tx.Exec(sql).Error; err != nil { + return err + } + } + return nil }, Rollback: func(tx *gorm.DB) error { - return tx.Exec("ALTER TABLE realms DROP COLUMN IF EXISTS alternate_sms_templates").Error + sqls := []string{ + `ALTER TABLE realms DROP COLUMN IF EXISTS alternate_sms_templates`, + `ALTER TABLE realms DROP COLUMN IF EXISTS alternate_sms_labels`, + } + + for _, sql := range sqls { + if err := tx.Exec(sql).Error; err != nil { + return err + } + } + return nil }, }, }) diff --git a/pkg/database/realm.go b/pkg/database/realm.go index 644e1bcbb..9404d7392 100644 --- a/pkg/database/realm.go +++ b/pkg/database/realm.go @@ -141,6 +141,7 @@ type Realm struct { // SMS configuration SMSTextTemplate string `gorm:"type:text; not null; default: 'This is your Exposure Notifications Verification code: [longcode] Expires in [longexpires] hours'"` + SMSTextAlternateLabels pq.StringArray `gorm:"column:alternate_sms_labels; type:varchar(50)[];"` SMSTextAlternateTemplates pq.StringArray `gorm:"column:alternate_sms_templates; type:text[];"` // SMSCountry is an optional field to hint the default phone picker country From 241f740d2520ac0653975764544b00e5f376bc39 Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 09:07:11 -0800 Subject: [PATCH 03/10] validation --- pkg/database/realm.go | 50 +++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/pkg/database/realm.go b/pkg/database/realm.go index 9404d7392..0b5c2c0a6 100644 --- a/pkg/database/realm.go +++ b/pkg/database/realm.go @@ -364,27 +364,14 @@ func (r *Realm) BeforeSave(tx *gorm.DB) error { r.AddError("longCodeDuration", "must be no more than 24 hours") } - if r.EnableENExpress { - if !strings.Contains(r.SMSTextTemplate, SMSENExpressLink) { - r.AddError("SMSTextTemplate", fmt.Sprintf("must contain %q", SMSENExpressLink)) - } - if strings.Contains(r.SMSTextTemplate, SMSRegion) { - r.AddError("SMSTextTemplate", fmt.Sprintf("cannot contain %q - this is automatically included in %q", SMSRegion, SMSENExpressLink)) - } - if strings.Contains(r.SMSTextTemplate, SMSCode) { - r.AddError("SMSTextTemplate", fmt.Sprintf("cannot contain %q - the long code is automatically included in %q", SMSCode, SMSENExpressLink)) - } - if strings.Contains(r.SMSTextTemplate, SMSExpires) { - r.AddError("SMSTextTemplate", fmt.Sprintf("cannot contain %q - only the %q is allowed for expiration", SMSExpires, SMSLongExpires)) - } - if strings.Contains(r.SMSTextTemplate, SMSLongCode) { - r.AddError("SMSTextTemplate", fmt.Sprintf("cannot contain %q - the long code is automatically included in %q", SMSLongCode, SMSENExpressLink)) + r.ValidateSMSTemplate(r.SMSTextTemplate) + if r.SMSTextAlternateTemplates != nil { + if r.SMSTextAlternateLabels == nil || len(r.SMSTextAlternateLabels) != len(r.SMSTextAlternateTemplates) { + r.AddError("smsAlternateLabels", "every alternate SMS template must have a label") } - } else { - // Check that we have exactly one of [code] or [longcode] as template substitutions. - if c, lc := strings.Contains(r.SMSTextTemplate, "[code]"), strings.Contains(r.SMSTextTemplate, "[longcode]"); !(c || lc) || (c && lc) { - r.AddError("SMSTextTemplate", "must contain exactly one of [code] or [longcode]") + for _, t := range r.SMSTextAlternateTemplates { + r.ValidateSMSTemplate(t) } } @@ -446,6 +433,31 @@ func (r *Realm) BeforeSave(tx *gorm.DB) error { return nil } +func (r *Realm) ValidateSMSTemplate(t string) { + if r.EnableENExpress { + if !strings.Contains(t, SMSENExpressLink) { + r.AddError("SMSTextTemplate", fmt.Sprintf("must contain %q", SMSENExpressLink)) + } + if strings.Contains(t, SMSRegion) { + r.AddError("SMSTextTemplate", fmt.Sprintf("cannot contain %q - this is automatically included in %q", SMSRegion, SMSENExpressLink)) + } + if strings.Contains(t, SMSCode) { + r.AddError("SMSTextTemplate", fmt.Sprintf("cannot contain %q - the long code is automatically included in %q", SMSCode, SMSENExpressLink)) + } + if strings.Contains(t, SMSExpires) { + r.AddError("SMSTextTemplate", fmt.Sprintf("cannot contain %q - only the %q is allowed for expiration", SMSExpires, SMSLongExpires)) + } + if strings.Contains(t, SMSLongCode) { + r.AddError("SMSTextTemplate", fmt.Sprintf("cannot contain %q - the long code is automatically included in %q", SMSLongCode, SMSENExpressLink)) + } + } else { + // Check that we have exactly one of [code] or [longcode] as template substitutions. + if c, lc := strings.Contains(t, "[code]"), strings.Contains(t, "[longcode]"); !(c || lc) || (c && lc) { + r.AddError("SMSTextTemplate", "must contain exactly one of [code] or [longcode]") + } + } +} + // GetCodeDurationMinutes is a helper for the HTML rendering to get a round // minutes value. func (r *Realm) GetCodeDurationMinutes() int { From 379f83679d3d8b6c82f11e8797e642e2dd6e7a35 Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 09:35:12 -0800 Subject: [PATCH 04/10] unit test --- pkg/database/realm.go | 7 +++---- pkg/database/realm_test.go | 43 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/pkg/database/realm.go b/pkg/database/realm.go index 0b5c2c0a6..31bb81900 100644 --- a/pkg/database/realm.go +++ b/pkg/database/realm.go @@ -364,14 +364,13 @@ func (r *Realm) BeforeSave(tx *gorm.DB) error { r.AddError("longCodeDuration", "must be no more than 24 hours") } - r.ValidateSMSTemplate(r.SMSTextTemplate) + r.validateSMSTemplate(r.SMSTextTemplate) if r.SMSTextAlternateTemplates != nil { if r.SMSTextAlternateLabels == nil || len(r.SMSTextAlternateLabels) != len(r.SMSTextAlternateTemplates) { r.AddError("smsAlternateLabels", "every alternate SMS template must have a label") } - for _, t := range r.SMSTextAlternateTemplates { - r.ValidateSMSTemplate(t) + r.validateSMSTemplate(t) } } @@ -433,7 +432,7 @@ func (r *Realm) BeforeSave(tx *gorm.DB) error { return nil } -func (r *Realm) ValidateSMSTemplate(t string) { +func (r *Realm) validateSMSTemplate(t string) { if r.EnableENExpress { if !strings.Contains(t, SMSENExpressLink) { r.AddError("SMSTextTemplate", fmt.Sprintf("must contain %q", SMSENExpressLink)) diff --git a/pkg/database/realm_test.go b/pkg/database/realm_test.go index 575b19a48..69bbf9783 100644 --- a/pkg/database/realm_test.go +++ b/pkg/database/realm_test.go @@ -46,6 +46,49 @@ func TestSMS(t *testing.T) { } } +func TestRealm_SMSTemplateValidation(t *testing.T) { + t.Parallel() + + db, _ := testDatabaseInstance.NewDatabase(t, nil) + valid := "State of Wonder, COVID-19 Exposure Verification code [code]. Expires in [expires] minutes. Act now!" + + realm := NewRealmWithDefaults("test") + if err := db.SaveRealm(realm, SystemTest); err != nil { + t.Fatalf("error saving realm: %v", err) + } + + realm.SMSTextTemplate = "No expansions. Should fail." + if err := db.SaveRealm(realm, SystemTest); err == nil { + t.Fatal("expected invalid: sms template, must contain [code] or [longcode]") + } + + realm.errors = make(map[string][]string) + realm.SMSTextTemplate = valid + if err := db.SaveRealm(realm, SystemTest); err != nil { + t.Fatalf("error saving realm: %v", err) + } + + realm.errors = make(map[string][]string) + realm.SMSTextAlternateTemplates = []string{valid} + if err := db.SaveRealm(realm, SystemTest); err == nil { + t.Fatal("expected invalid: alternate SMS template must have a label") + } + + realm.errors = make(map[string][]string) + realm.SMSTextAlternateTemplates = []string{"No expansions. Should fail."} + realm.SMSTextAlternateLabels = []string{"alternate label 1"} + if err := db.SaveRealm(realm, SystemTest); err == nil { + t.Fatal("expected invalid: sms template, must contain [code] or [longcode]l") + } + + realm.errors = make(map[string][]string) + realm.SMSTextAlternateTemplates = []string{valid} + realm.SMSTextAlternateLabels = []string{"alternate label 1"} + if err := db.SaveRealm(realm, SystemTest); err != nil { + t.Fatalf("error saving realm: %v", err) + } +} + func TestPerUserRealmStats(t *testing.T) { t.Parallel() From 04af3478c7a1ccfdc3e83d690396538e948924ea Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 09:42:40 -0800 Subject: [PATCH 05/10] retrieve realm in test --- pkg/database/realm_test.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pkg/database/realm_test.go b/pkg/database/realm_test.go index 69bbf9783..baf516830 100644 --- a/pkg/database/realm_test.go +++ b/pkg/database/realm_test.go @@ -51,6 +51,7 @@ func TestRealm_SMSTemplateValidation(t *testing.T) { db, _ := testDatabaseInstance.NewDatabase(t, nil) valid := "State of Wonder, COVID-19 Exposure Verification code [code]. Expires in [expires] minutes. Act now!" + label := "alternate label 1" realm := NewRealmWithDefaults("test") if err := db.SaveRealm(realm, SystemTest); err != nil { @@ -76,17 +77,31 @@ func TestRealm_SMSTemplateValidation(t *testing.T) { realm.errors = make(map[string][]string) realm.SMSTextAlternateTemplates = []string{"No expansions. Should fail."} - realm.SMSTextAlternateLabels = []string{"alternate label 1"} + realm.SMSTextAlternateLabels = []string{label} if err := db.SaveRealm(realm, SystemTest); err == nil { t.Fatal("expected invalid: sms template, must contain [code] or [longcode]l") } realm.errors = make(map[string][]string) realm.SMSTextAlternateTemplates = []string{valid} - realm.SMSTextAlternateLabels = []string{"alternate label 1"} + realm.SMSTextAlternateLabels = []string{label} if err := db.SaveRealm(realm, SystemTest); err != nil { t.Fatalf("error saving realm: %v", err) } + + realm, err := db.FindRealm(realm.ID) + if err != nil { + t.Fatalf("error retrieving realm: %v", err) + } + if realm.SMSTextTemplate != valid { + t.Fatalf("Template not set. got %s want %s.", realm.SMSTextTemplate, valid) + } + if realm.SMSTextAlternateLabels[0] != label { + t.Fatalf("Alternate labels not set. got %s want %s.", realm.SMSTextAlternateTemplates[0], label) + } + if realm.SMSTextAlternateTemplates[0] != valid { + t.Fatalf("Alternate template not set. got %s want %s.", realm.SMSTextAlternateTemplates[0], valid) + } } func TestPerUserRealmStats(t *testing.T) { From ee0f80c36f02ec03aaa9d8bfc50567032e1e2081 Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 11:47:21 -0800 Subject: [PATCH 06/10] Switch to hstore --- pkg/database/migrations.go | 36 ++++++++++++------------------------ pkg/database/realm.go | 17 +++++++++-------- pkg/database/realm_test.go | 23 +++++++---------------- 3 files changed, 28 insertions(+), 48 deletions(-) diff --git a/pkg/database/migrations.go b/pkg/database/migrations.go index 77bf826f6..1872b7aa9 100644 --- a/pkg/database/migrations.go +++ b/pkg/database/migrations.go @@ -37,7 +37,8 @@ func (db *Database) getMigrations(ctx context.Context) *gormigrate.Gormigrate { { ID: initState, Migrate: func(tx *gorm.DB) error { - return nil + // Create required extensions on new DB so AutoMigrate doesn't fail. + return tx.Exec("CREATE EXTENSION hstore").Error }, Rollback: func(tx *gorm.DB) error { return nil @@ -1802,32 +1803,19 @@ func (db *Database) getMigrations(ctx context.Context) *gormigrate.Gormigrate { }, }, { - ID: "00075-AddAlternateSMSTemplates", + ID: "00075-EnableExtension_hstore", Migrate: func(tx *gorm.DB) error { - sqls := []string{ - "ALTER TABLE realms ADD COLUMN IF NOT EXISTS alternate_sms_templates text[]", - "ALTER TABLE realms ADD COLUMN IF NOT EXISTS alternate_sms_labels varchar(50)[]", - } - - for _, sql := range sqls { - if err := tx.Exec(sql).Error; err != nil { - return err - } - } - return nil + logger.Debugw("enabling hstore extension") + return tx.Exec("CREATE EXTENSION IF NOT EXISTS hstore").Error + }, + }, + { + ID: "00076-AddAlternateSMSTemplates", + Migrate: func(tx *gorm.DB) error { + return tx.Exec(`ALTER TABLE realms ADD COLUMN IF NOT EXISTS alternate_sms_templates hstore`).Error }, Rollback: func(tx *gorm.DB) error { - sqls := []string{ - `ALTER TABLE realms DROP COLUMN IF EXISTS alternate_sms_templates`, - `ALTER TABLE realms DROP COLUMN IF EXISTS alternate_sms_labels`, - } - - for _, sql := range sqls { - if err := tx.Exec(sql).Error; err != nil { - return err - } - } - return nil + return tx.Exec(`ALTER TABLE realms DROP COLUMN IF EXISTS alternate_sms_templates`).Error }, }, }) diff --git a/pkg/database/realm.go b/pkg/database/realm.go index 31bb81900..543b9ff0e 100644 --- a/pkg/database/realm.go +++ b/pkg/database/realm.go @@ -34,6 +34,7 @@ import ( "github.com/microcosm-cc/bluemonday" "github.com/jinzhu/gorm" + "github.com/jinzhu/gorm/dialects/postgres" "github.com/lib/pq" "github.com/russross/blackfriday/v2" ) @@ -140,9 +141,8 @@ type Realm struct { LongCodeDuration DurationSeconds `gorm:"type:bigint; not null; default: 86400"` // default 24h // SMS configuration - SMSTextTemplate string `gorm:"type:text; not null; default: 'This is your Exposure Notifications Verification code: [longcode] Expires in [longexpires] hours'"` - SMSTextAlternateLabels pq.StringArray `gorm:"column:alternate_sms_labels; type:varchar(50)[];"` - SMSTextAlternateTemplates pq.StringArray `gorm:"column:alternate_sms_templates; type:text[];"` + SMSTextTemplate string `gorm:"type:text; not null; default: 'This is your Exposure Notifications Verification code: [longcode] Expires in [longexpires] hours'"` + SMSTextAlternateTemplates postgres.Hstore `gorm:"column:alternate_sms_templates; type:hstore"` // SMSCountry is an optional field to hint the default phone picker country // code. @@ -366,11 +366,12 @@ func (r *Realm) BeforeSave(tx *gorm.DB) error { r.validateSMSTemplate(r.SMSTextTemplate) if r.SMSTextAlternateTemplates != nil { - if r.SMSTextAlternateLabels == nil || len(r.SMSTextAlternateLabels) != len(r.SMSTextAlternateTemplates) { - r.AddError("smsAlternateLabels", "every alternate SMS template must have a label") - } - for _, t := range r.SMSTextAlternateTemplates { - r.validateSMSTemplate(t) + for l, t := range r.SMSTextAlternateTemplates { + if t == nil { + r.AddError("SMSTextAlternateTemplates", fmt.Sprintf("no template for label %s", l)) + continue + } + r.validateSMSTemplate(*t) } } diff --git a/pkg/database/realm_test.go b/pkg/database/realm_test.go index baf516830..f2fac86c9 100644 --- a/pkg/database/realm_test.go +++ b/pkg/database/realm_test.go @@ -51,14 +51,15 @@ func TestRealm_SMSTemplateValidation(t *testing.T) { db, _ := testDatabaseInstance.NewDatabase(t, nil) valid := "State of Wonder, COVID-19 Exposure Verification code [code]. Expires in [expires] minutes. Act now!" - label := "alternate label 1" + invalid := "No expansions. Should fail." + label := "alternate label" realm := NewRealmWithDefaults("test") if err := db.SaveRealm(realm, SystemTest); err != nil { t.Fatalf("error saving realm: %v", err) } - realm.SMSTextTemplate = "No expansions. Should fail." + realm.SMSTextTemplate = invalid if err := db.SaveRealm(realm, SystemTest); err == nil { t.Fatal("expected invalid: sms template, must contain [code] or [longcode]") } @@ -70,21 +71,14 @@ func TestRealm_SMSTemplateValidation(t *testing.T) { } realm.errors = make(map[string][]string) - realm.SMSTextAlternateTemplates = []string{valid} - if err := db.SaveRealm(realm, SystemTest); err == nil { - t.Fatal("expected invalid: alternate SMS template must have a label") - } + realm.SMSTextAlternateTemplates = map[string]*string{label: &invalid} - realm.errors = make(map[string][]string) - realm.SMSTextAlternateTemplates = []string{"No expansions. Should fail."} - realm.SMSTextAlternateLabels = []string{label} if err := db.SaveRealm(realm, SystemTest); err == nil { t.Fatal("expected invalid: sms template, must contain [code] or [longcode]l") } realm.errors = make(map[string][]string) - realm.SMSTextAlternateTemplates = []string{valid} - realm.SMSTextAlternateLabels = []string{label} + realm.SMSTextAlternateTemplates = map[string]*string{label: &valid} if err := db.SaveRealm(realm, SystemTest); err != nil { t.Fatalf("error saving realm: %v", err) } @@ -96,11 +90,8 @@ func TestRealm_SMSTemplateValidation(t *testing.T) { if realm.SMSTextTemplate != valid { t.Fatalf("Template not set. got %s want %s.", realm.SMSTextTemplate, valid) } - if realm.SMSTextAlternateLabels[0] != label { - t.Fatalf("Alternate labels not set. got %s want %s.", realm.SMSTextAlternateTemplates[0], label) - } - if realm.SMSTextAlternateTemplates[0] != valid { - t.Fatalf("Alternate template not set. got %s want %s.", realm.SMSTextAlternateTemplates[0], valid) + if *realm.SMSTextAlternateTemplates[label] != valid { + t.Fatalf("Alternate template not set. got %s want %s.", *realm.SMSTextAlternateTemplates[label], valid) } } From 9f8176cc3f77d8b9694526e00f36465fdb6f5bb9 Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 12:07:38 -0800 Subject: [PATCH 07/10] name --- pkg/database/realm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/database/realm_test.go b/pkg/database/realm_test.go index cc5b96145..b62121154 100644 --- a/pkg/database/realm_test.go +++ b/pkg/database/realm_test.go @@ -215,7 +215,7 @@ func TestValidation(t *testing.T) { { Name: "alternate_sms_template valid", Input: &Realm{ - Name: "a", + Name: "b", CodeLength: 6, LongCodeLength: 12, EnableENExpress: false, From 0051e437e012b5eb26401d8d8c3ec312fd8505c5 Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 12:09:32 -0800 Subject: [PATCH 08/10] if not exists --- pkg/database/migrations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/database/migrations.go b/pkg/database/migrations.go index 1872b7aa9..5cad4ba57 100644 --- a/pkg/database/migrations.go +++ b/pkg/database/migrations.go @@ -38,7 +38,7 @@ func (db *Database) getMigrations(ctx context.Context) *gormigrate.Gormigrate { ID: initState, Migrate: func(tx *gorm.DB) error { // Create required extensions on new DB so AutoMigrate doesn't fail. - return tx.Exec("CREATE EXTENSION hstore").Error + return tx.Exec("CREATE EXTENSION IF NOT EXISTS hstore").Error }, Rollback: func(tx *gorm.DB) error { return nil From 9e5d08ccd28db75d755bf518895f77b7bec1c540 Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Fri, 11 Dec 2020 12:10:35 -0800 Subject: [PATCH 09/10] needless log --- pkg/database/migrations.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/database/migrations.go b/pkg/database/migrations.go index 5cad4ba57..22fd3de33 100644 --- a/pkg/database/migrations.go +++ b/pkg/database/migrations.go @@ -1805,7 +1805,6 @@ func (db *Database) getMigrations(ctx context.Context) *gormigrate.Gormigrate { { ID: "00075-EnableExtension_hstore", Migrate: func(tx *gorm.DB) error { - logger.Debugw("enabling hstore extension") return tx.Exec("CREATE EXTENSION IF NOT EXISTS hstore").Error }, }, From e748e01506e64f86866e2d310b86866a7bccb3b7 Mon Sep 17 00:00:00 2001 From: Weston Haught Date: Mon, 14 Dec 2020 08:43:39 -0800 Subject: [PATCH 10/10] review things --- pkg/database/migrations.go | 4 ++-- pkg/database/realm.go | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pkg/database/migrations.go b/pkg/database/migrations.go index d970f6eff..0660fb127 100644 --- a/pkg/database/migrations.go +++ b/pkg/database/migrations.go @@ -1829,13 +1829,13 @@ func (db *Database) getMigrations(ctx context.Context) *gormigrate.Gormigrate { }, }, { - ID: "00075-EnableExtension_hstore", + ID: "00076-EnableExtension_hstore", Migrate: func(tx *gorm.DB) error { return tx.Exec("CREATE EXTENSION IF NOT EXISTS hstore").Error }, }, { - ID: "00076-AddAlternateSMSTemplates", + ID: "00077-AddAlternateSMSTemplates", Migrate: func(tx *gorm.DB) error { return tx.Exec(`ALTER TABLE realms ADD COLUMN IF NOT EXISTS alternate_sms_templates hstore`).Error }, diff --git a/pkg/database/realm.go b/pkg/database/realm.go index d3a9f2613..68dbbc85f 100644 --- a/pkg/database/realm.go +++ b/pkg/database/realm.go @@ -363,8 +363,12 @@ func (r *Realm) BeforeSave(tx *gorm.DB) error { r.validateSMSTemplate(r.SMSTextTemplate) if r.SMSTextAlternateTemplates != nil { for l, t := range r.SMSTextAlternateTemplates { - if t == nil { - r.AddError("SMSTextAlternateTemplates", fmt.Sprintf("no template for label %s", l)) + if t == nil || *t == "" { + r.AddError("SMSTextTemplate", fmt.Sprintf("no template for label %s", l)) + continue + } + if l == "" { + r.AddError("SMSTextTemplate", fmt.Sprintf("no label for template %s", *t)) continue } r.validateSMSTemplate(*t) @@ -425,6 +429,8 @@ func (r *Realm) BeforeSave(tx *gorm.DB) error { return nil } +// validateSMSTemplate is a helper method to validate a single SMSTemplate. +// Errors are returned by appending them to the realm's Errorable fields. func (r *Realm) validateSMSTemplate(t string) { if r.EnableENExpress { if !strings.Contains(t, SMSENExpressLink) { @@ -446,7 +452,7 @@ func (r *Realm) validateSMSTemplate(t string) { // Check template length. if l := len(t); l > SMSTemplateMaxLength { - r.AddError("SMSTextTemplate", fmt.Sprintf("must be %v characters or less, current message is %v characters long", SMSTemplateMaxLength, l)) + r.AddError("SMSTextTemplate", fmt.Sprintf("must be %d characters or less, current message is %v characters long", SMSTemplateMaxLength, l)) } }