Refactor user bootstrap

Signed-off-by: Sean Du <do4suki@gmail.com>
This commit is contained in:
2026-04-28 19:59:27 +08:00
parent 7a3ac35566
commit 581990a52f
6 changed files with 169 additions and 70 deletions
+142 -67
View File
@@ -11,6 +11,7 @@ import (
unitapischema "honoka-chan/internal/schema/api/unit" unitapischema "honoka-chan/internal/schema/api/unit"
ghomeschema "honoka-chan/internal/schema/ghome" ghomeschema "honoka-chan/internal/schema/ghome"
"honoka-chan/internal/session" "honoka-chan/internal/session"
"honoka-chan/pkg/db"
"honoka-chan/pkg/utils" "honoka-chan/pkg/utils"
"net/url" "net/url"
"strconv" "strconv"
@@ -21,6 +22,15 @@ import (
"github.com/go-think/openssl" "github.com/go-think/openssl"
) )
const (
defaultUserID = 377385143
defaultAwardID = 113 // 极推穗乃果
defaultBackgroundID = 65 // 穗乃果的房间
defaultUnitID = 338 // 高坂穂乃果 直到那天来临
defaultUserName = "梦路"
defaultUserDesc = "你好。"
)
func login(ctx *gin.Context) { func login(ctx *gin.Context) {
ss := session.New(ctx) ss := session.New(ctx)
defer ss.Finalize() defer ss.Finalize()
@@ -58,24 +68,74 @@ func login(ctx *gin.Context) {
return return
} }
var userID int loginData, loginCode, loginMsg, _, err := AddUser(phone, password, false)
var pass, autoKey, ticket string
_, err = ss.UserEng.Table("users").Cols("password,autokey,ticket,user_id").
Where("phone = ?", phone).Get(&pass, &autoKey, &ticket, &userID)
if ss.CheckErr(err) { if ss.CheckErr(err) {
return return
} }
data, err = json.Marshal(loginData)
if ss.CheckErr(err) {
return
}
encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey, openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
}
ss.Respond(ghomeschema.LoginResp{
Code: loginCode,
Msg: loginMsg,
Data: base64.StdEncoding.EncodeToString(encryptedData),
})
}
func AddUser(phone, password string, isDefault bool) (ghomeschema.LoginData, int, string, bool, error) {
loginData := ghomeschema.LoginData{} loginData := ghomeschema.LoginData{}
loginCode := 0 loginCode := 0
loginMsg := "ok" loginMsg := "ok"
loginTime := time.Now().Unix() loginTime := time.Now().Unix()
created := false
var userID int
var pass, autoKey, ticket string
session := db.UserEng.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
return loginData, loginCode, loginMsg, created, err
}
_, err := session.Table("users").Cols("password,autokey,ticket,user_id").
Where("phone = ?", phone).Get(&pass, &autoKey, &ticket, &userID)
if err != nil {
session.Rollback()
return loginData, loginCode, loginMsg, created, err
}
if pass == "" { if pass == "" {
// 未注册 - 自动注册 // 未注册 - 自动注册
awardID := 1 // 音乃木坂学生
backgroundID := 1 // 初始背景
unitID := 31 // 初始高坂穂乃果
userName := "音乃木坂学生"
userDesc := "你好。"
// 是否初始化
if isDefault {
// 初始化默认用户
userID = defaultUserID
awardID = defaultAwardID
backgroundID = defaultBackgroundID
unitID = defaultUnitID
userName = defaultUserName
userDesc = defaultUserDesc
} else {
// 检查是否 userID 已经注册 // 检查是否 userID 已经注册
userID, err = getAvailableUserID(ss, int(loginTime)) userID, err = getAvailableUserID(int(loginTime))
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
}
} }
pass = openssl.Md5ToString(password) pass = openssl.Md5ToString(password)
@@ -90,10 +150,12 @@ func login(ctx *gin.Context) {
UserID: userID, UserID: userID,
LastLoginTime: loginTime, LastLoginTime: loginTime,
} }
_, err = ss.UserEng.Table("users").Insert(&userData) _, err = session.Table("users").Insert(&userData)
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
created = true
// 方便起见初始化 userid 和 key 一样 // 方便起见初始化 userid 和 key 一样
// 注意:user_key 表中的 key 是上文生成的用于登录的 userid,而 userid 则是用于 Authorize Token 生成用的 // 注意:user_key 表中的 key 是上文生成的用于登录的 userid,而 userid 则是用于 Authorize Token 生成用的
@@ -101,23 +163,26 @@ func login(ctx *gin.Context) {
UserID: userID, UserID: userID,
Key: userID, Key: userID,
} }
_, err = ss.UserEng.Table("user_key").Insert(&userKey) _, err = session.Table("user_key").Insert(&userKey)
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
// 检查用户配置 // 检查用户配置
exists, err := ss.UserEng.Table("user_pref").Where("user_id = ?", userID).Exist() exists, err := session.Table("user_pref").Where("user_id = ?", userID).Exist()
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
if !exists { if !exists {
// 生成用于卡片 // 生成用于卡片
var unitData []unitmodel.CommonUnitData var unitData []unitmodel.CommonUnitData
err = ss.UserEng.Table(new(unitmodel.CommonUnitData)).Find(&unitData) err = session.Table(new(unitmodel.CommonUnitData)).Find(&unitData)
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
checked := false checked := false
@@ -128,58 +193,65 @@ func login(ctx *gin.Context) {
DisplayRank: u.MaxRank, DisplayRank: u.MaxRank,
UserID: userID, UserID: userID,
InsertDate: time.Now().Unix(), InsertDate: time.Now().Unix(),
UpdateDate: time.Now().Unix(),
} }
// 检查表里是否已经有数据 // 检查表里是否已经有数据
if !checked { if !checked {
ct, err := ss.UserEng.Table(new(usermodel.UserUnitData)).Count() ct, err := session.Table(new(usermodel.UserUnitData)).Count()
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
if ct == 0 { if ct == 0 {
userUnit.UnitOwningUserID = 38383 userUnit.UnitOwningUserID = 38383
} }
}
_, err = session.Table(new(usermodel.UserUnitData)).Insert(&userUnit)
if err != nil {
session.Rollback()
return loginData, loginCode, loginMsg, created, err
}
checked = true checked = true
} }
_, err = ss.UserEng.Table(new(usermodel.UserUnitData)).Insert(&userUnit)
if ss.CheckErr(err) {
return
}
}
// 默认中心成员 // 默认中心成员
var unitOwningUserID int var unitOwningUserID int
_, err = ss.UserEng.Table(new(usermodel.UserUnitData)). _, err = session.Table(new(usermodel.UserUnitData)).
Cols("unit_owning_user_id").Where("unit_id = ?", 31).Get(&unitOwningUserID) Cols("unit_owning_user_id").
if ss.CheckErr(err) { Where("user_id = ?", userID).
return Where("unit_id = ?", unitID).
Get(&unitOwningUserID)
if err != nil {
session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
userPref := usermodel.UserPref{ userPref := usermodel.UserPref{
UserID: userID, UserID: userID,
AwardID: 1, // 音乃木坂学生 AwardID: awardID,
BackgroundID: 1, // 初始背景 BackgroundID: backgroundID,
UnitOwningUserID: unitOwningUserID, UnitOwningUserID: unitOwningUserID,
UserName: "音乃木坂学生", UserName: userName,
UserLevel: 1028, UserLevel: 1028,
UserDesc: "你好。", UserDesc: userDesc,
InviteCode: strconv.Itoa(userID), InviteCode: strconv.Itoa(userID),
UpdateTime: time.Now().Unix(), UpdateTime: time.Now().Unix(),
} }
_, err = ss.UserEng.Table("user_pref").Insert(&userPref) _, err = session.Table("user_pref").Insert(&userPref)
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
} }
// 检查用户卡组配置 // 检查用户卡组配置
exists, err = ss.UserEng.Table("user_deck").Where("user_id = ?", userID).Exist() exists, err = session.Table("user_deck").Where("user_id = ?", userID).Exist()
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
if !exists { if !exists {
@@ -191,15 +263,24 @@ func login(ctx *gin.Context) {
UserID: userID, UserID: userID,
InsertDate: time.Now().Unix(), InsertDate: time.Now().Unix(),
} }
_, err = ss.UserEng.Table("user_deck").Insert(&userDeck) _, err = session.Table("user_deck").Insert(&userDeck)
if err != nil {
session.Rollback()
return loginData, loginCode, loginMsg, created, err
}
userDeckID := userDeck.ID userDeckID := userDeck.ID
// 默认卡组 - 仆光 // 默认卡组 - 仆光
unitID := []int{3465, 3466, 3467, 3468, 3469, 3470, 3471, 3472, 3473} unitID := []int{3465, 3466, 3467, 3468, 3469, 3470, 3471, 3472, 3473}
var unitData []unitmodel.UnitDataMap var unitData []unitmodel.UnitDataMap
err = ss.GetBasicUnitInfo().In("a.unit_id", unitID).Find(&unitData) err = session.Table("user_unit_data").Alias("a").
if ss.CheckErr(err) { Join("LEFT", "common_unit_data", "a.unit_id = common_unit_data.unit_id").
return Cols(`a.unit_owning_user_id,a.favorite_flag,a.display_rank,common_unit_data.*`).
Where("a.user_id = ?", userID).
In("a.unit_id", unitID).Find(&unitData)
if err != nil {
session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
for i, u := range unitData { for i, u := range unitData {
@@ -222,9 +303,10 @@ func login(ctx *gin.Context) {
UserID: userID, UserID: userID,
InsertDate: time.Now().Unix(), InsertDate: time.Now().Unix(),
} }
_, err = ss.UserEng.Table("user_deck_unit").Insert(&unitDeckData) _, err = session.Table("user_deck_unit").Insert(&unitDeckData)
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
} }
} }
@@ -247,9 +329,10 @@ func login(ctx *gin.Context) {
Ticket: ticket, Ticket: ticket,
LastLoginTime: loginTime, LastLoginTime: loginTime,
} }
_, err = ss.UserEng.Table("users").Where("user_id = ?", userID).Update(&userData) _, err = session.Table("users").Where("user_id = ?", userID).Update(&userData)
if ss.CheckErr(err) { if err != nil {
return session.Rollback()
return loginData, loginCode, loginMsg, created, err
} }
loginData.Autokey = autoKey // 注意:更换设备(deviceId 发生变化)应重新生成 autokey loginData.Autokey = autoKey // 注意:更换设备(deviceId 发生变化)应重新生成 autokey
@@ -262,28 +345,20 @@ func login(ctx *gin.Context) {
} }
} }
data, err = json.Marshal(loginData) if err := session.Commit(); err != nil {
if ss.CheckErr(err) { session.Rollback()
return return loginData, loginCode, loginMsg, created, err
}
encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey, openssl.PKCS7_PADDING)
if ss.CheckErr(err) {
return
} }
ss.Respond(ghomeschema.LoginResp{ return loginData, loginCode, loginMsg, created, nil
Code: loginCode,
Msg: loginMsg,
Data: base64.StdEncoding.EncodeToString(encryptedData),
})
} }
func getAvailableUserID(ss *session.Session, seed int) (int, error) { func getAvailableUserID(seed int) (int, error) {
const maxAttempts = 16 const maxAttempts = 16
userID := seed userID := seed
for attempt := range maxAttempts { for attempt := range maxAttempts {
exist, err := ss.UserEng.Table("users").Where("user_id = ?", userID).Exist() exist, err := db.UserEng.Table("users").Where("user_id = ?", userID).Exist()
if err != nil { if err != nil {
return 0, err return 0, err
} }
-1
View File
@@ -94,7 +94,6 @@ func upload(ctx *gin.Context) {
DisplayRank: uData.MaxRank, DisplayRank: uData.MaxRank,
UserID: ctx.GetInt("userid"), UserID: ctx.GetInt("userid"),
InsertDate: time.Now().Unix(), InsertDate: time.Now().Unix(),
UpdateDate: time.Now().Unix(),
} }
_, err = session.Table(new(usermodel.UserUnitData)).Insert(&unitData) _, err = session.Table(new(usermodel.UserUnitData)).Insert(&unitData)
-1
View File
@@ -7,5 +7,4 @@ type UserUnitData struct {
DisplayRank int `xorm:"display_rank"` DisplayRank int `xorm:"display_rank"`
UserID int `xorm:"user_id"` UserID int `xorm:"user_id"`
InsertDate int64 `xorm:"insert_date"` InsertDate int64 `xorm:"insert_date"`
UpdateDate int64 `xorm:"update_date"`
} }
-1
View File
@@ -193,7 +193,6 @@ func LoadUnitData() {
DisplayRank: u.RankMax, DisplayRank: u.RankMax,
UserID: id, UserID: id,
InsertDate: time.Now().Unix(), InsertDate: time.Now().Unix(),
UpdateDate: time.Now().Unix(),
} }
// 检查表里是否已经有数据 // 检查表里是否已经有数据
+26
View File
@@ -0,0 +1,26 @@
package startup
import (
"honoka-chan/internal/handler/ghome/account"
"log"
)
const (
defaultPhone = "86-1"
defaultPassword = "klsbgames"
)
func CreateDefaultUser() {
_, code, msg, created, err := account.AddUser(defaultPhone, defaultPassword, true)
if err != nil {
log.Fatalln("默认用户创建失败:", err.Error())
}
if code != 0 {
log.Fatalf("默认用户创建失败: code=%d msg=%s", code, msg)
}
if created {
log.Printf("默认用户创建成功, 账号: %s, 密码: %s\n", defaultPhone, defaultPassword)
return
}
log.Printf("默认用户已存在, 账号: %s\n", defaultPhone)
}
+1
View File
@@ -3,4 +3,5 @@ package startup
func StartUp() { func StartUp() {
CreateTables() CreateTables()
LoadUnitData() LoadUnitData()
CreateDefaultUser()
} }