Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
@@ -0,0 +1,16 @@
package sysconfmod
import "testing"
func TestFreeTrialBadgeConfigDefaultEnabled(t *testing.T) {
for _, item := range initData {
if item.VCode != string(VCodeFreeTrialBadgeEnabled) {
continue
}
if item.Type != CfgTypeBool || item.Value != "true" {
t.Fatalf("unexpected free trial badge config: type=%s value=%s", item.Type, item.Value)
}
return
}
t.Fatal("freeTrialBadgeEnabled config is not initialized")
}
@@ -0,0 +1,22 @@
package sysconfmod
import "testing"
func TestPaymentGuideConfigDefaultsEnabled(t *testing.T) {
found := make(map[VCode]bool)
for _, item := range initData {
code := VCode(item.VCode)
if code != VCodePaymentGuideEnabled && code != VCodePaymentGuideHomeEnabled {
continue
}
if item.GpCode != string(GPCodePopup) || item.Type != CfgTypeBool || item.Value != "true" {
t.Fatalf("unexpected payment guide config %s: group=%s type=%s value=%s", code, item.GpCode, item.Type, item.Value)
}
found[code] = true
}
for _, code := range []VCode{VCodePaymentGuideEnabled, VCodePaymentGuideHomeEnabled} {
if !found[code] {
t.Fatalf("%s config is not initialized", code)
}
}
}
@@ -0,0 +1,16 @@
package sysconfmod
import "testing"
func TestShortDramaCardConfigIsInitializedAsSelect(t *testing.T) {
for _, item := range initData {
if item.VCode != string(VCodeShortDramaCardID) {
continue
}
if item.Type != CfgTypeSelect {
t.Fatalf("short drama card config type = %q, want %q", item.Type, CfgTypeSelect)
}
return
}
t.Fatal("short drama card config is missing from initData")
}
+178
View File
@@ -0,0 +1,178 @@
package sysconfmod
import (
"91porn-server/common/db"
"91porn-server/common/log"
"encoding/json"
"errors"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// GetAllConfig 获取全部配置
func GetAllConfig() (res ConfMap, err error) {
var data []SysConf
if err = coll(nil).Find(&data, bson.M{}, options.Find().SetSort(bson.D{{Key: "_id", Value: -1}})); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetByGCode", table, "Find", err))
return res, err
}
if len(data) == 0 {
return res, errors.New("record not found")
}
res = make(ConfMap, len(data))
for _, v := range data {
res[v.VCode] = v.Value
}
return
}
// BatchGetInfoByVCode 按 vCode 列表批量获取配置项
func BatchGetInfoByVCode(vCodes []VCode) (res []SysConf, err error) {
if err = coll(nil).Find(&res, bson.M{"vCode": bson.M{"$in": vCodes}}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "BatchGetInfoByVCode", table, "Find", err),
log.Any("vCodes", vCodes),
)
return nil, err
}
if len(res) == 0 {
return nil, errors.New("record not found")
}
return
}
// GetByVCode 获取单个配置项。
func GetByVCode(code VCode) (*SysConf, error) {
var out SysConf
if err := coll(nil).FindOne(&out, bson.M{"vCode": string(code)}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetByVCode", table, "FindOne", err),
log.Any("vCode", code),
)
return nil, err
}
if out.ID.IsZero() {
return nil, errors.New("record not found")
}
return &out, nil
}
// GetByGpCode 获取分组配置
func GetByGpCode(code GPCode) (res ConfMap, err error) {
var data []SysConf
if err = coll(nil).Find(&data, bson.M{"gpCode": code}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetByGCode", table, "Find", err),
log.Any("gpCode", code),
)
return nil, err
}
if len(data) == 0 {
return nil, errors.New("record not found")
}
res = make(ConfMap, len(data))
for _, v := range data {
res[v.VCode] = v.Value
}
return
}
// GetAll 查询全部文档
func GetAll(filter primitive.M, sort bson.D) (out []*SysConf, err error) {
if len(sort) == 0 {
sort = bson.D{{Key: "_id", Value: -1}}
}
opts := options.Find().SetSort(sort)
// 检查 filter 是否为空
if filter == nil {
filter = primitive.M{}
}
// 使用切片初始化 out
out = make([]*SysConf, 0)
if err = coll(nil).Find(&out, filter, opts); err != nil {
log.Error("[METHOD-GetAll] Model "+table+" Find fail error:"+err.Error(),
log.Any("filter", filter),
log.Any("opts", opts),
)
return nil, err
}
return
}
// GetInfo 通过id获取详细信息
func GetInfo(id primitive.ObjectID) (SysConf, error) {
v := SysConf{}
if err := coll(nil).FindOne(&v, bson.M{"_id": id}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetInfo", table, "FindOne", err),
log.Any("id", id),
)
return v, err
}
if v.ID.IsZero() {
return v, errors.New("record not found")
}
return v, nil
}
// Insert 插入记录
func Insert(t *db.MongoTool, d SysConf) (data primitive.ObjectID, err error) {
result, err := coll(t).InsertOne(&d)
if err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Insert", table, "InsertOne", err))
return
}
byteID, err := json.Marshal(result.InsertedID)
if err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Insert", table, "Marshal", err))
return
}
if err = data.UnmarshalJSON(byteID); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Insert", table, "UnmarshalJSON", err))
return
}
return
}
// UpdateByID 根据id更新数据
func UpdateByID(t *db.MongoTool, id primitive.ObjectID, data map[string]interface{}) (int64, error) {
cond := bson.M{"_id": id}
return update(t, cond, data)
}
// update 更新数据
func update(t *db.MongoTool, cond primitive.M, data map[string]interface{}) (int64, error) {
result, err := coll(t).UpdateMany(cond, bson.M{"$set": bson.M(data)})
if err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Update", table, "UpdateMany", err),
log.Any("cond", cond),
log.Any("update", data),
)
return 0, err
}
return result.ModifiedCount, nil
}
// DeleteByID 删除数据
func DeleteByID(t *db.MongoTool, id primitive.ObjectID) error {
_, err := coll(t).DeleteOne(bson.M{"_id": id})
if err != nil {
if err == mongo.ErrNoDocuments {
return nil
} else {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DeleteByID", table, "DeleteOne", err), log.Any("id", id))
}
}
return err
}
+82
View File
@@ -0,0 +1,82 @@
package sysconfmod
import (
"91porn-server/common/log"
"encoding/json"
"strconv"
)
type ConfMap map[string]string
func (c ConfMap) getValue(code VCode) string {
obj, ok := c[string(code)]
if !ok {
log.Error("配置项 " + string(code) + " 未找到配置值!")
return ""
}
return obj
}
// GetStrSlice 获取字符串数组
func (c ConfMap) GetStrSlice(code VCode) []string {
var res []string
v := c.getValue(code)
err := json.Unmarshal([]byte(v), &res)
if err != nil {
log.Error("配置项 " + string(code) + " 不是有效的数组值!")
}
return res
}
// GetObject 对象类型配置
func (c ConfMap) GetObject(code VCode) map[string]string {
res := make(map[string]string)
v := c.getValue(code)
err := json.Unmarshal([]byte(v), &res)
if err != nil {
log.Error("配置项 " + string(code) + " 不是有效的对象值!")
}
return res
}
// GetString 字符串配置项
func (c ConfMap) GetString(code VCode) string {
return c.getValue(code)
}
// GetBool 布尔配置项
func (c ConfMap) GetBool(code VCode) bool {
v := c.getValue(code)
res, err := strconv.ParseBool(v)
if err != nil {
res = false
}
return res
}
// GetInt 数字型配置项
func (c ConfMap) GetInt(code VCode) int64 {
v := c.getValue(code)
res, err := strconv.ParseInt(v, 10, 64)
if err != nil {
res = 0
}
return res
}
// GetFloat 浮点型配置项
func (c ConfMap) GetFloat(code VCode) float64 {
v := c.getValue(code)
res, err := strconv.ParseFloat(v, 64)
if err != nil {
res = 0.00
}
return res
}
+121
View File
@@ -0,0 +1,121 @@
package sysconfmod
import (
"fmt"
"time"
"go.mongodb.org/mongo-driver/mongo/options"
"91porn-server/common/db"
"91porn-server/models"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
var mdb *db.MongoDB
const table = models.SysConf
const (
CfgTypeText = "text"
CfgTypeString = "string"
CfgTypeImg = "img"
CfgTypeObject = "object"
CfgTypeInt = "int"
CfgTypeFloat = "float"
CfgTypeBool = "bool"
CfgTypeTextArr = "text-array"
CfgTypeStrArr = "string-array"
CfgTypeSelect = "select"
)
type SysConf struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` // 文档id
GroupName string `json:"groupName" bson:"groupName"` // 分组名
GpCode string `json:"gpCode" bson:"gpCode"` // 分组编码
VCode string `json:"vCode" bson:"vCode"` // 变量名
Title string `json:"title" bson:"title"` // 变量标题
Tip string `json:"tip" bson:"tip"` // 变量描述
Type string `json:"type" bson:"type"` // 类型:text,string,img,int,bool,object,text-array,string-array
Value string `json:"value" bson:"value"` // 变量值
SelectValues []SelectItem `json:"selectValues" bson:"selectValues"` // 下拉框筛选项
IsRequired bool `json:"is_required" bson:"is_required"` // 是否必填
SortOrder int `json:"sort_order" bson:"sort_order"` // 排序值
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
type SelectItem struct {
Key string `json:"key" bson:"key"`
Value string `json:"value" bson:"value"`
}
func coll(t *db.MongoTool) *db.MongoTool {
if t == nil {
return mdb.Coll(table)
}
return t.Coll(table)
}
// Init 初始化索引
func Init() {
mdb = db.Init(table)
initIndex()
initConf()
}
func initIndex() {
many := []mongo.IndexModel{
{
Keys: bson.D{{Key: "gpCode", Value: 1}},
},
{
Keys: bson.D{{Key: "vCode", Value: 1}},
Options: options.Index().SetUnique(true),
},
}
if _, err := coll(nil).CreateIndex(many); err != nil {
panic(fmt.Sprintf("%s model set index err ==>[%+v]", table, err))
}
}
// initConf 初始化配置数据
func initConf() {
for _, d := range initData {
// 不存在则整条插入
if !isExists(d.VCode) {
d.CreatedAt = time.Now()
d.UpdatedAt = time.Now()
_, _ = Insert(nil, d)
continue
}
// 已存在则仅同步「描述类」元数据(分组/标题/描述/类型/是否必填/排序,
// 运营后台无法编辑这些字段,以代码为准),保留运营维护的 value 与 selectValues。
_, _ = update(nil, bson.M{"vCode": d.VCode}, map[string]interface{}{
"groupName": d.GroupName,
"gpCode": d.GpCode,
"title": d.Title,
"tip": d.Tip,
"type": d.Type,
"is_required": d.IsRequired,
"sort_order": d.SortOrder,
"updatedAt": time.Now(),
})
}
}
// EnsureInitData 暴露初始化配置入口,供启动后首次访问时补齐缺失配置。
func EnsureInitData() {
initConf()
}
func isExists(code string) bool {
count, err := coll(nil).Count(bson.M{"vCode": code})
if err != nil {
return false
}
return count > 0
}
+1395
View File
File diff suppressed because it is too large Load Diff