go-common/app/interface/main/feedback/service/feedback.go

647 lines
17 KiB
Go
Raw Normal View History

2019-04-22 10:49:16 +00:00
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
}