Browse Source

#2225

add auto reply
tags/v1.22.6.2^2
chenyifan01 3 years ago
parent
commit
44ff7687f2
4 changed files with 293 additions and 23 deletions
  1. +2
    -7
      models/repo.go
  2. +110
    -0
      modules/auth/wechat/auto_reply.go
  3. +83
    -4
      modules/auth/wechat/event_handle.go
  4. +98
    -12
      routers/authentication/wechat_event.go

+ 2
- 7
models/repo.go View File

@@ -2749,15 +2749,10 @@ func ReadLatestFileInRepo(userName, repoName, refName, treePath string) (*RepoFi
log.Error("ReadLatestFileInRepo: Close: %v", err)
}
}()

buf := make([]byte, 1024)
n, _ := reader.Read(buf)
if n >= 0 {
buf = buf[:n]
}
d, _ := ioutil.ReadAll(reader)
commitId := ""
if blob != nil {
commitId = fmt.Sprint(blob.ID)
}
return &RepoFile{CommitId: commitId, Content: buf}, nil
return &RepoFile{CommitId: commitId, Content: d}, nil
}

+ 110
- 0
modules/auth/wechat/auto_reply.go View File

@@ -0,0 +1,110 @@
package wechat

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"encoding/json"
"github.com/patrickmn/go-cache"
"strings"
"time"
)

var WechatReplyCache = cache.New(2*time.Minute, 1*time.Minute)

const (
WECHAT_REPLY_CACHE_KEY = "wechat_response"
)

const (
ReplyTypeText = "text"
ReplyTypeImage = "image"
ReplyTypeVoice = "voice"
ReplyTypeVideo = "video"
ReplyTypeMusic = "music"
ReplyTypeNews = "news"
)

type AutomaticResponseContent struct {
Reply *ReplyContent
ReplyType string
KeyWords []string
IsFullMatch int
}

type ReplyContent struct {
Content string
MediaId string
Title string
Description string
MusicUrl string
HQMusicUrl string
ThumbMediaId string
}

func GetAutomaticReply(msg string) *AutomaticResponseContent {
r, err := LoadAutomaticReplyFromCacheAndDisk()
if err != nil {
return nil
}
if r == nil || len(r) == 0 {
return nil
}
for i := 0; i < len(r); i++ {
if r[i].IsFullMatch > 0 {
for _, v := range r[i].KeyWords {
if strings.Contains(msg, v) {
return r[i]
}
}
} else if r[i].IsFullMatch == 0 {
for _, v := range r[i].KeyWords {
if msg == v {
return r[i]
}
}
}
}
return nil

}

func loadAutomaticReplyFromDisk() ([]*AutomaticResponseContent, error) {
log.Debug("LoadAutomaticResponseMap from disk")
repo, err := models.GetRepositoryByOwnerAndAlias("OpenIOSSG", "promote")
if err != nil {
log.Error("get notice repo failed, error=%v", err)
return nil, err
}
repoFile, err := models.ReadLatestFileInRepo("OpenIOSSG", repo.Name, "master", "wechat/auto_reply.json")
if err != nil {
log.Error("GetNewestNotice failed, error=%v", err)
return nil, err
}
res := make([]*AutomaticResponseContent, 0)
json.Unmarshal(repoFile.Content, &res)
if res == nil || len(res) == 0 {
return nil, err
}
return res, nil
}

func LoadAutomaticReplyFromCacheAndDisk() ([]*AutomaticResponseContent, error) {
v, success := WechatReplyCache.Get(WECHAT_REPLY_CACHE_KEY)
if success {
log.Debug("LoadAutomaticResponse from cache,value = %v", v)
if v == nil {
return nil, nil
}
n := v.([]*AutomaticResponseContent)
return n, nil
}

content, err := loadAutomaticReplyFromDisk()
if err != nil {
log.Error("GetNewestNotice failed, error=%v", err)
WechatReplyCache.Set(WECHAT_REPLY_CACHE_KEY, nil, 30*time.Second)
return nil, err
}
WechatReplyCache.Set(WECHAT_REPLY_CACHE_KEY, content, 60*time.Second)
return content, nil
}

+ 83
- 4
modules/auth/wechat/event_handle.go View File

@@ -18,7 +18,7 @@ import (
// <EventKey><![CDATA[SCENE_VALUE]]></EventKey>
// <Ticket><![CDATA[TICKET]]></Ticket>
//</xml>
type WechatEvent struct {
type WechatMsg struct {
ToUserName string
FromUserName string
CreateTime int64
@@ -26,9 +26,22 @@ type WechatEvent struct {
Event string
EventKey string
Ticket string
Content string
MsgId string
MsgDataId string
Idx string
}

type MsgReply struct {
XMLName xml.Name `xml:"xml"`
ToUserName string
FromUserName string
CreateTime int64
MsgType string
Content string
}

type EventReply struct {
type TextMsgReply struct {
XMLName xml.Name `xml:"xml"`
ToUserName string
FromUserName string
@@ -36,6 +49,71 @@ type EventReply struct {
MsgType string
Content string
}
type ImageMsgReply struct {
XMLName xml.Name `xml:"xml"`
ToUserName string
FromUserName string
CreateTime int64
MsgType string
Image ImageContent
}
type VoiceMsgReply struct {
XMLName xml.Name `xml:"xml"`
ToUserName string
FromUserName string
CreateTime int64
MsgType string
Voice VoiceContent
}
type VideoMsgReply struct {
XMLName xml.Name `xml:"xml"`
ToUserName string
FromUserName string
CreateTime int64
MsgType string
Video VideoContent
}
type MusicMsgReply struct {
XMLName xml.Name `xml:"xml"`
ToUserName string
FromUserName string
CreateTime int64
MsgType string
Music MusicContent
}
type ArticlesMsgReply struct {
XMLName xml.Name `xml:"xml"`
ToUserName string
FromUserName string
CreateTime int64
MsgType string
Articles []ArticlesContent
}

type ImageContent struct {
MediaId string
}
type VoiceContent struct {
MediaId string
}
type VideoContent struct {
MediaId string
Title string
Description string
}
type MusicContent struct {
Title string
Description string
MusicUrl string
HQMusicUrl string
ThumbMediaId string
}
type ArticlesContent struct {
Title string
Description string
PicUrl string
Url string
}

const (
WECHAT_EVENT_SUBSCRIBE = "subscribe"
@@ -43,10 +121,11 @@ const (
)

const (
WECHAT_MSG_TYPE_TEXT = "text"
WECHAT_MSG_TYPE_TEXT = "text"
WECHAT_MSG_TYPE_EVENT = "event"
)

func HandleSubscribeEvent(we WechatEvent) string {
func HandleSubscribeEvent(we WechatMsg) string {
eventKey := we.EventKey
if eventKey == "" {
return ""


+ 98
- 12
routers/authentication/wechat_event.go View File

@@ -14,14 +14,30 @@ import (
// https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html
func AcceptWechatEvent(ctx *context.Context) {
b, _ := ioutil.ReadAll(ctx.Req.Request.Body)
we := wechat.WechatEvent{}
we := wechat.WechatMsg{}
xml.Unmarshal(b, &we)

switch we.MsgType {
case wechat.WECHAT_MSG_TYPE_EVENT:
HandleEventMsg(ctx, we)
case wechat.WECHAT_MSG_TYPE_TEXT:
HandleTextMsg(ctx, we)
}
log.Info("accept wechat event= %+v", we)

}

// ValidEventSource
func ValidEventSource(ctx *context.Context) {
echostr := ctx.Query("echostr")
ctx.Write([]byte(echostr))
return
}

func HandleEventMsg(ctx *context.Context, msg wechat.WechatMsg) {
var replyStr string
switch we.Event {
switch msg.Event {
case wechat.WECHAT_EVENT_SUBSCRIBE, wechat.WECHAT_EVENT_SCAN:
replyStr = wechat.HandleSubscribeEvent(we)
replyStr = wechat.HandleSubscribeEvent(msg)
break
}

@@ -29,9 +45,9 @@ func AcceptWechatEvent(ctx *context.Context) {
log.Info("reply str is empty")
return
}
reply := &wechat.EventReply{
ToUserName: we.FromUserName,
FromUserName: we.ToUserName,
reply := &wechat.MsgReply{
ToUserName: msg.FromUserName,
FromUserName: msg.ToUserName,
CreateTime: time.Now().Unix(),
MsgType: wechat.WECHAT_MSG_TYPE_TEXT,
Content: replyStr,
@@ -39,9 +55,79 @@ func AcceptWechatEvent(ctx *context.Context) {
ctx.XML(200, reply)
}

// ValidEventSource
func ValidEventSource(ctx *context.Context) {
echostr := ctx.Query("echostr")
ctx.Write([]byte(echostr))
return
func HandleTextMsg(ctx *context.Context, msg wechat.WechatMsg) {
r := wechat.GetAutomaticReply(msg.Content)
if r == nil {
log.Info("TextMsg reply is empty")
return
}
reply := buildReplyContent(msg, r)
ctx.XML(200, reply)
}

func buildReplyContent(msg wechat.WechatMsg, r *wechat.AutomaticResponseContent) interface{} {
reply := &wechat.MsgReply{
ToUserName: msg.FromUserName,
FromUserName: msg.ToUserName,
CreateTime: time.Now().Unix(),
MsgType: r.ReplyType,
}
switch r.ReplyType {
case wechat.ReplyTypeText:
return &wechat.TextMsgReply{
ToUserName: msg.FromUserName,
FromUserName: msg.ToUserName,
CreateTime: time.Now().Unix(),
MsgType: r.ReplyType,
Content: r.Reply.Content,
}

case wechat.ReplyTypeImage:
return &wechat.ImageMsgReply{
ToUserName: msg.FromUserName,
FromUserName: msg.ToUserName,
CreateTime: time.Now().Unix(),
MsgType: r.ReplyType,
Image: wechat.ImageContent{
MediaId: r.Reply.MediaId,
},
}
case wechat.ReplyTypeVoice:
return &wechat.VoiceMsgReply{
ToUserName: msg.FromUserName,
FromUserName: msg.ToUserName,
CreateTime: time.Now().Unix(),
MsgType: r.ReplyType,
Voice: wechat.VoiceContent{
MediaId: r.Reply.MediaId,
},
}
case wechat.ReplyTypeVideo:
return &wechat.VideoMsgReply{
ToUserName: msg.FromUserName,
FromUserName: msg.ToUserName,
CreateTime: time.Now().Unix(),
MsgType: r.ReplyType,
Video: wechat.VideoContent{
MediaId: r.Reply.MediaId,
Title: r.Reply.Title,
Description: r.Reply.Description,
},
}
case wechat.ReplyTypeMusic:
return &wechat.MusicMsgReply{
ToUserName: msg.FromUserName,
FromUserName: msg.ToUserName,
CreateTime: time.Now().Unix(),
MsgType: r.ReplyType,
Music: wechat.MusicContent{
Title: r.Reply.Title,
Description: r.Reply.Description,
MusicUrl: r.Reply.MusicUrl,
HQMusicUrl: r.Reply.HQMusicUrl,
ThumbMediaId: r.Reply.ThumbMediaId,
},
}
}
return reply
}

Loading…
Cancel
Save