bilibili-backup/app/admin/main/growup/service/up_info.go
2019-04-22 02:59:20 +00:00

886 lines
21 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"bytes"
"context"
"fmt"
"strconv"
"strings"
"time"
"go-common/app/admin/main/growup/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
"go-common/library/xstr"
)
const (
_video = 0
_column = 2
_bgm = 3
_passTitle = "创作激励计划(%s)申请成功"
_rejectTitle = "创作激励计划(%s)申请未通过"
_passContent = "恭喜,您的创作激励计划(%s)申请已通过!"
_rejectContent = "您的创作激励计划(%s)申请被驳回,驳回原因:%s。如有任何疑问请参看帮助中心说明。"
)
func getUpTable(typ int) (table string, err error) {
switch typ {
case _video:
table = "up_info_video"
case _column:
table = "up_info_column"
case _bgm:
table = "up_info_bgm"
default:
err = fmt.Errorf("up type error")
}
return
}
func text(typ int, base string) (text string, err error) {
switch typ {
case _video:
text = fmt.Sprintf(base, "视频")
case _column:
text = fmt.Sprintf(base, "专栏")
case _bgm:
text = fmt.Sprintf(base, "素材")
default:
err = fmt.Errorf("up type error")
}
return
}
// AddUp add user to creative pgc不区分业务所有的都加入pgc
func (s *Service) AddUp(c context.Context, mid int64, accType int) (err error) {
id, err := s.dao.Blocked(c, mid)
if err != nil {
return
}
if id != 0 { // blocked == true
return ecode.GrowupDisabled
}
nickname, category, err := s.dao.CategoryInfo(c, mid)
if err != nil {
return
}
fans, oac, err := s.dao.Stat(c, mid)
if err != nil {
return
}
err = s.addUpVideo(c, mid, nickname, accType, category, fans, oac)
if err != nil {
log.Error("s.addUpVideo mid(%d), error(%v)", mid, err)
return
}
err = s.addUpColumn(c, mid, nickname, accType, category, fans)
if err != nil {
log.Error("s.addUpColumn mid(%d), error(%v)", mid, err)
}
err = s.addUpBgm(c, mid, nickname, accType, category, fans)
if err != nil {
log.Error("s.addUpBgm mid(%d), error(%v)", mid, err)
}
return
}
func (s *Service) addUpVideo(c context.Context, mid int64, nickname string, accType, category, fans, oac int) (err error) {
ups, err := s.dao.UpsVideoInfo(c, fmt.Sprintf("mid = %d and is_deleted = 0", mid))
if err != nil {
log.Error("s.dao.UpsInfo mid(%d), error(%v)", mid, err)
return
}
if len(ups) == 1 {
if ups[0].AccountType == accType {
return
}
}
up := &model.UpInfo{
MID: mid,
Nickname: nickname,
MainCategory: category,
Fans: fans,
AccountType: accType,
OriginalArchiveCount: oac,
}
if accType == 2 { // if account_type is pgc, sign_type update to first publish
up.SignType = 2
up.AccountState = 1
}
_, err = s.dao.InsertUpVideo(c, up)
return
}
func (s *Service) addUpColumn(c context.Context, mid int64, nickname string, accType, category, fans int) (err error) {
ups, err := s.dao.UpsColumnInfo(c, fmt.Sprintf("mid = %d and is_deleted = 0", mid))
if err != nil {
log.Error("s.dao.UpsColumnInfo mids(%d), error(%v)", mid, err)
return
}
if len(ups) == 1 {
if ups[0].AccountType == accType {
return
}
}
up := &model.UpInfo{
MID: mid,
Nickname: nickname,
MainCategory: category,
Fans: fans,
AccountType: accType,
}
if accType == 2 { // if account_type is pgc, sign_type update to first publish
up.SignType = 2
up.AccountState = 1
}
_, err = s.dao.InsertUpColumn(c, up)
return
}
func (s *Service) addUpBgm(c context.Context, mid int64, nickname string, accType, category, fans int) (err error) {
ups, err := s.dao.UpsBgmInfo(c, fmt.Sprintf("mid=%d AND is_deleted=0", mid))
if err != nil {
return
}
if len(ups) == 1 {
if ups[0].AccountType == accType {
return
}
}
count, err := s.dao.BGMCount(c, mid)
if err != nil {
return
}
up := &model.UpInfo{
MID: mid,
Nickname: nickname,
Fans: fans,
AccountType: accType,
BGMs: count,
}
if accType == 2 {
up.SignType = 2
up.AccountState = 1
}
_, err = s.dao.InsertBgmUpInfo(c, up)
return
}
func (s *Service) getBusinessType(c context.Context, mids []int64, state int) (business map[int64][]int, err error) {
business = make(map[int64][]int)
// video
video, err := s.dao.GetUpInfoByState(c, "up_info_video", mids, state)
if err != nil {
log.Error("s.dao.GetUpInfoSigned error(%v)", err)
return
}
// column
column, err := s.dao.GetUpInfoByState(c, "up_info_column", mids, state)
if err != nil {
log.Error("s.dao.GetUpInfoSigned error(%v)", err)
return
}
// bgm
bgm, err := s.dao.GetUpInfoByState(c, "up_info_bgm", mids, state)
if err != nil {
log.Error("s.dao.GetUpInfoSigned error(%v)", err)
return
}
for _, mid := range mids {
business[mid] = make([]int, 0)
if _, ok := video[mid]; ok {
business[mid] = append(business[mid], 0)
}
if _, ok := column[mid]; ok {
business[mid] = append(business[mid], 2)
}
if _, ok := bgm[mid]; ok {
business[mid] = append(business[mid], 3)
}
}
return
}
// QueryFromUpInfo query up-info in growup plan
func (s *Service) QueryFromUpInfo(c context.Context, busType int, accType int, states []int64, mid int64, category int, signType int, nickname string, lower int, upper int, from int, limit int, sort string) (ups []*model.UpInfo, total int, err error) {
table, err := getUpTable(busType)
if err != nil {
return
}
query := upsInfoStmt(accType, states, mid, category, signType, nickname, lower, upper)
total, err = s.dao.UpsCount(c, table, query)
if err != nil {
return
}
sb := sortBy(sort)
if len(sb) != 0 {
query += " " + sb
}
query += fmt.Sprintf(" LIMIT %d, %d", from, limit)
switch busType {
case _video:
ups, err = s.dao.UpsVideoInfo(c, query)
if err != nil {
log.Error("s.dao.UpsInfo mids(%+d), state(%d) error(%v)", mid, states, err)
return
}
case _column:
ups, err = s.dao.UpsColumnInfo(c, query)
if err != nil {
log.Error("s.dao.UpsColumnInfo mids(%+d), state(%d) error(%v)", mid, states, err)
return
}
case _bgm:
ups, err = s.dao.UpsBgmInfo(c, query)
if err != nil {
log.Error("s.dao.UpsBgmInfo mids(%+d), state(%d) error(%v)", mid, states, err)
return
}
}
if ups == nil {
ups = make([]*model.UpInfo, 0)
}
if len(ups) == 0 {
return
}
mids := make([]int64, 0)
for _, up := range ups {
mids = append(mids, up.MID)
}
signedType, err := s.getBusinessType(c, mids, 3)
if err != nil {
log.Error("s.getBusinessType error(%v)", err)
return
}
// credit scores
scores, err := s.dao.CreditScores(c, mids)
if err != nil {
return
}
for _, up := range ups {
up.SignedType = signedType[up.MID]
up.CreditScore = scores[up.MID]
}
if len(states) == 1 {
var other map[int64][]int
other, err = s.getBusinessType(c, mids, int(states[0]))
if err != nil {
log.Error("s.getBusinessType error(%v)", err)
return
}
for _, up := range ups {
up.OtherType = other[up.MID]
}
}
return
}
func sortBy(name string) (sort string) {
if len(name) == 0 {
return
}
if strings.HasPrefix(name, "-") {
name = strings.TrimPrefix(name, "-")
name += " DESC"
}
sort = " ORDER BY " + name
return
}
func upsInfoStmt(accountType int, states []int64, mid int64, category int, signType int, nickname string, lower, upper int) (query string) {
if accountType > 0 {
query += "account_type = " + strconv.Itoa(accountType)
query += " AND "
}
if len(states) > 0 {
query += fmt.Sprintf("account_state IN (%s)", xstr.JoinInts(states))
query += " AND "
}
if mid > 0 {
query += "mid = " + strconv.FormatInt(mid, 10)
query += " AND "
}
if category != 0 {
query += "category_id = " + strconv.Itoa(category)
query += " AND "
}
if signType > 0 {
query += "sign_type = " + strconv.Itoa(signType)
query += " AND "
}
if nickname != "" {
query += "nickname = " + "\"" + nickname + "\""
query += " AND "
}
query += "fans >= " + strconv.Itoa(lower)
query += " AND "
if upper > 0 {
query += "fans <=" + strconv.Itoa(upper)
query += " AND "
}
query += "is_deleted = 0"
return
}
// Reject update account state to 4(reject)
func (s *Service) Reject(c context.Context, typ int, mids []int64, reason string, days int) (err error) {
table, err := getUpTable(typ)
if err != nil {
return
}
now := time.Now().Unix()
_, err = s.dao.Reject(c, table, 4, reason, xtime.Time(now), xtime.Time(now+int64(86400*days)), mids)
if err != nil {
return
}
title, err := text(typ, _rejectTitle)
if err != nil {
return
}
var content string
switch typ {
case _video:
content = fmt.Sprintf(_rejectContent, "视频", reason)
case _column:
content = fmt.Sprintf(_rejectContent, "专栏", reason)
case _bgm:
content = fmt.Sprintf(_rejectContent, "素材", reason)
}
pushErr := s.msg.Send(c, "1_14_2", title, content, mids, now)
if pushErr != nil {
log.Error("reject push error(%v)", pushErr)
}
return
}
// Pass update account state to 3(signed) type 0.video 1.audio 2.column 3.bgm,
func (s *Service) Pass(c context.Context, mids []int64, typ int) (err error) {
if len(mids) == 0 {
return
}
table, err := getUpTable(typ)
if err != nil {
return
}
ms, err := s.dao.Pendings(c, mids, table)
if err != nil {
return
}
if len(ms) == 0 {
return
}
upM := make(map[int64]struct{})
for _, m := range ms {
upM[m] = struct{}{}
}
// check other two business
if typ != _video {
err = s.removeUnusualUps(c, "up_info_video", upM, ms)
if err != nil {
log.Error("s.removeUnusualUps error(%v)", err)
return
}
}
if typ != _column {
err = s.removeUnusualUps(c, "up_info_column", upM, ms)
if err != nil {
log.Error("s.removeUnusualUps error(%v)", err)
return
}
}
if typ != _bgm {
err = s.removeUnusualUps(c, "up_info_bgm", upM, ms)
if err != nil {
log.Error("s.removeUnusualUps error(%v)", err)
return
}
}
if len(upM) == 0 {
return
}
ms = make([]int64, 0)
for mid := range upM {
ms = append(ms, mid)
}
_, err = s.dao.Pass(c, table, 3, xtime.Time(time.Now().Unix()), ms)
if err != nil {
return
}
_, err = s.dao.InsertCreditScore(c, midValues(mids))
if err != nil {
return
}
title, err := text(typ, _passTitle)
if err != nil {
return
}
msg, err := text(typ, _passContent)
if err != nil {
return
}
pushErr := s.msg.Send(c, "1_14_1", title, msg, ms, time.Now().Unix())
if pushErr != nil {
log.Error("pass push error(%v)", pushErr)
}
// add creative task notify
s.msg.NotifyTask(c, mids)
return
}
func (s *Service) removeUnusualUps(c context.Context, table string, upM map[int64]struct{}, ms []int64) (err error) {
mids, err := s.dao.UnusualUps(c, ms, table)
if err != nil {
return
}
for _, mid := range mids {
if _, ok := upM[mid]; ok {
delete(upM, mid)
}
}
return
}
func midValues(mids []int64) (values string) {
var buf bytes.Buffer
for _, mid := range mids {
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(mid, 10))
buf.WriteString(")")
buf.WriteByte(',')
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
}
values = buf.String()
buf.Reset()
return
}
// Dismiss update account state to 6
func (s *Service) Dismiss(c context.Context, operator string, typ, oldState int, mid int64, reason string) (err error) {
var (
tx *sql.Tx
now = xtime.Time(time.Now().Unix())
current int
drows int64
crows int64
)
if tx, err = s.dao.BeginTran(c); err != nil {
return
}
if current, err = s.dao.CreditScore(c, mid); err != nil {
tx.Rollback()
return
}
// deduct credit score 10
var drows1, drows2, drows3 int64
if drows1, err = s.dao.TxDismiss(tx, "up_info_video", 6, oldState, reason, now, now, mid); err != nil {
tx.Rollback()
return
}
if drows2, err = s.dao.TxDismiss(tx, "up_info_column", 6, oldState, reason, now, now, mid); err != nil {
tx.Rollback()
return
}
if drows3, err = s.dao.TxDismiss(tx, "up_info_bgm", 6, oldState, reason, now, now, mid); err != nil {
tx.Rollback()
return
}
switch typ {
case _video:
drows = drows1
case _column:
drows = drows2
case _bgm:
drows = drows3
}
if crows, err = s.txInsertCreditRecord(tx, mid, operator, 6, 10, current-10); err != nil {
tx.Rollback()
return
}
if drows != crows {
tx.Rollback()
return
}
if typ == _video {
if _, err = s.dao.TxUpdateUpSpyState(tx, 6, mid); err != nil {
tx.Rollback()
return
}
if _, err = s.dao.DelCheatUp(c, mid); err != nil {
tx.Rollback()
return
}
}
_, err = s.dao.TxUpdateCreditScore(tx, mid, current-10)
if err != nil {
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
return
}
pushErr := s.msg.Send(c, "1_14_4", "您的创作激励计划参与资格已被取消", fmt.Sprintf(`您好,根据创作激励计划规则,您因%s已被永久取消参与创作激励计划的资格。如有任何疑问请联系客服。`, reason), []int64{mid}, time.Now().Unix())
if pushErr != nil {
log.Error("dismiss push error(%v)", pushErr)
}
return
}
func (s *Service) txInsertCreditRecord(tx *sql.Tx, mid int64, operator string, state, deducted, remaining int) (rows int64, err error) {
// insert to credit record
cr := &model.CreditRecord{
MID: mid,
OperateAt: xtime.Time(time.Now().Unix()),
Operator: operator,
Reason: state,
Deducted: deducted,
Remaining: remaining,
}
return s.dao.TxInsertCreditRecord(tx, cr)
}
// Forbid update account state to 7 and add a n days CD
func (s *Service) Forbid(c context.Context, operator string, typ, oldState int, mid int64, reason string, days, second int) (err error) {
var (
tx *sql.Tx
now = time.Now().Unix()
expiredIn = xtime.Time(now + int64(second))
current int
frows int64
crows int64
)
if tx, err = s.dao.BeginTran(c); err != nil {
return
}
if current, err = s.dao.CreditScore(c, mid); err != nil {
tx.Rollback()
return
}
var frows1, frows2, frows3 int64
// deduct credit score 5
if frows1, err = s.dao.TxForbid(tx, "up_info_video", 7, oldState, reason, xtime.Time(now), expiredIn, mid); err != nil {
tx.Rollback()
return
}
if frows2, err = s.dao.TxForbid(tx, "up_info_column", 7, oldState, reason, xtime.Time(now), expiredIn, mid); err != nil {
tx.Rollback()
return
}
if frows3, err = s.dao.TxForbid(tx, "up_info_bgm", 7, oldState, reason, xtime.Time(now), expiredIn, mid); err != nil {
tx.Rollback()
return
}
switch typ {
case _video:
frows = frows1
case _column:
frows = frows2
case _bgm:
frows = frows3
}
// insert credit record
if crows, err = s.txInsertCreditRecord(tx, mid, operator, 7, 5, current-5); err != nil {
tx.Rollback()
return
}
if frows != crows {
tx.Rollback()
return
}
if typ == _video {
// update up spy state
if _, err = s.dao.TxUpdateUpSpyState(tx, 7, mid); err != nil {
tx.Rollback()
return
}
// del up from cheat fans list
if _, err = s.dao.DelCheatUp(c, mid); err != nil {
tx.Rollback()
return
}
}
_, err = s.dao.TxUpdateCreditScore(tx, mid, current-5)
if err != nil {
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
return
}
pushErr := s.msg.Send(c, "1_14_3", "您已被暂停参加创作激励计划", fmt.Sprintf(`根据创作激励计划规则,您因为%s原因被停止参与计划%d天%d年%d月%d日恢复如有疑问请联系客服。`, reason, days, expiredIn.Time().Year(), expiredIn.Time().Month(), expiredIn.Time().Day()), []int64{mid}, time.Now().Unix())
if pushErr != nil {
log.Error("forbid push error(%v)", pushErr)
}
return
}
// Recovery update (video/column) account state to 3(signed)
func (s *Service) Recovery(c context.Context, mid int64) (err error) {
err = s.UpdateUpAccountState(c, "up_info_video", mid, 3)
if err != nil {
log.Error("s.UpdateUpAccountState(video) error(%v)", err)
return
}
err = s.UpdateUpAccountState(c, "up_info_column", mid, 3)
if err != nil {
log.Error("s.UpdateUpAccountState(column) error(%v)", err)
return
}
err = s.UpdateUpAccountState(c, "up_info_bgm", mid, 3)
if err != nil {
log.Error("s.UpdateUpAccountState(bgm) error(%v)", err)
}
return
}
// UpdateUpAccountState update video up account state
func (s *Service) UpdateUpAccountState(c context.Context, table string, mid int64, state int) (err error) {
_, err = s.dao.UpdateAccountState(c, table, state, mid)
return
}
// DeleteUp delete up from up_info (update is_deleted = 1)
func (s *Service) DeleteUp(c context.Context, mid int64) (err error) {
_, err = s.dao.DelUpInfo(c, "up_info_video", mid)
if err != nil {
return
}
_, err = s.dao.DelUpInfo(c, "up_info_column", mid)
if err != nil {
return
}
_, err = s.dao.DelUpInfo(c, "up_info_bgm", mid)
return
}
// Block add to blacklist
func (s *Service) Block(c context.Context, mid int64) (err error) {
nickname, categoryID, err := s.dao.CategoryInfo(c, mid)
if err != nil {
return
}
fans, oac, err := s.dao.Stat(c, mid)
if err != nil {
return
}
applyAt, err := s.dao.ApplyAt(c, mid)
if err != nil {
return
}
b := &model.Blocked{
MID: mid,
Nickname: nickname,
OriginalArchiveCount: oac,
MainCategory: categoryID,
Fans: fans,
ApplyAt: applyAt,
}
_, err = s.dao.InsertBlocked(c, b)
if err != nil {
return
}
// if up in table up_info_video, delete
_, err = s.dao.DelUpInfo(c, "up_info_video", mid)
if err != nil {
return
}
_, err = s.dao.DelUpInfo(c, "up_info_column", mid)
if err != nil {
return
}
_, err = s.dao.DelUpInfo(c, "up_info_bgm", mid)
return
}
// QueryFromBlocked query up-info in black list of growup plan
func (s *Service) QueryFromBlocked(c context.Context, mid int64, category int, nickname string, lower, upper, from, limit int, sort string) (ups []*model.Blocked, total int, err error) {
query := queryBlockStmt(mid, category, nickname, lower, upper)
total, err = s.dao.BlockCount(c, query)
if err != nil {
return
}
sb := sortBy(sort)
if len(sb) != 0 {
query += " " + sb
}
query += fmt.Sprintf(" LIMIT %d, %d", from, limit)
ups, err = s.dao.QueryFromBlocked(c, query)
if err != nil {
log.Error("s.dao.QueryFromBlocked error(%v)", err)
return
}
if ups == nil {
ups = make([]*model.Blocked, 0)
}
return
}
func queryBlockStmt(mid int64, categoryID int, nickname string, lower int, upper int) (query string) {
if mid > 0 {
query += "mid = " + strconv.FormatInt(mid, 10)
query += " AND "
}
if categoryID != 0 {
query += "category_id = " + strconv.Itoa(categoryID)
query += " AND "
}
if nickname != "" {
query += "nickname = " + "\"" + nickname + "\""
query += " AND "
}
query += "fans >= " + strconv.Itoa(lower)
query += " AND "
query += "is_deleted = 0"
if upper > 0 {
query += " AND "
query += "fans <=" + strconv.Itoa(upper)
}
return
}
// DeleteFromBlocked del blocked and recover up info of video
func (s *Service) DeleteFromBlocked(c context.Context, mid int64) (err error) {
_, err = s.dao.DelFromBlocked(c, mid)
if err != nil {
return
}
_, err = s.dao.RecUpInfo(c, "up_info_video", mid)
if err != nil {
return
}
_, err = s.dao.RecUpInfo(c, "up_info_column", mid)
if err != nil {
return
}
_, err = s.dao.RecUpInfo(c, "up_info_bgm", mid)
return
}
// DelUpAccount del mid from up_account
func (s *Service) DelUpAccount(c context.Context, mid int64) (err error) {
_, err = s.dao.DelUpAccount(c, mid)
return
}
// UpdateUpAccount update up_account
func (s *Service) UpdateUpAccount(c context.Context, mid int64, isDeleted int, withdrawDate string) (err error) {
_, err = s.dao.UpdateUpAccount(c, mid, isDeleted, withdrawDate)
return
}
// CreditRecords get credit records by mid
func (s *Service) CreditRecords(c context.Context, mid int64) (crs []*model.CreditRecord, err error) {
return s.dao.CreditRecords(c, mid)
}
// RecoverCreditScore recover credit score
func (s *Service) RecoverCreditScore(c context.Context, typ int, id, mid int64) (err error) {
var (
tx *sql.Tx
deducted int
drows int64
urows int64
)
if tx, err = s.dao.BeginTran(c); err != nil {
return
}
if deducted, err = s.dao.DeductedScore(c, id); err != nil {
tx.Rollback()
return
}
// del detucted record by id
if drows, err = s.dao.TxDelCreditRecord(tx, id); err != nil {
tx.Rollback()
return
}
// recover credit score
if urows, err = s.dao.TxRecoverCreditScore(tx, deducted, mid); err != nil {
return
}
if drows != urows {
tx.Rollback()
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
return
}
return
}
// ExportUps export ups by query
func (s *Service) ExportUps(c context.Context, busType, accType int, states []int64, mid int64, category int, signType int, nickname string, lower int, upper int, from int, limit int, sort string) (res []byte, err error) {
ups, _, err := s.QueryFromUpInfo(c, busType, accType, states, mid, category, signType, nickname, lower, upper, from, limit, sort)
if err != nil {
log.Error("s.QueryFromUpInfo error(%v)", err)
return
}
records := formatUpInfo(ups, states, busType)
res, err = FormatCSV(records)
if err != nil {
log.Error("FormatCSV error(%v)", err)
}
return
}
// UpState get up state
func (s *Service) UpState(c context.Context, mid int64, typ int) (data interface{}, err error) {
table, err := getUpTable(typ)
if err != nil {
return
}
state, err := s.dao.GetUpState(c, table, mid)
if err != nil {
return
}
data = map[string]interface{}{
"mid": mid,
"state": state,
}
return
}