mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-11-16 06:44:24 +08:00
132 lines
3.5 KiB
Go
132 lines
3.5 KiB
Go
// Copyright 2026 Arctel.net
|
||
// SPDX-License-Identifier: Apache-2.0
|
||
|
||
package system_config
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"errors"
|
||
"time"
|
||
|
||
"github.com/Rain-kl/Wavelet/internal/infra/objectstore"
|
||
"github.com/Rain-kl/Wavelet/internal/model"
|
||
"github.com/Rain-kl/Wavelet/internal/repository"
|
||
"github.com/Rain-kl/Wavelet/pkg/logger"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
func createSystemConfig(ctx context.Context, req CreateSystemConfigRequest) error {
|
||
// 防御:受保护 key(log_database / log_db_migration)仅允许内部写入,Handler 已拦截。
|
||
if isProtectedConfigKey(req.Key) {
|
||
return errors.New(protectedConfigKeyMessage)
|
||
}
|
||
|
||
exists, err := repository.SystemConfigExists(ctx, req.Key)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if exists {
|
||
return errors.New(ConfigKeyExists)
|
||
}
|
||
|
||
config := model.SystemConfig{
|
||
Key: req.Key,
|
||
Value: req.Value,
|
||
Type: req.Type,
|
||
Visibility: req.Visibility,
|
||
Description: req.Description,
|
||
}
|
||
if err := repository.CreateSystemConfig(ctx, &config); err != nil {
|
||
return err
|
||
}
|
||
|
||
invalidateSystemConfigCaches(ctx, req.Key)
|
||
if err := repository.InvalidateVisibleSystemConfigsCache(ctx); err != nil {
|
||
logger.WarnF(ctx, "Failed to clear public configuration list cache: %v", err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func listSystemConfigs(ctx context.Context, configType string) ([]model.SystemConfig, error) {
|
||
return repository.ListAdminSystemConfigs(ctx, configType)
|
||
}
|
||
|
||
func getSystemConfig(ctx context.Context, key string) (model.SystemConfig, error) {
|
||
return repository.GetAdminSystemConfigByKey(ctx, key)
|
||
}
|
||
|
||
func updateSystemConfig(ctx context.Context, key string, req UpdateSystemConfigRequest) error {
|
||
config, err := repository.GetAdminSystemConfigByKey(ctx, key)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
var originalDriver objectstore.Driver
|
||
if key == model.ConfigKeyStorageConfig {
|
||
var currentCfg objectstore.Config
|
||
if err := json.Unmarshal([]byte(config.Value), ¤tCfg); err == nil {
|
||
originalDriver = currentCfg.Driver
|
||
}
|
||
|
||
validatedVal, err := validateAndMergeStorageConfig(ctx, req.Value, config.Value)
|
||
if err != nil {
|
||
return &storageConfigValidationError{err}
|
||
}
|
||
req.Value = validatedVal
|
||
}
|
||
|
||
if err := repository.RunInTransaction(ctx, func(tx *gorm.DB) error {
|
||
updates := map[string]any{
|
||
"description": req.Description,
|
||
}
|
||
if req.Visibility != nil {
|
||
updates["visibility"] = *req.Visibility
|
||
config.Visibility = *req.Visibility
|
||
}
|
||
if key != model.ConfigKeySMTPPassword || req.Value != maskedConfigValue {
|
||
updates["value"] = req.Value
|
||
config.Value = req.Value
|
||
}
|
||
if err := repository.UpdateSystemConfigFieldsTx(tx, &config, updates); err != nil {
|
||
return err
|
||
}
|
||
resolveStorageMigrationTasksOnDirectDriverUpdate(ctx, tx, key, originalDriver, req.Value)
|
||
return nil
|
||
}); err != nil {
|
||
return err
|
||
}
|
||
|
||
invalidateCachesAfterConfigUpdate(ctx, key)
|
||
return nil
|
||
}
|
||
|
||
func resolveStorageMigrationTasksOnDirectDriverUpdate(
|
||
ctx context.Context,
|
||
tx *gorm.DB,
|
||
key string,
|
||
originalDriver objectstore.Driver,
|
||
newValue string,
|
||
) {
|
||
if key != model.ConfigKeyStorageConfig || originalDriver == "" {
|
||
return
|
||
}
|
||
|
||
var newCfg objectstore.Config
|
||
if err := json.Unmarshal([]byte(newValue), &newCfg); err != nil {
|
||
return
|
||
}
|
||
if newCfg.Driver != originalDriver {
|
||
return
|
||
}
|
||
|
||
if err := repository.MarkFailedTaskExecutionsSucceededTx(
|
||
tx,
|
||
"storage:migrate",
|
||
"Storage configuration updated directly; failed migration task marked as resolved",
|
||
time.Now(),
|
||
); err != nil {
|
||
logger.ErrorF(ctx, "Failed to automatically update migration task status: %v", err)
|
||
}
|
||
}
|