mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-03-30 10:34:20 +00:00
Unify the setup initialization endpoint’s error contract to match the rest
of the project and keep the frontend unchanged.
Changes
- controller/setup.go: Return HTTP 200 with {success:false, message} for all
predictable errors in POST /api/setup, including:
- already initialized
- invalid payload
- username too long
- password mismatch
- password too short
- password hashing failure
- root user creation failure
- option persistence failures (SelfUseModeEnabled, DemoSiteEnabled)
- setup record creation failure
- web/src/components/setup/SetupWizard.jsx: Restore catch handler to the
previous generic toast (frontend logic unchanged).
- web/src/helpers/utils.jsx: Restore the original showError implementation
(no Axios response.data parsing required).
Why
- Keep API behavior consistent across endpoints so the UI can rely on the
success flag and message in the normal .then() flow instead of falling
into Axios 4xx errors that only show a generic "400".
Impact
- UI now displays specific server messages during initialization without
frontend adaptations.
- Note: clients relying solely on HTTP status codes for error handling
should inspect the JSON body (success/message) instead.
No changes to the happy path; initialization success responses are unchanged.
181 lines
3.8 KiB
Go
181 lines
3.8 KiB
Go
package controller
|
|
|
|
import (
|
|
"github.com/gin-gonic/gin"
|
|
"one-api/common"
|
|
"one-api/constant"
|
|
"one-api/model"
|
|
"one-api/setting/operation_setting"
|
|
"time"
|
|
)
|
|
|
|
type Setup struct {
|
|
Status bool `json:"status"`
|
|
RootInit bool `json:"root_init"`
|
|
DatabaseType string `json:"database_type"`
|
|
}
|
|
|
|
type SetupRequest struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
ConfirmPassword string `json:"confirmPassword"`
|
|
SelfUseModeEnabled bool `json:"SelfUseModeEnabled"`
|
|
DemoSiteEnabled bool `json:"DemoSiteEnabled"`
|
|
}
|
|
|
|
func GetSetup(c *gin.Context) {
|
|
setup := Setup{
|
|
Status: constant.Setup,
|
|
}
|
|
if constant.Setup {
|
|
c.JSON(200, gin.H{
|
|
"success": true,
|
|
"data": setup,
|
|
})
|
|
return
|
|
}
|
|
setup.RootInit = model.RootUserExists()
|
|
if common.UsingMySQL {
|
|
setup.DatabaseType = "mysql"
|
|
}
|
|
if common.UsingPostgreSQL {
|
|
setup.DatabaseType = "postgres"
|
|
}
|
|
if common.UsingSQLite {
|
|
setup.DatabaseType = "sqlite"
|
|
}
|
|
c.JSON(200, gin.H{
|
|
"success": true,
|
|
"data": setup,
|
|
})
|
|
}
|
|
|
|
func PostSetup(c *gin.Context) {
|
|
// Check if setup is already completed
|
|
if constant.Setup {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "系统已经初始化完成",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Check if root user already exists
|
|
rootExists := model.RootUserExists()
|
|
|
|
var req SetupRequest
|
|
err := c.ShouldBindJSON(&req)
|
|
if err != nil {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "请求参数有误",
|
|
})
|
|
return
|
|
}
|
|
|
|
// If root doesn't exist, validate and create admin account
|
|
if !rootExists {
|
|
// Validate username length: max 12 characters to align with model.User validation
|
|
if len(req.Username) > 12 {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "用户名长度不能超过12个字符",
|
|
})
|
|
return
|
|
}
|
|
// Validate password
|
|
if req.Password != req.ConfirmPassword {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "两次输入的密码不一致",
|
|
})
|
|
return
|
|
}
|
|
|
|
if len(req.Password) < 8 {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "密码长度至少为8个字符",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Create root user
|
|
hashedPassword, err := common.Password2Hash(req.Password)
|
|
if err != nil {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "系统错误: " + err.Error(),
|
|
})
|
|
return
|
|
}
|
|
rootUser := model.User{
|
|
Username: req.Username,
|
|
Password: hashedPassword,
|
|
Role: common.RoleRootUser,
|
|
Status: common.UserStatusEnabled,
|
|
DisplayName: "Root User",
|
|
AccessToken: nil,
|
|
Quota: 100000000,
|
|
}
|
|
err = model.DB.Create(&rootUser).Error
|
|
if err != nil {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "创建管理员账号失败: " + err.Error(),
|
|
})
|
|
return
|
|
}
|
|
}
|
|
|
|
// Set operation modes
|
|
operation_setting.SelfUseModeEnabled = req.SelfUseModeEnabled
|
|
operation_setting.DemoSiteEnabled = req.DemoSiteEnabled
|
|
|
|
// Save operation modes to database for persistence
|
|
err = model.UpdateOption("SelfUseModeEnabled", boolToString(req.SelfUseModeEnabled))
|
|
if err != nil {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "保存自用模式设置失败: " + err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
err = model.UpdateOption("DemoSiteEnabled", boolToString(req.DemoSiteEnabled))
|
|
if err != nil {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "保存演示站点模式设置失败: " + err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Update setup status
|
|
constant.Setup = true
|
|
|
|
setup := model.Setup{
|
|
Version: common.Version,
|
|
InitializedAt: time.Now().Unix(),
|
|
}
|
|
err = model.DB.Create(&setup).Error
|
|
if err != nil {
|
|
c.JSON(200, gin.H{
|
|
"success": false,
|
|
"message": "系统初始化失败: " + err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(200, gin.H{
|
|
"success": true,
|
|
"message": "系统初始化成功",
|
|
})
|
|
}
|
|
|
|
func boolToString(b bool) string {
|
|
if b {
|
|
return "true"
|
|
}
|
|
return "false"
|
|
} |