Skip to content
This repository has been archived by the owner on Apr 25, 2022. It is now read-only.

Commit

Permalink
Merge pull request #99 from CodFrm/dev/import
Browse files Browse the repository at this point in the history
题库导入接口
  • Loading branch information
CodFrm authored Dec 14, 2019
2 parents ac1be19 + 6ba5cc7 commit fa12256
Show file tree
Hide file tree
Showing 16 changed files with 406 additions and 18 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/CodFrm/cxmooc-tools
go 1.13

require (
github.com/360EntSecGroup-Skylar/excelize v1.4.1
github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05
github.com/go-redis/redis/v7 v7.0.0-beta.4
github.com/go-sql-driver/mysql v1.4.1
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
github.com/360EntSecGroup-Skylar/excelize v1.4.1 h1:l55mJb6rkkaUzOpSsgEeKYtS6/0gHwBYyfo5Jcjv/Ks=
github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
Expand Down Expand Up @@ -73,6 +75,8 @@ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
Expand Down Expand Up @@ -100,6 +104,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
Expand Down
7 changes: 6 additions & 1 deletion server/application/dto/topic.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ type SubmitTopic struct {
Type int32 `json:"type"`
}

type ImportTopic struct {
*SubmitTopic
Platform string `json:"platform"`
}

type TopicSet struct {
Index int `json:"index"`
Result []*SearchResult `json:"result"`
Expand Down Expand Up @@ -112,7 +117,7 @@ type TopicHash struct {
Hash string `json:"hash"`
}

func ToTopicEntity(topic SubmitTopic, ip, platform, token string) *entity.TopicEntity {
func ToTopicEntity(topic *SubmitTopic, ip, platform, token string) *entity.TopicEntity {
ret := &entity.TopicEntity{
Type: topic.Type,
Answer: MapToAnswerValue(topic.Answers, topic.Type),
Expand Down
9 changes: 9 additions & 0 deletions server/application/dto/user.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dto

import "github.com/CodFrm/cxmooc-tools/server/domain/entity"

type User struct {
User string
Token string
Expand All @@ -10,3 +12,10 @@ type TokenTransaction struct {
Num int
AddNum int
}

func ToUser(e *entity.UserEntity) *User {
return &User{
User: e.User,
Token: e.Token,
}
}
4 changes: 4 additions & 0 deletions server/application/event/publish/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ func UserCreate(user, token string) {
func SubmitTopic(token string, num int) {
mq.Evbus.Publish("topic:submit_new_topic", token, num)
}

func ImportTopic(token string, num int) {
mq.Evbus.Publish("topic:import_new_topic", token, num)
}
19 changes: 17 additions & 2 deletions server/application/service/topic.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import (
type Topic struct {
topic *domain.Topic
integral *domain.Integral
user *domain.User
}

func NewTopicService() *Topic {
return &Topic{
topic: domain.NewTopicDomainService(persistence.NewTopicRepository()),
integral: domain.NewIntegralService(persistence.NewIntegralRepository()),
user: domain.NewUserDomainService(persistence.NewUserRepository()),
}
}

Expand All @@ -28,8 +30,8 @@ func (t *Topic) SearchTopicList(topic []string) ([]dto.TopicSet, error) {
return t.topic.SearchTopicList(topic)
}

func (t *Topic) SubmitTopic(topic []dto.SubmitTopic, ip, platform, token string) ([]dto.TopicHash, *dto.InternalAddMsg, error) {
topicHash, add, err := t.topic.SubmitTopic(topic, ip, platform, token)
func (t *Topic) SubmitTopic(topic []*dto.SubmitTopic, ip, platform, token string) ([]dto.TopicHash, *dto.InternalAddMsg, error) {
topicHash, add, err := t.topic.SubmitTopic(topic, ip, platform, token, false)
if err != nil {
return nil, nil, err
}
Expand All @@ -42,3 +44,16 @@ func (t *Topic) SubmitTopic(topic []dto.SubmitTopic, ip, platform, token string)

return topicHash, add, nil
}

func (t *Topic) ImportTopic(topic []*dto.ImportTopic, user, token, ip string) error {
_, err := t.user.VerifyUserToken(user, token)
if err != nil {
return err
}
for _, v := range topic {
if _, _, err := t.topic.SubmitTopic([]*dto.SubmitTopic{v.SubmitTopic}, ip, v.Platform, token, false); err != nil {
return err
}
}
return nil
}
6 changes: 6 additions & 0 deletions server/application/service/topic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,17 @@ func TestTopic_SubmitTopic(t *testing.T) {
mock.On("Exist", "判断,").Return(false, nil)

mock.On("Save", "判断,").Return(nil)
mock.On("Save", "多选,中文标点.()").Return(nil)

mocki.On("GetIntegral", "tk").Return(&entity.IntegralEntity{
Token: "tk",
Num: 100,
}, nil)

et := &entity.TopicEntity{Type: 2}
et.SetTopic("多选,中文标点.()")
mock.On("FindByHash", "05d901980b216c5f8c6b8d6e1f6820b6").Return(et, nil)

hash, add, err := topic.SubmitTopic([]dto.SubmitTopic{topic1, topic2}, "localhost", "cx", "tk")
assert.Nil(t, err)

Expand Down
10 changes: 5 additions & 5 deletions server/domain/repository/mocks/TopicRepository.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions server/domain/service/topic.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (t *Topic) SearchTopicList(topic []string) ([]dto.TopicSet, error) {
return ret, nil
}

func (t *Topic) SubmitTopic(topic []dto.SubmitTopic, ip, platform, token string) ([]dto.TopicHash, *dto.InternalAddMsg, error) {
func (t *Topic) SubmitTopic(topic []*dto.SubmitTopic, ip, platform, token string, isImport bool) ([]dto.TopicHash, *dto.InternalAddMsg, error) {
ret := make([]dto.TopicHash, 0)
addNum := &dto.InternalAddMsg{}
for _, v := range topic {
Expand Down Expand Up @@ -67,12 +67,16 @@ func (t *Topic) SubmitTopic(topic []dto.SubmitTopic, ip, platform, token string)
ret = append(ret, dto.TopicHash{Hash: et.GetHash()})
}
if addNum.AddTokenNum > 0 {
publish.SubmitTopic(token, addNum.AddTokenNum/10)
if isImport {
publish.ImportTopic(token, addNum.AddTokenNum/10)
} else {
publish.SubmitTopic(token, addNum.AddTokenNum/10)
}
}
return ret, addNum, nil
}

func (t *Topic) mergeAnswer(et *entity.TopicEntity, d dto.SubmitTopic) *entity.TopicEntity {
func (t *Topic) mergeAnswer(et *entity.TopicEntity, d *dto.SubmitTopic) *entity.TopicEntity {
if len(et.Correct) >= len(d.Correct) {
return et
}
Expand Down
17 changes: 14 additions & 3 deletions server/domain/service/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,18 @@ func (u *User) CreateUser(usr string) (*dto.User, error) {
return nil, err
}
publish.UserCreate(user.User, user.Token)
return &dto.User{
Token: user.Token,
}, nil
return dto.ToUser(user), nil
}

func (u *User) VerifyUserToken(user, token string) (*dto.User, error) {
m, err := u.userRepo.FindByUser(user)
if err != nil {
return nil, err
} else if m == nil {
return nil, errs.TokenNotExist
}
if m.Token == token {
return dto.ToUser(m), nil
}
return nil, errs.TokenNotExist
}
141 changes: 137 additions & 4 deletions server/interface/handler/topic.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@ package handler

import (
"encoding/json"
"github.com/CodFrm/cxmooc-tools/server/application/dto"
"github.com/CodFrm/cxmooc-tools/server/application/service"
"github.com/CodFrm/cxmooc-tools/server/internal/utils"
"github.com/360EntSecGroup-Skylar/excelize"
"github.com/CodFrm/cxmooc-tools/server/internal/errs"
"io/ioutil"
"net/http"
"regexp"
"strconv"

"github.com/CodFrm/cxmooc-tools/server/application/dto"
"github.com/CodFrm/cxmooc-tools/server/application/service"
"github.com/CodFrm/cxmooc-tools/server/internal/utils"
)

var importPlatFormMap = map[string]string{
"超星": "cx", "超星考试": "cx", "智慧树": "zhs",
}

type topic struct {
topic *service.Topic
}
Expand All @@ -20,9 +28,134 @@ func newTopicHandler(r *http.ServeMux) *topic {
}
r.HandleFunc("/v2/answer", t.SearchTopic())
r.HandleFunc("/answer", t.SubmitTopic())
r.HandleFunc("/topic/import", t.Import())
return t
}

func (t *topic) Import() func(http.ResponseWriter, *http.Request) {
return func(writer http.ResponseWriter, request *http.Request) {
if request.Method != "POST" {
http.NotFound(writer, request)
return
}
f, _, err := request.FormFile("topic")
if err != nil {
serverError(writer, err)
return
}
excel, err := excelize.OpenReader(f)
if err != nil {
serverError(writer, err)
return
}
var ipt = make([]*dto.ImportTopic, 0)
rows := excel.GetRows("Sheet1")
if len(rows) < 2 {
json_msg(writer, -1, "excel行格式错误")
return
}
if len(rows[0]) < 4 {
json_msg(writer, -1, "内容不全(至少会有4列)")
return
}
if len(rows[0]) > 10 {
json_msg(writer, -1, "选项过多")
return
}
rows = rows[1:]
for line, row := range rows {
topic, err := t.excelToTopic(line, row)
if err != nil {
serverError(writer, err)
return
}
ipt = append(ipt, topic)
}

if err := t.topic.ImportTopic(ipt, request.PostFormValue("user"), request.PostFormValue("token"), utils.ClientIP(request)); err != nil {
serverError(writer, err)
return
}
json_msg(writer, 0, "success")
}
}

func (t *topic) excelToTopic(line int, row []string) (*dto.ImportTopic, error) {
platfrom, ok := importPlatFormMap[row[0]]
if !ok {
return nil, errs.New(200, -1, strconv.Itoa(line)+"行错误,不存在的平台")
}

ret := &dto.ImportTopic{
SubmitTopic: &dto.SubmitTopic{
Answers: nil,
Correct: make([]map[string]interface{}, 0),
Topic: row[1],
},
Platform: platfrom,
}
var iter utils.Iterator
switch row[2] {
case "选择":
ret.Type = 1
if ok, _ := regexp.MatchString("[A-F]+", row[3]); ok && ((len(row) >= 5 && row[4] == "") || len(row) == 4) {
// 选项
if len(row[3]) > 7 {
return nil, errs.New(200, -1, "选项过多")
}
for k := range row[3] {
ret.Correct = append(ret.Correct, map[string]interface{}{
"option": string(row[3][k]),
"content": "",
})
}
if len(ret.Correct) > 1 {
ret.Type = 2
}
} else {
// 内容
iter = utils.NewUpLetterIterator()
}
case "填空":
ret.Type = 4
iter = utils.NewChineseNumbersIterator()
case "判断":
default:
return nil, errs.New(200, -1, strconv.Itoa(line)+"行错误,不支持的题目类型")
}
if row[2] == "判断" {
ret.Type = 3
ret.Correct = append(ret.Correct, map[string]interface{}{
"option": row[3] == "1",
"content": row[3] == "1",
})
} else if iter != nil {
for i := 3; i < len(row); i++ {
if row[i] == "" {
break
}
ret.Correct = append(ret.Correct, map[string]interface{}{
"option": iter.Value(),
"content": row[i],
})
iter = iter.Next()
}
if ret.Type == 1 && len(ret.Correct) > 1 {
ret.Type = 2
}
}

if row[0] != "超星" {
// 检测是否有答案内容
for _, val := range ret.Correct {
if v, ok := val["Content"].(string); ok && v == "" {
return nil, errs.New(200, -1, strconv.Itoa(line)+"行错误,超星考试和智慧树要求必须有选项内容")
}
}
}
return ret, nil
}

func (t *topic) SearchTopic() func(http.ResponseWriter, *http.Request) {
return func(writer http.ResponseWriter, request *http.Request) {
if request.Method != "POST" {
Expand Down Expand Up @@ -56,7 +189,7 @@ func (t *topic) SubmitTopic() func(http.ResponseWriter, *http.Request) {
http.NotFound(writer, request)
return
}
submit := make([]dto.SubmitTopic, 0)
submit := make([]*dto.SubmitTopic, 0)
if b, err := ioutil.ReadAll(request.Body); err != nil {
serverError(writer, err)
return
Expand Down
Loading

0 comments on commit fa12256

Please sign in to comment.