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,93 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"authority_test.go",
"blacklist_test.go",
"cheat_test.go",
"notice_test.go",
"offlineactivity_test.go",
"service_test.go",
"tag_test.go",
"trade_test.go",
"up_info_test.go",
"upload_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/growup/conf:go_default_library",
"//app/admin/main/growup/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"activity.go",
"authority.go",
"auto.go",
"banner.go",
"blacklist.go",
"budgetstatistics.go",
"business.go",
"cheat.go",
"format.go",
"notice.go",
"offlineactivity.go",
"service.go",
"speical_award.go",
"tag.go",
"trade.go",
"up_info.go",
"upload.go",
"white.go",
],
importpath = "go-common/app/admin/main/growup/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/growup/conf:go_default_library",
"//app/admin/main/growup/dao:go_default_library",
"//app/admin/main/growup/dao/message:go_default_library",
"//app/admin/main/growup/dao/resource:go_default_library",
"//app/admin/main/growup/dao/shell:go_default_library",
"//app/admin/main/growup/model:go_default_library",
"//app/admin/main/growup/model/offlineactivity:go_default_library",
"//app/admin/main/growup/util: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/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/admin/main/growup/service/income:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,434 @@
package service
import (
"bytes"
"context"
"fmt"
"sort"
"strconv"
"time"
"go-common/app/admin/main/growup/model"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
const (
_activityNotStart = iota
_activityStart
_activityEnd
)
// AddActivity add creative activity
func (s *Service) AddActivity(c context.Context, ac *model.CActivity, creator string) (err error) {
ac.Creator = creator
_, err = s.dao.GetActivityByName(c, ac.Name)
if err == sql.ErrNoRows {
err = s.insertActivity(c, ac, "", true)
return
}
if err != nil {
log.Error("s.dao.GetActivityByName error(%v)", err)
return
}
err = fmt.Errorf("activity has exist")
return
}
func actQueyStmt(name, sort string) string {
query := ""
if name != "" {
query = fmt.Sprintf("WHERE name = '%s'", name)
}
if sort != "" {
query += " ORDER BY "
query += sort
}
return query
}
// ListActivity list activity by query
func (s *Service) ListActivity(c context.Context, name string, from, limit int, sort string) (acs []*model.CActivity, total int, err error) {
query := actQueyStmt(name, sort)
total, err = s.dao.ActivityCount(c, query)
if err != nil {
log.Error("s.dao.ActivityCount error(%v)", err)
return
}
acs, err = s.dao.GetActivities(c, query, from, limit)
if err != nil {
log.Error("s.dao.GetActivities error(%v)", err)
return
}
if len(acs) == 0 {
return
}
ids := make([]int64, len(acs))
for i := 0; i < len(acs); i++ {
ids[i] = acs[i].ID
}
bonus, err := s.getActivityBonus(c, ids)
if err != nil {
log.Error("s.getActivityBonus error(%v)", err)
return
}
now := xtime.Time(time.Now().Unix())
for _, ac := range acs {
if now < ac.SignUpStart {
ac.State = _activityNotStart
} else if now >= ac.SignUpStart && now <= ac.BonusTime {
ac.State = _activityStart
} else if now > ac.BonusTime {
ac.State = _activityEnd
}
ac.BonusMoney = bonus[ac.ID]
ac.Enrolment, err = s.dao.UpActivityStateCount(c, ac.ID, []int64{1, 2, 3})
if err != nil {
log.Error("s.dao.UpActivityStateCount error(%v)", err)
return
}
ac.WinNum, err = s.dao.UpActivityStateCount(c, ac.ID, []int64{2, 3})
if err != nil {
log.Error("s.dao.UpActivityStateCount error(%v)", err)
return
}
}
return
}
func checkSignUp(oldAc, newAc *model.CActivity) bool {
if oldAc.SignedStart != newAc.SignedStart ||
oldAc.SignedEnd != newAc.SignedEnd ||
oldAc.SignUp != newAc.SignUp ||
oldAc.SignUpStart != newAc.SignUpStart {
return false
}
return true
}
func checkWin(oldAc, newAc *model.CActivity) bool {
if oldAc.Object != newAc.Object ||
oldAc.UploadStart != newAc.UploadStart ||
oldAc.UploadEnd != newAc.UploadEnd ||
oldAc.WinType != newAc.WinType ||
oldAc.RequireItems != newAc.RequireItems ||
oldAc.RequireValue != newAc.RequireValue ||
oldAc.StatisticsStart != newAc.StatisticsStart {
return false
}
return true
}
func checkBonus(oldAc, newAc *model.CActivity) bool {
if oldAc.BonusType != newAc.BonusType ||
oldAc.BonusTime != newAc.BonusTime {
return false
}
return true
}
func checkProgress(oldAc, newAc *model.CActivity) bool {
if oldAc.ProgressFrequency != newAc.ProgressFrequency ||
oldAc.UpdatePage != newAc.UpdatePage ||
oldAc.ProgressStart != newAc.ProgressStart ||
oldAc.ProgressSync != newAc.ProgressSync {
return false
}
return true
}
func checkOpenBonus(oldAc, newAc *model.CActivity) bool {
if oldAc.BonusQuery != newAc.BonusQuery ||
oldAc.BonusQuerStart != newAc.BonusQuerStart {
return false
}
return true
}
// UpdateActivity update creative activity
func (s *Service) UpdateActivity(c context.Context, newAc *model.CActivity) (err error) {
acs, _, err := s.ListActivity(c, newAc.Name, 0, 1, "")
if err != nil {
log.Error("s.ListActivity error(%v)", err)
return
}
if len(acs) == 0 {
err = fmt.Errorf("activity(%s) not exist", newAc.Name)
return
}
old := acs[0]
// 报名标准
signUpStr := "signed_start=VALUES(signed_start),signed_end=VALUES(signed_end),sign_up=VALUES(sign_up),sign_up_start=VALUES(sign_up_start)"
// 中奖标准
winStr := "object=VALUES(object),upload_start=VALUES(upload_start),upload_end=VALUES(upload_end),win_type=VALUES(win_type),require_items=VALUES(require_items),require_value=VALUES(require_value),statistics_start=VALUES(statistics_start),statistics_end=VALUES(statistics_end)"
// 奖金设置
bonusStr := "bonus_type=VALUES(bonus_type),bonus_time=VALUES(bonus_time)"
// 进展同步
progressStr := "progress_frequency=VALUES(progress_frequency),update_page=VALUES(update_page),progress_start=VALUES(progress_start),progress_end=VALUES(progress_end),progress_sync=VALUES(progress_sync)"
// 开奖查询
openBonusStr := "bonus_query=VALUES(bonus_query),bonus_query_start=VALUES(bonus_query_start),bonus_query_end=VALUES(bonus_query_end)"
// others
otherStr := "background=VALUES(background),win_desc=VALUES(win_desc),unwin_desc=VALUES(unwin_desc),details=VALUES(details)"
var (
update = ""
updateBonus = false
now = xtime.Time(time.Now().Unix())
)
switch {
case now < old.SignUpStart:
// 报名未时间开始
update = fmt.Sprintf("%s,%s,%s,%s,%s,%s,sign_up_end=VALUES(sign_up_end)", signUpStr, winStr, bonusStr, progressStr, openBonusStr, otherStr)
updateBonus = true
case now >= old.SignUpStart && now <= old.SignUpEnd && now < old.ProgressStart:
// 报名已开始未结束,进展同步未开始
if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) {
err = fmt.Errorf("报名已开始,无法修改报名、中奖、奖金相关内容,请检查修改项")
return
}
update = fmt.Sprintf("sign_up_end=VALUES(sign_up_end),%s,%s,%s", progressStr, openBonusStr, otherStr)
case now > old.SignUpEnd && now >= old.ProgressStart && now <= old.ProgressEnd:
// 报名已结束,进展同步开始未结束
if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) || !checkProgress(old, newAc) {
err = fmt.Errorf("报名已结束,进展同步开始未结束,无法修改报名、中奖、奖金、进展相关内容,请检查修改项")
return
}
update = fmt.Sprintf("progress_end=VALUES(progress_end),%s,%s", openBonusStr, otherStr)
case now > old.ProgressEnd && now < old.BonusQueryEnd:
// 进展同步已结束,开奖查询未结束
if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) || !checkProgress(old, newAc) || !checkOpenBonus(old, newAc) || old.ProgressEnd != newAc.ProgressEnd {
err = fmt.Errorf("进展同步已结束,开奖查询未结束,无法修改报名、中奖、奖金、进展、开奖相关内容,请检查修改项")
return
}
update = fmt.Sprintf("bonus_query_end=VALUES(bonus_query_end),%s", otherStr)
default:
err = fmt.Errorf("不符合任何修改时间段,没有任何修改")
return
}
update = fmt.Sprintf("ON DUPLICATE KEY UPDATE %s", update)
err = s.insertActivity(c, newAc, update, updateBonus)
return
}
func (s *Service) getActivityBonus(c context.Context, ids []int64) (bm map[int64][]int64, err error) {
bm = make(map[int64][]int64)
bonus, err := s.dao.GetActivityBonus(c, ids)
if err != nil {
return
}
sort.Slice(bonus, func(i, j int) bool {
return bonus[i].Rank < bonus[j].Rank
})
for i := 0; i < len(bonus); i++ {
id := bonus[i].ID
if _, ok := bm[id]; !ok {
bm[id] = make([]int64, 0)
}
bm[id] = append(bm[id], bonus[i].Money)
}
return
}
func (s *Service) insertActivity(c context.Context, ac *model.CActivity, updateVal string, updateBonus bool) (err error) {
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran error(%v)", err)
return
}
// insert activity
if _, err = s.dao.TxInsertActivity(tx, ac, updateVal); err != nil {
log.Error("s.dao.TxInsertActivity error(%v)", err)
return
}
id, err := s.dao.TxGetActivityByName(tx, ac.Name)
if err != nil {
log.Error("s.dao.GetActivityByName error(%v)", err)
return
}
// is update bonus
if updateBonus && len(ac.BonusMoney) > 0 {
bonus := make([]*model.BonusRank, 0)
if ac.WinType == 1 {
bonus = append(bonus, &model.BonusRank{ID: id, Rank: 0, Money: ac.BonusMoney[0]})
} else if ac.WinType == 2 {
for i := 0; i < len(ac.BonusMoney); i++ {
bonus = append(bonus, &model.BonusRank{ID: id, Rank: i + 1, Money: ac.BonusMoney[i]})
}
}
// insert bonus money
if err = s.txInsertActivityBonus(tx, bonus); err != nil {
log.Error("s.TxInsertBonusRank error(%v)", err)
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error")
}
return
}
func (s *Service) txInsertActivityBonus(tx *sql.Tx, bonus []*model.BonusRank) (err error) {
var buf bytes.Buffer
for _, row := range bonus {
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(row.ID, 10))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(row.Rank))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(row.Money, 10))
buf.WriteString(")")
buf.WriteByte(',')
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
}
vals := buf.String()
buf.Reset()
_, err = s.dao.TxInsertActivityBonusBatch(tx, vals)
return
}
// ListActivitySignUp list activity who sign up
func (s *Service) ListActivitySignUp(c context.Context, activityID int64, from, limit int) (ups []*model.UpActivity, total int, err error) {
total, err = s.dao.UpActivityStateCount(c, activityID, []int64{1, 2, 3})
if err != nil {
log.Error("s.dao.UpActivityStateCount error(%v)", err)
return
}
ups, err = s.dao.ListUpActivity(c, activityID, from, limit)
if err != nil {
log.Error("s.dao.ListUpActivity error(%v)", err)
}
return
}
// ListActivityWinners list activity winners
func (s *Service) ListActivityWinners(c context.Context, activityID, mid int64, from, limit int) (ups []*model.UpActivity, total int, err error) {
total, err = s.dao.UpActivityStateCount(c, activityID, []int64{2, 3})
if err != nil {
log.Error("s.dao.UpActivityStateCount error(%v)", err)
return
}
ups, err = s.dao.ListUpActivitySuccess(c, activityID, mid, from, limit)
if err != nil {
log.Error("s.dao.ListUpActivity error(%v)", err)
return
}
if mid != 0 {
total = len(ups)
}
return
}
// ActivityAward activity award
func (s *Service) ActivityAward(c context.Context, activityID int64, activityName string, date, statisticsEnd xtime.Time, creator string) (err error) {
if xtime.Time(time.Now().Unix()) <= statisticsEnd {
err = fmt.Errorf("统计阶段未结束,不能发奖")
return
}
ups, err := s.listUpActivity(c, activityID)
if err != nil {
log.Error("s.listUpActivity error(%v)", err)
return
}
if len(ups) == 0 {
return
}
rankMID := make(map[int][]int64)
rankMoney := make(map[int]int64)
for _, up := range ups {
if up.State != 2 {
continue
}
rank := up.Rank
rankMoney[rank] = up.Bonus
if _, ok := rankMID[rank]; !ok {
rankMID[rank] = make([]int64, 0)
}
rankMID[rank] = append(rankMID[rank], up.MID)
}
// insert to tag
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran error(%v)", err)
return
}
for rank, money := range rankMoney {
mids, ok := rankMID[rank]
if !ok || len(mids) == 0 {
continue
}
tagName := fmt.Sprintf("act-%s-%d", activityName, rank)
err = s.addActivityUpTag(tx, money, creator, tagName, mids, date)
if err != nil {
log.Error("s.addActivityUpTag error(%v)", err)
return
}
// update mids state
if _, err = s.dao.TxUpdateUpActivityState(tx, activityID, mids, 2, 3); err != nil {
tx.Rollback()
log.Error("s.dao.TxUpdateUpActivityState error(%v)", err)
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
}
return
}
func (s *Service) addActivityUpTag(tx *sql.Tx, money int64, creator, tagName string, mids []int64, date xtime.Time) (err error) {
tag := &model.TagInfo{
Tag: tagName,
Creator: creator,
Dimension: 1,
StartTime: date,
EndTime: date,
AdjustType: 1,
Ratio: int(money),
UploadStartTime: date,
UploadEndTime: date,
}
if _, err = s.dao.TxInsertTag(tx, tag); err != nil {
tx.Rollback()
log.Error("s.dao.TxInsertTag error(%v)", err)
return
}
tagID, err := s.dao.TxGetTagInfoByName(tx, tagName, 1, 0, 0)
if err != nil {
tx.Rollback()
log.Error("s.dao.TxGetTagInfoByName error(%v)", err)
return
}
for _, mid := range mids {
_, err = s.dao.TxInsertTagUpInfo(tx, tagID, mid, 0)
if err != nil {
tx.Rollback()
log.Error("s.dao.TxInsertTagUpInfo error(%v)", err)
return
}
}
return
}
func (s *Service) listUpActivity(c context.Context, activityID int64) (ups []*model.UpActivity, err error) {
from, limit := 0, 2000
ups = make([]*model.UpActivity, 0)
for {
var up []*model.UpActivity
up, err = s.dao.ListUpActivity(c, activityID, from, limit)
if err != nil {
return
}
ups = append(ups, up...)
if len(up) < limit {
break
}
from += limit
}
return
}

View File

@@ -0,0 +1,847 @@
package service
import (
"errors"
"fmt"
"sort"
"strconv"
"strings"
"time"
"go-common/app/admin/main/growup/model"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
)
// const for default groupid
const (
// task group Admin id
AdminID = 1
)
var (
// task role list privilege id
_privilegeTaskRoleList = "12,48"
// admin
_privilegePrivilege = "7,8,9,10,11,12,38,39,40,41,42,43,44,45,46,47,48"
)
func removeDuplicatesAndEmpty(a []string) (ret []string) {
for i := 0; i < len(a); i++ {
if (i > 0 && a[i-1] == a[i]) || len(a[i]) == 0 {
continue
}
ret = append(ret, a[i])
}
return
}
// GetUserPri get user privilege
func (s *Service) GetUserPri(username string) (priMap map[int64]bool, err error) {
priMap = make(map[int64]bool)
query := fmt.Sprintf("username = '%s'", username)
users, err := s.dao.GetAuthorityUsersInfo(query, "id, task_group, task_role")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
if len(users) == 0 {
return
}
if len(users) > 1 {
err = errors.New("get user error")
return
}
userPrivileges := []string{}
var taskPrivileges string
user := users[0]
if user.TaskGroup != "" {
groups := strings.Split(user.TaskGroup, ",")
for _, groupID := range groups {
id, _ := strconv.ParseInt(groupID, 10, 64)
taskPrivileges, err = s.dao.GetAuthorityTaskGroupPrivileges(id)
if err != nil {
log.Error("s.dao.GetAuthorityTaskGroupPrivileges Error(%v)", err)
return
}
userPrivileges = append(userPrivileges, strings.Split(taskPrivileges, ",")...)
}
}
if user.TaskRole != "" {
roles := strings.Split(user.TaskRole, ",")
for _, roleID := range roles {
id, _ := strconv.ParseInt(roleID, 10, 64)
taskPrivileges, err = s.dao.GetAuthorityTaskRolePrivileges(id)
if err != nil {
log.Error("s.dao.GetAuthorityTaskRolePrivileges Error(%v)", err)
return
}
userPrivileges = append(userPrivileges, strings.Split(taskPrivileges, ",")...)
}
}
sort.Strings(userPrivileges)
userPrivileges = removeDuplicatesAndEmpty(userPrivileges)
for _, privilegesID := range userPrivileges {
id, _ := strconv.ParseInt(privilegesID, 10, 64)
priMap[id] = true
}
return
}
// GetAuthorityUserPrivileges get user all privileges
func (s *Service) GetAuthorityUserPrivileges(username string) (data interface{}, err error) {
mPrivileges, err := s.GetUserPri(username)
if err != nil {
log.Error("s.GetUserPri Error(%v)", err)
return
}
if len(mPrivileges) == 0 {
data = map[string]interface{}{
"router": []string{},
}
return
}
all, err := s.ListPrivilege()
if err != nil {
log.Error("s.ListPrivilege Error(%v)", err)
return
}
router := []int64{}
for _, level1 := range all {
for _, level2 := range level1.Children {
for _, level3 := range level2.Children {
if _, ok := mPrivileges[level3.ID]; ok {
level3.Selected = true
level2.Selected = true
level1.Selected = true
if level3.IsRouter == 1 {
router = append(router, level3.ID)
}
}
}
}
}
data = map[string]interface{}{
"privileges": all,
"router": router,
}
return
}
// GetAuthorityUserGroup get authority user group
func (s *Service) GetAuthorityUserGroup(username string) (data []*model.Group, err error) {
query := fmt.Sprintf("username = '%s'", username)
users, err := s.dao.GetAuthorityUsersInfo(query, "id, task_group")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
if len(users) == 0 {
return
}
if len(users) > 1 {
err = errors.New("get user error")
return
}
if users[0].TaskGroup == "" {
return
}
groups := strings.Split(users[0].TaskGroup, ",")
allGroups, err := s.dao.GetAuthorityTaskGroups("")
if err != nil {
log.Error("s.dao.ListAuthorityTaskGroups Error(%v)", err)
return
}
gMap := make(map[int64]*model.Group)
for _, g := range allGroups {
gMap[g.ID] = g
}
data = make([]*model.Group, 0)
for _, id := range groups {
gID, _ := strconv.ParseInt(id, 10, 64)
if gID == 1 {
data = allGroups
return
}
data = append(data, gMap[gID])
}
return
}
// ListAuthorityUsers list all users in authority-manage
func (s *Service) ListAuthorityUsers(username string, from, limit int, sort string) (users []*model.User, total int, err error) {
query := ""
if len(username) != 0 {
query = fmt.Sprintf("username = '%s'", username)
}
users, total, err = s.dao.ListAuthorityUsers(query, from, limit, sort)
for i := 0; i < len(users); i++ {
taskGroup := users[i].TaskGroup
groups := []*model.Group{}
if len(taskGroup) > 0 {
query = fmt.Sprintf("id in (%s)", taskGroup)
groups, err = s.dao.GetAuthorityTaskGroups(query)
if err != nil {
log.Error("s.dao.GetAuthorityTaskGroups Error(%v)", err)
return
}
}
users[i].Groups = groups
taskRole := users[i].TaskRole
roles := []*model.Role{}
if len(taskRole) > 0 {
query = fmt.Sprintf("id in (%s)", taskRole)
roles, err = s.dao.GetAuthorityTaskRoles(query)
if err != nil {
log.Error("s.dao.GetAuthorityTaskRoles Error(%v)", err)
return
}
}
users[i].Roles = roles
}
return
}
// AddAuthorityUser add user to authority-manage
func (s *Service) AddAuthorityUser(username, nickname string) (err error) {
user := model.User{
Username: username,
Nickname: nickname,
ATime: xtime.Time(time.Now().Unix()),
}
return s.dao.AddAuthorityUser(&user)
}
// UpdateAuthorityUserInfo update user's nickname
func (s *Service) UpdateAuthorityUserInfo(id int64, nickname string) (err error) {
update := map[string]interface{}{
"nickname": nickname,
}
return s.dao.UpdateAuthorityUser(id, update)
}
// UpdateAuthorityUserAuth update user's task group and task role
func (s *Service) UpdateAuthorityUserAuth(id int64, groupID, roleID string) (err error) {
update := map[string]interface{}{
"task_group": groupID,
"task_role": roleID,
}
return s.dao.UpdateAuthorityUser(id, update)
}
// DeleteAuthorityUser delete user from authority-manage from id
func (s *Service) DeleteAuthorityUser(id int64) (err error) {
return s.dao.DeleteAuthorityUser(id)
}
func getAuthorityGroupUsers(groupID string, users []*model.User) (result []*model.SUser) {
result = []*model.SUser{}
for _, user := range users {
groupIDs := strings.Split(user.TaskGroup, ",")
for _, id := range groupIDs {
if id == groupID {
result = append(result, &model.SUser{
ID: user.ID,
Name: user.Username,
})
break
}
}
}
return
}
// ListAuthorityTaskGroups list all task groups in authority-manage
func (s *Service) ListAuthorityTaskGroups(from, limit int, sort string) (groups []*model.TaskGroup, total int, err error) {
groups, total, err = s.dao.ListAuthorityTaskGroups("", from, limit, sort)
if err != nil {
log.Error("s.dao.ListAuthorityTaskGroups Error(%v)", err)
return
}
users, err := s.dao.GetAuthorityUsersInfo("", "id, username, task_group")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
for i := 0; i < len(groups); i++ {
groups[i].Users = getAuthorityGroupUsers(strconv.FormatInt(groups[i].ID, 10), users)
}
return
}
// AddAuthorityTaskGroup add new task group to authority-manage and add privilege 48
func (s *Service) AddAuthorityTaskGroup(name, desc string) (err error) {
if len(name) == 0 {
return errors.New("get group name error")
}
group := model.TaskGroup{
Name: name,
Desc: desc,
ATime: xtime.Time(time.Now().Unix()),
}
err = s.dao.AddAuthorityTaskGroup(&group)
if err != nil {
log.Error("s.dao.AddAuthorityTaskGroup Error(%v)", err)
return
}
newGroup, err := s.dao.GetAuthorityTaskGroup(fmt.Sprintf("name = '%s'", name))
if err != nil {
log.Error("s.dao.AddAuthorityTaskGroup Error(%v)", err)
return
}
return s.UpdateAuthorityGroupPrivilege(newGroup.ID, "", "", 0)
}
// AddAuthorityTaskGroupUser add user to task group
func (s *Service) AddAuthorityTaskGroupUser(username, groupID string) (err error) {
if len(username) == 0 {
return errors.New("get username error")
}
var users []*model.User
query := fmt.Sprintf("username = '%s'", username)
users, err = s.dao.GetAuthorityUsersInfo(query, "id, task_group")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo error(%v)", err)
return
}
if len(users) != 1 {
return ecode.GrowupAuthorityUserNotFound
}
if len(users[0].TaskGroup) != 0 {
groupID = users[0].TaskGroup + "," + groupID
}
update := map[string]interface{}{"task_group": groupID}
err = s.dao.UpdateAuthorityUser(users[0].ID, update)
if err != nil {
log.Error("s.dao.UpdateAuthorityUser error(%v)", err)
}
return
}
// UpdateAuthorityTaskGroupInfo update task group info
func (s *Service) UpdateAuthorityTaskGroupInfo(groupID int64, name, desc string) (err error) {
update := make(map[string]interface{})
if len(desc) != 0 {
update["desc"] = desc
}
if len(name) != 0 {
update["name"] = name
}
return s.dao.UpdateAuthorityTaskGroup(groupID, update)
}
func spliceStrs(strs []string) (ret string) {
for _, str := range strs {
ret += str + ","
}
if len(ret) == 0 {
return
}
return ret[:len(ret)-1]
}
func (s *Service) updateAuthorityUsersGroup(groupID string, users []*model.User) (err error) {
for _, user := range users {
groupIDs := strings.Split(user.TaskGroup, ",")
for i := 0; i < len(groupIDs); i++ {
if groupIDs[i] == groupID {
groupIDs = append(groupIDs[:i], groupIDs[i+1:]...)
err = s.dao.UpdateAuthorityUser(user.ID, map[string]interface{}{"task_group": spliceStrs(groupIDs)})
if err != nil {
log.Error("s.dao.UpdateAuthorityUser error(%v)", err)
return
}
break
}
}
}
return
}
// DeleteAuthorityTaskGroup delete task group
func (s *Service) DeleteAuthorityTaskGroup(groupID int64) (err error) {
err = s.dao.DeleteAuthorityTaskGroup(groupID)
if err != nil {
log.Error("s.dao.DeleteAuthorityTaskGroup error(%v)", err)
return
}
// update users task group
users, err := s.dao.GetAuthorityUsersInfo("", "id, task_group")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
err = s.updateAuthorityUsersGroup(strconv.FormatInt(groupID, 10), users)
if err != nil {
log.Error("s.updateAuthorityUsersGroup error(%v)", err)
return
}
// delete task role which belong this group
query := fmt.Sprintf("group_id = %d", groupID)
roles, err := s.dao.GetAuthorityTaskRoles(query)
for _, role := range roles {
err = s.DeleteAuthorityTaskRole(role.ID)
if err != nil {
log.Error("s.DeleteAuthorityTaskRole error(%v)", err)
return
}
}
return
}
// DeleteAuthorityTaskGroupUser delete user from task group
func (s *Service) DeleteAuthorityTaskGroupUser(id, groupID int64) (err error) {
query := fmt.Sprintf("id = %d", id)
users, err := s.dao.GetAuthorityUsersInfo(query, "id, task_group")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
err = s.updateAuthorityUsersGroup(strconv.FormatInt(groupID, 10), users)
if err != nil {
log.Error("s.updateAuthorityUsersGroup error(%v)", err)
}
return
}
// ListAuthorityGroupPrivilege list task group's privileges
func (s *Service) ListAuthorityGroupPrivilege(groupID int64, fatherID int64) (ret *model.SPrivilege, err error) {
var privilege string
privilege, err = s.dao.GetAuthorityTaskGroupPrivileges(groupID)
if err != nil {
log.Error("s.dao.GetAuthorityTaskGroupPrivileges Error(%v)", err)
return
}
privileges := strings.Split(privilege, ",")
var data []*model.SPrivilege
data, err = s.ListPrivilege()
if err != nil {
log.Error("s.ListPrivilege Error(%v)", err)
return
}
for i := 0; i < len(data); i++ {
if data[i].ID == fatherID {
ret = data[i]
for _, idStr := range privileges {
id, _ := strconv.ParseInt(idStr, 10, 64)
for _, level2 := range ret.Children {
for _, level3 := range level2.Children {
if level3.ID == id {
level3.Selected = true
level2.Selected = true
}
}
}
}
ret.Selected = true
break
}
}
return
}
// UpdateAuthorityGroupPrivilege update group task privileges
func (s *Service) UpdateAuthorityGroupPrivilege(groupID int64, add, minus string, authType int) (err error) {
// get old privilege by group id
privilege, err := s.dao.GetAuthorityTaskGroupPrivileges(groupID)
if err != nil {
log.Error("s.dao.GetAuthorityTaskGroupPrivileges Error(%v)", err)
return
}
newP := make(map[string]struct{})
privilegeSli := strings.Split(privilege, ",")
for _, p := range privilegeSli {
if p == "" {
continue
}
newP[p] = struct{}{}
}
// default add task role list privilege
// 数据源权限不需要添加
if authType == 0 {
add += "," + _privilegeTaskRoleList
if groupID == 1 {
add += "," + _privilegePrivilege
}
add = strings.TrimPrefix(add, ",")
}
for _, p := range strings.Split(add, ",") {
if p == "" {
continue
}
newP[p] = struct{}{}
}
// minus
for _, p := range strings.Split(minus, ",") {
if p == "" {
continue
}
delete(newP, p)
}
privileges := ""
for p := range newP {
privileges += p + ","
}
update := map[string]interface{}{
"privileges": strings.TrimSuffix(privileges, ","),
}
return s.dao.UpdateAuthorityTaskGroup(groupID, update)
}
func getAuthorityRoleUsers(roleID string, users []*model.User) (result []*model.SUser) {
result = []*model.SUser{}
for _, user := range users {
roleIDs := strings.Split(user.TaskRole, ",")
for _, id := range roleIDs {
if id == roleID {
result = append(result, &model.SUser{
ID: user.ID,
Name: user.Username,
})
break
}
}
}
return
}
// ListAuthorityTaskRoles list user's task roles
func (s *Service) ListAuthorityTaskRoles(username string, from, limit int, sort string) (roles []*model.TaskRole, total int, err error) {
query := fmt.Sprintf("username = '%s'", username)
users, err := s.dao.GetAuthorityUsersInfo(query, "task_group")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
if len(users) == 0 || len(users) > 1 {
err = ecode.GrowupAuthorityUserNotFound
return
}
user := users[0]
query = fmt.Sprintf("group_id in (%s)", user.TaskGroup)
groupIDs := strings.Split(user.TaskGroup, ",")
for _, groupID := range groupIDs {
if groupID == strconv.Itoa(AdminID) { // Admin
query = ""
break
}
}
roles, total, err = s.dao.ListAuthorityTaskRoles(query, from, limit, sort)
if err != nil {
log.Error("s.dao.ListAuthorityTaskRoles Error(%v)", err)
return
}
users, err = s.dao.GetAuthorityUsersInfo("", "id, username, task_role")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
for i := 0; i < len(roles); i++ {
roles[i].Users = getAuthorityRoleUsers(strconv.FormatInt(roles[i].ID, 10), users)
roles[i].GroupName, err = s.dao.GetAuthorityTaskGroupName(roles[i].GroupID)
if err != nil {
log.Error("s.dao.GetAuthorityTaskGroupName Error(%v)", err)
return
}
}
return
}
// AddAuthorityTaskRole add task role to authority-manage
func (s *Service) AddAuthorityTaskRole(groupID int64, name, desc string) (err error) {
if len(name) == 0 {
return errors.New("get role name error")
}
role := model.TaskRole{
Name: name,
Desc: desc,
GroupID: groupID,
ATime: xtime.Time(time.Now().Unix()),
}
return s.dao.AddAuthorityTaskRole(&role)
}
// AddAuthorityTaskRoleUser add user to task group
func (s *Service) AddAuthorityTaskRoleUser(username, roleID string) (err error) {
if len(username) == 0 {
return errors.New("get username error")
}
var users []*model.User
query := fmt.Sprintf("username = '%s'", username)
users, err = s.dao.GetAuthorityUsersInfo(query, "id, task_role")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo error(%v)", err)
return
}
if len(users) != 1 {
return ecode.GrowupAuthorityUserNotFound
}
if len(users[0].TaskRole) != 0 {
roleID = users[0].TaskRole + "," + roleID
}
update := map[string]interface{}{"task_role": roleID}
err = s.dao.UpdateAuthorityUser(users[0].ID, update)
if err != nil {
log.Error("s.dao.UpdateAuthorityUser error(%v)", err)
}
return
}
// UpdateAuthorityTaskRoleInfo update task role info
func (s *Service) UpdateAuthorityTaskRoleInfo(roleID int64, name, desc string) (err error) {
update := make(map[string]interface{})
if len(desc) != 0 {
update["desc"] = desc
}
if len(name) != 0 {
update["name"] = name
}
return s.dao.UpdateAuthorityTaskRole(roleID, update)
}
func (s *Service) updateAuthorityUsersRole(roleID string, users []*model.User) (err error) {
for _, user := range users {
roleIDs := strings.Split(user.TaskRole, ",")
for i := 0; i < len(roleIDs); i++ {
if roleIDs[i] == roleID {
roleIDs = append(roleIDs[:i], roleIDs[i+1:]...)
err = s.dao.UpdateAuthorityUser(user.ID, map[string]interface{}{"task_role": spliceStrs(roleIDs)})
if err != nil {
log.Error("s.dao.UpdateAuthorityUser error(%v)", err)
return
}
break
}
}
}
return
}
// DeleteAuthorityTaskRole delete task role
func (s *Service) DeleteAuthorityTaskRole(roleID int64) (err error) {
err = s.dao.DeleteAuthorityTaskRole(roleID)
if err != nil {
log.Error("s.dao.DeleteAuthorityTaskRole error(%v)", err)
return
}
// update users task role
users, err := s.dao.GetAuthorityUsersInfo("", "id, task_role")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
err = s.updateAuthorityUsersRole(strconv.FormatInt(roleID, 10), users)
if err != nil {
log.Error("s.updateAuthorityUsersRole error(%v)", err)
}
return
}
// DeleteAuthorityTaskRoleUser delete user from task role
func (s *Service) DeleteAuthorityTaskRoleUser(id, roleID int64) (err error) {
query := fmt.Sprintf("id = %d", id)
users, err := s.dao.GetAuthorityUsersInfo(query, "id, task_role")
if err != nil {
log.Error("s.dao.GetAuthorityUsersInfo Error(%v)", err)
return
}
err = s.updateAuthorityUsersRole(strconv.FormatInt(roleID, 10), users)
if err != nil {
log.Error("s.updateAuthorityUsersRole error(%v)", err)
}
return
}
// ListAuthorityRolePrivilege list task role's privileges
func (s *Service) ListAuthorityRolePrivilege(groupID, roleID int64, fatherID int64) (data *model.SPrivilege, err error) {
var privilege string
privilege, err = s.dao.GetAuthorityTaskRolePrivileges(roleID)
if err != nil {
log.Error("s.dao.GetAuthorityTaskRolePrivileges Error(%v)", err)
return
}
privileges := strings.Split(privilege, ",")
data, err = s.ListAuthorityGroupPrivilege(groupID, fatherID)
if err != nil {
log.Error("s.ListAuthorityGroupPrivilege Error(%v)", err)
return
}
level2 := data.Children
for i := 0; i < len(level2); i++ {
if !level2[i].Selected {
level2 = append(level2[:i], level2[i+1:]...)
i--
} else {
level3 := level2[i].Children
for j := 0; j < len(level3); j++ {
if !level3[j].Selected {
level3 = append(level3[:j], level3[j+1:]...)
j--
} else {
level3[j].Selected = false
}
}
level2[i].Children = level3
level2[i].Selected = false
}
}
data.Children = level2
data.Selected = false
for _, idStr := range privileges {
id, _ := strconv.ParseInt(idStr, 10, 64)
for _, level2 := range data.Children {
for _, level3 := range level2.Children {
if level3.ID == id {
level3.Selected = true
level2.Selected = true
}
}
}
}
data.Selected = true
return
}
// UpdateAuthorityRolePrivilege update role task privileges
func (s *Service) UpdateAuthorityRolePrivilege(roleID int64, add, minus string) (err error) {
privilege, err := s.dao.GetAuthorityTaskRolePrivileges(roleID)
if err != nil {
log.Error("s.dao.GetAuthorityTaskRolePrivileges Error(%v)", err)
return
}
newP := make(map[string]struct{})
privilegeSli := strings.Split(privilege, ",")
for _, p := range privilegeSli {
if p == "" {
continue
}
newP[p] = struct{}{}
}
// add
for _, p := range strings.Split(add, ",") {
if p == "" {
continue
}
newP[p] = struct{}{}
}
// minus
for _, p := range strings.Split(minus, ",") {
if p == "" {
continue
}
delete(newP, p)
}
privileges := ""
for p := range newP {
privileges += p + ","
}
update := map[string]interface{}{
"privileges": strings.TrimSuffix(privileges, ","),
}
return s.dao.UpdateAuthorityTaskRole(roleID, update)
}
// ListGroupAndRole list all task groups and task roles to admin
func (s *Service) ListGroupAndRole() (groups []*model.Group, roles []*model.Role, err error) {
groups, err = s.dao.GetAuthorityTaskGroups("")
if err != nil {
log.Error("s.dao.GetAuthorityTaskGroups Error(%v)", err)
return
}
roles, err = s.dao.GetAuthorityTaskRoles("")
if err != nil {
log.Error("s.dao.GetAuthorityTaskRoles Error(%v)", err)
return
}
return
}
// AddPrivilege all privilege
func (s *Service) AddPrivilege(name string, level, fatherID int64, isRouter uint8) (err error) {
privilege := model.Privilege{
Name: name,
Level: level,
FatherID: fatherID,
IsRouter: isRouter,
}
return s.dao.AddPrivilege(&privilege)
}
// UpdatePrivilege update privilege info
func (s *Service) UpdatePrivilege(id int64, name string, level, fatherID int64, isRouter uint8) (err error) {
update := map[string]interface{}{
"name": name,
"level": level,
"father_id": fatherID,
"is_router": isRouter,
}
return s.dao.UpdatePrivilege(id, update)
}
// ListPrivilege list privilege by level
func (s *Service) ListPrivilege() (data []*model.SPrivilege, err error) {
var level1, level2, level3 []*model.SPrivilege
query := fmt.Sprintf("level = 1")
level1, err = s.dao.GetLevelPrivileges(query)
if err != nil {
log.Error("s.dao.GetLevelPrivileges Error(%v)", err)
return
}
for _, p1 := range level1 {
query = fmt.Sprintf("level = 2 AND father_id = %d", p1.ID)
level2, err = s.dao.GetLevelPrivileges(query)
if err != nil {
log.Error("s.dao.GetLevelPrivileges Error(%v)", err)
return
}
for _, p2 := range level2 {
query = fmt.Sprintf("level = 3 AND father_id = %d", p2.ID)
level3, err = s.dao.GetLevelPrivileges(query)
if err != nil {
log.Error("s.dao.GetLevelPrivileges Error(%v)", err)
return
}
p2.Children = level3
p2.Level = 2
}
p1.Children = level2
p1.Level = 1
}
data = level1
return
}

View File

@@ -0,0 +1,201 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_AddAuthorityUser(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "DELETE FROM authority_user WHERE username = 'maru'")
err := s.AddAuthorityUser("maru", "maru")
So(err, ShouldBeNil)
}))
}
func TestService_AddAuthorityTaskRoleUser(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.AddAuthorityTaskRoleUser("maru", "1")
So(err, ShouldBeNil)
}))
}
func TestService_AddAuthorityTaskGroupUser(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.AddAuthorityTaskGroupUser("maru", "1")
So(err, ShouldBeNil)
}))
}
func TestService_AddAuthorityTaskRole(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "DELETE FROM authority_task_role WHERE name = 'test'")
err := s.AddAuthorityTaskRole(1, "test", "test")
So(err, ShouldBeNil)
}))
}
func TestService_AddAuthorityTaskGroup(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "DELETE FROM authority_task_group WHERE name = 'test'")
err := s.AddAuthorityTaskGroup("test", "test")
So(err, ShouldBeNil)
}))
}
func TestService_AddPrivilege(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "DELETE FROM authority_privilege WHERE name = 'test'")
err := s.AddPrivilege("test", 1, 1, 1)
So(err, ShouldBeNil)
}))
}
func TestService_DeleteAuthorityTaskRoleUser(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.DeleteAuthorityTaskRoleUser(11, 1)
So(err, ShouldBeNil)
}))
}
func TestService_DeleteAuthorityUser(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.DeleteAuthorityUser(11)
So(err, ShouldBeNil)
}))
}
func TestService_DeleteAuthorityTaskRole(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.DeleteAuthorityTaskRole(1)
So(err, ShouldBeNil)
}))
}
func TestService_DeleteAuthorityTaskGroupUser(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.DeleteAuthorityTaskGroupUser(11, 1)
So(err, ShouldBeNil)
}))
}
func TestService_DeleteAuthorityTaskGroup(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.DeleteAuthorityTaskGroup(1)
So(err, ShouldBeNil)
}))
}
func TestService_GetAuthorityUserPrivileges(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
_, err := s.GetAuthorityUserPrivileges("maru")
So(err, ShouldBeNil)
}))
}
func TestService_ListPrivilege(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
_, err := s.ListPrivilege()
So(err, ShouldBeNil)
}))
}
func TestService_ListGroupAndRole(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
_, _, err := s.ListGroupAndRole()
So(err, ShouldBeNil)
}))
}
func TestService_ListAuthorityTaskRoles(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "UPDATE authority_user SET task_group = 1 WHERE username = 'test'")
_, _, err := s.ListAuthorityTaskRoles("test", 0, 10, "id")
So(err, ShouldBeNil)
}))
}
func TestService_ListAuthorityTaskGroups(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
_, _, err := s.ListAuthorityTaskGroups(0, 10, "id")
So(err, ShouldBeNil)
}))
}
func TestService_ListAuthorityRolePrivilege(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "UPDATE authority_task_group SET is_deleted = 0 WHERE id = 1")
s.dao.Exec(context.TODO(), "UPDATE authority_task_role SET is_deleted = 0 WHERE id = 1")
_, err := s.ListAuthorityRolePrivilege(1, 1, 2)
So(err, ShouldBeNil)
}))
}
func TestService_ListAuthorityGroupPrivilege(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "UPDATE authority_task_group SET is_deleted = 0 WHERE id = 1")
_, err := s.ListAuthorityGroupPrivilege(1, 1)
So(err, ShouldBeNil)
}))
}
func TestService_ListAuthorityUsers(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
_, _, err := s.ListAuthorityUsers("", 0, 0, "id")
So(err, ShouldBeNil)
}))
}
func TestService_UpdatePrivilege(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "DELETE FROM authority_privilege WHERE name = 'test'")
err := s.UpdatePrivilege(1, "test", 1, 1, 1)
So(err, ShouldBeNil)
}))
}
func TestService_UpdateAuthorityUserInfo(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "UPDATE authority_user SET nickname = 'abc' WHERE id = 1")
err := s.UpdateAuthorityUserInfo(1, "test")
So(err, ShouldBeNil)
}))
}
func TestService_UpdateAuthorityUserAuth(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.UpdateAuthorityUserAuth(1, "1", "1")
So(err, ShouldBeNil)
}))
}
func TestService_UpdateAuthorityTaskRoleInfo(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.UpdateAuthorityTaskRoleInfo(1, "maru", "test")
So(err, ShouldBeNil)
}))
}
func TestService_UpdateAuthorityRolePrivilege(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.UpdateAuthorityRolePrivilege(1, "", "")
So(err, ShouldBeNil)
}))
}
func TestService_UpdateAuthorityTaskGroupInfo(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
s.dao.Exec(context.TODO(), "UPDATE authority_task_group SET desc = 'tt' WHERE id = 1")
err := s.UpdateAuthorityTaskGroupInfo(1, "", "test")
So(err, ShouldBeNil)
}))
}
func TestService_UpdateAuthorityGroupPrivilege(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
err := s.UpdateAuthorityGroupPrivilege(1, "", "", 0)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,43 @@
package service
import (
"context"
"fmt"
"time"
"go-common/library/log"
)
// AutoDismiss update account state to 6
func (s *Service) AutoDismiss(c context.Context, operator string, typ int, mid int64, reason string) (err error) {
ups, err := s.dao.UpsVideoInfo(c, fmt.Sprintf("mid = %d", mid))
if err != nil {
log.Error("s.dao.UpsVideoInfo error(%v)", err)
return
}
if len(ups) <= 0 {
return
}
up := ups[0]
return s.Dismiss(c, operator, typ, up.AccountState, mid, reason)
}
// AutoForbid update account state to 7 and add a n days CD
func (s *Service) AutoForbid(c context.Context, operator string, typ int, mid int64, reason string, days, second int) (err error) {
ups, err := s.dao.UpsVideoInfo(c, fmt.Sprintf("mid = %d", mid))
if err != nil {
log.Error("s.dao.UpsVideoInfo error(%v)", err)
return
}
if len(ups) <= 0 {
return
}
up := ups[0]
switch up.AccountState {
case 3:
return s.Forbid(c, operator, typ, 3, mid, reason, days, second)
case 7:
return s.Forbid(c, operator, typ, 7, mid, reason, days, int(int64(up.ExpiredIn)+int64(second)-time.Now().Unix()))
}
return
}

View File

@@ -0,0 +1,56 @@
package service
import (
"context"
"time"
"go-common/app/admin/main/growup/model"
)
// Banners Get Banners
func (s *Service) Banners(c context.Context, from, limit int64) (total int64, bs []*model.Banner, err error) {
total, err = s.dao.TotalBannerCount(c)
if err != nil {
return
}
bs, err = s.dao.Banners(c, from, limit)
return
}
// AddBanner Add Banner
func (s *Service) AddBanner(c context.Context, image, link string, startAt, endAt int64) (dup int64, err error) {
if startAt > endAt {
return
}
dup, err = s.dao.DupBanner(c, startAt, endAt, time.Now().Unix())
if err != nil {
return
}
if dup > 0 {
return
}
_, err = s.dao.InsertBanner(c, image, link, startAt, endAt)
return
}
// EditBanner Update Banner
func (s *Service) EditBanner(c context.Context, id, startAt, endAt int64, image, link string) (dup int64, err error) {
if startAt > endAt {
return
}
dup, err = s.dao.DupEditBanner(c, startAt, endAt, time.Now().Unix(), id)
if err != nil {
return
}
if dup > 0 {
return
}
_, err = s.dao.UpdateBanner(c, image, link, startAt, endAt, id)
return
}
// Off set end time to now
func (s *Service) Off(c context.Context, endAt, id int64) (err error) {
_, err = s.dao.UpdateBannerEndAt(c, endAt, id)
return
}

View File

@@ -0,0 +1,117 @@
package service
import (
"fmt"
"time"
"go-common/app/admin/main/growup/model"
"go-common/library/log"
"go-common/library/xstr"
)
// QueryBlacklist query blacklist
func (s *Service) QueryBlacklist(fromTime, toTime int64, ctype, reason int, mid int64, nickname string, aid int64, from, limit int, sort string) (total int, blacklist []*model.Blacklist, err error) {
blacklistQuery := buildBlacklistQuery(fromTime, toTime, ctype, reason, mid, nickname, aid)
blacklist, total, err = s.dao.ListBlacklist(blacklistQuery, from, limit, sort)
if err != nil {
log.Error("s.dao.ListBlacklist error(%v)", err)
return
}
if total == 0 {
return
}
avIDs := make([]int64, len(blacklist))
for i := 0; i < len(blacklist); i++ {
avIDs[i] = blacklist[i].AvID
}
// get av total income
avIncomeMap, err := s.getAvIncomeStatis(avIDs)
if err != nil {
log.Error("s.getAvIncomeStatis error(%v)", err)
return
}
for i := 0; i < len(blacklist); i++ {
blacklist[i].Income = avIncomeMap[blacklist[i].AvID]
}
return
}
func buildBlacklistQuery(fromTime, toTime int64, ctype, reason int, mid int64, nickname string, aid int64) (query string) {
query += fmt.Sprintf("ctime >= '%s' AND ctime <= '%s'", time.Unix(fromTime, 0).Format("2006-01-02"), time.Unix(toTime, 0).Format("2006-01-02"))
query += " AND "
if aid <= 0 && mid <= 0 && nickname == "" {
query += "has_signed = 1"
query += " AND "
}
if mid > 0 {
query += fmt.Sprintf("mid = %d", mid)
query += " AND "
}
if nickname != "" {
query += fmt.Sprintf("nickname = \"%s\"", nickname)
query += " AND "
}
if aid > 0 {
query += fmt.Sprintf("av_id = %d", aid)
query += " AND "
}
if ctype != 4 {
query += fmt.Sprintf("ctype = %d", ctype)
query += " AND "
}
if reason > 0 {
query += fmt.Sprintf("reason = %d", reason)
query += " AND "
}
query += "is_delete = 0"
return
}
func (s *Service) getAvIncomeStatis(avIDs []int64) (avIncomeMap map[int64]int64, err error) {
avIncomeMap = make(map[int64]int64)
query := fmt.Sprintf("av_id IN (%s) AND is_deleted = 0", xstr.JoinInts(avIDs))
avIncomes, err := s.dao.GetAvIncomeStatis(query)
if err != nil {
log.Error("s.dao.GetAvIncomeStatis error(%v)", err)
return
}
for _, avIncome := range avIncomes {
avIncomeMap[avIncome.AvID] = avIncome.TotalIncome
}
return
}
// ExportBlacklist blacklist export csv
func (s *Service) ExportBlacklist(fromTime, toTime int64, ctype, reason int, mid int64, nickname string, aid int64, from, limit int, sort string) (res []byte, err error) {
_, blacklist, err := s.QueryBlacklist(fromTime, toTime, ctype, reason, mid, nickname, aid, from, limit, sort)
if err != nil {
log.Error("s.QueryBlacklist error(%v)", err)
return
}
records := formatBlacklist(blacklist)
res, err = FormatCSV(records)
if err != nil {
log.Error("FormatCSV error(%v)", err)
}
return
}
// RecoverBlacklist recover av from blacklist
func (s *Service) RecoverBlacklist(aID int64, ctype int) (err error) {
update := map[string]interface{}{
"is_delete": 1,
}
err = s.dao.UpdateBlacklist(aID, ctype, update)
if err != nil {
log.Error("s.dao.UpdateBlacklist error(%v)", err)
return
}
return
}

View File

@@ -0,0 +1,11 @@
package service
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_QueryBlacklist(t *testing.T) {
Convey("QueryBlacklist", t, func() {})
}

View File

@@ -0,0 +1,156 @@
package service
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/admin/main/growup/model"
"go-common/library/database/sql"
"go-common/library/log"
)
// BudgetDayStatistics budget day statistics.
func (s *Service) BudgetDayStatistics(c context.Context, ctype, from, limit int) (total int, infos []*model.BudgetDayStatistics, err error) {
infos = make([]*model.BudgetDayStatistics, 0)
latelyDate, err := s.dao.GetLatelyExpenseDate(c, "daily", ctype)
if err == sql.ErrNoRows {
err = nil
return
}
if err != nil {
log.Error("s.BudgetDayGraph dao.GetLatelyExpenseDate error(%v)", err)
return
}
beginDate := time.Date(latelyDate.Year(), 1, 1, 0, 0, 0, 0, time.Local)
total, err = s.dao.GetDayExpenseCount(c, beginDate, ctype)
if err != nil {
log.Error("s.dao.GetDayExpenseCount error(%v)", err)
return
}
if total == 0 {
return
}
infos, err = s.dao.GetAllDayExpenseInfo(c, beginDate, ctype, from, limit)
if err != nil {
log.Error("s.dao.GetAllDayExpenseInfo error(%v)", err)
return
}
var annualBudget, dayBudget int64
switch ctype {
case _video:
annualBudget, dayBudget = s.conf.Budget.Video.AnnualBudget, s.conf.Budget.Video.DayBudget
case _column:
annualBudget, dayBudget = s.conf.Budget.Column.AnnualBudget, s.conf.Budget.Column.DayBudget
case _bgm:
annualBudget, dayBudget = s.conf.Budget.Bgm.AnnualBudget, s.conf.Budget.Bgm.DayBudget
}
for _, info := range infos {
info.ExpenseRatio = strconv.FormatFloat(float64(info.TotalExpense)/float64(annualBudget), 'f', 2, 32)
info.DayRatio = strconv.FormatFloat(float64(info.DayExpense)/float64(dayBudget), 'f', 2, 32)
}
return
}
// BudgetDayGraph get day graph.
func (s *Service) BudgetDayGraph(c context.Context, ctype int) (ratioInfo *model.BudgetRatio, err error) {
ratioInfo = new(model.BudgetRatio)
switch ctype {
case _video:
ratioInfo.Year, ratioInfo.Budget = s.conf.Budget.Video.Year, s.conf.Budget.Video.AnnualBudget
case _column:
ratioInfo.Year, ratioInfo.Budget = s.conf.Budget.Column.Year, s.conf.Budget.Column.AnnualBudget
case _bgm:
ratioInfo.Year, ratioInfo.Budget = s.conf.Budget.Bgm.Year, s.conf.Budget.Bgm.AnnualBudget
}
latelyDate, err := s.dao.GetLatelyExpenseDate(c, "daily", ctype)
if err == sql.ErrNoRows {
err = nil
return
}
if err != nil {
log.Error("s.BudgetDayGraph dao.GetLatelyExpenseDate error(%v)", err)
return
}
t := time.Date(latelyDate.Year(), latelyDate.Month(), latelyDate.Day(), 0, 0, 0, 0, time.Local)
totalExpense, err := s.dao.GetDayTotalExpenseInfo(c, t, ctype)
if err != nil {
log.Error("s.BudgetDayGraph dao.GetDayTotalExpenseInfo error(%v)", err)
return
}
ratioInfo.ExpenseRatio = strconv.FormatFloat(float64(totalExpense)/float64(ratioInfo.Budget), 'f', 2, 32)
ratioInfo.DayRatio = strconv.FormatFloat(float64(getGoneDays(latelyDate)*100)/float64(getYearDays(latelyDate.Year())), 'f', 2, 32)
return
}
// BudgetMonthStatistics budget month statistics
func (s *Service) BudgetMonthStatistics(c context.Context, ctype, from, limit int) (total int, infos []*model.BudgetMonthStatistics, err error) {
latelyDate, err := s.dao.GetLatelyExpenseDate(c, "monthly", ctype)
if err == sql.ErrNoRows {
err = nil
return
}
if err != nil {
log.Error("s.BudgetMonthStatistics dao.GetLatelyExpenseDate error(%v)", err)
return
}
var month, beginMonth string
if int(latelyDate.Month()) < 10 {
month = fmt.Sprintf("%d-0%d", latelyDate.Year(), latelyDate.Month())
} else {
month = fmt.Sprintf("%d-%d", latelyDate.Year(), latelyDate.Month())
}
beginMonth = fmt.Sprintf("%d-01", latelyDate.Year())
total, err = s.dao.GetMonthExpenseCount(c, month, beginMonth, ctype)
if err != nil {
log.Error("s.dao.GetMonthExpenseCount error(%v)", err)
return
}
infos, err = s.dao.GetAllMonthExpenseInfo(c, month, beginMonth, ctype, from, limit)
if err != nil {
log.Error("s.BudgetMonthStatistics dao.GetAllMonthExpenseInfo error(%v)", err)
return
}
if len(infos) <= 0 {
infos = make([]*model.BudgetMonthStatistics, 0)
}
var dayBudget int64
switch ctype {
case _video:
dayBudget = s.conf.Budget.Video.DayBudget
case _column:
dayBudget = s.conf.Budget.Column.DayBudget
case _bgm:
dayBudget = s.conf.Budget.Bgm.DayBudget
}
for _, info := range infos {
info.ExpenseRatio = strconv.FormatFloat(float64(info.MonthExpense)/float64(int(dayBudget)*getMonthDays(time.Unix(int64(info.Date), 0))), 'f', 2, 32)
date := time.Unix(int64(info.Date), 0)
info.Month = strconv.Itoa(date.Year())
info.Month += "-"
if int(date.Month()) < 10 {
info.Month += "0"
}
info.Month += strconv.Itoa(int(date.Month()))
}
return
}
func getMonthDays(date time.Time) (count int) {
begin := time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, time.Local)
end := time.Date(date.Year(), date.Month()+1, 1, 0, 0, 0, 0, time.Local)
return int(end.Sub(begin).Hours() / 24)
}
func getYearDays(year int) (count int) {
yearBegin := time.Date(year, 1, 1, 0, 0, 0, 0, time.Local)
yearEnd := time.Date(year+1, 1, 1, 0, 0, 0, 0, time.Local)
return int(yearEnd.Sub(yearBegin).Hours() / 24)
}
func getGoneDays(date time.Time) (count int) {
yearBegin := time.Date(date.Year(), 1, 1, 0, 0, 0, 0, time.Local)
return int(date.Sub(yearBegin).Hours()/24) + 1
}

View File

@@ -0,0 +1,96 @@
package service
import (
"context"
"fmt"
"strconv"
"strings"
"go-common/app/admin/main/growup/dao/resource"
"go-common/app/admin/main/growup/model"
"go-common/library/log"
)
var (
// 视频和专栏的权限点
_videoPri = 13
_columnPri = 103
)
// BusPrivilege business privilege
func (s *Service) BusPrivilege(c context.Context, username string, ctypes string) (res []*model.BusRes, err error) {
res = make([]*model.BusRes, 0)
typs := strings.Split(ctypes, ",")
if len(typs) == 0 {
return
}
for _, typ := range typs {
var ctype int
ctype, err = strconv.Atoi(typ)
if err != nil {
log.Error("strconv.Atoi error(%v)", err)
return
}
var r []*model.BusRes
r, err = s.busPrivilege(c, username, ctype)
if err != nil {
log.Error("s.busPrivilege error(%v)", err)
return
}
res = append(res, r...)
}
return
}
func (s *Service) busPrivilege(c context.Context, username string, ctype int) (res []*model.BusRes, err error) {
category, err := s.getBusCategory(c, ctype)
if err != nil {
log.Error("s.getBusCategory error(%v)", err)
return
}
userPri, err := s.GetUserPri(username)
if err != nil {
log.Error("s.GetUserPri error(%v)", err)
return
}
// 获取数据源权限
fatherID := 0
switch ctype {
case 1:
fatherID = _videoPri
case 2:
fatherID = _columnPri
}
allPrivilege, err := s.dao.GetLevelPrivileges(fmt.Sprintf("level = 3 AND father_id = %d", fatherID))
if err != nil {
log.Error("s.dao.GetLevelPrivileges Error(%v)", err)
return
}
res = make([]*model.BusRes, 0)
for _, p := range allPrivilege {
if !userPri[p.ID] {
continue
}
if cid, ok := category[p.Title]; ok {
res = append(res, &model.BusRes{
PrivilegeID: p.ID,
CategoryID: cid,
Name: p.Title})
}
}
return
}
func (s *Service) getBusCategory(c context.Context, ctype int) (categorys map[string]int64, err error) {
categorys = make(map[string]int64)
switch ctype {
case 1:
return resource.VideoCategoryNameToID(c)
case 2:
return resource.ColumnCategoryNameToID(c)
}
return
}

View File

@@ -0,0 +1,194 @@
package service
import (
"bytes"
"context"
"fmt"
"strconv"
"time"
"go-common/library/log"
xtime "go-common/library/time"
"go-common/app/admin/main/growup/model"
)
// CheatUps get cheat ups
func (s *Service) CheatUps(c context.Context, mid int64, nickname string, from, limit int) (total int, spies []*model.UpSpy, err error) {
total, err = s.dao.UpSpyCount(c)
if err != nil {
return
}
var query string
if mid > 0 {
query = fmt.Sprintf("WHERE mid=%d", mid)
}
if nickname != "" {
query = fmt.Sprintf("WHERE nickname='%s'", nickname)
}
spies, err = s.dao.UpSpies(c, query, from, limit)
if err != nil {
return
}
if spies == nil {
spies = make([]*model.UpSpy, 0)
}
return
}
// CheatArchives get cheat avs
func (s *Service) CheatArchives(c context.Context, mid, avID int64, nickname string, from, limit int) (total int, spies []*model.ArchiveSpy, err error) {
var query string
if mid > 0 {
query = fmt.Sprintf("WHERE mid=%d", mid)
}
if nickname != "" {
query = fmt.Sprintf("WHERE nickname='%s'", nickname)
}
if avID > 0 {
if len(query) > 0 {
query += fmt.Sprintf(" AND archive_id=%d", avID)
} else {
query = fmt.Sprintf("WHERE archive_id=%d", avID)
}
}
total, err = s.dao.ArchiveSpyCount(c, query)
if err != nil {
return
}
spies, err = s.dao.ArchiveSpies(c, query, from, limit)
if err != nil {
return
}
return
}
// ExportCheatUps export up.
func (s *Service) ExportCheatUps(c context.Context, mid int64, nickname string, from, limit int) (res []byte, err error) {
_, spies, err := s.CheatUps(c, mid, nickname, from, limit)
if err != nil {
log.Error("s.ExportSpyUp QuerySpyUp error(%v)", err)
return
}
data := formatSpyUp(spies)
res, err = FormatCSV(data)
if err != nil {
log.Error("s.ExportSpyUp FormatCSV error(%v)", err)
}
return
}
func formatSpyUp(infos []*model.UpSpy) (data [][]string) {
str := []string{"序号", "UID", "昵称", "签约时间", "粉丝数", "作弊粉丝量", "播放量", "作弊播放量"}
data = append(data, str)
count := 0
for _, info := range infos {
count++
v := []string{strconv.Itoa(count), strconv.FormatInt(info.MID, 10), info.Nickname, time.Unix(int64(info.SignedAt), 0).Format("2006-01-02 15:04:05"), strconv.Itoa(info.Fans), strconv.Itoa(info.CheatFans), strconv.Itoa(info.PlayCount), strconv.Itoa(info.CheatPlayCount)}
data = append(data, v)
}
return
}
// ExportCheatAvs export cheat avs
func (s *Service) ExportCheatAvs(c context.Context, mid, avID int64, nickname string, from, limit int) (res []byte, err error) {
_, infos, err := s.CheatArchives(c, mid, avID, nickname, from, limit)
if err != nil {
log.Error("s.ExportSpyAV QuerySpyArchive error(%v)", err)
return
}
data := fromatSpyAV(infos)
res, err = FormatCSV(data)
if err != nil {
log.Error("s.ExportSpyAV FormatCSV error(%v)", err)
}
return
}
func fromatSpyAV(infos []*model.ArchiveSpy) (data [][]string) {
str := []string{"序号", "稿件ID", "UP昵称", "投稿时间", "累计收入", "作弊播放量", "作弊收藏量", "作弊硬币量"}
data = append(data, str)
count := 0
for _, info := range infos {
count++
v := []string{strconv.Itoa(count), strconv.FormatInt(info.ArchiveID, 10), info.Nickname, time.Unix(int64(info.UploadTime), 0).Format("2006-01-02 15:04:05"), strconv.FormatFloat(float64(info.TotalIncome)/100, 'f', 2, 32), strconv.Itoa(info.CheatPlayCount), strconv.Itoa(info.CheatFavorite), strconv.Itoa(info.CheatCoin)}
data = append(data, v)
}
return
}
// QueryCheatFans query cheat fans.
func (s *Service) QueryCheatFans(c context.Context, from, limit int64) (total int64, fans []*model.CheatFans, err error) {
total, err = s.dao.CheatFansCount(c)
if err != nil {
return
}
fans, err = s.dao.CheatFans(c, from, limit)
return
}
// CheatFans handle checkfans mid.
func (s *Service) CheatFans(c context.Context, mid int64) (err error) {
cu, err := s.cheatFans(c, mid)
if err != nil {
return
}
if cu.RealFans >= 1000 {
return
}
_, err = s.dao.InsertCheatFansInfo(c, cheatFansValues(cu))
return
}
func (s *Service) cheatFans(c context.Context, mid int64) (up *model.CheatFans, err error) {
up = &model.CheatFans{}
v, err := s.dao.UpInfo(c, mid, 3)
if err != nil {
return
}
if v.MID == 0 {
return
}
up.MID = v.MID
up.Nickname = v.Nickname
up.SignedAt = v.SignedAt
up.DeductAt = xtime.Time(time.Now().Unix())
up.RealFans, err = s.dao.GetUpRealFansCount(c, s.conf.Host.Common, v.MID)
if err != nil {
return
}
up.CheatFans, err = s.dao.GetUpCheatFansCount(c, s.conf.Host.Common, v.MID)
if err != nil {
return
}
return
}
func cheatFansValues(cu *model.CheatFans) (values string) {
var buf bytes.Buffer
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(cu.MID, 10))
buf.WriteByte(',')
buf.WriteString(fmt.Sprintf("'%s'", cu.Nickname))
buf.WriteByte(',')
buf.WriteString(fmt.Sprintf("'%s'", cu.SignedAt.Time().Format("2006-01-02 15:04:05")))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(cu.RealFans))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(cu.CheatFans))
buf.WriteByte(',')
buf.WriteString(fmt.Sprintf("'%s'", cu.DeductAt.Time().Format("2006-01-02 15:04-05")))
buf.WriteString(")")
buf.WriteByte(',')
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
}
values = buf.String()
buf.Reset()
return
}

View File

@@ -0,0 +1,50 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_CheatUps(t *testing.T) {
mid := int64(1011)
nickname := "helloworld"
from, limit := 0, 1000
Convey("admins", t, WithService(func(s *Service) {
_, _, err := s.CheatUps(context.Background(), mid, nickname, from, limit)
So(err, ShouldBeNil)
}))
}
func Test_CheatArchives(t *testing.T) {
mid, avID := int64(1011), int64(5011)
nickname := "helloworld"
from, limit := 0, 1000
Convey("admins", t, WithService(func(s *Service) {
_, _, err := s.CheatArchives(context.Background(), mid, avID, nickname, from, limit)
So(err, ShouldBeNil)
}))
}
func Test_ExportCheatUps(t *testing.T) {
mid := int64(1011)
nickname := "helloworld"
from, limit := 0, 1000
Convey("admins", t, WithService(func(s *Service) {
res, err := s.ExportCheatUps(context.Background(), mid, nickname, from, limit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}
func Test_ExportCheatAvs(t *testing.T) {
mid, avID := int64(1011), int64(5011)
nickname := "helloworld"
from, limit := 0, 1000
Convey("admins", t, WithService(func(s *Service) {
res, err := s.ExportCheatAvs(context.Background(), mid, avID, nickname, from, limit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}

View File

@@ -0,0 +1,198 @@
package service
import (
"bytes"
"encoding/csv"
"strconv"
"time"
"go-common/app/admin/main/growup/model"
)
var (
_accountState = map[int]string{
1: "未申请",
2: "待审核",
3: "已签约",
4: "已驳回",
5: "主动退出",
6: "被动退出",
7: "封禁",
}
_avCategory = map[int]string{
0: "默认",
1: "动画",
3: "音乐",
129: "舞蹈",
4: "游戏",
36: "科技",
160: "生活",
119: "鬼畜",
155: "时尚",
23: "电影",
11: "电视剧",
13: "番剧",
167: "国创",
165: "广告",
5: "娱乐",
177: "纪录片",
181: "影视",
}
_cmCategory = map[int]string{
1: "游戏",
2: "动画",
3: "生活",
16: "轻小说",
28: "影视",
29: "兴趣",
}
)
// FormatCSV format to csv data
func FormatCSV(records [][]string) (data []byte, err error) {
buf := new(bytes.Buffer)
// add utf bom
if len(records) > 0 {
buf.WriteString("\xEF\xBB\xBF")
}
w := csv.NewWriter(buf)
err = w.WriteAll(records)
if err != nil {
return
}
data = buf.Bytes()
return
}
func formatBlacklist(blacklist []*model.Blacklist) (data [][]string) {
if len(blacklist) <= 0 {
return
}
data = make([][]string, len(blacklist)+1)
data[0] = []string{"稿件id", "加入时间", "加入原因", "累计收入", "UP主UID", "UP主昵称", "业务类型"}
for i := 0; i < len(blacklist); i++ {
list := blacklist[i]
var ctype, reasonStr string
switch list.CType {
case 0:
ctype = "视频"
case 1:
ctype = "音频"
case 2:
ctype = "专栏"
}
switch list.Reason {
case 1:
reasonStr = "停止收入"
case 2:
reasonStr = "违规扣除"
case 3:
reasonStr = "私单"
case 4:
reasonStr = "绿洲商单"
}
data[i+1] = []string{
strconv.FormatInt(list.AvID, 10),
time.Unix(int64(list.CTime), 0).Format("2006-01-02 15:04:05"),
reasonStr,
strconv.FormatFloat(float64(list.Income)*0.01, 'f', 3, 64),
strconv.FormatInt(list.MID, 10),
list.Nickname,
ctype,
}
}
return
}
func formatUpInfo(ups []*model.UpInfo, states []int64, typ int) (data [][]string) {
if len(ups) <= 0 {
return
}
data = make([][]string, len(ups)+1)
switch typ {
case _video:
data[0] = []string{"UID", "昵称", "原创稿件数", "稿件播放量", "稿件量", "分区", "粉丝数"}
case _column:
data[0] = []string{"UID", "昵称", "稿件数", "阅读量", "分区", "粉丝数"}
case _bgm:
data[0] = []string{"UID", "昵称", "素材量", "视频播放量", "素材使用量", "粉丝数"}
}
if len(states) == 0 {
data[0] = append(data[0], "账号状态")
} else {
switch states[0] {
case 2:
data[0] = append(data[0], "申请时间")
case 3:
data[0] = append(data[0], "申请时间")
data[0] = append(data[0], "签约时间")
case 4:
data[0] = append(data[0], "驳回时间")
data[0] = append(data[0], "到期时间")
case 5:
data[0] = append(data[0], "退出时间")
data[0] = append(data[0], "到期时间")
case 6:
data[0] = append(data[0], "退出时间")
case 7:
data[0] = append(data[0], "封禁时间")
data[0] = append(data[0], "恢复时间")
}
}
for i := 1; i <= len(ups); i++ {
up := ups[i-1]
data[i] = []string{
strconv.FormatInt(up.MID, 10),
up.Nickname,
}
switch typ {
case _video:
data[i] = append(data[i], strconv.Itoa(up.OriginalArchiveCount))
data[i] = append(data[i], strconv.Itoa(up.TotalPlayCount))
data[i] = append(data[i], strconv.Itoa(up.Avs))
data[i] = append(data[i], _avCategory[up.MainCategory])
case _column:
data[i] = append(data[i], strconv.Itoa(up.ArticleCount))
data[i] = append(data[i], strconv.Itoa(up.TotalViewCount))
data[i] = append(data[i], _cmCategory[up.MainCategory])
case _bgm:
data[i] = append(data[i], strconv.Itoa(up.BGMs))
data[i] = append(data[i], strconv.Itoa(up.BgmPlayCount))
data[i] = append(data[i], strconv.Itoa(up.BgmApplyCount))
}
data[i] = append(data[i], strconv.Itoa(up.Fans))
if len(states) == 0 {
data[i] = append(data[i], _accountState[up.AccountState])
} else {
switch states[0] {
case 2:
data[i] = append(data[i], up.ApplyAt.Time().Format("2006-01-02"))
case 3:
data[i] = append(data[i], up.ApplyAt.Time().Format("2006-01-02"))
data[i] = append(data[i], up.SignedAt.Time().Format("2006-01-02"))
case 4:
data[i] = append(data[i], up.RejectAt.Time().Format("2006-01-02"))
data[i] = append(data[i], up.ExpiredIn.Time().Format("2006-01-02"))
case 5:
data[i] = append(data[i], up.QuitAt.Time().Format("2006-01-02"))
data[i] = append(data[i], up.ExpiredIn.Time().Format("2006-01-02"))
case 6:
data[i] = append(data[i], up.DismissAt.Time().Format("2006-01-02"))
case 7:
data[i] = append(data[i], up.ForbidAt.Time().Format("2006-01-02"))
data[i] = append(data[i], up.ExpiredIn.Time().Format("2006-01-02"))
}
}
}
return
}

View File

@@ -0,0 +1,80 @@
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_income_test.go",
"av_breach_test.go",
"blacklist_test.go",
"service_test.go",
"up_account_test.go",
"up_category_info_test.go",
"up_income_test.go",
"up_info_video_test.go",
"withdraw_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/growup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"archive_income.go",
"av_breach.go",
"blacklist.go",
"charge.go",
"const.go",
"format.go",
"lottery.go",
"service.go",
"up_account.go",
"up_category_info.go",
"up_income.go",
"up_info_video.go",
"withdraw.go",
],
importpath = "go-common/app/admin/main/growup/service/income",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/growup/conf:go_default_library",
"//app/admin/main/growup/dao:go_default_library",
"//app/admin/main/growup/dao/income:go_default_library",
"//app/admin/main/growup/dao/message:go_default_library",
"//app/admin/main/growup/dao/resource:go_default_library",
"//app/admin/main/growup/model:go_default_library",
"//app/admin/main/growup/model/income:go_default_library",
"//app/admin/main/growup/service: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/golang.org/x/sync/errgroup: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,380 @@
package income
import (
"context"
"fmt"
"sort"
"strconv"
"time"
model "go-common/app/admin/main/growup/model/income"
"go-common/library/log"
"go-common/library/xstr"
)
// ArchiveStatis archive income statis
func (s *Service) ArchiveStatis(c context.Context, categoryID []int64, typ, groupType int, fromTime, toTime int64) (data interface{}, err error) {
table := setArchiveTableByGroup(typ, groupType)
from := getDateByGroup(groupType, time.Unix(fromTime, 0))
to := getDateByGroup(groupType, time.Unix(toTime, 0))
query := formatArchiveQuery(categoryID, from, to)
if typ == _lottery {
data, err = s.lotteryStatis(c, categoryID, from, addDayByGroup(groupType, to).AddDate(0, 0, -1), groupType)
if err != nil {
log.Error("s.lotteryStatis error(%v)", err)
}
return
}
avs, err := s.GetArchiveStatis(c, table, query)
if err != nil {
log.Error("s.GetArchiveStatis error(%v)", err)
return
}
data = archiveStatis(avs, from, to, groupType)
return
}
func archiveStatis(avs []*model.ArchiveStatis, from, to time.Time, groupType int) interface{} {
avsMap := make(map[string]*model.ArchiveStatis)
ctgyMap := make(map[string]bool)
for _, av := range avs {
date := formatDateByGroup(av.CDate.Time(), groupType)
ctgykey := date + strconv.FormatInt(av.CategroyID, 10)
if val, ok := avsMap[date]; ok {
val.Avs += av.Avs
if !ctgyMap[ctgykey] {
val.Income += av.Income
ctgyMap[ctgykey] = true
}
} else {
avsMap[date] = &model.ArchiveStatis{
Avs: av.Avs,
Income: av.Income,
}
ctgyMap[ctgykey] = true
}
}
return parseArchiveStatis(avsMap, from, to, groupType)
}
func parseArchiveStatis(avsMap map[string]*model.ArchiveStatis, from, to time.Time, groupType int) interface{} {
income, counts, xAxis := []string{}, []int64{}, []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 := avsMap[dateStr]; ok {
income = append(income, fmt.Sprintf("%.2f", float64(val.Income)/float64(100)))
counts = append(counts, val.Avs)
} else {
income = append(income, "0")
counts = append(counts, int64(0))
}
from = addDayByGroup(groupType, from)
}
return map[string]interface{}{
"counts": counts,
"incomes": income,
"xaxis": xAxis,
}
}
// ArchiveSection get av/column income section
func (s *Service) ArchiveSection(c context.Context, categoryID []int64, typ, groupType int, fromTime, toTime int64) (data interface{}, err error) {
table := setArchiveTableByGroup(typ, groupType)
from := getDateByGroup(groupType, time.Unix(fromTime, 0))
to := getDateByGroup(groupType, time.Unix(toTime, 0))
query := formatArchiveQuery(categoryID, from, to)
avs, err := s.GetArchiveStatis(c, table, query)
if err != nil {
log.Error("s.GetArchiveStatis error(%v)", err)
return
}
data = archiveSection(avs, from, to, groupType)
return
}
func archiveSection(avs []*model.ArchiveStatis, from, to time.Time, groupType int) interface{} {
ret := make([]map[string]interface{}, 0)
avsMap := make(map[string][]int64)
for _, av := range avs {
date := formatDateByGroup(av.CDate.Time(), groupType)
if val, ok := avsMap[date]; ok {
val[av.MoneySection] += av.Avs
} else {
avsMap[date] = make([]int64, 12)
avsMap[date][av.MoneySection] = av.Avs
ret = append(ret, map[string]interface{}{
"date_format": date,
"sections": avsMap[date],
})
}
}
return ret
}
// ArchiveDetail archive detail (av column)
func (s *Service) ArchiveDetail(c context.Context, mid int64, typ, groupType int, fromTime, toTime int64) (archives []*model.ArchiveIncome, err error) {
archives = make([]*model.ArchiveIncome, 0)
from := getDateByGroup(groupType, time.Unix(fromTime, 0))
to := getDateByGroup(groupType, time.Unix(toTime, 0))
to = addDayByGroup(groupType, to).AddDate(0, 0, -1)
if typ == _video || typ == _up {
var avs []*model.ArchiveIncome
avs, err = s.archiveDetail(c, _video, groupType, mid, from, to)
if err != nil {
log.Error("s.archiveDetail error(%v)", err)
return
}
archives = append(archives, avs...)
}
if typ == _column || typ == _up {
var columns []*model.ArchiveIncome
columns, err = s.archiveDetail(c, _column, groupType, mid, from, to)
if err != nil {
log.Error("s.archiveDetail error(%v)", err)
return
}
archives = append(archives, columns...)
}
if typ == _bgm || typ == _up {
var bgms []*model.ArchiveIncome
bgms, err = s.archiveDetail(c, _bgm, groupType, mid, from, to)
if err != nil {
log.Error("s.archiveDetail error(%v)", err)
return
}
archives = append(archives, bgms...)
}
return
}
func (s *Service) archiveDetail(c context.Context, typ, groupType int, mid int64, from, to time.Time) (archives []*model.ArchiveIncome, err error) {
archives = make([]*model.ArchiveIncome, 0)
query := fmt.Sprintf("mid = %d", mid)
origins, err := s.GetArchiveIncome(c, typ, query, from.Format(_layout), to.Format(_layout))
if err != nil {
log.Error("s.GetArchiveIncome error(%v)", err)
return
}
var black map[int64]struct{}
black, err = s.dao.GetAvBlackListByMID(c, mid, typ)
if err != nil {
log.Error("s.dao.GetAvBlackListByMID error(%v)", err)
return
}
archives = calArchiveDetail(origins, black, groupType)
return
}
func calArchiveDetail(archives []*model.ArchiveIncome, blackMap map[int64]struct{}, groupType int) []*model.ArchiveIncome {
avsMap := make(map[string]*model.ArchiveIncome)
for _, av := range archives {
if _, ok := blackMap[av.AvID]; ok {
continue
}
date := formatDateByGroup(av.Date.Time(), groupType)
key := date + strconv.FormatInt(av.AvID, 10)
if val, ok := avsMap[key]; ok {
val.Income += av.Income
} else {
av.DateFormat = date
avsMap[key] = av
}
}
list := make([]*model.ArchiveIncome, 0)
for _, av := range avsMap {
list = append(list, av)
}
sort.Slice(list, func(i, j int) bool {
if list[i].DateFormat == list[j].DateFormat {
return list[i].Income > list[j].Income
}
return list[i].DateFormat > list[j].DateFormat
})
return list
}
// ArchiveTop archive_income top
func (s *Service) ArchiveTop(c context.Context, aIDs []int64, typ int, groupType int, fromTime, toTime int64, from, limit int) (data []*model.ArchiveIncome, total int, err error) {
query := ""
if len(aIDs) != 0 {
switch typ {
case _video, _lottery:
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))
}
}
if query == "" && typ != _lottery {
query = fmt.Sprintf("income >= %d", _leastAvIncome)
}
avs, err := s.GetArchiveIncome(c, typ, query, time.Unix(fromTime, 0).Format(_layout), time.Unix(toTime, 0).Format(_layout))
if err != nil {
log.Error("s.GetArchiveIncome error(%v)", err)
return
}
if typ == _lottery {
typ = _video
}
avBMap, err := s.GetAvBlackListByAvIds(c, avs, typ)
if err != nil {
log.Error("s.GetAvBlackListByAvIds error(%v)", err)
return
}
data, total = archiveTop(avs, avBMap, from, limit)
upInfo, err := s.GetUpInfoByAIDs(c, data)
if err != nil {
log.Error("s.GetUpInfoByAIDs error(%v)", err)
return
}
for i := 0; i < len(data); i++ {
data[i].Nickname = upInfo[data[i].MID]
}
return
}
func archiveTop(avs []*model.ArchiveIncome, avBlack map[int64]struct{}, from, limit int) ([]*model.ArchiveIncome, int) {
nAvs := make([]*model.ArchiveIncome, 0)
for _, av := range avs {
if _, ok := avBlack[av.AvID]; ok {
continue
}
av.DateFormat = av.Date.Time().Format(_layout)
nAvs = append(nAvs, av)
}
sort.Slice(nAvs, func(i, j int) bool {
if nAvs[i].Date == nAvs[j].Date {
return nAvs[i].Income > nAvs[j].Income
}
return nAvs[i].Date > nAvs[j].Date
})
if limit+from > len(nAvs) {
limit = len(nAvs)
}
total := len(nAvs)
return nAvs[from:limit], total
}
// BgmDetail bgm detail
func (s *Service) BgmDetail(c context.Context, sid int64, fromTime, toTime int64, from, limit int) (avs []*model.ArchiveIncome, total int, err error) {
avs = make([]*model.ArchiveIncome, 0)
fromDate := time.Unix(fromTime, 0).Format(_layout)
toDate := time.Unix(toTime, 0).Format(_layout)
avMap, err := s.dao.GetAvByBgm(c, sid, fromDate, toDate)
if err != nil {
log.Error("s.dao.GetAvByBgm error(%v)", err)
return
}
if len(avMap) == 0 {
return
}
avIDs := make([]int64, 0, len(avMap))
for avID := range avMap {
avIDs = append(avIDs, avID)
}
avs, err = s.GetArchiveIncome(c, _video, fmt.Sprintf("av_id in (%s)", xstr.JoinInts(avIDs)), fromDate, toDate)
if err != nil {
log.Error("s.GetArchiveIncome error(%v)", err)
return
}
if limit > len(avs) {
limit = len(avs)
}
total = len(avs)
avs = avs[from:limit]
return
}
// GetArchiveStatis get up income
func (s *Service) GetArchiveStatis(c context.Context, table, query string) (avs []*model.ArchiveStatis, err error) {
offset, size := 0, 2000
for {
av, err := s.dao.GetArchiveStatis(c, table, query, offset, size)
if err != nil {
return nil, err
}
avs = append(avs, av...)
if len(av) < size {
break
}
offset += len(av)
}
return
}
// GetArchiveIncome get archive income
func (s *Service) GetArchiveIncome(c context.Context, typ int, query string, from, to string) (archs []*model.ArchiveIncome, err error) {
var id int64
limit := 2000
for {
var arch []*model.ArchiveIncome
arch, err = s.dao.GetArchiveIncome(c, id, query, from, to, limit, typ)
if err != nil {
return
}
archs = append(archs, arch...)
if len(arch) < limit {
break
}
id = arch[len(arch)-1].ID
}
if typ == _bgm {
bgms := make(map[string]*model.ArchiveIncome)
for _, bgm := range archs {
key := bgm.Date.Time().Format(_layout) + strconv.FormatInt(bgm.AvID, 10)
if b, ok := bgms[key]; !ok {
bgms[key] = bgm
} else {
b.Income += bgm.Income
b.TotalIncome += bgm.TotalIncome
b.TaxMoney += bgm.TaxMoney
}
bgms[key].Avs++
}
archs = make([]*model.ArchiveIncome, 0, len(bgms))
for _, b := range bgms {
archs = append(archs, b)
}
}
return
}
func formatDateByGroup(date time.Time, groupType int) string {
str := ""
if groupType == _groupWeek {
date = getStartWeekDate(date)
str = date.Format(_layout) + "~" + date.AddDate(0, 0, 6).Format(_layout)
} else if groupType == _groupMonth {
date = getStartMonthDate(date)
str = date.Format(_layoutMonth)
} else {
str = date.Format(_layout)
}
return str
}
func formatArchiveQuery(categoryID []int64, from, to time.Time) string {
query := "cdate >= '" + from.Format(_layout) + "'"
query += " AND "
query += "cdate <= '" + to.Format(_layout) + "'"
if len(categoryID) != 0 {
query += " AND "
query += "category_id in (" + xstr.JoinInts(categoryID) + ")"
}
return query
}

View File

@@ -0,0 +1,49 @@
package income
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_ArchiveStatis(t *testing.T) {
Convey("ArchiveStatis", t, WithService(func(s *Service) {
categoryID := []int64{}
groupType := 1
var fromTime, endTime int64 = 1524240000000, 1526832000000
_, err := s.ArchiveStatis(context.Background(), categoryID, 0, groupType, fromTime, endTime)
So(err, ShouldBeNil)
}))
}
func Test_ArchiveSection(t *testing.T) {
Convey("ArchiveSection", t, WithService(func(s *Service) {
categoryID := []int64{}
groupType := 1
var fromTime, endTime int64 = 1524240000000, 1526832000000
_, err := s.ArchiveSection(context.Background(), categoryID, 0, groupType, fromTime, endTime)
So(err, ShouldBeNil)
}))
}
func Test_ArchiveDetail(t *testing.T) {
Convey("ArchiveDetail", t, WithService(func(s *Service) {
mid := int64(1)
groupType := 1
var fromTime, endTime int64 = 1524240000000, 1526832000000
_, err := s.ArchiveDetail(context.Background(), mid, 0, groupType, fromTime, endTime)
So(err, ShouldBeNil)
}))
}
func Test_ArchiveTop(t *testing.T) {
Convey("ArchiveTop", t, WithService(func(s *Service) {
avIDs := []int64{}
groupType := 1
var fromTime, endTime int64 = 1524240000000, 1526832000000
from, limit := 0, 10
_, _, err := s.ArchiveTop(context.Background(), avIDs, 0, groupType, fromTime, endTime, from, limit)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,359 @@
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
}

View File

@@ -0,0 +1,19 @@
package income
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_ArchiveBreach(t *testing.T) {
Convey("ArchiveBreach", t, WithService(func(s *Service) {
avID := []int64{}
mid := int64(1)
reason := "test"
operator := "szy"
err := s.ArchiveBreach(context.Background(), 0, avID, mid, reason, operator)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,102 @@
package income
import (
"bytes"
"context"
"strconv"
model "go-common/app/admin/main/growup/model/income"
"go-common/library/database/sql"
"go-common/library/log"
)
// ArchiveBlack stop archives income, add archive into av_black_list
func (s *Service) ArchiveBlack(c context.Context, typ int, aIDs []int64, mid int64) (err error) {
if len(aIDs) == 0 {
return
}
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran error(%v)", err)
return
}
if err = s.TxInsertAvBlacklist(c, tx, typ, aIDs, mid, _avBlack, len(aIDs)); err != nil {
log.Error("s.InsertAvBlacklist error(%v)", err)
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error")
}
return
}
// GetAvBlackListByAvIds get av_black_list by av_id and ctype
func (s *Service) GetAvBlackListByAvIds(c context.Context, avs []*model.ArchiveIncome, ctype int) (avBMap map[int64]struct{}, err error) {
avIDMap := make(map[int64]struct{})
for _, av := range avs {
avIDMap[av.AvID] = struct{}{}
}
avIDList := []int64{}
for avID := range avIDMap {
avIDList = append(avIDList, avID)
}
avBMap = make(map[int64]struct{})
if len(avIDList) > 0 {
avBMap, err = s.dao.ListAvBlackList(c, avIDList, ctype)
if err != nil {
log.Error("s.dao.ListAvBlackList error(%v)", err)
return
}
}
return
}
// TxInsertAvBlacklist insert av_black_list
func (s *Service) TxInsertAvBlacklist(c context.Context, tx *sql.Tx, ctype int, aIDs []int64, mid int64, reason int, count int) (err error) {
nickname, err := s.dao.GetUpInfoNicknameByMID(c, mid, getUpInfoTable(ctype))
if err != nil {
log.Error("s.dao.GetUpInfoNicknameByMID error(%v)", err)
return
}
isDeleted, hasSigned := 0, 0
if nickname != "" {
hasSigned = 1
}
var buf bytes.Buffer
for _, id := range aIDs {
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(id, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(mid, 10))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(ctype))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(reason))
buf.WriteByte(',')
buf.WriteString("\"" + nickname + "\"")
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(hasSigned))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(isDeleted))
buf.WriteString(")")
buf.WriteByte(',')
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
}
vals := buf.String()
buf.Reset()
rows, err := s.dao.TxInsertAvBlackList(tx, vals)
if err != nil {
tx.Rollback()
return
}
if rows < int64(count) {
log.Info("TxInsertAvBlackList(%v) rows(%d) < count(%d) error", vals, rows, count)
}
return
}

View File

@@ -0,0 +1,15 @@
package income
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_GetAvBlackListByAvIds(t *testing.T) {
Convey("GetAvBlackListByAvIds", t, WithService(func(s *Service) {
_, err := s.GetAvBlackListByAvIds(context.Background(), nil, 0)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,227 @@
package income
import (
"context"
"fmt"
"sort"
"strconv"
"time"
"go-common/app/admin/main/growup/dao/resource"
model "go-common/app/admin/main/growup/model/income"
"go-common/library/log"
)
// ArchiveChargeStatis av_charge statis
func (s *Service) ArchiveChargeStatis(c context.Context, categoryID []int64, typ, groupType int, fromTime, toTime int64) (data interface{}, err error) {
table := setChargeTableByGroup(typ, groupType)
from := getDateByGroup(groupType, time.Unix(fromTime, 0))
to := getDateByGroup(groupType, time.Unix(toTime, 0))
query := formatArchiveQuery(categoryID, from, to)
archives, err := s.GetArchiveChargeStatis(c, table, query)
if err != nil {
log.Error("s.GetArchiveChargeStatis error(%v)", err)
return
}
data = archiveChargeStatis(archives, from, to, groupType)
return
}
func archiveChargeStatis(archs []*model.ArchiveChargeStatis, from, to time.Time, groupType int) interface{} {
avsMap := make(map[string]*model.ArchiveChargeStatis)
ctgyMap := make(map[string]bool)
for _, arch := range archs {
date := formatDateByGroup(arch.CDate.Time(), groupType)
ctgykey := date + strconv.FormatInt(arch.CategroyID, 10)
if val, ok := avsMap[date]; ok {
val.Avs += arch.Avs
if !ctgyMap[ctgykey] {
val.Charge += arch.Charge
ctgyMap[ctgykey] = true
}
} else {
avsMap[date] = &model.ArchiveChargeStatis{
Avs: arch.Avs,
Charge: arch.Charge,
}
ctgyMap[ctgykey] = true
}
}
charge, counts, xAxis := []string{}, []int64{}, []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 := avsMap[dateStr]; ok {
charge = append(charge, fmt.Sprintf("%.2f", float64(val.Charge)/float64(100)))
counts = append(counts, val.Avs)
} else {
charge = append(charge, "0")
counts = append(counts, int64(0))
}
from = addDayByGroup(groupType, from)
}
return map[string]interface{}{
"counts": counts,
"charges": charge,
"xaxis": xAxis,
}
}
// ArchiveChargeSection get av_charge section
func (s *Service) ArchiveChargeSection(c context.Context, categoryID []int64, typ, groupType int, fromTime, toTime int64) (data interface{}, err error) {
table := setChargeTableByGroup(typ, groupType)
from := getDateByGroup(groupType, time.Unix(fromTime, 0))
to := getDateByGroup(groupType, time.Unix(toTime, 0))
query := formatArchiveQuery(categoryID, from, to)
archives, err := s.GetArchiveChargeStatis(c, table, query)
if err != nil {
log.Error("s.GetArchiveChargeStatis error(%v)", err)
return
}
data = archiveChargeSection(archives, from, to, groupType)
return
}
func archiveChargeSection(archs []*model.ArchiveChargeStatis, from, to time.Time, groupType int) interface{} {
ret := make([]map[string]interface{}, 0)
avsMap := make(map[string][]int64)
for _, arch := range archs {
date := formatDateByGroup(arch.CDate.Time(), groupType)
if val, ok := avsMap[date]; ok {
val[arch.MoneySection] += arch.Avs
} else {
avsMap[date] = make([]int64, 12)
avsMap[date][arch.MoneySection] = arch.Avs
ret = append(ret, map[string]interface{}{
"date_format": date,
"sections": avsMap[date],
})
}
}
return ret
}
// ArchiveChargeDetail archive charge details
func (s *Service) ArchiveChargeDetail(c context.Context, aid int64, typ int) (archives []*model.ArchiveCharge, err error) {
switch typ {
case _video:
archives, err = s.GetAvCharges(c, aid)
case _column:
archives, err = s.dao.GetColumnCharges(c, aid)
case _bgm:
archives, err = s.dao.GetBgmCharges(c, aid)
default:
err = fmt.Errorf("type error")
}
if err != nil {
log.Error("s.GetArchives(%d) error(%v)", typ, err)
return
}
err = s.archiveChargeDetail(c, archives, aid, typ)
return
}
func (s *Service) archiveChargeDetail(c context.Context, archs []*model.ArchiveCharge, aid int64, typ int) (err error) {
if len(archs) == 0 {
return
}
// get up nickname
nickname, err := resource.NameByMID(c, archs[0].MID)
if err != nil {
return
}
var table, query string
switch typ {
case _video:
table, query = "av_charge_statis", fmt.Sprintf("av_id = %d", aid)
case _column:
table, query = "column_charge_statis", fmt.Sprintf("aid = %d", aid)
case _bgm:
table, query = "bgm_charge_statis", fmt.Sprintf("sid = %d", aid)
}
totalCharge, err := s.dao.GetTotalCharge(c, table, query)
if err != nil {
log.Error("s.GetTotalCharge error(%v)", err)
return
}
sort.Slice(archs, func(i, j int) bool {
return archs[i].Date > archs[j].Date
})
for _, arch := range archs {
arch.TotalCharge = totalCharge
arch.Nickname = nickname
totalCharge -= arch.Charge
}
return
}
// BgmChargeDetail bgm charge detail
func (s *Service) BgmChargeDetail(c context.Context, sid int64) (archives []*model.ArchiveCharge, err error) {
archives = make([]*model.ArchiveCharge, 0)
bgms, err := s.dao.GetBgmCharges(c, sid)
if err != nil {
log.Error("s.dao.GetBgmCharges error(%v)", err)
return
}
avIDs := make(map[int64]struct{})
for _, bgm := range bgms {
avIDs[bgm.AvID] = struct{}{}
}
for avID := range avIDs {
var avs []*model.ArchiveCharge
avs, err = s.ArchiveChargeDetail(c, avID, _video)
if err != nil {
log.Error("s.ArchiveChargeDetail error(%v)", err)
return
}
archives = append(archives, avs...)
}
return
}
// UpRatio up charge ratio
func (s *Service) UpRatio(c context.Context, from, limit int64) (map[int64]int64, error) {
return s.dao.UpRatio(c, from, limit)
}
// GetAvCharges get av charge by av id
func (s *Service) GetAvCharges(c context.Context, avID int64) (avs []*model.ArchiveCharge, err error) {
avs = make([]*model.ArchiveCharge, 0)
for i := 1; i <= 12; i++ {
var av []*model.ArchiveCharge
av, err = s.dao.GetAvDailyCharge(c, i, avID)
if err != nil {
return
}
avs = append(avs, av...)
}
return
}
// GetArchiveChargeStatis get archive charge date statis
func (s *Service) GetArchiveChargeStatis(c context.Context, table, query string) (archs []*model.ArchiveChargeStatis, err error) {
offset, size := 0, 2000
for {
var arch []*model.ArchiveChargeStatis
arch, err = s.dao.GetArchiveChargeStatis(c, table, query, offset, size)
if err != nil {
return
}
archs = append(archs, arch...)
if len(arch) < size {
break
}
offset += len(arch)
}
return
}

View File

@@ -0,0 +1,201 @@
package income
import (
"time"
)
var (
_layout = "2006-01-02"
_layoutMonth = "2006-01"
)
const (
_upIncome = "up_income"
_upIncomeWeekly = "up_income_weekly"
_upIncomeMonthly = "up_income_monthly"
_avDailyStatis = "av_income_daily_statis"
_avWeeklyStatis = "av_income_weekly_statis"
_avMonthlyStatis = "av_income_monthly_statis"
_cmDailyStatis = "column_income_daily_statis"
_cmWeeklyStatis = "column_income_weekly_statis"
_cmMonthlyStatis = "column_income_monthly_statis"
_bgmDailyStatis = "bgm_income_daily_statis"
_bgmWeeklyStatis = "bgm_income_weekly_statis"
_bgmMonthlyStatis = "bgm_income_monthly_statis"
_avChargeDailyStatis = "av_charge_daily_statis"
_avChargeWeeklyStatis = "av_charge_weekly_statis"
_avChargeMonthlyStatis = "av_charge_monthly_statis"
_cmChargeDailyStatis = "column_charge_daily_statis"
_cmChargeWeeklyStatis = "column_charge_weekly_statis"
_cmChargeMonthlyStatis = "column_charge_monthly_statis"
_bgmChargeDailyStatis = "bgm_charge_daily_statis"
_bgmChargeWeeklyStatis = "bgm_charge_weekly_statis"
_bgmChargeMonthlyStatis = "bgm_charge_monthly_statis"
_upIncomeDailyStatis = "up_income_daily_statis"
_upAvDailyStatis = "up_av_daily_statis"
_upColumnDailyStatis = "up_column_daily_statis"
_upBgmDailyStatis = "up_bgm_daily_statis"
_groupDay = 1
_groupWeek = 2
_groupMonth = 3
_video = 0
// _audio = 1
_column = 2
_bgm = 3
_up = 4
_lottery = 5 // 动态抽奖
_leastAvIncome = 30000
// add blacklist reason
_avBlack = 1
_avBreach = 2
)
func getUpInfoTable(typ int) (table string) {
switch typ {
case _video:
table = "up_info_video"
case _column:
table = "up_info_column"
case _bgm:
table = "up_info_bgm"
}
return
}
func getUpInfoByType(typ int) (table string, incomeType string) {
switch typ {
case _video:
table, incomeType = _upAvDailyStatis, "av_income"
case _column:
table, incomeType = _upColumnDailyStatis, "column_income"
case _bgm:
table, incomeType = _upBgmDailyStatis, "bgm_income"
case _up:
table, incomeType = _upIncomeDailyStatis, "income"
}
return
}
func getUpFieldByType(typ int) (field string) {
switch typ {
case _video:
field = "av_income,av_tax,av_base_income,av_total_income"
case _column:
field = "column_income,column_tax,column_base_income,column_total_income"
case _bgm:
field = "bgm_income,bgm_tax,bgm_base_income,bgm_total_income"
case _up:
field = "income,tax_money,base_income,total_income"
}
return
}
func setUpTableByGroup(groupType int) string {
table := _upIncome
if groupType == _groupWeek {
table = _upIncomeWeekly
} else if groupType == _groupMonth {
table = _upIncomeMonthly
}
return table
}
func setArchiveTableByGroup(typ, groupType int) string {
table := ""
switch typ {
case _video:
table = _avDailyStatis
if groupType == _groupWeek {
table = _avWeeklyStatis
} else if groupType == _groupMonth {
table = _avMonthlyStatis
}
case _column:
table = _cmDailyStatis
if groupType == _groupWeek {
table = _cmWeeklyStatis
} else if groupType == _groupMonth {
table = _cmMonthlyStatis
}
case _bgm:
table = _bgmDailyStatis
if groupType == _groupWeek {
table = _bgmWeeklyStatis
} else if groupType == _groupMonth {
table = _bgmMonthlyStatis
}
}
return table
}
func setChargeTableByGroup(typ, groupType int) string {
table := ""
switch typ {
case _video:
table = _avChargeDailyStatis
if groupType == _groupWeek {
table = _avChargeWeeklyStatis
} else if groupType == _groupMonth {
table = _avChargeMonthlyStatis
}
case _column:
table = _cmChargeDailyStatis
if groupType == _groupWeek {
table = _cmChargeWeeklyStatis
} else if groupType == _groupMonth {
table = _cmChargeMonthlyStatis
}
case _bgm:
table = _bgmChargeDailyStatis
if groupType == _groupWeek {
table = _bgmChargeWeeklyStatis
} else if groupType == _groupMonth {
table = _bgmChargeMonthlyStatis
}
}
return table
}
func getDateByGroup(groupType int, date time.Time) time.Time {
if groupType == _groupWeek {
return getStartWeekDate(date)
} else if groupType == _groupMonth {
return getStartMonthDate(date)
}
return date
}
func addDayByGroup(groupType int, date time.Time) time.Time {
if groupType == _groupWeek {
return date.AddDate(0, 0, 7)
} else if groupType == _groupMonth {
return date.AddDate(0, 1, 0)
}
return date.AddDate(0, 0, 1)
}
func getStartWeekDate(date time.Time) time.Time {
for date.Weekday() != time.Monday {
date = date.AddDate(0, 0, -1)
}
return date
}
func getStartMonthDate(date time.Time) time.Time {
return time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, time.Local)
}
func fromYuanToFen(d int64) float64 {
return float64(d) / float64(100)
}

View File

@@ -0,0 +1,105 @@
package income
import (
"fmt"
"strconv"
model "go-common/app/admin/main/growup/model/income"
)
func formatUpWithdraw(ups []*model.UpWithdrawRes, isDeleted int) (data [][]string) {
if len(ups) <= 0 {
return
}
data = make([][]string, len(ups)+1)
if isDeleted == 0 {
data[0] = []string{"UID", "昵称", "已提现", "未提现", "最近提现时间"}
for i := 1; i <= len(ups); i++ {
up := ups[i-1]
data[i] = []string{
strconv.FormatInt(up.MID, 10),
up.Nickname,
up.WithdrawIncome,
up.UnWithdrawIncome,
up.WithdrawDate,
}
}
} else {
data[0] = []string{"UID", "昵称", "禁止提现", "禁止时间", "已提现", "最近提现时间"}
for i := 1; i <= len(ups); i++ {
up := ups[i-1]
data[i] = []string{
strconv.FormatInt(up.MID, 10),
up.Nickname,
up.UnWithdrawIncome,
up.MTime.Time().Format(_layout),
up.WithdrawIncome,
up.WithdrawDate,
}
}
}
return
}
func formatUpIncomeWithdraw(ups []*model.UpIncomeWithdraw) (data [][]string) {
if len(ups) <= 0 {
return
}
data = make([][]string, len(ups)+1)
data[0] = []string{"最近一次提现日期", "UP主ID", "UP主昵称", "已经提现的收入"}
for i := 1; i <= len(ups); i++ {
up := ups[i-1]
data[i] = []string{
up.MTime.Time().Format("2006-01-02"),
strconv.FormatInt(up.MID, 10),
up.Nickname,
fmt.Sprintf("%.2f", fromYuanToFen(up.WithdrawIncome)),
}
}
return
}
func formatUpIncome(ups []*model.UpIncome) (data [][]string) {
if len(ups) <= 0 {
return
}
data = make([][]string, 1)
data[0] = []string{"时间", "UID", "昵称", "新增收入", "稿件数", "基础收入", "额外收入", "违规扣除", "扣税金额", "累计收入"}
for _, up := range ups {
data = append(data, []string{
up.DateFormat,
strconv.FormatInt(up.MID, 10),
up.Nickname,
fmt.Sprintf("%.2f", fromYuanToFen(up.Income)),
strconv.FormatInt(up.AvCount, 10),
fmt.Sprintf("%.2f", fromYuanToFen(up.BaseIncome)),
fmt.Sprintf("%.2f", fromYuanToFen(up.ExtraIncome)),
fmt.Sprintf("%.2f", fromYuanToFen(up.Breach)),
fmt.Sprintf("%.2f", fromYuanToFen(up.TaxMoney)),
fmt.Sprintf("%.2f", fromYuanToFen(up.TotalIncome)),
})
}
return
}
func formatBreach(breachs []*model.AvBreach) (data [][]string) {
if len(breachs) <= 0 {
return
}
ctype := []string{"视频", "音频", "专栏", "素材"}
data = make([][]string, 1)
data[0] = []string{"日期", "稿件id", "稿件类型", "投稿时间", "UID", "up主昵称", "扣除金额", "扣除原因"}
for _, b := range breachs {
data = append(data, []string{
b.CDate.Time().Format(_layout),
strconv.FormatInt(b.AvID, 10),
ctype[b.CType],
b.UploadTime.Time().Format(_layout),
strconv.FormatInt(b.MID, 10),
b.Nickname,
fmt.Sprintf("%.2f", fromYuanToFen(b.Money)),
b.Reason,
})
}
return
}

View File

@@ -0,0 +1,39 @@
package income
import (
"context"
"fmt"
"time"
model "go-common/app/admin/main/growup/model/income"
"go-common/library/log"
"go-common/library/xstr"
)
func (s *Service) lotteryStatis(c context.Context, categoryID []int64, from, to time.Time, groupType int) (data interface{}, err error) {
query := ""
if len(categoryID) != 0 {
query = fmt.Sprintf("tag_id in (%s)", xstr.JoinInts(categoryID))
}
avs, err := s.GetArchiveIncome(c, _lottery, query, from.Format(_layout), to.Format(_layout))
if err != nil {
log.Error("s.GetArchiveIncome error(%v)")
return
}
avsMap := make(map[string]*model.ArchiveStatis)
for _, av := range avs {
date := formatDateByGroup(av.Date.Time(), groupType)
if val, ok := avsMap[date]; ok {
val.Income += av.Income
val.Avs++
} else {
avsMap[date] = &model.ArchiveStatis{
Income: av.Income,
Avs: 1,
}
}
}
data = parseArchiveStatis(avsMap, from, to, groupType)
return
}

View File

@@ -0,0 +1,39 @@
package income
import (
"context"
"go-common/app/admin/main/growup/conf"
upD "go-common/app/admin/main/growup/dao"
incomeD "go-common/app/admin/main/growup/dao/income"
"go-common/app/admin/main/growup/dao/message"
)
// Service struct
type Service struct {
conf *conf.Config
dao *incomeD.Dao
msg *message.Dao
upDao *upD.Dao
}
// New fn
func New(c *conf.Config) (s *Service) {
s = &Service{
conf: c,
dao: incomeD.New(c),
msg: message.New(c),
upDao: upD.New(c),
}
return s
}
// Ping check dao health.
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close dao
func (s *Service) Close() {
s.dao.Close()
}

View File

@@ -0,0 +1,28 @@
package income
import (
"flag"
"path/filepath"
"time"
"go-common/app/admin/main/growup/conf"
)
var (
s *Service
)
func init() {
dir, _ := filepath.Abs("../../cmd/growup-admin.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
// Reset(func() { CleanCache() })
f(s)
}
}

View File

@@ -0,0 +1,95 @@
package income
import (
"context"
"fmt"
model "go-common/app/admin/main/growup/model/income"
"go-common/library/database/sql"
"go-common/library/log"
)
// GetUpAccount get up_account
func (s *Service) GetUpAccount(c context.Context, query string, isDeleted int) (ups []*model.UpAccount, err error) {
from, limit := 0, 2000
for {
var up []*model.UpAccount
up, err = s.ListUpAccount(c, query, isDeleted, from, limit)
if err != nil {
return
}
ups = append(ups, up...)
if len(up) < limit {
break
}
from += limit
}
return
}
// TxUpAccountBreach up_account breach
func (s *Service) TxUpAccountBreach(c context.Context, tx *sql.Tx, mid, preMonthBreach, thisMonthBreach int64) error {
if mid <= 0 {
return fmt.Errorf("请输入正确的mid,请确认")
}
if preMonthBreach < 0 {
return fmt.Errorf("未提现金额必须大于等于零,请确认")
}
if thisMonthBreach < 0 {
return fmt.Errorf("当前月未提现金额必须大于等于零,请确认")
}
times := 0
for {
upAccount, err := s.dao.GetUpAccount(c, mid)
if err != nil {
log.Error("s.dao.GetUpAccount error(%v)", err)
return err
}
total := upAccount.TotalIncome - preMonthBreach - thisMonthBreach
unwithdraw := upAccount.TotalUnwithdrawIncome - preMonthBreach
if total < 0 {
log.Info("up_account(%d) total(%d) < 0", mid, total)
total = 0
}
if unwithdraw < 0 {
log.Info("up_account(%d) total_unwithdraw_income(%d) < 0", mid, unwithdraw)
unwithdraw = 0
}
rows, err := s.dao.TxBreachUpAccount(tx, total, unwithdraw, mid, upAccount.Version+1, upAccount.Version)
if err != nil {
tx.Rollback()
log.Error("s.dao.TxBreachUpAccount error(%v)", err)
return err
}
if rows == 1 {
break
}
times++
if times >= 5 {
tx.Rollback()
return fmt.Errorf("更新up主金额错误")
}
}
return nil
}
// UpAccountCount get up_account count
func (s *Service) UpAccountCount(c context.Context, query string, isDeleted int) (total int64, err error) {
if query != "" {
query += " AND"
}
return s.dao.UpAccountCount(c, query, isDeleted)
}
// ListUpAccount list up account bu query
func (s *Service) ListUpAccount(c context.Context, query string, isDeleted, from, limit int) (ups []*model.UpAccount, err error) {
if query != "" {
query += " AND"
}
return s.dao.ListUpAccount(c, query, isDeleted, from, limit)
}

View File

@@ -0,0 +1,22 @@
package income
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_TxUpAccountBreach(t *testing.T) {
Convey("TxUpAccountBreach", t, WithService(func(s *Service) {
tx, _ := s.dao.BeginTran(context.Background())
err := s.TxUpAccountBreach(context.Background(), tx, 11, -1, 1)
So(err, ShouldNotBeNil)
}))
Convey("TxUpAccountBreach", t, WithService(func(s *Service) {
tx, _ := s.dao.BeginTran(context.Background())
err := s.TxUpAccountBreach(context.Background(), tx, 11, 1, -1)
So(err, ShouldNotBeNil)
}))
}

View File

@@ -0,0 +1,29 @@
package income
import (
"context"
model "go-common/app/admin/main/growup/model/income"
"go-common/library/log"
)
// GetUpInfoByAIDs get up_info by av id
func (s *Service) GetUpInfoByAIDs(c context.Context, avs []*model.ArchiveIncome) (upInfoMap map[int64]string, err error) {
midMap := make(map[int64]struct{})
for _, av := range avs {
midMap[av.MID] = struct{}{}
}
midList := []int64{}
for mid := range midMap {
midList = append(midList, mid)
}
upInfoMap = make(map[int64]string)
if len(midList) > 0 {
upInfoMap, err = s.dao.ListUpInfo(c, midList)
if err != nil {
log.Error("s.dao.ListUpInfo error(%v)", err)
return
}
}
return
}

View File

@@ -0,0 +1,15 @@
package income
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_GetUpInfoByAIDs(t *testing.T) {
Convey("GetUpInfoByAIDs", t, WithService(func(s *Service) {
_, err := s.GetUpInfoByAIDs(context.Background(), nil)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,232 @@
package income
import (
"context"
"fmt"
"sort"
"time"
model "go-common/app/admin/main/growup/model/income"
"go-common/app/admin/main/growup/service"
"go-common/library/log"
"go-common/library/xstr"
)
// UpIncomeList up income list
func (s *Service) UpIncomeList(c context.Context, mids []int64, typ, groupType int, fromTime, toTime, minIncome, maxIncome int64, from, limit int) (upIncome []*model.UpIncome, total int, err error) {
table := setUpTableByGroup(groupType)
_, incomeType := getUpInfoByType(typ)
fromDate := getDateByGroup(groupType, time.Unix(fromTime, 0))
toDate := getDateByGroup(groupType, time.Unix(toTime, 0))
typeField := getUpFieldByType(typ)
query := formatUpQuery(mids, fromDate, toDate, incomeType)
if maxIncome != 0 || minIncome != 0 {
query = fmt.Sprintf("%s AND %s >= %d AND %s <= %d", query, incomeType, minIncome, incomeType, maxIncome)
}
total, err = s.dao.UpIncomeCount(c, table, query)
if err != nil {
log.Error("s.dao.UpIncomeCount error(%v)", err)
return
}
upIncome, err = s.dao.GetUpIncomeBySort(c, table, typeField, incomeType, query, from, limit)
if err != nil {
log.Error("s.dao.GetUpIncomeBySort error(%v)", err)
return
}
if len(upIncome) == 0 {
return
}
for _, up := range upIncome {
mids = append(mids, up.MID)
}
nicknames, err := s.dao.ListUpInfo(c, mids)
if err != nil {
log.Error("s.dao.ListUpInfo error(%v)", err)
return
}
var breachType []int64
switch typ {
case _video:
breachType = []int64{0}
case _column:
breachType = []int64{2}
case _bgm:
breachType = []int64{3}
case _up:
breachType = []int64{0, 1, 2, 3}
}
breachs, err := s.dao.GetAvBreachByMIDs(c, mids, breachType)
if err != nil {
log.Error("s.dao.GetAvBreachByMIDs error(%v)", err)
return
}
upIncomeList(upIncome, nicknames, breachs, typ, groupType)
return
}
func upIncomeList(upIncome []*model.UpIncome, nicknames map[int64]string, breachs []*model.AvBreach, typ, groupType int) {
midDateBreach := make(map[int64]map[string]int64) // map[mid][date] = money
for _, b := range breachs {
dateFormat := formatDateByGroup(b.CDate.Time(), groupType)
if _, ok := midDateBreach[b.MID]; !ok {
midDateBreach[b.MID] = make(map[string]int64)
}
midDateBreach[b.MID][dateFormat] += b.Money
}
for _, up := range upIncome {
up.Nickname = nicknames[up.MID]
up.DateFormat = formatDateByGroup(up.Date.Time(), groupType)
up.ExtraIncome = up.Income - up.BaseIncome
if _, ok := midDateBreach[up.MID]; ok {
up.Breach = midDateBreach[up.MID][up.DateFormat]
}
switch typ {
case _video:
up.Count = up.AvCount
case _column:
up.Count = up.ColumnCount
case _bgm:
up.Count = up.BgmCount
case _up:
up.Count = up.AvCount + up.ColumnCount + up.BgmCount
}
}
}
// UpIncomeListExport up income list
func (s *Service) UpIncomeListExport(c context.Context, mids []int64, typ, groupType int, fromTime, toTime, minIncome, maxIncome int64, from, limit int) (res []byte, err error) {
ups, _, err := s.UpIncomeList(c, mids, typ, groupType, fromTime, toTime, minIncome, maxIncome, from, limit)
if err != nil {
log.Error("s.UpIncomeList error(%v)", err)
return
}
records := formatUpIncome(ups)
res, err = service.FormatCSV(records)
if err != nil {
log.Error("FormatCSV error(%v)")
}
return
}
// UpIncomeStatis up income statis
func (s *Service) UpIncomeStatis(c context.Context, mids []int64, typ, groupType int, fromTime, toTime int64) (data interface{}, err error) {
from := getDateByGroup(groupType, time.Unix(fromTime, 0))
to := getDateByGroup(groupType, time.Unix(toTime, 0))
if groupType == _groupDay && len(mids) == 0 {
return s.upStatisDaily(c, typ, from, to)
}
return s.upIncomeStatisDate(c, mids, typ, groupType, from, to)
}
func (s *Service) upStatisDaily(c context.Context, typ int, from, to time.Time) (data interface{}, err error) {
table, _ := getUpInfoByType(typ)
statis, err := s.dao.GetUpDailyStatis(c, table, from.Format(_layout), to.Format(_layout))
if err != nil {
log.Error("s.dao.GetIncomeDailyStatis error(%v)", err)
return
}
dateMap := make(map[string]*model.UpStatisRsp)
for _, sta := range statis {
date := sta.Date.Time().Format(_layout)
if val, ok := dateMap[date]; ok {
val.Ups += sta.Ups
} else {
dateMap[date] = &model.UpStatisRsp{
Income: sta.Income,
Ups: sta.Ups,
}
}
}
data = calUpStatis(dateMap, 1, from, to)
return
}
func (s *Service) upIncomeStatisDate(c context.Context, mids []int64, typ, groupType int, from, to time.Time) (data interface{}, err error) {
table := setUpTableByGroup(groupType)
_, incomeType := getUpInfoByType(typ)
query := formatUpQuery(mids, from, to, incomeType)
upIncome, err := s.GetUpIncome(c, table, incomeType, query)
if err != nil {
log.Error("s.GetUpIncome error(%v)", err)
return
}
sort.Slice(upIncome, func(i, j int) bool {
return upIncome[i].Date < upIncome[j].Date
})
dateMap := make(map[string]*model.UpStatisRsp)
for _, up := range upIncome {
date := formatDateByGroup(up.Date.Time(), groupType)
if val, ok := dateMap[date]; ok {
val.Income += up.Income
val.Ups++
} else {
dateMap[date] = &model.UpStatisRsp{
Income: up.Income,
Ups: 1,
}
}
}
data = calUpStatis(dateMap, groupType, from, to)
return
}
func calUpStatis(dateMap map[string]*model.UpStatisRsp, groupType int, from, to time.Time) interface{} {
incomes, ups, xAxis := []string{}, []int{}, []string{}
to = to.AddDate(0, 0, 1)
for from.Before(to) {
dateStr := formatDateByGroup(from, groupType)
xAxis = append(xAxis, dateStr)
if val, ok := dateMap[dateStr]; ok {
incomes = append(incomes, fmt.Sprintf("%.2f", float64(val.Income)/float64(100)))
ups = append(ups, val.Ups)
} else {
incomes = append(incomes, "0")
ups = append(ups, 0)
}
from = addDayByGroup(groupType, from)
}
return map[string]interface{}{
"counts": ups,
"incomes": incomes,
"xaxis": xAxis,
}
}
// GetUpIncome get
func (s *Service) GetUpIncome(c context.Context, table, incomeType, query string) (upIncomes []*model.UpIncome, err error) {
var id int64
limit := 2000
for {
upIncome, err := s.dao.GetUpIncome(c, table, incomeType, query, id, limit)
if err != nil {
return upIncomes, err
}
upIncomes = append(upIncomes, upIncome...)
if len(upIncome) < limit {
break
}
id = upIncome[len(upIncome)-1].ID
}
return
}
func formatUpQuery(mids []int64, fromTime, toTime time.Time, incomeType string) string {
query := "date >= '" + fromTime.Format("2006-01-02") + "'"
query += " AND "
query += "date <= '" + toTime.Format("2006-01-02") + "'"
if len(mids) != 0 {
query += " AND "
query += "mid in (" + xstr.JoinInts(mids) + ")"
}
query += fmt.Sprintf(" AND %s > 0", incomeType)
return query
}

View File

@@ -0,0 +1,51 @@
package income
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func Test_UpIncomeStatis(t *testing.T) {
Convey("UpIncomeStatis", t, WithService(func(s *Service) {
mids := []int64{}
groupType := 1
fromTime := time.Now().AddDate(0, -1, 0).Unix() * 1000
toTime := time.Now().Unix() * 1000
_, err := s.UpIncomeStatis(context.Background(), mids, 0, groupType, fromTime, toTime)
So(err, ShouldBeNil)
}))
}
func Test_GetUpIncome(t *testing.T) {
Convey("GetUpIncome", t, WithService(func(s *Service) {
mids := []int64{}
fromTime := time.Now().AddDate(0, -1, 0)
toTime := time.Now()
query := formatUpQuery(mids, fromTime, toTime, "income")
_, err := s.GetUpIncome(context.Background(), "up_income", "income", query)
So(err, ShouldBeNil)
}))
}
func BenchmarkUpIncomeStatis(b *testing.B) {
for n := 0; n < b.N; n++ {
mids := []int64{}
groupType := 1
fromTime := time.Now().AddDate(0, -1, 0).Unix() * 1000
toTime := time.Now().Unix() * 1000
s.UpIncomeStatis(context.Background(), mids, 0, groupType, fromTime, toTime)
}
}
func BenchmarkGetUpIncome(b *testing.B) {
for n := 0; n < b.N; n++ {
mids := []int64{}
fromTime := time.Now().AddDate(0, -1, 0)
toTime := time.Now()
query := formatUpQuery(mids, fromTime, toTime, "income")
s.GetUpIncome(context.Background(), "up_income", "income", query)
}
}

View File

@@ -0,0 +1,23 @@
package income
import (
"go-common/library/database/sql"
"go-common/library/log"
)
// TxUpdateUpInfoScore update up_info_video score
func (s *Service) TxUpdateUpInfoScore(tx *sql.Tx, mid int64, score int) (err error) {
_, err = s.dao.TxUpdateUpInfoScore(tx, "up_info_video", score, mid)
if err != nil {
tx.Rollback()
log.Error("s.dao.TxUpdateUpInfoScore error(%v)", err)
return err
}
_, err = s.dao.TxUpdateUpInfoScore(tx, "up_info_column", score, mid)
if err != nil {
tx.Rollback()
log.Error("s.dao.TxUpdateUpInfoScore error(%v)", err)
}
return
}

View File

@@ -0,0 +1,23 @@
package income
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_UpInfoVideo(t *testing.T) {
Convey("update up_info_video score", t, WithService(func(s *Service) {
var (
mid = int64(1101)
score = 100
)
tx, err := s.dao.BeginTran(context.Background())
So(err, ShouldBeNil)
err = s.TxUpdateUpInfoScore(tx, mid, score)
So(err, ShouldBeNil)
err = tx.Commit()
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,221 @@
package income
import (
"context"
"fmt"
"sort"
"time"
model "go-common/app/admin/main/growup/model/income"
"go-common/app/admin/main/growup/service"
"go-common/library/log"
"go-common/library/xstr"
)
// UpWithdraw get up_account infos
func (s *Service) UpWithdraw(c context.Context, mids []int64, isDeleted, from, limit int) (data []*model.UpWithdrawRes, total int64, err error) {
query := ""
if len(mids) != 0 {
query += fmt.Sprintf("mid in (%s)", xstr.JoinInts(mids))
}
total, err = s.UpAccountCount(c, query, isDeleted)
if err != nil {
log.Error("s.UpAccountCount error(%v)", err)
return
}
ups, err := s.ListUpAccount(c, query, isDeleted, from, limit)
if err != nil {
log.Error("s.ListUpAccount error(%v)", err)
return
}
if len(mids) == 0 {
for _, up := range ups {
mids = append(mids, up.MID)
}
}
query = ""
if len(mids) != 0 {
query = fmt.Sprintf("mid in (%s)", xstr.JoinInts(mids))
}
upWithdraw, err := s.GetUpWithdraw(c, query)
if err != nil {
log.Error("s.GetUpWithdraw error(%v)", err)
return
}
withdrawMap := make(map[string]int64)
for _, w := range upWithdraw {
key := fmt.Sprintf("%d+%s", w.MID, w.DateVersion)
withdrawMap[key] = w.WithdrawIncome
}
upInfo, err := s.dao.ListUpInfo(c, mids)
if err != nil {
log.Error("s.dao.ListUpInfo error(%v)", err)
return
}
sort.Slice(ups, func(i, j int) bool {
return ups[i].LastWithdrawTime > ups[j].LastWithdrawTime
})
data = make([]*model.UpWithdrawRes, 0)
for _, up := range ups {
key := fmt.Sprintf("%d+%s", up.MID, up.WithdrawDateVersion)
data = append(data, &model.UpWithdrawRes{
MID: up.MID,
Nickname: upInfo[up.MID],
WithdrawIncome: fmt.Sprintf("%0.2f", fromYuanToFen(up.TotalWithdrawIncome)),
UnWithdrawIncome: fmt.Sprintf("%0.2f", fromYuanToFen(up.TotalUnwithdrawIncome)),
LastWithdrawIncome: fmt.Sprintf("%0.2f", fromYuanToFen(withdrawMap[key])),
WithdrawDate: up.LastWithdrawTime.Time().Format(_layout),
MTime: up.MTime,
})
}
return
}
// UpWithdrawExport export up withdraw
func (s *Service) UpWithdrawExport(c context.Context, mids []int64, isDeleted, from, limit int) (res []byte, err error) {
upWithdraw, _, err := s.UpWithdraw(c, mids, isDeleted, from, limit)
if err != nil {
log.Error("s.UpWithdraw error(%v)", err)
return
}
records := formatUpWithdraw(upWithdraw, isDeleted)
res, err = service.FormatCSV(records)
if err != nil {
log.Error("FormatCSV error(%v)")
}
return
}
// GetUpWithdraw get up_withdraw
func (s *Service) GetUpWithdraw(c context.Context, query string) (upW []*model.UpIncomeWithdraw, err error) {
upW = make([]*model.UpIncomeWithdraw, 0)
var id int64
limit := 2000
for {
var w []*model.UpIncomeWithdraw
w, err = s.ListUpWithdraw(c, id, query, limit)
if err != nil {
return
}
upW = append(upW, w...)
if len(w) < limit {
break
}
id = w[len(w)-1].ID
}
return
}
// ListUpWithdraw list up_withdraw
func (s *Service) ListUpWithdraw(c context.Context, id int64, query string, limit int) (upWithdraw []*model.UpIncomeWithdraw, err error) {
if query != "" {
query += " AND"
}
return s.dao.ListUpWithdraw(c, id, query, limit)
}
// UpWithdrawStatis up_withdraw statis
func (s *Service) UpWithdrawStatis(c context.Context, from, to int64, isDeleted int) (data interface{}, err error) {
now := time.Now()
var fromTime, toTime time.Time
if from == 0 || to == 0 {
fromTime = time.Date(now.Year()-1, now.Month(), 1, 0, 0, 0, 0, time.Local)
toTime = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.Local)
} else {
fromTime = time.Unix(from, 0)
toTime = time.Unix(to, 0)
}
query := fmt.Sprintf("date_version >= '%s' and date_version <= '%s'", fromTime.Format(_layoutMonth), toTime.Format(_layoutMonth))
upWithdraw, err := s.GetUpWithdraw(c, query)
if err != nil {
log.Error("s.GetUpWithdraw error(%v)", err)
return
}
deletedUp, err := s.GetUpAccount(c, "", 1)
if err != nil {
log.Error("s.GetUpAccount error(%v)", err)
return
}
deletedUpMap := make(map[int64]struct{})
for _, up := range deletedUp {
deletedUpMap[up.MID] = struct{}{}
}
data = upWithdrawStatis(upWithdraw, deletedUpMap, isDeleted, fromTime, toTime)
return
}
func upWithdrawStatis(upWithdraw []*model.UpIncomeWithdraw, deletedUp map[int64]struct{}, isDeleted int, startTime, endTime time.Time) interface{} {
dateCount := make(map[string]int)
dateIncome := make(map[string]int64)
for _, up := range upWithdraw {
_, ok := deletedUp[up.MID]
if (ok && isDeleted == 1) || (!ok && isDeleted == 0) {
dateCount[up.DateVersion]++
dateIncome[up.DateVersion] += up.WithdrawIncome
}
}
incomes, counts, xAxis := []string{}, []int{}, []string{}
endTime = endTime.AddDate(0, 0, 1)
for startTime.Before(endTime) {
key := startTime.Format(_layoutMonth)
incomes = append(incomes, fmt.Sprintf("%0.2f", fromYuanToFen(dateIncome[key])))
counts = append(counts, dateCount[key])
xAxis = append(xAxis, key)
startTime = startTime.AddDate(0, 1, 0)
}
return map[string]interface{}{
"incomes": incomes,
"counts": counts,
"xaxis": xAxis,
}
}
// UpWithdrawDetail get up withdraw by mid
func (s *Service) UpWithdrawDetail(c context.Context, mid int64) (upWithdraw []*model.UpIncomeWithdraw, err error) {
query := fmt.Sprintf("mid = %d", mid)
upWithdraw, err = s.GetUpWithdraw(c, query)
if err != nil {
log.Error("s.GetUpWithdraw error(%v)", err)
return
}
if len(upWithdraw) == 0 {
return
}
upInfo, err := s.dao.GetUpInfoNickname(c, []int64{upWithdraw[0].MID})
if err != nil {
log.Error("s.dao.GetUpInfoNickname error(%v)", err)
return
}
for _, up := range upWithdraw {
up.Nickname = upInfo[up.MID]
up.Income = fmt.Sprintf("%.2f", fromYuanToFen(up.WithdrawIncome))
}
return
}
// UpWithdrawDetailExport export up withdraw detail
func (s *Service) UpWithdrawDetailExport(c context.Context, mid int64) (res []byte, err error) {
upWithdraw, err := s.UpWithdrawDetail(c, mid)
if err != nil {
log.Error("s.UpWithdrawDetail error(%v)", err)
return
}
records := formatUpIncomeWithdraw(upWithdraw)
res, err = service.FormatCSV(records)
if err != nil {
log.Error("FormatCSV error(%v)")
}
return
}

View File

@@ -0,0 +1,90 @@
package income
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_UpWithdraw(t *testing.T) {
Convey("UpWithdraw", t, WithService(func(s *Service) {
var (
mids = []int64{int64(1101)}
isDeleted = 1
from, limit = 0, 1000
)
res, _, err := s.UpWithdraw(context.Background(), mids, isDeleted, from, limit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}
func Test_UpWithdrawExport(t *testing.T) {
Convey("UpWithdrawExport", t, WithService(func(s *Service) {
var (
mids = []int64{int64(1101)}
isDeleted = 1
from, limit = 0, 1000
)
res, err := s.UpWithdrawExport(context.Background(), mids, isDeleted, from, limit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}
func Test_GetUpWithdraw(t *testing.T) {
Convey("GetUpWithdraw", t, WithService(func(s *Service) {
var (
query = ""
)
res, err := s.GetUpWithdraw(context.Background(), query)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}
func Test_ListUpWithdraw(t *testing.T) {
Convey("ListUpWithdraw", t, WithService(func(s *Service) {
var (
id int64
query = ""
limit = 500
)
res, err := s.ListUpWithdraw(context.Background(), id, query, limit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}
func Test_UpWithdrawStatis(t *testing.T) {
Convey("UpWithdrawStatis", t, WithService(func(s *Service) {
var (
isDeleted = 0
)
_, err := s.UpWithdrawStatis(context.Background(), 1522512000, 1533052800, isDeleted)
So(err, ShouldBeNil)
}))
}
func Test_UpWithdrawDetail(t *testing.T) {
Convey("UpWithdrawDetail", t, WithService(func(s *Service) {
var (
mid int64 = 50
)
res, err := s.UpWithdrawDetail(context.Background(), mid)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}
func Test_UpWithdrawDetailExport(t *testing.T) {
Convey("UpWithdrawDetailExport", t, WithService(func(s *Service) {
var (
mid int64 = 50
)
res, err := s.UpWithdrawDetailExport(context.Background(), mid)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}

View File

@@ -0,0 +1,85 @@
package service
import (
"context"
"fmt"
"strings"
"go-common/app/admin/main/growup/model"
)
// InsertNotice insert notice
func (s *Service) InsertNotice(c context.Context, title string, typ int, platform int, link string, status int) (err error) {
notice := &model.Notice{
Title: title,
Type: typ,
Platform: platform,
Link: link,
Status: status,
}
_, err = s.dao.InsertNotice(c, notice)
return
}
// Notices notices
func (s *Service) Notices(c context.Context, typ int, status int, platform int, from int, limit int) (total int, notices []*model.Notice, err error) {
query := queryStr(typ, status, platform)
total, err = s.dao.NoticeCount(c, query)
if err != nil {
return
}
notices, err = s.dao.Notices(c, query, from, limit)
if notices == nil {
notices = make([]*model.Notice, 0)
}
return
}
func queryStr(typ int, status int, platform int) (query string) {
if typ != 0 {
query += " AND "
query += fmt.Sprintf("type=%d", typ)
}
if status != 0 {
query += " AND "
query += fmt.Sprintf("status=%d", status)
}
if platform != 0 {
query += " AND "
query += fmt.Sprintf("platform=%d", platform)
}
query += " AND is_deleted = 0"
return
}
// UpdateNotice update notice
func (s *Service) UpdateNotice(c context.Context, typ int, platform int, title string, link string, id int64, status int) (err error) {
var kv string
if typ != 0 {
kv += fmt.Sprintf("type=%d,", typ)
}
if platform != 0 {
kv += fmt.Sprintf("platform=%d,", platform)
}
if len(title) != 0 {
kv += fmt.Sprintf("title='%s',", title)
}
if len(link) != 0 {
kv += fmt.Sprintf("link='%s',", link)
}
if status != 0 {
kv += fmt.Sprintf("status=%d,", status)
}
if len(kv) == 0 {
return
}
kv = strings.TrimRight(kv, ",")
_, err = s.dao.UpdateNotice(c, kv, id)
return
}

View File

@@ -0,0 +1,38 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_InsertNotice(t *testing.T) {
title := "公告标题"
typ, platform, status := 0, 1, 0
link := "www.bilibili.com"
Convey("admins", t, WithService(func(s *Service) {
err := s.InsertNotice(context.Background(), title, typ, platform, link, status)
So(err, ShouldBeNil)
}))
}
func Test_Notices(t *testing.T) {
typ, platform, status := 0, 1, 0
from, limit := 0, 1000
Convey("admins", t, WithService(func(s *Service) {
_, res, err := s.Notices(context.Background(), typ, status, platform, from, limit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}
func Test_UpdateNotice(t *testing.T) {
title := "公告标题"
typ, platform, status, id := 0, 1, 0, int64(0)
link := "www.bilibili.com"
Convey("admins", t, WithService(func(s *Service) {
err := s.UpdateNotice(context.Background(), typ, platform, title, link, id, status)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,779 @@
package service
import (
"context"
"encoding/json"
"fmt"
"github.com/jinzhu/gorm"
"github.com/pkg/errors"
"go-common/app/admin/main/growup/conf"
"go-common/app/admin/main/growup/dao"
"go-common/app/admin/main/growup/dao/shell"
"go-common/app/admin/main/growup/model/offlineactivity"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/http/blademaster"
"io/ioutil"
"math/rand"
"sort"
"strconv"
"strings"
"time"
)
const (
uploadFilePath = "/data/uploadfiles/"
dateFmt = "20060102"
exportMaxCount = 1000
)
func (s *Service) offlineactivityCheckSendDbProc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("write stat data Runtime error caught, try recover: %+v", r)
go s.offlineactivityCheckSendDbProc()
}
}()
var timer = time.NewTicker(60 * time.Second)
for {
select {
case <-timer.C:
case <-s.chanCheckDb:
}
s.checkResultNotSendingOrder()
}
}
func (s *Service) offlineactivityCheckShellOrderProc() {
defer func() {
if r := recover(); r != nil {
r = errors.WithStack(r.(error))
log.Error("write stat data Runtime error caught, try recover: %+v", r)
go s.offlineactivityCheckShellOrderProc()
}
}()
var timer = time.NewTimer(10 * time.Second)
var timerStart = false
var resultIds []int64
for {
select {
case orderID := <-s.chanCheckShellOrder:
var all = []*offlineactivity.OfflineActivityResult{orderID}
for {
drain:
for {
select {
case orderID := <-s.chanCheckShellOrder:
all = append(all, orderID)
if len(all) >= 100 {
break drain
}
default:
break drain
}
}
s.checkShellOrder(context.Background(), all)
if len(all) < 100 {
break
}
all = nil
}
case resultID := <-s.chanCheckActivity:
if !timerStart {
timer.Reset(10 * time.Second)
timerStart = true
}
resultIds = append(resultIds, resultID)
case <-timer.C:
// 去检查对应活动的状态
timerStart = false
var ids []int64
ids = append(ids, resultIds...)
s.checkActivityState(context.Background(), ids)
// clear map
resultIds = nil
}
}
}
//PreAddOfflineActivity just test add resutl
func (s *Service) PreAddOfflineActivity(ctx context.Context, arg *offlineactivity.AddActivityArg) (res *offlineactivity.PreAddActivityResult, err error) {
if arg == nil {
return
}
res = new(offlineactivity.PreAddActivityResult)
var bonusList = arg.BonusList
var hasBonus = false
res.BonusType = arg.BonusType
for _, bonus := range bonusList {
if bonus.TotalMoney <= 0 {
err = fmt.Errorf("bonus money < 0, money=%f", bonus.TotalMoney)
log.Error(err.Error())
return
}
res.TotalMoney += bonus.TotalMoney
if bonus.Filename != "" {
var fullpath = uploadFilePath + bonus.Filename
var filecontent []byte
filecontent, err = ioutil.ReadFile(fullpath)
if err != nil {
log.Error("read file fail, path=%s", fullpath)
return
}
bonus.Mids = string(filecontent)
bonus.MidList = dao.ParseMidsFromString(bonus.Mids)
bonus.MemberCount = int64(len(bonus.MidList))
if bonus.MemberCount == 0 {
log.Warn("no mid for this bonus, bonusmoney=%d", bonus.TotalMoney)
continue
}
} else {
bonus.MidList = dao.ParseMidsFromString(bonus.Mids)
bonus.MemberCount = int64(len(bonus.MidList))
if bonus.MemberCount == 0 {
log.Warn("no mid for this bonus, bonusmoney=%d", bonus.TotalMoney)
continue
}
}
res.MemberCount += bonus.MemberCount
hasBonus = true
}
// 如果一个bonus都没有则什么也不做
if !hasBonus {
log.Error("no bonus")
err = fmt.Errorf("没有获奖人员信息/解析文件失败(请上传csv/txt等文本格式文件)")
return
}
return
}
//AddOfflineActivity add offline activity
func (s *Service) AddOfflineActivity(ctx context.Context, arg *offlineactivity.AddActivityArg) (res *offlineactivity.AddActivityResult, err error) {
if arg == nil {
return
}
var bonusList = arg.BonusList
var hasBonus = false
var bc = ctx.(*blademaster.Context)
var cookie, _ = bc.Request.Cookie("username")
if cookie != nil {
arg.Creator = cookie.Value
}
for _, bonus := range bonusList {
if bonus.TotalMoney <= 0 {
err = fmt.Errorf("bonus money < 0, money=%f", bonus.TotalMoney)
log.Error(err.Error())
return
}
if bonus.Filename != "" {
var fullpath = uploadFilePath + bonus.Filename
var filecontent []byte
filecontent, err = ioutil.ReadFile(fullpath)
if err != nil {
log.Error("read file fail, path=%s", fullpath)
return
}
bonus.Mids = string(filecontent)
} else {
bonus.MidList = dao.ParseMidsFromString(bonus.Mids)
bonus.MemberCount = int64(len(bonus.MidList))
if bonus.MemberCount == 0 {
log.Warn("no mid for this bonus, bonusmoney=%d", bonus.TotalMoney)
continue
}
}
hasBonus = true
}
// 如果一个bonus都没有则什么也不做
if !hasBonus {
log.Error("no bonus")
err = fmt.Errorf("no bonus info")
return
}
go func() {
err = s.dao.OfflineActivityAddActivity(context.Background(), arg)
if err != nil {
log.Error("offline add fail")
return
}
log.Info("offline add ok")
if len(s.chanCheckDb) == 0 {
s.chanCheckDb <- 1
}
}()
return
}
//ShellCallback shell callback
func (s *Service) ShellCallback(ctx context.Context, arg *shell.OrderCallbackParam) (err error) {
if arg == nil {
log.Error("arg is nil")
return ecode.RequestErr
}
var result = shell.OrderCallbackJSON{}
if err = json.Unmarshal([]byte(arg.MsgContent), &result); err != nil {
log.Error("msgid=%s, unmarshal msg content fail, err=%s, msgcontent=%s", err, arg.MsgID, string(arg.MsgContent))
return
}
log.Info("order id=%s, handle shell callback, status=%s", result.ThirdOrderNo, result.Status)
if result.CustomerID != conf.Conf.ShellConf.CustomID {
log.Error("order id=%s, customerid not the same, give=%s, expect=%s", result.ThirdOrderNo, result.CustomerID, conf.Conf.ShellConf.CustomID)
return
}
orderInfo, err := s.dao.ShellCallbackUpdate(ctx, &result, arg.MsgID)
if err == nil {
s.queueToUpdateActivityState(orderInfo.ResultID)
}
return
}
//OfflineActivityQueryActivity query activity
func (s *Service) OfflineActivityQueryActivity(ctx context.Context, arg *offlineactivity.QueryActivityByIDArg) (res *offlineactivity.QueryActivityResult, err error) {
var db = s.dao.OfflineActivityGetDB()
// make sure it's valid
var limit, offset = arg.CheckPageValidation()
if arg.ExportFormat() != "" {
limit = exportMaxCount
}
var now = time.Now()
if arg.FromDate == "" {
arg.FromDate = now.AddDate(0, -1, 0).Format(dateFmt)
}
if arg.ToDate == "" {
arg.ToDate = now.Format(dateFmt)
}
// 1.查询 OfflineActivityInfo 与 OfflineActivityBonus 数据,然后聚合
var activityList []*offlineactivity.OfflineActivityInfo
var total = 1
if arg.ID != 0 {
if err = db.Where("id=?", arg.ID).Find(&activityList).Error; err != nil && err != gorm.ErrRecordNotFound {
log.Error("fail to get from db, err=%s", err)
return
}
total = len(activityList)
} else {
if arg.FromDate == "" || arg.ToDate == "" {
log.Error("request error, fromdate or todate is nill")
err = ecode.RequestErr
return
}
var todate, e = time.Parse(dateFmt, arg.ToDate)
err = e
if err != nil {
log.Error("todate format err, todate=%s, err=%s", arg.ToDate, err)
return
}
todate = todate.AddDate(0, 0, 1)
var todatestr = todate.Format(dateFmt)
if err = db.Table(offlineactivity.TableOfflineActivityInfo).Where("ctime>=? and ctime<=?", arg.FromDate, todatestr).Count(&total).Error; err != nil {
log.Error("fail to get from db, err=%s", err)
return
}
if err = db.Where("ctime>=? and ctime<=?", arg.FromDate, todatestr).Order("id desc").Offset(offset).Limit(limit).Find(&activityList).Error; err != nil {
log.Error("fail to get from db, err=%s", err)
return
}
}
var activityIDs []int64
for _, v := range activityList {
activityIDs = append(activityIDs, v.ID)
}
if len(activityList) == 0 {
log.Warn("0 activity list")
return
}
// 查询bonus info
var bonusList []*offlineactivity.OfflineActivityBonus
if err = db.Where("activity_id in (?)", activityIDs).Find(&bonusList).Error; err != nil {
log.Error("fail to get from db, err=%s", err)
return
}
res = new(offlineactivity.QueryActivityResult)
var activityMap = make(map[int64]*offlineactivity.QueryActivityInfo, len(activityList))
for _, v := range activityList {
var info = new(offlineactivity.QueryActivityInfo)
info.CopyFromActivityDB(v)
activityMap[info.ID] = info
}
for _, v := range bonusList {
var info, _ = activityMap[v.ActivityID]
if info == nil {
continue
}
info.TotalMoney += offlineactivity.GetMoneyFromDb(v.TotalMoney)
info.MemberCount += v.MemberCount
}
for _, v := range activityList {
if info, ok := activityMap[v.ID]; ok {
res.Result = append(res.Result, info)
}
}
res.PageResult = arg.ToPageResult(total)
return
}
// OfflineActivityQueryUpBonusSummary query up bonus info
func (s *Service) OfflineActivityQueryUpBonusSummary(ctx context.Context, arg *offlineactivity.QueryUpBonusByMidArg) (res *offlineactivity.QueryUpBonusByMidResult, err error) {
var limit, offset = arg.CheckPageValidation()
if arg.ExportFormat() != "" {
limit = exportMaxCount
}
// 查询所有的 result for mid
// 区分已结算、未结算
// 已结算= 成功, 未结算= 初始、发送、等待
upResult, total, err := s.dao.OfflineActivityGetUpBonusResult(ctx, true, limit, offset, "mid=?", arg.Mid)
if err != nil {
log.Error("get from up result fail, err=%s", err)
return
}
res = new(offlineactivity.QueryUpBonusByMidResult)
res.PageResult = arg.ToPageResult(total)
var bonusMap = make(map[int64]*offlineactivity.UpSummaryBonusInfo)
for _, v := range upResult {
var bonusInfo, ok = bonusMap[v.Mid]
if !ok {
bonusInfo = &offlineactivity.UpSummaryBonusInfo{
Mid: v.Mid,
}
bonusMap[v.Mid] = bonusInfo
}
switch offlineactivity.ActivityState(v.State) {
case offlineactivity.ActivityStateSucess:
bonusInfo.BilledMoney += offlineactivity.GetMoneyFromDb(v.BonusMoney)
if bonusInfo.TmpBillTime < v.MTime {
bonusInfo.TmpBillTime = v.MTime
}
case offlineactivity.ActivityStateInit, offlineactivity.ActivityStateSending, offlineactivity.ActivityStateWaitResult:
bonusInfo.UnbilledMoney += offlineactivity.GetMoneyFromDb(v.BonusMoney)
}
}
for _, v := range bonusMap {
v.Finish()
res.Result = append(res.Result, v)
}
return
}
//OfflineActivityQueryUpBonusByActivity get bonus info group by activity
func (s *Service) OfflineActivityQueryUpBonusByActivity(ctx context.Context, arg *offlineactivity.QueryUpBonusByMidArg) (res *offlineactivity.QueryUpBonusByActivityResult, err error) {
var limit, offset = arg.CheckPageValidation()
if arg.ExportFormat() != "" {
limit = exportMaxCount
}
// 查询所有的 result for mid
// 区分已结算、未结算
// 已结算= 成功, 未结算= 初始、发送、等待
upResult, total, err := s.dao.OfflineActivityGetUpBonusByActivityResult(ctx, limit, offset, arg.Mid)
if err != nil {
log.Error("get from up result fail, err=%s", err)
return
}
res = new(offlineactivity.QueryUpBonusByActivityResult)
res.PageResult = arg.ToPageResult(total)
// [mid][activity_id], 按Activity做聚合
var bonusMap = make(map[int64]map[int64]*offlineactivity.UpSummaryBonusInfo)
for _, v := range upResult {
var bonusActivityMap, ok = bonusMap[v.Mid]
if !ok {
bonusActivityMap = make(map[int64]*offlineactivity.UpSummaryBonusInfo)
bonusMap[v.Mid] = bonusActivityMap
}
bonusInfo, ok := bonusActivityMap[v.ActivityID]
if !ok {
bonusInfo = &offlineactivity.UpSummaryBonusInfo{
Mid: v.Mid,
ActivityID: v.ActivityID,
}
bonusActivityMap[v.ActivityID] = bonusInfo
}
var bonusMoney = offlineactivity.GetMoneyFromDb(v.BonusMoney)
switch offlineactivity.ActivityState(v.State) {
case offlineactivity.ActivityStateSucess:
bonusInfo.BilledMoney += bonusMoney
if bonusInfo.TmpBillTime < v.MTime {
bonusInfo.TmpBillTime = v.MTime
}
bonusInfo.TotalBonusMoney += bonusMoney
case offlineactivity.ActivityStateInit, offlineactivity.ActivityStateSending, offlineactivity.ActivityStateWaitResult:
bonusInfo.UnbilledMoney += bonusMoney
bonusInfo.TotalBonusMoney += bonusMoney
}
}
for _, activityMap := range bonusMap {
for _, v := range activityMap {
v.Finish()
res.Result = append(res.Result, v)
}
}
return
}
//OfflineActivityQueryActivityByMonth activity by month
func (s *Service) OfflineActivityQueryActivityByMonth(ctx context.Context, arg *offlineactivity.QueryActvityMonthArg) (res *offlineactivity.QueryActivityMonthResult, err error) {
var db = s.dao.OfflineActivityGetDB()
var bonusInfo []*offlineactivity.OfflineActivityBonus
var limit, offset = 100, 0
var lastCount = limit
for limit == lastCount {
var bonusInfoTmp []*offlineactivity.OfflineActivityBonus
if err = db.Find(&bonusInfoTmp).Error; err != nil {
log.Error("get from db fail, err=%s", err)
return
}
bonusInfo = append(bonusInfo, bonusInfoTmp...)
lastCount = len(bonusInfoTmp)
offset += lastCount
}
var now = time.Now()
var dateStr = now.Format(dateFmt)
var monthDataMap = make(map[string]*offlineactivity.ActivityMonthInfo)
for _, v := range bonusInfo {
var date = v.CTime.Time().Format("200601")
var monthData, ok = monthDataMap[date]
if !ok {
monthData = &offlineactivity.ActivityMonthInfo{
CreateTime: date,
}
monthDataMap[date] = monthData
monthData.GenerateDay = dateStr
}
monthData.AddBonus(v)
}
var monthInfoS []*offlineactivity.ActivityMonthInfo
for _, v := range monthDataMap {
monthInfoS = append(monthInfoS, v)
v.Finish()
}
sort.Slice(monthInfoS, func(i, j int) bool {
return monthInfoS[i].CreateTime > monthInfoS[j].CreateTime
})
var lastIndex = len(monthInfoS) - 1
if lastIndex >= 0 {
monthInfoS[lastIndex].TotalMoneyAccumulate = monthInfoS[lastIndex].TotalBonusMoneyMonth
}
for i := len(monthInfoS) - 1; i > 0; i-- {
monthInfoS[i-1].TotalMoneyAccumulate = monthInfoS[i].TotalMoneyAccumulate + monthInfoS[i-1].TotalBonusMoneyMonth
}
res = new(offlineactivity.QueryActivityMonthResult)
res.Result = monthInfoS
return
}
/*
查询对应的activity_result表state=0 && bonus_type = 1 && ctime <= 86400
for each item state=0 and activity_id = ? limit 100
if 没有order_id
生成order_id写入数据库, result表与shellorder表
写入成功,记录等待发送
if 有order id
// 说明已经经历过上一步但是发送失败那么加入到检查order id的队列
记录等待发送
批量进行发送-> shell
if 发送成功
更新所有的item状态 -> 1
else if 失败:
错误码是8002999997->order_id有重复
更新所有的item order id = '',等待重试
*/
func (s *Service) checkResultNotSendingOrder() {
var db, err = gorm.Open("mysql", conf.Conf.ORM.Growup.DSN)
if err != nil {
log.Error("open db fail, dsn=%s", conf.Conf.ORM.Growup.DSN)
return
}
defer db.Close()
db.LogMode(false)
// 查询对应的activity_result表state=0 && bonus_type = 1 && diff(ctime) <= 86400
var minTime = time.Now().Add(-time.Hour * 24)
var limit = 100
var lastCount = limit
var lastID int64
for limit == lastCount {
var needSendResult = make([]*offlineactivity.OfflineActivityResult, limit)
if err = db.Select("id, mid, bonus_money, order_id, activity_id, bonus_id").
Where("state=0 and bonus_type=1 and ctime>=? and id>?", minTime, lastID).Limit(limit).
Find(&needSendResult).Error; err != nil {
log.Error("get result fail, err=%s", err)
return
}
lastCount = len(needSendResult)
var now = time.Now()
var sendRequestResult []*offlineactivity.OfflineActivityResult
for _, activityResult := range needSendResult {
if activityResult.ID > lastID {
lastID = activityResult.ID
}
// if 没有order_id
if activityResult.OrderID == "" {
activityResult.OrderID = generateOrderID(activityResult, now)
if err = s.offlineActivityUpdateResultForSend(db, activityResult); err != nil {
log.Warn("fail update result, err=%s, will retry next time", err)
continue
}
log.Info("update result ok, mid=%d, activity_id=%d, order_id=%s", activityResult.Mid, activityResult.ActivityID, activityResult.OrderID)
sendRequestResult = append(sendRequestResult, activityResult)
} else {
// if 有order id
go func(res *offlineactivity.OfflineActivityResult) {
s.chanCheckShellOrder <- res
log.Info("order has id, need to check, order id=%s, mid=%d, activityid=%d, bonusid=%d",
res.OrderID, res.Mid, res.ActivityID, res.BonusID)
}(activityResult)
}
if len(sendRequestResult) >= 10 {
err = s.sendRequestAndUpdate(db, sendRequestResult)
if err != nil {
log.Error("send request err, err=%s", err)
} else {
log.Info("send to shell ok, length=%d", len(sendRequestResult))
}
sendRequestResult = nil
}
}
if len(sendRequestResult) > 0 {
err = s.sendRequestAndUpdate(db, sendRequestResult)
if err != nil {
log.Error("send request err, err=%s", err)
} else {
log.Info("send to shell ok, length=%d", len(sendRequestResult))
}
}
}
}
func (s *Service) sendRequestAndUpdate(db *gorm.DB, sendRequestResult []*offlineactivity.OfflineActivityResult) (err error) {
switch {
default:
var res *shell.OrderResponse
if res, err = s.sendShellOrder(context.Background(), sendRequestResult); err != nil || res == nil {
if err != nil {
log.Error("fail to send to shell order, err=%s", err)
}
break
}
var ids []int64
for _, v := range sendRequestResult {
ids = append(ids, v.ID)
}
// 需要区分是否返回 错误码是8002999997,表示有重复
if res.Errno == 8002999997 {
log.Error("fail to send request, err=%d, msg=%s重复", res.Errno, res.Msg)
// 将order id 更新为""
if err = db.Table(offlineactivity.TableOfflineActivityResult).Where("id in (?)", ids).
Update("order_id=''").Error; err != nil {
log.Error("fail to update order id for duplicate order, id=%v", ids)
break
}
return
} else if res.Errno != 0 {
log.Error("fail to send request, err=%d, msg=%s", res.Errno, res.Msg)
return
}
if err = db.Table(offlineactivity.TableOfflineActivityResult).Where("id in (?)", ids).
Update("state", offlineactivity.ActivityStateWaitResult).Error; err != nil {
log.Error("fail to update state, id=%v", ids)
break
}
log.Info("send request to shell order")
}
return
}
func generateOrderID(result *offlineactivity.OfflineActivityResult, tm time.Time) string {
var order = fmt.Sprintf("%s%04d%010d%04d", time.Now().Format("20060102150405"), (result.ActivityID*100+result.BonusID)%10000, result.Mid, rand.Int()%10000)
if len(order) > 32 {
order = order[:32]
}
return order
}
func (s *Service) offlineActivityUpdateResultForSend(db *gorm.DB, result *offlineactivity.OfflineActivityResult) (err error) {
if result == nil {
err = fmt.Errorf("nil pointer")
return
}
var tx = db.Begin()
defer func() {
if r := recover(); r != nil || err != nil {
tx.Rollback()
}
}()
// create
var query = tx.Select("order_id").Where("order_id=''").Save(result)
err = db.Error
if err != nil {
log.Error("err save offline result, err=%s", err)
return
}
if query.RowsAffected == 0 {
var msg = fmt.Sprintf("update order fail, it may already be sent, result_id=%d, mid=%d, activity_id=%d", result.ID, result.Mid, result.ActivityID)
log.Warn(msg)
err = fmt.Errorf(msg)
return
}
var shellOrder = offlineactivity.OfflineActivityShellOrder{
OrderID: result.OrderID,
ResultID: result.ID,
}
if err = tx.Save(&shellOrder).Error; err != nil {
log.Error("err insert offline shell order, err=%s", err)
return
}
return tx.Commit().Error
}
func (s *Service) sendShellOrder(ctx context.Context, needSendResult []*offlineactivity.OfflineActivityResult) (res *shell.OrderResponse, err error) {
if len(needSendResult) == 0 {
log.Warn("no need to send, len=0")
return
}
var nowtime = time.Now()
var now = time.Now().UnixNano() / int64(time.Millisecond)
var request = shell.OrderRequest{
ProductName: "活动奖励",
NotifyURL: conf.Conf.ShellConf.CallbackURL,
Rate: "1.0",
SignType: "MD5",
Timestamp: strconv.Itoa(int(beginOfDay(nowtime).UnixNano() / int64(time.Millisecond))),
}
for _, item := range needSendResult {
var money = fmt.Sprintf("%0.2f", float64(offlineactivity.GetMoneyFromDb(item.BonusMoney)))
var orderInfo = shell.OrderInfo{
Mid: item.Mid,
Brokerage: money,
ThirdCoin: money,
ThirdOrderNo: item.OrderID,
ThirdCtime: strconv.Itoa(int(now)),
}
request.Data = append(request.Data, orderInfo)
}
//log.Info("request=%+v", request)
res, err = s.shellClient.SendOrderRequest(ctx, &request)
if err != nil || res == nil {
log.Error("fail to send request, err=%s", err)
} else {
log.Info("send shell request, msg=%s, errno=%d", res.Msg, res.Errno)
}
return
}
/*
2.定单查询 - 查询定单的状态,
for each state=0 and 存在order id
去贝壳查询该定单状态
if 定单不存在
设置order id='', state=0 // 清除定单,等待重新发送
else if 定单成功
设置state=10
else if 定单失败
设置state=11
*/
// 最大不要超过100个订单
func (s *Service) checkShellOrder(ctx context.Context, values []*offlineactivity.OfflineActivityResult) (err error) {
if len(values) == 0 {
err = fmt.Errorf("values slice 0 length")
return
}
var orderMap = make(map[string]*offlineactivity.OfflineActivityResult, len(values))
var orderIds []string
for i, v := range values {
if i > 99 {
break
}
orderIds = append(orderIds, v.OrderID)
orderMap[v.OrderID] = v
}
var orderIDString = strings.Join(orderIds, ",")
var orderCheckRequest = shell.OrderCheckRequest{
Timestamp: time.Now().UnixNano() / int64(time.Millisecond),
ThirdOrderNos: orderIDString,
}
res, err := s.shellClient.SendCheckOrderRequest(ctx, &orderCheckRequest)
if err != nil {
log.Error("fail to check order, order id=%s, err=%s", orderIDString, err)
return
}
// 区分找到的订单和未找到的订单
// 订单找到,更新状态
for _, v := range res.Orders {
log.Info("order find, orderid=%s, current status=%s", v.ThirdOrderNo, v.Status)
// 删除已找到的订单
delete(orderMap, v.ThirdOrderNo)
var resultJSON = shell.OrderCallbackJSON{
Status: v.Status,
ThirdOrderNo: v.ThirdOrderNo,
Mid: v.Mid,
}
// 更新订单结果
var orderInfo, e = s.dao.ShellCallbackUpdate(ctx, &resultJSON, "checkorder")
if e == nil {
s.queueToUpdateActivityState(orderInfo.ID)
}
}
// 订单未找到,重新发送请求
var needSendRequest []*offlineactivity.OfflineActivityResult
for _, v := range orderMap {
needSendRequest = append(needSendRequest, v)
}
err = s.sendRequestAndUpdate(s.dao.OfflineActivityGetDB(), needSendRequest)
if err != nil {
log.Error("send order request fail, err=%s", err)
return
}
return
}
func (s *Service) checkActivityState(ctx context.Context, values []int64) (err error) {
if len(values) == 0 {
log.Warn("no activity need to check")
return
}
//
upResult, err := s.dao.OfflineActivityGetUpBonusResultSelect(ctx, "distinct(activity_id) as activity_id", "id in (?)", values)
for _, v := range upResult {
var _, e = s.dao.UpdateActivityState(ctx, v.ActivityID)
if e != nil {
log.Error("err when update activity state, err=%s", e)
}
}
return
}
func (s *Service) queueToUpdateActivityState(resultID int64) {
s.chanCheckActivity <- resultID
}
func beginOfDay(t time.Time) time.Time {
year, month, day := t.Date()
return time.Date(year, month, day, 0, 0, 0, 0, t.Location())
}

View File

@@ -0,0 +1,9 @@
package service
import (
"testing"
)
func TestCheckResultNotSendingOrder(t *testing.T) {
}

View File

@@ -0,0 +1,53 @@
package service
import (
"context"
"go-common/app/admin/main/growup/conf"
"go-common/app/admin/main/growup/dao"
"go-common/app/admin/main/growup/dao/message"
"go-common/app/admin/main/growup/dao/resource"
"go-common/app/admin/main/growup/dao/shell"
"go-common/app/admin/main/growup/model/offlineactivity"
"go-common/library/net/http/blademaster"
)
// Service struct
type Service struct {
conf *conf.Config
dao *dao.Dao
msg *message.Dao
chanCheckDb chan int
chanCheckShellOrder chan *offlineactivity.OfflineActivityResult
chanCheckActivity chan int64 // it's result id in this channel
shellClient *shell.Client
}
// New fn
func New(c *conf.Config) (s *Service) {
s = &Service{
conf: c,
dao: dao.New(c),
msg: message.New(c),
chanCheckDb: make(chan int, 1),
chanCheckShellOrder: make(chan *offlineactivity.OfflineActivityResult, 10240),
chanCheckActivity: make(chan int64, 1000),
shellClient: shell.New(c.ShellConf, blademaster.NewClient(c.HTTPClient)),
}
resource.Init(c)
if c.OtherConf.OfflineOrderConsume {
go s.offlineactivityCheckSendDbProc()
}
go s.offlineactivityCheckShellOrderProc()
return s
}
// Ping fn
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close dao
func (s *Service) Close() {
s.dao.Close()
}

View File

@@ -0,0 +1,96 @@
package service
import (
"context"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/admin/main/growup/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func init() {
dir, _ := filepath.Abs("../cmd/growup-admin.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
time.Sleep(time.Second)
}
func TestService_AddUpInfo(t *testing.T) {
Convey("AddUpInfo", t, WithService(func(s *Service) {
err := s.AddUp(context.Background(), 11, 2)
So(err, ShouldBeNil)
}))
}
func TestService_Block(t *testing.T) {
Convey("Block", t, WithService(func(s *Service) {
err := s.Block(context.Background(), 11)
So(err, ShouldBeNil)
}))
}
func TestService_DeleteFromBlocked(t *testing.T) {
Convey("DeleteFromBlocked", t, WithService(func(s *Service) {
err := s.DeleteFromBlocked(context.Background(), 11)
So(err, ShouldBeNil)
}))
}
func TestService_DeleteUp(t *testing.T) {
Convey("DeleteUp", t, WithService(func(s *Service) {
err := s.DeleteUp(context.Background(), 11)
So(err, ShouldBeNil)
}))
}
func TestService_Pass(t *testing.T) {
Convey("Pass", t, WithService(func(s *Service) {
err := s.Pass(context.Background(), []int64{11}, 0)
So(err, ShouldBeNil)
}))
}
func TestService_QueryFromBlocked(t *testing.T) {
Convey("QueryFromBlocked", t, WithService(func(s *Service) {
_, _, err := s.QueryFromBlocked(context.Background(), 0, 0, "", 0, 0, 0, 0, "mid")
So(err, ShouldBeNil)
}))
}
func TestService_QueryFromUpInfo(t *testing.T) {
Convey("", t, WithService(func(s *Service) {
_, _, err := s.QueryFromUpInfo(context.Background(), 0, 1, nil, 0, 1, 0, "", 0, 0, 1, 1, "-mid")
So(err, ShouldBeNil)
}))
}
func TestService_Recovery(t *testing.T) {
Convey("Recovery", t, WithService(func(s *Service) {
err := s.Recovery(context.Background(), 11)
So(err, ShouldBeNil)
}))
}
func TestService_Reject(t *testing.T) {
Convey("Reject", t, WithService(func(s *Service) {
mids := []int64{11}
err := s.Reject(context.Background(), 0, mids, "违规", 1)
So(err, ShouldBeNil)
}))
}
func TestService_DelUpAccount(t *testing.T) {
Convey("DelUpAccount", t, WithService(func(s *Service) {
err := s.DelUpAccount(context.Background(), 11)
So(err, ShouldBeNil)
}))
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,510 @@
package service
import (
"context"
"fmt"
"sort"
"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"
)
// AddTagInfo add tag info service
func (s *Service) AddTagInfo(c context.Context, t *model.TagInfo, creator string) (err error) {
t.Creator = creator
if t.Dimension == 0 && (t.Category == 0 || t.Business == 0) {
err = fmt.Errorf("维度为稿件时必须填写业务和分区")
return
}
// bgm
if t.Business == 3 {
t.Category = 0
}
if t.Icon != "" && t.ActivityID == 0 {
err = fmt.Errorf("请填写活动id")
return
}
_, err = s.dao.GetTagInfoByName(c, t.Tag, t.Dimension, t.Category, t.Business)
if err == sql.ErrNoRows {
_, err = s.dao.InsertTag(c, t)
if err != nil {
log.Error("s.dao.InsertTag error(%v)", err)
}
return
}
if err != nil {
log.Error("s.dao.GetTagInfoByName error(%v)", err)
return
}
// tag has exist, can not add
return ecode.GrowupTagAddForbit
}
// UpdateTagInfo update tag
func (s *Service) UpdateTagInfo(c context.Context, t *model.TagInfo, creator string) (err error) {
t.Creator = creator
if t.Dimension == 0 && (t.Category == 0 || t.Business == 0) {
err = fmt.Errorf("维度为稿件时必须填写业务和分区")
return
}
// bgm
if t.Business == 3 {
t.Category = 0
}
if t.Icon != "" && t.ActivityID == 0 {
err = fmt.Errorf("请填写活动id")
return
}
old, err := s.dao.GetTagInfo(c, int(t.ID))
if err != nil {
log.Error("s.dao.GetTagInfo error(%v)", err)
return
}
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix()
if old.StartTime.Time().Unix() <= today && old.EndTime.Time().Unix() >= today {
err = fmt.Errorf("标签生效中,不能修改")
return
}
_, err = s.dao.UpdateTagInfo(c, t)
if err != nil {
log.Error("s.dao.UpdateTagInfo error(%v)", err)
}
return
}
// ModeTagState mode tag state
func (s *Service) ModeTagState(c context.Context, tagID int, isDeleted int) (err error) {
rows, err := s.dao.UpdateTagState(c, tagID, isDeleted)
if err != nil {
log.Error("s.dao.UpdateTagState error(%v)", err)
return
}
if rows == 0 {
return fmt.Errorf("Modification has not taken effect")
}
return
}
// AddTagUps add tag ups service
func (s *Service) AddTagUps(c context.Context, tagID int, mids []int64, isCommon int) (err error) {
info, err := s.dao.GetTagInfo(c, tagID)
if err != nil {
log.Error("s.dao.GetTagInfo error(%v)", err)
return
}
_, err = s.dao.UpdateTagCom(c, tagID, isCommon)
if err != nil {
log.Error("s.dao.UpdateTagCom error(%v)", err)
return
}
if isCommon == 0 && len(mids) > 0 {
if err = s.InsertTagUpInfos(c, info.ID, mids); err != nil {
log.Error("s.InsertTagUpInfos error(%v)", err)
}
}
return
}
// InsertTagUpInfos insert tag_info
func (s *Service) InsertTagUpInfos(c context.Context, tagID int64, mids []int64) (err error) {
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran error(%v)", err)
return
}
for _, mid := range mids {
_, err = s.dao.TxInsertTagUpInfo(tx, tagID, mid, 0)
if err != nil {
tx.Rollback()
log.Error("s.dao.TxInsertTagUpInfo error(%v)", err)
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
}
return
}
// ReleaseUp release tag ups service
func (s *Service) ReleaseUp(c context.Context, tagID int, mid int64) (err error) {
info, err := s.dao.GetTagInfo(c, tagID)
if err != nil {
log.Error("s.dao.GetTagInfo error(%v)", err)
return
}
if info.IsCommon == 1 {
return ecode.GrowupTagForbit
}
_, err = s.dao.InsertTagUpInfo(c, info.ID, mid, 1)
if err != nil {
log.Error("s.dao.InsertTagUpInfo error(%v)", err)
}
return
}
func tagQueryStmt(startTime int64, endTime int64, categories []int64, business []int64, tag string, effect int, sort string) (query string) {
if effect == 1 {
startTime = time.Now().Unix()
endTime = time.Now().Unix()
query += "is_deleted = 0"
query += " AND "
}
if startTime != 0 && endTime != 0 {
st := time.Unix(startTime, 0).Format("2006-01-02")
et := time.Unix(endTime, 0).Format("2006-01-02")
query += "("
query += "(start_at <= '" + st
query += "' AND "
query += "end_at >= '" + et
query += "') OR "
query += "(start_at BETWEEN '" + st + "' AND '" + et
query += "' OR "
query += "end_at BETWEEN '" + st + "' AND '" + et
query += "') OR "
query += "(start_at >= '" + st
query += "' AND "
query += "end_at <= '" + et
query += "'))"
query += " AND "
}
if tag != "" {
query += fmt.Sprintf("tag = \"%s\"", tag)
query += " AND "
}
query = strings.TrimSuffix(query, " AND ")
queryArchive := ""
if len(categories) != 0 {
queryArchive += fmt.Sprintf("category_id IN (%s)", xstr.JoinInts(categories))
queryArchive += " AND "
}
queryUp := "dimension = 1"
if len(business) != 0 {
queryArchive += fmt.Sprintf("business_id IN (%s)", xstr.JoinInts(business))
queryUp += fmt.Sprintf(" AND business_id IN (%s)", xstr.JoinInts(business))
}
if queryArchive != "" {
queryArchive = strings.TrimSuffix(queryArchive, " AND ")
query = fmt.Sprintf("%s AND ((%s AND dimension = 0) OR (%s))", query, queryArchive, queryUp)
}
query = strings.TrimPrefix(query, " AND ")
if query != "" {
query = fmt.Sprintf("WHERE %s", query)
}
if strings.HasPrefix(sort, "-") {
sort = strings.TrimPrefix(sort, "-")
sort += " DESC"
}
if sort != "" {
query += " ORDER BY "
query += sort
}
return
}
// QueryTagInfo query tag info service
func (s *Service) QueryTagInfo(c context.Context, start int64, end int64, categories []int64, business []int64, tag string, effect, from int, limit int, sort string) (total int, tagInfos []*model.TagInfo, err error) {
if len(categories) == 0 && len(business) == 0 {
return
}
for _, b := range business {
if b == 3 {
categories = append(categories, 0)
break
}
}
query := tagQueryStmt(start, end, categories, business, tag, effect, sort)
total, err = s.dao.TagsCount(c, query)
if err != nil {
log.Error("s.dao.TagsCount error(%v)", err)
return
}
if total == 0 {
tagInfos = []*model.TagInfo{}
return
}
tagInfos, err = s.dao.GetTagInfos(c, query, from, limit)
if err != nil {
log.Error("dao.GetTagInfos error(%v)", err)
return
}
for _, tag := range tagInfos {
tag.RetRatio = float32(tag.Ratio) / float32(100)
}
return
}
func (s *Service) getUpTagIncomeByDate(c context.Context, startTime, endTime time.Time, tagID int64, query string) (avs []*model.UpTagIncome, err error) {
endTime = endTime.AddDate(0, 0, 1)
avs = make([]*model.UpTagIncome, 0)
for startTime.Before(endTime) {
var av []*model.UpTagIncome
date := startTime.Format("2006-01-02")
av, err = s.dao.GetUpTagIncome(c, date, tagID, query)
if err != nil {
return
}
avs = append(avs, av...)
startTime = startTime.AddDate(0, 0, 1)
}
return
}
// ListUps list ups
func (s *Service) ListUps(c context.Context, tagID int, mid int64, from int, limit int) (total int, data []*model.UpIncomeInfo, err error) {
tagInfo, err := s.dao.GetTagInfo(c, tagID)
if err != nil {
log.Error("s.dao.GetTagInfo error(%v)", err)
return
}
query := ""
if mid != 0 {
query = fmt.Sprintf("mid = %d", mid)
}
avs, err := s.getUpTagIncomeByDate(c, tagInfo.StartTime.Time(), tagInfo.EndTime.Time(), tagInfo.ID, query)
if err != nil {
log.Error("s.getUpTagIncomeByDate error(%v)", err)
return
}
releaseUps, err := s.dao.GetTagUpInfoMID(c, tagInfo.ID, 1)
if err != nil {
log.Error("s.dao.GetTagUpInfoUps error(%v)", err)
return
}
upIncomes := statisTagUps(c, avs, releaseUps)
total = len(upIncomes)
if from > len(upIncomes) {
return
}
if from+limit > len(upIncomes) {
limit = len(upIncomes) - from
}
data = upIncomes[from : from+limit]
for _, d := range data {
d.Nickname, err = s.dao.GetNickname(c, d.MID)
if err != nil {
log.Error("s.dao.GetNickname error(%v)", err)
return
}
}
return
}
func statisTagUps(c context.Context, avs []*model.UpTagIncome, releaseUps map[int64]int) (ups []*model.UpIncomeInfo) {
upsMap := make(map[int64]*model.UpIncomeInfo)
for _, av := range avs {
if av.IsDeleted == 1 {
continue
}
if _, ok := upsMap[av.MID]; ok {
upsMap[av.MID].BaseIncome += av.BaseIncome
upsMap[av.MID].TotalIncome += av.Income
upsMap[av.MID].AdjustIncome += av.Income - av.BaseIncome
} else {
upsMap[av.MID] = &model.UpIncomeInfo{
MID: av.MID,
CreateTime: xtime.Time(av.Date.Unix()),
BaseIncome: av.BaseIncome,
TotalIncome: av.Income,
AdjustIncome: av.Income - av.BaseIncome,
IsDeleted: releaseUps[av.MID],
}
}
}
ups = make([]*model.UpIncomeInfo, 0)
for _, up := range upsMap {
ups = append(ups, up)
}
sort.Slice(ups, func(i, j int) bool {
return ups[i].TotalIncome > ups[j].TotalIncome
})
return
}
// ListAvs list avs
func (s *Service) ListAvs(c context.Context, tagID, from, limit int, avID int64) (total int, data []*model.AvIncomeInfo, err error) {
data = make([]*model.AvIncomeInfo, 0)
tagInfo, err := s.dao.GetTagInfo(c, tagID)
if err != nil {
log.Error("s.dao.GetTagInfo error(%v)", err)
return
}
if tagInfo.Dimension == 1 {
return
}
query := ""
if avID != 0 {
query = fmt.Sprintf("av_id = %d", avID)
}
avs, err := s.getUpTagIncomeByDate(c, tagInfo.StartTime.Time(), tagInfo.EndTime.Time(), tagInfo.ID, query)
if err != nil {
log.Error("s.getUpTagIncomeByDate error(%v)", err)
return
}
avIncomes := statisTagAvs(c, avs)
total = len(avIncomes)
if from > len(avIncomes) {
return
}
if from+limit > len(avIncomes) {
limit = len(avIncomes) - from
}
data = avIncomes[from : from+limit]
for _, d := range data {
d.Category = tagInfo.Category
d.Nickname, err = s.dao.GetNickname(c, d.MID)
if err != nil {
log.Error("s.dao.GetNickname error(%v)", err)
return
}
}
return
}
func statisTagAvs(c context.Context, avs []*model.UpTagIncome) (avIncome []*model.AvIncomeInfo) {
avsMap := make(map[int64]*model.AvIncomeInfo)
for _, av := range avs {
if av.IsDeleted == 1 {
continue
}
if _, ok := avsMap[av.AvID]; ok {
avsMap[av.AvID].BaseIncome += av.BaseIncome
avsMap[av.AvID].AdjustIncome += av.Income - av.BaseIncome
avsMap[av.AvID].TotalIncome += av.Income
} else {
avsMap[av.AvID] = &model.AvIncomeInfo{
AVID: av.AvID,
MID: av.MID,
CreateTime: xtime.Time(av.Date.Unix()),
BaseIncome: av.BaseIncome,
TotalIncome: av.Income,
AdjustIncome: av.Income - av.BaseIncome,
}
}
}
avIncome = make([]*model.AvIncomeInfo, 0)
for _, av := range avsMap {
avIncome = append(avIncome, av)
}
sort.Slice(avIncome, func(i, j int) bool {
return avIncome[i].TotalIncome > avIncome[j].TotalIncome
})
return
}
// TagDetails query tag details.
func (s *Service) TagDetails(c context.Context, tagID, from, limit int) (total int, data []*model.Details, err error) {
tagInfo, err := s.dao.GetTagInfo(c, tagID)
if err != nil {
log.Error("s.dao.GetTagInfo error(%v)", err)
return
}
avs, err := s.getUpTagIncomeByDate(c, tagInfo.StartTime.Time(), tagInfo.EndTime.Time(), tagInfo.ID, "")
if err != nil {
log.Error("s.getUpTagIncomeByDate error(%v)", err)
return
}
tags := statisTags(c, avs)
total = len(tags)
if from > len(tags) {
return
}
if from+limit > len(tags) {
limit = len(tags) - from
}
data = tags[from : from+limit]
return
}
func statisTags(c context.Context, avs []*model.UpTagIncome) (tags []*model.Details) {
var (
tagsMap = make(map[string]*model.Details)
dateMID = make(map[string]map[int64]struct{})
avMap = make(map[int64]struct{})
upMap = make(map[int64]struct{})
totalIncome, baseIncome int
)
for _, av := range avs {
key := av.Date.Format("2006-01-02")
if av.IsDeleted == 1 {
continue
}
if _, ok := tagsMap[key]; ok {
tagsMap[key].Income += av.Income
tagsMap[key].BaseIncome += av.BaseIncome
tagsMap[key].AdjustIncome += av.Income - av.BaseIncome
tagsMap[key].AvCnt++
if _, ok := dateMID[key][av.MID]; !ok {
tagsMap[key].UpCnt++
}
} else {
tagsMap[key] = &model.Details{
Date: key,
Income: av.Income,
UpCnt: 1,
AvCnt: 1,
}
dateMID[key] = make(map[int64]struct{})
}
dateMID[key][av.MID] = struct{}{}
// all
if av.AvID != 0 {
avMap[av.AvID] = struct{}{}
}
upMap[av.MID] = struct{}{}
totalIncome += av.Income
baseIncome += av.BaseIncome
}
tags = make([]*model.Details, 1)
tags[0] = &model.Details{
Date: "累计",
UpCnt: len(upMap),
AvCnt: len(avMap),
Income: totalIncome,
BaseIncome: baseIncome,
AdjustIncome: totalIncome - baseIncome,
}
for _, t := range tagsMap {
tags = append(tags, t)
}
sort.Slice(tags, func(i, j int) bool {
return tags[i].Date > tags[j].Date
})
return
}
// UpdateTagActivity update tag activity_id
func (s *Service) UpdateTagActivity(c context.Context, tagID, activityID int64) (err error) {
rows, err := s.dao.UpdateTagActivity(c, tagID, activityID)
if err == nil && rows != 1 {
err = fmt.Errorf("UpdateActivity effect rows(%d) error ", rows)
}
return
}

View File

@@ -0,0 +1,153 @@
package service
import (
"context"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/admin/main/growup/conf"
"go-common/app/admin/main/growup/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
srv *Service
)
func init() {
dir, _ := filepath.Abs("../cmd/growup-admin.toml")
flag.Set("conf", dir)
conf.Init()
srv = New(conf.Conf)
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
// Reset(func() { CleanCache() })
f(srv)
}
}
func Test_AddTagInfo(t *testing.T) {
var (
c = context.Background()
tag = &model.TagInfo{
Tag: "标签1",
Category: 6,
Business: 1,
}
creator = "creator"
)
Convey("admins", t, WithService(func(s *Service) {
s.dao.Exec(c, "DELETE FROM tag_info WHERE tag = '标签1'")
err := s.AddTagInfo(c, tag, creator)
So(err, ShouldBeNil)
}))
}
func Test_ModeTagState(t *testing.T) {
var (
c = context.Background()
tagID = 1
isDeleted = 1
)
Convey("admins", t, WithService(func(s *Service) {
s.dao.Exec(c, "DELETE FROM tag_info WHERE id = 1")
s.dao.Exec(c, "insert into tag_info(id, tag) values(1, 'test')")
err := s.ModeTagState(c, tagID, isDeleted)
So(err, ShouldBeNil)
}))
}
func Test_AddTagUps(t *testing.T) {
var (
c = context.Background()
tagID = 1
mids = []int64{1011, 1022}
isCommon = 1
)
Convey("admins", t, WithService(func(s *Service) {
s.dao.Exec(c, "DELETE FROM tag_up_info WHERE mid in (1011, 1022)")
err := s.AddTagUps(c, tagID, mids, isCommon)
So(err, ShouldBeNil)
}))
}
func Test_ReleaseUp(t *testing.T) {
var (
c = context.Background()
tagID = 1
mid = int64(1011)
)
Convey("admins", t, WithService(func(s *Service) {
s.dao.Exec(c, "UPDATE tag_info SET is_common = 0 WHERE id = 1")
err := s.ReleaseUp(c, tagID, mid)
So(err, ShouldBeNil)
}))
}
func Test_QueryTagInfo(t *testing.T) {
var (
c = context.Background()
startTime = int64(1515945600)
endTime = int64(1516809600)
categories = []int64{21, 167}
business = []int64{1, 2}
tag = "标签1"
from = 0
limit = 20
sort = "-ctime"
)
Convey("admins", t, WithService(func(s *Service) {
_, _, err := s.QueryTagInfo(c, startTime, endTime, categories, business, tag, 0, from, limit, sort)
So(err, ShouldBeNil)
}))
}
func Test_ListUps(t *testing.T) {
var (
c = context.Background()
tagID = 1
mid = int64(1011)
from = 0
limit = 20
)
Convey("admins", t, WithService(func(s *Service) {
_, _, err := s.ListUps(c, tagID, mid, from, limit)
So(err, ShouldBeNil)
}))
}
func Test_ListAvs(t *testing.T) {
var (
c = context.Background()
tagID = 1
avid = int64(2011)
from = 0
limit = 20
)
Convey("admins", t, WithService(func(s *Service) {
_, _, err := s.ListAvs(c, tagID, from, limit, avid)
So(err, ShouldBeNil)
}))
}
func Test_TagDetails(t *testing.T) {
var (
c = context.Background()
tagID = 1
from = 0
limit = 20
)
Convey("admins", t, WithService(func(s *Service) {
_, res, err := s.TagDetails(c, tagID, from, limit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
t.Logf("admins len(%d)", len(res))
}))
}

View File

@@ -0,0 +1,301 @@
package service
import (
"context"
"fmt"
"strings"
"time"
"go-common/app/admin/main/growup/dao"
"go-common/app/admin/main/growup/dao/resource"
"go-common/app/admin/main/growup/model"
"go-common/library/log"
)
const (
_datetimeLayout = "2006-01-02 15:04:05"
_dateLayout = "2006-01-02"
)
func (s *Service) tradeDao() dao.TradeDao {
return s.dao
}
// SyncGoods . secret portal...
func (s *Service) SyncGoods(c context.Context, gt int) (eff int64, err error) {
if gt != int(model.GoodsVIP) {
err = fmt.Errorf("unsupported goodsType(%v)", gt)
return
}
// query
vips, err := resource.VipProducts(c)
if err != nil {
return
}
existing := make(map[string]*model.GoodsInfo)
allGoods, err := s.tradeDao().GoodsList(c, fmt.Sprintf("is_deleted=0 AND goods_type=%d", gt), 0, 200)
if err != nil {
return
}
for _, v := range allGoods {
existing[v.ProductID] = v
}
// hardcoded <vip_product_duration_in_month, external_resource_id> k-v pairs
m := map[int32]int64{
1: 16,
3: 17,
12: 18,
}
// add incrementally
newGoods := make([]string, 0)
for k, v := range vips {
if _, ok := existing[k]; ok {
continue
}
rid, ok := m[v.Month]
if !ok {
err = fmt.Errorf("unkonwn vip goods, month(%d)", v.Month)
}
newGoods = append(newGoods, fmt.Sprintf("('%s', %d, %d, %d, %d)", v.ProductID, rid, gt, model.DisplayOff, 100))
}
if len(newGoods) == 0 {
return
}
fields := "ex_product_id, ex_resource_id, goods_type, is_display, discount"
return s.tradeDao().AddGoods(c, fields, strings.Join(newGoods, ","))
}
// GoodsList .
func (s *Service) GoodsList(c context.Context, from, limit int) (total int64, res []*model.GoodsInfo, err error) {
if total, err = s.tradeDao().GoodsCount(c, "is_deleted=0"); err != nil {
return
}
if total == 0 {
res = make([]*model.GoodsInfo, 0)
return
}
if res, err = s.tradeDao().GoodsList(c, "is_deleted=0", from, limit); err != nil || len(res) == 0 {
return
}
// external information of vip goods
var vips map[string]*model.GoodsInfo
if vips, err = resource.VipProducts(c); err != nil {
return
}
for _, target := range res {
if src, ok := vips[target.ProductID]; ok {
model.MergeExternal(target, src)
}
target.GoodsTypeDesc = target.GoodsType.Desc()
}
return
}
// UpdateGoodsInfo by ID
func (s *Service) UpdateGoodsInfo(c context.Context, discount int, ID int64) (int64, error) {
// select and diff before update?
set := fmt.Sprintf("discount=%d", discount)
return s.tradeDao().UpdateGoods(c, set, "", []int64{ID})
}
// UpdateGoodsDisplay by IDs
func (s *Service) UpdateGoodsDisplay(c context.Context, status model.DisplayStatus, IDs []int64) (eff int64, err error) {
switch status {
case model.DisplayOn:
eff, err = s.onlineGoods(c, IDs)
case model.DisplayOff:
eff, err = s.offlineGoods(c, IDs)
default:
err = fmt.Errorf("illegal display status(%v)", status)
}
return
}
// onlineGoods by IDs
func (s *Service) onlineGoods(c context.Context, IDs []int64) (int64, error) {
now := time.Now().Format(_datetimeLayout)
set := fmt.Sprintf("is_display=%d, display_on_time='%s'", model.DisplayOn, now)
return s.tradeDao().UpdateGoods(c, set, "is_deleted=0", IDs)
}
// offlineGoods by IDs
func (s *Service) offlineGoods(c context.Context, IDs []int64) (int64, error) {
now := time.Now().Format(_datetimeLayout)
set := fmt.Sprintf("is_display=%d, display_off_time='%s'", model.DisplayOff, now)
return s.tradeDao().UpdateGoods(c, set, "is_deleted=0", IDs)
}
// OrderStatistics .
func (s *Service) OrderStatistics(c context.Context, arg *model.OrderQueryArg) (data interface{}, err error) {
if pass := preprocess(c, arg); !pass {
return
}
where := orderQueryStr(arg)
var orders []*model.OrderInfo
if orders, err = s.orderAll(c, where); err != nil {
return
}
for _, v := range orders {
v.GenDerived()
}
data = orderStatistics(orders, arg.StartTime, arg.EndTime, arg.TimeType)
return
}
// orderAll . be careful using this
func (s *Service) orderAll(c context.Context, where string) (orders []*model.OrderInfo, err error) {
offset, size := 0, 2000
for {
list, err := s.tradeDao().OrderList(c, where, offset, size)
if err != nil {
return nil, err
}
orders = append(orders, list...)
if len(list) < size {
break
}
offset += len(list)
}
return
}
// orderStatistics . ugly...
func orderStatistics(orders []*model.OrderInfo, start, end time.Time, timeType model.TimeType) interface{} {
type orderStatUnit struct {
orderNum int64
totalPrice int64
totalCost int64
}
m := make(map[time.Time]*orderStatUnit)
for _, v := range orders {
date := timeType.RangeStart(v.OrderTime)
if _, ok := m[date]; !ok {
m[date] = &orderStatUnit{}
}
m[date].orderNum += v.GoodsNum
m[date].totalCost += v.TotalCost
m[date].totalPrice += v.TotalPrice
}
dates, orderNums, totalCost, totalPrice := make([]string, 0), make([]int64, 0), make([]int64, 0), make([]int64, 0)
for start.Before(end) {
next := timeType.Next()(start)
dates = append(dates, timeType.RangeDesc(start, next))
if v, ok := m[start]; ok {
orderNums = append(orderNums, v.orderNum)
totalCost = append(totalCost, v.totalCost)
totalPrice = append(totalPrice, v.totalPrice)
} else {
orderNums = append(orderNums, 0)
totalCost = append(totalCost, 0)
totalPrice = append(totalPrice, 0)
}
start = next
}
// result
data := map[string]interface{}{
"xAxis": dates,
"order_num": orderNums,
"total_cost": totalCost,
"total_income": totalPrice,
}
return data
}
// OrderExport .
func (s *Service) OrderExport(c context.Context, arg *model.OrderQueryArg, from, limit int) (res []byte, err error) {
_, orders, err := s.OrderList(c, arg, from, limit)
if err != nil {
return
}
records := make([][]string, 0, len(orders)+1)
records = append(records, model.OrderExportFields())
for _, v := range orders {
records = append(records, v.ExportStrings())
}
if res, err = FormatCSV(records); err != nil {
log.Error("FormatCSV error(%v)", err)
}
return
}
// OrderList .
func (s *Service) OrderList(c context.Context, arg *model.OrderQueryArg, from, limit int) (total int64, list []*model.OrderInfo, err error) {
list = make([]*model.OrderInfo, 0)
if pass := preprocess(c, arg); !pass {
return
}
where := orderQueryStr(arg)
if total, err = s.tradeDao().OrderCount(c, where); err != nil || total == 0 {
return
}
if list, err = s.tradeDao().OrderList(c, where, from, limit); err != nil || len(list) == 0 {
return
}
// fetch names
mids := make([]int64, 0)
for _, v := range list {
mids = append(mids, v.MID)
}
m, err := resource.NamesByMIDs(c, mids)
if err != nil {
return
}
// generate & merge
for _, v := range list {
v.GenDerived().GenDesc()
if name, ok := m[v.MID]; ok {
v.Nickname = name
}
}
return
}
func preprocess(c context.Context, arg *model.OrderQueryArg) bool {
if arg.Nickname != "" {
mid, err := resource.MidByNickname(c, arg.Nickname)
if err != nil || mid == 0 {
return false
}
log.Info("resource.MidByNickname name(%s) mid(%d)", arg.Nickname, arg.MID)
if arg.MID == 0 {
arg.MID = mid
}
if arg.MID != mid {
log.Error("illegal mid(%d) and nickname(%s) pair", arg.MID, arg.Nickname)
return false
}
}
arg.StartTime = arg.TimeType.RangeStart(time.Unix(arg.FromTime, 0))
arg.EndTime = arg.TimeType.RangeEnd(time.Unix(arg.ToTime, 0))
return true
}
func orderQueryStr(arg *model.OrderQueryArg) string {
var where []string
where = append(where, "is_deleted=0")
{
// 左开右闭
where = append(where, fmt.Sprintf("order_time >= '%s'", arg.StartTime.Format(_dateLayout)))
where = append(where, fmt.Sprintf("order_time < '%s'", arg.EndTime.Format(_dateLayout)))
}
if arg.GoodsType > 0 {
where = append(where, fmt.Sprintf("goods_type=%d", arg.GoodsType))
}
if arg.GoodsID != "" {
where = append(where, fmt.Sprintf("goods_id='%s'", arg.GoodsID))
}
if arg.GoodsName != "" {
where = append(where, fmt.Sprintf("goods_name='%s'", arg.GoodsName))
}
if arg.OrderNO != "" {
where = append(where, fmt.Sprintf("order_no='%s'", arg.OrderNO))
}
if arg.MID > 0 {
where = append(where, fmt.Sprintf("mid=%d", arg.MID))
}
return strings.Join(where, " AND ")
}

View File

@@ -0,0 +1,236 @@
package service
import (
"context"
"go-common/app/admin/main/growup/model"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestServicetradeDao(t *testing.T) {
convey.Convey("tradeDao", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := s.tradeDao()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceSyncGoods(t *testing.T) {
convey.Convey("SyncGoods", t, func(ctx convey.C) {
var (
c = context.Background()
gt = int(1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
eff, err := s.SyncGoods(c, gt)
ctx.Convey("Then err should be nil.eff should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(eff, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceGoodsList(t *testing.T) {
convey.Convey("GoodsList", t, func(ctx convey.C) {
var (
c = context.Background()
from = int(0)
limit = int(20)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
total, res, err := s.GoodsList(c, from, limit)
ctx.Convey("Then err should be nil.total,res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
ctx.So(total, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceUpdateGoodsInfo(t *testing.T) {
convey.Convey("UpdateGoodsInfo", t, func(ctx convey.C) {
var (
c = context.Background()
discount = int(100)
ID = int64(1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1, err := s.UpdateGoodsInfo(c, discount, ID)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceUpdateGoodsDisplay(t *testing.T) {
convey.Convey("UpdateGoodsDisplay", t, func(ctx convey.C) {
var (
c = context.Background()
status = model.DisplayOff
IDs = []int64{1}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
eff, err := s.UpdateGoodsDisplay(c, status, IDs)
ctx.Convey("Then err should be nil.eff should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(eff, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceonlineGoods(t *testing.T) {
convey.Convey("onlineGoods", t, func(ctx convey.C) {
var (
c = context.Background()
IDs = []int64{1}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1, err := s.onlineGoods(c, IDs)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceofflineGoods(t *testing.T) {
convey.Convey("offlineGoods", t, func(ctx convey.C) {
var (
c = context.Background()
IDs = []int64{1}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1, err := s.offlineGoods(c, IDs)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceOrderStatistics(t *testing.T) {
convey.Convey("OrderStatistics", t, func(ctx convey.C) {
var (
c = context.Background()
arg = &model.OrderQueryArg{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
data, err := s.OrderStatistics(c, arg)
ctx.Convey("Then err should be nil.data should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(data, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceorderAll(t *testing.T) {
convey.Convey("orderAll", t, func(ctx convey.C) {
var (
c = context.Background()
where = "id<10"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
orders, err := s.orderAll(c, where)
ctx.Convey("Then err should be nil.orders should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(orders, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceorderStatistics(t *testing.T) {
convey.Convey("orderStatistics", t, func(ctx convey.C) {
var (
orders = []*model.OrderInfo{}
start = time.Now()
end = time.Now().AddDate(0, 0, -1)
timeType = model.Monthly
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := orderStatistics(orders, start, end, timeType)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceOrderExport(t *testing.T) {
convey.Convey("OrderExport", t, func(ctx convey.C) {
var (
c = context.Background()
arg = &model.OrderQueryArg{}
from = int(0)
limit = int(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := s.OrderExport(c, arg, from, limit)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceOrderList(t *testing.T) {
convey.Convey("OrderList", t, func(ctx convey.C) {
var (
c = context.Background()
arg = &model.OrderQueryArg{}
from = int(0)
limit = int(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
total, list, err := s.OrderList(c, arg, from, limit)
ctx.Convey("Then err should be nil.total,list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(list, convey.ShouldNotBeNil)
ctx.So(total, convey.ShouldNotBeNil)
})
})
})
}
func TestServicepreprocess(t *testing.T) {
convey.Convey("preprocess", t, func(ctx convey.C) {
var (
c = context.Background()
arg = &model.OrderQueryArg{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := preprocess(c, arg)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeTrue)
})
})
})
}
func TestServiceorderQueryStr(t *testing.T) {
convey.Convey("orderQueryStr", t, func(ctx convey.C) {
var (
arg = &model.OrderQueryArg{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := orderQueryStr(arg)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,885 @@
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
}

View File

@@ -0,0 +1,187 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_QueryFromUpInfo(t *testing.T) {
var (
accType = 3
states = []int64{int64(1)}
mid = int64(1011)
category = 1
signType = 1
nickname = "hello"
lower, upper = 0, 100
from, limit = 0, 1000
sort = "ctime"
)
Convey("admins", t, WithService(func(s *Service) {
_, _, err := s.QueryFromUpInfo(context.Background(), 0, accType, states, mid, category, signType, nickname, lower, upper, from, limit, sort)
So(err, ShouldBeNil)
}))
}
func Test_Reject(t *testing.T) {
var (
mids = []int64{int64(1101)}
reason = "reject"
days = 1
)
Convey("admins", t, WithService(func(s *Service) {
err := s.Reject(context.Background(), 0, mids, reason, days)
So(err, ShouldBeNil)
}))
}
func Test_Pass(t *testing.T) {
var (
mids = []int64{int64(1101)}
)
Convey("admins", t, WithService(func(s *Service) {
err := s.Pass(context.Background(), mids, 0)
So(err, ShouldBeNil)
}))
}
func Test_Dismiss(t *testing.T) {
var (
operator = "user"
mid = int64(1101)
reason = "dismiss"
)
Convey("admins", t, WithService(func(s *Service) {
err := s.Dismiss(context.Background(), operator, 0, 3, mid, reason)
So(err, ShouldBeNil)
}))
}
func Test_Forbid(t *testing.T) {
var (
operator = "user"
mid = int64(1101)
reason = "dismiss"
days = 5
)
Convey("admins", t, WithService(func(s *Service) {
err := s.Forbid(context.Background(), operator, 0, 3, mid, reason, days, 100)
So(err, ShouldBeNil)
}))
}
func Test_Recovery(t *testing.T) {
var (
mid = int64(1101)
)
Convey("admins", t, WithService(func(s *Service) {
err := s.Recovery(context.Background(), mid)
So(err, ShouldBeNil)
}))
}
func Test_UpdateUpAccountState(t *testing.T) {
var (
mid = int64(1101)
state = 3
)
Convey("admins", t, WithService(func(s *Service) {
err := s.UpdateUpAccountState(context.Background(), "up_info_video", mid, state)
So(err, ShouldBeNil)
}))
}
func Test_DeleteUp(t *testing.T) {
var (
mid = int64(1101)
)
Convey("admins", t, WithService(func(s *Service) {
err := s.DeleteUp(context.Background(), mid)
So(err, ShouldBeNil)
}))
}
func Test_Block(t *testing.T) {
var (
mid = int64(1101)
)
Convey("admins", t, WithService(func(s *Service) {
err := s.Block(context.Background(), mid)
So(err, ShouldBeNil)
}))
}
func Test_QueryFromBlocked(t *testing.T) {
var (
mid = int64(1011)
category = 1
nickname = "hello"
lower, upper = 0, 100
from, limit = 0, 1000
sort = "ctime"
)
Convey("admins", t, WithService(func(s *Service) {
_, _, err := s.QueryFromBlocked(context.Background(), mid, category, nickname, lower, upper, from, limit, sort)
So(err, ShouldBeNil)
}))
}
func Test_DeleteFromBlocked(t *testing.T) {
var (
mid = int64(1101)
)
Convey("admins", t, WithService(func(s *Service) {
err := s.DeleteFromBlocked(context.Background(), mid)
So(err, ShouldBeNil)
}))
}
func Test_DelUpAccount(t *testing.T) {
var (
mid = int64(1101)
)
Convey("admins", t, WithService(func(s *Service) {
err := s.DelUpAccount(context.Background(), mid)
So(err, ShouldBeNil)
}))
}
func Test_CreditRecords(t *testing.T) {
var (
mid = int64(1101)
)
Convey("admins", t, WithService(func(s *Service) {
_, err := s.CreditRecords(context.Background(), mid)
So(err, ShouldBeNil)
}))
}
func Test_RecoverCreditScore(t *testing.T) {
var (
id, mid int64 = 1, 1011
)
Convey("admins", t, WithService(func(s *Service) {
err := s.RecoverCreditScore(context.Background(), 0, id, mid)
So(err, ShouldBeNil)
}))
}
func Test_ExportUps(t *testing.T) {
var (
accType = 3
states = []int64{int64(1)}
mid = int64(1011)
category = 1
signType = 1
nickname = "hello"
lower, upper = 0, 100
from, limit = 0, 1000
sort = "ctime"
)
Convey("admins", t, WithService(func(s *Service) {
_, err := s.ExportUps(context.Background(), 0, accType, states, mid, category, signType, nickname, lower, upper, from, limit, sort)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,27 @@
package service
import (
"bytes"
"context"
"time"
"go-common/library/ecode"
"go-common/library/log"
)
// Upload upload.
func (s *Service) Upload(c context.Context, fileName, fileType string, t time.Time, body []byte) (location string, err error) {
if len(body) == 0 {
err = ecode.GrowupBodyNotExist
return
}
if len(body) > s.conf.Bfs.MaxFileSize {
err = ecode.GrowupBodyTooLarge
return
}
if location, err = s.dao.Upload(c, fileName, fileType, t.Unix(), bytes.NewReader(body)); err != nil {
log.Error("s.dao.Upload error(%v)", err)
return
}
return
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
package service
import (
"context"
)
// InsertWhite insert white
func (s *Service) InsertWhite(c context.Context, mid int64, typ int) (err error) {
_, err = s.dao.InsertWhitelist(c, mid, typ)
return
}