Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"account_test.go",
"album_test.go",
"app_test.go",
"archive_test.go",
"article_test.go",
"bangumi_test.go",
"channel_archive_test.go",
"channel_test.go",
"coin_test.go",
"dynamic_test.go",
"fav_test.go",
"notice_test.go",
"service_test.go",
"setting_test.go",
"tag_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/space/conf:go_default_library",
"//app/interface/main/space/model:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"account.go",
"album.go",
"app.go",
"archive.go",
"article.go",
"assist.go",
"bangumi.go",
"blacklist.go",
"channel.go",
"channel_archive.go",
"coin.go",
"dynamic.go",
"fav.go",
"game.go",
"notice.go",
"service.go",
"setting.go",
"shop.go",
"tag.go",
],
importpath = "go-common/app/interface/main/space/service",
tags = ["automanaged"],
deps = [
"//app/interface/main/space/conf:go_default_library",
"//app/interface/main/space/dao:go_default_library",
"//app/interface/main/space/model:go_default_library",
"//app/interface/main/tag/model:go_default_library",
"//app/interface/main/tag/rpc/client:go_default_library",
"//app/interface/openplatform/article/model:go_default_library",
"//app/interface/openplatform/article/rpc/client:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/assist/model/assist:go_default_library",
"//app/service/main/assist/rpc/client:go_default_library",
"//app/service/main/coin/api:go_default_library",
"//app/service/main/favorite/api/gorpc:go_default_library",
"//app/service/main/favorite/model:go_default_library",
"//app/service/main/filter/model/rpc:go_default_library",
"//app/service/main/filter/rpc/client:go_default_library",
"//app/service/main/member/api/gorpc:go_default_library",
"//app/service/main/member/model:go_default_library",
"//app/service/main/member/model/block:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/main/relation/rpc/client:go_default_library",
"//app/service/main/thumbup/model:go_default_library",
"//app/service/main/thumbup/rpc/client:go_default_library",
"//app/service/main/up/api/v1:go_default_library",
"//library/conf/env:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/sync/errgroup.v2:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//library/time:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)

View File

@@ -0,0 +1,382 @@
package service
import (
"context"
"encoding/json"
"go-common/app/interface/main/space/model"
tagmdl "go-common/app/interface/main/tag/model"
artmdl "go-common/app/interface/openplatform/article/model"
accwar "go-common/app/service/main/account/api"
accmdl "go-common/app/service/main/account/model"
favmdl "go-common/app/service/main/favorite/model"
memmdl "go-common/app/service/main/member/model"
relmdl "go-common/app/service/main/relation/model"
upmdl "go-common/app/service/main/up/api/v1"
"go-common/library/conf/env"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
const (
_samplePn = 1
_samplePs = 1
_silenceForbid = 1
_accBlockDefault = 0
_accBlockDue = 1
_officialNoType = -1
_audioCardOn = 1
_noticeForbid = 1
)
var (
_emptyThemeList = make([]*model.ThemeDetail, 0)
_emptyArcItem = make([]*model.ArcItem, 0)
)
// NavNum get space nav num by mid.
func (s *Service) NavNum(c context.Context, mid, vmid int64) (res *model.NavNum) {
ip := metadata.String(c, metadata.RemoteIP)
res = new(model.NavNum)
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
if reply, err := s.upClient.UpCount(errCtx, &upmdl.UpCountReq{Mid: vmid}); err != nil {
log.Error("s.upClient.UpCount(%d) error(%v)", vmid, err)
} else if reply.Count > 0 {
res.Video = reply.Count
}
return nil
})
group.Go(func() error {
res.Channel = new(model.Num)
if chs, err := s.ChannelList(errCtx, vmid, false); err != nil {
log.Error("s.ChannelList(%d) error(%v)", vmid, err)
} else if chCnt := len(chs); chCnt > 0 {
res.Channel.Master = chCnt
for _, v := range chs {
if v.Count > 0 {
res.Channel.Guest++
}
}
}
return nil
})
group.Go(func() error {
res.Favourite = new(model.Num)
if favs, err := s.dao.FavFolder(errCtx, mid, vmid); err != nil {
log.Error("s.dao.FavFolder(%d) error(%v)", vmid, err)
} else if favCnt := len(favs); favCnt > 0 {
res.Favourite.Master = favCnt
for _, v := range favs {
if v.IsPublic() {
res.Favourite.Guest++
}
}
}
return nil
})
group.Go(func() error {
if _, cnt, err := s.dao.BangumiList(errCtx, vmid, _samplePn, _samplePs); err != nil {
log.Error("s.dao.BangumiList(%d) error(%v)", vmid, err)
} else if cnt > 0 {
res.Bangumi = cnt
}
return nil
})
group.Go(func() error {
if tag, err := s.tag.SubTags(errCtx, &tagmdl.ArgSub{Mid: vmid, Pn: _samplePn, Ps: _samplePs, RealIP: ip}); err != nil {
log.Error("s.tag.SubTags(%d) error(%v)", vmid, err)
} else if tag != nil {
res.Tag = tag.Total
}
return nil
})
group.Go(func() error {
if art, err := s.art.UpArtMetas(errCtx, &artmdl.ArgUpArts{Mid: vmid, Pn: 1, Ps: 10, RealIP: ip}); err != nil {
log.Error("s.art.UpArtMetas(%d) error(%v)", vmid, err)
} else if art != nil {
res.Article = art.Count
}
return nil
})
group.Go(func() error {
if cnt, err := s.fav.CntUserFolders(errCtx, &favmdl.ArgCntUserFolders{Type: favmdl.TypePlayVideo, Mid: vmid, RealIP: ip}); err != nil {
log.Error("s.dao.Playlist(%d) error(%v)", vmid, err)
} else if cnt > 0 {
res.Playlist = cnt
}
return nil
})
group.Go(func() error {
if cnt, err := s.dao.AlbumCount(errCtx, vmid); err == nil && cnt > 0 {
res.Album = cnt
}
return nil
})
group.Go(func() error {
if cnt, err := s.dao.AudioCnt(errCtx, vmid); err != nil {
log.Error("s.dao.AudioCnt(%d) error(%v)", vmid, err)
} else if cnt > 0 {
res.Audio = cnt
}
return nil
})
group.Wait()
return
}
// UpStat get up stat.
func (s *Service) UpStat(c context.Context, mid int64) (res *model.UpStat, err error) {
var (
info *accwar.InfoReply
arcStat *model.UpArcStat
artStat *model.UpArtStat
arcErr, artErr error
)
if info, err = s.accClient.Info3(c, &accwar.MidReq{Mid: mid}); err != nil || info == nil {
log.Error("s.accClient.Info3(%d) error(%v)", mid, err)
return
}
res = new(model.UpStat)
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
if arcStat, arcErr = s.UpArcStat(errCtx, mid); arcErr != nil {
log.Error("s.UpArcStat(%d) error(%v)", mid, arcErr)
} else if arcStat != nil {
res.Archive.View = arcStat.View
}
return nil
})
group.Go(func() error {
if artStat, artErr = s.UpArtStat(errCtx, mid); artErr != nil {
log.Error("s.UpArtStat(%d) error(%v)", mid, artErr)
} else if artStat != nil {
res.Article.View = artStat.View
}
return nil
})
group.Wait()
return
}
// MyInfo get my info.
func (s *Service) MyInfo(c context.Context, mid int64) (res *accmdl.ProfileStat, err error) {
var reply *accwar.ProfileStatReply
if reply, err = s.accClient.ProfileWithStat3(c, &accwar.MidReq{Mid: mid}); err != nil {
log.Error("s.accClient.ProfileWithStat3(%d) error(%v)", mid, err)
return
}
level := memmdl.LevelInfo{
Cur: reply.LevelInfo.Cur,
Min: reply.LevelInfo.Min,
NowExp: reply.LevelInfo.NowExp,
NextExp: reply.LevelInfo.NextExp,
}
res = &accmdl.ProfileStat{
Profile: reply.Profile,
LevelExp: level,
Coins: reply.Coins,
Following: reply.Follower,
Follower: reply.Follower,
}
return
}
// AccTags get account tags.
func (s *Service) AccTags(c context.Context, mid int64) (res json.RawMessage, err error) {
return s.dao.AccTags(c, mid)
}
// SetAccTags set account tags.
func (s *Service) SetAccTags(c context.Context, tags, ck string) (err error) {
return s.dao.SetAccTags(c, tags, ck)
}
// AccInfo web acc info.
func (s *Service) AccInfo(c context.Context, mid, vmid int64) (res *model.AccInfo, err error) {
if env.DeployEnv == env.DeployEnvProd {
if _, ok := s.BlacklistValue[vmid]; ok {
err = ecode.NothingFound
return
}
}
var (
reply *accwar.ProfileStatReply
topPhoto *model.TopPhoto
topErr error
)
if reply, err = s.accClient.ProfileWithStat3(c, &accwar.MidReq{Mid: vmid}); err != nil || reply == nil {
log.Error("s.accClient.ProfileWithStat3(%d) error(%v)", vmid, err)
if ecode.Cause(err) != ecode.UserNotExist {
return
}
reply = model.DefaultProfileStat
}
res = new(model.AccInfo)
res.FromCard(reply)
if res.Mid == 0 {
res.Mid = vmid
}
group, errCtx := errgroup.WithContext(c)
//check privacy
if mid != vmid {
group.Go(func() error {
if privacyErr := s.privacyCheck(errCtx, vmid, model.PcyUserInfo); privacyErr != nil {
res.JoinTime = 0
res.Sex = "保密"
res.Birthday = ""
}
return nil
})
if mid > 0 {
group.Go(func() error {
if relation, err := s.accClient.Relation3(errCtx, &accwar.RelationReq{Mid: mid, Owner: vmid}); err != nil {
log.Error("s.accClient.Relation3(%d,%d) error (%v)", mid, vmid, err)
} else if relation != nil {
res.IsFollowed = relation.Following
}
return nil
})
}
}
//get top photo
group.Go(func() error {
topPhoto, topErr = s.dao.WebTopPhoto(errCtx, vmid)
return nil
})
//get all theme
group.Go(func() error {
res.Theme = struct{}{}
if theme, err := s.dao.Theme(errCtx, vmid); err == nil && theme != nil && len(theme.List) > 0 {
for _, v := range theme.List {
if v.IsActivated == 1 {
res.Theme = v
break
}
}
}
return nil
})
//get live metal
group.Go(func() error {
res.FansBadge, _ = s.dao.LiveMetal(errCtx, vmid)
return nil
})
group.Wait()
if topErr != nil || topPhoto == nil || topPhoto.LImg == "" {
res.TopPhoto = s.c.Rule.TopPhoto
} else {
res.TopPhoto = topPhoto.LImg
}
return
}
// ThemeList get theme list.
func (s *Service) ThemeList(c context.Context, mid int64) (data []*model.ThemeDetail, err error) {
var theme *model.ThemeDetails
if theme, err = s.dao.Theme(c, mid); err != nil {
return
}
if theme == nil || len(theme.List) == 0 {
data = _emptyThemeList
return
}
data = theme.List
return
}
// ThemeActive theme active.
func (s *Service) ThemeActive(c context.Context, mid, themeID int64) (err error) {
var (
theme *model.ThemeDetails
check bool
)
if theme, err = s.dao.Theme(c, mid); err != nil {
return
}
if theme == nil || len(theme.List) == 0 {
err = ecode.RequestErr
return
}
for _, v := range theme.List {
if v.ID == themeID {
if v.IsActivated == 1 {
err = ecode.NotModified
return
}
check = true
}
}
if !check {
err = ecode.RequestErr
return
}
if err = s.dao.ThemeActive(c, mid, themeID); err == nil {
s.dao.DelCacheTheme(c, mid)
}
return
}
// Relation .
func (s *Service) Relation(c context.Context, mid, vmid int64) (data *model.Relation) {
data = &model.Relation{Relation: struct{}{}, BeRelation: struct{}{}}
ip := metadata.String(c, metadata.RemoteIP)
if mid == vmid {
return
}
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
if relation, err := s.relation.Relation(errCtx, &relmdl.ArgRelation{Mid: mid, Fid: vmid, RealIP: ip}); err != nil {
log.Error("Relation s.relation.Relation(Mid:%d,Fid:%d,%s) error %v", mid, vmid, ip, err)
} else if relation != nil {
data.Relation = relation
}
return nil
})
group.Go(func() error {
if beRelation, err := s.relation.Relation(errCtx, &relmdl.ArgRelation{Mid: vmid, Fid: mid, RealIP: ip}); err != nil {
log.Error("Relation s.relation.Relation(Mid:%d,Fid:%d,%s) error %v", vmid, mid, ip, err)
} else if beRelation != nil {
data.BeRelation = beRelation
}
return nil
})
group.Wait()
return
}
// WebIndex web index.
func (s *Service) WebIndex(c context.Context, mid, vmid int64, pn, ps int32) (data *model.WebIndex, err error) {
data = new(model.WebIndex)
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
info, infoErr := s.AccInfo(errCtx, mid, vmid)
if infoErr != nil {
return infoErr
}
data.Account = info
return nil
})
group.Go(func() error {
if setting, e := s.SettingInfo(errCtx, vmid); e == nil {
data.Setting = setting
}
return nil
})
group.Go(func() error {
if upArc, e := s.UpArcs(errCtx, vmid, pn, ps); e != nil {
data.Archive = &model.WebArc{Archives: _emptyArcItem}
} else {
arc := &model.WebArc{
Page: model.WebPage{Pn: pn, Ps: ps, Count: upArc.Count},
Archives: upArc.List,
}
data.Archive = arc
}
return nil
})
err = group.Wait()
return
}

View File

@@ -0,0 +1,56 @@
package service
import (
"context"
"encoding/json"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_NavNum(t *testing.T) {
Convey("test nav num", t, WithService(func(s *Service) {
mid := int64(883968)
vmid := int64(883968)
data := s.NavNum(context.Background(), mid, vmid)
Printf("%+v", data)
}))
}
func TestService_UpStat(t *testing.T) {
Convey("test up stat", t, WithService(func(s *Service) {
mid := int64(883968)
data, err := s.UpStat(context.Background(), mid)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}
func TestService_AccTags(t *testing.T) {
Convey("test account tags", t, WithService(func(s *Service) {
mid := int64(15555180)
data, err := s.AccTags(context.Background(), mid)
So(err, ShouldBeNil)
str, _ := json.Marshal(data)
Println(string(str))
}))
}
func TestService_SetAccTags(t *testing.T) {
Convey("test set account tags", t, WithService(func(s *Service) {
tags := "a,b,c,test"
ck := ""
err := s.SetAccTags(context.Background(), tags, ck)
So(err, ShouldBeNil)
}))
}
func TestService_MyInfo(t *testing.T) {
Convey("test my info", t, WithService(func(s *Service) {
mid := int64(15555180)
data, err := s.MyInfo(context.Background(), mid)
So(err, ShouldBeNil)
str, _ := json.Marshal(data)
Println(string(str))
}))
}

View File

@@ -0,0 +1,24 @@
package service
import (
"context"
"go-common/app/interface/main/space/model"
)
const _albumIndexPn = 0
var _emptyAlbumList = make([]*model.Album, 0)
// AlbumIndex get album index with mid.
func (s *Service) AlbumIndex(c context.Context, mid int64, ps int) (data []*model.Album, err error) {
if data, err = s.dao.AlbumList(c, mid, _albumIndexPn, ps); err != nil {
err = nil
data = _emptyAlbumList
return
}
if len(data) == 0 {
data = _emptyAlbumList
}
return
}

View File

@@ -0,0 +1,18 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_AlbumIndex(t *testing.T) {
Convey("test album index", t, WithService(func(s *Service) {
mid := int64(883968)
ps := 10
data, err := s.AlbumIndex(context.Background(), mid, ps)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}

View File

@@ -0,0 +1,317 @@
package service
import (
"context"
"time"
"go-common/app/interface/main/space/model"
artmdl "go-common/app/interface/openplatform/article/model"
accwar "go-common/app/service/main/account/api"
blkmdl "go-common/app/service/main/member/model/block"
relmdl "go-common/app/service/main/relation/model"
upmdl "go-common/app/service/main/up/api/v1"
"go-common/library/conf/env"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
const (
_devicePad = "pad"
_platShopH5 = 1
_shopGoodsOn = 1
)
// AppIndex app index info.
func (s *Service) AppIndex(c context.Context, arg *model.AppIndexArg) (data *model.AppIndex, err error) {
if env.DeployEnv == env.DeployEnvProd {
if _, ok := s.BlacklistValue[arg.Vmid]; ok {
err = ecode.NothingFound
return
}
}
var appInfo *model.AppAccInfo
if appInfo, err = s.appAccInfo(c, arg.Mid, arg.Vmid, arg.Platform, arg.Device); err != nil {
return
}
data = new(model.AppIndex)
data.Info = appInfo
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
data.Tab, _ = s.appTabInfo(errCtx, arg.Mid, arg.Vmid, arg.Device, arg.Platform)
return nil
})
if arg.Device == _devicePad {
group.Go(func() error {
data.Archive, _ = s.UpArcs(errCtx, arg.Vmid, _samplePn, arg.Ps)
return nil
})
}
group.Go(func() error {
dyListArg := &model.DyListArg{Mid: arg.Mid, Vmid: arg.Vmid, Qn: arg.Qn, Pn: _samplePn}
data.Dynamic, _ = s.DynamicList(errCtx, dyListArg)
return nil
})
group.Wait()
if arg.Device == _devicePad {
if data.Archive != nil && len(data.Archive.List) > 0 {
data.Tab.Archive = true
}
}
if data.Dynamic != nil && len(data.Dynamic.List) > 0 {
data.Tab.Dynamic = true
}
return
}
// AppAccInfo get app account info.
func (s *Service) appAccInfo(c context.Context, mid, vmid int64, platform, device string) (data *model.AppAccInfo, err error) {
var (
profile *accwar.ProfileStatReply
ip = metadata.String(c, metadata.RemoteIP)
)
data = new(model.AppAccInfo)
if profile, err = s.accClient.ProfileWithStat3(c, &accwar.MidReq{Mid: vmid}); err != nil {
if ecode.Cause(err) == ecode.UserNotExist {
err = ecode.NothingFound
return
}
log.Error("s.accClient.ProfileWithStat3(%d) error(%v)", vmid, err)
err = nil
profile = model.DefaultProfileStat
} else if profile == nil || profile.Profile == nil {
profile = model.DefaultProfileStat
}
data.FromProfile(profile)
if data.Mid == 0 {
data.Mid = vmid
}
group, errCtx := errgroup.WithContext(c)
data.Relation = struct{}{}
data.BeRelation = struct{}{}
if mid > 0 {
if mid != vmid {
group.Go(func() error {
if relation, err := s.relation.Relation(errCtx, &relmdl.ArgRelation{Mid: mid, Fid: vmid, RealIP: ip}); err != nil {
log.Error("s.relation.Relation(%d,%d,%s) error %v", mid, vmid, ip, err)
} else if relation != nil {
data.Relation = relation
}
return nil
})
group.Go(func() error {
if relation, err := s.relation.Relation(errCtx, &relmdl.ArgRelation{Mid: vmid, Fid: mid, RealIP: ip}); err != nil {
log.Error("s.relation.Relation(%d,%d,%s) error %v", vmid, mid, ip, err)
} else if relation != nil {
data.BeRelation = relation
}
return nil
})
} else {
data.LevelInfo = profile.LevelInfo
if data.Silence == _silenceForbid {
group.Go(func() error {
if i, err := s.member.BlockInfo(errCtx, &blkmdl.RPCArgInfo{MID: mid}); err != nil {
log.Error("s.member.BlockInfo mid(%d) error(%v)", mid, err)
data.Block = &model.AccBlock{Status: _accBlockDefault}
} else {
data.Block = &model.AccBlock{
Status: int(i.BlockStatus),
}
if i.BlockStatus == blkmdl.BlockStatusLimit {
if time.Now().Unix() >= i.EndTime {
data.Block.IsDue = _accBlockDue
}
if status, err := s.dao.IsAnswered(errCtx, mid, i.StartTime); err == nil {
data.Block.IsAnswered = status
}
}
}
return nil
})
}
}
}
//get top photo
group.Go(func() error {
data.TopPhoto, _ = s.dao.TopPhoto(errCtx, mid, vmid, platform, device)
return nil
})
//get live status
group.Go(func() error {
if live, err := s.dao.Live(errCtx, vmid, ""); err != nil || live == nil {
log.Error("s.dao.Live error(%+v) live(%+v)", err, live)
data.Live = struct{}{}
} else {
data.Live = live
}
return nil
})
//get live metal
group.Go(func() error {
if fansBadge, err := s.dao.LiveMetal(errCtx, vmid); err != nil {
log.Error("s.dao.LiveMetal error(%+v)", err)
} else {
data.FansBadge = fansBadge
}
return nil
})
//get audio card
group.Go(func() error {
if card, err := s.dao.AudioCard(errCtx, vmid); err != nil {
log.Error("s.dao.AudioCard error(%+v)", err)
} else {
if v, ok := card[vmid]; ok && v.Type == _audioCardOn && v.Status == 1 {
data.Audio = 1
}
}
return nil
})
//get elec info
group.Go(func() error {
if elec, err := s.dao.ElecInfo(errCtx, vmid, mid); err != nil || elec == nil {
log.Error("appAccInfo s.dao.ElecInfo vmid:%d mid:%d error(%+v) elec(%+v)", vmid, mid, err, elec)
data.Elec = struct{}{}
} else {
elec.Show = true
data.Elec = elec
}
return nil
})
//get shop info
group.Go(func() error {
if shop, err := s.dao.ShopLink(errCtx, vmid, _platShopH5); err != nil || shop == nil {
log.Error("s.dao.ShopInfo error(%+v) shop(%+v)", err, shop)
data.Shop = struct{}{}
} else {
data.Shop = &model.ShopInfo{ID: shop.ShopID, Name: shop.Name, URL: shop.JumpURL}
}
return nil
})
//audio card
group.Go(func() error {
if cert, err := s.dao.AudioUpperCert(errCtx, vmid); err != nil {
log.Error("s.dao.AudioUpperCert error(%+v)", err)
} else if cert != nil && cert.Cert != nil && cert.Cert.Type != -1 && cert.Cert.Desc != "" {
if data.OfficialInfo.Type == _officialNoType {
data.OfficialInfo.Type = cert.Cert.Type
}
if data.OfficialInfo.Desc != "" {
data.OfficialInfo.Desc = data.OfficialInfo.Desc + "、" + cert.Cert.Desc
} else {
data.OfficialInfo.Desc = cert.Cert.Desc
}
}
return nil
})
//group count
group.Go(func() error {
if fansGroup, err := s.dao.GroupsCount(errCtx, mid, vmid); err != nil {
log.Error("s.dao.GroupsCount mid(%d) vmid(%d) error(%v)", mid, vmid, err)
} else {
data.FansGroup = fansGroup
}
return nil
})
group.Wait()
return
}
// AppTabInfo get app tab info.
func (s *Service) appTabInfo(c context.Context, mid, vmid int64, device, platform string) (tab *model.AppTab, err error) {
ip := metadata.String(c, metadata.RemoteIP)
tab = new(model.AppTab)
privacy := s.privacy(c, vmid)
group, errCtx := errgroup.WithContext(c)
// pad tab dy,arc value out this func
if device != _devicePad {
group.Go(func() error {
if dyCnt, err := s.dao.DynamicCnt(errCtx, vmid); err != nil {
log.Error("s.dao.DynamicCnt error(%+v)", err)
} else if dyCnt > 0 {
tab.Dynamic = true
}
return nil
})
group.Go(func() error {
if shop, err := s.dao.ShopLink(errCtx, vmid, _platShopH5); err != nil {
log.Error("s.dao.ShopInfo error(%+v)", err)
} else if shop != nil && shop.ShowItemsTab == _shopGoodsOn {
tab.Shop = true
}
return nil
})
group.Go(func() error {
if reply, err := s.upClient.UpCount(c, &upmdl.UpCountReq{Mid: vmid}); err != nil {
log.Error("s.arc.UpCount2 mid(%d) error(%v)", vmid, err)
} else if reply.Count > 0 {
tab.Archive = true
}
return nil
})
group.Go(func() error {
if article, err := s.art.UpArtMetas(errCtx, &artmdl.ArgUpArts{Mid: vmid, Pn: 1, Ps: 10, RealIP: ip}); err != nil {
log.Error("s.art.UpArtMetas(%d) error(%v)", vmid, err)
} else if article != nil && len(article.Articles) > 0 {
tab.Article = true
}
return nil
})
group.Go(func() error {
if audioCnt, err := s.dao.AudioCnt(errCtx, vmid); err != nil {
log.Error("s.dao.AudioCnt error(%+v)", err)
} else if audioCnt > 0 {
tab.Audio = true
}
return nil
})
group.Go(func() error {
if albumCnt, err := s.dao.AlbumCount(errCtx, vmid); err == nil && albumCnt > 0 {
tab.Album = true
}
return nil
})
if value, ok := privacy[model.PcyGame]; (ok && value == _defaultPrivacy) || mid == vmid {
group.Go(func() error {
if _, gameCnt, err := s.dao.AppPlayedGame(errCtx, vmid, platform, _samplePn, _samplePs); err == nil && gameCnt > 0 {
tab.Game = true
}
return nil
})
}
}
if value, ok := privacy[model.PcyFavVideo]; (ok && value == _defaultPrivacy) || mid == vmid {
group.Go(func() error {
if fav, err := s.dao.FavFolder(errCtx, mid, vmid); err != nil {
log.Error("s.dao.FavFolder error(%+v)", err)
} else if len(fav) > 0 {
for _, v := range fav {
if v.CurCount > 0 {
tab.Favorite = true
break
}
}
}
return nil
})
}
if value, ok := privacy[model.PcyBangumi]; (ok && value == _defaultPrivacy) || mid == vmid {
group.Go(func() error {
if _, cnt, err := s.dao.BangumiList(errCtx, vmid, _samplePn, _samplePs); err != nil {
log.Error("s.dao.BangumiList mid(%d) error(%v)", vmid, err)
} else if cnt > 0 {
tab.Bangumi = true
}
return nil
})
}
group.Wait()
return
}
// AppTopPhoto get app top photo.
func (s *Service) AppTopPhoto(c context.Context, mid, vmid int64, platform, device string) (imgURL string) {
imgURL, _ = s.dao.TopPhoto(c, mid, vmid, platform, device)
return
}

View File

@@ -0,0 +1,27 @@
package service
import (
"context"
"encoding/json"
"testing"
"go-common/app/interface/main/space/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_AppIndex(t *testing.T) {
Convey("test app acc info", t, WithService(func(s *Service) {
arg := &model.AppIndexArg{
Vmid: 15555180,
Mid: 0,
Platform: "ios",
Qn: 16,
Device: _devicePad,
}
data, err := s.AppIndex(context.Background(), arg)
So(err, ShouldBeNil)
str, _ := json.Marshal(data)
Println(string(str))
}))
}

View File

@@ -0,0 +1,413 @@
package service
import (
"context"
"html/template"
"time"
"go-common/app/interface/main/space/model"
arcmdl "go-common/app/service/main/archive/api"
filmdl "go-common/app/service/main/filter/model/rpc"
upmdl "go-common/app/service/main/up/api/v1"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup.v2"
)
const (
_reasonWarnLevel = int8(20)
_reasonErrLevel = int8(30)
_checkTypeChannel = "channel"
)
var (
_emptyArchiveReason = make([]*model.ArchiveReason, 0)
_emptySearchVList = make([]*model.SearchVList, 0)
)
// UpArcStat get up all article stat.
func (s *Service) UpArcStat(c context.Context, mid int64) (data *model.UpArcStat, err error) {
addCache := true
if data, err = s.dao.UpArcCache(c, mid); err != nil {
addCache = false
} else if data != nil {
return
}
dt := time.Now().AddDate(0, 0, -1).Add(-12 * time.Hour).Format("20060102")
if data, err = s.dao.UpArcStat(c, mid, dt); data != nil && addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetUpArcCache(c, mid, data)
})
}
return
}
// TopArc get top archive.
func (s *Service) TopArc(c context.Context, mid, vmid int64) (res *model.ArchiveReason, err error) {
var (
topArc *model.AidReason
arcReply *arcmdl.ArcReply
)
if topArc, err = s.dao.TopArc(c, vmid); err != nil {
return
}
if topArc == nil || topArc.Aid == 0 {
err = ecode.SpaceNoTopArc
return
}
if arcReply, err = s.arcClient.Arc(c, &arcmdl.ArcRequest{Aid: topArc.Aid}); err != nil {
log.Error("TopArc s.arcClient.Arc(%d) error(%v)", topArc.Aid, err)
return
}
arc := arcReply.Arc
if mid != vmid && !arc.IsNormal() {
err = ecode.SpaceNoTopArc
return
}
if arc.Access >= 10000 {
arc.Stat.View = -1
}
res = &model.ArchiveReason{Arc: arc, Reason: template.HTMLEscapeString(topArc.Reason)}
return
}
// SetTopArc set top archive.
func (s *Service) SetTopArc(c context.Context, mid, aid int64, reason string) (err error) {
var (
arcReply *arcmdl.ArcReply
filRes *filmdl.FilterRes
topArc *model.AidReason
)
if arcReply, err = s.arcClient.Arc(c, &arcmdl.ArcRequest{Aid: aid}); err != nil || arcReply.Arc == nil {
log.Error("SetTopArc s.arcClient.Arc(%d) error(%v)", aid, err)
return
}
arc := arcReply.Arc
if !arc.IsNormal() {
err = ecode.SpaceFakeAid
return
}
if arc.Author.Mid != mid {
err = ecode.SpaceNotAuthor
return
}
if reason != "" {
if filRes, err = s.filter.FilterArea(c, &filmdl.ArgFilter{Area: "common", Message: reason}); err != nil || filRes == nil {
log.Error("SetTopArc s.filter.FilterArea(%s) error(%v)", reason, err)
return
}
if filRes.Level >= _reasonErrLevel {
err = ecode.SpaceTextBanned
return
}
if filRes.Level == _reasonWarnLevel {
reason = filRes.Result
}
}
if topArc, err = s.dao.TopArc(c, mid); err != nil {
return
}
if topArc != nil && aid == topArc.Aid && reason == topArc.Reason {
err = ecode.NotModified
return
}
if err = s.dao.AddTopArc(c, mid, aid, reason); err == nil {
s.dao.AddCacheTopArc(c, mid, &model.AidReason{Aid: aid, Reason: reason})
}
return
}
// DelTopArc delete top archive.
func (s *Service) DelTopArc(c context.Context, mid int64) (err error) {
var topArc *model.AidReason
if topArc, err = s.dao.TopArc(c, mid); err != nil {
return
}
if topArc == nil {
err = ecode.RequestErr
return
}
if err = s.dao.DelTopArc(c, mid); err == nil {
s.dao.AddCacheTopArc(c, mid, &model.AidReason{Aid: -1})
}
return
}
// Masterpiece get masterpiece.
func (s *Service) Masterpiece(c context.Context, mid, vmid int64) (res []*model.ArchiveReason, err error) {
var (
mps *model.AidReasons
arcsReply *arcmdl.ArcsReply
aids []int64
)
if mps, err = s.dao.Masterpiece(c, vmid); err != nil {
return
}
if mps == nil || len(mps.List) == 0 {
res = _emptyArchiveReason
return
}
for _, v := range mps.List {
aids = append(aids, v.Aid)
}
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
log.Error("Masterpiece s.arcClient.Arcs(%v) error(%v)", aids, err)
return
}
for _, v := range mps.List {
if arc, ok := arcsReply.Arcs[v.Aid]; ok && arc != nil {
if !arc.IsNormal() && mid != vmid {
continue
}
if arc.Access >= 10000 {
arc.Stat.View = -1
}
res = append(res, &model.ArchiveReason{Arc: arc, Reason: template.HTMLEscapeString(v.Reason)})
}
}
if len(res) == 0 {
res = _emptyArchiveReason
}
return
}
// AddMasterpiece add masterpiece.
func (s *Service) AddMasterpiece(c context.Context, mid, aid int64, reason string) (err error) {
var (
mps *model.AidReasons
arcReply *arcmdl.ArcReply
filRes *filmdl.FilterRes
)
if mps, err = s.dao.Masterpiece(c, mid); err != nil {
return
}
if mps == nil {
mps = &model.AidReasons{}
}
mpLen := len(mps.List)
if mpLen >= s.c.Rule.MaxMpLimit {
err = ecode.SpaceMpMaxCount
return
}
if mpLen > 0 {
for _, v := range mps.List {
if v.Aid == aid {
err = ecode.SpaceMpExist
return
}
}
}
if arcReply, err = s.arcClient.Arc(c, &arcmdl.ArcRequest{Aid: aid}); err != nil || arcReply.Arc == nil {
log.Error("AddMasterpiece s.arcClient.Arc(%d) error(%v)", aid, err)
return
}
arc := arcReply.Arc
if !arc.IsNormal() {
err = ecode.SpaceFakeAid
return
}
if arc.Author.Mid != mid {
err = ecode.SpaceNotAuthor
return
}
if reason != "" {
if filRes, err = s.filter.FilterArea(c, &filmdl.ArgFilter{Area: "common", Message: reason}); err != nil || filRes == nil {
log.Error("SetTopArc s.filter.FilterArea(%s) error(%v)", reason, err)
return
}
if filRes.Level >= _reasonErrLevel {
err = ecode.SpaceTextBanned
return
}
if filRes.Level == _reasonWarnLevel {
reason = filRes.Result
}
}
if err = s.dao.AddMasterpiece(c, mid, aid, reason); err == nil {
mps.List = append(mps.List, &model.AidReason{Aid: aid, Reason: reason})
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheMasterpiece(c, mid, mps)
})
}
return
}
// EditMasterpiece edit masterpiece.
func (s *Service) EditMasterpiece(c context.Context, mid, preAid, aid int64, reason string) (err error) {
var (
mps *model.AidReasons
arcReply *arcmdl.ArcReply
filRes *filmdl.FilterRes
preCheck bool
)
if mps, err = s.dao.Masterpiece(c, mid); err != nil {
return
}
if mps == nil || len(mps.List) == 0 {
err = ecode.SpaceMpNoArc
return
}
for _, v := range mps.List {
if v.Aid == preAid {
preCheck = true
}
if v.Aid == aid {
err = ecode.SpaceMpExist
return
}
}
if !preCheck {
err = ecode.SpaceMpNoArc
return
}
if arcReply, err = s.arcClient.Arc(c, &arcmdl.ArcRequest{Aid: aid}); err != nil || arcReply.Arc == nil {
log.Error("AddMasterpiece s.arcClient.Arc(%d) error(%v)", aid, err)
return
}
arc := arcReply.Arc
if !arc.IsNormal() {
err = ecode.SpaceFakeAid
return
}
if arc.Author.Mid != mid {
err = ecode.SpaceNotAuthor
return
}
if reason != "" {
if filRes, err = s.filter.FilterArea(c, &filmdl.ArgFilter{Area: "common", Message: reason}); err != nil || filRes == nil {
log.Error("SetTopArc s.filter.FilterArea(%s) error(%v)", reason, err)
return
}
if filRes.Level >= _reasonErrLevel {
err = ecode.SpaceTextBanned
return
}
if filRes.Level == _reasonWarnLevel {
reason = filRes.Result
}
}
if err = s.dao.EditMasterpiece(c, mid, aid, preAid, reason); err == nil {
newAidReasons := &model.AidReasons{}
for _, v := range mps.List {
if v.Aid == preAid {
newAidReasons.List = append(newAidReasons.List, &model.AidReason{Aid: aid, Reason: reason})
} else {
newAidReasons.List = append(newAidReasons.List, v)
}
}
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheMasterpiece(c, mid, newAidReasons)
})
}
return
}
// CancelMasterpiece delete masterpiece.
func (s *Service) CancelMasterpiece(c context.Context, mid, aid int64) (err error) {
var (
mps *model.AidReasons
existCheck bool
)
if mps, err = s.dao.Masterpiece(c, mid); err != nil {
return
}
if mps == nil || len(mps.List) == 0 {
err = ecode.SpaceMpNoArc
return
}
for _, v := range mps.List {
if v.Aid == aid {
existCheck = true
break
}
}
if !existCheck {
err = ecode.SpaceMpNoArc
return
}
if err = s.dao.DelMasterpiece(c, mid, aid); err == nil {
newAidReasons := &model.AidReasons{}
for _, v := range mps.List {
if v.Aid == aid {
continue
}
newAidReasons.List = append(newAidReasons.List, v)
}
if len(newAidReasons.List) == 0 {
newAidReasons.List = append(newAidReasons.List, &model.AidReason{Aid: -1})
}
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheMasterpiece(c, mid, newAidReasons)
})
}
return
}
// UpArcs get upload archive .
func (s *Service) UpArcs(c context.Context, mid int64, pn, ps int32) (res *model.UpArc, err error) {
res = &model.UpArc{List: []*model.ArcItem{}}
group := errgroup.WithContext(c)
group.Go(func(ctx context.Context) error {
if upCount, e := s.upClient.UpCount(ctx, &upmdl.UpCountReq{Mid: mid}); e != nil {
log.Error("UpArcs s.upClient.UpCount mid(%d) error(%v)", mid, e)
} else {
res.Count = upCount.Count
}
return nil
})
group.Go(func(ctx context.Context) error {
if reply, e := s.upClient.UpArcs(ctx, &upmdl.UpArcsReq{Mid: mid, Pn: pn, Ps: ps}); e != nil {
log.Error("UpArcs s.upClient.UpArcs mid(%d) error(%v)", mid, err)
} else if len(reply.Archives) > 0 {
res.List = make([]*model.ArcItem, 0, len(reply.Archives))
for _, v := range reply.Archives {
si := &model.ArcItem{}
si.FromArc(v)
res.List = append(res.List, si)
}
}
return nil
})
if e := group.Wait(); e != nil {
log.Error("UpArcs group.Wait mid(%d) error(%v)", mid, e)
}
return
}
// ArcSearch get archive from search.
func (s *Service) ArcSearch(c context.Context, mid int64, arg *model.SearchArg) (data *model.SearchRes, total int, err error) {
if data, total, err = s.dao.ArcSearchList(c, arg); err != nil {
return
}
if len(data.VList) == 0 {
data.VList = _emptySearchVList
return
}
checkAids := make(map[int64]int64)
if arg.CheckType == _checkTypeChannel {
if mid == 0 {
err = ecode.RequestErr
return
}
var chArcs []*model.ChannelArc
if chArcs, err = s.dao.ChannelVideos(c, mid, arg.CheckID, false); err != nil {
err = nil
} else {
for _, chArc := range chArcs {
checkAids[chArc.Aid] = chArc.Aid
}
}
}
vlist := make([]*model.SearchVList, 0)
for _, v := range data.VList {
if v.HideClick {
v.Play = "--"
}
if _, ok := checkAids[v.Aid]; !ok {
vlist = append(vlist, v)
}
}
data.VList = vlist
return
}

View File

@@ -0,0 +1,89 @@
package service
import (
"context"
"encoding/json"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_UpArcStat(t *testing.T) {
Convey("test up stat", t, WithService(func(s *Service) {
mid := int64(883968)
data, err := s.UpArcStat(context.Background(), mid)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}
func TestService_SetTopArc(t *testing.T) {
Convey("test set top arc", t, WithService(func(s *Service) {
mid := int64(15555180)
aid := int64(5464686)
reason := "11123"
err := s.SetTopArc(context.Background(), mid, aid, reason)
So(err, ShouldBeNil)
}))
}
func TestService_TopArc(t *testing.T) {
Convey("test top arc", t, WithService(func(s *Service) {
mid := int64(0)
vmid := int64(15555180)
data, err := s.TopArc(context.Background(), mid, vmid)
So(err, ShouldBeNil)
str, _ := json.Marshal(data)
Println(string(str))
}))
}
func TestService_DelTopArc(t *testing.T) {
Convey("test del top arc", t, WithService(func(s *Service) {
mid := int64(16913)
err := s.DelTopArc(context.Background(), mid)
So(err, ShouldBeNil)
}))
}
func TestService_Masterpiece(t *testing.T) {
Convey("test masterpiece", t, WithService(func(s *Service) {
mid := int64(0)
vmid := int64(15555180)
data, err := s.Masterpiece(context.Background(), mid, vmid)
So(err, ShouldBeNil)
str, _ := json.Marshal(data)
Println(string(str))
}))
}
func TestService_EditMasterpiece(t *testing.T) {
Convey("test masterpiece", t, WithService(func(s *Service) {
mid := int64(15555180)
preAid := int64(5464686)
aid := int64(10098536)
//aid := int64(5464827)
reason := "test edit"
err := s.EditMasterpiece(context.Background(), mid, preAid, aid, reason)
So(err, ShouldBeNil)
}))
}
func TestService_AddMasterpiece(t *testing.T) {
Convey("test masterpiece", t, WithService(func(s *Service) {
mid := int64(15555180)
aid := int64(5464827)
reason := "test add"
err := s.AddMasterpiece(context.Background(), mid, aid, reason)
So(err, ShouldBeNil)
}))
}
func TestService_CancelMasterpiece(t *testing.T) {
Convey("test masterpiece", t, WithService(func(s *Service) {
mid := int64(15555180)
aid := int64(5464827)
err := s.CancelMasterpiece(context.Background(), mid, aid)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,41 @@
package service
import (
"context"
"go-common/app/interface/main/space/model"
artmdl "go-common/app/interface/openplatform/article/model"
"go-common/library/log"
"go-common/library/net/metadata"
)
var _emptyArticle = make([]*artmdl.Meta, 0)
// Article get articles by upMid.
func (s *Service) Article(c context.Context, mid int64, pn, ps, sort int) (res *artmdl.UpArtMetas, err error) {
ip := metadata.String(c, metadata.RemoteIP)
if res, err = s.art.UpArtMetas(c, &artmdl.ArgUpArts{Mid: mid, Pn: pn, Ps: ps, Sort: sort, RealIP: ip}); err != nil {
log.Error("s.art.UpArtMetas(%d,%d,%d) error(%v)", mid, pn, ps, err)
return
}
if res != nil && len(res.Articles) == 0 {
res.Articles = _emptyArticle
}
return
}
// UpArtStat get up all article stat.
func (s *Service) UpArtStat(c context.Context, mid int64) (data *model.UpArtStat, err error) {
addCache := true
if data, err = s.dao.UpArtCache(c, mid); err != nil {
addCache = false
} else if data != nil {
return
}
if data, err = s.dao.UpArtStat(c, mid); data != nil && addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetUpArtCache(c, mid, data)
})
}
return
}

View File

@@ -0,0 +1,27 @@
package service
import (
"context"
"testing"
"go-common/app/interface/main/space/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Article(t *testing.T) {
Convey("article list test", t, WithService(func(s *Service) {
mid := int64(442549)
pn := 1
ps := 10
sort := model.ArticleSortType["publish_time"]
res, err := s.Article(context.Background(), mid, pn, ps, sort)
So(err, ShouldBeNil)
if res != nil && len(res.Articles) > 0 {
Print(len(res.Articles), res.Count)
for _, v := range res.Articles {
Printf("%+v", v)
}
}
}))
}

View File

@@ -0,0 +1,33 @@
package service
import (
"context"
"go-common/app/service/main/assist/model/assist"
"go-common/library/log"
"go-common/library/net/metadata"
)
var _emptyAssists = make([]*assist.AssistUp, 0)
// RiderList get rider list by mid
func (s *Service) RiderList(c context.Context, mid int64, pn, ps int) (res *assist.AssistUpsPager, err error) {
ip := metadata.String(c, metadata.RemoteIP)
arg := &assist.ArgAssistUps{AssistMid: mid, Pn: int64(pn), Ps: int64(ps), RealIP: ip}
if res, err = s.ass.AssistUps(c, arg); err != nil {
log.Error("s.ass.AssistUps(%d,%d,%d) error(%v)", mid, pn, ps, err)
}
if len(res.Data) == 0 {
res.Data = _emptyAssists
}
return
}
// ExitRider del rider with mid and upMid
func (s *Service) ExitRider(c context.Context, mid, upMid int64) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
if err = s.ass.AssistExit(c, &assist.ArgAssist{Mid: upMid, AssistMid: mid, RealIP: ip}); err != nil {
log.Error("s.add.DelAssist(%d,%d) error(%v)", mid, upMid, err)
}
return
}

View File

@@ -0,0 +1,35 @@
package service
import (
"context"
"go-common/app/interface/main/space/model"
)
var _emptyBangumiList = make([]*model.Bangumi, 0)
// BangumiList get bangumi list by mid.
func (s *Service) BangumiList(c context.Context, mid, vmid int64, pn, ps int) (data []*model.Bangumi, count int, err error) {
if mid != vmid {
if err = s.privacyCheck(c, vmid, model.PcyBangumi); err != nil {
return
}
}
if data, count, err = s.dao.BangumiList(c, vmid, pn, ps); err != nil {
return
}
if len(data) == 0 {
data = _emptyBangumiList
}
return
}
// BangumiConcern bangumi concern.
func (s *Service) BangumiConcern(c context.Context, mid, seasonID int64) (err error) {
return s.dao.BangumiConcern(c, mid, seasonID)
}
// BangumiUnConcern bangumi unconcern.
func (s *Service) BangumiUnConcern(c context.Context, mid, seasonID int64) (err error) {
return s.dao.BangumiUnConcern(c, mid, seasonID)
}

View File

@@ -0,0 +1,20 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_BangumiList(t *testing.T) {
Convey("test bangumi list", t, WithService(func(s *Service) {
mid := int64(0)
vmid := int64(883968)
pn := 1
ps := 10
data, cnt, err := s.BangumiList(context.Background(), mid, vmid, pn, ps)
So(err, ShouldBeNil)
Printf("%+v,%d", data, cnt)
}))
}

View File

@@ -0,0 +1,24 @@
package service
import (
"context"
"go-common/library/log"
)
// Blacklist space blacklist
func (s *Service) Blacklist(c context.Context) {
var (
blTmp []int64
err error
)
if blTmp, err = s.dao.Blacklist(c); err != nil {
log.Error("Service.Blacklist error(%v)", err)
return
}
blacklist := make(map[int64]struct{}, len(blTmp))
for _, mid := range blTmp {
blacklist[mid] = struct{}{}
}
s.BlacklistValue = blacklist
}

View File

@@ -0,0 +1,319 @@
package service
import (
"context"
"sync"
"time"
"go-common/app/interface/main/space/conf"
"go-common/app/interface/main/space/model"
arcmdl "go-common/app/service/main/archive/api"
filmdl "go-common/app/service/main/filter/model/rpc"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
xtime "go-common/library/time"
)
var (
_emptyChArc = make([]*arcmdl.Arc, 0)
_emptyChList = make([]*model.Channel, 0)
_emptyChDetailList = make([]*model.ChannelDetail, 0)
_nameErrorLevel = int8(20)
_introWarnLevel = int8(20)
_introErrorLevel = int8(30)
)
// ChannelList get channel list.
func (s *Service) ChannelList(c context.Context, mid int64, isGuest bool) (channels []*model.Channel, err error) {
var (
channelExtra map[int64]*model.ChannelExtra
cids []int64
addCache = true
)
if channels, err = s.dao.ChannelListCache(c, mid); err != nil {
addCache = false
} else if len(channels) > 0 {
return
}
if channels, err = s.dao.ChannelList(c, mid); err != nil {
log.Error("s.dao.ChannelList(%d) error(%v)", mid, err)
return
}
if len(channels) == 0 {
channels = _emptyChList
return
}
for _, channel := range channels {
cids = append(cids, channel.Cid)
}
if channelExtra, err = s.channelExtra(c, mid, cids); err != nil {
err = nil
return
}
for _, channel := range channels {
if _, ok := channelExtra[channel.Cid]; ok {
channel.Count = channelExtra[channel.Cid].Count
channel.Cover = channelExtra[channel.Cid].Cover
}
}
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetChannelListCache(c, mid, channels)
})
}
return
}
// Channel get channel info.
func (s *Service) Channel(c context.Context, mid, cid int64) (channel *model.Channel, err error) {
var (
extra *model.ChannelExtra
arcReply *arcmdl.ArcReply
addCache bool
)
if channel, addCache, err = s.channel(c, mid, cid); err != nil {
log.Error("s.channel(%d,%d) error(%v)", mid, cid, err)
return
}
if extra, err = s.dao.ChannelExtra(c, mid, cid); err != nil {
log.Error("s.dao.ChannelExtra(%d,%d) error(%v)", mid, cid, err)
err = nil
} else if extra != nil {
channel.Count = extra.Count
if extra.Aid > 0 {
if arcReply, err = s.arcClient.Arc(c, &arcmdl.ArcRequest{Aid: extra.Aid}); err != nil {
log.Error("s.arcClient.Arc(%d) error(%v)", extra.Aid, err)
err = nil
} else {
channel.Cover = arcReply.Arc.Pic
}
}
}
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetChannelCache(c, mid, cid, channel)
})
}
return
}
func (s *Service) channel(c context.Context, mid, cid int64) (res *model.Channel, addCache bool, err error) {
addCache = true
if res, err = s.dao.ChannelCache(c, mid, cid); err != nil {
addCache = false
} else if res != nil {
return
}
if res, err = s.dao.Channel(c, mid, cid); err != nil {
log.Error("s.dao.Channel(%d,%d) error(%v)", mid, cid, err)
} else if res == nil {
err = ecode.NothingFound
}
return
}
// ChannelIndex get channel index info.
func (s *Service) ChannelIndex(c context.Context, mid int64, isGuest bool) (channelDetails []*model.ChannelDetail, err error) {
var (
channels []*model.Channel
detail *model.ChannelDetail
)
if channels, err = s.ChannelList(c, mid, isGuest); err != nil {
log.Error("s.Channel(%d) error(%v)", mid, err)
return
} else if len(channels) == 0 {
channelDetails = _emptyChDetailList
return
}
group, errCtx := errgroup.WithContext(c)
mutex := sync.Mutex{}
for _, channel := range channels {
cid := channel.Cid
group.Go(func() (err error) {
if detail, err = s.ChannelVideos(errCtx, mid, cid, 1, conf.Conf.Rule.ChIndexCnt, isGuest, false); err != nil {
log.Error("s.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
err = nil
} else if detail != nil {
mutex.Lock()
channelDetails = append(channelDetails, detail)
mutex.Unlock()
}
return
})
}
group.Wait()
if len(channelDetails) == 0 {
channelDetails = _emptyChDetailList
}
return
}
// AddChannel add channel.
func (s *Service) AddChannel(c context.Context, mid int64, name, intro string) (cid int64, err error) {
var (
afIntro string
ts = time.Now()
)
if _, err = s.realName(c, mid); err != nil {
return
}
if err = s.channelCheck(c, mid, 0, name, true, true); err != nil {
log.Error("s.channelCheck(%d,%s) error(%v)", mid, name, err)
return
}
if afIntro, err = s.channelFilter(c, name, intro); err != nil {
log.Error("s.channelFilter(%s,%s) error(%v)", name, intro, err)
return
}
if cid, err = s.dao.AddChannel(c, mid, name, afIntro, ts); err != nil {
log.Error("s.dao.AddChannel(%d,%s,%s) error(%v)", mid, name, intro, err)
return
} else if cid > 0 {
s.cache.Do(c, func(c context.Context) {
ch := &model.Channel{Cid: cid, Mid: mid, Name: name, Intro: intro, Mtime: xtime.Time(ts.Unix())}
s.dao.SetChannelCache(c, mid, cid, ch)
})
}
return
}
// EditChannel edit channel.
func (s *Service) EditChannel(c context.Context, mid, cid int64, name, intro string) (err error) {
var (
affected int64
afIntro string
ts = time.Now()
)
if _, err = s.realName(c, mid); err != nil {
return
}
if err = s.channelCheck(c, mid, cid, name, true, false); err != nil {
log.Error("s.channelCheck(%d,%d,%s) error(%v)", mid, cid, name, err)
return
}
if afIntro, err = s.channelFilter(c, name, intro); err != nil {
log.Error("s.channelFilter(%s,%s) error(%v)", name, intro, err)
return
}
//if channel,err := s.Channel(c,mid,cid,ip)
if affected, err = s.dao.EditChannel(c, mid, cid, name, afIntro, ts); err != nil {
log.Error("s.dao.EditChannel(%d,%s,%s) error(%v)", mid, name, intro, err)
return
} else if affected > 0 {
s.cache.Do(c, func(c context.Context) {
ch := &model.Channel{Cid: cid, Mid: mid, Name: name, Intro: intro, Mtime: xtime.Time(ts.Unix())}
s.dao.SetChannelCache(c, mid, cid, ch)
})
}
return
}
// DelChannel del channel.
func (s *Service) DelChannel(c context.Context, mid, cid int64) (err error) {
var affected int64
if affected, err = s.dao.DelChannel(c, mid, cid); err != nil {
log.Error("s.dao.DelChannel(%d,%d) error(%v)", mid, cid, err)
return
} else if affected > 0 {
s.dao.DelChannelCache(c, mid, cid)
s.dao.DelChannelArcsCache(c, mid, cid)
}
return
}
func (s *Service) channelExtra(c context.Context, mid int64, cids []int64) (extra map[int64]*model.ChannelExtra, err error) {
if len(cids) == 0 {
return
}
var (
arcsReply *arcmdl.ArcsReply
aids = make([]int64, 0, len(cids))
)
extra = make(map[int64]*model.ChannelExtra, len(cids))
for _, cid := range cids {
var data *model.ChannelExtra
if data, err = s.dao.ChannelExtra(c, mid, cid); err != nil {
log.Error("s.dao.ChannelExtra(%d,%d) error(%v)", mid, cid, err)
continue
} else if data != nil {
extra[cid] = &model.ChannelExtra{Aid: data.Aid, Cid: data.Cid, Count: data.Count}
if data.Aid > 0 {
aids = append(aids, data.Aid)
}
}
}
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
log.Error("s.arcClient.Arcs(%v) error (%v)", aids, err)
return
}
for _, cid := range cids {
if _, ok := extra[cid]; ok {
if arc, ok := arcsReply.Arcs[extra[cid].Aid]; ok {
extra[cid].Cover = arc.Pic
}
}
}
return
}
func (s *Service) channelCheck(c context.Context, mid, cid int64, name string, nameCheck, countCheck bool) (err error) {
var (
channels []*model.Channel
dbCheck = false
)
if channels, err = s.dao.ChannelListCache(c, mid); err != nil {
err = nil
dbCheck = true
} else if len(channels) == 0 {
dbCheck = true
}
if dbCheck {
if channels, err = s.dao.ChannelList(c, mid); err != nil {
log.Error("s.dao.ChannelList(%d) error(%v)", mid, err)
return
}
}
if cnt := len(channels); cnt > 0 {
if countCheck && cnt > conf.Conf.Rule.MaxChLimit {
err = ecode.ChMaxCount
return
}
if nameCheck {
for _, channel := range channels {
if name == channel.Name && cid != channel.Cid {
err = ecode.ChNameExist
return
}
}
}
}
return
}
func (s *Service) channelFilter(c context.Context, name, intro string) (afterIntro string, err error) {
var (
filterRes map[string]*filmdl.FilterRes
arg = &filmdl.ArgMfilter{Area: "common", Message: map[string]string{"name": name, "intro": intro}}
)
afterIntro = intro
if filterRes, err = s.filter.MFilter(c, arg); err != nil {
log.Error("s.filter.MFilter(%v) error(%v)", arg, err)
return
}
for k, v := range filterRes {
if k == "name" && v.Level >= _nameErrorLevel {
err = ecode.ChNameBanned
return
}
if k == "intro" {
if v.Level == _introWarnLevel {
afterIntro = v.Result
} else if v.Level >= _introErrorLevel {
err = ecode.ChIntroBanned
return
}
}
}
return
}

View File

@@ -0,0 +1,367 @@
package service
import (
"context"
"sync"
"time"
"go-common/app/interface/main/space/conf"
"go-common/app/interface/main/space/model"
arcmdl "go-common/app/service/main/archive/api"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
xtime "go-common/library/time"
)
const _aidBulkSize = 50
// AddChannelArc add channel archive.
func (s *Service) AddChannelArc(c context.Context, mid, cid int64, aids []int64) (fakeAids []int64, err error) {
var (
lastID int64
orderNum int
chAids, addAids []int64
arcs map[int64]*arcmdl.Arc
videos []*model.ChannelArc
videoMap map[int64]int64
remainVideos []*model.ChannelArcSort
ts = time.Now()
)
fakeAids = make([]int64, 0)
if _, _, err = s.channel(c, mid, cid); err != nil {
log.Error("s.dao.Channel(%d,%d) error(%v)", mid, cid, err)
return
}
if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
log.Error("s.dao.channelVideos(%d,%d) error(%v)", mid, cid, err)
return
} else if orderNum = len(videos); orderNum > 0 {
if len(aids)+orderNum > conf.Conf.Rule.MaxChArcLimit {
err = ecode.ChMaxArcCount
return
}
videoMap = make(map[int64]int64)
for _, video := range videos {
chAids = append(chAids, video.Aid)
videoMap[video.Aid] = video.Aid
}
}
for _, aid := range aids {
if _, ok := videoMap[aid]; ok {
fakeAids = append(fakeAids, aid)
} else {
addAids = append(addAids, aid)
}
}
if len(addAids) == 0 {
err = ecode.ChAidsExist
return
}
if err = s.arcsCheck(c, mid, chAids); err != nil {
return
}
if arcs, err = s.archives(c, addAids); err != nil {
log.Error("s.arc.Archive3(%v) error(%v)", addAids, err)
return
}
for _, aid := range addAids {
if arc, ok := arcs[aid]; !ok || !arc.IsNormal() || arc.Author.Mid != mid {
fakeAids = append(fakeAids, aid)
continue
}
orderNum++
remainVideos = append(remainVideos, &model.ChannelArcSort{Aid: aid, OrderNum: orderNum})
}
if len(remainVideos) == 0 {
err = ecode.ChAidsExist
return
}
if lastID, err = s.dao.AddChannelArc(c, mid, cid, ts, remainVideos); err != nil {
log.Error("s.dao.AddChannelArc(mid:%d,cid:%d) error(%v)", mid, cid, err)
return
} else if lastID > 0 {
var arcs []*model.ChannelArc
for _, v := range remainVideos {
arc := &model.ChannelArc{ID: lastID, Mid: mid, Cid: cid, Aid: v.Aid, OrderNum: v.OrderNum, Mtime: xtime.Time(ts.Unix())}
arcs = append(arcs, arc)
}
s.dao.AddChannelArcCache(context.Background(), mid, cid, arcs)
}
return
}
func (s *Service) arcsCheck(c context.Context, mid int64, aids []int64) (err error) {
var arcs map[int64]*arcmdl.Arc
if arcs, err = s.archives(c, aids); err != nil {
log.Error("s.archives error(%v)", err)
return
}
for _, aid := range aids {
if arc, ok := arcs[aid]; !ok || !arc.IsNormal() || arc.Author.Mid != mid {
err = ecode.ChFakeAid
return
}
}
return
}
// DelChannelArc delete channel archive.
func (s *Service) DelChannelArc(c context.Context, mid, cid, aid int64) (err error) {
var (
affected int64
orderNum int
videos []*model.ChannelArc
)
if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
log.Error("s.dao.Channel(%d,%d) error(%v)", mid, cid, err)
return
} else if len(videos) == 0 {
err = ecode.ChNoArcs
return
} else {
check := false
for _, video := range videos {
if aid == video.Aid {
check = true
orderNum = video.OrderNum
}
}
if !check {
err = ecode.ChNoArc
return
}
}
if affected, err = s.dao.DelChannelArc(c, mid, cid, aid, orderNum); err != nil {
log.Error("s.dao.DelChannelArc(%d,%d) error(%v)", mid, aid, err)
return
} else if affected > 0 {
s.dao.DelChannelArcCache(c, mid, cid, aid)
s.setChannelArcSortCache(c, mid, cid)
}
return
}
// SortChannelArc sort channel archive.
func (s *Service) SortChannelArc(c context.Context, mid, cid, aid int64, orderNum int) (err error) {
var (
videos []*model.ChannelArc
bfSortBegin, bfSortEnd, chSort, afSort []*model.ChannelArcSort
affected int64
aidIndex, aidOn int
aidCheck bool
ts = time.Now()
)
if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
log.Error("s.dao.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
return
} else if len(videos) == 0 {
err = ecode.ChNoArcs
return
} else {
videoLen := len(videos)
if orderNum > videoLen {
err = ecode.RequestErr
return
}
for index, video := range videos {
if aid == video.Aid {
aidCheck = true
aidIndex = index
aidOn = video.OrderNum
break
}
}
if !aidCheck {
err = ecode.RequestErr
return
}
if orderNum > aidOn {
chSort = append(chSort, &model.ChannelArcSort{Aid: aid, OrderNum: orderNum})
for i, v := range videos {
if i < videoLen-orderNum {
bfSortBegin = append(bfSortBegin, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum})
} else if i >= videoLen-orderNum && i < aidIndex {
chSort = append(chSort, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum - 1})
} else if i > aidIndex {
bfSortEnd = append(bfSortEnd, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum})
}
}
} else if orderNum < aidOn {
for i, v := range videos {
if i < aidIndex {
bfSortBegin = append(bfSortBegin, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum})
} else if i > aidIndex && i <= videoLen-orderNum {
chSort = append(chSort, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum + 1})
} else if i > videoLen-orderNum {
bfSortEnd = append(bfSortEnd, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum})
}
}
chSort = append(chSort, &model.ChannelArcSort{Aid: aid, OrderNum: orderNum})
} else {
return
}
afSort = append(afSort, bfSortBegin...)
afSort = append(afSort, chSort...)
afSort = append(afSort, bfSortEnd...)
}
if affected, err = s.dao.EditChannelArc(c, mid, cid, ts, chSort); err != nil {
log.Error("s.dao.s.dao.EditChannelArc(%d,%d,%d,%d) error(%v)", mid, cid, aid, orderNum, err)
return
} else if affected > 0 {
s.dao.SetChannelArcSortCache(c, mid, cid, afSort)
}
return
}
// ChannelVideos get channel and channel video info.
func (s *Service) ChannelVideos(c context.Context, mid, cid int64, pn, ps int, isGuest, order bool) (res *model.ChannelDetail, err error) {
var (
channel *model.Channel
start = (pn - 1) * ps
end = start + ps - 1
)
if channel, err = s.Channel(c, mid, cid); err != nil {
return
}
res = &model.ChannelDetail{Channel: channel}
res.Archives, err = s.channelArc(c, mid, cid, start, end, isGuest, order)
return
}
func (s *Service) channelVideos(c context.Context, mid, cid int64, start, end int, order bool) (res []*model.ChannelArc, err error) {
var (
videos []*model.ChannelArc
addCache = true
)
if res, err = s.dao.ChannelArcsCache(c, mid, cid, start, end, order); err != nil {
addCache = false
} else if len(res) > 0 {
return
}
if videos, err = s.dao.ChannelVideos(c, mid, cid, order); err != nil {
log.Error("s.dao.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
return
} else if len(videos) > 0 {
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetChannelArcsCache(c, mid, cid, videos)
s.setChannelArcSortCache(c, mid, cid)
})
}
length := len(videos)
if length < start {
res = make([]*model.ChannelArc, 0)
return
}
if length > end {
res = videos[start : end+1]
} else {
res = videos[start:]
}
}
return
}
// CheckChannelVideo check useless channel video.
func (s *Service) CheckChannelVideo(c context.Context, mid, cid int64) (err error) {
var (
videos []*model.ChannelArc
aids []int64
)
if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
log.Error("s.dao.channelVideos(%d,%d) error(%v)", mid, cid, err)
return
}
for _, v := range videos {
aids = append(aids, v.Aid)
}
err = s.arcsCheck(c, mid, aids)
return
}
func (s *Service) channelArc(c context.Context, mid, cid int64, start, end int, isGuest, order bool) (res []*arcmdl.Arc, err error) {
var (
videoAids []*model.ChannelArc
archives map[int64]*arcmdl.Arc
aids []int64
)
if videoAids, err = s.channelVideos(c, mid, cid, start, end, order); err != nil {
log.Error("s.dao.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
return
} else if len(videoAids) == 0 {
res = _emptyChArc
return
}
for _, video := range videoAids {
aids = append(aids, video.Aid)
}
if archives, err = s.archives(c, aids); err != nil {
log.Error("s.arc.Archives3(%v) error(%v)", aids, err)
return
}
for _, video := range videoAids {
if arc, ok := archives[video.Aid]; ok {
if arc.IsNormal() {
if arc.Access >= 10000 {
arc.Stat.View = -1
}
res = append(res, arc)
} else {
res = append(res, &arcmdl.Arc{Aid: video.Aid, Title: arc.Title, Pic: arc.Pic, Stat: arc.Stat, PubDate: arc.PubDate, State: arc.State})
}
}
}
return
}
func (s *Service) setChannelArcSortCache(c context.Context, mid, cid int64) (err error) {
var (
videos []*model.ChannelArc
sorts []*model.ChannelArcSort
)
if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
log.Error("s.dao.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
return
} else if len(videos) == 0 {
return
}
for _, v := range videos {
sort := &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum}
sorts = append(sorts, sort)
}
return s.dao.SetChannelArcSortCache(c, mid, cid, sorts)
}
func (s *Service) archives(c context.Context, aids []int64) (archives map[int64]*arcmdl.Arc, err error) {
var (
mutex = sync.Mutex{}
aidsLen = len(aids)
group, errCtx = errgroup.WithContext(c)
)
archives = make(map[int64]*arcmdl.Arc, aidsLen)
for i := 0; i < aidsLen; i += _aidBulkSize {
var partAids []int64
if i+_aidBulkSize > aidsLen {
partAids = aids[i:]
} else {
partAids = aids[i : i+_aidBulkSize]
}
group.Go(func() (err error) {
var arcs *arcmdl.ArcsReply
arg := &arcmdl.ArcsRequest{Aids: partAids}
if arcs, err = s.arcClient.Arcs(errCtx, arg); err != nil {
log.Error("s.arcClient.Arcs(%v) error(%v)", partAids, err)
return
}
mutex.Lock()
for _, v := range arcs.Arcs {
archives[v.Aid] = v
}
mutex.Unlock()
return
})
}
err = group.Wait()
return
}

View File

@@ -0,0 +1,42 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_SortChannelArc(t *testing.T) {
Convey("test sort channel arc", t, WithService(func(s *Service) {
var (
mid = int64(27515260)
cid = int64(37)
aid = int64(5462035)
preAid = 1
)
err := s.SortChannelArc(context.Background(), mid, cid, aid, preAid)
So(err, ShouldBeNil)
}))
}
func TestService_AddChannelArc(t *testing.T) {
Convey("add channel arc", t, WithService(func(s *Service) {
mid := int64(27515260)
cid := int64(34)
aid := []int64{5462036}
_, err := s.AddChannelArc(context.Background(), mid, cid, aid)
So(err, ShouldBeNil)
}))
}
func TestService_archives(t *testing.T) {
Convey("archives", t, WithService(func(s *Service) {
aids := []int64{4053640, 4053639, 4053638, 4053637, 4053635, 4053634, 4053633, 4053632, 4053631, 4053630, 4053629, 4053628, 4053627, 4053626, 4053625, 4053624, 4053623, 4053622, 4053617, 4053611, 4053608, 4053607, 4053605, 4053604, 4053603, 4053602, 4053600, 4053599, 4053598, 4053596, 4053595, 4053594, 4053593, 4053592, 4053591, 4053590, 4053589, 4053588, 4053587, 4053586, 4053585, 4053584, 4053583, 4053582, 4053581, 4053579, 4053577, 4053576, 4053575, 4053574}
arcs, err := s.archives(context.Background(), aids)
So(err, ShouldBeNil)
for _, v := range arcs {
Printf("%+v", v)
}
}))
}

View File

@@ -0,0 +1,58 @@
package service
import (
"context"
"testing"
"go-common/app/interface/main/space/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Channel(t *testing.T) {
Convey("test channel", t, WithService(func(s *Service) {
mid := int64(27515260)
cid := int64(37)
res, err := s.Channel(context.Background(), mid, cid)
So(err, ShouldBeNil)
Printf("res %+v", res)
So(res, ShouldHaveSameTypeAs, &model.Channel{})
}))
}
func TestService_ChannelIndex(t *testing.T) {
Convey("test channel index", t, WithService(func(s *Service) {
mid := int64(27515260)
isGuest := false
res, err := s.ChannelIndex(context.Background(), mid, isGuest)
So(err, ShouldBeNil)
for _, v := range res {
Printf("res %+v", v)
}
var sample []*model.ChannelDetail
So(res, ShouldHaveSameTypeAs, sample)
}))
}
func TestService_ChannelList(t *testing.T) {
Convey("test channel list", t, WithService(func(s *Service) {
mid := int64(27515260)
isGuest := false
res, err := s.ChannelList(context.Background(), mid, isGuest)
So(err, ShouldBeNil)
for _, v := range res {
Printf("res %+v", v)
}
var sample []*model.Channel
So(res, ShouldHaveSameTypeAs, sample)
}))
}
func TestService_DelChannel(t *testing.T) {
Convey("del channel", t, WithService(func(s *Service) {
mid := int64(27515260)
cid := int64(34)
err := s.DelChannel(context.Background(), mid, cid)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,78 @@
package service
import (
"context"
"time"
"go-common/app/interface/main/space/model"
arcmdl "go-common/app/service/main/archive/api"
coinmdl "go-common/app/service/main/coin/api"
"go-common/library/log"
)
const (
_coinVideoLimit = 100
_businessCoin = "archive"
)
var _emptyCoinArcList = make([]*model.CoinArc, 0)
// CoinVideo get coin archives
func (s *Service) CoinVideo(c context.Context, mid, vmid int64) (list []*model.CoinArc, err error) {
var (
coinReply *coinmdl.ListReply
aids []int64
arcReply *arcmdl.ArcsReply
)
if mid != vmid {
if err = s.privacyCheck(c, vmid, model.PcyCoinVideo); err != nil {
return
}
}
if coinReply, err = s.coinClient.List(c, &coinmdl.ListReq{Mid: vmid, Business: _businessCoin, Ts: time.Now().Unix()}); err != nil {
log.Error("s.coinClinet.List(%d) error(%v)", vmid, err)
err = nil
list = _emptyCoinArcList
return
}
existAids := make(map[int64]int64, len(coinReply.List))
afVideos := make(map[int64]*coinmdl.ModelList, len(coinReply.List))
for _, v := range coinReply.List {
if len(aids) > _coinVideoLimit {
break
}
if _, ok := existAids[v.Aid]; ok {
if v.Aid > 0 {
afVideos[v.Aid].Number += v.Number
}
continue
}
if v.Aid > 0 {
afVideos[v.Aid] = v
aids = append(aids, v.Aid)
existAids[v.Aid] = v.Aid
}
}
if len(aids) == 0 {
list = _emptyCoinArcList
return
}
if arcReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
return
}
for _, aid := range aids {
if arc, ok := arcReply.Arcs[aid]; ok && arc.IsNormal() {
if arc.Access >= 10000 {
arc.Stat.View = -1
}
if item, ok := afVideos[aid]; ok {
list = append(list, &model.CoinArc{Arc: arc, Coins: item.Number, Time: item.Ts})
}
}
}
if len(list) == 0 {
list = _emptyCoinArcList
}
return
}

View File

@@ -0,0 +1,18 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_CoinVideo(t *testing.T) {
Convey("test coin video", t, WithService(func(s *Service) {
mid := int64(0)
vmid := int64(88889018)
data, err := s.CoinVideo(context.Background(), mid, vmid)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}

View File

@@ -0,0 +1,402 @@
package service
import (
"context"
"sort"
"time"
"go-common/app/interface/main/space/model"
arcmdl "go-common/app/service/main/archive/api"
coinmdl "go-common/app/service/main/coin/api"
thumbup "go-common/app/service/main/thumbup/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
const (
_dyTypeCoin = -1
_dyTypeLike = -2
_dyTypeMerge = -3
_businessLike = "archive"
_likeVideoCnt = 100
_dyListCnt = 20
_dyDefaultQn = 16
_dyFoldNum = 3
)
var dyTypeFoldMap = map[int]struct{}{_dyTypeCoin: {}, _dyTypeLike: {}, _dyTypeMerge: {}}
// DynamicList get dynamic list.
func (s Service) DynamicList(c context.Context, arg *model.DyListArg) (dyTotal *model.DyTotal, err error) {
var (
list, actList []*model.DyItem
mergeList []*model.DyActItem
dyList *model.DyList
topDy *model.DyCard
dyListTs, lastCoinTs, lastLikeTs int64
topErr, dyErr error
hasCoin, hasDy, hasLike, top bool
)
fp := arg.Pn == 1
repeatDyIDs := make(map[int64]int64, 1)
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
if topDy, topErr = s.topDynamic(errCtx, arg.Vmid, arg.Qn); topErr == nil && topDy != nil {
top = fp
repeatDyIDs[topDy.Desc.DynamicID] = topDy.Desc.DynamicID
}
return nil
})
group.Go(func() error {
if dyList, dyErr = s.dao.DynamicList(errCtx, arg.Mid, arg.Vmid, arg.DyID, arg.Qn, arg.Pn); dyErr != nil {
log.Error("s.dao.DynamicList(mid:%d,vmid:%d,dyID:%d,qn:%d,pn:%d) error(%+v)", arg.Mid, arg.Vmid, arg.DyID, arg.Qn, arg.Pn, dyErr)
}
return nil
})
group.Go(func() error {
lastCoinTs, lastLikeTs, mergeList = s.actList(errCtx, arg.Mid, arg.Vmid)
return nil
})
if e := group.Wait(); e != nil {
log.Error("DynamicList group.Wait mid(%d) error(%v)", arg.Vmid, e)
}
// rm repeat data
if dyErr == nil && dyList != nil && len(dyList.Cards) > 0 {
for _, v := range dyList.Cards {
if _, ok := repeatDyIDs[v.Desc.DynamicID]; ok {
continue
}
item := new(model.DyResult)
item.FromCard(v)
list = append(list, &model.DyItem{Type: v.Desc.Type, Card: item, Ctime: v.Desc.Timestamp})
}
hasDy = dyList.HasMore == 1
dyListTs = dyList.Cards[len(dyList.Cards)-1].Desc.Timestamp
}
if len(mergeList) > 0 {
hasCoin, hasLike, actList = s.filterActList(c, lastCoinTs, lastLikeTs, arg.LastTime, dyListTs, mergeList, fp)
list = append(list, actList...)
}
sort.Slice(list, func(i, j int) bool { return list[i].Ctime > list[j].Ctime })
dyTotal = new(model.DyTotal)
if top {
topItem := new(model.DyResult)
topItem.FromCard(topDy)
dyTotal.List = append(dyTotal.List, &model.DyItem{Type: topDy.Desc.Type, Top: true, Card: topItem, Ctime: topDy.Desc.Timestamp})
}
dyTotal.HasMore = hasDy || hasCoin || hasLike
dyTotal.List = append(dyTotal.List, list...)
if s.c.Rule.ActFold {
dyTotal.List = foldDyActItem(dyTotal.List)
}
return
}
func (s *Service) actList(c context.Context, mid, vmid int64) (lastCoinTs, lastLikeTs int64, mergeList []*model.DyActItem) {
var (
coinList, likeList, preList []*model.DyActItem
coinErr, likeErr error
coinPcy, likePcy bool
)
group, errCtx := errgroup.WithContext(c)
privacy := s.privacy(c, vmid)
if value, ok := privacy[model.PcyCoinVideo]; ok && value != _defaultPrivacy {
coinPcy = true
}
if value, ok := privacy[model.PcyLikeVideo]; ok && value != _defaultPrivacy {
likePcy = true
}
// coin video
if mid == vmid || !coinPcy {
group.Go(func() error {
coinList, coinErr = s.coinVideos(errCtx, vmid, coinPcy)
return nil
})
}
// like video
if mid == vmid || !likePcy {
group.Go(func() error {
likeList, likeErr = s.likeVideos(errCtx, vmid, likePcy)
return nil
})
}
group.Wait()
if coinErr == nil {
if l := len(coinList); l > 0 {
preList = append(preList, coinList...)
lastCoinTs = coinList[l-1].ActionTime
}
}
if likeErr == nil {
if l := len(likeList); l > 0 {
preList = append(preList, likeList...)
lastLikeTs = likeList[l-1].ActionTime
}
}
if len(preList) == 0 {
return
}
sort.Slice(preList, func(i, j int) bool { return preList[i].ActionTime > preList[j].ActionTime })
if s.c.Rule.Merge {
mergeList = mergeDyActItem(preList)
} else {
mergeList = preList
}
return
}
func (s *Service) filterActList(c context.Context, lastCoinTs, lastLikeTs, lastTime, dyListTs int64, mergeList []*model.DyActItem, fp bool) (hasCoin, hasLike bool, list []*model.DyItem) {
var (
actList []*model.DyActItem
actAids []int64
coinTs, likeTs int64
)
for _, v := range mergeList {
if dyListTs == 0 && len(actList) >= _dyListCnt {
lastActTs := actList[len(actList)-1].ActionTime
penultActTs := actList[len(actList)-2].ActionTime
y1, m1, d1 := time.Unix(lastActTs, 0).Date()
y2, m2, d2 := time.Unix(penultActTs, 0).Date()
if d1 != d2 || m1 != m2 || y1 != y2 {
actList = actList[:len(actList)-1]
break
}
}
if fp {
if dyListTs > 0 {
if v.ActionTime >= dyListTs {
actList = append(actList, v)
actAids = append(actAids, v.Aid)
}
} else {
actList = append(actList, v)
actAids = append(actAids, v.Aid)
}
} else {
if dyListTs > 0 {
if v.ActionTime >= dyListTs && v.ActionTime < lastTime {
actList = append(actList, v)
actAids = append(actAids, v.Aid)
}
} else {
if v.ActionTime < lastTime {
actList = append(actList, v)
actAids = append(actAids, v.Aid)
}
}
}
switch v.Type {
case _dyTypeCoin:
coinTs = v.ActionTime
case _dyTypeLike:
likeTs = v.ActionTime
}
}
if coinTs > lastCoinTs {
hasCoin = true
}
if likeTs > lastLikeTs {
hasLike = true
}
if arcsReply, err := s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: actAids}); err != nil {
log.Error("DynamicList s.arcClient.Arcs(%v) error(%v)", actAids, err)
} else {
for _, v := range actList {
if arc, ok := arcsReply.Arcs[v.Aid]; ok && arc != nil && arc.IsNormal() {
video := new(model.VideoItem)
video.FromArchive(arc)
video.ActionTime = v.ActionTime
list = append(list, &model.DyItem{Type: v.Type, Archive: video, Ctime: v.ActionTime, Privacy: v.Privacy})
}
}
}
return
}
func mergeDyActItem(preList []*model.DyActItem) (mergeList []*model.DyActItem) {
type privacy struct {
Num int
Coin bool
Like bool
}
aidNumMap := make(map[int64]*privacy, len(preList))
aidExist := make(map[int64]struct{}, len(preList))
for _, v := range preList {
if _, exist := aidNumMap[v.Aid]; !exist {
aidNumMap[v.Aid] = new(privacy)
}
aidNumMap[v.Aid].Num++
switch v.Type {
case _dyTypeCoin:
aidNumMap[v.Aid].Coin = v.Privacy
case _dyTypeLike:
aidNumMap[v.Aid].Like = v.Privacy
}
}
for _, v := range preList {
num := aidNumMap[v.Aid].Num
if num > 1 {
if _, ok := aidExist[v.Aid]; !ok {
v.Type = _dyTypeMerge
v.Privacy = aidNumMap[v.Aid].Coin && aidNumMap[v.Aid].Like
mergeList = append(mergeList, v)
}
aidExist[v.Aid] = struct{}{}
} else {
mergeList = append(mergeList, v)
}
}
return
}
func foldDyActItem(list []*model.DyItem) (foldList []*model.DyItem) {
l := len(list)
if l == 0 {
foldList = make([]*model.DyItem, 0)
return
}
if l < _dyFoldNum {
foldList = list
return
}
var preCk bool
for index, v := range list {
if index == 0 {
foldList = append(foldList, v)
continue
}
last := index == l-1
if index >= _dyFoldNum-1 {
_, tpCheck := dyTypeFoldMap[v.Type]
y1, m1, d1 := time.Unix(v.Ctime, 0).Date()
_, preTpCheck := dyTypeFoldMap[list[index-1].Type]
y2, m2, d2 := time.Unix(list[index-1].Ctime, 0).Date()
_, check := dyTypeFoldMap[list[index-2].Type]
y3, m3, d3 := time.Unix(list[index-2].Ctime, 0).Date()
ck := tpCheck && preTpCheck && check && (y1 == y2 && m1 == m2 && d1 == d2) && (y1 == y3 && m1 == m3 && d1 == d3)
// append pre item to fold if ck or preCk
if ck || preCk {
foldList[len(foldList)-1].Fold = append(foldList[len(foldList)-1].Fold, list[index-1])
if last {
foldList[len(foldList)-1].Fold = append(foldList[len(foldList)-1].Fold, v)
}
} else {
foldList = append(foldList, list[index-1])
if last {
foldList = append(foldList, v)
}
}
preCk = ck
}
}
return foldList
}
func (s *Service) coinVideos(c context.Context, vmid int64, pcy bool) (list []*model.DyActItem, err error) {
var (
coinReply *coinmdl.ListReply
aids []int64
)
if coinReply, err = s.coinClient.List(c, &coinmdl.ListReq{Mid: vmid, Business: _businessCoin, Ts: time.Now().Unix()}); err != nil {
log.Error("s.coinClient.List(%d) error(%v)", vmid, err)
return
}
existArcs := make(map[int64]*coinmdl.ModelList, len(coinReply.List))
for _, v := range coinReply.List {
if len(aids) > _coinVideoLimit {
break
}
if _, ok := existArcs[v.Aid]; ok {
continue
}
if v.Aid > 0 {
list = append(list, &model.DyActItem{Aid: v.Aid, Type: _dyTypeCoin, ActionTime: v.Ts, Privacy: pcy})
existArcs[v.Aid] = v
}
}
return
}
func (s *Service) likeVideos(c context.Context, mid int64, pcy bool) (list []*model.DyActItem, err error) {
var (
likes *thumbup.UserTotalLike
ip = metadata.String(c, metadata.RemoteIP)
)
arg := &thumbup.ArgUserLikes{Mid: mid, Business: _businessLike, Pn: 1, Ps: _likeVideoCnt, RealIP: ip}
if likes, err = s.thumbup.UserTotalLike(c, arg); err != nil {
log.Error("s.thumbup.UserTotalLike(%d) error(%v)", mid, err)
return
}
if likes != nil {
for _, v := range likes.List {
if v.MessageID > 0 {
list = append(list, &model.DyActItem{Aid: v.MessageID, Type: _dyTypeLike, ActionTime: int64(v.Time), Privacy: pcy})
}
}
}
return
}
// topDynamic get top dynamic.
func (s *Service) topDynamic(c context.Context, mid int64, qn int) (res *model.DyCard, err error) {
var (
dyID int64
)
if dyID, err = s.dao.TopDynamic(c, mid); err != nil {
return
}
if dyID == 0 {
err = ecode.NothingFound
return
}
if res, err = s.dao.Dynamic(c, mid, dyID, qn); err != nil || res == nil {
log.Error("Dynamic s.dao.Dynamic mid(%d) dyID(%d) error(%v)", mid, dyID, err)
err = ecode.NothingFound
}
return
}
// SetTopDynamic set top dynamic.
func (s *Service) SetTopDynamic(c context.Context, mid, dynamicID int64) (err error) {
var (
dynamic *model.DyCard
preDyID int64
)
if dynamic, err = s.dao.Dynamic(c, mid, dynamicID, _dyDefaultQn); err != nil || dynamic == nil {
log.Error("SetTopDynamic s.dao.Dynamic(%d) error(%v)", dynamicID, err)
return
}
if dynamic.Desc.UID != mid {
err = ecode.RequestErr
return
}
if preDyID, err = s.dao.TopDynamic(c, mid); err != nil {
return
}
if preDyID == dynamicID {
err = ecode.NotModified
return
}
if err = s.dao.AddTopDynamic(c, mid, dynamicID); err == nil {
s.dao.AddCacheTopDynamic(c, mid, dynamicID)
}
return
}
// CancelTopDynamic cancel top dynamic.
func (s *Service) CancelTopDynamic(c context.Context, mid int64, now time.Time) (err error) {
var dyID int64
if dyID, err = s.dao.TopDynamic(c, mid); err != nil {
return
}
if dyID == 0 {
err = ecode.RequestErr
return
}
if err = s.dao.DelTopDynamic(c, mid, now); err == nil {
s.dao.AddCacheTopDynamic(c, mid, -1)
}
return
}

View File

@@ -0,0 +1,25 @@
package service
import (
"context"
"encoding/json"
"testing"
"go-common/app/interface/main/space/model"
"github.com/smartystreets/goconvey/convey"
)
func TestService_DynamicList(t *testing.T) {
convey.Convey("test dynamic list", t, WithService(func(s *Service) {
arg := &model.DyListArg{
Vmid: 908085,
Pn: 1,
Qn: 16,
}
list, err := s.DynamicList(context.Background(), arg)
convey.So(err, convey.ShouldBeNil)
bs, _ := json.Marshal(list)
convey.Println(string(bs))
}))
}

View File

@@ -0,0 +1,107 @@
package service
import (
"context"
"go-common/app/interface/main/space/model"
favmdl "go-common/app/service/main/favorite/model"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
const (
_typeFavAlbum = 2
_typeFavMovie = 2
)
var _emptyArcFavFolder = make([]*favmdl.VideoFolder, 0)
// FavNav get fav info.
func (s *Service) FavNav(c context.Context, mid int64, vmid int64) (res *model.FavNav, err error) {
var (
folder []*favmdl.VideoFolder
plData, topicData, artData *favmdl.Favorites
albumCount, movieCount int
folErr, plErr, topicErr, artErr, albumErr, movieErr error
ip = metadata.String(c, metadata.RemoteIP)
)
group, errCtx := errgroup.WithContext(c)
res = new(model.FavNav)
// video fav folder
if mid == vmid || s.privacyCheck(c, vmid, model.PcyFavVideo) == nil {
group.Go(func() error {
if folder, folErr = s.dao.FavFolder(errCtx, mid, vmid); folErr != nil {
log.Error("s.dao.FavFolder(%d) error(%v)", vmid, folErr)
} else {
res.Archive = folder
}
return nil
})
}
// playlist
group.Go(func() error {
arg := &favmdl.ArgFavs{Type: favmdl.TypePlayList, Mid: vmid, Pn: _samplePn, Ps: _samplePs, RealIP: ip}
if plData, plErr = s.fav.Favorites(errCtx, arg); plErr != nil {
log.Error("s.fav.Favorites TypePlayVideo (%d) error(%v)", vmid, plErr)
} else if plData != nil {
res.Playlist = plData.Page.Count
}
return nil
})
// topic
group.Go(func() error {
arg := &favmdl.ArgFavs{Type: favmdl.TypeTopic, Mid: vmid, Pn: _samplePn, Ps: _samplePs, RealIP: ip}
if topicData, topicErr = s.fav.Favorites(errCtx, arg); topicErr != nil {
log.Error("s.fav.Favorites TypeTopic (%d) error(%v)", vmid, topicErr)
} else if topicData != nil {
res.Topic = topicData.Page.Count
}
return nil
})
// article
group.Go(func() error {
arg := &favmdl.ArgFavs{Type: favmdl.Article, Mid: vmid, Pn: _samplePn, Ps: _samplePs, RealIP: ip}
if artData, artErr = s.fav.Favorites(errCtx, arg); artErr != nil {
log.Error("s.fav.Favorites Article (%d) error(%v)", vmid, artErr)
} else if artData != nil {
res.Article = artData.Page.Count
}
return nil
})
// album
group.Go(func() error {
if albumCount, albumErr = s.dao.LiveFavCount(errCtx, vmid, _typeFavAlbum); albumErr != nil {
log.Error("s.dao.LiveFavCount(%d,%d) error(%v)", vmid, _typeFavAlbum, albumErr)
} else if albumCount > 0 {
res.Album = albumCount
}
return nil
})
// movie
if mid > 0 {
group.Go(func() error {
if movieCount, movieErr = s.dao.MovieFavCount(errCtx, mid, _typeFavMovie); movieErr != nil {
log.Error("s.dao.MovieFavCount(%d,%d) error(%v)", vmid, _typeFavMovie, movieErr)
} else if movieCount > 0 {
res.Movie = movieCount
}
return nil
})
}
group.Wait()
if len(res.Archive) == 0 {
res.Archive = _emptyArcFavFolder
}
return
}
// FavArchive get favorite archive.
func (s *Service) FavArchive(c context.Context, mid int64, arg *model.FavArcArg) (res *favmdl.SearchArchive, err error) {
if mid != arg.Vmid {
if err = s.privacyCheck(c, arg.Vmid, model.PcyFavVideo); err != nil {
return
}
}
return s.dao.FavArchive(c, mid, arg)
}

View File

@@ -0,0 +1,35 @@
package service
import (
"context"
"testing"
"go-common/app/interface/main/space/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_FavNav(t *testing.T) {
Convey("test fav nav", t, WithService(func(s *Service) {
vmid := int64(24598781)
mid := int64(0)
data, err := s.FavNav(context.Background(), mid, vmid)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}
func TestService_FavArchive(t *testing.T) {
Convey("test fav archive", t, WithService(func(s *Service) {
mid := int64(0)
arg := &model.FavArcArg{
Vmid: 908085,
Fid: 629658,
Pn: 1,
Ps: 20,
}
data, err := s.FavArchive(context.Background(), mid, arg)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}

View File

@@ -0,0 +1,48 @@
package service
import (
"context"
"go-common/app/interface/main/space/model"
)
var (
_emptyGameList = make([]*model.Game, 0)
_emptyAppGameList = make([]*model.AppGame, 0)
)
// LastPlayGame get last play game by mid
func (s *Service) LastPlayGame(c context.Context, mid, vmid int64) (data []*model.Game, err error) {
if mid != vmid {
if err = s.privacyCheck(c, vmid, model.PcyGame); err != nil {
return
}
}
if data, err = s.dao.LastPlayGame(c, vmid); err != nil {
err = nil
data = _emptyGameList
return
}
if len(data) == 0 {
data = _emptyGameList
}
return
}
// AppPlayedGame get app played games.
func (s *Service) AppPlayedGame(c context.Context, mid, vmid int64, platform string, pn, ps int) (data []*model.AppGame, count int, err error) {
if mid != vmid {
if err = s.privacyCheck(c, vmid, model.PcyGame); err != nil {
return
}
}
if data, count, err = s.dao.AppPlayedGame(c, vmid, platform, pn, ps); err != nil {
err = nil
data = _emptyAppGameList
return
}
if len(data) == 0 {
data = _emptyAppGameList
}
return
}

View File

@@ -0,0 +1,89 @@
package service
import (
"context"
"encoding/json"
"html/template"
"strings"
"go-common/app/interface/main/space/model"
accmdl "go-common/app/service/main/account/model"
"go-common/library/ecode"
"go-common/library/log"
)
const _noticeTable = "member_up_notice"
// Notice get notice.
func (s *Service) Notice(c context.Context, mid int64) (res string, err error) {
if _, ok := s.noNoticeMids[mid]; ok {
return
}
var notice *model.Notice
if notice, err = s.dao.Notice(c, mid); err != nil {
return
}
if notice.IsForbid == _noticeForbid {
notice.Notice = ""
}
res = template.HTMLEscapeString(notice.Notice)
return
}
// SetNotice set notice.
func (s *Service) SetNotice(c context.Context, mid int64, notice string) (err error) {
var (
info *accmdl.Profile
preData *model.Notice
)
if info, err = s.realName(c, mid); err != nil {
return
}
if info.Silence == _silenceForbid {
err = ecode.UserDisabled
return
}
if preData, err = s.dao.Notice(c, mid); err != nil {
return
}
if notice == preData.Notice {
err = ecode.NotModified
return
}
if err = s.dao.SetNotice(c, mid, notice); err != nil {
log.Error("s.dao.SetNotice(%d,%s) error(%v)", mid, notice, err)
return
}
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheNotice(c, mid, &model.Notice{Notice: notice})
})
return
}
// ClearCache del match and object cache
func (s *Service) ClearCache(c context.Context, msg string) (err error) {
var m struct {
Table string `json:"table"`
Old struct {
Mid int64 `json:"mid"`
Notice string `json:"notice"`
IsForbid int `json:"is_forbid"`
} `json:"old,omitempty"`
New struct {
Mid int64 `json:"mid"`
Notice string `json:"notice"`
IsForbid int `json:"is_forbid"`
} `json:"new,omitempty"`
}
if err = json.Unmarshal([]byte(msg), &m); err != nil || m.Table == "" {
log.Error("ClearCache json.Unmarshal msg(%s) error(%v)", msg, err)
return
}
log.Info("ClearCache json.Unmarshal msg(%s)", msg)
if strings.HasPrefix(m.Table, _noticeTable) && (m.Old.IsForbid != m.New.IsForbid || m.Old.Notice != m.New.Notice) {
if err = s.dao.DelCacheNotice(c, m.New.Mid); err != nil {
log.Error("s.dao.DelCacheNotice mid(%d) error(%v)", m.New.Mid, err)
}
}
return
}

View File

@@ -0,0 +1,26 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Notice(t *testing.T) {
Convey("test notice", t, WithService(func(s *Service) {
mid := int64(883968)
data, err := s.Notice(context.Background(), mid)
So(err, ShouldBeNil)
Printf("%v", data)
}))
}
func TestService_SetNotice(t *testing.T) {
Convey("test set notice", t, WithService(func(s *Service) {
mid := int64(883968)
notice := ""
err := s.SetNotice(context.Background(), mid, notice)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,138 @@
package service
import (
"context"
"time"
"go-common/app/interface/main/space/conf"
"go-common/app/interface/main/space/dao"
tagrpc "go-common/app/interface/main/tag/rpc/client"
artrpc "go-common/app/interface/openplatform/article/rpc/client"
accclient "go-common/app/service/main/account/api"
accwar "go-common/app/service/main/account/api"
accmdl "go-common/app/service/main/account/model"
arcclient "go-common/app/service/main/archive/api"
assrpc "go-common/app/service/main/assist/rpc/client"
coinclient "go-common/app/service/main/coin/api"
favrpc "go-common/app/service/main/favorite/api/gorpc"
fltrpc "go-common/app/service/main/filter/rpc/client"
member "go-common/app/service/main/member/api/gorpc"
"go-common/app/service/main/relation/rpc/client"
thumbup "go-common/app/service/main/thumbup/rpc/client"
upclient "go-common/app/service/main/up/api/v1"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/pipeline/fanout"
)
// Service service struct.
type Service struct {
c *conf.Config
dao *dao.Dao
// rpc
art *artrpc.Service
ass *assrpc.Service
tag *tagrpc.Service
filter *fltrpc.Service
fav *favrpc.Service
thumbup *thumbup.Service
relation *relation.Service
member *member.Service
// grpc
accClient accwar.AccountClient
arcClient arcclient.ArchiveClient
coinClient coinclient.CoinClient
upClient upclient.UpClient
// cache proc
cache *fanout.Fanout
// noNoticeMids
noNoticeMids map[int64]struct{}
BlacklistValue map[int64]struct{}
}
// New new service.
func New(c *conf.Config) *Service {
s := &Service{
c: c,
dao: dao.New(c),
art: artrpc.New(c.ArticleRPC),
ass: assrpc.New(c.AssistRPC),
tag: tagrpc.New2(c.TagRPC),
fav: favrpc.New2(c.FavoriteRPC),
filter: fltrpc.New(c.FilterRPC),
thumbup: thumbup.New(c.ThumbupRPC),
relation: relation.New(c.RelationRPC),
member: member.New(c.MemberRPC),
cache: fanout.New("cache"),
}
var err error
if s.accClient, err = accclient.NewClient(c.AccClient); err != nil {
panic(err)
}
if s.arcClient, err = arcclient.NewClient(c.ArcClient); err != nil {
panic(err)
}
if s.coinClient, err = coinclient.NewClient(c.CoinClient); err != nil {
panic(err)
}
if s.upClient, err = upclient.NewClient(c.UpClient); err != nil {
panic(err)
}
s.initMids()
go s.loadBlacklist()
return s
}
// Ping ping service
func (s *Service) Ping(c context.Context) (err error) {
if err = s.dao.Ping(c); err != nil {
log.Error("s.dao.Ping error(%v)", err)
}
return
}
func (s *Service) initMids() {
tmp := make(map[int64]struct{}, len(s.c.Rule.NoNoticeMids))
for _, id := range s.c.Rule.NoNoticeMids {
tmp[id] = struct{}{}
}
s.noNoticeMids = tmp
}
func (s *Service) realName(c context.Context, mid int64) (profile *accmdl.Profile, err error) {
var reply *accwar.ProfileReply
if reply, err = s.accClient.Profile3(c, &accwar.MidReq{Mid: mid}); err != nil || reply == nil {
log.Error("s.accClient.Profile3(%d) error(%v)", mid, err)
return
}
profile = reply.Profile
if !s.c.Rule.RealNameOn {
return
}
if profile.Identification == 0 && profile.TelStatus == 0 {
err = ecode.UserCheckNoPhone
return
}
if profile.Identification == 0 && profile.TelStatus == 2 {
err = ecode.UserCheckInvalidPhone
return
}
return
}
func (s *Service) privacyCheck(c context.Context, vmid int64, field string) (err error) {
privacy := s.privacy(c, vmid)
if value, ok := privacy[field]; !ok || value != _defaultPrivacy {
err = ecode.SpaceNoPrivacy
return
}
return
}
// loadBlacklist load spack blacklist
func (s *Service) loadBlacklist() {
for {
time.Sleep(time.Duration(conf.Conf.Rule.BlackFre))
s.Blacklist(context.Background())
}
}

View File

@@ -0,0 +1,24 @@
package service
import (
"flag"
"path/filepath"
"time"
"go-common/app/interface/main/space/conf"
"go-common/library/log"
)
var svf *Service
func WithService(f func(s *Service)) func() {
return func() {
dir, _ := filepath.Abs("../cmd/space-test.toml")
flag.Set("conf", dir)
conf.Init()
log.Init(conf.Conf.Log)
svf = New(conf.Conf)
time.Sleep(200 * time.Millisecond)
f(svf)
}
}

View File

@@ -0,0 +1,180 @@
package service
import (
"context"
"encoding/json"
"strconv"
"strings"
"go-common/app/interface/main/space/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
const _defaultPrivacy = 1
// SettingInfo get setting info.
func (s *Service) SettingInfo(c context.Context, mid int64) (data *model.Setting, err error) {
data = new(model.Setting)
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
data.Privacy = s.privacy(errCtx, mid)
return nil
})
group.Go(func() error {
data.IndexOrder = s.indexOrder(errCtx, mid)
return nil
})
group.Wait()
return
}
// PrivacyModify privacy modify.
func (s *Service) PrivacyModify(c context.Context, mid int64, field string, value int) (err error) {
privacy := s.privacy(c, mid)
for k, v := range privacy {
if field == k && value == v {
err = ecode.NotModified
return
}
}
if err = s.dao.PrivacyModify(c, mid, field, value); err == nil {
s.dao.DelPrivacyCache(c, mid)
}
return
}
// PrivacyBatchModify privacy batch modify.
func (s *Service) PrivacyBatchModify(c context.Context, mid int64, data map[string]int) (err error) {
group, errCtx := errgroup.WithContext(c)
for k, v := range data {
field := k
value := v
group.Go(func() error {
if e := s.PrivacyModify(errCtx, mid, field, value); e != nil {
log.Warn("PrivacyBatchModify mid(%d) filed(%s) value(%d) error(%v)", mid, field, value, e)
}
return nil
})
}
group.Wait()
return
}
// IndexOrderModify index order modify
func (s *Service) IndexOrderModify(c context.Context, mid int64, orderNum []string) (err error) {
var orderStr []byte
if orderStr, err = json.Marshal(orderNum); err != nil {
log.Error("index order modify json.Marshal(%v) error(%v)", orderNum, err)
err = ecode.RequestErr
return
}
if err = s.dao.IndexOrderModify(c, mid, string(orderStr)); err == nil {
s.cache.Do(c, func(c context.Context) {
var cacheData []*model.IndexOrder
for _, v := range orderNum {
i, _ := strconv.Atoi(v)
cacheData = append(cacheData, &model.IndexOrder{ID: i, Name: model.IndexOrderMap[i]})
}
s.dao.SetIndexOrderCache(c, mid, cacheData)
})
}
return
}
func (s *Service) privacy(c context.Context, mid int64) (data map[string]int) {
var (
privacy map[string]int
err error
addCache = true
)
if data, err = s.dao.PrivacyCache(c, mid); err != nil {
addCache = false
} else if data != nil {
return
}
if privacy, err = s.dao.Privacy(c, mid); err != nil || len(privacy) == 0 {
data = model.DefaultPrivacy
} else {
data = fmtPrivacy(privacy)
}
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetPrivacyCache(c, mid, data)
})
}
return
}
func (s *Service) indexOrder(c context.Context, mid int64) (data []*model.IndexOrder) {
var (
indexOrderStr string
err error
addCache = true
)
if data, err = s.dao.IndexOrderCache(c, mid); err != nil {
addCache = false
} else if len(data) != 0 {
return
}
if indexOrderStr, err = s.dao.IndexOrder(c, mid); err != nil || indexOrderStr == "" {
data = model.DefaultIndexOrder
} else {
orderNum := make([]string, 0)
if err = json.Unmarshal([]byte(indexOrderStr), &orderNum); err != nil {
log.Error("indexOrder mid(%d) json.Unmarshal(%s) error(%v)", mid, indexOrderStr, err)
addCache = false
s.cache.Do(c, func(c context.Context) {
s.fixIndexOrder(c, mid, indexOrderStr)
})
data = model.DefaultIndexOrder
} else {
extraOrder := make(map[int]string)
for _, v := range orderNum {
if index, err := strconv.Atoi(v); err != nil {
continue
} else if name, ok := model.IndexOrderMap[index]; ok {
data = append(data, &model.IndexOrder{ID: index, Name: name})
extraOrder[index] = name
}
}
for i, v := range model.IndexOrderMap {
if _, ok := extraOrder[i]; !ok {
data = append(data, &model.IndexOrder{ID: i, Name: v})
}
}
}
}
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetIndexOrderCache(c, mid, data)
})
}
return
}
func fmtPrivacy(privacy map[string]int) (data map[string]int) {
data = make(map[string]int, len(model.PrivacyFields))
for _, v := range model.PrivacyFields {
if value, ok := privacy[v]; ok {
data[v] = value
} else {
data[v] = _defaultPrivacy
}
}
return
}
func (s *Service) fixIndexOrder(c context.Context, mid int64, indexOrderStr string) {
fixStr := strings.Replace(strings.TrimRight(strings.TrimLeft(indexOrderStr, "["), "]"), "\"", "", -1)
fixArr := strings.Split(fixStr, ",")
fixByte, err := json.Marshal(fixArr)
if err != nil {
log.Error("fixIndexOrder mid(%d) indexOrder(%s) error(%v)", mid, indexOrderStr, err)
return
}
if err := s.dao.IndexOrderModify(c, mid, string(fixByte)); err == nil {
s.dao.DelIndexOrderCache(c, mid)
}
}

View File

@@ -0,0 +1,48 @@
package service
import (
"context"
"encoding/json"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_SettingInfo(t *testing.T) {
Convey("test setting info", t, WithService(func(s *Service) {
mid := int64(88889018)
data, err := s.SettingInfo(context.Background(), mid)
So(err, ShouldBeNil)
var str []byte
str, err = json.Marshal(data)
So(err, ShouldBeNil)
Printf("%+v", string(str))
}))
}
func TestService_IndexOrderModify(t *testing.T) {
Convey("test index order modify", t, WithService(func(s *Service) {
mid := int64(88889018)
orderNum := []string{"1", "8", "7", "2", "3", "4", "5", "6", "9", "21", "22", "23", "24", "25"}
err := s.IndexOrderModify(context.Background(), mid, orderNum)
So(err, ShouldBeNil)
}))
}
func TestService_PrivacyModify(t *testing.T) {
Convey("test index order modify", t, WithService(func(s *Service) {
mid := int64(88889018)
field := "bangumi"
value := 0
err := s.PrivacyModify(context.Background(), mid, field, value)
So(err, ShouldBeNil)
}))
}
func TestService_fixIndexOrder(t *testing.T) {
Convey("test fixIndexOrder", t, WithService(func(s *Service) {
mid := int64(88889018)
indexOrder := `["1","3","2","5","6","4",7,21,22,23,24,25]`
s.fixIndexOrder(context.Background(), mid, indexOrder)
}))
}

View File

@@ -0,0 +1,12 @@
package service
import (
"context"
"go-common/app/interface/main/space/model"
)
// ShopInfo get shop info.
func (s *Service) ShopInfo(c context.Context, mid int64) (data *model.ShopInfo, err error) {
return s.dao.ShopInfo(c, mid)
}

View File

@@ -0,0 +1,33 @@
package service
import (
"context"
"go-common/app/interface/main/space/model"
)
// TagSub subscribe tag.
func (s *Service) TagSub(c context.Context, mid, tid int64) error {
return s.dao.TagSub(c, mid, tid)
}
// TagCancelSub cancel subscribe tag.
func (s *Service) TagCancelSub(c context.Context, mid, tid int64) error {
return s.dao.TagCancelSub(c, mid, tid)
}
// TagSubList get tag subscribe list by mid.
func (s *Service) TagSubList(c context.Context, mid, vmid int64, pn, ps int) (rs []*model.Tag, total int, err error) {
if mid != vmid {
if err = s.privacyCheck(c, vmid, model.PcyTag); err != nil {
return
}
}
if rs, total, err = s.dao.TagSubList(c, vmid, pn, ps); err != nil {
return
}
if len(rs) == 0 {
rs = make([]*model.Tag, 0)
}
return
}

View File

@@ -0,0 +1,21 @@
package service
import (
"testing"
"context"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_TagSubList(t *testing.T) {
Convey("test sub list", t, WithService(func(s *Service) {
mid := int64(0)
vmid := int64(908085)
pn := 1
ps := 10
data, count, err := s.TagSubList(context.Background(), mid, vmid, pn, ps)
So(err, ShouldBeNil)
Printf("%+v,%d", data, count)
}))
}