From 2ccda1932249eb7e99dbfeb9e7a90643f86f8974 Mon Sep 17 00:00:00 2001 From: ferhat elmas Date: Sun, 26 Jul 2026 04:04:08 +0200 Subject: [PATCH] fix: advanced site settings setup from migration 30 Signed-off-by: ferhat elmas --- internal/migrations/migrations.go | 1 + internal/migrations/v35.go | 72 +++++++++++++++++++++ internal/migrations/v35_test.go | 101 ++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 internal/migrations/v35.go create mode 100644 internal/migrations/v35_test.go diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go index 59fbb7bea..360f688af 100644 --- a/internal/migrations/migrations.go +++ b/internal/migrations/migrations.go @@ -110,6 +110,7 @@ var migrations = []Migration{ NewMigration("v2.0.1", "change avatar type to text", updateAvatarType, false), NewMigration("v2.0.2", "add reasoning content to ai conversation record", addAIConversationReasoningContent, false), NewMigration("v2.0.3", "add require email verification login setting", addRequireEmailVerification, true), + NewMigration("v2.0.4", "repair missing advanced site settings", repairAdvancedSiteInfo, true), } func GetMigrations() []Migration { diff --git a/internal/migrations/v35.go b/internal/migrations/v35.go new file mode 100644 index 000000000..f63037cc9 --- /dev/null +++ b/internal/migrations/v35.go @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package migrations + +import ( + "context" + "encoding/json" + + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "xorm.io/builder" + "xorm.io/xorm" +) + +func repairAdvancedSiteInfo(ctx context.Context, x *xorm.Engine) error { + advanced := &entity.SiteInfo{} + exists, err := x.Context(ctx).Where(builder.Eq{"type": constant.SiteTypeAdvanced}).Get(advanced) + if err != nil { + return err + } + if exists { + return nil + } + + write := &entity.SiteInfo{} + exists, err = x.Context(ctx).Where(builder.Eq{"type": constant.SiteTypeWrite}).Get(write) + if err != nil { + return err + } + if !exists { + return nil + } + + siteWrite := &schema.SiteWriteResp{} + if err := json.Unmarshal([]byte(write.Content), siteWrite); err != nil { + return err + } + content, err := json.Marshal(&schema.SiteAdvancedResp{ + MaxImageSize: siteWrite.MaxImageSize, + MaxAttachmentSize: siteWrite.MaxAttachmentSize, + MaxImageMegapixel: siteWrite.MaxImageMegapixel, + AuthorizedImageExtensions: siteWrite.AuthorizedImageExtensions, + AuthorizedAttachmentExtensions: siteWrite.AuthorizedAttachmentExtensions, + }) + if err != nil { + return err + } + _, err = x.Context(ctx).Insert(&entity.SiteInfo{ + Type: constant.SiteTypeAdvanced, + Content: string(content), + Status: 1, + }) + return err +} diff --git a/internal/migrations/v35_test.go b/internal/migrations/v35_test.go new file mode 100644 index 000000000..7c065e933 --- /dev/null +++ b/internal/migrations/v35_test.go @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package migrations + +import ( + "context" + "testing" + + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "xorm.io/xorm" +) + +func TestRepairAdvancedSiteInfoAddsMissingSettings(t *testing.T) { + x, err := xorm.NewEngine("sqlite", ":memory:") + require.NoError(t, err) + defer func() { + _ = x.Close() + }() + require.NoError(t, x.Sync(new(entity.SiteInfo))) + + _, err = x.Insert(&entity.SiteInfo{ + Type: constant.SiteTypeWrite, + Content: `{"max_image_size":5}`, + Status: 1, + }) + require.NoError(t, err) + + var repairMigration Migration + for _, m := range GetMigrations() { + if m.Version() == "v2.0.4" { + repairMigration = m + break + } + } + require.NotNil(t, repairMigration) + require.NoError(t, repairMigration.Migrate(context.Background(), x)) + + advanced := &entity.SiteInfo{} + exists, err := x.Where("type = ?", constant.SiteTypeAdvanced).Get(advanced) + require.NoError(t, err) + require.True(t, exists) + assert.JSONEq(t, `{ + "max_image_size": 5, + "max_attachment_size": 0, + "max_image_megapixel": 0, + "authorized_image_extensions": null, + "authorized_attachment_extensions": null + }`, advanced.Content) +} + +func TestRepairAdvancedSiteInfoPreservesExistingSettings(t *testing.T) { + x, err := xorm.NewEngine("sqlite", ":memory:") + require.NoError(t, err) + defer func() { + _ = x.Close() + }() + require.NoError(t, x.Sync(new(entity.SiteInfo))) + + const existingContent = `{"max_image_size":99}` + _, err = x.Insert( + &entity.SiteInfo{ + Type: constant.SiteTypeWrite, + Content: `{invalid`, + Status: 1, + }, + &entity.SiteInfo{ + Type: constant.SiteTypeAdvanced, + Content: existingContent, + Status: 1, + }, + ) + require.NoError(t, err) + + require.NoError(t, repairAdvancedSiteInfo(context.Background(), x)) + + advanced := &entity.SiteInfo{} + exists, err := x.Where("type = ?", constant.SiteTypeAdvanced).Get(advanced) + require.NoError(t, err) + require.True(t, exists) + assert.JSONEq(t, existingContent, advanced.Content) +}