feat(banner): 首页常驻滚动通知 - 合并 PR #531 到本地
将常驻通知迁移顺延为 v20-v22,避免与已发布的 v19 支付插件版本冲突。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
commit
615974f1d9
36 files changed
+3379
-12
No files matched your search
@@ -11,7 +11,7 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const CurrentSchemaVersion int64 = 19
|
||||
const CurrentSchemaVersion int64 = 22
|
||||
|
||||
const baselineSchemaChecksum = "sha256:open-ai-canvas-schema-v1-20260830"
|
||||
const schemaMigrationAppliedAtIndexChecksum = "sha256:schema-migrations-applied-at-index-v2-20260830"
|
||||
@@ -77,6 +77,15 @@ var schemaMigrations = []migration{
|
||||
return tx.AutoMigrate(&model.AgentMemorySetting{})
|
||||
}},
|
||||
{version: 19, name: "payment_plugin_version", checksum: "sha256:payment-plugin-version-v19-20260917", apply: migrateSchemaV19},
|
||||
{version: 20, name: "banner_announcements", checksum: "sha256:banner-announcements-v20-20260917", apply: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.BannerAnnouncement{})
|
||||
}},
|
||||
{version: 21, name: "banner_announcement_title_runs", checksum: "sha256:banner-announcement-title-runs-v21-20260917", apply: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.BannerAnnouncement{})
|
||||
}},
|
||||
{version: 22, name: "banner_announcement_notice_type", checksum: "sha256:banner-announcement-notice-type-v22-20260917", apply: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.BannerAnnouncement{})
|
||||
}},
|
||||
}
|
||||
|
||||
func migrateSchemaV14(tx *gorm.DB) error {
|
||||
|
||||
@@ -47,6 +47,15 @@ func TestMigrateSchemaRecordsAndValidatesVersion(t *testing.T) {
|
||||
if !db.Migrator().HasColumn(&model.PaymentProviderConfig{}, "plugin_version") || !db.Migrator().HasColumn(&model.PaymentOrder{}, "plugin_version") {
|
||||
t.Fatal("schema migration v19 did not add payment plugin version columns")
|
||||
}
|
||||
if !db.Migrator().HasTable(&model.BannerAnnouncement{}) {
|
||||
t.Fatal("schema migration v20 did not create banner announcements")
|
||||
}
|
||||
if !db.Migrator().HasColumn(&model.BannerAnnouncement{}, "title_runs") {
|
||||
t.Fatal("schema migration v21 did not create banner announcements title_runs")
|
||||
}
|
||||
if !db.Migrator().HasColumn(&model.BannerAnnouncement{}, "notice_type") {
|
||||
t.Fatal("schema migration v22 did not create banner announcements notice_type")
|
||||
}
|
||||
if err := MigrateSchema(db); err != nil {
|
||||
t.Fatalf("migration should be idempotent: %v", err)
|
||||
}
|
||||
@@ -188,6 +197,116 @@ func TestMigrateSchemaV19AddsPaymentPluginVersion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateSchemaV20UpgradesExistingDatabaseWithBannerAnnouncements(t *testing.T) {
|
||||
db, err := Open(Config{Driver: "sqlite", DSN: "file:migration-banner-announcements-v20?mode=memory&cache=shared"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := MigrateSchema(db); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !db.Migrator().HasTable(&model.BannerAnnouncement{}) {
|
||||
t.Fatal("v20 migration did not create banner_announcements table")
|
||||
}
|
||||
// 模拟旧库升级:删表 + 删除 v20 记录,重跑迁移应能重建。
|
||||
if err := db.Migrator().DropTable(&model.BannerAnnouncement{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Where("version = ?", 20).Delete(&schemaMigration{}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := MigrateSchema(db); err != nil {
|
||||
t.Fatalf("upgrade from v19: %v", err)
|
||||
}
|
||||
if !db.Migrator().HasTable(&model.BannerAnnouncement{}) {
|
||||
t.Fatal("v20 upgrade did not reinstall banner_announcements table")
|
||||
}
|
||||
status, err := ReadSchemaStatus(db)
|
||||
if err != nil || !status.Ready || status.Current != CurrentSchemaVersion {
|
||||
t.Fatalf("unexpected upgraded schema status: %+v, %v", status, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateSchemaV21AddsBannerAnnouncementTitleRuns(t *testing.T) {
|
||||
db, err := Open(Config{Driver: "sqlite", DSN: "file:migration-banner-title-runs-v21?mode=memory&cache=shared"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := MigrateSchema(db); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !db.Migrator().HasColumn(&model.BannerAnnouncement{}, "title_runs") {
|
||||
t.Fatal("v21 migration did not add banner_announcements.title_runs")
|
||||
}
|
||||
legacy := &model.BannerAnnouncement{ID: "legacy-banner", Title: "旧库通知", Status: "active"}
|
||||
if err := db.Create(legacy).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Migrator().DropColumn(&model.BannerAnnouncement{}, "title_runs"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Where("version = ?", 21).Delete(&schemaMigration{}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := MigrateSchema(db); err != nil {
|
||||
t.Fatalf("upgrade from v20: %v", err)
|
||||
}
|
||||
if !db.Migrator().HasColumn(&model.BannerAnnouncement{}, "title_runs") {
|
||||
t.Fatal("v21 upgrade did not restore banner_announcements.title_runs")
|
||||
}
|
||||
var stored model.BannerAnnouncement
|
||||
if err := db.First(&stored, "id = ?", "legacy-banner").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if stored.Title != "旧库通知" {
|
||||
t.Fatalf("legacy banner lost during upgrade: %+v", stored)
|
||||
}
|
||||
status, err := ReadSchemaStatus(db)
|
||||
if err != nil || !status.Ready || status.Current != CurrentSchemaVersion {
|
||||
t.Fatalf("unexpected upgraded schema status: %+v, %v", status, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateSchemaV22AddsBannerAnnouncementNoticeType(t *testing.T) {
|
||||
db, err := Open(Config{Driver: "sqlite", DSN: "file:migration-banner-notice-type-v22?mode=memory&cache=shared"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := MigrateSchema(db); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !db.Migrator().HasColumn(&model.BannerAnnouncement{}, "notice_type") {
|
||||
t.Fatal("v22 migration did not add banner_announcements.notice_type")
|
||||
}
|
||||
legacy := &model.BannerAnnouncement{ID: "legacy-banner-v21", Title: "旧库通知", TitleRunsJSON: `[{"text":"旧库通知"}]`, Status: "active"}
|
||||
if err := db.Create(legacy).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Migrator().DropColumn(&model.BannerAnnouncement{}, "notice_type"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Where("version = ?", 22).Delete(&schemaMigration{}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := MigrateSchema(db); err != nil {
|
||||
t.Fatalf("upgrade from v21: %v", err)
|
||||
}
|
||||
if !db.Migrator().HasColumn(&model.BannerAnnouncement{}, "notice_type") {
|
||||
t.Fatal("v22 upgrade did not restore banner_announcements.notice_type")
|
||||
}
|
||||
var stored model.BannerAnnouncement
|
||||
if err := db.First(&stored, "id = ?", "legacy-banner-v21").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if stored.Title != "旧库通知" || stored.TitleRunsJSON != `[{"text":"旧库通知"}]` {
|
||||
t.Fatalf("legacy banner lost during upgrade: %+v", stored)
|
||||
}
|
||||
status, err := ReadSchemaStatus(db)
|
||||
if err != nil || !status.Ready || status.Current != CurrentSchemaVersion {
|
||||
t.Fatalf("unexpected upgraded schema status: %+v, %v", status, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateSchemaV8AllowsReusingArchivedLogicalModelCode(t *testing.T) {
|
||||
db, err := Open(Config{Driver: "sqlite", DSN: "file:migration-logical-model-active-code?mode=memory&cache=shared"})
|
||||
if err != nil {
|
||||
|
||||
@@ -91,6 +91,7 @@ func Models() []any {
|
||||
&model.UserPromptCustomization{},
|
||||
&model.Announcement{},
|
||||
&model.UserAnnouncementRead{},
|
||||
&model.BannerAnnouncement{},
|
||||
&model.Task{},
|
||||
&model.CreationRun{},
|
||||
&model.CreationSubmission{},
|
||||
|
||||
Reference in new issue
Block a user