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/admin/main/videoup-task/cmd:all-srcs",
"//app/admin/main/videoup-task/conf:all-srcs",
"//app/admin/main/videoup-task/dao:all-srcs",
"//app/admin/main/videoup-task/http:all-srcs",
"//app/admin/main/videoup-task/model:all-srcs",
"//app/admin/main/videoup-task/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,36 @@
#### 稿件审核后台接口
##### Version 1.0.10
> 1.up-service使用grpc
##### Version 1.0.9
> 1.account使用grpc
##### Version 1.0.8
> 1.1000条登入日志不够用扩充为10000条
##### Version 1.0.7
> 1.任务复审
> 2.从videoup-admin迁移task
##### Version 1.0.6
> 1.质检任务删除一个月前操作过的数据
##### Version 1.0.5
> 1.稿件表主从库实例分离,防止主从同步延迟导致读取从库报错,从而上报任务停留时间失败
##### Version 1.0.4
> 1.任务质检上报任务停留时间加日志
##### Version 1.0.3
> 1.审核员报表去掉不在线的员工的退出时间
##### Version 1.0.2
> 1.迁移审核员24小时处理报表优化查询速度
##### Version 1.0.1
> 1.详情页的最新视频审核备注从archive_video_audit.note改为archive_video_oper.remark前者长度过小
> 2.任务上报停留时间接口先查询任务是否存在
##### Version 1.0.0
> 1.一审任务质检

View File

@@ -0,0 +1,11 @@
# Owner
shencen
wangzhe01
# Author
chenxi01
chenxuefeng
# Reviewer
chenxi01
chenxuefeng

View File

@@ -0,0 +1,16 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- chenxi01
- chenxuefeng
- shencen
- wangzhe01
labels:
- admin
- admin/main/videoup-task
- main
options:
no_parent_owners: true
reviewers:
- chenxi01
- chenxuefeng

View File

@@ -0,0 +1,46 @@
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 = ["videoup-task-admin.toml"],
importpath = "go-common/app/admin/main/videoup-task/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/videoup-task/conf:go_default_library",
"//app/admin/main/videoup-task/http:go_default_library",
"//app/admin/main/videoup-task/service:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
"//library/os/signal:go_default_library",
"//library/queue/databus/report:go_default_library",
"//library/syscall: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,59 @@
package main
import (
"flag"
"fmt"
"os"
"time"
"go-common/app/admin/main/videoup-task/conf"
"go-common/app/admin/main/videoup-task/http"
"go-common/app/admin/main/videoup-task/service"
"go-common/library/log"
"go-common/library/net/trace"
"go-common/library/os/signal"
"go-common/library/queue/databus/report"
"go-common/library/syscall"
)
func main() {
var err error
//conf init
flag.Parse()
if err = conf.Init(); err != nil {
panic(err)
}
//log init
log.Init(conf.Conf.Xlog)
defer log.Close()
fmt.Printf("conf(%+v)", conf.Conf)
report.InitManager(conf.Conf.ManagerReport)
//trace init
trace.Init(nil)
defer trace.Close()
//http init
srv := service.New(conf.Conf)
http.Init(conf.Conf, srv)
//signal notify to change service behavior
sch := make(chan os.Signal, 1)
signal.Notify(sch, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-sch
log.Info("videoup-task-admin got a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("videoup-task-admin is closed")
srv.Close()
time.Sleep(time.Second * 1)
return
case syscall.SIGHUP:
//reload
default:
return
}
}
}

View File

@@ -0,0 +1,205 @@
# This is a TOML document. Boom.
[host]
api = "http://uat-api.bilibili.com"
search = "http://uat-bili-search.bilibili.co"
[xlog]
dir = "/data/log/videoup-task-admin/"
family = "videoup-task-admin"
#[xlog.agent]
#taskID = "000069"
#proto = "unixgram"
#addr = "/var/run/lancer/collector.sock"
#chanSize = 10240
[managerReport]
key = "2511663d546f1413"
secret="cde3b480836cc76df3d635470f991caa"
group= "LogAudit-MainSearch-P"
topic= "LogAudit-T"
action="pub"
buffer=10240
name = "log-audit/log-sub"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 10
active = 10
dialTimeout = "200ms"
readTimeout = "200ms"
writeTimeout = "200ms"
idleTimeout = "80s"
[httpClient]
key = "6aa4286456d16b97"
secret = "351cf022e1ae8296109c3c524faafcc8"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[bm]
addr = "0.0.0.0:7701"
maxListen = 1000
timeout = "1s"
[db]
[db.archive]
name = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_archive?interpolateParams=true&timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
idleTimeout ="4h"
queryTimeout = "5s"
execTimeout = "5s"
tranTimeout = "10s"
[db.archive.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.archiveRead]
name = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_archive?interpolateParams=true&timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
idleTimeout ="4h"
queryTimeout = "5s"
execTimeout = "5s"
tranTimeout = "10s"
[db.archiveRead.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.manager]
name = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_manager?interpolateParams=true&timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8"
active = 5
idle = 2
idleTimeout ="4h"
queryTimeout = "5s"
execTimeout = "5s"
tranTimeout = "10s"
[db.manager.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth]
managerHost = "http://uat-manager.bilibili.co"
dashboardHost = "http://dashboard-mng.bilibili.co"
dashboardCaller = "manager-go"
[auth.DsHTTPClient]
key = "manager-go"
secret = "949bbb2dd3178252638c2407578bc7ad"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.DsHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.MaHTTPClient]
key = "f6433799dbd88751"
secret = "36f8ddb1806207fe07013ab6a77a3935"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.MaHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.session]
sessionIDLength = 32
cookieLifeTime = 604800
cookieName = "mng-go"
domain = ".bilibili.co"
[auth.session.Memcache]
name = "go-business/auth"
proto = "tcp"
addr = "172.18.33.61:11232"
active = 5
idle = 2
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[identify]
whiteAccessKey = ""
whiteMid = 0
[identify.app]
key = "53e2fa226f5ad348"
secret = "3cf6bd1b0ff671021da5f424fea4b04a"
[identify.host]
auth = "http://uat-passport.bilibili.com"
secret = "http://uat-open.bilibili.com"
[identify.httpClient]
key = "6aa4286456d16b97"
secret = "351cf022e1ae8296109c3c524faafcc8"
dial = "500ms"
timeout = "800ms"
keepAlive = "60s"
[identify.httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[identify.httpClient.url]
"http://uat-passport.bilibili.co/intranet/auth/tokenInfo" = {timeout = "100ms"}
"http://uat-passport.bilibili.co/intranet/auth/cookieInfo" = {timeout = "100ms"}
"http://uat-open.bilibili.co/api/getsecret" = {timeout = "500ms"}
[redis]
[redis.weight]
name = "video-admin/weight"
proto = "tcp"
addr = "172.16.33.54:6381"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "10s"
[hbase]
master = ""
meta = ""
dialTimeout = "1s"
readTimeout = "10s"
readsTimeout = "10s"
writeTimeout = "10s"
writesTimeout = "10s"
[hbase.zookeeper]
root = ""
addrs = ["172.18.33.131:2181","172.18.33.168:2181","172.18.33.169:2181"]
timeout = "30s"
[RPC]
[rpc.upsRPC]
timeout = "1s"
[GRPC]
[grpc.accRPC]
timeout = "30s"

View File

@@ -0,0 +1,41 @@
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/admin/main/videoup-task/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/hbase.v2:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
"//library/net/rpc/warden: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,134 @@
package conf
import (
"flag"
"fmt"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/hbase.v2"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
"go-common/library/net/rpc/warden"
"go-common/library/queue/databus"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
//Config config.
type Config struct {
Xlog *log.Config
ManagerReport *databus.Config
HTTPClient *bm.ClientConfig
BM *bm.ServerConfig
DB *db
Auth *permit.Config
Host host
HBase *HBaseConfig
// redis
Redis *Redis
GRPC *GRPC
}
// HBaseConfig extra hbase config
type HBaseConfig struct {
*hbase.Config
ReadTimeout time.Duration
WriteTimeout time.Duration
}
//GRPC .
type GRPC struct {
AccRPC *warden.ClientConfig
UpsRPC *warden.ClientConfig
}
// Redis .
type Redis struct {
Weight *struct {
*redis.Config
Expire time.Duration
}
}
type host struct {
API string
Manager string
Search string
}
type db struct {
Archive *sql.Config
ArchiveRead *sql.Config
Manager *sql.Config
}
//common + xlog(agent) + trace(better) + http + perf(web代码性能分析) + os.signal监听stop/reload服务
var (
confPath string
client *conf.Client
Conf = &Config{}
)
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
//Init config init.
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
tmpConf := &Config{}
if _, err = toml.DecodeFile(confPath, tmpConf); err == nil {
Conf = tmpConf
}
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() {
if err = load(); err != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
ok bool
tmpConf = &Config{}
)
if confPath, ok = client.Toml2(); !ok {
err = fmt.Errorf("config load error")
return
}
if _, err = toml.Decode(confPath, tmpConf); err != nil {
err = fmt.Errorf("couldn't decode config, error (%v)", err)
return
}
Conf = tmpConf
return
}

View File

@@ -0,0 +1,101 @@
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",
"auth_role_test.go",
"consumer_test.go",
"dao_test.go",
"manager_test.go",
"oper_test.go",
"report_test.go",
"search_test.go",
"task_dispatch_test.go",
"task_history_test.go",
"task_oper_history_test.go",
"task_qa_test.go",
"task_qa_video_test.go",
"task_review_test.go",
"task_weight_test.go",
"type_test.go",
"up_group_test.go",
"user_test.go",
"video_test.go",
"weight_log_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/videoup-task/conf:go_default_library",
"//app/admin/main/videoup-task/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"archive.go",
"auth_role.go",
"consumer.go",
"dao.go",
"manager.go",
"oper.go",
"report.go",
"search.go",
"task_dispatch.go",
"task_history.go",
"task_oper_history.go",
"task_qa.go",
"task_qa_video.go",
"task_review.go",
"task_weight.go",
"type.go",
"up_group.go",
"user.go",
"video.go",
"weight_log.go",
],
importpath = "go-common/app/admin/main/videoup-task/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/videoup-task/conf:go_default_library",
"//app/admin/main/videoup-task/model:go_default_library",
"//app/admin/main/videoup/model/archive:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/hbase.v2:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/stat/prom:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/tsuna/gohbase/hrpc: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,45 @@
package dao
import (
"context"
"database/sql"
"go-common/app/admin/main/videoup-task/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_arcSQL = "SELECT id,mid,title,access,attribute,reject_reason,tag,forward,round,state,copyright,cover,content,typeid,pubtime,ctime,mtime FROM archive WHERE id=?"
_archiveParamSQL = `SELECT a.typeid,addit.up_from FROM archive AS a LEFT JOIN archive_addit AS addit ON a.id=addit.aid WHERE a.id=?`
)
// Archive get archive by aid
func (d *Dao) Archive(c context.Context, aid int64) (a *model.Archive, err error) {
var (
row = d.arcDB.QueryRow(c, _arcSQL, aid)
reason, tag sql.NullString
)
a = &model.Archive{}
if err = row.Scan(&a.Aid, &a.Mid, &a.Title, &a.Access, &a.Attribute, &reason, &tag, &a.Forward, &a.Round, &a.State,
&a.Copyright, &a.Cover, &a.Desc, &a.TypeID, &a.PTime, &a.CTime, &a.MTime); err != nil {
if err == xsql.ErrNoRows {
a = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
return
}
a.RejectReason = reason.String
a.Tag = tag.String
return
}
// ArchiveParam .
func (d *Dao) ArchiveParam(c context.Context, aid int64) (typeid int16, upfrom int8, err error) {
if err = d.arcDB.QueryRow(c, _archiveParamSQL, aid).Scan(&typeid, &upfrom); err != nil {
log.Error("ArchiveParam error(%v)", err)
}
return
}

View File

@@ -0,0 +1,37 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoArchive(t *testing.T) {
convey.Convey("Archive", t, func(ctx convey.C) {
var (
c = context.Background()
aid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.Archive(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoArchiveParam(t *testing.T) {
convey.Convey("ArchiveParam", t, func(ctx convey.C) {
var (
c = context.Background()
aid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.ArchiveParam(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
})
})
})
}

View File

@@ -0,0 +1,22 @@
package dao
import (
"context"
"database/sql"
"go-common/library/log"
)
const (
_getUserRoleSQL = "SELECT `role` FROM `auth_role` WHERE uid = ?"
)
// GetUserRole 用户角色
func (d *Dao) GetUserRole(c context.Context, uid int64) (role int8, err error) {
err = d.mngDB.QueryRow(c, _getUserRoleSQL, uid).Scan(&role)
if err != nil && err != sql.ErrNoRows {
log.Error("d.managerDB.Query error(%v)", err)
return
}
return role, nil
}

View File

@@ -0,0 +1,24 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoGetUserRole(t *testing.T) {
convey.Convey("GetUserRole", t, func(ctx convey.C) {
var (
c = context.Background()
uid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
role, err := d.GetUserRole(c, uid)
ctx.Convey("Then err should be nil.role should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(role, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,67 @@
package dao
import (
"context"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_taskUserCheckInSQL = "INSERT INTO task_consumer (uid,state) VALUES (?,1) ON DUPLICATE KEY UPDATE state = 1"
_taskUserCheckOffSQL = "UPDATE task_consumer SET state = 0 WHERE uid=?"
_consumersSQL = "SELECT id,uid,state,ctime,mtime FROM task_consumer where state=1"
_isConsumerOnSQL = "SELECT state FROM task_consumer WHERE uid=?"
)
// TaskUserCheckIn insert or update task consumer check state
func (d *Dao) TaskUserCheckIn(c context.Context, uid int64) (rows int64, err error) {
res, err := d.arcDB.Exec(c, _taskUserCheckInSQL, uid)
if err != nil {
log.Error("tx.Exec(%s, %d) error(%v)", _taskUserCheckInSQL, uid, err)
return
}
return res.RowsAffected()
}
// TaskUserCheckOff update task consumer check state
func (d *Dao) TaskUserCheckOff(c context.Context, uid int64) (rows int64, err error) {
res, err := d.arcDB.Exec(c, _taskUserCheckOffSQL, uid)
if err != nil {
log.Error("tx.Exec(%s, %d) error(%v)", _taskUserCheckOffSQL, uid, err)
return
}
return res.RowsAffected()
}
// Consumers 用户列表
func (d *Dao) Consumers(c context.Context) (cms []*model.Consumers, err error) {
rows, err := d.arcDB.Query(c, _consumersSQL)
if err != nil {
log.Error("d.arcDB.Query(%s) error(%v)", _consumersSQL, err)
return
}
defer rows.Close()
for rows.Next() {
cm := new(model.Consumers)
err = rows.Scan(&cm.ID, &cm.UID, &cm.State, &cm.Ctime, &cm.Mtime)
if err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
cms = append(cms, cm)
}
return
}
// IsConsumerOn 判断是否登入
func (d *Dao) IsConsumerOn(c context.Context, uid int64) (state int8) {
err := d.arcDB.QueryRow(c, _isConsumerOnSQL, uid).Scan(&state)
if err != nil {
if err != sql.ErrNoRows {
log.Error("d.arcDB.QueryRow error(%v)", err)
}
}
return
}

View File

@@ -0,0 +1,70 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoTaskUserCheckIn(t *testing.T) {
convey.Convey("TaskUserCheckIn", t, func(ctx convey.C) {
var (
c = context.Background()
uid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.TaskUserCheckIn(c, uid)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoTaskUserCheckOff(t *testing.T) {
convey.Convey("TaskUserCheckOff", t, func(ctx convey.C) {
var (
c = context.Background()
uid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.TaskUserCheckOff(c, uid)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoConsumers(t *testing.T) {
convey.Convey("Consumers", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
cms, err := d.Consumers(c)
ctx.Convey("Then err should be nil.cms should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(cms, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoIsConsumerOn(t *testing.T) {
convey.Convey("IsConsumerOn", t, func(ctx convey.C) {
var (
c = context.Background()
uid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
state := d.IsConsumerOn(c, uid)
ctx.Convey("Then state should not be nil.", func(ctx convey.C) {
ctx.So(state, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,117 @@
package dao
import (
"context"
"time"
"go-common/app/admin/main/videoup-task/conf"
account "go-common/app/service/main/account/api"
"go-common/app/service/main/account/model"
"go-common/library/cache/redis"
"go-common/library/database/hbase.v2"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/stat/prom"
)
//Dao dao.
type Dao struct {
c *conf.Config
arcDB *sql.DB
arcReadDB *sql.DB
mngDB *sql.DB
upGroupURL string
hbase *hbase.Client
redis *redis.Pool
hclient *bm.Client
//grpc
acc account.AccountClient
}
var errCount = prom.BusinessErrCount
//New new dao
func New(config *conf.Config) (d *Dao) {
d = &Dao{
c: config,
arcDB: sql.NewMySQL(config.DB.Archive),
arcReadDB: sql.NewMySQL(config.DB.ArchiveRead),
mngDB: sql.NewMySQL(config.DB.Manager),
upGroupURL: config.Host.API + "/x/internal/uper/special/get",
hbase: hbase.NewClient(config.HBase.Config),
redis: redis.NewPool(config.Redis.Weight.Config),
hclient: bm.NewClient(config.HTTPClient),
}
var err error
if d.acc, err = account.NewClient(config.GRPC.AccRPC); err != nil {
panic(err)
}
return
}
//BeginTran begin transaction
func (d *Dao) BeginTran(ctx context.Context) (tx *sql.Tx, err error) {
if tx, err = d.arcDB.Begin(ctx); err != nil {
PromeErr("arcdb: begintran", "BeginTran d.arcDB.Begin error(%v)", err)
}
return
}
//Close close
func (d *Dao) Close() {
if d.arcDB != nil {
d.arcDB.Close()
}
if d.arcReadDB != nil {
d.arcReadDB.Close()
}
if d.mngDB != nil {
d.mngDB.Close()
}
}
//Ping ping
func (d *Dao) Ping(ctx context.Context) (err error) {
if d.arcDB != nil {
if err = d.arcDB.Ping(ctx); err != nil {
PromeErr("arcdb: ping", "d.arcDB.Ping error(%v)", err)
return
}
}
if d.arcReadDB != nil {
if err = d.arcReadDB.Ping(ctx); err != nil {
PromeErr("arcReaddb: ping", "d.arcReadDB.Ping error(%v)", err)
return
}
}
if d.mngDB != nil {
if err = d.mngDB.Ping(ctx); err != nil {
PromeErr("mngdb: ping", "d.mngDB.Ping error(%v)", err)
return
}
}
return
}
//AccountInfos get multi mids' accountinfo
func (d *Dao) AccountInfos(ctx context.Context, mids []int64) (info map[int64]*model.Info, err error) {
tctx, cancel := context.WithTimeout(ctx, time.Millisecond*500)
defer cancel()
var infosreply *account.InfosReply
if infosreply, err = d.acc.Infos3(tctx, &account.MidsReq{Mids: mids}); err != nil {
PromeErr("account_infos", "AccountInfos d.acc.Infos3 error(%v) mid(%d)", err, mids)
}
if infosreply != nil {
info = infosreply.Infos
}
return
}
//PromeErr prome & log err
func PromeErr(name string, format string, args ...interface{}) {
errCount.Incr(name)
log.Error(format, args...)
}

View File

@@ -0,0 +1,47 @@
package dao
import (
"flag"
"os"
"strings"
"testing"
"go-common/app/admin/main/videoup-task/conf"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup-task-admin")
flag.Set("conf_token", "7e2256b4bc8e4084cf848fe27a474a20")
flag.Set("tree_id", "25095")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "dev")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup-task-admin.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.hclient.SetTransport(gock.DefaultTransport)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,95 @@
package dao
import (
"context"
"net/url"
"strings"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_uidsURL = "/x/admin/manager/users/uids"
_unamesURL = "/x/admin/manager/users/unames"
)
// Unames get unames by uid
func (d *Dao) Unames(c context.Context, uids []int64) (res map[int64]string, err error) {
var (
param = url.Values{}
uidStr = xstr.JoinInts(uids)
unameURI = d.c.Host.Manager + _unamesURL
)
param.Set("uids", uidStr)
var httpRes struct {
Code int `json:"code"`
Data map[int64]string `json:"data"`
Message string `json:"message"`
}
err = d.hclient.Get(c, unameURI, "", param, &httpRes)
if err != nil {
log.Error("d.client.Get(%s) error(%v)", unameURI+"?"+param.Encode(), err)
return
}
if httpRes.Code != 0 {
log.Error("url(%s) error(%v), code(%d), message(%s)", unameURI+"?"+param.Encode(), err, httpRes.Code, httpRes.Message)
}
res = httpRes.Data
return
}
// Uids get uids by unames
func (d *Dao) Uids(c context.Context, names []string) (res map[string]int64, err error) {
var (
param = url.Values{}
namesStr = strings.Join(names, ",")
uidURI = d.c.Host.Manager + _uidsURL
)
param.Set("unames", namesStr)
var httpRes struct {
Code int `json:"code"`
Data map[string]int64 `json:"data"`
Message string `json:"message"`
}
err = d.hclient.Get(c, uidURI, "", param, &httpRes)
if err != nil {
log.Error("d.client.Get(%s) error(%v)", uidURI+"?"+param.Encode(), err)
return
}
if httpRes.Code != 0 {
log.Error("url(%s) error(%v), code(%d), message(%s)", uidURI+"?"+param.Encode(), err, httpRes.Code, httpRes.Message)
}
res = httpRes.Data
return
}
// GetUIDByName 获取uid
func (d *Dao) GetUIDByName(c context.Context, name string) (uid int64, err error) {
var res map[string]int64
if res, err = d.Uids(c, []string{name}); err != nil {
return
}
if uid, ok := res[name]; ok {
return uid, nil
}
return
}
// GetNameByUID 获取用户名
func (d *Dao) GetNameByUID(c context.Context, uids []int64) (mcases map[int64][]interface{}, err error) {
var res map[int64]string
if res, err = d.Unames(c, uids); err != nil {
return
}
mcases = make(map[int64][]interface{})
for uid, uname := range res {
mcases[uid] = []interface{}{uname}
}
return
}

View File

@@ -0,0 +1,69 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoUids(t *testing.T) {
convey.Convey("Uids", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_uidsURL).Reply(200).JSON(`{"code":0}`)
_, err := d.Uids(c, []string{})
ctx.Convey("Then nil should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoUnames(t *testing.T) {
convey.Convey("Unames", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_unamesURL).Reply(200).JSON(`{"code":0,"message":"0","data":{"10086":"cxf"}}`)
_, err := d.Unames(c, []int64{})
ctx.Convey("Then nil should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoGetUIDByName(t *testing.T) {
convey.Convey("GetUIDByName", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_uidsURL).Reply(200).JSON(`{"code":0,"message":"0","data":{"cxf":10086}}`)
uid, err := d.GetUIDByName(c, "cxf")
ctx.Convey("Then nil should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(uid, convey.ShouldEqual, 10086)
})
})
})
}
func TestDaoGetNameByUID(t *testing.T) {
convey.Convey("GetNameByUID", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_unamesURL).Reply(200).JSON(`{"code":0,"message":"0","data":{"10086":"cxf"}}`)
_, err := d.GetNameByUID(c, []int64{10086})
ctx.Convey("Then nil should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,65 @@
package dao
import (
"context"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_inVideoOperSQL = "INSERT INTO archive_video_oper (aid,uid,vid,status,content,attribute,last_id,remark) VALUES (?,?,?,?,?,?,?,?)"
_videoOperSQL = "SELECT id,aid,uid,vid,status,content,attribute,last_id,remark,ctime FROM archive_video_oper WHERE vid = ? ORDER BY ctime DESC"
_upVideoOperSQL = "UPDATE archive_video_oper SET last_id=? WHERE id=?"
)
// AddVideoOper insert archive_video_oper.
func (d *Dao) AddVideoOper(c context.Context, aid, adminID, vid int64, attribute int32, status int16, lastID int64, content, remark string) (id int64, err error) {
res, err := d.arcDB.Exec(c, _inVideoOperSQL, aid, adminID, vid, status, content, attribute, lastID, remark)
if err != nil {
log.Error("d.inVideoOper.Exec error(%v)", err)
return
}
id, err = res.LastInsertId()
return
}
//VideoOpers get video oper history list
func (d *Dao) VideoOpers(c context.Context, vid int64) (op []*model.VOper, uids []int64, err error) {
var (
rows *sql.Rows
ctime time.Time
)
op = []*model.VOper{}
uids = []int64{}
if rows, err = d.arcReadDB.Query(c, _videoOperSQL, vid); err != nil {
log.Error("d.arcReadDB.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
p := &model.VOper{}
if err = rows.Scan(&p.ID, &p.AID, &p.UID, &p.VID, &p.Status, &p.Content, &p.Attribute, &p.LastID, &p.Remark, &ctime); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
p.CTime = ctime.Format("2006-01-02 15:04:05")
op = append(op, p)
uids = append(uids, p.UID)
}
return
}
// UpVideoOper update archive_video_oper last_id by id.
func (d *Dao) UpVideoOper(c context.Context, lastID, id int64) (rows int64, err error) {
res, err := d.arcDB.Exec(c, _upVideoOperSQL, lastID, id)
if err != nil {
log.Error("d.upVideoOper.Exec error(%v)", err)
return
}
rows, err = res.RowsAffected()
return
}

View File

@@ -0,0 +1,44 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAddVideoOper(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
adminID = int64(421)
vid = int64(1)
attribute = int32(0)
status = int16(0)
lastID = int64(0)
content = "测试"
remark = "测试"
)
convey.Convey("AddVideoOper", t, func(ctx convey.C) {
id, err := d.AddVideoOper(c, aid, adminID, vid, attribute, status, lastID, content, remark)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
}
func TestDaoVideoOpers(t *testing.T) {
var (
c = context.TODO()
vid = int64(1)
)
convey.Convey("VideoOpers", t, func(ctx convey.C) {
op, uids, err := d.VideoOpers(c, vid)
ctx.Convey("Then err should be nil.op,uids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(uids, convey.ShouldNotBeNil)
ctx.So(op, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,32 @@
package dao
import (
"context"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/log"
)
const (
_taskTooksByHalfHourSQL = "SELECT id,m50,m60,m80,m90,type,ctime,mtime FROM task_dispatch_took WHERE type=2 AND ctime>=? AND ctime<=? ORDER BY ctime ASC"
)
// TaskTooksByHalfHour get TaskTooks by half hour
func (d *Dao) TaskTooksByHalfHour(c context.Context, stime time.Time, etime time.Time) (tooks []*archive.TaskTook, err error) {
rows, err := d.arcDB.Query(c, _taskTooksByHalfHourSQL, stime, etime)
if err != nil {
log.Error("d.TaskTooksByHalfHour.Query(%v,%v) error(%v)", stime, etime, err)
return
}
defer rows.Close()
for rows.Next() {
took := &archive.TaskTook{}
if err = rows.Scan(&took.ID, &took.M50, &took.M60, &took.M80, &took.M90, &took.TypeID, &took.Ctime, &took.Mtime); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
tooks = append(tooks, took)
}
return
}

View File

@@ -0,0 +1,25 @@
package dao
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoTaskTooksByHalfHour(t *testing.T) {
convey.Convey("TaskTooksByHalfHour", t, func(ctx convey.C) {
var (
c = context.Background()
stime = time.Now()
etime = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.TaskTooksByHalfHour(c, stime, etime)
ctx.Convey("Then err should be nil.tooks should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,98 @@
package dao
import (
"context"
"net/url"
"strconv"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_searchURL = "/x/admin/search/log"
)
// OutTime 退出时间,es的group by查询,最大1000条
func (d *Dao) OutTime(c context.Context, ids []int64) (mcases map[int64][]interface{}, err error) {
mcases = make(map[int64][]interface{})
params := url.Values{}
params.Set("appid", "log_audit_group")
params.Set("group", "uid")
params.Set("uid", xstr.JoinInts(ids))
params.Set("business", strconv.Itoa(model.LogClientConsumer))
params.Set("action", strconv.Itoa(int(model.ActionHandsOFF)))
params.Set("ps", strconv.Itoa(len(ids)))
res := &model.SearchLogResult{}
if err = d.hclient.Get(c, d.c.Host.Search+_searchURL, "", params, &res); err != nil {
log.Error("log_audit_group d.hclient.Get error(%v)", err)
return
}
if res.Code != ecode.OK.Code() {
log.Error("log_audit_group ecode:%v", res.Code)
return
}
for _, item := range res.Data.Result {
mcases[item.UID] = []interface{}{item.Ctime}
}
log.Info("log_audit_group get: %s params:%s ret:%v", _searchURL, params.Encode(), res)
return
}
// InQuitList 登入登出日志
func (d *Dao) InQuitList(c context.Context, uids []int64, bt, et string) (l []*model.InQuit, err error) {
params := url.Values{}
params.Set("appid", "log_audit")
params.Set("business", strconv.Itoa(model.LogClientConsumer))
if len(uids) > 0 {
params.Set("uid", xstr.JoinInts(uids))
}
if len(bt) > 0 && len(et) > 0 {
params.Set("ctime_from", bt)
params.Set("ctime_to", et)
}
params.Set("order", "ctime")
params.Set("sort", "desc")
params.Set("ps", "10000")
res := &model.SearchLogResult{}
if err = d.hclient.Get(c, d.c.Host.Search+_searchURL, "", params, res); err != nil {
log.Error("InQuitList d.hclient.Get error(%v)", err)
return
}
if res.Code != ecode.OK.Code() {
log.Error("InQuitList ecode:%v", res.Code)
return
}
mapHelp := make(map[int64]*model.InQuit)
for i := len(res.Data.Result) - 1; i >= 0; i-- {
item := res.Data.Result[i]
if item.Action == "0" {
ctime, _ := time.Parse(model.TimeFormatSec, item.Ctime)
iqlog := &model.InQuit{
Date: ctime.Format("2006-01-02"),
UID: item.UID,
Uname: item.Uname,
InTime: ctime.Format("15:04:05"),
}
mapHelp[item.UID] = iqlog
l = append([]*model.InQuit{iqlog}, l[:]...)
}
if item.Action == "1" {
if iqlog, ok := mapHelp[item.UID]; ok {
ctime, _ := time.Parse(model.TimeFormatSec, item.Ctime)
if date := ctime.Format("2006-01-02"); date == iqlog.Date {
iqlog.OutTime = ctime.Format("15:04:05")
} else {
iqlog.OutTime = ctime.Format(model.TimeFormatSec)
}
}
}
}
return
}

View File

@@ -0,0 +1,45 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoOutTime(t *testing.T) {
convey.Convey("OutTime", t, func(ctx convey.C) {
var (
c = context.Background()
ids = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
httpMock("GET", d.c.Host.Search+_searchURL).Reply(200).JSON(`{"code":0,"data":{"result":[{"uid":0}]}}`)
mcases, err := d.OutTime(c, ids)
ctx.Convey("Then err should be nil.mcases should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(mcases, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoInQuitList(t *testing.T) {
convey.Convey("InQuitList", t, func(ctx convey.C) {
var (
c = context.Background()
uids = []int64{}
bt = ""
et = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
httpMock("GET", d.c.Host.Search+_searchURL).Reply(200).JSON(`{"code":0,"data":{"result":[{"uid":0,"action":"0"}]}}`)
l, err := d.InQuitList(c, uids, bt, et)
ctx.Convey("Then err should be nil.l should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(l, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,346 @@
package dao
import (
"context"
xsql "database/sql"
"encoding/json"
"fmt"
"strings"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_upTaskByIDSQL = "UPDATE task_dispatch SET %s WHERE id=?"
_upGtimeByIDSQL = "UPDATE task_dispatch SET gtime=? WHERE id=?"
_releaseByIDSQL = "UPDATE task_dispatch SET subject=0,state=0,uid=0,gtime='0000-00-00 00:00:00' WHERE id=?"
_releaseMtimeSQL = "UPDATE task_dispatch SET subject=0,state=0,uid=0,gtime='0000-00-00 00:00:00' WHERE id IN (%s) AND mtime<=?"
_timeOutTaskSQL = "SELECT id,cid,subject,mtime FROM task_dispatch WHERE (state=1 AND mtime<?) OR (state=0 AND uid<>0 AND ctime<?)"
_getRelTaskSQL = "SELECT id,cid,subject,mtime,gtime FROM task_dispatch WHERE state IN (0,1) AND uid=?"
_releaseSpecialSQL = "UPDATE task_dispatch SET subject=0,state=0,uid=0 WHERE id=? AND gtime='0000-00-00 00:00:00' AND mtime<=? AND state=? AND uid=?"
)
// UpGtimeByID update gtime
func (d *Dao) UpGtimeByID(c context.Context, id int64, gtime string) (rows int64, err error) {
var res xsql.Result
if res, err = d.arcDB.Exec(c, _upGtimeByIDSQL, gtime, id); err != nil {
log.Error("d.arcDB.Exec(%s, %v, %d) error(%v)", _upGtimeByIDSQL, gtime, id)
return
}
return res.RowsAffected()
}
// TxUpTaskByID 更新任务状态
func (d *Dao) TxUpTaskByID(tx *sql.Tx, id int64, paras map[string]interface{}) (rows int64, err error) {
arrSet := []string{}
arrParas := []interface{}{}
for k, v := range paras {
arrSet = append(arrSet, k+"=?")
arrParas = append(arrParas, v)
}
arrParas = append(arrParas, id)
sqlstring := fmt.Sprintf(_upTaskByIDSQL, strings.Join(arrSet, ","))
res, err := tx.Exec(sqlstring, arrParas...)
if err != nil {
log.Error("tx.Exec(%v %v) error(%v)", sqlstring, arrParas, err)
return
}
return res.RowsAffected()
}
// TxReleaseByID 释放指定任务
func (d *Dao) TxReleaseByID(tx *sql.Tx, id int64) (rows int64, err error) {
res, err := tx.Exec(_releaseByIDSQL, id)
if err != nil {
log.Error("tx.Exec(%s, %d) error(%v)", _releaseByIDSQL, id, err)
return
}
return res.RowsAffected()
}
// MulReleaseMtime 批量释放任务,加时间防止释放错误
func (d *Dao) MulReleaseMtime(c context.Context, ids []int64, mtime time.Time) (rows int64, err error) {
sqlstring := fmt.Sprintf(_releaseMtimeSQL, xstr.JoinInts(ids))
res, err := d.arcDB.Exec(c, sqlstring, mtime)
if err != nil {
log.Error("tx.Exec(%s, %v) error(%v)", sqlstring, mtime, err)
return
}
return res.RowsAffected()
}
// GetTimeOutTask 释放正在处理且超时的,释放指派后但长时间未审核的
func (d *Dao) GetTimeOutTask(c context.Context) (rts []*model.TaskForLog, err error) {
var (
rows *sql.Rows
)
if rows, err = d.arcDB.Query(c, _timeOutTaskSQL, time.Now().Add(-10*time.Minute), time.Now().Add(-80*time.Minute)); err != nil {
log.Error("d.arcDB.Query(%s) error(%v)", _timeOutTaskSQL, err)
return
}
defer rows.Close()
for rows.Next() {
rt := &model.TaskForLog{}
if err = rows.Scan(&rt.ID, &rt.Cid, &rt.Subject, &rt.Mtime); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
rts = append(rts, rt)
}
return
}
// GetRelTask 用户登出或者主动释放(分配给该用户的都释放)
func (d *Dao) GetRelTask(c context.Context, uid int64) (rts []*model.TaskForLog, lastid int64, err error) {
var (
gtime time.Time
rows *sql.Rows
)
if rows, err = d.arcDB.Query(c, _getRelTaskSQL, uid); err != nil {
log.Error("d.arcDB.Query(%s, %d) error(%v)", _getRelTaskSQL, uid, err)
return
}
defer rows.Close()
for rows.Next() {
rt := &model.TaskForLog{}
if err = rows.Scan(&rt.ID, &rt.Cid, &rt.Subject, &rt.Mtime, &gtime); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
if gtime.IsZero() {
rts = append(rts, rt)
} else {
lastid = rt.ID
}
}
return
}
// TxReleaseSpecial 延时固定时间释放的任务,需要校验释放时的状态,时间,认领人等
func (d *Dao) TxReleaseSpecial(tx *sql.Tx, mtime time.Time, state int8, taskid, uid int64) (rows int64, err error) {
res, err := tx.Exec(_releaseSpecialSQL, taskid, mtime, state, uid)
if err != nil {
log.Error("tx.Exec(%s, %d, %v, %d, %d) error(%v)", _releaseSpecialSQL, taskid, mtime, state, uid, err)
return
}
return res.RowsAffected()
}
const (
_userUndoneSpecifiedSQL = "SELECT id,pool,subject,adminid,aid,cid,uid,state,ctime,mtime FROM task_dispatch WHERE uid = ? AND state !=2 AND subject = 1"
_dispatchTaskSQL = "SELECT id,cid,mtime FROM task_dispatch WHERE uid in (0,?) AND state = 0 ORDER BY `weight` DESC,`subject` DESC,`id` ASC limit 8"
_upDispatchTaskSQL = "UPDATE task_dispatch SET state=1,uid=?,gtime='0000-00-00 00:00:00' WHERE id IN (%s) AND state=0"
_getNextTaskSQL = "SELECT id,pool,subject,adminid,aid,cid,uid,state,utime,ctime,mtime,dtime,gtime,weight FROM task_dispatch WHERE uid=? AND state = 1 ORDER BY `weight` DESC,`subject` DESC,`id` ASC limit 1"
_upTaskGtimeSQL = "UPDATE task_dispatch SET gtime=? WHERE id=?"
_listByConditionSQL = "SELECT id,pool,subject,adminid,aid,cid,uid,state,utime,ctime,mtime,dtime,gtime,weight FROM task_dispatch where %s order by %s %s"
_taskByIDSQL = "SELECT id,pool,subject,adminid,aid,cid,uid,state,utime,ctime,mtime,dtime,gtime,ptime,weight FROM task_dispatch WHERE id =? union " +
"SELECT task_id as id,pool,subject,adminid,aid,cid,uid,state,utime,ctime,mtime,dtime,gtime,ptime,weight FROM task_dispatch_done WHERE task_id=?"
_getWeightDBSQL = "SELECT t.id,t.state,a.mid,t.ctime,t.upspecial,t.ptime,e.description FROM `task_dispatch` AS t " +
"LEFT JOIN `task_dispatch_extend` AS e ON t.id=e.task_id INNER JOIN archive as a ON a.id=t.aid WHERE t.id IN (%s)"
)
// UserUndoneSpecTask get undone dispatch which belongs to someone.
func (d *Dao) UserUndoneSpecTask(c context.Context, uid int64) (tasks []*model.Task, err error) {
rows, err := d.arcDB.Query(c, _userUndoneSpecifiedSQL, uid)
if err != nil {
log.Error("d.arcDB.Query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
t := &model.Task{}
if err = rows.Scan(&t.ID, &t.Pool, &t.Subject, &t.AdminID, &t.Aid, &t.Cid, &t.UID, &t.State, &t.CTime, &t.MTime); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("row.Scan(%d) error(%v)", err)
return
}
tasks = append(tasks, t)
}
return
}
// GetDispatchTask 获取抢占到的任务(用于记录日志)
func (d *Dao) GetDispatchTask(c context.Context, uid int64) (tls []*model.TaskForLog, err error) {
rows, err := d.arcDB.Query(c, _dispatchTaskSQL, uid)
if err != nil {
log.Error("d.arcDB.Query(%s, %d) error(%v)", _dispatchTaskSQL, uid, err)
return
}
defer rows.Close()
for rows.Next() {
taskLog := &model.TaskForLog{}
if err = rows.Scan(&taskLog.ID, &taskLog.Cid, &taskLog.Mtime); err != nil {
log.Error("rows.Scan(%s, %d) error(%v)", _dispatchTaskSQL, uid, err)
return
}
tls = append(tls, taskLog)
}
return
}
// UpDispatchTask 抢占任务
func (d *Dao) UpDispatchTask(c context.Context, uid int64, ids []int64) (rows int64, err error) {
var (
res xsql.Result
sqlstring = fmt.Sprintf(_upDispatchTaskSQL, xstr.JoinInts(ids))
)
res, err = d.arcDB.Exec(c, sqlstring, uid)
if err != nil {
log.Error("d.arcDB.Exec(%s %d %v) error(%v)", sqlstring, uid, err)
return
}
return res.RowsAffected()
}
// GetNextTask 获取一条任务
func (d *Dao) GetNextTask(c context.Context, uid int64) (task *model.Task, err error) {
task = new(model.Task)
err = d.arcDB.QueryRow(c, _getNextTaskSQL, uid).Scan(&task.ID, &task.Pool, &task.Subject, &task.AdminID,
&task.Aid, &task.Cid, &task.UID, &task.State, &task.UTime, &task.CTime, &task.MTime, &task.DTime, &task.GTime, &task.Weight)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
log.Error("db.QueryRow(%d) error(%v)", err)
return nil, err
}
if task.GTime.TimeValue().IsZero() {
timeNow := time.Now()
_, err = d.arcDB.Exec(c, _upTaskGtimeSQL, timeNow, task.ID)
if err != nil {
log.Error("d.arcDB.Exec(%v,%d) error(%v)", timeNow, task.ID, err)
return nil, err
}
task.GTime = model.NewFormatTime(timeNow)
}
return
}
// TaskByID get task
func (d *Dao) TaskByID(c context.Context, id int64) (task *model.Task, err error) {
task = new(model.Task)
err = d.arcDB.QueryRow(c, _taskByIDSQL, id, id).Scan(&task.ID, &task.Pool, &task.Subject, &task.AdminID,
&task.Aid, &task.Cid, &task.UID, &task.State, &task.UTime, &task.CTime, &task.MTime, &task.DTime, &task.GTime, &task.PTime, &task.Weight)
if err != nil {
if err == sql.ErrNoRows {
err = nil
task = nil
return
}
log.Error("db.QueryRow(%d) error(%v)", id, err)
return nil, err
}
return
}
// ListByCondition 从数据库获取读取任务列表
func (d *Dao) ListByCondition(c context.Context, uid int64, pn, ps int, ltype, leader int8) (tasks []*model.Task, err error) {
var task *model.Task
tasks = []*model.Task{}
if !model.IsDispatch(ltype) {
log.Error("ListByCondition listtype(%d) error", ltype)
return
}
listSQL := d.sqlHelper(uid, pn, ps, ltype, leader)
rows, err := d.arcDB.Query(c, listSQL)
if err != nil {
log.Error("rddb.Query(%s) error(%v)", listSQL, err)
return
}
defer rows.Close()
for rows.Next() {
task = &model.Task{}
err = rows.Scan(&task.ID, &task.Pool, &task.Subject, &task.AdminID,
&task.Aid, &task.Cid, &task.UID, &task.State, &task.UTime, &task.CTime, &task.MTime, &task.DTime, &task.GTime, &task.Weight)
if err != nil {
log.Error("rows.Scan(%s) error(%v)", listSQL, err)
return nil, nil
}
tasks = append(tasks, task)
}
return
}
func (d *Dao) sqlHelper(uid int64, pn, ps int, ltype int8, leader int8) string {
var (
wherecase []string
ordercase []string
limitStr string
whereStr string
orderStr string
)
limitStr = fmt.Sprintf("LIMIT %d,%d", (pn-1)*ps, ps)
if uid != 0 && (ltype != model.TypeRealTime && leader != 1) { //实时任务或者组长不区分uid
wherecase = append(wherecase, fmt.Sprintf("uid=%d", uid))
}
ordercase = append(ordercase, "weight desc,ctime asc")
switch ltype {
case model.TypeRealTime:
wherecase = append(wherecase, "state=0")
case model.TypeDispatched:
wherecase = append(wherecase, "state=1 AND subject=0")
ordercase = append(ordercase, "utime desc")
case model.TypeDelay:
wherecase = append(wherecase, "state=3")
ordercase = append(ordercase, "dtime asc")
case model.TypeReview:
wherecase = append(wherecase, "state=5")
ordercase = append(ordercase, "mtime asc")
case model.TypeSpecialWait:
wherecase = append(wherecase, "state=1 AND subject=1")
ordercase = append(ordercase, "utime desc")
default:
wherecase = append(wherecase, "state=0")
}
whereStr = strings.Join(wherecase, " AND ")
orderStr = strings.Join(ordercase, ",")
return fmt.Sprintf(_listByConditionSQL, whereStr, orderStr, limitStr)
}
// GetWeightDB 从数据库读取权重配置
func (d *Dao) GetWeightDB(c context.Context, ids []int64) (mcases map[int64]*model.TaskPriority, err error) {
var (
rows *sql.Rows
desc xsql.NullString
)
sqlstring := fmt.Sprintf(_getWeightDBSQL, xstr.JoinInts(ids))
if rows, err = d.arcDB.Query(c, sqlstring); err != nil {
log.Error("d.arcDB.Query(%s) error(%v)", sqlstring, err)
return
}
defer rows.Close()
mcases = make(map[int64]*model.TaskPriority)
for rows.Next() {
tp := new(model.TaskPriority)
if err = rows.Scan(&tp.TaskID, &tp.State, &tp.Mid, &tp.Ctime, &tp.Special, &tp.Ptime, &desc); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
if desc.Valid && len(desc.String) > 0 {
if err = json.Unmarshal([]byte(desc.String), &(tp.CfItems)); err != nil {
log.Error("json.Unmarshal error(%v)", err)
return
}
}
mcases[tp.TaskID] = tp
}
return
}

View File

@@ -0,0 +1,184 @@
package dao
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoUpGtimeByID(t *testing.T) {
convey.Convey("UpGtimeByID", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
gtime = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.UpGtimeByID(c, id, gtime)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUserUndoneSpecTask(t *testing.T) {
convey.Convey("UserUndoneSpecTask", t, func(ctx convey.C) {
var (
c = context.Background()
uid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.UserUndoneSpecTask(c, uid)
ctx.Convey("Then err should be nil.tasks should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoListByCondition(t *testing.T) {
convey.Convey("ListByCondition", t, func(ctx convey.C) {
var (
c = context.Background()
uid = int64(0)
pn = int(0)
ps = int(0)
ltype = int8(0)
leader = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
tasks, err := d.ListByCondition(c, uid, pn, ps, ltype, leader)
ctx.Convey("Then err should be nil.tasks should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(tasks, convey.ShouldNotBeNil)
})
})
})
}
func TestDaosqlHelper(t *testing.T) {
convey.Convey("sqlHelper", t, func(ctx convey.C) {
var (
uid = int64(0)
pn = int(0)
ps = int(0)
ltype = int8(0)
leader = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.sqlHelper(uid, pn, ps, ltype, leader)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoGetWeightDB(t *testing.T) {
convey.Convey("GetWeightDB", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.GetWeightDB(c, []int64{0, 1, 2})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoTaskByID(t *testing.T) {
convey.Convey("TaskByID", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.TaskByID(c, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoTxUpTaskByID(t *testing.T) {
convey.Convey("TxUpTaskByID", t, func(ctx convey.C) {
var (
c = context.Background()
)
tx, _ := d.BeginTran(c)
defer tx.Commit()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.TxUpTaskByID(tx, 0, map[string]interface{}{"uid": 0})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoTxReleaseByID(t *testing.T) {
convey.Convey("TxReleaseByID", t, func(ctx convey.C) {
var (
c = context.Background()
)
tx, _ := d.BeginTran(c)
defer tx.Commit()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.TxReleaseByID(tx, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoMulReleaseMtime(t *testing.T) {
convey.Convey("MulReleaseMtime", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.MulReleaseMtime(c, []int64{1}, time.Now())
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoGetTimeOutTask(t *testing.T) {
convey.Convey("GetTimeOutTask", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.GetTimeOutTask(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoGetRelTask(t *testing.T) {
convey.Convey("GetRelTask", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, _, err := d.GetRelTask(c, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,61 @@
package dao
import (
"context"
"fmt"
"strings"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_inTaskHisSQL = "INSERT INTO task_oper_history(pool,action,task_id,cid,uid,result,reason,utime) VALUE (?,?,?,?,?,?,?,?)"
_mulinTaskHisSQL = "INSERT INTO task_oper_history(action,task_id,cid,uid) VALUES "
)
// TxAddTaskHis add task oper history
func (d *Dao) TxAddTaskHis(tx *sql.Tx, pool, action int8, taskID, cid, uid, utime int64, result int16, reason string) (rows int64, err error) {
res, err := tx.Exec(_inTaskHisSQL, pool, action, taskID, cid, uid, result, reason, utime)
if err != nil {
log.Error("tx.Exec(%s) error(%v)", _inTaskHisSQL, err)
return
}
return res.RowsAffected()
}
// AddTaskHis 非事务
func (d *Dao) AddTaskHis(c context.Context, pool, action int8, taskID, cid, uid, utime int64, result int16, reason string) (rows int64, err error) {
res, err := d.arcDB.Exec(c, _inTaskHisSQL, pool, action, taskID, cid, uid, result, reason, utime)
if err != nil {
log.Error("d.arcDB.Exec(%s) error(%v)", _inTaskHisSQL, err)
return
}
return res.RowsAffected()
}
// MulAddTaskHis 批量插入日志
func (d *Dao) MulAddTaskHis(c context.Context, tls []*model.TaskForLog, action int8, uid int64) (rows int64, err error) {
params := []string{}
for _, item := range tls {
var itemstr string
itemstr += fmt.Sprintf("(%d,", action)
itemstr += fmt.Sprintf("%d,", item.ID)
itemstr += fmt.Sprintf("%d,", item.Cid)
itemstr += fmt.Sprintf("%d)", uid)
params = append(params, itemstr)
}
if len(params) == 0 {
log.Warn("MulAddTaskHis empty params")
return
}
sqlsring := strings.Join(params, ",")
res, err := d.arcDB.Exec(c, _mulinTaskHisSQL+sqlsring)
if err != nil {
log.Error("d.arcDB.Exec(%s, %s) error(%v)", _mulinTaskHisSQL, sqlsring, err)
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,50 @@
package dao
import (
"context"
"go-common/app/admin/main/videoup-task/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAddTaskHis(t *testing.T) {
convey.Convey("AddTaskHis", t, func(ctx convey.C) {
var (
c = context.Background()
pool = int8(0)
action = int8(0)
taskID = int64(0)
cid = int64(0)
uid = int64(0)
utime = int64(0)
result = int16(0)
reason = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.AddTaskHis(c, pool, action, taskID, cid, uid, utime, result, reason)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoMulAddTaskHis(t *testing.T) {
convey.Convey("MulAddTaskHis", t, func(ctx convey.C) {
var (
c = context.Background()
tls = []*model.TaskForLog{}
action = int8(0)
uid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.MulAddTaskHis(c, tls, action, uid)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,114 @@
package dao
import (
"context"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_avgUtimeSQL = "SELECT IFNULL(avg(utime),0.0) FROM task_oper_history WHERE action=2 AND uid=? AND ctime>=? AND ctime<?"
_sumDurationSQL = "SELECT IFNULL(sum(v.duration),0) FROM task_oper_history as t LEFT JOIN video as v ON t.cid=v.id WHERE action IN (2,5) AND t.uid=? AND t.ctime>=? AND t.ctime<?"
_actionCountSQL = "SELECT action,count(*) FROM task_oper_history WHERE uid=? AND ctime>=? AND ctime<? AND action IN (2,5,6,7) GROUP BY action"
_passCountSQL = "SELECT count(*) FROM task_oper_history WHERE action IN (2,5) AND uid=? AND ctime>=? AND ctime<? AND result=0"
_subjectCountSQL = `SELECT count(*) FROM (
SELECT id FROM task_dispatch WHERE uid=? AND state=? AND mtime>=? AND ctime<? AND subject=1
UNION ALL SELECT task_id as id FROM task_dispatch_done WHERE uid=? AND state=? AND mtime>=? AND ctime<? AND subject=1) as t
`
_activeUidsSQL = "SELECT DISTINCT uid from task_oper_history WHERE ctime>=? AND ctime<? AND uid!=0 AND action IN (2,5)"
)
// AvgUtimeByUID 平均处理耗时, 只统计action=2的
func (d *Dao) AvgUtimeByUID(c context.Context, uid int64, stime, etime time.Time) (utime float64, err error) {
if err = d.arcReadDB.QueryRow(c, _avgUtimeSQL, uid, stime, etime).Scan(&utime); err != nil {
if err == sql.ErrNoRows {
err = nil
}
log.Error("d.arcReadDB.QueryRow error(%v)", err)
}
return
}
// SumDurationByUID 视频总时长统计action=2,5的
func (d *Dao) SumDurationByUID(c context.Context, uid int64, stime, etime time.Time) (duration int64, err error) {
if err = d.arcReadDB.QueryRow(c, _sumDurationSQL, uid, stime, etime).Scan(&duration); err != nil {
if err == sql.ErrNoRows {
err = nil
}
log.Error("d.arcReadDB.QueryRow error(%v)", err)
}
return
}
// ActionCountByUID 操作个数统计
func (d *Dao) ActionCountByUID(c context.Context, uid int64, stime, etime time.Time) (mapAction map[int8]int64, err error) {
mapAction = make(map[int8]int64)
rows, err := d.arcReadDB.Query(c, _actionCountSQL, uid, stime, etime)
if err != nil {
log.Error("d.arcReadDB.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var (
action int8
count int64
)
if err = rows.Scan(&action, &count); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
mapAction[action] = count
}
return
}
// PassCountByUID 总过审个数
func (d *Dao) PassCountByUID(c context.Context, uid int64, stime, etime time.Time) (count int64, err error) {
if err = d.arcReadDB.QueryRow(c, _passCountSQL, uid, stime, etime).Scan(&count); err != nil {
if err == sql.ErrNoRows {
err = nil
}
log.Error("d.arcReadDB.QueryRow error(%v)", err)
}
return
}
// SubjectCountByUID 总指派个数
func (d *Dao) SubjectCountByUID(c context.Context, uid int64, stime, etime time.Time) (count int64, err error) {
if err = d.arcReadDB.QueryRow(c, _subjectCountSQL, uid, model.TaskStateCompleted, stime, etime, uid, model.TaskStateCompleted, stime, etime).Scan(&count); err != nil {
if err == sql.ErrNoRows {
err = nil
}
log.Error("d.arcReadDB.QueryRow error(%v)", err)
}
return
}
// ActiveUids 统计24小时内有提交的
func (d *Dao) ActiveUids(c context.Context, stime, etime time.Time) (uids []int64, err error) {
st := time.Now()
defer func() {
log.Info("ActiveUids du(%.2fm) wait(%.2fs)", etime.Sub(stime).Minutes(), time.Since(st).Seconds())
}()
rows, err := d.arcReadDB.Query(c, _activeUidsSQL, stime, etime)
if err != nil {
log.Error("d.arcReadDB.Query error(%v)", 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
}
uids = append(uids, uid)
}
return
}

View File

@@ -0,0 +1,103 @@
package dao
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAvgUtimeByUID(t *testing.T) {
var (
c = context.TODO()
uid = int64(421)
stime = time.Now()
etime = time.Now()
)
convey.Convey("AvgUtimeByUID", t, func(ctx convey.C) {
utime, err := d.AvgUtimeByUID(c, uid, stime, etime)
ctx.Convey("Then err should be nil.utime should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(utime, convey.ShouldNotBeNil)
})
})
}
func TestDaoSumDurationByUID(t *testing.T) {
var (
c = context.TODO()
uid = int64(421)
stime = time.Now()
etime = time.Now()
)
convey.Convey("SumDurationByUID", t, func(ctx convey.C) {
duration, err := d.SumDurationByUID(c, uid, stime, etime)
ctx.Convey("Then err should be nil.duration should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(duration, convey.ShouldNotBeNil)
})
})
}
func TestDaoActionCountByUID(t *testing.T) {
var (
c = context.TODO()
uid = int64(421)
stime = time.Now()
etime = time.Now()
)
convey.Convey("ActionCountByUID", t, func(ctx convey.C) {
mapAction, err := d.ActionCountByUID(c, uid, stime, etime)
ctx.Convey("Then err should be nil.mapAction should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(mapAction, convey.ShouldNotBeNil)
})
})
}
func TestDaoPassCountByUID(t *testing.T) {
var (
c = context.TODO()
uid = int64(421)
stime = time.Now()
etime = time.Now()
)
convey.Convey("PassCountByUID", t, func(ctx convey.C) {
count, err := d.PassCountByUID(c, uid, stime, etime)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestDaoSubjectCountByUID(t *testing.T) {
var (
c = context.TODO()
uid = int64(421)
stime = time.Now()
etime = time.Now()
)
convey.Convey("SubjectCountByUID", t, func(ctx convey.C) {
count, err := d.SubjectCountByUID(c, uid, stime, etime)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestDaoActiveUids(t *testing.T) {
var (
c = context.TODO()
stime = time.Now().AddDate(-1, 0, 0)
etime = time.Now()
)
convey.Convey("ActiveUids", t, func(ctx convey.C) {
_, err := d.ActiveUids(c, stime, etime)
ctx.Convey("Then err should be nil.uids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,39 @@
package dao
import (
"context"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
)
const (
_inTaskQA = "INSERT INTO task_qa(state,type,detail_id,uid,ctime,mtime) VALUES(?,?,?,?,?,?)"
_upTaskQA = "UPDATE task_qa SET state=?, ftime=?, mtime=? WHERE id=?"
)
//InTaskQA insert a qa task
func (d *Dao) InTaskQA(tx *sql.Tx, uid int64, detailID int64, taskType int8) (id int64, err error) {
now := time.Now()
res, err := tx.Exec(_inTaskQA, model.QAStateWait, taskType, detailID, uid, now, now)
if err != nil {
PromeErr("arcdb: insert", "InTaskQA tx.Exe error(%v) uid(%d) detailid(%d)", err, uid, detailID)
return
}
id, err = res.LastInsertId()
return
}
//UpTask update qa task
func (d *Dao) UpTask(ctx context.Context, id int64, state int16, ftime time.Time) (rows int64, err error) {
res, err := d.arcDB.Exec(ctx, _upTaskQA, state, ftime, ftime, id)
if err != nil {
PromeErr("arcdb: update", "UpTask d.arcDB.Exec error(%v) id(%d) state(%d)", err, id, state)
return
}
rows, err = res.RowsAffected()
return
}

View File

@@ -0,0 +1,45 @@
package dao
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoInTaskQA(t *testing.T) {
var (
tx, _ = d.BeginTran(context.TODO())
uid = int64(421)
detailID = int64(1)
taskType = int8(1)
)
convey.Convey("InTaskQA", t, func(ctx convey.C) {
id, err := d.InTaskQA(tx, uid, detailID, taskType)
if err == nil {
tx.Commit()
} else {
tx.Rollback()
}
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpTask(t *testing.T) {
var (
c = context.TODO()
id = int64(41)
state = int16(2)
ftime = time.Now()
)
convey.Convey("UpTask", t, func(ctx convey.C) {
_, err := d.UpTask(c, id, state, ftime)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,198 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"time"
xsql "database/sql"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_inQAVideo = "INSERT INTO task_qa_video(cid,aid,task_id,task_utime,attribute,mid,fans,up_groups,arc_title,arc_typeid,audit_status,audit_tagid,audit_submit,audit_details,ctime,mtime) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
_QATaskVideo = `SELECT qa.id, qa.state, qa.type, qa.detail_id, qa.uid, qa.ftime, qa.ctime,
qav.cid, qav.aid, coalesce(qav.task_id, 0) task_id, qav.task_utime, qav.attribute, qav.audit_tagid, qav.arc_title, qav.arc_typeid, qav.audit_status, qav.audit_submit, qav.audit_details, qav.mid, qav.fans, qav.up_groups
FROM task_qa qa LEFT JOIN task_qa_video qav ON qa.detail_id = qav.id WHERE qa.id = ? LIMIT 1`
_QATaskVideoSimple = `SELECT qa.id, qa.state, qa.type, qa.detail_id, qa.uid, qa.ftime, qa.ctime,
qav.cid, qav.aid, coalesce(qav.task_id, 0) task_id,qav.task_utime, qav.attribute, qav.audit_tagid, qav.arc_title, qav.arc_typeid, qav.audit_status, qav.audit_submit, qav.mid, qav.fans, qav.up_groups
FROM task_qa qa LEFT JOIN task_qa_video qav ON qa.detail_id = qav.id WHERE qa.id = ? LIMIT 1`
_QAVideoDetail = "SELECT qa.id, qav.id, qav.mid, qav.task_utime FROM task_qa qa LEFT JOIN task_qa_video qav ON qa.detail_id = qav.id WHERE qa.id IN (%s)"
_QAVideoByTASKID = `SELECT id FROM task_qa_video WHERE aid=? AND cid=? AND task_id=?`
_upQAVideoUTime = "UPDATE task_qa_video SET task_utime=? WHERE aid=? AND cid=? AND task_id=?"
_delQAVideo = "DELETE FROM task_qa_video WHERE mtime<? LIMIT ?"
_delQATask = "DELETE FROM task_qa WHERE mtime<? LIMIT ?"
)
//InsertQAVideo insert qa video detail
func (d *Dao) InsertQAVideo(tx *sql.Tx, dt *model.VideoDetail) (id int64, err error) {
var (
groups string
)
if len(dt.UPGroups) > 0 {
var b []byte
b, err = json.Marshal(dt.UPGroups)
if err != nil {
log.Error("InsertQAVideo json.Marshal(%v) error(%v) aid(%d) cid(%d)", dt.UPGroups, err, dt.AID, dt.CID)
return
}
groups = string(b)
}
now := time.Now()
res, err := tx.Exec(_inQAVideo, dt.CID, dt.AID, dt.TaskID, dt.TaskUTime, dt.Attribute, dt.MID, dt.Fans, groups,
dt.ArcTitle, dt.ArcTypeID, dt.AuditStatus, dt.TagID, dt.AuditSubmit, dt.AuditDetails, now, now)
if err != nil {
PromeErr("arcdb: exec", "InsertQAVideo tx.Exec error(%v) aid(%d) cid(%d)", err, dt.AID, dt.CID)
return
}
id, err = res.LastInsertId()
return
}
//QATaskVideoByID get by id
func (d *Dao) QATaskVideoByID(ctx context.Context, id int64) (q *model.QATaskVideo, err error) {
var (
groups string
)
q = new(model.QATaskVideo)
if err = d.arcReadDB.QueryRow(ctx, _QATaskVideo, id).Scan(&q.ID, &q.State, &q.Type, &q.DetailID, &q.UID, &q.FTime, &q.CTime,
&q.CID, &q.AID, &q.TaskID, &q.TaskUTime, &q.Attribute, &q.TagID, &q.ArcTitle, &q.ArcTypeID, &q.AuditStatus, &q.AuditSubmit, &q.AuditDetails,
&q.MID, &q.Fans, &groups); err != nil {
if err == sql.ErrNoRows {
err = nil
q = nil
} else {
PromeErr("arcReaddb: scan", "QATaskVideoByID row.Scan error(%v) id(%d)", err, id)
}
return
}
q.UPGroups = []int64{}
if groups != "" {
if err = json.Unmarshal([]byte(groups), &q.UPGroups); err != nil {
log.Error("QATaskVideoByID json.Unmarshal(%s) error(%v) id(%d)", groups, err, id)
return
}
}
return
}
// QATaskVideoSimpleByID get without audit_details by id
func (d *Dao) QATaskVideoSimpleByID(ctx context.Context, id int64) (q *model.QATaskVideo, err error) {
var (
groups string
)
q = new(model.QATaskVideo)
if err = d.arcReadDB.QueryRow(ctx, _QATaskVideoSimple, id).Scan(&q.ID, &q.State, &q.Type, &q.DetailID, &q.UID, &q.FTime, &q.CTime,
&q.CID, &q.AID, &q.TaskID, &q.TaskUTime, &q.Attribute, &q.TagID, &q.ArcTitle, &q.ArcTypeID, &q.AuditStatus, &q.AuditSubmit,
&q.MID, &q.Fans, &groups); err != nil {
if err == sql.ErrNoRows {
err = nil
q = nil
} else {
PromeErr("arcReaddb: scan", "QATaskVideoSimpleByID row.Scan error(%v) id(%d)", err, id)
}
return
}
q.UPGroups = []int64{}
if groups != "" {
if err = json.Unmarshal([]byte(groups), &q.UPGroups); err != nil {
log.Error("QATaskVideoByID json.Unmarshal(%s) error(%v) id(%d)", groups, err, id)
return
}
}
return
}
//QAVideoDetail get detail id & task_utime
func (d *Dao) QAVideoDetail(ctx context.Context, ids []int64) (list map[int64]map[string]int64, arr []int64, err error) {
var (
idStr string
rows *sql.Rows
)
list = map[int64]map[string]int64{}
arr = make([]int64, 0)
idStr = xstr.JoinInts(ids)
if rows, err = d.arcReadDB.Query(ctx, fmt.Sprintf(_QAVideoDetail, idStr)); err != nil {
PromeErr("arcReaddb: query", "QAVideoDetail d.arcReadDB.Query error(%v) ids(%s)", err, idStr)
return
}
defer rows.Close()
for rows.Next() {
var (
id, detailID, mid, taskUTime int64
)
if err = rows.Scan(&id, &detailID, &mid, &taskUTime); err != nil {
PromeErr("arcReaddb: scan", "QAVideoDetail rows.Scan error(%v) ids(%s)", err, idStr)
return
}
list[id] = map[string]int64{
"detail_id": detailID,
"mid": mid,
"task_utime": taskUTime,
}
arr = append(arr, mid)
}
return
}
//GetQAVideoID get id by aid & cid & taskid
func (d *Dao) GetQAVideoID(ctx context.Context, aid int64, cid int64, taskID int64) (id int64, err error) {
if err = d.arcDB.QueryRow(ctx, _QAVideoByTASKID, aid, cid, taskID).Scan(&id); err != nil {
if err == sql.ErrNoRows {
id = 0
err = nil
} else {
log.Error("GetQAVideoID scan error(%v) aid(%d) cid(%d) taskid(%d)", err, aid, cid, taskID)
}
}
return
}
//UpdateQAVideoUTime update task_utime
func (d *Dao) UpdateQAVideoUTime(ctx context.Context, aid int64, cid int64, taskID, utime int64) (err error) {
if _, err = d.arcDB.Exec(ctx, _upQAVideoUTime, utime, aid, cid, taskID); err != nil {
PromeErr("arcdb: exec", "UpdateQAVideoUTime error(%v) aid(%d) cid(%d) taskid(%d)", err, aid, cid, taskID)
}
return
}
//DelQAVideo 删除数据
func (d *Dao) DelQAVideo(ctx context.Context, mtime time.Time, limit int) (rows int64, err error) {
var (
result xsql.Result
)
if result, err = d.arcDB.Exec(ctx, _delQAVideo, mtime, limit); err != nil {
PromeErr("arcdb: exec", "DelQAVideo error(%v) mtime(%v)", err, mtime)
return
}
rows, err = result.RowsAffected()
return
}
//DelQATask 删除数据
func (d *Dao) DelQATask(ctx context.Context, mtime time.Time, limit int) (rows int64, err error) {
var (
result xsql.Result
)
if result, err = d.arcDB.Exec(ctx, _delQATask, mtime, limit); err != nil {
PromeErr("arcdb: exec", "DelQATask error(%v) mtime(%v)", err, mtime)
return
}
rows, err = result.RowsAffected()
return
}

View File

@@ -0,0 +1,130 @@
package dao
import (
"context"
"go-common/app/admin/main/videoup-task/model"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoInsertQAVideo(t *testing.T) {
var (
tx, _ = d.BeginTran(context.TODO())
dt = &model.VideoDetail{
UPGroups: []int64{0},
}
)
convey.Convey("InsertQAVideo", t, func(ctx convey.C) {
id, err := d.InsertQAVideo(tx, dt)
if err == nil {
tx.Commit()
} else {
tx.Rollback()
}
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
}
func TestDaoQAVideoDetail(t *testing.T) {
var (
c = context.TODO()
ids = []int64{437}
)
convey.Convey("QAVideoDetail", t, func(ctx convey.C) {
list, arr, err := d.QAVideoDetail(c, ids)
ctx.Convey("Then err should be nil.list,arr should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(arr, convey.ShouldNotBeNil)
ctx.So(list, convey.ShouldNotBeNil)
})
})
}
func TestDaoGetQAVideoID(t *testing.T) {
var (
c = context.TODO()
aid = int64(10110610)
cid = int64(10134188)
taskID = int64(8725)
)
convey.Convey("GetQAVideoID", t, func(ctx convey.C) {
id, err := d.GetQAVideoID(c, aid, cid, taskID)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpdateQAVideoUTime(t *testing.T) {
var (
c = context.TODO()
aid = int64(10110610)
cid = int64(10134188)
taskID = int64(8725)
utime = int64(10)
)
convey.Convey("UpdateQAVideoUTime", t, func(ctx convey.C) {
err := d.UpdateQAVideoUTime(c, aid, cid, taskID, utime)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelQAVideo(t *testing.T) {
var (
c = context.TODO()
mtime = time.Now().AddDate(-1, -1, 0)
limit = int(1)
)
convey.Convey("DelQAVideo", t, func(ctx convey.C) {
_, err := d.DelQAVideo(c, mtime, limit)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelQATask(t *testing.T) {
var (
c = context.TODO()
mtime = time.Now().AddDate(-1, -1, 0)
limit = int(1)
)
convey.Convey("DelQATask", t, func(ctx convey.C) {
_, err := d.DelQATask(c, mtime, limit)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoQATaskVideoByID(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("QATaskVideoByID", t, func(ctx convey.C) {
_, err := d.QATaskVideoByID(c, 0)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoQATaskVideoSimpleByID(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("QATaskVideoSimpleByID", t, func(ctx convey.C) {
_, err := d.QATaskVideoSimpleByID(c, 0)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,240 @@
package dao
import (
"context"
xsql "database/sql"
"encoding/json"
"fmt"
"strings"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_reviewCfg = 3
_countSQL = "SELECT COUNT(*) FROM task_json_config"
_listConfsSQL = "SELECT id,conf_json,conf_type,btime,etime,state,uid,uname,description,mtime FROM task_json_config WHERE conf_type=3"
_reConfsSQL = "SELECT id,conf_json,conf_type,btime,etime,state,uid,uname,description,mtime FROM task_json_config WHERE conf_type=3"
_inConfSQL = "INSERT INTO task_json_config(conf_json,conf_type,btime,etime,state,uid,uname,description) VALUE (?,?,?,?,?,?,?,?)"
_upConfSQL = "UPDATE task_json_config SET conf_json=?,conf_type=?,btime=?,etime=?,state=?,uid=?,uname=?,description=? WHERE id=?"
_delConfSQL = "DELETE FROM task_json_config WHERE id=?"
_reviewSQL = "SELECT review_form FROM task_review WHERE task_id=?"
_inReviewSQL = "INSERT INTO task_review(task_id,review_form,uid,uname) VALUE (?,?,?,?)"
)
// ListConfs 配置列表
func (d *Dao) ListConfs(c context.Context, uids []int64, bt, et, sort string, pn, ps int64) (rcs []*model.ReviewConf, count int64, err error) {
var (
rows *sql.Rows
countstring, sqlstring, params string
wherecases []string
)
if len(uids) > 0 {
wherecases = append(wherecases, fmt.Sprintf("uid IN (%s)", xstr.JoinInts(uids)))
}
if len(bt) > 0 && len(et) > 0 {
wherecases = append(wherecases, fmt.Sprintf("mtime>='%s' AND mtime<='%s'", bt, et))
}
if len(wherecases) > 0 {
params = " AND " + strings.Join(wherecases, " AND ")
}
countstring = _countSQL + " WHERE conf_type=3" + params
sqlstring = _listConfsSQL + params + fmt.Sprintf(" ORDER BY mtime %s LIMIT %d,%d", sort, (pn-1)*ps, pn*ps)
if err = d.arcDB.QueryRow(c, countstring).Scan(&count); err != nil {
log.Error("d.arcDB.QueryRow(%s) error(%v)", countstring, err)
return
}
if count == 0 {
return
}
if rows, err = d.arcDB.Query(c, sqlstring); err != nil {
log.Error("d.arcDB.Query(%s) error(%v)", sqlstring, err)
return
}
defer rows.Close()
for rows.Next() {
var (
jsonCfg []byte
cfgType int8
)
trc := &model.ReviewConf{}
if err = rows.Scan(&trc.ID, &jsonCfg, &cfgType, &trc.Bt, &trc.Et, &trc.State, &trc.UID, &trc.Uname, &trc.Desc, &trc.Mt); err != nil {
log.Error("rows.Scan error(%v)", err)
continue
}
if err = json.Unmarshal(jsonCfg, trc); err != nil {
log.Error("json.Unmarshal error(%v)", err)
continue
}
trc.Refresh()
rcs = append(rcs, trc)
}
return
}
// ReviewConfs 复审配置
func (d *Dao) ReviewConfs(c context.Context) (rcs []*model.ReviewConf, err error) {
var rows *sql.Rows
if rows, err = d.arcDB.Query(c, _reConfsSQL); err != nil {
log.Error("d.arcDB.Query(%s, %d) error(%v)", _reConfsSQL, err)
return
}
defer rows.Close()
for rows.Next() {
var (
jsonCfg []byte
cfgType int8
)
trc := &model.ReviewConf{}
if err = rows.Scan(&trc.ID, &jsonCfg, &cfgType, &trc.Bt, &trc.Et, &trc.State, &trc.UID, &trc.Uname, &trc.Desc, &trc.Mt); err != nil {
log.Error("rows.Scan error(%v)", err)
continue
}
if err = json.Unmarshal(jsonCfg, trc); err != nil {
log.Error("json.Unmarshal error(%v)", err)
continue
}
trc.Refresh()
rcs = append(rcs, trc)
}
return
}
// InReviewConf 插入配置
func (d *Dao) InReviewConf(c context.Context, rc *model.ReviewConf) (lastid int64, err error) {
var (
res xsql.Result
jsonCfg []byte
)
v := new(struct {
Types []int64 `json:"types" params:"types"` // 分区
UpFroms []int64 `json:"upfroms" params:"upfroms"` // 投稿来源
UpGroups []int64 `json:"upgroups" params:"upgroups"` // 用户组
Uids []int64 `json:"uids" params:"uids"` // 指定uid
FansLow int64 `json:"fanslow" params:"fanslow"` // 粉丝数最低值
FansHigh int64 `json:"fanshigh" params:"fanshigh"` // 粉丝数最高
})
v.Types = rc.Types
v.UpFroms = rc.UpFroms
v.UpGroups = rc.UpGroups
v.Uids = rc.Uids
v.FansLow = rc.FansLow
v.FansHigh = rc.FansHigh
if rc.Bt.TimeValue().IsZero() {
rc.Bt = model.NewFormatTime(time.Now())
}
if jsonCfg, err = json.Marshal(v); err != nil {
log.Error("json.Marshal(%+v) error(%v)", rc, err)
return
}
if res, err = d.arcDB.Exec(c, _inConfSQL, jsonCfg, _reviewCfg, rc.Bt, rc.Et, 0, rc.UID, rc.Uname, rc.Desc); err != nil {
log.Error("d.arcDB.Exec(%+v) error(%s, %v)", _inConfSQL, rc, err)
return
}
return res.LastInsertId()
}
// UpReviewConf 更新指定配置
func (d *Dao) UpReviewConf(c context.Context, rc *model.ReviewConf) (lastid int64, err error) {
var (
res xsql.Result
jsonCfg []byte
)
v := new(struct {
Types []int64 `json:"types" params:"types"` // 分区
UpFroms []int64 `json:"upfroms" params:"upfroms"` // 投稿来源
UpGroups []int64 `json:"upgroups" params:"upgroups"` // 用户组
Uids []int64 `json:"uids" params:"uids"` // 指定uid
FansLow int64 `json:"fanslow" params:"fanslow"` // 粉丝数最低值
FansHigh int64 `json:"fanshigh" params:"fanshigh"` // 粉丝数最高
})
v.Types = rc.Types
v.UpFroms = rc.UpFroms
v.UpGroups = rc.UpGroups
v.Uids = rc.Uids
v.FansLow = rc.FansLow
v.FansHigh = rc.FansHigh
if rc.Bt.TimeValue().IsZero() {
rc.Bt = model.NewFormatTime(time.Now())
}
if jsonCfg, err = json.Marshal(v); err != nil {
log.Error("json.Marshal(%+v) error(%v)", rc, err)
return
}
if res, err = d.arcDB.Exec(c, _upConfSQL, jsonCfg, _reviewCfg, rc.Bt, rc.Et, rc.State, rc.UID, rc.Uname, rc.Desc, rc.ID); err != nil {
log.Error("d.arcDB.Exec(%s %+v) error(%v)", _upConfSQL, rc, err)
return
}
return res.RowsAffected()
}
// DelReviewConf 删除指定配置
func (d *Dao) DelReviewConf(c context.Context, id int) (lastid int64, err error) {
var res xsql.Result
if res, err = d.arcDB.Exec(c, _delConfSQL, id); err != nil {
log.Error("d.arcDB.Exec(%s %d) error(%v)", _delConfSQL, id, err)
return
}
return res.RowsAffected()
}
// ReviewForm 复审表单
func (d *Dao) ReviewForm(c context.Context, tid int64) (tsf *model.SubmitForm, err error) {
var form []byte
if err = d.arcDB.QueryRow(c, _reviewSQL, tid).Scan(&form); err != nil {
if err == sql.ErrNoRows {
log.Info("ReviewForm QueryRow empty(%d)", tid)
err = nil
return
}
log.Error("d.arcDB.QueryRow(%s, %d) error(%v)", _reviewSQL, tid, err)
return
}
tsf = &model.SubmitForm{}
if err = json.Unmarshal(form, tsf); err != nil {
log.Error("json.Unmarshal error(%v)", err)
tsf = nil
}
return
}
// InReviewForm insert submit form
func (d *Dao) InReviewForm(c context.Context, sf *model.SubmitForm, uid int64, uname string) (lastid int64, err error) {
var (
res xsql.Result
bsf []byte
)
if bsf, err = json.Marshal(sf); err != nil {
log.Error("json.Marshal error(%v)", err)
return
}
if res, err = d.arcDB.Exec(c, _inReviewSQL, sf.TaskID, bsf, uid, uname); err != nil {
log.Error("d.arcDB.Exec(%s,%d,%v,%d,%s) error(%v)", _inReviewSQL, sf.TaskID, bsf, uid, uname, err)
return
}
return res.LastInsertId()
}

View File

@@ -0,0 +1,80 @@
package dao
import (
"context"
"testing"
"go-common/app/admin/main/videoup-task/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoListConfs(t *testing.T) {
convey.Convey("ListConfs", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, _, err := d.ListConfs(c, []int64{}, "", "", "", 0, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoReviewConfs(t *testing.T) {
convey.Convey("ReviewConfs", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ReviewConfs(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoUpReviewConf(t *testing.T) {
convey.Convey("UpReviewConf", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.UpReviewConf(c, &model.ReviewConf{})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoDelReviewConf(t *testing.T) {
convey.Convey("DelReviewConf", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.DelReviewConf(c, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoReviewForm(t *testing.T) {
convey.Convey("ReviewForm", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ReviewForm(c, 0)
ctx.Convey("Then err should be nil.max should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,337 @@
package dao
import (
"context"
xsql "database/sql"
"encoding/json"
"fmt"
"go-common/library/xstr"
"strings"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_getMaxWeightSQL = "SELECT MAX(weight) FROM task_dispatch WHERE state in (0,1)"
_upCwAfterAddSQL = "INSERT INTO `task_dispatch_extend` (`task_id`,`description`) VALUES(?,?) ON DUPLICATE KEY UPDATE description=?"
_inWeightConfSQL = "INSERT INTO task_weight_config(mid,rule,weight,uid,uname,radio,description) VALUES (?,?,?,?,?,?,?)" // 增
_delWeightConfSQL = "UPDATE task_weight_config SET state=1 WHERE id=?" // 软删
_listWeightConfSQL = "SELECT id,uname,state,rule,weight,mtime,description FROM task_weight_config" // 查
_WeightConfSQL = "SELECT id,description FROM task_weight_config WHERE state=0" // 查
_lwconfigHelpSQL = "SELECT t.id,t.cid,a.title,v.filename FROM task_dispatch t INNER JOIN archive a ON t.aid=a.id INNER JOIN archive_video v ON t.cid=v.cid WHERE t.id IN (%s)"
// archive_config
_confSQL = "SELECT value FROM archive_config WHERE state=0 AND name=?"
_upconfSQL = "UPDATE archive_config SET value=?,remark=? WHERE name=?"
_inconfSQL = "INSERT archive_config(value,remark,name,state) VALUE (?,?,?,0)"
_twexpire = 24 * 60 * 60 // 1 day
)
// GetMaxWeight 获取当前最大权重数值
func (d *Dao) GetMaxWeight(c context.Context) (max int64, err error) {
if err = d.arcDB.QueryRow(c, _getMaxWeightSQL).Scan(&max); err != nil {
log.Error("d.arcDB.QueryRow error(%v)", err)
err = nil
}
return
}
// UpCwAfterAdd update config weight after add config
func (d *Dao) UpCwAfterAdd(c context.Context, id int64, desc string) (rows int64, err error) {
row, err := d.arcDB.Exec(c, _upCwAfterAddSQL, id, desc, desc)
if err != nil {
log.Error("arcDB.Exec(%s,%d,%s,%s) error(%v)", _upCwAfterAddSQL, id, desc, desc, err)
return
}
return row.RowsAffected()
}
// InWeightConf 写入权重配置表
func (d *Dao) InWeightConf(c context.Context, mcases map[int64]*model.WCItem) (err error) {
tx, err := d.arcDB.Begin(c)
if err != nil {
log.Error("db.Begin() error(%v)", err)
return
}
for _, item := range mcases {
var descb []byte
if descb, err = json.Marshal(item); err != nil {
log.Error("json.Marshal(%+v) error(%v)", item, err)
tx.Rollback()
return
}
if _, err = tx.Exec(_inWeightConfSQL, item.CID, item.Rule, item.Weight, item.UID, item.Uname, item.Radio, string(descb)); err != nil {
log.Error("db.Exec(%s) error(%v)", _inWeightConfSQL, err)
tx.Rollback()
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
return
}
// DelWeightConf 删除权重配置
func (d *Dao) DelWeightConf(c context.Context, id int64) (rows int64, err error) {
res, err := d.arcDB.Exec(c, _delWeightConfSQL, id)
if err != nil {
log.Error("tx.Exec(%s %d) error(%v)", _delWeightConfSQL, id, err)
return
}
return res.RowsAffected()
}
// ListWeightConf 查看权重配置表列表
func (d *Dao) ListWeightConf(c context.Context, cf *model.Confs) (citems []*model.WCItem, err error) {
var (
count int64
rows *sql.Rows
where string
wherecase []string
descb []byte
bt = cf.Bt.TimeValue()
et = cf.Et.TimeValue()
)
if cid := cf.Cid; cid != -1 {
wherecase = append(wherecase, fmt.Sprintf("mid=%d", cid))
}
if operator := cf.Operator; len(operator) > 0 {
wherecase = append(wherecase, fmt.Sprintf("uname='%s'", operator))
}
if rule := cf.Rule; rule != -1 {
wherecase = append(wherecase, fmt.Sprintf("rule=%d", rule))
}
wherecase = append(wherecase, fmt.Sprintf("radio=%d AND state=%d", cf.Radio, cf.State))
where = "WHERE " + strings.Join(wherecase, " AND ")
sqlstring := fmt.Sprintf("%s %s LIMIT %d,%d", _listWeightConfSQL, where, (cf.Pn-1)*cf.Ps, cf.Pn*cf.Ps)
rows, err = d.arcDB.Query(c, sqlstring)
if err != nil {
log.Error("d.arcDB.Query(%s) error(%v)", sqlstring, err)
return
}
defer rows.Close()
for rows.Next() {
wci := &model.WCItem{}
if err = rows.Scan(&wci.ID, &wci.Uname, &wci.State, &wci.Rule, &wci.Weight, &wci.Mtime, &descb); err != nil {
log.Error("rows.Scan(%s) error(%v)", sqlstring, err)
return
}
if len(descb) > 0 {
if err = json.Unmarshal(descb, wci); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(descb), err)
err = nil
continue
}
eti := wci.Et.TimeValue()
// filter time
if !et.IsZero() && !bt.IsZero() && (bt.After(wci.Mtime.TimeValue()) || et.Before(wci.Mtime.TimeValue())) {
log.Info("config expired (%+v) parse et(%v)", wci, et)
continue
}
// filter state
if cf.State == 0 && !eti.IsZero() && eti.Before(time.Now()) {
log.Info("config expired (%+v) parse et(%v)", wci, eti)
continue
}
}
if count > 50 {
break
}
count++
citems = append(citems, wci)
}
return
}
// WeightConf 所有有效的配置(用于检测是否和已有的配置冲突)
func (d *Dao) WeightConf(c context.Context) (items []*model.WCItem, err error) {
var (
id int64
descb []byte
rows *sql.Rows
wci *model.WCItem
)
if rows, err = d.arcDB.Query(c, _WeightConfSQL); err != nil {
log.Error("d.arcDB.Query(%s) error(%v)", _WeightConfSQL, err)
return
}
defer rows.Close()
for rows.Next() {
wci = new(model.WCItem)
if err = rows.Scan(&id, &descb); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
if err = json.Unmarshal(descb, wci); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(descb), err)
err = nil
continue
}
wci.ID = id
items = append(items, wci)
}
return
}
// LWConfigHelp 补充任务对应稿件的title和filename
func (d *Dao) LWConfigHelp(c context.Context, ids []int64) (res map[int64][]interface{}, err error) {
var (
taskid, vid int64
filename, title string
rows *sql.Rows
)
rows, err = d.arcDB.Query(c, fmt.Sprintf(_lwconfigHelpSQL, xstr.JoinInts(ids)))
if err != nil {
log.Error("d.arcDB.Query(%v) error(%v)", ids, err)
return
}
defer rows.Close()
res = make(map[int64][]interface{})
for rows.Next() {
err = rows.Scan(&taskid, &vid, &title, &filename)
if err != nil {
log.Error("rows.Scan error(%v)", err)
continue
}
res[taskid] = []interface{}{filename, title, vid}
}
return
}
func key(id int64) string {
return fmt.Sprintf("tw_%d", id)
}
//SetWeightRedis 设置权重配置
func (d *Dao) SetWeightRedis(c context.Context, mcases map[int64]*model.TaskPriority) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
for tid, mcase := range mcases {
var bs []byte
key := key(tid)
if bs, err = json.Marshal(mcase); err != nil {
log.Error("json.Marshal(%+v) error(%v)", mcase, err)
continue
}
if err = conn.Send("SET", key, bs); err != nil {
log.Error("SET error(%v)", err)
continue
}
if err = conn.Send("EXPIRE", key, _twexpire); err != nil {
log.Error("EXPIRE error(%v)", err)
continue
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < 2*len(mcases); i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
//GetWeightRedis 获取实时任务的权重配置
func (d *Dao) GetWeightRedis(c context.Context, ids []int64) (mcases map[int64]*model.TaskPriority, err error) {
conn := d.redis.Get(c)
defer conn.Close()
mcases = make(map[int64]*model.TaskPriority)
for _, id := range ids {
var bs []byte
key := key(int64(id))
if bs, err = redis.Bytes(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(GET, %v) error(%v)", key, err)
}
continue
}
p := &model.TaskPriority{}
if err = json.Unmarshal(bs, p); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(bs), err)
err = nil
continue
}
mcases[int64(id)] = p
}
return
}
// WeightVC 获取权重分值
func (d *Dao) WeightVC(c context.Context) (wvc *model.WeightVC, err error) {
var value []byte
row := d.arcDB.QueryRow(c, _confSQL, model.ConfForWeightVC)
if err = row.Scan(&value); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
return
}
wvc = new(model.WeightVC)
if err = json.Unmarshal(value, wvc); err != nil {
log.Error("json.Unmarshal error(%v)", err)
wvc = nil
}
return
}
// SetWeightVC 设置权重分值
func (d *Dao) SetWeightVC(c context.Context, wvc *model.WeightVC, desc string) (rows int64, err error) {
var (
valueb []byte
res xsql.Result
)
if valueb, err = json.Marshal(wvc); err != nil {
log.Error("json.Marshal(%+v) error(%v)", wvc, err)
return
}
if res, err = d.arcDB.Exec(c, _upconfSQL, string(valueb), desc, model.ConfForWeightVC); err != nil {
log.Error("d.arcDB.Exec(%s, %s, %s, %s) error(%v)", _upconfSQL, string(valueb), desc, model.ConfForWeightVC, err)
return
}
return res.RowsAffected()
}
// InWeightVC 插入
func (d *Dao) InWeightVC(c context.Context, wvc *model.WeightVC, desc string) (rows int64, err error) {
var (
valueb []byte
res xsql.Result
)
if valueb, err = json.Marshal(wvc); err != nil {
log.Error("json.Marshal(%+v) error(%v)", wvc, err)
return
}
if res, err = d.arcDB.Exec(c, _inconfSQL, string(valueb), desc, model.ConfForWeightVC); err != nil {
log.Error("d.arcDB.Exec(%s, %s, %s, %s) error(%v)", _inconfSQL, string(valueb), desc, model.ConfForWeightVC, err)
return
}
return res.LastInsertId()
}

View File

@@ -0,0 +1,212 @@
package dao
import (
"context"
"go-common/app/admin/main/videoup-task/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoGetMaxWeight(t *testing.T) {
convey.Convey("GetMaxWeight", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
max, err := d.GetMaxWeight(c)
ctx.Convey("Then err should be nil.max should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(max, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUpCwAfterAdd(t *testing.T) {
convey.Convey("UpCwAfterAdd", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
desc = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.UpCwAfterAdd(c, id, desc)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoInWeightConf(t *testing.T) {
convey.Convey("InWeightConf", t, func(ctx convey.C) {
var (
c = context.Background()
mcases map[int64]*model.WCItem
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.InWeightConf(c, mcases)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoDelWeightConf(t *testing.T) {
convey.Convey("DelWeightConf", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.DelWeightConf(c, id)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoListWeightConf(t *testing.T) {
convey.Convey("ListWeightConf", t, func(ctx convey.C) {
var (
c = context.Background()
cf = &model.Confs{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ListWeightConf(c, cf)
ctx.Convey("Then err should be nil.citems should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoWeightConf(t *testing.T) {
convey.Convey("WeightConf", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
items, err := d.WeightConf(c)
ctx.Convey("Then err should be nil.items should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(items, convey.ShouldNotBeNil)
})
})
})
}
func TestDaokey(t *testing.T) {
convey.Convey("key", t, func(ctx convey.C) {
var (
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := key(id)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoGetWeightRedis(t *testing.T) {
convey.Convey("GetWeightRedis", t, func(ctx convey.C) {
var (
c = context.Background()
ids = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
mcases, err := d.GetWeightRedis(c, ids)
ctx.Convey("Then err should be nil.mcases should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(mcases, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoWeightVC(t *testing.T) {
convey.Convey("WeightVC", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
wvc, err := d.WeightVC(c)
ctx.Convey("Then err should be nil.wvc should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(wvc, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoSetWeightVC(t *testing.T) {
convey.Convey("SetWeightVC", t, func(ctx convey.C) {
var (
c = context.Background()
wvc = &model.WeightVC{}
desc = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.SetWeightVC(c, wvc, desc)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoInWeightVC(t *testing.T) {
convey.Convey("InWeightVC", t, func(ctx convey.C) {
var (
c = context.Background()
wvc = &model.WeightVC{}
desc = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.InWeightVC(c, wvc, desc)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoLWConfigHelp(t *testing.T) {
convey.Convey("LWConfigHelp", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.LWConfigHelp(c, []int64{1})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSetWeightRedis(t *testing.T) {
convey.Convey("SetWeightRedis", t, func(ctx convey.C) {
var (
c = context.Background()
mcases = map[int64]*model.TaskPriority{
0: &model.TaskPriority{},
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetWeightRedis(c, mcases)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,32 @@
package dao
import (
"context"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/log"
)
const (
_tpsSQL = "SELECT id,pid,name,description FROM archive_type"
)
// TypeMapping is second types opposite first types.
func (d *Dao) TypeMapping(c context.Context) (tmap map[int16]*model.Type, err error) {
rows, err := d.arcDB.Query(c, _tpsSQL)
if err != nil {
log.Error("d.arcDB.Query error(%v)", err)
return
}
defer rows.Close()
tmap = make(map[int16]*model.Type)
for rows.Next() {
t := &model.Type{}
if err = rows.Scan(&t.ID, &t.PID, &t.Name, &t.Desc); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
tmap[t.ID] = t
}
return
}

View File

@@ -0,0 +1,23 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoTypeMapping(t *testing.T) {
convey.Convey("TypeMapping", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
tmap, err := d.TypeMapping(c)
ctx.Convey("Then err should be nil.tmap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(tmap, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,51 @@
package dao
import (
"context"
"net/url"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/log"
"go-common/library/xstr"
)
//UPGroups get all the up groups
func (d *Dao) UPGroups(c context.Context, mids []int64) (groups map[int64][]*model.UPGroup, err error) {
val := url.Values{}
mid := xstr.JoinInts(mids)
val.Set("mids", mid)
val.Set("group_id", "0")
groups = map[int64][]*model.UPGroup{}
for _, mid := range mids {
groups[mid] = []*model.UPGroup{}
}
var res struct {
Code int `json:"code"`
Data struct {
Items []map[string]interface{} `json:"items"`
}
}
if err = d.hclient.Get(c, d.upGroupURL, "", val, &res); err != nil {
log.Error("UPGroups url(%s) error(%v)", d.upGroupURL+"?"+val.Encode(), err)
return
}
if res.Code != 0 || res.Data.Items == nil {
log.Warn("UPGroups code(%d) !=0 or empty url(%s) error(%v)", res.Code, d.upGroupURL+"?"+val.Encode(), res.Code)
return
}
for _, item := range res.Data.Items {
g := &model.UPGroup{
ID: int64(item["group_id"].(float64)),
Tag: item["group_name"].(string),
ShortTag: item["group_tag"].(string),
FontColor: item["font_color"].(string),
BgColor: item["bg_color"].(string),
Note: item["note"].(string),
}
mid := int64(item["mid"].(float64))
groups[mid] = append(groups[mid], g)
}
return
}

View File

@@ -0,0 +1,22 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoUPGroups(t *testing.T) {
var (
c = context.TODO()
mids = []int64{27515256, 27515304}
)
convey.Convey("UPGroups", t, func(ctx convey.C) {
httpMock("GET", d.upGroupURL).Reply(200).JSON(`{"code":0,"data":{"items":[{"group_id":1,"group_name":"name","group_tag":"tag","font_color":"font","bg_color":"bg","note":"note","mid":11}]}}`)
_, err := d.UPGroups(c, mids)
ctx.Convey("Then err should be nil.groups should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,95 @@
package dao
import (
"context"
"fmt"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/xstr"
)
const (
_usernameRoleSQL = `SELECT u.id, u.username, coalesce(r.role,0) role FROM user u LEFT JOIN auth_role r ON u.id = r.uid WHERE u.id IN (%s)`
_usernameDepartmentSQL = `SELECT u.id, u.username, coalesce(d.name,'') department FROM user u LEFT JOIN user_department d ON u.department_id = d.id WHERE u.id IN (%s)`
_usernameSQL = `SELECT id,username FROM user WHERE id IN (%s)`
)
//GetUsernameAndRole batch get username & role
func (d *Dao) GetUsernameAndRole(ctx context.Context, uids []int64) (list map[int64]*model.UserRole, err error) {
var (
rows *sql.Rows
)
list = map[int64]*model.UserRole{}
uidStr := xstr.JoinInts(uids)
if rows, err = d.mngDB.Query(ctx, fmt.Sprintf(_usernameRoleSQL, uidStr)); err != nil {
PromeErr("mngdb: query", "GetUsernameAndRole d.mngDB.Query error(%v) uids(%s)", err, uidStr)
return
}
defer rows.Close()
for rows.Next() {
u := new(model.UserRole)
if err = rows.Scan(&u.UID, &u.Name, &u.Role); err != nil {
PromeErr("mngdb: scan", "GetUsernameAndRole rows.Scan error(%v) uids(%s)", err, uidStr)
return
}
list[u.UID] = u
}
return
}
//GetUsernameAndDepartment batch get username & department
func (d *Dao) GetUsernameAndDepartment(ctx context.Context, uids []int64) (list map[int64]*model.UserDepart, err error) {
var (
rows *sql.Rows
)
list = map[int64]*model.UserDepart{}
uidStr := xstr.JoinInts(uids)
if rows, err = d.mngDB.Query(ctx, fmt.Sprintf(_usernameDepartmentSQL, uidStr)); err != nil {
PromeErr("mngdb: query", "GetUsernameAndDepartment d.mngDB.Query error(%v) uids(%s)", err, uidStr)
return
}
defer rows.Close()
for rows.Next() {
u := new(model.UserDepart)
if err = rows.Scan(&u.UID, &u.Name, &u.Department); err != nil {
PromeErr("mngdb: scan", "GetUsernameAndDepartment rows.Scan error(%v) uids(%s)", err, uidStr)
return
}
list[u.UID] = u
}
return
}
//GetUsername get username
func (d *Dao) GetUsername(ctx context.Context, uids []int64) (list map[int64]string, err error) {
var (
rows *sql.Rows
uid int64
name string
)
list = map[int64]string{}
uidStr := xstr.JoinInts(uids)
if rows, err = d.mngDB.Query(ctx, fmt.Sprintf(_usernameSQL, uidStr)); err != nil {
PromeErr("mngdb: query", "GetUsername d.mngDB.Query error(%v) uids(%s)", err, uidStr)
return
}
defer rows.Close()
for rows.Next() {
if err = rows.Scan(&uid, &name); err != nil {
PromeErr("mngdb: scan", "GetUsername rows.Scan error(%v) uids(%s)", err, uidStr)
return
}
list[uid] = name
}
return
}

View File

@@ -0,0 +1,50 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoGetUsernameAndRole(t *testing.T) {
var (
c = context.TODO()
uids = []int64{1, 74, 241}
)
convey.Convey("GetUsernameAndRole", t, func(ctx convey.C) {
list, err := d.GetUsernameAndRole(c, uids)
ctx.Convey("Then err should be nil.list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(list, convey.ShouldNotBeNil)
})
})
}
func TestDaoGetUsernameAndDepartment(t *testing.T) {
var (
c = context.TODO()
uids = []int64{1, 74, 241}
)
convey.Convey("GetUsernameAndDepartment", t, func(ctx convey.C) {
list, err := d.GetUsernameAndDepartment(c, uids)
ctx.Convey("Then err should be nil.list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(list, convey.ShouldNotBeNil)
})
})
}
func TestDaoGetUsername(t *testing.T) {
var (
c = context.TODO()
uids = []int64{1, 74, 241}
)
convey.Convey("GetUsername", t, func(ctx convey.C) {
list, err := d.GetUsername(c, uids)
ctx.Convey("Then err should be nil.list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(list, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,103 @@
package dao
import (
"context"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_videoVID = `SELECT vr.id FROM archive_video_relation vr LEFT JOIN video v ON vr.cid=v.id
LEFT JOIN archive a ON vr.aid=a.id
WHERE vr.aid=? AND vr.cid=? AND vr.state != -100 AND v.status != -100 AND a.state != -100`
_video = `SELECT vr.id, vr.aid, vr.cid, ar.mid, ar.copyright, ar.typeid, v.status, v.attribute, v.xcode_state, vr.title, vr.description, v.filename,
coalesce(ad.tid, 0) tid, coalesce(ad.reason, '') reason, coalesce(ao.remark, '') note
FROM archive_video_relation vr LEFT JOIN video v ON vr.cid=v.id
LEFT JOIN archive ar ON vr.aid=ar.id
LEFT JOIN archive_video_audit ad ON vr.id = ad.vid
LEFT JOIN archive_video_oper ao ON vr.id = ao.vid
WHERE vr.aid=? AND vr.cid=? AND ao.content NOT LIKE '%一审任务质检TAG: [%'
ORDER BY ao.id DESC LIMIT 0,1`
_videoByCid = `SELECT vr.id,vr.aid,vr.title AS eptitle,vr.description,v.filename,v.src_type,vr.cid,v.duration,v.filesize,
v.resolutions,vr.index_order,vr.ctime,vr.mtime,v.status,v.playurl,v.attribute,v.failcode AS failinfo,v.xcode_state,v.weblink
FROM archive_video_relation AS vr LEFT JOIN video AS v ON vr.cid = v.id WHERE vr.cid = ?`
_newVideoIDSQL = `SELECT avr.id,v.filename,avr.cid,avr.aid,avr.title,avr.description,v.src_type,v.duration,v.filesize,v.resolutions,v.playurl,v.failcode,
avr.index_order,v.attribute,v.xcode_state,avr.state,avr.ctime,avr.mtime FROM archive_video_relation avr JOIN video v on avr.cid = v.id
WHERE avr.id=? LIMIT 1`
_videoAttributeSQL = `SELECT attribute FROM video WHERE id = ?`
)
// VideoAttribute get attr
func (d *Dao) VideoAttribute(ctx context.Context, cid int64) (attr int32, err error) {
if err = d.arcDB.QueryRow(ctx, _videoAttributeSQL, cid).Scan(&attr); err != nil {
if err == sql.ErrNoRows {
attr = 0
err = nil
} else {
PromeErr("arcdb: scan", "GetVVideoAttributeID row.Scan error(%v), cid(%d)", err, cid)
}
}
return
}
//GetVID get vid
func (d *Dao) GetVID(ctx context.Context, aid int64, cid int64) (vid int64, err error) {
if err = d.arcReadDB.QueryRow(ctx, _videoVID, aid, cid).Scan(&vid); err != nil {
if err == sql.ErrNoRows {
vid = 0
err = nil
} else {
PromeErr("arcReaddb: scan", "GetVID row.Scan error(%v) aid(%d), cid(%d)", err, aid, cid)
}
}
return
}
//Video get video by aid & cid
func (d *Dao) Video(ctx context.Context, aid int64, cid int64) (v *model.Video, err error) {
v = &model.Video{}
if err = d.arcReadDB.QueryRow(ctx, _video, aid, cid).Scan(&v.ID, &v.AID, &v.CID, &v.MID, &v.Copyright, &v.TypeID, &v.Status,
&v.Attribute, &v.XcodeState, &v.Title, &v.Description, &v.Filename,
&v.TagID, &v.Reason, &v.Note); err != nil {
if err == sql.ErrNoRows {
err = nil
v = nil
} else {
PromeErr("arcReaddb: scan", "Video row.Scan error(%v) aid(%d), cid(%d)", err, aid, cid)
}
}
return
}
// ArcVideoByCID get video by cid
func (d *Dao) ArcVideoByCID(c context.Context, cid int64) (v *model.ArcVideo, err error) {
row := d.arcDB.QueryRow(c, _videoByCid, cid)
v = &model.ArcVideo{}
if err = row.Scan(&v.ID, &v.Aid, &v.Title, &v.Desc, &v.Filename, &v.SrcType, &v.Cid, &v.Duration, &v.Filesize, &v.Resolutions, &v.Index, &v.CTime, &v.MTime, &v.Status, &v.Playurl, &v.Attribute, &v.FailCode, &v.XcodeState, &v.WebLink); err != nil {
if err == sql.ErrNoRows {
v = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}
// NewVideoByID .
func (d *Dao) NewVideoByID(c context.Context, id int64) (v *model.ArcVideo, err error) {
row := d.arcDB.QueryRow(c, _newVideoIDSQL, id)
v = &model.ArcVideo{}
if err = row.Scan(&v.ID, &v.Filename, &v.Cid, &v.Aid, &v.Title, &v.Desc, &v.SrcType, &v.Duration, &v.Filesize, &v.Resolutions,
&v.Playurl, &v.FailCode, &v.Index, &v.Attribute, &v.XcodeState, &v.Status, &v.CTime, &v.MTime); err != nil {
if err == sql.ErrNoRows {
v = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}

View File

@@ -0,0 +1,73 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoGetVID(t *testing.T) {
var (
c = context.TODO()
aid = int64(10098208)
cid = int64(10108827)
)
convey.Convey("GetVID", t, func(ctx convey.C) {
vid, err := d.GetVID(c, aid, cid)
ctx.Convey("Then err should be nil.vid should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(vid, convey.ShouldNotBeNil)
})
})
}
func TestDaoVideo(t *testing.T) {
var (
c = context.TODO()
aid = int64(10110750)
cid = int64(10134516)
)
convey.Convey("Video", t, func(ctx convey.C) {
_, err := d.Video(c, aid, cid)
ctx.Convey("Then err should be nil.v should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoVideoAttribute(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("VideoAttribute", t, func(ctx convey.C) {
_, err := d.VideoAttribute(c, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoArcVideoByCID(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("ArcVideoByCID", t, func(ctx convey.C) {
_, err := d.ArcVideoByCID(c, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoNewVideoByID(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("NewVideoByID", t, func(ctx convey.C) {
_, err := d.NewVideoByID(c, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,57 @@
package dao
import (
"bytes"
"context"
"crypto/md5"
"encoding/binary"
"encoding/json"
"fmt"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/log"
"github.com/tsuna/gohbase/hrpc"
)
var (
tableInfo = "ugc:ArchiveTaskWeight"
family = "weightlog"
familyB = []byte(family)
)
// hashRowKey create rowkey(md5(tid)[:2]+tid) for track by tid.
func hashRowKey(tid int64) string {
var bs = make([]byte, 8)
binary.LittleEndian.PutUint64(bs, uint64(tid))
rk := md5.Sum(bs)
return fmt.Sprintf("%x%d", rk[:2], tid)
}
// WeightLog get weight log.
func (d *Dao) WeightLog(c context.Context, taskid int64) (ls []*model.TaskWeightLog, err error) {
var (
result *hrpc.Result
key = hashRowKey(taskid)
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
)
defer cancel()
if result, err = d.hbase.GetStr(ctx, tableInfo, key); err != nil {
log.Error("hrpc.NewGetStr(%s,%s) error(%v)", tableInfo, key, err)
return
}
for _, c := range result.Cells {
if c == nil || !bytes.Equal(c.Family, familyB) {
return
}
aLog := &model.TaskWeightLog{}
if err = json.Unmarshal(c.Value, aLog); err != nil {
log.Warn("json.Unmarshal(%s) error(%v)", string(c.Value), err)
err = nil
continue
}
ls = append(ls, aLog)
}
return
}

View File

@@ -0,0 +1,38 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaohashRowKey(t *testing.T) {
convey.Convey("hashRowKey", t, func(ctx convey.C) {
var (
tid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := hashRowKey(tid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoWeightLog(t *testing.T) {
convey.Convey("WeightLog", t, func(ctx convey.C) {
var (
c = context.Background()
taskid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ls, err := d.WeightLog(c, taskid)
ctx.Convey("Then err should be nil.ls should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ls, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"consumer.go",
"http.go",
"prehandler.go",
"qa_video.go",
"report.go",
"review.go",
"task.go",
"weight.go",
],
importpath = "go-common/app/admin/main/videoup-task/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/videoup-task/conf:go_default_library",
"//app/admin/main/videoup-task/model:go_default_library",
"//app/admin/main/videoup-task/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/http/blademaster/render: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,79 @@
package http
import (
"net/http"
"strconv"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/render"
)
// 登录管理
func on(c *bm.Context) {
uid, uname := getUIDName(c)
err := srv.HandsUp(c, uid, uname)
if err != nil {
data := map[string]interface{}{
"code": ecode.RequestErr,
"message": err.Error(),
}
c.Render(http.StatusOK, render.MapJSON(data))
return
}
c.JSON(nil, nil)
}
// 踢出
func forceoff(c *bm.Context) {
uidS := c.Request.Form.Get("uid")
uid, _ := strconv.ParseInt(uidS, 10, 64)
if uid == 0 {
c.JSON(nil, ecode.RequestErr)
return
}
adminuid, _ := getUIDName(c)
err := srv.HandsOff(c, adminuid, uid)
if err != nil {
data := map[string]interface{}{
"code": ecode.RequestErr,
"message": err.Error(),
}
c.Render(http.StatusOK, render.MapJSON(data))
return
}
c.JSON(nil, nil)
}
func off(c *bm.Context) {
adminuid, _ := getUIDName(c)
err := srv.HandsOff(c, adminuid, 0)
if err != nil {
data := map[string]interface{}{
"code": ecode.RequestErr,
"message": err.Error(),
}
c.Render(http.StatusOK, render.MapJSON(data))
return
}
c.JSON(nil, nil)
}
func online(c *bm.Context) {
c.JSON(srv.Online(c))
}
func inoutlist(c *bm.Context) {
v := new(struct {
Unames string `form:"unames" default:""`
Bt string `form:"bt" default:""`
Et string `form:"et" default:""`
})
if err := c.Bind(v); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(srv.InOutList(c, v.Unames, v.Bt, v.Et))
}

View File

@@ -0,0 +1,119 @@
package http
import (
http2 "net/http"
"go-common/app/admin/main/videoup-task/conf"
"go-common/app/admin/main/videoup-task/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
srv *service.Service
permSrv *permit.Permit
vfySvc *verify.Verify
)
//Init init http
func Init(conf *conf.Config, s *service.Service) {
srv = s
permSrv = permit.New(conf.Auth)
vfySvc = verify.New(nil)
engine := bm.DefaultServer(conf.BM)
innerRoute(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
func innerRoute(engine *bm.Engine) {
engine.Ping(ping)
g := engine.Group("/x/admin/vt")
{
v := g.Group("/video", permSrv.Permit("TASK_QA_VIDEO"))
{
v.GET("/list", list)
v.GET("/detail", detail)
v.POST("/submit", submit)
}
t := g.Group("/task", permSrv.Permit(""))
{
w := t.Group("/", permSrv.Permit("TASKWEIGHT"))
{
w.GET("/weightconfig/maxweight", maxweight)
w.POST("/weightconfig/add", addwtconf)
w.POST("/weightconfig/del", delwtconf)
w.GET("/weightconfig/list", listwtconf)
w.GET("/weightlog/list", listwtlog)
w.GET("/wcv/show", show)
w.POST("/wcv/set", set)
}
r := t.Group("/review")
{
r.GET("/config/list", listreviews)
r.POST("/config/add", addreview)
r.POST("/config/edit", editreview)
r.POST("/config/delete", delreview)
}
c := t.Group("consumer")
{
c.GET("/on", checkgroup(), on)
c.GET("/off", checkgroup(), off) //自己退出
c.POST("/forceoff", forceoff) //强制踢出
}
t.GET("/online", permSrv.Permit("ONLINE"), online)
t.GET("/inoutlist", inoutlist)
t.POST("/delay", checkowner(), delay)
t.POST("/free", taskfree)
}
}
g = engine.Group("/vt", vfySvc.Verify)
{
v := g.Group("/video")
{
v.POST("/add", add)
v.POST("/uputime", upTaskUTime)
}
g.GET("/report/memberstats", memberStats)
r := g.Group("review")
{
r.POST("/check", checkReview)
}
t := g.Group("task")
{
t.GET("/tooks", taskTooks)
t.GET("/next", next)
t.GET("/list", listTask)
t.GET("/info", info)
}
}
}
func ping(ctx *bm.Context) {
if srv.Ping(ctx) != nil {
ctx.AbortWithStatus(http2.StatusServiceUnavailable)
ctx.Done()
}
}
func getUIDName(ctx *bm.Context) (uid int64, username string) {
if uidi, _ := ctx.Get("uid"); uidi != nil {
uid = uidi.(int64)
}
if name, _ := ctx.Get("username"); name != nil {
username = name.(string)
}
return
}

View File

@@ -0,0 +1,50 @@
package http
import (
"net/http"
"strconv"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/render"
)
func checkgroup() bm.HandlerFunc {
return func(ctx *bm.Context) {
uid, _ := getUIDName(ctx)
role, err := srv.CheckGroup(ctx, uid)
if err != nil || role == 0 {
data := map[string]interface{}{
"code": ecode.RequestErr,
"message": "权限错误",
}
ctx.Render(http.StatusOK, render.MapJSON(data))
ctx.Abort()
return
}
}
}
// 校验任务操作权限
func checkowner() bm.HandlerFunc {
return func(ctx *bm.Context) {
tidS := ctx.Request.Form.Get("task_id")
tid, err := strconv.Atoi(tidS)
if err != nil {
ctx.JSON(nil, ecode.RequestErr)
ctx.Abort()
return
}
uid, _ := getUIDName(ctx)
if err := srv.CheckOwner(ctx, int64(tid), uid); err != nil {
data := map[string]interface{}{
"code": ecode.RequestErr,
"message": err.Error(),
}
ctx.Render(http.StatusOK, render.MapJSON(data))
ctx.Abort()
return
}
}
}

View File

@@ -0,0 +1,110 @@
package http
import (
"strconv"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
)
func list(ctx *bm.Context) {
params := new(model.ListParams)
if err := ctx.Bind(params); err != nil {
ctx.JSON(nil, ecode.RequestErr)
return
}
if params.Limit > 0 && (params.Limit <= (params.Pn-1)*params.Ps || params.Seed == "") {
ctx.JSON(nil, ecode.RequestErr)
return
}
//params 默认值
tformat := "2006-01-02 15:04:05"
if params.CTimeFrom == "" && params.CTimeTo == "" {
params.CTimeFrom = time.Now().AddDate(0, 0, -7).Format(tformat)
params.CTimeTo = time.Now().Format(tformat)
}
if params.FTimeFrom != "" || params.FTimeTo != "" {
params.State = model.QAStateFinish
}
if params.State != 0 && params.State != model.QAStateFinish {
params.State = model.QAStateWait
}
list, err := srv.GetVideoList(ctx, params)
ctx.JSON(list, err)
}
func detail(ctx *bm.Context) {
idStr := ctx.Request.FormValue("id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
ctx.JSON(nil, ecode.RequestErr)
return
}
//任务详情
detail, err := srv.GetDetail(ctx, id)
ctx.JSON(detail, err)
}
func add(ctx *bm.Context) {
//veri params
params := new(model.AddVideoParams)
if err := ctx.BindWith(params, binding.JSON); err != nil {
ctx.JSON(nil, ecode.RequestErr)
return
}
//insert
taskID, err := srv.AddQATaskVideo(ctx, params)
if err != nil {
ctx.JSON(nil, err)
return
}
if taskID <= 0 {
ctx.JSON(nil, ecode.RequestErr)
return
}
ctx.JSON(taskID, nil)
}
func submit(ctx *bm.Context) {
uid, username := getUIDName(ctx)
params := new(model.QASubmitParams)
if err := ctx.Bind(params); err != nil {
ctx.JSON(nil, ecode.RequestErr)
return
}
if _, exist := model.QAAuditStatus[params.AuditStatus]; !exist {
ctx.JSON(nil, ecode.RequestErr)
return
}
if params.AuditStatus == model.VideoStatusRecycle && (params.TagID <= 0 || params.Reason == "") {
ctx.JSON(nil, ecode.RequestErr)
return
}
ctx.JSON(nil, srv.QAVideoSubmit(ctx, username, uid, params))
}
func upTaskUTime(ctx *bm.Context) {
params := new(struct {
TaskID int64 `form:"task_id" validate:"required,gt=0"`
AID int64 `form:"aid" validate:"required,gt=0"`
CID int64 `form:"cid" validate:"required,gt=0"`
UTime int64 `form:"utime"`
})
if err := ctx.Bind(params); err != nil {
log.Error("upTaskUTime ctx.Bind error(%v) params(%+v)", err, ctx.Request.PostForm)
ctx.JSON(nil, ecode.RequestErr)
return
}
ctx.JSON(nil, srv.UpVideoUTime(ctx, params.AID, params.CID, params.TaskID, params.UTime))
}

View File

@@ -0,0 +1,42 @@
package http
import (
"time"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func memberStats(c *bm.Context) {
c.JSON(srv.GetStats(c))
}
func taskTooks(c *bm.Context) {
req := c.Request
params := req.Form
stimeStr := params.Get("stime")
etimeStr := params.Get("etime")
if stimeStr == "" {
stimeStr = time.Now().Format("2006-01-02") + " 00:00:00"
}
if etimeStr == "" {
etimeStr = time.Now().Format("2006-01-02 15:04:05")
}
local, _ := time.LoadLocation("Local")
stime, err := time.ParseInLocation("2006-01-02 15:04:05", stimeStr, local)
if stime.Unix() < 1 || err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
etime, err := time.ParseInLocation("2006-01-02 15:04:05", etimeStr, local)
if etime.Unix() < 1 || err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
tooks, err := srv.TaskTooksByHalfHour(c, stime, etime)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(tooks, nil)
}

View File

@@ -0,0 +1,80 @@
package http
import (
"go-common/app/admin/main/videoup-task/model"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
"strconv"
)
func checkReview(c *bm.Context) {
sf := &model.SubmitForm{}
if err := c.Bind(sf); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if ok, err := srv.CheckReview(c, sf); err != nil {
c.JSON(nil, err)
} else {
c.JSON(ok, nil)
}
}
// list
func listreviews(c *bm.Context) {
v := &model.ListParser{}
if err := c.Bind(v); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
rcs, count, err := srv.ListReviewConfs(c, v.Unames, v.Bt, v.Et, v.Sort, v.Pn, v.Ps)
if err != nil {
c.JSON(nil, err)
return
}
c.JSONMap(map[string]interface{}{
"data": rcs,
"pager": &model.Pager{Pn: int(v.Pn), Ps: int(v.Ps), Sum: count},
}, nil)
}
func addreview(c *bm.Context) {
uid, uname := getUIDName(c)
trc := &model.ReviewConf{}
if err := c.Bind(trc); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
trc.UID = uid
trc.Uname = uname
c.JSON(nil, srv.AddReviewConf(c, trc))
}
func editreview(c *bm.Context) {
uid, uname := getUIDName(c)
trc := &model.ReviewConf{}
if err := c.Bind(trc); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
trc.UID = uid
trc.Uname = uname
c.JSON(nil, srv.EditReviewConf(c, trc))
}
func delreview(c *bm.Context) {
idStr := c.Request.Form.Get("id")
id, err := strconv.Atoi(idStr)
if err != nil || id == 0 {
c.JSON(nil, ecode.RequestErr)
}
c.JSON(nil, srv.DelReviewConf(c, id))
}

View File

@@ -0,0 +1,100 @@
package http
import (
"strconv"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// 任务管理
func delay(c *bm.Context) {
v := new(struct {
Taskid int64 `form:"task_id" validate:"required"`
Reason string `form:"reason"`
})
if err := c.Bind(v); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
uid, _ := getUIDName(c)
c.JSON(nil, srv.Delay(c, v.Taskid, uid, v.Reason))
}
func taskfree(c *bm.Context) {
var uid, rows int64
uid, _ = getUIDName(c)
rows = srv.Free(c, uid)
log.Info("释放任务(uid=%d,rows=%d)", uid, rows)
c.JSON(nil, nil)
}
func next(c *bm.Context) {
uidS := c.Request.Form.Get("uid")
uid, err := strconv.Atoi(uidS)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
task, err := srv.Next(c, int64(uid))
if err != nil {
log.Error("srv.Next(uid=%d) error(%v)", uid, err)
c.JSON(nil, err)
return
}
c.JSON(task, nil)
}
func listTask(c *bm.Context) {
v := new(struct {
UID int64 `form:"uid" default:"0"`
IsLeader int8 `form:"isleader" default:"0"`
Lt int8 `form:"listtype" default:"0"`
Pn int `form:"page" default:"1"`
Ps int `form:"pagesize" default:"20"`
})
err := c.Bind(v)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
tasks, err := srv.List(c, v.UID, v.Pn, v.Ps, v.Lt, v.IsLeader)
if err != nil {
log.Error("srv.List(uid=%d,page=%d, pagesize=%d, listtype=%d, isleader=%d) error(%v)",
v.UID, v.Pn, v.Ps, v.Lt, v.IsLeader, err)
c.JSON(nil, err)
return
}
c.JSON(tasks, nil)
}
// info 返回任务信息,复审信息
func info(c *bm.Context) {
var tid int
if tid, _ = strconv.Atoi(c.Request.Form.Get("taskid")); tid == 0 {
c.JSON(nil, ecode.RequestErr)
return
}
task, err := srv.Info(c, int64(tid))
if err != nil {
c.JSON(nil, err)
return
}
form, err := srv.ReviewForm(c, int64(tid))
if err != nil {
c.JSON(nil, err)
return
}
c.JSONMap(map[string]interface{}{
"task": task,
"review": form,
}, nil)
}

View File

@@ -0,0 +1,99 @@
package http
import (
"net/http"
"strconv"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/render"
)
// 权重管理
func addwtconf(c *bm.Context) {
var err error
cfg := &model.WeightConf{}
if err = c.Bind(cfg); err != nil {
log.Error("addwtconf error(%v)", err)
c.JSON(nil, ecode.RequestErr)
return
}
uid, uname := getUIDName(c)
err = srv.AddWeightConf(c, cfg, uid, uname)
if err != nil {
data := map[string]interface{}{
"code": ecode.RequestErr,
"message": err.Error(),
}
c.Render(http.StatusOK, render.MapJSON(data))
return
}
c.JSON(nil, nil)
}
func delwtconf(c *bm.Context) {
var err error
ids := c.Request.Form.Get("id")
id, err := strconv.Atoi(ids)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(srv.DelWeightConf(c, int64(id)), nil)
}
func listwtconf(c *bm.Context) {
v := new(model.Confs)
if err := c.Bind(v); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(srv.ListWeightConf(c, v))
}
func maxweight(c *bm.Context) {
c.JSON(srv.MaxWeight(c))
}
func listwtlog(c *bm.Context) {
v := new(struct {
Taskid int64 `form:"taskid" validate:"required"`
Pn int `form:"page" default:"1"`
Ps int `form:"ps" default:"20"`
})
if err := c.Bind(v); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
cfg, count, err := srv.ListWeightLogs(c, v.Taskid, v.Pn)
if err != nil {
c.JSON(nil, err)
return
}
data := make(map[string]interface{})
data["data"] = cfg
data["pager"] = map[string]int{
"current_page": v.Pn,
"total_items": int(count),
"page_size": 20,
}
c.JSONMap(data, err)
}
func show(c *bm.Context) {
c.JSON(srv.ShowWeightVC(c))
}
func set(c *bm.Context) {
v := new(model.WeightVC)
if err := c.Bind(v); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(nil, srv.SetWeightVC(c, v))
}

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 = [
"task_qa_video_test.go",
"video_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//vendor/github.com/smartystreets/goconvey/convey:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"archive.go",
"log.go",
"oper.go",
"params.go",
"review.go",
"task.go",
"task_qa.go",
"task_qa_video.go",
"time.go",
"up_group.go",
"user.go",
"utils.go",
"video.go",
"weight.go",
],
importpath = "go-common/app/admin/main/videoup-task/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/log:go_default_library",
"//library/time: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,123 @@
package model
import (
"go-common/library/time"
)
const (
// UpFromWeb 网页上传
UpFromWeb = int8(0)
// UpFromPGC PGC上传
UpFromPGC = int8(1)
// UpFromWindows Windows客户端上传
UpFromWindows = int8(2)
// UpFromAPP APP上传
UpFromAPP = int8(3)
// UpFromMAC Mac客户端上传
UpFromMAC = int8(4)
// UpFromSecretPGC 机密PGC上传
UpFromSecretPGC = int8(5)
// UpFromCoopera 合作方嵌套
UpFromCoopera = int8(6)
// UpFromCreator 创作姬上传
UpFromCreator = int8(7)
// UpFromAndroid 安卓上传
UpFromAndroid = int8(8)
// UpFromIOS IOS上传
UpFromIOS = int8(9)
// AttrYes attribute yes
AttrYes = int32(1)
// AttrNo attribute no
AttrNo = int32(0)
// StateForbidUpDelete 用户删除
StateForbidUpDelete = int8(-100)
)
var (
_bits = map[uint]string{
AttrBitNoRank: "排行禁止",
AttrBitNoDynamic: "动态禁止",
AttrBitNoWeb: "禁止web端输出",
AttrBitNoMobile: "禁止移动端输出",
AttrBitNoSearch: "禁止搜索",
AttrBitOverseaLock: "海外禁止",
AttrBitNoRecommend: "推荐禁止",
AttrBitNoReprint: "禁止转载",
AttrBitHasHD5: "高清1080P",
// AttrBitVisitorDm: AttrBitVisitorDm,
AttrBitIsPGC: "PGC",
AttrBitAllowBp: "允许承包",
AttrBitIsBangumi: "番剧",
AttrBitIsPorder: "是否私单",
AttrBitLimitArea: "是否地区限制",
AttrBitAllowTag: "允许操作TAG",
// AttrBitIsFromArcAPI: AttrBitIsFromArcAPI,
AttrBitJumpURL: "跳转",
AttrBitIsMovie: "电影",
AttrBitBadgepay: "付费",
AttrBitPushBlog: "禁止粉丝动态",
}
_upFromTypes = map[int8]string{
UpFromWeb: "网页上传",
UpFromPGC: "PGC上传",
UpFromWindows: "Windows客户端上传",
UpFromAPP: "APP上传",
UpFromMAC: "Mac客户端上传",
UpFromSecretPGC: "机密PGC上传",
UpFromCoopera: "合作方嵌套",
UpFromCreator: "创作姬上传",
UpFromAndroid: "安卓上传",
UpFromIOS: "IOS上传",
}
)
// BitDesc return bit desc.
func BitDesc(bit uint) (desc string) {
return _bits[bit]
}
// Archive is archive model.
type Archive struct {
Aid int64 `json:"aid"`
Mid int64 `json:"mid"`
TypeID int16 `json:"tid"`
HumanRank int `json:"-"`
Title string `json:"title"`
Author string `json:"-"`
Cover string `json:"cover"`
RejectReason string `json:"reject_reason"`
Tag string `json:"tag"`
Duration int64 `json:"duration"`
Copyright int8 `json:"copyright"`
Desc string `json:"desc"`
MissionID int64 `json:"mission_id"`
Round int8 `json:"-"`
Forward int64 `json:"-"`
Attribute int32 `json:"attribute"`
Access int16 `json:"-"`
State int8 `json:"state"`
Source string `json:"source"`
NoReprint int32 `json:"no_reprint"`
OrderID int64 `json:"order_id"`
Dynamic string `json:"dynamic"`
DTime time.Time `json:"dtime"`
PTime time.Time `json:"ptime"`
CTime time.Time `json:"ctime"`
MTime time.Time `json:"-"`
}
// Type is archive type info
type Type struct {
ID int16 `json:"id"`
PID int16 `json:"pid"`
Name string `json:"name"`
Desc string `json:"description"`
}
// UpFrom get upfrom desc
func UpFrom(ufID int8) string {
return _upFromTypes[ufID]
}

View File

@@ -0,0 +1,42 @@
package model
const (
//LogClientVideo 视频business id
LogClientVideo = int(2)
//LogClientTypeVideo 视频 type id
LogClientTypeVideo = int(1)
//LogClientConsumer 一审任务 business id
LogClientConsumer = int(131)
//LogClientTypeConsumer 一审任务type id
LogClientTypeConsumer = int(1)
)
// SearchLogResult is.
type SearchLogResult struct {
Code int `json:"code"`
Data struct {
Order string `json:"order"`
Sort string `json:"sort"`
Result []struct {
UID int64 `json:"uid"`
Uname string `json:"uname"`
OID int64 `json:"oid"`
Type int8 `json:"type"`
Action string `json:"action"`
Str0 string `json:"str_0"`
Str1 string `json:"str_1"`
Str2 string `json:"str_2"`
Int0 int `json:"int_0"`
Int1 int `json:"int_1"`
Int2 int `json:"int_2"`
Ctime string `json:"ctime"`
Extra string `json:"extra_data"`
} `json:"result"`
Page struct {
Num int `json:"num"`
Size int `json:"size"`
Total int `json:"total"`
} `json:"page"`
} `json:"data"`
}

View File

@@ -0,0 +1,151 @@
package model
import (
"fmt"
)
// .
const (
// OperTypeMission 活动id被修改
OperTypeMission = int8(1)
// OperTypeTag tag被修改
OperTypeTag = int8(2)
// OperTypeCopyright 版权类型被修改
OperTypeCopyright = int8(3)
// OperTypeTypeID 分区ID被修改
OperTypeTypeID = int8(4)
// OperTypeRejectReason 打回理由被修改
OperTypeRejectReason = int8(5)
// OperTypeForwardID 转车跳转被修改
OperTypeForwardID = int8(6)
// OperTypeFlowID 私单类型被修改
OperTypeFlowID = int8(7)
// OperTypeDelay 定时发布被修改
OperTypeDelay = int8(8)
// OperTypeReply 评论开关被修改
OperTypeReply = int8(9)
// OperTypePtime 发布时间被修改
OperTypePtime = int8(10)
// OperTypeAccess 可见属性被修改
OperTypeAccess = int8(11)
// OperTypeAduitReason 审核理由被修改
OperTypeAduitReason = int8(12)
// OperTypeRecicleTag 打回理由被修改
OperTypeRecicleTag = int8(13)
// OperTypeTaskID 任务ID被修改
OperTypeTaskID = int8(14)
// OperTypeOpenTag 通过Tag被修改
OperTypeOpenTag = int8(15)
// OperTypeDynamic 动态描述被修改
OperTypeDynamic = int8(16)
OperNotify = int8(17)
//私单
OperPorderIndustryID = int8(18)
OperPorderOfficial = int8(19)
OperPorderBrandID = int8(20)
OperPorderBrandName = int8(21)
OperPorderShowType = int8(22)
OperPorderAdvertiser = int8(23)
OperPorderAgent = int8(24)
OperPorderShowFront = int8(25)
//频道回查属性
OperFlowAttrNoChannel = int8(26)
OperFlowAttrNoHot = int8(27)
// OperStyleOne 操作展示类型1[%s]从[%v]设为[%v]
OperStyleOne = int8(1)
// OperStyleTwo 操作展示类型2[%s]%v:%v
OperStyleTwo = int8(2)
)
//VOper video oper
type VOper struct {
ID int64 `json:"id"`
AID int64 `json:"aid"`
UID int64 `json:"uid"`
VID int64 `json:"vid"`
Status int16 `json:"status"`
Content string `json:"content"`
Attribute int64 `json:"attribute"`
LastID int64 `json:"last_id"`
Remark string `json:"remark"`
CTime string `json:"ctime"`
}
//VideoOperInfo video oper with user info
type VideoOperInfo struct {
VOper
UserDepart
}
var (
_operType = map[int8]string{
OperTypeMission: "活动ID",
OperTypeTag: "TAG内容",
OperTypeCopyright: "投稿类型",
OperTypeTypeID: "分区类型",
OperTypeRejectReason: "回查理由",
OperTypeForwardID: "撞车跳转",
OperTypeFlowID: "流量TAG",
OperTypeDelay: "定时发布",
OperTypeReply: "评论开关",
OperTypePtime: "发布时间",
OperTypeAccess: "可见属性",
OperTypeAduitReason: "审核理由",
OperTypeRecicleTag: "打回Tag",
OperTypeTaskID: "任务ID",
OperTypeOpenTag: "通过Tag",
OperTypeDynamic: "动态描述",
OperNotify: "系统通知",
OperPorderIndustryID: "推广行业",
OperPorderOfficial: "是否官方",
OperPorderBrandID: "推广品牌ID",
OperPorderBrandName: "推广品牌",
OperPorderShowType: "推广形式",
OperPorderAdvertiser: "广告主",
OperPorderAgent: "代理商",
OperPorderShowFront: "是否前端展示",
OperFlowAttrNoChannel: "频道禁止",
OperFlowAttrNoHot: "热门禁止",
}
)
// ArcOper archive oper.
type ArcOper struct {
ID int64
Aid int64
UID int64
TypeID int16
State int16
Content string
Round int8
Attribute int32
LastID int64
Remark string
}
// VideoOper video oper.
type VideoOper struct {
ID int64
Aid int64
UID int64
Vid int64
Status int16
Content string
Attribute int32
LastID int64
Remark string
}
// Operformat oper format.
func Operformat(tagID int8, old, new interface{}, style int8) (cont string) {
var template string
switch style {
case OperStyleOne:
template = "[%s]从[%v]设为[%v]"
case OperStyleTwo:
template = "[%s]%v:%v"
}
cont = fmt.Sprintf(template, _operType[tagID], old, new)
return
}

View File

@@ -0,0 +1,182 @@
package model
import (
"go-common/library/time"
)
// ListParams query qa vide task list params
type ListParams struct {
AuditStatus []int `form:"auditStatus,split" validate:"omitempty,max=100"`
TaskID []int64 `form:"taskID,split" validate:"omitempty,max=100,dive,gt=0"`
Keyword []string `form:"keyword,split" validate:"omitempty,max=100"`
UPGroup []int64 `form:"upGroup,split" validate:"omitempty,max=100,dive,gt=0"`
UID []int64 `form:"uid,split" validate:"omitempty,max=100,dive,gt=0"`
Limit int `form:"limit" validate:"omitempty,max=1000"`
Seed string `form:"seed"`
ArcTypeID []int64 `form:"arcTypeid[]" validate:"omitempty,max=100,dive,gt=0"`
TagID []int64 `form:"tagID,split" validate:"omitempty,max=100,dive,gt=0"`
State int16 `form:"state"`
CTimeFrom string `form:"ctimeFrom"`
CTimeTo string `form:"ctimeTo"`
FTimeFrom string `form:"ftimeFrom"`
FTimeTo string `form:"ftimeTo"`
FansFrom int64 `form:"fansFrom"`
FansTo int64 `form:"fansTo"`
Order string `form:"order" default:"id"`
Sort string `form:"sort" default:"desc"`
Ps int `form:"ps" default:"50" validate:"omitempty,gt=0,max=100"`
Pn int `form:"pn" default:"1" validate:"omitempty,gt=0"`
}
//AddVideoParams add qa video task params
type AddVideoParams struct {
OUID int64 `json:"uid"`
Oname string `json:"username"`
VideoDetail
}
//QASubmitParams submit qa video task params
type QASubmitParams struct {
ID int64 `json:"id" form:"id" validate:"required,gt=0"`
AuditStatus int16 `json:"audit_status" form:"auditStatus"`
Encoding int32 `json:"encoding" form:"encoding"`
Norank int32 `json:"norank" form:"norank"`
Nodynamic int32 `json:"nodynamic" form:"nodynamic"`
PushBlog int32 `json:"push_blog" form:"push_blog"`
Norecommend int32 `json:"norecommend" form:"norecommend"`
Nosearch int32 `json:"nosearch" form:"nosearch"`
OverseaBlock int32 `json:"oversea_block" form:"oversea_block"`
TagID int64 `json:"tag_id" form:"tagID" validate:"omitempty,gt=0"`
ReasonID int64 `json:"reason_id" form:"reasonID" validate:"omitempty,gt=0"`
Reason string `json:"reason" form:"reason"`
Note string `json:"note" form:"note"`
QaTagID int64 `json:"qa_tag_id" form:"qaTagid" validate:"required,gt=0"`
QATag string `json:"qa_tag" form:"qaTag" validate:"required"`
QaNote string `json:"qa_note" form:"qaNote"`
}
//TaskVideoItem qa vide task list item
type TaskVideoItem struct {
ID int64 `json:"id"`
DetailID int64 `json:"detail_id"`
TaskID int64 `json:"task_id"`
TaskUTime int64 `json:"task_utime"`
CTime string `json:"ctime"`
FTime string `json:"ftime"`
AuditStatus int16 `json:"audit_status"`
TagID int64 `json:"audit_tagid"`
MID int64 `json:"mid"`
UPName string `json:"up_name"`
UPGroups []int64 `json:"up_groups"`
UPGroupList []*UPGroup `json:"up_group_list"`
Fans int64 `json:"fans"`
ArcTitle string `json:"arc_title"`
ArcTypeid int64 `json:"arc_typeid"`
UID int64 `json:"uid"`
User *UserRole `json:"user"`
State int16 `json:"state"`
StateName string `json:"state_name"`
}
//Page page
type Page struct {
Num int `json:"num"`
Size int `json:"size"`
Total int `json:"total"`
}
//QAVideoList qa video task list return struct
type QAVideoList struct {
Result []*TaskVideoItem `json:"result"`
Page Page `json:"page"`
}
// VideoParam video struct
type VideoParam struct { // TODO: batch param
ID int64 `json:"id"`
Filename string `json:"filename"`
Aid int64 `json:"aid"`
Mid int64 `json:"mid"`
RegionID int16 `json:"region_id"`
VideoDesign *VideoDesign `json:"video_design,omitempty"`
Status int16 `json:"status"`
CTime time.Time `json:"ctime"`
Cid int64 `json:"cid,omitempty"`
Title string `json:"title,omitempty"`
Desc string `json:"desc,omitempty"`
Index int `json:"index,omitempty"`
SrcType string `json:"src_type,omitempty"`
Playurl string `json:"playurl,omitempty"`
FailCode int8 `json:"failinfo,omitempty"`
Duration int64 `json:"duration,omitempty"`
XcodeState int8 `json:"xcode_state,omitempty"`
Attribute int32 `json:"attribute,omitempty"`
Filesize int64 `json:"filesize,omitempty"`
WebLink string `json:"weblink,omitempty"`
Resolutions string `json:"resolutions,omitempty"`
Encoding int8 `json:"encoding"`
EncodePurpose string `json:"encode_purpose,omitempty"`
UID int64 `json:"uid,omitempty"`
TaskID int64 `json:"task_id,omitempty"`
Oname string `json:"oname,omitempty"`
TagID int64 `json:"tag_id,omitempty"`
Reason string `json:"reason,omitempty"`
ReasonID int64 `json:"reject_reason_id,omitempty"`
Note string `json:"note,omitempty"`
Attrs *AttrParam `json:"attrs,omitempty"`
Fans int64 `json:"-"`
CateID int64 `json:"-"`
UpFrom int8 `json:"-"`
TaskState int8 `json:"-"`
TypeID int16 `json:"-"`
}
// AttrParam bit
type AttrParam struct {
NoRank int32 `json:"no_rank,omitempty"` // 0
NoDynamic int32 `json:"no_dynamic,omitempty"` // 1
NoWeb int32 `json:"no_web,omitempty"` // 2
NoMobile int32 `json:"no_mobile,omitempty"` // 3
NoSearch int32 `json:"no_search,omitempty"` // 4
OverseaLock int32 `json:"oversea_block,omitempty"` // 5
NoRecommend int32 `json:"no_recommend,omitempty"` // 6
NoReprint int32 `json:"no_reprint,omitempty"` // 7
HasHD5 int32 `json:"is_hd,omitempty"` // 8
IsPGC int32 `json:"is_pgc,omitempty"` // 9
AllowBp int32 `json:"allow_bp,omitempty"` // 10
IsBangumi int32 `json:"is_bangumi,omitempty"` // 11
IsPorder int32 `json:"is_porder,omitempty"` // 12
LimitArea int32 `json:"limit_area,omitempty"` // 13
AllowTag int32 `json:"allow_tag,omitempty"` // 14
JumpURL int32 `json:"is_jumpurl,omitempty"` // 16
IsMovie int32 `json:"is_movie,omitempty"` // 17
BadgePay int32 `json:"is_pay,omitempty"` // 18
PushBlog int32 `json:"push_blog,omitempty"` // 20
}
// VideoDesign mosaic and watermark
type VideoDesign struct {
Mosaic []*Mosaic `json:"mosaic,omitempty"`
WaterMark []*WaterMark `json:"watermark,omitempty"`
}
// Mosaic .
type Mosaic struct {
X int64 `json:"x" form:"mosaic[0][x]"`
Y int64 `json:"y" form:"mosaic[0][y]"`
W int64 `json:"w" form:"mosaic[0][w]"`
H int64 `json:"h" form:"mosaic[0][h]"`
Start int64 `json:"start" form:"mosaic[0][start]"`
End int64 `json:"end" form:"mosaic[0][end]"`
}
// WaterMark .
type WaterMark struct {
LOC int8 `json:"loc,omitempty"`
URL string `json:"url,omitempty"`
MD5 string `json:"md5,omitempty"`
Start int64 `json:"start,omitempty"`
End int64 `json:"end,omitempty"`
X int64 `json:"x,omitempty"`
Y int64 `json:"y,omitempty"`
}

View File

@@ -0,0 +1,163 @@
package model
import (
"context"
"sync"
"time"
"go-common/library/log"
)
// ReviewConf 复审配置
type ReviewConf struct {
ID int64 `json:"id" form:"id"`
Types []int64 `json:"types" form:"types,split"` // 分区
mtp map[int16]struct{}
UpFroms []int64 `json:"upfroms" form:"upfroms,split"` // 投稿来源
muf map[int8]struct{}
UpGroups []int64 `json:"upgroups" form:"upgroups,split"` // 用户组
mug map[int8]struct{}
Uids []int64 `json:"uids" form:"uids,split"` // 指定uid
Unames []string `json:"unames"` // 指定uid
muid map[int64]struct{}
FansLow int64 `json:"fanslow" form:"fanslow"` // 粉丝数最低值
FansHigh int64 `json:"fanshigh" form:"fanshigh"` // 粉丝数最高
Bt FormatTime `json:"bt" form:"bt"`
Et FormatTime `json:"et" form:"et"`
State int8 `json:"state" form:"state"`
UID int64 `json:"uid"`
Uname string `json:"uname"`
Desc string `json:"desc" form:"desc"`
Mt FormatTime `json:"mt"`
}
// Refresh refresh
func (r *ReviewConf) Refresh() {
mtp := make(map[int16]struct{})
muf := make(map[int8]struct{})
mug := make(map[int8]struct{})
muid := make(map[int64]struct{})
for _, tp := range r.Types {
mtp[int16(tp)] = struct{}{}
}
for _, uf := range r.UpFroms {
muf[int8(uf)] = struct{}{}
}
for _, ug := range r.UpGroups {
mug[int8(ug)] = struct{}{}
}
for _, uid := range r.Uids {
muid[uid] = struct{}{}
}
r.mtp = mtp
r.muf = muf
r.mug = mug
r.muid = muid
}
// SubmitForm form
type SubmitForm struct {
Status int16 `json:"status" form:"status"`
ID int64 `json:"id" form:"id"`
CID int64 `json:"cid" form:"cid"`
AID int64 `json:"aid" form:"aid"`
MID int64 `json:"mid" form:"mid"`
Eptitle string `json:"eptitle,omitempty" form:"eptitle"`
Description string `json:"description,omitempty" form:"description"`
Note string `json:"note,omitempty" form:"note"`
ReasonID int64 `json:"reason_id,omitempty" form:"reason_id"`
Reason string `json:"reason,omitempty" form:"reason"`
TID int64 `json:"tid,omitempty" form:"tid"`
Norank int32 `json:"norank" form:"norank"`
Noindex int32 `json:"noindex" form:"noindex"`
PushBlog int32 `json:"push_blog" form:"push_blog"`
NoRecommend int32 `json:"norecommend" form:"norecommend"`
Nosearch int32 `json:"nosearch" form:"nosearch"`
OverseaBlock int32 `json:"oversea_block" form:"oversea_block"`
Encoding int8 `json:"encoding" form:"encoding"`
TaskID int64 `json:"task_id" form:"task_id"`
UID int64 `json:"uid" form:"uid"`
Uname string `json:"uname" form:"uname"`
}
// ReviewCache 快速判断配置项是否命中
type ReviewCache struct {
MRC map[int64]*ReviewConf
Mux sync.RWMutex
}
// NewRC 复审配置
func NewRC() *ReviewCache {
rc := &ReviewCache{}
rc.MRC = make(map[int64]*ReviewConf)
return rc
}
// Check 检查配置是否命中
func (rc *ReviewCache) Check(c context.Context, opt *TaskPriority, uid int64) bool {
rc.Mux.RLock()
defer rc.Mux.RUnlock()
if len(rc.MRC) == 0 {
log.Info("ReviewCache empty")
return false
}
log.Info("ReviewCache opt(%+v) uid(%d),", opt, uid)
for id, item := range rc.MRC {
log.Info("ReviewCache config(%+v)", item)
if item.State != 0 {
continue
}
bt := item.Bt.TimeValue()
et := item.Et.TimeValue()
if bt.After(time.Now()) || (!et.IsZero() && et.Before(time.Now())) {
continue
}
if len(item.mtp) > 0 {
if _, ok := item.mtp[opt.TypeID]; !ok {
continue
}
}
if len(item.muf) > 0 {
if _, ok := item.muf[opt.UpFrom]; !ok {
continue
}
}
if len(item.mug) > 0 {
var hit bool
for _, ug := range opt.UpGroups {
if _, ok := item.mug[ug]; ok {
hit = true
break
}
}
if !hit {
continue
}
}
if len(item.muid) > 0 {
if _, ok := item.muid[uid]; !ok {
continue
}
}
if item.FansHigh > 0 {
if opt.Fans < item.FansLow || opt.Fans > item.FansHigh {
continue
}
}
log.Info("ReviewCache task(%d) hit config(%d)", opt.TaskID, id)
return true
}
return false
}

View File

@@ -0,0 +1,391 @@
package model
import (
"time"
"go-common/library/log"
"go-common/library/xstr"
)
var (
// TookTypeMinute video task took time in 1 minute
TookTypeMinute = int8(1)
// TookTypeHalfHour video task took time in 10 minutes
TookTypeHalfHour = int8(2)
// TaskStateUnclaimed video task belongs to nobody
TaskStateUnclaimed = int8(0)
// TaskStateUntreated video task not submit
TaskStateUntreated = int8(1)
// TaskStateCompleted video task completed
TaskStateCompleted = int8(2)
// TaskStateDelayed video task delayed
TaskStateDelayed = int8(3)
// TaskStateClosed video task closed
TaskStateClosed = int8(4)
// PoolForFirst 一审任务池
PoolForFirst = int8(0)
// PoolForSecond 二审任务池
PoolForSecond = int8(1)
// TypeRealTime 实时任务
TypeRealTime = int8(0)
// TypeDispatched 已分发任务
TypeDispatched = int8(1)
// TypeFinished 结束任务
TypeFinished = int8(2)
// TypeDelay 延时任务
TypeDelay = int8(3)
// TypeReview 复审任务
TypeReview = int8(5)
// TypeUpDelete 已删除任务
TypeUpDelete = int8(6)
// TypeSpecialWait 特殊停滞任务
TypeSpecialWait = int8(7)
// SubjectForNormal 普通任务
SubjectForNormal = int8(0) //normal task subject
// SubjectForTask 指派任务
SubjectForTask = int8(1) //specified task subject
_taskdispatchstate = map[int8]struct{}{
TypeRealTime: {},
TypeDispatched: {},
TypeFinished: {},
TypeDelay: {},
TypeReview: {},
TypeUpDelete: {},
TypeSpecialWait: {},
}
// WLVConf 默认值
WLVConf = &WeightVC{
MaxWeight: int64(200000), //最大权重值
SubRelease: int64(18), //指派再释放的任务
//特殊任务参数
Slv1: int64(8), // 普通用户>=1W粉
Slv2: int64(10), // 普通用户>=10W粉
Slv3: int64(12), // 优质用户<1W粉
Slv4: int64(15), // 优质用户>=1W粉
Slv5: int64(18), // 优质用户>=10W粉
Slv6: int64(6), // 高危用户>=10W粉
Slv7: int64(0), // 其他高危
//普通任务参数
Nlv1: int64(3), // 等待时长 9-15
Nlv2: int64(6), // 等待时长 15-27
Nlv3: int64(9), // 等待时长 27-45
Nlv4: int64(12), // 等待时长 >45
Nlv5: int64(0), // 等待时长 <=9
//定时任务参数
Tlv1: int64(3), // 距离发布2h-4h
Tlv2: int64(9), // 距离发布1-2h
Tlv3: int64(21), // 距离发布 <1h
Tlv4: int64(0), // 距离发布 > 4h
}
)
const (
// ActionHandsUP 0签入
ActionHandsUP = int8(0)
// ActionHandsOFF 1签出
ActionHandsOFF = int8(1)
// ActionSubmit 2提交
ActionSubmit = int8(2)
// ActionDelay 3延迟
ActionDelay = int8(3)
// ActionClose 4关闭
ActionClose = int8(4)
//ActionOldSubmit 5旧一审提交
ActionOldSubmit = int8(5)
//ActionTaskDelete 10任务删除
ActionTaskDelete = int8(10)
//ActionDispatch 分配
ActionDispatch = int8(6)
//ActionRelease 释放(拒审)
ActionRelease = int8(7)
// WConfMid 按照mid配置权重
WConfMid = int8(0)
// WConfTaskID 按照taskid配置权重
WConfTaskID = int8(1)
// WConfType 按照分区配置权重
WConfType = int8(2)
// WConfUpFrom 按照投稿来源配置权重
WConfUpFrom = int8(3)
// WConfRelease 指派任务释放
WConfRelease = int8(4)
// TimeFormatSec 时间格式化
TimeFormatSec = "2006-01-02 15:04:05"
// TaskLeader 组长
TaskLeader int8 = 1
// TaskMember 组员
TaskMember int8 = 2
)
// MemberStat .
type MemberStat struct {
UID int64 `json:"uid"`
DispatchCount int64 `json:"dispatch"`
ReleaseCount int64 `json:"release"`
SubmitCount int64 `json:"submit"` // 总提交数
OSubmitCount int64 `json:"oldsubmit"` // action=5
NSubmitCount int64 `json:"newsubmit"` // action=2
BelongCount int64 `json:"belong"` // 总推送数 分配到的-释法的
PassCount int64 `json:"pass"` // 提交并且通过的数量
NormalCount int64 `json:"normalCount"` // 普通任务数量
SubjectCount int64 `json:"specialCount"` // 指派任务数量
InTime string `json:"inTime"` // 最近开始时间
QuitTime string `json:"quitTime"` // 最近退出时间
CompleteRate string `json:"completeRate"` // 处理率
PassRate string `json:"passRate"` // 通过率
SumDu int64 `json:"-"`
SumDuration string `json:"videoDuration"` // 累积处理视频总时长
AvgUt float64 `json:"-"`
AvgUtime string `json:"avgTime"` // 单任务平均耗时
}
// CfWeightDesc 权重配置文字描述
func CfWeightDesc(radio int8) (desc string) {
switch radio {
case WConfMid:
desc = "mid配置"
case WConfTaskID:
desc = "taskid配置"
case WConfType:
desc = "分区配置"
case WConfUpFrom:
desc = "投稿来源"
case WConfRelease:
desc = "指派释放"
default:
desc = "其他配置"
}
return
}
// IsDispatch 判断任务状态
func IsDispatch(st int8) bool {
if _, ok := _taskdispatchstate[st]; ok {
return true
}
return false
}
// ParseWeightConf 解析权重配置
func ParseWeightConf(twc *WeightConf, uid int64, uname string) (mcases map[int64]*WCItem, IsTaskID bool, err error) {
var (
ids []int64
)
mcases = make(map[int64]*WCItem)
if ids, err = xstr.SplitInts(twc.Ids); err != nil {
log.Error("ParseWeightConfig Config(%v) parse error(%v) Idlist(%s)", twc, err)
return nil, false, err
}
for _, id := range ids {
wci := &WCItem{
CID: id,
Radio: twc.Radio,
Rule: twc.Rule,
Weight: twc.Weight,
Uname: uname,
Desc: twc.Desc,
Bt: twc.Bt,
Et: twc.Et,
Mtime: NewFormatTime(time.Now()),
}
if twc.Radio == WConfTaskID {
IsTaskID = true
}
mcases[id] = wci
}
return
}
// WeightVC Weight Value Config 权重分值配置
type WeightVC struct {
MaxWeight int64 `json:"maxweight" form:"maxweight" default:"20000"`
SubRelease int64 `json:"subrelease" form:"subrelease" default:"18"`
Slv1 int64 `json:"slv1" form:"slv1" default:"8"`
Slv2 int64 `json:"slv2" form:"slv2" default:"10"`
Slv3 int64 `json:"slv3" form:"slv3" default:"12"`
Slv4 int64 `json:"slv4" form:"slv4" default:"15"`
Slv5 int64 `json:"slv5" form:"slv5" default:"18"`
Slv6 int64 `json:"slv6" form:"slv6" default:"6"`
Slv7 int64 `json:"slv7" form:"slv7" default:"0"`
Nlv1 int64 `json:"nlv1" form:"nlv1" default:"3"`
Nlv2 int64 `json:"nlv2" form:"nlv2" default:"6"`
Nlv3 int64 `json:"nlv3" form:"nlv3" default:"9"`
Nlv4 int64 `json:"nlv4" form:"nlv4" default:"12"`
Nlv5 int64 `json:"nlv5" form:"nlv5" default:"0"`
Tlv1 int64 `json:"tlv1" form:"tlv1" default:"3"`
Tlv2 int64 `json:"tlv2" form:"tlv2" default:"9"`
Tlv3 int64 `json:"tlv3" form:"tlv3" default:"21"`
Tlv4 int64 `json:"tlv4" form:"tlv4" default:"0"`
}
// Task 审核任务
type Task struct {
ID int64 `json:"id"`
Pool int8 `json:"pool"`
Subject int8 `json:"subject"`
AdminID int64 `json:"adminid"`
Aid int64 `json:"aid"`
Cid int64 `json:"cid"`
UID int64 `json:"uid"`
State int8 `json:"state"`
UTime int64 `json:"utime"`
CTime FormatTime `json:"ctime"`
MTime FormatTime `json:"mtime"`
DTime FormatTime `json:"dtime"`
GTime FormatTime `json:"gtime"`
PTime FormatTime `json:"ptime"`
Weight int64 `json:"weight"`
Mid int64 `json:"mid"`
}
// TaskWeightLog 权重变更日志
type TaskWeightLog struct {
TaskID int64 `json:"taskid"`
Mid int64 `json:"mid"`
Weight int64 `json:"weight"`
CWeight int64 `json:"cweight"`
NWeight int64 `json:"nweight"`
SWeight int64 `json:"sweight"`
TWeight int64 `json:"tweight"`
Uptime FormatTime `json:"uptime"`
Creator string `json:"creator"` //创作者
UpSpecial []int8 `json:"upspecial"` //标记是否优质,劣质用户
Fans int64 `json:"fans"` //粉丝数
Wait float64 `json:"wait"` //等待时长
Ptime string `json:"ptime,omitempty"`
CfItems []*WCItem `json:"cfitems,omitempty"`
Desc string `json:"desc,omitempty"` // 配置描述
}
// TaskPriority 任务参数
type TaskPriority struct {
TaskID int64 `json:"taskid"`
Weight int64 `json:"weight"` //权重总值
State int8 `json:"state"` //任务状态
Mid int64 `json:"mid"`
Special int8 `json:"special"` //特殊任务
Ctime FormatTime `json:"ctime"` //任务生成时间
Ptime FormatTime `json:"ptime"` //定时发布时间
CfItems []*WCItem `json:"cfitems,omitempty"`
Fans int64 `json:"fans"` //粉丝数
AccFailed bool `json:"accfaild"` //账号查询是否失败
UpGroups []int8 `json:"ugs"` //分组
UpFrom int8 `json:"upfrom"` //来源
TypeID int16 `json:"typeid"` //分区
}
// WeightConf 任务权重配置
type WeightConf struct {
Radio int8 `form:"radio"` // 0,mid1taskid2分区, 3, 投稿来源
Ids string `form:"ids" validate:"required"` // id列表逗号分隔
Rule int8 `form:"rule"` // 0,动态权重1静态权重
Weight int64 `form:"weight" validate:"required"` // 配置的权重
Desc string `form:"desc" validate:"required"` // 描述信息
Bt FormatTime `form:"bt"` //配置生效开始时间
Et FormatTime `form:"et"` //配置生效结束时间
}
// WCItem task weight config item
type WCItem struct {
Radio int8 `json:"radio"`
ID int64 `json:"id,omitempty"`
CID int64 `json:"cid"` // config id 四种配置通用
UID int64 `json:"uid,omitempty"`
Uname string `json:"user,omitempty"`
TypeName string `json:"typename,omitempty"`
UpFrom string `json:"upfrom,omitempty"`
Rule int8 `json:"rule"`
State int8 `json:"state"`
Weight int64 `json:"weight,omitempty"`
Mtime FormatTime `json:"mtime,omitempty"`
Desc string `json:"desc,omitempty"`
FileName string `json:"filename,omitempty"`
Title string `json:"title,omitempty"`
Vid int64 `json:"vid,omitempty"`
Creator string `json:"creator,omitempty"`
Fans int64 `json:"fans,omitempty"`
Bt FormatTime `json:"bt,omitempty"`
Et FormatTime `json:"et,omitempty"`
}
// Confs 权重配置筛选参数
type Confs struct {
Radio int8 `form:"radio" default:"1"`
Cid int64 `form:"cid" default:"-1"`
Operator string `form:"operator"`
Bt FormatTime `form:"bt"`
Et FormatTime `form:"et"`
Rule int8 `form:"rule" default:"-1"`
State int `form:"state"`
Pn int `form:"page" default:"1"`
Ps int `form:"ps" default:"20"`
}
// TaskTook 一审耗时
type TaskTook struct {
ID int64 `json:"id"`
M90 int `json:"m90"`
M80 int `json:"m80"`
M60 int `json:"m60"`
M50 int `json:"m50"`
TypeID int8 `json:"type"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"-"`
}
// AuthRole 一审任务角色
type AuthRole struct {
ID int64 `json:"id"`
UID int64 `json:"uid"`
Role int8 `json:"role"`
UserName string `json:"username"`
NickName string `json:"nickname"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// Consumers 组员信息
type Consumers struct {
ID int64 `json:"id"`
UID int64 `json:"uid"`
UserName string `json:"username"`
State int8 `json:"state"`
Ctime FormatTime `json:"ctime"`
Mtime FormatTime `json:"mtime"`
LastOut string `json:"lastout,omitempty"`
}
// ConsumerLog 组员日志
type ConsumerLog struct {
UID int64 `json:"uid"`
Uname string `json:"uname"`
Action int8 `json:"action"`
Ctime string `json:"ctime"`
Desc string `json:"desc"`
}
// InQuit 组员日志
type InQuit struct {
Date string `json:"date"`
UID int64 `json:"uid"`
Uname string `json:"uname"`
InTime string `json:"inTime"`
OutTime string `json:"quitTime"`
}
// TaskForLog 释放任务
type TaskForLog struct {
ID int64
Cid int64
Subject int8
Mtime time.Time
}

View File

@@ -0,0 +1,33 @@
package model
import "time"
//qa task state & type & log business/type.
const (
QAStateWait = int16(1)
QAStateFinish = int16(2)
QATypeVideo = int8(1)
LogQATask = 111
LogQATaskVideo = 1
)
//QAStates states.
var (
QAStates = map[int16]string{
QAStateWait: "待质检",
QAStateFinish: "已质检",
}
)
//QATask qatask
type QATask struct {
ID int64 `json:"id"`
State int16 `json:"state"`
Type int8 `json:"type"`
DetailID int64 `json:"detail_id"`
UID int64 `json:"uid"`
FTime time.Time `json:"ftime"`
CTime time.Time `json:"ctime"`
}

View File

@@ -0,0 +1,68 @@
package model
import (
"encoding/json"
)
//VideoDetail qa video task detail
type VideoDetail struct {
CID int64 `json:"cid" validate:"required,gt=0"`
AID int64 `json:"aid" validate:"required,gt=0"`
TaskID int64 `json:"task_id" validate:"omitempty,gt=0"`
TaskUTime int64 `json:"task_utime"`
Attribute int32 `json:"attribute"`
TagID int64 `json:"tag_id" validate:"omitempty,gt=0"`
ArcTitle string `json:"arc_title"`
ArcTypeID int64 `json:"arc_typeid" validate:"required,gt=0"`
AuditStatus int16 `json:"audit_status" `
AuditSubmit string `json:"audit_submit" validate:"required"`
AuditDetails string `json:"audit_details" validate:"required"`
MID int64 `json:"mid" validate:"required,gt=0"`
UPGroups []int64 `json:"up_groups"`
Fans int64 `json:"fans"`
}
//QATaskVideo qa video
type QATaskVideo struct {
QATask
VideoDetail
AttributeList map[string]int32 `json:"attribute_list"`
}
//VideoTaskInfo info
type VideoTaskInfo struct {
QATaskVideo
UPGroupList []*UPGroup `json:"up_group_list"`
Warnings []interface{} `json:"warnings"`
}
//TaskVideoDetail detail
type TaskVideoDetail struct {
Task *VideoTaskInfo `json:"task"`
Video *Video `json:"review"`
VideoHistory []*VideoOperInfo `json:"video_history"`
}
//GetNote get task submit note
func (qv *QATaskVideo) GetNote() (note string, err error) {
submit := map[string]string{}
if err = json.Unmarshal([]byte(qv.AuditSubmit), &submit); err != nil {
return
}
note = submit["note"]
return
}
//GetAttributeList get task submit attribute
func (qv *QATaskVideo) GetAttributeList() {
qv.AttributeList = AttributeList(qv.Attribute)
}
//GetWarnings get task warnings
func (qv *VideoTaskInfo) GetWarnings() {
qv.Warnings = []interface{}{}
for _, g := range qv.UPGroupList {
qv.Warnings = append(qv.Warnings, g)
}
}

View File

@@ -0,0 +1,26 @@
package model
import (
. "github.com/smartystreets/goconvey/convey"
"testing"
)
var qv = &QATaskVideo{
VideoDetail: VideoDetail{
Attribute: 1048691,
UPGroups: []int64{1, 2},
},
}
func TestQATaskVideo_GetAttributeList(t *testing.T) {
Convey("GetAttributeqv.AttributeList", t, func() {
qv.GetAttributeList()
t.Logf("attributeList(%+v)", qv.AttributeList)
So(qv.AttributeList["norank"], ShouldEqual, 1)
So(qv.AttributeList["nosearch"], ShouldEqual, 1)
So(qv.AttributeList["nodynamic"], ShouldEqual, 1)
So(qv.AttributeList["norecommend"], ShouldEqual, 1)
So(qv.AttributeList["oversea_block"], ShouldEqual, 1)
So(qv.AttributeList["push_blog"], ShouldEqual, 1)
})
}

View File

@@ -0,0 +1,58 @@
package model
import (
"database/sql/driver"
"time"
)
// FormatTime format time
type FormatTime string
// NewFormatTime net formatTime
func NewFormatTime(t time.Time) FormatTime {
ft := new(FormatTime)
ft.Scan(t)
return *ft
}
// Scan scan time.
func (jt *FormatTime) Scan(src interface{}) (err error) {
switch sc := src.(type) {
case time.Time:
*jt = FormatTime(sc.Format("2006-01-02 15:04:05"))
case string:
*jt = FormatTime(sc)
}
return
}
// Value get string value.
func (jt FormatTime) Value() (driver.Value, error) {
return string(jt), nil
}
// TimeValue get time value.
func (jt FormatTime) TimeValue() time.Time {
t, _ := time.ParseInLocation("2006-01-02 15:04:05", string(jt), time.Local)
if t.Unix() <= 0 {
t, _ = time.ParseInLocation("2006-01-02 15:04:05", "0000-00-00 00:00:00", time.Local)
}
return t
}
// UnmarshalJSON implement Unmarshaler
func (jt *FormatTime) UnmarshalJSON(data []byte) error {
if data == nil || len(data) <= 1 {
*jt = FormatTime("0000-00-00 00:00:00")
return nil
}
str := string(data[1 : len(data)-1])
st, err := time.Parse(time.RFC3339, str)
if err == nil {
*jt = FormatTime(st.Format("2006-01-02 15:04:05"))
} else {
*jt = FormatTime(str)
}
return nil
}

View File

@@ -0,0 +1,28 @@
package model
const (
//UpperTypeWhite 优质
UpperTypeWhite int8 = 1
//UpperTypeBlack 高危
UpperTypeBlack int8 = 2
//UpperTypePGC 生产组
UpperTypePGC int8 = 3
//UpperTypeUGCX don't know
UpperTypeUGCX int8 = 3
//UpperTypePolitices 时政
UpperTypePolitices int8 = 5
//UpperTypeEnterprise 企业
UpperTypeEnterprise int8 = 7
//UpperTypeSigned 签约
UpperTypeSigned int8 = 15
)
//UPGroup up主所属的所有特殊用户组
type UPGroup struct {
ID int64 `json:"id"`
Tag string `json:"tag"`
ShortTag string `json:"short_tag"`
FontColor string `json:"font_color"` //字体颜色
BgColor string `json:"bg_color"` //背景颜色
Note string `json:"note"`
}

View File

@@ -0,0 +1,15 @@
package model
//UserRole role
type UserRole struct {
UID int64 `json:"uid"`
Name string `json:"username"`
Role int8 `json:"role"`
}
//UserDepart department
type UserDepart struct {
UID int64 `json:"uid"`
Name string `json:"username"`
Department string `json:"department"`
}

View File

@@ -0,0 +1,18 @@
package model
// Pager pager
type Pager struct {
Pn int `json:"num"`
Ps int `json:"size"`
Sum int64 `json:"total"`
}
// ListParser list parser
type ListParser struct {
Unames string `form:"uname"`
Bt string `form:"bt"`
Et string `form:"et"`
Sort string `form:"sort" default:"desc"`
Ps int64 `form:"ps" default:"20"`
Pn int64 `form:"pn" default:"1"`
}

View File

@@ -0,0 +1,151 @@
package model
import (
"time"
)
//video status & attr.
const (
VideoStatusOpen = int16(0)
VideoStatusOrange = int16(10000)
VideoStatusRecycle = int16(-2)
VideoStatusLock = int16(-4)
VideoStatusDelete = -100
ArcStateDelete = -100
RLStateDelete = -100
CopyrightOriginal = int8(1)
VideoXcodeSDFinish = int8(2)
VideoXcodeHDFinish = int8(4)
AttrBitNoRank = uint(0) // NOTE: double write for archive_forbid
// AttrBitNoDynamic 动态禁止
AttrBitNoDynamic = uint(1) // NOTE: double write for archive_forbid
// AttrBitNoWeb 禁止网页输出
AttrBitNoWeb = uint(2)
// AttrBitNoMobile 禁止客户端列表
AttrBitNoMobile = uint(3)
// AttrBitNoSearch 搜索禁止
AttrBitNoSearch = uint(4)
// AttrBitOverseaLock 海外禁止
AttrBitOverseaLock = uint(5)
// AttrBitNoRecommend 禁止推荐
AttrBitNoRecommend = uint(6) // NOTE: double write for archive_forbid
// AttrBitNoReprint 禁止转载
AttrBitNoReprint = uint(7)
// AttrBitHasHD5 是否高清
AttrBitHasHD5 = uint(8)
// AttrBitIsPGC 是否PGC稿件
AttrBitIsPGC = uint(9)
// AttrBitAllowBp 允许承包
AttrBitAllowBp = uint(10)
// AttrBitIsBangumi 是否番剧
AttrBitIsBangumi = uint(11)
// AttrBitIsPorder 是否私单
AttrBitIsPorder = uint(12)
// AttrBitLimitArea 是否限制地区
AttrBitLimitArea = uint(13)
// AttrBitAllowTag 允许其他人添加tag
AttrBitAllowTag = uint(14)
// AttrBitJumpURL 跳转
AttrBitJumpURL = uint(16)
// AttrBitIsMovie 是否影视
AttrBitIsMovie = uint(17)
// AttrBitBadgepay 付费
AttrBitBadgepay = uint(18)
AttrBitPushBlog = uint(20)
)
//qa audit status & attr.
var (
QAAuditStatus = map[int16]string{
VideoStatusOpen: "开放浏览",
VideoStatusOrange: "会员可见",
VideoStatusRecycle: "打回",
VideoStatusLock: "锁定",
}
VideoAttribute = map[uint]string{
AttrBitNoRank: "norank",
AttrBitNoDynamic: "nodynamic",
AttrBitNoWeb: "noweb",
AttrBitNoMobile: "nomobile",
AttrBitNoSearch: "nosearch",
AttrBitOverseaLock: "oversea_block",
AttrBitNoRecommend: "norecommend",
AttrBitNoReprint: "no_reprint",
AttrBitHasHD5: "hd",
AttrBitIsPGC: "is_pgc",
AttrBitAllowBp: "allow_bp",
AttrBitIsBangumi: "bangumi",
AttrBitIsPorder: "is_porder",
AttrBitLimitArea: "limit_area",
AttrBitAllowTag: "allow_tag",
AttrBitJumpURL: "j",
AttrBitIsMovie: "is_movie",
AttrBitBadgepay: "badgepay",
AttrBitPushBlog: "push_blog",
}
)
//Video video info
type Video struct {
ID int64 `json:"id"`
AID int64 `json:"aid"`
CID int64 `json:"cid"`
MID int64 `json:"mid"`
Copyright int8 `json:"copyright"`
TypeID int64 `json:"type_id"`
Status int16 `json:"status"`
Attribute int32 `json:"attribute"`
XcodeState int8 `json:"xcode_state"`
Title string `json:"title"`
Description string `json:"description"`
Filename string `json:"filename"`
TagID int64 `json:"tag_id"`
Reason string `json:"reason"`
Note string `json:"note"`
AttributeList map[string]int32 `json:"attribute_list"`
Encoding int32 `json:"encoding"`
}
//AttributeList get attr as map
func AttributeList(attr int32) (list map[string]int32) {
list = map[string]int32{}
for bit, name := range VideoAttribute {
list[name] = int32(((attr >> bit) & 1))
}
return
}
// AttrSet video Attr set
func (v *Video) AttrSet(attr int32, bit uint) {
v.Attribute = v.Attribute&(^(1 << bit)) | (attr << bit)
}
// ArcVideo is archive_video model.
type ArcVideo struct {
ID int64 `json:"-"`
Aid int64 `json:"aid"`
Title string `json:"title"`
Desc string `json:"desc"`
Filename string `json:"filename"`
SrcType string `json:"-"`
Cid int64 `json:"cid"`
Duration int64 `json:"-"`
Filesize int64 `json:"-"`
Resolutions string `json:"-"`
Index int `json:"index"`
Playurl string `json:"-"`
Status int16 `json:"status"`
StatusDesc string `json:"status_desc"`
FailCode int8 `json:"fail_code"`
FailDesc string `json:"fail_desc"`
XcodeState int8 `json:"xcode"`
Attribute int32 `json:"-"`
RejectReason string `json:"reject_reason"`
WebLink string `json:"weblink"`
CTime time.Time `json:"ctime"`
MTime time.Time `json:"-"`
}

View File

@@ -0,0 +1,18 @@
package model
import (
"github.com/smartystreets/goconvey/convey"
"testing"
)
func Test_attribute(t *testing.T) {
list := AttributeList(1048691)
convey.Convey("属性列表", t, func() {
convey.So(list["norank"], convey.ShouldEqual, 1)
convey.So(list["nosearch"], convey.ShouldEqual, 1)
convey.So(list["nodynamic"], convey.ShouldEqual, 1)
convey.So(list["norecommend"], convey.ShouldEqual, 1)
convey.So(list["oversea_block"], convey.ShouldEqual, 1)
convey.So(list["push_blog"], convey.ShouldEqual, 1)
})
}

View File

@@ -0,0 +1,6 @@
package model
const (
// ConfForWeightVC 权重配置
ConfForWeightVC = "weight_conf_values"
)

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 = [
"search_test.go",
"service_test.go",
"video_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/videoup-task/conf:go_default_library",
"//app/admin/main/videoup-task/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"consumer.go",
"extra_func.go",
"log.go",
"oper.go",
"qa_video.go",
"review.go",
"search.go",
"service.go",
"task.go",
"task_dispatch.go",
"task_report.go",
"utils.go",
"video.go",
"weight.go",
],
importpath = "go-common/app/admin/main/videoup-task/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/videoup-task/conf:go_default_library",
"//app/admin/main/videoup-task/dao:go_default_library",
"//app/admin/main/videoup-task/model:go_default_library",
"//app/admin/main/videoup/model/archive:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/up/api/v1:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/queue/databus/report: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,172 @@
package service
import (
"context"
"fmt"
"go-common/library/sync/errgroup"
"strings"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/log"
)
// HandsUp 签入
func (s *Service) HandsUp(c context.Context, uid int64, uname string) (err error) {
if s.CheckOnline(c, uid) {
log.Info("已经登入(%d)", uid)
return
}
_, err = s.dao.TaskUserCheckIn(c, uid)
if err != nil {
log.Error("s.dao.TaskUserCheckIn(%d) error(%v)", uid, err)
return
}
s.sendConsumerLog(c, &model.ConsumerLog{
UID: uid,
Uname: uname,
Action: model.ActionHandsUP,
Ctime: time.Now().Format(model.TimeFormatSec),
Desc: "checkin",
})
mapParas := map[string]interface{}{
"action": model.ActionHandsUP,
"uid": uid,
}
if _, err = s.dao.AddTaskHis(c, 0, model.ActionHandsUP, 0, 0, uid, 0, 0, "checkin"); err != nil {
log.Error("s.dao.AddTaskLog(%v) error(%v)", mapParas, uid)
return
}
log.Info("用户签入(%d)", uid)
return
}
// HandsOff 签出
func (s *Service) HandsOff(c context.Context, uid int64, fuid int64) (err error) {
if fuid != 0 { //管理员强制踢出组员
if !s.isLeader(c, uid) {
return fmt.Errorf("只有组长能强制踢出")
}
log.Info("管理员%d踢出组员%d", uid, fuid)
uid = fuid
}
err = s.checkOut(c, uid)
if err != nil {
log.Error("s.checkOut(%d) error(%v)", uid, err)
return
}
s.Free(c, uid)
return
}
// Online 用户列表
func (s *Service) Online(c context.Context) (cms []*model.Consumers, err error) {
cms, err = s.dao.Consumers(c)
if err != nil {
log.Error("s.dao.Consumers error(%v)", err)
return
}
if len(cms) > 0 {
var wg errgroup.Group
wg.Go(func() error {
if err := s.mulIDtoName(c, cms, s.dao.GetNameByUID, "UID", "UserName"); err != nil {
log.Error("mulIDtoName s.dao.GetNameByUID error(%v)", err)
}
return nil
})
wg.Go(func() error {
if err := s.mulIDtoName(c, cms, s.dao.OutTime, "UID", "LastOut"); err != nil {
log.Error("mulIDtoName s.dao.OutTime error(%v)", err)
}
return nil
})
wg.Wait()
}
return
}
// InOutList 用户登入登出历史
func (s *Service) InOutList(c context.Context, unames string, bt, et string) (l []*model.InQuit, err error) {
uids := []int64{}
if len(unames) > 0 {
if res, err := s.dao.Uids(c, strings.Split(unames, ",")); err == nil {
for _, uid := range res {
uids = append(uids, uid)
}
}
}
// 前端参数是日期,搜索参数必须到秒
if len(bt) > 0 && len(et) > 0 {
bt = bt + " 00:00:00"
et = et + " 23:59:59"
}
return s.dao.InQuitList(c, uids, bt, et)
}
// CheckOnline 检查在线状态
func (s *Service) CheckOnline(c context.Context, uid int64) (on bool) {
if s.dao.IsConsumerOn(c, uid) == 1 {
on = true
}
return
}
// CheckGroup 检查用户组权限
func (s *Service) CheckGroup(c context.Context, uid int64) (role int8, err error) {
role, err = s.dao.GetUserRole(c, uid)
if err != nil || role == 0 {
log.Error("非法用户(%d) error(%v)", uid, err)
return
}
return
}
func (s *Service) checkOut(c context.Context, uid int64) (err error) {
if s.dao.IsConsumerOn(c, uid) == 0 {
log.Info("已经签出(%d)", uid)
return
}
_, err = s.dao.TaskUserCheckOff(c, uid)
if err != nil {
log.Error("s.dao.TaskUserCheckOff(%d) error(%v)", uid, err)
return
}
s.sendConsumerLog(c, &model.ConsumerLog{
UID: uid,
Uname: "",
Action: model.ActionHandsOFF,
Ctime: time.Now().Format(model.TimeFormatSec),
Desc: "checkout",
})
mapParas := map[string]interface{}{
"action": model.ActionHandsOFF,
"uid": uid,
}
if _, err = s.dao.AddTaskHis(c, 0, model.ActionHandsOFF, 0, 0, uid, 0, 0, "checkOut"); err != nil {
log.Error("s.dao.AddTaskLog(%v) error(%v)", mapParas, uid)
}
return
}
func (s *Service) isLeader(c context.Context, uid int64) bool {
role, e := s.dao.GetUserRole(c, uid)
if e != nil {
log.Error("s.dao.GetUserRole(%d) error(%v)", uid, e)
return false
}
if role == model.TaskLeader {
return true
}
return false
}

View File

@@ -0,0 +1,106 @@
package service
import (
"context"
"errors"
tmod "go-common/app/admin/main/videoup-task/model"
account "go-common/app/service/main/account/api"
upsrpc "go-common/app/service/main/up/api/v1"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
//ERROR
var (
ErrRPCEmpty = errors.New("rpc reply empty")
)
func (s *Service) profile(c context.Context, mid int64) (profile *account.ProfileStatReply, err error) {
if profile, err = s.accRPC.ProfileWithStat3(c, &account.MidReq{Mid: mid}); err != nil {
log.Error("s.accRPC.ProfileWithStat3(%d) error(%v)", mid, err)
}
return
}
func (s *Service) upSpecial(c context.Context) (ups map[int8]map[int64]struct{}, err error) {
var (
g errgroup.Group
whitegroup, blackgroup, policesgroup, enterprisegroup, signedgroup map[int64]struct{}
)
ups = make(map[int8]map[int64]struct{})
f := func(gid int8) (map[int64]struct{}, error) {
group := make(map[int64]struct{})
mids, e := s.upGroupMids(c, int64(gid))
if e != nil {
return group, e
}
for _, mid := range mids {
group[mid] = struct{}{}
}
return group, nil
}
g.Go(func() error {
whitegroup, err = f(tmod.UpperTypeWhite)
return err
})
g.Go(func() error {
blackgroup, err = f(tmod.UpperTypeBlack)
return err
})
g.Go(func() error {
policesgroup, err = f(tmod.UpperTypePolitices)
return err
})
g.Go(func() error {
enterprisegroup, err = f(tmod.UpperTypeEnterprise)
return err
})
g.Go(func() error {
signedgroup, err = f(tmod.UpperTypeSigned)
return err
})
if err = g.Wait(); err != nil {
return
}
ups[tmod.UpperTypeWhite] = whitegroup
ups[tmod.UpperTypeBlack] = blackgroup
ups[tmod.UpperTypePolitices] = policesgroup
ups[tmod.UpperTypeEnterprise] = enterprisegroup
ups[tmod.UpperTypeSigned] = signedgroup
return
}
func (s *Service) upGroupMids(c context.Context, gid int64) (mids []int64, err error) {
var (
total int
maxps = 10000
req = &upsrpc.UpGroupMidsReq{
Pn: 1,
GroupID: gid,
Ps: maxps,
}
reply *upsrpc.UpGroupMidsReply
)
for {
reply, err = s.upsRPC.UpGroupMids(c, req)
if err == nil && (reply == nil || reply.Mids == nil) {
err = ErrRPCEmpty
}
if err != nil {
log.Error("UpGroupMids req(%+v) error(%v)", req, err)
return
}
total = reply.Total
mids = append(mids, reply.Mids...)
if reply.Size() != maxps {
break
}
req.Pn++
}
log.Info("upGroupMids(%d) reply total(%d) len(%d)", gid, total, len(mids))
return
}

View File

@@ -0,0 +1,69 @@
package service
import (
"context"
"strconv"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/log"
"go-common/library/queue/databus/report"
)
// send to log service
func (s *Service) sendVideoLog(c context.Context, vp *model.VideoParam, others string) (err error) {
var (
v *model.ArcVideo
a *model.Archive
)
if vp.Cid != 0 {
v, err = s.dao.ArcVideoByCID(c, vp.Cid)
} else if vp.ID != 0 {
v, err = s.dao.NewVideoByID(c, vp.ID)
}
if err != nil || v == nil {
v = &model.ArcVideo{} // ignore err
}
a, err = s.dao.Archive(c, vp.Aid)
if err != nil || a == nil {
a = &model.Archive{} // ignore err
}
// send
logData := &report.ManagerInfo{
Uname: vp.Oname,
UID: vp.UID,
Business: model.LogClientVideo,
Type: model.LogClientTypeVideo,
Oid: vp.Cid,
Action: strconv.Itoa(int(vp.Status)),
Ctime: time.Now(),
Index: []interface{}{int64(vp.Attribute), v.CTime.Unix(), vp.TagID, a.Title, vp.Note},
Content: map[string]interface{}{
"content": vp,
"others": others,
},
}
report.Manager(logData)
return
}
// sendConsumerLog send consumer log
func (s *Service) sendConsumerLog(c context.Context, cl *model.ConsumerLog) (err error) {
logData := &report.ManagerInfo{
Uname: cl.Uname,
UID: cl.UID,
Business: model.LogClientConsumer,
Type: model.LogClientTypeConsumer,
Oid: cl.UID,
Action: strconv.Itoa(int(cl.Action)),
Ctime: time.Now(),
Index: []interface{}{cl.UID, cl.Action, cl.Ctime},
Content: map[string]interface{}{
"content": cl,
},
}
report.Manager(logData)
log.Info("sendConsumerLog logData(%+v)", cl)
return
}

View File

@@ -0,0 +1,41 @@
package service
import (
"context"
"go-common/app/admin/main/videoup-task/model"
)
func (s *Service) diffVideoOper(vp *model.VideoParam) (conts []string) {
if vp.TagID > 0 {
var operType int8
if vp.Status >= model.VideoStatusOpen {
operType = model.OperTypeOpenTag
} else {
operType = model.OperTypeRecicleTag
}
conts = append(conts, model.Operformat(operType, "tagid", vp.TagID, model.OperStyleTwo))
}
if vp.Reason != "" {
conts = append(conts, model.Operformat(model.OperTypeAduitReason, "reason", vp.Reason, model.OperStyleTwo))
}
if vp.TaskID > 0 {
conts = append(conts, model.Operformat(model.OperTypeTaskID, "task", vp.TaskID, model.OperStyleTwo))
}
return
}
func (s *Service) addVideoOper(c context.Context, oper *model.VideoOper) (err error) {
/*
if oldOper, _ := s.dao.VideoOper(c, oper.Vid); oldOper != nil && oldOper.LastID == 1 {
oper.LastID = oldOper.ID
s.dao.AddVideoOper(c, oper.Aid, oper.UID, oper.Vid, oper.Attribute, oper.Status, oper.LastID, oper.Content, oper.Remark)
return
}
*/
if lastID, _ := s.dao.AddVideoOper(c, oper.Aid, oper.UID, oper.Vid, oper.Attribute, oper.Status, oper.LastID, oper.Content, oper.Remark); lastID > 0 {
s.dao.UpVideoOper(c, lastID, lastID)
return
}
return
}

View File

@@ -0,0 +1,320 @@
package service
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/admin/main/videoup-task/dao"
"go-common/app/admin/main/videoup-task/model"
accmdl "go-common/app/service/main/account/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/queue/databus/report"
)
//GetVideoList list qa video tasks
func (s *Service) GetVideoList(ctx context.Context, pm *model.ListParams) (list *model.QAVideoList, err error) {
var (
listLen int
detailMap map[int64]map[string]int64
midList []int64
users map[int64]*model.UserRole
infos map[int64]*accmdl.Info
upGroupList map[int64][]*model.UPGroup
)
if list, err = s.searchQAVideo(ctx, pm); err != nil || list == nil || len(list.Result) <= 0 {
return
}
ids := make([]int64, listLen)
uids := make([]int64, listLen)
for _, item := range list.Result {
ids = append(ids, item.ID)
uids = append(uids, item.UID)
}
if detailMap, midList, err = s.dao.QAVideoDetail(ctx, ids); err != nil {
return
}
if users, err = s.dao.GetUsernameAndRole(ctx, uids); err != nil {
return
}
if infos, err = s.dao.AccountInfos(ctx, midList); err != nil {
return
}
//获取列表页获取
if upGroupList, err = s.dao.UPGroups(ctx, midList); err != nil {
return
}
for _, item := range list.Result {
item.User = users[item.UID]
item.StateName = model.QAStates[item.State]
item.UPName = ""
dt, exist := detailMap[item.ID]
if exist {
item.DetailID = dt["detail_id"]
item.TaskUTime = dt["task_utime"]
item.MID = dt["mid"]
item.UPGroupList = upGroupList[item.MID]
if infos[item.MID] != nil {
item.UPName = infos[item.MID].Name
}
}
}
return
}
//AddQATaskVideo add a qa video task
func (s *Service) AddQATaskVideo(ctx context.Context, detail *model.AddVideoParams) (taskID int64, err error) {
var vid int64
if vid, err = s.dao.GetVID(ctx, detail.AID, detail.CID); err != nil {
log.Error("AddQATaskVideo s.dao.GetVID(aid(%d), cid(%d)) error(%v)", detail.AID, detail.CID, err)
return
}
if vid <= 0 {
log.Error("AddQATaskVideo non-deleted video(aid(%d), cid(%d)) not exist", detail.AID, detail.CID)
return
}
taskID, err = s.insertVideoTask(ctx, detail)
return
}
func (s *Service) insertVideoTask(ctx context.Context, detail *model.AddVideoParams) (taskID int64, err error) {
var (
tx *sql.Tx
detailID int64
)
defer func() {
if msg := recover(); msg != nil {
if tx != nil {
tx.Rollback()
}
log.Error("insertVideoTask panic recover, msg(%s)", msg)
}
}()
if tx, err = s.dao.BeginTran(ctx); err != nil {
return
}
if detailID, err = s.dao.InsertQAVideo(tx, &detail.VideoDetail); err != nil {
tx.Rollback()
return
}
if taskID, err = s.dao.InTaskQA(tx, detail.OUID, detailID, model.QATypeVideo); err != nil {
tx.Rollback()
return
}
if err = tx.Commit(); err != nil {
dao.PromeErr("arcdb: commit", "insertVideoTask commit error(%v) aid(%d) cid(%d)", err, detail.AID, detail.CID)
}
return
}
func (s *Service) getQATaskVideo(ctx context.Context, id int64, simple bool) (task *model.QATaskVideo, err error) {
if simple {
task, err = s.dao.QATaskVideoSimpleByID(ctx, id)
} else {
task, err = s.dao.QATaskVideoByID(ctx, id)
}
if err != nil {
return
}
if task == nil {
err = ecode.NothingFound
return
}
task.GetAttributeList()
return
}
//GetDetail get qa video task detail
func (s *Service) GetDetail(ctx context.Context, id int64) (dt *model.TaskVideoDetail, err error) {
var (
taskVideo *model.QATaskVideo
video *model.Video
history []*model.VideoOperInfo
)
if taskVideo, err = s.getQATaskVideo(ctx, id, false); err != nil {
return
}
info := &model.VideoTaskInfo{
QATaskVideo: *taskVideo,
}
groups, _ := s.dao.UPGroups(ctx, []int64{taskVideo.MID})
info.UPGroupList = groups[taskVideo.MID]
info.GetWarnings()
if video, err = s.getVideo(ctx, taskVideo.AID, taskVideo.CID); err != nil {
return
}
if history, err = s.getVideoOperInfo(ctx, video.ID); err != nil {
return
}
dt = &model.TaskVideoDetail{
Task: info,
Video: video,
VideoHistory: history,
}
return
}
//QAVideoSubmit submit qa video task
func (s *Service) QAVideoSubmit(ctx context.Context, username string, uid int64, vp *model.QASubmitParams) (err error) {
var (
task *model.QATaskVideo
video *model.Video
)
if task, err = s.getQATaskVideo(ctx, vp.ID, true); err != nil {
log.Error("QAVideoSubmit s.arc.QATaskVideoByID error(%v), id(%d) task(%+v)", err, vp.ID, task)
return
}
if video, err = s.getVideo(ctx, task.AID, task.CID); err != nil {
log.Error("sendLog s.getVideo error(%v) qa.id(%d) aid(%d) cid(%d)", err, vp.ID, task.AID, task.CID)
return
}
//不重复质检
if task.State == model.QAStateFinish {
return
}
//更新task
task.State = model.QAStateFinish
task.FTime = time.Now()
if _, err = s.dao.UpTask(ctx, vp.ID, task.State, task.FTime); err != nil {
return
}
s.dao.AddVideoOper(ctx, task.AID, uid, video.ID, video.Attribute, video.Status, 0, fmt.Sprintf("一审任务质检TAG: [%s]", vp.QATag), vp.QaNote)
s.sendLog(ctx, username, uid, video, task, vp)
return
}
func (s *Service) sendLog(ctx context.Context, username string, uid int64, video *model.Video, task *model.QATaskVideo, vp *model.QASubmitParams) (err error) {
var (
note string
taskUIDName string
)
if task == nil || len(task.AttributeList) == 0 {
log.Error("sendLog task/task.attributelist not exist, task(%+v) params(%+v)", task, vp)
return
}
if note, err = task.GetNote(); err != nil {
log.Error("sendLog task.GetNote() error(%v), params(%+v)", err, vp)
return
}
if vp.Norank == 1 {
video.AttributeList["norank"] = 1
}
if vp.Nodynamic == 1 {
video.AttributeList["nodynamic"] = 1
}
if vp.Norecommend == 1 {
video.AttributeList["norecommend"] = 1
}
if vp.Nosearch == 1 {
video.AttributeList["nosearch"] = 1
}
if vp.PushBlog == 1 {
video.AttributeList["push_blog"] = 1
}
if vp.OverseaBlock == 1 {
video.AttributeList["oversea_block"] = 1
}
video.TagID = vp.TagID
video.Status = vp.AuditStatus
video.Note = vp.Note
video.Reason = vp.Reason
video.Encoding = vp.Encoding
if taskUIDNames, err := s.dao.GetUsername(ctx, []int64{task.UID}); err != nil {
taskUIDName = ""
err = nil
} else {
taskUIDName = taskUIDNames[task.UID]
}
content := map[string]interface{}{
"audit_status": task.AuditStatus,
"audit_attr": task.AttributeList,
"audit_tag_id": task.TagID,
"audit_note": note,
"qa_status": video.Status,
"qa_attr": video.AttributeList,
"qa_tag_id": video.TagID,
"qa_note": video.Note,
}
data := &report.ManagerInfo{
Uname: username,
UID: uid,
Business: model.LogQATask,
Type: model.LogQATaskVideo,
Oid: vp.ID,
Action: strconv.Itoa(int(video.Status)),
Ctime: task.FTime,
Index: []interface{}{task.TaskID, task.MID, task.CTime.Unix(), strconv.FormatInt(vp.QaTagID, 10), strconv.FormatInt(task.UID, 10), taskUIDName},
Content: content,
}
report.Manager(data)
log.Info(" sendLog data(%+v)", data)
return
}
//UpVideoUTime update qa video task utime
func (s *Service) UpVideoUTime(ctx context.Context, aid, cid, taskID, utime int64) (err error) {
var id int64
if id, err = s.dao.GetQAVideoID(ctx, aid, cid, taskID); err != nil {
log.Error("UpVideoUTime s.dao.GetQAVideoID error(%v) aid(%d) cid(%d) taskid(%d) utime(%d)", err, aid, cid, taskID, utime)
return
}
if id <= 0 {
log.Error("UpVideoUTime s.dao.GetQAVideoID not found aid(%d) cid(%d) taskid(%d) utime(%d)", aid, cid, taskID, utime)
err = ecode.RequestErr
return
}
return s.dao.UpdateQAVideoUTime(ctx, aid, cid, taskID, utime)
}
func (s *Service) delProc() {
var (
err error
qaVideoRows, qaTaskRows int64 = 1, 1
limit = 1000
)
for {
deadLine := time.Now().AddDate(0, -1, 0)
for {
if qaVideoRows > 0 {
if qaVideoRows, err = s.dao.DelQAVideo(context.TODO(), deadLine, limit); err != nil {
log.Error("delProc s.dao.DelQAVideo(%v,%d) error(%v)", deadLine, limit, err)
}
}
if qaTaskRows > 0 {
if qaTaskRows, err = s.dao.DelQATask(context.TODO(), deadLine, limit); err != nil {
log.Error("delProc s.dao.DelQATask(%v,%d) error(%v)", deadLine, limit, err)
}
}
if qaVideoRows+qaTaskRows == 0 {
break
}
time.Sleep(time.Minute)
}
time.Sleep(time.Hour * 24)
}
}

View File

@@ -0,0 +1,264 @@
package service
import (
"context"
"fmt"
"strings"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
// ErrTaskMISS .
var ErrTaskMISS = fmt.Errorf("任务缓存查找失败")
// ReviewForm 复审表单
func (s *Service) ReviewForm(c context.Context, tid int64) (form *model.SubmitForm, err error) {
return s.dao.ReviewForm(c, tid)
}
// CheckReview 检查任务复审
func (s *Service) CheckReview(c context.Context, form *model.SubmitForm) (isReview bool, err error) {
var (
v *model.Video
attr int32
tx *sql.Tx
rows int64
tp *model.TaskPriority
)
attr, err = s.dao.VideoAttribute(c, form.CID)
if err != nil {
log.Error("CheckReview VideoAttribute(aid%d,cid%d) miss(%v)", form.AID, form.CID, err)
return false, ErrTaskMISS
}
v = &model.Video{Attribute: attr}
tp, err = s.getReviewParams(c, form)
if err != nil || tp == nil {
log.Info("CheckReview(%d) 不需要复审(%+v)", form.TaskID, tp)
return false, err
}
s.SyncRC(c)
ck := s.reviewCache.Check(c, tp, form.UID)
if !ck {
log.Info("CheckReview(%d) 不需要复审(%+v)", form.TaskID, tp)
return false, nil
}
if _, err = s.dao.InReviewForm(c, form, form.UID, form.Uname); err != nil {
return false, err
}
if tx, err = s.dao.BeginTran(c); err != nil {
return false, err
}
if rows, err = s.dao.TxUpTaskByID(tx, form.TaskID, map[string]interface{}{"state": model.TypeReview}); err != nil {
tx.Rollback()
return false, err
}
if rows > 0 {
if _, err = s.dao.TxAddTaskHis(tx, 0, model.ActionSubmit, form.TaskID, form.CID, form.UID, 0, form.Status, "TaskReview"); err != nil {
tx.Rollback()
return false, err
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
return false, err
}
// log
attrs := map[uint]int32{
model.AttrBitNoRank: form.Norank,
model.AttrBitNoDynamic: form.Noindex,
model.AttrBitNoRecommend: form.NoRecommend,
model.AttrBitNoSearch: form.Nosearch,
model.AttrBitOverseaLock: form.OverseaBlock,
model.AttrBitPushBlog: form.PushBlog,
}
var conts []string
const template = "[%s]从[%s]设为[%s]"
var yesOrNo = map[int32]string{model.AttrYes: "是", model.AttrNo: "否"}
for bit, attr := range attrs {
v.AttrSet(attr, bit)
if attr == 1 {
conts = append(conts, fmt.Sprintf(template, model.BitDesc(bit), yesOrNo[^attr&1], yesOrNo[attr]))
log.Info("vid(%d) update video bit(%d) bitdesc(%s) attrs(%d)", form.ID, bit, model.BitDesc(bit), attr)
}
}
vp := &model.VideoParam{
ID: form.ID,
Aid: form.AID,
Mid: form.MID,
RegionID: tp.TypeID,
Status: form.Status,
Cid: form.CID,
Title: form.Eptitle,
Desc: form.Description,
UID: form.UID,
TaskID: form.TaskID,
Oname: form.Uname,
TagID: form.TID,
Reason: form.Reason,
ReasonID: form.ReasonID,
Note: form.Note,
Attribute: v.Attribute,
}
oper := &model.VideoOper{Aid: form.AID, UID: form.UID, Vid: form.ID, Attribute: vp.Attribute, Status: form.Status, Remark: form.Note}
operConts := append([]string{fmt.Sprintf("初审提交")}, conts...)
operConts = append(operConts, s.diffVideoOper(vp)...)
oper.Content = strings.Join(operConts, "")
s.addVideoOper(c, oper)
s.sendVideoLog(c, vp, oper.Content)
return true, nil
}
// ListReviewConfs 配置列表
func (s *Service) ListReviewConfs(c context.Context, unames, bt, et, sort string, pn, ps int64) (rcs []*model.ReviewConf, count int64, err error) {
var uids []int64
if len(unames) > 0 {
res, _ := s.dao.Uids(c, strings.Split(unames, ","))
for _, uid := range res {
uids = append(uids, uid)
}
}
rcs, count, err = s.dao.ListConfs(c, uids, bt, et, sort, pn, ps)
for _, v := range rcs {
if v.Bt.TimeValue().IsZero() {
v.Bt = ""
}
if v.Et.TimeValue().IsZero() {
v.Et = ""
}
if len(v.Uids) > 0 {
if unames, _ := s.dao.Unames(c, v.Uids); len(unames) > 0 {
for _, uname := range unames {
v.Unames = append(v.Unames, uname)
}
}
}
}
return
}
// AddReviewConf 添加配置
func (s *Service) AddReviewConf(c context.Context, rc *model.ReviewConf) (err error) {
if len(rc.Types) > 0 {
stypes, _ := xstr.SplitInts(s.tarnsType(c, xstr.JoinInts(rc.Types)))
rc.Types = stypes
}
if _, err = s.dao.InReviewConf(c, rc); err != nil {
log.Error("s.AddReviewConf(%+v) error(%v)", rc, err)
return err
}
s.SyncRC(c)
return
}
// EditReviewConf 修改配置
func (s *Service) EditReviewConf(c context.Context, rc *model.ReviewConf) (err error) {
if len(rc.Types) > 0 {
stypes, _ := xstr.SplitInts(s.tarnsType(c, xstr.JoinInts(rc.Types)))
rc.Types = stypes
}
if _, err = s.dao.UpReviewConf(c, rc); err != nil {
log.Error("s.EditReviewConf(%+v) error(%v)", rc, err)
return err
}
s.SyncRC(c)
return
}
// DelReviewConf 删除配置
func (s *Service) DelReviewConf(c context.Context, id int) (err error) {
if _, err = s.dao.DelReviewConf(c, id); err != nil {
log.Error("s.DelReviewConf(%d) error(%v)", id, err)
return err
}
s.SyncRC(c)
return
}
// SyncRC sync from db
func (s *Service) SyncRC(c context.Context) {
rcs, err := s.dao.ReviewConfs(context.TODO())
if err != nil {
log.Error("loadRC error(%v)", err)
return
}
if len(rcs) > 0 {
s.reviewCache.Mux.Lock()
defer s.reviewCache.Mux.Unlock()
s.reviewCache.MRC = make(map[int64]*model.ReviewConf)
for _, item := range rcs {
s.reviewCache.MRC[item.ID] = item
}
}
}
func (s *Service) loadRC() {
s.SyncRC(context.TODO())
}
func (s *Service) loadRCproc() {
for {
time.Sleep(3 * time.Minute)
s.SyncRC(context.TODO())
}
}
func (s *Service) getReviewParams(c context.Context, form *model.SubmitForm) (tp *model.TaskPriority, err error) {
t, err := s.dao.TaskByID(c, form.TaskID)
if err != nil || t == nil {
return nil, ErrTaskMISS
}
if t.State != model.TypeDispatched {
log.Info("CheckReview(%d) 不需要复审 state(%d)", form.TaskID, t.State)
return nil, nil
}
mp, err := s.dao.GetWeightRedis(c, []int64{form.TaskID})
if err != nil || len(mp) == 0 {
if mp, err = s.dao.GetWeightDB(c, []int64{form.TaskID}); err != nil || len(mp) == 0 {
log.Error("GetWeightDB(%d) miss", form.TaskID)
return nil, ErrTaskMISS
}
}
if _, ok := mp[form.TaskID]; !ok {
log.Error("mp(%d) miss", form.TaskID)
return nil, ErrTaskMISS
}
tp = mp[form.TaskID]
// 补充复审判断的参数
if tp.TypeID == 0 {
s.setReviewParams(c, form.MID, form.AID, tp)
}
return
}
func (s *Service) setReviewParams(c context.Context, mid, aid int64, tp *model.TaskPriority) {
typeid, upfrom, err := s.dao.ArchiveParam(c, aid)
if err == nil {
tp.TypeID = typeid
tp.UpFrom = upfrom
}
tp.UpGroups = s.getSpecial(mid)
}

View File

@@ -0,0 +1,118 @@
package service
import (
"context"
"go-common/library/ecode"
"go-common/library/xstr"
"net/url"
"strconv"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/elastic"
"go-common/library/log"
)
const (
_searchBusinessQAVideo = "task_qa"
_searchBusinessQAVideoRandom = "task_qa_random"
_searchIndexQAVideo = "task_qa"
_searchLogURL = "/x/admin/search/log"
)
func (s *Service) searchQAVideo(c context.Context, pm *model.ListParams) (list *model.QAVideoList, err error) {
needRandom := pm.Limit > 0 && pm.Seed != ""
business := _searchBusinessQAVideo
if needRandom {
business = _searchBusinessQAVideoRandom
}
req := s.es.NewRequest(business).Index(_searchIndexQAVideo).Ps(pm.Ps).Pn(pm.Pn)
if pm.CTimeFrom != "" || pm.CTimeTo != "" {
req.WhereRange("ctime", pm.CTimeFrom, pm.CTimeTo, elastic.RangeScopeLcRc)
}
if pm.FTimeFrom != "" || pm.FTimeTo != "" {
req.WhereRange("ftime", pm.FTimeFrom, pm.FTimeTo, elastic.RangeScopeLcRc)
}
if pm.FansFrom > 0 || pm.FansTo > 0 {
req.WhereRange("fans", pm.FansFrom, pm.FansTo, elastic.RangeScopeLcRc)
}
if len(pm.UID) > 0 {
req.WhereIn("uid", pm.UID)
}
if len(pm.TaskID) > 0 {
req.WhereIn("task_id", pm.TaskID)
}
if len(pm.TagID) > 0 {
req.WhereIn("audit_tagid", pm.TagID)
}
if len(pm.UPGroup) > 0 {
req.WhereIn("up_groups", pm.UPGroup)
}
if len(pm.ArcTypeID) > 0 {
req.WhereIn("arc_typeid", pm.ArcTypeID)
}
if len(pm.AuditStatus) > 0 {
req.WhereIn("audit_status", pm.AuditStatus)
}
if len(pm.Keyword) > 0 {
req.WhereLike([]string{"arc_title"}, pm.Keyword, true, elastic.LikeLevelLow)
}
if needRandom {
req.WhereEq("seed", pm.Seed)
} else {
req.Order(pm.Order, pm.Sort)
}
if pm.State == model.QAStateWait || pm.State == model.QAStateFinish {
req.WhereEq("state", pm.State)
}
if err = req.Scan(c, &list); err != nil {
log.Error("searchQAVideo elastic scan error(%v) params(%+v)", err, pm)
return
}
if needRandom && list != nil && list.Page.Total > pm.Limit {
list.Page.Total = pm.Limit
//移除多余部分
addition := list.Page.Num*list.Page.Size - pm.Limit
if addition > 0 {
list.Result = list.Result[:(list.Page.Size - addition)]
}
}
return
}
func (s *Service) lastInTime(c context.Context, ids []int64) (mcases map[int64][]interface{}, err error) {
return s.lastTime(c, model.ActionHandsUP, ids)
}
func (s *Service) lastOutTime(c context.Context, ids []int64) (mcases map[int64][]interface{}, err error) {
return s.lastTime(c, model.ActionHandsOFF, ids)
}
// lastInOutTime
func (s *Service) lastTime(c context.Context, action int8, ids []int64) (mcases map[int64][]interface{}, err error) {
mcases = make(map[int64][]interface{})
params := url.Values{}
uri := s.c.Host.Search + _searchLogURL
params.Set("appid", "log_audit_group")
params.Set("group", "uid")
params.Set("uid", xstr.JoinInts(ids))
params.Set("business", strconv.Itoa(model.LogClientConsumer))
params.Set("action", strconv.Itoa(int(action)))
params.Set("ps", strconv.Itoa(len(ids)))
res := &model.SearchLogResult{}
if err = s.httpClient.Get(c, uri, "", params, &res); err != nil {
log.Error("log_audit_group d.httpClient.Get error(%v)", err)
return
}
if res.Code != ecode.OK.Code() {
log.Error("log_audit_group ecode:%v", res.Code)
return
}
for _, item := range res.Data.Result {
mcases[item.UID] = []interface{}{item.Ctime}
}
log.Info("log_audit_group get: %s params:%s ret:%v", uri, params.Encode(), res)
return
}

View File

@@ -0,0 +1,40 @@
package service
import (
"context"
"github.com/smartystreets/goconvey/convey"
"testing"
"go-common/app/admin/main/videoup-task/model"
)
func Test_searchQAVideo(t *testing.T) {
Init()
convey.Convey("search qavideo", t, func() {
pm := &model.ListParams{
State: 1,
Ps: 50,
Pn: 1,
Sort: "desc",
Order: "id",
CTimeFrom: "2018-05-08 00:00:00",
CTimeTo: "2018-07-20 00:00:00",
//FTimeFrom: "2018-07-10 00:00:00",
//FTimeTo: "2018-07-20 00:00:00",
FansFrom: 1,
FansTo: 100,
UID: []int64{421, 481},
UPGroup: []int64{1, 2},
AuditStatus: []int{-4, -2, 10000},
ArcTypeID: []int64{76},
TagID: []int64{14, 6, 23, 15},
Keyword: []string{"普通"},
TaskID: []int64{8326, 8327},
//Limit: 2,
}
resp, err := s.searchQAVideo(context.TODO(), pm)
convey.So(err, convey.ShouldBeNil)
t.Logf("resp(%+v)", resp)
})
}

View File

@@ -0,0 +1,136 @@
package service
import (
"context"
"sync"
"time"
"go-common/app/admin/main/videoup-task/conf"
"go-common/app/admin/main/videoup-task/dao"
"go-common/app/admin/main/videoup-task/model"
account "go-common/app/service/main/account/api"
upsrpc "go-common/app/service/main/up/api/v1"
"go-common/library/database/elastic"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// MemberCache .
type MemberCache struct {
sync.RWMutex
uptime time.Time
ms map[int64]*model.MemberStat
}
//Service service
type Service struct {
c *conf.Config
dao *dao.Dao
es *elastic.Elastic
httpClient *bm.Client
memberCache *MemberCache
// cache
typeCache map[int16]*model.Type
reviewCache *model.ReviewCache
twConCache map[int8]map[int64]*model.WCItem
upperCache map[int8]map[int64]struct{}
typeCache2 map[int16][]int64 // 记录每个一级分区下的二级分区
//grpc
accRPC account.AccountClient
upsRPC upsrpc.UpClient
}
//New new service
func New(conf *conf.Config) (svr *Service) {
svr = &Service{
c: conf,
dao: dao.New(conf),
es: elastic.NewElastic(nil),
httpClient: bm.NewClient(conf.HTTPClient),
memberCache: &MemberCache{},
// cache
reviewCache: model.NewRC(),
}
var err error
if svr.accRPC, err = account.NewClient(conf.GRPC.AccRPC); err != nil {
panic(err)
}
if svr.upsRPC, err = upsrpc.NewClient(conf.GRPC.UpsRPC); err != nil {
panic(err)
}
go svr.memberproc()
svr.loadConf()
go svr.cacheproc()
go svr.delProc()
svr.loadRC()
go svr.loadRCproc()
return
}
//Close close
func (s *Service) Close() {
s.dao.Close()
}
//Ping ping
func (s *Service) Ping(ctx context.Context) (err error) {
err = s.dao.Ping(ctx)
return
}
func (s *Service) loadConf() {
var (
err error
tpm map[int16]*model.Type
tpm2 map[int16][]int64
twConCache map[int8]map[int64]*model.WCItem
upm map[int8]map[int64]struct{}
)
if tpm, err = s.dao.TypeMapping(context.TODO()); err != nil {
log.Error("s.dao.TypeMapping error(%v)", err)
return
}
s.typeCache = tpm
tpm2 = make(map[int16][]int64)
for id, tmod := range tpm {
if tmod.PID == 0 {
if _, ok := tpm2[id]; !ok {
tpm2[id] = []int64{}
}
continue
}
arrid, ok := tpm2[tmod.PID]
if !ok {
tpm2[tmod.PID] = []int64{int64(id)}
} else {
tpm2[tmod.PID] = append(arrid, int64(id))
}
}
s.typeCache2 = tpm2
if twConCache, err = s.weightConf(context.TODO()); err != nil {
log.Error("s.weightConf error(%v)", err)
return
}
s.twConCache = twConCache
upm, err = s.upSpecial(context.TODO())
if err != nil {
log.Error("s.upSpecial error(%v)", err)
return
}
s.upperCache = upm
}
func (s *Service) cacheproc() {
for {
time.Sleep(3 * time.Minute)
s.loadConf()
}
}

View File

@@ -0,0 +1,22 @@
package service
import (
"flag"
"go-common/app/admin/main/videoup-task/conf"
)
var s *Service
func Init() {
if s != nil {
return
}
flag.Set("conf", "../cmd/videoup-task-admin.toml")
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}

View File

@@ -0,0 +1,198 @@
package service
import (
"context"
"fmt"
"sync"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// GetStats .
func (s *Service) GetStats(c context.Context) (stats []*model.MemberStat, err error) {
s.memberCache.RLock()
defer s.memberCache.RUnlock()
st := s.memberCache.uptime
if st.IsZero() {
st = time.Now().Add(-30 * time.Minute)
}
rst, err := s.memberStats(c, st, time.Now())
if err != nil {
log.Error("s.MemberStats error(%v)", err)
err = nil
}
for uid, omst := range s.memberCache.ms {
if nmst, ok := rst[uid]; ok {
mst := &model.MemberStat{UID: uid}
mst.DispatchCount = omst.DispatchCount + nmst.DispatchCount
mst.ReleaseCount = omst.ReleaseCount + nmst.ReleaseCount
mst.SubmitCount = omst.SubmitCount + nmst.SubmitCount
mst.OSubmitCount = omst.OSubmitCount + nmst.OSubmitCount
mst.NSubmitCount = omst.NSubmitCount + nmst.NSubmitCount
mst.BelongCount = omst.BelongCount + nmst.BelongCount
mst.PassCount = omst.PassCount + nmst.PassCount
mst.NormalCount = omst.NormalCount + nmst.NormalCount
mst.SubjectCount = omst.SubjectCount + nmst.SubjectCount
mst.SumDu = omst.SumDu + nmst.SumDu
mst.SumDuration = fmt.Sprintf("%.2d:%.2d:%.2d", mst.SumDu/3600, (mst.SumDu%3600)/60, (mst.SumDu%3600)%60)
var CompleteRate, PassRate = 100.0, 100.0
if mst.SubmitCount < mst.BelongCount {
CompleteRate = float64(mst.SubmitCount) / float64(mst.BelongCount) * 100.0
}
if mst.PassCount < mst.SubmitCount {
PassRate = float64(mst.PassCount) / float64(mst.SubmitCount) * 100.0
}
mst.CompleteRate = fmt.Sprintf("%.2f%%", CompleteRate)
mst.PassRate = fmt.Sprintf("%.2f%%", PassRate)
if mst.NSubmitCount == 0 {
mst.AvgUtime = "00:00:00"
} else {
mst.AvgUt = (omst.AvgUt*float64(omst.NSubmitCount) + nmst.AvgUt*float64(nmst.NSubmitCount)) / float64(mst.NSubmitCount)
mst.AvgUtime = fmt.Sprintf("%.2d:%.2d:%.2d", int64(mst.AvgUt)/3600, (int64(mst.AvgUt)%3600)/60, (int64(mst.AvgUt)%3600)%60)
}
delete(rst, uid)
stats = append(stats, mst)
} else {
stats = append(stats, omst)
}
}
if len(rst) > 0 {
for _, nmst := range rst {
stats = append(stats, nmst)
}
}
if len(stats) > 0 {
wg, ctx := errgroup.WithContext(c)
wg.Go(func() error {
if err := s.mulIDtoName(ctx, stats, s.lastInTime, "UID", "InTime"); err != nil {
log.Error("mulIDtoName s.lastInTime error(%v)", err)
}
return nil
})
wg.Go(func() error {
if err := s.mulIDtoName(ctx, stats, s.lastOutTime, "UID", "QuitTime"); err != nil {
log.Error("mulIDtoName s.lastOutTime error(%v)", err)
}
return nil
})
wg.Wait()
}
for _, st := range stats {
if st.QuitTime <= st.InTime {
st.QuitTime = ""
}
}
return
}
// MemberStats 审核人员统计数据[通过旧一审提交。会导致同一个任务被多次完成]
func (s *Service) memberStats(c context.Context, st, et time.Time) (stats map[int64]*model.MemberStat, err error) {
var (
mx sync.Mutex
uids []int64
)
stats = make(map[int64]*model.MemberStat)
if uids, err = s.dao.ActiveUids(c, st, et); err != nil || len(uids) == 0 {
return
}
log.Info("MemberStats,st(%s),et(%s) count(%d) uids(%v) ", st.String(), et.String(), len(uids), uids)
wg := errgroup.Group{}
for _, uid := range uids {
id := uid
wg.Go(func() error {
st, e := s.singleStat(context.TODO(), id, st, et)
if e != nil || st == nil {
log.Error("s.singleStat(%d) error(%v)", id, e)
return nil
}
mx.Lock()
stats[st.UID] = st
mx.Unlock()
return nil
})
}
err = wg.Wait()
return
}
func (s *Service) singleStat(c context.Context, uid int64, stime, etime time.Time) (stat *model.MemberStat, err error) {
var (
SumDuration int64
AvgUtime float64
)
stat = &model.MemberStat{UID: uid}
mapAction, err := s.dao.ActionCountByUID(c, uid, stime, etime)
if err != nil {
return
}
stat.OSubmitCount = mapAction[model.ActionOldSubmit]
stat.NSubmitCount = mapAction[model.ActionSubmit]
stat.SubmitCount = stat.OSubmitCount + stat.NSubmitCount
stat.DispatchCount = mapAction[model.ActionDispatch]
stat.ReleaseCount = mapAction[model.ActionRelease]
if stat.PassCount, err = s.dao.PassCountByUID(c, uid, stime, etime); err != nil {
return
}
if stat.SubjectCount, err = s.dao.SubjectCountByUID(c, uid, stime, etime); err != nil {
return
}
if SumDuration, err = s.dao.SumDurationByUID(c, uid, stime, etime); err != nil {
return
}
if AvgUtime, err = s.dao.AvgUtimeByUID(c, uid, stime, etime); err != nil {
return
}
stat.BelongCount = stat.DispatchCount - stat.ReleaseCount
var CompleteRate, PassRate = 100.0, 100.0
if stat.SubmitCount < stat.BelongCount {
CompleteRate = float64(stat.SubmitCount) / float64(stat.BelongCount) * 100.0
}
if stat.PassCount < stat.SubmitCount {
PassRate = float64(stat.PassCount) / float64(stat.SubmitCount) * 100.0
}
stat.CompleteRate = fmt.Sprintf("%.2f%%", CompleteRate)
stat.PassRate = fmt.Sprintf("%.2f%%", PassRate)
stat.NormalCount = stat.SubmitCount - stat.SubjectCount
stat.SumDu = SumDuration
stat.AvgUt = AvgUtime
stat.SumDuration = fmt.Sprintf("%.2d:%.2d:%.2d", SumDuration/3600, (SumDuration%3600)/60, (SumDuration%3600)%60)
stat.AvgUtime = fmt.Sprintf("%.2d:%.2d:%.2d", int64(AvgUtime)/3600, (int64(AvgUtime)%3600)/60, (int64(AvgUtime)%3600)%60)
return
}
func (s *Service) memberproc() {
for {
st := time.Now()
stats, err := s.memberStats(context.TODO(), st.Add(-24*time.Hour), st)
if err != nil {
log.Error("s.MemberStats error(%v)", err)
} else {
s.memberCache.Lock()
s.memberCache.uptime = st
s.memberCache.ms = stats
s.memberCache.Unlock()
}
log.Info("s.MemberStats ut(%.2f)", time.Since(st).Seconds())
time.Sleep(30 * time.Minute)
}
}

View File

@@ -0,0 +1,325 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
// List 查看任务列表
func (s *Service) List(c context.Context, uid int64, pn, ps int, ltype, leader int8) (tasks []*model.Task, err error) {
return s.dao.ListByCondition(c, uid, pn, ps, ltype, leader)
}
// Delay 申请延迟
func (s *Service) Delay(c context.Context, id, uid int64, reason string) (err error) {
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran() error(%v)", err)
return
}
rows, err := s.dao.TxUpTaskByID(tx, id, map[string]interface{}{"state": model.TypeDelay, "dtime": time.Now()})
if err != nil {
log.Error("s.dao.TxUpTaskByID(%d) error(%v)", id, err)
tx.Rollback()
return
}
if rows > 0 {
if _, err = s.dao.TxAddTaskHis(tx, 0, model.ActionDelay /*action*/, id /*task_id*/, 0, uid /*uid*/, 0, 0, reason /*reason*/); err != nil {
log.Error("s.dao.AddTaskLog(%d) error(%v)", id, err)
tx.Rollback()
return
}
}
return tx.Commit()
}
// TaskSubmit 提交审核结果
func (s *Service) TaskSubmit(c context.Context, t *model.Task, uid int64, status int16) (err error) {
var utime int64
switch {
case t.State == model.TypeDelay || t.State == model.TypeReview: //延迟任务复审任务不记录utime
utime = 0
case t.GTime.TimeValue().IsZero():
utime = int64(time.Since(t.MTime.TimeValue()))
default:
utime = int64(time.Since(t.GTime.TimeValue()))
}
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran error(%v)", err)
return
}
rows, err := s.dao.TxUpTaskByID(tx, t.ID, map[string]interface{}{"state": model.TypeFinished, "utime": utime})
if err != nil {
log.Error("s.dao.TxUpTaskByID(%d) error(%v)", t.ID, err)
tx.Rollback()
return
}
if rows > 0 {
if _, err = s.dao.TxAddTaskHis(tx, 0, model.ActionSubmit /*action*/, t.ID /*task_id*/, t.Cid /*cid*/, uid /*uid*/, utime /*utime*/, status /*result*/, "TaskSubmit" /*reason*/); err != nil {
log.Error("s.dao.AddTaskLog(%d) error(%v)", t.ID, err)
tx.Rollback()
return
}
}
return tx.Commit()
}
// Next 领取任务
func (s *Service) Next(c context.Context, uid int64) (task *model.Task, err error) {
var rows int64
task, err = s.dao.GetNextTask(c, uid)
if err != nil {
log.Error("d.getTask(%d) error(%v)", uid, err)
return
}
if task != nil {
return
}
// 释放超时任务
s.Free(c, 0)
// 从实时任务池抢占
if rows, err = s.dispatchTask(c, uid); err != nil {
return
} else if rows > 0 {
return s.dao.GetNextTask(c, uid)
}
return
}
// Info 查询任务信息
func (s *Service) Info(c context.Context, tid int64) (task *model.Task, err error) {
return s.dao.TaskByID(c, tid)
}
// 抢占任务(先抢占再查,避免重复下发)
func (s *Service) dispatchTask(c context.Context, uid int64) (rows int64, err error) {
var (
tls []*model.TaskForLog
arrid []int64
)
if tls, err = s.dao.GetDispatchTask(c, uid); err != nil {
log.Error("s.dao.GetDispatchTask(%d) error(%v)", uid, err)
return
}
for _, item := range tls {
arrid = append(arrid, item.ID)
}
if len(arrid) > 0 {
if rows, err = s.dao.UpDispatchTask(c, uid, arrid); err != nil {
log.Error("s.dao.UpDispatchTask(%d,%v,%v) error(%v)", uid, arrid, err)
return
}
// 日志允许错误
if int(rows) == len(arrid) {
log.Info("UpDispatchTask 更新数量(%d)", rows)
} else {
log.Warn("UpDispatchTask 更新数量(%d) 日志数量(%d)", rows, len(arrid))
}
s.dao.MulAddTaskHis(c, tls, model.ActionDispatch, uid)
}
return
}
// Free 任务释放(有uid为主动释放没有uid为被动释放)(先查再释放,有可能记录冗余释放信息)
func (s *Service) Free(c context.Context, uid int64) (rows int64) {
var (
rts []*model.TaskForLog
ids, rtids []int64
lastid int64
err error
mtime = time.Now()
)
if uid == 0 {
if rts, err = s.dao.GetTimeOutTask(c); err != nil {
log.Error("s.Free s.dao.GetTimeOutTask error(%v)", err)
return
}
} else {
if rts, lastid, err = s.dao.GetRelTask(c, uid); err != nil {
log.Error("s.Free s.dao.GetRelTask(%d) error(%v)", uid, err)
return
}
}
mcases := make(map[int64]*model.WCItem)
for _, rt := range rts {
ids = append(ids, rt.ID)
if rt.Subject == 1 { //指派任务回流
rtids = append(rtids, rt.ID)
mcases[rt.ID] = &model.WCItem{Radio: 4, Weight: model.WLVConf.SubRelease,
Mtime: model.NewFormatTime(time.Now()), Desc: "指派回流权重"}
}
}
if len(ids) > 0 {
if rows, err = s.dao.MulReleaseMtime(c, ids, mtime); err != nil {
log.Error("s.dao.MulReleaseMtime(%v, %v) error(%v)", ids, mtime, err)
return
}
if rows > 0 {
s.dao.MulAddTaskHis(c, rts, model.ActionRelease, uid)
}
}
if lastid > 0 {
s.dao.UpGtimeByID(c, lastid, "0000-00-00 00:00:00")
timelogout := time.Now()
log.Info("添加延时释放任务(%d %v)", lastid, timelogout)
time.AfterFunc(5*time.Minute, func() {
s.releaseSpecial(timelogout, lastid, uid)
})
}
if len(rtids) > 0 {
s.setWeightConf(c, xstr.JoinInts(rtids), mcases)
}
return
}
func (s *Service) releaseSpecial(tout time.Time, taskid, uid int64) {
tx, err := s.dao.BeginTran(context.TODO())
if err != nil {
log.Error(" s.dao.BeginTran error(%v)", err)
return
}
rows, err := s.dao.TxReleaseSpecial(tx, tout, 1, taskid, uid)
if err != nil {
log.Error("s.dao.TxReleaseSpecial error(%v)", err)
tx.Rollback()
return
}
if rows > 0 {
log.Info("s.dao.TxReleaseSpecial 释放任务(%d)", taskid)
if _, err = s.dao.TxAddTaskHis(tx, 0, model.ActionRelease, taskid, 0, uid, 0, 0, "登出延时释放"); err != nil {
log.Error("s.dao.TxAddTaskHis error(%v)", err)
tx.Rollback()
return
}
}
tx.Commit()
}
func (s *Service) judge(c context.Context, tid, aid, cid, uid int64) (err error) {
var (
rows int64
tx *sql.Tx
v *model.ArcVideo
a *model.Archive
)
// 1.校验视频
if v, err = s.dao.ArcVideoByCID(c, cid); err != nil {
log.Error("s.dao.ArcVideoByCID(%d) error(%v)", cid, err)
return
}
if v == nil || v.Status == model.VideoStatusDelete {
err = fmt.Errorf("视频(cid=%d)被删除", cid)
goto DELETE
}
// 2.校验稿件
if a, err = s.dao.Archive(c, aid); err != nil {
log.Error("s.dao.Archive(%d) error(%v)", aid, err)
return
}
if a == nil || a.State == model.StateForbidUpDelete {
err = fmt.Errorf("稿件(aid=%d)被删除", aid)
}
DELETE:
if err != nil {
if tx, err = s.dao.BeginTran(c); err != nil {
log.Error("s.dao.BeginTran() error(%v)", err)
return
}
if rows, err = s.dao.TxUpTaskByID(tx, tid, map[string]interface{}{"state": model.TypeFinished, "utime": 0}); err != nil {
log.Error("s.dao.TxUpTaskByID(%d) error(%v)", tid, err)
tx.Rollback()
return
}
if rows > 0 {
if _, err = s.dao.TxAddTaskHis(tx, 0 /*pool*/, model.ActionTaskDelete /*action*/, tid /*task_id*/, cid /*cid*/, uid /*uid*/, 0 /*utime*/, model.VideoStatusDelete /*result*/, "judge delete" /*reason*/); err != nil {
log.Error("s.dao.AddTaskLog(%d) error(%v)", tid, err)
tx.Rollback()
return
}
}
return tx.Commit()
}
return
}
// CheckOwner 检查任务状态修改权限
func (s *Service) CheckOwner(c context.Context, tid, uid int64) (err error) {
var role int8
var rows int64
task, err := s.dao.TaskByID(c, tid)
if task == nil || err != nil {
log.Error("s.dao.TaskByID(%d) error(%v)", tid, err)
return
}
if err = s.judge(c, task.ID, task.Aid, task.Cid, uid); err != nil {
log.Error("s.judge(%+v) error(%v)", task, err)
return
}
if role, err = s.dao.GetUserRole(c, uid); err != nil || role == 0 {
err = fmt.Errorf("非法用户(%d)", uid)
return
}
if task.State == model.TypeDelay || task.State == model.TypeReview {
return
}
if !s.CheckOnline(c, uid) {
err = fmt.Errorf("请先签到(%d)", uid)
return
}
if role == model.TaskLeader {
return
}
if task.UID != uid {
err = fmt.Errorf("没有权限处理该任务")
return
}
// 普通用户处理超时了,将任务释放掉
if task.State == model.TypeDispatched && time.Since(task.GTime.TimeValue()).Minutes() > 10.0 {
var tx *sql.Tx
if tx, err = s.dao.BeginTran(c); err != nil {
log.Error("s.dao.BeginTran() error(%v)", err)
return
}
if rows, err = s.dao.TxUpTaskByID(tx, tid, map[string]interface{}{"state": model.TypeRealTime, "uid": 0, "gtime": "0000-00-00 00:00:00"}); err != nil {
log.Error("s.dao.TxUpTaskByID(%d) error(%v)", tid, err)
tx.Rollback()
return
}
if rows > 0 {
if _, err = s.dao.TxAddTaskHis(tx, 0 /*pool*/, model.ActionRelease /*action*/, tid /*task_id*/, 0 /*cid*/, uid /*uid*/, 0 /*utime*/, 0 /*result*/, "timeout release" /*reason*/); err != nil {
log.Error("s.dao.AddTaskLog(%d) error(%v)", tid, err)
tx.Rollback()
return
}
}
return tx.Commit()
}
return
}

View File

@@ -0,0 +1,18 @@
package service
import (
"context"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/log"
)
// TaskTooksByHalfHour get task books by ctime
func (s *Service) TaskTooksByHalfHour(c context.Context, stime, etime time.Time) (tooks []*archive.TaskTook, err error) {
if tooks, err = s.dao.TaskTooksByHalfHour(c, stime, etime); err != nil {
log.Error("s.dao.TaskTooksByHalfHour(%v,%v)", stime, etime)
return
}
return
}

View File

@@ -0,0 +1,123 @@
package service
import (
"context"
"fmt"
"reflect"
"go-common/library/log"
)
// 每个ID单独查询 strict严格模式下一次错误直接返回
func (s *Service) singleIDtoName(c context.Context, list interface{}, singletrans func(context.Context, int64) ([]interface{}, error), strict bool, ID string, Names ...string) (err error) {
var (
lV, itemI, itemIE, idFiled, nameFiled, valueField reflect.Value
id int64
values []interface{}
)
if lV = reflect.ValueOf(list); !lV.IsValid() || lV.IsNil() || lV.Kind() != reflect.Slice {
return fmt.Errorf("invalid list")
}
count := lV.Len()
for i := 0; i < count; i++ {
if itemI = lV.Index(i); !itemI.IsValid() || itemI.IsNil() || itemI.Kind() != reflect.Ptr {
return fmt.Errorf("invalid itemI")
}
if itemIE = itemI.Elem(); !itemIE.IsValid() || itemIE.Kind() != reflect.Struct {
return fmt.Errorf("invalid itemIE")
}
if idFiled = itemIE.FieldByName(ID); !idFiled.IsValid() || idFiled.Kind() != reflect.Int64 {
return fmt.Errorf("invalid idFiled")
}
for _, Name := range Names {
if nameFiled = itemIE.FieldByName(Name); !nameFiled.IsValid() || !nameFiled.CanSet() {
return fmt.Errorf("invalid nameFiled")
}
}
if id = idFiled.Int(); id != 0 {
if values, err = singletrans(c, id); err != nil || len(values) != len(Names) {
log.Error("s.sigleIDtoName error(%v) len(values)=%d len(Names)=%d", err, len(values), len(Names))
if strict {
return
}
err = nil
continue
}
for i, value := range values {
nameFiled = itemIE.FieldByName(Names[i])
valueField = reflect.ValueOf(value)
if nameFiled.Kind() != valueField.Kind() {
log.Error("singletrans return %s while need %s", valueField.Kind().String(), nameFiled.Kind().String())
continue
}
nameFiled.Set(valueField)
}
}
}
return
}
/* 批量查询,批量转换
* list []*struct{}
* multrans 转化器根据ID查出其他值
* ID id字段名称id字段类型必须是int64
* Names 查出来的各个字段名称
*/
func (s *Service) mulIDtoName(c context.Context, list interface{}, multrans func(context.Context, []int64) (map[int64][]interface{}, error), ID string, Names ...string) (err error) {
var (
lV, itemI, itemIE, idFiled, nameFiled, valueField reflect.Value
id int64
ids []int64
hashIDName = make(map[int64][]interface{})
)
if lV = reflect.ValueOf(list); !lV.IsValid() || lV.IsNil() || lV.Kind() != reflect.Slice {
return fmt.Errorf("invalid list")
}
count := lV.Len()
for i := 0; i < count; i++ {
if itemI = lV.Index(i); !itemI.IsValid() || itemI.IsNil() || itemI.Kind() != reflect.Ptr {
return fmt.Errorf("invalid itemI")
}
if itemIE = itemI.Elem(); !itemIE.IsValid() || itemIE.Kind() != reflect.Struct {
return fmt.Errorf("invalid itemIE")
}
if idFiled = itemIE.FieldByName(ID); !idFiled.IsValid() || idFiled.Kind() != reflect.Int64 {
return fmt.Errorf("invalid idFiled")
}
for _, name := range Names {
if nameFiled = itemIE.FieldByName(name); !nameFiled.IsValid() || !nameFiled.CanSet() {
return fmt.Errorf("invalid nameFiled")
}
}
if id = idFiled.Int(); id != 0 {
if _, ok := hashIDName[id]; !ok {
hashIDName[id] = []interface{}{}
ids = append(ids, id)
}
}
}
if hashIDName, err = multrans(c, ids); err != nil {
return
}
for i := 0; i < count; i++ {
itemIE = lV.Index(i).Elem()
id = itemIE.FieldByName(ID).Int()
if names, ok := hashIDName[id]; ok && len(names) == len(Names) {
for i, name := range names {
nameFiled = itemIE.FieldByName(Names[i])
valueField = reflect.ValueOf(name)
if nameFiled.Kind() != valueField.Kind() {
log.Error("multrans return %v while need %v", ids)
continue
}
itemIE.FieldByName(Names[i]).Set(reflect.ValueOf(name))
}
}
}
return
}

View File

@@ -0,0 +1,57 @@
package service
import (
"context"
"go-common/app/admin/main/videoup-task/model"
"go-common/library/ecode"
"go-common/library/log"
)
func (s *Service) getVideo(ctx context.Context, aid int64, cid int64) (video *model.Video, err error) {
if video, err = s.dao.Video(ctx, aid, cid); err != nil {
log.Error("getVideo s.arc.Video error(%v) aid(%d) cid(%d)", err, aid, cid)
return
}
if video == nil {
err = ecode.NothingFound
log.Error("getVideo s.arc.Video error(%v) aid(%d) cid(%d)", err, aid, cid)
return
}
video.AttributeList = model.AttributeList(video.Attribute)
if video.XcodeState >= model.VideoXcodeHDFinish {
video.Encoding = 1
}
return
}
func (s *Service) getVideoOperInfo(ctx context.Context, vid int64) (list []*model.VideoOperInfo, err error) {
var (
vopers []*model.VOper
uids []int64
users map[int64]*model.UserDepart
)
list = []*model.VideoOperInfo{}
if vopers, uids, err = s.dao.VideoOpers(ctx, vid); err != nil {
log.Error("getVideoOperInfo s.dao.VideoOpers(%d) error(%v)", vid, err)
return
}
if users, err = s.dao.GetUsernameAndDepartment(ctx, uids); err != nil {
log.Error("getVideoOperInfo s.dao.GetUsernameAndRol(%d) error(%v) uids(%v)", vid, err, uids)
return
}
for _, op := range vopers {
u := users[op.UID]
if u == nil {
u = &model.UserDepart{UID: op.UID}
}
info := &model.VideoOperInfo{
VOper: *op,
UserDepart: *u,
}
list = append(list, info)
}
return
}

View File

@@ -0,0 +1,21 @@
package service
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func Test_getVideoOperInfo(t *testing.T) {
Init()
convey.Convey("getVideoOperInfo", t, func() {
list, err := s.getVideoOperInfo(context.TODO(), 8942606)
for _, info := range list {
t.Logf("info(%+v)", info)
}
convey.So(err, convey.ShouldBeNil)
convey.So(len(list), convey.ShouldEqual, 66)
})
}

View File

@@ -0,0 +1,321 @@
package service
import (
"context"
"encoding/json"
"fmt"
"time"
"go-common/app/admin/main/videoup-task/model"
account "go-common/app/service/main/account/api"
"go-common/library/log"
"go-common/library/sync/errgroup"
"go-common/library/xstr"
)
// weightConf 所有激活的配置项
func (s *Service) weightConf(c context.Context) (wconfs map[int8]map[int64]*model.WCItem, err error) {
items, err := s.dao.WeightConf(c)
if err != nil {
log.Error("WeightConf error(%v)", err)
return
}
wconfs = map[int8]map[int64]*model.WCItem{}
for _, item := range items {
conf, ok := wconfs[item.Radio]
if !ok {
conf = make(map[int64]*model.WCItem)
}
conf[item.CID] = item
wconfs[item.Radio] = conf
}
return
}
// 同一类型的同id配置只能有一个
func (s *Service) checkConflict(c context.Context, mcases map[int64]*model.WCItem) (err error) {
wcf, err := s.weightConf(c)
if err != nil {
log.Error("s.weightConf error(%v)", err)
return
}
s.twConCache = wcf
for _, item := range mcases {
if cfgs, ok := s.twConCache[item.Radio]; ok {
if cfg, ok := cfgs[item.CID]; ok {
return fmt.Errorf("config(%d) conflict with (id=%d,desc=%s)", item.CID, cfg.ID, cfg.Desc)
}
}
}
return
}
// AddWeightConf 配置权重
func (s *Service) AddWeightConf(c context.Context, cfg *model.WeightConf, uid int64, uname string) (err error) {
//0. 一级分区转化为二级分区
if cfg.Radio == model.WConfType {
cfg.Ids = s.tarnsType(c, cfg.Ids)
}
//1. 解析表单提交的配置
mcases, istaskid, err := model.ParseWeightConf(cfg, uid, uname)
if err != nil {
log.Error("model.ParseWeightConf(%v, %v, %v) error(%v)", cfg, uname, err)
return
}
//2. 检查是否互相冲突
if err = s.checkConflict(c, mcases); err != nil {
log.Error("s.checkConflict error(%v)", err)
return
}
//3. 更新任务的权重配置
if istaskid {
if err = s.setWeightConf(c, cfg.Ids, mcases); err != nil {
log.Error("s.setWeightConf error(%v)", err)
return
}
}
//4. 将配置存储到数据库表
if err = s.dao.InWeightConf(c, mcases); err != nil {
log.Error("s.dao.InWeightConf(%v) error(%v)", mcases, err)
return
}
return
}
// DelWeightConf 删除配置项
func (s *Service) DelWeightConf(c context.Context, id int64) (err error) {
if _, err = s.dao.DelWeightConf(c, id); err != nil {
log.Error("s.DelWeightConf(%d) error(%v)", id, err)
}
return
}
// ListWeightConf 列出配置
func (s *Service) ListWeightConf(c context.Context, v *model.Confs) (cfg []*model.WCItem, err error) {
if cfg, err = s.dao.ListWeightConf(c, v); err != nil {
log.Error("s.ListWeightConf(%+v) error(%v)", v, err)
return
}
// 根据taskid补充filename和title
switch v.Radio {
case model.WConfMid: // 补充昵称和粉丝数
s.singleIDtoName(c, cfg, func(c context.Context, cid int64) (res []interface{}, err error) {
stat, err := s.profile(c, cid)
if err != nil {
log.Error("s.profile(%d) error(%v)", cid, err)
return
}
res = []interface{}{stat.Profile.Name, stat.Follower}
return
}, false, "CID", "Creator", "Fans")
case model.WConfTaskID: //补充title和filename
s.mulIDtoName(c, cfg, s.dao.LWConfigHelp, "CID", "FileName", "Title", "Vid")
case model.WConfType: //补充分区名称
s.singleIDtoName(c, cfg, func(c context.Context, cid int64) (res []interface{}, err error) {
if item, ok := s.typeCache[int16(cid)]; ok {
res = []interface{}{item.Name}
}
return
}, false, "CID", "TypeName")
case model.WConfUpFrom: //补充投稿来源
s.singleIDtoName(c, cfg, func(c context.Context, cid int64) (res []interface{}, err error) {
res = []interface{}{model.UpFrom(int8(cid))}
return
}, false, "CID", "UpFrom")
default:
}
return
}
// ListWeightLogs 权重变更日志
func (s *Service) ListWeightLogs(c context.Context, taskid int64, page int) (cfg []*model.TaskWeightLog, items int64, err error) {
cfg, err = s.dao.WeightLog(c, taskid)
if err != nil {
log.Info("s.ListWeightLogs(%d) error(%v)", taskid, err)
return
}
cfg, items, err = s.weightLogHelp(c, taskid, cfg, page)
return
}
// MaxWeight 当前的权重最大值, 供用户配置做参考
func (s *Service) MaxWeight(c context.Context) (max int64, err error) {
return s.dao.GetMaxWeight(c)
}
// 补充查询日志需要的信息
func (s *Service) weightLogHelp(c context.Context, taskid int64, twl []*model.TaskWeightLog, page int) (retwl []*model.TaskWeightLog, items int64, err error) {
var (
mid int64
ps *account.ProfileStatReply
name string
fans int
upspecial []int8
)
task, err := s.dao.TaskByID(c, taskid)
if task == nil {
log.Error("s.dao.TaskByID(%d) err(%v)", taskid, err)
return
}
// 1.获取用户信息
items = int64(len(twl))
if items == 0 {
return
}
mid = twl[items-1].Mid
if mid == 0 {
log.Error("weightLogHelp taskid=%d miss mid", taskid)
goto EMPTYMID
}
ps, err = s.profile(c, mid)
if err != nil || ps == nil {
log.Error("can't get Account.Card(%d) err(%v)", mid, err)
err = nil
} else {
name = ps.Profile.Name
fans = int(ps.Follower)
}
upspecial = s.getSpecial(mid)
EMPTYMID:
retwl = []*model.TaskWeightLog{}
// 反转日志顺序
var count int
for i := len(twl) - 1 - (page-1)*20; i >= 0 && count <= 20; func() { i--; count++ }() {
twl[i].Creator = name
twl[i].UpSpecial = upspecial
twl[i].Fans = int64(fans)
twl[i].Wait = twl[i].Uptime.TimeValue().Sub(task.CTime.TimeValue()).Seconds() * 1000.0
if !task.PTime.TimeValue().IsZero() {
twl[i].Ptime = string(task.PTime)
}
if len(twl[i].CfItems) > 0 {
for _, item := range twl[i].CfItems {
var desc = item.Desc
var v = new(model.WCItem)
if err = json.Unmarshal([]byte(item.Desc), v); err == nil { //兼容新旧日志格式
desc = v.Desc
}
err = nil
twl[i].Desc += fmt.Sprintf("%s:%s; ", model.CfWeightDesc(item.Radio), desc)
}
}
retwl = append(retwl, twl[i])
}
return
}
func (s *Service) getSpecial(mid int64) []int8 {
upspecial := []int8{}
for k, v := range s.upperCache {
if _, ok := v[mid]; ok {
upspecial = append(upspecial, k)
}
}
return upspecial
}
func (s *Service) setWeightConf(c context.Context, ids string, mcases map[int64]*model.WCItem) (err error) {
var mitems map[int64]*model.TaskPriority
arrid, _ := xstr.SplitInts(ids)
// 1. 获取旧的配置
if mitems, err = s.getTWCache(c, arrid); err != nil {
log.Error("s.getTWCache(%v) error(%v)", arrid, err)
return
}
if len(mitems) == 0 {
return fmt.Errorf("没有找到任务(%v)", arrid)
}
// 2. 将新加配置加入
for _, item := range mitems {
if one, ok := mcases[item.TaskID]; ok && one != nil {
one.Mtime = model.NewFormatTime(time.Now())
item.CfItems = append(item.CfItems, one)
}
}
// 3. 更新配置到redis和数据库
var wg errgroup.Group
wg.Go(func() (err error) {
return s.dao.SetWeightRedis(c, mitems)
})
for _, item := range mitems {
var descb []byte
v := item
wg.Go(func() (err error) {
if descb, err = json.Marshal(v.CfItems); err != nil {
return
}
_, err = s.dao.UpCwAfterAdd(c, v.TaskID, string(descb))
return
})
}
err = wg.Wait()
return
}
// ShowWeightVC 展示权重配置值
func (s *Service) ShowWeightVC(c context.Context) (wvc *model.WeightVC, err error) {
if wvc, err = s.dao.WeightVC(c); err != nil {
log.Error("s.dao.WeightVC error(%v)", err)
return
}
if wvc == nil {
wvc = model.WLVConf
s.dao.InWeightVC(c, wvc, "默认权重配置")
}
return
}
// SetWeightVC 设置权重配置
func (s *Service) SetWeightVC(c context.Context, wvc *model.WeightVC) (err error) {
_, err = s.dao.SetWeightVC(c, wvc, "设置权重配置")
return
}
// 处理一级分区转二级分区
func (s *Service) tarnsType(c context.Context, ids string) (res string) {
var (
mapNoNeed = make(map[int16]struct{}) // 不需要的一级分区
mapNeed = make(map[int16]struct{}) // 需要的一级分区
idres = []int64{}
)
arrid, _ := xstr.SplitInts(ids)
for _, id := range arrid {
if mod, ok := s.typeCache[int16(id)]; ok {
if mod.PID == 0 {
mapNeed[int16(id)] = struct{}{}
} else {
mapNoNeed[mod.PID] = struct{}{}
idres = append(idres, id)
}
}
}
for k := range mapNoNeed {
delete(mapNeed, k)
}
for k := range mapNeed {
idres = append(idres, s.typeCache2[k]...)
}
return xstr.JoinInts(idres)
}
func (s *Service) getTWCache(c context.Context, ids []int64) (mcases map[int64]*model.TaskPriority, err error) {
if mcases, err = s.dao.GetWeightRedis(c, ids); len(mcases) != len(ids) {
mcases, err = s.dao.GetWeightDB(c, ids)
}
return
}