187 lines
6.4 KiB
Go
187 lines
6.4 KiB
Go
|
package wechat
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
XmlUtils "encoding/xml"
|
|||
|
"net/http"
|
|||
|
|
|||
|
"code.gitea.io/gitea/modules/log"
|
|||
|
"code.gitea.io/gitea/modules/setting"
|
|||
|
"github.com/ArtisanCloud/PowerLibs/v3/http/helper"
|
|||
|
|
|||
|
"fmt"
|
|||
|
|
|||
|
"github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/contract"
|
|||
|
"github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/messages"
|
|||
|
models2 "github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/models"
|
|||
|
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount/server/handlers/models"
|
|||
|
)
|
|||
|
|
|||
|
// CallbackVerifyMessage
|
|||
|
/**
|
|||
|
* 微信服务器验证消息
|
|||
|
* GET /api/wechat/callback/message
|
|||
|
* https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
|
|||
|
*/
|
|||
|
func CallbackVerifyMessage(responseWriter http.ResponseWriter, request *http.Request) {
|
|||
|
resp, err := setting.Wechat.SDK.Server.VerifyURL(request)
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to verify message in Wechat Official Account callback")
|
|||
|
responseWriter.WriteHeader(resp.StatusCode)
|
|||
|
responseWriter.Write([]byte("Failed to verify message in Wechat Official Account callback (CallbackVerifyMessage): " + err.Error()))
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// 给微信服务器回信
|
|||
|
err = helper.HttpResponseSend(resp, responseWriter)
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to reply back to Wechat Server (CallbackVerifyMessage): ", err.Error())
|
|||
|
responseWriter.WriteHeader(500)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// CallbackNotifyEvents
|
|||
|
/**
|
|||
|
* 微信服务器通知事件
|
|||
|
* POST /api/wechat/callback/message
|
|||
|
* https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
|
|||
|
*/
|
|||
|
func CallbackNotifyEvents(responseWriter http.ResponseWriter, request *http.Request) {
|
|||
|
|
|||
|
resp, err := setting.Wechat.SDK.Server.Notify(request, func(event contract.EventInterface) interface{} {
|
|||
|
|
|||
|
switch event.GetMsgType() {
|
|||
|
|
|||
|
case models2.CALLBACK_MSG_TYPE_EVENT:
|
|||
|
// "event" 类型消息处理
|
|||
|
return callbackMsgEventHandler(request, event)
|
|||
|
|
|||
|
case models2.CALLBACK_MSG_TYPE_TEXT:
|
|||
|
// "text" 类型消息处理
|
|||
|
return callbackMsgTextHandler(event)
|
|||
|
}
|
|||
|
|
|||
|
return messages.NewText("undefined event type: " + event.GetMsgType())
|
|||
|
})
|
|||
|
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to get notified in Wechat Official Account callback (CallbackNotifyEvents): ", err.Error())
|
|||
|
responseWriter.WriteHeader(resp.StatusCode)
|
|||
|
responseWriter.Write([]byte("Failed to verify message in Wechat Official Account callback" + err.Error()))
|
|||
|
}
|
|||
|
|
|||
|
// 给微信服务器回信
|
|||
|
err = helper.HttpResponseSend(resp, responseWriter)
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to reply back to Wechat Server (CallbackNotifyEvents): ", err.Error())
|
|||
|
responseWriter.WriteHeader(500)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func callbackMsgEventHandler(request *http.Request, event contract.EventInterface) *messages.Text {
|
|||
|
ctx := request.Context()
|
|||
|
|
|||
|
// 根据不同 event 分别处理
|
|||
|
switch event.GetEvent() {
|
|||
|
|
|||
|
case models.CALLBACK_EVENT_SUBSCRIBE:
|
|||
|
// event:subscribe 新用户关注公众号事件
|
|||
|
return eventSubscribeHandler(event)
|
|||
|
|
|||
|
case models.CALLBACK_EVENT_SCAN:
|
|||
|
// event:SCAN 老用户扫描二维码事件
|
|||
|
return eventScanHandler(ctx, event)
|
|||
|
|
|||
|
case models.CALLBACK_EVENT_UNSUBSCRIBE:
|
|||
|
// event:unsubscribe 掉粉事件处理
|
|||
|
return eventUnsubscribeHandler(event)
|
|||
|
}
|
|||
|
return messages.NewText("undefined event type: " + event.GetChangeType())
|
|||
|
}
|
|||
|
|
|||
|
// "text" 类型消息处理
|
|||
|
func callbackMsgTextHandler(event contract.EventInterface) *messages.Text {
|
|||
|
msg := models.MessageText{}
|
|||
|
err := event.ReadMessage(&msg)
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to handle callback Message TEXT: " + err.Error())
|
|||
|
return messages.NewText("error: " + err.Error())
|
|||
|
}
|
|||
|
// fmt.Dump(msg)
|
|||
|
log.Info("[+] Got message from " + msg.FromUserName + ": " + msg.Content)
|
|||
|
return messages.NewText("您发送的消息已收到,感谢您使用梦宁软件DevStar Studio \n\n" + " -- DevStar Studio" + "\n\n")
|
|||
|
}
|
|||
|
|
|||
|
// event:subscribe 新用户关注公众号事件
|
|||
|
func eventSubscribeHandler(event contract.EventInterface) *messages.Text {
|
|||
|
msg := models.EventSubscribe{}
|
|||
|
err := event.ReadMessage(&msg)
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to handle callback Message event:subscribe: " + err.Error())
|
|||
|
return messages.NewText("error: " + err.Error())
|
|||
|
}
|
|||
|
// log.Info("[+] event:subscribe User Subscribed: " + msg.FromUserName + ", at Timestamp " + msg.CreateTime)
|
|||
|
return messages.NewText("欢迎新用户! 请关注公众号后重新扫码!\n\n" + " -- DevStar Studio" + "\n\n")
|
|||
|
}
|
|||
|
|
|||
|
// event:SCAN 类型消息,已关注公众号的老用户扫码
|
|||
|
func eventScanHandler(ctx context.Context, event contract.EventInterface) *messages.Text {
|
|||
|
|
|||
|
msg := models.EventScanCodePush{}
|
|||
|
err := event.ReadMessage(&msg)
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to handle callback event SCAN: " + err.Error())
|
|||
|
return messages.NewText("error: " + err.Error())
|
|||
|
}
|
|||
|
|
|||
|
var qrScanResponseDigest struct {
|
|||
|
FromUserName string `xml:"FromUserName"`
|
|||
|
Ticket string `xml:"Ticket"`
|
|||
|
SceneStr string `xml:"EventKey"`
|
|||
|
}
|
|||
|
err = XmlUtils.Unmarshal([]byte(event.GetContent()), &qrScanResponseDigest)
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to handle callback event SCAN: " + err.Error())
|
|||
|
return messages.NewText("error: " + err.Error())
|
|||
|
}
|
|||
|
|
|||
|
// 准备扫码状态VO对象
|
|||
|
qrStatus := WechatTempQRStatus{
|
|||
|
SceneStr: qrScanResponseDigest.SceneStr,
|
|||
|
IsScanned: true,
|
|||
|
OpenId: qrScanResponseDigest.FromUserName,
|
|||
|
}
|
|||
|
|
|||
|
log.Info("扫码成功:\n" +
|
|||
|
fmt.Sprintf(" Ticket: %s\n", qrScanResponseDigest.Ticket) +
|
|||
|
fmt.Sprintf(" SceneStr: %s\n", qrStatus.SceneStr))
|
|||
|
|
|||
|
qrStatus.IsBinded = false
|
|||
|
qrStatus.OpenId = qrScanResponseDigest.FromUserName
|
|||
|
qrVOJsonString, err := qrStatus.Marshal2JSONString()
|
|||
|
if err == nil {
|
|||
|
SetWechatQrTicketWithTTL(
|
|||
|
qrScanResponseDigest.Ticket,
|
|||
|
qrVOJsonString,
|
|||
|
setting.Wechat.TempQrExpireSeconds)
|
|||
|
}
|
|||
|
|
|||
|
loginSuccessInfo := "您正在微信扫码登录" + fmt.Sprintf(" %s ", msg.EventKey) +
|
|||
|
"\n\n" + " -- DevStar Studio" + "\n\n" +
|
|||
|
"如非本人操作,请尽快重新绑定微信!"
|
|||
|
|
|||
|
return messages.NewText(loginSuccessInfo)
|
|||
|
}
|
|||
|
|
|||
|
// event:unsubscribe 掉粉事件处理
|
|||
|
func eventUnsubscribeHandler(event contract.EventInterface) *messages.Text {
|
|||
|
msg := models.EventUnSubscribe{}
|
|||
|
err := event.ReadMessage(&msg)
|
|||
|
if err != nil {
|
|||
|
log.Error("[X] Failed to handle callback Message event:unsubscribe: " + err.Error())
|
|||
|
return messages.NewText("error: " + err.Error())
|
|||
|
}
|
|||
|
// log.Info("[+] event:unsubscribe User Unsubscribed: " + msg.ToUserName + ", at Timestamp " + msg.CreateTime)
|
|||
|
return messages.NewText("user unsubscribed: " + msg.FromUserName)
|
|||
|
}
|