From f59a6597f7b318f6ef7d4c67325249349697e34f Mon Sep 17 00:00:00 2001
From: JustSong
Date: Sat, 5 Nov 2022 15:49:39 +0800
Subject: [PATCH] Able to set menu now
---
common/access-token-store.go | 9 +++++-
common/constants.go | 9 ++++++
controller/misc.go | 32 ---------------------
controller/option.go | 29 +++++++++++++++++++
controller/wechat.go | 44 +++++++++++++++++++++++++++++
model/option.go | 3 ++
web/src/components/WeChatSetting.js | 34 +++++++++++++++++++++-
7 files changed, 126 insertions(+), 34 deletions(-)
create mode 100644 controller/wechat.go
diff --git a/common/access-token-store.go b/common/access-token-store.go
index ba01f95..022e5d9 100644
--- a/common/access-token-store.go
+++ b/common/access-token-store.go
@@ -48,6 +48,7 @@ func RefreshAccessToken() {
SysError("failed to refresh access token: " + err.Error())
return
}
+ defer responseData.Body.Close()
var res response
err = json.NewDecoder(responseData.Body).Decode(&res)
if err != nil {
@@ -61,8 +62,14 @@ func RefreshAccessToken() {
SysLog("access token refreshed")
}
-func GetAccessToken() (string, int) {
+func GetAccessTokenAndExpirationSeconds() (string, int) {
s.Mutex.RLock()
defer s.Mutex.RUnlock()
return s.AccessToken, s.ExpirationSeconds
}
+
+func GetAccessToken() string {
+ s.Mutex.RLock()
+ defer s.Mutex.RUnlock()
+ return s.AccessToken
+}
diff --git a/common/constants.go b/common/constants.go
index b20fe13..35b8220 100644
--- a/common/constants.go
+++ b/common/constants.go
@@ -19,6 +19,15 @@ var WeChatAppID = ""
var WeChatAppSecret = ""
var WeChatEncodingAESKey = ""
var WeChatOwnerID = ""
+var WeChatMenu = `{
+ "button": [
+ {
+ "type": "click",
+ "name": "登录验证",
+ "key": "USER_VERIFICATION"
+ }
+ ]
+}`
var SessionSecret = uuid.New().String()
var SQLitePath = ".wechat-server.db"
diff --git a/controller/misc.go b/controller/misc.go
index fb7c5ed..3d40e28 100644
--- a/controller/misc.go
+++ b/controller/misc.go
@@ -1,13 +1,9 @@
package controller
import (
- "crypto/sha1"
- "encoding/hex"
"fmt"
"github.com/gin-gonic/gin"
"net/http"
- "sort"
- "strings"
"wechat-server/common"
"wechat-server/model"
)
@@ -40,34 +36,6 @@ func GetNotice(c *gin.Context) {
return
}
-func WeChatVerification(c *gin.Context) {
- // https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
- signature := c.Query("signature")
- timestamp := c.Query("timestamp")
- nonce := c.Query("nonce")
- echoStr := c.Query("echostr")
- arr := []string{common.WeChatToken, timestamp, nonce}
- sort.Strings(arr)
- str := strings.Join(arr, "")
- hash := sha1.Sum([]byte(str))
- hexStr := hex.EncodeToString(hash[:])
- if signature == hexStr {
- c.String(http.StatusOK, echoStr)
- } else {
- c.Status(http.StatusForbidden)
- }
-}
-
-func GetAccessToken(c *gin.Context) {
- accessToken, expiration := common.GetAccessToken()
- c.JSON(http.StatusOK, gin.H{
- "success": true,
- "message": "",
- "access_token": accessToken,
- "expiration": expiration,
- })
-}
-
func SendEmailVerification(c *gin.Context) {
email := c.Query("email")
if err := common.Validate.Var(email, "required,email"); err != nil {
diff --git a/controller/option.go b/controller/option.go
index d4e7729..5fd0e27 100644
--- a/controller/option.go
+++ b/controller/option.go
@@ -1,7 +1,9 @@
package controller
import (
+ "bytes"
"encoding/json"
+ "fmt"
"github.com/gin-gonic/gin"
"net/http"
"strings"
@@ -55,6 +57,33 @@ func UpdateOption(c *gin.Context) {
})
return
}
+ if option.Key == "WeChatMenu" {
+ httpResponse, err := http.Post(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s", common.GetAccessToken()), "application/json", bytes.NewBuffer([]byte(option.Value)))
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "success": false,
+ "message": err.Error(),
+ })
+ return
+ }
+ defer httpResponse.Body.Close()
+ var res wechatResponse
+ err = json.NewDecoder(httpResponse.Body).Decode(&res)
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "success": false,
+ "message": err.Error(),
+ })
+ return
+ }
+ if res.ErrCode != 0 {
+ c.JSON(http.StatusOK, gin.H{
+ "success": false,
+ "message": res.ErrMsg,
+ })
+ return
+ }
+ }
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
diff --git a/controller/wechat.go b/controller/wechat.go
new file mode 100644
index 0000000..211f7d4
--- /dev/null
+++ b/controller/wechat.go
@@ -0,0 +1,44 @@
+package controller
+
+import (
+ "crypto/sha1"
+ "encoding/hex"
+ "github.com/gin-gonic/gin"
+ "net/http"
+ "sort"
+ "strings"
+ "wechat-server/common"
+)
+
+type wechatResponse struct {
+ ErrCode int `json:"errcode"`
+ ErrMsg string `json:"errmsg"`
+}
+
+func WeChatVerification(c *gin.Context) {
+ // https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
+ signature := c.Query("signature")
+ timestamp := c.Query("timestamp")
+ nonce := c.Query("nonce")
+ echoStr := c.Query("echostr")
+ arr := []string{common.WeChatToken, timestamp, nonce}
+ sort.Strings(arr)
+ str := strings.Join(arr, "")
+ hash := sha1.Sum([]byte(str))
+ hexStr := hex.EncodeToString(hash[:])
+ if signature == hexStr {
+ c.String(http.StatusOK, echoStr)
+ } else {
+ c.Status(http.StatusForbidden)
+ }
+}
+
+func GetAccessToken(c *gin.Context) {
+ accessToken, expiration := common.GetAccessTokenAndExpirationSeconds()
+ c.JSON(http.StatusOK, gin.H{
+ "success": true,
+ "message": "",
+ "access_token": accessToken,
+ "expiration": expiration,
+ })
+}
diff --git a/model/option.go b/model/option.go
index 51c895f..99695e7 100644
--- a/model/option.go
+++ b/model/option.go
@@ -43,6 +43,7 @@ func InitOptionMap() {
common.OptionMap["WeChatAppSecret"] = ""
common.OptionMap["WeChatEncodingAESKey"] = ""
common.OptionMap["WeChatOwnerID"] = ""
+ common.OptionMap["WeChatMenu"] = common.WeChatMenu
common.OptionMapRWMutex.Unlock()
options, _ := AllOption()
for _, option := range options {
@@ -121,5 +122,7 @@ func updateOptionMap(key string, value string) {
common.WeChatEncodingAESKey = value
case "WeChatOwnerID":
common.WeChatOwnerID = value
+ case "WeChatMenu":
+ common.WeChatMenu = value
}
}
diff --git a/web/src/components/WeChatSetting.js b/web/src/components/WeChatSetting.js
index f1cd7ff..3b412f0 100644
--- a/web/src/components/WeChatSetting.js
+++ b/web/src/components/WeChatSetting.js
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Form, Grid } from 'semantic-ui-react';
import { API, showError } from '../helpers';
+import { Link } from 'react-router-dom';
const WeChatSetting = () => {
let [inputs, setInputs] = useState({
@@ -9,6 +10,7 @@ const WeChatSetting = () => {
WeChatAppSecret: '',
WeChatEncodingAESKey: '',
WeChatOwnerID: '',
+ WeChatMenu: '',
});
let [loading, setLoading] = useState(false);
@@ -48,7 +50,15 @@ const WeChatSetting = () => {
};
const handleInputChange = async (e, { name, value }) => {
- await updateOption(name, value);
+ if (name === 'WeChatMenu') {
+ setInputs((inputs) => ({ ...inputs, [name]: value }));
+ } else {
+ await updateOption(name, value);
+ }
+ };
+
+ const submitWeChatMenu = async () => {
+ await updateOption('WeChatMenu', inputs.WeChatMenu);
};
return (
@@ -100,6 +110,28 @@ const WeChatSetting = () => {
onChange={handleInputChange}
/>
+
+
+ 公众号菜单(
+
+ 格式请参考此处
+
+ )
+
+ }
+ placeholder="JSON 格式"
+ value={inputs.WeChatMenu}
+ name="WeChatMenu"
+ onChange={handleInputChange}
+ style={{ minHeight: 150, fontFamily: 'JetBrains Mono, Consolas' }}
+ />
+
+ 更新公众号菜单