bilibili-backup/app/admin/main/growup/service/income/av_breach.go

360 lines
10 KiB
Go
Raw Normal View History

2019-04-22 10:59:20 +08:00
package income
import (
"bytes"
"context"
"fmt"
"strconv"
"time"
upModel "go-common/app/admin/main/growup/model"
model "go-common/app/admin/main/growup/model/income"
"go-common/app/admin/main/growup/service"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
"go-common/library/xstr"
"golang.org/x/sync/errgroup"
)
// BreachList list
func (s *Service) BreachList(c context.Context, mids, aids []int64, typ int, fromTime, toTime int64, reason string, from, limit int) (breachs []*model.AvBreach, total int, err error) {
query := formatBreachQuery(mids, aids, typ, fromTime, toTime, reason)
total, err = s.dao.BreachCount(c, query)
if err != nil {
log.Error("s.dao.GetBreachCount error(%v)", err)
return
}
query = fmt.Sprintf("%s LIMIT %d,%d", query, from, limit)
breachs, err = s.dao.ListArchiveBreach(c, query)
if err != nil {
log.Error("s.dao.ListArchiveBreach error(%v)", err)
}
mids = make([]int64, 0, len(breachs))
for _, b := range breachs {
mids = append(mids, b.MID)
}
nickname, err := s.dao.ListUpInfo(c, mids)
for _, b := range breachs {
b.Nickname = nickname[b.MID]
}
return
}
// BreachStatis statis
func (s *Service) BreachStatis(c context.Context, mids, aids []int64, typ, groupType int, fromTime, toTime int64, reason string) (date interface{}, err error) {
from := getDateByGroup(groupType, time.Unix(fromTime, 0))
to := getDateByGroup(groupType, time.Unix(toTime, 0))
query := formatBreachQuery(mids, aids, typ, from.Unix(), to.Unix(), reason)
breachs, err := s.dao.ListArchiveBreach(c, query)
if err != nil {
log.Error("s.dao.ListArchiveBreach error(%v)", err)
return
}
date = breachStatis(breachs, from, to, groupType)
return
}
func breachStatis(breachs []*model.AvBreach, from, to time.Time, groupType int) interface{} {
dateIncome := make(map[string]int64)
dateUps := make(map[string]map[int64]struct{})
for _, breach := range breachs {
date := formatDateByGroup(breach.CDate.Time(), groupType)
if _, ok := dateIncome[date]; ok {
dateIncome[date] += breach.Money
} else {
dateIncome[date] = breach.Money
}
if _, ok := dateUps[date]; !ok {
dateUps[date] = make(map[int64]struct{})
}
dateUps[date][breach.MID] = struct{}{}
}
income, counts, xAxis := []string{}, []int{}, []string{}
// get result by date
to = to.AddDate(0, 0, 1)
for from.Before(to) {
dateStr := formatDateByGroup(from, groupType)
xAxis = append(xAxis, dateStr)
if val, ok := dateIncome[dateStr]; ok {
income = append(income, fmt.Sprintf("%.2f", float64(val)/float64(100)))
counts = append(counts, len(dateUps[dateStr]))
} else {
income = append(income, "0")
counts = append(counts, 0)
}
from = addDayByGroup(groupType, from)
}
return map[string]interface{}{
"counts": counts,
"incomes": income,
"xaxis": xAxis,
}
}
// ExportBreach export
func (s *Service) ExportBreach(c context.Context, mids, aids []int64, typ int, fromTime, toTime int64, reason string, from, limit int) (res []byte, err error) {
breachs, _, err := s.BreachList(c, mids, aids, typ, fromTime, toTime, reason, from, limit)
if err != nil {
log.Error("s.BreachList error(%v)", err)
return
}
records := formatBreach(breachs)
res, err = service.FormatCSV(records)
if err != nil {
log.Error("FormatCSV error(%v)")
}
return
}
func formatBreachQuery(mids, aids []int64, typ int, fromTime, toTime int64, reason string) (query string) {
query = fmt.Sprintf("cdate >= '%s' AND cdate <= '%s'", time.Unix(fromTime, 0).Format(_layout), time.Unix(toTime, 0).Format(_layout))
if typ != 4 {
query = fmt.Sprintf("%s AND ctype = %d", query, typ)
}
if len(mids) > 0 {
query = fmt.Sprintf("%s AND mid IN (%s)", query, xstr.JoinInts(mids))
}
if len(aids) > 0 {
query = fmt.Sprintf("%s AND av_id IN (%s)", query, xstr.JoinInts(aids))
}
if reason != "" {
query = fmt.Sprintf("%s AND reason = '%s'", query, reason)
}
return
}
// ArchiveBreach breach archive batch
func (s *Service) ArchiveBreach(c context.Context, typ int, aids []int64, mid int64, reason string, operator string) (err error) {
count, err := s.dao.BreachCount(c, fmt.Sprintf("av_id in (%s) AND cdate = '%s'", xstr.JoinInts(aids), time.Now().Format(_layout)))
if err != nil {
log.Error("s.dao.AvBreachCount error(%v)", err)
return
}
if count > 0 {
err = fmt.Errorf("有稿件已被扣除")
return
}
return s.avBreach(c, typ, aids, mid, reason, operator)
}
func assembleAvBreach(aids []int64, mid int64, ctype int, reason string, breach map[int64]int64, upload map[int64]string) (vals string) {
var buf bytes.Buffer
for _, aid := range aids {
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(aid, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(mid, 10))
buf.WriteByte(',')
buf.WriteString("'" + time.Now().Format(_layout) + "'")
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(breach[aid], 10))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(ctype))
buf.WriteByte(',')
buf.WriteString("\"" + reason + "\"")
buf.WriteByte(',')
buf.WriteString("'" + upload[aid] + "'")
buf.WriteString(")")
buf.WriteByte(',')
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
}
vals = buf.String()
buf.Reset()
return
}
// AvBreach av breach from av_income
func (s *Service) avBreach(c context.Context, ctype int, aids []int64, mid int64, reason string, operator string) (err error) {
archives, withdrawMonth, err := s.GetArchiveByUpAccount(c, ctype, aids, mid)
if err != nil {
log.Error("s.GetArchiveByUpAccount error(%v)", err)
return
}
if len(archives) == 0 {
return
}
preMonthBreach, thisMonthBreach, avBreach, avUpload := getBreachMoney(archives, withdrawMonth)
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran error(%v)", err)
return
}
var eg errgroup.Group
// insert av_breach
eg.Go(func() (err error) {
if _, err = s.dao.TxInsertAvBreach(tx, assembleAvBreach(aids, mid, ctype, reason, avBreach, avUpload)); err != nil {
log.Error("s.TxInsertAvBreach error(%v)", err)
tx.Rollback()
}
return
})
// update av breach pre state = 2
eg.Go(func() (err error) {
if _, err = s.dao.TxUpdateBreachPre(tx, aids, time.Now().Format(_layout)); err != nil {
log.Error("s.TxUpdateBreachPre error(%v)", err)
tx.Rollback()
}
return
})
// save av_black_list
eg.Go(func() (err error) {
if err = s.TxInsertAvBlacklist(c, tx, ctype, aids, mid, _avBreach, len(aids)); err != nil {
log.Error("s.InsertAvBlacklist error(%v)", err)
}
return
})
// update up_account
eg.Go(func() (err error) {
if err = s.TxUpAccountBreach(c, tx, mid, preMonthBreach, thisMonthBreach); err != nil {
log.Error("s.UpdateUpAccount error(%v)", err)
}
return
})
// update up credit score
eg.Go(func() (err error) {
if err = s.UpdateUpCredit(c, tx, ctype, mid, aids, operator); err != nil {
log.Error("s.UpdateUpCredit error(%v)", err)
}
return
})
eg.Go(func() (err error) {
if _, err = s.upDao.TxUpdateAvSpyState(tx, 1, aids); err != nil {
tx.Rollback()
log.Error("s.upDao.TxUpdateAvSpyState error(%v)", err)
}
return
})
if err = eg.Wait(); err != nil {
log.Error("run eg.Wait error(%v)", err)
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error")
return
}
var business string
switch ctype {
case _video:
business = "avid"
case _column:
business = "cv"
case _bgm:
business = "au"
}
for _, aid := range aids {
err = s.msg.Send(c, "1_14_5",
fmt.Sprintf("您的稿件 %s %d 违反创作激励计划规则。", business, aid),
fmt.Sprintf("您的稿件 %s %d 因为%s原因被取消参加创作激励计划资格已获得收入将被扣除。如有疑问请联系客服。", business, aid, reason),
[]int64{mid},
time.Now().Unix())
if err != nil {
log.Error("s.msg.Send error(%v)", err)
return
}
}
return
}
// UpdateUpCredit update up_info credit score
func (s *Service) UpdateUpCredit(c context.Context, tx *sql.Tx, ctype int, mid int64, aids []int64, operator string) (err error) {
score, err := s.upDao.CreditScore(c, mid)
if err != nil {
return
}
// insert credit_score_record
creditRecord := &upModel.CreditRecord{
MID: mid,
OperateAt: xtime.Time(time.Now().Unix()),
Operator: operator,
Reason: 9,
Deducted: 3 * len(aids),
Remaining: score - 3*len(aids),
}
r1, err := s.upDao.TxInsertCreditRecord(tx, creditRecord)
if err != nil {
tx.Rollback()
return
}
r2, err := s.upDao.TxUpdateCreditScore(tx, mid, score-3*len(aids))
if err != nil {
tx.Rollback()
return
}
if r1 != r2 {
tx.Rollback()
return
}
return
}
// GetArchiveByUpAccount get archive income by withdraw date
func (s *Service) GetArchiveByUpAccount(c context.Context, typ int, aids []int64, mid int64) (archives []*model.ArchiveIncome, withdrawMonth time.Month, err error) {
archives = make([]*model.ArchiveIncome, 0)
upAccount, err := s.dao.GetUpAccount(c, mid)
if err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("s.dao.GetUpAccount error(%v)", err)
return
}
withdrawDateStr := upAccount.WithdrawDateVersion + "-01"
withdrawDate, err := time.Parse(_layout, withdrawDateStr)
if err != nil {
log.Error("time.Parse error(%v)", err)
return
}
withdrawMonth = withdrawDate.AddDate(0, 1, 0).Month()
from, now := withdrawDate.AddDate(0, 1, 0).Format(_layout), time.Now().Format(_layout)
query := ""
switch typ {
case _video:
query = fmt.Sprintf("av_id in (%s)", xstr.JoinInts(aids))
case _column:
query = fmt.Sprintf("aid in (%s)", xstr.JoinInts(aids))
case _bgm:
query = fmt.Sprintf("sid in (%s)", xstr.JoinInts(aids))
}
archives, err = s.GetArchiveIncome(c, typ, query, from, now)
if err != nil {
log.Error("s.GetArchiveIncome error(%v)", err)
}
return
}
func getBreachMoney(archives []*model.ArchiveIncome, withdrawMonth time.Month) (int64, int64, map[int64]int64, map[int64]string) {
var preMonthBreach, thisMonthBreach int64 = 0, 0
avBreach := make(map[int64]int64)
avUpload := make(map[int64]string)
for _, arch := range archives {
if arch.Date.Time().Month() == withdrawMonth {
preMonthBreach += arch.Income
} else {
thisMonthBreach += arch.Income
}
avBreach[arch.AvID] += arch.Income
avUpload[arch.AvID] = arch.UploadTime.Time().Format(_layout)
}
return preMonthBreach, thisMonthBreach, avBreach, avUpload
}