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

21
app/job/main/mcn/BUILD Normal file
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/job/main/mcn/cmd:all-srcs",
"//app/job/main/mcn/conf:all-srcs",
"//app/job/main/mcn/dao:all-srcs",
"//app/job/main/mcn/model:all-srcs",
"//app/job/main/mcn/server/http:all-srcs",
"//app/job/main/mcn/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,21 @@
# v1.3.0
1. mcn四期功能
# v1.2.0
1. mcn三期功能
# v1.1.0
1. mcn二期功能
# v1.0.3
1. mcn_up 状态更新包含结束日
# v1.0.2
1. mcn一期停掉 一期零时数据job
# v1.0.1
1. mcn一期功能上线
# v1.0.0
1. mcn-job init

View File

@@ -0,0 +1,11 @@
# Owner
wangzhe01
shencen
# Author
hejianbing
wangyuzhe
yanjinbin
# Reviewer
wangzhe01

20
app/job/main/mcn/OWNERS Normal file
View File

@@ -0,0 +1,20 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- hejianbing
- shencen
- wangzhe01
labels:
- job
- job/main/mcn
- main
options:
no_parent_owners: true
reviewers:
- hejianbing
- limengqing
- liyixin
- shencen
- wangyuzhe
- wangzhe01
- yanjinbin

View File

@@ -0,0 +1,12 @@
# mcn-job
# 项目简介
1.
# 编译环境
# 依赖包
# 编译执行

View File

@@ -0,0 +1 @@
# HTTP API文档

View File

@@ -0,0 +1,43 @@
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 = ["mcn-job-test.toml"],
importpath = "go-common/app/job/main/mcn/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/mcn/conf:go_default_library",
"//app/job/main/mcn/server/http:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,38 @@
[MailTemplateConf]
SignTmplTitle = """[{{Now.Format "2006-01-02"}}] MCN-签约到期提醒"""
SignTmplContent = """
<html>
<body>
<table border="1">
<tr>
<td>昵称(uid)</td>
<td>到期提示信息</td>
</tr>
{{range .}}
<tr>
<td>{{.McnName}}{{.McnMid}}</td>
<td>{{.EndDate.Time.Format "2006-01-02"}} 签约即将到期,请尽快去<a href="http://up-profit.bilibili.co/allowance/#/mcn/mcnList">【up主CRM-MCN签约管理】查看</a></td>
</tr>
{{end}}
</table>
</body>
</html>
"""
PayTmplTitle = """[{{Now.Format "2006-01-02"}}] MCN-"""
PayTmplContent = """
<html>
<body>
<table border=1>
<tr>
<td>(uid)</td>
<td></td>
</tr>
{{range .}}
<tr>
<td>{{.McnName}}{{.McnMid}}</td>
<td>{{.DueDate.Time.Format "2006-01-02"}} {{printf "%.2f" .GetPayValue}}<a href="http://up-profit.bilibili.co/allowance/#/mcn/mcnList">upCRM-MCN</a></td>
</tr>
{{end}}
</table>
</body>
</html>"""

View File

@@ -0,0 +1,43 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/job/main/mcn/conf"
"go-common/app/job/main/mcn/server/http"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
// log.SetFormat("[%D %T] [%L] [%S] %M")
defer log.Close()
log.Info("start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
http.Init(conf.Conf)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,50 @@
[log]
stdout = true
[mysql]
addr = "172.16.33.205:3306"
dsn = "upcrm:DdL6c5JaWCYKMAQ10PURbfeImow9HXlx@tcp(172.16.33.205:3306)/bilibili_upcrm?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 1
idleTimeout ="4h"
queryTimeout = "200ms"
execTimeout = "300ms"
tranTimeout = "400ms"
[mysql.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[memcache]
name = "mcn-admin"
proto = "tcp"
addr = "172.18.33.60:11216"
active = 10
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
[property]
upMcnSignStateCron = "0 0 0 * * ?"
upMcnUpStateCron = "0 0 0 * * ?"
upExpirePayCron = "0 0 0 * * ?"
upMcnDataSummaryCron = "0 5 0 * * ?"
mcnRecommendCron = "@hourly"
dealFailRecommendCron = "@hourly"
checkMcnSignUpDueCron = "0 20 0 * * ?"
[MailConf]
host = "smtp.exmail.qq.com"
port = 465
username = "manager@bilibili.com"
password = "123"
DueMailReceivers = [""] # 需要发送的额外管理员名称
DueAuthorityGroups = ["mcnplan@bilibili.com"]
[GRPCClient]
[GRPCClient.account]
timeout = "1s"

View File

@@ -0,0 +1,39 @@
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/job/main/mcn/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace: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,131 @@
package conf
import (
"errors"
"flag"
"path"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Tracer *trace.Config
Memcache *memcache.Config
MySQL *sql.Config
Ecode *ecode.Config
// Property
Property *Property
// mail
MailConf *Mail
MailTemplateConf *MailTemplateConfig
// rpc client
GRPCClient *RPC
}
// RPC rpc client config.
type RPC struct {
Account *warden.ClientConfig
}
// Property config for biz logic.
type Property struct {
UpMcnSignStateCron string
UpMcnUpStateCron string
UpExpirePayCron string
UpMcnDataSummaryCron string
McnRecommendCron string
DealFailRecommendCron string
CheckMcnSignUpDueCron string
}
// Mail 邮件配置
type Mail struct {
Host string
Port int
Username, Password string
DueMailReceivers []string // []adminname, send to adminname@bilibili.com
DueAuthorityGroups []string
}
//MailTemplateConfig mail template conf
type MailTemplateConfig struct {
SignTmplTitle string
SignTmplContent string
PayTmplTitle string
PayTmplContent string
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
if err != nil {
return
}
var templateConfPath = path.Join(path.Dir(confPath), "mail-template.toml")
_, err = toml.DecodeFile(templateConfPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,66 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"email.go",
"mcn.go",
"memcache.go",
"recommend.go",
],
importpath = "go-common/app/job/main/mcn/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/mcn/conf:go_default_library",
"//app/job/main/mcn/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/gopkg.in/gomail.v2: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"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"email_test.go",
"mcn_test.go",
"memcache_test.go",
"recommend_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/mcn/conf:go_default_library",
"//app/job/main/mcn/model:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,47 @@
package dao
import (
"context"
"crypto/tls"
"go-common/app/job/main/mcn/conf"
"go-common/library/cache/memcache"
xsql "go-common/library/database/sql"
gomail "gopkg.in/gomail.v2"
)
// Dao dao
type Dao struct {
c *conf.Config
mc *memcache.Pool
db *xsql.DB
email *gomail.Dialer
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
mc: memcache.NewPool(c.Memcache),
db: xsql.NewMySQL(c.MySQL),
// mail
email: gomail.NewDialer(c.MailConf.Host, c.MailConf.Port, c.MailConf.Username, c.MailConf.Password),
}
dao.email.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
// TODO: if you need use mc,redis, please add
return d.db.Ping(c)
}

View File

@@ -0,0 +1,38 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/job/main/mcn/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.mcn-job")
flag.Set("conf_token", "6214e16a2d849e375d899cbe37df31d1")
flag.Set("tree_id", "58888")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/mcn-job-test.toml")
}
if os.Getenv("UT_LOCAL_TEST") != "" {
flag.Set("conf", "../cmd/mcn-job-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,40 @@
package dao
import (
"os"
"go-common/app/job/main/mcn/conf"
"go-common/library/log"
"gopkg.in/gomail.v2"
)
// SendMail send the email.
func (d *Dao) SendMail(body string, subject string, send []string) (err error) {
log.Info("send mail send:%v", send)
msg := gomail.NewMessage()
msg.SetHeader("From", conf.Conf.MailConf.Username)
msg.SetHeader("To", send...)
msg.SetHeader("Subject", subject)
msg.SetBody("text/html", body, gomail.SetPartEncoding(gomail.Base64))
if err = d.email.DialAndSend(msg); err != nil {
log.Error("s.email.DialAndSend error(%v)", err)
return
}
return
}
// SendMailAttach send the email.
func (d *Dao) SendMailAttach(filename string, subject string, send []string) (err error) {
msg := gomail.NewMessage()
msg.SetHeader("From", conf.Conf.MailConf.Username)
msg.SetHeader("To", send...)
msg.SetHeader("Subject", subject)
msg.Attach(filename)
if err = d.email.DialAndSend(msg); err != nil {
log.Error("s.email.DialAndSend error(%v)", err)
return
}
err = os.Remove(filename)
return
}

View File

@@ -0,0 +1,39 @@
package dao
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSendMail(t *testing.T) {
convey.Convey("SendMail", t, func(ctx convey.C) {
var (
body = ""
subject = ""
send = []string{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SendMail(body, subject, send)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoSendMailAttach(t *testing.T) {
convey.Convey("SendMailAttach", t, func(ctx convey.C) {
var (
filename = ""
subject = ""
send = []string{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SendMailAttach(filename, subject, send)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

318
app/job/main/mcn/dao/mcn.go Normal file
View File

@@ -0,0 +1,318 @@
package dao
import (
"context"
"database/sql"
"fmt"
"time"
"go-common/app/job/main/mcn/model"
xsql "go-common/library/database/sql"
xtime "go-common/library/time"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_upMcnSignStateOPSQL = "UPDATE mcn_sign SET state = ? WHERE id = ?"
_upMcnUpStateOPSQL = "UPDATE mcn_up SET state = ?, state_change_time = ? WHERE id = ?"
_upMcnSignPayExpOPSQL = "UPDATE mcn_sign SET pay_expire_state = 2 WHERE id = ?"
_upMcnSignEmailStateSQL = "UPDATE mcn_sign SET email_state = 2 WHERE id IN (%s)"
_upMcnSignPayEmailStateSQL = "UPDATE mcn_sign_pay SET email_state = 2 WHERE id IN (%s)"
_inMcnDataSummarySQL = "INSERT mcn_data_summary(mcn_mid,sign_id,up_count,fans_count_accumulate,generate_date,data_type) VALUES (?,?,?,?,?,1)"
_selMcnSignsSQL = `SELECT id,begin_date,end_date,state FROM mcn_sign`
_selMcnUpsSQL = `SELECT id,begin_date,end_date,state FROM mcn_up LIMIT ?,?`
_selMcnSignPayWarnsSQL = `SELECT p.sign_id,p.due_date,p.pay_value FROM mcn_sign_pay p INNER JOIN mcn_sign s ON p.sign_id = s.id WHERE p.state = 0 AND
s.state = 10 AND s.end_date >= ? AND s.begin_date <= p.due_date AND p.due_date <= s.end_date AND date_sub(p.due_date,interval 7 day) <= ?`
_selMcnSignMidsSQL = "SELECT id,mcn_mid FROM mcn_sign WHERE state = 10"
_selMcnUPCountSQL = "SELECT sign_id,count(up_mid) as count FROM mcn_up WHERE sign_id IN (%s) AND state = 10 GROUP BY sign_id"
_selMcnUPMidsSQL = "SELECT sign_id,up_mid FROM mcn_up WHERE sign_id IN (%s) AND state = 10"
_selCrmUpMidsSumSQL = "SELECT SUM(fans_count) as count FROM up_base_info WHERE mid IN (%s)"
_selMcnSignPayDues = `SELECT p.id, p.mcn_mid, p.sign_id, p.due_date, p.pay_value FROM mcn_sign_pay p LEFT JOIN mcn_sign s ON p.sign_id = s.id
WHERE p.due_date <= ? AND p.email_state = 1 AND p.state = 0 AND s.state = 10 AND s.end_date >= ?`
_selMcnSignDues = "SELECT id, mcn_mid, begin_date, end_date FROM mcn_sign WHERE end_date <= ? and end_date >= ? and email_state = 1"
)
// UpMcnSignStateOP .
func (d *Dao) UpMcnSignStateOP(c context.Context, signID int64, state int8) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _upMcnSignStateOPSQL, state, signID); err != nil {
return rows, err
}
return res.RowsAffected()
}
// UpMcnUpStateOP .
func (d *Dao) UpMcnUpStateOP(c context.Context, signUpID int64, state int8) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _upMcnUpStateOPSQL, state, time.Now(), signUpID); err != nil {
return rows, err
}
return res.RowsAffected()
}
// UpMcnSignPayExpOP .
func (d *Dao) UpMcnSignPayExpOP(c context.Context, signPayID int64) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _upMcnSignPayExpOPSQL, signPayID); err != nil {
return rows, err
}
return res.RowsAffected()
}
// UpMcnSignPayEmailState .
func (d *Dao) UpMcnSignPayEmailState(c context.Context, ids []int64) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_upMcnSignPayEmailStateSQL, xstr.JoinInts(ids))); err != nil {
return rows, err
}
return res.RowsAffected()
}
// UpMcnSignEmailState .
func (d *Dao) UpMcnSignEmailState(c context.Context, ids []int64) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_upMcnSignEmailStateSQL, xstr.JoinInts(ids))); err != nil {
return rows, err
}
return res.RowsAffected()
}
// AddMcnDataSummary .
func (d *Dao) AddMcnDataSummary(c context.Context, mcnMid, signID, upCount, fansCountAccumulate int64, genDate xtime.Time) (err error) {
_, err = d.db.Exec(c, _inMcnDataSummarySQL, mcnMid, signID, upCount, fansCountAccumulate, genDate)
return
}
// McnSigns .
func (d *Dao) McnSigns(c context.Context) (mss []*model.MCNSignInfo, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _selMcnSignsSQL); err != nil {
return
}
defer rows.Close()
for rows.Next() {
ms := new(model.MCNSignInfo)
if err = rows.Scan(&ms.SignID, &ms.BeginDate, &ms.EndDate, &ms.State); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
mss = append(mss, ms)
}
err = rows.Err()
return
}
// McnUps .
func (d *Dao) McnUps(c context.Context, offset, limit int64) (ups []*model.MCNUPInfo, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _selMcnUpsSQL, offset, limit); err != nil {
return
}
defer rows.Close()
for rows.Next() {
up := new(model.MCNUPInfo)
if err = rows.Scan(&up.SignUpID, &up.BeginDate, &up.EndDate, &up.State); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
ups = append(ups, up)
}
err = rows.Err()
return
}
// McnSignPayWarns .
func (d *Dao) McnSignPayWarns(c context.Context) (sps []*model.SignPayInfo, err error) {
var (
rows *xsql.Rows
now time.Time
template = time.Now().Format(model.TimeFormatDay)
)
if now, err = time.ParseInLocation(model.TimeFormatDay, template, time.Local); err != nil {
err = errors.Errorf("time.ParseInLocation(%s) error(%+v)", template, err)
return
}
if rows, err = d.db.Query(c, _selMcnSignPayWarnsSQL, now, now); err != nil {
return
}
defer rows.Close()
for rows.Next() {
sp := new(model.SignPayInfo)
if err = rows.Scan(&sp.SignID, &sp.DueDate, &sp.PayValue); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
sps = append(sps, sp)
}
err = rows.Err()
return
}
// McnSignMids .
func (d *Dao) McnSignMids(c context.Context) (msid map[int64]int64, sids []int64, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _selMcnSignMidsSQL); err != nil {
return
}
defer rows.Close()
msid = make(map[int64]int64)
for rows.Next() {
var signID, mcnMid int64
if err = rows.Scan(&signID, &mcnMid); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
msid[signID] = mcnMid
sids = append(sids, signID)
}
err = rows.Err()
return
}
// McnUPCount .
func (d *Dao) McnUPCount(c context.Context, signIDs []int64) (mmc map[int64]int64, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_selMcnUPCountSQL, xstr.JoinInts(signIDs))); err != nil {
return
}
defer rows.Close()
mmc = make(map[int64]int64)
for rows.Next() {
var signID, count int64
if err = rows.Scan(&signID, &count); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
mmc[signID] = count
}
err = rows.Err()
return
}
// McnUPMids .
func (d *Dao) McnUPMids(c context.Context, signIDs []int64) (mup map[int64][]int64, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_selMcnUPMidsSQL, xstr.JoinInts(signIDs))); err != nil {
return
}
defer rows.Close()
mup = make(map[int64][]int64)
for rows.Next() {
var signID, upMid int64
if err = rows.Scan(&signID, &upMid); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
mup[signID] = append(mup[signID], upMid)
}
err = rows.Err()
return
}
// CrmUpMidsSum .
func (d *Dao) CrmUpMidsSum(c context.Context, upMids []int64) (count int64, err error) {
row := d.db.QueryRow(c, fmt.Sprintf(_selCrmUpMidsSumSQL, xstr.JoinInts(upMids)))
var countNull sql.NullInt64
if err = row.Scan(&countNull); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
}
count = countNull.Int64
return
}
// McnSignPayDues .
func (d *Dao) McnSignPayDues(c context.Context) (sps []*model.SignPayInfo, err error) {
var (
rows *xsql.Rows
now, future time.Time
nowDate = time.Now()
date = nowDate.AddDate(0, 0, 7)
template = date.Format(model.TimeFormatDay)
nowTemplate = nowDate.Format(model.TimeFormatDay)
)
if now, err = time.ParseInLocation(model.TimeFormatDay, nowTemplate, time.Local); err != nil {
err = errors.Errorf("time.ParseInLocation(%s) now error(%+v)", nowTemplate, err)
return
}
if future, err = time.ParseInLocation(model.TimeFormatDay, template, time.Local); err != nil {
err = errors.Errorf("time.ParseInLocation(%s) error(%+v)", template, err)
return
}
if rows, err = d.db.Query(c, _selMcnSignPayDues, future, now); err != nil {
return
}
defer rows.Close()
for rows.Next() {
sp := new(model.SignPayInfo)
if err = rows.Scan(&sp.SignPayID, &sp.McnMid, &sp.SignID, &sp.DueDate, &sp.PayValue); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
sps = append(sps, sp)
}
err = rows.Err()
return
}
// McnSignDues .
func (d *Dao) McnSignDues(c context.Context) (mss []*model.MCNSignInfo, err error) {
var (
rows *xsql.Rows
now, future time.Time
nowDate = time.Now()
nowTemplate = nowDate.Format(model.TimeFormatDay)
futureDate = nowDate.AddDate(0, 0, 30)
futureTemplate = futureDate.Format(model.TimeFormatDay)
)
if now, err = time.ParseInLocation(model.TimeFormatDay, nowTemplate, time.Local); err != nil {
err = errors.Errorf("time.ParseInLocation(%s) now error(%+v)", nowTemplate, err)
return
}
if future, err = time.ParseInLocation(model.TimeFormatDay, futureTemplate, time.Local); err != nil {
err = errors.Errorf("time.ParseInLocation(%s) future error(%+v)", futureTemplate, err)
return
}
if rows, err = d.db.Query(c, _selMcnSignDues, future, now); err != nil {
return
}
defer rows.Close()
for rows.Next() {
ms := new(model.MCNSignInfo)
if err = rows.Scan(&ms.SignID, &ms.McnMid, &ms.BeginDate, &ms.EndDate); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
mss = append(mss, ms)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,194 @@
package dao
import (
"context"
"testing"
xtime "go-common/library/time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoUpMcnSignStateOP(t *testing.T) {
convey.Convey("UpMcnSignStateOP", t, func(ctx convey.C) {
var (
c = context.Background()
signID = int64(0)
state = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.UpMcnSignStateOP(c, signID, state)
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 TestDaoUpMcnUpStateOP(t *testing.T) {
convey.Convey("UpMcnUpStateOP", t, func(ctx convey.C) {
var (
c = context.Background()
signUpID = int64(0)
state = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.UpMcnUpStateOP(c, signUpID, state)
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 TestDaoUpMcnSignPayExpOP(t *testing.T) {
convey.Convey("UpMcnSignPayExpOP", t, func(ctx convey.C) {
var (
c = context.Background()
signPayID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.UpMcnSignPayExpOP(c, signPayID)
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 TestDaoAddMcnDataSummary(t *testing.T) {
convey.Convey("AddMcnDataSummary", t, func(ctx convey.C) {
var (
c = context.Background()
mcnMid = int64(0)
signID = int64(1)
upCount = int64(0)
fansCountAccumulate = int64(0)
genDate xtime.Time
)
var _, err = d.db.Exec(c, "delete from mcn_data_summary where sign_id=? and generate_date='1970-01-01'", signID)
if err != nil {
t.Logf("err=%v", err)
}
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddMcnDataSummary(c, mcnMid, signID, upCount, fansCountAccumulate, genDate)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoMcnSigns(t *testing.T) {
convey.Convey("McnSigns", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
mss, err := d.McnSigns(c)
ctx.Convey("Then err should be nil.mss should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(mss, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoMcnUps(t *testing.T) {
convey.Convey("McnUps", t, func(ctx convey.C) {
var (
c = context.Background()
offset = int64(0)
limit = int64(1)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ups, err := d.McnUps(c, offset, limit)
ctx.Convey("Then err should be nil.ups should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(ups), convey.ShouldBeGreaterThanOrEqualTo,0)
})
})
})
}
func TestDaoMcnSignPays(t *testing.T) {
convey.Convey("McnSignPays", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
sps, err := d.McnSignPayWarns(c)
ctx.Convey("Then err should be nil.sps should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(sps), convey.ShouldBeGreaterThanOrEqualTo, 0)
})
})
})
}
func TestDaoMcnSignMids(t *testing.T) {
convey.Convey("McnSignMids", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
msid, sids, err := d.McnSignMids(c)
ctx.Convey("Then err should be nil.msid,sids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(sids, convey.ShouldNotBeNil)
ctx.So(msid, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoMcnUPCount(t *testing.T) {
convey.Convey("McnUPCount", t, func(ctx convey.C) {
var (
c = context.Background()
signIDs = []int64{0}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
mmc, err := d.McnUPCount(c, signIDs)
ctx.Convey("Then err should be nil.mmc should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(mmc, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoMcnUPMids(t *testing.T) {
convey.Convey("McnUPMids", t, func(ctx convey.C) {
var (
c = context.Background()
signIDs = []int64{0}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
mup, err := d.McnUPMids(c, signIDs)
ctx.Convey("Then err should be nil.mup should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(mup, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoCrmUpMidsSum(t *testing.T) {
convey.Convey("CrmUpMidsSum", t, func(ctx convey.C) {
var (
c = context.Background()
upMids = []int64{0}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
count, err := d.CrmUpMidsSum(c, upMids)
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)
})
})
})
}

View File

@@ -0,0 +1,32 @@
package dao
import (
"context"
"strconv"
gmc "go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_mcnSign = "mcn_s_"
)
// user mcn sign key.
func mcnSignKey(mcnMid int64) string {
return _mcnSign + strconv.FormatInt(mcnMid, 10)
}
// DelMcnSignCache del mcn sign cache info.
func (d *Dao) DelMcnSignCache(c context.Context, mcnMid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(mcnSignKey(mcnMid)); err != nil {
if err == gmc.ErrNotFound {
err = nil
return
}
log.Error("conn.Delete(%d) error(%v)", mcnMid, err)
}
return
}

View File

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

View File

@@ -0,0 +1,68 @@
package dao
import (
"context"
"database/sql"
"time"
"go-common/app/job/main/mcn/model"
xsql "go-common/library/database/sql"
)
const (
_inMcnUpRecommendPoolSQL = `INSERT INTO mcn_up_recommend_pool (up_mid, fans_count, fans_count_increase_month, archive_count, play_count_accumulate, play_count_average, active_tid, last_archive_time, generate_time) VALUES (?,?,?,?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE fans_count=?, fans_count_increase_month=?, archive_count=?, play_count_accumulate=?, play_count_average=?, active_tid=?, last_archive_time=?, generate_time=?`
_delMcnUpRecommendPoolSQL = "UPDATE mcn_up_recommend_pool SET state = 100 WHERE generate_time < ? AND state IN (1,2) AND source = 1"
_delMcnUpRecommendSourceSQL = "DELETE FROM mcn_up_recommend_source WHERE id = ?"
_selMcnUpRecommendSourcesSQL = "SELECT id,up_mid,fans_count,fans_count_increase_month,archive_count,play_count_accumulate,play_count_average,active_tid,last_archive_time,ctime,mtime FROM mcn_up_recommend_source LIMIT ?"
)
// AddMcnUpRecommend .
func (d *Dao) AddMcnUpRecommend(c context.Context, arg *model.McnUpRecommendPool) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _inMcnUpRecommendPoolSQL, arg.UpMid, arg.FansCount, arg.FansCountIncreaseMonth, arg.ArchiveCount, arg.PlayCountAccumulate, arg.PlayCountAverage, arg.ActiveTid, arg.LastArchiveTime, arg.GenerateTime,
arg.FansCount, arg.FansCountIncreaseMonth, arg.ArchiveCount, arg.PlayCountAccumulate, arg.PlayCountAverage, arg.ActiveTid, arg.LastArchiveTime, arg.GenerateTime); err != nil {
return rows, err
}
return res.RowsAffected()
}
// DelMcnUpRecommendPool .
func (d *Dao) DelMcnUpRecommendPool(c context.Context) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _delMcnUpRecommendPoolSQL, time.Now().AddDate(0, 0, -3)); err != nil {
return rows, err
}
return res.RowsAffected()
}
// DelMcnUpRecommendSource .
func (d *Dao) DelMcnUpRecommendSource(c context.Context, id int64) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _delMcnUpRecommendSourceSQL, id); err != nil {
return rows, err
}
return res.RowsAffected()
}
// McnUpRecommendSources .
func (d *Dao) McnUpRecommendSources(c context.Context, limit int) (rps []*model.McnUpRecommendPool, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _selMcnUpRecommendSourcesSQL, limit); err != nil {
return
}
defer rows.Close()
for rows.Next() {
rp := new(model.McnUpRecommendPool)
if err = rows.Scan(&rp.ID, &rp.UpMid, &rp.FansCount, &rp.FansCountIncreaseMonth, &rp.ArchiveCount, &rp.PlayCountAccumulate, &rp.PlayCountAverage, &rp.ActiveTid, &rp.LastArchiveTime, &rp.Ctime, &rp.Mtime); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
return
}
rps = append(rps, rp)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,73 @@
package dao
import (
"context"
"testing"
"go-common/app/job/main/mcn/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAddMcnUpRecommend(t *testing.T) {
convey.Convey("AddMcnUpRecommend", t, func(ctx convey.C) {
var (
c = context.Background()
arg = &model.McnUpRecommendPool{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.AddMcnUpRecommend(c, arg)
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 TestDaoDelMcnUpRecommendPool(t *testing.T) {
convey.Convey("DelMcnUpRecommendPool", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.DelMcnUpRecommendPool(c)
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 TestDaoDelMcnUpRecommendSource(t *testing.T) {
convey.Convey("DelMcnUpRecommendSource", 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.DelMcnUpRecommendSource(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 TestDaoMcnUpRecommendSources(t *testing.T) {
convey.Convey("McnUpRecommendSources", t, func(ctx convey.C) {
var (
c = context.Background()
limit = 100
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rps, err := d.McnUpRecommendSources(c, limit)
ctx.Convey("Then err should be nil.rps should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(rps), convey.ShouldBeGreaterThanOrEqualTo, 0)
})
})
})
}

View File

@@ -0,0 +1,33 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"base_model.go",
"mcn.go",
"recommend.go",
],
importpath = "go-common/app/job/main/mcn/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//library/time:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,8 @@
package model
// const .
const (
TimeFormatSec = "2006-01-02 15:04:05"
TimeFormatDay = "2006-01-02"
ThirtyDayUnixTime = 30 * 24 * 60 * 60
)

View File

@@ -0,0 +1,155 @@
package model
import (
xtime "go-common/library/time"
)
// EmailState .
type EmailState int8
// const .
const (
EmailStateSendNone EmailState = 1
EmailStateSendSucc EmailState = 2
)
// MCNSignState .
type MCNSignState int8
// const .
const (
// MCNSignStateNoApply 未申请
MCNSignStateNoApply MCNSignState = 0
// MCNSignStateOnReview 待审核
MCNSignStateOnReview MCNSignState = 1
// MCNSignStateOnReject 已驳回
MCNSignStateOnReject MCNSignState = 2
// MCNSignStateOnSign 已签约
MCNSignStateOnSign MCNSignState = 10
// MCNSignStateOnCooling 冷却中
MCNSignStateOnCooling MCNSignState = 11
// MCNSignStateOnExpire 已到期
MCNSignStateOnExpire MCNSignState = 12
// MCNSignStateOnBlock 已封禁
MCNSignStateOnBlock MCNSignState = 13
// MCNSignStateOnClear 已清退
MCNSignStateOnClear MCNSignState = 14
// MCNSignStateOnPreOpen 待开启
MCNSignStateOnPreOpen MCNSignState = 15
// MCNSignStateOnDelete 已移除
MCNSignStateOnDelete MCNSignState = 100
)
// NotDealState .
func (mss MCNSignState) NotDealState() bool {
if mss == MCNSignStateNoApply || mss == MCNSignStateOnReview || mss == MCNSignStateOnReject ||
mss == MCNSignStateOnBlock || mss == MCNSignStateOnClear || mss == MCNSignStateOnDelete ||
mss == MCNSignStateOnExpire {
return true
}
return false
}
// MCNSignInfo .
type MCNSignInfo struct {
SignID int64 `json:"sign_id"`
McnMid int64 `json:"mcn_mid"`
McnName string `json:"mcn_name"`
CompanyName string `json:"company_name"`
CompanyLicenseID string `json:"company_license_id"`
CompanyLicenseLink string `json:"company_license_link"`
ContractLink string `json:"contract_link"`
ContactName string `json:"contact_name"`
ContactTitle string `json:"contact_title"`
ContactPhone string `json:"contact_phone"`
ContactIdcard string `json:"contact_idcard"`
BeginDate xtime.Time `json:"begin_date"`
EndDate xtime.Time `json:"end_date"`
PayExpireState int8 `json:"pay_expire_state"`
State MCNSignState `json:"state"`
RejectTime xtime.Time `json:"reject_time"`
RejectReason string `json:"reject_reason"`
Ctime xtime.Time `json:"ctime"`
Mtime xtime.Time `json:"mtime"`
}
// SignPayInfo .
type SignPayInfo struct {
SignPayID int64 `json:"sign_pay_id"`
McnMid int64 `json:"mcn_mid"`
McnName string `json:"mcn_name"`
SignID int64 `json:"sign_id"`
State int8 `json:"state"`
DueDate xtime.Time `json:"due_date"`
PayValue int64 `json:"pay_value"` // thousand bit
}
// GetDueDate used for template
func (s *SignPayInfo) GetDueDate() string {
return s.DueDate.Time().Format(TimeFormatDay)
}
// GetPayValue for template
func (s *SignPayInfo) GetPayValue() float64 {
return float64(s.PayValue) / 1000.0
}
// MCNUPState .
type MCNUPState int8
// const .
const (
// MCNUPStateNoAuthorize 未授权
MCNUPStateNoAuthorize MCNUPState = 0
// MCNUPStateOnRefuse 已拒绝
MCNUPStateOnRefuse MCNUPState = 1
// MCNUPStateOnReview 待审核
MCNUPStateOnReview MCNUPState = 2
// MCNSignStateOnReject 已驳回
MCNUPStateOnReject MCNUPState = 3
// MCNUPStateOnSign 已签约
MCNUPStateOnSign MCNUPState = 10
// MCNUPStateOnFreeze 已冻结
MCNUPStateOnFreeze MCNUPState = 11
// MCNUPStateOnExpire 已到期
MCNUPStateOnExpire MCNUPState = 12
// MCNUPStateOnBlock 已封禁
MCNUPStateOnBlock MCNUPState = 13
// MCNUPStateOnClear 已解约
MCNUPStateOnClear MCNUPState = 14
// MCNUPStateOnPreOpen 待开启
MCNUPStateOnPreOpen MCNUPState = 15
// MCNUPStateOnDelete 已删除
MCNUPStateOnDelete MCNUPState = 100
)
// MCNUPInfo .
type MCNUPInfo struct {
SignUpID int64 `json:"sign_up_id"`
SignID int64 `json:"sign_id"`
McnMid int64 `json:"mcn_mid"`
UpMid int64 `json:"up_mid"`
BeginDate xtime.Time `json:"begin_date"`
EndDate xtime.Time `json:"end_date"`
ContractLink string `json:"contract_link"`
UpAuthLink string `json:"up_auth_link"`
RejectTime xtime.Time `json:"reject_time"`
RejectReason string `json:"reject_reason"`
State MCNUPState `json:"state"`
StateChangeTime xtime.Time `json:"state_change_time"`
Ctime xtime.Time `json:"ctime"`
Mtime xtime.Time `json:"mtime"`
UpName string `json:"up_name"`
FansCount int64 `json:"fans_count"`
ActiveTid int64 `json:"active_tid"`
}
// NotDealState .
func (mus MCNUPState) NotDealState() bool {
if mus == MCNUPStateNoAuthorize || mus == MCNUPStateOnRefuse || mus == MCNUPStateOnReview ||
mus == MCNUPStateOnReject || mus == MCNUPStateOnFreeze || mus == MCNUPStateOnExpire ||
mus == MCNUPStateOnBlock || mus == MCNUPStateOnClear || mus == MCNUPStateOnDelete {
return true
}
return false
}

View File

@@ -0,0 +1,52 @@
package model
import xtime "go-common/library/time"
// MCNUPRecommendSource .
type MCNUPRecommendSource int8
// const .
const (
// MCNUPRecommendSourceUnKnown 未知来源
MCNUPRecommendSourceUnKnown MCNUPRecommendSource = iota
// MCNUPRecommendSourceAuto 自动添加(大数据)
MCNUPRecommendSourceAuto
// MCNUPRecommendStateManual 手动添加
MCNUPRecommendStateManual
)
// MCNUPRecommendState .
type MCNUPRecommendState int8
// const .
const (
// MCNUPRecommendStateUnKnown 未知状态
MCNUPRecommendStateUnKnown MCNUPRecommendState = 0
// MCNUPRecommendStateOff 未推荐
MCNUPRecommendStateOff MCNUPRecommendState = 1
// MCNUPRecommendStateOn 推荐中
MCNUPRecommendStateOn MCNUPRecommendState = 2
// MCNUPRecommendStateBan 禁止推荐
MCNUPRecommendStateBan MCNUPRecommendState = 3
// MCNUPRecommendStateDel 移除中
MCNUPRecommendStateDel MCNUPRecommendState = 100
)
// McnUpRecommendPool .
type McnUpRecommendPool struct {
ID int64 `json:"id"`
UpMid int64 `json:"up_mid"`
UpName string `json:"up_name"`
FansCount int64 `json:"fans_count"`
FansCountIncreaseMonth int64 `json:"fans_count_increase_month"`
ArchiveCount int64 `json:"archive_count"`
PlayCountAccumulate int64 `json:"play_count_accumulate"`
PlayCountAverage int64 `json:"play_count_average"`
ActiveTid int16 `json:"active_tid"`
LastArchiveTime xtime.Time `json:"last_archive_time"`
State MCNUPRecommendState `json:"state"`
Source MCNUPRecommendSource `json:"source"`
GenerateTime xtime.Time `json:"generate_time"`
Ctime xtime.Time `json:"ctime"`
Mtime xtime.Time `json:"mtime"`
}

View File

@@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"test.go",
],
importpath = "go-common/app/job/main/mcn/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/mcn/conf:go_default_library",
"//app/job/main/mcn/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster: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 http
import (
"net/http"
"go-common/app/job/main/mcn/conf"
"go-common/app/job/main/mcn/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
srv *service.Service
)
// Init init
func Init(c *conf.Config) {
srv = service.New(c)
engine := bm.DefaultServer(c.BM)
route(engine)
if err := engine.Start(); err != nil {
log.Error("bm Start error(%v)", err)
panic(err)
}
}
func route(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/job/mcn") // authSvc.Verify() manager use
{
g.GET("/run", run)
}
}
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}

View File

@@ -0,0 +1,16 @@
package http
import (
bm "go-common/library/net/http/blademaster"
)
func run(c *bm.Context) {
srv.UpMcnSignStateCron()
srv.UpMcnUpStateCron()
srv.UpExpirePayCron()
//srv.UpMcnDataSummaryCron()
srv.McnRecommendCron()
srv.DealFailRecommendCron()
srv.CheckDateDueCron()
c.JSON("job is run", nil)
}

View File

@@ -0,0 +1,66 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"email.go",
"mcn.go",
"recommend.go",
"service.go",
"summary.go",
"up.go",
],
importpath = "go-common/app/job/main/mcn/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/mcn/conf:go_default_library",
"//app/job/main/mcn/dao:go_default_library",
"//app/job/main/mcn/model:go_default_library",
"//app/service/main/account/api:go_default_library",
"//library/log:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/robfig/cron: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"],
)
go_test(
name = "go_default_test",
srcs = [
"mcn_test.go",
"recommend_test.go",
"service_test.go",
"summary_test.go",
"up_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/mcn/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,290 @@
package service
import (
"bytes"
"context"
"fmt"
"html/template"
"time"
"go-common/app/job/main/mcn/conf"
"go-common/app/job/main/mcn/model"
accgrpc "go-common/app/service/main/account/api"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
// var .
var (
// ErrNoAdminName no admin name
ErrNoAdminName = errors.New("no admin name")
tmplSignDueTitle *template.Template
tmplSignDueContent *template.Template
tmplPayDueTitle *template.Template
tmplPayDueContent *template.Template
)
// use for template function call
var funcHelper = template.FuncMap{
"Now": time.Now,
}
func (s *Service) initEmailTemplate() (err error) {
if conf.Conf.MailTemplateConf.SignTmplTitle == "" ||
conf.Conf.MailTemplateConf.SignTmplContent == "" ||
conf.Conf.MailTemplateConf.PayTmplTitle == "" ||
conf.Conf.MailTemplateConf.PayTmplContent == "" {
err = fmt.Errorf(`mail template conf is invalid, check mail-template.toml file, make sure all the following has value:
TaskTmplContent
TaskTmplTitle
PayTmplContent
PayTmplTitle`)
return
}
tmplSignDueTitle, err = template.New("signTitle").Funcs(funcHelper).Parse(conf.Conf.MailTemplateConf.SignTmplTitle)
if err != nil {
log.Error("parse template fail, err=%v", err)
return
}
tmplSignDueContent, err = template.New("signContent").Funcs(funcHelper).Parse(conf.Conf.MailTemplateConf.SignTmplContent)
if err != nil {
log.Error("parse template fail, err=%v", err)
return
}
tmplPayDueTitle, err = template.New("payTitle").Funcs(funcHelper).Parse(conf.Conf.MailTemplateConf.PayTmplTitle)
if err != nil {
log.Error("parse template fail, err=%v", err)
return
}
tmplPayDueContent, err = template.New("payContent").Funcs(funcHelper).Parse(conf.Conf.MailTemplateConf.PayTmplContent)
if err != nil {
log.Error("parse template fail, err=%v", err)
return
}
return
}
// CheckDateDueCron .
func (s *Service) CheckDateDueCron() {
log.Info("start run CheckDateDueJob, date=%s", time.Now().Format(model.TimeFormatSec))
s.checkSignUpDue()
log.Info("finish run CheckDateDueJob, date=%s", time.Now().Format(model.TimeFormatSec))
}
type stateFunc func(context.Context, []int64) (int64, error)
type emailData struct {
IDs []int64
AdminName []string
Data interface{}
UpStateFunc stateFunc
Title, Content *template.Template
}
func (e *emailData) addEmailDatas(es *[]*emailData) {
*es = append(*es, e)
}
// buildEmail .
func buildEmail(ids []int64, data interface{}, title, content *template.Template, upStateFunc stateFunc, adminName ...string) *emailData {
return &emailData{
IDs: ids,
Data: data,
Title: title,
Content: content,
UpStateFunc: upStateFunc,
AdminName: adminName,
}
}
type dueData struct {
Signs []*model.MCNSignInfo
Pays []*model.SignPayInfo
Sids, Pids []int64
}
func (d *dueData) addSign(sign *model.MCNSignInfo) {
d.Signs = append(d.Signs, sign)
d.Sids = append(d.Sids, sign.SignID)
}
func (d *dueData) addPay(pay *model.SignPayInfo) {
d.Pays = append(d.Pays, pay)
d.Pids = append(d.Pids, pay.SignPayID)
}
func (d *dueData) addName(infoMap map[int64]*accgrpc.Info) {
for _, v := range d.Signs {
v.McnName = getName(infoMap, v.McnMid)
}
for _, v := range d.Pays {
v.McnName = getName(infoMap, v.McnMid)
}
}
// func getOrCreate(dataMap map[string]*dueData, key string) *dueData {
// var data, ok = dataMap[key]
// if !ok {
// data = &dueData{}
// dataMap[key] = data
// }
// return data
// }
func getName(infoMap map[int64]*accgrpc.Info, mid int64) string {
if info, ok := infoMap[mid]; ok {
return info.Name
}
return ""
}
func (s *Service) checkSignUpDue() {
var (
mids []int64
emailDatas []*emailData
data = &dueData{}
c = context.Background()
infoMap map[int64]*accgrpc.Info
)
// 30天内到期 sign
listDue, err := s.dao.McnSignDues(c)
if err != nil {
log.Error("s.dao.McnSignDues error(%+v)", err)
return
}
for _, v := range listDue {
mids = append(mids, v.McnMid)
data.addSign(v)
}
// 7天内到期的pay
listPayDue, err := s.dao.McnSignPayDues(c)
if err != nil {
log.Error("s.dao.McnSignPayDues error(%+v)", err)
return
}
for _, v := range listPayDue {
mids = append(mids, v.McnMid)
data.addPay(v)
}
mids = uniqNoEmpty(mids)
infosReply, err := s.accGRPC.Infos3(c, &accgrpc.MidsReq{Mids: mids})
if err != nil {
log.Error("s.accGRPC.Infos3(%s) error(%+v)", xstr.JoinInts(mids), err)
err = nil
} else {
infoMap = infosReply.Infos
}
emailDatas = make([]*emailData, 0)
data.addName(infoMap)
buildEmail(data.Sids, data.Signs, tmplSignDueTitle, tmplSignDueContent, s.dao.UpMcnSignEmailState, conf.Conf.MailConf.DueAuthorityGroups...).addEmailDatas(&emailDatas)
buildEmail(data.Pids, data.Pays, tmplPayDueTitle, tmplPayDueContent, s.dao.UpMcnSignPayEmailState, conf.Conf.MailConf.DueAuthorityGroups...).addEmailDatas(&emailDatas)
for _, e := range emailDatas {
s.doSendEmailFunc(c, e)
}
}
func (s *Service) doSendEmailFunc(c context.Context, e *emailData) {
s.worker.Do(c, func(c context.Context) {
if len(e.IDs) == 0 {
log.Warn("not need to update")
return
}
var err error
if err = s.sendMailWithTemplate(e.Data, e.Title, e.Content, e.AdminName...); err != nil {
log.Error("s.sendMailWithTemplate(%+v,%+v,%+v,%+v) error(%+v)", e.Data, e.Title, e.Content, e.AdminName, err)
return
}
if _, err = e.UpStateFunc(c, e.IDs); err != nil {
log.Error("upfunc(%+v,%s) error(%+v)", e.UpStateFunc, xstr.JoinInts(e.IDs), err)
return
}
log.Info("func(%s) update succ", xstr.JoinInts(e.IDs))
})
}
// data, data to generate email content
// contentTmpl, template to generate email content
// adminname, slice for all admin name
//
func (s *Service) sendMailWithTemplate(data interface{}, subjectTmpl, contentTmpl *template.Template, adminName ...string) (err error) {
if contentTmpl == nil {
err = fmt.Errorf("template for email is nil, data=%+v", data)
log.Error("%s", err)
return
}
var contentBuf = bytes.NewBuffer(nil)
err = contentTmpl.Execute(contentBuf, data)
if err != nil {
log.Error("template fail to execute, err=%v", err)
return
}
var subjectBuf = bytes.NewBuffer(nil)
err = subjectTmpl.Execute(subjectBuf, data)
if err != nil {
log.Error("template fail to execute, err=%v", err)
return
}
var addrs []string
for _, v := range adminName {
if v == "" {
log.Warn("admin name is empty")
continue
}
addrs = append(addrs, v)
}
if len(addrs) == 0 {
log.Error("admin name is empty, cannot send email, data=%+v", data)
err = ErrNoAdminName
return
}
if err = s.dao.SendMail(contentBuf.String(), subjectBuf.String(), addrs); err != nil {
log.Error("s.dao.SendMail(%s,%s,%+v) error(%+v)", contentBuf.String(), subjectBuf.String(), addrs, err)
return
}
log.Info("email send succ, sub=%s, admin=%s", subjectBuf.String(), adminName)
return
}
func chain(ids ...[]int64) []int64 {
res := make([]int64, 0, len(ids))
for _, l := range ids {
res = append(res, l...)
}
return res
}
// func uniq(ids ...[]int64) []int64 {
// hm := make(map[int64]struct{})
// for _, i := range chain(ids...) {
// hm[i] = struct{}{}
// }
// res := make([]int64, 0, len(ids))
// for i := range hm {
// res = append(res, i)
// }
// return res
// }
func uniqNoEmpty(ids ...[]int64) []int64 {
hm := make(map[int64]struct{})
for _, i := range chain(ids...) {
hm[i] = struct{}{}
}
res := make([]int64, 0, len(ids))
for i := range hm {
if i > 0 {
res = append(res, i)
}
}
return res
}

View File

@@ -0,0 +1,96 @@
package service
import (
"context"
"time"
"go-common/app/job/main/mcn/model"
"go-common/library/log"
"github.com/pkg/errors"
)
// UpMcnSignStateCron .
func (s *Service) UpMcnSignStateCron() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("recover panic error(%+v)", r)
}
}()
var (
err error
c = context.TODO()
now = time.Now()
nowDate = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix()
mss []*model.MCNSignInfo
)
if mss, err = s.dao.McnSigns(c); err != nil {
log.Error("s.dao.McnSigns error(%+v)", err)
return
}
if len(mss) == 0 {
log.Warn("mcn sign data is empty!")
return
}
for _, v := range mss {
var state int8
switch {
case v.State.NotDealState():
continue
case nowDate > v.EndDate.Time().Unix() && nowDate-v.EndDate.Time().Unix() <= model.ThirtyDayUnixTime && v.State != model.MCNSignStateOnCooling:
state = int8(model.MCNSignStateOnCooling)
case nowDate > v.EndDate.Time().Unix() && nowDate-v.EndDate.Time().Unix() > model.ThirtyDayUnixTime:
state = int8(model.MCNSignStateOnExpire)
case nowDate < v.BeginDate.Time().Unix() && v.State != model.MCNSignStateOnPreOpen:
state = int8(model.MCNSignStateOnPreOpen)
case v.BeginDate.Time().Unix() <= nowDate && nowDate <= v.EndDate.Time().Unix() && v.State != model.MCNSignStateOnSign && v.State == model.MCNSignStateOnPreOpen:
state = int8(model.MCNSignStateOnSign)
default:
continue
}
if _, err = s.dao.UpMcnSignStateOP(c, v.SignID, state); err != nil {
log.Error("s.dao.UpMcnSignStateOP(%d,%d) error(%+v)", v.SignID, state, err)
continue
}
if err = s.dao.DelMcnSignCache(c, v.McnMid); err != nil {
log.Error("s.dao.DelMcnSignCache(%d) error(%+v)", v.McnMid, err)
continue
}
log.Info("signID(%d) change old state(%d) to new state(%d)", v.SignID, v.State, state)
}
}
// UpExpirePayCron .
func (s *Service) UpExpirePayCron() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("recover panic error(%+v)", r)
}
}()
var (
err error
c = context.TODO()
sps []*model.SignPayInfo
)
if sps, err = s.dao.McnSignPayWarns(c); err != nil {
log.Error("s.dao.McnSignPayWarns error(%+v)", err)
return
}
if len(sps) == 0 {
log.Warn("mcn sign pay date is empty!")
return
}
ms := make(map[int64]struct{})
for _, v := range sps {
ms[v.SignID] = struct{}{}
}
for signID := range ms {
if _, err = s.dao.UpMcnSignPayExpOP(c, signID); err != nil {
log.Error("s.dao.UpMcnSignPayExpOP(%d) error(%+v)", signID, err)
continue
}
log.Info("sign_id(%d) change pay data warn state to 2", signID)
}
}

View File

@@ -0,0 +1,27 @@
package service
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestServiceUpMcnSignStateCron(t *testing.T) {
convey.Convey("UpMcnSignStateCron", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
s.UpMcnSignStateCron()
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestServiceUpExpirePayCron(t *testing.T) {
convey.Convey("UpExpirePayCron", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
s.UpExpirePayCron()
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}

View File

@@ -0,0 +1,67 @@
package service
import (
"context"
"go-common/app/job/main/mcn/model"
"go-common/library/log"
"github.com/pkg/errors"
)
// McnRecommendCron .
func (s *Service) McnRecommendCron() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("recover panic error(%+v)", r)
}
}()
var (
err error
limit = 100
c = context.TODO()
rps []*model.McnUpRecommendPool
)
for {
if rps, err = s.dao.McnUpRecommendSources(c, limit); err != nil {
log.Error("s.dao.McnUpRecommendSources(%d) error(%+v)", limit, err)
return
}
if len(rps) == 0 {
log.Warn("big data recommend up data is empty!")
return
}
for _, v := range rps {
rp := new(model.McnUpRecommendPool)
*rp = *v
rp.GenerateTime = v.Mtime
if _, err = s.dao.AddMcnUpRecommend(c, rp); err != nil {
log.Error("s.dao.AddMcnUpRecommend(%+v) error(%+v)", rp, err)
continue
}
if _, err = s.dao.DelMcnUpRecommendSource(c, v.ID); err != nil {
log.Error("s.dao.DelMcnUpRecommendSource(%d) error(%+v)", v.ID, err)
continue
}
log.Info("source id(%d) sync to recommend poll(%+v)", v.ID, rp)
}
}
}
// DealFailRecommendCron .
func (s *Service) DealFailRecommendCron() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("recover panic error(%+v)", r)
}
}()
var (
err error
c = context.TODO()
)
if _, err = s.dao.DelMcnUpRecommendPool(c); err != nil {
log.Error("s.dao.DelMcnUpRecommendPool error(%+v)", err)
}
}

View File

@@ -0,0 +1,27 @@
package service
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestServiceMcnRecommendCron(t *testing.T) {
convey.Convey("McnRecommendCron", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
s.McnRecommendCron()
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestServiceDealFailRecommendCron(t *testing.T) {
convey.Convey("DealFailRecommendCron", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
s.DealFailRecommendCron()
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}

View File

@@ -0,0 +1,60 @@
package service
import (
"context"
"runtime"
"go-common/app/job/main/mcn/conf"
"go-common/app/job/main/mcn/dao"
accgrpc "go-common/app/service/main/account/api"
"go-common/library/sync/pipeline/fanout"
"github.com/pkg/errors"
"github.com/robfig/cron"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
// rpc
accGRPC accgrpc.AccountClient
worker *fanout.Fanout
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
worker: fanout.New("cache", fanout.Worker(runtime.NumCPU()), fanout.Buffer(1024)),
}
var err error
if s.accGRPC, err = accgrpc.NewClient(c.GRPCClient.Account); err != nil {
panic(errors.WithMessage(err, "Failed to dial account service"))
}
if err := s.initEmailTemplate(); err != nil {
panic(err)
}
t := cron.New()
t.AddFunc(c.Property.UpMcnSignStateCron, s.UpMcnSignStateCron)
t.AddFunc(c.Property.UpMcnUpStateCron, s.UpMcnUpStateCron)
t.AddFunc(c.Property.UpExpirePayCron, s.UpExpirePayCron)
//t.AddFunc(c.Property.UpMcnDataSummaryCron, s.UpMcnDataSummaryCron)
t.AddFunc(c.Property.McnRecommendCron, s.McnRecommendCron)
t.AddFunc(c.Property.DealFailRecommendCron, s.DealFailRecommendCron)
t.AddFunc(c.Property.CheckMcnSignUpDueCron, s.CheckDateDueCron)
t.Start()
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
s.worker.Close()
}

View File

@@ -0,0 +1,24 @@
package service
import (
"flag"
"os"
"testing"
"go-common/app/job/main/mcn/conf"
)
var (
s *Service
)
func TestMain(m *testing.M) {
flag.Set("conf", "../cmd/mcn-job-test.toml")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
m.Run()
os.Exit(m.Run())
}

View File

@@ -0,0 +1,77 @@
package service
import (
"context"
"time"
"go-common/library/log"
xtime "go-common/library/time"
"go-common/library/xstr"
"github.com/pkg/errors"
)
// UpMcnDataSummaryCron .
func (s *Service) UpMcnDataSummaryCron() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("recover panic error(%+v)", r)
}
}()
var (
err error
sids []int64
msid map[int64]int64
mmc map[int64]int64
mup map[int64][]int64
c = context.TODO()
)
if msid, sids, err = s.dao.McnSignMids(c); err != nil {
log.Error("s.dao.McnSignMids error(%+v)", err)
return
}
if len(sids) == 0 {
log.Warn("mcn sign data summary empty!")
return
}
if mmc, err = s.dao.McnUPCount(c, sids); err != nil {
log.Error("s.dao.McnUPCount(%s) error(%+v)", xstr.JoinInts(sids), err)
return
}
if mup, err = s.dao.McnUPMids(c, sids); err != nil {
log.Error("s.dao.McnUPMids(%s) error(%+v)", xstr.JoinInts(sids), err)
return
}
for sid, smid := range msid {
var (
upOK, upMidOK bool
upNums int64
upMids []int64
totalFans int64
now = time.Now()
gDate = time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local)
)
if upNums, upOK = mmc[sid]; !upOK {
upNums = 0
}
if upMids, upMidOK = mup[sid]; upMidOK {
if len(upMids) == 0 {
totalFans = 0
} else {
if totalFans, err = s.dao.CrmUpMidsSum(c, upMids); err != nil {
log.Error("s.dao.CrmUpMidsSum(%s) error(%+v)", xstr.JoinInts(upMids), err)
err = nil
totalFans = 0
}
}
} else {
totalFans = 0
}
if err = s.dao.AddMcnDataSummary(c, smid, sid, upNums, totalFans, xtime.Time(gDate.Unix())); err != nil {
log.Error("s.dao.UpMcnUpStateOP(%d,%d,%d,%d,%+v) error(%+v)", smid, sid, upNums, totalFans, xtime.Time(gDate.Unix()), err)
continue
}
log.Info("mcnMid(%d) signID(%d) upNum(%d) totalFans(%d) date(%+v) add data summary table", smid, sid, upNums, totalFans, xtime.Time(gDate.Unix()))
}
}

View File

@@ -0,0 +1,17 @@
package service
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestServiceUpMcnDataSummaryCron(t *testing.T) {
convey.Convey("UpMcnDataSummaryCron", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
s.UpMcnDataSummaryCron()
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}

View File

@@ -0,0 +1,60 @@
package service
import (
"context"
"time"
"go-common/app/job/main/mcn/model"
"go-common/library/log"
"github.com/pkg/errors"
)
// UpMcnUpStateCron .
func (s *Service) UpMcnUpStateCron() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("recover panic error(%+v)", r)
}
}()
var (
err error
page = 1
limit = 100
c = context.TODO()
now = time.Now()
nowDate = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix()
mus []*model.MCNUPInfo
)
for {
offset := int64((page - 1) * limit)
if mus, err = s.dao.McnUps(c, offset, int64(limit)); err != nil {
log.Error("s.dao.McnUps(%d,%d) error(%+v)", offset, limit, err)
return
}
if len(mus) == 0 {
log.Warn("mcn up data is empty!")
return
}
for _, v := range mus {
var state int8
switch {
case v.State.NotDealState():
continue
case v.BeginDate.Time().Unix() <= nowDate && nowDate <= v.EndDate.Time().Unix() && v.State != model.MCNUPStateOnSign && v.State == model.MCNUPStateOnPreOpen:
state = int8(model.MCNUPStateOnSign)
case nowDate > v.EndDate.Time().Unix() && v.State != model.MCNUPStateOnExpire:
state = int8(model.MCNUPStateOnExpire)
default:
continue
}
if _, err = s.dao.UpMcnUpStateOP(c, v.SignUpID, state); err != nil {
log.Error("s.dao.UpMcnUpStateOP(%d,%d) error(%+v)", v.SignUpID, state, err)
continue
}
log.Info("signUpID(%d) change old state(%d) to new state(%d)", v.SignUpID, v.State, state)
}
page++
}
}

View File

@@ -0,0 +1,17 @@
package service
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestServiceUpMcnUpStateCron(t *testing.T) {
convey.Convey("UpMcnUpStateCron", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
s.UpMcnUpStateCron()
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}