You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
646 lines
17 KiB
646 lines
17 KiB
package service |
|
|
|
import ( |
|
"context" |
|
"net" |
|
"sort" |
|
"strconv" |
|
"strings" |
|
"time" |
|
"unicode/utf8" |
|
|
|
"go-common/app/interface/main/feedback/model" |
|
locmdl "go-common/app/service/main/location/model" |
|
"go-common/library/database/sql" |
|
"go-common/library/ecode" |
|
"go-common/library/log" |
|
"go-common/library/net/metadata" |
|
xtime "go-common/library/time" |
|
"go-common/library/xstr" |
|
) |
|
|
|
const ( |
|
_androidFeedback = "android-feedback" |
|
_androidFeedbackI = "android-fb-i" |
|
_iosFeedback = "ios-feedback" |
|
_iosFeedbackI = "ios-fb-i" |
|
_androidPlayer = "android-player" |
|
_iosPlayer = "ios-player" |
|
_androidCreative = "android-creative" |
|
_iosCreative = "ios-creative" |
|
_androidLivePink = "android-live-pink" |
|
_iosLivePink = "ios-live-pink" |
|
_tvYST = "tv-yst" |
|
_creativeCenter = "creative-center" |
|
) |
|
|
|
var ( |
|
defaultTag = &model.Tag{ |
|
ID: 314, |
|
Name: "其它问题", |
|
Type: 0, |
|
} |
|
) |
|
|
|
// AddReply add feedback raply and create session if session isn't exist |
|
func (s *Service) AddReply(c context.Context, mid, tagID int64, buvid, system, version, mobiApp, content, imgURL, logURL, device, channel, entrance, |
|
netState, netOperator, agencyArea, platform, browser, qq, email string, now time.Time) (r *model.Reply, err error) { |
|
// check size |
|
if utf8.RuneCountInString(content) > s.c.Feedback.MaxContentSize { |
|
err = ecode.FeedbackBodyTooLarge |
|
return |
|
} |
|
var ( |
|
ssn *model.Session |
|
reply *model.Reply |
|
cTime xtime.Time |
|
replyID = buvid |
|
id int64 |
|
imgURLs []string |
|
ip = metadata.String(c, metadata.RemoteIP) |
|
) |
|
if entrance == "view" { |
|
if model.IsAndroid(model.Plat(mobiApp, device)) { |
|
platform = _androidPlayer |
|
} else if model.IsIOS(model.Plat(mobiApp, device)) { |
|
platform = _iosPlayer |
|
} |
|
} else if entrance == _tvYST || entrance == _creativeCenter { |
|
platform = entrance |
|
} else if platform == "android" { |
|
if entrance == _androidCreative { |
|
platform = _androidCreative |
|
} else if entrance == _androidLivePink { |
|
platform = _androidLivePink |
|
} else if model.Plat(mobiApp, device) == model.PlatAndroid { |
|
platform = _androidFeedback |
|
} else if model.Plat(mobiApp, device) == model.PlatAndroidI { |
|
platform = _androidFeedbackI |
|
} |
|
} else if platform == "ios" { |
|
if entrance == _iosCreative { |
|
platform = _iosCreative |
|
} else if entrance == _iosLivePink { |
|
platform = _iosLivePink |
|
} else if model.Plat(mobiApp, device) == model.PlatIPhone { |
|
platform = _iosFeedback |
|
} else if model.Plat(mobiApp, device) == model.PlatIPhoneI { |
|
platform = _iosFeedbackI |
|
} |
|
} |
|
if ssn, err = s.dao.Session(c, buvid, system, version, mid); err != nil { |
|
log.Error("s.dao.Session(%s,%s,%s,%d) error(%v)", buvid, system, version, mid, err) |
|
return |
|
} |
|
if mid != 0 { |
|
replyID = strconv.FormatInt(mid, 10) |
|
} |
|
cTime = xtime.Time(now.Unix()) |
|
if ssn == nil { |
|
if content != "" || logURL != "" || imgURL != "" { |
|
// TODO delete ; |
|
imgURLs = strings.Split(imgURL, ";") |
|
var sid int64 |
|
sid, err = s.session(c, mid, tagID, buvid, system, version, "", content, imgURLs[0], logURL, device, channel, ip, entrance, netState, netOperator, agencyArea, platform, browser, qq, email, now) |
|
if err == nil { |
|
for _, v := range imgURLs[1:] { |
|
if v != "" { |
|
reply = &model.Reply{ |
|
SessionID: sid, |
|
ReplyID: replyID, |
|
Content: "", |
|
ImgURL: v, |
|
LogURL: "", |
|
CTime: cTime, |
|
MTime: cTime, |
|
} |
|
if id, err = s.dao.AddReply(c, reply); err != nil { |
|
log.Error("s.dao.AddReply error(%v)", err) |
|
continue |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
if entrance == "view" || entrance == _androidLivePink || entrance == _iosLivePink || platform == _androidLivePink || platform == _iosLivePink || model.IsPlayerScreen(tagID) || entrance == _tvYST || platform == _tvYST || entrance == _creativeCenter || platform == _creativeCenter { |
|
_, err = s.session(c, mid, tagID, buvid, system, version, "", content, imgURL, logURL, device, channel, ip, entrance, netState, netOperator, agencyArea, platform, browser, qq, email, now) |
|
if err != nil { |
|
log.Error("s.session error (%v)", err) |
|
return |
|
} |
|
} else { |
|
stat := ssn.State |
|
if ssn.State == model.StateReplied { |
|
stat = model.StateRepeated |
|
} |
|
var ip32 uint32 |
|
ipv := net.ParseIP(ip) |
|
if ip2 := ipv.To4(); ip2 != nil { |
|
ip32 = model.InetAtoN(ip) |
|
} |
|
ssn = &model.Session{ |
|
ID: ssn.ID, |
|
Device: device, |
|
Channel: channel, |
|
IP: ip32, |
|
NetState: netState, |
|
NetOperator: netOperator, |
|
AgencyArea: agencyArea, |
|
Platform: platform, |
|
Browser: browser, |
|
QQ: qq, |
|
Email: email, |
|
State: stat, |
|
LasterTime: cTime, |
|
MTime: cTime, |
|
} |
|
if _, err = s.dao.UpdateSession(c, ssn); err != nil { |
|
log.Error("s.dao.UpdateSession error(%v)", err) |
|
return |
|
} |
|
if content != "" || logURL != "" { |
|
reply = &model.Reply{ |
|
SessionID: ssn.ID, |
|
ReplyID: replyID, |
|
Content: content, |
|
ImgURL: "", |
|
LogURL: logURL, |
|
CTime: cTime, |
|
MTime: cTime, |
|
} |
|
if id, err = s.dao.AddReply(c, reply); err != nil { |
|
log.Error("s.dao.AddReply error(%v)", err) |
|
return |
|
} |
|
} |
|
for _, v := range strings.Split(imgURL, ";") { |
|
if v != "" { |
|
cTime = xtime.Time(now.Unix()) |
|
reply = &model.Reply{ |
|
SessionID: ssn.ID, |
|
ReplyID: replyID, |
|
Content: "", |
|
ImgURL: v, |
|
LogURL: "", |
|
CTime: cTime, |
|
MTime: cTime, |
|
} |
|
if id, err = s.dao.AddReply(c, reply); err != nil { |
|
log.Error("s.dao.AddReply error(%v)", err) |
|
continue |
|
} |
|
} |
|
} |
|
} |
|
} |
|
r = &model.Reply{ |
|
ID: id, |
|
ReplyID: replyID, |
|
Type: model.TypeCustomer, |
|
Content: content, |
|
ImgURL: imgURL, |
|
LogURL: logURL, |
|
CTime: cTime, |
|
} |
|
return |
|
} |
|
|
|
// AddWebReply add web reply. |
|
func (s *Service) AddWebReply(c context.Context, mid, sid, tagID int64, aid, content, imgURL, netState, netOperator, agencyArea, platform, version, buvid, browser, qq, email string, now time.Time) (r *model.Reply, err error) { |
|
var ( |
|
cTime xtime.Time |
|
reply *model.Reply |
|
tx *sql.Tx |
|
rid int |
|
id int64 |
|
sessionID int64 |
|
replyID string |
|
ip = metadata.String(c, metadata.RemoteIP) |
|
) |
|
if mid != 0 { |
|
replyID = strconv.FormatInt(mid, 10) |
|
} |
|
sessionID = sid |
|
cTime = xtime.Time(now.Unix()) |
|
if buvid == "" { |
|
buvid = strconv.FormatInt(now.Unix(), 10) |
|
} |
|
rid, err = s.dao.JudgeSsnRecord(c, sessionID) |
|
if err != nil { |
|
log.Error("s.dao.JudgeSsnRecord error(%v)", err) |
|
return |
|
} |
|
if sessionID > 0 || rid > 0 { |
|
reply = &model.Reply{ |
|
SessionID: sessionID, |
|
ReplyID: replyID, |
|
Content: content, |
|
ImgURL: imgURL, |
|
CTime: cTime, |
|
MTime: cTime, |
|
} |
|
tx, err = s.dao.BeginTran(c) |
|
if err != nil { |
|
log.Error("s.dao.Begin error(%v)", err) |
|
return |
|
} |
|
if id, err = s.dao.TxAddReply(tx, reply); err != nil { |
|
log.Error("s.dao.TxAddReply error(%v)", err) |
|
tx.Rollback() |
|
return |
|
} |
|
if err = s.dao.TxUpdateSessionState(tx, model.StateNoReply, sessionID); err != nil { |
|
log.Error("s.dao.TxUpdateSessionState error(%v)", err) |
|
tx.Rollback() |
|
return |
|
} |
|
if err = tx.Commit(); err != nil { |
|
log.Error("tx.Commit(), error(%v)", err) |
|
return |
|
} |
|
r = &model.Reply{ |
|
ID: id, |
|
ReplyID: replyID, |
|
Type: model.TypeCustomer, |
|
Content: content, |
|
ImgURL: imgURL, |
|
CTime: cTime, |
|
} |
|
} else { |
|
sessionID, err = s.session(c, mid, tagID, buvid, "", version, aid, content, imgURL, "", "", "", ip, "", netState, netOperator, agencyArea, platform, browser, qq, email, now) |
|
if err == nil { |
|
reply = &model.Reply{ |
|
SessionID: sessionID, |
|
ReplyID: replyID, |
|
Content: content, |
|
ImgURL: imgURL, |
|
CTime: cTime, |
|
MTime: cTime, |
|
} |
|
if _, err = s.dao.AddReply(c, reply); err != nil { |
|
log.Error("s.dao.AddReplyNoTx error(%v)", err) |
|
return |
|
} |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) session(c context.Context, mid, tagID int64, buvid, system, version string, aid, content, imgURL, logURL, device, channel, ip, entrance, |
|
netState, netOperator, agencyArea, platform, browser, qq, email string, now time.Time) (sid int64, err error) { |
|
if platform == "ugc" { |
|
var count int |
|
// 通过平台进行处理 |
|
count, err = s.dao.SessionCount(c, mid) |
|
if err != nil { |
|
log.Error("s.dao.SessionCount error(%v)", err) |
|
return |
|
} |
|
if count >= 10 { |
|
err = ecode.FeedbackContentOver |
|
return |
|
} |
|
} |
|
cTime := xtime.Time(now.Unix()) |
|
var ip32 uint32 |
|
ipv := net.ParseIP(ip) |
|
if ip2 := ipv.To4(); ip2 != nil { |
|
ip32 = model.InetAtoN(ip) |
|
} |
|
ssn := &model.Session{ |
|
Buvid: buvid, |
|
System: system, |
|
Version: version, |
|
Mid: mid, |
|
Aid: aid, |
|
Content: content, |
|
ImgURL: imgURL, |
|
LogURL: logURL, |
|
Device: device, |
|
Channel: channel, |
|
IP: ip32, |
|
NetState: netState, |
|
NetOperator: netOperator, |
|
AgencyArea: agencyArea, |
|
Platform: platform, |
|
Browser: browser, |
|
QQ: qq, |
|
Email: email, |
|
State: model.StateNoReply, |
|
LasterTime: cTime, |
|
CTime: cTime, |
|
MTime: cTime, |
|
} |
|
if entrance == "view" || content == "播放器反馈日志" || entrance == _androidLivePink || entrance == _iosLivePink || platform == _androidLivePink || platform == _iosLivePink || model.IsPlayerScreen(tagID) || entrance == _tvYST || platform == _tvYST || entrance == _creativeCenter || platform == _creativeCenter { |
|
ssn.State = model.StateOther |
|
} |
|
var tx *sql.Tx |
|
tx, err = s.dao.BeginTran(c) |
|
if err != nil { |
|
log.Error("s.dao.Begin error(%v)", err) |
|
return |
|
} |
|
sid, err = s.dao.TxAddSession(tx, ssn) |
|
if err != nil { |
|
log.Error("s.dao.TxAddSession error(%v)", err) |
|
tx.Rollback() |
|
return |
|
} |
|
if err = s.dao.TxUpSsnMtime(tx, now, sid); err != nil { |
|
log.Error("s.dao.TxUpSsnMtime error(%v)", err) |
|
tx.Rollback() |
|
return |
|
} |
|
ssn.ID = sid |
|
if tagID > 0 { |
|
if _, err = s.dao.TxAddSessionTag(tx, ssn.ID, tagID, now); err != nil { |
|
log.Error("s.dao.TxAddSessionTag error(%v)", err) |
|
tx.Rollback() |
|
return |
|
} |
|
} |
|
if err = tx.Commit(); err != nil { |
|
log.Error("tx.Commit(), error(%v)", err) |
|
} |
|
return |
|
} |
|
|
|
// Replys show all feedback replays |
|
func (s *Service) Replys(c context.Context, buvid, platform, mobiApp, device, system, version, entrance string, mid int64, pn, ps int) (rs []model.Reply, isEndReply bool, err error) { |
|
var ( |
|
replyID = buvid |
|
ssns []*model.Session |
|
ssn *model.Session |
|
r model.Reply |
|
tmp []model.Reply |
|
offset int |
|
limit int |
|
start int |
|
end int |
|
rsl int |
|
) |
|
offset = (pn - 1) * ps |
|
limit = ps |
|
if mid != 0 { |
|
if platform == "android" { |
|
if entrance == _androidCreative { |
|
platform = _androidCreative |
|
} else if entrance == _androidLivePink { |
|
platform = _androidLivePink |
|
} else if model.Plat(mobiApp, device) == model.PlatAndroid { |
|
platform = _androidFeedback |
|
} else if model.Plat(mobiApp, device) == model.PlatAndroidI { |
|
platform = _androidFeedbackI |
|
} |
|
} else if platform == "ios" { |
|
if entrance == _iosCreative { |
|
platform = _iosCreative |
|
} else if entrance == _iosLivePink { |
|
platform = _iosLivePink |
|
} else if model.Plat(mobiApp, device) == model.PlatIPhone { |
|
platform = _iosFeedback |
|
} else if model.Plat(mobiApp, device) == model.PlatIPhoneI { |
|
platform = _iosFeedbackI |
|
} |
|
} |
|
if ssns, err = s.dao.SessionByMid(c, mid, platform); err != nil { |
|
log.Error("s.dao.SessionByMid(%d) error(%v)", mid, err) |
|
return |
|
} |
|
if len(ssns) == 0 { |
|
err = ecode.FeedbackSsnNotExist |
|
return |
|
} |
|
replyID = strconv.FormatInt(mid, 10) |
|
if tmp, err = s.dao.ReplysByMid(c, mid, offset, limit); err != nil { |
|
log.Error("s.dao.ReplysByMid(%d) error(%v)", mid, err) |
|
return |
|
} |
|
if len(tmp) > 0 { |
|
rs = tmp |
|
} |
|
for _, ssn = range ssns { |
|
r = model.Reply{ |
|
ID: ssn.ID, |
|
ReplyID: replyID, |
|
Type: model.TypeCustomer, |
|
Content: ssn.Content, |
|
ImgURL: ssn.ImgURL, |
|
LogURL: ssn.LogURL, |
|
CTime: ssn.CTime, |
|
} |
|
rs = append(rs, r) |
|
} |
|
sort.Sort(model.Replys(rs)) |
|
rsl = len(rs) |
|
end = rsl |
|
if limit > rsl { |
|
start = 0 |
|
isEndReply = true |
|
} else { |
|
start = end - limit |
|
} |
|
rs = rs[start:end] |
|
} else { |
|
if ssn, err = s.dao.Session(c, buvid, system, version, mid); err != nil { |
|
log.Error("s.dao.Session(%s,%s,%s,%d) error(%v)", buvid, system, version, mid, err) |
|
return |
|
} |
|
if ssn == nil { |
|
err = ecode.FeedbackSsnNotExist |
|
return |
|
} |
|
if tmp, err = s.dao.Replys(c, ssn.ID, offset, limit); err != nil { |
|
log.Error("s.dao.Replays(%d) error(%v)", ssn.ID, err) |
|
return |
|
} |
|
if len(tmp) == limit { |
|
rs = tmp |
|
} else { |
|
r = model.Reply{ |
|
ID: ssn.ID, |
|
ReplyID: replyID, |
|
Type: model.TypeCustomer, |
|
Content: ssn.Content, |
|
ImgURL: ssn.ImgURL, |
|
LogURL: ssn.LogURL, |
|
CTime: ssn.CTime, |
|
} |
|
rs = append(tmp, r) |
|
isEndReply = true |
|
} |
|
sort.Sort(model.Replys(rs)) |
|
} |
|
return |
|
} |
|
|
|
// Sessions sessions. |
|
func (s *Service) Sessions(c context.Context, mid int64, state string, tagID, platform string, start, end time.Time, ps, pn int) (total int, wssns []*model.WebSession, err error) { |
|
var ( |
|
sids, sidsTmp, tids, intersect, sidTmp, sidCut []int64 |
|
limit, st, en, sls int |
|
ssnMap map[int64]*model.Session |
|
ssns []*model.Session |
|
) |
|
if mid > 0 { |
|
ssns, err = s.dao.SessionByMid(c, mid, platform) |
|
if err != nil { |
|
log.Error("s.dao.SessionByMid error(%v)", err) |
|
return |
|
} |
|
for _, v := range ssns { |
|
sids = append(sids, v.ID) |
|
} |
|
if tagID != "" { |
|
tids, err = xstr.SplitInts(tagID) |
|
if err != nil { |
|
log.Error("xstr.SplitInts error(%v)", err) |
|
return |
|
} |
|
if len(tids) > 0 { |
|
sidsTmp, err = s.dao.SessionIDByTagID(c, tids) |
|
if err != nil { |
|
log.Error("s.dao.SessionIDByTagID error(%v)", err) |
|
return |
|
} |
|
} |
|
for _, v := range sids { |
|
if contains(sidsTmp, v) { |
|
intersect = append(intersect, v) |
|
} |
|
} |
|
} else { |
|
intersect = sids |
|
} |
|
} |
|
if len(intersect) > 0 { |
|
if state == "" { |
|
ssns, err = s.dao.SSnBySsnIDAllSate(c, intersect, start, end) |
|
if err != nil { |
|
log.Error("s.dao.sSessionBySsnID error(%v)", err) |
|
return |
|
} |
|
} else { |
|
ssns, err = s.dao.SessionBySsnID(c, intersect, state, start, end) |
|
if err != nil { |
|
log.Error("s.dao.sSessionBySsnID error(%v)", err) |
|
return |
|
} |
|
} |
|
ssnMap = make(map[int64]*model.Session, len(ssns)) |
|
for _, v := range ssns { |
|
sidTmp = append(sidTmp, v.ID) |
|
ssnMap[v.ID] = v |
|
} |
|
sls = len(sidTmp) |
|
total = sls |
|
limit = ps |
|
if limit > sls { |
|
st = 0 |
|
en = sls |
|
} else { |
|
st = (pn - 1) * limit |
|
en = pn * limit |
|
if en > sls { |
|
en = st + (sls % limit) |
|
} |
|
} |
|
} |
|
sidCut = sidTmp[st:en] |
|
if len(sidCut) > 0 { |
|
var tagsMap map[int64][]*model.Tag |
|
tagsMap, err = s.dao.TagBySsnID(c, sidCut) |
|
if err != nil { |
|
log.Error("s.dao.TagBySsnID error(%v)", err) |
|
return |
|
} |
|
for _, v := range sidCut { |
|
wssn := &model.WebSession{} |
|
wssn.Session = ssnMap[v] |
|
tags := tagsMap[v] |
|
if len(tags) == 0 { |
|
wssn.Tag = defaultTag |
|
} else { |
|
wssn.Tag = tags[len(tags)-1] |
|
} |
|
wssns = append(wssns, wssn) |
|
} |
|
} |
|
return |
|
} |
|
|
|
// UpdateSessionState up session state. |
|
func (s *Service) UpdateSessionState(c context.Context, state int, sid int64) (err error) { |
|
if err = s.dao.UpdateSessionState(c, state, sid); err != nil { |
|
log.Error("s.dao.UpdateSessionState error(%v)", err) |
|
} |
|
return |
|
} |
|
|
|
// Tags tags. |
|
func (s *Service) Tags(c context.Context, mid int64, mold int, platform string) (tag *model.UGCTag, err error) { |
|
tags, err := s.dao.Tags(c, mold, platform) |
|
if err != nil { |
|
log.Error("s.dao.Tags error(%v)", err) |
|
return |
|
} |
|
cnt, err := s.dao.SessionCount(c, mid) |
|
if err != nil { |
|
log.Error("s.dao.SessionCount error(%v)", err) |
|
return |
|
} |
|
tag = &model.UGCTag{ |
|
Tags: tags, |
|
Limit: 10 - cnt, |
|
} |
|
return |
|
} |
|
|
|
// WebReplys web replys. |
|
func (s *Service) WebReplys(c context.Context, sid, mid int64) (mp []*model.Reply, err error) { |
|
if mp, err = s.dao.WebReplys(c, sid, mid); err != nil { |
|
log.Error("s.dao.WebReplys(%d, %d) error(%v)", sid, mid, err) |
|
return |
|
} |
|
if len(mp) == 0 { |
|
err = ecode.NothingFound |
|
} |
|
return |
|
} |
|
|
|
func contains(s []int64, e int64) bool { |
|
for _, a := range s { |
|
if a == e { |
|
return true |
|
} |
|
} |
|
return false |
|
} |
|
|
|
// PlayerCheck check for player. |
|
func (s *Service) PlayerCheck(c context.Context, platform, ipChangeTimes int, mid, checkTime, aid, connectSpeed, ioSpeed int64, region, school, cdnip string) (err error) { |
|
var ( |
|
ipinfo *locmdl.Info |
|
isp int |
|
ipAddr = metadata.String(c, metadata.RemoteIP) |
|
) |
|
if ipinfo, err = s.locationRPC.Info(c, &locmdl.ArgIP{IP: ipAddr}); err != nil { |
|
log.Error("s.locationRPC.Info(%s) error(%v)", ipAddr, err) |
|
} |
|
if ipinfo != nil { |
|
if strings.Contains(ipinfo.ISP, "移动") { |
|
isp = 1 |
|
} else if strings.Contains(ipinfo.ISP, "联通") { |
|
isp = 2 |
|
} else if strings.Contains(ipinfo.ISP, "电信") { |
|
isp = 3 |
|
} else { |
|
isp = 0 |
|
} |
|
} |
|
if _, err = s.dao.InPlayCheck(c, platform, isp, ipChangeTimes, mid, checkTime, aid, connectSpeed, ioSpeed, region, school, ipAddr, cdnip); err != nil { |
|
log.Error("s.dao.InPlayCheck(%d, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %s) error(%v)", platform, isp, ipChangeTimes, mid, checkTime, aid, connectSpeed, ioSpeed, region, school, ipAddr, cdnip, err) |
|
} |
|
return |
|
}
|
|
|