@@ -0,0 +1,224 @@
|
||||
package aicommentrecord
|
||||
|
||||
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 db *mongos.Collection
|
||||
|
||||
func Init(ctx context.Context) {
|
||||
db = mongos.Shop.Coll(TN.AiCommentRecord)
|
||||
indexes := []mongo.IndexModel{
|
||||
{Keys: bson.D{{Key: FN.AiCommentRecord.Key, Value: 1}}, Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{FN.AiCommentRecord.Key: bson.M{"$exists": true}})},
|
||||
{Keys: bson.D{{Key: FN.AiCommentRecord.Vid, Value: 1}, {Key: FN.AiCommentRecord.TaskId, Value: 1}}},
|
||||
{Keys: bson.D{{Key: FN.AiCommentRecord.ObjType, Value: 1}, {Key: FN.AiCommentRecord.Vid, Value: 1}}},
|
||||
{Keys: bson.D{{Key: FN.AiCommentRecord.Vid, Value: 1}, {Key: FN.AiCommentRecord.Status, Value: 1}, {Key: FN.AiCommentRecord.CreatedAt, Value: 1}}},
|
||||
{Keys: bson.D{{Key: FN.AiCommentRecord.TaskId, Value: 1}, {Key: FN.AiCommentRecord.Status, Value: 1}}},
|
||||
{Keys: bson.D{{Key: FN.AiCommentRecord.ObjType, Value: 1}, {Key: FN.AiCommentRecord.Status, Value: 1}, {Key: FN.AiCommentRecord.CreatedAt, Value: 1}}},
|
||||
{Keys: bson.D{{Key: FN.AiCommentRecord.Status, Value: 1}, {Key: FN.AiCommentRecord.CreatedAt, Value: 1}}},
|
||||
{Keys: bson.D{{Key: FN.AiCommentRecord.CreatedAt, Value: 1}}},
|
||||
}
|
||||
if _, err := db.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(aicommentrecord:Init) Create AiCommentRecord Index failed! err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve claims one playlet before the external submit request. A failed claim
|
||||
// can be retried, while a submitted or completed claim blocks duplicate work.
|
||||
func Reserve(ctx context.Context, record *AiCommentRecord) (bool, *srvdef.SrvErr) {
|
||||
now := time.Now()
|
||||
record.Status = StatusSubmitting
|
||||
record.CreatedAt = now
|
||||
record.UpdatedAt = now
|
||||
result, err := db.UpsertOne(ctx, bson.M{FN.AiCommentRecord.Key: record.Key}, bson.M{"$setOnInsert": record})
|
||||
if err != nil {
|
||||
log.Warn("aicommentrecord:Reserve failed", log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
if result.UpsertedCount > 0 {
|
||||
return true, nil
|
||||
}
|
||||
result, err = db.UpdateOne(ctx,
|
||||
bson.M{FN.AiCommentRecord.Key: record.Key, FN.AiCommentRecord.Status: bson.M{"$in": []int{StatusFailed, StatusAbandoned}}},
|
||||
bson.M{"$set": bson.M{
|
||||
FN.AiCommentRecord.Status: StatusSubmitting,
|
||||
FN.AiCommentRecord.TaskId: "",
|
||||
FN.AiCommentRecord.RetainCount: record.RetainCount,
|
||||
FN.AiCommentRecord.TargetCount: record.TargetCount,
|
||||
FN.AiCommentRecord.Title: record.Title,
|
||||
FN.AiCommentRecord.Desc: record.Desc,
|
||||
FN.AiCommentRecord.CreatedAt: now,
|
||||
FN.AiCommentRecord.UpdatedAt: now,
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn("aicommentrecord:Reserve retry failed", log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
return result.ModifiedCount > 0, nil
|
||||
}
|
||||
|
||||
func SetSubmission(ctx context.Context, key, taskID string, status int, desc string) *srvdef.SrvErr {
|
||||
result, err := db.UpdateOne(ctx,
|
||||
bson.M{FN.AiCommentRecord.Key: key, FN.AiCommentRecord.Status: StatusSubmitting},
|
||||
bson.M{"$set": bson.M{
|
||||
FN.AiCommentRecord.TaskId: taskID,
|
||||
FN.AiCommentRecord.Status: status,
|
||||
FN.AiCommentRecord.Desc: desc,
|
||||
FN.AiCommentRecord.UpdatedAt: time.Now(),
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn("aicommentrecord:SetSubmission failed", log.E(err), log.Any("key", key))
|
||||
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
if result.MatchedCount == 0 {
|
||||
log.Warn("aicommentrecord:SetSubmission reservation not found", log.Any("key", key))
|
||||
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func InsertMany(ctx context.Context, records AiCommentRecordList) *srvdef.SrvErr {
|
||||
if len(records) == 0 {
|
||||
return nil
|
||||
}
|
||||
now := time.Now()
|
||||
for _, record := range records {
|
||||
if record.CreatedAt.IsZero() {
|
||||
record.CreatedAt = now
|
||||
}
|
||||
record.UpdatedAt = now
|
||||
}
|
||||
if _, err := db.InsertMany(ctx, &records); err != nil {
|
||||
log.Warn("aicommentrecord:InsertMany db.InsertMany failed", log.E(err))
|
||||
return srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FindByStatus(ctx context.Context, status int, limit int64) (AiCommentRecordList, *srvdef.SrvErr) {
|
||||
if limit <= 0 {
|
||||
limit = 100
|
||||
}
|
||||
records := make(AiCommentRecordList, 0)
|
||||
err := db.Find(ctx,
|
||||
&records,
|
||||
bson.M{FN.AiCommentRecord.Status: status},
|
||||
options.Find().SetSort(bson.D{{Key: FN.AiCommentRecord.CreatedAt, Value: 1}}).SetLimit(limit),
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn("aicommentrecord:FindByStatus db.Find failed", log.E(err), log.Any("status", status))
|
||||
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func FindFailedForRetry(ctx context.Context, limit int64) (AiCommentRecordList, *srvdef.SrvErr) {
|
||||
if limit <= 0 {
|
||||
limit = 100
|
||||
}
|
||||
records := make(AiCommentRecordList, 0)
|
||||
err := db.Find(ctx, &records,
|
||||
bson.M{FN.AiCommentRecord.Status: StatusFailed},
|
||||
options.Find().SetSort(bson.D{{Key: FN.AiCommentRecord.UpdatedAt, Value: 1}}).SetLimit(limit),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func SetStatusByKey(ctx context.Context, key string, status int, desc string) *srvdef.SrvErr {
|
||||
_, err := db.UpdateOne(ctx,
|
||||
bson.M{FN.AiCommentRecord.Key: key},
|
||||
bson.M{"$set": bson.M{
|
||||
FN.AiCommentRecord.Status: status,
|
||||
FN.AiCommentRecord.Desc: desc,
|
||||
FN.AiCommentRecord.UpdatedAt: time.Now(),
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FindByVIDsAndObjType(ctx context.Context, objType int64, vids []string) (AiCommentRecordList, *srvdef.SrvErr) {
|
||||
if len(vids) == 0 {
|
||||
return AiCommentRecordList{}, nil
|
||||
}
|
||||
records := make(AiCommentRecordList, 0)
|
||||
filter := bson.M{FN.AiCommentRecord.Vid: bson.M{"$in": vids}}
|
||||
if objType > 0 {
|
||||
filter[FN.AiCommentRecord.ObjType] = objType
|
||||
}
|
||||
if err := db.Find(ctx, &records, filter); err != nil {
|
||||
log.Warn("aicommentrecord:FindByVIDsAndObjType db.Find failed", log.E(err), log.Any("objType", objType), log.Any("vids", vids))
|
||||
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func BatchUpdateStatus(ctx context.Context, taskIDs []string, status int) *srvdef.SrvErr {
|
||||
if len(taskIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
if _, err := db.UpdateMMany(ctx,
|
||||
bson.M{FN.AiCommentRecord.TaskId: bson.M{"$in": taskIDs}},
|
||||
bson.M{"$set": bson.M{
|
||||
FN.AiCommentRecord.Status: status,
|
||||
FN.AiCommentRecord.UpdatedAt: time.Now(),
|
||||
}},
|
||||
); err != nil {
|
||||
log.Warn("aicommentrecord:BatchUpdateStatus db.UpdateMMany failed", log.E(err), log.Any("taskIDs", taskIDs))
|
||||
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateStatusAndDescByTaskID(ctx context.Context, taskID string, status int, desc string) *srvdef.SrvErr {
|
||||
if taskID == "" {
|
||||
return nil
|
||||
}
|
||||
if _, err := db.UpdateOne(ctx,
|
||||
bson.M{FN.AiCommentRecord.TaskId: taskID},
|
||||
bson.M{"$set": bson.M{
|
||||
FN.AiCommentRecord.Status: status,
|
||||
FN.AiCommentRecord.Desc: desc,
|
||||
FN.AiCommentRecord.UpdatedAt: time.Now(),
|
||||
}},
|
||||
); err != nil {
|
||||
log.Warn("aicommentrecord:UpdateStatusAndDescByTaskID db.UpdateOne failed", log.E(err), log.Any("taskID", taskID))
|
||||
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExpireSubmittedBefore(ctx context.Context, deadline time.Time, desc string) (int64, *srvdef.SrvErr) {
|
||||
result, err := db.UpdateMMany(ctx,
|
||||
bson.M{
|
||||
FN.AiCommentRecord.Status: bson.M{"$in": []int{StatusSubmitting, StatusSubmitted}},
|
||||
FN.AiCommentRecord.CreatedAt: bson.M{"$lt": deadline},
|
||||
},
|
||||
bson.M{"$set": bson.M{
|
||||
FN.AiCommentRecord.Status: StatusFailed,
|
||||
FN.AiCommentRecord.Desc: desc,
|
||||
FN.AiCommentRecord.UpdatedAt: time.Now(),
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn("aicommentrecord:ExpireSubmittedBefore db.UpdateMMany failed", log.E(err), log.Any("deadline", deadline))
|
||||
return 0, srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
return result.ModifiedCount, nil
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package aicommentrecord
|
||||
|
||||
type TagAiCommentRecord struct {
|
||||
Id string
|
||||
Key string
|
||||
Vid string
|
||||
Title string
|
||||
TaskId string
|
||||
ObjType string
|
||||
RetainCount string
|
||||
TargetCount string
|
||||
Status string
|
||||
Desc string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
DeletedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
AiCommentRecord TagAiCommentRecord
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
AiCommentRecord string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.AiCommentRecord.Id = "_id"
|
||||
FN.AiCommentRecord.Key = "key"
|
||||
FN.AiCommentRecord.Vid = "vid"
|
||||
FN.AiCommentRecord.Title = "title"
|
||||
FN.AiCommentRecord.TaskId = "task_id"
|
||||
FN.AiCommentRecord.ObjType = "objType"
|
||||
FN.AiCommentRecord.RetainCount = "retainCount"
|
||||
FN.AiCommentRecord.TargetCount = "targetCount"
|
||||
FN.AiCommentRecord.Status = "status"
|
||||
FN.AiCommentRecord.Desc = "desc"
|
||||
FN.AiCommentRecord.CreatedAt = "createdAt"
|
||||
FN.AiCommentRecord.UpdatedAt = "updatedAt"
|
||||
FN.AiCommentRecord.DeletedAt = "deletedAt"
|
||||
TN.AiCommentRecord = "ai_comment_record"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package aicommentrecord
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
const (
|
||||
StatusSubmitting = 0
|
||||
StatusSubmitted = 1
|
||||
StatusSuccess = 2
|
||||
StatusFailed = 3
|
||||
StatusAbandoned = 4
|
||||
)
|
||||
|
||||
// AiCommentRecord 记录已提交到自动评论服务的短剧任务,避免重复提交。
|
||||
// @table:ai_comment_record
|
||||
type AiCommentRecord struct {
|
||||
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
|
||||
Key string `json:"key" bson:"key,omitempty"`
|
||||
Vid string `json:"vid" bson:"vid"`
|
||||
Title string `json:"title" bson:"title"`
|
||||
TaskId string `json:"taskId" bson:"task_id"`
|
||||
ObjType int64 `json:"objType" bson:"objType"`
|
||||
RetainCount int `json:"retainCount" bson:"retainCount,omitempty"` // 该任务结果需保留的评论数
|
||||
TargetCount int `json:"targetCount" bson:"targetCount,omitempty"` // 本轮内容最终需要达到的AI评论数
|
||||
Status int `json:"status" bson:"status"`
|
||||
Desc string `json:"desc" bson:"desc"`
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
|
||||
DeletedAt time.Time `json:"deletedAt" bson:"deletedAt"`
|
||||
}
|
||||
|
||||
type AiCommentRecordList []*AiCommentRecord
|
||||
@@ -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
|
||||
}
|
||||
Executable
+42
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
Executable
+42
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"videoweb/pub/mongos"
|
||||
)
|
||||
|
||||
var (
|
||||
sysCfgColl *mongos.Collection
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
package cfg
|
||||
|
||||
type TagSysCfg struct {
|
||||
AppAddr string
|
||||
OfficialAppAddr 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
|
||||
CustomerServiceHost string
|
||||
WeiChart string
|
||||
DHNewUrlAddr1 string
|
||||
DHNewUrlAddr2 string
|
||||
DHNewUrlAddr3 string
|
||||
DHForeverUrlAddr string
|
||||
DHTitle string
|
||||
DHKeyworld string
|
||||
DHDescription string
|
||||
DHSiteName string
|
||||
ChannelCode string
|
||||
EnableH265 string
|
||||
AppKey string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
SysCfg TagSysCfg
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
SysCfg string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.SysCfg.AppAddr = "appAddr"
|
||||
FN.SysCfg.OfficialAppAddr = "officialAppAddr"
|
||||
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.CustomerServiceHost = "customerServiceHost"
|
||||
FN.SysCfg.WeiChart = "weiChart"
|
||||
FN.SysCfg.DHNewUrlAddr1 = "dHNewUrlAddr1"
|
||||
FN.SysCfg.DHNewUrlAddr2 = "dHNewUrlAddr2"
|
||||
FN.SysCfg.DHNewUrlAddr3 = "dHNewUrlAddr3"
|
||||
FN.SysCfg.DHForeverUrlAddr = "dHForeverUrlAddr"
|
||||
FN.SysCfg.DHTitle = "dhTitle"
|
||||
FN.SysCfg.DHKeyworld = "dhKeyworld"
|
||||
FN.SysCfg.DHDescription = "dhDescription"
|
||||
FN.SysCfg.DHSiteName = "dhSiteName"
|
||||
FN.SysCfg.ChannelCode = "channelCode"
|
||||
FN.SysCfg.EnableH265 = "enableH265"
|
||||
FN.SysCfg.AppKey = "appKey"
|
||||
TN.SysCfg = "sys_cfg"
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package cfg
|
||||
|
||||
import "strings"
|
||||
|
||||
// @table:sys_cfg
|
||||
type SysCfg struct {
|
||||
Id int64 `json:"id" bson:"_id"`
|
||||
UnencryptedCdn string `json:"unencryptedCdn" bson:"unencryptedCdn"` // 不加密资源使用的cdn
|
||||
SitemapDefaultImages []string `json:"sitemapDefaultImages" bson:"sitemapDefaultImages"` // Sitemap里面默认封面图
|
||||
ImgAppCdn string `json:"imgAppCdn" bson:"imgAppCdn"` // 图片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使用)
|
||||
ImgAppUsCdn string `json:"imgAppUsCdn" bson:"imgAppUsCdn"` // 图片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
|
||||
CustomerServiceHost string `json:"customerServiceHost" bson:"customerServiceHost"` // 在线客服
|
||||
//网站管理
|
||||
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下载地址(落地页)
|
||||
OfficialAppAddr string `json:"officialAppAddr" bson:"officialAppAddr"` //官网app地址
|
||||
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"` // 所有使用中的域名
|
||||
AdvitiesTopicNum int64 `json:"advitiesTopicNum" bson:"advitiesTopicNum"` // 广告间隔
|
||||
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网站名称
|
||||
ActressBackGround string `json:"actressBackGround" bson:"actressBackGround"` // 女优通用背景图
|
||||
ChannelCode string `json:"channelCode" bson:"channelCode"` // 渠道码
|
||||
EnableH265 bool `json:"enableH265" bson:"enableH265"` // 是否允许客户端使用 H265 地址播放
|
||||
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, "/")
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cointransmod
|
||||
|
||||
type TagCoinTrans struct {
|
||||
Id string
|
||||
UserId string
|
||||
UserName string
|
||||
FlowDir string
|
||||
TranType string
|
||||
Amount string
|
||||
BalanceBefore string
|
||||
BalanceAfter string
|
||||
OrderNo string
|
||||
RelatedId string
|
||||
Remark string
|
||||
CreatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
CoinTrans TagCoinTrans
|
||||
}
|
||||
var TN struct {
|
||||
CoinTrans string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.CoinTrans.Id = "_id"
|
||||
FN.CoinTrans.UserId = "userId"
|
||||
FN.CoinTrans.UserName = "userName"
|
||||
FN.CoinTrans.FlowDir = "flowDir"
|
||||
FN.CoinTrans.TranType = "tranType"
|
||||
FN.CoinTrans.Amount = "amount"
|
||||
FN.CoinTrans.BalanceBefore = "balanceBefore"
|
||||
FN.CoinTrans.BalanceAfter = "balanceAfter"
|
||||
FN.CoinTrans.OrderNo = "orderNo"
|
||||
FN.CoinTrans.RelatedId = "relatedId"
|
||||
FN.CoinTrans.Remark = "remark"
|
||||
FN.CoinTrans.CreatedAt = "createdAt"
|
||||
|
||||
TN.CoinTrans = "coin_trans"
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package cointransmod
|
||||
|
||||
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 coll *mongos.Collection
|
||||
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.CoinTrans)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
// 按用户+时间倒序查流水(最常用)
|
||||
{Keys: bson.D{
|
||||
{Key: FN.CoinTrans.UserId, Value: 1},
|
||||
{Key: FN.CoinTrans.CreatedAt, Value: -1},
|
||||
}},
|
||||
// 按交易类型筛选
|
||||
{Keys: bson.D{{Key: FN.CoinTrans.TranType, Value: 1}}},
|
||||
// 按订单号查(幂等校验)
|
||||
{Keys: bson.D{{Key: FN.CoinTrans.OrderNo, Value: 1}}},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(cointransmod:initIndex) Create Index failed! err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOneCoinTrans 写入一条流水记录
|
||||
func InsertOneCoinTrans(ctx context.Context, doc *CoinTrans) *srvdef.SrvErr {
|
||||
if _, err := coll.InsertOne(ctx, doc); err != nil {
|
||||
log.Error("cointransmod:InsertOneCoinTrans failed", log.Any("doc", doc), log.E(err))
|
||||
return srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindManyCoinTrans 分页查询流水列表
|
||||
func FindManyCoinTrans(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (CoinTransList, *srvdef.SrvErr) {
|
||||
var data CoinTransList
|
||||
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
|
||||
log.Warn("cointransmod:FindManyCoinTrans failed", log.E(err), log.Any("filter", filter))
|
||||
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CountCoinTrans 统计流水条数
|
||||
func CountCoinTrans(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
|
||||
count, err := coll.Count(ctx, filter)
|
||||
if err != nil {
|
||||
log.Warn("cointransmod:CountCoinTrans failed", log.E(err), log.Any("filter", filter))
|
||||
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// StatSyncConsumeList 按 ID 游标增量拉取金币消费流水(统计中心)
|
||||
func StatSyncConsumeList(ctx context.Context, startId int64, size int64) (CoinTransList, error) {
|
||||
opt := (&options.FindOptions{}).SetLimit(size).SetSort(bson.D{{Key: FN.CoinTrans.Id, Value: 1}})
|
||||
filter := bson.M{
|
||||
FN.CoinTrans.Id: bson.M{"$gt": startId},
|
||||
FN.CoinTrans.FlowDir: FlowOut,
|
||||
}
|
||||
list := CoinTransList{}
|
||||
if err := coll.Find(ctx, &list, filter, opt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package cointransmod
|
||||
|
||||
import "time"
|
||||
|
||||
// FlowDir 收支方向
|
||||
type FlowDir int8
|
||||
|
||||
const (
|
||||
FlowIn FlowDir = 1 // 收入(充值、赠送)
|
||||
FlowOut FlowDir = -1 // 支出(消费、解锁)
|
||||
)
|
||||
|
||||
func (f FlowDir) Desc() string {
|
||||
if f == FlowIn {
|
||||
return "收入"
|
||||
}
|
||||
return "支出"
|
||||
}
|
||||
|
||||
// TranType 交易类型
|
||||
type TranType int32
|
||||
|
||||
const (
|
||||
TranTypeCoinRecharge TranType = 1 // 金币充值(购买金币)
|
||||
TranTypeVipGiftCoin TranType = 2 // 购买会员赠送金币
|
||||
TranTypeDarkAlley TranType = 3 // 历史遗留交易类型(已下线)
|
||||
TranTypeVideoUnlock TranType = 4 // 视频解锁
|
||||
TranTypeAdminAdjust TranType = 5 // 管理员手动调整
|
||||
TranTypeCoinGift TranType = 6 // 金币充值赠送
|
||||
)
|
||||
|
||||
var TranTypeNameMap = map[TranType]string{
|
||||
TranTypeCoinRecharge: "金币充值",
|
||||
TranTypeVipGiftCoin: "会员赠送",
|
||||
TranTypeDarkAlley: "历史交易",
|
||||
TranTypeVideoUnlock: "视频解锁",
|
||||
TranTypeAdminAdjust: "管理员调整",
|
||||
TranTypeCoinGift: "充值赠送",
|
||||
}
|
||||
|
||||
func (t TranType) Desc() string {
|
||||
if name, ok := TranTypeNameMap[t]; ok {
|
||||
return name
|
||||
}
|
||||
return "未知"
|
||||
}
|
||||
|
||||
// @table: coin_trans
|
||||
type CoinTrans struct {
|
||||
Id int64 `json:"id" bson:"_id"` // 唯一ID
|
||||
UserId int64 `json:"userId" bson:"userId"` // 用户ID
|
||||
UserName string `json:"userName" bson:"userName"` // 用户昵称(快照)
|
||||
FlowDir FlowDir `json:"flowDir" bson:"flowDir"` // 收支方向:1收入 -1支出
|
||||
TranType TranType `json:"tranType" bson:"tranType"` // 交易类型
|
||||
Amount int64 `json:"amount" bson:"amount"` // 本次交易金币数(正整数)
|
||||
BalanceBefore int64 `json:"balanceBefore" bson:"balanceBefore"` // 交易前余额
|
||||
BalanceAfter int64 `json:"balanceAfter" bson:"balanceAfter"` // 交易后余额
|
||||
OrderNo string `json:"orderNo" bson:"orderNo"` // 关联订单号(可为空)
|
||||
RelatedId int64 `json:"relatedId" bson:"relatedId"` // 关联内容ID(视频等,可为空)
|
||||
Remark string `json:"remark" bson:"remark"` // 备注描述
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 交易时间
|
||||
}
|
||||
|
||||
type CoinTransList []*CoinTrans
|
||||
@@ -0,0 +1,90 @@
|
||||
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"
|
||||
)
|
||||
|
||||
var coll *mongos.Collection
|
||||
|
||||
// Init 初始化 comment_like 集合和常用查询索引
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.CommentLike)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.CommentLike.UserId, Value: 1},
|
||||
{Key: FN.CommentLike.CommentId, Value: 1},
|
||||
},
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.CommentLike.CommentId, Value: 1},
|
||||
{Key: FN.CommentLike.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.CommentLike.ObjectType, Value: 1},
|
||||
{Key: FN.CommentLike.ObjectId, Value: 1},
|
||||
{Key: FN.CommentLike.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(commentlikemod:initIndex) 创建索引失败 err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOneCommentLike 插入一条评论点赞关系
|
||||
func InsertOneCommentLike(ctx context.Context, doc *CommentLike) (bool, *srvdef.SrvErr) {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.CommentLike.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) {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("插入评论点赞关系失败", log.Any("doc", doc), log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// DeleteOneCommentLike 删除一条评论点赞关系
|
||||
func DeleteOneCommentLike(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
|
||||
count, err := coll.DeleteOne(ctx, filter)
|
||||
if err != nil {
|
||||
log.Warn("删除评论点赞关系失败", log.E(err), log.Any("filter", filter))
|
||||
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// FindManyCommentLike 按条件查询评论点赞关系
|
||||
func FindManyCommentLike(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (CommentLikeList, *srvdef.SrvErr) {
|
||||
data := make(CommentLikeList, 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, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package commentlikemod
|
||||
|
||||
// TagCommentLike 保存 comment_like 集合字段名
|
||||
type TagCommentLike struct {
|
||||
Id string
|
||||
UserId string
|
||||
CommentId string
|
||||
ObjectId string
|
||||
ObjectType string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
CommentLike TagCommentLike
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
CommentLike string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.CommentLike.Id = "_id"
|
||||
FN.CommentLike.UserId = "userId"
|
||||
FN.CommentLike.CommentId = "commentId"
|
||||
FN.CommentLike.ObjectId = "objectId"
|
||||
FN.CommentLike.ObjectType = "objectType"
|
||||
FN.CommentLike.CreatedAt = "createdAt"
|
||||
FN.CommentLike.UpdatedAt = "updatedAt"
|
||||
|
||||
TN.CommentLike = "comment_like"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package commentlikemod
|
||||
|
||||
import "time"
|
||||
|
||||
// CommentLike @table: comment_like
|
||||
//
|
||||
// CommentLike 评论点赞关系模型
|
||||
type CommentLike struct {
|
||||
Id int64 `json:"id" bson:"_id,omitempty"` // 点赞记录ID
|
||||
UserId int64 `json:"userId" bson:"userId"` // 用户ID
|
||||
CommentId int64 `json:"commentId" bson:"commentId"` // 评论ID
|
||||
ObjectId int64 `json:"objectId" bson:"objectId"` // 评论对象ID
|
||||
ObjectType int64 `json:"objectType" bson:"objectType"` // 评论对象类型 10-短剧 11-短剧剧集 20-视频
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
|
||||
}
|
||||
|
||||
// CommentLikeList 评论点赞关系列表
|
||||
type CommentLikeList []*CommentLike
|
||||
@@ -0,0 +1,241 @@
|
||||
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.AiTaskId, Value: 1}, {Key: FN.Comment.AiIndex, Value: 1}},
|
||||
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{FN.Comment.AiTaskId: bson.M{"$exists": true}}),
|
||||
},
|
||||
{
|
||||
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.ParentsId, Value: 1},
|
||||
{Key: FN.Comment.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.Comment.UserId, Value: 1},
|
||||
{Key: FN.Comment.ObjectType, 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.ParentsId, Value: 1},
|
||||
{Key: FN.Comment.CountLike, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.Comment.ParentsId, Value: 1},
|
||||
{Key: FN.Comment.Level, Value: 1},
|
||||
{Key: FN.Comment.ReviewStatus, Value: 1},
|
||||
{Key: FN.Comment.CreatedAt, Value: 1},
|
||||
{Key: FN.Comment.Id, 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))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertAICommentOnce makes a generated result safe to process again after a crash.
|
||||
func InsertAICommentOnce(ctx context.Context, comment *CommentModel) (bool, *srvdef.SrvErr) {
|
||||
filter := bson.M{FN.Comment.AiTaskId: comment.AiTaskId, FN.Comment.AiIndex: comment.AiIndex}
|
||||
result, err := db.UpsertOne(ctx, filter, bson.M{"$setOnInsert": comment})
|
||||
if err != nil {
|
||||
log.Warn("comment:InsertAICommentOnce failed", log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return result.UpsertedCount > 0, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
package commentmod
|
||||
|
||||
type TagComment struct {
|
||||
CreatedAt string
|
||||
Id string
|
||||
Level string
|
||||
ObjectId string
|
||||
ParentsId string
|
||||
ReplyCommentId string
|
||||
ReplyUserName string
|
||||
Text string
|
||||
TopRank string
|
||||
UpdatedAt string
|
||||
UserId string
|
||||
UserName string
|
||||
UserAvatar string
|
||||
ReviewStatus string
|
||||
IsAi string
|
||||
AiTaskId string
|
||||
AiIndex 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.ReplyCommentId = "replyCommentId"
|
||||
FN.Comment.ReplyUserName = "replyUserName"
|
||||
FN.Comment.Text = "text"
|
||||
FN.Comment.TopRank = "topRank"
|
||||
FN.Comment.UpdatedAt = "updatedAt"
|
||||
FN.Comment.UserId = "userId"
|
||||
FN.Comment.UserName = "userName"
|
||||
FN.Comment.UserAvatar = "userAvatar"
|
||||
FN.Comment.ReviewStatus = "reviewStatus"
|
||||
FN.Comment.IsAi = "isAi"
|
||||
FN.Comment.AiTaskId = "aiTaskId"
|
||||
FN.Comment.AiIndex = "aiIndex"
|
||||
FN.Comment.Ip = "ip"
|
||||
FN.Comment.CommentCount = "commentCount"
|
||||
FN.Comment.CountLike = "countLike"
|
||||
FN.Comment.ObjectName = "objectName"
|
||||
FN.Comment.ObjectType = "objectType"
|
||||
TN.Comment = "_comment"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package commentmod
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 评论管理
|
||||
// @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 int64 `json:"objectType" bson:"objectType"` // 对象类型
|
||||
ObjectName string `json:"objectName" bson:"objectName"` // 对象名
|
||||
UserId int64 `json:"userId" bson:"userId"` // 评论用户ID
|
||||
UserName string `json:"userName" bson:"userName"` // 用户名称
|
||||
UserAvatar string `json:"userAvatar" bson:"userAvatar"` // 评论用户头像
|
||||
Level int64 `json:"level" bson:"level"` // 评论级别,1-一级评论 2-二级评论
|
||||
ParentsId int64 `json:"parentsId" bson:"parentsId"` // 上级评论ID,一级评论为0
|
||||
ReplyCommentId int64 `json:"replyCommentId" bson:"replyCommentId"` // 被回复评论ID,一级评论为0
|
||||
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 审核失败
|
||||
IsAi bool `json:"isAi" bson:"isAi,omitempty"` // 自动生成评论
|
||||
AiTaskId string `json:"-" bson:"aiTaskId,omitempty"` // 生成任务ID
|
||||
AiIndex int `json:"-" bson:"aiIndex,omitempty"` // 任务内序号
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
|
||||
CreatedAt time.Time `bson:"createdAt" json:"createdAt"` // 创建时间
|
||||
TopRank int64 `json:"topRank" bson:"topRank"` // 置顶排序
|
||||
}
|
||||
|
||||
type CommentModelList []*CommentModel
|
||||
@@ -0,0 +1,100 @@
|
||||
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 coll *mongos.Collection
|
||||
|
||||
// Init 初始化 contactus 集合和常用查询索引
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.ContactUs)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.ContactUs.UserId, Value: 1},
|
||||
{Key: FN.ContactUs.CreatedAt, Value: -1},
|
||||
{Key: FN.ContactUs.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.ContactUs.Status, Value: 1},
|
||||
{Key: FN.ContactUs.CreatedAt, Value: -1},
|
||||
{Key: FN.ContactUs.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.ContactUs.QuestionType, Value: 1},
|
||||
{Key: FN.ContactUs.CreatedAt, Value: -1},
|
||||
{Key: FN.ContactUs.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.ContactUs.CreatedAt, Value: -1},
|
||||
{Key: FN.ContactUs.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(contactusmod:initIndex) Create Index failed! err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOneContactUs 插入一条联系我们数据
|
||||
//
|
||||
// 当 doc.Id 为空时,会使用 mongos.Lid.ContactUs 自动生成自增ID
|
||||
func InsertOneContactUs(ctx context.Context, doc *ContactUs) *srvdef.SrvErr {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.ContactUs.Get()
|
||||
}
|
||||
if _, err := coll.InsertOne(ctx, doc); err != nil {
|
||||
log.Warn("联系我们记录写入失败", log.Any("doc", doc), log.E(err))
|
||||
return srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindManyContactUs 按条件查询多条联系我们数据
|
||||
func FindManyContactUs(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (ContactUsList, *srvdef.SrvErr) {
|
||||
var data ContactUsList
|
||||
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, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CountContactUs 统计满足条件的联系我们数量
|
||||
func CountContactUs(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
|
||||
}
|
||||
|
||||
// UpdateManyContactUsWithResult 批量更新联系我们数据,并返回命中数量和修改数量
|
||||
func UpdateManyContactUsWithResult(ctx context.Context, filter bson.M, update bson.M) (matchedCount int64, modifiedCount int64, serr *srvdef.SrvErr) {
|
||||
result, err := coll.UpdateMany(ctx, filter, update)
|
||||
if err != nil {
|
||||
log.Warn("联系我们批量更新失败", log.E(err), log.Any("filter", filter))
|
||||
return 0, 0, srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
return result.MatchedCount, result.ModifiedCount, nil
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package contactusmod
|
||||
|
||||
// TagContactUs 保存contactus集合字段名
|
||||
type TagContactUs struct {
|
||||
Id string
|
||||
UserId string
|
||||
Email string
|
||||
QuestionType string
|
||||
Title string
|
||||
Content string
|
||||
Attachments string
|
||||
Status string
|
||||
Remark string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
ContactUs TagContactUs
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
ContactUs string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.ContactUs.Id = "_id"
|
||||
FN.ContactUs.UserId = "userId"
|
||||
FN.ContactUs.Email = "email"
|
||||
FN.ContactUs.QuestionType = "questionType"
|
||||
FN.ContactUs.Title = "title"
|
||||
FN.ContactUs.Content = "content"
|
||||
FN.ContactUs.Attachments = "attachments"
|
||||
FN.ContactUs.Status = "status"
|
||||
FN.ContactUs.Remark = "remark"
|
||||
FN.ContactUs.CreatedAt = "createdAt"
|
||||
FN.ContactUs.UpdatedAt = "updatedAt"
|
||||
|
||||
TN.ContactUs = "contactus"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package contactusmod
|
||||
|
||||
import "time"
|
||||
|
||||
// ContactUs @table: contactus
|
||||
//
|
||||
// ContactUs 联系我们集合模型
|
||||
type ContactUs struct {
|
||||
// ID
|
||||
Id int64 `json:"id" bson:"_id,omitempty"`
|
||||
// 用户ID
|
||||
UserId int64 `json:"userId" bson:"userId"`
|
||||
// 邮箱
|
||||
Email string `json:"email" bson:"email"`
|
||||
// 问题类型,1-订单问题、2-账号问题、3-功能问题、4-体验问题、5-其他
|
||||
QuestionType int32 `json:"questionType" bson:"questionType"`
|
||||
// 标题
|
||||
Title string `json:"title" bson:"title"`
|
||||
// 内容
|
||||
Content string `json:"content" bson:"content"`
|
||||
// 附件地址,可存放多张图片或文件地址
|
||||
Attachments []string `json:"attachments" bson:"attachments"`
|
||||
// 处理状态,0-待处理、1-已处理
|
||||
Status int32 `json:"status" bson:"status"`
|
||||
// 处理备注
|
||||
Remark string `json:"remark" bson:"remark,omitempty"`
|
||||
// 创建时间
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
|
||||
// 更新时间
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
|
||||
}
|
||||
|
||||
// ContactUsList 联系我们列表
|
||||
type ContactUsList []*ContactUs
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,58 @@
|
||||
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 = "webhddjweb_video_index_v1"
|
||||
playletIndex = "webhddjweb_playlet_index_v1"
|
||||
)
|
||||
|
||||
func GetVideoIndex() string {
|
||||
return videoIndex
|
||||
}
|
||||
|
||||
func GetPlayletIndex() string {
|
||||
return playletIndex
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
package esmod
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"videoweb/pub/common/log"
|
||||
"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
|
||||
}
|
||||
initPlayletIndex(playletIndex)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
log.Warn("初始化视频ES索引失败,跳过索引创建", log.Any("索引", esIndex), log.E(err))
|
||||
}
|
||||
}
|
||||
|
||||
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.OperateType: esmanager.M{
|
||||
"type": "integer",
|
||||
},
|
||||
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.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.PlayName: esmanager.M{
|
||||
"type": "text",
|
||||
"analyzer": esmanager.AnalyzerIkMaxWord,
|
||||
"search_analyzer": esmanager.AnalyzerIkSmart,
|
||||
},
|
||||
FN.ESPlaylet.Description: esmanager.M{
|
||||
"type": "keyword",
|
||||
"index": false,
|
||||
},
|
||||
FN.ESPlaylet.Slug: esmanager.M{
|
||||
"type": "keyword",
|
||||
},
|
||||
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.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",
|
||||
},
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := esmanager.Instance.InitIndices(esIndex, setting); err != nil {
|
||||
log.Warn("初始化短剧ES索引失败,跳过索引创建", log.Any("索引", esIndex), log.E(err))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Executable
+299
@@ -0,0 +1,299 @@
|
||||
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
|
||||
Slug 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
|
||||
OperateType string
|
||||
ShowOnBanner string
|
||||
Banner string
|
||||
OnlineAt string
|
||||
ThemeIds string
|
||||
ThemeNames string
|
||||
CategoryIds string
|
||||
Title string
|
||||
PlayName string
|
||||
Description string
|
||||
Slug string
|
||||
Desc string
|
||||
Anchor string
|
||||
Cover string
|
||||
TagIds string
|
||||
TagNames string
|
||||
TotalEpisode string
|
||||
UpdateStatus string
|
||||
CountBrowse string
|
||||
HeatValue string
|
||||
CountCollect string
|
||||
CountLike string
|
||||
UpdatedAt string
|
||||
CreatedAt string
|
||||
SeoInfo string
|
||||
}
|
||||
|
||||
type TagESActress struct {
|
||||
Id string
|
||||
Alias string
|
||||
Avatar string
|
||||
Meas string
|
||||
Office string
|
||||
DebutDate string
|
||||
BornDate string
|
||||
Region string
|
||||
Score string
|
||||
Works 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
|
||||
}
|
||||
type TagESPost struct {
|
||||
Id string
|
||||
CreateId string
|
||||
Title string
|
||||
Cover string
|
||||
Thumb string
|
||||
TagIds string
|
||||
Kind string
|
||||
Nodes string
|
||||
VideoId string
|
||||
Status string
|
||||
Remark string
|
||||
Rank string
|
||||
AddedTime string
|
||||
Real struct {
|
||||
WatchTimes string
|
||||
ShowTimes string
|
||||
Comments string
|
||||
WeekWatchs string
|
||||
MonthWatchs string
|
||||
TodayWatchs string
|
||||
}
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
Keyworlds string
|
||||
FirstTag string
|
||||
Desc string
|
||||
IsHot string
|
||||
Sort string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
ESRecord TagESRecord
|
||||
ESVideo TagESVideo
|
||||
ESPlaylet TagESPlaylet
|
||||
ESActress TagESActress
|
||||
ESPost TagESPost
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
ESRecord string
|
||||
ESVideo string
|
||||
ESPlaylet string
|
||||
ESActress string
|
||||
ESPost 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",
|
||||
Slug: "slug",
|
||||
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",
|
||||
OperateType: "operateType",
|
||||
ShowOnBanner: "showOnBanner",
|
||||
Banner: "banner",
|
||||
OnlineAt: "onlineAt",
|
||||
ThemeIds: "themeIds",
|
||||
ThemeNames: "themeNames",
|
||||
CategoryIds: "categoryIds",
|
||||
Title: "title",
|
||||
PlayName: "playName",
|
||||
Description: "description",
|
||||
Slug: "slug",
|
||||
Desc: "desc",
|
||||
Anchor: "anchor",
|
||||
Cover: "cover",
|
||||
TagIds: "tagIds",
|
||||
TagNames: "tagNames",
|
||||
TotalEpisode: "totalEpisode",
|
||||
UpdateStatus: "updateStatus",
|
||||
CountBrowse: "countBrowse",
|
||||
HeatValue: "heatValue",
|
||||
CountCollect: "countCollect",
|
||||
CountLike: "countLike",
|
||||
UpdatedAt: "updatedAt",
|
||||
CreatedAt: "createdAt",
|
||||
SeoInfo: "seoInfo",
|
||||
}
|
||||
|
||||
FN.ESActress = TagESActress{
|
||||
Id: "_id",
|
||||
Alias: "alias",
|
||||
Avatar: "avatar",
|
||||
Meas: "meas",
|
||||
Office: "office",
|
||||
DebutDate: "debutDate",
|
||||
BornDate: "bornDate",
|
||||
Region: "region",
|
||||
Score: "score",
|
||||
Works: "works",
|
||||
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",
|
||||
}
|
||||
|
||||
FN.ESPost = TagESPost{
|
||||
Id: "_id",
|
||||
CreateId: "createId",
|
||||
Title: "title",
|
||||
Cover: "cover",
|
||||
Thumb: "thumb",
|
||||
TagIds: "tagIds",
|
||||
Kind: "kind",
|
||||
Nodes: "nodes",
|
||||
VideoId: "videoId",
|
||||
Status: "status",
|
||||
Remark: "remark",
|
||||
Rank: "rank",
|
||||
AddedTime: "addedTime",
|
||||
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"},
|
||||
CreatedAt: "createdAt",
|
||||
UpdatedAt: "updatedAt",
|
||||
Keyworlds: "keyworlds",
|
||||
FirstTag: "firstTag",
|
||||
Desc: "desc",
|
||||
IsHot: "isHot",
|
||||
Sort: "sort",
|
||||
}
|
||||
|
||||
TN.ESRecord = "es_record"
|
||||
TN.ESVideo = "es_video"
|
||||
TN.ESPlaylet = "es_playlet"
|
||||
TN.ESActress = "es_actress"
|
||||
TN.ESPost = "es_post"
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
//go:generate gen_bson_tag -m esmod
|
||||
//esmod essearch数据结构定义
|
||||
|
||||
package esmod
|
||||
|
||||
import (
|
||||
"time"
|
||||
"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"` // 帖子标题
|
||||
Slug string `json:"slug" bson:"slug"` // slug
|
||||
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 videoinformationmod.InformationSatus `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"` // 视频
|
||||
CategoryIds []int64 `json:"categoryIds" bson:"categoryIds"` // 分类Id
|
||||
Tags []int64 `json:"tags" bson:"tags"` // 标签
|
||||
Real videoinformationmod.Flow `json:"real" bson:"real"` // 真实流量
|
||||
VideoCount int64 `json:"videoCount" bson:"videoCount"` // 合集视频数量
|
||||
}
|
||||
|
||||
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"` // 是否爆剧(true-是,false-否)
|
||||
IsRecommend bool `json:"isRecommend" bson:"isRecommend"` // 是否推荐 true-推荐,false-不推荐
|
||||
OperateType playletmod.OperateType `json:"operateType" bson:"operateType"` // 运营类型 1-短剧 2-漫剧
|
||||
ShowOnBanner bool `json:"showOnBanner" bson:"showOnBanner"` // 是否显示在首页banner
|
||||
Banner string `json:"banner" bson:"banner"` // banner图
|
||||
OnlineAt time.Time `json:"onlineAt" bson:"onlineAt"` // 上架时间
|
||||
ThemeIds []int64 `json:"themeIds" bson:"themeIds"` // 题材ID集合
|
||||
ThemeNames []string `json:"themeNames" bson:"themeNames"` // 题材名称集合
|
||||
CategoryIds []int64 `json:"categoryIds" bson:"categoryIds"` // 分类ID集合
|
||||
Title string `json:"title" bson:"title"` // 标题
|
||||
PlayName string `json:"playName" bson:"playName"` // 剧名
|
||||
Description string `json:"description" bson:"description"` // SEO Description
|
||||
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"` // 封面
|
||||
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"` // 展示点赞数
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"` // 修改时间
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package feedbackmod
|
||||
|
||||
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 coll *mongos.Collection
|
||||
|
||||
// Init 初始化 feedback 集合和常用查询索引
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.Feedback)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.Feedback.UserId, Value: 1},
|
||||
{Key: FN.Feedback.CreatedAt, Value: -1},
|
||||
{Key: FN.Feedback.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.Feedback.Status, Value: 1},
|
||||
{Key: FN.Feedback.CreatedAt, Value: -1},
|
||||
{Key: FN.Feedback.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.Feedback.CreatedAt, Value: -1},
|
||||
{Key: FN.Feedback.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(feedbackmod:initIndex) Create Index failed! err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOneFeedback 插入一条用户意见反馈数据
|
||||
//
|
||||
// 当 doc.Id 为空时,会使用 mongos.Lid.Feedback 自动生成自增ID
|
||||
func InsertOneFeedback(ctx context.Context, doc *Feedback) *srvdef.SrvErr {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.Feedback.Get()
|
||||
}
|
||||
if _, err := coll.InsertOne(ctx, doc); err != nil {
|
||||
log.Warn("用户意见反馈写入失败", log.Any("doc", doc), log.E(err))
|
||||
return srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindManyFeedback 按条件查询多条用户意见反馈数据
|
||||
func FindManyFeedback(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (FeedbackList, *srvdef.SrvErr) {
|
||||
var data FeedbackList
|
||||
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, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CountFeedback 统计满足条件的用户意见反馈数量
|
||||
func CountFeedback(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
|
||||
}
|
||||
|
||||
// UpdateManyFeedbackWithResult 批量更新用户意见反馈数据,并返回命中数量和修改数量
|
||||
func UpdateManyFeedbackWithResult(ctx context.Context, filter bson.M, update bson.M) (matchedCount int64, modifiedCount int64, serr *srvdef.SrvErr) {
|
||||
result, err := coll.UpdateMany(ctx, filter, update)
|
||||
if err != nil {
|
||||
log.Warn("用户意见反馈批量更新失败", log.E(err), log.Any("filter", filter))
|
||||
return 0, 0, srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
return result.MatchedCount, result.ModifiedCount, nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package feedbackmod
|
||||
|
||||
// TagFeedback 保存feedback集合字段名
|
||||
type TagFeedback struct {
|
||||
Id string
|
||||
UserId string
|
||||
FeedbackType string
|
||||
Content string
|
||||
Screenshots string
|
||||
Contact string
|
||||
Status string
|
||||
Remark string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
Feedback TagFeedback
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
Feedback string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.Feedback.Id = "_id"
|
||||
FN.Feedback.UserId = "userId"
|
||||
FN.Feedback.FeedbackType = "feedbackType"
|
||||
FN.Feedback.Content = "content"
|
||||
FN.Feedback.Screenshots = "screenshots"
|
||||
FN.Feedback.Contact = "contact"
|
||||
FN.Feedback.Status = "status"
|
||||
FN.Feedback.Remark = "remark"
|
||||
FN.Feedback.CreatedAt = "createdAt"
|
||||
FN.Feedback.UpdatedAt = "updatedAt"
|
||||
|
||||
TN.Feedback = "feedback"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package feedbackmod
|
||||
|
||||
import "time"
|
||||
|
||||
// Feedback @table: feedback
|
||||
//
|
||||
// Feedback 用户意见反馈集合模型
|
||||
type Feedback struct {
|
||||
// ID
|
||||
Id int64 `json:"id" bson:"_id,omitempty"`
|
||||
// 用户ID
|
||||
UserId int64 `json:"userId" bson:"userId"`
|
||||
// 问题类型,1-功能建议、2-播放问题、3-账号问题、4-其他
|
||||
FeedbackType int32 `json:"feedbackType" bson:"feedbackType"`
|
||||
// 描述内容
|
||||
Content string `json:"content" bson:"content"`
|
||||
// 问题截图,可存放多张图片地址
|
||||
Screenshots []string `json:"screenshots" bson:"screenshots"`
|
||||
// 联系方式,可为空
|
||||
Contact string `json:"contact" bson:"contact,omitempty"`
|
||||
// 处理状态,0-待处理、1-已处理
|
||||
Status int32 `json:"status" bson:"status"`
|
||||
// 处理备注
|
||||
Remark string `json:"remark" bson:"remark,omitempty"`
|
||||
// 创建时间
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
|
||||
// 更新时间
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
|
||||
}
|
||||
|
||||
// FeedbackList 用户意见反馈列表
|
||||
type FeedbackList []*Feedback
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,136 @@
|
||||
package homeconfigmod
|
||||
|
||||
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_config 集合和常用查询索引
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.HomeConfig)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.HomeConfig.Type, Value: 1},
|
||||
{Key: FN.HomeConfig.SortType, Value: 1},
|
||||
{Key: FN.HomeConfig.Status, Value: 1},
|
||||
{Key: FN.HomeConfig.Rank, Value: -1},
|
||||
{Key: FN.HomeConfig.UpdatedAt, Value: -1},
|
||||
{Key: FN.HomeConfig.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.HomeConfig.Name, Value: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.HomeConfig.Slug, Value: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.HomeConfig.CreatedAt, Value: -1},
|
||||
{Key: FN.HomeConfig.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.HomeConfig.Status, Value: 1},
|
||||
{Key: FN.HomeConfig.Rank, Value: -1},
|
||||
{Key: FN.HomeConfig.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(homeconfigmod:initIndex) Create Index failed! err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOneHomeConfig 插入一条首页配置数据
|
||||
func InsertOneHomeConfig(ctx context.Context, doc *HomeConfig) *srvdef.SrvErr {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.HomeConfig.Get()
|
||||
}
|
||||
now := time.Now()
|
||||
if doc.CreatedAt.IsZero() {
|
||||
doc.CreatedAt = now
|
||||
}
|
||||
doc.UpdatedAt = now
|
||||
if _, err := coll.InsertOne(ctx, doc); err != nil {
|
||||
log.Warn("homeconfigmod:InsertOneHomeConfig failed", log.Any("doc", doc), log.E(err))
|
||||
return srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelOneHomeConfig 删除一条首页配置数据
|
||||
func DelOneHomeConfig(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
|
||||
count, err := coll.DeleteOne(ctx, filter)
|
||||
if err != nil {
|
||||
log.Warn("homeconfigmod:DelOneHomeConfig failed", log.E(err), log.Any("filter", filter))
|
||||
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// FindManyHomeConfig 按条件查询多条首页配置数据
|
||||
func FindManyHomeConfig(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (HomeConfigList, *srvdef.SrvErr) {
|
||||
data := make(HomeConfigList, 0)
|
||||
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
|
||||
log.Warn("homeconfigmod:FindManyHomeConfig failed", log.E(err), log.Any("filter", filter))
|
||||
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CountHomeConfig 统计满足条件的首页配置数量
|
||||
func CountHomeConfig(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
|
||||
count, err := coll.Count(ctx, filter, opts...)
|
||||
if err != nil {
|
||||
log.Warn("homeconfigmod:CountHomeConfig failed", log.E(err), log.Any("filter", filter))
|
||||
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// FindOneHomeConfig 查询一条首页配置
|
||||
func FindOneHomeConfig(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*HomeConfig, *srvdef.SrvErr) {
|
||||
var doc HomeConfig
|
||||
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
|
||||
if err != mongo.ErrNoDocuments {
|
||||
log.Warn("homeconfigmod:FindOneHomeConfig failed", log.E(err), log.Any("filter", filter))
|
||||
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return nil, srvdef.New(srvdef.ErrNoData, "", "")
|
||||
}
|
||||
return &doc, nil
|
||||
}
|
||||
|
||||
// UpdateOneHomeConfig 更新一条首页配置数据
|
||||
func UpdateOneHomeConfig(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
|
||||
result, err := coll.UpdateOne(ctx, filter, update)
|
||||
if err != nil {
|
||||
log.Warn("homeconfigmod:UpdateOneHomeConfig failed", log.E(err), log.Any("filter", filter))
|
||||
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
if result.MatchedCount != 1 {
|
||||
return srvdef.New(srvdef.ErrNoData, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package homeconfigmod
|
||||
|
||||
// TagHomeConfig 保存 home_config 集合字段名
|
||||
type TagHomeConfig struct {
|
||||
Id string
|
||||
Name string
|
||||
Slug string
|
||||
Desc string
|
||||
Keyword string
|
||||
Label string
|
||||
Style string
|
||||
CardBackgroundImage string
|
||||
TopicIds string
|
||||
CategoryId string
|
||||
RecommendType string
|
||||
Type string
|
||||
Rank string
|
||||
Limit string
|
||||
SortType string
|
||||
Status string
|
||||
SeoInfo struct {
|
||||
Description string
|
||||
Keyworld string
|
||||
Title string
|
||||
}
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
HomeConfig TagHomeConfig
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
HomeConfig string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.HomeConfig.Id = "_id"
|
||||
FN.HomeConfig.Name = "name"
|
||||
FN.HomeConfig.Slug = "slug"
|
||||
FN.HomeConfig.Desc = "desc"
|
||||
FN.HomeConfig.Keyword = "keyword"
|
||||
FN.HomeConfig.Label = "label"
|
||||
FN.HomeConfig.Style = "style"
|
||||
FN.HomeConfig.CardBackgroundImage = "cardBackgroundImage"
|
||||
FN.HomeConfig.TopicIds = "topicIds"
|
||||
FN.HomeConfig.CategoryId = "categoryId"
|
||||
FN.HomeConfig.RecommendType = "recommendType"
|
||||
FN.HomeConfig.Type = "type"
|
||||
FN.HomeConfig.Rank = "rank"
|
||||
FN.HomeConfig.Limit = "limit"
|
||||
FN.HomeConfig.SortType = "sortType"
|
||||
FN.HomeConfig.Status = "status"
|
||||
FN.HomeConfig.SeoInfo.Description = "seoInfo.webDescription"
|
||||
FN.HomeConfig.SeoInfo.Keyworld = "seoInfo.webKeyworld"
|
||||
FN.HomeConfig.SeoInfo.Title = "seoInfo.webTitle"
|
||||
FN.HomeConfig.CreatedAt = "createdAt"
|
||||
FN.HomeConfig.UpdatedAt = "updatedAt"
|
||||
TN.HomeConfig = "home_config"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package homeconfigmod
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
"videoweb/pub/pubdef"
|
||||
)
|
||||
|
||||
const (
|
||||
TypePlaylet int32 = 1 // 短剧
|
||||
TypeTheme int32 = 3 // 题材
|
||||
)
|
||||
|
||||
const (
|
||||
SortTypeRecommend int32 = 1 // 推荐
|
||||
SortTypeHot int32 = 2 // 热播
|
||||
SortTypeLatest int32 = 3 // 最近更新
|
||||
SortTypeOnlineAt int32 = 4 // 上架时间
|
||||
SortTypeCategory int32 = 5 // 分类
|
||||
)
|
||||
|
||||
// HomeConfig @table: home_config
|
||||
//
|
||||
// HomeConfig 首页配置集合模型
|
||||
type HomeConfig struct {
|
||||
Id int64 `json:"id" bson:"_id,omitempty"` // ID
|
||||
Name string `json:"name" bson:"name"` // 名称
|
||||
Slug string `json:"slug" bson:"slug"` // slug,H5 更多页路径优先用它
|
||||
Desc string `json:"desc" bson:"desc"` // 描述
|
||||
Keyword []string `json:"keyword" bson:"keyword"` // 页面关键字
|
||||
Label string `json:"label" bson:"label"`
|
||||
Style string `json:"style" bson:"style"`
|
||||
CardBackgroundImage string `json:"cardBackgroundImage" bson:"cardBackgroundImage"`
|
||||
TopicIds []int64 `json:"topicIds" bson:"topicIds"`
|
||||
CategoryId int64 `json:"categoryId" bson:"categoryId"`
|
||||
RecommendType int64 `json:"recommendType" bson:"recommendType"` // 参考项目排序;0 沿用本项目 sortType
|
||||
Type int32 `json:"type" bson:"type"` // 首页配置类型 1-短剧 3-题材
|
||||
Rank int64 `json:"rank" bson:"rank"` // 排序,越大越靠前
|
||||
Limit int64 `json:"limit" bson:"limit"` // 首页展示数量,0 时短剧默认12条、题材默认8个
|
||||
SortType int32 `json:"sortType" bson:"sortType"` // 短剧模块排序 1-推荐 2-热播 3-最近更新 4-上架时间 5-分类,题材模块预览按专题详情默认排序
|
||||
Status bool `json:"status" bson:"status"` // 上下架状态 true-上架 false-下架
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
|
||||
}
|
||||
|
||||
// HomeConfigList 首页配置列表
|
||||
type HomeConfigList []*HomeConfig
|
||||
|
||||
// NormalizeKeywords 去掉空白项和重复项,始终返回非 nil 数组
|
||||
func NormalizeKeywords(items []string) []string {
|
||||
out := make([]string, 0, len(items))
|
||||
seen := make(map[string]struct{}, len(items))
|
||||
for _, item := range items {
|
||||
item = strings.TrimSpace(item)
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[item]; ok {
|
||||
continue
|
||||
}
|
||||
seen[item] = struct{}{}
|
||||
out = append(out, item)
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package hotsearchmod
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
"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.HotSearch)
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{{Key: FN.HotSearch.Keyword, Value: 1}},
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.HotSearch.Count, Value: -1},
|
||||
{Key: FN.HotSearch.UpdatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := db.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(hotsearchmod:Init) Create HotSearch Index failed! err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// NormalizeKeyword 去掉首尾空白、压缩中间空格,并限制长度。
|
||||
func NormalizeKeyword(raw string) string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return ""
|
||||
}
|
||||
fields := strings.FieldsFunc(raw, unicode.IsSpace)
|
||||
raw = strings.Join(fields, " ")
|
||||
if utf8.RuneCountInString(raw) > MaxKeywordRunes {
|
||||
raw = string([]rune(raw)[:MaxKeywordRunes])
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
// IncrByKeyword 按搜索词累加次数,不存在则插入。
|
||||
func IncrByKeyword(ctx context.Context, keyword string) *srvdef.SrvErr {
|
||||
keyword = NormalizeKeyword(keyword)
|
||||
if keyword == "" {
|
||||
return nil
|
||||
}
|
||||
now := time.Now()
|
||||
filter := bson.M{FN.HotSearch.Keyword: keyword}
|
||||
update := bson.M{
|
||||
"$inc": bson.M{FN.HotSearch.Count: 1},
|
||||
"$set": bson.M{FN.HotSearch.UpdatedAt: now},
|
||||
"$setOnInsert": bson.M{
|
||||
FN.HotSearch.Id: mongos.Lid.HotSearch.Get(),
|
||||
FN.HotSearch.Keyword: keyword,
|
||||
FN.HotSearch.CreatedAt: now,
|
||||
},
|
||||
}
|
||||
if _, err := db.UpsertOne(ctx, filter, update); err != nil {
|
||||
if _, retryErr := db.UpdateOne(ctx, filter, bson.M{
|
||||
"$inc": bson.M{FN.HotSearch.Count: 1},
|
||||
"$set": bson.M{FN.HotSearch.UpdatedAt: now},
|
||||
}); retryErr != nil {
|
||||
log.Warn("hotsearchmod:IncrByKeyword failed", log.E(err), log.E(retryErr), log.Any("keyword", keyword))
|
||||
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FindTopHotSearch(ctx context.Context, limit int64) (HotSearchList, *srvdef.SrvErr) {
|
||||
if limit <= 0 {
|
||||
limit = TopLimit
|
||||
}
|
||||
opts := options.Find().
|
||||
SetSort(bson.D{
|
||||
{Key: FN.HotSearch.Count, Value: -1},
|
||||
{Key: FN.HotSearch.UpdatedAt, Value: -1},
|
||||
{Key: FN.HotSearch.Id, Value: -1},
|
||||
}).
|
||||
SetLimit(limit).
|
||||
SetProjection(bson.D{
|
||||
{Key: FN.HotSearch.Id, Value: 1},
|
||||
{Key: FN.HotSearch.Keyword, Value: 1},
|
||||
{Key: FN.HotSearch.Count, Value: 1},
|
||||
})
|
||||
data := make(HotSearchList, 0)
|
||||
if err := db.Find(ctx, &data, bson.M{}, opts); err != nil {
|
||||
log.Warn("hotsearchmod:FindTopHotSearch db.Find failed", log.E(err))
|
||||
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package hotsearchmod
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNormalizeKeyword(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
raw string
|
||||
want string
|
||||
}{
|
||||
{name: "空串", raw: " ", want: ""},
|
||||
{name: "压缩空白", raw: " 霸道 总裁\t ", want: "霸道 总裁"},
|
||||
{name: "截断长度", raw: stringsRepeat("测", 60), want: stringsRepeat("测", MaxKeywordRunes)},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := NormalizeKeyword(tt.raw); got != tt.want {
|
||||
t.Fatalf("NormalizeKeyword() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func stringsRepeat(s string, n int) string {
|
||||
out := make([]rune, 0, n)
|
||||
r := []rune(s)[0]
|
||||
for i := 0; i < n; i++ {
|
||||
out = append(out, r)
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package hotsearchmod
|
||||
|
||||
type TagHotSearch struct {
|
||||
Id string
|
||||
Keyword string
|
||||
Count string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
HotSearch TagHotSearch
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
HotSearch string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.HotSearch.Id = "_id"
|
||||
FN.HotSearch.Keyword = "keyword"
|
||||
FN.HotSearch.Count = "count"
|
||||
FN.HotSearch.CreatedAt = "createdAt"
|
||||
FN.HotSearch.UpdatedAt = "updatedAt"
|
||||
TN.HotSearch = "hot_search"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package hotsearchmod
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
MaxKeywordRunes = 50
|
||||
TopLimit = 10
|
||||
)
|
||||
|
||||
// HotSearch 热搜词
|
||||
// @table:hot_search
|
||||
type HotSearch struct {
|
||||
Id int64 `json:"id" bson:"_id,omitempty"`
|
||||
Keyword string `json:"keyword" bson:"keyword"` // 搜索词
|
||||
Count int64 `json:"count" bson:"count"` // 搜索次数
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 首次记录时间
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 最近搜索时间
|
||||
}
|
||||
|
||||
type HotSearchList []*HotSearch
|
||||
@@ -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
|
||||
}
|
||||
Executable
+26
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,59 @@
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package ipdailystatmod
|
||||
|
||||
import "time"
|
||||
|
||||
// IpDailyStat 每日访客 IP 去重统计。
|
||||
// @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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/models/aicommentrecord"
|
||||
"videoweb/pub/models/announcementmod"
|
||||
"videoweb/pub/models/cfg"
|
||||
"videoweb/pub/models/cointransmod"
|
||||
"videoweb/pub/models/commentlikemod"
|
||||
"videoweb/pub/models/commentmod"
|
||||
"videoweb/pub/models/contactusmod"
|
||||
"videoweb/pub/models/detailnavmod"
|
||||
"videoweb/pub/models/esmod"
|
||||
"videoweb/pub/models/eventmod"
|
||||
"videoweb/pub/models/feedbackmod"
|
||||
"videoweb/pub/models/homebannermod"
|
||||
"videoweb/pub/models/homeconfigmod"
|
||||
"videoweb/pub/models/hotsearchmod"
|
||||
"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/playletchaptercollectmod"
|
||||
"videoweb/pub/models/playletchapterlikemod"
|
||||
"videoweb/pub/models/playletchaptermod"
|
||||
"videoweb/pub/models/playletchapterunlockmod"
|
||||
"videoweb/pub/models/playletcollectmod"
|
||||
"videoweb/pub/models/playletlikemod"
|
||||
"videoweb/pub/models/playletmod"
|
||||
"videoweb/pub/models/playlettagmod"
|
||||
"videoweb/pub/models/playletthememod"
|
||||
"videoweb/pub/models/playlettopicgroupmod"
|
||||
"videoweb/pub/models/playletwatchhistorymod"
|
||||
"videoweb/pub/models/playletwatchprogressmod"
|
||||
"videoweb/pub/models/rechargepackagemod"
|
||||
"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/uservisitlog"
|
||||
"videoweb/pub/models/videocategorymod"
|
||||
"videoweb/pub/models/videocollectmod"
|
||||
"videoweb/pub/models/videocreatermod"
|
||||
"videoweb/pub/models/videoinformationmod"
|
||||
"videoweb/pub/models/videolikemod"
|
||||
"videoweb/pub/models/videotagmod"
|
||||
"videoweb/pub/models/videotopicmod"
|
||||
"videoweb/pub/models/videowatchhistorymod"
|
||||
"videoweb/pub/models/vipordermod"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
log.Info("models init start..")
|
||||
ctx := context.Background()
|
||||
cfg.Init(ctx)
|
||||
mwacc.Init(ctx)
|
||||
oplog.Init(ctx)
|
||||
m3u8requestlogmod.Init(ctx)
|
||||
|
||||
syncfilemod.Init(ctx)
|
||||
seopushmod.Init(ctx)
|
||||
richtextcontentmod.Init(ctx)
|
||||
announcementmod.Init(ctx)
|
||||
hotsearchmod.Init(ctx)
|
||||
homebannermod.Init(ctx)
|
||||
homeconfigmod.Init(ctx)
|
||||
commentmod.Init(ctx)
|
||||
aicommentrecord.Init(ctx)
|
||||
commentlikemod.Init(ctx)
|
||||
ipblackmod.Init(ctx)
|
||||
ipdailystatmod.Init(ctx)
|
||||
esmod.Init(ctx)
|
||||
detailnavmod.Init(ctx)
|
||||
eventmod.Init(ctx)
|
||||
translationcategorymod.Init(ctx)
|
||||
translationmod.Init(ctx)
|
||||
playletthememod.Init(ctx)
|
||||
playlettopicgroupmod.Init(ctx)
|
||||
playlettagmod.Init(ctx)
|
||||
playletmod.Init(ctx)
|
||||
playletbackflowstatmod.Init(ctx)
|
||||
playletchaptermod.Init(ctx)
|
||||
playletchapterlikemod.Init(ctx)
|
||||
playletchaptercollectmod.Init(ctx)
|
||||
playletchapterunlockmod.Init(ctx)
|
||||
playletlikemod.Init(ctx)
|
||||
playletcollectmod.Init(ctx)
|
||||
playletwatchhistorymod.Init(ctx)
|
||||
playletwatchprogressmod.Init(ctx)
|
||||
feedbackmod.Init(ctx)
|
||||
videocategorymod.Init(ctx)
|
||||
videocreatermod.Init(ctx)
|
||||
videotagmod.Init(ctx)
|
||||
videoinformationmod.Init(ctx)
|
||||
videolikemod.Init(ctx)
|
||||
videocollectmod.Init(ctx)
|
||||
videowatchhistorymod.Init(ctx)
|
||||
videotopicmod.Init(ctx)
|
||||
rechargepackagemod.Init(ctx)
|
||||
cointransmod.Init(ctx)
|
||||
contactusmod.Init(ctx)
|
||||
vipordermod.Init(ctx)
|
||||
usermod.Init(ctx)
|
||||
userlogin.Init(ctx)
|
||||
uservisitlog.Init(ctx)
|
||||
log.Info("models init end")
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
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.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
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Executable
+88
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"` // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package mwacc
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type AccGetListRec struct {
|
||||
Id int64 `bson:"_id"` // id
|
||||
Username string `bson:"username"` // 用户名
|
||||
Acc string `bson:"acc"` // 用户名
|
||||
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"` // 角色名称
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package oplog
|
||||
|
||||
import (
|
||||
"videoweb/pub/mongos"
|
||||
)
|
||||
|
||||
var (
|
||||
opLogColl *mongos.Collection
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
Executable
+34
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,115 @@
|
||||
package playletchaptercollectmod
|
||||
|
||||
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_chapter_collect 集合和常用查询索引
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.PlayletChapterCollect)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterCollect.UserId, Value: 1},
|
||||
{Key: FN.PlayletChapterCollect.ChapterId, Value: 1},
|
||||
},
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterCollect.ChapterId, Value: 1},
|
||||
{Key: FN.PlayletChapterCollect.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterCollect.PlayletId, Value: 1},
|
||||
{Key: FN.PlayletChapterCollect.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterCollect.UserId, Value: 1},
|
||||
{Key: FN.PlayletChapterCollect.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(playletchaptercollectmod:initIndex) 创建索引失败 err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOnePlayletChapterCollect 插入一条短剧剧集收藏关系
|
||||
func InsertOnePlayletChapterCollect(ctx context.Context, doc *PlayletChapterCollect) (bool, *srvdef.SrvErr) {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.PlayletChapterCollect.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) {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("插入短剧剧集收藏关系失败", log.Any("doc", doc), log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// DeleteOnePlayletChapterCollect 删除一条短剧剧集收藏关系
|
||||
func DeleteOnePlayletChapterCollect(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
|
||||
count, err := coll.DeleteOne(ctx, filter)
|
||||
if err != nil {
|
||||
log.Warn("删除短剧剧集收藏关系失败", log.E(err), log.Any("filter", filter))
|
||||
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// DeleteManyPlayletChapterCollect 按条件批量删除短剧剧集收藏关系
|
||||
func DeleteManyPlayletChapterCollect(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
|
||||
}
|
||||
|
||||
// FindManyPlayletChapterCollect 按条件查询短剧剧集收藏关系
|
||||
func FindManyPlayletChapterCollect(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletChapterCollectList, *srvdef.SrvErr) {
|
||||
data := make(PlayletChapterCollectList, 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, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CountPlayletChapterCollect 统计满足条件的短剧剧集收藏关系数量
|
||||
func CountPlayletChapterCollect(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
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package playletchaptercollectmod
|
||||
|
||||
// TagPlayletChapterCollect 保存 playlet_chapter_collect 集合字段名
|
||||
type TagPlayletChapterCollect struct {
|
||||
Id string
|
||||
UserId string
|
||||
PlayletId string
|
||||
ChapterId string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
PlayletChapterCollect TagPlayletChapterCollect
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
PlayletChapterCollect string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.PlayletChapterCollect.Id = "_id"
|
||||
FN.PlayletChapterCollect.UserId = "userId"
|
||||
FN.PlayletChapterCollect.PlayletId = "playletId"
|
||||
FN.PlayletChapterCollect.ChapterId = "chapterId"
|
||||
FN.PlayletChapterCollect.CreatedAt = "createdAt"
|
||||
FN.PlayletChapterCollect.UpdatedAt = "updatedAt"
|
||||
|
||||
TN.PlayletChapterCollect = "playlet_chapter_collect"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package playletchaptercollectmod
|
||||
|
||||
import "time"
|
||||
|
||||
// PlayletChapterCollect @table: playlet_chapter_collect
|
||||
//
|
||||
// PlayletChapterCollect 短剧剧集收藏关系模型
|
||||
type PlayletChapterCollect struct {
|
||||
Id int64 `json:"id" bson:"_id,omitempty"` // 收藏记录ID
|
||||
UserId int64 `json:"userId" bson:"userId"` // 用户ID
|
||||
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
|
||||
ChapterId int64 `json:"chapterId" bson:"chapterId"` // 短剧剧集ID
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
|
||||
}
|
||||
|
||||
// PlayletChapterCollectList 短剧剧集收藏关系列表
|
||||
type PlayletChapterCollectList []*PlayletChapterCollect
|
||||
@@ -0,0 +1,105 @@
|
||||
package playletchapterlikemod
|
||||
|
||||
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_chapter_like 集合和常用查询索引
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.PlayletChapterLike)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterLike.UserId, Value: 1},
|
||||
{Key: FN.PlayletChapterLike.ChapterId, Value: 1},
|
||||
},
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterLike.ChapterId, Value: 1},
|
||||
{Key: FN.PlayletChapterLike.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterLike.PlayletId, Value: 1},
|
||||
{Key: FN.PlayletChapterLike.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterLike.UserId, Value: 1},
|
||||
{Key: FN.PlayletChapterLike.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(playletchapterlikemod:initIndex) 创建索引失败 err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOnePlayletChapterLike 插入一条短剧剧集点赞关系
|
||||
func InsertOnePlayletChapterLike(ctx context.Context, doc *PlayletChapterLike) (bool, *srvdef.SrvErr) {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.PlayletChapterLike.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) {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("插入短剧剧集点赞关系失败", log.Any("doc", doc), log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// DeleteOnePlayletChapterLike 删除一条短剧剧集点赞关系
|
||||
func DeleteOnePlayletChapterLike(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
|
||||
count, err := coll.DeleteOne(ctx, filter)
|
||||
if err != nil {
|
||||
log.Warn("删除短剧剧集点赞关系失败", log.E(err), log.Any("filter", filter))
|
||||
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// DeleteManyPlayletChapterLike 按条件批量删除短剧剧集点赞关系
|
||||
func DeleteManyPlayletChapterLike(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
|
||||
}
|
||||
|
||||
// FindManyPlayletChapterLike 按条件查询短剧剧集点赞关系
|
||||
func FindManyPlayletChapterLike(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletChapterLikeList, *srvdef.SrvErr) {
|
||||
data := make(PlayletChapterLikeList, 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, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package playletchapterlikemod
|
||||
|
||||
// TagPlayletChapterLike 保存 playlet_chapter_like 集合字段名
|
||||
type TagPlayletChapterLike struct {
|
||||
Id string
|
||||
UserId string
|
||||
PlayletId string
|
||||
ChapterId string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
PlayletChapterLike TagPlayletChapterLike
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
PlayletChapterLike string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.PlayletChapterLike.Id = "_id"
|
||||
FN.PlayletChapterLike.UserId = "userId"
|
||||
FN.PlayletChapterLike.PlayletId = "playletId"
|
||||
FN.PlayletChapterLike.ChapterId = "chapterId"
|
||||
FN.PlayletChapterLike.CreatedAt = "createdAt"
|
||||
FN.PlayletChapterLike.UpdatedAt = "updatedAt"
|
||||
|
||||
TN.PlayletChapterLike = "playlet_chapter_like"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package playletchapterlikemod
|
||||
|
||||
import "time"
|
||||
|
||||
// PlayletChapterLike @table: playlet_chapter_like
|
||||
//
|
||||
// PlayletChapterLike 短剧剧集点赞关系模型
|
||||
type PlayletChapterLike struct {
|
||||
Id int64 `json:"id" bson:"_id,omitempty"` // 点赞记录ID
|
||||
UserId int64 `json:"userId" bson:"userId"` // 用户ID
|
||||
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
|
||||
ChapterId int64 `json:"chapterId" bson:"chapterId"` // 短剧剧集ID
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
|
||||
}
|
||||
|
||||
// PlayletChapterLikeList 短剧剧集点赞关系列表
|
||||
type PlayletChapterLikeList []*PlayletChapterLike
|
||||
@@ -0,0 +1,335 @@
|
||||
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
|
||||
|
||||
const duplicatePlayletChapterMsg = "短剧剧集已存在"
|
||||
|
||||
// Init 初始化 playlet_chapter 集合和常用查询索引
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.PlayletChapter)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
commonIndexes := []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.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, commonIndexes); err != nil {
|
||||
panic(fmt.Sprintf("(playletchaptermod:initIndex) Create Index failed! err:%+v:", err))
|
||||
}
|
||||
|
||||
uniqueIndexes := []mongo.IndexModel{
|
||||
{
|
||||
// 反向键序避免和线上已有 playletId_1_currentEpisode_1 普通索引冲突,同时兜住同一短剧同一集数的并发重复写入。
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapter.CurrentEpisode, Value: 1},
|
||||
{Key: FN.PlayletChapter.PlayletId, Value: 1},
|
||||
},
|
||||
Options: options.Index().
|
||||
SetName("uniq_playlet_chapter_episode").
|
||||
SetUnique(true),
|
||||
},
|
||||
{
|
||||
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},
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, index := range uniqueIndexes {
|
||||
if _, err := coll.CreateIndex(ctx, []mongo.IndexModel{index}); err != nil {
|
||||
if isPlayletChapterDuplicateIndexErr(err) {
|
||||
log.Warn("短剧章节唯一索引创建失败,请先清理历史重复章节数据", log.E(err), log.Any("index", index.Keys))
|
||||
continue
|
||||
}
|
||||
panic(fmt.Sprintf("(playletchaptermod:initIndex) Create Unique Index failed! err:%+v:", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isPlayletChapterDuplicateIndexErr 判断唯一索引创建时是否命中历史重复数据。
|
||||
func isPlayletChapterDuplicateIndexErr(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return mongo.IsDuplicateKeyError(err) || strings.Contains(err.Error(), "E11000 duplicate key error")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if mongo.IsDuplicateKeyError(err) {
|
||||
return duplicatePlayletChapterErr()
|
||||
}
|
||||
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 {
|
||||
if mongo.IsDuplicateKeyError(err) {
|
||||
return duplicatePlayletChapterErr()
|
||||
}
|
||||
log.Warn("playletchaptermod:InsertManyPlayletChapter failed", log.Any("count", len(data)), log.E(err))
|
||||
return srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// duplicatePlayletChapterErr 返回章节唯一约束冲突的统一业务错误。
|
||||
func duplicatePlayletChapterErr() *srvdef.SrvErr {
|
||||
return srvdef.New(srvdef.ErrDbInputExist, duplicatePlayletChapterMsg, duplicatePlayletChapterMsg)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
type firstChapterRow struct {
|
||||
PlayletId int64 `bson:"_id"`
|
||||
ChapterId int64 `bson:"chapterId"`
|
||||
}
|
||||
|
||||
// FirstChapterIDs 按集数取每部短剧第一集的章节 ID,排序与详情页选集列表一致。
|
||||
func FirstChapterIDs(ctx context.Context, playletIDs []int64) (map[int64]int64, *srvdef.SrvErr) {
|
||||
out := make(map[int64]int64, len(playletIDs))
|
||||
if len(playletIDs) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
const batchSize = 500
|
||||
for start := 0; start < len(playletIDs); start += batchSize {
|
||||
end := start + batchSize
|
||||
if end > len(playletIDs) {
|
||||
end = len(playletIDs)
|
||||
}
|
||||
pipeline := []bson.M{
|
||||
{"$match": bson.M{
|
||||
FN.PlayletChapter.PlayletId: bson.M{"$in": playletIDs[start:end]},
|
||||
FN.PlayletChapter.Status: StatusUp,
|
||||
}},
|
||||
{"$sort": bson.D{
|
||||
{Key: FN.PlayletChapter.CurrentEpisode, Value: 1},
|
||||
{Key: FN.PlayletChapter.Id, Value: 1},
|
||||
}},
|
||||
{"$group": bson.M{
|
||||
"_id": "$" + FN.PlayletChapter.PlayletId,
|
||||
"chapterId": bson.M{"$first": "$_id"},
|
||||
}},
|
||||
}
|
||||
rows := make([]firstChapterRow, 0)
|
||||
if err := coll.Aggregate(ctx, &rows, pipeline); err != nil {
|
||||
log.Warn("playletchaptermod:FirstChapterIDs failed", log.E(err), log.Any("count", end-start))
|
||||
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
for _, row := range rows {
|
||||
if row.PlayletId > 0 && row.ChapterId > 0 {
|
||||
out[row.PlayletId] = row.ChapterId
|
||||
}
|
||||
}
|
||||
}
|
||||
return out, 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 {
|
||||
if mongo.IsDuplicateKeyError(err) {
|
||||
return duplicatePlayletChapterErr()
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
if mongo.IsDuplicateKeyError(err) {
|
||||
return duplicatePlayletChapterErr()
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
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
|
||||
Status string
|
||||
PayType string
|
||||
SingleCoins string
|
||||
WatermarkStatus string
|
||||
WatermarkRetryAt 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.Status = "status"
|
||||
FN.PlayletChapter.PayType = "payType"
|
||||
FN.PlayletChapter.SingleCoins = "singleCoins"
|
||||
FN.PlayletChapter.WatermarkStatus = "watermarkStatus"
|
||||
FN.PlayletChapter.WatermarkRetryAt = "watermarkRetryAt"
|
||||
FN.PlayletChapter.MediaSourceId = "mediaSourceId"
|
||||
FN.PlayletChapter.MediaTaskId = "mediaTaskId"
|
||||
FN.PlayletChapter.CreatedAt = "createdAt"
|
||||
FN.PlayletChapter.UpdatedAt = "updatedAt"
|
||||
|
||||
TN.PlayletChapter = "playlet_chapter"
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package playletchaptermod
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/models/playletmod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
// Status 剧集上架状态
|
||||
type Status int32
|
||||
|
||||
const (
|
||||
StatusDown Status = 0 // 下架
|
||||
StatusUp Status = 1 // 上架
|
||||
)
|
||||
|
||||
// DefaultStatusByMediaSource 根据媒资来源生成默认上架状态
|
||||
func DefaultStatusByMediaSource(mediaSource string) Status {
|
||||
if mediaSource == playletmod.MediaSourceHG {
|
||||
return StatusDown
|
||||
}
|
||||
return StatusUp
|
||||
}
|
||||
|
||||
// VisibleStatusFilter 前台可见剧集过滤条件
|
||||
func VisibleStatusFilter() bson.M {
|
||||
return bson.M{FN.PlayletChapter.Status: StatusUp}
|
||||
}
|
||||
|
||||
// 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"` // 不喜欢数
|
||||
Status Status `json:"status" bson:"status"` // 上架状态 0-下架 1-上架
|
||||
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-处理失败
|
||||
WatermarkRetryAt time.Time `json:"watermarkRetryAt,omitempty" bson:"watermarkRetryAt,omitempty"` // 原片未处理完时的下次提交时间,到点前不参与 task/add
|
||||
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
|
||||
@@ -0,0 +1,34 @@
|
||||
package playletchapterunlockmod
|
||||
|
||||
// TagPlayletChapterUnlock 保存 playlet_chapter_unlock 集合字段名。
|
||||
type TagPlayletChapterUnlock struct {
|
||||
Id string
|
||||
UserId string
|
||||
PlayletId string
|
||||
ChapterId string
|
||||
Coins string
|
||||
OrderNo string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
PlayletChapterUnlock TagPlayletChapterUnlock
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
PlayletChapterUnlock string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.PlayletChapterUnlock.Id = "_id"
|
||||
FN.PlayletChapterUnlock.UserId = "userId"
|
||||
FN.PlayletChapterUnlock.PlayletId = "playletId"
|
||||
FN.PlayletChapterUnlock.ChapterId = "chapterId"
|
||||
FN.PlayletChapterUnlock.Coins = "coins"
|
||||
FN.PlayletChapterUnlock.OrderNo = "orderNo"
|
||||
FN.PlayletChapterUnlock.CreatedAt = "createdAt"
|
||||
FN.PlayletChapterUnlock.UpdatedAt = "updatedAt"
|
||||
|
||||
TN.PlayletChapterUnlock = "playlet_chapter_unlock"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package playletchapterunlockmod
|
||||
|
||||
import "time"
|
||||
|
||||
// PlayletChapterUnlock @table: playlet_chapter_unlock
|
||||
//
|
||||
// PlayletChapterUnlock 记录用户已用金币解锁的短剧剧集;一条记录代表该用户永久可观看该剧集。
|
||||
type PlayletChapterUnlock struct {
|
||||
Id int64 `json:"id" bson:"_id,omitempty"` // 解锁记录ID
|
||||
UserId int64 `json:"userId" bson:"userId"` // 用户ID
|
||||
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
|
||||
ChapterId int64 `json:"chapterId" bson:"chapterId"` // 短剧剧集ID
|
||||
Coins int64 `json:"coins" bson:"coins"` // 解锁消耗金币
|
||||
OrderNo string `json:"orderNo" bson:"orderNo"` // 解锁流水号
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
|
||||
}
|
||||
|
||||
type PlayletChapterUnlockList []*PlayletChapterUnlock
|
||||
@@ -0,0 +1,132 @@
|
||||
package playletchapterunlockmod
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"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/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
var coll *mongos.Collection
|
||||
|
||||
// Init 初始化 playlet_chapter_unlock 集合和索引。
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.PlayletChapterUnlock)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterUnlock.UserId, Value: 1},
|
||||
{Key: FN.PlayletChapterUnlock.ChapterId, Value: 1},
|
||||
},
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterUnlock.UserId, Value: 1},
|
||||
{Key: FN.PlayletChapterUnlock.PlayletId, Value: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletChapterUnlock.CreatedAt, Value: 1},
|
||||
{Key: FN.PlayletChapterUnlock.PlayletId, Value: 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(playletchapterunlockmod:initIndex) 创建索引失败 err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOnePlayletChapterUnlock 插入解锁记录。
|
||||
//
|
||||
// 返回 inserted=false 表示该用户已经解锁过该剧集;调用方应将其视为幂等成功,不可继续扣费。
|
||||
func InsertOnePlayletChapterUnlock(ctx context.Context, doc *PlayletChapterUnlock) (bool, *srvdef.SrvErr) {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.PlayletChapterUnlock.Get()
|
||||
}
|
||||
now := utils.Now()
|
||||
if doc.CreatedAt.IsZero() {
|
||||
doc.CreatedAt = now
|
||||
}
|
||||
doc.UpdatedAt = now
|
||||
if _, err := coll.InsertOne(ctx, doc); err != nil {
|
||||
if mongo.IsDuplicateKeyError(err) {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("插入短剧剧集解锁记录失败", log.Any("doc", doc), log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ExistsPlayletChapterUnlock 判断用户是否已解锁指定剧集。
|
||||
func ExistsPlayletChapterUnlock(ctx context.Context, userId int64, chapterId int64) (bool, *srvdef.SrvErr) {
|
||||
if userId <= 0 || chapterId <= 0 {
|
||||
return false, nil
|
||||
}
|
||||
var doc PlayletChapterUnlock
|
||||
err := coll.FindOneEx(ctx, &doc, bson.M{
|
||||
FN.PlayletChapterUnlock.UserId: userId,
|
||||
FN.PlayletChapterUnlock.ChapterId: chapterId,
|
||||
}, options.FindOne().SetProjection(bson.D{
|
||||
{Key: FN.PlayletChapterUnlock.Id, Value: 1},
|
||||
}))
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("查询短剧剧集解锁记录失败", log.E(err), log.Any("userId", userId), log.Any("chapterId", chapterId))
|
||||
return false, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return doc.Id > 0, nil
|
||||
}
|
||||
|
||||
// DeleteManyPlayletChapterUnlock 按条件批量删除剧集解锁记录。
|
||||
func DeleteManyPlayletChapterUnlock(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
|
||||
}
|
||||
|
||||
// FindManyPlayletChapterUnlock 按条件查询多条剧集解锁记录。
|
||||
func FindManyPlayletChapterUnlock(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletChapterUnlockList, *srvdef.SrvErr) {
|
||||
data := make(PlayletChapterUnlockList, 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, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CountPlayletChapterUnlock 统计满足条件的剧集解锁记录数量
|
||||
func CountPlayletChapterUnlock(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
|
||||
}
|
||||
|
||||
// AggregatePlayletChapterUnlock 聚合查询剧集解锁记录
|
||||
func AggregatePlayletChapterUnlock(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
|
||||
if err := coll.Aggregate(ctx, bind, pipeline); err != nil {
|
||||
log.Warn("聚合短剧剧集解锁记录失败", log.E(err), log.Any("pipeline", pipeline))
|
||||
return srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package playletcollectmod
|
||||
|
||||
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_collect 集合和常用查询索引
|
||||
func Init(ctx context.Context) {
|
||||
coll = mongos.Shop.Coll(TN.PlayletCollect)
|
||||
initIndex(ctx)
|
||||
}
|
||||
|
||||
func initIndex(ctx context.Context) {
|
||||
indexes := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletCollect.UserId, Value: 1},
|
||||
{Key: FN.PlayletCollect.PlayletId, Value: 1},
|
||||
},
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletCollect.PlayletId, Value: 1},
|
||||
{Key: FN.PlayletCollect.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletCollect.UserId, Value: 1},
|
||||
{Key: FN.PlayletCollect.CreatedAt, Value: -1},
|
||||
{Key: FN.PlayletCollect.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletCollect.CreatedAt, Value: 1},
|
||||
{Key: FN.PlayletCollect.PlayletId, Value: 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(playletcollectmod:initIndex) 创建索引失败 err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOnePlayletCollect 插入一条短剧收藏关系
|
||||
func InsertOnePlayletCollect(ctx context.Context, doc *PlayletCollect) (bool, *srvdef.SrvErr) {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.PlayletCollect.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) {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("插入短剧收藏关系失败", log.Any("doc", doc), log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ExistsPlayletCollect 查询短剧收藏关系是否存在
|
||||
func ExistsPlayletCollect(ctx context.Context, filter bson.M) (bool, *srvdef.SrvErr) {
|
||||
var doc PlayletCollect
|
||||
if err := coll.FindOneEx(ctx, &doc, filter, options.FindOne().SetProjection(bson.D{
|
||||
{Key: FN.PlayletCollect.Id, Value: 1},
|
||||
})); err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("查询短剧收藏关系失败", log.E(err), log.Any("filter", filter))
|
||||
return false, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// DeleteOnePlayletCollect 删除一条短剧收藏关系
|
||||
func DeleteOnePlayletCollect(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
|
||||
count, err := coll.DeleteOne(ctx, filter)
|
||||
if err != nil {
|
||||
log.Warn("删除短剧收藏关系失败", log.E(err), log.Any("filter", filter))
|
||||
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// FindManyPlayletCollect 按条件查询短剧收藏关系列表
|
||||
func FindManyPlayletCollect(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletCollectList, *srvdef.SrvErr) {
|
||||
data := make(PlayletCollectList, 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, "", "")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CountPlayletCollect 统计满足条件的短剧收藏关系数量
|
||||
func CountPlayletCollect(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
|
||||
}
|
||||
|
||||
// AggregatePlayletCollect 聚合查询短剧收藏关系
|
||||
func AggregatePlayletCollect(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
|
||||
if err := coll.Aggregate(ctx, bind, pipeline); err != nil {
|
||||
log.Warn("聚合短剧收藏关系失败", log.E(err), log.Any("pipeline", pipeline))
|
||||
return srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package playletcollectmod
|
||||
|
||||
// TagPlayletCollect 保存 playlet_collect 集合字段名
|
||||
type TagPlayletCollect struct {
|
||||
Id string
|
||||
UserId string
|
||||
PlayletId string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
}
|
||||
|
||||
var FN struct {
|
||||
PlayletCollect TagPlayletCollect
|
||||
}
|
||||
|
||||
var TN struct {
|
||||
PlayletCollect string
|
||||
}
|
||||
|
||||
func init() {
|
||||
FN.PlayletCollect.Id = "_id"
|
||||
FN.PlayletCollect.UserId = "userId"
|
||||
FN.PlayletCollect.PlayletId = "playletId"
|
||||
FN.PlayletCollect.CreatedAt = "createdAt"
|
||||
FN.PlayletCollect.UpdatedAt = "updatedAt"
|
||||
|
||||
TN.PlayletCollect = "playlet_collect"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package playletcollectmod
|
||||
|
||||
import "time"
|
||||
|
||||
// PlayletCollect @table: playlet_collect
|
||||
//
|
||||
// PlayletCollect 短剧收藏关系模型
|
||||
type PlayletCollect struct {
|
||||
Id int64 `json:"id" bson:"_id,omitempty"` // 收藏记录ID
|
||||
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"` // 修改时间
|
||||
}
|
||||
|
||||
// PlayletCollectList 短剧收藏关系列表
|
||||
type PlayletCollectList []*PlayletCollect
|
||||
@@ -0,0 +1,110 @@
|
||||
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},
|
||||
{Key: FN.PlayletLike.CreatedAt, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletLike.UserId, Value: 1},
|
||||
{Key: FN.PlayletLike.CreatedAt, Value: -1},
|
||||
{Key: FN.PlayletLike.Id, Value: -1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{
|
||||
{Key: FN.PlayletLike.CreatedAt, Value: 1},
|
||||
{Key: FN.PlayletLike.PlayletId, Value: 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
|
||||
panic(fmt.Sprintf("(playletlikemod:initIndex) 创建索引失败 err:%+v:", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOnePlayletLike 插入一条短剧点赞关系
|
||||
func InsertOnePlayletLike(ctx context.Context, doc *PlayletLike) (bool, *srvdef.SrvErr) {
|
||||
if doc.Id == 0 {
|
||||
doc.Id = mongos.Lid.PlayletLike.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) {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("插入短剧点赞关系失败", log.Any("doc", doc), log.E(err))
|
||||
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ExistsPlayletLike 查询短剧点赞关系是否存在
|
||||
func ExistsPlayletLike(ctx context.Context, filter bson.M) (bool, *srvdef.SrvErr) {
|
||||
var doc PlayletLike
|
||||
if err := coll.FindOneEx(ctx, &doc, filter, options.FindOne().SetProjection(bson.D{
|
||||
{Key: FN.PlayletLike.Id, Value: 1},
|
||||
})); err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return false, nil
|
||||
}
|
||||
log.Warn("查询短剧点赞关系失败", log.E(err), log.Any("filter", filter))
|
||||
return false, srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// DeleteOnePlayletLike 删除一条短剧点赞关系
|
||||
func DeleteOnePlayletLike(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
|
||||
count, err := coll.DeleteOne(ctx, filter)
|
||||
if err != nil {
|
||||
log.Warn("删除短剧点赞关系失败", log.E(err), log.Any("filter", filter))
|
||||
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
|
||||
}
|
||||
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("聚合短剧点赞关系失败", log.E(err), log.Any("pipeline", pipeline))
|
||||
return srvdef.New(srvdef.ErrDbQueryError, "", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package playletlikemod
|
||||
|
||||
import "time"
|
||||
|
||||
// PlayletLike @table: playlet_like
|
||||
//
|
||||
// PlayletLike 短剧点赞关系模型
|
||||
type PlayletLike struct {
|
||||
Id int64 `json:"id" bson:"_id,omitempty"` // 点赞记录ID
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user