go-common/app/job/main/reply/service/admin.go
2019-04-22 18:49:16 +08:00

895 lines
29 KiB
Go

package service
import (
"context"
"encoding/json"
"fmt"
"strconv"
"time"
"go-common/app/job/main/reply/model/reply"
model "go-common/app/job/main/reply/model/reply"
xsql "go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
const (
_eventReportAdd = "report_add"
_eventReportDel = "report_del"
_eventReportIgnore = "report_ignore"
_eventReportRecover = "report_recover"
)
func (s *Service) actionAdmin(c context.Context, msg *consumerMsg) {
var d struct {
Op string `json:"op"`
Adid int64 `json:"adid"`
AdName string `json:"adname"`
Oid int64 `json:"oid"`
RpID int64 `json:"rpid"`
Mid int64 `json:"mid"`
Tp int8 `json:"tp"`
Action uint32 `json:"action"`
Moral int `json:"moral"`
Notify bool `json:"notify"`
Remark string `json:"remark"`
MTime xtime.Time `json:"mtime"`
Ftime int64 `json:"ftime"`
Audit int8 `json:"audit"`
Reason int8 `json:"reason"`
Content string `json:"content"`
FReason int8 `json:"freason"`
Assist bool `json:"assist"`
State int8 `json:"state"`
}
if err := json.Unmarshal([]byte(msg.Data), &d); err != nil {
log.Error("json.Unmarshal() error(%v)", err)
return
}
if d.Oid <= 0 || d.RpID <= 0 {
log.Error("The structure of msg.Data(%s) was wrong", msg.Data)
return
}
rp, err := s.getReply(c, d.Oid, d.RpID)
if err != nil {
log.Error("s.getReply failed , oid(%d), RpID(%d) err(%v)", d.Oid, d.RpID, err)
return
}
if rp == nil {
log.Error("getReply nil oid(%d) RpID(%d)", d.Oid, d.RpID)
return
}
switch {
case d.Op == "del":
s.adminDel(c, rp, d.Adid, d.Mid, d.Ftime, d.Moral, d.AdName, d.Remark, d.MTime, d.Notify, d.Reason, d.FReason)
case d.Op == "del_rpt":
s.reportDel(c, rp, d.Adid, d.Mid, d.Ftime, d.Moral, d.AdName, d.Remark, d.MTime, d.Notify, d.Audit, d.Reason, d.Content, d.FReason)
case d.Op == "del_up":
s.userDel(c, rp, d.Mid, d.MTime, d.Remark, d.Assist)
case d.Op == "re", d.Op == "pass":
s.passReply(c, rp, d.MTime, d.Adid, d.Remark, d.Op)
case d.Op == "edit":
s.addSearchUp(c, rp.State, rp, nil)
case d.Op == "ignore":
s.reportIgnore(c, rp, d.Audit, d.MTime, d.Adid, d.Remark)
case d.Op == "transfer":
s.reportTransfer(c, rp, d.Audit, d.MTime, d.Adid, d.Remark)
case d.Op == "stateset":
s.reportStateSet(c, rp, d.State, d.MTime, d.Adid, d.Remark)
case d.Op == "top_add":
err := s.topAdd(c, rp, d.MTime, d.Action, model.SubAttrAdminTop)
if err != nil {
log.Error("s.topAdd(oid:%d,tp:%d err(%v))", rp.Oid, rp.Type, err)
return
}
// s.dao.Redis.AddTopOid(c, rp.Oid, rp.Type)
s.adminLog(c, rp, d.Adid, model.AdminIsReport, model.AdminOperSubTop, "管理员置顶评论", d.Remark)
s.addSearchUp(c, rp.State, rp, nil)
case d.Op == "rpt_re":
s.reportRecover(c, rp, d.Audit, d.MTime, d.Adid, d.Remark)
}
}
func (s *Service) reportStateSet(c context.Context, rp *model.Reply, state int8, mtime xtime.Time, adid int64, remark string) (err error) {
var (
op int8
result string
oldState = rp.State
)
rpt, err := s.dao.Report.Get(c, rp.Oid, rp.RpID)
if err != nil || rpt == nil {
log.Error("dao.Report.GetReport(%d, %d) met error (%v)", rp.Oid, rp.RpID, err)
return
}
rpt.State = state
rpt.MTime = mtime
op = model.AdminOperRptTransferArbitration
if adid == 0 {
result = "系统自动移交至风纪委"
} else {
result = "管理员移交至风纪委"
}
if _, err = s.dao.Report.Update(c, rpt); err != nil {
log.Error("dao.Report.Update(%v) error(%v)", rpt, err)
return
}
// admin log
s.adminLog(c, rp, adid, model.AdminIsReport, op, result, remark)
s.addSearchUp(c, oldState, rp, rpt)
return
}
func (s *Service) reportTransfer(c context.Context, rp *model.Reply, audit int8, mtime xtime.Time, adid int64, remark string) (err error) {
var (
op int8
result string
oldState = rp.State
)
rpt, err := s.dao.Report.Get(c, rp.Oid, rp.RpID)
if err != nil || rpt == nil {
log.Error("dao.Report.GetReport(%d, %d) met error (%v)", rp.Oid, rp.RpID, err)
return
}
if rpt.IsTransferred() {
log.Error("report(%v) has been transfferd before!", *rpt)
return
}
if audit == model.AuditTypeOne {
rpt.State = model.ReportStateNew
op = model.AdminOperRptTransfer1
result = "二审转一审"
} else if audit == model.AuditTypeTwo {
rpt.State = model.ReportStateNewTwo
op = model.AdminOperRptTransfer2
result = "一审转二审"
}
rpt.MTime = mtime
rpt.SetTransferred()
if _, err = s.dao.Report.Update(c, rpt); err != nil {
log.Error("dao.Report.Update(%v) error(%v)", rpt, err)
return
}
// admin log
s.adminLog(c, rp, adid, model.AdminIsReport, op, result, remark)
s.addSearchUp(c, oldState, rp, rpt)
return
}
func (s *Service) reportIgnore(c context.Context, rp *model.Reply, audit int8, mtime xtime.Time, adid int64, remark string) (err error) {
var (
op int8
result string
oldState = rp.State
)
rpt, err := s.dao.Report.Get(c, rp.Oid, rp.RpID)
if err != nil || rpt == nil {
log.Error("dao.Report.GetReport(%d, %d) met error (%v)", rp.Oid, rp.RpID, err)
return
}
if audit == model.AuditTypeOne {
rpt.State = model.ReportStateIgnoreOne
op = model.AdminOperRptIgnore1
result = "一审忽略"
} else if audit == model.AuditTypeTwo {
rpt.State = model.ReportStateIgnoreTwo
op = model.AdminOperRptIgnore2
result = "二审忽略"
} else {
if rpt.State == model.ReportStateNew {
rpt.State = model.ReportStateIgnoreOne
} else {
rpt.State = model.ReportStateIgnoreTwo
}
op = model.AdminOperIgnoreReport
result = "已忽略举报"
}
rpt.MTime = mtime
if _, err = s.dao.Report.Update(c, rpt); err != nil {
log.Error("dao.Report.Update(%v) error(%v)", rpt, err)
return
}
// admin log
s.adminLog(c, rp, adid, model.AdminIsReport, op, result, remark)
s.addSearchUp(c, oldState, rp, rpt)
sub, err := s.getSubject(c, rp.Oid, rp.Type)
if err != nil || sub == nil {
log.Error("s.getSubject(%v,%v) err(%v) or sub nil", sub.Oid, sub.Type, err)
return
}
if err = s.dao.PubEvent(c, _eventReportIgnore, rpt.Mid, sub, rp, rpt); err != nil {
return
}
return
}
func (s *Service) reportRecover(c context.Context, rp *model.Reply, audit int8, mtime xtime.Time, adid int64, remark string) (err error) {
var (
ok bool
op int8
result string
rootRp *model.Reply
oldState = rp.State
)
isRoot := rp.Root == 0 && rp.Parent == 0
rpt, _ := s.dao.Report.Get(c, rp.Oid, rp.RpID)
if err != nil || rpt == nil {
log.Error("dao.Report.GetReport(%d, %d) met error (%v)", rp.Oid, rp.RpID, err)
return
}
sub, err := s.getSubject(c, rp.Oid, rp.Type)
if err != nil || sub == nil {
log.Error("s.getSubject(%v,%v) err(%v) or sub nil", sub.Oid, sub.Type, err)
return
}
if audit == model.AuditTypeOne {
// 一审移除,恢复到待一审忽略,评论正常
rpt.State = model.ReportStateIgnoreOne
op = model.AdminOperRptRecover1
result = "一审恢复评论"
} else if audit == model.AuditTypeTwo {
// 二审移除,恢复到二审忽略,评论正常
rpt.State = model.ReportStateIgnoreTwo
op = model.AdminOperRptRecover2
result = "二审恢复评论"
} else {
log.Error("reportRecover unsupport audit: %d", audit)
return
}
rpt.MTime = mtime
if _, err = s.dao.Report.Update(c, rpt); err != nil {
log.Error("dao.Report.Update(%v) error(%v) or row==0", rpt, err)
return
}
// 只恢复管理员删除的评论,不恢复用户删除的
if rp.State == model.ReplyStateAdminDel {
rp.MTime = mtime
rp.State = model.ReplyStateNormal
if err = s.tranRecover(c, rp, model.ReplyStateNormal, isRoot); err != nil {
log.Error("Transaction recover reply failed err(%v)", err)
return
}
}
// add cache
if isRoot {
if err = s.dao.Mc.AddReply(c, rp); err != nil {
log.Error("s.dao.Mc.AddReply failed , RpID(%d), err(%v)", rp.RpID, err)
}
if err = s.dao.Redis.AddIndex(c, rp.Oid, rp.Type, rpt, rp, true); err != nil {
log.Error("s.dao.Redis.AddIndex(%d, %d) error(%v)", rp.Oid, rp.Type, err)
}
} else {
if ok, err = s.dao.Redis.ExpireNewChildIndex(c, rp.Root); err == nil && ok {
if err = s.dao.Redis.AddNewChildIndex(c, rp.Root, rp); err != nil {
log.Error("s.dao.Redis.AddFloorIndexByRoot failed , rproot(%d), err(%v)", rp.Root, err)
}
}
if rootRp, err = s.getReplyCache(c, rp.Oid, rp.Root); err != nil {
log.Error("s.getReply failed , oid(%d), root(%d) err(%v)", rp.Oid, rp.Root, err)
} else if rootRp != nil {
rootRp.RCount++
if err = s.dao.Mc.AddReply(c, rootRp); err != nil {
log.Error("s.dao.Mc.AddReply failed , RpID(%d) err(%v)", rootRp.RpID, err)
}
}
}
// log
s.adminLog(c, rp, adid, model.AdminIsReport, op, result, remark)
// notify
s.addSearchUp(c, oldState, rp, rpt)
s.upAcount(c, sub.Oid, sub.Type, sub.ACount, rp.CTime.Time())
if err = s.dao.PubEvent(c, _eventReportRecover, rpt.Mid, sub, rp, rpt); err != nil {
return
}
return
}
// topAdd add top reply
func (s *Service) topAdd(c context.Context, rp *model.Reply, ts xtime.Time, act uint32, tp uint32) (err error) {
sub, err := s.getSubject(c, rp.Oid, rp.Type)
if err != nil || sub == nil {
log.Error("s.getsubject(%v,%v) err(%v) or sub nil", rp.Oid, rp.Type, err)
return
}
if act == 1 && sub.AttrVal(tp) == 1 {
log.Error("Repeat to add top reply(%d,%d,%d,%d) ", rp.RpID, rp.Oid, tp, sub.Attr)
return
}
err = sub.TopSet(rp.RpID, tp, act)
if err != nil {
log.Error("sub.TopSet(%d,%d,%d) failed!err:=%v ", rp.RpID, rp.Oid, tp, err)
return
}
sub.AttrSet(act, tp)
rp.AttrSet(act, tp)
tx, err := s.beginTran(c)
if err != nil {
log.Error("s.beginTran() err(%v)", err)
return
}
var rows int64
//rp.State = model.ReplyStateTop
if rows, err = s.dao.Reply.TxUpAttr(tx, rp.Oid, rp.RpID, rp.Attr, ts.Time()); err != nil || rows == 0 {
tx.Rollback()
log.Error("dao.Reply.UpState(%v, %d) error(%v) or row==0", rp, rp.State, err)
return
}
if rows, err = s.dao.Subject.TxUpMeta(tx, sub.Oid, sub.Type, sub.Meta, ts.Time()); err != nil || rows == 0 {
tx.Rollback()
log.Error("dao.TxUpMeta(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
return
}
if rows, err = s.dao.Subject.TxUpAttr(tx, sub.Oid, sub.Type, sub.Attr, ts.Time()); err != nil || rows == 0 {
tx.Rollback()
log.Error("dao.Upattr(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
return
}
tx.Commit()
s.dao.Mc.AddSubject(c, sub)
if act == 1 {
s.dao.Redis.DelIndexBySortType(c, rp, reply.SortByCount)
s.dao.Redis.DelIndexBySortType(c, rp, reply.SortByLike)
} else if rp.IsNormal() {
if ok, err := s.dao.Redis.ExpireIndex(c, sub.Oid, sub.Type, model.SortByCount); err == nil && ok {
if err = s.dao.Redis.AddCountIndex(c, sub.Oid, sub.Type, rp); err != nil {
log.Error("s.dao.Redis.AddCountIndex failed , oid(%d) type(%d) err(%v)", sub.Oid, sub.Type, err)
}
}
if ok, err := s.dao.Redis.ExpireIndex(c, sub.Oid, sub.Type, model.SortByLike); err == nil && ok {
rpts := make(map[int64]*reply.Report, 1)
if rpt, _ := s.dao.Report.Get(c, rp.Oid, rp.RpID); rpt != nil {
rpts[rp.RpID] = rpt
}
if err = s.dao.Redis.AddLikeIndex(c, sub.Oid, sub.Type, rpts, rp); err != nil {
log.Error("s.dao.Redis.AddLikeIndex failed , oid(%d) type(%d) err(%v)", sub.Oid, sub.Type, err)
}
}
}
s.dao.Mc.AddReply(c, rp)
s.dao.Mc.AddTop(c, rp)
if act == 1 {
s.dao.PubEvent(c, "top", 0, sub, rp, nil)
} else if act == 0 {
s.dao.PubEvent(c, "untop", 0, sub, rp, nil)
}
// 折叠评论被置顶自动取消折叠
if rp.IsFolded() && act == 1 {
rp.State = model.ReplyStateNormal
s.marker.Do(c, func(ctx context.Context) {
if _, err := s.dao.Reply.UpState(ctx, rp.Oid, rp.RpID, rp.State, time.Now()); err == nil {
if ok, err := s.dao.Redis.ExpireIndex(c, rp.Oid, rp.Type, model.SortByFloor); err == nil && ok {
s.dao.Redis.AddFloorIndex(c, rp.Oid, rp.Type, rp)
}
s.handleFolded(ctx, rp)
}
})
}
return
}
func (s *Service) userDel(c context.Context, rp *model.Reply, mid int64, mtime xtime.Time, remark string, assist bool) (err error) {
var (
state int8
sub *model.Subject
oldState = rp.State
isRoot = rp.Root == 0 && rp.Parent == 0
isFolded = rp.IsFolded()
)
if rp.IsDeleted() {
s.addSearchUp(c, oldState, rp, nil)
return
}
if sub, err = s.dao.Subject.Get(c, rp.Oid, rp.Type); err != nil || sub == nil {
log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
return
}
if rp.Mid == mid {
state = model.ReplyStateUserDel
} else if assist {
state = model.ReplyStateAssistDel
} else if mid > 0 {
state = model.ReplyStateUpDel
} else {
state = model.ReplyStateAdminDel
}
rp.MTime = mtime
if err = s.tranDel(c, rp, state, sub, isRoot); err != nil {
log.Error("reportDel tranDel(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
return
}
if isFolded {
s.marker.Do(c, func(ctx context.Context) {
s.handleFolded(ctx, rp)
})
}
if err = s.clearReplyCache(c, rp); err != nil {
log.Error("reportDel clearReplyCache(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
}
rp.State = state
if rp.Mid == mid {
s.adminLog(c, rp, mid, model.AdminIsNotReport, model.AdminOperDeleteUser, "由本人删除", remark)
s.searchDao.DelReply(c, rp.RpID, sub.Oid, mid, state)
} else if assist {
s.adminLog(c, rp, mid, model.AdminIsNotReport, model.AdminOperDeleteAssist, "由UP主协管员删除", remark)
s.addAssistLog(c, sub.Mid, mid, sub.Oid, 1, 1, strconv.FormatInt(rp.RpID, 10), rp.Content.Message)
} else if mid > 0 {
s.adminLog(c, rp, mid, model.AdminIsNotReport, model.AdminOperDeleteUp, "由up主删除", remark)
} else {
s.adminLog(c, rp, 0, model.AdminIsNotReport, model.AdminOperDelete, "由系统删除", remark)
}
s.dao.PubEvent(c, "reply_del", rp.Mid, sub, rp, nil)
return
}
func (s *Service) adminDel(c context.Context, rp *model.Reply, adid, mid, ftime int64, moral int, adName, remark string, mtime xtime.Time, notify bool, reason, freason int8) (err error) {
var (
sub *model.Subject
report *model.Report
oldState = rp.State
isRoot = rp.Root == 0 && rp.Parent == 0
isFolded = rp.IsFolded()
)
if rp.IsDeleted() {
s.addSearchUp(c, oldState, rp, nil)
return
}
if sub, err = s.dao.Subject.Get(c, rp.Oid, rp.Type); err != nil || sub == nil {
log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
return
}
rp.MTime = mtime
if err = s.tranDel(c, rp, model.ReplyStateAdminDel, sub, isRoot); err != nil {
log.Error("reportDel tranDel(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
return
}
if isFolded {
s.marker.Do(c, func(ctx context.Context) {
s.handleFolded(ctx, rp)
})
}
if err = s.clearReplyCache(c, rp); err != nil {
log.Error("reportDel clearReplyCache(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
}
if report, err = s.dao.Report.Get(c, rp.Oid, rp.RpID); err != nil {
log.Error("reportDel getReport(%d,%d) error(%v)", rp.Oid, rp.RpID, err)
return
}
if report != nil {
if report.State == model.ReportStateNew || report.State == model.ReportStateNewTwo {
if report.State == model.ReportStateNew {
report.State = model.ReportStateDeleteOne
} else if report.State == model.ReportStateNewTwo {
report.State = model.ReportStateDeleteTwo
}
report.MTime = mtime
if _, err = s.dao.Report.Update(c, report); err != nil {
log.Error("reportDel updateReport(%d, %d) error(%v)", report.Oid, report.ID, err)
return
}
s.addSearchUp(c, oldState, rp, report)
s.dao.PubEvent(c, _eventReportDel, 0, sub, rp, report)
}
}
rp.State = model.ReplyStateAdminDel
// add moral and notify
s.moralAndNotify(c, rp, moral, notify, mid, adid, adName, remark, reason, freason, ftime, false)
// forbidden tip
forbidDay := strconv.FormatInt(ftime, 10) + "天"
if ftime == -1 {
forbidDay = "永久"
}
s.adminLog(c, rp, adid, model.AdminIsNotReport, model.AdminOperDelete, fmt.Sprintf("已删除并封禁%s/扣除%d节操", forbidDay, moral), remark)
s.addSearchUp(c, oldState, rp, nil)
if report == nil {
s.dao.PubEvent(c, "reply_del", 0, sub, rp, nil)
}
return
}
func (s *Service) reportDel(c context.Context, rp *model.Reply, adid, mid, ftime int64, moral int, adName, remark string, mtime xtime.Time, notify bool, audit int8, reason int8, content string, freason int8) (err error) {
var (
op int8
isPunish bool
sub *model.Subject
report *model.Report
oldState = rp.State
)
if sub, err = s.dao.Subject.Get(c, rp.Oid, rp.Type); err != nil || sub == nil {
log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
return
}
if report, err = s.dao.Report.Get(c, rp.Oid, rp.RpID); err != nil || report == nil {
log.Error("reportDel getReport(%d,%d) error(%v)", rp.Oid, rp.RpID, err)
return
}
report.MTime = mtime
// 一审、二审操作
switch audit {
case model.AuditTypeOne:
report.State = model.ReportStateDeleteOne
op = model.AdminOperRptDel1
case model.AuditTypeTwo:
report.State = model.ReportStateDeleteTwo
op = model.AdminOperRptDel2
default:
report.State = model.ReportStateDelete
op = model.AdminOperDeleteByReport
}
report.Reason = reason
report.Content = content
if _, err = s.dao.Report.Update(c, report); err != nil {
log.Error("reportDel updateReport(%d, %d) error(%v)", report.Oid, report.ID, err)
return
}
if !rp.IsDeleted() {
isRoot := rp.Root == 0 && rp.Parent == 0
rp.MTime = mtime
if err = s.tranDel(c, rp, model.ReplyStateAdminDel, sub, isRoot); err != nil {
log.Error("reportDel tranDel(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
return
}
if err = s.clearReplyCache(c, rp); err != nil {
log.Error("reportDel clearReplyCache(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
}
rp.State = model.ReplyStateAdminDel
} else {
isPunish = true
}
// add moral and notify
s.moralAndNotify(c, rp, moral, notify, mid, adid, adName, remark, reason, freason, ftime, isPunish)
// forbidden tip
forbidDay := strconv.FormatInt(ftime, 10) + "天"
if ftime == -1 {
forbidDay = "永久"
}
s.adminLog(c, rp, adid, model.AdminIsReport, op, fmt.Sprintf("已通过举报删除并封禁%s/扣除%d节操", forbidDay, moral), remark)
s.addSearchUp(c, oldState, rp, report)
if err = s.dao.PubEvent(c, _eventReportDel, report.Mid, sub, rp, report); err != nil {
return
}
return
}
func (s *Service) clearReplyCache(c context.Context, rp *model.Reply) (err error) {
var (
sub *model.Subject
rootRp *model.Reply
isRoot = rp.Root == 0 && rp.Parent == 0
)
if !isRoot && rp.IsNormal() {
// update root cache for count.
if rootRp, err = s.getReplyCache(c, rp.Oid, rp.Root); err != nil {
return
}
if rootRp != nil {
rootRp.RCount--
if err = s.addReplyCache(c, rootRp); err != nil {
log.Error("s.dao.Mc.addReplyCache(%d,%d,%d) error(%v)", rp.Oid, rp.Type, rp.RpID, err)
}
}
}
if rp.IsAdminTop() {
s.dao.Mc.DeleteTop(c, rp, model.ReplyAttrAdminTop)
}
if rp.IsUpTop() {
s.dao.Mc.DeleteTop(c, rp, model.ReplyAttrUpperTop)
}
if err = s.dao.Mc.DeleteReply(c, rp.RpID); err != nil {
log.Error("s.dao.Mc.DeleteReply failed , RpID(%d), err(%v)", rp.RpID, err)
}
if err = s.dao.Redis.DelIndex(c, rp); err != nil {
log.Error("s.dao.Redis.DelIndex failed , RpID(%d), err(%v)", rp.RpID, err)
}
if rp.State == model.ReplyStateAudit {
s.eraseAuditIndex(c, rp)
}
// update reply count
sub, err = s.dao.Subject.Get(c, rp.Oid, rp.Type)
if err != nil || sub == nil {
log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
return
}
if err = s.dao.Mc.AddSubject(c, sub); err != nil {
log.Error("s.dao.Mc.AddSubject failed , oid(%d), err(%v)", sub.Oid, err)
}
s.upAcount(c, sub.Oid, sub.Type, sub.ACount, rp.CTime.Time())
return
}
func (s *Service) passReply(c context.Context, rp *model.Reply, mtime xtime.Time, adid int64, remark, op string) {
var (
err error
ok bool
rootRp *model.Reply
oldState = rp.State
isRoot = rp.Root == 0 && rp.Parent == 0
)
sub, err := s.dao.Subject.Get(c, rp.Oid, rp.Type)
if err != nil || sub == nil {
log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
return
}
if rp.State <= model.ReplyStateHidden {
s.addSearchUp(c, oldState, rp, nil)
return
}
rp.MTime = mtime
rp.State = model.ReplyStateNormal
if op == "re" || oldState == model.ReplyStateAudit {
if err = s.tranRecover(c, rp, model.ReplyStateNormal, isRoot); err != nil {
log.Error("Transaction recover reply failed err(%v)", err)
return
}
} else if op == "pass" {
var row int64
var tx *xsql.Tx
tx, err = s.dao.BeginTran(c)
if err != nil {
return
}
if row, err = s.dao.Reply.TxUpState(tx, rp.Oid, rp.RpID, model.ReplyStateNormal, mtime.Time()); err != nil || row == 0 {
tx.Rollback()
log.Error("dao.Reply.TxUpState(%v, %d) error(%v) or row==0", rp, model.ReplyStateNormal, err)
return
}
if rp.State == model.ReplyStateAudit || rp.State == model.ReplyStateMonitor {
if _, err = s.dao.Subject.TxDecrMCount(tx, rp.Oid, rp.Type, mtime.Time()); err != nil {
tx.Rollback()
log.Error("dao.Reply.TxDecrMCount(%v) error(%v)", rp, err)
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
return
}
}
if isRoot {
if ok, err = s.dao.Redis.ExpireIndex(c, rp.Oid, rp.Type, model.SortByFloor); err == nil && ok {
var min int
min, err = s.dao.Redis.MinScore(c, rp.Oid, rp.Type, reply.SortByFloor)
if err != nil {
log.Error("s.dao.Redis.AddFloorIndex failed , oid(%d) type(%d) err(%v)", rp.Oid, rp.Type, err)
} else if rp.Floor > min {
if err = s.dao.Redis.AddFloorIndex(c, rp.Oid, rp.Type, rp); err != nil {
log.Error("s.dao.Redis.AddFloorIndex failed , RpID(%d), err(%v)", rp.RpID, err)
}
}
}
if ok, err = s.dao.Redis.ExpireIndex(c, rp.Oid, rp.Type, model.SortByCount); err == nil && ok {
if err = s.dao.Redis.AddCountIndex(c, rp.Oid, rp.Type, rp); err != nil {
log.Error("s.dao.Redis.AddCountIndex failed , RpID(%d), err(%v)", rp.RpID, err)
}
}
if ok, err = s.dao.Redis.ExpireIndex(c, rp.Oid, rp.Type, model.SortByLike); err == nil && ok {
rpts := make(map[int64]*reply.Report, 1)
if rpt, _ := s.dao.Report.Get(c, rp.Oid, rp.RpID); rpt != nil {
rpts[rp.RpID] = rpt
}
if err = s.dao.Redis.AddLikeIndex(c, rp.Oid, rp.Type, rpts, rp); err != nil {
log.Error("s.dao.Redis.AddLikeIndex failed , RpID(%d), err(%v)", rp.RpID, err)
}
}
} else {
if ok, err = s.dao.Redis.ExpireDialogIndex(c, rp.Dialog); err == nil && ok {
if err = s.dao.Redis.AddDialogIndex(c, rp.Dialog, []*model.Reply{rp}); err != nil {
log.Error("s.dao.Redis.AddDialogINdex Error (%v)", err)
}
}
if ok, err = s.dao.Redis.ExpireNewChildIndex(c, rp.Root); err == nil && ok {
if err = s.dao.Redis.AddNewChildIndex(c, rp.Root, rp); err != nil {
log.Error("s.dao.Redis.AddFloorIndexByRoot failed , rproot(%d), err(%v)", rp.Root, err)
}
}
if op == "re" || oldState == model.ReplyStateAudit {
if rootRp, err = s.getReplyCache(c, rp.Oid, rp.Root); err != nil {
log.Error("s.getReply failed , oid(%d), root(%d) err(%v)", rp.Oid, rp.Root, err)
} else if rootRp != nil {
rootRp.RCount++
if err = s.addReplyCache(c, rootRp); err != nil {
log.Error("s.addReplyCache oid(%d), rpid(%d) err(%v)", rootRp.Oid, rootRp.RpID, err)
}
}
}
}
if err = s.addReplyCache(c, rp); err != nil {
log.Error("s.addReplyCache oid(%d), rpid(%d) err(%v)", rp.Oid, rp.RpID, err)
}
if oldState == model.ReplyStateAudit {
s.dao.Redis.DelAuditIndexs(c, rp)
}
// update reply count
s.upAcount(c, sub.Oid, sub.Type, sub.ACount, rp.CTime.Time())
if err = s.dao.Mc.AddSubject(c, sub); err != nil {
log.Error("s.dao.Mc.AddSubject failed , oid(%d) err(%v)", sub.Oid, err)
}
// admin log
if op == "re" {
s.adminLog(c, rp, adid, model.AdminIsNotReport, model.AdminOperRecover, "已恢复评论", remark)
} else if op == "pass" {
s.adminLog(c, rp, adid, model.AdminIsNotReport, model.AdminOperPass, "已通过评论", remark)
}
s.addSearchUp(c, oldState, rp, nil)
}
func (s *Service) tranRecover(c context.Context, rp *model.Reply, state int8, isRoot bool) error {
var (
err error
rootReply *model.Reply
count int
rows int64
tx *xsql.Tx
)
if tx, err = s.beginTran(c); err != nil {
return err
}
mtime := rp.MTime
if rp, err = s.dao.Reply.GetForUpdate(tx, rp.Oid, rp.RpID); err != nil || rp == nil {
tx.Rollback()
return fmt.Errorf("s.dao.Reply.GetForUpdate(%d,%d) error(%v) or is nil)", rp.Oid, rp.RpID, err)
}
if mtime != 0 {
rp.MTime = mtime
}
if rp.IsNormal() {
tx.Rollback()
return fmt.Errorf("reply(%d,%d) already is normal", rp.Oid, rp.RpID)
}
rows, err = s.dao.Reply.TxUpState(tx, rp.Oid, rp.RpID, state, rp.MTime.Time())
if err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("TxUpState error(%v) or rows(%d)", err, rows)
}
if isRoot {
count = rp.RCount + 1
} else {
rootReply, err = s.dao.Reply.Get(c, rp.Oid, rp.Root)
if err != nil {
tx.Rollback()
return err
}
count = 1
}
if isRoot {
rows, err = s.dao.Subject.TxIncrRCount(tx, rp.Oid, rp.Type, rp.MTime.Time())
} else {
rows, err = s.dao.Reply.TxIncrRCount(tx, rp.Oid, rp.Root, rp.MTime.Time())
}
if err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("TxIncrRCount error(%v) or rows(%d)", err, rows)
}
if isRoot || rootReply != nil && rootReply.IsNormal() {
rows, err = s.dao.Subject.TxIncrACount(tx, rp.Oid, rp.Type, count, rp.MTime.Time())
if err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("TxIncrACount error(%v) or rows(%d)", err, rows)
}
}
return tx.Commit()
}
func (s *Service) tranDel(c context.Context, rp *model.Reply, state int8, sub *model.Subject, isRoot bool) error {
var (
count int
rows int64
rootReply *model.Reply
err error
tx *xsql.Tx
)
if tx, err = s.beginTran(c); err != nil {
return err
}
mtime := rp.MTime
if rp, err = s.dao.Reply.GetForUpdate(tx, rp.Oid, rp.RpID); err != nil || rp == nil {
tx.Rollback()
return fmt.Errorf("s.dao.Reply.GetForUpdate(%d,%d) error(%v) or is nil)", rp.Oid, rp.RpID, err)
}
if mtime != 0 {
rp.MTime = mtime
}
if rp.IsDeleted() || rp.AttrVal(reply.ReplyAttrAdminTop) == 1 {
tx.Rollback()
return fmt.Errorf("reply(%d,%d) already deleted", rp.Oid, rp.RpID)
}
rows, err = s.dao.Reply.TxUpState(tx, rp.Oid, rp.RpID, state, rp.MTime.Time())
if err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("error(%v) or rows(%d)", err, rows)
}
if rp.IsNormal() {
if isRoot {
count = rp.RCount + 1
rows, err = s.dao.Subject.TxDecrACount(tx, rp.Oid, rp.Type, count, rp.MTime.Time())
if err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("error(%v) or rows(%d)", err, rows)
}
rows, err = s.dao.Subject.TxDecrCount(tx, rp.Oid, rp.Type, rp.MTime.Time())
if err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("SubjectTxDecrCount error(%v) or rows(%d)", err, rows)
}
} else {
if rootReply, err = s.dao.Reply.GetForUpdate(tx, rp.Oid, rp.Root); err != nil {
tx.Rollback()
return err
}
if rootReply != nil {
if rootReply.IsNormal() {
rows, err = s.dao.Subject.TxDecrACount(tx, rp.Oid, rp.Type, 1, rp.MTime.Time())
if err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("error(%v) or rows(%d)", err, rows)
}
}
rows, err = s.dao.Reply.TxDecrCount(tx, rp.Oid, rp.Root, rp.MTime.Time())
if err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("ReplyTxDecrCount error(%v) or rows(%d)", err, rows)
}
}
}
}
if rp.AttrVal(model.ReplyAttrUpperTop) == 1 {
rp.AttrSet(0, model.ReplyAttrUpperTop)
sub.AttrSet(0, model.SubAttrUpperTop)
sub.TopSet(0, model.SubAttrUpperTop, 0)
if rows, err = s.dao.Subject.TxUpMeta(tx, sub.Oid, sub.Type, sub.Meta, rp.MTime.Time()); err != nil || rows == 0 {
tx.Rollback()
log.Error("dao.TxUpMeta(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
return fmt.Errorf("dao.TxUpMeta(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
}
if rows, err = s.dao.Subject.TxUpAttr(tx, sub.Oid, sub.Type, sub.Attr, rp.MTime.Time()); err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("dao.Upattr(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
}
//rp.State = model.ReplyStateTop
if rows, err = s.dao.Reply.TxUpAttr(tx, rp.Oid, rp.RpID, rp.Attr, rp.MTime.Time()); err != nil || rows == 0 {
tx.Rollback()
return fmt.Errorf("dao.Reply.UpState(%v, %d) error(%v) or rows(%d)", rp, rp.State, err, rows)
}
}
if rp.State == model.ReplyStateMonitor || rp.State == model.ReplyStateAudit {
if _, err = s.dao.Subject.TxDecrMCount(tx, rp.Oid, rp.Type, rp.MTime.Time()); err != nil {
tx.Rollback()
log.Error("dao.Reply.TxDecrMCount(%v) error(%v)", rp, err)
return fmt.Errorf("dao.Reply.TxDecrMCount error(%v)", err)
}
}
return tx.Commit()
}
func (s *Service) eraseAuditIndex(c context.Context, rp *model.Reply) (err error) {
var rs []*model.Reply
if rp.Root == 0 && rp.Parent == 0 {
if rs, err = s.dao.Reply.GetsByRoot(c, rp.Oid, rp.RpID, rp.Type, model.ReplyStateAudit); err != nil {
return
}
}
if err = s.dao.Redis.DelAuditIndexs(c, append(rs, rp)...); err != nil {
return
}
return
}
func (s *Service) addReplyCache(c context.Context, rp *model.Reply) (err error) {
var isRoot = rp.Root == 0 && rp.Parent == 0
if err = s.dao.Mc.AddReply(c, rp); err != nil {
log.Error("s.dao.Mc.AddReply(%d,%d,%d) error(%v)", rp.Oid, rp.RpID, rp.Type, err)
}
if isRoot && rp.IsTop() {
if err = s.dao.Mc.AddTop(c, rp); err != nil {
log.Error("s.dao.Mc.AddTop(%d,%d,%d) error(%v)", rp.Oid, rp.RpID, rp.Type, err)
}
}
return
}