Initial commit: web_hghl_server

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 16:28:14 +08:00
co-authored by Claude Opus 4.7
commit 65fca60622
653 changed files with 135901 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
package actress
import (
"context"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 表名
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.Actress)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Alias, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.Alias, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.Rank, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.UpdatedAt, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.Works, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.Works, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.HotValue, Value: -1},
{Key: FN.Actress.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.Real.WeekWatchs, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.Real.MonthWatchs, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Actress.Status, Value: 1},
{Key: FN.Actress.Real.WatchTimes, Value: 1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(channelmod:initActressIndex) Create Actress Index failed! err:%+v:", err))
}
}
// InsertOneActress 插入一个导航分类
func InsertOneActress(ctx context.Context, qa *Actress) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, qa); err != nil {
log.Warn("Actressmod:InsertOneActress db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneActress 删除一个导航分类
func DelOneActress(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("Actressmod:DelOneActress db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneActress 查找一个导航分类
func FindOneActress(ctx context.Context, filter bson.M) (
*Actress, *srvdef.SrvErr) {
var Actress Actress
if err := db.FindOneEx(ctx, &Actress, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("Actressmod:FindOneActress db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &Actress, nil
}
func FindManyActresss(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (ActressList, *srvdef.SrvErr) {
data := make(ActressList, 0)
if err := db.Find(ctx, &data, filter, opts...); nil != err {
log.Warn("faq:FindManyActresss", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQuery.Code, "", "")
}
return data, nil
}
// CountActresss 统计导航分类数量
func CountActresss(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("faqmod:CountActresss db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneActress 更新一个导航分类
func UpdateOneActress(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("post:UpdateOneActress db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("post:UpdateOneActress db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
func UpdateManyActress(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
_, err := db.UpdateMany(ctx, filter, update)
if err != nil {
log.Warn("post:UpdateManyActress db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
+96
View File
@@ -0,0 +1,96 @@
package actress
type TagActress struct {
Meas struct {
Gender string // Type: int , Desc: 性别 0:女 1:男 2:其他
Height string // Type: int , Desc: 身高 厘米
Weight string // Type: int , Desc: 体重 公斤
Bust string // Type: int , Desc: 胸围 英寸
Waist string // Type: int , Desc: 腰围 英寸
Hip string // Type: int , Desc: 臀围 英寸
Cup string // Type: int , Desc: 罩杯(A:1-G:9)1表示A,2表示B,3表示C,4表示D,5表示E,6表示F,7表示G,8表示H,9表示I
Len string // Type: int , Desc: 长度 毫米(前端可以显示为厘米,如45毫米,显示为14.5厘米,返回后端时,乘以10,保留整数,返回145)
Dia string // Type: int , Desc: 直径 毫米(前端可以显示为厘米,如45毫米,显示为4.5厘米,返回后端时,乘以10,保留整数,返回45)
Blood string // Type: string , Desc: 血型
}
Id string
Alias string
Slug string
Avatar string
Cover string
Desc string
TranslationCategoryId string
Office string
DebutDate string
BornDate string
Region string
Score string
Rank string
HotValue string
Status string
Works string
CreatedAt string
UpdatedAt string
RealUpdateAt string
SeoInfo string
IndexNow string
Real struct {
WatchTimes string
ShowTimes string
Comments string
Likes string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}
}
var FN struct {
Actress TagActress
}
var TN struct {
Actress string
}
func init() {
FN.Actress.Id = "_id"
FN.Actress.UpdatedAt = "updatedAt"
FN.Actress.Works = "works"
FN.Actress.Status = "status"
FN.Actress.Rank = "rank"
FN.Actress.HotValue = "hotValue"
FN.Actress.Score = "score"
FN.Actress.Region = "region"
FN.Actress.BornDate = "bornDate"
FN.Actress.DebutDate = "debutDate"
FN.Actress.Office = "office"
FN.Actress.Meas.Gender = "meas.gender"
FN.Actress.Meas.Height = "meas.height"
FN.Actress.Meas.Weight = "meas.weight"
FN.Actress.Meas.Bust = "meas.bust"
FN.Actress.Meas.Waist = "meas.waist"
FN.Actress.Meas.Hip = "meas.hip"
FN.Actress.Meas.Cup = "meas.cup"
FN.Actress.Meas.Len = "meas.len"
FN.Actress.Meas.Dia = "meas.dia"
FN.Actress.Meas.Blood = "meas.blood"
FN.Actress.Desc = "desc"
FN.Actress.Cover = "cover"
FN.Actress.Avatar = "avatar"
FN.Actress.Alias = "alias"
FN.Actress.Slug = "slug"
FN.Actress.CreatedAt = "createdAt"
FN.Actress.UpdatedAt = "updatedAt"
FN.Actress.TranslationCategoryId = "translationCategoryId"
FN.Actress.Real.WatchTimes = "watchTimes"
FN.Actress.Real.ShowTimes = "showTimes"
FN.Actress.Real.Comments = "comments"
FN.Actress.Real.Likes = "likes"
FN.Actress.Real.WeekWatchs = "weekWatchs"
FN.Actress.Real.MonthWatchs = "monthWatchs"
FN.Actress.Real.TodayWatchs = "todayWatchs"
FN.Actress.SeoInfo = "seoInfo"
FN.Actress.IndexNow = "indexNow"
FN.Actress.RealUpdateAt = "realUpdateAt"
TN.Actress = "actress"
}
+172
View File
@@ -0,0 +1,172 @@
// @title:女优管理
package actress
import (
"fmt"
"regexp"
"strconv"
"strings"
"time"
"videoweb/pub/pubdef"
)
type Meas struct {
Gender int `bson:"gender" json:"gender"` // 性别 0:女 1:男 2:其他
Height int `bson:"height" json:"height"` // 身高 厘米
Weight int `bson:"weight" json:"weight"` // 体重 公斤
Bust int `bson:"bust" json:"bust"` // 胸围 英寸
Waist int `bson:"waist" json:"waist"` // 腰围 英寸
Hip int `bson:"hip" json:"hip"` // 臀围 英寸
Cup int `bson:"cup" json:"cup"` // 罩杯(A:1-G:9)1表示A,2表示B,3表示C,4表示D,5表示E,6表示F,7表示G,8表示H,9表示I
Len int `bson:"len" json:"len"` // 长度 毫米(前端可以显示为厘米,如145毫米,显示为14.5厘米,返回后端时,乘以10,保留整数,返回145)
Dia int `bson:"dia" json:"dia"` // 直径 毫米(前端可以显示为厘米,如45毫米,显示为4.5厘米,返回后端时,乘以10,保留整数,返回45)
Blood string `json:"blood" bson:"blood"` // 血型
}
func calculateCup(bust int, waist int) int {
// 计算胸围和腰围的差值
difference := bust - waist
// 根据差值大致判断罩杯
switch {
case difference < 5:
return 1 // A杯
case difference < 7:
return 2 // B杯
case difference < 9:
return 3 // C杯
case difference < 11:
return 4 // D杯
case difference < 13:
return 5 // E杯
case difference < 15:
return 6 // F杯
case difference < 17:
return 7 // G杯
case difference < 19:
return 8 // H杯
case difference < 21:
return 9 // I杯
default:
return 0
}
}
func (m *Meas) Parse(text string) {
text = strings.ReplaceAll(text, "长度", "尺寸")
text = strings.ReplaceAll(text, "長度", "尺寸")
text = strings.ReplaceAll(text, "厘米", "cm")
text = strings.ReplaceAll(text, "公分", "cm")
text = strings.ReplaceAll(text, "公斤", "kg")
text = strings.ReplaceAll(text, "體", "体")
text = strings.ReplaceAll(text, "圍", "围")
text = strings.ReplaceAll(text, "徑", "径")
// 将字母转换为对应的数字
cupMap := map[string]int{
"A": 1, "B": 2, "C": 3, "D": 4,
"E": 5, "F": 6, "G": 7, "H": 8, "I": 9,
"a": 1, "b": 2, "c": 3, "d": 4,
"e": 5, "f": 6, "g": 7, "h": 8, "i": 9,
}
// 身高提取cm
heightReg := regexp.MustCompile(`(?i)身高\s*(\d+)cm`)
if matches := heightReg.FindStringSubmatch(text); len(matches) > 1 {
m.Height, _ = strconv.Atoi(matches[1])
}
// 体重提取kg
weightReg := regexp.MustCompile(`(?i)体重\s*(\d+)kg`)
if matches := weightReg.FindStringSubmatch(text); len(matches) > 1 {
m.Weight, _ = strconv.Atoi(matches[1])
}
// 体重提取斤
weightReg = regexp.MustCompile(`(?i)体重\s*(\d+)斤`)
if matches := weightReg.FindStringSubmatch(text); len(matches) > 1 {
m.Weight, _ = strconv.Atoi(matches[1])
m.Weight = m.Weight / 2
}
// 胸围提取
bustReg := regexp.MustCompile(`胸围\s*(\d+)`)
if matches := bustReg.FindStringSubmatch(text); len(matches) > 1 {
m.Bust, _ = strconv.Atoi(matches[1])
}
// 三围单个数值提取
bustReg = regexp.MustCompile(`三围\s*(\d+)`)
if matches := bustReg.FindStringSubmatch(text); len(matches) > 1 {
m.Bust, _ = strconv.Atoi(matches[1])
}
// 罩杯提取
cupReg := regexp.MustCompile(`(?i)(\d+)([A-Z])`)
if matches := cupReg.FindStringSubmatch(text); len(matches) > 2 {
m.Cup = cupMap[matches[2]]
}
// 长度提取cm,支持浮点数
lengthReg := regexp.MustCompile(`(?i)尺寸\s*(\d+\.?\d*)cm`)
if matches := lengthReg.FindStringSubmatch(text); len(matches) > 1 {
value, _ := strconv.ParseFloat(matches[1], 64)
m.Len = int(value * 10) // 转换为mm
}
// 直径提取cm,支持浮点数
diaReg := regexp.MustCompile(`(?i)直径\s*(\d+\.?\d*)cm`)
if matches := diaReg.FindStringSubmatch(text); len(matches) > 1 {
value, _ := strconv.ParseFloat(matches[1], 64)
m.Len = int(value * 10) // 转换为mm
}
// 提取三围和罩杯
threeSizeReg := regexp.MustCompile(`(?i)三围\s*(\d+)([A-Z])/(\d+)/(\d+)`)
if matches := threeSizeReg.FindStringSubmatch(text); len(matches) > 1 {
m.Bust, _ = strconv.Atoi(matches[1])
m.Cup = cupMap[matches[2]]
m.Waist, _ = strconv.Atoi(matches[3])
m.Hip, _ = strconv.Atoi(matches[4])
}
}
func (m *Meas) convertCupToString(cup int) string {
if cup <= 0 {
cup = calculateCup(m.Bust, m.Waist)
}
if cup >= 1 && cup <= 9 {
letter := rune('A' + cup - 1)
return string(letter)
} else {
if m.Gender == 1 {
return "" // 男性默认返回空字符串
}
return "B" // 非男性默认返回B杯
}
}
func (m *Meas) Measurements() string {
//三围 格式为 35D-24-34 // 胸围(罩杯)-腰围-臀围
return fmt.Sprintf("%d%s-%d-%d", m.Bust, m.convertCupToString(m.Cup), m.Waist, m.Hip)
}
// @title:女优
// @table:actress
type Actress struct {
Id int64 `json:"id" bson:"_id"` // Id
Alias string `bson:"alias" json:"alias"` // 别名
Slug string `json:"slug" bson:"slug"` // slug
Avatar string `bson:"avatar" json:"avatar"` // 头像
Cover string `bson:"cover" json:"cover"` // 封面大图
Desc string `bson:"desc" json:"desc"` // 详细描述
TranslationCategoryId int64 `bson:"translationCategoryId" json:"translationCategoryId"` // 关联导航分类id
Meas Meas `bson:"meas" json:"meas"` // 三围
Office string `json:"office" bson:"office"` // 事务所
DebutDate time.Time `bson:"debutDate" json:"debutDate" ` // 出道日期
BornDate time.Time `bson:"bornDate" json:"bornDate"` // 出生日期
Region string `json:"region" bson:"region"` // 地区/国家
Score string `json:"score" bson:"score"` // 评分
Rank int64 `json:"rank" bson:"rank"` // 排序
HotValue int64 `json:"hotValue" bson:"hotValue"` // 热度值
Status bool `json:"status" bson:"status"` // 是否启用
Works int64 `json:"works" bson:"works"` // 作品数
Real pubdef.Flow `json:"real" bson:"real"` // 真实流量
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
RealUpdateAt time.Time `json:"realUpdateAt" bson:"realUpdateAt"` // 播放相关数据更新时间
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
IndexNow int64 `json:"indexNow" bson:"indexNow"` // 是否需要提交 0:代表提交 1:表示已提交 运营通过接口可以修改
}
type ActressList []*Actress
+182
View File
@@ -0,0 +1,182 @@
package analyticsdailystat
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 表名
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.AnalyticsDailyInfo)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.AnalyticsDailyInfo.AppId, Value: 1},
{Key: FN.AnalyticsDailyInfo.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.AnalyticsDailyInfo.SumDate, Value: 1},
{Key: FN.AnalyticsDailyInfo.AppId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.AnalyticsDailyInfo.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(AnalyticsDailyInfo:initAnalyticsDailyInfoIndex) Create AnalyticsDailyInfo Index failed! err:%+v:", err))
}
}
// InsertOneAnalyticsDailyInfo 插入一个评论
func InsertOneAnalyticsDailyInfo(ctx context.Context, AnalyticsDailyInfo *AnalyticsDailyInfo) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, AnalyticsDailyInfo); err != nil {
log.Warn("AnalyticsDailyInfo:InsertOneAnalyticsDailyInfo db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneAnalyticsDailyInfo 删除一个评论
func DelOneAnalyticsDailyInfo(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("AnalyticsDailyInfo:DelOneAnalyticsDailyInfo db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyAnalyticsDailyInfo 删除一个评论评论
func DelManyAnalyticsDailyInfo(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("AnalyticsDailyInfo:DelOneAnalyticsDailyInfo db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneAnalyticsDailyInfo 查找一个评论
func FindOneAnalyticsDailyInfo(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (
*AnalyticsDailyInfo, *srvdef.SrvErr) {
var AnalyticsDailyInfo AnalyticsDailyInfo
if err := db.FindOneEx(
ctx, &AnalyticsDailyInfo, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("AnalyticsDailyInfo:FindOneAnalyticsDailyInfo db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &AnalyticsDailyInfo, nil
}
// CountAnalyticsDailyInfos 统计评论视频评论数量
func CountAnalyticsDailyInfos(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("AnalyticsDailyInfo:CountAnalyticsDailyInfos db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneAnalyticsDailyInfo 更新一个评论
func UpdateOneAnalyticsDailyInfo(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("AnalyticsDailyInfo:UpdateOneAnalyticsDailyInfo db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("AnalyticsDailyInfo:UpdateOneAnalyticsDailyInfo db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyAnalyticsDailyInfo 更新一批评论
func UpdateManyAnalyticsDailyInfo(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("AnalyticsDailyInfo:UpdateManyAnalyticsDailyInfo db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("AnalyticsDailyInfo:UpdateManyAnalyticsDailyInfo db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrAnalyticsDailyInfoNotExsit, "", "")
}
return nil
}
// FindManyAnalyticsDailyInfo 查找一批评论
func FindManyAnalyticsDailyInfo(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (AnalyticsDailyInfoList, *srvdef.SrvErr) {
data := make(AnalyticsDailyInfoList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("AnalyticsDailyInfo:FindManyAnalyticsDailyInfo db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// InsertManyAnalyticsDailyInfo 插入一批用户
func InsertManyAnalyticsDailyInfo(ctx context.Context, histrory *AnalyticsDailyInfoList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, histrory); err != nil {
log.Warn("AnalyticsDailyInfo:InsertManyAnalyticsDailyInfo db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// AggregateAnalyticsDailyInfo 聚合查找一批数据
func AggregateAnalyticsDailyInfo(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("AnalyticsDailyInfo:AggregateAnalyticsDailyInfo db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateAnalyticsDailyInfo 聚合查找一批数据
func ObjectAggregateAnalyticsDailyInfo(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("AnalyticsDailyInfo:AggregateAnalyticsDailyInfo db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+42
View File
@@ -0,0 +1,42 @@
package analyticsdailystat
type TagAnalyticsDailyInfo struct {
AppId string
AppName string
CreatedAt string
Id string
LeadAmount string
LeadNewCount string
SumDate string
UpdatedAt string
YestodayActiveUsers string
YestodayNewUsers string
YestodayPV string
YestodaySessions string
YestodayUV string
}
var FN struct {
AnalyticsDailyInfo TagAnalyticsDailyInfo
}
var TN struct {
AnalyticsDailyInfo string
}
func init() {
FN.AnalyticsDailyInfo.AppId = "appId"
FN.AnalyticsDailyInfo.AppName = "appName"
FN.AnalyticsDailyInfo.CreatedAt = "createdAt"
FN.AnalyticsDailyInfo.Id = "_id"
FN.AnalyticsDailyInfo.LeadAmount = "leadAmount"
FN.AnalyticsDailyInfo.LeadNewCount = "leadNewCount"
FN.AnalyticsDailyInfo.SumDate = "sumDate"
FN.AnalyticsDailyInfo.UpdatedAt = "updatedAt"
FN.AnalyticsDailyInfo.YestodayActiveUsers = "yestodayActiveUsers"
FN.AnalyticsDailyInfo.YestodayNewUsers = "yestodayNewUsers"
FN.AnalyticsDailyInfo.YestodayPV = "yestodayPV"
FN.AnalyticsDailyInfo.YestodaySessions = "yestodaySessions"
FN.AnalyticsDailyInfo.YestodayUV = "yestodayUV"
TN.AnalyticsDailyInfo = "analytics_daily_info"
}
+27
View File
@@ -0,0 +1,27 @@
package analyticsdailystat
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 数据统计
// @table:analytics_daily_info
type AnalyticsDailyInfo struct {
Id primitive.ObjectID `bson:"_id,omitempty"`
SumDate time.Time `json:"sumDate" bson:"sumDate"` // 时间半小时
AppId int64 `json:"appId" bson:"appId"` // appId
AppName string `json:"appName" bson:"appName"` // APP名称
YestodayPV int64 `json:"yestodayPV" bson:"yestodayPV"` // 页面浏览量 (PV)
YestodayUV int64 `json:"yestodayUV" bson:"yestodayUV"` // 独立用户数 (UV)
YestodayActiveUsers int64 `json:"yestodayActiveUsers" bson:"yestodayActiveUsers"` // 活跃用户数
YestodaySessions int64 `json:"yestodaySessions" bson:"yestodaySessions"` // 会话数
YestodayNewUsers int64 `json:"yestodayNewUsers" bson:"yestodayNewUsers"` // 新增数量
LeadNewCount float64 `json:"leadNewCount" bson:"leadNewCount"` // 日导量新增
LeadAmount float64 `json:"leadAmount" bson:"leadAmount"` // 日导量充值
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
}
type AnalyticsDailyInfoList []*AnalyticsDailyInfo
+182
View File
@@ -0,0 +1,182 @@
package analyticsstat
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 表名
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.AnalyticsInfo)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.AnalyticsInfo.AppId, Value: 1},
{Key: FN.AnalyticsInfo.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.AnalyticsInfo.SumDate, Value: 1},
{Key: FN.AnalyticsInfo.AppId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.AnalyticsInfo.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(AnalyticsInfo:initAnalyticsInfoIndex) Create AnalyticsInfo Index failed! err:%+v:", err))
}
}
// InsertOneAnalyticsInfo 插入一个评论
func InsertOneAnalyticsInfo(ctx context.Context, AnalyticsInfo *AnalyticsInfo) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, AnalyticsInfo); err != nil {
log.Warn("AnalyticsInfo:InsertOneAnalyticsInfo db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneAnalyticsInfo 删除一个评论
func DelOneAnalyticsInfo(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("AnalyticsInfo:DelOneAnalyticsInfo db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyAnalyticsInfo 删除一个评论评论
func DelManyAnalyticsInfo(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("AnalyticsInfo:DelOneAnalyticsInfo db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneAnalyticsInfo 查找一个评论
func FindOneAnalyticsInfo(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (
*AnalyticsInfo, *srvdef.SrvErr) {
var AnalyticsInfo AnalyticsInfo
if err := db.FindOneEx(
ctx, &AnalyticsInfo, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("AnalyticsInfo:FindOneAnalyticsInfo db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &AnalyticsInfo, nil
}
// CountAnalyticsInfos 统计评论视频评论数量
func CountAnalyticsInfos(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("AnalyticsInfo:CountAnalyticsInfos db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneAnalyticsInfo 更新一个评论
func UpdateOneAnalyticsInfo(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("AnalyticsInfo:UpdateOneAnalyticsInfo db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("AnalyticsInfo:UpdateOneAnalyticsInfo db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyAnalyticsInfo 更新一批评论
func UpdateManyAnalyticsInfo(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("AnalyticsInfo:UpdateManyAnalyticsInfo db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("AnalyticsInfo:UpdateManyAnalyticsInfo db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrAnalyticsInfoNotExsit, "", "")
}
return nil
}
// FindManyAnalyticsInfo 查找一批评论
func FindManyAnalyticsInfo(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (AnalyticsInfoList, *srvdef.SrvErr) {
data := make(AnalyticsInfoList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("AnalyticsInfo:FindManyAnalyticsInfo db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// InsertManyAnalyticsInfo 插入一批用户
func InsertManyAnalyticsInfo(ctx context.Context, histrory *AnalyticsInfoList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, histrory); err != nil {
log.Warn("AnalyticsInfo:InsertManyAnalyticsInfo db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// AggregateAnalyticsInfo 聚合查找一批数据
func AggregateAnalyticsInfo(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("AnalyticsInfo:AggregateAnalyticsInfo db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateAnalyticsInfo 聚合查找一批数据
func ObjectAggregateAnalyticsInfo(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("AnalyticsInfo:AggregateAnalyticsInfo db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+42
View File
@@ -0,0 +1,42 @@
package analyticsstat
type TagAnalyticsInfo struct {
ActiveUsers string
AppId string
AppName string
CreatedAt string
DaySumDate string
Id string
SumDate string
UpdatedAt string
YestodayActiveUsers string
YestodayNewUsers string
YestodayPV string
YestodaySessions string
YestodayUV string
}
var FN struct {
AnalyticsInfo TagAnalyticsInfo
}
var TN struct {
AnalyticsInfo string
}
func init() {
FN.AnalyticsInfo.ActiveUsers = "activeUsers"
FN.AnalyticsInfo.AppId = "appId"
FN.AnalyticsInfo.AppName = "appName"
FN.AnalyticsInfo.CreatedAt = "createdAt"
FN.AnalyticsInfo.DaySumDate = "daySumDate"
FN.AnalyticsInfo.Id = "_id"
FN.AnalyticsInfo.SumDate = "sumDate"
FN.AnalyticsInfo.UpdatedAt = "updatedAt"
FN.AnalyticsInfo.YestodayActiveUsers = "yestodayActiveUsers"
FN.AnalyticsInfo.YestodayNewUsers = "yestodayNewUsers"
FN.AnalyticsInfo.YestodayPV = "yestodayPV"
FN.AnalyticsInfo.YestodaySessions = "yestodaySessions"
FN.AnalyticsInfo.YestodayUV = "yestodayUV"
TN.AnalyticsInfo = "analytics_info"
}
+27
View File
@@ -0,0 +1,27 @@
package analyticsstat
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 数据统计
// @table:analytics_info
type AnalyticsInfo struct {
Id primitive.ObjectID `bson:"_id,omitempty"`
SumDate time.Time `json:"sumDate" bson:"sumDate"` // 时间半小时
DaySumDate time.Time `json:"daySumDate" bson:"daySumDate"` // 当天
AppId int64 `json:"appId" bson:"appId"` // appId
AppName string `json:"appName" bson:"appName"` // APP名称
ActiveUsers int64 `json:"activeUsers" bson:"activeUsers"` // 最近半小时活跃数
YestodayPV int64 `json:"yestodayPV" bson:"yestodayPV"` // 页面浏览量 (PV)
YestodayUV int64 `json:"yestodayUV" bson:"yestodayUV"` // 独立用户数 (UV)
YestodayActiveUsers int64 `json:"yestodayActiveUsers" bson:"yestodayActiveUsers"` // 活跃用户数
YestodaySessions int64 `json:"yestodaySessions" bson:"yestodaySessions"` // 会话数
YestodayNewUsers int64 `json:"yestodayNewUsers" bson:"yestodayNewUsers"` // 新增数量
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
}
type AnalyticsInfoList []*AnalyticsInfo
+102
View File
@@ -0,0 +1,102 @@
package announcementmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.Announcement)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Announcement.Status, Value: 1},
{Key: FN.Announcement.Sort, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Announcement.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(announcementmod:Init) Create Announcement Index failed! err:%+v:", err))
}
}
func InsertOneAnnouncement(ctx context.Context, doc *Announcement) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, doc); err != nil {
log.Warn("announcementmod:InsertOneAnnouncement db.InsertOne failed",
log.E(err), log.Any("doc", doc))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
func DelOneAnnouncement(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("announcementmod:DelOneAnnouncement db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
func FindOneAnnouncement(ctx context.Context, filter bson.M) (*Announcement, *srvdef.SrvErr) {
var doc Announcement
if err := db.FindOneEx(ctx, &doc, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("announcementmod:FindOneAnnouncement db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrAnnouncementNotExsit, "", "")
}
return &doc, nil
}
func FindManyAnnouncement(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (AnnouncementList, *srvdef.SrvErr) {
data := make(AnnouncementList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("announcementmod:FindManyAnnouncement db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
func CountAnnouncement(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("announcementmod:CountAnnouncement db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
func UpdateOneAnnouncement(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("announcementmod:UpdateOneAnnouncement db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("announcementmod:UpdateOneAnnouncement not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrAnnouncementNotExsit, "", "")
}
return nil
}
+30
View File
@@ -0,0 +1,30 @@
package announcementmod
type TagAnnouncement struct {
Id string
Title string
Content string
Sort string
Status string
CreatedAt string
UpdatedAt string
}
var FN struct {
Announcement TagAnnouncement
}
var TN struct {
Announcement string
}
func init() {
FN.Announcement.Id = "_id"
FN.Announcement.Title = "title"
FN.Announcement.Content = "content"
FN.Announcement.Sort = "sort"
FN.Announcement.Status = "status"
FN.Announcement.CreatedAt = "createdAt"
FN.Announcement.UpdatedAt = "updatedAt"
TN.Announcement = "announcement"
}
+17
View File
@@ -0,0 +1,17 @@
package announcementmod
import "time"
// Announcement 公告
// @table:announcement
type Announcement struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Title string `json:"title" bson:"title"` // 标题
Content string `json:"content" bson:"content"` // 内容
Sort int64 `json:"sort" bson:"sort"` // 排序,越大越靠前
Status bool `json:"status" bson:"status"` // 是否启用
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
type AnnouncementList []*Announcement
+42
View File
@@ -0,0 +1,42 @@
package cfg
import (
"context"
"strings"
"sync"
"go.mongodb.org/mongo-driver/bson"
)
var appKeyCache struct {
sync.RWMutex
value string
ready bool
}
// CacheAppKey 把系统配置里的 appKey 放进内存,供媒资写接口读取。
func CacheAppKey(appKey string) {
appKeyCache.Lock()
appKeyCache.value = strings.TrimSpace(appKey)
appKeyCache.ready = true
appKeyCache.Unlock()
}
// CachedAppKey 返回已缓存的 appKey。缓存未建立时读取 sys_cfg 并写入缓存。
func CachedAppKey(ctx context.Context) string {
appKeyCache.RLock()
if appKeyCache.ready {
value := appKeyCache.value
appKeyCache.RUnlock()
return value
}
appKeyCache.RUnlock()
sysCfg, serr := FindOneSysCfg(ctx, bson.M{FN.SysCfg.Id: 1})
if serr != nil || sysCfg == nil {
return ""
}
value := strings.TrimSpace(sysCfg.AppKey)
CacheAppKey(value)
return value
}
+9
View File
@@ -0,0 +1,9 @@
package cfg
import (
"videoweb/pub/mongos"
)
var (
sysCfgColl *mongos.Collection
)
+55
View File
@@ -0,0 +1,55 @@
package cfg
import (
"context"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
// Init 初始化数据
func Init(ctx context.Context) {
sysCfgColl = mongos.Shop.Coll(TN.SysCfg)
}
// FindOneSysCfg 查找一个系统配置
func FindOneSysCfg(ctx context.Context, filter bson.M) (
*SysCfg, *srvdef.SrvErr) {
var sysCfg SysCfg
if err := sysCfgColl.FindOneEx(
ctx, &sysCfg, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("cfg:FindOneSysCfg db.FindOneEx failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return &sysCfg, nil
}
// UpdateOneSysCfg 更新一个系统配置
func UpdateOneSysCfg(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := sysCfgColl.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("cfg:UpdateOneSysCfg db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
func DeleteOneSysCfg(ctx context.Context, filter bson.M) *srvdef.SrvErr {
_, err := sysCfgColl.DeleteOne(ctx, filter)
if err != nil {
log.Warn("cfg:DeleteOneSysCfg db.DeleteOne failed", log.Any("filter", filter), log.E(err))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+88
View File
@@ -0,0 +1,88 @@
package cfg
type TagSysCfg struct {
AppAddr string
DownloadVideoUrl string
ForeverUrlAddr string
GitAddr string
GmailAddr string
Id string
ImgAppCdn string
ImgWebCdn string
MediaAppCdn string
MediaWebCdn string
NewUrlAddr string
NewUrlAddr1 string
NewUrlAddr2 string
QQ string
Telegram string
TelegramAdd string
TgGroup string
TranslationAddr string
TwitterAddr string
WatermarkImage string
WatermarkMedia string
WatermarkMediaTop string
WatermarkMediaTopRight string
WatermarkMediaBottomLeft string
WeiChart string
DHNewUrlAddr1 string
DHNewUrlAddr2 string
DHNewUrlAddr3 string
DHForeverUrlAddr string
UnencryptedCdn string
SitemapDefaultImages string
Version string
ChannelCode string
EnableH265 string
M3U8DayRateLimitMax string
AppKey string
}
var FN struct {
SysCfg TagSysCfg
}
var TN struct {
SysCfg string
}
func init() {
FN.SysCfg.AppAddr = "appAddr"
FN.SysCfg.DownloadVideoUrl = "downloadVideoUrl"
FN.SysCfg.ForeverUrlAddr = "foreverUrlAddr"
FN.SysCfg.GitAddr = "gitAddr"
FN.SysCfg.GmailAddr = "gmailAddr"
FN.SysCfg.Id = "_id"
FN.SysCfg.ImgAppCdn = "imgAppCdn"
FN.SysCfg.ImgWebCdn = "imgWebCdn"
FN.SysCfg.MediaAppCdn = "mediaAppCdn"
FN.SysCfg.MediaWebCdn = "mediaWebCdn"
FN.SysCfg.NewUrlAddr = "newUrlAddr"
FN.SysCfg.NewUrlAddr1 = "newUrlAddr1"
FN.SysCfg.NewUrlAddr2 = "newUrlAddr2"
FN.SysCfg.QQ = "qq"
FN.SysCfg.Telegram = "telegram"
FN.SysCfg.TelegramAdd = "telegramAdd"
FN.SysCfg.TgGroup = "tgGroup"
FN.SysCfg.TranslationAddr = "translationAddr"
FN.SysCfg.TwitterAddr = "twitterAddr"
FN.SysCfg.WatermarkImage = "watermarkImage"
FN.SysCfg.WatermarkMedia = "watermarkMedia"
FN.SysCfg.WatermarkMediaTop = "watermarkMediaTop"
FN.SysCfg.WatermarkMediaTopRight = "watermarkMediaTopRight"
FN.SysCfg.WatermarkMediaBottomLeft = "watermarkMediaBottomLeft"
FN.SysCfg.WeiChart = "weiChart"
FN.SysCfg.DHNewUrlAddr1 = "dHNewUrlAddr1"
FN.SysCfg.DHNewUrlAddr2 = "dHNewUrlAddr2"
FN.SysCfg.DHNewUrlAddr3 = "dHNewUrlAddr3"
FN.SysCfg.DHForeverUrlAddr = "dHForeverUrlAddr"
FN.SysCfg.UnencryptedCdn = "unencryptedCdn"
FN.SysCfg.SitemapDefaultImages = "sitemapDefaultImages"
FN.SysCfg.Version = "version"
FN.SysCfg.ChannelCode = "channelCode"
FN.SysCfg.EnableH265 = "enableH265"
FN.SysCfg.M3U8DayRateLimitMax = "m3u8DayRateLimitMax"
FN.SysCfg.AppKey = "appKey"
TN.SysCfg = "sys_cfg"
}
+73
View File
@@ -0,0 +1,73 @@
package cfg
import "strings"
// @table:sys_cfg
type SysCfg struct {
Id int64 `json:"id" bson:"_id"`
Version int64 `json:"version" bson:"version"` // 版本号,用于更新乐观锁
UnencryptedCdn string `json:"unencryptedCdn" bson:"unencryptedCdn"` // 不加密资源使用的cdn
SitemapDefaultImages []string `json:"sitemapDefaultImages" bson:"sitemapDefaultImages"` // Sitemap里面默认封面图
ImgAppCdn string `json:"imgAppCdn" bson:"imgAppCdn"` // 图片CDN(app使用)
ImgAppUsCdn string `json:"imgAppUsCdn" bson:"imgAppUsCdn"` // 图片CDN(海外app使用)
ImgWebCdn string `json:"imgWebCdn" bson:"imgWebCdn"` // 图片CDN(web使用)
MediaWebCdn string `json:"mediaWebCdn" bson:"mediaWebCdn"` // 视频CDN(web使用)
MediaAppCdn string `json:"mediaAppCdn" bson:"mediaAppCdn"` // 视频CDN(app使用)
MediaAppUsCdn string `json:"mediaAppUsCdn" bson:"mediaAppUsCdn"` // 视频CDN(海外app使用)
WatermarkImage string `json:"watermarkImage" bson:"watermarkImage"` // 图片水印文件
WatermarkMedia string `json:"watermarkMedia" bson:"watermarkMedia"` // 视频水印文件(底部右边)
WatermarkMediaTop string `json:"watermarkMediaTop" bson:"watermarkMediaTop"` // 视频水印文件(顶部左边)
WatermarkMediaTopRight string `json:"watermarkMediaTopRight" bson:"watermarkMediaTopRight"` // 视频水印文件(顶部右边)
WatermarkMediaBottomLeft string `json:"watermarkMediaBottomLeft" bson:"watermarkMediaBottomLeft"` // 视频水印文件(底部左边)
Mp4Addr string `json:"mp4Addr" bson:"mp4Addr"` // mp4地址(web使用)
PdfAddr string `json:"pdfAddr" bson:"pdfAddr"` // 回家的路PDF
//网站管理
NewUrlAddr string `json:"newUrlAddr" bson:"newUrlAddr"` //最新地址
NewUrlAddr1 string `json:"newUrlAddr1" bson:"newUrlAddr1"` //最新地址(备用地址1)
NewUrlAddr2 string `json:"newUrlAddr2" bson:"newUrlAddr2"` //最新地址(备用地址2)
ForeverUrlAddr string `json:"foreverUrlAddr" bson:"foreverUrlAddr"` //永久地址
GmailAddr string `json:"gmailAddr" bson:"gmailAddr"` //邮箱地址
AppAddr string `json:"appAddr" bson:"appAddr"` //APP下载地址(落地页)
DownloadVideoUrl string `json:"downloadVideoUrl" bson:"downloadVideoUrl"` // 下载视频URL
WeiChart string `json:"weiChart" bson:"weiChart"` //微信群
QQ string `json:"qq" bson:"qq"` //qq群
TgGroup string `json:"tgGroup" bson:"tgGroup"` //tg群
PotaoGroup string `json:"potaoGroup" bson:"potaoGroup"` //土豆群
GitAddr string `json:"gitAddr" bson:"gitAddr"` //git地址
TwitterAddr string `json:"twitterAddr" bson:"twitterAddr"` //推特地址
Telegram string `json:"telegram" bson:"telegram"` //商务tg
TelegramAdd string `json:"telegramAdd" bson:"telegramAdd"` //加入我们tg
TranslationAddr string `json:"translationAddr" bson:"translationAddr"` //应用导航
//SEO
WebTitle string `json:"webTitle" bson:"webTitle"` // 网站SEO标题
WebKeyworld []string `json:"webKeyworld" bson:"webKeyworld"` // 网站SEO关键字
WebDescription string `json:"webDescription" bson:"webDescription"` // 网站SEO描述
WebSiteName string `json:"webSiteName" bson:"webSiteName"` // 网站SEO网站名称
WebAddr string `json:"webAddr" bson:"webAddr"` // 网站SEO网站地址
DHNewUrlAddr1 string `json:"dhNewUrlAddr1" bson:"dhNewUrlAddr1"` // 导航页-线路1
DHNewUrlAddr2 string `json:"dhNewUrlAddr2" bson:"dhNewUrlAddr2"` // 导航页-线路2
DHNewUrlAddr3 string `json:"dhNewUrlAddr3" bson:"dhNewUrlAddr3"` // 导航页-线路3
FreeVPN string `json:"freeVPN" bson:"freeVPN"` // 免费vpn链接
UseAddress []string `json:"useAddress" bson:"useAddress"` // 所有使用中的域名
DHTitle string `json:"dhTitle" bson:"dhTitle"` // 导航SEO标题
DHKeyworld []string `json:"dhKeyworld" bson:"dhKeyworld"` // 导航SEO关键字
DHDescription string `json:"dhDescription" bson:"dhDescription"` // 导航SEO描述
DHSiteName string `json:"dhSiteName" bson:"dhSiteName"` // 导航SEO网站名称
ChannelCode string `json:"channelCode" bson:"channelCode"` // 渠道码
EnableH265 bool `json:"enableH265" bson:"enableH265"` // 是否允许客户端使用 H265 地址播放
M3U8DayRateLimitMax int64 `json:"m3u8DayRateLimitMax" bson:"m3u8DayRateLimitMax"` // 每 IP 每天最多不同正片数,<=0 使用默认 80
AppKey string `json:"appKey" bson:"appKey"` // 媒资库 appKey,调用 media 写接口时传入
}
// SEOBaseURL 返回与页面 canonical 一致的 SEO 主域。
// 永久域名未配置时回退到 WebAddr,避免生成空地址。
func (c *SysCfg) SEOBaseURL() string {
if c == nil {
return ""
}
base := strings.TrimSpace(c.ForeverUrlAddr)
if base == "" {
base = strings.TrimSpace(c.WebAddr)
}
return strings.TrimRight(base, "/")
}
+87
View File
@@ -0,0 +1,87 @@
package commentlikemod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const collectionName = "comment_like"
const CollectionName = collectionName
type CommentLike struct {
UserId int64 `bson:"userId"`
CommentId int64 `bson:"commentId"`
CreatedAt time.Time `bson:"createdAt"`
}
var coll *mongos.Collection
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(collectionName)
indexes := []mongo.IndexModel{
{Keys: bson.D{{Key: "userId", Value: 1}, {Key: "commentId", Value: 1}}, Options: options.Index().SetUnique(true)},
{Keys: bson.D{{Key: "commentId", Value: 1}}},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("commentlikemod.Init CreateIndex failed: %v", err))
}
}
// Add 新增点赞关系,重复点赞不改变状态
func Add(ctx context.Context, userId, commentId int64) (bool, *srvdef.SrvErr) {
_, err := coll.InsertOne(ctx, &CommentLike{UserId: userId, CommentId: commentId, CreatedAt: time.Now()})
if mongo.IsDuplicateKeyError(err) {
return false, nil
}
if err != nil {
log.Warn("commentlikemod.Add", log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return true, nil
}
// Remove 删除点赞关系,重复取消不改变状态
func Remove(ctx context.Context, userId, commentId int64) (bool, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, bson.M{"userId": userId, "commentId": commentId})
if err != nil {
log.Warn("commentlikemod.Remove", log.E(err))
return false, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count > 0, nil
}
// FindByUserAndComments 批量查询当前用户的评论点赞关系
func FindByUserAndComments(ctx context.Context, userId int64, commentIds []int64) ([]CommentLike, *srvdef.SrvErr) {
result := make([]CommentLike, 0)
if userId <= 0 || len(commentIds) == 0 {
return result, nil
}
err := coll.Find(ctx, &result, bson.M{"userId": userId, "commentId": bson.M{"$in": commentIds}})
if err != nil {
log.Warn("commentlikemod.FindByUserAndComments", log.E(err))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return result, nil
}
// DeleteByCommentIds 清理已删除评论的点赞关系
func DeleteByCommentIds(ctx context.Context, commentIds []int64) *srvdef.SrvErr {
if len(commentIds) == 0 {
return nil
}
_, err := coll.DeleteMany(ctx, bson.M{"commentId": bson.M{"$in": commentIds}})
if err != nil {
log.Warn("commentlikemod.DeleteByCommentIds", log.E(err))
return srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return nil
}
+238
View File
@@ -0,0 +1,238 @@
package commentmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 表名
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.Comment)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Comment.ObjectId, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.Id, Value: 1},
{Key: FN.Comment.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.ObjectId, Value: 1},
{Key: FN.Comment.ReviewStatus, Value: 1},
{Key: FN.Comment.Level, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.ObjectId, Value: 1},
{Key: FN.Comment.ObjectType, Value: 1},
{Key: FN.Comment.ReviewStatus, Value: 1},
{Key: FN.Comment.Level, Value: 1},
{Key: FN.Comment.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.ObjectId, Value: 1},
{Key: FN.Comment.ObjectType, Value: 1},
{Key: FN.Comment.ReviewStatus, Value: 1},
{Key: FN.Comment.Level, Value: 1},
{Key: FN.Comment.CountLike, Value: -1},
{Key: FN.Comment.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.ParentsId, Value: 1},
{Key: FN.Comment.ReviewStatus, Value: 1},
{Key: FN.Comment.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.TopRank, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(comment:initCommentIndex) Create Comment Index failed! err:%+v:", err))
}
}
// InsertOneComment 插入一个评论
func InsertOneComment(ctx context.Context, Comment *CommentModel) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, Comment); err != nil {
log.Warn("comment:InsertOneComment db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneComment 删除一个评论
func DelOneComment(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("comment:DelOneComment db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyComment 删除一个评论评论
func DelManyComment(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("comment:DelOneComment db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneComment 查找一个评论
func FindOneComment(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (
*CommentModel, *srvdef.SrvErr) {
var Comment CommentModel
if err := db.FindOneEx(
ctx, &Comment, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("comment:FindOneComment db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &Comment, nil
}
// CountComments 统计评论视频评论数量
func CountComments(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("comment:CountComments db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneComment 更新一个评论
func UpdateOneComment(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("comment:UpdateOneComment db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("comment:UpdateOneComment db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// ChangeLikeCount 原子更新已审核评论的点赞数并返回最新值
func ChangeLikeCount(ctx context.Context, commentId, delta int64) (int64, *srvdef.SrvErr) {
filter := bson.M{FN.Comment.Id: commentId, FN.Comment.ReviewStatus: 1}
if delta < 0 {
filter[FN.Comment.CountLike] = bson.M{"$gt": 0}
}
var comment CommentModel
err := db.FindOneAndUpdate(ctx, &comment, filter,
bson.M{"$inc": bson.M{FN.Comment.CountLike: delta}},
options.FindOneAndUpdate().SetReturnDocument(options.After))
if err == mongo.ErrNoDocuments {
return 0, srvdef.New(srvdef.ErrNoData, "", "")
}
if err != nil {
log.Warn("commentmod.ChangeLikeCount", log.E(err))
return 0, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return comment.CountLike, nil
}
// UpdateManyComment 更新一批评论
func UpdateManyComment(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("comment:UpdateManyComment db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("comment:UpdateManyComment db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrCommentNotExsit, "", "")
}
return nil
}
// FindManyComment 查找一批评论
func FindManyComment(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (CommentModelList, *srvdef.SrvErr) {
data := make(CommentModelList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("comment:FindManyComment db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// InsertManyComment 插入一批用户
func InsertManyComment(ctx context.Context, histrory *CommentModelList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, histrory); err != nil {
log.Warn("comment:InsertManyComment db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// AggregateComment 聚合查找一批数据
func AggregateComment(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("comment:AggregateComment db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateComment 聚合查找一批数据
func ObjectAggregateComment(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("comment:AggregateComment db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+52
View File
@@ -0,0 +1,52 @@
package commentmod
type TagComment struct {
CreatedAt string
Id string
Level string
ObjectId string
ParentsId string
ReplyUserName string
Text string
TopRank string
UpdatedAt string
UserName string
UserId string
Avatar string
ReviewStatus string
CommentCount string
CountLike string
Ip string
ObjectName string
ObjectType string
}
var FN struct {
Comment TagComment
}
var TN struct {
Comment string
}
func init() {
FN.Comment.CreatedAt = "createdAt"
FN.Comment.Id = "_id"
FN.Comment.Level = "level"
FN.Comment.ObjectId = "objectId"
FN.Comment.ParentsId = "parentsId"
FN.Comment.ReplyUserName = "replyUserName"
FN.Comment.Text = "text"
FN.Comment.TopRank = "topRank"
FN.Comment.UpdatedAt = "updatedAt"
FN.Comment.UserName = "userName"
FN.Comment.ReviewStatus = "reviewStatus"
FN.Comment.Ip = "ip"
FN.Comment.CommentCount = "commentCount"
FN.Comment.CountLike = "countLike"
FN.Comment.ObjectName = "objectName"
FN.Comment.ObjectType = "objectType"
FN.Comment.UserId = "userId"
FN.Comment.Avatar = "avatar"
TN.Comment = "_comment"
}
+31
View File
@@ -0,0 +1,31 @@
package commentmod
import (
"time"
"videoweb/pub/pubdef"
)
// 评论管理
// @table:_comment
type CommentModel struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 评论ID
Ip string `json:"ip" bson:"ip"` // 评论IP
ObjectId int64 `json:"objectId" bson:"objectId"` // 对象ID
ObjectType pubdef.CommentObjectType `json:"objectType" bson:"objectType"` // 对象类型 0=视频 4=短剧
ObjectName string `json:"objectName" bson:"objectName"` // 对象类型名称 视频/短剧
UserName string `json:"userName" bson:"userName"` // 用户名称
UserId int64 `json:"userId" bson:"userId"` // 用户ID
Avatar string `json:"avatar" bson:"avatar"` // 用户头像
Level int64 `json:"level" bson:"level"` // 评论级别
ParentsId int64 `json:"parentsId" bson:"parentsId"` // 上级评论ID
ReplyUserName string `json:"replyUserName" bson:"replyUserName"` // 回复名称
Text string `json:"text" bson:"text"` // 评论内容
CommentCount int64 `json:"commentCount" bson:"commentCount"` // 该评论回复数量
CountLike int64 `json:"countLike" bson:"countLike"` // 点赞数
ReviewStatus int `json:"reviewStatus" bson:"reviewStatus"` // 审核状态 0 未审核 1审核成功 2 审核失败
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `bson:"createdAt" json:"createdAt"` // 创建时间
TopRank int64 `json:"topRank" bson:"topRank"` // 置顶排序
}
type CommentModelList []*CommentModel
+189
View File
@@ -0,0 +1,189 @@
package contactusmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 表名
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.ContactUsModel)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.ContactUsModel.Status, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.ContactUsModel.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.ContactUsModel.Name, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.ContactUsModel.Email, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.ContactUsModel.Ip, Value: 1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(ContactUsModel:initContactUsModelIndex) Create ContactUsModel Index failed! err:%+v:", err))
}
}
// InsertOneContactUsModel 插入一个评论
func InsertOneContactUsModel(ctx context.Context, ContactUsModel *ContactUsModel) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, ContactUsModel); err != nil {
log.Warn("ContactUsModel:InsertOneContactUsModel db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneContactUsModel 删除一个评论
func DelOneContactUsModel(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("ContactUsModel:DelOneContactUsModel db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyContactUsModel 删除一个评论评论
func DelManyContactUsModel(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("ContactUsModel:DelOneContactUsModel db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneContactUsModel 查找一个评论
func FindOneContactUsModel(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (
*ContactUsModel, *srvdef.SrvErr) {
var ContactUsModel ContactUsModel
if err := db.FindOneEx(
ctx, &ContactUsModel, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("ContactUsModel:FindOneContactUsModel db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &ContactUsModel, nil
}
// CountContactUsModels 统计评论视频评论数量
func CountContactUsModels(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("ContactUsModel:CountContactUsModels db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneContactUsModel 更新一个评论
func UpdateOneContactUsModel(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("ContactUsModel:UpdateOneContactUsModel db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("ContactUsModel:UpdateOneContactUsModel db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyContactUsModel 更新一批评论
func UpdateManyContactUsModel(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("ContactUsModel:UpdateManyContactUsModel db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("ContactUsModel:UpdateManyContactUsModel db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrContactUsModelNotExsit, "", "")
}
return nil
}
// FindManyContactUsModel 查找一批评论
func FindManyContactUsModel(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (ContactUsModelList, *srvdef.SrvErr) {
data := make(ContactUsModelList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("ContactUsModel:FindManyContactUsModel db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// InsertManyContactUsModel 插入一批用户
func InsertManyContactUsModel(ctx context.Context, histrory *ContactUsModelList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, histrory); err != nil {
log.Warn("ContactUsModel:InsertManyContactUsModel db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// AggregateContactUsModel 聚合查找一批数据
func AggregateContactUsModel(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("ContactUsModel:AggregateContactUsModel db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateContactUsModel 聚合查找一批数据
func ObjectAggregateContactUsModel(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("ContactUsModel:AggregateContactUsModel db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+34
View File
@@ -0,0 +1,34 @@
package contactusmod
type TagContactUsModel struct {
Id string
Ip string
Name string
Email string
CategoryName string
Content string
Status string
UpdatedAt string
CreatedAt string
}
var FN struct {
ContactUsModel TagContactUsModel
}
var TN struct {
ContactUsModel string
}
func init() {
FN.ContactUsModel.Id = "_id"
FN.ContactUsModel.Ip = "ip"
FN.ContactUsModel.Name = "name"
FN.ContactUsModel.Email = "email"
FN.ContactUsModel.CategoryName = "categoryName"
FN.ContactUsModel.Content = "content"
FN.ContactUsModel.Status = "status"
FN.ContactUsModel.UpdatedAt = "updatedAt"
FN.ContactUsModel.CreatedAt = "createdAt"
TN.ContactUsModel = "contact_us"
}
+23
View File
@@ -0,0 +1,23 @@
package contactusmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// ContactUsModel 联系我们
// @table:contact_us
type ContactUsModel struct {
Id primitive.ObjectID `json:"id" bson:"_id,omitempty"` // ID
Ip string `json:"ip" bson:"ip"` // 评论IP
Name string `json:"name" bson:"name"` // 名字
Email string `json:"email" bson:"email"` // 邮件
CategoryName string `json:"categoryName" bson:"categoryName"` // 主旨分类
Content string `json:"content" bson:"content"` // 内容
Status int64 `json:"status" bson:"status"` // 状态 0=初始 1=已回复 2=不予处理 3=已完结
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `bson:"createdAt" json:"createdAt"` // 创建时间
}
type ContactUsModelList []*ContactUsModel
+206
View File
@@ -0,0 +1,206 @@
package contenttagmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 content_tag 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.ContentTag)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.ContentTag.Name, Value: 1},
},
Options: options.Index().
SetUnique(true).
SetName("uniq_content_tag_name").
SetPartialFilterExpression(bson.M{FN.ContentTag.Name: bson.M{"$type": "string", "$gt": ""}}),
},
{
Keys: bson.D{
{Key: FN.ContentTag.Types, Value: 1},
{Key: FN.ContentTag.Status, Value: 1},
{Key: FN.ContentTag.Rank, Value: -1},
{Key: FN.ContentTag.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.ContentTag.Status, Value: 1},
{Key: FN.ContentTag.Rank, Value: -1},
{Key: FN.ContentTag.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.ContentTag.VideoCount, Value: -1},
{Key: FN.ContentTag.Rank, Value: -1},
{Key: FN.ContentTag.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.ContentTag.PlayletCount, Value: -1},
{Key: FN.ContentTag.Rank, Value: -1},
{Key: FN.ContentTag.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(contenttagmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOneContentTag 插入一条统一标签数据
func InsertOneContentTag(ctx context.Context, doc *ContentTag) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.ContentTag.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
log.Warn("contenttagmod:InsertOneContentTag duplicate key", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInputExist, "标签名称已存在", "")
}
log.Warn("contenttagmod:InsertOneContentTag failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneContentTag 删除一条统一标签数据
func DelOneContentTag(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("contenttagmod:DelOneContentTag failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneContentTag 查询一条统一标签数据
func FindOneContentTag(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*ContentTag, *srvdef.SrvErr) {
var doc ContentTag
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("contenttagmod:FindOneContentTag failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyContentTag 按条件查询多条统一标签数据
func FindManyContentTag(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (ContentTagList, *srvdef.SrvErr) {
data := make(ContentTagList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("contenttagmod:FindManyContentTag failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// AggregateContentTag 聚合查询统一标签数据
func AggregateContentTag(ctx context.Context, bind interface{}, pipeline []bson.M, opts ...*options.AggregateOptions) *srvdef.SrvErr {
if err := coll.Aggregate(ctx, bind, pipeline, opts...); err != nil {
log.Warn("contenttagmod:AggregateContentTag 聚合查询统一标签失败", log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// GetMapTags 按标签ID批量查询统一标签映射
func GetMapTags(ctx context.Context, ids []int64) (ContentTagMap, *srvdef.SrvErr) {
result := make(ContentTagMap)
if len(ids) == 0 {
return result, nil
}
list, err := FindManyContentTag(ctx, bson.M{
FN.ContentTag.Id: bson.M{"$in": ids},
}, options.Find().SetProjection(bson.M{
FN.ContentTag.Id: 1,
FN.ContentTag.Name: 1,
FN.ContentTag.Slug: 1,
FN.ContentTag.Types: 1,
FN.ContentTag.Status: 1,
"seoInfo": 1,
FN.ContentTag.Rank: 1,
}))
if err != nil {
return nil, err
}
for _, item := range list {
if item != nil {
result[item.Id] = item
}
}
return result, nil
}
// CountContentTag 统计满足条件的统一标签数量
func CountContentTag(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("contenttagmod:CountContentTag failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneContentTag 更新一条统一标签数据
func UpdateOneContentTag(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
if mongo.IsDuplicateKeyError(err) {
log.Warn("contenttagmod:UpdateOneContentTag duplicate key", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbInputExist, "标签名称已存在", "")
}
log.Warn("contenttagmod:UpdateOneContentTag failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyContentTag 批量更新统一标签数据
func UpdateManyContentTag(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
_, err := coll.UpdateMany(ctx, filter, update)
if err != nil {
log.Warn("contenttagmod:UpdateManyContentTag failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// BulkWriteContentTag 批量写入/更新统一标签数据
func BulkWriteContentTag(ctx context.Context, docs []mongo.WriteModel, opts ...*options.BulkWriteOptions) (*mongo.BulkWriteResult, *srvdef.SrvErr) {
result, err := coll.BulkWrite(ctx, docs, opts...)
if err != nil {
log.Warn("contenttagmod:BulkWriteContentTag failed", log.E(err))
return nil, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return result, nil
}
+51
View File
@@ -0,0 +1,51 @@
package contenttagmod
// TagContentTag 保存 content_tag 集合字段名
type TagContentTag struct {
Id string
Name string
Slug string
Types string
Status string
Rank string
VideoCount string
PlayletCount string
SeoInfo struct {
Description string
Keyworld string
Title string
}
CreatedById string
CreatedByName string
UpdatedByName string
CreatedAt string
UpdatedAt string
}
var FN struct {
ContentTag TagContentTag
}
var TN struct {
ContentTag string
}
func init() {
FN.ContentTag.Id = "_id"
FN.ContentTag.Name = "name"
FN.ContentTag.Slug = "slug"
FN.ContentTag.Types = "types"
FN.ContentTag.Status = "status"
FN.ContentTag.Rank = "rank"
FN.ContentTag.VideoCount = "videoCount"
FN.ContentTag.PlayletCount = "playletCount"
FN.ContentTag.SeoInfo.Description = "seoInfo.webDescription"
FN.ContentTag.SeoInfo.Keyworld = "seoInfo.webKeyworld"
FN.ContentTag.SeoInfo.Title = "seoInfo.webTitle"
FN.ContentTag.CreatedById = "createdById"
FN.ContentTag.CreatedByName = "createdByName"
FN.ContentTag.UpdatedByName = "updatedByName"
FN.ContentTag.CreatedAt = "createdAt"
FN.ContentTag.UpdatedAt = "updatedAt"
TN.ContentTag = "content_tag"
}
+40
View File
@@ -0,0 +1,40 @@
package contenttagmod
import (
"time"
"videoweb/pub/pubdef"
)
// ContentTagType 统一内容标签支持的内容类型
type ContentTagType int32
const (
ContentTagTypeVideo ContentTagType = 1 // 视频
ContentTagTypePlaylet ContentTagType = 5 // 短剧
)
// ContentTag @table: content_tag
//
// ContentTag 内容统一标签集合模型
type ContentTag struct {
Id int64 `json:"id" bson:"_id,omitempty"` // ID
Name string `json:"name" bson:"name"` // 标签名称
Slug string `json:"slug" bson:"slug"` // slug
Types []ContentTagType `json:"types" bson:"types"` // 支持类型 1-视频 5-短剧
Status bool `json:"status" bson:"status"` // 状态 true-启用 false-停用
Rank int64 `json:"rank" bson:"rank"` // 排序,越大越靠前
VideoCount int64 `json:"videoCount" bson:"videoCount"` // 绑定视频数量
PlayletCount int64 `json:"playletCount" bson:"playletCount"` // 绑定短剧数量
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
CreatedById int64 `json:"createdById" bson:"createdById"` // 创建人ID
CreatedByName string `json:"createdByName" bson:"createdByName"` // 创建人名称
UpdatedByName string `json:"updatedByName" bson:"updatedByName"` // 修改人名称
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// ContentTagList 内容统一标签列表
type ContentTagList []*ContentTag
// ContentTagMap 内容统一标签ID映射
type ContentTagMap map[int64]*ContentTag
+102
View File
@@ -0,0 +1,102 @@
package detailnavmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.DetailNavModel)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.DetailNavModel.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(detailnavmod:Init) Create DetailNavModel Index failed! err:%+v:", err))
}
}
// InsertOneDetailNav 插入一条详情页导航
func InsertOneDetailNav(ctx context.Context, doc *DetailNavModel) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, doc); err != nil {
log.Warn("detailnavmod:InsertOneDetailNav db.InsertOne failed",
log.E(err), log.Any("doc", doc))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneDetailNav 删除一条详情页导航
func DelOneDetailNav(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("detailnavmod:DelOneDetailNav db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneDetailNav 查找一条详情页导航
func FindOneDetailNav(ctx context.Context, filter bson.M) (*DetailNavModel, *srvdef.SrvErr) {
var doc DetailNavModel
if err := db.FindOneEx(ctx, &doc, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("detailnavmod:FindOneDetailNav db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyDetailNav 查找多条详情页导航
func FindManyDetailNav(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (DetailNavModelList, *srvdef.SrvErr) {
data := make(DetailNavModelList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("detailnavmod:FindManyDetailNav db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountDetailNav 统计详情页导航数量
func CountDetailNav(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("detailnavmod:CountDetailNav db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneDetailNav 更新一条详情页导航
func UpdateOneDetailNav(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("detailnavmod:UpdateOneDetailNav db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("detailnavmod:UpdateOneDetailNav not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+30
View File
@@ -0,0 +1,30 @@
package detailnavmod
type TagDetailNavModel struct {
CreatedAt string
ID string
Name string
Url string
Sort string
Status string
UpdatedAt string
}
var FN struct {
DetailNavModel TagDetailNavModel
}
var TN struct {
DetailNavModel string
}
func init() {
FN.DetailNavModel.CreatedAt = "createdAt"
FN.DetailNavModel.ID = "_id"
FN.DetailNavModel.Name = "name"
FN.DetailNavModel.Url = "url"
FN.DetailNavModel.Sort = "sort"
FN.DetailNavModel.Status = "status"
FN.DetailNavModel.UpdatedAt = "updatedAt"
TN.DetailNavModel = "detail_nav"
}
+21
View File
@@ -0,0 +1,21 @@
package detailnavmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 详情页导航配置
// @table:detail_nav
type DetailNavModel struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"` // 导航名称
Url string `json:"url" bson:"url"` // 导航链接
Sort int64 `json:"sort" bson:"sort"` // 排序
Status bool `json:"status" bson:"status"` // 是否启用
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
type DetailNavModelList []*DetailNavModel
+105
View File
@@ -0,0 +1,105 @@
package esmod
import (
"fmt"
"videoweb/app/api/proto"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/esmanager"
)
// SearchActress 根据关键字搜索媒体
func SearchActress(content string, from int64, size int64, sort string) (int64, []*ESActress, *srvdef.SrvErr) {
fields := []string{FN.ESActress.Alias, FN.ESActress.Office, FN.ESActress.Region, FN.ESActress.Desc}
must := esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields},
},
{"term": esmanager.M{FN.ESActress.Status: true}},
},
},
}
switch sort {
case string(proto.SearchSortTypeHot):
must = esmanager.M{
"function_score": esmanager.M{
"query": esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields,
}},
{"term": esmanager.M{FN.ESActress.Status: true}},
},
},
},
"functions": esmanager.A{
esmanager.M{
"field_value_factor": esmanager.M{
"field": FN.ESActress.Real.WatchTimes,
"factor": 1.0,
"modifier": "none",
},
},
},
"score_mode": "sum",
"boost_mode": "multiply",
},
}
case string(proto.SearchSortTypeNew):
must = esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields},
},
{"term": esmanager.M{FN.ESActress.Status: true}},
},
"should": esmanager.A{
{"range": esmanager.M{FN.ESActress.CreatedAt: esmanager.M{"gte": "now-30d/d", "boost": 2.0}}}, //7天内提升4倍权重
{"range": esmanager.M{FN.ESActress.CreatedAt: esmanager.M{"gte": "now-180d/d", "boost": 1.5}}}, // 30天内提升3倍权重
{"range": esmanager.M{FN.ESActress.CreatedAt: esmanager.M{"gte": "now-365d/d", "boost": 1.1}}}, // 90天内提升1.5倍权重
},
"minimum_should_match": 0, // 允许不匹配任何should条件
},
}
}
query := esmanager.M{
"query": must,
"sort": esmanager.A{
esmanager.M{"_score": esmanager.M{"order": "desc"}},
},
"from": from,
"size": size,
}
actressList := &ESActressHits{}
err := esmanager.Instance.Search(actressIndex, actressList, query)
if err != nil {
info := fmt.Sprintf(
"(esmod:SearchActress) Search failed! err:%+v:", err)
log.Warn(info,
log.Any("keywords", content),
log.Any("from", from),
log.Any("size", size))
return 0, nil, srvdef.New(srvdef.ErrElsOperError, "", "")
}
total := int64(0)
rslData := make([]*ESActress, 0)
if actressList != nil && actressList.Hits != nil && len(actressList.Hits) > 0 {
total = actressList.Total.Value
for _, video := range actressList.Hits {
rslData = append(rslData, video.Source)
}
}
return total, rslData, nil
}
+62
View File
@@ -0,0 +1,62 @@
package esmod
import (
"context"
"time"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const (
FiveMinuteScale = 5 //对齐时间(分钟)
)
var (
videoIndex = "webhjsq_video_index_v1"
playletIndex = "webhjsq_playlet_index_v1"
actressIndex = "webhjsq_actress_index_v1"
)
func GetVideoIndex() string {
return videoIndex
}
func GetPlayletIndex() string {
return playletIndex
}
func GetActressIndex() string {
return actressIndex
}
func GetRecordByESIndex(ctx context.Context, esIndex string) (
*ESTimestamp, *srvdef.SrvErr) {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
esRecord, serr := FindOneESRecord(ctx, filter)
if serr != nil {
if serr.Code != srvdef.ErrNoData {
return nil, serr
}
return nil, nil
}
return &esRecord.Timestamp, nil
}
func SetOneEsRecord(ctx context.Context, esIndex string,
timestamp *ESTimestamp) *srvdef.SrvErr {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
upsertDoc := bson.M{
"$set": bson.M{
FN.ESRecord.Timestamp.T: timestamp.T,
FN.ESRecord.Timestamp.I: timestamp.I,
FN.ESRecord.UpdatedAt: time.Now(),
},
"$setOnInsert": bson.M{
FN.ESRecord.Id: primitive.NewObjectID(),
FN.ESRecord.CreatedAt: time.Now(),
},
}
serr := UpsertOneESRecord(ctx, filter, upsertDoc)
return serr
}
+343
View File
@@ -0,0 +1,343 @@
package esmod
import (
"context"
"fmt"
"videoweb/pub/esmanager"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
// Init 初始化数据
func Init(ctx context.Context) {
initDBIndex(ctx)
initIndex()
return
}
// initIndex 初始化索引
func initIndex() {
if esmanager.Instance == nil {
return
}
initVideoIndex(videoIndex)
initPlayletIndex(playletIndex)
initActressIndex(actressIndex)
}
// initDBIndex 初始化数据库索引
func initDBIndex(ctx context.Context) {
//获取数据库表
db = mongos.Shop.Coll(TN.ESRecord)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.ESRecord.EsIndex, Value: 1},
},
Options: options.Index().SetUnique(true),
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(esmod:initDBIndex) Create es_record Index failed! err:%+v:", err))
}
}
func initVideoIndex(esIndex string) {
var setting = esmanager.M{
"settings": esmanager.M{
"number_of_shards": esmanager.NumberOfShards,
"number_of_replicas": esmanager.NumberOfReplicas,
"analysis": esmanager.M{
"analyzer": esmanager.M{
"ik": esmanager.M{
"tokenizer": esmanager.AnalyzerIkSmart,
},
},
},
},
"mappings": esmanager.M{
"properties": esmanager.M{
FN.ESVideo.Title: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.MediaType: esmanager.M{
"type": "integer",
},
FN.ESVideo.Remark: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.Desc: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.Keyworlds: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.CreatorName: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.Bango: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.IssuedBrand: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.Status: esmanager.M{
"type": "integer",
},
//FN.ESVideo.IsHot: esmanager.M{
// "type": "boolean",
//},
//FN.ESVideo.Sort: esmanager.M{
// "type": "integer",
//},
FN.ESVideo.WatchTimes: esmanager.M{
"type": "integer",
},
FN.ESVideo.ShowTimes: esmanager.M{
"type": "integer",
},
FN.ESVideo.Comments: esmanager.M{
"type": "integer",
},
FN.ESVideo.AddedTime: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESVideo.IssuedAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
//FN.ESVideo.CreatedAt: esmanager.M{
// "type": "date",
// "format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
//},
},
},
}
if err := esmanager.Instance.InitIndices(esIndex, setting); err != nil {
panic(fmt.Sprintf("ElasticSearch Index %s initMediaIndex error", esIndex))
}
}
func initPlayletIndex(esIndex string) {
var setting = esmanager.M{
"settings": esmanager.M{
"number_of_shards": esmanager.NumberOfShards,
"number_of_replicas": esmanager.NumberOfReplicas,
"analysis": esmanager.M{
"analyzer": esmanager.M{
"ik": esmanager.M{
"tokenizer": esmanager.AnalyzerIkSmart,
},
},
},
},
"mappings": esmanager.M{
"properties": esmanager.M{
FN.ESPlaylet.Id: esmanager.M{
"type": "long",
},
FN.ESPlaylet.Status: esmanager.M{
"type": "integer",
},
FN.ESPlaylet.IsFeatured: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.IsRecommend: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.ShowOnBanner: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.Banner: esmanager.M{
"type": "keyword",
"index": false,
},
FN.ESPlaylet.OnlineAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESPlaylet.CategoryIds: esmanager.M{
"type": "long",
},
FN.ESPlaylet.CategoryNames: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.ThemeIds: esmanager.M{
"type": "long",
},
FN.ESPlaylet.ThemeNames: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Title: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Desc: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Anchor: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Cover: esmanager.M{
"type": "keyword",
"index": false,
},
FN.ESPlaylet.TagIds: esmanager.M{
"type": "long",
},
FN.ESPlaylet.TagNames: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.TotalEpisode: esmanager.M{
"type": "long",
},
FN.ESPlaylet.UpdateStatus: esmanager.M{
"type": "integer",
},
FN.ESPlaylet.CountBrowse: esmanager.M{
"type": "long",
},
FN.ESPlaylet.HeatValue: esmanager.M{
"type": "long",
},
FN.ESPlaylet.CountCollect: esmanager.M{
"type": "long",
},
FN.ESPlaylet.CountLike: esmanager.M{
"type": "long",
},
FN.ESPlaylet.SeoInfo: esmanager.M{
"properties": esmanager.M{
"title": esmanager.M{
"type": "keyword",
"index": false,
},
"keyworld": esmanager.M{
"type": "keyword",
"index": false,
},
"description": esmanager.M{
"type": "keyword",
"index": false,
},
},
},
FN.ESPlaylet.UpdatedAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESPlaylet.CreatedAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
},
},
}
if err := esmanager.Instance.InitIndices(esIndex, setting); err != nil {
panic(fmt.Sprintf("ElasticSearch Index %s initPlayletIndex error", esIndex))
}
}
func initActressIndex(esIndex string) {
var setting = esmanager.M{
"settings": esmanager.M{
"number_of_shards": esmanager.NumberOfShards,
"number_of_replicas": esmanager.NumberOfReplicas,
"analysis": esmanager.M{
"analyzer": esmanager.M{
"ik": esmanager.M{
"tokenizer": esmanager.AnalyzerIkSmart,
},
},
},
},
"mappings": esmanager.M{
"properties": esmanager.M{
FN.ESActress.Alias: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESActress.Desc: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESActress.Office: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESActress.Region: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESActress.Rank: esmanager.M{
"type": "integer",
},
FN.ESActress.Status: esmanager.M{
"type": "integer",
},
FN.ESActress.Works: esmanager.M{
"type": "integer",
},
FN.ESActress.HotValue: esmanager.M{
"type": "integer",
},
FN.ESActress.Real.WatchTimes: esmanager.M{
"type": "integer",
},
FN.ESActress.Real.WeekWatchs: esmanager.M{
"type": "integer",
},
FN.ESActress.Real.MonthWatchs: esmanager.M{
"type": "integer",
},
FN.ESActress.DebutDate: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESActress.DebutDate: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
},
},
}
if err := esmanager.Instance.InitIndices(esIndex, setting); err != nil {
panic(fmt.Sprintf("ElasticSearch Index %s initMediaIndex error", esIndex))
}
}
+112
View File
@@ -0,0 +1,112 @@
package esmod
import (
"fmt"
"videoweb/app/api/proto"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/esmanager"
"videoweb/pub/models/playletmod"
)
// SearchPlaylet 根据关键字搜索短剧
func SearchPlaylet(content string, from int64, size int64, sort string) (int64, []*ESPlaylet, *srvdef.SrvErr) {
fields := []string{
FN.ESPlaylet.Title,
FN.ESPlaylet.Desc,
FN.ESPlaylet.Anchor,
FN.ESPlaylet.CategoryNames,
FN.ESPlaylet.ThemeNames,
FN.ESPlaylet.TagNames,
}
must := esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields,
}},
{"term": esmanager.M{FN.ESPlaylet.Status: playletmod.StatusUp}},
},
},
}
switch sort {
case string(proto.SearchSortTypeHot):
must = esmanager.M{
"function_score": esmanager.M{
"query": esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields,
}},
{"term": esmanager.M{FN.ESPlaylet.Status: playletmod.StatusUp}},
},
},
},
"functions": esmanager.A{
esmanager.M{
"field_value_factor": esmanager.M{
"field": FN.ESPlaylet.CountBrowse,
"factor": 1.0,
"modifier": "none",
},
},
},
"score_mode": "sum",
"boost_mode": "multiply",
},
}
case string(proto.SearchSortTypeNew):
must = esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields,
}},
{"term": esmanager.M{FN.ESPlaylet.Status: playletmod.StatusUp}},
},
"should": esmanager.A{
{"range": esmanager.M{FN.ESPlaylet.OnlineAt: esmanager.M{"gte": "now-30d/d", "boost": 2.0}}},
{"range": esmanager.M{FN.ESPlaylet.OnlineAt: esmanager.M{"gte": "now-180d/d", "boost": 1.5}}},
{"range": esmanager.M{FN.ESPlaylet.OnlineAt: esmanager.M{"gte": "now-365d/d", "boost": 1.1}}},
},
"minimum_should_match": 0,
},
}
}
query := esmanager.M{
"query": must,
"sort": esmanager.A{
esmanager.M{"_score": esmanager.M{"order": "desc"}},
},
"from": from,
"size": size,
"terminate_after": 1000,
}
playletList := &ESPlayletHits{}
err := esmanager.Instance.Search(playletIndex, playletList, query)
if err != nil {
info := fmt.Sprintf("(esmod:SearchPlaylet) Search failed! err:%+v:", err)
log.Warn(info, log.Any("keywords", content), log.Any("from", from), log.Any("size", size))
return 0, nil, srvdef.New(srvdef.ErrElsOperError, "", "")
}
total := int64(0)
result := make([]*ESPlaylet, 0)
if playletList != nil && playletList.Hits != nil && len(playletList.Hits) > 0 {
total = playletList.Total.Value
for _, item := range playletList.Hits {
if item != nil && item.Source != nil {
result = append(result, item.Source)
}
}
}
return total, result, nil
}
+144
View File
@@ -0,0 +1,144 @@
package esmod
import (
"context"
"go.mongodb.org/mongo-driver/bson/primitive"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// InsertOneESRecord 插入ES操作记录
func InsertOneESRecord(ctx context.Context, esRecord *ESRecord) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, esRecord); err != nil {
log.Warn("esmod:InsertOneESRecord db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneESRecord 删除一个ES操作记录
func DelOneESRecord(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("esmod:DelOnAppTag db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneESRecord 查找一个ES操作记录
func FindOneESRecord(ctx context.Context, filter bson.M) (
*ESRecord, *srvdef.SrvErr) {
var esRecord ESRecord
if err := db.FindOneEx(
ctx, &esRecord, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("esmod:FindOnESRecord db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &esRecord, nil
}
// CountESRecords 统计ES操作记录
func CountESRecords(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("esmod:CountMediaCats db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneESRecord 更新ES操作记录
func UpdateOneESRecord(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("esmod:UpdateOnESRecord db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("esmod:UpdateOnESRecord db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrMediaRecordNotExsit, "", "")
}
return nil
}
// UpsertOneESRecord 插入或更新一条ES操作记录
func UpsertOneESRecord(ctx context.Context,
filter bson.M, update bson.M) *srvdef.SrvErr {
if _, err := db.UpsertOne(ctx, filter, update); err != nil {
log.Info("esmod:UpsertOneESRecord db.InsertOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// UpdateManyESRecord 更新一批ES操作记录
func UpdateManyESRecord(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("esmod:UpdateManyMediaCat db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("esmod:UpdateManyMediaCat db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrMediaTagNotExsit, "", "")
}
return nil
}
// FindManyESRecord 查找一批ES操作记录
func FindManyESRecord(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (ESRecordList, *srvdef.SrvErr) {
data := make(ESRecordList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("esmod:FindManyESRecord db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
func GetRecordTimeByESIndex(ctx context.Context, esIndex string) (*ESRecord, *srvdef.SrvErr) {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
esRecord, serr := FindOneESRecord(ctx, filter)
if serr != nil {
if serr.Code != srvdef.ErrNoData {
return nil, serr
}
return nil, nil
}
return esRecord, nil
}
func SetOneEsRecordTime(ctx context.Context, esIndex string, recordTime time.Time) *srvdef.SrvErr {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
upsertDoc := bson.M{
"$set": bson.M{
FN.ESRecord.RecordTime: recordTime,
FN.ESRecord.UpdatedAt: time.Now(),
},
"$setOnInsert": bson.M{
FN.ESRecord.Id: primitive.NewObjectID(),
FN.ESRecord.CreatedAt: time.Now(),
},
}
serr := UpsertOneESRecord(ctx, filter, upsertDoc)
return serr
}
+227
View File
@@ -0,0 +1,227 @@
package esmod
type TagESRecord struct {
CreatedAt string
EsIndex string
Id string
RecordTime string
Timestamp struct {
I string
T string
}
UpdatedAt string
}
type TagESVideo struct {
Id string
Title string
MediaType string
AddedTime string
CreatorName string
Keyworlds string
Desc string
Remark string
Status string
IsHot string
Sort string
WatchTimes string
ShowTimes string
Comments string
UpdatedAt string
CreatedAt string
Keyworld string
CreatorId string
FirstTag string
SecondTags string
CoverImg string
Nodes string
Video string
CategoryIds string
Tags string
Real struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}
IssuedAt string
IssuedBrand string
Bango string
}
type TagESPlaylet struct {
Id string
Status string
IsFeatured string
IsRecommend string
ShowOnBanner string
Banner string
OnlineAt string
CategoryIds string
CategoryNames string
ThemeIds string
ThemeNames string
Title string
Desc string
Anchor string
Cover string
TagIds string
TagNames string
TotalEpisode string
UpdateStatus string
CountBrowse string
HeatValue string
CountCollect string
CountLike string
SeoInfo string
UpdatedAt string
CreatedAt string
}
type TagESActress struct {
Id string
Alias string
Avatar string
Meas string
Office string
DebutDate string
BornDate string
Region string
Score string
Works string
HotValue string
Real struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}
Desc string
Status string
CreatedAt string
UpdatedAt string
Rank string
}
var FN struct {
ESRecord TagESRecord
ESVideo TagESVideo
ESPlaylet TagESPlaylet
ESActress TagESActress
}
var TN struct {
ESRecord string
ESVideo string
ESPlaylet string
ESActress string
}
func init() {
FN.ESRecord = TagESRecord{
CreatedAt: "createdAt",
EsIndex: "esIndex",
Id: "_id",
RecordTime: "recordTime",
Timestamp: struct {
I string
T string
}{
I: "i",
T: "t",
},
UpdatedAt: "updatedAt",
}
FN.ESVideo = TagESVideo{
Id: "_id",
Title: "title",
Desc: "desc",
Status: "status",
AddedTime: "addedTime",
MediaType: "mediaType",
CreatorName: "creatorName",
Keyworlds: "keyworlds",
Remark: "remark",
IsHot: "isHot",
Sort: "sort",
UpdatedAt: "updatedAt",
CreatedAt: "createdAt",
WatchTimes: "watchTimes",
ShowTimes: "showTimes",
Comments: "comments",
IssuedAt: "issuedAt",
IssuedBrand: "issuedBrand",
Bango: "bango",
Real: struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}{WatchTimes: "watchTimes", ShowTimes: "showTimes", Comments: "comments", WeekWatchs: "weekWatchs", MonthWatchs: "monthWatchs", TodayWatchs: "todayWatchs"},
}
FN.ESPlaylet = TagESPlaylet{
Id: "id",
Status: "status",
IsFeatured: "isFeatured",
IsRecommend: "isRecommend",
ShowOnBanner: "showOnBanner",
Banner: "banner",
OnlineAt: "onlineAt",
CategoryIds: "categoryIds",
CategoryNames: "categoryNames",
ThemeIds: "themeIds",
ThemeNames: "themeNames",
Title: "title",
Desc: "desc",
Anchor: "anchor",
Cover: "cover",
TagIds: "tagIds",
TagNames: "tagNames",
TotalEpisode: "totalEpisode",
UpdateStatus: "updateStatus",
CountBrowse: "countBrowse",
HeatValue: "heatValue",
CountCollect: "countCollect",
CountLike: "countLike",
SeoInfo: "seoInfo",
UpdatedAt: "updatedAt",
CreatedAt: "createdAt",
}
FN.ESActress = TagESActress{
Id: "_id",
Alias: "alias",
Avatar: "avatar",
Meas: "meas",
Office: "office",
DebutDate: "debutDate",
BornDate: "bornDate",
Region: "region",
Score: "score",
Works: "works",
HotValue: "hotValue",
Real: struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}{WatchTimes: "watchTimes", ShowTimes: "showTimes", Comments: "comments", WeekWatchs: "weekWatchs", MonthWatchs: "monthWatchs", TodayWatchs: "todayWatchs"},
Desc: "desc",
Status: "status",
CreatedAt: "createdAt",
UpdatedAt: "updatedAt",
Rank: "rank",
}
TN.ESRecord = "es_record"
TN.ESVideo = "es_video"
TN.ESPlaylet = "es_playlet"
TN.ESActress = "es_actress"
}
+172
View File
@@ -0,0 +1,172 @@
//go:generate gen_bson_tag -m esmod
//esmod essearch数据结构定义
package esmod
import (
"time"
"videoweb/pub/models/actress"
"videoweb/pub/models/playletmod"
"videoweb/pub/models/videoinformationmod"
"videoweb/pub/pubdef"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type ESTimestamp struct {
T uint32 `json:"t" bson:"t"`
I uint32 `json:"i" bson:"i"`
}
func (v *ESTimestamp) IsZero() bool {
if v == nil {
return true
}
return v.T == 0 && v.I == 0
}
// ESOperator es操作记录
// @table:es_record
type ESRecord struct {
Id primitive.ObjectID `json:"id" bson:"_id"`
EsIndex string `json:"esIndex" bson:"esIndex"` //es索引名称
Timestamp ESTimestamp `json:"timestamp" bson:"timestamp"` //操作时间
RecordTime time.Time `json:"recordTime" bson:"recordTime"` // 操作记录时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` //更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` //创建时间
}
type ESRecordList []*ESRecord
// ESVideo es中存储的media数据
// @table:es_video
type ESVideo struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Title string `json:"title" bson:"title"` // 帖子标题
MediaType videoinformationmod.MediaType `json:"mediaType" bson:"mediaType"` // 资源类型
AddedTime time.Time `json:"addedTime" bson:"addedTime"` // 帖子上架时间
CreatorName string `json:"creatorName" bson:"creatorName"` // 作者名称
Keyworlds string `bson:"keyworlds,omitempty" json:"keyworlds"` // 关键字
Desc string `bson:"desc,omitempty" json:"desc"` // 详细描述
Remark string `bson:"remark,omitempty" json:"remark"` // 备注
Status pubdef.InformationStatus `json:"status" bson:"status"` // 帖子上架状态
IsHot bool `json:"isHot" bson:"isHot"` // 是否热门
Sort int64 `json:"sort" bson:"sort"` // 排序
WatchTimes int64 `json:"watchTimes" bson:"watchTimes"` // 观看次数
ShowTimes int64 `json:"showTimes" bson:"showTimes"` // 展示次数
Comments int64 `json:"comments" bson:"comments"` // 评论条数
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
Keyworld []string `bson:"keyworld,omitempty" json:"keyworld"` // 关键字
CreatorId int64 `json:"creatorId" bson:"creatorId"` // 作者Id
FirstTag string `bson:"firstTag,omitempty" json:"firstTag"` // 一级标签
SecondTags []string `bson:"secondTags,omitempty" json:"secondTags"` // 二级标签标签
CoverImg string `bson:"coverImg,omitempty" json:"coverImg"` // 封面
Nodes []videoinformationmod.Node `json:"nodes" bson:"nodes"` // 节点
Video videoinformationmod.VideoInfo `json:"video" bson:"video"` // 视频
Tags []int64 `json:"tags" bson:"tags"` // 标签
Real pubdef.Flow `json:"real" bson:"real"` // 真实流量
VideoCount int64 `json:"videoCount" bson:"videoCount"` // 合集视频数量
IssuedAt time.Time `json:"issuedAt" bson:"issuedAt"` // 发行时间
IssuedBrand string `json:"issuedBrand" bson:"issuedBrand"` // 发行商
Bango string `bson:"bango,omitempty" json:"bango"` // 番号,唯一
}
type ESVideoList []*ESVideo
type ESTotal struct {
Value int64 `json:"value"`
}
type ESVideoSource struct {
ID string `json:"_id"`
Score float32 `json:"_score"`
Source *ESVideo `json:"_source"`
}
// ESVideoHits search media hits
type ESVideoHits struct {
Total ESTotal `json:"total"`
Hits []*ESVideoSource `json:"hits"`
}
// ESPlaylet es中存储的短剧搜索数据
// @table:es_playlet
type ESPlaylet struct {
Id int64 `json:"id" bson:"id"` // 短剧ID
Status playletmod.Status `json:"status" bson:"status"` // 状态: 0下架 1上架
IsFeatured bool `json:"isFeatured" bson:"isFeatured"` // 是否爆剧
IsRecommend bool `json:"isRecommend" bson:"isRecommend"` // 是否推荐
ShowOnBanner bool `json:"showOnBanner" bson:"showOnBanner"` // 是否显示在首页banner
Banner string `json:"banner" bson:"banner"` // banner图
OnlineAt time.Time `json:"onlineAt" bson:"onlineAt"` // 上架时间
CategoryIds []int64 `json:"categoryIds" bson:"categoryIds"` // 分类ID集合
CategoryNames []string `json:"categoryNames" bson:"categoryNames"` // 分类名称集合
ThemeIds []int64 `json:"themeIds" bson:"themeIds"` // 题材ID集合
ThemeNames []string `json:"themeNames" bson:"themeNames"` // 题材名称集合
Title string `json:"title" bson:"title"` // 剧名
Desc string `json:"desc" bson:"desc"` // 简介
Anchor string `json:"anchor" bson:"anchor"` // 作者/演员
Cover string `json:"cover" bson:"cover"` // 封面
TagIds []int64 `json:"tagIds" bson:"tagIds"` // 标签ID集合
TagNames []string `json:"tagNames" bson:"tagNames"` // 标签名称集合
TotalEpisode int64 `json:"totalEpisode" bson:"totalEpisode"` // 总集数
UpdateStatus int `json:"updateStatus" bson:"updateStatus"` // 更新状态 1-连载中 2-已完结
CountBrowse int64 `json:"countBrowse" bson:"countBrowse"` // 观看量
HeatValue int64 `json:"heatValue" bson:"heatValue"` // 热度值
CountCollect int64 `json:"countCollect" bson:"countCollect"` // 收藏数
CountLike int64 `json:"countLike" bson:"countLike"` // 展示点赞数
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
}
type ESPlayletList []*ESPlaylet
type ESPlayletSource struct {
ID string `json:"_id"`
Score float32 `json:"_score"`
Source *ESPlaylet `json:"_source"`
}
// ESPlayletHits search playlet hits
type ESPlayletHits struct {
Total ESTotal `json:"total"`
Hits []*ESPlayletSource `json:"hits"`
}
// ESActress es中存储的actress数据
// @table:es_actress
type ESActress struct {
Id int64 `json:"id" bson:"_id"` // Id
Alias string `bson:"alias" json:"alias"` // 别名
Avatar string `bson:"avatar" json:"avatar"` // 头像
Meas actress.Meas `bson:"meas" json:"meas"` // 三围
Desc string `bson:"desc" json:"desc"` // 详细描述
Office string `json:"office" bson:"office"` // 事务所
DebutDate time.Time `bson:"debutDate" json:"debutDate" ` // 出道日期
BornDate time.Time `bson:"bornDate" json:"bornDate"` // 出生日期
Region string `json:"region" bson:"region"` // 地区/国家
Score string `json:"score" bson:"score"` // 评分
Works int64 `json:"works" bson:"works"` // 作品数
HotValue int64 `json:"hotValue" bson:"hotValue"` // 热度值
Real pubdef.Flow `json:"real" bson:"real"` // 真实流量
Status bool `json:"status" bson:"status"` // 状态
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
TranslationCategoryId int64 `bson:"translationCategoryId" json:"translationCategoryId"` // 关联导航分类id
Rank int64 `json:"rank" bson:"rank"` // 排序
}
type ESActressList []*ESActress
type ESActressSource struct {
ID string `json:"_id"`
Score float32 `json:"_score"`
Source *ESActress `json:"_source"`
}
// ESActressHits search media hits
type ESActressHits struct {
Total ESTotal `json:"total"`
Hits []*ESActressSource `json:"hits"`
}
+153
View File
@@ -0,0 +1,153 @@
package esmod
import (
"fmt"
"videoweb/app/api/proto"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/esmanager"
"videoweb/pub/models/videoinformationmod"
"videoweb/pub/pubdef"
)
// SearchVideo 根据关键字搜索媒体
func SearchVideo(content string, from int64, size int64, sort string, isAv bool) (int64, []*videoinformationmod.VideoInformation, *srvdef.SrvErr) {
fields := []string{FN.ESVideo.Title, FN.ESVideo.Bango, FN.ESVideo.IssuedBrand, FN.ESVideo.Keyworlds, FN.ESVideo.Desc}
mediaType := videoinformationmod.MediaType_Video
if isAv {
mediaType = videoinformationmod.MediaType_AV
}
must := esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields},
},
{"term": esmanager.M{FN.ESVideo.Status: pubdef.InformationStatusVerifyOK}},
{"term": esmanager.M{FN.ESVideo.MediaType: mediaType}},
},
},
}
switch sort {
case string(proto.SearchSortTypeHot):
must = esmanager.M{
"function_score": esmanager.M{
"query": esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields,
}},
{"term": esmanager.M{FN.ESVideo.Status: pubdef.InformationStatusVerifyOK}},
{"term": esmanager.M{FN.ESVideo.MediaType: mediaType}},
},
},
},
"functions": esmanager.A{
esmanager.M{
"field_value_factor": esmanager.M{
"field": FN.ESVideo.WatchTimes,
"factor": 1.0,
"modifier": "none",
},
},
},
"score_mode": "sum",
"boost_mode": "multiply",
},
}
case string(proto.SearchSortTypeNew):
must = esmanager.M{
"bool": esmanager.M{
"must": esmanager.A{
{"multi_match": esmanager.M{
"query": content,
"type": "best_fields",
"fields": fields},
},
{"term": esmanager.M{FN.ESVideo.Status: pubdef.InformationStatusVerifyOK}},
{"term": esmanager.M{FN.ESVideo.MediaType: mediaType}},
},
"should": esmanager.A{
{"range": esmanager.M{FN.ESVideo.AddedTime: esmanager.M{"gte": "now-30d/d", "boost": 2.0}}}, //7天内提升4倍权重
{"range": esmanager.M{FN.ESVideo.AddedTime: esmanager.M{"gte": "now-180d/d", "boost": 1.5}}}, // 30天内提升3倍权重
{"range": esmanager.M{FN.ESVideo.AddedTime: esmanager.M{"gte": "now-365d/d", "boost": 1.1}}}, // 90天内提升1.5倍权重
},
"minimum_should_match": 0, // 允许不匹配任何should条件
},
}
}
query := esmanager.M{
"query": must,
"sort": esmanager.A{
esmanager.M{"_score": esmanager.M{"order": "desc"}},
},
"from": from,
"size": size,
}
log.Info("(esmod:SearchVideo) 执行搜索",
log.Any("index", videoIndex),
log.Any("keywords", content),
log.Any("sort", sort),
log.Any("from", from),
log.Any("size", size))
videos := &ESVideoHits{}
err := esmanager.Instance.Search(videoIndex, videos, query)
if err != nil {
info := fmt.Sprintf(
"(esmod:SearchVideo) Search failed! err:%+v:", err)
log.Warn(info,
log.Any("keywords", content),
log.Any("from", from),
log.Any("size", size))
return 0, nil, srvdef.New(srvdef.ErrElsOperError, "", "")
}
total := int64(0)
rslData := make([]*videoinformationmod.VideoInformation, 0)
if videos != nil && videos.Hits != nil && len(videos.Hits) > 0 {
total = videos.Total.Value
for _, video := range videos.Hits {
rslData = append(rslData, EsVideoInfoToData(video.Source))
}
}
log.Info("(esmod:SearchVideo) 搜索完成",
log.Any("index", videoIndex),
log.Any("keywords", content),
log.Any("total", total),
log.Any("hits", len(rslData)))
return total, rslData, nil
}
func EsVideoInfoToData(esInfo *ESVideo) *videoinformationmod.VideoInformation {
info := &videoinformationmod.VideoInformation{
Id: esInfo.Id,
Title: esInfo.Title,
MediaType: esInfo.MediaType,
AddedTime: esInfo.AddedTime,
CreatorId: esInfo.CreatorId,
CreatorName: esInfo.CreatorName,
Keyworld: esInfo.Keyworld,
FirstTag: esInfo.FirstTag,
SecondTags: esInfo.SecondTags,
CoverImg: esInfo.CoverImg,
Desc: esInfo.Desc,
Remark: esInfo.Remark,
Nodes: esInfo.Nodes,
Status: esInfo.Status,
Video: esInfo.Video,
Tags: esInfo.Tags,
IsHot: esInfo.IsHot,
Sort: esInfo.Sort,
Real: esInfo.Real,
VideoCount: esInfo.VideoCount,
UpdatedAt: esInfo.UpdatedAt,
CreatedAt: esInfo.CreatedAt,
}
return info
}
+47
View File
@@ -0,0 +1,47 @@
package eventmod
import (
"context"
"fmt"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.Event)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Event.Status, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Event.EventType, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Event.EventId, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Event.Status, Value: 1},
{Key: FN.Event.RetryCount, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Event.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(eventmod:Init) Create Event Index failed! err:%+v:", err))
}
}
+130
View File
@@ -0,0 +1,130 @@
package eventmod
import (
"context"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// InsertOneEvent 插入一个事件
func InsertOneEvent(ctx context.Context, event *Event) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, event); err != nil {
log.Warn("eventmod:InsertOneEvent db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// InsertManyEvent 批量插入事件
func InsertManyEvent(ctx context.Context, events *EventList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, events); err != nil {
log.Warn("eventmod:InsertManyEvent db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneEvent 删除一个事件
func DelOneEvent(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("eventmod:DelOneEvent db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyEvent 批量删除事件
func DelManyEvent(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("eventmod:DelManyEvent db.DeleteMany failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneEvent 查找一个事件
func FindOneEvent(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*Event, *srvdef.SrvErr) {
var event Event
if err := db.FindOneEx(ctx, &event, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("eventmod:FindOneEvent db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &event, nil
}
// FindManyEvent 查找多个事件
func FindManyEvent(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (EventList, *srvdef.SrvErr) {
data := make(EventList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("eventmod:FindManyEvent db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountEvent 统计事件数量
func CountEvent(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("eventmod:CountEvent db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneEvent 更新一个事件
func UpdateOneEvent(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("eventmod:UpdateOneEvent db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("eventmod:UpdateOneEvent db.UpdateOne not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyEvent 批量更新事件
func UpdateManyEvent(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMany(ctx, filter, update)
if err != nil {
log.Warn("eventmod:UpdateManyEvent db.UpdateMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount < 1 {
log.Warn("eventmod:UpdateManyEvent db.UpdateMany not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpsertOneEvent 插入或更新一个事件
func UpsertOneEvent(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
opts := options.Update().SetUpsert(true)
if _, err := db.UpdateOne(ctx, filter, update, opts); err != nil {
log.Warn("eventmod:UpsertOneEvent db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
+31
View File
@@ -0,0 +1,31 @@
package eventmod
type TagEvent struct {
ID string //
CreatedAt string // 创建事件
RetryCount string // 重试次数
Status string //
Data string //
EventType string //
EventId string //
UpdatedAt string // 修改时间
}
var FN struct {
Event TagEvent
}
var TN struct {
Event string
}
func init() {
FN.Event.ID = "_id"
FN.Event.CreatedAt = "createdAt"
FN.Event.RetryCount = "retryCount"
FN.Event.Status = "status"
FN.Event.Data = "data"
FN.Event.EventType = "eventType"
FN.Event.EventId = "eventId"
FN.Event.UpdatedAt = "updatedAt"
TN.Event = "event"
}
+32
View File
@@ -0,0 +1,32 @@
package eventmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type EventStatus int
const (
Default EventStatus = 0 // 默认状态,等待上报
Success EventStatus = 1 // 成功
Failure EventStatus = 2 // 失败
)
//go:generate fox mongo --model
//go:generate fox mongo --tag
//go:generate fox mongo --update
// @table:event
// @title:事件表
type Event struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
EventId string `json:"eventId" bson:"eventId"`
EventType string `json:"eventType" bson:"eventType"`
Data string `json:"data" bson:"data"`
Status EventStatus `json:"status" bson:"status"` //
RetryCount int `json:"retryCount" bson:"retryCount"` // 重试次数
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建事件
UpdatedAt time.Time `bson:"updatedAt"` // 修改时间
}
+53
View File
@@ -0,0 +1,53 @@
package eventmod
import (
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type EventList []*Event
type EventUpdate struct {
RetryCount *int `json:"retryCount" bson:"retryCount,omitempty"` // 重试次数
Status *EventStatus `json:"status" bson:"status,omitempty"` //
Data *string `json:"data" bson:"data,omitempty"` //
EventType *string `json:"eventType" bson:"eventType,omitempty"` //
EventId *string `json:"eventId" bson:"eventId,omitempty"` //
UpdatedAt *time.Time `json:"" bson:"updatedAt,omitempty"` // 修改时间
}
type EventQuery struct {
ID *primitive.ObjectID `json:"" bson:"_id,omitempty"` //
RetryCount *int `json:"retryCount" bson:"retryCount,omitempty"` // 重试次数
Status *EventStatus `json:"status" bson:"status,omitempty"` //
Data *string `json:"data" bson:"data,omitempty"` //
EventType *string `json:"eventType" bson:"eventType,omitempty"` //
EventId *string `json:"eventId" bson:"eventId,omitempty"` //
UpdatedAt *time.Time `json:"" bson:"updatedAt,omitempty"` // 修改时间
}
func (query *EventQuery) GetQueryFilter() bson.M {
filter := bson.M{}
if query.ID != nil {
filter[FN.Event.ID] = *query.ID
}
if query.RetryCount != nil {
filter[FN.Event.RetryCount] = *query.RetryCount
}
if query.Status != nil {
filter[FN.Event.Status] = *query.Status
}
if query.Data != nil {
filter[FN.Event.Data] = bson.M{"$regex": primitive.Regex{Pattern: *query.Data, Options: "i"}}
}
if query.EventType != nil {
filter[FN.Event.EventType] = bson.M{"$regex": primitive.Regex{Pattern: *query.EventType, Options: "i"}}
}
if query.EventId != nil {
filter[FN.Event.EventId] = bson.M{"$regex": primitive.Regex{Pattern: *query.EventId, Options: "i"}}
}
if query.UpdatedAt != nil {
filter[FN.Event.UpdatedAt] = *query.UpdatedAt
}
return filter
}
+135
View File
@@ -0,0 +1,135 @@
package homebannermod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 home_banner 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.HomeBanner)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.HomeBanner.Status, Value: 1},
{Key: FN.HomeBanner.UpdatedAt, Value: -1},
{Key: FN.HomeBanner.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HomeBanner.Name, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.HomeBanner.CreatedAt, Value: -1},
{Key: FN.HomeBanner.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HomeBanner.Status, Value: 1},
{Key: FN.HomeBanner.CreatedAt, Value: -1},
{Key: FN.HomeBanner.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HomeBanner.Status, Value: 1},
{Key: FN.HomeBanner.Rank, Value: -1},
{Key: FN.HomeBanner.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(homebannermod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOneHomeBanner 插入一条首页 banner 数据
func InsertOneHomeBanner(ctx context.Context, doc *HomeBanner) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.HomeBanner.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("homebannermod:InsertOneHomeBanner failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneHomeBanner 删除一条首页 banner 数据
func DelOneHomeBanner(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("homebannermod:DelOneHomeBanner failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneHomeBanner 查询一条首页 banner 数据
func FindOneHomeBanner(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*HomeBanner, *srvdef.SrvErr) {
var doc HomeBanner
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("homebannermod:FindOneHomeBanner failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyHomeBanner 按条件查询多条首页 banner 数据
func FindManyHomeBanner(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (HomeBannerList, *srvdef.SrvErr) {
data := make(HomeBannerList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("homebannermod:FindManyHomeBanner failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountHomeBanner 统计满足条件的首页 banner 数量
func CountHomeBanner(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("homebannermod:CountHomeBanner failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneHomeBanner 更新一条首页 banner 数据
func UpdateOneHomeBanner(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("homebannermod:UpdateOneHomeBanner failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+41
View File
@@ -0,0 +1,41 @@
package homebannermod
// TagHomeBanner 保存 home_banner 集合字段名
type TagHomeBanner struct {
Id string
Name string
Image string
VerticalImage string
Url string
Rank string
Status string
CreatedById string
CreatedByName string
UpdatedByName string
CreatedAt string
UpdatedAt string
}
var FN struct {
HomeBanner TagHomeBanner
}
var TN struct {
HomeBanner string
}
func init() {
FN.HomeBanner.Id = "_id"
FN.HomeBanner.Name = "name"
FN.HomeBanner.Image = "image"
FN.HomeBanner.VerticalImage = "verticalImage"
FN.HomeBanner.Url = "url"
FN.HomeBanner.Rank = "rank"
FN.HomeBanner.Status = "status"
FN.HomeBanner.CreatedById = "createdById"
FN.HomeBanner.CreatedByName = "createdByName"
FN.HomeBanner.UpdatedByName = "updatedByName"
FN.HomeBanner.CreatedAt = "createdAt"
FN.HomeBanner.UpdatedAt = "updatedAt"
TN.HomeBanner = "home_banner"
}
+24
View File
@@ -0,0 +1,24 @@
package homebannermod
import "time"
// HomeBanner @table: home_banner
//
// HomeBanner 首页 banner 配置集合模型
type HomeBanner struct {
Id int64 `json:"id" bson:"_id,omitempty"` // ID
Name string `json:"name" bson:"name"` // 名称
Image string `json:"image" bson:"image"` // 图片
VerticalImage string `json:"verticalImage" bson:"verticalImage"` // 竖版图片
Url string `json:"url" bson:"url"` // URL
Rank int64 `json:"rank" bson:"rank"` // 排序
Status bool `json:"status" bson:"status"` // 状态 true-启用 false-停用
CreatedById int64 `json:"createdById" bson:"createdById"` // 创建人ID
CreatedByName string `json:"createdByName" bson:"createdByName"` // 创建人名称
UpdatedByName string `json:"updatedByName" bson:"updatedByName"` // 修改人名称
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// HomeBannerList 首页 banner 列表
type HomeBannerList []*HomeBanner
+101
View File
@@ -0,0 +1,101 @@
package hotnavmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.HotNav)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.HotNav.Sort, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HotNav.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(hotnavmod:Init) Create HotNav Index failed! err:%+v:", err))
}
}
func InsertOneHotNav(ctx context.Context, doc *HotNav) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, doc); err != nil {
log.Warn("hotnavmod:InsertOneHotNav db.InsertOne failed",
log.E(err), log.Any("doc", doc))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
func DelOneHotNav(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("hotnavmod:DelOneHotNav db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
func FindOneHotNav(ctx context.Context, filter bson.M) (*HotNav, *srvdef.SrvErr) {
var doc HotNav
if err := db.FindOneEx(ctx, &doc, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("hotnavmod:FindOneHotNav db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
func FindManyHotNav(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (HotNavList, *srvdef.SrvErr) {
data := make(HotNavList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("hotnavmod:FindManyHotNav db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
func CountHotNav(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("hotnavmod:CountHotNav db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
func UpdateOneHotNav(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("hotnavmod:UpdateOneHotNav db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("hotnavmod:UpdateOneHotNav not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+34
View File
@@ -0,0 +1,34 @@
package hotnavmod
type TagHotNav struct {
CreatedAt string
Icon string
Id string
Intro string
Sort string
Status string
Title string
UpdatedAt string
Url string
}
var FN struct {
HotNav TagHotNav
}
var TN struct {
HotNav string
}
func init() {
FN.HotNav.CreatedAt = "createdAt"
FN.HotNav.Icon = "icon"
FN.HotNav.Id = "_id"
FN.HotNav.Intro = "intro"
FN.HotNav.Sort = "sort"
FN.HotNav.Status = "status"
FN.HotNav.Title = "title"
FN.HotNav.UpdatedAt = "updatedAt"
FN.HotNav.Url = "url"
TN.HotNav = "hot_nav"
}
+19
View File
@@ -0,0 +1,19 @@
package hotnavmod
import "time"
// HotNav 热门导航配置
// @table:hot_nav
type HotNav struct {
Id int64 `json:"id" bson:"_id,omitempty"` // ID
Title string `json:"title" bson:"title"` // 标题
Intro string `json:"intro" bson:"intro"` // 介绍
Url string `json:"url" bson:"url"` // 链接
Icon string `json:"icon" bson:"icon"` // 图标
Sort int64 `json:"sort" bson:"sort"` // 排序
Status bool `json:"status" bson:"status"` // 是否启用
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
type HotNavList []*HotNav
+109
View File
@@ -0,0 +1,109 @@
package ipblackmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.IPBlackModel)
// 初始化索引
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.IPBlackModel.Ip, Value: 1},
},
Options: options.Index().SetUnique(true),
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(IPBlackModel:InitIPBlackModel) Create IPBlackModel Index failed! err:%+v:", err))
}
}
// CountIPBlackModel 统计活动数量
func CountIPBlackModel(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("IPBlackModelmod:CountIPBlackModel db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// InsertOneIPBlackModel 插入一条活动
func InsertOneIPBlackModel(ctx context.Context, IPBlackModel *IPBlackModel) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, IPBlackModel); err != nil {
log.Info("IPBlackModelmod:InsertOneIPBlackModel db.InsertOne failed",
log.E(err), log.Any("IPBlackModel", IPBlackModel))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneIPBlackModel 删除一个活动
func DelOneIPBlackModel(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("IPBlackModelmod:DelOneIPBlackModel db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// UpdateOneIPBlackModel 更新一个IPBlackModel
func UpdateOneIPBlackModel(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("IPBlackModelmod:UpdateOneIPBlackModel db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("IPBlackModelmod:UpdateOneIPBlackModel db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ObjectNotExist, "", "")
}
return nil
}
// FindManyIPBlackModel 查找一批活动数据
func FindManyIPBlackModel(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (IPBlackModelList, *srvdef.SrvErr) {
data := make(IPBlackModelList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("IPBlackModelmod:FindManyAcivities db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// FindOneIPBlackModel 查找一个媒体
func FindOneIPBlackModel(ctx context.Context, filter bson.M) (
*IPBlackModel, *srvdef.SrvErr) {
var IPBlackModel IPBlackModel
if err := db.FindOneEx(ctx, &IPBlackModel, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("IPBlackModel:FindOneIPBlackModel db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ObjectDayStatDoesNotExist, "", "")
}
return &IPBlackModel, nil
}
+26
View File
@@ -0,0 +1,26 @@
package ipblackmod
type TagIPBlackModel struct {
CreatedAt string
ID string
Ip string
Desc string
UpdatedAt string
}
var FN struct {
IPBlackModel TagIPBlackModel
}
var TN struct {
IPBlackModel string
}
func init() {
FN.IPBlackModel.CreatedAt = "createdAt"
FN.IPBlackModel.ID = "_id"
FN.IPBlackModel.Ip = "ip"
FN.IPBlackModel.UpdatedAt = "updatedAt"
FN.IPBlackModel.Desc = "desc"
TN.IPBlackModel = "ip_black"
}
+18
View File
@@ -0,0 +1,18 @@
package ipblackmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 资源同步
// @table:ip_black
type IPBlackModel struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Ip string `json:"ip" bson:"ip"`
Desc string `json:"desc" bson:"desc"` // 备注
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
type IPBlackModelList []*IPBlackModel
+62
View File
@@ -0,0 +1,62 @@
package ipdailystatmod
import (
"context"
"time"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.IpDailyStat)
// 唯一索引:(appId, date)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.IpDailyStat.AppId, Value: 1},
{Key: FN.IpDailyStat.Date, Value: 1},
},
Options: options.Index().SetUnique(true),
},
}
_, _ = db.CreateIndex(ctx, indexes)
}
// UpsertCount 写入或更新指定 appId 当天的 IP 去重数
func UpsertCount(ctx context.Context, appId int64, date string, count int64) error {
filter := bson.M{
FN.IpDailyStat.AppId: appId,
FN.IpDailyStat.Date: date,
}
update := bson.M{
"$set": bson.M{
FN.IpDailyStat.Count: count,
FN.IpDailyStat.UpdatedAt: time.Now(),
},
}
_, err := db.UpsertOne(ctx, filter, update)
return err
}
// FindCount 查询指定 appId 在某天的 IP 去重数,未找到返回 0
func FindCount(ctx context.Context, appId int64, date string) (int64, error) {
filter := bson.M{
FN.IpDailyStat.AppId: appId,
FN.IpDailyStat.Date: date,
}
var stat IpDailyStat
err := db.FindOneEx(ctx, &stat, filter)
if err != nil {
if err == mongo.ErrNoDocuments {
return 0, nil
}
return 0, err
}
return stat.Count, nil
}
+25
View File
@@ -0,0 +1,25 @@
package ipdailystatmod
type tagIpDailyStat struct {
AppId string
Date string
Count string
UpdatedAt string
}
var FN struct {
IpDailyStat tagIpDailyStat
}
var TN struct {
IpDailyStat string
}
func init() {
FN.IpDailyStat.AppId = "appId"
FN.IpDailyStat.Date = "date"
FN.IpDailyStat.Count = "count"
FN.IpDailyStat.UpdatedAt = "updatedAt"
TN.IpDailyStat = "ip_daily_stat"
}
+13
View File
@@ -0,0 +1,13 @@
package ipdailystatmod
import "time"
// IpDailyStat 每日访客 IP 去重统计
// app 端写入,web 端读取,通过共享 MongoDB 跨进程共享数据。
// @table:ip_daily_stat
type IpDailyStat struct {
AppId int64 `bson:"appId"` // 站点 ID
Date string `bson:"date"` // 日期,格式 "20060102"
Count int64 `bson:"count"` // 当日去重 IP 数
UpdatedAt time.Time `bson:"updatedAt"` // 最后同步时间
}
@@ -0,0 +1,73 @@
package m3u8requestlogmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.M3U8RequestLog)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.VideoId, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.M3U8Path, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.ClientIP, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.Host, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.Status, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.TokenOK, Value: 1},
{Key: FN.M3U8RequestLog.PathOK, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(m3u8requestlogmod:Init) Create M3U8RequestLog Index failed! err:%+v:", err))
}
}
func InsertOneM3U8RequestLog(ctx context.Context, doc *M3U8RequestLog) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, doc); err != nil {
log.Warn("m3u8requestlogmod:InsertOneM3U8RequestLog db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
+66
View File
@@ -0,0 +1,66 @@
package m3u8requestlogmod
type TagM3U8RequestLog struct {
CDNDomain string
CFConnectingIP string
ClientIP string
CostMs string
CreatedAt string
Error string
Headers string
Host string
Id string
IsOverseas string
M3U8Path string
PathOK string
Query string
RawQuery string
Referer string
RemoteAddr string
RequestURI string
Status string
T string
Token string
TokenOK string
UserAgent string
VideoId string
XForwardedFor string
XRealIP string
}
var FN struct {
M3U8RequestLog TagM3U8RequestLog
}
var TN struct {
M3U8RequestLog string
}
func init() {
FN.M3U8RequestLog.CDNDomain = "cdnDomain"
FN.M3U8RequestLog.CFConnectingIP = "cfConnectingIP"
FN.M3U8RequestLog.ClientIP = "clientIP"
FN.M3U8RequestLog.CostMs = "costMs"
FN.M3U8RequestLog.CreatedAt = "createdAt"
FN.M3U8RequestLog.Error = "error"
FN.M3U8RequestLog.Headers = "headers"
FN.M3U8RequestLog.Host = "host"
FN.M3U8RequestLog.Id = "_id"
FN.M3U8RequestLog.IsOverseas = "isOverseas"
FN.M3U8RequestLog.M3U8Path = "m3u8Path"
FN.M3U8RequestLog.PathOK = "pathOK"
FN.M3U8RequestLog.Query = "query"
FN.M3U8RequestLog.RawQuery = "rawQuery"
FN.M3U8RequestLog.Referer = "referer"
FN.M3U8RequestLog.RemoteAddr = "remoteAddr"
FN.M3U8RequestLog.RequestURI = "requestURI"
FN.M3U8RequestLog.Status = "status"
FN.M3U8RequestLog.T = "t"
FN.M3U8RequestLog.Token = "token"
FN.M3U8RequestLog.TokenOK = "tokenOK"
FN.M3U8RequestLog.UserAgent = "userAgent"
FN.M3U8RequestLog.VideoId = "videoId"
FN.M3U8RequestLog.XForwardedFor = "xForwardedFor"
FN.M3U8RequestLog.XRealIP = "xRealIP"
TN.M3U8RequestLog = "m3u8_request_log"
}
+37
View File
@@ -0,0 +1,37 @@
package m3u8requestlogmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// M3U8RequestLog records every HLS playlist request for hotlink analysis.
// @table:m3u8_request_log
type M3U8RequestLog struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
CreatedAt time.Time `bson:"createdAt"`
Host string `bson:"host"`
RequestURI string `bson:"requestURI"`
M3U8Path string `bson:"m3u8Path"`
RawQuery string `bson:"rawQuery"`
Query map[string][]string `bson:"query"`
Headers map[string][]string `bson:"headers"`
VideoId int64 `bson:"videoId"`
T int64 `bson:"t"`
Token string `bson:"token"`
ClientIP string `bson:"clientIP"`
RemoteAddr string `bson:"remoteAddr"`
XForwardedFor string `bson:"xForwardedFor"`
XRealIP string `bson:"xRealIP"`
CFConnectingIP string `bson:"cfConnectingIP"`
UserAgent string `bson:"userAgent"`
Referer string `bson:"referer"`
IsOverseas bool `bson:"isOverseas"`
CDNDomain string `bson:"cdnDomain"`
TokenOK bool `bson:"tokenOK"`
PathOK bool `bson:"pathOK"`
Status string `bson:"status"`
Error string `bson:"error"`
CostMs int64 `bson:"costMs"`
}
+202
View File
@@ -0,0 +1,202 @@
package models
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/models/actress"
"videoweb/pub/models/announcementmod"
"videoweb/pub/models/cfg"
"videoweb/pub/models/commentlikemod"
"videoweb/pub/models/commentmod"
"videoweb/pub/models/contactusmod"
"videoweb/pub/models/contenttagmod"
"videoweb/pub/models/detailnavmod"
"videoweb/pub/models/esmod"
"videoweb/pub/models/eventmod"
"videoweb/pub/models/homebannermod"
"videoweb/pub/models/hotnavmod"
"videoweb/pub/models/ipblackmod"
"videoweb/pub/models/ipdailystatmod"
"videoweb/pub/models/m3u8requestlogmod"
"videoweb/pub/models/mwacc"
"videoweb/pub/models/oplog"
"videoweb/pub/models/playletbackflowstatmod"
"videoweb/pub/models/playletcategorymod"
"videoweb/pub/models/playletchaptermod"
"videoweb/pub/models/playletfavoritemod"
"videoweb/pub/models/playlethomeconfigmod"
"videoweb/pub/models/playletlikemod"
"videoweb/pub/models/playletmod"
"videoweb/pub/models/playlettagmod"
"videoweb/pub/models/playletthememod"
"videoweb/pub/models/questionnairemod"
"videoweb/pub/models/richtextcontentmod"
"videoweb/pub/models/seopushmod"
"videoweb/pub/models/syncfilemod"
"videoweb/pub/models/translationcategorymod"
"videoweb/pub/models/translationmod"
"videoweb/pub/models/userlogin"
"videoweb/pub/models/usermod"
"videoweb/pub/models/videocategorymod"
"videoweb/pub/models/videocollectionmediamod"
"videoweb/pub/models/videocreatermod"
"videoweb/pub/models/videofavoritemod"
"videoweb/pub/mongos"
"videoweb/pub/models/videoinformationmod"
"videoweb/pub/models/videolikemod"
"videoweb/pub/models/videotagmod"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func Init() {
log.Info("models init start..")
ctx := context.Background()
cfg.Init(ctx)
mwacc.Init(ctx)
oplog.Init(ctx)
m3u8requestlogmod.Init(ctx)
videocategorymod.Init(ctx)
videoinformationmod.Init(ctx)
videofavoritemod.Init(ctx)
videolikemod.Init(ctx)
videotagmod.Init(ctx)
translationcategorymod.Init(ctx)
translationmod.Init(ctx)
contenttagmod.Init(ctx)
playletcategorymod.Init(ctx)
playlethomeconfigmod.Init(ctx)
playlettagmod.Init(ctx)
playletthememod.Init(ctx)
playletmod.Init(ctx)
playletbackflowstatmod.Init(ctx)
playletchaptermod.Init(ctx)
playletlikemod.Init(ctx)
playletfavoritemod.Init(ctx)
initWatchHistory(ctx)
videocategorymod.Init(ctx)
videocreatermod.Init(ctx)
videotagmod.Init(ctx)
videoinformationmod.Init(ctx)
videocreatermod.Init(ctx)
syncfilemod.Init(ctx)
seopushmod.Init(ctx)
richtextcontentmod.Init(ctx)
announcementmod.Init(ctx)
commentmod.Init(ctx)
commentlikemod.Init(ctx)
videocollectionmediamod.Init(ctx)
ipblackmod.Init(ctx)
esmod.Init(ctx)
actress.Init(ctx)
contactusmod.Init(ctx)
detailnavmod.Init(ctx)
hotnavmod.Init(ctx)
homebannermod.Init(ctx)
eventmod.Init(ctx)
usermod.Init(ctx)
userlogin.Init(ctx)
questionnairemod.Init(ctx)
ipdailystatmod.Init(ctx)
log.Info("models init end")
}
const (
WatchHistoryTypePlaylet int64 = 1
WatchHistoryTypeVideo int64 = 2
WatchHistoryRetentionDays = 60
watchHistoryCollectionName = "watch_history"
WatchHistoryCollectionName = watchHistoryCollectionName
WatchHistoryUserID = "userId"
WatchHistoryDataType = "dataType"
WatchHistoryContentID = "contentId"
WatchHistoryChapterID = "chapterId"
WatchHistoryEpisode = "episode"
WatchHistoryCreatedAt = "createdAt"
WatchHistoryUpdatedAt = "updatedAt"
)
// WatchHistory 保存当前用户最近观看的内容
type WatchHistory struct {
UserID int64 `bson:"userId"`
DataType int64 `bson:"dataType"`
ContentID int64 `bson:"contentId"`
ChapterID int64 `bson:"chapterId"`
Episode int64 `bson:"episode"`
CreatedAt time.Time `bson:"createdAt"`
UpdatedAt time.Time `bson:"updatedAt"`
}
var watchHistoryColl *mongos.Collection
// initWatchHistory 初始化观看历史及 60 天 TTL 索引
func initWatchHistory(ctx context.Context) {
watchHistoryColl = mongos.Shop.Coll(watchHistoryCollectionName)
indexes := []mongo.IndexModel{
{Keys: bson.D{{Key: WatchHistoryUserID, Value: 1}, {Key: WatchHistoryDataType, Value: 1}, {Key: WatchHistoryContentID, Value: 1}}, Options: options.Index().SetUnique(true)},
{Keys: bson.D{{Key: WatchHistoryUserID, Value: 1}, {Key: WatchHistoryDataType, Value: 1}, {Key: WatchHistoryUpdatedAt, Value: -1}, {Key: "_id", Value: -1}}},
{Keys: bson.D{{Key: WatchHistoryUpdatedAt, Value: 1}}, Options: options.Index().SetExpireAfterSeconds(WatchHistoryRetentionDays * 24 * 60 * 60)},
}
if _, err := watchHistoryColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(models:initWatchHistory) Create Index failed! err:%+v:", err))
}
}
// TouchWatchHistory 从已验证的播放清单刷新历史
func TouchWatchHistory(ctx context.Context, item WatchHistory) *srvdef.SrvErr {
filter := bson.M{WatchHistoryUserID: item.UserID, WatchHistoryDataType: item.DataType, WatchHistoryContentID: item.ContentID}
if item.DataType == WatchHistoryTypePlaylet {
sameChapter := bson.M{WatchHistoryUserID: item.UserID, WatchHistoryDataType: item.DataType, WatchHistoryContentID: item.ContentID, WatchHistoryChapterID: item.ChapterID}
result, err := watchHistoryColl.UpdateOne(ctx, sameChapter, bson.M{"$set": bson.M{WatchHistoryUpdatedAt: item.UpdatedAt, WatchHistoryEpisode: item.Episode}})
if err != nil {
log.Warn("TouchWatchHistory failed", log.Any("filter", sameChapter), log.E(err))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount > 0 {
return nil
}
}
update := bson.M{
"$set": bson.M{WatchHistoryChapterID: item.ChapterID, WatchHistoryEpisode: item.Episode, WatchHistoryUpdatedAt: item.UpdatedAt},
"$setOnInsert": bson.M{WatchHistoryUserID: item.UserID, WatchHistoryDataType: item.DataType, WatchHistoryContentID: item.ContentID, WatchHistoryCreatedAt: item.CreatedAt},
}
if _, err := watchHistoryColl.UpdateOne(ctx, filter, update, options.Update().SetUpsert(true)); err != nil {
if mongo.IsDuplicateKeyError(err) {
_, err = watchHistoryColl.UpdateOne(ctx, filter, bson.M{"$set": update["$set"]})
if err == nil {
return nil
}
}
log.Warn("TouchWatchHistory failed", log.Any("filter", filter), log.E(err))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// AggregateWatchHistory 聚合查询观看历史
func AggregateWatchHistory(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := watchHistoryColl.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("AggregateWatchHistory failed", log.Any("pipeline", pipeline), log.E(err))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// DeleteWatchHistory 删除当前用户指定类型的观看历史
func DeleteWatchHistory(ctx context.Context, userID, dataType int64) (int64, *srvdef.SrvErr) {
filter := bson.M{WatchHistoryUserID: userID, WatchHistoryDataType: dataType}
count, err := watchHistoryColl.DeleteMany(ctx, filter)
if err != nil {
log.Warn("DeleteWatchHistory failed", log.Any("filter", filter), log.E(err))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
+170
View File
@@ -0,0 +1,170 @@
package mwacc
import (
"context"
"fmt"
"time"
"videoweb/pub/common/errors"
sErr "videoweb/pub/common/errors"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 过滤查询数量
func AccCountByFilter(ctx context.Context, filters primitive.M, opts ...*options.CountOptions) (c int64, err error) {
c, err = mwAccColl.Count(ctx, filters)
return
}
// 过滤查询账号
func FindOneAccByFilter(ctx context.Context, filters primitive.M, opts ...*options.FindOneOptions) (*MwAcc, error) {
var res MwAcc
err := mwAccColl.FindOne(ctx, &res, filters, opts...)
if err != nil {
log.Error("mwacc FindOneAccByFilter err", log.Any("filters", filters), log.E(err))
}
return &res, err
}
// 过滤更新
func UpOneAccByFilter(ctx context.Context, query primitive.M, update primitive.M) (err error) {
_, err = mwAccColl.UpdateOne(ctx, query, primitive.M{"$set": update})
return
}
// 过滤删除角色
func DelAccByFilter(ctx context.Context, filters primitive.M) (err error) {
_, err = mwAccColl.DeleteOne(ctx, filters)
if err != nil {
log.Error("mwacc DelAccByFilter err", log.Any("filters", filters), log.E(err))
}
return
}
// // 更新最后登录时间
// func UpAccLastTimeById(ctx context.Context, id int64) (*mongo.UpdateResult, error) {
// ret, err := mwAccColl.UpdateOne(ctx, primitive.M{FN.MwAcc.Id: id}, primitive.M{"$set": primitive.M{FN.MwAcc.LastTime: time.Now()}})
// if err != nil {
// log.Error("mvacc UpLastTimeById err", log.Any(FN.MwAcc.Id, id), log.E(err))
// }
// return ret, err
// }
// 绑定二维码
func BindAccQurl(ctx context.Context, acc string) (ok bool, err error) {
res, dataErr := FindOneAccByFilter(ctx, primitive.M{
FN.MwAcc.Acc: acc,
})
if dataErr != nil || res.Id == 0 {
err = sErr.MakeWithMsg(sErr.Logo, "用户不存在!")
return false, err
}
if res.IsEnb == false {
err = sErr.MakeWithMsg(sErr.UserPermission, "用户被禁用!")
return false, err
}
err = UpOneAccByFilter(ctx, primitive.M{
FN.MwAcc.Acc: acc,
}, primitive.M{
FN.MwAcc.IsBase32: true,
})
if err != nil {
return false, err
}
return true, err
}
// 插入角色
func AccAdd(ctx context.Context, insertReq *AccInsertDoc) (id int64, ok bool, err error) {
insertReq.Id = int64(mongos.Lid.MwAcc.Get())
insertReq.CreatedAt = time.Now()
_, err = mwAccColl.InsertOne(ctx, insertReq)
if err != nil {
log.ZapLog.Error(fmt.Sprintf("InsertRole mongo error %v", err))
err = errors.MakeWithErr(errors.DBInsert, err)
return 0, false, err
}
return insertReq.Id, true, nil
}
// 获取角色列表
func GetAccList(ctx context.Context, search primitive.M, sort []primitive.M) (
total int64, data []*AccGetListRec, err error) {
var countPipe []primitive.M
countPipe = append(countPipe, search, bson.M{"$count": "total"})
var aggCount AggStatCount
err = mwAccColl.ObjectAggregate(ctx, &aggCount, countPipe)
if err != nil {
return 0, nil, err
}
total = aggCount.Total
var pip []primitive.M
pip = append(pip, search)
pip = append(pip, sort...)
pip = append(pip,
primitive.M{
"$lookup": primitive.M{
"localField": FN.MwAcc.RoleId,
"from": TN.MwRole,
"foreignField": FN.MwRole.Id,
"as": "roles",
},
},
primitive.M{"$unwind": primitive.M{
"path": "$roles",
"preserveNullAndEmptyArrays": true,
},
},
primitive.M{
"$project": primitive.M{
FN.MwAcc.Id: 1,
FN.MwAcc.UserName: 1,
FN.MwAcc.Acc: 1,
FN.MwAcc.Pwd: 1,
FN.MwAcc.Email: 1,
FN.MwAcc.RoleId: 1,
FN.MwAcc.RoleName: "$roles.name",
FN.MwAcc.Base32: 1,
FN.MwAcc.IsBase32: 1,
// mwacc.FN.MwAcc.LastTime: 1,
FN.MwAcc.IsEnb: 1,
FN.MwAcc.Feedback: 1,
FN.MwAcc.CreatedAt: 1,
FN.MwAcc.UpdatedAt: 1,
FN.MwAcc.LimitIP: 1,
},
})
err = mwAccColl.Aggregate(ctx, &data, pip)
if err != nil {
err = errors.MakeWithErr(errors.DBQuery, err)
return
}
return
}
// 过滤查询账号
func FindManyAccByFilter(ctx context.Context, filters primitive.M, opts ...*options.FindOptions) ([]*MwAcc, *srvdef.SrvErr) {
var res []*MwAcc
err := mwAccColl.Find(ctx, &res, filters, opts...)
if err != nil {
log.Error("mwacc FindOneAccByFilter err", log.Any("filters", filters), log.E(err))
return res, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
log.Info("success")
return res, nil
}
+13
View File
@@ -0,0 +1,13 @@
package mwacc
import "videoweb/pub/mongos"
var (
mwAccColl *mongos.Collection = nil
mwRoleColl *mongos.Collection = nil
mwAccTokenColl *mongos.Collection = nil
)
type AggStatCount struct {
Total int64 `bson:"total"`
}
+66
View File
@@ -0,0 +1,66 @@
package mwacc
import (
"context"
"fmt"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
// Init 初始化数据
func Init(ctx context.Context) {
mwAccColl = mongos.Shop.Coll(TN.MwAcc)
mwRoleColl = mongos.Shop.Coll(TN.MwRole)
mwAccTokenColl = mongos.Shop.Coll(TN.MwAccToken)
initIndex(ctx)
return
}
// initIndex 初始化索引
func initIndex(ctx context.Context) {
initAccIndex(ctx)
initRoleIndex(ctx)
initAccTokenIndex(ctx)
}
func initAccIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{FN.MwAcc.Id, 1},
},
},
}
if _, err := mwAccColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(mwacc:initAccIndex) Create mwacc Index failed! err:%+v:", err))
}
}
func initRoleIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{FN.MwRole.Id, 1},
},
// Options: options.Index().SetUnique(true),
},
}
if _, err := mwRoleColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(mwacc:initRoleIndex) Create mwacc Index failed! err:%+v:", err))
}
}
func initAccTokenIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{FN.MwAccToken.Id, 1},
},
// Options: options.Index().SetUnique(true),
},
}
if _, err := mwAccTokenColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(mwacc:initAccTokenIndex) Create mwacc Index failed! err:%+v:", err))
}
}
+61
View File
@@ -0,0 +1,61 @@
package mwacc
import (
"strconv"
"videoweb/pub/pubdef"
"go.mongodb.org/mongo-driver/bson"
)
func MakeSearch(keyWords string, status int64, page pubdef.Page) (searchs bson.M) {
var search []bson.M
if len(keyWords) > 0 {
userId, _ := strconv.ParseInt(keyWords, 10, 64)
search = append(search, bson.M{FN.MwAcc.Id: userId})
search = append(search, bson.M{FN.MwAcc.UserName: bson.M{"$regex": keyWords}})
search = append(search, bson.M{FN.MwAcc.Acc: bson.M{"$regex": keyWords}})
search = append(search, bson.M{FN.MwAcc.Email: bson.M{"$regex": keyWords}})
}
match := bson.M{}
if len(search) > 0 {
match["$or"] = search
}
if status > 0 {
if status == 1 {
match[FN.MwAcc.IsEnb] = true
} else {
match[FN.MwAcc.IsEnb] = false
}
}
searchs = bson.M{}
searchs["$match"] = match
return
}
func MakeSort(pageNum int64, pageSize int64) (sort []bson.M) {
sort = append(sort, bson.M{
"$sort": bson.M{
FN.MwAcc.CreatedAt: -1,
},
})
if pageNum <= 0 {
pageNum = 1
}
if pageSize <= 0 {
pageSize = 10
}
skip := (pageNum - 1) * pageSize
sort = append(sort, bson.M{
"$skip": skip,
})
sort = append(sort, bson.M{
"$limit": pageSize,
})
return
}
+130
View File
@@ -0,0 +1,130 @@
// Code generated by gen_bson_tag. DO NOT EDIT.
package mwacc
import (
"context"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// CreateOneMwAcc 创建一个MwAcc
func CreateOneMwAcc(ctx context.Context, data *MwAcc) *srvdef.SrvErr {
_, err := mwAccColl.InsertOne(ctx, data)
if err != nil {
log.Error("mwacc:CreateOneMwAcc db.InsertOne failed",
log.Any("doc", data),
log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// FindOneMwAcc 查找一个MwAcc
func FindOneMwAcc(ctx context.Context, filter bson.M) (
*MwAcc, *srvdef.SrvErr) {
var data *MwAcc
if err := mwAccColl.FindOneEx(ctx, &data, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("mwacc:FindOneMwAcc mwAccColl.FindOneEx failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return data, nil
}
// DelOneOneMwAcc 删除一个MwAcc
func DelOneOneMwAcc(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := mwAccColl.DeleteOne(ctx, filter)
if err != nil {
log.Warn("mwacc:DelOneOneMwAcc mwAccColl.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// UpdateOneMwAcc 更新一个MwAcc
func UpdateOneMwAcc(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := mwAccColl.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("mwacc:UpdateOneMwAcc mwAccColl.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// CountMwAccs 统计MwAcc数量
func CountMwAccs(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := mwAccColl.Count(ctx, filter)
if err != nil {
log.Warn("mwacc:CountMwAccs mwAccColl.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// FindManyMwAccs 查找一批MwAcc
func FindManyMwAccs(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (MwAccList, *srvdef.SrvErr) {
data := make(MwAccList, 0)
if err := mwAccColl.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("mwacc:FindManyMwAccs mwAccColl.Find failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// FindManyMwAccsWithBind 用自己定义结构查找一批MwAcc数据
func FindManyMwAccsWithBind(ctx context.Context, bind interface{}, filter bson.M,
opts ...*options.FindOptions) *srvdef.SrvErr {
if err := mwAccColl.Find(ctx, bind, filter, opts...); err != nil {
log.Warn("mwacc:FindManyMwAccsWithBind mwAccColl.Find failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// AggregateMwAccs 聚合查找一批MwAcc
func AggregateMwAccs(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := mwAccColl.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("mwacc:AggregateMwAccs mwAccColl.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateMwAccs 聚合查找一批MwAcc数据
func ObjectAggregateMwAccs(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := mwAccColl.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("mwacc:AggregateMwAccs mwAccColl.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateMwAccs 批量写入或者更新MwAcc数据
func BulkWriteMwAccs(ctx context.Context,
docs []mongo.WriteModel, opts ...*options.BulkWriteOptions) *srvdef.SrvErr {
_, err := mwAccColl.BulkWrite(ctx, docs, opts...)
if err != nil {
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
+158
View File
@@ -0,0 +1,158 @@
package mwacc
import (
"context"
"fmt"
"time"
"videoweb/pub/common/errors"
"videoweb/pub/common/log"
"videoweb/pub/common/pageopt"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 角色聚集处理
func RoleAggregate(ctx context.Context, filters []primitive.M, opts ...*options.AggregateOptions) (roles []*MwRole, err error) {
roles = make([]*MwRole, 0)
err = mwRoleColl.Aggregate(ctx, &roles, filters)
return
}
// 过滤查询数量
func RoleCountByFilter(ctx context.Context, filters primitive.M, opts ...*options.CountOptions) (c int64, err error) {
c, err = mwRoleColl.Count(ctx, filters)
return
}
// 过滤查询角色
func FindOneRoleByFilter(ctx context.Context, filters primitive.M, opts ...*options.FindOneOptions) (*MwRole, *srvdef.SrvErr) {
var res MwRole
err := mwRoleColl.FindOne(ctx, &res, filters, opts...)
if err != nil {
log.Error("mwacc FindOneRoleByFilter err", log.Any("filters", filters), log.E(err))
return &res, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return &res, nil
}
// 过滤更新
func UpOneRoleByFilter(ctx context.Context, query primitive.M, update primitive.M) *srvdef.SrvErr {
_, err := mwRoleColl.UpdateOne(ctx, query, update)
if err != nil {
log.Error("mwacc UpOneRoleByFilter: db.UpdateOne err", log.Any("update", update), log.E(err))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// 过滤删除角色
func DelRoleByFilter(ctx context.Context, filters primitive.M) *srvdef.SrvErr {
_, err := mwRoleColl.DeleteOne(ctx, filters)
if err != nil {
log.Error("mwacc DelRoleByFilter err", log.Any("filters", filters), log.E(err))
return srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return nil
}
// 更新角色权限
func UpRoleAuth(ctx context.Context, id int64, keys []string, dataRouter []*Router) (ok bool, err error) {
_, err = mwRoleColl.UpdateOne(ctx, primitive.M{
FN.MwRole.Id: id,
}, primitive.M{
"$set": primitive.M{
FN.MwRole.ApiMenus: keys,
FN.MwRole.Router: dataRouter,
},
})
if err != nil {
log.Error("mvacc UpRoleAuth err", log.Any(FN.MwRole.Id, id), log.E(err))
return false, err
}
return true, nil
}
// 获取角色列表
func GetRoleList(ctx context.Context, skip, limit int64, matchs ...pageopt.Matcher) (data []*RoleGetListRec, err error) {
data = make([]*RoleGetListRec, 0)
err = mwRoleColl.Aggregate(ctx, &data,
[]primitive.M{
{"$match": pageopt.MergeM(matchs)},
{"$sort": primitive.M{FN.MwRole.Id: -1}},
{"$skip": skip},
{"$limit": limit},
{"$lookup": primitive.M{
"localField": FN.MwRole.Id,
"from": TN.MwAcc,
"foreignField": FN.MwAcc.RoleId,
"as": "onlyRole",
}},
{"$project": primitive.M{
FN.MwRole.Id: 1,
FN.MwRole.Name: 1,
FN.MwRole.Desc: 1,
FN.MwRole.IsEnb: 1,
FN.MwRole.ApiMenus: 1,
FN.MwRole.CreatedAt: 1,
FN.MwRole.UpdatedAt: 1,
"account": primitive.M{
"$size": "$onlyRole",
},
}},
})
if err != nil && err.Error() != errors.NotFind {
log.ZapLog.Error(fmt.Sprintf("mwacc GetRoleList error %v", err))
err = errors.MakeWithErr(errors.DBQuery, err)
return
}
return
}
// 下拉列表
func RoleDrop(ctx context.Context) (data []*RoleDropDoc, err error) {
query := primitive.M{FN.MwRole.IsEnb: true}
opt := options.Find().SetProjection(primitive.M{
FN.MwRole.Id: 1,
FN.MwRole.Name: 1,
})
err = mwRoleColl.Find(ctx, &data, query, opt)
if err != nil {
err = errors.MakeWithErr(errors.DBQuery, err)
return
}
return
}
// 插入角色
func RoleAdd(ctx context.Context, name string, desc string, isEnb bool) (ok bool, err error) {
c, err := mwRoleColl.Count(ctx, primitive.M{FN.MwRole.Name: name})
if c > 0 {
err = errors.MakeWithMsg(errors.DBInsert, "角色名称")
return false, err
}
_, err = mwRoleColl.InsertOne(ctx, primitive.M{
FN.MwRole.Id: mongos.Lid.MwRole.Get(),
FN.MwRole.Name: name,
FN.MwRole.Desc: desc,
FN.MwRole.IsEnb: isEnb,
FN.MwRole.CreatedAt: time.Now(),
})
if err != nil {
log.ZapLog.Error(fmt.Sprintf("InsertRole mongo error %v", err))
err = errors.MakeWithErr(errors.DBInsert, err)
return false, err
}
return true, nil
}
+88
View File
@@ -0,0 +1,88 @@
package mwacc
type TagMwRole struct {
ApiMenus string
CreatedAt string
Desc string
Id string
IsEnb string
Name string
Router string
UpdatedAt string
}
type TagMwAcc struct {
Acc string
Base32 string
Code string
CreatedAt string
Email string
Feedback string
Id string
IsBase32 string
IsEnb string
LastTime string
LimitIP string
Pwd string
Qurl string
RoleId string
RoleName string
Token string
UpdatedAt string
UserName string
}
type TagMwAccToken struct {
AccId string
CreatedAt string
Id string
Token string
UpdatedAt string
}
var FN struct {
MwRole TagMwRole
MwAcc TagMwAcc
MwAccToken TagMwAccToken
}
var TN struct {
MwRole string
MwAcc string
MwAccToken string
}
func init() {
FN.MwRole.ApiMenus = "apiMenus"
FN.MwRole.CreatedAt = "createdAt"
FN.MwRole.Desc = "desc"
FN.MwRole.Id = "_id"
FN.MwRole.IsEnb = "isEnb"
FN.MwRole.Name = "name"
FN.MwRole.Router = "router"
FN.MwRole.UpdatedAt = "updatedAt"
FN.MwAcc.Acc = "acc"
FN.MwAcc.Base32 = "base32"
FN.MwAcc.Code = "code"
FN.MwAcc.CreatedAt = "createdAt"
FN.MwAcc.Email = "email"
FN.MwAcc.Feedback = "feedback"
FN.MwAcc.Id = "_id"
FN.MwAcc.IsBase32 = "isBase32"
FN.MwAcc.IsEnb = "isEnb"
FN.MwAcc.LastTime = "lastTime"
FN.MwAcc.LimitIP = "limitIP"
FN.MwAcc.Pwd = "pwd"
FN.MwAcc.Qurl = "qurl"
FN.MwAcc.RoleId = "roleId"
FN.MwAcc.RoleName = "roleName"
FN.MwAcc.Token = "token"
FN.MwAcc.UpdatedAt = "updatedAt"
FN.MwAcc.UserName = "userName"
FN.MwAccToken.AccId = "accId"
FN.MwAccToken.CreatedAt = "createdAt"
FN.MwAccToken.Id = "_id"
FN.MwAccToken.Token = "token"
FN.MwAccToken.UpdatedAt = "updatedAt"
TN.MwRole = "mw_role"
TN.MwAcc = "mw_acc"
TN.MwAccToken = "mw_acc_token"
}
+84
View File
@@ -0,0 +1,84 @@
package mwacc
import (
"context"
"time"
"videoweb/pub/common/errors"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 过滤更新
func UpOneTokenByFilter(ctx context.Context, query primitive.M, update primitive.M) (err error) {
_, err = mwAccTokenColl.UpdateOne(ctx, query, primitive.M{"$set": update})
return
}
func SaveToken(ctx context.Context, accId int64, token string) (ok bool, err error) {
var booToken MwAccToken
// 查找
err = mwAccTokenColl.FindOne(ctx, &booToken, primitive.M{FN.MwAccToken.AccId: accId})
if booToken.AccId > 0 {
// 更新
err = UpOneTokenByFilter(ctx, primitive.M{
FN.MwAccToken.AccId: accId,
}, primitive.M{
FN.MwAccToken.Token: token,
FN.MwAccToken.UpdatedAt: time.Now(),
})
if err != nil {
return false, err
}
return true, nil
}
if err != nil || booToken.AccId == 0 {
if _, err := mwAccTokenColl.InsertOne(ctx,
primitive.M{
FN.MwAccToken.Id: mongos.Lid.MwAccToken.Get(),
FN.MwAccToken.AccId: accId,
FN.MwAccToken.Token: token,
FN.MwAccToken.CreatedAt: time.Now(),
}); err != nil {
return false, err
}
}
return true, nil
}
func CheckToken(ctx context.Context, token string) (ok bool, err error) {
var booToken MwAccToken
Terr := mwAccTokenColl.FindOne(ctx, &booToken, primitive.M{FN.MwAccToken.Token: token})
if Terr != nil || booToken.AccId == 0 {
err = errors.MakeWithMsg(errors.NoToken, "token 不存在或已过期")
return false, err
}
return true, nil
}
// // 检测Token
// func CheckToken(ctx context.Context, token string) (ok bool, err error) {
// var booToken WebToken
// Terr := tokenColl.FindOne(ctx, &booToken, primitive.M{"token": token})
// if Terr != nil || booToken.Id == 0 {
// err = errors.MakeWithMsg(errors.NoToken, "token 不存在或已过期")
// return
// }
// return true, nil
// }
// 删除token
func DeleteOneToken(ctx context.Context, filter bson.M) *srvdef.SrvErr {
if _, err := mwAccTokenColl.DeleteOne(ctx, filter); err != nil {
log.Warn("mwacc:DeleteOneToken db.DeleteOne failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return nil
}
+78
View File
@@ -0,0 +1,78 @@
package mwacc
import (
"time"
)
type Meta struct {
Title string `bson:"title"`
Icon string `bson:"icon"`
NoCache bool `bson:"noCache"`
}
type Apiurl struct {
Url []string `bson:"url"`
Desc string `bson:"desc"`
Status bool `bson:"status"`
Method []string `bson:"method"`
}
// 编辑返回去的数据
type Router struct {
Path string `bson:"path"`
Component string `bson:"component"`
Redirect string `bson:"redirect"`
Name string `bson:"name"`
IsShow bool `bson:"isShow"`
Hidden bool `bson:"hidden"`
Meta Meta `bson:"meta"`
Children []Router `bson:"children"`
ApiUrl []Apiurl `bson:"apiUrl"`
}
// 角色
// @table:mw_role
type MwRole struct {
Id int64 `bson:"_id"`
Name string `bson:"name"` // 角色名称
Desc string `bson:"desc"` // 描述
IsEnb bool `bson:"isEnb"` // 是否启用 false:禁用 true:启用
ApiMenus []string `bson:"apiMenus"` // 已有权限的api
Router []Router `bson:"router"`
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
}
// 账号
// @table:mw_acc
type MwAcc struct {
Id int64 `bson:"_id"` // id
UserName string `bson:"userName"` // 用户名
Acc string `bson:"acc"` // 账号
Pwd string `bson:"pwd"` // 密码
Email string `bson:"email"` // 邮箱
RoleId int64 `bson:"roleId"` // 角色Id
RoleName string `bson:"roleName"` // 角色名
Base32 string `bson:"base32"` // 二步签名
IsBase32 bool `bson:"isBase32"` // 是否已签名
Code string `bson:"code"` // 验证码
Qurl []byte `bson:"qurl"` // 二维码链接
Token string `bson:"token"` // token
LastTime time.Time `bson:"lastTime"` // 登录时间
IsEnb bool `bson:"isEnb"` // 使能
Feedback string `bson:"feedback"` // 禁用原因
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
LimitIP []string `bson:"limitIP"` // 限制IP
}
type MwAccList []*MwAcc
// 账号Token
// @table:mw_acc_token
type MwAccToken struct {
Id int64 `bson:"_id"` // id
AccId int64 `bson:"accId"` // 账号id
Token string `bson:"token"` // token
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
}
+53
View File
@@ -0,0 +1,53 @@
package mwacc
import (
"time"
)
type AccGetListRec struct {
Id int64 `bson:"_id"` // id
Username string `bson:"username"` // 用户名
Acc string `bson:"acc"` // 用户名
Pwd string `bson:"pwd"` // 密码
Email string `bson:"email"` // 邮箱
RoleId int64 `bson:"roleId"` // 角色Id
RoleName string `bson:"roleName"` // 角色名
// Base32 string `bson:"base32"` // 二步签名
IsBase32 bool `bson:"isBase32"` // 是否已签名
IsEnb bool `bson:"isEnb"` // 使能
Feedback string `bson:"feedback"` // 禁用原因
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
LimitIP []string `bson:"limitIP"` // 允许访问的IP
}
type RoleGetListRec struct {
Id int64 `bson:"_id"` // 角色Id
Name string `bson:"name"` // 角色名称
Desc string `bson:"desc"` // 描述
IsEnb bool `bson:"isEnb"` // 是否启用 false:禁用 true:启用
ApiMenus []string `bson:"apiMenus"` // 已有权限的api
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
AccCount int64 `bson:"accCount"` // 账户数量
}
type AccInsertDoc struct {
Id int64 `bson:"_id"` // id
UserName string `bson:"userName"` // 用户名
Pwd string `bson:"pwd"` // 密码
Acc string `bson:"acc"` // 用户名
Email string `bson:"email"` // 邮箱
RoleId int64 `bson:"roleId"` // 角色Id
Base32 string `bson:"base32"` // 二步签名
IsBase32 bool `bson:"isBase32"` // 是否已签名
IsEnb bool `bson:"isEnb"` // 使能
LastTime time.Time `bson:"lastTime"` // 登录时间
CreatedAt time.Time `bson:"createdAt"` // 创建时间
LimitIP []string `bson:"limitIP"` // 允许访问的IP
}
type RoleDropDoc struct {
Id int64 `bson:"_id"` // 角色Id
Name string `bson:"name"` // 角色名称
}
+9
View File
@@ -0,0 +1,9 @@
package oplog
import (
"videoweb/pub/mongos"
)
var (
opLogColl *mongos.Collection
)
+175
View File
@@ -0,0 +1,175 @@
package oplog
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/common/utils"
"videoweb/pub/mongos"
"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"
)
// Init 初始化数据
func Init(ctx context.Context) {
opLogColl = mongos.ShopLog.Coll(TN.OpLog)
initIndex(ctx)
return
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{FN.OpLog.ActId, 1},
{FN.OpLog.Action, 1},
{FN.OpLog.Path, 1},
},
},
{
Keys: bson.D{
{FN.OpLog.CreatedAt, -1},
},
},
}
if _, err := opLogColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(oplog:initIndex) Create adLog Index failed! err:%+v:", err))
}
}
// 添加日志
func AddLog(ctx context.Context, path string, desc string, actId int64, rawData, ip string) (err error) {
_, err = opLogColl.InsertOne(ctx, primitive.M{
FN.OpLog.Id: mongos.Lid.MwOpLog.Get(),
FN.OpLog.Action: desc,
FN.OpLog.Path: path,
FN.OpLog.ActId: actId,
FN.OpLog.RawData: rawData,
FN.OpLog.CreatedAt: utils.Now(),
FN.OpLog.IP: ip,
})
return
}
type LogReq struct {
PageNum int64 `json:"pageNum"` // 页码
PageSize int64 `json:"pageSize"` //
Path *string `json:"path"` // 请求接口
Action *string `json:"action"` // 操作目的
ActId *int64 `json:"actId"` // 操作人Id
StartTime *time.Time `json:"startTime"` // 开始时间
EndTime *time.Time `json:"endTime"` // 开始时间
}
// 操作日志信息
type OpLogInfo struct {
Path string `json:"path" bson:"path"` // 请求接口
ActId int64 `json:"actId" bson:"actId"` // 操作人Id
Action string `json:"action" bson:"action"` // 操作目的
Param string `json:"param" bson:"rawData"` // 操作内容
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 操作时间
ActName string `json:"actName" bson:"actName"` // 操作人
}
type OpPageRes struct {
Total int64 `json:"total" bson:"total"`
List []*OpLogInfo `json:"list" bson:"list"`
}
// 获取日志列表
func PageLogList(ctx context.Context, req *LogReq) (res *OpPageRes, err error) {
filter := bson.M{}
if req.Path != nil && *req.Path != "" {
filter[FN.OpLog.Path] = bson.M{"$regex": req.Path}
}
if req.Action != nil && *req.Action != "" {
filter[FN.OpLog.Action] = req.Action
}
if req.ActId != nil && *req.ActId > 0 {
filter[FN.OpLog.ActId] = req.ActId
}
if req.StartTime != nil && req.EndTime != nil {
filter[FN.OpLog.CreatedAt] = bson.M{"$gte": req.StartTime, "$lt": req.EndTime}
}
res = new(OpPageRes)
res.Total, err = mongos.ShopLog.Coll(TN.OpLog).Count(ctx, filter)
if err != nil {
return
}
sort := bson.M{FN.OpLog.CreatedAt: -1}
opt := &options.FindOptions{}
opt.SetSort(sort)
skip := (req.PageNum - 1) * req.PageSize
opt.SetSkip(skip)
opt.SetLimit(req.PageSize)
list := make(OpLogList, 0)
err = mongos.ShopLog.Coll(TN.OpLog).Find(ctx, &list, filter, opt)
if err != nil {
return
}
actIds := make([]int64, 0)
for _, v := range list {
actIds = append(actIds, v.ActId)
}
// err = opLogColl.Aggregate(ctx, &res.List, []bson.M{
// {"$match": conf},
// {"$sort": bson.M{FN.OpLog.CreatedAt: -1}},
// {"$skip": (req.PageNum - 1) * req.PageSize},
// {"$limit": req.PageSize},
// {"$lookup": bson.M{
// "localField": FN.OpLog.ActId,
// "from": mwacc.TN.MwAcc,
// "foreignField": mwacc.FN.MwAcc.Id,
// "as": "admins",
// }},
// {"$unwind": "$admins"},
// {"$project": bson.M{
// FN.OpLog.Path: 1,
// FN.OpLog.Action: 1,
// FN.OpLog.ActId: 1,
// FN.OpLog.RawData: 1,
// FN.OpLog.CreatedAt: 1,
// "actName": "$admins.userName",
// }},
// })
return
}
// CountOpLogs 计算某个查询的数量
func CountOpLogs(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
total, err := mongos.ShopLog.Coll(TN.OpLog).Count(ctx, filter)
if err != nil {
log.Info("oplog:CountOpLogs db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return total, nil
}
// InsertOneUser 插入一个用户
func InsertOneUser(ctx context.Context, opLog *OpLog) *srvdef.SrvErr {
if _, err := mongos.ShopLog.Coll(TN.OpLog).InsertOne(ctx, opLog); err != nil {
log.Warn("oplog:InsertOneUser db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// FindManyOpLogs 查找一批数据
func FindManyOpLogs(ctx context.Context,
filter bson.M, opts ...*options.FindOptions) (
OpLogList, *srvdef.SrvErr) {
data := make(OpLogList, 0)
if err := mongos.ShopLog.Coll(TN.OpLog).Find(ctx, &data, filter, opts...); err != nil {
log.Warn("oplog:FindManyOpLogs db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
+34
View File
@@ -0,0 +1,34 @@
package oplog
type TagOpLog struct {
ActId string
Action string
CreatedAt string
IP string
Id string
IsWhite string
OpType string
Path string
RawData string
}
var FN struct {
OpLog TagOpLog
}
var TN struct {
OpLog string
}
func init() {
FN.OpLog.ActId = "actId"
FN.OpLog.Action = "action"
FN.OpLog.CreatedAt = "createdAt"
FN.OpLog.IP = "ip"
FN.OpLog.Id = "_id"
FN.OpLog.IsWhite = "isWhite"
FN.OpLog.OpType = "opType"
FN.OpLog.Path = "path"
FN.OpLog.RawData = "rawData"
TN.OpLog = "mw_op_log"
}
+22
View File
@@ -0,0 +1,22 @@
package oplog
import (
"time"
"videoweb/pub/common"
)
// 操作日志
// @table:mw_op_log
type OpLog struct {
Id int64 `bson:"_id"` // id
Path string `bson:"path"` // 请求接口
OpType common.ApiOpType `bson:"opType"` // 操作类型
IsWhite bool `bson:"isWhite"` // 是否白名单
ActId int64 `bson:"actId"` // 操作人Id
Action string `bson:"action"` // 操作目的
RawData string `bson:"rawData"` // 原始数据
CreatedAt time.Time `bson:"createdAt"` // 操作时间
IP string `bson:"ip"` // 操作人IP
}
type OpLogList []*OpLog
+172
View File
@@ -0,0 +1,172 @@
package playletbackflowstatmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"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"
)
var coll *mongos.Collection
// Init 初始化原创短剧 AI 内容回流日统计表和查询索引。
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletBackflowDailyStat)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletBackflowDailyStat.DataDate, Value: 1},
{Key: FN.PlayletBackflowDailyStat.ReportStatus, Value: 1},
{Key: FN.PlayletBackflowDailyStat.Id, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletBackflowDailyStat.DataDate, Value: 1},
{Key: FN.PlayletBackflowDailyStat.PlayletId, Value: 1},
},
Options: options.Index().SetUnique(true).SetName("uniq_dataDate_playletId"),
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletbackflowstatmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// UpsertManyPlayletBackflowDailyStats 批量保存每天原创短剧回流数据快照。
func UpsertManyPlayletBackflowDailyStats(ctx context.Context, docs PlayletBackflowDailyStatList) *srvdef.SrvErr {
if len(docs) == 0 {
return nil
}
now := time.Now()
writes := make([]mongo.WriteModel, 0, len(docs))
for _, doc := range docs {
if doc == nil || doc.DataDate == "" || doc.PlayletId <= 0 {
continue
}
doc.UpdatedAt = now
doc.LastStatAt = now
update := bson.M{
"$set": bson.M{
FN.PlayletBackflowDailyStat.DataDate: doc.DataDate,
FN.PlayletBackflowDailyStat.PlayletId: doc.PlayletId,
FN.PlayletBackflowDailyStat.ChapterId: doc.ChapterId,
FN.PlayletBackflowDailyStat.CurrentEpisode: doc.CurrentEpisode,
FN.PlayletBackflowDailyStat.MediaCenterId: doc.MediaCenterId,
FN.PlayletBackflowDailyStat.MediaContentId: doc.MediaContentId,
FN.PlayletBackflowDailyStat.Title: doc.Title,
FN.PlayletBackflowDailyStat.PublishedData: doc.PublishedData,
FN.PlayletBackflowDailyStat.ScriptName: doc.ScriptName,
FN.PlayletBackflowDailyStat.DramaName: doc.DramaName,
FN.PlayletBackflowDailyStat.DramaNo: doc.DramaNo,
FN.PlayletBackflowDailyStat.VideoURL: doc.VideoURL,
FN.PlayletBackflowDailyStat.PlatformURL: doc.PlatformURL,
FN.PlayletBackflowDailyStat.Views: doc.Views,
FN.PlayletBackflowDailyStat.Clicks: doc.Clicks,
FN.PlayletBackflowDailyStat.Likes: doc.Likes,
FN.PlayletBackflowDailyStat.LikeRate: doc.LikeRate,
FN.PlayletBackflowDailyStat.CompletionRate: doc.CompletionRate,
FN.PlayletBackflowDailyStat.PaidRate: doc.PaidRate,
FN.PlayletBackflowDailyStat.Comments: doc.Comments,
FN.PlayletBackflowDailyStat.Shares: doc.Shares,
FN.PlayletBackflowDailyStat.CompletionRateScope: doc.CompletionRateScope,
FN.PlayletBackflowDailyStat.ReportStatus: doc.ReportStatus,
FN.PlayletBackflowDailyStat.ReportError: "",
FN.PlayletBackflowDailyStat.LastStatAt: doc.LastStatAt,
FN.PlayletBackflowDailyStat.UpdatedAt: doc.UpdatedAt,
},
"$setOnInsert": bson.M{
FN.PlayletBackflowDailyStat.Id: primitive.NewObjectID(),
FN.PlayletBackflowDailyStat.ReportRetryCount: int64(0),
FN.PlayletBackflowDailyStat.CreatedAt: now,
},
}
model := mongo.NewUpdateOneModel().
SetFilter(bson.M{
FN.PlayletBackflowDailyStat.DataDate: doc.DataDate,
FN.PlayletBackflowDailyStat.PlayletId: doc.PlayletId,
}).
SetUpdate(update).
SetUpsert(true)
writes = append(writes, model)
}
if len(writes) == 0 {
return nil
}
if _, err := coll.BulkWrite(ctx, writes, options.BulkWrite().SetOrdered(false)); err != nil {
log.Warn("playletbackflowstatmod:UpsertManyPlayletBackflowDailyStats failed", log.E(err), log.Any("count", len(writes)))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// FindManyPlayletBackflowDailyStats 查询原创短剧回流日统计。
func FindManyPlayletBackflowDailyStats(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletBackflowDailyStatList, *srvdef.SrvErr) {
data := make(PlayletBackflowDailyStatList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("playletbackflowstatmod:FindManyPlayletBackflowDailyStats failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletBackflowDailyStats 统计原创短剧回流日统计条数。
func CountPlayletBackflowDailyStats(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("playletbackflowstatmod:CountPlayletBackflowDailyStats failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// MarkPlayletBackflowDailyStatsReported 把一批统计记录标记为上报成功。
func MarkPlayletBackflowDailyStatsReported(ctx context.Context, ids []primitive.ObjectID, reportAt time.Time) *srvdef.SrvErr {
if len(ids) == 0 {
return nil
}
_, err := coll.UpdateMany(ctx, bson.M{FN.PlayletBackflowDailyStat.Id: bson.M{"$in": ids}}, bson.M{"$set": bson.M{
FN.PlayletBackflowDailyStat.ReportStatus: ReportStatusSuccess,
FN.PlayletBackflowDailyStat.ReportAt: reportAt,
FN.PlayletBackflowDailyStat.ReportError: "",
FN.PlayletBackflowDailyStat.UpdatedAt: time.Now(),
}})
if err != nil {
log.Warn("playletbackflowstatmod:MarkPlayletBackflowDailyStatsReported failed", log.E(err), log.Any("count", len(ids)))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// MarkPlayletBackflowDailyStatsFailed 把一批统计记录标记为上报失败。
func MarkPlayletBackflowDailyStatsFailed(ctx context.Context, ids []primitive.ObjectID, reportErr string) *srvdef.SrvErr {
if len(ids) == 0 {
return nil
}
_, err := coll.UpdateMany(ctx, bson.M{FN.PlayletBackflowDailyStat.Id: bson.M{"$in": ids}}, bson.M{
"$set": bson.M{
FN.PlayletBackflowDailyStat.ReportStatus: ReportStatusFailed,
FN.PlayletBackflowDailyStat.ReportError: reportErr,
FN.PlayletBackflowDailyStat.UpdatedAt: time.Now(),
},
"$inc": bson.M{
FN.PlayletBackflowDailyStat.ReportRetryCount: int64(1),
},
})
if err != nil {
log.Warn("playletbackflowstatmod:MarkPlayletBackflowDailyStatsFailed failed", log.E(err), log.Any("count", len(ids)))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
+78
View File
@@ -0,0 +1,78 @@
package playletbackflowstatmod
// TagPlayletBackflowDailyStat 保存 playlet_backflow_daily_stat 集合字段名。
type TagPlayletBackflowDailyStat struct {
Id string
DataDate string
PlayletId string
ChapterId string
CurrentEpisode string
MediaCenterId string
MediaContentId string
Title string
PublishedData string
ScriptName string
DramaName string
DramaNo string
VideoURL string
PlatformURL string
Views string
Clicks string
Likes string
LikeRate string
CompletionRate string
PaidRate string
Comments string
Shares string
CompletionRateScope string
ReportStatus string
ReportRetryCount string
ReportAt string
ReportError string
LastStatAt string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletBackflowDailyStat TagPlayletBackflowDailyStat
}
var TN struct {
PlayletBackflowDailyStat string
}
func init() {
FN.PlayletBackflowDailyStat.Id = "_id"
FN.PlayletBackflowDailyStat.DataDate = "dataDate"
FN.PlayletBackflowDailyStat.PlayletId = "playletId"
FN.PlayletBackflowDailyStat.ChapterId = "chapterId"
FN.PlayletBackflowDailyStat.CurrentEpisode = "currentEpisode"
FN.PlayletBackflowDailyStat.MediaCenterId = "mediaCenterId"
FN.PlayletBackflowDailyStat.MediaContentId = "mediaContentId"
FN.PlayletBackflowDailyStat.Title = "title"
FN.PlayletBackflowDailyStat.PublishedData = "publishedData"
FN.PlayletBackflowDailyStat.ScriptName = "scriptName"
FN.PlayletBackflowDailyStat.DramaName = "dramaName"
FN.PlayletBackflowDailyStat.DramaNo = "dramaNo"
FN.PlayletBackflowDailyStat.VideoURL = "videoUrl"
FN.PlayletBackflowDailyStat.PlatformURL = "platformUrl"
FN.PlayletBackflowDailyStat.Views = "views"
FN.PlayletBackflowDailyStat.Clicks = "clicks"
FN.PlayletBackflowDailyStat.Likes = "likes"
FN.PlayletBackflowDailyStat.LikeRate = "likeRate"
FN.PlayletBackflowDailyStat.CompletionRate = "completionRate"
FN.PlayletBackflowDailyStat.PaidRate = "paidRate"
FN.PlayletBackflowDailyStat.Comments = "comments"
FN.PlayletBackflowDailyStat.Shares = "shares"
FN.PlayletBackflowDailyStat.CompletionRateScope = "completionRateScope"
FN.PlayletBackflowDailyStat.ReportStatus = "reportStatus"
FN.PlayletBackflowDailyStat.ReportRetryCount = "reportRetryCount"
FN.PlayletBackflowDailyStat.ReportAt = "reportAt"
FN.PlayletBackflowDailyStat.ReportError = "reportError"
FN.PlayletBackflowDailyStat.LastStatAt = "lastStatAt"
FN.PlayletBackflowDailyStat.CreatedAt = "createdAt"
FN.PlayletBackflowDailyStat.UpdatedAt = "updatedAt"
TN.PlayletBackflowDailyStat = "playlet_backflow_daily_stat"
}
+55
View File
@@ -0,0 +1,55 @@
package playletbackflowstatmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// ReportStatus 是 AI 内容中台数据回流上报状态。
type ReportStatus int64
const (
ReportStatusPending ReportStatus = 0 // 待上报
ReportStatusSuccess ReportStatus = 1 // 上报成功
ReportStatusFailed ReportStatus = 2 // 上报失败
)
// PlayletBackflowDailyStat @table: playlet_backflow_daily_stat
//
// PlayletBackflowDailyStat 保存原创短剧每天回流给 AI 内容中台的数据快照。
type PlayletBackflowDailyStat struct {
Id primitive.ObjectID `json:"id" bson:"_id,omitempty"` // MongoDB ObjectID
DataDate string `json:"dataDate" bson:"dataDate"` // 指标日期,格式 DD/MM/YYYY
PlayletId int64 `json:"playletId" bson:"playletId"` // 业务短剧 ID
ChapterId int64 `json:"chapterId" bson:"chapterId"` // 上报使用的章节 ID
CurrentEpisode int64 `json:"currentEpisode" bson:"currentEpisode"` // 上报使用的章节序号
MediaCenterId int64 `json:"mediaCenterId" bson:"mediaCenterId"` // 媒资库资源 ID
MediaContentId int64 `json:"mediaContentId" bson:"mediaContentId"` // 上报剧集的媒资章节 ID
Title string `json:"title" bson:"title"` // 本地短剧标题
PublishedData string `json:"publishedData" bson:"publishedData"` // 中台字段:视频上线日期
ScriptName string `json:"scriptName" bson:"scriptName"` // 中台字段:剧本名称
DramaName string `json:"dramaName" bson:"dramaName"` // 中台字段:短剧名称
DramaNo string `json:"dramaNo" bson:"dramaNo"` // 中台字段:集数
VideoURL string `json:"videoUrl" bson:"videoUrl"` // 中台字段:成片下载/存储链接
PlatformURL string `json:"platformUrl" bson:"platformUrl"` // 中台字段:产品内播放页链接
Views int64 `json:"views" bson:"views"` // 浏览量
Clicks int64 `json:"clicks" bson:"clicks"` // 播放量
Likes int64 `json:"likes" bson:"likes"` // 点赞量
LikeRate string `json:"likeRate" bson:"likeRate"` // 点赞率
CompletionRate string `json:"completionRate" bson:"completionRate"` // 完播率
PaidRate string `json:"paidRate" bson:"paidRate"` // 付费率
Comments int64 `json:"comments" bson:"comments"` // 评论量
Shares int64 `json:"shares" bson:"shares"` // 分享量
CompletionRateScope string `json:"completionRateScope" bson:"completionRateScope"` // 完播率口径
ReportStatus ReportStatus `json:"reportStatus" bson:"reportStatus"` // 上报状态
ReportRetryCount int64 `json:"reportRetryCount" bson:"reportRetryCount"` // 上报失败次数
ReportAt time.Time `json:"reportAt" bson:"reportAt"` // 最近一次上报成功时间
ReportError string `json:"reportError" bson:"reportError"` // 最近一次上报失败原因
LastStatAt time.Time `json:"lastStatAt" bson:"lastStatAt"` // 最近一次计算时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
// PlayletBackflowDailyStatList 是原创短剧日回流统计列表。
type PlayletBackflowDailyStatList []*PlayletBackflowDailyStat
+121
View File
@@ -0,0 +1,121 @@
package playletcategorymod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_category 集合和后台常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletCategory)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletCategory.Status, Value: 1},
{Key: FN.PlayletCategory.Rank, Value: -1},
{Key: FN.PlayletCategory.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletCategory.Name, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletCategory.CreatedAt, Value: -1},
{Key: FN.PlayletCategory.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletcategorymod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOnePlayletCategory 插入一条短剧分类数据
func InsertOnePlayletCategory(ctx context.Context, doc *PlayletCategory) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletCategory.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("playletcategorymod:InsertOnePlayletCategory failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOnePlayletCategory 删除一条短剧分类数据
func DelOnePlayletCategory(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("playletcategorymod:DelOnePlayletCategory failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOnePlayletCategory 查询一条短剧分类数据
func FindOnePlayletCategory(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*PlayletCategory, *srvdef.SrvErr) {
var doc PlayletCategory
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("playletcategorymod:FindOnePlayletCategory failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyPlayletCategory 按条件查询多条短剧分类数据
func FindManyPlayletCategory(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletCategoryList, *srvdef.SrvErr) {
data := make(PlayletCategoryList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("playletcategorymod:FindManyPlayletCategory failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletCategory 统计满足条件的短剧分类数量
func CountPlayletCategory(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("playletcategorymod:CountPlayletCategory failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOnePlayletCategory 更新一条短剧分类数据
func UpdateOnePlayletCategory(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("playletcategorymod:UpdateOnePlayletCategory failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+44
View File
@@ -0,0 +1,44 @@
package playletcategorymod
// TagPlayletCategory 保存 playlet_category 集合字段名
type TagPlayletCategory struct {
Id string
Name string
Slug string
Icon string
Status string
Rank string
Remark string
SeoInfo struct {
Description string
Keyworld string
Title string
}
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletCategory TagPlayletCategory
}
var TN struct {
PlayletCategory string
}
func init() {
FN.PlayletCategory.Id = "_id"
FN.PlayletCategory.Name = "name"
FN.PlayletCategory.Slug = "slug"
FN.PlayletCategory.Icon = "icon"
FN.PlayletCategory.Status = "status"
FN.PlayletCategory.Rank = "rank"
FN.PlayletCategory.Remark = "remark"
FN.PlayletCategory.SeoInfo.Description = "seoInfo.webDescription"
FN.PlayletCategory.SeoInfo.Keyworld = "seoInfo.webKeyworld"
FN.PlayletCategory.SeoInfo.Title = "seoInfo.webTitle"
FN.PlayletCategory.CreatedAt = "createdAt"
FN.PlayletCategory.UpdatedAt = "updatedAt"
TN.PlayletCategory = "playlet_category"
}
+25
View File
@@ -0,0 +1,25 @@
package playletcategorymod
import (
"time"
"videoweb/pub/pubdef"
)
// PlayletCategory @table: playlet_category
//
// PlayletCategory 短剧分类集合模型
type PlayletCategory struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"` // 分类名称
Slug string `json:"slug" bson:"slug"` // slug
Icon string `json:"icon" bson:"icon"` // 分类图标
Status bool `json:"status" bson:"status"` // 启用状态
Rank int64 `json:"rank" bson:"rank"` // 排序,越大越靠前
Remark string `json:"remark" bson:"remark"` // 备注
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletCategoryList 短剧分类列表
type PlayletCategoryList []*PlayletCategory
+265
View File
@@ -0,0 +1,265 @@
package playletchaptermod
import (
"context"
"fmt"
"strings"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_chapter 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletChapter)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletChapter.PlayletId, Value: 1},
{Key: FN.PlayletChapter.CurrentEpisode, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.PlayletId, Value: 1},
{Key: FN.PlayletChapter.MediaContentId, Value: 1},
},
Options: options.Index().
SetUnique(true).
SetPartialFilterExpression(bson.M{
FN.PlayletChapter.MediaContentId: bson.M{"$gt": 0},
}),
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.PlayletId, Value: 1},
{Key: FN.PlayletChapter.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.CreatedAt, Value: -1},
{Key: FN.PlayletChapter.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.WatermarkStatus, Value: 1},
{Key: FN.PlayletChapter.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.MediaSourceId, Value: 1},
},
Options: options.Index().
SetPartialFilterExpression(bson.M{
FN.PlayletChapter.MediaSourceId: bson.M{"$gt": ""},
}),
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletchaptermod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOnePlayletChapter 插入一条章节数据
func InsertOnePlayletChapter(ctx context.Context, doc *PlayletChapter) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletChapter.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("playletchaptermod:InsertOnePlayletChapter failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// InsertManyPlayletChapter 批量插入章节数据
func InsertManyPlayletChapter(ctx context.Context, docs PlayletChapterList) *srvdef.SrvErr {
data := make(PlayletChapterList, 0, len(docs))
now := time.Now()
for _, doc := range docs {
if doc == nil {
continue
}
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletChapter.Get()
}
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
data = append(data, doc)
}
if len(data) == 0 {
return nil
}
if _, err := coll.InsertMany(ctx, &data); err != nil {
log.Warn("playletchaptermod:InsertManyPlayletChapter failed", log.Any("count", len(data)), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOnePlayletChapter 删除一条章节数据
func DelOnePlayletChapter(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("playletchaptermod:DelOnePlayletChapter failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyPlayletChapter 按条件批量删除章节数据
func DelManyPlayletChapter(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteMany(ctx, filter)
if err != nil {
log.Warn("playletchaptermod:DelManyPlayletChapter failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOnePlayletChapter 查询一条章节数据
func FindOnePlayletChapter(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*PlayletChapter, *srvdef.SrvErr) {
var doc PlayletChapter
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("playletchaptermod:FindOnePlayletChapter failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyPlayletChapter 按条件查询多条章节数据
func FindManyPlayletChapter(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletChapterList, *srvdef.SrvErr) {
data := make(PlayletChapterList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("playletchaptermod:FindManyPlayletChapter failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletChapter 统计满足条件的章节数量
func CountPlayletChapter(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("playletchaptermod:CountPlayletChapter failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOnePlayletChapter 更新一条章节数据
func UpdateOnePlayletChapter(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("playletchaptermod:UpdateOnePlayletChapter failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// IsLinkedMedia 是否短剧媒资:显式标记或已挂到剧集
func IsLinkedMedia(ctx context.Context, isPlaylet bool, ids ...string) bool {
if isPlaylet {
return true
}
return ExistsByMediaIDs(ctx, ids...)
}
// ExistsByMediaIDs 判断媒资 ID 是否属于短剧剧集(mediaSourceId / mediaTaskId)
func ExistsByMediaIDs(ctx context.Context, ids ...string) bool {
clean := uniqueNonEmptyStrings(ids)
if len(clean) == 0 {
return false
}
item, _ := FindOnePlayletChapter(ctx, bson.M{
"$or": []bson.M{
{FN.PlayletChapter.MediaSourceId: bson.M{"$in": clean}},
{FN.PlayletChapter.MediaTaskId: bson.M{"$in": clean}},
},
}, options.FindOne().SetProjection(bson.M{FN.PlayletChapter.Id: 1}))
return item != nil
}
// ListLinkedMediaIDs 返回短剧剧集关联的媒资 ID,用于排除短剧视频
func ListLinkedMediaIDs(ctx context.Context) []string {
list, err := FindManyPlayletChapter(ctx, bson.M{
"$or": []bson.M{
{FN.PlayletChapter.MediaSourceId: bson.M{"$gt": ""}},
{FN.PlayletChapter.MediaTaskId: bson.M{"$gt": ""}},
},
}, options.Find().SetProjection(bson.M{
FN.PlayletChapter.MediaSourceId: 1,
FN.PlayletChapter.MediaTaskId: 1,
}))
if err != nil || len(list) == 0 {
return nil
}
ids := make([]string, 0, len(list)*2)
for _, item := range list {
if item == nil {
continue
}
ids = append(ids, item.MediaSourceId, item.MediaTaskId)
}
return uniqueNonEmptyStrings(ids)
}
func uniqueNonEmptyStrings(ids []string) []string {
if len(ids) == 0 {
return nil
}
seen := make(map[string]struct{}, len(ids))
out := make([]string, 0, len(ids))
for _, id := range ids {
id = strings.TrimSpace(id)
if id == "" {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
out = append(out, id)
}
return out
}
// UpdateManyPlayletChapter 批量更新章节数据
func UpdateManyPlayletChapter(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateMany(ctx, filter, update)
if err != nil {
log.Warn("批量更新短剧章节数据失败", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount == 0 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+72
View File
@@ -0,0 +1,72 @@
package playletchaptermod
// TagPlayletChapter 保存 playlet_chapter 集合字段名
type TagPlayletChapter struct {
Id string
PlayletId string
MediaContentId string
CurrentEpisode string
Title string
Md5 string
Hash string
Height string
Width string
Ratio string
VideoUrl string
WatermarkVideoUrl string
MediaSize string
MediaTime string
CountComment string
CountBuy string
CountBrowse string
CountCollect string
CountLike string
CountDisLike string
PayType string
SingleCoins string
WatermarkStatus string
MediaSourceId string
MediaTaskId string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletChapter TagPlayletChapter
}
var TN struct {
PlayletChapter string
}
func init() {
FN.PlayletChapter.Id = "_id"
FN.PlayletChapter.PlayletId = "playletId"
FN.PlayletChapter.MediaContentId = "mediaContentId"
FN.PlayletChapter.CurrentEpisode = "currentEpisode"
FN.PlayletChapter.Title = "title"
FN.PlayletChapter.Md5 = "md5"
FN.PlayletChapter.Hash = "hash"
FN.PlayletChapter.Height = "height"
FN.PlayletChapter.Width = "width"
FN.PlayletChapter.Ratio = "ratio"
FN.PlayletChapter.VideoUrl = "videoUrl"
FN.PlayletChapter.WatermarkVideoUrl = "watermarkVideoUrl"
FN.PlayletChapter.MediaSize = "mediaSize"
FN.PlayletChapter.MediaTime = "mediaTime"
FN.PlayletChapter.CountComment = "countComment"
FN.PlayletChapter.CountBuy = "countBuy"
FN.PlayletChapter.CountBrowse = "countBrowse"
FN.PlayletChapter.CountCollect = "countCollect"
FN.PlayletChapter.CountLike = "countLike"
FN.PlayletChapter.CountDisLike = "countDisLike"
FN.PlayletChapter.PayType = "payType"
FN.PlayletChapter.SingleCoins = "singleCoins"
FN.PlayletChapter.WatermarkStatus = "watermarkStatus"
FN.PlayletChapter.MediaSourceId = "mediaSourceId"
FN.PlayletChapter.MediaTaskId = "mediaTaskId"
FN.PlayletChapter.CreatedAt = "createdAt"
FN.PlayletChapter.UpdatedAt = "updatedAt"
TN.PlayletChapter = "playlet_chapter"
}
+59
View File
@@ -0,0 +1,59 @@
package playletchaptermod
import "time"
// PayType 支付方式
type PayType int32
const (
PayTypeFree PayType = 0 // 免费
PayTypeCoin PayType = 1 // 金币
PayTypeVip PayType = 2 // VIP
)
// WatermarkStatus 水印状态
type WatermarkStatus int32
const (
WatermarkStatusPending WatermarkStatus = 0 // 未处理(待 mediafile/sync)
WatermarkStatusRegistered WatermarkStatus = 1 // 已登记(原片已登记,待 task/add)
WatermarkStatusProcessing WatermarkStatus = 2 // 处理中(已提交加水印任务,待回写)
WatermarkStatusDone WatermarkStatus = 3 // 已完成
WatermarkStatusFailed WatermarkStatus = 4 // 处理失败
)
// PlayletChapter @table: playlet_chapter
//
// PlayletChapter 连载短剧章节集合模型
type PlayletChapter struct {
Id int64 `json:"id" bson:"_id,omitempty"`
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
MediaContentId uint `json:"mediaContentId" bson:"mediaContentId"` // 媒资中心章节ID
CurrentEpisode int64 `json:"currentEpisode" bson:"currentEpisode"` // 第几集
Title string `json:"title" bson:"title"` // 章节名
Md5 string `json:"md5" bson:"md5"` // 媒体md5
Hash string `json:"hash" bson:"hash"` // 媒体hash
Height int64 `json:"height" bson:"height"` // 高
Width int64 `json:"width" bson:"width"` // 宽
Ratio float64 `json:"ratio" bson:"ratio"` // 宽高比
VideoUrl string `json:"videoUrl" bson:"videoUrl"` // 原片视频地址(加水印后保持不变,方便换水印)
WatermarkVideoUrl string `json:"watermarkVideoUrl" bson:"watermarkVideoUrl"` // 加水印后的视频地址
MediaSize int64 `json:"mediaSize" bson:"mediaSize"` // 资源大小
MediaTime int64 `json:"mediaTime" bson:"mediaTime"` // 影片长度(秒)
CountComment int64 `json:"countComment" bson:"countComment"` // 评论数
CountBuy int64 `json:"countBuy" bson:"countBuy"` // 购买数
CountBrowse int64 `json:"countBrowse" bson:"countBrowse"` // 浏览数
CountCollect int64 `json:"countCollect" bson:"countCollect"` // 收藏数
CountLike int64 `json:"countLike" bson:"countLike"` // 喜欢数
CountDisLike int64 `json:"countDisLike" bson:"countDisLike"` // 不喜欢数
PayType PayType `json:"payType" bson:"payType"` // 支付方式 0-免费 1-金币 2-VIP
SingleCoins int64 `json:"singleCoins" bson:"singleCoins"` // 单集金币(支付方式为1-金币时候生效)
WatermarkStatus WatermarkStatus `json:"watermarkStatus" bson:"watermarkStatus"` // 水印状态 0-未处理 1-已登记 2-处理中 3-已完成 4-处理失败
MediaSourceId string `json:"mediaSourceId" bson:"mediaSourceId"` // media切片服原片ID
MediaTaskId string `json:"mediaTaskId" bson:"mediaTaskId"` // media切片服水印任务ID
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletChapterList 章节列表
type PlayletChapterList []*PlayletChapter
+100
View File
@@ -0,0 +1,100 @@
package playletfavoritemod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const CollectionName = "playlet_favorite"
const (
FieldID = "_id"
FieldUserID = "userId"
FieldPlayletID = "playletId"
FieldCreatedAt = "createdAt"
FieldUpdatedAt = "updatedAt"
)
type PlayletFavorite struct {
ID int64 `bson:"_id,omitempty"`
UserID int64 `bson:"userId"`
PlayletID int64 `bson:"playletId"`
CreatedAt time.Time `bson:"createdAt"`
UpdatedAt time.Time `bson:"updatedAt"`
}
var coll *mongos.Collection
// Init 初始化短剧收藏集合及查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(CollectionName)
indexes := []mongo.IndexModel{
{Keys: bson.D{{Key: FieldUserID, Value: 1}, {Key: FieldPlayletID, Value: 1}}, Options: options.Index().SetUnique(true)},
{Keys: bson.D{{Key: FieldUserID, Value: 1}, {Key: FieldCreatedAt, Value: -1}, {Key: FieldID, Value: -1}}},
{Keys: bson.D{{Key: FieldPlayletID, Value: 1}}},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletfavoritemod:Init) Create Index failed! err:%+v:", err))
}
}
// Upsert 按用户和短剧写入收藏关系并返回是否新增
func Upsert(ctx context.Context, userID, playletID int64, now time.Time) (bool, *srvdef.SrvErr) {
filter := bson.M{FieldUserID: userID, FieldPlayletID: playletID}
update := bson.M{"$set": bson.M{FieldUpdatedAt: now}, "$setOnInsert": bson.M{
FieldID: mongos.Lid.PlayletFavorite.Get(), FieldUserID: userID, FieldPlayletID: playletID, FieldCreatedAt: now,
}}
result, err := coll.UpdateOne(ctx, filter, update, options.Update().SetUpsert(true))
if err != nil {
log.Warn("playletfavoritemod:Upsert failed", log.Any("filter", filter), log.E(err))
return false, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return result.UpsertedCount > 0, nil
}
// Delete 删除收藏关系并返回是否实际删除
func Delete(ctx context.Context, filter bson.M) (bool, *srvdef.SrvErr) {
deleted, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("playletfavoritemod:Delete failed", log.Any("filter", filter), log.E(err))
return false, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return deleted > 0, nil
}
// Count 统计收藏关系数量
func Count(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter)
if err != nil {
log.Warn("playletfavoritemod:Count failed", log.Any("filter", filter), log.E(err))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// FindMany 查询收藏关系列表
func FindMany(ctx context.Context, filter bson.M, opts ...*options.FindOptions) ([]*PlayletFavorite, *srvdef.SrvErr) {
list := make([]*PlayletFavorite, 0)
if err := coll.Find(ctx, &list, filter, opts...); err != nil {
log.Warn("playletfavoritemod:FindMany failed", log.Any("filter", filter), log.E(err))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return list, nil
}
// Aggregate 聚合收藏关系和短剧数据
func Aggregate(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := coll.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("playletfavoritemod:Aggregate failed", log.Any("pipeline", pipeline), log.E(err))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+168
View File
@@ -0,0 +1,168 @@
package playlethomeconfigmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_home_config 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletHomeConfig)
backfillSlugs(ctx)
initIndex(ctx)
}
// backfillSlugs 为历史配置生成稳定路径标识
func backfillSlugs(ctx context.Context) {
var docs PlayletHomeConfigList
filter := bson.M{"$or": []bson.M{{FN.PlayletHomeConfig.Slug: bson.M{"$exists": false}}, {FN.PlayletHomeConfig.Slug: nil}, {FN.PlayletHomeConfig.Slug: ""}}}
if err := coll.Find(ctx, &docs, filter, options.Find().SetProjection(bson.M{FN.PlayletHomeConfig.Id: 1})); err != nil {
panic(fmt.Sprintf("(playlethomeconfigmod:backfillSlugs) Find failed! err:%+v", err))
}
for _, doc := range docs {
if doc == nil {
continue
}
if _, err := coll.UpdateOne(ctx, bson.M{FN.PlayletHomeConfig.Id: doc.Id, "$or": filter["$or"]}, bson.M{"$set": bson.M{FN.PlayletHomeConfig.Slug: fmt.Sprintf("home-config-%d", doc.Id)}}); err != nil {
panic(fmt.Sprintf("(playlethomeconfigmod:backfillSlugs) UpdateOne failed! id:%d err:%+v", doc.Id, err))
}
}
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletHomeConfig.Enabled, Value: 1},
{Key: FN.PlayletHomeConfig.ModuleType, Value: 1},
{Key: FN.PlayletHomeConfig.Rank, Value: -1},
{Key: FN.PlayletHomeConfig.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletHomeConfig.CreatedAt, Value: -1},
{Key: FN.PlayletHomeConfig.Id, Value: -1},
},
},
{
Keys: bson.D{{Key: FN.PlayletHomeConfig.Slug, Value: 1}},
Options: options.Index().SetUnique(true).SetName("slug_unique"),
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playlethomeconfigmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOnePlayletHomeConfig 插入一条首页配置
func InsertOnePlayletHomeConfig(ctx context.Context, doc *PlayletHomeConfig) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletHomeConfig.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
normalizePlayletHomeConfig(doc)
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
return srvdef.New(srvdef.ErrParamError, "slug已存在", "")
}
log.Warn("插入首页配置失败", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
func normalizePlayletHomeConfig(doc *PlayletHomeConfig) {
if doc == nil {
return
}
if doc.ModuleType != ModuleTypeTopic {
doc.ModuleType = ModuleTypePlaylet
}
if doc.DataType != DataTypeVideo {
doc.DataType = DataTypeAll
}
if doc.Limit <= 0 {
doc.Limit = DefaultLimit
}
if doc.Limit > MaxLimit {
doc.Limit = MaxLimit
}
}
// DelManyPlayletHomeConfig 删除多条首页配置
func DelManyPlayletHomeConfig(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteMany(ctx, filter)
if err != nil {
log.Warn("删除首页配置失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOnePlayletHomeConfig 查询一条首页配置
func FindOnePlayletHomeConfig(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*PlayletHomeConfig, *srvdef.SrvErr) {
var doc PlayletHomeConfig
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("查询首页配置失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
normalizePlayletHomeConfig(&doc)
return &doc, nil
}
// FindManyPlayletHomeConfig 按条件查询多条首页配置
func FindManyPlayletHomeConfig(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletHomeConfigList, *srvdef.SrvErr) {
data := make(PlayletHomeConfigList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("查询首页配置列表失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
for _, item := range data {
normalizePlayletHomeConfig(item)
}
return data, nil
}
// CountPlayletHomeConfig 统计满足条件的首页配置数量
func CountPlayletHomeConfig(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("统计首页配置失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOnePlayletHomeConfig 更新一条首页配置
func UpdateOnePlayletHomeConfig(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
if mongo.IsDuplicateKeyError(err) {
return srvdef.New(srvdef.ErrParamError, "slug已存在", "")
}
log.Warn("更新首页配置失败", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+52
View File
@@ -0,0 +1,52 @@
package playlethomeconfigmod
// TagPlayletHomeConfig 保存 playlet_home_config 集合字段名
type TagPlayletHomeConfig struct {
Id string
Slug string
Title string
Desc string
Label string
Style string
CardBackgroundImage string
ModuleType string
DataType string
RecommendType string
CategoryId string
TopicIds string
Rank string
Enabled string
Limit string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletHomeConfig TagPlayletHomeConfig
}
var TN struct {
PlayletHomeConfig string
}
func init() {
FN.PlayletHomeConfig.Id = "_id"
FN.PlayletHomeConfig.Slug = "slug"
FN.PlayletHomeConfig.Title = "title"
FN.PlayletHomeConfig.Desc = "desc"
FN.PlayletHomeConfig.Label = "label"
FN.PlayletHomeConfig.Style = "style"
FN.PlayletHomeConfig.CardBackgroundImage = "cardBackgroundImage"
FN.PlayletHomeConfig.ModuleType = "moduleType"
FN.PlayletHomeConfig.DataType = "dataType"
FN.PlayletHomeConfig.RecommendType = "recommendType"
FN.PlayletHomeConfig.CategoryId = "categoryId"
FN.PlayletHomeConfig.TopicIds = "topicIds"
FN.PlayletHomeConfig.Rank = "rank"
FN.PlayletHomeConfig.Enabled = "enabled"
FN.PlayletHomeConfig.Limit = "limit"
FN.PlayletHomeConfig.CreatedAt = "createdAt"
FN.PlayletHomeConfig.UpdatedAt = "updatedAt"
TN.PlayletHomeConfig = "playlet_home_config"
}
+60
View File
@@ -0,0 +1,60 @@
package playlethomeconfigmod
import "time"
const (
RecommendTypeUpdated int64 = 1 // 按更新
RecommendTypeLike int64 = 2 // 按点赞
RecommendTypeBrowse int64 = 3 // 按观看
RecommendTypeHeat int64 = 4 // 按热度
RecommendTypeCategory int64 = 5 // 按分类
DefaultLimit int64 = 30
MaxLimit int64 = 100
)
const (
DataTypeAll int64 = 1 // 全部上架短剧
DataTypeVideo int64 = 2 // 全部上架视频
)
const (
ModuleTypePlaylet int64 = 1 // 列表,具体为短剧或视频由 DataType 决定
ModuleTypeTopic int64 = 2 // 专题
)
const (
StyleA = "A"
StyleB = "B"
StyleC = "C"
StyleD = "D"
StyleE = "E"
StyleF = "F"
StyleG = "G"
StyleH = "H"
)
// PlayletHomeConfig @table: playlet_home_config
//
// PlayletHomeConfig 短剧首页配置表
type PlayletHomeConfig struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Slug string `json:"slug" bson:"slug"` // 页面路径标识
Title string `json:"title" bson:"title"` // 模块标题
Desc string `json:"desc" bson:"desc"` // 模块描述
Label string `json:"label" bson:"label"` // 样式名称
Style string `json:"style" bson:"style"` // 样式 A-H
CardBackgroundImage string `json:"cardBackgroundImage" bson:"cardBackgroundImage"` // 卡片背景图
ModuleType int64 `json:"moduleType" bson:"moduleType"` // 模块类型 1列表 2专题,短剧或视频由 DataType 决定
DataType int64 `json:"dataType" bson:"dataType"` // 数据类型 1全部上架短剧 2全部上架视频
RecommendType int64 `json:"recommendType" bson:"recommendType"` // 推荐类型 1按更新 2按点赞 3按观看 4按热度 5按分类
CategoryId int64 `json:"categoryId" bson:"categoryId"` // 按分类推荐时使用的分类ID
TopicIds []int64 `json:"topicIds" bson:"topicIds"` // 专题模块关联的题材或视频分类ID
Rank int64 `json:"rank" bson:"rank"` // 排序,越大越靠前
Enabled bool `json:"enabled" bson:"enabled"` // 是否启用
Limit int64 `json:"limit" bson:"limit"` // 展示条数
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletHomeConfigList 首页配置列表
type PlayletHomeConfigList []*PlayletHomeConfig
+83
View File
@@ -0,0 +1,83 @@
package playletlikemod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_like 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletLike)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{Keys: bson.D{{Key: FN.PlayletLike.UserID, Value: 1}, {Key: FN.PlayletLike.PlayletID, Value: 1}}, Options: options.Index().SetUnique(true)},
{Keys: bson.D{{Key: FN.PlayletLike.PlayletID, Value: 1}}},
{Keys: bson.D{{Key: FN.PlayletLike.CreatedAt, Value: -1}, {Key: FN.PlayletLike.PlayletID, Value: 1}}},
{Keys: bson.D{{Key: FN.PlayletLike.UserID, Value: 1}, {Key: FN.PlayletLike.CreatedAt, Value: -1}, {Key: FN.PlayletLike.Id, Value: -1}}},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletlikemod:initIndex) Create Index failed! err:%+v:", err))
}
}
// UpsertOnePlayletLike 按用户ID和短剧ID写入点赞关系,返回是否新增点赞
func UpsertOnePlayletLike(ctx context.Context, userId, playletId int64, now time.Time) (bool, *srvdef.SrvErr) {
filter := bson.M{FN.PlayletLike.UserID: userId, FN.PlayletLike.PlayletID: playletId}
update := bson.M{
"$set": bson.M{FN.PlayletLike.UpdatedAt: now},
"$setOnInsert": bson.M{
FN.PlayletLike.Id: mongos.Lid.PlayletLike.Get(),
FN.PlayletLike.UserID: userId,
FN.PlayletLike.PlayletID: playletId,
FN.PlayletLike.CreatedAt: now,
},
}
result, err := coll.UpdateOne(ctx, filter, update, options.Update().SetUpsert(true))
if err != nil {
log.Warn("playletlikemod:UpsertOnePlayletLike db.UpdateOne failed", log.Any("filter", filter), log.E(err))
return false, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return result.UpsertedCount > 0, nil
}
// DeleteOnePlayletLike 删除一条短剧点赞关系,返回是否实际删除
func DeleteOnePlayletLike(ctx context.Context, filter bson.M) (bool, *srvdef.SrvErr) {
result, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("playletlikemod:DeleteOnePlayletLike db.DeleteOne failed", log.Any("filter", filter), log.E(err))
return false, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return result > 0, nil
}
// CountPlayletLike 统计短剧点赞关系数量
func CountPlayletLike(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter)
if err != nil {
log.Warn("playletlikemod:CountPlayletLike db.Count failed", log.Any("filter", filter), log.E(err))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// AggregatePlayletLike 聚合查询短剧点赞关系
func AggregatePlayletLike(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := coll.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("playletlikemod:AggregatePlayletLike db.Aggregate failed", log.Any("pipeline", pipeline), log.E(err))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+28
View File
@@ -0,0 +1,28 @@
package playletlikemod
// TagPlayletLike 保存 playlet_like 集合字段名
type TagPlayletLike struct {
Id string
UserID string
PlayletID string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletLike TagPlayletLike
}
var TN struct {
PlayletLike string
}
func init() {
FN.PlayletLike.Id = "_id"
FN.PlayletLike.UserID = "userId"
FN.PlayletLike.PlayletID = "playletId"
FN.PlayletLike.CreatedAt = "createdAt"
FN.PlayletLike.UpdatedAt = "updatedAt"
TN.PlayletLike = "playlet_like"
}
+15
View File
@@ -0,0 +1,15 @@
package playletlikemod
import "time"
// PlayletLike 短剧点赞关系
type PlayletLike struct {
Id int64 `json:"id" bson:"_id,omitempty"`
UserID int64 `json:"userId" bson:"userId"` // 用户ID
PlayletID int64 `json:"playletId" bson:"playletId"` // 短剧ID
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
}
// PlayletLikeList 短剧点赞列表
type PlayletLikeList []*PlayletLike
+173
View File
@@ -0,0 +1,173 @@
package playletmod
import (
"context"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
)
const categoryRankField = "_categoryRank"
// PlayletCategoryBind 短剧绑定的分类及该分类下的排序
type PlayletCategoryBind struct {
Id int64 `json:"id" bson:"id"` // 分类ID
Rank int64 `json:"rank" bson:"rank"` // 该分类下的排序,越大越靠前
}
// NormalizeCategoryBinds 去重并丢弃无效分类ID,保留首次出现的排序
func NormalizeCategoryBinds(binds []PlayletCategoryBind) []PlayletCategoryBind {
result := make([]PlayletCategoryBind, 0, len(binds))
seen := make(map[int64]struct{}, len(binds))
for _, bind := range binds {
if bind.Id <= 0 {
continue
}
if _, ok := seen[bind.Id]; ok {
continue
}
seen[bind.Id] = struct{}{}
result = append(result, PlayletCategoryBind{Id: bind.Id, Rank: bind.Rank})
}
return result
}
// CategoryIdsFromBinds 从分类绑定中提取分类ID
func CategoryIdsFromBinds(binds []PlayletCategoryBind) []int64 {
result := make([]int64, 0, len(binds))
for _, bind := range binds {
if bind.Id <= 0 {
continue
}
result = append(result, bind.Id)
}
return result
}
// CategoryBindsFromIds 仅有分类ID时补默认排序0
func CategoryBindsFromIds(ids []int64) []PlayletCategoryBind {
result := make([]PlayletCategoryBind, 0, len(ids))
seen := make(map[int64]struct{}, len(ids))
for _, id := range ids {
if id <= 0 {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
result = append(result, PlayletCategoryBind{Id: id})
}
return result
}
// MergeCategoryBindsByIds 按新分类ID集合保留旧排序,新增分类rank为0
func MergeCategoryBindsByIds(exist []PlayletCategoryBind, ids []int64) []PlayletCategoryBind {
rankByID := make(map[int64]int64, len(exist))
for _, bind := range exist {
if bind.Id <= 0 {
continue
}
rankByID[bind.Id] = bind.Rank
}
result := make([]PlayletCategoryBind, 0, len(ids))
seen := make(map[int64]struct{}, len(ids))
for _, id := range ids {
if id <= 0 {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
result = append(result, PlayletCategoryBind{Id: id, Rank: rankByID[id]})
}
return result
}
// CategoryRankOf 取指定分类下的排序,未绑定返回0
func CategoryRankOf(binds []PlayletCategoryBind, categoryId int64) int64 {
if categoryId <= 0 {
return 0
}
for _, bind := range binds {
if bind.Id == categoryId {
return bind.Rank
}
}
return 0
}
// EffectiveCategoryBinds 历史数据只有categoryIds时补默认绑定,便于编辑回显
func EffectiveCategoryBinds(item *Playlet) []PlayletCategoryBind {
if item == nil {
return make([]PlayletCategoryBind, 0)
}
if len(item.CategoryBinds) > 0 {
return item.CategoryBinds
}
return CategoryBindsFromIds(item.CategoryIds)
}
// CategoryRankAddFields 聚合取出当前分类的排序字段,供分类列表排序
func CategoryRankAddFields(categoryId int64) bson.M {
return bson.M{
categoryRankField: bson.M{
"$let": bson.M{
"vars": bson.M{
"hit": bson.M{
"$first": bson.M{
"$filter": bson.M{
"input": bson.M{"$ifNull": bson.A{"$categoryBinds", bson.A{}}},
"as": "b",
"cond": bson.M{"$eq": bson.A{"$$b.id", categoryId}},
},
},
},
},
"in": bson.M{"$ifNull": bson.A{"$$hit.rank", 0}},
},
},
}
}
// CategoryRankSort 分类短剧排序:当前分类rank降序,再按上架时间和ID
func CategoryRankSort() bson.D {
return bson.D{
{Key: categoryRankField, Value: -1},
{Key: "onlineAt", Value: -1},
{Key: "_id", Value: -1},
}
}
// CategoryRankAdminSort 后台按分类查询时的排序:当前分类rank降序
func CategoryRankAdminSort() bson.D {
return bson.D{
{Key: categoryRankField, Value: -1},
{Key: "_id", Value: -1},
}
}
// FindManyPlayletByCategoryRank 按指定分类的排序分页查询短剧
func FindManyPlayletByCategoryRank(ctx context.Context, filter bson.M, categoryId, skip, limit int64, sort bson.D, projection bson.D) (PlayletList, *srvdef.SrvErr) {
pipeline := []bson.M{
{"$match": filter},
{"$addFields": CategoryRankAddFields(categoryId)},
{"$sort": sort},
{"$skip": skip},
{"$limit": limit},
{"$unset": categoryRankField},
}
if len(projection) > 0 {
project := bson.M{}
for _, field := range projection {
project[field.Key] = field.Value
}
pipeline = append(pipeline, bson.M{"$project": project})
}
list := make(PlayletList, 0)
if err := AggregatePlaylet(ctx, &list, pipeline); err != nil {
return nil, err
}
return list, nil
}
+342
View File
@@ -0,0 +1,342 @@
package playletmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.Playlet)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Playlet.ThemeIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.ThemeIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CountCollect, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.ThemeIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.UpdatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.ThemeIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.IsRecommend, Value: 1},
{Key: FN.Playlet.RecommendRank, Value: -1},
{Key: FN.Playlet.CreatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.ThemeIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CountBrowse, Value: -1},
{Key: FN.Playlet.UpdatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.CategoryIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.TagIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.UpdatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.TagIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.IsRecommend, Value: 1},
{Key: FN.Playlet.RecommendRank, Value: -1},
{Key: FN.Playlet.CreatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.TagIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CountBrowse, Value: -1},
{Key: FN.Playlet.UpdatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.CategoryIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.RecommendRank, Value: -1},
{Key: FN.Playlet.CreatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.CategoryIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.IsRecommend, Value: 1},
{Key: FN.Playlet.RecommendRank, Value: -1},
{Key: FN.Playlet.CreatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.CategoryIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.UpdatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.CategoryIds, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CountBrowse, Value: -1},
{Key: FN.Playlet.UpdatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.IsFeatured, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.ShowOnBanner, Value: 1},
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.TopRank, Value: -1},
{Key: FN.Playlet.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.IsRecommend, Value: 1},
{Key: FN.Playlet.RecommendRank, Value: -1},
{Key: FN.Playlet.CreatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.CreatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CountCollect, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.CountBrowse, Value: -1},
{Key: FN.Playlet.UpdatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.HeatValue, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.OnlineAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.Status, Value: 1},
{Key: FN.Playlet.UpdatedAt, Value: -1},
{Key: FN.Playlet.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Playlet.MediaCenterId, Value: 1},
},
Options: options.Index().
SetUnique(true).
SetPartialFilterExpression(bson.M{
FN.Playlet.MediaCenterId: bson.M{"$gt": 0},
}),
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOnePlaylet 插入一条短剧数据
func InsertOnePlaylet(ctx context.Context, doc *Playlet) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.Playlet.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("playletmod:InsertOnePlaylet failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOnePlaylet 删除一条短剧数据
func DelOnePlaylet(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("playletmod:DelOnePlaylet failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOnePlaylet 查询一条短剧数据
func FindOnePlaylet(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*Playlet, *srvdef.SrvErr) {
var doc Playlet
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("playletmod:FindOnePlaylet failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyPlaylet 按条件查询多条短剧数据
func FindManyPlaylet(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletList, *srvdef.SrvErr) {
data := make(PlayletList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("playletmod:FindManyPlaylet failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlaylet 统计满足条件的短剧数量
func CountPlaylet(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("playletmod:CountPlaylet failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// AggregatePlaylet 聚合查询短剧数据
func AggregatePlaylet(ctx context.Context, bind interface{}, pipeline []bson.M, opts ...*options.AggregateOptions) *srvdef.SrvErr {
if err := coll.Aggregate(ctx, bind, pipeline, opts...); err != nil {
log.Warn("playletmod:AggregatePlaylet failed", log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// UpdateOnePlaylet 更新一条短剧数据
func UpdateOnePlaylet(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("playletmod:UpdateOnePlaylet failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// FindOneAndUpdatePlaylet 更新一条短剧数据并返回更新后的数据
func FindOneAndUpdatePlaylet(ctx context.Context, filter bson.M, update bson.M, opts ...*options.FindOneAndUpdateOptions) (*Playlet, *srvdef.SrvErr) {
var doc Playlet
if err := coll.FindOneAndUpdate(ctx, &doc, filter, update, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("更新并查询短剧数据失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// UpdateManyPlaylet 批量更新短剧数据
func UpdateManyPlaylet(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateMany(ctx, filter, update)
if err != nil {
log.Warn("批量更新短剧数据失败", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount == 0 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// BulkWritePlaylet 批量写入短剧更新操作。
func BulkWritePlaylet(ctx context.Context, docs []mongo.WriteModel, opts ...*options.BulkWriteOptions) *srvdef.SrvErr {
if len(docs) == 0 {
return nil
}
result, err := coll.BulkWrite(ctx, docs, opts...)
if err != nil {
log.Warn("批量写入短剧数据失败", log.E(err))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount == 0 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+134
View File
@@ -0,0 +1,134 @@
package playletmod
// TagPlaylet 保存 playlet 集合字段名
type TagPlaylet struct {
Id string
MediaCenterId string
MediaCreatedAt string
MediaUpdatedAt string
MediaSyncTime string
Status string
IsFeatured string
IsOriginal string
ShowOriginal string
MediaBusiness string
IsRecommend string
ShowOnBanner string
Banner string
ReviewAt string
OnlineAt string
CategoryIds string
CategoryBinds string
ThemeIds string
Title string
Slug string
Desc string
Anchor string
Cover string
CompressedCover string
Preview string
TagIds string
OldTags string
ContentType string
PayType string
SingleCoins string
TotalEpisode string
FreeEpisodeCount string
UpdateStatus string
TopRank string
RecommendRank string
CountComment string
CountBuy string
CountBrowse string
VirtualCountBrowse string
WeekWatchs string
MonthWatchs string
YearWatchs string
WatchUpdatedAt string
HeatValue string
VirtualHeatValue string
CountCollect string
CountLike string
VirtualCountLike string
CountDisLike string
SeoInfo struct {
Description string
Keyworld string
Title string
}
IndexNow string
OperatorId string
OperatorName string
CreatedAt string
UpdatedAt string
}
var FN struct {
Playlet TagPlaylet
}
var TN struct {
Playlet string
}
func init() {
FN.Playlet.Id = "_id"
FN.Playlet.MediaCenterId = "mediaCenterId"
FN.Playlet.MediaCreatedAt = "mediaCreatedAt"
FN.Playlet.MediaUpdatedAt = "mediaUpdatedAt"
FN.Playlet.MediaSyncTime = "mediaSyncTime"
FN.Playlet.Status = "status"
FN.Playlet.IsFeatured = "isFeatured"
FN.Playlet.IsOriginal = "isOriginal"
FN.Playlet.ShowOriginal = "showOriginal"
FN.Playlet.MediaBusiness = "mediaBusiness"
FN.Playlet.IsRecommend = "isRecommend"
FN.Playlet.ShowOnBanner = "showOnBanner"
FN.Playlet.Banner = "banner"
FN.Playlet.ReviewAt = "reviewAt"
FN.Playlet.OnlineAt = "onlineAt"
FN.Playlet.CategoryIds = "categoryIds"
FN.Playlet.CategoryBinds = "categoryBinds"
FN.Playlet.ThemeIds = "themeIds"
FN.Playlet.Title = "title"
FN.Playlet.Slug = "slug"
FN.Playlet.Desc = "desc"
FN.Playlet.Anchor = "anchor"
FN.Playlet.Cover = "cover"
FN.Playlet.CompressedCover = "compressedCover"
FN.Playlet.Preview = "preview"
FN.Playlet.TagIds = "tagIds"
FN.Playlet.OldTags = "oldTags"
FN.Playlet.ContentType = "contentType"
FN.Playlet.PayType = "payType"
FN.Playlet.SingleCoins = "singleCoins"
FN.Playlet.TotalEpisode = "totalEpisode"
FN.Playlet.FreeEpisodeCount = "freeEpisodeCount"
FN.Playlet.UpdateStatus = "updateStatus"
FN.Playlet.TopRank = "topRank"
FN.Playlet.RecommendRank = "recommendRank"
FN.Playlet.CountComment = "countComment"
FN.Playlet.CountBuy = "countBuy"
FN.Playlet.CountBrowse = "countBrowse"
FN.Playlet.VirtualCountBrowse = "virtualCountBrowse"
FN.Playlet.WeekWatchs = "weekWatchs"
FN.Playlet.MonthWatchs = "monthWatchs"
FN.Playlet.YearWatchs = "yearWatchs"
FN.Playlet.WatchUpdatedAt = "watchUpdatedAt"
FN.Playlet.HeatValue = "heatValue"
FN.Playlet.VirtualHeatValue = "virtualHeatValue"
FN.Playlet.CountCollect = "countCollect"
FN.Playlet.CountLike = "countLike"
FN.Playlet.VirtualCountLike = "virtualCountLike"
FN.Playlet.CountDisLike = "countDisLike"
FN.Playlet.SeoInfo.Description = "seoInfo.webDescription"
FN.Playlet.SeoInfo.Keyworld = "seoInfo.webKeyworld"
FN.Playlet.SeoInfo.Title = "seoInfo.webTitle"
FN.Playlet.IndexNow = "indexNow"
FN.Playlet.OperatorId = "operatorId"
FN.Playlet.OperatorName = "operatorName"
FN.Playlet.CreatedAt = "createdAt"
FN.Playlet.UpdatedAt = "updatedAt"
TN.Playlet = "playlet"
}
+143
View File
@@ -0,0 +1,143 @@
package playletmod
import (
"strings"
"time"
"videoweb/pub/pubdef"
)
// ContentType 内容类型(与媒资 media_type 对应)
type ContentType int32
const (
ContentTypeTheater ContentType = 0 // 短剧(对应 media_type=5)
ContentTypeAlbum ContentType = 1 // 普通短剧/影集(对应 media_type=6)
ContentTypeComic ContentType = 2 // 漫画短剧(对应 media_type=4)
ContentTypeAnime ContentType = 3 // 动漫(对应 media_type=1)
ContentTypeManga ContentType = 4 // 漫画(对应 media_type=2)
)
// Status 上架状态
type Status int32
const (
StatusDown Status = 0 // 下架
StatusUp Status = 1 // 上架
)
// PayType 支付方式(剧级默认,连载上架后新增剧集沿用)
type PayType int32
const (
PayTypeFree PayType = 0 // 免费
PayTypeCoin PayType = 1 // 金币
PayTypeVip PayType = 2 // VIP
)
// Playlet @table: playlet
//
// Playlet 连载短剧集合模型
type Playlet struct {
Id int64 `json:"id" bson:"_id,omitempty"`
MediaCenterId uint `json:"mediaCenterId" bson:"mediaCenterId"` // 媒资中心资源ID
MediaCreatedAt time.Time `json:"mediaCreatedAt" bson:"mediaCreatedAt"` // 媒资中心创建时间
MediaUpdatedAt time.Time `json:"mediaUpdatedAt" bson:"mediaUpdatedAt"` // 媒资中心更新时间
MediaSyncTime int64 `json:"mediaSyncTime" bson:"mediaSyncTime"` // 媒资中心增量同步时间点
Status Status `json:"status" bson:"status"` // 状态: 0下架 1上架
IsFeatured bool `json:"isFeatured" bson:"isFeatured"` // 是否爆剧(true-是,false-否)
IsOriginal bool `json:"isOriginal" bson:"isOriginal"` // 是否原创:后台新增为true,媒资导入为false
ShowOriginal bool `json:"showOriginal" bson:"showOriginal"` // 页面是否展示原创标识
MediaBusiness string `json:"mediaBusiness" bson:"mediaBusiness"` // 媒资业务来源,按媒资标题前缀记录,如 CGDJ;空表示未标记
IsRecommend bool `json:"isRecommend" bson:"isRecommend"` // 是否推荐 true-推荐,false-不推荐
ShowOnBanner bool `json:"showOnBanner" bson:"showOnBanner"` // 是否显示在首页banner
Banner string `json:"banner" bson:"banner"` // banner图
ReviewAt time.Time `json:"reviewAt" bson:"reviewAt"` // 审核时间
OnlineAt time.Time `json:"onlineAt" bson:"onlineAt"` // 上架时间
CategoryIds []int64 `json:"categoryIds" bson:"categoryIds"` // 分类ID集合
CategoryBinds []PlayletCategoryBind `json:"categoryBinds" bson:"categoryBinds"` // 各分类下的排序
ThemeIds []int64 `json:"themeIds" bson:"themeIds"` // 题材ID集合
Title string `json:"title" bson:"title"` // 标题
Slug string `json:"slug" bson:"slug"` // slug
Desc string `json:"desc" bson:"desc"` // 简介
Anchor string `json:"anchor" bson:"anchor"` // 作者/演员
Cover string `json:"cover" bson:"cover"` // 封面原图
CompressedCover string `json:"compressedCover" bson:"compressedCover"` // 压缩封面,压缩成功才有值
Preview string `json:"preview" bson:"preview"` // 预告
TagIds []int64 `json:"tagIds" bson:"tagIds"` // 标签ID
OldTags []string `json:"oldTags" bson:"oldTags"` // 媒资库原标签名称
ContentType ContentType `json:"contentType" bson:"contentType"` // 内容类型: 0短剧 1普通短剧/影集 2漫画短剧 3动漫 4漫画
PayType PayType `json:"payType" bson:"payType"` // 支付方式 0-免费 1-金币 2-VIP
SingleCoins int64 `json:"singleCoins" bson:"singleCoins"` // 单集金币(支付方式为1-金币时候生效)
TotalEpisode int64 `json:"totalEpisode" bson:"totalEpisode"` // 总集数
FreeEpisodeCount int64 `json:"freeEpisodeCount" bson:"freeEpisodeCount"` // 官网开放集数 1至1000表示开放第1集到第N集 -1表示开放全集 0或字段缺失按2集
UpdateStatus int `json:"updateStatus" bson:"updateStatus"` // 更新状态 1-连载中 2-已完结
TopRank int64 `json:"topRank" bson:"topRank"` // 置顶排名
RecommendRank int64 `json:"recommendRank" bson:"recommendRank"` // 推荐排序
CountComment int64 `json:"countComment" bson:"countComment"` // 评论数
CountBuy int64 `json:"countBuy" bson:"countBuy"` // 购买数
CountBrowse int64 `json:"countBrowse" bson:"countBrowse"` // 浏览数
VirtualCountBrowse int64 `json:"virtualCountBrowse" bson:"virtualCountBrowse"` // 后台虚拟观看数
WeekWatchs int64 `json:"weekWatchs" bson:"weekWatchs"` // 本周观看次数(北京时间)
MonthWatchs int64 `json:"monthWatchs" bson:"monthWatchs"` // 本月观看次数(北京时间)
YearWatchs int64 `json:"yearWatchs" bson:"yearWatchs"` // 本年观看次数(北京时间)
WatchUpdatedAt time.Time `json:"watchUpdatedAt" bson:"watchUpdatedAt"` // 最近一次观看计数时间
HeatValue int64 `json:"heatValue" bson:"heatValue"` // 热度值
VirtualHeatValue int64 `json:"virtualHeatValue" bson:"virtualHeatValue"` // 后台虚拟热度值
CountCollect int64 `json:"countCollect" bson:"countCollect"` // 收藏数
CountLike int64 `json:"countLike" bson:"countLike"` // 喜欢数
VirtualCountLike int64 `json:"virtualCountLike" bson:"virtualCountLike"` // 虚拟喜欢数,后台配置
CountDisLike int64 `json:"countDisLike" bson:"countDisLike"` // 不喜欢数
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
IndexNow int64 `json:"indexNow" bson:"indexNow"` // 搜索引擎推送标记 0:待提交 1:已入队/已提交
OperatorId int64 `json:"operatorId" bson:"operatorId"` // 最后操作人ID(后台账号)
OperatorName string `json:"operatorName" bson:"operatorName"` // 最后操作人名称
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// EffectiveFreeEpisodeCount 历史短剧未配置时官网默认开放前2集
func (p *Playlet) EffectiveFreeEpisodeCount() int64 {
if p == nil || p.FreeEpisodeCount == 0 {
return 2
}
return p.FreeEpisodeCount
}
// IsOfficialEpisodeOpen 判断剧集是否在官网开放范围内
func (p *Playlet) IsOfficialEpisodeOpen(episode int64) bool {
if p == nil || p.Status != StatusUp || episode <= 0 {
return false
}
count := p.EffectiveFreeEpisodeCount()
return count == -1 || episode <= count
}
// PlayletList 短剧列表
type PlayletList []*Playlet
// DisplayCountBrowse 返回真实观看数与虚拟观看数之和
func (p *Playlet) DisplayCountBrowse() int64 {
if p == nil {
return 0
}
return p.CountBrowse + p.VirtualCountBrowse
}
// DisplayHeatValue 返回原热度与虚拟热度之和
func (p *Playlet) DisplayHeatValue() int64 {
if p == nil {
return 0
}
return p.HeatValue + p.VirtualHeatValue
}
// DisplayCover App 展示用封面:压缩图有值则优先,否则回退原图
func (p *Playlet) DisplayCover() string {
if p == nil {
return ""
}
if cover := strings.TrimSpace(p.CompressedCover); cover != "" {
return cover
}
return strings.TrimSpace(p.Cover)
}
+121
View File
@@ -0,0 +1,121 @@
package playlettagmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_tag 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletTag)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletTag.Status, Value: 1},
{Key: FN.PlayletTag.Rank, Value: -1},
{Key: FN.PlayletTag.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletTag.Name, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletTag.CreatedAt, Value: -1},
{Key: FN.PlayletTag.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playlettagmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOnePlayletTag 插入一条标签数据
func InsertOnePlayletTag(ctx context.Context, doc *PlayletTag) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletTag.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("playlettagmod:InsertOnePlayletTag failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOnePlayletTag 删除一条标签数据
func DelOnePlayletTag(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("playlettagmod:DelOnePlayletTag failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOnePlayletTag 查询一条标签数据
func FindOnePlayletTag(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*PlayletTag, *srvdef.SrvErr) {
var doc PlayletTag
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("playlettagmod:FindOnePlayletTag failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyPlayletTag 按条件查询多条标签数据
func FindManyPlayletTag(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletTagList, *srvdef.SrvErr) {
data := make(PlayletTagList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("playlettagmod:FindManyPlayletTag failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletTag 统计满足条件的标签数量
func CountPlayletTag(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("playlettagmod:CountPlayletTag failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOnePlayletTag 更新一条标签数据
func UpdateOnePlayletTag(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("playlettagmod:UpdateOnePlayletTag failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+38
View File
@@ -0,0 +1,38 @@
package playlettagmod
// TagPlayletTag 保存 playlet_tag 集合字段名
type TagPlayletTag struct {
Id string
Name string
Status string
Rank string
SeoInfo struct {
Description string
Keyworld string
Title string
}
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletTag TagPlayletTag
}
var TN struct {
PlayletTag string
}
func init() {
FN.PlayletTag.Id = "_id"
FN.PlayletTag.Name = "name"
FN.PlayletTag.Status = "status"
FN.PlayletTag.Rank = "rank"
FN.PlayletTag.SeoInfo.Description = "seoInfo.webDescription"
FN.PlayletTag.SeoInfo.Keyworld = "seoInfo.webKeyworld"
FN.PlayletTag.SeoInfo.Title = "seoInfo.webTitle"
FN.PlayletTag.CreatedAt = "createdAt"
FN.PlayletTag.UpdatedAt = "updatedAt"
TN.PlayletTag = "playlet_tag"
}
+22
View File
@@ -0,0 +1,22 @@
package playlettagmod
import (
"time"
"videoweb/pub/pubdef"
)
// PlayletTag @table: playlet_tag
//
// PlayletTag 短剧标签集合模型
type PlayletTag struct {
Id int64 `json:"id" bson:"_id,omitempty"` // ID
Name string `json:"name" bson:"name"` // 标签名称
Status bool `json:"status" bson:"status"` // 上架状态
Rank int64 `json:"rank" bson:"rank"` // 排序,越大越靠前
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletTagList 标签列表
type PlayletTagList []*PlayletTag
+42
View File
@@ -0,0 +1,42 @@
package playletthememod
// TagPlayletTheme 保存 playlet_theme 集合字段名
type TagPlayletTheme struct {
Id string
Name string
Slug string
Icon string
Status string
Rank string
SeoInfo struct {
Description string
Keyworld string
Title string
}
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletTheme TagPlayletTheme
}
var TN struct {
PlayletTheme string
}
func init() {
FN.PlayletTheme.Id = "_id"
FN.PlayletTheme.Name = "name"
FN.PlayletTheme.Slug = "slug"
FN.PlayletTheme.Icon = "icon"
FN.PlayletTheme.Status = "status"
FN.PlayletTheme.Rank = "rank"
FN.PlayletTheme.SeoInfo.Description = "seoInfo.webDescription"
FN.PlayletTheme.SeoInfo.Keyworld = "seoInfo.webKeyworld"
FN.PlayletTheme.SeoInfo.Title = "seoInfo.webTitle"
FN.PlayletTheme.CreatedAt = "createdAt"
FN.PlayletTheme.UpdatedAt = "updatedAt"
TN.PlayletTheme = "playlet_theme"
}
+121
View File
@@ -0,0 +1,121 @@
package playletthememod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_theme 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletTheme)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletTheme.Status, Value: 1},
{Key: FN.PlayletTheme.Rank, Value: -1},
{Key: FN.PlayletTheme.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletTheme.Name, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletTheme.CreatedAt, Value: -1},
{Key: FN.PlayletTheme.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletthememod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOnePlayletTheme 插入一条题材数据
func InsertOnePlayletTheme(ctx context.Context, doc *PlayletTheme) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletTheme.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("playletthememod:InsertOnePlayletTheme failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOnePlayletTheme 删除一条题材数据
func DelOnePlayletTheme(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("playletthememod:DelOnePlayletTheme failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOnePlayletTheme 查询一条题材数据
func FindOnePlayletTheme(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*PlayletTheme, *srvdef.SrvErr) {
var doc PlayletTheme
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("playletthememod:FindOnePlayletTheme failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyPlayletTheme 按条件查询多条题材数据
func FindManyPlayletTheme(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletThemeList, *srvdef.SrvErr) {
data := make(PlayletThemeList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("playletthememod:FindManyPlayletTheme failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletTheme 统计满足条件的题材数量
func CountPlayletTheme(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("playletthememod:CountPlayletTheme failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOnePlayletTheme 更新一条题材数据
func UpdateOnePlayletTheme(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("playletthememod:UpdateOnePlayletTheme failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+24
View File
@@ -0,0 +1,24 @@
package playletthememod
import (
"time"
"videoweb/pub/pubdef"
)
// PlayletTheme @table: playlet_theme
//
// PlayletTheme 短剧题材集合模型
type PlayletTheme struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"` // 题材名称
Slug string `json:"slug" bson:"slug"` // slug
Icon string `json:"icon" bson:"icon"` // 图标
Status bool `json:"status" bson:"status"` // 上架状态
Rank int64 `json:"rank" bson:"rank"` // 排序,越大越靠前
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
}
// PlayletThemeList 题材列表
type PlayletThemeList []*PlayletTheme
@@ -0,0 +1,88 @@
package questionnairemod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.Questionnaire)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Questionnaire.Status, Value: 1},
{Key: FN.Questionnaire.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Questionnaire.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(questionnaire:Init) Create Index failed! err:%+v", err))
}
}
// InsertOne 插入一条问卷
func InsertOne(ctx context.Context, doc *QuestionnaireModel) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, doc); err != nil {
log.Warn("questionnairemod:InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// FindOne 查找一条问卷
func FindOne(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*QuestionnaireModel, *srvdef.SrvErr) {
var doc QuestionnaireModel
if err := db.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err == mongo.ErrNoDocuments {
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
log.Warn("questionnairemod:FindOne failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return &doc, nil
}
// FindMany 查找多条问卷
func FindMany(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (QuestionnaireModelList, *srvdef.SrvErr) {
data := make(QuestionnaireModelList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("questionnairemod:FindMany failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// Count 统计问卷数量
func Count(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("questionnairemod:Count failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOne 更新一条问卷,返回 MatchedCount
func UpdateOne(ctx context.Context, filter bson.M, update bson.M) (int64, *srvdef.SrvErr) {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("questionnairemod:UpdateOne failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return result.MatchedCount, nil
}

Some files were not shown because too many files have changed in this diff Show More