123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- package service
- import (
- "context"
- "go-common/app/admin/main/workflow/model"
- "go-common/app/admin/main/workflow/model/param"
- "go-common/app/admin/main/workflow/model/search"
- "go-common/library/ecode"
- "go-common/library/log"
- bm "go-common/library/net/http/blademaster"
- "github.com/pkg/errors"
- )
- // PlatformChallCount will return count of challenges which are backlog of an admin
- func (s *Service) PlatformChallCount(c context.Context, assigneeAdminID int64, permissionMap map[int8]int64) (challCount *search.ChallCount, err error) {
- var challSearchCommonResp *search.ChallSearchCommonResp
- if challCount, err = s.dao.ChallCountCache(c, assigneeAdminID); err != nil {
- log.Warn("s.dao.ChallCountCache(%d) error(%v)", assigneeAdminID, err)
- err = nil
- }
- if challCount != nil {
- return
- }
- // not fit cache, need to search es
- challCount = new(search.ChallCount)
- challCount.BusinessCount = make(map[int8]int64)
- for business, round := range permissionMap {
- cond := new(search.ChallSearchCommonCond)
- cond.Fields = []string{"id"}
- cond.Business = business
- cond.AssigneeAdminIDs = []int64{assigneeAdminID}
- cond.PN = 1
- cond.PS = 1000
- cond.Order = "id"
- cond.Sort = "desc"
- if round == model.FeedbackRound {
- cond.BusinessStates = []int64{0, 1}
- } else {
- cond.States = []int64{0}
- }
- if challSearchCommonResp, err = s.dao.SearchChallenge(c, cond); err != nil {
- log.Error("s.dao.SearchChallenge(%v) error(%v)", cond, err)
- return
- }
- challCount.BusinessCount[business] = int64(challSearchCommonResp.Page.Total)
- challCount.TotalCount += int64(challSearchCommonResp.Page.Total)
- }
- if err = s.dao.UpChallCountCache(c, challCount, assigneeAdminID); err != nil {
- log.Error("s.dao.UpChallCountCache(%d) error(%v)", assigneeAdminID, err)
- err = nil
- }
- return
- }
- // PlatformChallListPending will return challenges which are backlog of an admin
- func (s *Service) PlatformChallListPending(c context.Context, assigneeAdminID int64, permissionMap map[int8]int64, pclp *param.ChallListParam) (challPage *search.ChallListPageCommon, err error) {
- var (
- challSearchCommonResp *search.ChallSearchCommonResp
- cids []int64
- uids []int64
- challs map[int64]*model.Chall
- challLastLog map[int64]string
- challLastEvent map[int64]*model.Event
- attPaths map[int64][]string
- uNames map[int64]string
- attr *model.BusinessAttr
- rcids []int64
- exist bool
- ok bool
- pMeta map[int8]map[int64][]int64
- t *model.TagMeta
- l string
- gidToBus map[int64]*model.Business
- )
- rand := pclp.R
- log.Info("assignee_adminid(%d) call pending rand(%d)", assigneeAdminID, rand)
- pMetas := model.PlatformMetas()
- // todo: if assign type = 0 judge if admin is online
- if exist, err = s.dao.IsOnline(c, assigneeAdminID); err != nil {
- log.Info("s.dao.IsOnline(%d) error(%v)", assigneeAdminID, err)
- return
- }
- for i, business := range pclp.Businesses {
- pMeta, ok = pMetas[business]
- if !ok {
- log.Error("not read platform meta of business(%d)", business)
- }
- if attr, ok = s.busAttrCache[business]; !ok {
- log.Error("can not find business(%d) attr", business)
- continue
- }
- assignNum := pclp.AssignNum[i]
- // assignNum not allow over assignMax
- if assignNum > attr.AssignMax {
- assignNum = attr.AssignMax
- }
- round, ok := permissionMap[business]
- if !ok {
- log.Warn("uid(%d) not has permission of business(%d) rand(%d)", assigneeAdminID, business, rand)
- continue
- }
- // need get mission from redis list (not assigneed)
- if attr.AssignType == 0 {
- // assignType == 0 need judge checkin
- if !exist {
- log.Info("uid(%d) not checkin platform rand(%d)", assigneeAdminID, rand)
- continue
- }
- // get mission from es first
- cond := &search.ChallSearchCommonCond{
- Fields: []string{"id"},
- AssigneeAdminIDs: []int64{assigneeAdminID},
- PS: int(assignNum),
- PN: pclp.PN,
- }
- if round >= model.AuditRoundMin && round <= model.AuditRoundMax {
- cond.Business = business
- cond.States, ok = pMeta[0][0]
- if !ok {
- continue
- }
- }
- if round == model.FeedbackRound { //feedback flow
- cond.Business = business
- cond.BusinessStates, ok = pMeta[0][1]
- if !ok {
- continue
- }
- }
- if challSearchCommonResp, err = s.dao.SearchChallenge(c, cond); err != nil {
- log.Error("s.dao.SearchChallenge(%+v) error(%v)", cond, err)
- return
- }
- for _, r := range challSearchCommonResp.Result {
- cids = append(cids, r.ID)
- }
- log.Warn("uid(%d) has mission in db, cids:(%v) rand(%d)", assigneeAdminID, cids, rand)
- assignNum = assignNum - int8(len(challSearchCommonResp.Result))
- if assignNum <= 0 {
- log.Warn("uid(%d) cids:(%v) business(%d) round(%d) not need consume, continue rand(%d)", assigneeAdminID, cids, business, round, rand)
- continue
- }
- log.Warn("uid(%d) wanna consume redis business(%d) round(%d) num(%d) already has cids(%v) rand(%d)", assigneeAdminID, business, round, assignNum, cids, rand)
- // mission from redis
- rcids, err = s.dao.RedisRPOPCids(c, business, round, assignNum)
- if err != nil {
- log.Error("s.dao.RedisRPOPCids(%d,%d,%d) error(%v)", business, round, assignNum, err)
- err = errors.WithStack(err)
- return nil, err
- }
- tx := s.dao.ORM.Begin()
- if tx.Error != nil {
- return
- }
- defer func() {
- if r := recover(); r != nil {
- tx.Rollback()
- log.Error("s.PlatformChallListPending() panic(%v)", r)
- }
- }()
- // set dispatch_time if consume mission from redis
- if err = s.dao.TxUpChallAssignee(tx, rcids); err != nil {
- log.Error("s.dao.TxUpChallAssignee(%v,%d)", rcids, assigneeAdminID)
- return nil, err
- }
- log.Warn("uid(%d) consume cids(%v) business(%d) round(%d) rand(%d)", assigneeAdminID, rcids, business, round, rand)
- cids = append(cids, rcids...)
- // set challenge business_state to pending
- if err = s.dao.TxUpChallsBusStateByIDs(tx, rcids, 1, assigneeAdminID); err != nil {
- log.Error("s.dao.TxUpChallsBusStateByIDs(%v,%d,%d)", cids, 1, assigneeAdminID)
- return nil, err
- }
- if err = tx.Commit().Error; err != nil {
- tx.Rollback()
- log.Error("Failed to tx.Commit(): %v", err)
- return
- }
- } else if attr.AssignType == 1 { // get mission only from es search (already assigneed)
- cond := &search.ChallSearchCommonCond{
- Fields: []string{"id"},
- AssigneeAdminIDs: []int64{assigneeAdminID},
- PS: int(assignNum),
- PN: 1,
- }
- if round >= model.AuditRoundMin && round <= model.AuditRoundMax {
- cond.Business = business
- cond.States = pMetas[business][0][0]
- } else {
- continue //feedback flow not support assign type 0
- }
- if challSearchCommonResp, err = s.dao.SearchChallenge(c, cond); err != nil {
- log.Error("s.dao.SearchChallenge(%+v) error(%v)", cond, err)
- return
- }
- for _, r := range challSearchCommonResp.Result {
- cids = append(cids, r.ID)
- }
- }
- }
- log.Info("after a pending uid(%d) rand(%d)", assigneeAdminID, rand)
- challPage = &search.ChallListPageCommon{}
- if len(cids) == 0 {
- challPage.Items = make([]*model.Chall, 0)
- challPage.Page = &model.Page{
- Num: pclp.PN,
- Size: pclp.PS,
- Total: 0,
- }
- return
- }
- if challs, err = s.dao.Challs(c, cids); err != nil {
- log.Error("s.dao.Challs(%v) error(%v)", cids, err)
- return
- }
- if challLastLog, err = s.LastLog(c, cids, []int{model.WLogModuleChallenge, model.WLogModuleReply}); err != nil {
- log.Error("s.batchLastLog(%v,%v) error(%v)", cids, model.WLogModuleChallenge, err)
- err = nil
- }
- if attPaths, err = s.dao.AttPathsByCids(c, cids); err != nil {
- log.Error("s.dao.AttPathsByCids() error(%v)", err)
- return
- }
- cond := &search.ChallSearchCommonCond{
- Fields: []string{"id", "gid"},
- IDs: cids,
- PS: 1000,
- PN: 1,
- }
- if challSearchCommonResp, err = s.dao.SearchChallenge(c, cond); err != nil {
- log.Error("s.dao.SearchChallenge(%+v) error(%v)", cond, err)
- return
- }
- var gids []int64
- for _, r := range challSearchCommonResp.Result {
- gids = append(gids, r.Gid)
- }
- if gidToBus, err = s.dao.BusObjectByGids(c, gids); err != nil {
- log.Error("s.dao.BusObjectByGids(%v) error(%v)", gids, err)
- return
- }
- if challLastEvent, err = s.batchLastEvent(c, cids); err != nil {
- log.Error("s.batchLastEvent(%v) error(%v)", cids, err)
- return
- }
- for _, c := range challs {
- uids = append(uids, int64(c.AdminID))
- uids = append(uids, int64(c.AssigneeAdminID))
- }
- if uNames, err = s.dao.BatchUNameByUID(c, uids); err != nil {
- log.Error("s.dao.SearchUNameByUid(%v) error(%v)", uids, err)
- err = nil
- }
- challList := make([]*model.Chall, 0, len(challSearchCommonResp.Result))
- for _, cid := range cids {
- c, ok := challs[cid]
- if !ok {
- log.Warn("Invalid challenge id %d", cid)
- continue
- }
- // fill tag
- if t, err = s.tag(c.Business, c.Tid); err != nil {
- log.Error("s.tag(%d,%d) error(%v)", c.Business, c.Tid, err)
- err = nil
- } else {
- c.Tag = t.Name
- c.Round = t.RID
- }
- // fill last log
- if l, ok = challLastLog[cid]; ok {
- c.LastLog = l
- }
- // fill last event
- c.LastEvent = challLastEvent[cid]
- // fill attachments
- c.Attachments = make([]string, 0)
- if ps, ok := attPaths[cid]; ok {
- c.Attachments = ps
- c.FixAttachments()
- }
- //fill business object
- if b, ok := gidToBus[c.Gid]; ok {
- c.BusinessObject = b
- } else {
- log.Warn("failed to find bus object gid(%d) cid(%d)", c.Gid, c.Cid)
- }
- c.AssigneeAdminName = uNames[c.AssigneeAdminID]
- c.AdminName = uNames[c.AdminID]
- c.FromState()
- challList = append(challList, c)
- }
- challPage.Items = challList
- challPage.Page = &model.Page{
- Num: challSearchCommonResp.Page.Num,
- Size: challSearchCommonResp.Page.Size,
- Total: len(cids),
- }
- return
- }
- // PlatformChallListHandlingDone list handling challenges of admin
- func (s *Service) PlatformChallListHandlingDone(c *bm.Context, pchlp *param.ChallHandlingDoneListParam, permissionMap map[int8]int64, assigneeAdminID int64, feature int8) (challPage interface{}, err error) {
- pMetas := model.PlatformMetas()
- business := pchlp.Businesses
- round := permissionMap[business]
- if _, ok := pMetas[business]; !ok { // business not in platform
- err = errors.Wrap(ecode.MethodNotAllowed, "business not in platform")
- return
- }
- if _, ok := pMetas[business][feature]; !ok { // business not has platform state
- err = errors.Wrap(ecode.MethodNotAllowed, "business not has platform state")
- return
- }
- cond := &search.ChallSearchCommonCond{
- Fields: []string{"id", "gid"},
- Business: business,
- AssigneeAdminIDs: []int64{assigneeAdminID},
- PS: pchlp.PS,
- PN: pchlp.PN,
- Sort: pchlp.Sort,
- Order: pchlp.Order,
- }
- if round >= model.AuditRoundMin && round <= model.AuditRoundMax { //audit flow
- cond.Business = business
- cond.States = pMetas[business][feature][0]
- }
- if round == model.FeedbackRound { //feedback flow
- cond.Business = business
- cond.BusinessStates = pMetas[business][feature][1]
- }
- return s.ChallsWrap(c, cond)
- }
- // PlatformChallListCreated list created challenges of admin
- func (s *Service) PlatformChallListCreated(c context.Context, cond *search.ChallSearchCommonCond) (challPage *search.ChallListPageCommon, err error) {
- return s.ChallsWrap(c, cond)
- }
- // PlatformRelease admin offline
- func (s *Service) PlatformRelease(c context.Context, permissionMap map[int8]int64, assigneeAdminID int64) (err error) {
- var (
- challSearchCommonResp *search.ChallSearchCommonResp
- cids []int64
- attr *model.BusinessAttr
- ok bool
- )
- cids = make([]int64, 0)
- for business, round := range permissionMap {
- cond := &search.ChallSearchCommonCond{
- Fields: []string{"id"},
- AssigneeAdminIDs: []int64{assigneeAdminID},
- PN: 1,
- PS: 1000,
- }
- if attr, ok = s.busAttrCache[business]; !ok {
- log.Error("can not find business(%d) attr", business)
- continue
- }
- if attr.AssignType == 1 {
- continue
- } else { //任务消费 退出需要释放待处理状态的工单
- if round == model.FeedbackRound { //客服
- cond.BusinessStates = []int64{0, 1}
- } else {
- cond.States = []int64{0}
- }
- cond.Business = business
- if challSearchCommonResp, err = s.dao.SearchChallenge(c, cond); err != nil {
- log.Error("s.dao.SearchChallenge(%v) error(%v)", cond, err)
- return
- }
- for _, r := range challSearchCommonResp.Result {
- cids = append(cids, r.ID)
- }
- }
- }
- if err = s.dao.BatchResetAssigneeAdminID(cids); err != nil {
- return
- }
- err = s.dao.DelOnline(c, assigneeAdminID)
- // add report
- log.Info("uid(%d) offline success err(%v)", assigneeAdminID, err)
- return
- }
- // PlatformCheckIn admin online
- func (s *Service) PlatformCheckIn(c context.Context, assigneeAdminID int64) (err error) {
- err = s.dao.AddOnline(c, assigneeAdminID)
- // add report
- log.Info("uid(%d) online success err(%v)", assigneeAdminID, err)
- return
- }
- // PlatformOnlineList .
- func (s *Service) PlatformOnlineList(c context.Context) (err error) {
- var onlineAdminIDs []int64
- if onlineAdminIDs, err = s.dao.ListOnline(c); err != nil {
- return
- }
- // search login/out time, last 24h operate
- s.dao.LogInOutTime(c, onlineAdminIDs)
- return
- }
- // ChallsWrap warp challenges list result
- func (s *Service) ChallsWrap(c context.Context, cond *search.ChallSearchCommonCond) (challPageCommon *search.ChallListPageCommon, err error) {
- var (
- challSearchCommonResp *search.ChallSearchCommonResp
- challLastLog map[int64]string
- challLastEvent map[int64]*model.Event
- attPaths map[int64][]string
- gidToBus map[int64]*model.Business
- uNames map[int64]string
- challs map[int64]*model.Chall
- cids []int64
- uids []int64
- gids []int64
- t *model.TagMeta
- l string
- )
- challSearchCommonResp, err = s.dao.SearchChallenge(c, cond)
- if err != nil {
- err = errors.WithStack(err)
- return nil, err
- }
- cids = make([]int64, 0)
- uids = make([]int64, 0, len(challSearchCommonResp.Result)*2)
- gids = make([]int64, 0)
- for _, r := range challSearchCommonResp.Result {
- cids = append(cids, r.ID)
- gids = append(gids, r.Gid)
- }
- challPageCommon = new(search.ChallListPageCommon)
- if len(cids) == 0 {
- challPageCommon.Items = make([]*model.Chall, 0)
- challPageCommon.Page = &model.Page{
- Num: cond.PN,
- Size: cond.PS,
- Total: 0,
- }
- return
- }
- if challs, err = s.dao.Challs(c, cids); err != nil {
- log.Error("s.dao.Challs(%v) error(%v)", cids, err)
- return
- }
- if challLastLog, err = s.LastLog(c, cids, []int{model.WLogModuleChallenge, model.WLogModuleReply}); err != nil {
- log.Error("s.batchLastLog(%v,%v) error(%v)", cids, model.WLogModuleChallenge, err)
- err = nil
- }
- if attPaths, err = s.dao.AttPathsByCids(c, cids); err != nil {
- log.Error("s.dao.AttPathsByCids() error(%v)", err)
- return
- }
- if gidToBus, err = s.dao.BusObjectByGids(c, gids); err != nil {
- log.Error("s.dao.BusObjectByGids(%v) error(%v)", gids, err)
- return
- }
- if challLastEvent, err = s.batchLastEvent(c, cids); err != nil {
- log.Error("s.batchLastEvent(%v) error(%v)", cids, err)
- return
- }
- for _, c := range challs {
- uids = append(uids, int64(c.AdminID))
- uids = append(uids, int64(c.AssigneeAdminID))
- }
- if uNames, err = s.dao.BatchUNameByUID(c, uids); err != nil {
- log.Error("s.dao.SearchUNameByUid(%v) error(%v)", uids, err)
- err = nil
- }
- challList := make([]*model.Chall, 0, len(cids))
- for _, cid := range cids {
- c, ok := challs[cid]
- if !ok {
- log.Warn("Invalid challenge id %d", cid)
- continue
- }
- // fill tag
- if t, err = s.tag(c.Business, c.Tid); err != nil {
- log.Error("s.tag(%d,%d) error(%v)", c.Business, c.Tid, err)
- err = nil
- } else {
- c.Tag = t.Name
- c.Round = t.RID
- }
- // fill last log
- if l, ok = challLastLog[cid]; ok {
- c.LastLog = l
- }
- // fill last event
- c.LastEvent = challLastEvent[cid]
- // fill attachments
- c.Attachments = make([]string, 0)
- if ps, ok := attPaths[cid]; ok {
- c.Attachments = ps
- c.FixAttachments()
- }
- //fill business object
- if b, ok := gidToBus[c.Gid]; ok {
- c.BusinessObject = b
- } else {
- log.Warn("failed to find bus object gid(%d) cid(%d)", c.Gid, c.Cid)
- }
- c.AssigneeAdminName = uNames[c.AssigneeAdminID]
- c.AdminName = uNames[c.AdminID]
- c.FromState()
- challList = append(challList, c)
- }
- challPageCommon.Items = challList
- challPageCommon.Page = &model.Page{
- Num: challSearchCommonResp.Page.Num,
- Size: challSearchCommonResp.Page.Size,
- Total: challSearchCommonResp.Page.Total,
- }
- return
- }
|