feat(1.0):调试模版消息

This commit is contained in:
summer 2025-10-27 11:05:03 +08:00
parent d469c4a8ab
commit de9acfa863
12 changed files with 658 additions and 58 deletions

View File

@ -34,6 +34,6 @@ eg :
```shell
# 根目录下执行
go run cmd/gormgen/main.go -dsn "root:api2api..@tcp(sh-cynosdbmysql-grp-88th45wy.sql.tencentcdb.com:28555)/mini_chat?charset=utf8mb4&parseTime=True&loc=Local" -tables "log_operation,log_request,admin,app_keyword,app_keyword_reply,app_user,app_message_log,mini_program"
go run cmd/gormgen/main.go -dsn "root:api2api..@tcp(sh-cynosdbmysql-grp-88th45wy.sql.tencentcdb.com:28555)/mini_chat?charset=utf8mb4&parseTime=True&loc=Local" -tables "log_operation,log_request,admin,app_keyword,app_keyword_reply,app_user,app_message_log,mini_program,mini_program_access_token"
```

View File

@ -0,0 +1,39 @@
package miniprogram
import (
"fmt"
"github.com/go-resty/resty/v2"
)
type AccessTokenResponse struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
}
// GetAccessToken 获取微信 access_token
// DOC: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
func GetAccessToken(appID, appSecret string, resultStruct interface{}) error {
requestData := map[string]string{}
requestData["grant_type"] = "client_credential"
requestData["appid"] = appID
requestData["secret"] = appSecret
response, err := resty.New().R().
ForceContentType("application/json").
SetHeader("Content-Type", "application/json").
SetQueryParams(requestData).
SetResult(resultStruct).
Get("https://api.weixin.qq.com/cgi-bin/token")
if err != nil {
return err
}
// 检查响应状态码
if response.IsError() {
return fmt.Errorf("服务异常(%d)", response.StatusCode())
}
return nil
}

View File

@ -0,0 +1,16 @@
package miniprogram
import (
"testing"
)
func TestGetAccessToken(t *testing.T) {
res := new(AccessTokenResponse)
err := GetAccessToken("wx26ad074017e1e63f", "026c19ce4f3bb090c56573024c59a8be", res)
if err != nil {
t.Error(err)
}
t.Logf("access_token: %s", res.AccessToken)
t.Logf("expires_in: %d", res.ExpiresIn)
}

View File

@ -0,0 +1,58 @@
package miniprogram
import (
"fmt"
"github.com/go-resty/resty/v2"
)
type SendSubscribeMessageResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
type SendSubscribeMessageRequest struct {
Touser string `json:"touser"`
TemplateID string `json:"template_id"`
Page string `json:"page"`
MiniprogramState string `json:"miniprogram_state"`
Lang string `json:"lang"`
Data struct {
Thing1 struct {
Value string `json:"value"`
} `json:"thing1"`
Time2 struct {
Value string `json:"value"`
} `json:"time2"`
Thing4 struct {
Value string `json:"value"`
} `json:"thing4"`
} `json:"data"`
}
// SendSubscribeMessage 发送订阅消息
// DOC: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/sendMessage.html
func SendSubscribeMessage(accessToken string, requestData *SendSubscribeMessageRequest, resultStruct interface{}) error {
response, err := resty.New().R().
ForceContentType("application/json").
SetHeader("Content-Type", "application/json").
SetBody(requestData).
SetResult(resultStruct).
Post(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s", accessToken))
if err != nil {
return err
}
// 检查响应状态码
if response.IsError() {
return fmt.Errorf("服务异常(%d)", response.StatusCode())
}
// 检查响应结果
if response.Result().(*SendSubscribeMessageResponse).Errcode != 0 {
return fmt.Errorf("服务异常(%d): %s", response.Result().(*SendSubscribeMessageResponse).Errcode, response.Result().(*SendSubscribeMessageResponse).Errmsg)
}
return nil
}

View File

@ -0,0 +1,32 @@
package miniprogram
import (
"testing"
)
func TestSendSubscribeMessage(t *testing.T) {
res := new(AccessTokenResponse)
err := GetAccessToken("wx26ad074017e1e63f", "026c19ce4f3bb090c56573024c59a8be", res)
if err != nil {
t.Errorf("获取 access_token 错误: %s", err.Error())
}
sendSubscribeMessageRequest := new(SendSubscribeMessageRequest)
sendSubscribeMessageRequest.Touser = "onjlN4wrsGe09SdRrpl4D_FWBh0I"
sendSubscribeMessageRequest.TemplateID = "9dCV3z7vRPBGm8iMtSXsD7ZVyUjld46w7HTH9zLnzWw"
sendSubscribeMessageRequest.Page = "pages/contact/index"
sendSubscribeMessageRequest.MiniprogramState = "trial"
sendSubscribeMessageRequest.Lang = "zh_CN"
sendSubscribeMessageRequest.Data.Thing1.Value = "测试(CC)"
sendSubscribeMessageRequest.Data.Time2.Value = "2025-10-27"
sendSubscribeMessageRequest.Data.Thing4.Value = "测试(CC)"
sendSubscribeMessageResponse := new(SendSubscribeMessageResponse)
err = SendSubscribeMessage(res.AccessToken, sendSubscribeMessageRequest, sendSubscribeMessageResponse)
if err != nil {
t.Error(err)
}
t.Logf("Errcode: %d", sendSubscribeMessageResponse.Errcode)
t.Logf("Errmsg: %s", sendSubscribeMessageResponse.Errmsg)
}

View File

@ -35,8 +35,8 @@ func newAppMessageLog(db *gorm.DB, opts ...gen.DOOption) appMessageLog {
_appMessageLog.ReceiverID = field.NewString(tableName, "receiver_id")
_appMessageLog.MsgType = field.NewInt32(tableName, "msg_type")
_appMessageLog.Content = field.NewString(tableName, "content")
_appMessageLog.IsRead = field.NewInt32(tableName, "is_read")
_appMessageLog.CreatedAt = field.NewTime(tableName, "created_at")
_appMessageLog.IsRead = field.NewInt32(tableName, "is_read")
_appMessageLog.fillFieldMap()
@ -56,8 +56,8 @@ type appMessageLog struct {
ReceiverID field.String // 接收人ID
MsgType field.Int32 // 消息类型(1:文本 2:图片)
Content field.String // 消息内容
IsRead field.Int32 // 是否已读(0:未读 1:已读)
CreatedAt field.Time // 创建时间
IsRead field.Int32 // 是否已读(0:未读 1:已读)
fieldMap map[string]field.Expr
}
@ -83,6 +83,7 @@ func (a *appMessageLog) updateTableName(table string) *appMessageLog {
a.MsgType = field.NewInt32(table, "msg_type")
a.Content = field.NewString(table, "content")
a.CreatedAt = field.NewTime(table, "created_at")
a.IsRead = field.NewInt32(table, "is_read")
a.fillFieldMap()
@ -108,8 +109,8 @@ func (a *appMessageLog) fillFieldMap() {
a.fieldMap["receiver_id"] = a.ReceiverID
a.fieldMap["msg_type"] = a.MsgType
a.fieldMap["content"] = a.Content
a.fieldMap["is_read"] = a.IsRead
a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["is_read"] = a.IsRead
}
func (a appMessageLog) clone(db *gorm.DB) appMessageLog {

View File

@ -25,6 +25,7 @@ var (
LogOperation *logOperation
LogRequest *logRequest
MiniProgram *miniProgram
MiniProgramAccessToken *miniProgramAccessToken
)
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
@ -37,6 +38,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
LogOperation = &Q.LogOperation
LogRequest = &Q.LogRequest
MiniProgram = &Q.MiniProgram
MiniProgramAccessToken = &Q.MiniProgramAccessToken
}
func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
@ -50,6 +52,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
LogOperation: newLogOperation(db, opts...),
LogRequest: newLogRequest(db, opts...),
MiniProgram: newMiniProgram(db, opts...),
MiniProgramAccessToken: newMiniProgramAccessToken(db, opts...),
}
}
@ -64,6 +67,7 @@ type Query struct {
LogOperation logOperation
LogRequest logRequest
MiniProgram miniProgram
MiniProgramAccessToken miniProgramAccessToken
}
func (q *Query) Available() bool { return q.db != nil }
@ -79,6 +83,7 @@ func (q *Query) clone(db *gorm.DB) *Query {
LogOperation: q.LogOperation.clone(db),
LogRequest: q.LogRequest.clone(db),
MiniProgram: q.MiniProgram.clone(db),
MiniProgramAccessToken: q.MiniProgramAccessToken.clone(db),
}
}
@ -101,6 +106,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
LogOperation: q.LogOperation.replaceDB(db),
LogRequest: q.LogRequest.replaceDB(db),
MiniProgram: q.MiniProgram.replaceDB(db),
MiniProgramAccessToken: q.MiniProgramAccessToken.replaceDB(db),
}
}
@ -113,6 +119,7 @@ type queryCtx struct {
LogOperation *logOperationDo
LogRequest *logRequestDo
MiniProgram *miniProgramDo
MiniProgramAccessToken *miniProgramAccessTokenDo
}
func (q *Query) WithContext(ctx context.Context) *queryCtx {
@ -125,16 +132,17 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
LogOperation: q.LogOperation.WithContext(ctx),
LogRequest: q.LogRequest.WithContext(ctx),
MiniProgram: q.MiniProgram.WithContext(ctx),
MiniProgramAccessToken: q.MiniProgramAccessToken.WithContext(ctx),
}
}
func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.ReplaceDB(tx)) }, opts...)
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
}
func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {
tx := q.db.Begin(opts...)
return &QueryTx{Query: q.ReplaceDB(tx), Error: tx.Error}
return &QueryTx{Query: q.clone(tx), Error: tx.Error}
}
type QueryTx struct {

View File

@ -0,0 +1,336 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dao
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"mini-chat/internal/repository/mysql/model"
)
func newMiniProgramAccessToken(db *gorm.DB, opts ...gen.DOOption) miniProgramAccessToken {
_miniProgramAccessToken := miniProgramAccessToken{}
_miniProgramAccessToken.miniProgramAccessTokenDo.UseDB(db, opts...)
_miniProgramAccessToken.miniProgramAccessTokenDo.UseModel(&model.MiniProgramAccessToken{})
tableName := _miniProgramAccessToken.miniProgramAccessTokenDo.TableName()
_miniProgramAccessToken.ALL = field.NewAsterisk(tableName)
_miniProgramAccessToken.ID = field.NewInt32(tableName, "id")
_miniProgramAccessToken.AppID = field.NewString(tableName, "app_id")
_miniProgramAccessToken.AccessToken = field.NewString(tableName, "access_token")
_miniProgramAccessToken.CreatedAt = field.NewTime(tableName, "created_at")
_miniProgramAccessToken.ExpiredAt = field.NewTime(tableName, "expired_at")
_miniProgramAccessToken.fillFieldMap()
return _miniProgramAccessToken
}
// miniProgramAccessToken 小程序 access_token 表
type miniProgramAccessToken struct {
miniProgramAccessTokenDo
ALL field.Asterisk
ID field.Int32 // 主键
AppID field.String // app_id
AccessToken field.String // access_token
CreatedAt field.Time // 创建时间
ExpiredAt field.Time // 过期时间
fieldMap map[string]field.Expr
}
func (m miniProgramAccessToken) Table(newTableName string) *miniProgramAccessToken {
m.miniProgramAccessTokenDo.UseTable(newTableName)
return m.updateTableName(newTableName)
}
func (m miniProgramAccessToken) As(alias string) *miniProgramAccessToken {
m.miniProgramAccessTokenDo.DO = *(m.miniProgramAccessTokenDo.As(alias).(*gen.DO))
return m.updateTableName(alias)
}
func (m *miniProgramAccessToken) updateTableName(table string) *miniProgramAccessToken {
m.ALL = field.NewAsterisk(table)
m.ID = field.NewInt32(table, "id")
m.AppID = field.NewString(table, "app_id")
m.AccessToken = field.NewString(table, "access_token")
m.CreatedAt = field.NewTime(table, "created_at")
m.ExpiredAt = field.NewTime(table, "expired_at")
m.fillFieldMap()
return m
}
func (m *miniProgramAccessToken) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := m.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (m *miniProgramAccessToken) fillFieldMap() {
m.fieldMap = make(map[string]field.Expr, 5)
m.fieldMap["id"] = m.ID
m.fieldMap["app_id"] = m.AppID
m.fieldMap["access_token"] = m.AccessToken
m.fieldMap["created_at"] = m.CreatedAt
m.fieldMap["expired_at"] = m.ExpiredAt
}
func (m miniProgramAccessToken) clone(db *gorm.DB) miniProgramAccessToken {
m.miniProgramAccessTokenDo.ReplaceConnPool(db.Statement.ConnPool)
return m
}
func (m miniProgramAccessToken) replaceDB(db *gorm.DB) miniProgramAccessToken {
m.miniProgramAccessTokenDo.ReplaceDB(db)
return m
}
type miniProgramAccessTokenDo struct{ gen.DO }
func (m miniProgramAccessTokenDo) Debug() *miniProgramAccessTokenDo {
return m.withDO(m.DO.Debug())
}
func (m miniProgramAccessTokenDo) WithContext(ctx context.Context) *miniProgramAccessTokenDo {
return m.withDO(m.DO.WithContext(ctx))
}
func (m miniProgramAccessTokenDo) ReadDB() *miniProgramAccessTokenDo {
return m.Clauses(dbresolver.Read)
}
func (m miniProgramAccessTokenDo) WriteDB() *miniProgramAccessTokenDo {
return m.Clauses(dbresolver.Write)
}
func (m miniProgramAccessTokenDo) Session(config *gorm.Session) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Session(config))
}
func (m miniProgramAccessTokenDo) Clauses(conds ...clause.Expression) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Clauses(conds...))
}
func (m miniProgramAccessTokenDo) Returning(value interface{}, columns ...string) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Returning(value, columns...))
}
func (m miniProgramAccessTokenDo) Not(conds ...gen.Condition) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Not(conds...))
}
func (m miniProgramAccessTokenDo) Or(conds ...gen.Condition) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Or(conds...))
}
func (m miniProgramAccessTokenDo) Select(conds ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Select(conds...))
}
func (m miniProgramAccessTokenDo) Where(conds ...gen.Condition) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Where(conds...))
}
func (m miniProgramAccessTokenDo) Order(conds ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Order(conds...))
}
func (m miniProgramAccessTokenDo) Distinct(cols ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Distinct(cols...))
}
func (m miniProgramAccessTokenDo) Omit(cols ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Omit(cols...))
}
func (m miniProgramAccessTokenDo) Join(table schema.Tabler, on ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Join(table, on...))
}
func (m miniProgramAccessTokenDo) LeftJoin(table schema.Tabler, on ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.LeftJoin(table, on...))
}
func (m miniProgramAccessTokenDo) RightJoin(table schema.Tabler, on ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.RightJoin(table, on...))
}
func (m miniProgramAccessTokenDo) Group(cols ...field.Expr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Group(cols...))
}
func (m miniProgramAccessTokenDo) Having(conds ...gen.Condition) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Having(conds...))
}
func (m miniProgramAccessTokenDo) Limit(limit int) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Limit(limit))
}
func (m miniProgramAccessTokenDo) Offset(offset int) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Offset(offset))
}
func (m miniProgramAccessTokenDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Scopes(funcs...))
}
func (m miniProgramAccessTokenDo) Unscoped() *miniProgramAccessTokenDo {
return m.withDO(m.DO.Unscoped())
}
func (m miniProgramAccessTokenDo) Create(values ...*model.MiniProgramAccessToken) error {
if len(values) == 0 {
return nil
}
return m.DO.Create(values)
}
func (m miniProgramAccessTokenDo) CreateInBatches(values []*model.MiniProgramAccessToken, batchSize int) error {
return m.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (m miniProgramAccessTokenDo) Save(values ...*model.MiniProgramAccessToken) error {
if len(values) == 0 {
return nil
}
return m.DO.Save(values)
}
func (m miniProgramAccessTokenDo) First() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) Take() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) Last() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) Find() ([]*model.MiniProgramAccessToken, error) {
result, err := m.DO.Find()
return result.([]*model.MiniProgramAccessToken), err
}
func (m miniProgramAccessTokenDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.MiniProgramAccessToken, err error) {
buf := make([]*model.MiniProgramAccessToken, 0, batchSize)
err = m.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (m miniProgramAccessTokenDo) FindInBatches(result *[]*model.MiniProgramAccessToken, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return m.DO.FindInBatches(result, batchSize, fc)
}
func (m miniProgramAccessTokenDo) Attrs(attrs ...field.AssignExpr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Attrs(attrs...))
}
func (m miniProgramAccessTokenDo) Assign(attrs ...field.AssignExpr) *miniProgramAccessTokenDo {
return m.withDO(m.DO.Assign(attrs...))
}
func (m miniProgramAccessTokenDo) Joins(fields ...field.RelationField) *miniProgramAccessTokenDo {
for _, _f := range fields {
m = *m.withDO(m.DO.Joins(_f))
}
return &m
}
func (m miniProgramAccessTokenDo) Preload(fields ...field.RelationField) *miniProgramAccessTokenDo {
for _, _f := range fields {
m = *m.withDO(m.DO.Preload(_f))
}
return &m
}
func (m miniProgramAccessTokenDo) FirstOrInit() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) FirstOrCreate() (*model.MiniProgramAccessToken, error) {
if result, err := m.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.MiniProgramAccessToken), nil
}
}
func (m miniProgramAccessTokenDo) FindByPage(offset int, limit int) (result []*model.MiniProgramAccessToken, count int64, err error) {
result, err = m.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = m.Offset(-1).Limit(-1).Count()
return
}
func (m miniProgramAccessTokenDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = m.Count()
if err != nil {
return
}
err = m.Offset(offset).Limit(limit).Scan(result)
return
}
func (m miniProgramAccessTokenDo) Scan(result interface{}) (err error) {
return m.DO.Scan(result)
}
func (m miniProgramAccessTokenDo) Delete(models ...*model.MiniProgramAccessToken) (result gen.ResultInfo, err error) {
return m.DO.Delete(models)
}
func (m *miniProgramAccessTokenDo) withDO(do gen.Dao) *miniProgramAccessTokenDo {
m.DO = *do.(*gen.DO)
return m
}

View File

@ -20,8 +20,8 @@ type AppMessageLog struct {
ReceiverID string `gorm:"column:receiver_id;not null;comment:接收人ID" json:"receiver_id"` // 接收人ID
MsgType int32 `gorm:"column:msg_type;not null;comment:消息类型(1:文本 2:图片)" json:"msg_type"` // 消息类型(1:文本 2:图片)
Content string `gorm:"column:content;not null;comment:消息内容" json:"content"` // 消息内容
IsRead int32 `gorm:"column:is_read;not null;default:0;comment:是否已读(0:未读 1:已读)" json:"is_read"` // 是否已读(0:未读 1:已读)
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
IsRead int32 `gorm:"column:is_read;comment:是否已读(0:未读 1:已读)" json:"is_read"` // 是否已读(0:未读 1:已读)
}
// TableName AppMessageLog's table name

View File

@ -0,0 +1,25 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"time"
)
const TableNameMiniProgramAccessToken = "mini_program_access_token"
// MiniProgramAccessToken 小程序 access_token 表
type MiniProgramAccessToken struct {
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键
AppID string `gorm:"column:app_id;not null;comment:app_id" json:"app_id"` // app_id
AccessToken string `gorm:"column:access_token;not null;comment:access_token" json:"access_token"` // access_token
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
ExpiredAt time.Time `gorm:"column:expired_at;not null;default:CURRENT_TIMESTAMP;comment:过期时间" json:"expired_at"` // 过期时间
}
// TableName MiniProgramAccessToken's table name
func (*MiniProgramAccessToken) TableName() string {
return TableNameMiniProgramAccessToken
}

View File

@ -0,0 +1,32 @@
package services_miniprogram
import (
"mini-chat/internal/pkg/core"
"mini-chat/internal/pkg/logger"
"mini-chat/internal/repository/mysql"
"mini-chat/internal/repository/mysql/dao"
)
var _ Service = (*service)(nil)
type Service interface {
i()
GetAccessToken(appID, appSecret string, ctx core.Context) (string, error)
}
type service struct {
logger logger.CustomLogger
writeDB *dao.Query
readDB *dao.Query
}
func New(logger logger.CustomLogger, db mysql.Repo) Service {
return &service{
logger: logger,
writeDB: dao.Use(db.GetDbW()),
readDB: dao.Use(db.GetDbR()),
}
}
func (s *service) i() {}

View File

@ -0,0 +1,53 @@
package services_miniprogram
import (
"fmt"
"time"
"mini-chat/internal/pkg/core"
"mini-chat/internal/pkg/miniprogram"
"mini-chat/internal/repository/mysql/model"
"go.uber.org/zap"
"gorm.io/gorm"
)
func (s *service) GetAccessToken(appID, appSecret string, ctx core.Context) (string, error) {
info, err := s.readDB.MiniProgramAccessToken.WithContext(ctx.RequestContext()).
Where(s.readDB.MiniProgramAccessToken.AppID.Eq(appID)).
Where(s.readDB.MiniProgramAccessToken.ExpiredAt.Gte(time.Now())).First()
if err != nil && err != gorm.ErrRecordNotFound {
return "", err
}
accessToken := ""
if err == gorm.ErrRecordNotFound {
// 生成 access_token
accessTokenResponse := new(miniprogram.AccessTokenResponse)
if err := miniprogram.GetAccessToken(appID, appSecret, accessTokenResponse); err != nil {
s.logger.Error("GetAccessToken failed", zap.Error(err))
return "", err
}
if accessTokenResponse.AccessToken == "" {
return "", fmt.Errorf("access_token is empty")
}
// 保存 access_token
accessTokenData := new(model.MiniProgramAccessToken)
accessTokenData.AppID = appID
accessTokenData.AccessToken = accessTokenResponse.AccessToken
accessTokenData.CreatedAt = time.Now()
accessTokenData.ExpiredAt = time.Now().Add(time.Duration(accessTokenResponse.ExpiresIn) * time.Second)
if err := s.writeDB.MiniProgramAccessToken.WithContext(ctx.RequestContext()).Create(accessTokenData); err != nil {
return "", err
}
accessToken = accessTokenResponse.AccessToken
} else {
accessToken = info.AccessToken
}
return accessToken, nil
}