Files
go-common/app/service/openplatform/anti-fraud/service/question.go
2019-04-22 18:49:16 +08:00

551 lines
11 KiB
Go

package service
import (
"context"
"math"
"math/rand"
"time"
"go-common/app/service/openplatform/anti-fraud/model"
xsql "go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
)
func (s *Service) beginTran(c context.Context) (*xsql.Tx, error) {
return s.d.BeginTran(c)
}
// GetQusInfo 获取题目信息
func (s *Service) GetQusInfo(c context.Context, qsID int64) (res *model.Question, err error) {
if res, err = s.d.GetQusInfo(c, qsID); err != nil {
return
}
return
}
// GetAnswerList 答案列表
func (s *Service) GetAnswerList(c context.Context, qsID int64) (res []*model.Answer, err error) {
if res, err = s.d.GetAnswerList(c, qsID); err != nil {
return
}
return
}
// AddQus 添加题目
func (s *Service) AddQus(c context.Context, in *model.AddQus, answers []model.Answer) (res model.AddReturn, err error) {
tx, err := s.beginTran(c)
if err != nil {
log.Error("AddQusQusbeginTran error(%v)", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback() error(%v)", err1)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}()
qb := &model.Question{
QsID: time.Now().UnixNano() / 1e6,
QsName: in.Name,
QsDif: in.Dif,
QsBId: in.BId,
QsType: in.Type,
AnswerType: in.AnType,
}
res.ID, err = s.d.InsertQus(c, qb)
if err != nil {
log.Error("s.dao.AddQusBank(%v) error(%v)", qb)
return
}
list := make([]*model.AnswerAdd, 0)
for _, item := range answers {
answer := &model.AnswerAdd{}
answer.IsCorrect = item.IsCorrect
answer.AnswerContent = item.AnswerContent
answer.QsID = qb.QsID
answer.AnswerID = time.Now().UnixNano() / 1e6
time.Sleep(time.Millisecond)
list = append(list, answer)
}
err = s.d.MultiAddAnwser(c, list)
if err != nil {
log.Error("s.dao.AnswerAdd error(%v)", err)
return
}
_, err = s.d.UpdateQsBankCnt(c, in.BId)
if err != nil {
log.Error("s.dao.UpdateQsBankCnt error(%v)", err)
return
}
return
}
// DelQus 删除题目
func (s *Service) DelQus(c context.Context, qid int64) (res bool, err error) {
res = false
tx, err := s.beginTran(c)
if err != nil {
log.Error("DelQus beginTran error(%v)", err)
return
}
var rows int64
info, err := s.GetQusInfo(c, qid)
if err != nil || info == nil {
err = ecode.QusIDInvalid
return
}
cnt, err := s.d.CountBindItem(c, info.QsBId)
if cnt > 0 || err != nil {
err = ecode.BankUsing
}
rows, err = s.d.DelQus(c, qid)
if err != nil || rows == 0 {
tx.Rollback()
log.Error("dao.Subject.DelQus error(%v) or rows==0", err)
err = ecode.ParamInvalid
return
}
rows, err = s.d.DelAnwser(c, qid)
if err != nil || rows == 0 {
tx.Rollback()
log.Error("dao.Subject.Del Answer error(%v) or rows==0", err)
err = ecode.ParamInvalid
return
}
if err = tx.Commit(); err != nil {
return
}
_, err = s.d.UpdateQsBankCnt(c, info.QsBId)
if err != nil {
log.Error("s.dao.UpdateQsBankCnt error(%v)", err)
return
}
res = true
return
}
// GetQuslist 题目列表
func (s *Service) GetQuslist(c context.Context, pageNo int, pageSize int, qBid int64) (res []*model.QuestionAll, err error) {
offset, limit := s.PageInfo(pageNo, pageSize)
list, err := s.d.GetQusList(c, offset, limit, qBid)
if err != nil {
return
}
for _, item := range list {
alist, err := s.d.GetAnswerList(c, item.QsID)
if err != nil {
break
}
data := &model.QuestionAll{
Question: *item,
AnswersList: alist,
}
res = append(res, data)
}
return
}
// GetQusTotal 题目列表
func (s *Service) GetQusTotal(c context.Context, bid int64) (res int64, err error) {
if res, err = s.d.GetQusCount(c, bid); err != nil {
return
}
return
}
// UpdateQus 更新题库
func (s *Service) UpdateQus(c context.Context, in *model.ArgUpdateQus, answers []model.Answer) (res bool, err error) {
res = false
info, _ := s.GetQusBankInfo(c, in.BId)
if info == nil {
err = ecode.QusbNotFound
return
}
var row int64
tx, err := s.beginTran(c)
if err != nil {
log.Error("Del Qus beginTran error(%v)", err)
return
}
if row, err = s.d.UpdateQus(c, in, answers); err != nil {
tx.Rollback()
log.Error("s.dao.DelQusBank(%v) error(%v)", err)
err = ecode.UpdateError
return
}
if row > 0 {
res = true
}
_, err = s.d.DelAnwser(c, in.QsID)
if err != nil {
tx.Rollback()
log.Error("s.dao.DelAnwser error(%v)", err)
err = ecode.UpdateError
return
}
list := make([]*model.AnswerAdd, 0)
for _, item := range answers {
answer := model.AnswerAdd{}
answer.Answer = item
answer.QsID = in.QsID
if item.AnswerID != 0 {
_, err = s.d.UpdateAnwser(c, &answer)
if err != nil {
tx.Rollback()
log.Error("s.dao.UpdateAnwser error(%v)", err)
return
}
} else {
list = append(list, &answer)
}
}
//批量插入
if len(list) > 0 {
err = s.d.MultiAddAnwser(c, list)
if err != nil {
tx.Rollback()
log.Error("s.dao.MultiAddAnwser error(%v)", err)
return
}
}
if err = tx.Commit(); err != nil {
return
}
res = true
_, err = s.d.UpdateQsBankCnt(c, in.BId)
if err != nil {
log.Error("s.dao.UpdateQsBankCnt error(%v)", err)
return
}
err = s.d.DelQusCache(c, in.QsID)
if err != nil {
log.Error("s.dao.DelQusCache error(%v)", err)
return
}
err = s.d.DelAnswerCache(c, in.QsID)
if err != nil {
log.Error("s.dao.DelAnswerCache error(%v)", err)
return
}
return
}
// CheckAnswer 检查答案
func (s *Service) CheckAnswer(c context.Context, qusID int64, qusType int8, anlist []model.Answer) (etag string, err error) {
var correct int8
for _, item := range anlist {
if item.AnswerContent == "" {
etag = "answer_content is empty"
err = ecode.ParamInvalid
return
}
if item.IsCorrect > 1 || item.IsCorrect < 0 {
etag = "invalid is_correct"
err = ecode.AnswerError
return
}
correct = item.IsCorrect + correct
if item.QsID > 0 {
if qusID == item.QsID {
if res, _ := s.d.GetQusInfo(c, item.QsID); res == nil {
etag = "invalid QsID"
err = ecode.QusIDInvalid
return
}
continue
} else {
etag = "invalid QsID"
err = ecode.QusIDInvalid
return
}
}
}
if qusType == model.MULTIPLECHOICE {
if correct < 2 {
etag = "invalid is_correct"
err = ecode.AnswerError
return
}
} else {
if correct != 1 {
etag = "invalid is_correct"
err = ecode.AnswerError
return
}
}
return
}
// GetQuestion 获取题目
func (s *Service) GetQuestion(c context.Context, args *model.ArgGetQuestion) (q *model.GetQuestionItem, err error) {
// 获取已绑定的题库
bind, err := s.d.GetBindBankInfo(c, args.Source, args.TargetItemType, args.TargetItem)
if err != nil {
return
}
// 判断是不是答题组件
cid, err := s.d.GetComponentID(c, args)
if err != nil {
log.Info("s.GetQuestion(%v) 两次获取题目间隔小于 cd 时间", args)
err = ecode.GetComponentIDErr
return
}
// 组件第一题答题
if cid == 0 || cid != args.ComponentID {
// 检查上次时间与这次的差值如果小于 cd 时间
//if time.Now().Unix()-s.d.QusFetchTime(c, args) < bind.QuestionBank.CdTime {
// log.Info("s.GetQuestion(%v) 两次获取题目间隔小于 cd 时间", args)
// err = ecode.AnswerIntervalInvalid
// return
//}
//缓存新的组件
if err = s.d.SetComponentID(c, args); err != nil {
err = ecode.SetComponentIDErr
return
}
// 把组件答题次数清零
err = s.d.SetComponentTimes(c, args)
if err != nil {
log.Info("s.GetQuestion(%v) 两次获取题目间隔小于 cd 时间", args)
err = ecode.SetComponentTimesErr
return
}
}
BankInfo, err := s.d.GetQusBankInfoCache(c, bind.QsBId)
if err != nil {
err = ecode.GetQusBankInfoCache
return
}
// 同一组件
times, err := s.d.GetComponentTimes(c, args)
if err != nil {
err = ecode.GetComponentTimesErr
return
}
if times == BankInfo.MaxRetryTime {
err = ecode.SameCompentErr
return
}
// 获取题库包含的问题
var qusIds []int64
qusIds, err = s.d.GetQusIds(c, BankInfo.QsBId)
if err != nil {
err = ecode.GetQusIDsErr
return
}
q = new(model.GetQuestionItem)
// 随机取一道
q.Question, err = s.randQuestion(c, qusIds, args)
if err != nil {
err = ecode.GetQusIDsErr
return
}
//记录答题次数
q.AllCnt = BankInfo.MaxRetryTime
q.AnTime = times + 1
//产生答题背景图片
if q.QsType == 1 {
q.QuestBkPic, err = s.d.GetRandPic(c, args)
}
if err != nil {
log.Error("s.GetRandPic(%v) error(%v)", args, err)
q = nil
return
}
q.Answers, err = s.d.GetAnswersByCache(c, q.QsID)
if err != nil {
log.Error("s.GetQuestion(%v) error(%v)", args, err)
q = nil
return
}
// 组件题目+1
err = s.d.IncrComponentTimes(c, args)
if err != nil {
q = nil
return
}
// 记录上次获取题目时间
err = s.d.SetQusFetchTime(c, args, time.Now().Unix())
if err != nil {
q = nil
return
}
return
}
// UserAnswer 回答
func (s *Service) UserAnswer(c context.Context, check *model.ArgCheckAnswer) (res bool, err error) {
// 检查题目合法不合法
args := check.ArgGetQuestion
bind, err := s.d.GetBindBankInfo(c, args.Source, args.TargetItemType, args.TargetItem)
if err != nil {
return
}
//答题记录
insertID, err := s.d.AddUserAnwser(c, check, 1)
if err != nil || insertID == 0 {
log.Error("s.dao.AddUser Answser error(%v)", err)
return
}
//检查这是第几次答题
times, err := s.d.GetComponentTimes(c, &check.ArgGetQuestion)
if err != nil {
err = ecode.GetComponentTimesErr
return
}
if times > bind.QuestionBank.MaxRetryTime {
err = ecode.SameCompentErr
return
}
qusInfo, err := s.d.GetCacheQus(c, check.QsID)
if err != nil {
err = ecode.AnswerError
return
}
//检查xy坐标
if qusInfo.QsType == 1 {
answerPic, err1 := s.d.GetCacheAnswerPic(c, &check.ArgGetQuestion)
if err1 != nil {
err = ecode.AnswerError
return
}
m := check.X - answerPic.X
n := check.X - answerPic.X
if int(math.Abs(float64(m))) > 75 || int(math.Abs(float64(n))) > 75 {
err = ecode.AnswerPoiError
return
}
}
//检查答案
ids, err := s.d.CorrectAnswerIds(c, check.QsID)
if len(ids) < 1 || len(ids) != len(check.Answers) || err != nil {
log.Info("s.CheckAnswer(%v) 答案错误", err)
err = ecode.AnswerError
return
}
num := 0
for _, id := range ids {
for _, answerid := range check.Answers {
if answerid == id {
num++
continue
}
}
}
if num != len(ids) {
log.Info("s.CheckAnswer(%v) 答案错误", err)
err = ecode.AnswerError
return
}
res = true
return
}
// randQuestion 随机获取题目
func (s *Service) randQuestion(c context.Context, qs []int64, args *model.ArgGetQuestion) (q *model.Question, err error) {
// 获取已经答过的题目 id
usedIds := s.d.GetAnsweredID(c, args)
var notUseQ []int64
for _, id := range qs {
used := false
for _, i := range usedIds {
if id == i {
used = true
break
}
}
if !used {
notUseQ = append(notUseQ, id)
}
}
// 全部使用过了就重新开始随机
if len(notUseQ) == 0 {
err = s.d.RmAnsweredID(c, args)
if err != nil {
log.Error("d.randQuestion(%v, %v) error(%v)", qs, args, err)
return
}
notUseQ = qs
}
qid := notUseQ[rand.Intn(len(notUseQ))]
q, err = s.d.GetCacheQus(c, qid)
if err != nil {
log.Error("d.GetQusInfo(%v) error(%v)", qid, err)
return
}
// 设置已经答过的题目 id
err = s.d.SetAnsweredID(c, args, qid)
if err != nil {
log.Error("d.randQuestion(%v, %v) s.d.SetAnsweredID(%d) error(%v)", qs, args, qid, err)
return
}
return
}