Files
devstar-create-from-template/services/wechat/callback.go

187 lines
6.4 KiB
Go
Raw Normal View History

2025-08-25 15:46:12 +08:00
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)
}