@@ -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")
|
||||
}
|
||||
Executable
+178
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Executable
+121
@@ -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
|
||||
}
|
||||
Executable
+1395
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user