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,21 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/main/dm/cmd:all-srcs",
"//app/interface/main/dm/conf:all-srcs",
"//app/interface/main/dm/dao:all-srcs",
"//app/interface/main/dm/http:all-srcs",
"//app/interface/main/dm/model:all-srcs",
"//app/interface/main/dm/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,421 @@
### dm的Gateway服务
#### Version 3.18.2
> 1. fix dmid =0
#### Version 3.18.1
> 1. remove cache.Cache
#### Version 3.18.0
> 1. account service使用grpc
#### Version 3.17.12
> 1. 修改创作中心弹幕举报排序字段
#### Version 3.17.11
> 1. 创作中心弹幕举报增加排序
#### Version 3.17.10
> 1. 修复up主弹幕保护时的bug
#### Version 3.17.9
> 1. 未处理的弹幕审核不发送通知的
#### Version 3.17.8
> 1. 弹幕举报稿件搜索添加二审
#### Version 3.17.7
> 1. rebuild master
#### Version 3.17.6
> 1. 弹幕举报deleted字段更新
> 2. 获取稿件信息去除多余代码
#### Version 3.17.5
> 1. up主处理举报弹幕验证owner
#### Version 3.17.4
> 1. 弹幕举报结果为空不返回null
#### Version 3.17.3
> 1. 弹幕举报稿件以及更新接口对接搜索v3
#### Version 3.17.2
> 1. 移除视频维度的屏蔽词
#### Version 3.17.1
> 1. rebuild master
#### Version 3.17.0
> 1. 切换identify 为auth和verify
#### Version 3.16.4
> 1. fix rows.Err()
#### Version 3.16.3
> 1. 弹幕举报搜索使用sdk v3
#### Version 3.16.2
> 1. 修复保护弹幕不能举报的bug
> 2. 移除DMOld结构体
#### Version 3.16.1
> 1. 使用公共配置
#### Version 3.16.0
> 1. 弹幕举报对接搜索新索引
> 2. 优化部分notify相关代码
> 3. 移除多余http client
#### Version 3.15.3
> 1. 重新构建master
#### Version 3.15.2
> 1. 修复弹幕转移的bug
#### Version 3.15.1
> 1. 变更弹幕转移时目标视频不存在时的提示信息
#### Version 3.15.0
> 1. 移除无用的接口
#### Version 3.14.4
> 1. 修复弹幕举报隐藏恢复
#### Version 3.14.3
> 1. 修复弹幕保护列表接口
#### Version 3.14.2
> 1. 高级弹幕购买需要参数优化
> 2. 高级弹幕相关接口RPC调用结构体优化
> 3. user filter列表RPC调用结构体优化
#### Version 3.14.1
> 1. remove cors handler
#### Version 3.14.0
> 1. http接口迁移bm
> 2. 移除协管无用接口
#### Version 3.13.18
> 1. 用户屏蔽词增加接口增加防刷
#### Version 3.13.17
> 1. 修复弹幕转移的bug
#### Version 3.13.16
> 1. 修改弹幕转移状态变量名
#### Version 3.13.15
> 1. 修改隐藏时间为20h
#### Version 3.13.14
> 1. 使用弹幕主题表中的mid
#### Version 3.13.13
> 1. 修复弹幕状态修改参数传错bug
#### Version 3.13.12
> 1. fix archiveinfos 批量100请求
#### Version 3.13.11
> 1. global filter 因为没有数据http层直接return空
#### Version 3.13.10
> 1. 修复up主拉黑用户cid为空的bug
#### Version 3.13.9
> 1. 根据举报有效分自动删除或隐藏弹幕
#### Version 3.13.8
> 1. 协管保护弹幕直接调RPC.EditDMAttr
#### Version 3.13.7
> 1. dm_subject新增字段
#### Version 3.13.6
> 1. 添加举报有效分
#### Version 3.13.5
> 1. 高级弹幕购买迁移dm -> dm2
#### Version 3.13.4
> 1. up主屏蔽编辑时增加oid
#### Version 3.13.3
> 1. 彻底移除表dm_index_filter
#### Version 3.13.2
> 1. 迁移main目录
#### Version 3.13.1
> 1. 屏蔽词迁移至dm2服务
#### Version 3.13.0
> 1. up 主屏蔽词重构
#### Version 3.12.6
> 1. 使用account-service v7
#### Version 3.12.5
> 1. 修复用户撤回判断弹幕逻辑
#### Version 3.12.4
> 1. 修改高级弹幕列表限制
#### Version 3.12.3
> 1. 弹幕举报新增举报理由
#### Version 3.12.2
> 1. 修复弹幕转移导致的panic
#### Version 3.12.1
> 1. test 去除 simplejson 依赖
> 1. 修改弹幕状态和弹幕池接口调用
> 2. 获取若干dao层数据获取sql
#### Version 3.12.0
> 1. 将变更弹幕状态、变更弹幕池相关方法都转向dm2
> 2. 弹幕撤回临时先传up主mid
#### Version 3.11.9
> 1. 修复 cache.Save context
#### Version 3.11.8
> 1. 优化弹幕日志接口
#### Version 3.11.7
> 1. 弹幕转移日志和重试接口
#### Version 3.11.6
> 1. 高级弹幕请求信息中 url 修改
#### Version 3.11.5
> 1. 高级弹幕申请列表优化
#### Version 3.11.4
> 1. up主添加屏蔽词验证正则
#### Version 3.11.3
> 1. 高级弹幕申请列表添加aid
#### Version 3.11.2
> 1. 兼容屏蔽词双份缓存
#### Version 3.11.1
> 1. 兼容filter表脏数据
#### Version 3.11.0
> 1. 调整项目代码结构
#### Version 3.10.6
> 1. 调整弹幕转移部分代码
#### Version 3.10.5
> 1. 修复高级弹幕购买并发问题
> 2. 优化部分代码结构
#### Version 3.10.4
> 1. 移除拒绝高级弹幕购买相关接口
> 2. 修复高级弹幕缓存刷新
#### Version 3.10.3
> 1. 合并dao 层mc
> 2. 接入普罗米休斯
#### Version 3.10.2
> 1. 从dm项目中去除读comment库相关逻辑
> 2. 从稿件获取cid的mid
#### Version 3.10.1
> 1. 屏蔽词列表接口优化
#### Version 3.10.0
> 1. 优化重构部分函数
> 2. 整理冗余model
#### Version 3.9.4
> 1. 更新高级弹幕购买状态接口
#### Version 3.9.3
> 1. remove ecode.NoLogin
#### Version 3.9.2
> 1. 移除单元测试代码(暂时)
#### Version 3.9.2
> 1. 移除无用的最新弹幕消息代码
> 2. 移除rpc server
> 3. 移除refresh index 逻辑
> 4. 移除无用的ugc databus
#### Version 3.9.1
> 1. 修改filter使用的mc
#### Version 3.9.0
> 1. 创作中心屏蔽词列表和修改
#### Version 3.8.12
> 1. change archives2->archives3
#### Version 3.8.11
> 1. 变更弹幕购买提示
#### Version v3.8.10
> 1. Archive2 to Archive3
#### Version 3.8.4
> 1. 修复ecode message="0"的bug
#### Version 3.8.3
> 1. 弹幕自动删除条件限制
#### Version 3.8.2
> 1. 修复mysql使用
#### Version 3.8.1
> 1. 弹幕转移添加重试逻辑
#### Version 3.8.0
> 1.迁移大仓库
#### Version 3.7.9
> 1.高级弹幕购买重构
#### Version 3.7.7
> 1. 创作中心up主弹幕举报显示一二审理由
#### Version 3.7.6
> 1. remove mysql stmt
#### Version 3.7.5
> 1. 修复global filter rule 空缓存穿透
#### Version 3.7.4
> 1. 升级基础库
> 2. fix memcached链接泄露
#### Version 3.7.3
> 1. 修复协管日志
#### Version 3.7.2
> 1. 修改协日志
> 2. 修改添加up主屏蔽接口
#### Version 3.7.1
> 1. 自动删除时发信息的bug修复
#### Version 3.7.0
> 1. 弹幕举报超过10次自动删除
#### Version 3.6.2
> 1. 使用go-common/cache包进行异步缓存回刷屏蔽词缓存
> 2. 增加一些单元测试
#### Version 3.6.1
> 1. 修复一些错误日志
#### Version 3.6.0
> 1. 协管
#### Version 3.5.1
> 1. 修复弹幕保护由于sql关键字导致的错误
#### Version 3.5.0
> 1. 加入普罗米修斯监控
> 2. 接入logagent
> 3. 修复go-common中的一个bug
> 4. 弹幕已举报后重复举报则状态不再改变
#### Version 3.4.3
> 1. 修复弹幕撤回一个BUG
> 2. 普罗米休息监控
> 3. logagent
#### Version 3.3
> 1. 弹幕举报根据理由分成一审和二审
#### Version 3.2.12
> 1. 删除推荐弹幕接口
> 2. 删除一些没用的代码
#### Version 3.2.11
> 1. 我的弹幕功能接入搜索
> 2. 删除大量无用代码
#### Version 3.2.10
> 1. 移除实时弹幕大数据过滤
#### Version 3.2.9
> 1. 修复保护弹幕通知的地址错误
#### Version 3.2.8
> 1. 弹幕举报一二审对接搜索修改
#### Version 3.2.7
> 1. 更新正则解析器
> 2. 下线弹幕云推荐的功能
#### Version 3.2.6
> 1. 修复 up 主最新弹幕中存在的 bug
> 2. 限定正则屏蔽词解析的次数,防止出现无限解析的 bug
#### Version 3.2.5
> 1. 弹幕举报一二审
#### Version 3.2.4
> 1. 移除屏蔽词中使用的select for update的SQL语句
> 2. 变更配置文件,弹幕保护写市北主库
#### Version 3.2.3
> 1. 申请保护弹幕
#### Version 3.1.4
> 1. 新增的屏蔽规则已存在时返回屏蔽规则内容
#### Version 3.1.3
> 1. 弹幕实时id增加过期时间
> 2. 弹幕云屏蔽的参数配置通过配置文件设定
> 3. 当从cache层获取屏蔽规则出错时不再直接返回-500而是尝试从db load数据
#### Version 3.1.2
> 1. 禁止重复添加用户id到云屏蔽
#### Version 3.1.1
> 1. 升级go-business
#### Version 3.1.0
> 1. 修复屏蔽词可以重复添加的bug
> 2. 修复屏蔽词内容为空的bug
> 3. 更新go-common go-business
#### Version 3.0.6
> 1. 增加弹幕云屏蔽相关功能
> 2. 增加稿件弹幕计数功能,将弹幕计数写入hbase
> 3. 增加弹幕信息查询接口
#### Version 3.0.3
> 1. 实时过虑添加白名单配置cid不走推荐弹幕和过虑弹幕。
#### Version 3.0.2
> 1. hbase里面没有推荐弹幕直接从redis读取弹幕ID如果不够从DB中补充<实时弹幕ID
#### Version 3.0.1
> 1. 支持up主最近弹幕
> 2. 支持没有推荐弹幕时实时过虑弹幕从DB中加载
#### Version 3.0.0
> 1.redis保存最近cid弹幕ID
> 2.hbase中获取大数据推荐弹幕ID
> 3.通过redis弹幕ID和hbase弹幕ID从数据库中获取弹幕内容

View File

@@ -0,0 +1,12 @@
# Owner
liangkai
renwei
# Author
liangkai
renwei
guhao
# Reviewer
liangkai
guhao

View File

@@ -0,0 +1,17 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- guhao
- liangkai
- renwei
labels:
- interface
- interface/main/dm
- main
options:
no_parent_owners: true
reviewers:
- guhao
- liangkai
- renwei
- renyashun

View File

@@ -0,0 +1,5 @@
### dm的api服务
##### 项目说明
1. 封装弹幕服务相关的接口

View File

@@ -0,0 +1,44 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["dm-test.toml"],
importpath = "go-common/app/interface/main/dm/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/dm/conf:go_default_library",
"//app/interface/main/dm/http:go_default_library",
"//app/interface/main/dm/service:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace: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"],
)

View File

@@ -0,0 +1,168 @@
# This is a TOML config file.
[httpClient]
key = "53e2fa226f5ad348"
secret = "3cf6bd1b0ff671021da5f424fea4b04a"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpFigure]
infoURL = "http://uat-api.bilibili.co/x/internal/figure/info"
key = "89ffc6e896106fd3"
secret = "1359cdbaf9ff6e2f9b6251579d966101"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
timer = 1000
[httpFigure.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[HTTPServer]
addr = "0.0.0.0:6214"
maxListen = 1000
timeout = "1s"
readTimeout = "800ms"
writeTimeout = "800ms"
[host]
api = "http://uat-api.bilibili.co"
archive = "http://uat-archive.api.bilibili.co"
message = "http://message.bilibili.co"
[db]
[db.dm]
addr = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_dm?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8"
active = 10
idle = 5
idleTimeout ="4h"
queryTimeout = "200ms"
execTimeout = "200ms"
tranTimeout = "200ms"
[db.dm.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.dmMetaReader]
addr = "172.16.33.205:3310"
dsn = "test_3308:test_3308@tcp(172.16.33.205:3310)/bilibili_dm_meta?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8mb4"
active = 10
idle = 5
idleTimeout ="4h"
queryTimeout = "500ms"
execTimeout = "500ms"
tranTimeout = "500ms"
[db.dmMetaReader.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.dmwriter]
addr = "172.16.33.205:3310"
dsn = "test_3308:test_3308@tcp(172.16.33.205:3310)/bilibili_dm_meta?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8mb4"
active = 10
idle = 5
idleTimeout ="4h"
queryTimeout = "500ms"
execTimeout = "500ms"
tranTimeout = "500ms"
[db.dmwriter.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[redis]
[redis.dm]
name = "dm/dm"
proto = "tcp"
addr = "172.16.33.54:6379"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
dmidExpire = "1h"
indexExpire = "1h"
lockExpire = "10s"
videoExpire = "1h"
[archiveRPC]
group = "uat"
timeout = "1s"
[accountRPC]
group = "v7"
timeout = "1s"
[assistRPC]
group="uat"
timeout = "1s"
[dmRPC]
timeout = "1s"
[dmReport]
count = 3
mcKey = "1_6_5"
msgURL = "http://message.bilibili.com/api/notify/send.user.notify.do"
[databus]
key = "170e302355453683"
secret = "51b66df3ebeca2b08f0017f350b6f0ce"
group = "DMReport-MainCommunity-P"
topic = "DMReport-T"
action = "pub"
name = "dm"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 1
active = 5
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
[antispam]
on=true
second=4
n=1
hour=12
m=1000
[antispam.redis]
name = "dm/dm"
proto = "tcp"
addr = "172.16.33.54:6379"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
[es]
host="http://uat-manager.bilibili.co"
[es.httpClient]
key="3c4e41f926e51656"
secret="26a2095b60c24154521d24ae62b885bb"
timeout = "8s"
dial = "1s"

View File

@@ -0,0 +1,56 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/interface/main/dm/conf"
"go-common/app/interface/main/dm/http"
"go-common/app/interface/main/dm/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
// init log
log.Init(conf.Conf.Xlog)
trace.Init(conf.Conf.Tracer)
defer trace.Close()
defer func() {
log.Close()
// wait for a while to guarantee that all log messages are written
time.Sleep(10 * time.Millisecond)
}()
// ecode init
ecode.Init(conf.Conf.Ecode)
// service init
svr := service.New(conf.Conf)
http.Init(conf.Conf, svr)
log.Info("dm start")
// init signal
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("dm get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT:
log.Info("dm exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,46 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/interface/main/dm/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/antispam:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml: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"],
)

View File

@@ -0,0 +1,141 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/elastic"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/antispam"
"go-common/library/net/http/blademaster/middleware/auth"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf export config variable
Conf = &Config{}
)
// Config dm config file
type Config struct {
// base
// ecode
Ecode *ecode.Config
// xlog
Xlog *log.Config
Auth *auth.Config
Verify *verify.Config
// http client
HTTPClient *bm.ClientConfig
ArchiveRPC *rpc.ClientConfig
AccountRPC *warden.ClientConfig
AssistRPC *rpc.ClientConfig
DMRPC *rpc.ClientConfig
// http server
HTTPServer *bm.ServerConfig
// db
DB *DB
// redis
Redis *Redis
// tracer
Tracer *trace.Config
// databus
Databus *databus.Config
// Antispam
Antispam *antispam.Config
Host Host
ES *elastic.Config
}
// Host hosts used in dm admin
type Host struct {
API string
Archive string
Message string
}
// DB mysql database instance
type DB struct {
DM *sql.Config
DMMetaReader *sql.Config
DMWriter *sql.Config
}
// Redis redis instance
type Redis struct {
DM *DMRedis
}
// DMRedis redis instance of dm
type DMRedis struct {
*redis.Config
DMIDExpire time.Duration
LockExpire time.Duration
IndexExpire time.Duration
VideoExpire time.Duration
}
func init() {
flag.StringVar(&confPath, "conf", "", "config path")
}
//Init int config
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,78 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"archive_test.go",
"dao_test.go",
"databus_test.go",
"figure_test.go",
"mysql_protect_test.go",
"mysql_report_test.go",
"mysql_test.go",
"notify_test.go",
"redis_test.go",
"search_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/dm/conf:go_default_library",
"//app/interface/main/dm/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 = [
"archive.go",
"dao.go",
"databus.go",
"figure.go",
"mysql.go",
"mysql_protect.go",
"mysql_report.go",
"notify.go",
"redis.go",
"search.go",
],
importpath = "go-common/app/interface/main/dm/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/dm/conf:go_default_library",
"//app/interface/main/dm/model:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/queue/databus:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/xstr: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"],
)

View File

@@ -0,0 +1,41 @@
package dao
import (
"context"
"fmt"
"net/url"
"go-common/app/interface/main/dm/model"
"go-common/library/log"
)
const (
_cidInfo = "/videoup/cid"
)
func (d *Dao) cidInfoURI() string {
return d.conf.Host.Archive + _cidInfo
}
// CidInfo 获取cid详细信息
func (d *Dao) CidInfo(c context.Context, cid int64) (info *model.CidInfo, err error) {
var (
res = &struct {
Code int `json:"code"`
Data *model.CidInfo `json:"data"`
}{}
params = url.Values{}
uri = d.cidInfoURI()
)
params.Set("cid", fmt.Sprint(cid))
if err = d.httpClient.Get(c, uri, "", params, &res); err != nil {
log.Error("d.httpClient.Get(%s,%v,%d)", uri, params, err)
return
}
if res.Code != 0 {
err = fmt.Errorf("code is:%d", res.Code)
log.Error("d.httpClient.Get(%s,%v,%v,%d)", uri, params, err, res.Code)
return
}
return res.Data, nil
}

View File

@@ -0,0 +1,16 @@
package dao
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestCidInfo(t *testing.T) {
Convey("test cid info", t, func() {
cidInfo, err := testDao.CidInfo(context.TODO(), 10109082)
So(err, ShouldBeNil)
So(cidInfo, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,94 @@
package dao
import (
"context"
"time"
"go-common/app/interface/main/dm/conf"
"go-common/library/cache/redis"
"go-common/library/database/elastic"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/queue/databus"
"go-common/library/stat/prom"
)
var (
missedCount = prom.CacheMiss
cachedCount = prom.CacheHit
)
// Dao dao struct
type Dao struct {
conf *conf.Config
httpClient *bm.Client
// redis
redisDM *redis.Pool
redisDMIDExpire int32
redisLockExpire int32
redisIndexExpire int32
redisVideoExpire int32
// database
dmMetaReader *sql.DB // bilibili_dm_meta
biliDM *sql.DB // blibili_dm
dmWriter *sql.DB
// databus
databus *databus.Databus
// elastic
es *elastic.Elastic
}
// New new a dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
conf: c,
httpClient: bm.NewClient(c.HTTPClient),
// redis
redisDM: redis.NewPool(c.Redis.DM.Config),
redisDMIDExpire: int32(time.Duration(c.Redis.DM.DMIDExpire) / time.Second),
redisLockExpire: int32(time.Duration(c.Redis.DM.LockExpire) / time.Second),
redisIndexExpire: int32(time.Duration(c.Redis.DM.IndexExpire) / time.Second),
redisVideoExpire: int32(time.Duration(c.Redis.DM.VideoExpire) / time.Second),
// database
dmMetaReader: sql.NewMySQL(c.DB.DMMetaReader),
biliDM: sql.NewMySQL(c.DB.DM),
dmWriter: sql.NewMySQL(c.DB.DMWriter),
// databus
databus: databus.New(c.Databus),
// elastic
es: elastic.NewElastic(c.ES),
}
return
}
// PromCacheHit prom cache hit
func PromCacheHit(name string) {
cachedCount.Incr(name)
}
// PromCacheMiss prom cache hit
func PromCacheMiss(name string) {
missedCount.Incr(name)
}
// Ping ping dao status
func (d *Dao) Ping(c context.Context) (err error) {
// dm redis
rds := d.redisDM.Get(c)
defer rds.Close()
if _, err = rds.Do("SET", "ping", "pong"); err != nil {
log.Error("rds.Do(SET) error(%v)", err)
return
}
// database
if err = d.dmMetaReader.Ping(c); err != nil {
log.Error("dmMetaReader.Ping() error(%v)", err)
return
}
if err = d.biliDM.Ping(c); err != nil {
log.Error("biliDM.Ping() error(%v)", err)
return
}
return
}

View File

@@ -0,0 +1,32 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/interface/main/dm/conf"
"go-common/library/log"
)
var testDao *Dao
func TestMain(m *testing.M) {
flag.Set("app_id", "main.community.dm")
flag.Set("conf_token", "4d343dc5d8c33460156baec8913eb64a")
flag.Set("tree_id", "2692")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Xlog)
defer log.Close()
testDao = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,19 @@
package dao
import (
"context"
"go-common/app/interface/main/dm/model"
"go-common/library/log"
)
// SendAction send action to job.
func (d *Dao) SendAction(c context.Context, k string, act *model.ReportAction) (err error) {
if err = d.databus.Send(c, k, act); err != nil {
log.Error("actionPub.Send(data:%v) error(%v)", act, err)
} else {
log.Info("actionPub.Send(action:%v) success", act)
}
return
}

View File

@@ -0,0 +1,27 @@
package dao
import (
"context"
"fmt"
"testing"
"time"
"go-common/app/interface/main/dm/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestSendAction(t *testing.T) {
var (
c = context.TODO()
act = &model.ReportAction{
Cid: int64(10106598),
Did: int64(719918177),
HideTime: time.Now().Unix() + 10,
}
)
Convey("", t, func() {
err := testDao.SendAction(c, fmt.Sprint(act.Cid), act)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,46 @@
package dao
import (
"context"
"fmt"
"net/url"
"go-common/library/log"
)
const (
_codeFigureNotFound = 55001
_figureInfoURL = "/x/internal/figure/info"
)
func (d *Dao) figureInfoURI() string {
return d.conf.Host.API + _figureInfoURL
}
// FigureInfo .
func (d *Dao) FigureInfo(c context.Context, mid int64) (score int32, err error) {
var (
res = &struct {
Code int `json:"code"`
Data *struct {
Percentage int32 `json:"percentage"`
} `json:"data"`
}{}
params = url.Values{}
uri = d.figureInfoURI()
)
params.Set("mid", fmt.Sprint(mid))
if err = d.httpClient.Get(c, uri, "", params, &res); err != nil {
log.Error("d.httpClient.Get(%s,%v,%d)", uri, params, err)
return
}
if res.Code != 0 && res.Code != _codeFigureNotFound {
err = fmt.Errorf("code != 0 && code !=%d", _codeFigureNotFound)
log.Error("d.httpClient.Get(%s,%v,%v,%d)", uri, params, err, res.Code)
return
}
if res != nil && res.Data != nil {
score = res.Data.Percentage
}
return
}

View File

@@ -0,0 +1,35 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaofigureInfoURI(t *testing.T) {
convey.Convey("figureInfoURI", t, func(convCtx convey.C) {
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
p1 := testDao.figureInfoURI()
convCtx.Convey("Then p1 should not be nil.", func(convCtx convey.C) {
convCtx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoFigureInfo(t *testing.T) {
convey.Convey("FigureInfo", t, func(convCtx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
score, err := testDao.FigureInfo(c, mid)
convCtx.Convey("Then err should be nil.score should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(score, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,281 @@
package dao
import (
"context"
"fmt"
"sync"
"go-common/app/interface/main/dm/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/sync/errgroup"
"go-common/library/xstr"
)
const (
_pagesize = 1000
_subjectSharding = 100
_indexSharding = 1000
_contentSharding = 1000
_subSQL = "SELECT id,type,oid,pid,mid,state,attr,acount,count,mcount,move_count,maxlimit,childpool,ctime,mtime FROM dm_subject_%02d WHERE type=? AND oid=?"
_idxSQL = "SELECT id,type,oid,mid,progress,state,pool,attr,ctime,mtime FROM dm_index_%03d WHERE id=? AND oid=? AND type=?"
_idxsByIDSQL = "SELECT id,type,oid,mid,progress,state,pool,attr,ctime,mtime FROM dm_index_%03d WHERE id IN(%s) AND oid=? AND type=?"
_contentSQL = "SELECT dmid,fontsize,color,mode,ip,plat,msg,ctime,mtime FROM dm_content_%03d WHERE dmid=?"
_contentsSQL = "SELECT dmid,fontsize,color,mode,ip,plat,msg,ctime,mtime FROM dm_content_%03d WHERE dmid IN(%s)"
_contentSpeSQL = "SELECT dmid,msg,ctime,mtime FROM dm_special_content WHERE dmid=?"
_contentsSpeSQL = "SELECT dmid,msg,ctime,mtime FROM dm_special_content WHERE dmid IN(%s)"
// dm transfer
_addTransferJob = "INSERT INTO dm_transfer_job SET from_cid=?,to_cid=?,mid=?,offset=?,state=?"
_selTransferJob = "SELECT id,from_cid,to_cid,mid,offset,state,ctime,mtime from dm_transfer_job WHERE from_cid=? AND to_cid=?"
_transferListSQL = "SELECT id,from_cid,state,ctime FROM dm_transfer_job where to_cid=?"
_uptTransferSQL = "UPDATE dm_transfer_job SET state=? WHERE id=?"
_selTransferID = "SELECT id,from_cid,to_cid,mid,offset,state,ctime,mtime from dm_transfer_job WHERE id=?"
//dm state update
_updateIdxStatSQL = "UPDATE dm_index_%03d SET state=? WHERE type=? AND oid=? AND id IN(%s)"
)
func (d *Dao) hitSubject(oid int64) int64 {
return oid % _subjectSharding
}
func (d *Dao) hitIndex(oid int64) int64 {
return oid % _indexSharding
}
func (d *Dao) hitContent(dmid int64) int64 {
return dmid % _contentSharding
}
// Subject get subject info from db.
func (d *Dao) Subject(c context.Context, tp int32, oid int64) (s *model.Subject, err error) {
s = &model.Subject{}
row := d.dmMetaReader.QueryRow(c, fmt.Sprintf(_subSQL, d.hitSubject(oid)), tp, oid)
if err = row.Scan(&s.ID, &s.Type, &s.Oid, &s.Pid, &s.Mid, &s.State, &s.Attr, &s.ACount, &s.Count, &s.MCount, &s.MoveCnt, &s.Maxlimit, &s.Childpool, &s.Ctime, &s.Mtime); err != nil {
if err == sql.ErrNoRows {
s = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// Index get index by dmid
func (d *Dao) Index(c context.Context, tp int32, oid, dmid int64) (dm *model.DM, err error) {
dm = &model.DM{}
row := d.dmMetaReader.QueryRow(c, fmt.Sprintf(_idxSQL, d.hitIndex(oid)), dmid, oid, tp)
if err = row.Scan(&dm.ID, &dm.Type, &dm.Oid, &dm.Mid, &dm.Progress, &dm.State, &dm.Pool, &dm.Attr, &dm.Ctime, &dm.Mtime); err != nil {
if err == sql.ErrNoRows {
dm = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// IndexsByID get dm index by dmids.
func (d *Dao) IndexsByID(c context.Context, tp int32, oid int64, dmids []int64) (res map[int64]*model.DM, special []int64, err error) {
rows, err := d.dmMetaReader.Query(c, fmt.Sprintf(_idxsByIDSQL, d.hitIndex(oid), xstr.JoinInts(dmids)), oid, tp)
if err != nil {
log.Error("db.Query() error(%v)", err)
return
}
defer rows.Close()
res = make(map[int64]*model.DM, len(dmids))
for rows.Next() {
dm := &model.DM{}
if err = rows.Scan(&dm.ID, &dm.Type, &dm.Oid, &dm.Mid, &dm.Progress, &dm.State, &dm.Pool, &dm.Attr, &dm.Ctime, &dm.Mtime); err != nil {
log.Error("row.Scan() error(%v)", err)
return
}
res[dm.ID] = dm
if dm.Pool == model.PoolSpecial {
special = append(special, dm.ID)
}
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// Content dm content by dmid
func (d *Dao) Content(c context.Context, oid, dmid int64) (ct *model.Content, err error) {
ct = &model.Content{}
row := d.dmMetaReader.QueryRow(c, fmt.Sprintf(_contentSQL, d.hitContent(oid)), dmid)
if err = row.Scan(&ct.ID, &ct.FontSize, &ct.Color, &ct.Mode, &ct.IP, &ct.Plat, &ct.Msg, &ct.Ctime, &ct.Mtime); err != nil {
if err == sql.ErrNoRows {
ct = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// Contents multi get dm content by dmids.
func (d *Dao) Contents(c context.Context, oid int64, dmids []int64) (res []*model.Content, err error) {
var (
wg errgroup.Group
lock sync.Mutex
)
pageNum := len(dmids) / _pagesize
if len(dmids)%_pagesize > 0 {
pageNum = pageNum + 1
}
for i := 0; i < pageNum; i++ {
start := i * _pagesize
end := (i + 1) * _pagesize
if end > len(dmids) {
end = len(dmids)
}
wg.Go(func() (err error) {
rows, err := d.dmMetaReader.Query(c, fmt.Sprintf(_contentsSQL, d.hitContent(oid), xstr.JoinInts(dmids[start:end])))
if err != nil {
log.Error("db.Query(%s) error(%v)", fmt.Sprintf(_contentsSQL, d.hitContent(oid), xstr.JoinInts(dmids)), err)
return
}
defer rows.Close()
for rows.Next() {
ct := &model.Content{}
if err = rows.Scan(&ct.ID, &ct.FontSize, &ct.Color, &ct.Mode, &ct.IP, &ct.Plat, &ct.Msg, &ct.Ctime, &ct.Mtime); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
lock.Lock()
res = append(res, ct)
lock.Unlock()
}
err = rows.Err()
return
})
}
if err = wg.Wait(); err != nil {
log.Error("wg.Wait() error(%v)", err)
}
return
}
// ContentSpecial get special dm content by dmids.
func (d *Dao) ContentSpecial(c context.Context, dmid int64) (contentSpe *model.ContentSpecial, err error) {
contentSpe = &model.ContentSpecial{}
row := d.dmMetaReader.QueryRow(c, _contentSpeSQL, dmid)
if err = row.Scan(&contentSpe.ID, &contentSpe.Msg, &contentSpe.Ctime, &contentSpe.Mtime); err != nil {
if err == sql.ErrNoRows {
contentSpe = nil
err = nil
} else {
log.Error("rows.Scan() error(%v)", err)
}
}
return
}
// ContentsSpecial multi get special dm content by dmids.
func (d *Dao) ContentsSpecial(c context.Context, dmids []int64) (res map[int64]*model.ContentSpecial, err error) {
res = make(map[int64]*model.ContentSpecial, len(dmids))
rows, err := d.dmMetaReader.Query(c, fmt.Sprintf(_contentsSpeSQL, xstr.JoinInts(dmids)))
if err != nil {
log.Error("db.Query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
content := &model.ContentSpecial{}
if err = rows.Scan(&content.ID, &content.Msg, &content.Ctime, &content.Mtime); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
res[content.ID] = content
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// AddTransferJob add transfer job.
func (d *Dao) AddTransferJob(c context.Context, fromCid, toCid, mid int64, offset float64, state int8) (affect int64, err error) {
row, err := d.biliDM.Exec(c, _addTransferJob, fromCid, toCid, mid, offset, model.TransferJobStatInit)
if err != nil {
log.Error("d.biliDM.Exec(fromCid:%d,toCid:%d,mid:%d,offset:%v) error(%v)", fromCid, toCid, mid, offset, err)
}
return row.LastInsertId()
}
// CheckTransferJob check transfer job state.
func (d *Dao) CheckTransferJob(c context.Context, fromCid, toCid int64) (job *model.TransferJob, err error) {
job = new(model.TransferJob)
row := d.biliDM.QueryRow(c, _selTransferJob, fromCid, toCid)
if err = row.Scan(&job.ID, &job.FromCID, &job.ToCID, &job.MID, &job.Offset, &job.State, &job.Ctime, &job.Mtime); err != nil {
if err == sql.ErrNoRows {
job = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}
// CheckTransferID check transfer job state by id
func (d *Dao) CheckTransferID(c context.Context, id int64) (job *model.TransferJob, err error) {
job = new(model.TransferJob)
row := d.biliDM.QueryRow(c, _selTransferID, id)
if err = row.Scan(&job.ID, &job.FromCID, &job.ToCID, &job.MID, &job.Offset, &job.State, &job.Ctime, &job.Mtime); err != nil {
if err == sql.ErrNoRows {
job = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}
// TransferList cid 的转移历史
func (d *Dao) TransferList(c context.Context, cid int64) (l []*model.TransferHistory, err error) {
l = make([]*model.TransferHistory, 0)
rows, err := d.biliDM.Query(c, _transferListSQL, cid)
if err != nil {
log.Error("d.biliDM.Query(%s,%d) error(%v)", _transferListSQL, cid, err)
return
}
defer rows.Close()
for rows.Next() {
hs := new(model.TransferHistory)
if err = rows.Scan(&hs.ID, &hs.CID, &hs.State, &hs.CTime); err != nil {
log.Error("TransfrerList: rows.Scan() error(%v)", err)
return
}
l = append(l, hs)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// SetTransferState change transfer state
func (d *Dao) SetTransferState(c context.Context, id int64, state int8) (affect int64, err error) {
row, err := d.biliDM.Exec(c, _uptTransferSQL, state, id)
if err != nil {
log.Error("d.biliDM.Exec(%s,%d) error(%v)", _uptTransferSQL, id, err)
return
}
return row.RowsAffected()
}
// UpdateDMStat edit dm state
func (d *Dao) UpdateDMStat(c context.Context, tp int32, oid int64, state int32, dmids []int64) (affect int64, err error) {
res, err := d.dmWriter.Exec(c, fmt.Sprintf(_updateIdxStatSQL, d.hitIndex(oid), xstr.JoinInts(dmids)), state, tp, oid)
if err != nil {
log.Error("dmWriter.Exec(%s %d) error(%v)", _updateIdxStatSQL, oid, err)
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,258 @@
package dao
import (
"context"
"fmt"
"sort"
"strings"
"time"
"go-common/app/interface/main/dm/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
// dm protect apply
_addProtect = "INSERT INTO dm_protect_apply (cid, uid, apply_uid, aid, playtime, dmid, msg, status, ctime, mtime) VALUES %s"
_selProtect = "SELECT ctime FROM dm_protect_apply WHERE dmid=? ORDER BY id DESC"
_getPrttApply = "SELECT id,cid,apply_uid,aid,playtime,msg,ctime from dm_protect_apply where uid=? %s and status=-1"
_getProtectAids = "SELECT aid FROM dm_protect_apply WHERE uid=? GROUP BY aid"
_paStatus = "UPDATE dm_protect_apply SET status=%d WHERE uid=%d AND id IN (%s)"
_chgPaSwitch = "INSERT INTO dm_protect_up (uid, notice_switch) VALUES(?, ?) ON DUPLICATE KEY UPDATE notice_switch=?"
_getProtectByIDs = "SELECT cid,dmid FROM dm_protect_apply WHERE uid=%d AND id IN (%s)"
_paUsrStat = "SELECT aid,apply_uid,status,ctime from dm_protect_apply where ctime>?"
_paStatistics = "SELECT uid from dm_protect_apply where status=-1 GROUP BY uid"
_paNoticeSwitch = "SELECT uid FROM dm_protect_up WHERE uid IN (%s) AND notice_switch=0"
)
// AddProtectApply 添加保护弹幕申请
func (d *Dao) AddProtectApply(c context.Context, pas []*model.Pa) (affect int64, err error) {
var (
values, s string
)
for _, pa := range pas {
pa.Msg = strings.Replace(pa.Msg, `\`, `\\`, -1)
pa.Msg = strings.Replace(pa.Msg, `'`, `\'`, -1)
values += fmt.Sprintf(`(%d, %d, %d, %d, %f, %d, '%s', %d, '%s', '%s'),`, pa.CID, pa.UID, pa.ApplyUID, pa.AID, pa.Playtime, pa.DMID, pa.Msg, pa.Status, pa.Ctime.Format("2006-01-02 15:04:05"), pa.Mtime.Format("2006-01-02 15:04:05"))
}
if len(values) > 0 {
values = values[0:(len(values) - 1)]
}
s = fmt.Sprintf(_addProtect, values)
res, err := d.biliDM.Exec(c, s)
if err != nil {
log.Error("d.biliDM.Exec(%v) error(%v)", s, err)
return
}
affect, err = res.RowsAffected()
return
}
// ProtectApplyTime 根据dmid获取保护弹幕申请
func (d *Dao) ProtectApplyTime(c context.Context, dmid int64) (t time.Time, err error) {
row := d.biliDM.QueryRow(c, _selProtect, dmid)
if err = row.Scan(&t); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}
// ProtectApplies 保护弹幕申请列表
func (d *Dao) ProtectApplies(c context.Context, uid, aid int64, order string) (res []*model.Apply, err error) {
var (
query string
rows *sql.Rows
)
if aid > 0 {
query = fmt.Sprintf(_getPrttApply, "AND aid=?")
rows, err = d.biliDM.Query(c, query, uid, aid)
} else {
query = fmt.Sprintf(_getPrttApply, "")
rows, err = d.biliDM.Query(c, query, uid)
}
if err != nil {
log.Error("d.biliDM.Query(%s,%v,%v) error(%v)", query, uid, aid, err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.Apply{}
t := time.Time{}
if err = rows.Scan(&r.ID, &r.CID, &r.ApplyUID, &r.AID, &r.Playtime, &r.Msg, &t); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
r.Ctime = t.Format("2006-01-02 15:04:05")
res = append(res, r)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
return
}
if order == "playtime" {
sort.Sort(model.ApplySortPlaytime(res))
} else {
sort.Sort(model.ApplySortID(res))
}
return
}
// ProtectAids 被申请保护弹幕稿件列表
func (d *Dao) ProtectAids(c context.Context, uid int64) (res []int64, err error) {
rows, err := d.biliDM.Query(c, _getProtectAids, uid)
if err != nil {
log.Error("d.biliDM.Query(%s,%d) error(%v)", _getProtectAids, uid, err)
return
}
defer rows.Close()
for rows.Next() {
var aid int64
if err = rows.Scan(&aid); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
res = append(res, aid)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// UptPaStatus 修改保护弹幕状态
func (d *Dao) UptPaStatus(c context.Context, uid int64, ids string, status int) (affect int64, err error) {
s := fmt.Sprintf(_paStatus, status, uid, ids)
res, err := d.biliDM.Exec(c, s)
if err != nil {
log.Error("d.biliDM.Exec(%v) error(%v)", s, err)
}
affect, err = res.RowsAffected()
return
}
// ProtectApplyByIDs get protect apply by dmid
func (d *Dao) ProtectApplyByIDs(c context.Context, uid int64, ids string) (res map[int64][]int64, err error) {
res = make(map[int64][]int64, 10)
s := fmt.Sprintf(_getProtectByIDs, uid, ids)
rows, err := d.biliDM.Query(c, s)
if err != nil {
log.Error("d.biliDM.Query(%s) error(%v)", s, err)
return
}
defer rows.Close()
for rows.Next() {
var (
dmid int64
cid int64
)
if err = rows.Scan(&cid, &dmid); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
_, ok := res[cid]
if ok {
res[cid] = append(res[cid], dmid)
} else {
res[cid] = []int64{dmid}
}
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// UptPaNoticeSwitch 设置申请保护弹幕站内通知开关
func (d *Dao) UptPaNoticeSwitch(c context.Context, uid int64, status int) (affect int64, err error) {
res, err := d.biliDM.Exec(c, _chgPaSwitch, uid, status, status)
if err != nil {
log.Error("d.biliDM.Exec(%s,%d,%d) error(%v)", _chgPaSwitch, status, uid, err)
}
affect, err = res.RowsAffected()
return
}
// PaNoticeClose 获取关闭申请保护弹幕站内通知
func (d *Dao) PaNoticeClose(c context.Context, uids []int64) (res map[int64]bool, err error) {
if len(uids) < 1 {
return
}
res = make(map[int64]bool, len(uids))
s := fmt.Sprintf(_paNoticeSwitch, xstr.JoinInts(uids))
rows, err := d.biliDM.Query(c, s)
if err != nil {
log.Error("d.biliDM.Query(%s) error(%v)", s, err)
return
}
defer rows.Close()
for rows.Next() {
var uid int64
if err = rows.Scan(&uid); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
res[uid] = true
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// ProtectApplyStatistics 保护弹幕申请up统计
func (d *Dao) ProtectApplyStatistics(c context.Context) (res []int64, err error) {
rows, err := d.biliDM.Query(c, _paStatistics)
if err != nil {
log.Error("d.biliDM.Query(%s) error(%v)", _paStatistics, err)
return
}
defer rows.Close()
for rows.Next() {
var uid int64
if err = rows.Scan(&uid); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
res = append(res, uid)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// twoDayAgo22 两天前的22点
func twoDayAgo22() string {
yesterday := time.Now().Add(-48 * time.Hour)
year, month, day := yesterday.Date()
return time.Date(year, month, day, 0, 0, 0, 0, time.Local).Format("2006-01-02") + " 22:00:00"
}
// PaUsrStat 保护弹幕申请用户统计
func (d *Dao) PaUsrStat(c context.Context) (res []*model.ApplyUserStat, err error) {
rows, err := d.biliDM.Query(c, _paUsrStat, twoDayAgo22())
if err != nil {
log.Error("d.biliDM.Query(%s) error(%v)", _paUsrStat, err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.ApplyUserStat{}
if err = rows.Scan(&r.Aid, &r.UID, &r.Status, &r.Ctime); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
res = append(res, r)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}

View File

@@ -0,0 +1,189 @@
package dao
import (
"context"
"go-common/app/interface/main/dm/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAddProtectApply(t *testing.T) {
convey.Convey("AddProtectApply", t, func(convCtx convey.C) {
var (
c = context.Background()
pas = []*model.Pa{
{
ID: 123,
CID: 1,
UID: 1,
},
}
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
affect, err := testDao.AddProtectApply(c, pas)
convCtx.Convey("Then err should be nil.affect should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(affect, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoProtectApplyTime(t *testing.T) {
convey.Convey("ProtectApplyTime", t, func(convCtx convey.C) {
var (
c = context.Background()
dmid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
no, err := testDao.ProtectApplyTime(c, dmid)
convCtx.Convey("Then err should be nil.no should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(no, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoProtectApplies(t *testing.T) {
convey.Convey("ProtectApplies", t, func(convCtx convey.C) {
var (
c = context.Background()
uid = int64(123)
aid = int64(111)
order = ""
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
_, err := testDao.ProtectApplies(c, uid, aid, order)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoProtectAids(t *testing.T) {
convey.Convey("ProtectAids", t, func(convCtx convey.C) {
var (
c = context.Background()
uid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := testDao.ProtectAids(c, uid)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUptPaStatus(t *testing.T) {
convey.Convey("UptPaStatus", t, func(convCtx convey.C) {
var (
c = context.Background()
uid = int64(123)
ids = "123"
status = int(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
affect, err := testDao.UptPaStatus(c, uid, ids, status)
convCtx.Convey("Then err should be nil.affect should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(affect, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoProtectApplyByIDs(t *testing.T) {
convey.Convey("ProtectApplyByIDs", t, func(convCtx convey.C) {
var (
c = context.Background()
uid = int64(123)
ids = "123"
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := testDao.ProtectApplyByIDs(c, uid, ids)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUptPaNoticeSwitch(t *testing.T) {
convey.Convey("UptPaNoticeSwitch", t, func(convCtx convey.C) {
var (
c = context.Background()
uid = int64(0)
status = int(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
affect, err := testDao.UptPaNoticeSwitch(c, uid, status)
convCtx.Convey("Then err should be nil.affect should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(affect, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoPaNoticeClose(t *testing.T) {
convey.Convey("PaNoticeClose", t, func(convCtx convey.C) {
var (
c = context.Background()
uids = []int64{123}
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := testDao.PaNoticeClose(c, uids)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoProtectApplyStatistics(t *testing.T) {
convey.Convey("ProtectApplyStatistics", t, func(convCtx convey.C) {
var (
c = context.Background()
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := testDao.ProtectApplyStatistics(c)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaotwoDayAgo22(t *testing.T) {
convey.Convey("twoDayAgo22", t, func(convCtx convey.C) {
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
p1 := twoDayAgo22()
convCtx.Convey("Then p1 should not be nil.", func(convCtx convey.C) {
convCtx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoPaUsrStat(t *testing.T) {
convey.Convey("PaUsrStat", t, func(convCtx convey.C) {
var (
c = context.Background()
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := testDao.PaUsrStat(c)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,160 @@
package dao
import (
"context"
"fmt"
"go-common/app/interface/main/dm/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_rptSharding = 100
_rptUserSharding = 100
_rptLogSharding = 100
_insertRpt = "INSERT INTO dm_report_%d (cid,dmid,uid,reason,content,count,state,up_op,rp_time,score,ctime,mtime) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)" +
" ON DUPLICATE KEY UPDATE uid=?,reason=?,state=?,content=?,count=count+1,rp_time=?,score=score+?"
_selectRpt = "SELECT id,cid,dmid,uid,reason,content,count,state,up_op,score,rp_time,ctime,mtime FROM dm_report_%d WHERE dmid=?"
_updateRptUPOp = "UPDATE dm_report_%d SET up_op=? WHERE dmid=?"
_updateRpt = "UPDATE dm_report_%d SET state=? WHERE dmid=?"
_insertUser = "INSERT IGNORE INTO dm_report_user_%d (dmid,uid,reason,state,content,ctime,mtime) VALUES(?,?,?,?,?,?,?)"
_selectRptLog = "SELECT id,dmid,adminid,reason,result,remark,elapsed,ctime,mtime FROM dm_report_admin_log_%d WHERE dmid=? ORDER BY mtime"
_insertRptLog = "INSERT INTO dm_report_admin_log_%d (dmid,adminid,reason,result,remark,elapsed) VALUES (?,?,?,?,?,?)"
_selectRptUser = "SELECT id,dmid,uid,reason,state,ctime,mtime FROM dm_report_user_%d WHERE dmid=? AND state=?"
_updateRptUserStat = "UPDATE dm_report_user_%d SET state=? WHERE dmid=? AND state!=?"
)
func rptTable(cid int64) int64 {
return cid % _rptSharding
}
func rptUserTable(dmid int64) int64 {
return dmid % _rptUserSharding
}
// RptLogTable return log table id by dmid
func RptLogTable(dmid int64) int64 {
return dmid % _rptLogSharding
}
// AddReport insert or update dm report.
func (d *Dao) AddReport(c context.Context, rpt *model.Report) (id int64, err error) {
res, err := d.biliDM.Exec(c, fmt.Sprintf(_insertRpt, rptTable(rpt.Cid)), rpt.Cid, rpt.Did, rpt.UID, rpt.Reason, rpt.Content, rpt.Count, rpt.State, rpt.UpOP, rpt.RpTime, rpt.Score, rpt.Ctime, rpt.Mtime, rpt.UID, rpt.Reason, rpt.State, rpt.Content, rpt.RpTime, rpt.Score)
if err != nil {
log.Error("d.AddReport(%v) error(%v)", rpt, err)
return
}
return res.LastInsertId()
}
// AddReportUser add dm report user.
func (d *Dao) AddReportUser(c context.Context, u *model.User) (id int64, err error) {
res, err := d.biliDM.Exec(c, fmt.Sprintf(_insertUser, rptUserTable(u.Did)), u.Did, u.UID, u.Reason, u.State, u.Content, u.Ctime, u.Mtime)
if err != nil {
log.Error("d.AddReportUser(%v) error(%v)", u, err)
return
}
return res.LastInsertId()
}
// ReportLog get report log of dmid.
func (d *Dao) ReportLog(c context.Context, dmid int64) (res []*model.RptLog, err error) {
rows, err := d.biliDM.Query(c, fmt.Sprintf(_selectRptLog, RptLogTable(dmid)), dmid)
if err != nil {
log.Error("d.ReportLog(dmid:%d) error(%v)", dmid, err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.RptLog{}
if err = rows.Scan(&r.ID, &r.Did, &r.AdminID, &r.Reason, &r.Result, &r.Remark, &r.Elapsed, &r.Ctime, &r.Mtime); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
res = append(res, r)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// Report dm report info by cid and dmid.
func (d *Dao) Report(c context.Context, cid, dmid int64) (rpt *model.Report, err error) {
rpt = &model.Report{}
row := d.biliDM.QueryRow(c, fmt.Sprintf(_selectRpt, rptTable(cid)), dmid)
err = row.Scan(&rpt.ID, &rpt.Cid, &rpt.Did, &rpt.UID, &rpt.Reason, &rpt.Content, &rpt.Count, &rpt.State, &rpt.UpOP, &rpt.Score, &rpt.RpTime, &rpt.Ctime, &rpt.Mtime)
if err != nil {
if err == sql.ErrNoRows {
rpt = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// UpdateReportStat update report state
func (d *Dao) UpdateReportStat(c context.Context, cid, dmid int64, state int8) (affect int64, err error) {
sqlStr := fmt.Sprintf(_updateRpt, rptTable(cid))
res, err := d.biliDM.Exec(c, sqlStr, state, dmid)
if err != nil {
log.Error("d.UpdateReportStat(cid:%d, dmid:%d) error(%v)", cid, dmid, err)
return
}
return res.RowsAffected()
}
// UpdateReportUPOp update dm report state.
func (d *Dao) UpdateReportUPOp(c context.Context, cid, dmid int64, op int8) (affect int64, err error) {
res, err := d.biliDM.Exec(c, fmt.Sprintf(_updateRptUPOp, rptTable(cid)), op, dmid)
if err != nil {
log.Error("d.UpdateReportUPOp(cid:%d, dmid:%d) error(%v)", cid, dmid, err)
return
}
return res.RowsAffected()
}
// AddReportLog add report log.
func (d *Dao) AddReportLog(c context.Context, lg *model.RptLog) (err error) {
sqlStr := fmt.Sprintf(_insertRptLog, RptLogTable(lg.Did))
_, err = d.biliDM.Exec(c, sqlStr, lg.Did, lg.AdminID, lg.Reason, lg.Result, lg.Remark, lg.Elapsed)
if err != nil {
log.Error("d.AddReportLog(%v) error(%v)", lg, err)
}
return
}
// ReportUser return report use list of dmid.
func (d *Dao) ReportUser(c context.Context, dmid int64) (users []*model.User, err error) {
sqlStr := fmt.Sprintf(_selectRptUser, rptUserTable(dmid))
rows, err := d.biliDM.Query(c, sqlStr, dmid, model.NoticeUnsend)
if err != nil {
log.Error("d.ReportUser(query:%s, dmid:%d) error(%v)", sqlStr, dmid, err)
return
}
defer rows.Close()
for rows.Next() {
u := &model.User{}
if err = rows.Scan(&u.ID, &u.Did, &u.UID, &u.Reason, &u.State, &u.Ctime, &u.Mtime); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
users = append(users, u)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// SetReportUserFinished set dmid state to be noticesend.
func (d *Dao) SetReportUserFinished(c context.Context, dmid int64) (err error) {
sqlStr := fmt.Sprintf(_updateRptUserStat, rptUserTable(dmid))
if _, err = d.biliDM.Exec(c, sqlStr, model.NoticeSend, dmid, model.NoticeSend); err != nil {
log.Error("d.SetReportUserFinished(sql:%s, dmid:%d) error(%v)", sqlStr, dmid, err)
}
return
}

View File

@@ -0,0 +1,198 @@
package dao
import (
"context"
"testing"
"go-common/app/interface/main/dm/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaorptTable(t *testing.T) {
convey.Convey("rptTable", t, func(convCtx convey.C) {
var (
cid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
p1 := rptTable(cid)
convCtx.Convey("Then p1 should not be nil.", func(convCtx convey.C) {
convCtx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaorptUserTable(t *testing.T) {
convey.Convey("rptUserTable", t, func(convCtx convey.C) {
var (
dmid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
p1 := rptUserTable(dmid)
convCtx.Convey("Then p1 should not be nil.", func(convCtx convey.C) {
convCtx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRptLogTable(t *testing.T) {
convey.Convey("RptLogTable", t, func(convCtx convey.C) {
var (
dmid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
p1 := RptLogTable(dmid)
convCtx.Convey("Then p1 should not be nil.", func(convCtx convey.C) {
convCtx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoAddReport(t *testing.T) {
convey.Convey("AddReport", t, func(convCtx convey.C) {
var (
c = context.Background()
rpt = &model.Report{}
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
id, err := testDao.AddReport(c, rpt)
convCtx.Convey("Then err should be nil.id should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoAddReportUser(t *testing.T) {
convey.Convey("AddReportUser", t, func(convCtx convey.C) {
var (
c = context.Background()
u = &model.User{}
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
id, err := testDao.AddReportUser(c, u)
convCtx.Convey("Then err should be nil.id should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoReportLog(t *testing.T) {
convey.Convey("ReportLog", t, func(convCtx convey.C) {
var (
c = context.Background()
dmid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
res, err := testDao.ReportLog(c, dmid)
convCtx.Convey("Then err should be nil.res should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoReport(t *testing.T) {
convey.Convey("Report", t, func(convCtx convey.C) {
var (
c = context.Background()
cid = int64(0)
dmid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
rpt, err := testDao.Report(c, cid, dmid)
convCtx.Convey("Then err should be nil.rpt should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(rpt, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUpdateReportStat(t *testing.T) {
convey.Convey("UpdateReportStat", t, func(convCtx convey.C) {
var (
c = context.Background()
cid = int64(0)
dmid = int64(0)
state = int8(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
affect, err := testDao.UpdateReportStat(c, cid, dmid, state)
convCtx.Convey("Then err should be nil.affect should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(affect, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUpdateReportUPOp(t *testing.T) {
convey.Convey("UpdateReportUPOp", t, func(convCtx convey.C) {
var (
c = context.Background()
cid = int64(0)
dmid = int64(0)
op = int8(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
affect, err := testDao.UpdateReportUPOp(c, cid, dmid, op)
convCtx.Convey("Then err should be nil.affect should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
convCtx.So(affect, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoAddReportLog(t *testing.T) {
convey.Convey("AddReportLog", t, func(convCtx convey.C) {
var (
c = context.Background()
lg = &model.RptLog{}
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
err := testDao.AddReportLog(c, lg)
convCtx.Convey("Then err should be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoReportUser(t *testing.T) {
convey.Convey("ReportUser", t, func(convCtx convey.C) {
var (
c = context.Background()
dmid = int64(123)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
_, err := testDao.ReportUser(c, dmid)
convCtx.Convey("Then err should be nil.users should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSetReportUserFinished(t *testing.T) {
convey.Convey("SetReportUserFinished", t, func(convCtx convey.C) {
var (
c = context.Background()
dmid = int64(0)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
err := testDao.SetReportUserFinished(c, dmid)
convCtx.Convey("Then err should be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,141 @@
package dao
import (
"context"
"testing"
"go-common/app/interface/main/dm/model"
)
func TestSubject(t *testing.T) {
var (
c = context.TODO()
tp int32 = 1
oid int64 = 1221
)
s, err := testDao.Subject(c, tp, oid)
if err != nil {
t.Error(err)
}
if s == nil {
t.Logf("oid:%d subject not exist", oid)
} else {
t.Logf("subject:%+v", s)
}
}
func TestIndex(t *testing.T) {
var (
c = context.TODO()
tp int32 = 1
oid int64 = 1221
dmid int64 = 719150137
)
dm, err := testDao.Index(c, tp, oid, dmid)
if err != nil {
t.Error(err)
}
if dm == nil {
t.Logf("dmid:%d not exist", dmid)
} else {
t.Logf("dm:%+v", dm)
}
}
func TestIndexsByID(t *testing.T) {
var (
c = context.TODO()
tp int32 = 1
oid int64 = 1221
dmids = []int64{719150137, 719150230, 719150141}
)
res, special, err := testDao.IndexsByID(c, tp, oid, dmids)
if err != nil {
t.Error(err)
}
for _, dm := range res {
t.Logf("dm:%+v", dm)
}
t.Logf("special:%+v", special)
}
func TestContent(t *testing.T) {
var (
c = context.TODO()
oid int64 = 1221
dmid int64 = 719150137
)
ct, err := testDao.Content(c, oid, dmid)
if err != nil {
t.Error(err)
}
if ct == nil {
t.Logf("content:%d not exist", dmid)
} else {
t.Logf("content:%+v", ct)
}
}
func TestContents(t *testing.T) {
var (
c = context.TODO()
oid int64 = 1221
dmids = []int64{719150137, 719150230, 719150141}
)
res, err := testDao.Contents(c, oid, dmids)
if err != nil {
t.Error(err)
}
for _, ct := range res {
t.Logf("content:%+v", ct)
}
}
func TestContentSpecial(t *testing.T) {
var (
c = context.TODO()
dmid int64 = 719150141
)
cs, err := testDao.ContentSpecial(c, dmid)
if err != nil {
t.Error(err)
}
t.Logf("content special:%+v", cs)
}
func TestContentsSpecial(t *testing.T) {
var (
c = context.TODO()
dmids = []int64{719150141, 719150141}
)
res, err := testDao.ContentsSpecial(c, dmids)
if err != nil {
t.Error(err)
}
for _, cs := range res {
t.Logf("content special:%+v", cs)
}
}
func TestCheckTransferJob(t *testing.T) {
var (
from, to int64 = 10108765, 10108763
)
job, err := testDao.CheckTransferJob(context.TODO(), from, to)
if err != nil {
t.Fatal(err)
}
t.Log(job)
}
func TestAddTransferJob(t *testing.T) {
var (
from, to, mid int64 = 10108765, 10108763, 27515615
offset = 1.00
state = model.TransferJobStatInit
)
_, err := testDao.AddTransferJob(context.TODO(), from, to, mid, offset, state)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,46 @@
package dao
import (
"context"
"errors"
"net/url"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_notifyDataType = "4" // 消息类型1、回复我的2、@我3、收到的爱4、业务通知
_notifyURL = "/api/notify/send.user.notify.do"
_notifyMC = "1_8_2"
)
func (d *Dao) notifyURI() string {
return d.conf.Host.Message + _notifyURL
}
// SendNotify 发送站内信
func (d *Dao) SendNotify(c context.Context, title, content string, mids []int64) (err error) {
res := struct {
Code int `json:"code"`
Data struct {
TotalCount int
ErrorCount int
} `json:"data"`
}{}
params := url.Values{}
params.Set("mc", _notifyMC)
params.Set("title", title)
params.Set("data_type", _notifyDataType)
params.Set("context", content)
params.Set("mid_list", xstr.JoinInts(mids))
if err = d.httpClient.Post(c, d.notifyURI(), "", params, &res); err != nil {
log.Error("d.httpClient.Post(%s,%v,%d)", d.notifyURI(), params, err)
return
}
if res.Code != 0 {
err = errors.New("code != 0")
log.Error("d.httpClient.Post(%s,%v,%v,%d)", d.notifyURI(), params, err, res.Code)
}
return
}

View File

@@ -0,0 +1,36 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaonotifyURI(t *testing.T) {
convey.Convey("notifyURI", t, func(convCtx convey.C) {
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
p1 := testDao.notifyURI()
convCtx.Convey("Then p1 should not be nil.", func(convCtx convey.C) {
convCtx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoSendNotify(t *testing.T) {
convey.Convey("SendNotify", t, func(convCtx convey.C) {
var (
c = context.Background()
title = ""
content = ""
mids = []int64{1}
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
err := testDao.SendNotify(c, title, content, mids)
convCtx.Convey("Then err should be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,264 @@
package dao
import (
"context"
"strconv"
"time"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_rptCnt = "rc_"
_rptBrig = "rb_"
_prfxPaUsrCntKey = "pa_user_count_"
_prfxUdAccCntKey = "usr_dm_acc_cnt_"
_prfxRecallCntKey = "recall_cnt_"
_crontabRedisLock = "crontab_redis_lock"
_crontabRedisLockExpire = 2 * 3600
)
// tomorrowUnixTime 明天unix time
func tomorrowUnixTime() int64 {
tomorrow := time.Now().Add(24 * time.Hour)
year, month, day := tomorrow.Date()
return time.Date(year, month, day, 0, 0, 0, 0, time.Local).Unix()
}
// paUsrCntKey 用户申请保护弹幕计数 redis key
func keyProtectApplyCmt() string {
return _prfxPaUsrCntKey + time.Now().Format("20060102")
}
func keyRptCnt() string {
return _rptCnt + time.Now().Format("04")
}
func keyRptBrig(mid int64) string {
return _rptBrig + strconv.FormatInt(mid, 10)
}
func keyRecallCnt() string {
return _prfxRecallCntKey + time.Now().Format("20060102")
}
// UptUsrPaCnt 设置申请保护弹幕数
func (d *Dao) UptUsrPaCnt(c context.Context, uid int64, count int64) (err error) {
var (
key, expire = keyProtectApplyCmt(), tomorrowUnixTime()
conn = d.redisDM.Get(c)
)
defer conn.Close()
if err = conn.Send("ZINCRBY", key, count, uid); err != nil {
log.Error("conn.Send(ZADD,%s,%d,%d) error(%v)", key, count, uid, err)
return
}
if err = conn.Send("EXPIREAT", key, expire); err != nil {
log.Error("conn.Send(EXPIREAT key(%s) expire(%d)) error(%v)", key, expire, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
return
}
}
return
}
// PaUsrCnt 保护弹幕申请计数
func (d *Dao) PaUsrCnt(c context.Context, uid int64) (cnt int, err error) {
var (
key = keyProtectApplyCmt()
conn = d.redisDM.Get(c)
)
defer conn.Close()
if cnt, err = redis.Int(conn.Do("ZSCORE", key, uid)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(ZSCORE, %s,%d) error(%v)", key, uid, err)
}
}
return
}
// UsrDMAccCnt 我的弹幕访问计数
func (d *Dao) UsrDMAccCnt(c context.Context, uid int64, t int64) (cnt int64, err error) {
var (
key = _prfxUdAccCntKey + strconv.FormatInt(uid, 10)
conn = d.redisDM.Get(c)
)
defer conn.Close()
if cnt, err = redis.Int64(conn.Do("INCRBY", key, t)); err != nil {
log.Error("conn.Do(INCRBY, %s,%d) error(%v)", key, t, err)
return
}
if cnt != t {
return
}
_, err = redis.Int(conn.Do("EXPIREAT", key, t+5))
if err != nil {
log.Error("conn.Do(EXPIREAT, %s,%d) error(%v)", key, t+5, err)
}
return
}
// RecallCnt 撤回弹幕计数
func (d *Dao) RecallCnt(c context.Context, uid int64) (cnt int, err error) {
var (
key = keyRecallCnt()
conn = d.redisDM.Get(c)
)
defer conn.Close()
if cnt, err = redis.Int(conn.Do("ZSCORE", key, uid)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("redis.Int(conn.Do(GET, %s,%d)) error(%v)", key, uid, err)
}
}
return
}
// UptRecallCnt 更新撤回弹幕计数
func (d *Dao) UptRecallCnt(c context.Context, uid int64) (err error) {
var (
key = keyRecallCnt()
conn = d.redisDM.Get(c)
)
defer conn.Close()
if err = conn.Send("ZINCRBY", key, 1, uid); err != nil {
log.Error("conn.Send(ZINCRBY, %s,%d) error(%v)", key, 1, err)
return
}
if err = conn.Send("EXPIRE", key, 3600*24); err != nil {
log.Error("conn.Send(EXPIRE, %s,%d) error(%v)", key, 3600*24, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush() error(%v)", err)
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// PaLock redis定时任务锁保证只有一个地方在执行定时任务
func (d *Dao) PaLock(c context.Context, key string) (incr int, err error) {
var (
conn = d.redisDM.Get(c)
r interface{}
)
key = _crontabRedisLock + key
defer conn.Close()
if err = conn.Send("INCRBY", key, 1); err != nil {
log.Error("conn.Send(INCRBY,%s) error(%v)", key, err)
return
}
if err = conn.Send("EXPIRE", key, _crontabRedisLockExpire); err != nil {
log.Error("conn.Send(EXPIRE key(%s) expire(%d)) error(%v)", key, _crontabRedisLockExpire, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
if r, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
return
}
if incr, err = redis.Int(r, err); err != nil {
log.Error("redis.Int error(%v)", err)
return
}
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
}
return
}
// RptCnt 弹幕举报一分钟计数
func (d *Dao) RptCnt(c context.Context, uid int64) (n int, err error) {
var (
k = keyRptCnt()
conn = d.redisDM.Get(c)
)
if n, err = redis.Int(conn.Do("ZSCORE", k, uid)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(ZSCORE, %s,%d) error(%v)", k, uid, err)
}
}
conn.Close()
return
}
// UptRptCnt 更新一分钟的弹幕举报数
func (d *Dao) UptRptCnt(c context.Context, uid int64) (n int64, err error) {
var (
k = keyRptCnt()
conn = d.redisDM.Get(c)
)
defer conn.Close()
if err = conn.Send("ZINCRBY", k, 1, uid); err != nil {
log.Error("conn.Send(ZINCRBY, %s,%d) error(%v)", k, 1, err)
return
}
if err = conn.Send("EXPIRE", k, 60); err != nil {
log.Error("conn.Send(EXPIRE, %s,%d) error(%v)", k, 60, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush() error(%v)", err)
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// AddRptBrig 将用户禁闭30分钟不让举报
func (d *Dao) AddRptBrig(c context.Context, mid int64) (err error) {
var (
k = keyRptBrig(mid)
conn = d.redisDM.Get(c)
)
if _, err = conn.Do("SETEX", k, 1800, time.Now().Unix()); err != nil {
log.Error("conn.Do(SETEX, %s,%d) error(%v)", k, 1, err)
}
conn.Close()
return
}
// RptBrigTime 获得禁闭的开始时间
func (d *Dao) RptBrigTime(c context.Context, mid int64) (t int64, err error) {
var (
k = keyRptBrig(mid)
conn = d.redisDM.Get(c)
)
if t, err = redis.Int64(conn.Do("GET", k)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(GET, %s,%d) error(%v)", k, 1, err)
}
}
conn.Close()
return
}

View File

@@ -0,0 +1,59 @@
package dao
import (
"context"
"testing"
)
func TestUptUsrPaCnt(t *testing.T) {
err := testDao.UptUsrPaCnt(context.TODO(), 1234356789, 1)
if err != nil {
t.Fatal(err)
}
}
func TestPaUsrCnt(t *testing.T) {
cnt, err := testDao.PaUsrCnt(context.TODO(), 1234356789)
if err != nil {
t.Fatal(err)
}
if cnt == 0 {
t.Fatal("pa usr cnt err")
}
}
func TestUsrDMAccCnt(t *testing.T) {
n, err := testDao.UsrDMAccCnt(context.TODO(), 1234356789, 1)
if err != nil {
t.Fatal(err)
}
if n == 0 {
t.Fatal("usr dm acc cnt err")
}
}
func TestUptRecallCnt(t *testing.T) {
err := testDao.UptRecallCnt(context.TODO(), 1234356789)
if err != nil {
t.Fatal(err)
}
}
func TestRecallCnt(t *testing.T) {
n, err := testDao.RecallCnt(context.TODO(), 1234356789)
if err != nil {
t.Fatal(err)
}
if n == 0 {
t.Fatal("usr dm acc cnt err")
}
}
func TestPaLock(t *testing.T) {
incr, err := testDao.PaLock(context.TODO(), "go-test")
if err != nil {
t.Fatal(err)
}
if incr < 1 {
t.Fatal("PaLock err")
}
}

View File

@@ -0,0 +1,85 @@
package dao
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/interface/main/dm/model"
"go-common/library/database/elastic"
"go-common/library/log"
)
// return recent two years report search index.
func (d *Dao) rptSearchIndex() string {
year := time.Now().Year()
return fmt.Sprintf("dmreport_%d,dmreport_%d", year-1, year)
}
// SearchReportAid 根据mid获取用户的所有有举报弹幕的稿件
func (d *Dao) SearchReportAid(c context.Context, mid int64, upOp int8, states []int8, pn, ps int64) (aids []int64, err error) {
res := new(model.SearchReportAidResult)
order := []map[string]string{{"arc_aid": "desc"}}
req := d.es.NewRequest("dmreport").Fields("arc_aid").Index(d.rptSearchIndex())
req.WhereEq("arc_mid", mid).WhereEq("up_op", upOp).WhereIn("state", states).GroupBy(elastic.EnhancedModeGroupBy, "arc_aid", order)
req.Pn(int(pn)).Ps(int(ps))
if err = req.Scan(c, res); err != nil {
log.Error("search params(%s), err(%v)", req.Params(), err)
return
}
if values, ok := res.Result["group_by_arc_aid"]; ok {
for _, v := range values {
var aid int64
if aid, err = strconv.ParseInt(v.Key, 10, 64); err != nil {
log.Error("strconv.ParseInt(%s) error(%v)", v.Key, err)
return
}
aids = append(aids, aid)
}
}
return
}
// SearchReport 根据up主id,稿件id获取举报弹幕列表
func (d *Dao) SearchReport(c context.Context, mid, aid, pn, ps int64, upOp int8, states []int64) (res *model.SearchReportResult, err error) {
req := d.es.NewRequest("dmreport")
req.Fields("id", "dmid", "cid", "arc_aid", "arc_typeid", "dm_owner_uid", "dm_msg", "count", "content", "up_op", "state",
"uid", "rp_time", "reason", "dm_deleted", "arc_mid", "pool_id", "model", "score", "dm_ctime", "ctime", "mtime")
req.Index(d.rptSearchIndex())
if aid > 0 {
req.WhereEq("arc_aid", aid)
}
if mid > 0 {
req.WhereEq("arc_mid", mid)
}
if len(states) > 0 {
req.WhereIn("state", states)
}
req.WhereNot(elastic.NotTypeEq, "dm_owner_uid").WhereEq("dm_owner_uid", 0)
req.WhereEq("up_op", upOp)
req.Order("rp_time", "desc")
req.Pn(int(pn)).Ps(int(ps))
res = &model.SearchReportResult{}
if err = req.Scan(c, res); err != nil {
log.Error("req.Scan() search params(%s), err(%v)", req.Params(), err)
}
return
}
// UpdateSearchReport update report search index.
func (d *Dao) UpdateSearchReport(c context.Context, rpts []*model.UptSearchReport) (err error) {
up := d.es.NewUpdate("dmreport").Insert() // if data not exist insert,else update
for _, rpt := range rpts {
t, err1 := time.ParseInLocation("2006-01-02 15:04:05", rpt.Ctime, time.Local)
if err1 != nil {
log.Error("time.ParseInLocation(%s) error(%v)", rpt.Ctime, err1)
return err1
}
up.AddData(fmt.Sprintf("dmreport_%d", t.Year()), rpt)
}
if err = up.Do(c); err != nil {
log.Error("update.Do() error(%v)", err)
}
return
}

View File

@@ -0,0 +1,67 @@
package dao
import (
"context"
"testing"
"go-common/app/interface/main/dm/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestRptSearchIndex(t *testing.T) {
Convey("", t, func() {
s := testDao.rptSearchIndex()
So(s, ShouldNotBeEmpty)
t.Log(s)
})
}
func TestSearchReport(t *testing.T) {
var (
c = context.TODO()
// mid, aid, pn, ps int64 = 432230, 9548327, 1, 20 //pre
mid, aid, pn, ps int64 = 27515615, 10100087, 1, 20
upOp int8 = 2
states = []int64{0, 2}
)
Convey("", t, func() {
res, err := testDao.SearchReport(c, mid, aid, pn, ps, upOp, states)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
t.Logf("%+v", res.Page)
for _, v := range res.Result {
t.Logf("%+v", v)
}
})
}
func TestSearchReportAid(t *testing.T) {
var (
c = context.TODO()
mid, pn, ps int64 = 27515256, 1, 20
upOp int8
state = []int8{0, 2}
)
Convey("", t, func() {
aids, err := testDao.SearchReportAid(c, mid, upOp, state, pn, ps)
So(err, ShouldBeNil)
t.Logf("%+v", aids)
})
}
func TestUptSearchReport(t *testing.T) {
var (
c = context.TODO()
upt = &model.UptSearchReport{
DMid: 1958334770970627,
Upop: 0,
Ctime: "2018-07-06 09:20:57",
Mtime: "2018-07-27 19:20:50",
}
)
Convey("", t, func() {
err := testDao.UpdateSearchReport(c, []*model.UptSearchReport{upt})
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"adv_test.go",
"http_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"adv.go",
"assist.go",
"dm.go",
"filter.go",
"http.go",
"report.go",
"up.go",
],
importpath = "go-common/app/interface/main/dm/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/dm/conf:go_default_library",
"//app/interface/main/dm/model:go_default_library",
"//app/interface/main/dm/service:go_default_library",
"//app/interface/main/dm2/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/antispam:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/xstr: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"],
)

View File

@@ -0,0 +1,116 @@
package http
import (
"strconv"
"go-common/app/interface/main/dm2/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// buyAdv 购买高级弹幕
func buyAdv(c *bm.Context) {
p := c.Request.Form
mid, _ := c.Get("mid")
cid, err := strconv.ParseInt(p.Get("cid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
mode := p.Get("mode")
if mode == "" || (mode != model.AdvSpeMode && mode != model.AdvMode) {
c.JSON(nil, ecode.RequestErr)
return
}
if err = dmSvc.BuyAdvance(c, mid.(int64), cid, mode); err != nil {
c.JSON(nil, err)
log.Error("dmSvc.BuyAdvance(mid:%v,cid:%d,mode:%s) error(%v)", mid, cid, mode, err)
return
}
res := map[string]interface{}{}
res["message"] = "已成功购买"
c.JSONMap(res, err)
}
// advState 高级弹幕状态
func advState(c *bm.Context) {
p := c.Request.Form
mid, _ := c.Get("mid")
cid, err := strconv.ParseInt(p.Get("cid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
mode := p.Get("mode")
if mode == "" {
c.JSON(nil, ecode.RequestErr)
return
}
state, err := dmSvc.AdvanceState(c, mid.(int64), cid, mode)
if err != nil {
c.JSON(nil, err)
log.Error("dmSvc.AdvState(%v,%d,%s) error(%v)", mid, cid, mode, err)
return
}
c.JSON(state, err)
}
// advList 高级弹幕列表
func advList(c *bm.Context) {
mid, _ := c.Get("mid")
list, err := dmSvc.Advances(c, mid.(int64))
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(list, err)
}
// passAdv 通过高级弹幕
func passAdv(c *bm.Context) {
var (
err error
id int64
params = c.Request.Form
)
mid, _ := c.Get("mid")
if id, err = strconv.ParseInt(params.Get("id"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
err = dmSvc.PassAdvance(c, mid.(int64), id)
c.JSON(nil, err)
}
// denyAdv 拒绝高级弹幕
func denyAdv(c *bm.Context) {
var (
err error
id int64
params = c.Request.Form
)
mid, _ := c.Get("mid")
if id, err = strconv.ParseInt(params.Get("id"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
err = dmSvc.DenyAdvance(c, mid.(int64), id)
c.JSON(nil, err)
}
// cancelAdv 取消高级弹幕
func cancelAdv(c *bm.Context) {
var (
err error
id int64
params = c.Request.Form
)
mid, _ := c.Get("mid")
if id, err = strconv.ParseInt(params.Get("id"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
err = dmSvc.CancelAdvance(c, mid.(int64), id)
c.JSON(nil, err)
}

View File

@@ -0,0 +1,132 @@
package http
import (
"crypto/md5"
"encoding/hex"
"fmt"
"net/url"
"strconv"
"testing"
"time"
)
func Test_advBuy(t *testing.T) {
params := url.Values{}
params.Set("cid", "3786607")
params.Set("mode", "sp")
s := _host + "/x/dm/adv/buy?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func Test_advStat(t *testing.T) {
params := url.Values{}
params.Set("cid", "3786607")
params.Set("mode", "sp")
s := _host + "/x/dm/adv/state?" + params.Encode()
body, err := cget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// Test_advPass list
func Test_advList(t *testing.T) {
params := url.Values{}
params.Set("mid", "27515260")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _innerHost + "/x/internal/dm/adv/list?" + params.Encode()
body, err := oget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// Test_advPass list
func Test_advPass(t *testing.T) {
params := url.Values{}
params.Set("mid", "13444")
params.Set("id", "8")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _innerHost + "/x/internal/dm/adv/pass?" + params.Encode()
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// Test_advDeny list
func Test_advDeny(t *testing.T) {
params := url.Values{}
params.Set("mid", "13444")
params.Set("id", "8")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _innerHost + "/x/internal/dm/adv/deny?" + params.Encode()
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// Test_advCancel list
func Test_advCancel(t *testing.T) {
params := url.Values{}
params.Set("mid", "13444")
params.Set("id", "8")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _innerHost + "/x/internal/dm/adv/cancel?" + params.Encode()
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}

View File

@@ -0,0 +1,129 @@
package http
import (
"strconv"
"strings"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
// assistBanned 添加up主屏蔽
func assistBanned(c *bm.Context) {
var (
err error
cid int64
dmids []int64
params = c.Request.Form
)
mid, _ := c.Get("mid")
cid, err = strconv.ParseInt(params.Get("cid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if params.Get("dmids") == "" {
c.JSON(nil, ecode.RequestErr)
return
}
if dmids, err = xstr.SplitInts(params.Get("dmids")); err != nil {
log.Error("xstr.SplitInts(%s) error(%v)", params.Get("dmids"), err)
return
}
err = dmSvc.AssistBanned(c, mid.(int64), cid, dmids)
c.JSON(nil, err)
}
// assistBannedUpt 修改up主屏蔽状态
func assistBannedUpt(c *bm.Context) {
var (
err error
hash string
stat int
params = c.Request.Form
)
mid, _ := c.Get("mid")
if hash = params.Get("hash"); hash == "" {
c.JSON(nil, ecode.RequestErr)
return
}
if stat, err = strconv.Atoi(params.Get("stat")); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
err = dmSvc.AssistUptBanned(c, mid.(int64), hash, int8(stat))
c.JSON(nil, err)
}
// assistDelete 协管删除弹幕
func assistDelete(c *bm.Context) {
var (
mid, _ = c.Get("mid")
params = c.Request.Form
)
cid, err := strconv.ParseInt(params.Get("cid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if params.Get("dmids") == "" {
c.JSON(nil, ecode.RequestErr)
return
}
dmids, err := xstr.SplitInts(params.Get("dmids"))
if err != nil || len(dmids) == 0 {
c.JSON(nil, ecode.RequestErr)
return
}
err = dmSvc.AssistDeleteDM(c, mid.(int64), cid, dmids)
c.JSON(nil, err)
}
// assistBannedUsers 获取UP主屏蔽的用户列表
func assistBannedUsers(c *bm.Context) {
var (
err error
aid int64
hashes []string
params = c.Request.Form
)
mid, _ := c.Get("mid")
aid, err = strconv.ParseInt(params.Get("aid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
hashes, err = dmSvc.AssistBannedUsers(c, mid.(int64), aid)
if err != nil {
c.JSON(nil, err)
log.Error("dmSvc.AssistBannedUsers(%v,%d) error(%v)", mid, aid, err)
return
}
c.JSON(hashes, nil)
}
// AssistDelBanned2 批量撤销up主屏蔽
func AssistDelBanned2(c *bm.Context) {
var (
err error
aid int64
hashes []string
params = c.Request.Form
)
mid, _ := c.Get("mid")
aid, err = strconv.ParseInt(params.Get("aid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if params.Get("hashes") == "" {
c.JSON(nil, ecode.RequestErr)
return
}
hashes = strings.Split(params.Get("hashes"), ",")
err = dmSvc.AssistDelBanned2(c, mid.(int64), aid, hashes)
c.JSON(nil, err)
}

View File

@@ -0,0 +1,163 @@
package http
import (
"strconv"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
// addPa 申请保护弹幕.
func addPa(c *bm.Context) {
var (
str string
err error
cid int64
dmids []int64
)
mid, _ := c.Get("mid")
params := c.Request.Form
str = params.Get("cid")
cid, err = strconv.ParseInt(str, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
str = params.Get("dmids")
if dmids, err = xstr.SplitInts(str); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
err = dmSvc.AddProtectApply(c, mid.(int64), cid, dmids)
c.JSON(nil, err)
}
// recall 弹幕撤回
func recall(c *bm.Context) {
var (
str string
msg string
err error
cid int64
dmid int64
)
mid, _ := c.Get("mid")
params := c.Request.Form
str = params.Get("cid")
cid, err = strconv.ParseInt(str, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
dmid, err = strconv.ParseInt(params.Get("dmid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
msg, err = dmSvc.Recall(c, mid.(int64), cid, dmid)
if err != nil {
c.JSON(nil, err)
log.Error("dmSvc.Recall(%v,%d,%d) error(%v)", mid, cid, dmid, err)
return
}
res := map[string]interface{}{}
if msg != "" {
res["message"] = msg
}
c.JSONMap(res, err)
}
// midHash 获取用户mid hash.
func midHash(c *bm.Context) {
var err error
mid, _ := c.Get("mid")
hash, err := dmSvc.MidHash(c, mid.(int64))
if err != nil {
c.JSON(nil, err)
log.Error("dmSvc.MidHash(%d) error(%v)", mid.(int64), err)
return
}
res := map[string]interface{}{}
res["data"] = map[string]interface{}{
"hash": hash,
}
c.JSONMap(res, err)
}
// transfer 弹幕转移
func transfer(c *bm.Context) {
p := c.Request.Form
toCid, err := strconv.ParseInt(p.Get("to"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
offset, err := strconv.ParseFloat(p.Get("offset"), 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
mid, _ := c.Get("mid")
if err = dmSvc.CheckExist(c, mid.(int64), toCid); err != nil {
c.JSON(nil, err)
return
}
fromCids, err := xstr.SplitInts(p.Get("from"))
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
for _, cid := range fromCids {
if cid == toCid {
c.JSON(nil, ecode.DMTransferSame)
return
}
if err = dmSvc.CheckExist(c, mid.(int64), cid); err != nil {
c.JSON(nil, err)
return
}
if err = dmSvc.TransferJob(c, mid.(int64), cid, toCid, offset); err != nil {
log.Error("dmSvc.TransferJob(mid:%d,from:%d,to:%d,offset:%v) error(%v)", mid.(int64), cid, toCid, offset, err)
c.JSON(nil, err)
return
}
}
c.JSON(nil, err)
}
func transferList(c *bm.Context) {
var (
cid int64
p = c.Request.Form
)
cid, err := strconv.ParseInt(p.Get("cid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
l, err := dmSvc.TransferList(c, cid)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(l, err)
}
func transferRetry(c *bm.Context) {
var (
id int64
err error
p = c.Request.Form
)
id, err = strconv.ParseInt(p.Get("id"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
mid, _ := c.Get("mid")
err = dmSvc.TransferRetry(c, id, mid.(int64))
c.JSON(nil, err)
}

View File

@@ -0,0 +1,240 @@
package http
import (
"encoding/json"
"strconv"
"strings"
"go-common/app/interface/main/dm/model"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
var (
_userValidTime = 86400
_glbValidTime = 86400
)
func userRules(c *bm.Context) {
mid, _ := c.Get("mid")
rs, err := dmSvc.UserRules(c, mid.(int64))
if err != nil {
c.JSON(nil, err)
return
}
data := map[string]interface{}{
"rule": rs,
"ver": 123,
"valid": _userValidTime,
}
c.JSON(data, err)
}
func globalRuleEmpty(c *bm.Context) {
var (
param = c.Request.Form
curVersion = dmSvc.GlobalRuleVersion()
)
_, err := strconv.ParseUint(param.Get("ver"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
data := map[string]interface{}{
"rule": make([]*dm2Mdl.GlobalFilter, 0),
"ver": curVersion,
"valid": _glbValidTime,
}
c.JSON(data, err)
}
// func globalRules(c context.Context) {
// var (
// res = c.Result()
// param = c.Request().Form
// curVersion = dmSvc.GlobalRuleVersion()
// )
// version, err := strconv.ParseUint(param.Get("ver"), 10, 64)
// if err != nil {
// res["code"] = ecode.RequestErr
// return
// }
// if version == curVersion {
// res["code"] = ecode.NotModified
// return
// }
// rs, err := dmSvc.GlobalRules(c)
// if err != nil {
// res["code"] = err
// return
// }
// data := map[string]interface{}{
// "rule": rs,
// "ver": curVersion,
// "valid": _glbValidTime,
// }
// res["data"] = data
// }
func addUserRule(c *bm.Context) {
params := c.Request.Form
typeStr := params.Get("type")
filter := params.Get("filter")
comment := params.Get("comment")
mid, _ := c.Get("mid")
tp, err := strconv.ParseInt(typeStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if filter == "" {
c.JSON(nil, ecode.DMFilterIsEmpty)
return
}
v, err := dmSvc.AddUserRule(c, int8(tp), mid.(int64), []string{filter}, comment)
if err != nil || len(v) <= 0 {
c.JSON(nil, err)
return
}
c.JSON(v[0], err)
}
func multiAddUserRule(c *bm.Context) {
params := c.Request.Form
typeStr := params.Get("type")
filters := params.Get("filters")
comment := params.Get("comment")
mid, _ := c.Get("mid")
tp, err := strconv.ParseInt(typeStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if filters == "" {
c.JSON(nil, ecode.DMFilterIsEmpty)
return
}
values := strings.Split(filters, ",")
v, err := dmSvc.AddUserRule(c, int8(tp), mid.(int64), values, comment)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(v, err)
}
func addGlobalRule(c *bm.Context) {
params := c.Request.Form
filter := params.Get("filter")
typeStr := params.Get("type")
tp, err := strconv.ParseInt(typeStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if filter == "" {
c.JSON(nil, ecode.DMFilterIsEmpty)
return
}
v, err := dmSvc.AddGlobalRule(c, int8(tp), filter)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(v, err)
}
func delUserRules(c *bm.Context) {
params := c.Request.Form
mid, _ := c.Get("mid")
idsStr := params.Get("ids")
if len(idsStr) == 0 {
c.JSON(nil, ecode.RequestErr)
return
}
ids, err := xstr.SplitInts(idsStr)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
_, err = dmSvc.DelUserRules(c, mid.(int64), ids)
c.JSON(nil, err)
}
func delGlobalRules(c *bm.Context) {
var params = c.Request.Form
idsStr := params.Get("ids")
if len(idsStr) == 0 {
c.JSON(nil, ecode.RequestErr)
return
}
ids, err := xstr.SplitInts(idsStr)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
_, err = dmSvc.DelGlobalRules(c, ids)
c.JSON(nil, err)
}
// filterList
func filterList(c *bm.Context) {
var (
cid int64
err error
p = c.Request.Form
)
cidStr := p.Get("cid")
if len(cidStr) > 0 {
if cid, err = strconv.ParseInt(cidStr, 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
}
mid, _ := c.Get("mid")
data, err := dmSvc.FilterList(c, mid.(int64), cid)
if err != nil {
log.Error("dmSvc.FilterList(mid:%v cid:%d) error(%v)", mid, cid, err)
c.JSON(nil, err)
return
}
c.JSON(data, nil)
}
func editFilter(c *bm.Context) {
var (
cid int64
fList = make([]*model.IndexFilter, 0)
p = c.Request.Form
err error
)
mid, _ := c.Get("mid")
cidStr := p.Get("cid")
if cidStr != "" {
if cid, err = strconv.ParseInt(cidStr, 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
}
fStr := p.Get("filters")
if err = json.Unmarshal([]byte(fStr), &fList); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
for _, f := range fList {
if f.Regex == dm2Mdl.FilterTypeRev ||
f.Regex == dm2Mdl.FilterTypeTop ||
f.Regex == dm2Mdl.FilterTypeBottom {
f.Filter = dm2Mdl.FilterContent
}
if err = dmSvc.EditFilter(c, cid, mid.(int64), f.Filter, f.Regex, f.Activate); err != nil {
log.Error("dmSvc.EditFilter(mid:%v cid:%d filter:%s type:%d) error(%v)", mid, cid, f.Filter, f.Regex, err)
c.JSON(nil, err)
return
}
}
c.JSON(nil, nil)
}

View File

@@ -0,0 +1,108 @@
package http
import (
"net/http"
"go-common/app/interface/main/dm/conf"
"go-common/app/interface/main/dm/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/antispam"
"go-common/library/net/http/blademaster/middleware/auth"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
// service
dmSvc *service.Service
antispamSvc *antispam.Antispam
authSvc *auth.Auth
verifySvc *verify.Verify
)
// Init http init
func Init(c *conf.Config, s *service.Service) {
dmSvc = s
authSvc = auth.New(c.Auth)
verifySvc = verify.New(c.Verify)
antispamSvc = antispam.New(c.Antispam)
engine := bm.DefaultServer(c.HTTPServer)
outerRouter(engine)
interRouter(engine)
// init external server
if err := engine.Start(); err != nil {
log.Error("bm.DefaultServer error(%v)", err)
panic(err)
}
}
func outerRouter(e *bm.Engine) {
e.Ping(ping)
group := e.Group("/x/dm")
{
fltGroup := group.Group("/filter")
{
fltGroup.GET("/user", authSvc.User, userRules)
fltGroup.POST("/user/add", authSvc.User, antispamSvc.Handler(), addUserRule)
fltGroup.POST("/user/add2", authSvc.User, antispamSvc.Handler(), multiAddUserRule)
fltGroup.POST("/user/del", authSvc.User, delUserRules)
fltGroup.GET("/global", authSvc.Guest, globalRuleEmpty)
}
group.POST("/protect/apply", authSvc.User, addPa)
group.POST("/recall", authSvc.User, recall)
group.GET("/user", authSvc.User, midHash)
group.GET("/transfer/list", authSvc.User, transferList)
group.POST("/transfer/retry", authSvc.User, transferRetry)
group.POST("/adv/buy", authSvc.User, buyAdv)
group.GET("/adv/state", authSvc.User, advState)
group.GET("/up/banned/users", authSvc.User, assistBannedUsers)
group.POST("/up/banned/del", authSvc.User, AssistDelBanned2)
group.POST("/assist/banned", authSvc.User, assistBanned)
group.POST("/assist/del", authSvc.User, assistDelete)
group.POST("/report/add", authSvc.User, addReport)
group.POST("/report/add2", authSvc.User, addReport2)
}
}
func interRouter(e *bm.Engine) {
group := e.Group("/x/internal/dm")
{
advGroup := group.Group("/adv")
{
advGroup.POST("/pass", verifySvc.VerifyUser, passAdv)
advGroup.POST("/deny", verifySvc.VerifyUser, denyAdv)
advGroup.POST("/cancel", verifySvc.VerifyUser, cancelAdv)
advGroup.GET("/list", verifySvc.VerifyUser, advList)
}
fltGroup := group.Group("/filter")
{
fltGroup.POST("/global/add", verifySvc.Verify, addGlobalRule)
fltGroup.POST("/global/del", verifySvc.Verify, delGlobalRules)
fltGroup.GET("/index/list", verifySvc.VerifyUser, filterList)
fltGroup.POST("/index/edit", verifySvc.VerifyUser, editFilter)
}
rptGroup := group.Group("/report")
{
rptGroup.POST("/up/edit", verifySvc.VerifyUser, editReport)
rptGroup.GET("/up/list", verifySvc.VerifyUser, reportList)
rptGroup.GET("/up/archives", verifySvc.VerifyUser, rptArchives)
}
prtGroup := group.Group("/up/protect/apply")
{
prtGroup.POST("/notice/switch", verifySvc.Verify, uptPaSwitch)
prtGroup.POST("/status", verifySvc.Verify, UptPaStatus)
prtGroup.GET("/list", verifySvc.Verify, paLs)
prtGroup.GET("/video/list", verifySvc.Verify, paVideoLs)
}
group.POST("/assist/banned/upt", verifySvc.VerifyUser, assistBannedUpt)
group.POST("/up/transfer", verifySvc.VerifyUser, transfer)
}
}
// ping check server ok.
func ping(c *bm.Context) {
if err := dmSvc.Ping(c); err != nil {
log.Error("dm service ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -0,0 +1,825 @@
package http
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"testing"
"time"
)
const (
_host = "http://127.0.0.1:6214"
_innerHost = "http://127.0.0.1:6214"
)
var (
apply = _host + "/x/dm/protect/apply"
recallURL = _host + "/x/dm/recall"
my = _host + "/x/dm/my/listxml.so"
applyList = _innerHost + "/x/dm/up/protect/apply/list"
videoList = _innerHost + "/x/dm/up/protect/apply/video/list"
applyChangeStatus = _innerHost + "/x/dm/up/protect/apply/status"
applyNoticeSwitch = _innerHost + "/x/dm/up/protect/apply/notice/switch"
)
func TestUpFilter(t *testing.T) {
params := url.Values{}
params.Set("mid", "1")
params.Set("oid", "0")
s := _host + "/x/dm/filter/up?" + params.Encode()
body, err := cget(s)
fmt.Println(string(body))
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
}
func TestAddUpFilter(t *testing.T) {
params := url.Values{}
params.Set("mid", "1")
params.Set("oid", "2")
params.Set("filter", "aabbccdd1234567")
params.Set("type", "2")
s := _host + "/x/dm/filter/user/add?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestDelUpFilter1(t *testing.T) {
params := url.Values{}
params.Set("ids", "1554")
s := _host + "/x/dm/filter/user/del?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestAddFilter2(t *testing.T) {
params := url.Values{}
params.Set("filters", "1233432,78439214")
params.Set("type", "2")
params.Set("comment", "reason")
s := _host + "/x/dm/filter/user/add2?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestAddReport(t *testing.T) {
params := url.Values{}
params.Set("dmid", "719923250")
params.Set("cid", "8937277")
params.Set("reason", "1")
s := _host + "/x/dm/report/add?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestAddReport2(t *testing.T) {
params := url.Values{}
params.Set("dmids", "719189659,719189660")
params.Set("cid", "8937185")
params.Set("reason", "1")
s := _host + "/x/dm/report/add2?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestList list
func TestApply(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937277")
params.Set("dmids", "719214016,123")
s := apply + "?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestRecall(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937185")
params.Set("dmid", "719189659")
s := recallURL + "?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestList list
func TestMy(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937277")
s := my + "?" + params.Encode()
body, err := cget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
fmt.Println(string(body))
}
// TestList list
func TestApplyList(t *testing.T) {
var (
s string
body []byte
err error
mh [16]byte
)
params := url.Values{}
params.Set("uid", "15555180")
params.Set("page", "1")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh = md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s = applyList + "?" + params.Encode()
body, err = oget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
params.Del("sign")
params.Set("sort", "playtime")
mh = md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s = applyList + "?" + params.Encode()
body, err = oget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
params.Del("sign")
params.Set("aid", "4052732")
mh = md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s = applyList + "?" + params.Encode()
body, err = oget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
params.Del("sign")
params.Set("sort", "playtime")
mh = md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s = applyList + "?" + params.Encode()
body, err = oget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TesVideoList list
func TestVideoList(t *testing.T) {
params := url.Values{}
params.Set("uid", "15555180")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := videoList + "?" + params.Encode()
body, err := oget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestApplyChangeStatus TestApplyChangeStatus
func TestApplyChangeStatus(t *testing.T) {
params := url.Values{}
params.Set("uid", "15555180")
params.Set("status", "1")
params.Set("ids", "1,2")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := applyChangeStatus + "?" + params.Encode()
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestApplyNoticeSwitch TestApplyChangeStatus
func TestApplyNoticeSwitch(t *testing.T) {
var (
mh [16]byte
s string
body []byte
err error
)
params := url.Values{}
params.Set("uid", "15555180")
params.Set("status", "0")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh = md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s = applyNoticeSwitch + "?" + params.Encode()
body, err = opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
params.Del("sign")
params.Set("status", "1")
mh = md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s = applyNoticeSwitch + "?" + params.Encode()
body, err = opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestUptStat list
func TestUptStat(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937278")
params.Set("dmid", "719189706")
params.Set("stat", "0")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _innerHost + "/x/internal/dm/stat/upt?" + params.Encode()
fmt.Println(s)
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestUptStat list
func TestDMTransfer(t *testing.T) {
params := url.Values{}
params.Set("from", "10108810")
params.Set("to", "10108809")
params.Set("mid", "452156")
params.Set("offset", "0")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _innerHost + "/x/internal/dm/up/transfer2?" + params.Encode()
fmt.Println(s)
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestAssistBanned list
func TestAssistBanned(t *testing.T) {
params := url.Values{}
params.Set("cid", "10108163")
params.Set("dmids", "719925837,719925859")
s := _host + "/x/dm/assist/banned?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestAssistDelBanned2 list
func TestAssistDelBanned2(t *testing.T) {
params := url.Values{}
params.Set("aid", "4052732")
params.Set("hashes", "131141213,mdzz")
s := _host + "/x/dm/up/banned/del?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestUser user
func TestUser(t *testing.T) {
s := _host + "/x/dm/user"
body, err := cget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestBannedUsers(t *testing.T) {
s := _host + "/x/dm/up/banned/users"
params := url.Values{}
params.Set("aid", "10097375")
body, err := cget(s + "?" + params.Encode())
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestAssistDel list
func TestAssistDel(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937278")
params.Set("dmids", "719189706,719189707")
s := "http://api.bilibili.com/x/dm/assist/del?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestAssistProtect list
func TestAssistProtect(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937278")
params.Set("dmids", "719189706,719189707")
s := _host + "/x/dm/assist/protect?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestAssistProtect list
func TestAssistMove(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937278")
params.Set("dmids", "719189706,719189707")
s := _host + "/x/dm/assist/move?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestAssistIgnore list
func TestAssistBannedUpt(t *testing.T) {
params := url.Values{}
params.Set("mid", "15555180")
params.Set("hash", "123")
params.Set("stat", "0")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _innerHost + "/x/internal/dm/assist/banned/upt?" + params.Encode()
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestUptPool
func TestUptPool(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937278")
params.Set("dmid", "719189708")
params.Set("pool", "1")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _innerHost + "/x/internal/dm/pool/upt?" + params.Encode()
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// TestAssistIgnore list
func TestAssistIgnore(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937278")
params.Set("dmids", "719189706,719189707")
s := _host + "/x/dm/assist/ignore?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestDMList(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937278")
params.Set("page", "1")
s := _host + "/x/dm/list?" + params.Encode()
body, err := cget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestDMedit(t *testing.T) {
params := url.Values{}
params.Set("cid", "8937278")
params.Set("dmids", "1,2,3,4")
params.Set("state", "1")
s := _host + "/x/dm/edit?" + params.Encode()
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestFilterList(t *testing.T) {
params := url.Values{}
params.Set("mid", "150781")
params.Set("cid", "0")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _host + "/x/internal/dm/filter/index/list?" + params.Encode()
fmt.Println(s)
body, err := oget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestTransferList(t *testing.T) {
params := url.Values{}
params.Set("cid", "10109082")
params.Set("mid", "1")
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _host + "/x/dm/transfer/list?" + params.Encode()
fmt.Println(s)
body, err := oget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestTransferRetry(t *testing.T) {
params := url.Values{}
params.Set("id", "265")
params.Set("mid", "1")
s := _host + "/x/dm/transfer/retry?" + params.Encode()
fmt.Println(s)
body, err := cpost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestEditFilter(t *testing.T) {
fStr := `[
{
"type": 0,
"filter": "傻逼",
"activate": 1
},
{
"type": 1,
"filter": "*",
"activate": 1
},
{
"type": 4,
"filter": "",
"activate":1
},
{
"type": 2,
"filter": "150781",
"activate": 0
}
]`
params := url.Values{}
params.Set("mid", "150781")
params.Set("cid", "0")
params.Set("filters", fStr)
params.Set("appkey", "53e2fa226f5ad348")
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + "3cf6bd1b0ff671021da5f424fea4b04a"))
params.Set("sign", hex.EncodeToString(mh[:]))
s := _host + "/x/internal/dm/filter/index/edit?" + params.Encode()
fmt.Println(s)
body, err := opost(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
func TestUserRules(t *testing.T) {
s := _host + "/x/dm/filter/user"
body, err := cget(s)
if err != nil {
t.Errorf("url(%s) error(%s)", s, err)
t.FailNow()
}
if err = ccode(body); err != nil {
t.Fatal(err, string(body))
t.FailNow()
}
fmt.Println(string(body))
}
// oget http get request
func oget(url string) (body []byte, err error) {
resp, err := http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
return
}
// ccode check code == 0
// ccode check code == 0
func ccode(body []byte) (err error) {
var d interface{}
err = json.Unmarshal(body, &d)
if err != nil {
return
}
ma, ok := d.(map[string]interface{})
if !ok {
return
}
code := ma["code"].(float64)
if code != 0 {
err = errors.New("code != 0")
return
}
return
}
// opost http post request
func opost(url string) (body []byte, err error) {
resp, err := http.Post(url, "", nil)
if err != nil {
return
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
return
}
func cpost(url string) (body []byte, err error) {
client := &http.Client{}
req, err := http.NewRequest("POST", url, nil)
if err != nil {
return
}
req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
req.Header.Add("Accept-Language", "ja,zh-CN;q=0.8,zh;q=0.6")
req.Header.Add("Connection", "keep-alive")
req.Header.Add("Cookie", `buvid3=7B833293-671D-47D9-9BAB-464DE756DFBF14331infoc; UM_distinctid=15ba97a9afed0-0b51074d03d7c4-396b7805-1fa400-15ba97a9aff25b; pgv_pvi=6667228160; pgv_si=s603312128; fts=1493197036; sid=chto560j; rpdid=kwmqqoqxomdoplppwwppw; PHPSESSID=nepo3f6lhgci20gbdet1vvfig1; HTML5PlayerCRC32=3819803418; biliMzIsnew=1; biliMzTs=0; html5_player_gray=false; player_gray=false; LIVE_BUVID=ecbc29c14b41a4c5ff883313e734a336; LIVE_BUVID__ckMd5=f2922ceec4b33165; user_face=http%3A%2F%2Fi2.hdslb.com%2Fbfs%2Fface%2F9c843ff4cdcf38e6031e493ff17b1b8610e36e7a.jpg; purl_token=bilibili_1500257956; finger=0e029071; DedeUserID=27515260; DedeUserID__ckMd5=ae01241c690f95b5; SESSDATA=8bb74c97%2C1502854413%2Ccffcbc21; bili_jct=2b4c5f02e710a7f676acecb80c03271f; _cnt_pm=0; _cnt_notify=0; CNZZDATA2724999=cnzz_eid%3D714476842-1493196394-null%26ntime%3D1500262370; _dfcaptcha=a1ca150412337140d3d763aea1da2d41`)
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0")
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
return
}
func cget(url string) (body []byte, err error) {
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return
}
req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
req.Header.Add("Accept-Language", "ja,zh-CN;q=0.8,zh;q=0.6")
req.Header.Add("Connection", "keep-alive")
req.Header.Add("Cookie", `sid=88dol9eo; fts=1508407962; UM_distinctid=15f3436b684ab-08804fe751374a-31657c00-1fa400-15f3436b685298; pgv_pvi=3618563072; rpdid=kmilkmximpdoswqploqxw; buvid3=CBB97852-6CF6-4D3A-B97F-5A9AD1D5827F26561infoc; biliMzIsnew=1; biliMzTs=null; LIVE_BUVID=aabb755e95239c26d7f2dbeba748ce27; LIVE_BUVID__ckMd5=8b3ae56b45b2626a; member_v2=1; finger=14bc3c4e; BANGUMI_SS_21715_REC=192513; im_notify_type_3078992=0; DedeUserID=3078992; DedeUserID__ckMd5=55845496fd6119b5; SESSDATA=f7d955fd%2C1519879629%2Ca8074050; bili_jct=553a35adf1c94efb8d125d000798d1ca; pgv_si=s6786742272; purl_token=bilibili_1517461841; _dfcaptcha=30e17d94b2de231c8862ff9d16fff5dc`)
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0")
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
return
}

View File

@@ -0,0 +1,179 @@
package http
import (
"strconv"
"go-common/app/interface/main/dm/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
const (
_maxContentLen = 100
)
func addReport(c *bm.Context) {
var (
p = c.Request.Form
err error
cid, dmid int64
reason int64
)
mid, _ := c.Get("mid")
if cid, err = strconv.ParseInt(p.Get("cid"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if dmid, err = strconv.ParseInt(p.Get("dmid"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if reason, err = strconv.ParseInt(p.Get("reason"), 10, 8); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if int8(reason) > model.ReportReasonTeenagers {
c.JSON(nil, ecode.DMReportReasonError)
return
}
content := p.Get("content")
if len([]rune(content)) > _maxContentLen {
c.JSON(nil, ecode.DMReportReasonTooLong)
return
}
if _, err = dmSvc.AddReport(c, cid, dmid, mid.(int64), int8(reason), content); err != nil {
log.Error("dmSvc.AddReport(cid:%d, dmid:%d, mid:%v) error(%v)", cid, dmid, mid, err)
c.JSON(nil, err)
return
}
res := map[string]interface{}{}
res["message"] = ""
c.JSONMap(res, err)
}
func addReport2(c *bm.Context) {
var (
p = c.Request.Form
err error
cid int64
reason int64
dmids []int64
ok2 bool
)
mid, _ := c.Get("mid")
if cid, err = strconv.ParseInt(p.Get("cid"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if dmids, err = xstr.SplitInts(p.Get("dmids")); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if reason, err = strconv.ParseInt(p.Get("reason"), 10, 8); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if int8(reason) > model.ReportReasonOther {
c.JSON(nil, ecode.DMReportReasonError)
return
}
content := p.Get("content")
if len([]rune(content)) > _maxContentLen {
c.JSON(nil, ecode.DMReportReasonTooLong)
return
}
for _, dmid := range dmids {
if _, err = dmSvc.AddReport(c, cid, dmid, mid.(int64), int8(reason), content); err != nil {
log.Error("dmSvc.AddReport(cid:%d, dmid:%d, mid:%v) error(%v)", cid, dmid, mid, err)
}
if err == nil {
ok2 = true
}
}
if ok2 {
res := map[string]interface{}{}
res["message"] = ""
c.JSONMap(res, nil)
return
}
c.JSON(nil, err)
}
func editReport(c *bm.Context) {
var (
err error
cid, dmid, op int64
p = c.Request.Form
)
mid, _ := c.Get("mid")
if dmid, err = strconv.ParseInt(p.Get("dmid"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if cid, err = strconv.ParseInt(p.Get("cid"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if op, err = strconv.ParseInt(p.Get("op"), 10, 8); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if int8(op) != model.StatUpperIgnore && int8(op) != model.StatUpperDelete {
c.JSON(nil, ecode.RequestErr)
return
}
_, err = dmSvc.EditReport(c, 1, cid, mid.(int64), dmid, int8(op))
c.JSON(nil, err)
}
func reportList(c *bm.Context) {
var (
err error
aid int64 = -1
page, pageSize int64
p = c.Request.Form
upOp = model.StatUpperInit
)
mid, _ := c.Get("mid")
aidStr := p.Get("aid")
if aidStr != "" {
if aid, err = strconv.ParseInt(aidStr, 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
}
if page, err = strconv.ParseInt(p.Get("page"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if pageSize, err = strconv.ParseInt(p.Get("size"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
data, err := dmSvc.ReportList(c, mid.(int64), aid, page, pageSize, upOp, []int64{int64(model.StatFirstInit), int64(model.StatSecondInit)})
if err != nil {
log.Error("dmSvc.ReportList(mid:%v, aid:%d) error(%v)", mid, aid, err)
c.JSON(nil, err)
return
}
c.JSON(data, nil)
}
func rptArchives(c *bm.Context) {
var (
err error
upOp = model.StatUpperInit
states = []int8{model.StatFirstInit, model.StatSecondInit}
pn, ps int64 = 1, 20
)
mid, _ := c.Get("mid")
data, err := dmSvc.ReportArchives(c, mid.(int64), upOp, states, pn, ps)
if err != nil {
log.Error("dmSvc.ReportArchives(mid:%v) error(%v)", mid, err)
c.JSON(nil, err)
return
}
c.JSON(data, nil)
}

View File

@@ -0,0 +1,124 @@
package http
import (
"strconv"
"go-common/app/interface/main/dm/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
// uptPaSwitch 申请保护弹幕开关
func uptPaSwitch(c *bm.Context) {
var (
err error
uid int64
status int
params = c.Request.Form
)
// uid
uid, err = strconv.ParseInt(params.Get("uid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
// uid
status, err = strconv.Atoi(params.Get("status"))
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
err = dmSvc.UptPaSwitch(c, uid, status)
c.JSON(nil, err)
}
// UptPaStatus 处理保护弹幕申请
func UptPaStatus(c *bm.Context) {
var (
err error
uid int64
status int
ids []int64
params = c.Request.Form
)
// uid
uid, err = strconv.ParseInt(params.Get("uid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if uid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
// status
status, err = strconv.Atoi(params.Get("status"))
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
ids, err = xstr.SplitInts(params.Get("ids"))
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
err = dmSvc.UptPaStatus(c, uid, ids, status)
c.JSON(nil, err)
}
// paLs 保护弹幕申请列表
func paLs(c *bm.Context) {
var (
err error
uid, aid int64
page int
data *model.ApplyListResult
params = c.Request.Form
)
// uid
uid, err = strconv.ParseInt(params.Get("uid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
aid, err = strconv.ParseInt(params.Get("aid"), 10, 64)
if err != nil {
aid = 0
}
page, err = strconv.Atoi(params.Get("page"))
if err != nil {
page = 1
}
data, err = dmSvc.ProtectApplies(c, uid, aid, page, params.Get("sort"))
if err != nil {
c.JSON(nil, err)
log.Error("dmSvc.PaLs(%v,%v,%v,%v) error(%v)", uid, aid, page, params.Get("sort"), err)
return
}
c.JSON(data, nil)
}
// paVideoLs 保护弹幕申请的视频列表
func paVideoLs(c *bm.Context) {
var (
err error
uid int64
params = c.Request.Form
)
// uid
uid, err = strconv.ParseInt(params.Get("uid"), 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
data, err := dmSvc.PaVideoLs(c, uid)
if err != nil {
log.Error("dmSvc.PaVideoLs(%v) error(%v)", uid, err)
c.JSON(nil, err)
return
}
c.JSON(data, nil)
}

View File

@@ -0,0 +1,36 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"dm.go",
"filter.go",
"protect.go",
"report.go",
"subject.go",
"transfer.go",
],
importpath = "go-common/app/interface/main/dm/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//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"],
)

View File

@@ -0,0 +1,98 @@
package model
import (
"hash/crc32"
"strconv"
"go-common/library/time"
)
// All const variable used in dm2
const (
AttrNo = int32(0) // 属性位为0
AttrYes = int32(1) // 属性位为1
AttrProtect = uint(0) // 保护弹幕
StateNormal = int32(0) // 普通状态
StateDelete = int32(1) // 删除状态
StateHide = int32(2) // 隐藏状态
StateBlock = int32(3) // 屏蔽状态
StateFilter = int32(4) // 过滤状态
StateMonitorBefore = int32(5) // 先审后发
StateMonitorAfter = int32(6) // 先发后审
StateSystemFilter = int32(7) // 敏感词过滤
StateReportDelete = int32(8) // 举报删除
StateAdminDelete = int32(9) // 弹幕管理删除
StateUserDelete = int32(10) // 用户删除
StateScriptDelete = int32(11) // 举报脚本删除
PoolNormal = int32(0) // 普通弹幕池
PoolSubtitle = int32(1) // 字幕弹幕池
PoolSpecial = int32(2) // 特殊弹幕池
NotFound = -1
)
// Hash 用户匿名弹幕uid hash
func Hash(uid int64, ip uint32) string {
var s uint32
if uid != 0 {
s = crc32.ChecksumIEEE([]byte(strconv.FormatInt(uid, 10)))
return strconv.FormatInt(int64(s), 16)
}
s = crc32.ChecksumIEEE([]byte(strconv.FormatInt(int64(ip), 10)))
return "D" + strconv.FormatInt(int64(s), 16)
}
// DM dm_index and dm_content
type DM struct {
ID int64 `json:"id"`
Type int32 `json:"type"`
Oid int64 `json:"oid"`
Mid int64 `json:"mid"`
Progress int32 `json:"progress"`
Pool int32 `json:"pool"`
Attr int32 `json:"attr"`
State int32 `json:"state"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
Content *Content `json:"content,omitempty"`
ContentSpe *ContentSpecial `json:"content_special,omitempty"`
}
// AttrVal return val of index'attr
func (d *DM) AttrVal(bit uint) int32 {
return (d.Attr >> bit) & int32(1)
}
// AttrSet set val of index'attr
func (d *DM) AttrSet(v int32, bit uint) {
d.Attr = d.Attr&(^(1 << bit)) | (v << bit)
}
// NeedDisplay 判断该条弹幕是否需要展示
func (d *DM) NeedDisplay() bool {
return d.State == StateNormal || d.State == StateMonitorAfter
}
// Content dm_content
type Content struct {
ID int64 `json:"id"`
FontSize int32 `json:"fontsize"`
Color int64 `json:"color"`
Mode int32 `json:"mode"`
IP int64 `json:"ip"`
Plat int32 `json:"plat"`
Msg string `json:"msg"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// ContentSpecial dm_content_special
type ContentSpecial struct {
ID int64 `json:"id"`
Msg string `json:"msg"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}

View File

@@ -0,0 +1,21 @@
package model
// IndexFilter for dm_index_filter
type IndexFilter struct {
ID int64 `json:"id"`
CID int64 `json:"cid"`
MID int64 `json:"mid"`
Filter string `json:"filter"`
Activate int8 `json:"activate"`
Regex int8 `json:"type"`
Ctime int64 `json:"ctime"`
}
// UserFilterList for member filter list
// to show global filter or video filter
type UserFilterList struct {
Top int8 `json:"accept_top"`
Bottom int8 `json:"accept_bottom"`
Reverse int8 `json:"accept_reverse"`
Filter []*IndexFilter `json:"filter_list"`
}

View File

@@ -0,0 +1,111 @@
package model
import (
"time"
)
const (
// ProtectApplyLimit protect apply limit
ProtectApplyLimit = 20
)
// Pager comment
type Pager struct {
Total int `json:"total"`
Current int `json:"current"`
Size int `json:"size"`
TotalCount int `json:"total_count"`
}
// Pa 保护弹幕
type Pa struct {
ID int64
CID int64
UID int64
ApplyUID int64
AID int64
Playtime float32
DMID int64
Msg string
Status int
Ctime time.Time
Mtime time.Time
}
// Apply apply protect dm
type Apply struct {
ID int64 `json:"id"`
AID int64 `json:"aid"`
CID int64 `json:"cid"`
Title string `json:"title"`
ApplyUID int64 `json:"-"`
Pic string `json:"pic"`
Uname string `json:"uname"`
Msg string `json:"msg"`
Playtime float32 `json:"playtime"`
Ctime string `json:"ctime"`
}
// ApplySortPlaytime what
type ApplySortPlaytime []*Apply
func (c ApplySortPlaytime) Len() int {
return len(c)
}
func (c ApplySortPlaytime) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}
func (c ApplySortPlaytime) Less(i, j int) bool {
if c[i].CID == c[j].CID {
return c[i].Playtime < c[j].Playtime
}
return c[i].CID > c[j].CID
}
// ApplySortID what
type ApplySortID []*Apply
// Len get len
func (c ApplySortID) Len() int {
return len(c)
}
// Swap change dm
func (c ApplySortID) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}
// Less count
func (c ApplySortID) Less(i, j int) bool {
return c[i].ID > c[j].ID
}
// ApplyListResult get
type ApplyListResult struct {
Pager *Pager
List []*Apply
}
// Video video info
type Video struct {
Aid int64 `json:"aid"`
Title string `json:"title"`
}
// ApplyUserStat user stat
type ApplyUserStat struct {
Aid int64
UID int64
Status int
Ctime time.Time
}
// ApplyUserNotify user notify
type ApplyUserNotify struct {
Title string
Aid int64
Protect int
Unprotect int
}

View File

@@ -0,0 +1,189 @@
package model
import (
"time"
)
// var const text
var (
ReportReason = map[int8]string{
1: "内容涉及违禁相关",
2: "内容涉及非法网站信息",
3: "内容涉及赌博诈骗信息",
4: "内容涉及人身攻击",
5: "内容涉及侵犯他人隐私",
6: "内容涉及垃圾广告",
7: "内容涉及引战",
8: "内容涉及视频剧透",
9: "恶意刷屏",
10: "视频不相关",
11: "其他",
12: "青少年不良信息",
}
RptMsgTitle = "举报处理结果通知"
RptMsgTemplate = `您好,您在视频#{%s}{"http://www.bilibili.com/av%d"}中举报的弹幕『%s』已被删除原因是『%s』感谢您对bilibili社区秩序的维护哔哩哔哩 (゜-゜)つロ 干杯~`
)
// const var
const (
// up主操作
StatUpperInit = int8(0) // up主未处理
StatUpperIgnore = int8(1) // up主已忽略
StatUpperDelete = int8(2) // up主已删除
// 管理员操作
StatFirstInit = int8(0) // 待一审
StatFirstDelete = int8(1) // 一审删除
StatSecondInit = int8(2) // 待二审
StatSecondIgnore = int8(3) // 二审忽略
StatSecondDelete = int8(4) // 二审删除
StatFirstIgnore = int8(5) // 一审忽略
StatSecondAutoDelete = int8(6) // 二审脚本删除
// 处理结果通知
NoticeUnsend = int8(0) // 未通知用户
NoticeSend = int8(1) // 已通知用户
// 举报原因
ReportReasonProhibited = int8(1) // 违禁
ReportReasonPorn = int8(2) // 色情
ReportReasonFraud = int8(3) // 赌博诈骗
ReportReasonAttack = int8(4) // 人身攻击
ReportReasonPrivate = int8(5) // 隐私
ReportReasonAd = int8(6) // 广告
ReportReasonWar = int8(7) // 引战
ReportReasonSpoiler = int8(8) // 剧透
ReportReasonMeaningless = int8(9) // 刷屏
ReportReasonUnrelated = int8(10) // 视频不相关
ReportReasonOther = int8(11) // 其他
ReportReasonTeenagers = int8(12) // 青少年不良信息
)
// Report dm report info
type Report struct {
ID int64 `json:"id"` // 主键id
Cid int64 `json:"cid"` // 视频id
Did int64 `json:"dmid"` // 弹幕id
UID int64 `json:"uid"` // 举报用户的id
Reason int8 `json:"reason"` // 举报原因类型
Content string `json:"content"` // 举报内容reason为其它时有值
Count int64 `json:"count"` // 被举报次数
State int8 `json:"state"` // 举报状态
UpOP int8 `json:"up_op"` // up主操作
Score int32 `json:"score"` // 举报分
RpTime time.Time `json:"rp_time"` // 举报时间
Ctime time.Time `json:"ctime"` // 插入时间
Mtime time.Time `json:"mtime"` // 更新时间
}
// User report user info
type User struct {
ID int64 `json:"id"`
Did int64 `json:"dmid"`
UID int64 `json:"uid"`
Reason int8 `json:"reason"`
State int8 `json:"state"`
Content string `json:"content"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// RptLog dm admin log
type RptLog struct {
ID int64 `json:"id"`
Did int64 `json:"dmid"`
AdminID int64 `json:"admin_id"`
Reason int8 `json:"reason"`
Result int8 `json:"result"`
Remark string `json:"remark"`
Elapsed int64 `json:"elapsed"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// RptSearch report info from search
type RptSearch struct {
ID int64 `json:"id"`
Cid int64 `json:"cid"` // 视频的id
Did int64 `json:"dmid"` // 弹幕id
Aid int64 `json:"arc_aid"` // 稿件的id
Tid int64 `json:"arc_typeid"` // 稿件的分区id
Owner int64 `json:"dm_owner_uid"` // 弹幕发送者的uid
Msg string `json:"dm_msg"` // 弹幕内容
Count int64 `json:"count"` // 被举报次数
Content string `json:"content"` // 举报内容:只有类别其他才有值
UpOP int8 `json:"up_op"` // up主操作状态
State int8 `json:"state"` // 举报状态
UID int64 `json:"uid"` // 举报用户id
RpTime string `json:"rp_time"` // 举报时间
Reason int64 `json:"reason"` // 举报原因类型
Ctime string `json:"ctime"` // 插入时间
Mtime string `json:"mtime"` // 更新时间
Title string `json:"arc_title"` // 稿件标题
Deleted int64 `json:"dm_deleted"` // 弹幕状态
UPUid int64 `json:"arc_mid"` // up主id
Cover string `json:"arc_cover"` // 稿件的封面图
}
// RptSearchs report list
type RptSearchs struct {
Page int64 `json:"page"`
PageSize int64 `json:"pagesize"`
PageCount int64 `json:"pagecount"`
Total int64 `json:"total"`
Result []*RptSearch `json:"result"`
}
// UptSearchReport update search report
type UptSearchReport struct {
DMid int64 `json:"dmid"`
Upop int8 `json:"up_op"`
Ctime string `json:"ctime"`
Mtime string `json:"mtime"`
}
// Page search page
type Page struct {
Num int64 `json:"num"`
Size int64 `json:"size"`
Total int64 `json:"total"`
}
// SearchReportResult dm repost list from search
type SearchReportResult struct {
Page *Page `json:"page"`
Result []*RptSearch `json:"result"`
}
// SearchReportAidResult dm repost archive list from search
type SearchReportAidResult struct {
Page *Page `json:"page"`
Result map[string][]struct {
Key string `json:"key"`
} `json:"result"`
}
// RptMsg dm report message
type RptMsg struct {
Aid int64
UID int64
Did int64
Title string
Msg string
State int8
Reason int8
}
// Archives report archive list
type Archives struct {
Result []*struct {
Aid int64 `json:"aid"`
Title string `json:"title"`
} `json:"result"`
}
// ReportAction send dm info and hidetime
type ReportAction struct {
Cid int64 `json:"cid"` // 视频id
Did int64 `json:"dmid"` // 弹幕id
HideTime int64 `json:"hide_time"` // 弹幕隐藏截止时间
}

View File

@@ -0,0 +1,50 @@
package model
import (
"go-common/library/time"
)
// All const variable used in dm subject
const (
SubTypeVideo = int32(1) // 主题类型
SubStateOpen = int32(0) // 主题打开
SubStateClosed = int32(1) // 主题关闭
AttrSubGuest = uint(0) // 允许游客弹幕
AttrSubSpolier = uint(1) // 允许剧透弹幕
AttrSubMission = uint(2) // 允许活动弹幕
AttrSubAdvance = uint(3) // 允许高级弹幕
// StateProtect protected dm
StateProtect = 2
)
// Subject dm_subject
type Subject struct {
ID int64 `json:"id"`
Type int32 `json:"type"`
Oid int64 `json:"oid"`
Pid int64 `json:"pid"`
Mid int64 `json:"mid"`
State int32 `json:"state"`
Attr int32 `json:"attr"`
ACount int64 `json:"acount"`
Count int64 `json:"count"`
MCount int64 `json:"mcount"`
MoveCnt int64 `json:"move_count"`
Maxlimit int64 `json:"maxlimit"`
Childpool int32 `json:"childpool"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// AttrVal return val of subject'attr
func (s *Subject) AttrVal(bit uint) int32 {
return (s.Attr >> bit) & int32(1)
}
// AttrSet set val of subject'attr
func (s *Subject) AttrSet(v int32, bit uint) {
s.Attr = s.Attr&(^(1 << bit)) | (v << bit)
}

View File

@@ -0,0 +1,50 @@
package model
import (
"time"
xtime "go-common/library/time"
)
// all variable used in dm transfer
const (
TransferJobStatInit = int8(0)
TransferJobStatFinished = int8(1)
TransferJobStatFailed = int8(2)
)
// TransferJob dm transfer
type TransferJob struct {
ID int64
FromCID int64
ToCID int64
MID int64
Offset float64
State int8
Ctime time.Time
Mtime time.Time
}
// TransferHistory transfer list item
type TransferHistory struct {
ID int64 `json:"id"`
PartID int32 `json:"part_id"`
CID int64 `json:"cid"`
Title string `json:"title"`
CTime xtime.Time `json:"ctime"`
State int8 `json:"state"`
}
// CidInfo is archive_video model.
type CidInfo struct {
Aid int64 `json:"aid"`
Title string `json:"title"`
Desc string `json:"desc"`
Filename string `json:"filename"`
Index int `json:"index"`
Status int16 `json:"status"`
StatusDesc string `json:"status_desc"`
FailCode int8 `json:"fail_code"`
FailDesc string `json:"fail_desc"`
CTime xtime.Time `json:"ctime"`
}

View File

@@ -0,0 +1,79 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"advance_test.go",
"assist_test.go",
"dm_test.go",
"filter_test.go",
"protect_test.go",
"report_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/dm/conf:go_default_library",
"//app/interface/main/dm/model:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"advance.go",
"archive.go",
"assist.go",
"dm.go",
"filter.go",
"protect.go",
"report.go",
"service.go",
"subject.go",
],
importpath = "go-common/app/interface/main/dm/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/dm/conf:go_default_library",
"//app/interface/main/dm/dao:go_default_library",
"//app/interface/main/dm/model:go_default_library",
"//app/interface/main/dm2/model:go_default_library",
"//app/interface/main/dm2/model/oplog:go_default_library",
"//app/interface/main/dm2/rpc/client:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/assist/model/assist:go_default_library",
"//app/service/main/assist/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/zhenjl/cityhash: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"],
)

View File

@@ -0,0 +1,81 @@
package service
import (
"context"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/library/log"
)
// BuyAdvance 购买高级弹幕
func (s *Service) BuyAdvance(c context.Context, mid, cid int64, mode string) (err error) {
arg := &dm2Mdl.ArgAdvance{
Mid: mid,
Cid: cid,
Mode: mode,
}
if err = s.dmRPC.BuyAdvance(c, arg); err != nil {
log.Error("dmRPC.BuyAdvance(%v) error(%v)")
}
return
}
// AdvanceState 高级弹幕状态
func (s *Service) AdvanceState(c context.Context, mid, cid int64, mode string) (state *dm2Mdl.AdvState, err error) {
arg := &dm2Mdl.ArgAdvance{
Mid: mid,
Cid: cid,
Mode: mode,
}
if state, err = s.dmRPC.AdvanceState(c, arg); err != nil {
log.Error("dmRPC.AdvanceState(%v) error(%v)", arg, err)
}
return
}
// Advances 高级弹幕申请列表
func (s *Service) Advances(c context.Context, mid int64) (res []*dm2Mdl.Advance, err error) {
arg := &dm2Mdl.ArgMid{
Mid: mid,
}
if res, err = s.dmRPC.Advances(c, arg); err != nil {
log.Error("dmRPC.Advances(%v) error(%v)", arg, err)
}
return
}
// PassAdvance 通过高级弹幕申请
func (s *Service) PassAdvance(c context.Context, mid, id int64) (err error) {
arg := &dm2Mdl.ArgUpAdvance{
Mid: mid,
ID: id,
}
if err = s.dmRPC.PassAdvance(c, arg); err != nil {
log.Error("dmRPC.PassAdvance(%v) error(%v)", arg, err)
}
return
}
// DenyAdvance 拒绝高级弹幕申请
func (s *Service) DenyAdvance(c context.Context, mid, id int64) (err error) {
arg := &dm2Mdl.ArgUpAdvance{
Mid: mid,
ID: id,
}
if err = s.dmRPC.DenyAdvance(c, arg); err != nil {
log.Error("dmRPC.DenyAdvance(%v) error(%v)", arg, err)
}
return
}
// CancelAdvance 取消高级弹幕申请
func (s *Service) CancelAdvance(c context.Context, mid, id int64) (err error) {
arg := &dm2Mdl.ArgUpAdvance{
Mid: mid,
ID: id,
}
if err = s.dmRPC.CancelAdvance(c, arg); err != nil {
log.Error("dmRPC.CancelAdvance(%v) error(%v)", arg, err)
}
return
}

View File

@@ -0,0 +1,51 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestBuyAdvance(t *testing.T) {
Convey("test adv State", t, func() {
err := svr.BuyAdvance(c, 27515330, 10107292, "sp")
So(err, ShouldBeNil)
})
}
func TestAdvanceState(t *testing.T) {
Convey("test adv State", t, func() {
_, err := svr.AdvanceState(c, 27515330, 10107292, "sp")
So(err, ShouldBeNil)
})
}
func TestAdvances(t *testing.T) {
Convey("test adv", t, func() {
res, err := svr.Advances(context.TODO(), 27515260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestPassAdvance(t *testing.T) {
Convey("test pass adv", t, func() {
err := svr.PassAdvance(context.TODO(), 7158471, 2)
So(err, ShouldBeNil)
})
}
func TestDenyAdvance(t *testing.T) {
Convey("test deny adv", t, func() {
err := svr.DenyAdvance(context.TODO(), 27515615, 107)
So(err, ShouldBeNil)
})
}
func TestCancelAdvance(t *testing.T) {
Convey("test cancel adv", t, func() {
err := svr.CancelAdvance(context.TODO(), 27515615, 122)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,38 @@
package service
import (
"context"
"math"
"go-common/app/service/main/archive/api"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/library/log"
)
func (s *Service) archiveInfos(c context.Context, aids []int64) (archiveInfos map[int64]*api.Arc) {
var (
start, end int
)
archiveInfos = map[int64]*api.Arc{}
if len(aids) <= 0 {
return
}
page := int(math.Ceil(float64(len(aids)) / float64(100)))
for i := 0; i < page; i++ {
start = i * 100
end = (i + 1) * 100
if end > len(aids) {
end = len(aids)
}
arg := &arcMdl.ArgAids2{Aids: aids[start:end]}
infos, err := s.acvSvc.Archives3(c, arg)
if err != nil {
log.Error("s.arcRPC.Archives3(%v) error(%v)", arg, err)
return
}
for _, info := range infos {
archiveInfos[info.Aid] = info
}
}
return
}

View File

@@ -0,0 +1,122 @@
package service
import (
"context"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/app/interface/main/dm2/model/oplog"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/app/service/main/assist/model/assist"
"go-common/library/ecode"
"go-common/library/log"
)
// assist
func (s *Service) assist(c context.Context, mid int64, aid int64) (upID int64, isUp bool, err error) {
var ares *assist.AssistRes
arc, err := s.acvSvc.Archive3(c, &arcMdl.ArgAid2{Aid: aid})
if err != nil {
log.Error("s.acvSvc.Archive3(%d) error(%v)", aid, err)
return
}
upID = arc.Author.Mid
isUp = upID == mid
if isUp {
return
}
arg := &assist.ArgAssist{Mid: upID, AssistMid: mid, Type: assist.TypeDm}
if ares, err = s.astSvc.Assist(c, arg); err != nil {
log.Error("s.astSvc.Assist(%v) error(%v)", arg, err)
return
}
if ares.Assist == 0 {
err = ecode.DMAssistNo
return
}
if ares.Allow < 1 {
err = ecode.DMAssistLimit
}
return
}
// AssistBanned up主屏蔽
func (s *Service) AssistBanned(c context.Context, mid, cid int64, dmids []int64) (err error) {
arg := &dm2Mdl.ArgBanUsers{
Mid: mid,
Oid: cid,
DMIDs: dmids,
}
if err = s.dmRPC.BanUsers(c, arg); err != nil {
log.Error("dmRPC.BanUsers(%+v) error(%v)", arg, err)
}
return
}
// AssistUptBanned 更新up主屏蔽
func (s *Service) AssistUptBanned(c context.Context, mid int64, hash string, active int8) (err error) {
arg := &dm2Mdl.ArgEditUpFilters{
Mid: mid,
Type: dm2Mdl.FilterTypeID,
Active: active,
Filters: []string{hash},
}
if _, err = s.dmRPC.EditUpFilters(c, arg); err != nil {
log.Error("dmRPC.EditUpFilters(%+v) error(%v)", arg, err)
}
return
}
// AssistDelBanned2 批量撤销up主屏蔽
func (s *Service) AssistDelBanned2(c context.Context, mid, aid int64, hashes []string) (err error) {
arg := &dm2Mdl.ArgCancelBanUsers{
Mid: mid,
Aid: aid,
Filters: hashes,
}
if err = s.dmRPC.CancelBanUsers(c, arg); err != nil {
log.Error("dmRPC.CancelBanUsers(%+v) error(%v)", arg, err)
}
return
}
// AssistBannedUsers 获取up主屏蔽列表
func (s *Service) AssistBannedUsers(c context.Context, mid, aid int64) (hashes []string, err error) {
upID, _, err := s.assist(c, mid, aid)
if err != nil {
if err == ecode.DMAssistLimit {
err = nil
} else {
log.Error("s.assist(%d,%d) error(%v)", mid, aid, err)
return
}
}
arg := &dm2Mdl.ArgUpFilters{Mid: upID}
res, err := s.dmRPC.UpFilters(c, arg)
if err != nil {
log.Error("dmRPC.UpFilters(%+v) error(%v)", arg, err)
return
}
for _, v := range res {
if v.Type == dm2Mdl.FilterTypeID {
hashes = append(hashes, v.Filter)
}
}
return
}
// AssistDeleteDM assist delete dm.
func (s *Service) AssistDeleteDM(c context.Context, mid, oid int64, dmids []int64) (err error) {
arg := &dm2Mdl.ArgEditDMState{
Type: dm2Mdl.SubTypeVideo,
Oid: oid,
Mid: mid,
State: dm2Mdl.StateDelete, // must be this value
Dmids: dmids,
Source: oplog.SourcePlayer,
OperatorType: oplog.OperatorMember,
}
if err = s.dmRPC.EditDMState(c, arg); err != nil {
log.Error("dmRPC.EditDMState(%v) error(%v)", arg, err)
}
return
}

View File

@@ -0,0 +1,73 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestAssist(t *testing.T) {
var (
upID int64
isUp bool
err error
)
Convey("test assist not up", t, func() {
upID, isUp, err = svr.assist(context.Background(), int64(27515406), int64(10097377))
So(err, ShouldBeNil)
So(upID, ShouldBeGreaterThan, 1)
So(isUp, ShouldBeFalse)
})
Convey("test assist is up", t, func() {
upID, isUp, err = svr.assist(context.Background(), int64(27515256), int64(10097377))
So(err, ShouldBeNil)
So(upID, ShouldBeGreaterThan, 1)
So(isUp, ShouldBeTrue)
})
}
func TestAssistBanned(t *testing.T) {
Convey("test assist banned", t, func() {
err := svr.AssistBanned(context.TODO(), 27515256, 9967830, []int64{719926094, 719926092})
So(err, ShouldBeNil)
})
}
func TestAssistUptBanned(t *testing.T) {
Convey("test assist upt banned", t, func() {
err := svr.AssistUptBanned(context.TODO(), 27515256, "hash1", 0)
So(err, ShouldBeNil)
err = svr.AssistUptBanned(context.TODO(), 27515256, "hash1", 1)
So(err, ShouldBeNil)
})
}
func TestAssistDelBanned2(t *testing.T) {
Convey("test assist banned2", t, func() {
err := svr.AssistDelBanned2(context.TODO(), 27515256, 10097377, []string{"hash1", "hash2"})
So(err, ShouldBeNil)
err = svr.AssistUptBanned(context.TODO(), 27515256, "hash1", 1)
So(err, ShouldBeNil)
err = svr.AssistUptBanned(context.TODO(), 27515256, "hash2", 1)
So(err, ShouldBeNil)
})
}
func TestAssistBannedUsers(t *testing.T) {
Convey("test assist banned users", t, func() {
rs, err := svr.AssistBannedUsers(context.TODO(), 27515256, 10097377)
So(err, ShouldBeNil)
So(rs, ShouldBeGreaterThan, 1)
})
}
func TestAssistDelete(t *testing.T) {
Convey("test assist delete dm", t, func() {
err := svr.AssistDeleteDM(context.TODO(), 27515256, 10108163, []int64{719925514, 719925516})
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,202 @@
package service
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/interface/main/dm/model"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/app/interface/main/dm2/model/oplog"
account "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_recallLt = 5 //普通用户每天可以撤回几个
_recallTO = 120 //多久以前的弹幕可以撤回
_recallCap = 20000 // 字幕君
_recallOK = "撤回成功,你还有%s次撤回机会" // 弹幕撤回成功提示
)
// Recall 撤回弹幕
func (s *Service) Recall(c context.Context, mid, cid int64, id int64) (msg string, err error) {
var (
card *account.CardReply
cnt int
ts string
isSuper bool
)
if card, err = s.accountSvc.Card3(c, &account.MidReq{Mid: mid}); err != nil {
log.Error("s.actSvc.Card3(%d) error(%v)", mid, err)
return
}
ts = "无限"
isSuper = card.GetCard().GetRank() >= _recallCap
if !isSuper {
if cnt, err = s.dao.RecallCnt(c, mid); err != nil {
log.Error("s.dao.RecallCnt(%d) error(%v)", mid, err)
return
}
if cnt >= _recallLt {
err = ecode.DMRecallLimit
return
}
ts = strconv.Itoa(_recallLt - cnt - 1)
}
dm, err := s.dao.Index(c, model.SubTypeVideo, cid, id)
if err != nil {
return
}
if dm == nil || !dm.NeedDisplay() || dm.Mid != mid {
err = ecode.DMRecallDeleted
return
}
if (time.Now().Unix()-int64(dm.Ctime)) > _recallTO && !(isSuper && (dm.Pool == 1 || dm.Pool == 2)) {
err = ecode.DMRecallTimeout
return
}
if err = s.EditDMState(c, 1, cid, mid, dm2Mdl.StateUserDelete, oplog.SourcePlayer, oplog.OperatorMember, id); err != nil {
log.Error("s.EditDMStat(%d,%d) error(%v)", cid, id, err)
err = ecode.DMRecallError
return
}
if err = s.dao.UptRecallCnt(c, mid); err != nil {
log.Error("s.dao.Item(%d,%d) error(%v)", cid, mid, err)
err = nil
}
msg = fmt.Sprintf(_recallOK, ts)
return
}
// EditDMState edit dm state used rpc method in dm2.
func (s *Service) EditDMState(c context.Context, tp int32, oid, mid int64, state int32, source oplog.Source, operatorType oplog.OperatorType, dmids ...int64) (err error) {
arg := &dm2Mdl.ArgEditDMState{
Type: tp,
Oid: oid,
Mid: mid,
State: state,
Dmids: dmids,
Source: source,
OperatorType: operatorType,
}
if err = s.dmRPC.EditDMState(c, arg); err != nil {
log.Error("dmRPC.EditDMState(%v) error(%v)", arg, err)
}
return
}
// MidHash 弹幕发送者mid hash.
func (s *Service) MidHash(c context.Context, mid int64) (hash string, err error) {
hash = model.Hash(mid, 0)
return
}
// TransferJob set task to db
func (s *Service) TransferJob(c context.Context, mid, fromCid, toCid int64, offset float64) (err error) {
job, err := s.dao.CheckTransferJob(c, fromCid, toCid)
if err != nil {
log.Error("dao.CheckTransferJob(from:%d,to:%d) err(%v)", fromCid, toCid, err)
return
}
if job != nil && job.FromCID == fromCid && job.ToCID == toCid && job.State != model.TransferJobStatFailed {
err = ecode.DMTransferRepet
return
}
_, err = s.dao.AddTransferJob(c, fromCid, toCid, mid, offset, model.TransferJobStatInit)
if err != nil {
log.Error("dao.AddTransferJob(from:%d,to:%d) err(%v)", fromCid, toCid, err)
}
return
}
// TransferList service
func (s *Service) TransferList(c context.Context, cid int64) (hiss []*model.TransferHistory, err error) {
hiss, err = s.dao.TransferList(c, cid)
if err != nil || len(hiss) == 0 {
return
}
for _, his := range hiss {
cidInfo, err := s.dao.CidInfo(c, his.CID)
if err != nil {
log.Error("dao.CidInfo(%d) err(%v)", cid, err)
continue
}
his.Title = cidInfo.Title
his.PartID = int32(cidInfo.Index)
}
return
}
// TransferRetry change transferjob state
func (s *Service) TransferRetry(c context.Context, id, mid int64) (err error) {
job, err := s.dao.CheckTransferID(c, id)
if err != nil {
log.Error("dao.CheckTransferID(%d) err(%v)", id, err)
return
}
if job.State != model.TransferJobStatFailed || job.MID != mid {
err = ecode.RequestErr
return
}
_, err = s.dao.SetTransferState(c, id, model.TransferJobStatInit)
if err != nil {
log.Error("dao.TransferList(%d %d %d) err(%v)", id, err)
}
return
}
// CheckExist check exit of up id.
func (s *Service) CheckExist(c context.Context, mid, cid int64) (err error) {
sub, err := s.subject(c, 1, cid)
if err != nil {
if ecode.Cause(err) == ecode.NothingFound {
err = ecode.DMTransferNotFound
}
return
}
if sub.Mid == 0 {
err = ecode.DMTransferNotFound
return
}
if sub.Mid != mid {
err = ecode.DMTransferNotBelong
return
}
return
}
// dms get dm list by dmid from database
func (s *Service) dms(c context.Context, tp int32, oid int64, ids []int64) (dms []*model.DM, err error) {
var (
idxMap = make(map[int64]*model.DM)
contentSpe = make(map[int64]*model.ContentSpecial)
special []int64
contents []*model.Content
)
if idxMap, special, err = s.dao.IndexsByID(c, tp, oid, ids); err != nil || len(idxMap) == 0 {
return
}
if contents, err = s.dao.Contents(c, oid, ids); err != nil {
return
}
if len(special) > 0 {
if contentSpe, err = s.dao.ContentsSpecial(c, special); err != nil {
return
}
}
for _, content := range contents {
if dm, ok := idxMap[content.ID]; ok {
dm.Content = content
if dm.Pool == model.PoolSpecial {
if _, ok = contentSpe[dm.ID]; ok {
dm.ContentSpe = contentSpe[dm.ID]
}
}
dms = append(dms, dm)
}
}
return
}

View File

@@ -0,0 +1,61 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDMS(t *testing.T) {
Convey("test dm list by dmids", t, func() {
rs, err := svr.dms(context.TODO(), 1, 10108013, []int64{719925639, 719925638})
So(err, ShouldBeNil)
So(rs, ShouldNotBeEmpty)
for _, r := range rs {
t.Logf("%+v", r)
t.Logf("%+v", r.Content)
}
})
}
func TestMidHash(t *testing.T) {
Convey("test mid hash", t, func() {
hash, err := svr.MidHash(context.TODO(), 27515256)
So(err, ShouldBeNil)
So(hash, ShouldNotBeBlank, hash)
})
}
func TestTransferJob(t *testing.T) {
Convey("test TransferJob", t, func() {
err := svr.TransferJob(context.TODO(), 27515615, 10108765, 10108763, 1.00)
So(err, ShouldBeNil)
})
}
func TestTransferList(t *testing.T) {
var (
cid int64 = 10109082
)
Convey("test transfer list", t, func() {
l, err := svr.TransferList(c, cid)
So(err, ShouldBeNil)
So(l, ShouldNotBeEmpty)
})
}
func TestTransferRetry(t *testing.T) {
var (
id, mid int64 = 265, 1
)
Convey("test transfer retry", t, func() {
err := svr.TransferRetry(c, id, mid)
So(err, ShouldBeNil)
})
Convey("test transfer retry fail", t, func() {
err := svr.TransferRetry(c, id, mid)
So(err, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,162 @@
package service
import (
"context"
"encoding/json"
"math"
"sync/atomic"
"time"
"go-common/app/interface/main/dm/model"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/library/log"
"github.com/zhenjl/cityhash"
)
var (
_defaultVersion = uint64(0)
globalRuleVersion = uint64(time.Now().Nanosecond())
)
// AddUserRule add user rule
func (s *Service) AddUserRule(c context.Context, fType int8, mid int64, filters []string, comment string) (res []*dm2Mdl.UserFilter, err error) {
arg := &dm2Mdl.ArgAddUserFilters{
Type: fType,
Mid: mid,
Filters: filters,
Comment: comment,
}
if res, err = s.dmRPC.AddUserFilters(c, arg); err != nil {
log.Error("dmRPC.AddUserFilters(%+v) error(%v)", arg, err)
}
return
}
// UserRules return user rules
func (s *Service) UserRules(c context.Context, mid int64) (res []*dm2Mdl.UserFilter, err error) {
arg := &dm2Mdl.ArgMid{Mid: mid}
if res, err = s.dmRPC.UserFilters(c, arg); err != nil {
log.Error("dmRPC.UserFilters(%+v) error(%v)", arg, err)
}
return
}
// DelUserRules delete user rules
func (s *Service) DelUserRules(c context.Context, mid int64, idss []int64) (affect int64, err error) {
arg := &dm2Mdl.ArgDelUserFilters{Mid: mid, IDs: idss}
if affect, err = s.dmRPC.DelUserFilters(c, arg); err != nil {
log.Error("dmRPC.DelUserFilters(%+v) error(%v)", arg, err)
}
return
}
// GlobalRuleVersion return global rule version
func (s *Service) GlobalRuleVersion() uint64 {
return globalRuleVersion
}
// AddGlobalRule add global rule
func (s *Service) AddGlobalRule(c context.Context, fType int8, filter string) (res *dm2Mdl.GlobalFilter, err error) {
arg := &dm2Mdl.ArgAddGlobalFilter{Type: fType, Filter: filter}
if res, err = s.dmRPC.AddGlobalFilter(c, arg); err != nil {
log.Error("dmRPC.AddGlobalFilter(%+v) error(%v)", arg, err)
return
}
atomic.StoreUint64(&globalRuleVersion, _defaultVersion)
return
}
// GlobalRules return global rules
func (s *Service) GlobalRules(c context.Context) (res []*dm2Mdl.GlobalFilter, err error) {
arg := &dm2Mdl.ArgGlobalFilters{}
if res, err = s.dmRPC.GlobalFilters(c, arg); err != nil {
log.Error("dmRPC.GlobalFilters(%+v) error(%v)", arg, err)
return
}
if len(res) == 0 {
atomic.StoreUint64(&globalRuleVersion, _defaultVersion)
} else {
var buf []byte
if buf, err = json.Marshal(res); err != nil {
log.Error("json.Marshal() error(%v)", err)
return
}
atomic.StoreUint64(&globalRuleVersion, cityhash.CityHash64(buf, 16)%math.MaxInt64)
}
return
}
// DelGlobalRules delete global rules
func (s *Service) DelGlobalRules(c context.Context, ids []int64) (affect int64, err error) {
arg := &dm2Mdl.ArgDelGlobalFilters{IDs: ids}
if affect, err = s.dmRPC.DelGlobalFilters(c, arg); err != nil {
log.Error("dmRPC.DelGlobalFilters(%+v) error(%v)", arg, err)
return
}
// update global rule version
atomic.StoreUint64(&globalRuleVersion, _defaultVersion)
return
}
// FilterList get user filter list
func (s *Service) FilterList(c context.Context, mid, cid int64) (l *model.UserFilterList, err error) {
l = new(model.UserFilterList)
arg := &dm2Mdl.ArgUpFilters{Mid: mid}
res, err := s.dmRPC.UpFilters(c, arg)
if err != nil {
log.Error("dmRPC.UpFilters(%v) error(%v)", arg, err)
return
}
if len(res) == 0 {
return
}
for _, f := range res {
switch f.Type {
case dm2Mdl.FilterTypeBottom:
l.Bottom = f.Active
continue
case dm2Mdl.FilterTypeTop:
l.Top = f.Active
continue
case dm2Mdl.FilterTypeRev:
l.Reverse = f.Active
continue
}
filter := &model.IndexFilter{
ID: f.ID,
MID: f.Mid,
Filter: f.Filter,
Activate: f.Active,
Regex: f.Type,
Ctime: int64(f.Ctime),
}
l.Filter = append(l.Filter, filter)
}
return
}
// EditFilter edit up filter from creative center.
func (s *Service) EditFilter(c context.Context, cid, mid int64, filter string, fType, state int8) (err error) {
if state == dm2Mdl.FilterActive {
arg := &dm2Mdl.ArgAddUpFilters{
Mid: mid,
Type: fType,
Filters: []string{filter},
}
if err = s.dmRPC.AddUpFilters(c, arg); err != nil {
log.Error("dmRPC.AddUpFilters(%v) error(%v)", arg, err)
}
} else {
arg := &dm2Mdl.ArgEditUpFilters{
Type: fType,
Mid: mid,
Active: dm2Mdl.FilterUnActive,
Filters: []string{filter},
}
if _, err = s.dmRPC.EditUpFilters(c, arg); err != nil {
log.Error("dmRPC.EditUpFilters(%v) error(%v)", arg, err)
}
}
return
}

View File

@@ -0,0 +1,83 @@
package service
import (
"context"
"testing"
"go-common/library/ecode"
. "github.com/smartystreets/goconvey/convey"
)
// )
func TestAddUserRule(t *testing.T) {
Convey("test add user rule", t, func() {
_, err := svr.AddUserRule(context.TODO(), 1, 150781, []string{"aa", "bb"}, "comment")
So(err, ShouldBeNil)
})
}
func TestUserRules(t *testing.T) {
Convey("test get user rule", t, func() {
rs, err := svr.UserRules(context.TODO(), 27515256)
So(err, ShouldBeNil)
So(rs, ShouldNotBeEmpty)
})
}
func TestDelUserRules(t *testing.T) {
Convey("test del user rule", t, func() {
_, err := svr.DelUserRules(context.TODO(), 27515256, []int64{12, 3, 4})
So(err, ShouldBeNil)
})
}
func TestAddGlobalRule(t *testing.T) {
Convey("test add global rule", t, func() {
_, err := svr.AddGlobalRule(context.TODO(), 1, "aa")
So(err, ShouldBeNil)
})
}
func TestGlobalRules(t *testing.T) {
Convey("test global rule", t, func() {
rs, err := svr.GlobalRules(context.TODO())
So(err, ShouldBeNil)
So(rs, ShouldNotBeEmpty)
})
}
func TestDelGlobalRules(t *testing.T) {
Convey("test del global rule", t, func() {
_, err := svr.DelGlobalRules(context.TODO(), []int64{12, 3, 4})
So(err, ShouldBeNil)
})
}
func TestServiceFilterList(t *testing.T) {
var (
c = context.TODO()
cid, mid int64 = 0, 150781
)
Convey("test filter list", t, func() {
f, err := svr.FilterList(c, mid, cid)
So(err, ShouldBeNil)
So(f, ShouldNotBeNil)
})
}
func TestEditFilter(t *testing.T) {
Convey("test insert regex filter", t, func() {
err := svr.EditFilter(c, 0, 150781, ".*", 1, 1)
So(err, ShouldBeNil)
})
Convey("test insert wrong regex filter", t, func() {
err := svr.EditFilter(c, 0, 150781, ".[*", 1, 1)
So(err, ShouldEqual, ecode.DMFitlerIllegalRegex)
})
Convey("test update filter", t, func() {
err := svr.EditFilter(c, 0, 150781, ".*", 1, 1)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,363 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/dm/model"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/app/interface/main/dm2/model/oplog"
account "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_notifyUpTitle = "有新的弹幕保护申请"
_notifyUpContent = `您今天新增了一些未处理弹幕保护申请,前去 #{创作中心 - 哔哩哔哩弹幕视频网 - ( ゜- ゜)つロ 乾杯~}{"http://member.bilibili.com/v/#/danmu/report/save"} 处理吧`
_notifyUsrTitle = "弹幕保护申请情况更新~"
_pa48 = "由于up主日理万机您之前申请的%d条弹幕暂未受理请稍后再次申请"
_paa = `您在视频 #{%s}{"http://www.bilibili.com/video/av%d/"} 已被全部保护`
_pap = `您在视频 #{%s}{"http://www.bilibili.com/video/av%d/"} 已被部分保护`
_protectApplyLevel = 4
_maxProtectApply = 100
_paExpire = 48 * 3600
)
// AddProtectApply 批量申请保护弹幕
func (s *Service) AddProtectApply(c context.Context, uid, cid int64, dmids []int64) (err error) {
if len(dmids) == 0 {
err = ecode.DMNotFound
return
}
count, err := s.dao.PaUsrCnt(c, uid)
if err != nil {
log.Error("s.dao.PaUsrCnt(%d) error(%v)", uid, err)
return
}
if (count + len(dmids)) > _maxProtectApply {
err = ecode.DMPAUserLimit
return
}
cardReply, err := s.accountSvc.Card3(c, &account.MidReq{Mid: uid})
if err != nil {
log.Error("s.actSvc.Card3(%d) error(%v)", uid, err)
return
}
if cardReply.GetCard().GetLevel() < _protectApplyLevel {
err = ecode.DMPAUserLevel
return
}
dms, err := s.dms(c, model.SubTypeVideo, cid, dmids)
if err != nil {
return
}
dc := len(dmids)
if len(dms) < 1 && dc == 1 {
err = ecode.DMNotFound
return
}
sub, err := s.subject(c, 1, cid)
if err != nil {
return
}
aps := make([]*model.Pa, 0, len(dms))
now := time.Now().Unix()
var ctime time.Time
for _, dm := range dms {
if dm.Mid != uid && dc == 1 {
err = ecode.DMPADMNotOwner
return
}
if dm.AttrVal(model.AttrProtect) == model.AttrYes && dc == 1 {
err = ecode.DMPADMProtected
return
}
if !dm.NeedDisplay() && dc == 1 {
err = ecode.DMNotFound
return
}
ctime, err = s.dao.ProtectApplyTime(c, dm.ID)
if err != nil {
log.Error("dao.ProtectApplyTime(%d) error(%v)", uid, err)
continue
}
if now-ctime.Unix() < _paExpire {
if dc == 1 {
err = ecode.DMPADMLimit
return
}
continue
}
ap := &model.Pa{
CID: cid,
UID: sub.Mid,
ApplyUID: dm.Mid,
AID: sub.Pid,
Playtime: float32(dm.Progress) / 1000,
DMID: dm.ID,
Msg: dm.Content.Msg,
Status: -1,
Ctime: time.Now(),
Mtime: time.Now(),
}
aps = append(aps, ap)
}
if len(aps) < 1 {
err = ecode.DMPAFailed
return
}
affect, err := s.dao.AddProtectApply(c, aps)
if err != nil {
log.Error("dao.AddProtectApply(%v) error(%v)", aps, err)
return
}
if err = s.dao.UptUsrPaCnt(c, uid, affect); err != nil {
log.Error("s.dao.UptUsrPaCnt(%d,%d) error(%v)", uid, affect, err)
}
return
}
// UptPaSwitch 保护弹幕申请开关
func (s *Service) UptPaSwitch(c context.Context, uid int64, status int) (err error) {
if status != 1 {
status = 0
}
_, err = s.dao.UptPaNoticeSwitch(c, uid, status)
return
}
// UptPaStatus 审核保护弹幕申请
func (s *Service) UptPaStatus(c context.Context, mid int64, ids []int64, status int) (err error) {
dmids, err := s.dao.ProtectApplyByIDs(c, mid, xstr.JoinInts(ids))
if err != nil {
log.Error("s.dao.ProtectApplyByIDs(%d,%s) error(%v)", mid, xstr.JoinInts(ids), err)
return
}
if status != 1 {
status = 0
}
if _, err = s.dao.UptPaStatus(c, mid, xstr.JoinInts(ids), status); err != nil {
log.Error("s.dao.UptPaStatus(%d,%v,%d) error(%v)", mid, ids, status, err)
return
}
if status == 0 {
return
}
for oid, ids := range dmids {
arg := &dm2Mdl.ArgEditDMAttr{
Type: 1,
Oid: oid,
Mid: mid,
Bit: dm2Mdl.AttrProtect,
Value: dm2Mdl.AttrYes,
Dmids: ids,
Source: oplog.SourceUp,
OperatorType: oplog.OperatorUp,
}
if err = s.dmRPC.EditDMAttr(c, arg); err != nil {
log.Error("s.dmRPC.EditDMAttr(%+v) error(%v)", arg, err)
return
}
}
return
}
// ProtectApplies 保护弹幕申请列表
func (s *Service) ProtectApplies(c context.Context, uid, aid int64, page int, sort string) (res *model.ApplyListResult, err error) {
var (
count int
start int
)
if page < 1 {
page = 1
}
res = &model.ApplyListResult{
Pager: &model.Pager{},
List: make([]*model.Apply, 0, model.ProtectApplyLimit),
}
res.List, err = s.dao.ProtectApplies(c, uid, aid, sort)
if err != nil {
log.Error("s.dao.PaLs(%d) error(%v)", uid, err)
return
}
count = len(res.List)
res.Pager.Current = page
res.Pager.Total = count / model.ProtectApplyLimit
res.Pager.Size = model.ProtectApplyLimit
res.Pager.TotalCount = count
if count%model.ProtectApplyLimit != 0 {
res.Pager.Total++
}
if count == 0 {
res.List = make([]*model.Apply, 0, 1)
return
}
start = (page - 1) * model.ProtectApplyLimit
if start > count {
start = 0
}
end := start + model.ProtectApplyLimit
if end > count {
end = count
}
res.List = res.List[start:end]
aids := make([]int64, 0, len(res.List))
uids := make([]int64, 0, len(res.List))
for _, a := range res.List {
aids = append(aids, a.AID)
uids = append(uids, a.ApplyUID)
}
infosReply, err := s.accountSvc.Infos3(c, &account.MidsReq{
Mids: uids,
})
if err != nil {
log.Error("s.actSvc.Infos2(%v) error(%v)", uids, err)
err = nil
}
archives := s.archiveInfos(c, aids)
for _, a := range res.List {
v, ok := archives[a.AID]
if ok {
a.Pic = v.Pic
a.Title = v.Title
}
u, ok := infosReply.GetInfos()[a.ApplyUID]
if ok {
a.Uname = u.GetName()
}
}
return
}
// PaVideoLs 被申请保护弹幕的视频列表
func (s *Service) PaVideoLs(c context.Context, uid int64) (res []*model.Video, err error) {
aids, err := s.dao.ProtectAids(c, uid)
if err != nil {
log.Error("s.dao.ProtectArchives(%d) error(%v)", uid, err)
return
}
archives := s.archiveInfos(c, aids)
res = make([]*model.Video, 0, len(aids))
for _, aid := range aids {
a := new(model.Video)
v, ok := archives[aid]
a.Aid = aid
if ok {
a.Title = v.Title
} else {
a.Title = ""
}
res = append(res, a)
}
return
}
// sendProtectNotifyToUp 发送申请保护弹幕通知给up主
func (s *Service) sendProtectNotifyToUp(c context.Context) (err error) {
if time.Now().Format("15") != "20" {
return
}
lk, err := s.dao.PaLock(c, "up")
if err != nil {
log.Error("s.dao.PaLock() error(%v)", err)
return
}
if lk != 1 {
return
}
uids, err := s.dao.ProtectApplyStatistics(c)
if err != nil {
log.Error("s.dao.PaStat() error(%v)", err)
return
}
if len(uids) < 1 {
return
}
m, err := s.dao.PaNoticeClose(c, uids)
if err != nil {
log.Error("s.dao.PaNoticeClose(%v) error(%v)", uids, err)
return
}
if len(m) > 0 {
for k, v := range uids {
if _, ok := m[v]; ok {
uids = append(uids[:k], uids[k+1:]...)
}
}
}
s.dao.SendNotify(c, _notifyUpTitle, _notifyUpContent, uids)
return
}
// sendProtectNotifyToUser 发送申请保护弹幕处理结果给申请用户
func (s *Service) sendProtectNotifyToUser(c context.Context) {
if time.Now().Format("15") != "22" {
return
}
incr, err := s.dao.PaLock(c, "user")
if err != nil {
log.Error("s.dao.PaLock() error(%v)", err)
return
}
if incr != 1 {
return
}
stats, err := s.dao.PaUsrStat(c)
if err != nil {
log.Error("s.dao.PaStat() error(%v)", err)
return
}
aids := make([]int64, 0, len(stats))
for _, stat := range stats {
aids = append(aids, stat.Aid)
}
archives := s.archiveInfos(c, aids)
userStats := make(map[int64]map[int64]*model.ApplyUserNotify)
now := time.Now().Unix()
untreated := make(map[int64]int)
for _, stat := range stats {
m, ok := userStats[stat.Aid]
if !ok {
m = make(map[int64]*model.ApplyUserNotify)
userStats[stat.Aid] = m
}
n, ok := m[stat.UID]
if !ok {
n = &model.ApplyUserNotify{}
m[stat.UID] = n
}
if stat.Status == 1 {
n.Protect++
} else {
n.Unprotect++
if stat.Status == -1 && (now-stat.Ctime.Unix()) > 2*24*3600 {
untreated[stat.UID]++
}
}
}
for k, v := range untreated {
s.dao.SendNotify(c, _notifyUsrTitle, fmt.Sprintf(_pa48, v), []int64{k})
}
for aid, m := range userStats {
archive, ok := archives[aid]
if !ok {
continue
}
for uid, stat := range m {
var content string
if stat.Protect > 0 && stat.Unprotect == 0 {
content = fmt.Sprintf(_paa, archive.Title, archive.Aid)
}
if stat.Protect > 0 && stat.Unprotect > 0 {
content = fmt.Sprintf(_pap, archive.Title, archive.Aid)
}
if content == "" {
continue
}
s.dao.SendNotify(c, _notifyUsrTitle, content, []int64{uid})
}
}
}

View File

@@ -0,0 +1,48 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestAddProtectApply(t *testing.T) {
Convey("test add protect apply", t, func() {
err := svr.AddProtectApply(context.TODO(), 27515256, 10108163, []int64{719925843, 719925844})
So(err, ShouldBeNil)
})
}
func TestUptPaSwitch(t *testing.T) {
Convey("test upt pa switch", t, func() {
err := svr.UptPaSwitch(context.TODO(), 27515256, 1)
So(err, ShouldBeNil)
err = svr.UptPaSwitch(context.TODO(), 27515256, 0)
So(err, ShouldBeNil)
})
}
func TestUptPaStatus(t *testing.T) {
Convey("test upt pa status", t, func() {
err := svr.UptPaStatus(context.TODO(), 27515256, []int64{541, 542}, 1)
So(err, ShouldBeNil)
err = svr.UptPaStatus(context.TODO(), 27515256, []int64{541, 542}, -1)
So(err, ShouldBeNil)
})
}
func TestProtectApplies(t *testing.T) {
Convey("test protect applies", t, func() {
res, err := svr.ProtectApplies(context.TODO(), 27515256, 10097377, 1, "playtime")
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestPaVideoLs(t *testing.T) {
Convey("test pa video ls", t, func() {
_, err := svr.PaVideoLs(context.TODO(), 27515256)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,412 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/dm/model"
"go-common/app/interface/main/dm2/model/oplog"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_reportLock = 1800
_reportLimit = 10
_rptAutoDelCnt = 3
)
// AddReport add dm report.
func (s *Service) AddReport(c context.Context, cid, dmid, uid int64, reason int8, content string) (id int64, err error) {
var (
needDelete, needHide bool
state int8
score int32
)
t, err := s.dao.RptBrigTime(c, uid)
if err != nil {
return
}
if time.Now().Unix()-t < _reportLock {
err = ecode.DMReportLimit
return
}
cnt, err := s.dao.RptCnt(c, uid)
if err != nil {
return
}
if cnt >= _reportLimit {
if err = s.dao.AddRptBrig(c, uid); err != nil {
log.Error("s.dao.AddRptBrig(%d) error(%v)", uid, err)
}
err = ecode.DMReportLimit
return
}
dms, err := s.dms(c, model.SubTypeVideo, cid, []int64{dmid})
if err != nil {
return
}
if len(dms) == 0 || !dms[0].NeedDisplay() {
err = ecode.DMReportNotExist
return
}
if _, err = s.dao.UptRptCnt(c, uid); err != nil {
log.Error("s.dao.UptRptCnt(%d) error(%v)", uid, err)
err = nil
}
rpt, err := s.dao.Report(c, cid, dmid)
if err != nil {
log.Error("s.dao.Report(cid:%d,dmid:%d) error(%v)", cid, dmid, err)
return
}
// score
if score, err = s.dao.FigureInfo(c, uid); err != nil {
log.Error("s.dao.FigureInfo(uid: %d) error(%v)", uid, err)
return
}
if score < 0 || score > 100 {
log.Error("s.AddReport.score illegal(uid: %d) score(%v)", uid, score)
score = 0
} else {
score = 100 - score
}
if rpt != nil {
state, err = s.checkReasonType(c, reason, cid, dmid, rpt)
if err != nil {
log.Error("s.checkReasonType(reason: %d) error(%v)", reason, err)
return
}
/*
以下弹幕不能自动删除与隐藏
1. mode7、mode8、mode9弹幕
2. 字幕弹幕
3. 保护弹幕
4. up主在自己的视频下发送的弹幕
*/
if state == model.StatSecondInit &&
dms[0].Content.Mode != 7 &&
dms[0].Content.Mode != 8 &&
dms[0].Content.Mode != 9 &&
dms[0].AttrVal(model.AttrProtect) != model.AttrYes &&
dms[0].Pool == 0 &&
!s.isUpper(c, cid, dms[0].Mid) {
if (reason == model.ReportReasonAd && rpt.Reason == model.ReportReasonAd) || rpt.Count >= _rptAutoDelCnt-1 || rpt.Score+score >= 160 {
needDelete = true
} else {
needHide = true
}
}
} else {
state = s.reasonType(reason)
if state == model.StatSecondInit &&
dms[0].Content.Mode != 7 &&
dms[0].Content.Mode != 8 &&
dms[0].Content.Mode != 9 &&
dms[0].AttrVal(model.AttrProtect) != model.AttrYes &&
dms[0].Pool == 0 &&
!s.isUpper(c, cid, dms[0].Mid) {
needHide = true
}
}
nowTime := time.Now()
r := &model.Report{
Cid: cid,
Did: dmid,
UID: uid,
Reason: reason,
Content: content,
Count: 1,
State: state,
UpOP: model.StatUpperInit,
Score: score,
RpTime: nowTime,
Ctime: nowTime,
Mtime: nowTime,
}
u := &model.User{
Did: dmid,
UID: uid,
State: model.NoticeUnsend,
Reason: reason,
Content: content,
Ctime: nowTime,
Mtime: nowTime,
}
lastID, err := s.dao.AddReportUser(c, u)
if err != nil {
log.Error("s.dao.AddReportUser(%v) error(%v)", u, err)
return
}
if lastID < 1 {
err = ecode.DMReportExist
return
}
if id, err = s.dao.AddReport(c, r); err != nil {
log.Error("s.dao.AddReport(%v) error(%v)", r, err)
return
}
if needDelete {
select {
case s.delDMReportChan <- rpt:
default:
log.Error("s.delDMReportChan.full(%v)", rpt)
}
}
if needHide && !needDelete {
select {
case s.hideDMReportChan <- r:
default:
log.Error("s.hideDMReportChan.full(%v)", r)
}
}
return
}
// EditReport edit report dm.
func (s *Service) EditReport(c context.Context, tp int32, cid, mid, dmid int64, op int8) (affect int64, err error) {
r, err := s.dao.Report(c, cid, dmid)
if err != nil {
log.Error("s.dao.Report(cid:%d, dmid:%d), error(%v)", cid, dmid, err)
return
}
if r == nil {
err = ecode.DMReportNotExist
return
}
if !s.isUpper(c, cid, mid) {
err = ecode.ArchiveOwnerErr
return
}
if affect, err = s.dao.UpdateReportUPOp(c, cid, dmid, op); err != nil {
log.Error("s.dao.UpdateReportUPOp(cid:%d, dmid:%d, op:%d) error(%v)", cid, dmid, op, err)
}
if op == model.StatUpperDelete {
if err = s.EditDMState(c, tp, cid, mid, model.StateDelete, oplog.SourceUp, oplog.OperatorUp, dmid); err != nil {
log.Error("s.EditDMStat(cid:%d,dmid:%d) error(%v)", cid, dmid, err)
return
}
}
v := &model.UptSearchReport{
DMid: dmid,
Upop: op,
Ctime: r.Ctime.Format("2006-01-02 15:04:05"),
Mtime: time.Now().Format("2006-01-02 15:04:05"),
}
err = s.dao.UpdateSearchReport(c, []*model.UptSearchReport{v})
return
}
// ReportList 获取一个用户的所有被举报的弹幕
func (s *Service) ReportList(c context.Context, mid, aid, page, size int64, upOp int8, states []int64) (res *model.RptSearchs, err error) {
res = &model.RptSearchs{}
var (
aidsMap = make(map[int64]struct{})
aids = []int64{}
cidDMids = make(map[int64][]int64)
stateMap = make(map[int64]int64)
)
rptSearch, err := s.dao.SearchReport(c, mid, aid, page, size, upOp, states)
if err != nil || rptSearch == nil {
return
}
for _, v := range rptSearch.Result {
if _, ok := aidsMap[v.Aid]; !ok {
aidsMap[v.Aid] = struct{}{}
aids = append(aids, v.Aid)
}
cidDMids[v.Cid] = append(cidDMids[v.Cid], v.Did)
}
archives := s.archiveInfos(c, aids)
if stateMap, err = s.dmState(c, cidDMids); err != nil {
return
}
for _, v := range rptSearch.Result {
if arc, ok := archives[v.Aid]; ok {
v.Title = arc.Title
v.Cover = arc.Pic
}
if state, ok := stateMap[v.Did]; ok {
v.Deleted = state
}
}
res = &model.RptSearchs{
Page: rptSearch.Page.Num,
PageSize: rptSearch.Page.Size,
PageCount: (rptSearch.Page.Total-1)/rptSearch.Page.Size + 1,
Total: rptSearch.Page.Total,
Result: rptSearch.Result,
}
return
}
func (s *Service) isUpper(c context.Context, cid, mid int64) bool {
sub, err := s.subject(c, 1, cid)
if err != nil {
return false
}
return sub.Mid == mid
}
// checkReasonType get state by report reason
func (s *Service) checkReasonType(c context.Context, reason int8, cid, dmid int64, rpt *model.Report) (state int8, err error) {
reportLog, err := s.dao.ReportLog(c, dmid)
if err != nil {
log.Error("s.dao.ReportLog(dmid:%d) error(%v)", dmid, err)
return
}
if len(reportLog) > 0 { // 如果这个举报已经在后台被处理了,那就根据举报当前的状态返回对应的一二审状态
if rpt.State == model.StatFirstInit ||
rpt.State == model.StatFirstDelete ||
rpt.State == model.StatFirstIgnore {
state = model.StatFirstInit
} else {
state = model.StatSecondInit
}
} else { // 否则就根据举报理由来返回状态
state = s.reasonType(reason)
}
return
}
// ReportArchives 获取一个用户的所有被举报的稿件
func (s *Service) ReportArchives(c context.Context, mid int64, upOp int8, states []int8, pn, ps int64) (res *model.Archives, err error) {
res = &model.Archives{}
aids, err := s.dao.SearchReportAid(c, mid, upOp, states, pn, ps)
if err != nil || len(aids) == 0 {
return
}
archiveInfos := s.archiveInfos(c, aids)
for aid, info := range archiveInfos {
res.Result = append(res.Result, &struct {
Aid int64 `json:"aid"`
Title string `json:"title"`
}{Aid: aid, Title: info.Title})
}
return
}
func (s *Service) reasonType(reason int8) (state int8) {
if reason == model.ReportReasonProhibited ||
reason == model.ReportReasonPorn ||
reason == model.ReportReasonFraud ||
reason == model.ReportReasonAttack ||
reason == model.ReportReasonPrivate ||
reason == model.ReportReasonTeenagers {
state = model.StatFirstInit
} else {
state = model.StatSecondInit
}
return
}
// deleteDMReport delete dm report.
func (s *Service) deleteDMReport(c context.Context, rpt *model.Report) (err error) {
sub, err := s.subject(c, 1, rpt.Cid)
if err != nil {
return
}
rpt.State = model.StatSecondAutoDelete
if err = s.EditDMState(c, 1, rpt.Cid, sub.Mid, model.StateScriptDelete, oplog.SourceUp, oplog.OperatorUp, rpt.Did); err != nil {
log.Error("s.EditDMStat(cid:%d, state:%d, dmid:%d ) error(%v)", rpt.Cid, rpt.State, rpt.Did, err)
return
}
if _, err = s.dao.UpdateReportStat(c, rpt.Cid, rpt.Did, rpt.State); err != nil {
log.Error("s.dao.UpdateReportStat(cid:%d, state:%d, dmid:%d ) error(%v)", rpt.Cid, rpt.State, rpt.Did, err)
return
}
lg := &model.RptLog{
Did: rpt.Did,
AdminID: 0,
Reason: rpt.Reason,
Result: rpt.State,
Remark: "自动删除",
Elapsed: int64(time.Since(rpt.Mtime).Seconds()),
Ctime: time.Now(),
Mtime: time.Now(),
}
if err = s.dao.AddReportLog(c, lg); err != nil {
log.Error("s.dao.AddReportLog(log:%v) error(%v)", lg, err)
return
}
users, err := s.dao.ReportUser(c, rpt.Did)
if err != nil {
log.Error("s.dao.ReportUser(dmid:%d) error(%v)", rpt.Did, err)
return
}
if err = s.dao.SetReportUserFinished(c, rpt.Did); err != nil {
log.Error("s.dao.SetReportUserFinished(dmid:%d) error(%v)", rpt.Did, err)
return
}
ct, err := s.dao.Content(c, rpt.Cid, rpt.Did)
if err != nil || ct == nil {
return
}
arc, err := s.acvSvc.Archive3(c, &arcMdl.ArgAid2{Aid: sub.Pid})
if err != nil {
log.Error("s.acvSvc.Archive3(%d) error(%v)", sub.Pid, err)
return
}
for _, u := range users {
content := fmt.Sprintf(model.RptMsgTemplate, arc.Title, arc.Aid, ct.Msg, model.ReportReason[rpt.Reason])
s.dao.SendNotify(c, model.RptMsgTitle, content, []int64{u.UID})
}
return
}
//hideDMReport hide reported dm
func (s *Service) hideDMReport(c context.Context, rpt *model.Report) (err error) {
dmids := []int64{rpt.Did}
//change dm state to hide
_, err = s.dao.UpdateDMStat(c, 1, rpt.Cid, model.StateHide, dmids)
if err != nil {
log.Error("s.dao.UpdateDMStat(oid:%d state:%d dmids:%v) error(%v)", rpt.Cid, model.StateHide, rpt.Did, err)
return
}
// send hideTime to databus
time := time.Now().Unix() + 72000
act := &model.ReportAction{
Cid: rpt.Cid,
Did: rpt.Did,
HideTime: time,
}
// make sure all the hided dms are in one partition
if err = s.dao.SendAction(context.TODO(), "1", act); err != nil {
log.Error("databus.Send(%+v) error(%v)", act, err)
}
return
}
func (s *Service) dmReportProc() {
for {
select {
case rpt := <-s.delDMReportChan:
if err := s.deleteDMReport(context.TODO(), rpt); err != nil {
log.Error("s.deleteDMReport(rpt:%v) error(%v)", rpt, err)
}
case rpt := <-s.hideDMReportChan:
if err := s.hideDMReport(context.TODO(), rpt); err != nil {
log.Error("s.hideDMReport(rpt:%v) error(%v)", rpt, err)
}
}
}
}
func (s *Service) dmState(c context.Context, cidDmids map[int64][]int64) (stateMap map[int64]int64, err error) {
var (
idxMap map[int64]*model.DM
tp = int32(1)
)
stateMap = make(map[int64]int64)
for oid, dmids := range cidDmids {
if idxMap, _, err = s.dao.IndexsByID(c, tp, oid, dmids); err != nil {
return
}
for dmid, dm := range idxMap {
stateMap[dmid] = int64(dm.State)
}
}
return
}

View File

@@ -0,0 +1,70 @@
package service
import (
"context"
"testing"
"go-common/app/interface/main/dm/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
c = context.TODO()
cid = int64(10106598)
dmid = int64(719918177)
uid = int64(1234567)
reason = int8(1)
content = "aaaaaa"
)
func TestAddReport(t *testing.T) {
Convey("test add report", t, func() {
id, err := svr.AddReport(c, cid, dmid, uid, reason, content)
So(err, ShouldBeNil)
So(id, ShouldBeGreaterThan, 0)
})
}
func TestReportList(t *testing.T) {
var (
mid, aid, page, size int64 = 27515615, 0, 1, 100
upOp int8
state = []int64{0, 2}
)
Convey("test report list", t, func() {
list, err := svr.ReportList(c, mid, aid, page, size, upOp, state)
So(err, ShouldBeNil)
So(list, ShouldNotBeNil)
})
}
func TestReportArchives(t *testing.T) {
var (
mid, pn, ps int64 = 27515256, 1, 20
upOp int8
states = []int8{0, 2}
)
Convey("test report archive list", t, func() {
res, err := svr.ReportArchives(c, mid, upOp, states, pn, ps)
So(err, ShouldBeNil)
if res != nil {
for _, v := range res.Result {
t.Logf("%+v", v)
}
}
})
}
func TestEditReport(t *testing.T) {
var (
cid int64 = 10114205
dmid int64 = 719218893
mid int64 = 27515615
upOp = int8(model.StateDelete)
)
Convey("test edit report", t, func() {
_, err := svr.EditReport(c, 1, cid, mid, dmid, upOp)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,67 @@
package service
import (
"context"
"time"
"go-common/app/interface/main/dm/conf"
"go-common/app/interface/main/dm/dao"
"go-common/app/interface/main/dm/model"
dmCli "go-common/app/interface/main/dm2/rpc/client"
accoutCli "go-common/app/service/main/account/api"
arcCli "go-common/app/service/main/archive/api/gorpc"
assCli "go-common/app/service/main/assist/rpc/client"
)
// Service define Service struct
type Service struct {
c *conf.Config
// dao
dao *dao.Dao
// rpc
acvSvc *arcCli.Service2
accountSvc accoutCli.AccountClient
astSvc *assCli.Service
dmRPC *dmCli.Service
//proc
delDMReportChan chan *model.Report
hideDMReportChan chan *model.Report
}
// New new a Service and return.cdfg
func New(c *conf.Config) *Service {
s := &Service{
c: c,
// dmDao
dao: dao.New(c),
// archive rpc service
acvSvc: arcCli.New2(c.ArchiveRPC),
astSvc: assCli.New(c.AssistRPC),
dmRPC: dmCli.New(c.DMRPC),
//proc
delDMReportChan: make(chan *model.Report, 1024),
hideDMReportChan: make(chan *model.Report, 1024),
}
accountSvc, err := accoutCli.NewClient(c.AccountRPC)
if err != nil {
panic(err)
}
s.accountSvc = accountSvc
go s.dmReportProc()
go s.cronproc()
return s
}
// Ping check server ok
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// cronproc 一分钟执行一次
func (s *Service) cronproc() {
for {
<-time.After(time.Minute)
go s.sendProtectNotifyToUp(context.Background())
go s.sendProtectNotifyToUser(context.Background())
}
}

View File

@@ -0,0 +1,29 @@
package service
import (
"flag"
"os"
"path/filepath"
"testing"
"go-common/app/interface/main/dm/conf"
)
var (
svr *Service
)
func TestMain(m *testing.M) {
var (
err error
)
dir, _ := filepath.Abs("../cmd/dm-test.toml")
if err = flag.Set("conf", dir); err != nil {
panic(err)
}
if err = conf.Init(); err != nil {
panic(err)
}
svr = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,18 @@
package service
import (
"context"
"go-common/app/interface/main/dm/model"
"go-common/library/ecode"
)
func (s *Service) subject(c context.Context, tp int32, oid int64) (sub *model.Subject, err error) {
if sub, err = s.dao.Subject(c, tp, oid); err != nil {
return
}
if sub == nil {
err = ecode.NothingFound
}
return
}