feat: H1 to H2 setting with the admin save conversion (tracer)
- content_h1_to_h2 and generic_anchors on the settings row (migration
202610280001), Headings and links tab, config key
golem15.journal.content_h1_to_h2 used when no settings row exists
- classes.ConvertH1 on the x/net/html tokenizer; the Blog Editor types
convert while the setting is on and answer editor.h1_converted
- GET /posts/{slug} reports content_h1_to_h2 (additive key)
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package updates
|
||||
|
||||
import (
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// addSettingsHeadings adds the Headings and links settings to the
|
||||
// golem15_journal_settings row: content_h1_to_h2 (on by default, so a site
|
||||
// keeps converting H1 in Journal rich text to H2) and generic_anchors (the
|
||||
// link texts the editor warns about, one per line; NULL means the built-in
|
||||
// lists). Adding the columns rewrites no stored content.
|
||||
var addSettingsHeadings = []*gormigrate.Migration{
|
||||
{
|
||||
ID: "202610280001_add_golem15_journal_settings_headings",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
for _, stmt := range []string{
|
||||
`ALTER TABLE golem15_journal_settings ADD COLUMN content_h1_to_h2 BOOLEAN NOT NULL DEFAULT TRUE`,
|
||||
`ALTER TABLE golem15_journal_settings ADD COLUMN generic_anchors TEXT NULL`,
|
||||
} {
|
||||
if err := tx.Exec(stmt).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Rollback: func(tx *gorm.DB) error {
|
||||
for _, stmt := range []string{
|
||||
`ALTER TABLE golem15_journal_settings DROP COLUMN IF EXISTS generic_anchors`,
|
||||
`ALTER TABLE golem15_journal_settings DROP COLUMN IF EXISTS content_h1_to_h2`,
|
||||
} {
|
||||
if err := tx.Exec(stmt).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(addSettingsHeadings...)
|
||||
}
|
||||
@@ -28,9 +28,20 @@ func TestCategoryContentMigration(t *testing.T) {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
|
||||
all := All()
|
||||
if last := all[len(all)-1].ID; last != "202610090001_add_content_to_golem15_journal_categories" {
|
||||
t.Fatalf("last migration = %s, want 202610090001_add_content_to_golem15_journal_categories", last)
|
||||
// The content column's step and the one before it: later migrations
|
||||
// are rolled back with it, so the test does not depend on being last.
|
||||
const contentStep = "202610090001_add_content_to_golem15_journal_categories"
|
||||
previous := ""
|
||||
for i, mig := range All() {
|
||||
if mig.ID == contentStep {
|
||||
if i == 0 {
|
||||
t.Fatalf("%s is the first migration", contentStep)
|
||||
}
|
||||
previous = All()[i-1].ID
|
||||
}
|
||||
}
|
||||
if previous == "" {
|
||||
t.Fatalf("migration %s is not registered", contentStep)
|
||||
}
|
||||
if !gdb.Migrator().HasColumn("golem15_journal_categories", "content") {
|
||||
t.Fatal("golem15_journal_categories.content missing")
|
||||
@@ -49,8 +60,8 @@ func TestCategoryContentMigration(t *testing.T) {
|
||||
if err := gdb.Exec(`UPDATE golem15_journal_categories SET content = '<p>x</p>' WHERE slug = 'uncategorized'`).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := m.RollbackLast(); err != nil {
|
||||
t.Fatalf("rollback last: %v", err)
|
||||
if err := m.RollbackTo(previous); err != nil {
|
||||
t.Fatalf("rollback to %s: %v", previous, err)
|
||||
}
|
||||
if !gdb.Migrator().HasTable("golem15_journal_categories") {
|
||||
t.Fatal("golem15_journal_categories dropped by the content rollback")
|
||||
|
||||
72
updates/settings_headings_migration_test.go
Normal file
72
updates/settings_headings_migration_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package updates
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/lagoon"
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
)
|
||||
|
||||
// TestSettingsHeadingsMigration checks the Headings and links columns:
|
||||
// content_h1_to_h2 defaults to true on the existing settings row,
|
||||
// generic_anchors is NULL, and the rollback drops both and keeps the row.
|
||||
func TestSettingsHeadingsMigration(t *testing.T) {
|
||||
sqlDB := dedicatedDB(t, fmt.Sprintf("journal_settings_headings_%d", time.Now().UnixNano()))
|
||||
gdb, err := lagoon.Use(t.Context(), sqlDB)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
backend := gormigrate.New(gdb, &gormigrate.Options{
|
||||
TableName: "summer_migrations_summercms_cabana",
|
||||
UseTransaction: true,
|
||||
}, lagoon.BackendAdminMigrations)
|
||||
if err := backend.Migrate(); err != nil {
|
||||
t.Fatalf("backend_users migrations: %v", err)
|
||||
}
|
||||
m := journalMigrator(gdb)
|
||||
if err := m.Migrate(); err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
assertUdt(t, gdb, "golem15_journal_settings", "content_h1_to_h2", "bool")
|
||||
assertUdt(t, gdb, "golem15_journal_settings", "generic_anchors", "text")
|
||||
var on bool
|
||||
var anchors sql.NullString
|
||||
if err := gdb.Raw(`SELECT content_h1_to_h2, generic_anchors FROM golem15_journal_settings WHERE id = 1`).Row().Scan(&on, &anchors); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !on || anchors.Valid {
|
||||
t.Fatalf("settings row: content_h1_to_h2 = %v, generic_anchors = %v, want true and NULL", on, anchors)
|
||||
}
|
||||
|
||||
const step = "202610280001_add_golem15_journal_settings_headings"
|
||||
previous := ""
|
||||
for i, mig := range All() {
|
||||
if mig.ID == step && i > 0 {
|
||||
previous = All()[i-1].ID
|
||||
}
|
||||
}
|
||||
if previous == "" {
|
||||
t.Fatalf("migration %s is not registered after another step", step)
|
||||
}
|
||||
if err := m.RollbackTo(previous); err != nil {
|
||||
t.Fatalf("rollback to %s: %v", previous, err)
|
||||
}
|
||||
for _, column := range []string{"content_h1_to_h2", "generic_anchors"} {
|
||||
if gdb.Migrator().HasColumn("golem15_journal_settings", column) {
|
||||
t.Fatalf("%s survived rollback", column)
|
||||
}
|
||||
}
|
||||
var rows int64
|
||||
if err := gdb.Raw(`SELECT COUNT(*) FROM golem15_journal_settings WHERE id = 1`).Scan(&rows).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if rows != 1 {
|
||||
t.Fatalf("settings rows after rollback = %d, want 1", rows)
|
||||
}
|
||||
if err := m.Migrate(); err != nil {
|
||||
t.Fatalf("re-migrate: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user