init: web_hgdjc_server
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
package srv_homeconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"videoweb/pub/common/playletcache"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/homeconfigmod"
|
||||
"videoweb/pub/pubdef"
|
||||
"videoweb/pub/seo/sitemapdirty"
|
||||
"videoweb/web/api/proto"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultHomeConfigPageSize int64 = 10
|
||||
maxHomeConfigPageSize int64 = 100
|
||||
)
|
||||
|
||||
var homeConfigWebProjection = bson.D{
|
||||
{Key: homeconfigmod.FN.HomeConfig.Id, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Name, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Slug, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Desc, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Keyword, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Label, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Style, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.CardBackgroundImage, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.TopicIds, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.CategoryId, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.RecommendType, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Type, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Rank, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Limit, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.SortType, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Status, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.SeoInfo.Title, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.SeoInfo.Description, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.SeoInfo.Keyworld, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.CreatedAt, Value: 1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.UpdatedAt, Value: 1},
|
||||
}
|
||||
|
||||
// ListHomeConfig 分页查询首页配置列表
|
||||
func ListHomeConfig(ctx context.Context, req *proto.HomeConfigListReq) (*proto.HomeConfigListPageResp, *srvdef.SrvErr) {
|
||||
if req == nil {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "", "")
|
||||
}
|
||||
filter := bson.M{
|
||||
homeconfigmod.FN.HomeConfig.Type: bson.M{"$in": []int32{homeconfigmod.TypePlaylet, homeconfigmod.TypeTheme}},
|
||||
}
|
||||
if req.Id != nil && *req.Id > 0 {
|
||||
filter[homeconfigmod.FN.HomeConfig.Id] = *req.Id
|
||||
}
|
||||
if req.Type != nil {
|
||||
if !validHomeConfigType(*req.Type) {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "类型无效", "")
|
||||
}
|
||||
filter[homeconfigmod.FN.HomeConfig.Type] = *req.Type
|
||||
}
|
||||
if req.SortType != nil {
|
||||
if !validHomeConfigSortType(*req.SortType) {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "排序字段无效", "")
|
||||
}
|
||||
filter[homeconfigmod.FN.HomeConfig.SortType] = *req.SortType
|
||||
}
|
||||
if req.Status != nil {
|
||||
filter[homeconfigmod.FN.HomeConfig.Status] = *req.Status
|
||||
}
|
||||
if name := strings.TrimSpace(req.Name); name != "" {
|
||||
filter[homeconfigmod.FN.HomeConfig.Name] = bson.M{"$regex": regexp.QuoteMeta(name)}
|
||||
}
|
||||
if slug := strings.TrimSpace(req.Slug); slug != "" {
|
||||
filter[homeconfigmod.FN.HomeConfig.Slug] = slug
|
||||
}
|
||||
pageNum, pageSize := normalizeHomeConfigPage(req.PageNum, req.PageSize)
|
||||
totalCount, err := homeconfigmod.CountHomeConfig(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := &proto.HomeConfigListPageResp{
|
||||
BasePageResp: response.BasePageResp{
|
||||
TotalCount: totalCount,
|
||||
PageSize: int(pageSize),
|
||||
PageNum: int(pageNum),
|
||||
List: make([]*proto.HomeConfigListResp, 0),
|
||||
},
|
||||
}
|
||||
if totalCount == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
list, err := homeconfigmod.FindManyHomeConfig(ctx, filter, options.Find().
|
||||
SetProjection(homeConfigWebProjection).
|
||||
SetSort(bson.D{
|
||||
{Key: homeconfigmod.FN.HomeConfig.Rank, Value: -1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.UpdatedAt, Value: -1},
|
||||
{Key: homeconfigmod.FN.HomeConfig.Id, Value: -1},
|
||||
}).
|
||||
SetSkip((pageNum-1)*pageSize).
|
||||
SetLimit(pageSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]*proto.HomeConfigListResp, 0, len(list))
|
||||
for _, item := range list {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
items = append(items, &proto.HomeConfigListResp{
|
||||
Id: item.Id,
|
||||
Name: item.Name,
|
||||
Slug: item.Slug,
|
||||
Desc: item.Desc,
|
||||
Keyword: homeconfigmod.NormalizeKeywords(item.Keyword),
|
||||
Label: item.Label,
|
||||
Style: item.Style,
|
||||
CardBackgroundImage: item.CardBackgroundImage,
|
||||
TopicIds: item.TopicIds,
|
||||
CategoryId: item.CategoryId,
|
||||
RecommendType: item.RecommendType,
|
||||
Type: item.Type,
|
||||
Rank: item.Rank,
|
||||
Limit: item.Limit,
|
||||
SortType: item.SortType,
|
||||
Status: item.Status,
|
||||
SeoInfo: normalizeHomeConfigSeoValue(item.SeoInfo),
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
})
|
||||
}
|
||||
resp.List = items
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// AddHomeConfig 新增首页配置
|
||||
func AddHomeConfig(ctx context.Context, req *proto.HomeConfigAddReq) (*proto.HomeConfigAddResp, *srvdef.SrvErr) {
|
||||
if req == nil {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "", "")
|
||||
}
|
||||
name := strings.TrimSpace(req.Name)
|
||||
if name == "" {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "名称不能为空", "")
|
||||
}
|
||||
if !validHomeConfigType(req.Type) {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "类型无效", "")
|
||||
}
|
||||
if !validHomeConfigSortType(req.SortType) {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "排序字段无效", "")
|
||||
}
|
||||
if req.Limit < 0 {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "展示数量不能小于0", "")
|
||||
}
|
||||
if req.Status == nil {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "状态不能为空", "")
|
||||
}
|
||||
doc := &homeconfigmod.HomeConfig{
|
||||
Name: name,
|
||||
Slug: strings.TrimSpace(req.Slug),
|
||||
Desc: strings.TrimSpace(req.Desc),
|
||||
Keyword: homeconfigmod.NormalizeKeywords(req.Keyword),
|
||||
Label: strings.TrimSpace(req.Label),
|
||||
Style: strings.ToUpper(strings.TrimSpace(req.Style)),
|
||||
CardBackgroundImage: strings.TrimSpace(req.CardBackgroundImage),
|
||||
TopicIds: req.TopicIds,
|
||||
CategoryId: req.CategoryId,
|
||||
RecommendType: req.RecommendType,
|
||||
Type: req.Type,
|
||||
Rank: req.Rank,
|
||||
Limit: req.Limit,
|
||||
SortType: req.SortType,
|
||||
Status: *req.Status,
|
||||
SeoInfo: normalizeHomeConfigSeoValue(req.SeoInfo),
|
||||
}
|
||||
if err := ensureHomeConfigSlug(ctx, doc, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateHomeConfigTopics(ctx, doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := homeconfigmod.InsertOneHomeConfig(ctx, doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clearHomeConfigCache()
|
||||
sitemapdirty.Mark(ctx)
|
||||
return &proto.HomeConfigAddResp{Id: doc.Id}, nil
|
||||
}
|
||||
|
||||
// UpdateHomeConfig 更新首页配置
|
||||
func UpdateHomeConfig(ctx context.Context, req *proto.HomeConfigUpdateReq) *srvdef.SrvErr {
|
||||
if req == nil || req.Id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "首页配置 ID无效", "")
|
||||
}
|
||||
info, err := homeconfigmod.FindOneHomeConfig(ctx, bson.M{homeconfigmod.FN.HomeConfig.Id: req.Id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setDoc := bson.M{homeconfigmod.FN.HomeConfig.UpdatedAt: time.Now()}
|
||||
if req.Name != nil {
|
||||
name := strings.TrimSpace(*req.Name)
|
||||
if name == "" {
|
||||
return srvdef.New(srvdef.ErrParamError, "名称不能为空", "")
|
||||
}
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Name] = name
|
||||
}
|
||||
if req.Desc != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Desc] = strings.TrimSpace(*req.Desc)
|
||||
}
|
||||
if req.Keyword != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Keyword] = homeconfigmod.NormalizeKeywords(*req.Keyword)
|
||||
}
|
||||
if req.Label != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Label] = strings.TrimSpace(*req.Label)
|
||||
}
|
||||
if req.Style != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Style] = strings.ToUpper(strings.TrimSpace(*req.Style))
|
||||
}
|
||||
if req.CardBackgroundImage != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.CardBackgroundImage] = strings.TrimSpace(*req.CardBackgroundImage)
|
||||
}
|
||||
if req.TopicIds != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.TopicIds] = *req.TopicIds
|
||||
}
|
||||
if req.CategoryId != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.CategoryId] = *req.CategoryId
|
||||
}
|
||||
if req.RecommendType != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.RecommendType] = *req.RecommendType
|
||||
}
|
||||
if req.Type != nil {
|
||||
if !validHomeConfigType(*req.Type) {
|
||||
return srvdef.New(srvdef.ErrParamError, "类型无效", "")
|
||||
}
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Type] = *req.Type
|
||||
}
|
||||
if req.Rank != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Rank] = *req.Rank
|
||||
}
|
||||
if req.Limit != nil {
|
||||
if *req.Limit < 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "展示数量不能小于0", "")
|
||||
}
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Limit] = *req.Limit
|
||||
}
|
||||
if req.SortType != nil {
|
||||
if !validHomeConfigSortType(*req.SortType) {
|
||||
return srvdef.New(srvdef.ErrParamError, "排序字段无效", "")
|
||||
}
|
||||
setDoc[homeconfigmod.FN.HomeConfig.SortType] = *req.SortType
|
||||
}
|
||||
if req.Status != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Status] = *req.Status
|
||||
}
|
||||
if req.SeoInfo != nil {
|
||||
setDoc["seoInfo"] = normalizeHomeConfigSeoValue(*req.SeoInfo)
|
||||
}
|
||||
if serr := prepareHomeConfigSlugOnUpdate(ctx, req.Id, info, req, setDoc); serr != nil {
|
||||
return serr
|
||||
}
|
||||
merged := *info
|
||||
if v, ok := setDoc[homeconfigmod.FN.HomeConfig.Type]; ok {
|
||||
merged.Type = v.(int32)
|
||||
}
|
||||
if v, ok := setDoc[homeconfigmod.FN.HomeConfig.Status]; ok {
|
||||
merged.Status = v.(bool)
|
||||
}
|
||||
if v, ok := setDoc[homeconfigmod.FN.HomeConfig.TopicIds]; ok {
|
||||
merged.TopicIds = v.([]int64)
|
||||
}
|
||||
if v, ok := setDoc[homeconfigmod.FN.HomeConfig.Style]; ok {
|
||||
merged.Style = v.(string)
|
||||
}
|
||||
if v, ok := setDoc[homeconfigmod.FN.HomeConfig.CategoryId]; ok {
|
||||
merged.CategoryId = v.(int64)
|
||||
}
|
||||
if v, ok := setDoc[homeconfigmod.FN.HomeConfig.RecommendType]; ok {
|
||||
merged.RecommendType = v.(int64)
|
||||
}
|
||||
if err := validateHomeConfigTopics(ctx, &merged); err != nil {
|
||||
return err
|
||||
}
|
||||
if req.TopicIds != nil {
|
||||
setDoc[homeconfigmod.FN.HomeConfig.TopicIds] = merged.TopicIds
|
||||
}
|
||||
if len(setDoc) <= 1 {
|
||||
return srvdef.New(srvdef.ErrParamError, "没有可更新字段", "")
|
||||
}
|
||||
if err := homeconfigmod.UpdateOneHomeConfig(ctx,
|
||||
bson.M{homeconfigmod.FN.HomeConfig.Id: req.Id},
|
||||
bson.M{"$set": setDoc},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
clearHomeConfigCache()
|
||||
sitemapdirty.Mark(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelHomeConfig 删除首页配置
|
||||
func DelHomeConfig(ctx context.Context, req *proto.HomeConfigDelReq) *srvdef.SrvErr {
|
||||
if req == nil || req.Id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "首页配置 ID无效", "")
|
||||
}
|
||||
count, err := homeconfigmod.DelOneHomeConfig(ctx, bson.M{homeconfigmod.FN.HomeConfig.Id: req.Id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return srvdef.New(srvdef.ErrNoData, "", "")
|
||||
}
|
||||
clearHomeConfigCache()
|
||||
sitemapdirty.Mark(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func validHomeConfigType(typ int32) bool {
|
||||
return typ == homeconfigmod.TypePlaylet || typ == homeconfigmod.TypeTheme
|
||||
}
|
||||
|
||||
func validHomeConfigSortType(sortType int32) bool {
|
||||
return sortType == homeconfigmod.SortTypeRecommend ||
|
||||
sortType == homeconfigmod.SortTypeHot ||
|
||||
sortType == homeconfigmod.SortTypeLatest ||
|
||||
sortType == homeconfigmod.SortTypeOnlineAt ||
|
||||
sortType == homeconfigmod.SortTypeCategory
|
||||
}
|
||||
|
||||
func clearHomeConfigCache() {
|
||||
playletcache.ClearHomeCache()
|
||||
}
|
||||
|
||||
// normalizeHomeConfigPage 规范分页参数,限制单页数量避免大分页拖慢查询
|
||||
func normalizeHomeConfigPage(pageNum, pageSize int64) (int64, int64) {
|
||||
if pageNum <= 0 {
|
||||
pageNum = 1
|
||||
}
|
||||
if pageSize <= 0 {
|
||||
pageSize = defaultHomeConfigPageSize
|
||||
}
|
||||
if pageSize > maxHomeConfigPageSize {
|
||||
pageSize = maxHomeConfigPageSize
|
||||
}
|
||||
return pageNum, pageSize
|
||||
}
|
||||
|
||||
// normalizeHomeConfigSeoValue 规范化 SEO 字段,避免 keywords 为 null
|
||||
func normalizeHomeConfigSeoValue(seo pubdef.SeoValue) pubdef.SeoValue {
|
||||
seo.Title = strings.TrimSpace(seo.Title)
|
||||
seo.Description = strings.TrimSpace(seo.Description)
|
||||
if seo.Keyworld == nil {
|
||||
seo.Keyworld = make([]string, 0)
|
||||
return seo
|
||||
}
|
||||
words := make([]string, 0, len(seo.Keyworld))
|
||||
for _, word := range seo.Keyworld {
|
||||
word = strings.TrimSpace(word)
|
||||
if word == "" {
|
||||
continue
|
||||
}
|
||||
words = append(words, word)
|
||||
}
|
||||
seo.Keyworld = words
|
||||
return seo
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package srv_homeconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/common/utils"
|
||||
"videoweb/pub/models/homeconfigmod"
|
||||
"videoweb/web/api/proto"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func ensureHomeConfigSlug(ctx context.Context, ac *homeconfigmod.HomeConfig, excludeId int64) *srvdef.SrvErr {
|
||||
ac.Slug = utils.SanitizeSlug(ac.Slug)
|
||||
if ac.Slug != "" {
|
||||
if utils.IsSlugAllDigits(ac.Slug) {
|
||||
return srvdef.New(srvdef.ErrParamError, "Slug不能全是数字", "Slug不能全是数字")
|
||||
}
|
||||
filter := bson.M{homeconfigmod.FN.HomeConfig.Slug: ac.Slug}
|
||||
if excludeId > 0 {
|
||||
filter[homeconfigmod.FN.HomeConfig.Id] = bson.M{"$ne": excludeId}
|
||||
}
|
||||
exist, _ := homeconfigmod.FindOneHomeConfig(ctx, filter)
|
||||
if exist != nil {
|
||||
return srvdef.New(srvdef.ErrDbInputExist, "Slug已存在", "Slug已存在")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
source := utils.SlugSourceFromKeywordsOrTitle(ac.SeoInfo.Keyworld, ac.Name)
|
||||
ac.Slug = utils.MakeUniqueSlug(source, func(slug string) bool {
|
||||
filter := bson.M{homeconfigmod.FN.HomeConfig.Slug: slug}
|
||||
if excludeId > 0 {
|
||||
filter[homeconfigmod.FN.HomeConfig.Id] = bson.M{"$ne": excludeId}
|
||||
}
|
||||
exist, _ := homeconfigmod.FindOneHomeConfig(ctx, filter)
|
||||
return exist != nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func prepareHomeConfigSlugOnUpdate(ctx context.Context, id int64, info *homeconfigmod.HomeConfig, req *proto.HomeConfigUpdateReq, setDoc bson.M) *srvdef.SrvErr {
|
||||
slug := info.Slug
|
||||
if req.Slug != nil {
|
||||
slug = utils.SanitizeSlug(*req.Slug)
|
||||
}
|
||||
if slug != "" {
|
||||
if req.Slug != nil {
|
||||
if utils.IsSlugAllDigits(slug) {
|
||||
return srvdef.New(srvdef.ErrParamError, "Slug不能全是数字", "Slug不能全是数字")
|
||||
}
|
||||
exist, _ := homeconfigmod.FindOneHomeConfig(ctx, bson.M{
|
||||
homeconfigmod.FN.HomeConfig.Slug: slug,
|
||||
homeconfigmod.FN.HomeConfig.Id: bson.M{"$ne": id},
|
||||
})
|
||||
if exist != nil {
|
||||
return srvdef.New(srvdef.ErrDbInputExist, "Slug已存在", "Slug已存在")
|
||||
}
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Slug] = slug
|
||||
}
|
||||
return nil
|
||||
}
|
||||
name := info.Name
|
||||
if req.Name != nil {
|
||||
name = strings.TrimSpace(*req.Name)
|
||||
}
|
||||
keywords := info.SeoInfo.Keyworld
|
||||
if req.SeoInfo != nil {
|
||||
keywords = normalizeHomeConfigSeoValue(*req.SeoInfo).Keyworld
|
||||
}
|
||||
source := utils.SlugSourceFromKeywordsOrTitle(keywords, name)
|
||||
setDoc[homeconfigmod.FN.HomeConfig.Slug] = utils.MakeUniqueSlug(source, func(s string) bool {
|
||||
exist, _ := homeconfigmod.FindOneHomeConfig(ctx, bson.M{
|
||||
homeconfigmod.FN.HomeConfig.Slug: s,
|
||||
homeconfigmod.FN.HomeConfig.Id: bson.M{"$ne": id},
|
||||
})
|
||||
return exist != nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func emptyHomeConfigSlugFilter() bson.M {
|
||||
return bson.M{
|
||||
"$or": []bson.M{
|
||||
{homeconfigmod.FN.HomeConfig.Slug: ""},
|
||||
{homeconfigmod.FN.HomeConfig.Slug: bson.M{"$exists": false}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SyncEmptySlugs 为首页配置中空 slug 自动生成。
|
||||
func SyncEmptySlugs(ctx context.Context, maxSize int64) (int64, bool, *srvdef.SrvErr) {
|
||||
if maxSize <= 0 {
|
||||
return 0, false, nil
|
||||
}
|
||||
list, err := homeconfigmod.FindManyHomeConfig(ctx, emptyHomeConfigSlugFilter(), options.Find().
|
||||
SetSort(bson.D{{Key: homeconfigmod.FN.HomeConfig.Id, Value: 1}}).
|
||||
SetLimit(maxSize+1))
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
hasMore := int64(len(list)) > maxSize
|
||||
if hasMore {
|
||||
list = list[:maxSize]
|
||||
}
|
||||
var updated int64
|
||||
for _, item := range list {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
if serr := ensureHomeConfigSlug(ctx, item, item.Id); serr != nil {
|
||||
return updated, hasMore, serr
|
||||
}
|
||||
if strings.TrimSpace(item.Slug) == "" {
|
||||
continue
|
||||
}
|
||||
if serr := homeconfigmod.UpdateOneHomeConfig(ctx,
|
||||
bson.M{homeconfigmod.FN.HomeConfig.Id: item.Id},
|
||||
bson.M{"$set": bson.M{homeconfigmod.FN.HomeConfig.Slug: item.Slug}},
|
||||
); serr != nil {
|
||||
return updated, hasMore, serr
|
||||
}
|
||||
updated++
|
||||
}
|
||||
return updated, hasMore, nil
|
||||
}
|
||||
|
||||
func HasEmptySlug(ctx context.Context) bool {
|
||||
count, _ := homeconfigmod.CountHomeConfig(ctx, emptyHomeConfigSlugFilter())
|
||||
return count > 0
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package srv_homeconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/homeconfigmod"
|
||||
"videoweb/pub/models/playletthememod"
|
||||
"videoweb/web/api/proto"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// validateHomeConfigTopics 校验题材配置、去重,并阻止启用模块重复占用题材
|
||||
func validateHomeConfigTopics(ctx context.Context, config *homeconfigmod.HomeConfig) *srvdef.SrvErr {
|
||||
if config.Style != "" && (len(config.Style) != 1 || config.Style[0] < 'A' || config.Style[0] > 'H') {
|
||||
return srvdef.New(srvdef.ErrParamError, "样式仅支持 A-H", "")
|
||||
}
|
||||
if config.CategoryId < 0 || config.RecommendType < 0 || config.RecommendType > 5 {
|
||||
return srvdef.New(srvdef.ErrParamError, "推荐配置无效", "")
|
||||
}
|
||||
if config.RecommendType == 5 && config.CategoryId == 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "按分类推荐时必须填写分类ID", "")
|
||||
}
|
||||
if config.Type != homeconfigmod.TypeTheme {
|
||||
if len(config.TopicIds) != 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "短剧模块不能配置题材ID", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
seen := map[int64]bool{}
|
||||
ids := make([]int64, 0, len(config.TopicIds))
|
||||
for _, id := range config.TopicIds {
|
||||
if id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "题材ID无效", "")
|
||||
}
|
||||
if !seen[id] {
|
||||
ids = append(ids, id)
|
||||
seen[id] = true
|
||||
}
|
||||
}
|
||||
config.TopicIds = ids
|
||||
if !config.Status {
|
||||
return nil
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
if config.Id == 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "启用的题材模块必须配置题材ID", "")
|
||||
}
|
||||
return nil // 历史题材配置沿用自动选题材
|
||||
}
|
||||
themes, err := playletthememod.FindManyPlayletTheme(ctx, bson.M{playletthememod.FN.PlayletTheme.Id: bson.M{"$in": ids}, playletthememod.FN.PlayletTheme.Status: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(themes) != len(ids) {
|
||||
return srvdef.New(srvdef.ErrParamError, "题材不存在或未上架", "")
|
||||
}
|
||||
others, err := homeconfigmod.FindManyHomeConfig(ctx, bson.M{homeconfigmod.FN.HomeConfig.Status: true, homeconfigmod.FN.HomeConfig.Type: homeconfigmod.TypeTheme, homeconfigmod.FN.HomeConfig.TopicIds: bson.M{"$in": ids}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, other := range others {
|
||||
if other != nil && other.Id != config.Id {
|
||||
return srvdef.New(srvdef.ErrParamError, "题材已被其他启用模块使用", "")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListHomeTopicOptions 分页查询可选的已上架短剧题材,并回显当前配置已选题材
|
||||
func ListHomeTopicOptions(ctx context.Context, req *proto.HomeTopicOptionsReq) (*proto.HomeTopicOptionsResp, *srvdef.SrvErr) {
|
||||
if req == nil || req.ConfigId < 0 {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "配置ID无效", "")
|
||||
}
|
||||
pageNum, pageSize := normalizeHomeConfigPage(req.PageNum, req.PageSize)
|
||||
resp := &proto.HomeTopicOptionsResp{List: make([]*proto.HomeTopicOption, 0), SelectedList: make([]*proto.HomeTopicOption, 0), PageNum: pageNum, PageSize: pageSize}
|
||||
var selected []int64
|
||||
if req.ConfigId > 0 {
|
||||
current, err := homeconfigmod.FindOneHomeConfig(ctx, bson.M{homeconfigmod.FN.HomeConfig.Id: req.ConfigId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if current.Type != homeconfigmod.TypeTheme {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "当前配置不是题材模块", "")
|
||||
}
|
||||
selected = current.TopicIds
|
||||
}
|
||||
occupied := map[int64]bool{}
|
||||
configs, err := homeconfigmod.FindManyHomeConfig(ctx, bson.M{homeconfigmod.FN.HomeConfig.Status: true, homeconfigmod.FN.HomeConfig.Type: homeconfigmod.TypeTheme})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, config := range configs {
|
||||
if config != nil && config.Id != req.ConfigId {
|
||||
for _, id := range config.TopicIds {
|
||||
occupied[id] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
filter := bson.M{playletthememod.FN.PlayletTheme.Status: true}
|
||||
if len(occupied) > 0 {
|
||||
ids := make([]int64, 0, len(occupied))
|
||||
for id := range occupied {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
filter[playletthememod.FN.PlayletTheme.Id] = bson.M{"$nin": ids}
|
||||
}
|
||||
resp.TotalCount, err = playletthememod.CountPlayletTheme(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list, err := playletthememod.FindManyPlayletTheme(ctx, filter, options.Find().SetSort(bson.D{{Key: playletthememod.FN.PlayletTheme.Rank, Value: -1}, {Key: playletthememod.FN.PlayletTheme.Id, Value: -1}}).SetSkip((pageNum-1)*pageSize).SetLimit(pageSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, item := range list {
|
||||
if item != nil {
|
||||
resp.List = append(resp.List, &proto.HomeTopicOption{Id: item.Id, Name: item.Name, Status: item.Status})
|
||||
}
|
||||
}
|
||||
if len(selected) > 0 {
|
||||
themes, err := playletthememod.FindManyPlayletTheme(ctx, bson.M{playletthememod.FN.PlayletTheme.Id: bson.M{"$in": selected}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byID := map[int64]*proto.HomeTopicOption{}
|
||||
for _, item := range themes {
|
||||
if item != nil {
|
||||
byID[item.Id] = &proto.HomeTopicOption{Id: item.Id, Name: item.Name, Status: item.Status}
|
||||
}
|
||||
}
|
||||
for _, id := range selected {
|
||||
if item := byID[id]; item != nil {
|
||||
resp.SelectedList = append(resp.SelectedList, item)
|
||||
} else {
|
||||
resp.SelectedList = append(resp.SelectedList, &proto.HomeTopicOption{Id: id})
|
||||
}
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
Reference in New Issue
Block a user