Files
2025-08-25 15:46:12 +08:00

187 lines
6.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}