Some checks are pending
Security Checks / security (push) Waiting to run
统一 frontend、backend、test、test-log 和 out 目录,更新构建、部署及测试入口;纳入配置管理兼容与首次安全引导修复;排除本机配置、密钥和测试产物。
103 lines
3.3 KiB
Go
103 lines
3.3 KiB
Go
package controllers
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"git.pcux.cn/xuans/Smail/config"
|
|
"git.pcux.cn/xuans/Smail/dto/response"
|
|
"git.pcux.cn/xuans/Smail/services/access"
|
|
"git.pcux.cn/xuans/Smail/services/dbmigration"
|
|
appcontext "git.pcux.cn/xuans/Smail/utils/context"
|
|
)
|
|
|
|
type databaseMigrationPreviewRequest struct {
|
|
TargetName string `json:"targetName"`
|
|
ExpectedGeneration uint64 `json:"expectedGeneration"`
|
|
}
|
|
|
|
type databaseMigrationExecuteRequest struct {
|
|
ID string `json:"id"`
|
|
Token string `json:"token"`
|
|
}
|
|
|
|
// PreviewDatabaseMigration 校验只改数据库名称的迁移计划,不连接或修改目标数据库。
|
|
func PreviewDatabaseMigration(ctx *appcontext.Context, w http.ResponseWriter, req *http.Request) {
|
|
if err := authorizeCapability(ctx, access.CapabilityDatabaseMigrate, "", false); err != nil {
|
|
writeConfigAccessError(w, err)
|
|
return
|
|
}
|
|
manager, ok := configManagerOrError(w)
|
|
if !ok {
|
|
return
|
|
}
|
|
service := dbmigration.Current()
|
|
if service == nil {
|
|
writeConfigError(w, dbmigration.ErrExecutorUnavailable)
|
|
return
|
|
}
|
|
var input databaseMigrationPreviewRequest
|
|
if err := decodeJSONRequest(w, req, &input); err != nil || input.ExpectedGeneration == 0 {
|
|
writeConfigError(w, dbmigration.ErrInvalidRequest)
|
|
return
|
|
}
|
|
status := manager.Status()
|
|
if input.ExpectedGeneration != status.ActiveGeneration {
|
|
writeConfigError(w, config.ErrGenerationConflict)
|
|
return
|
|
}
|
|
record, token, err := service.Preview(req.Context(), manager.Snapshot().Root.Database, status.ActiveGeneration, input.TargetName)
|
|
if err != nil {
|
|
writeConfigError(w, err)
|
|
return
|
|
}
|
|
response.NewSuccessResponse(map[string]any{"migration": record, "token": token}).FPrint(w)
|
|
}
|
|
|
|
// ExecuteDatabaseMigration 执行预览票据对应的固定迁移计划,不接受 DSN、SQL 或连接参数。
|
|
func ExecuteDatabaseMigration(ctx *appcontext.Context, w http.ResponseWriter, req *http.Request) {
|
|
if err := authorizeCapability(ctx, access.CapabilityDatabaseMigrate, "", false); err != nil {
|
|
writeConfigAccessError(w, err)
|
|
return
|
|
}
|
|
if dbmigration.Current() == nil {
|
|
writeConfigError(w, dbmigration.ErrExecutorUnavailable)
|
|
return
|
|
}
|
|
var input databaseMigrationExecuteRequest
|
|
if err := decodeJSONRequest(w, req, &input); err != nil {
|
|
writeConfigError(w, dbmigration.ErrInvalidRequest)
|
|
return
|
|
}
|
|
record, err := dbmigration.Current().ExecuteAuthorized(req.Context(), input.ID, input.Token, configActor(ctx, req))
|
|
if err != nil {
|
|
writeConfigError(w, err)
|
|
return
|
|
}
|
|
response.NewSuccessResponse(record).FPrint(w)
|
|
}
|
|
|
|
// GetDatabaseMigration 返回迁移状态,不返回密码、密钥或底层数据库错误。
|
|
func GetDatabaseMigration(ctx *appcontext.Context, w http.ResponseWriter, req *http.Request) {
|
|
if err := authorizeCapability(ctx, access.CapabilityDatabaseMigrate, "", false); err != nil {
|
|
writeConfigAccessError(w, err)
|
|
return
|
|
}
|
|
service := dbmigration.Current()
|
|
if service == nil {
|
|
writeConfigError(w, dbmigration.ErrExecutorUnavailable)
|
|
return
|
|
}
|
|
parts := strings.Split(strings.Trim(req.URL.Path, "/"), "/")
|
|
if len(parts) != 5 || parts[0] != "api" || parts[1] != "v1" || parts[2] != "database" || parts[3] != "migrations" || strings.TrimSpace(parts[4]) == "" {
|
|
writeConfigError(w, dbmigration.ErrInvalidRequest)
|
|
return
|
|
}
|
|
record, err := service.Get(parts[4])
|
|
if err != nil {
|
|
writeConfigError(w, err)
|
|
return
|
|
}
|
|
response.NewSuccessResponse(record).FPrint(w)
|
|
}
|