Skip to content

Commit

Permalink
feat(oauth): 增加oauth2授权相关API
Browse files Browse the repository at this point in the history
  • Loading branch information
bububa committed Feb 26, 2024
1 parent 20ad672 commit 9fe2e7e
Show file tree
Hide file tree
Showing 48 changed files with 1,305 additions and 54 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,24 @@

## API

- Oauth2.0授权(api/oauth)
- 获取授权链接 [ URL(ctx context.Context, clt *core.SDKClient, req *oauth.URLRequest) string ]
- 获取token [ AccessToken(ctx context.Context, clt *core.SDKClient, req *oauth.AccessTokenRequest) (*oauth.AccessToken, error) ]
- 刷新token [ RefreshToken(ctx context.Context, clt *core.SDKClient, req *oauth.RefreshTokenRequest) (*oauth.AccessToken, error) ]

- 账户服务
- 广告主(api/advertiser)
- 获取账号余额接口 [ BalanceInfo(ctx context.Context, clt *core.SDKClient, req *advertiser.BalanceInfoRequest, accessToken string) (*advertiser.Balance, error) ]

- 广告投放
- 广告单元(api/unit)
- 获取单元列表接口 [ List(ctx context.Context, clt *core.SDKClient, req *unit.ListRequest, accessToken string) (*unit.ListResult, error) ]

- 数据报表
- 实时报表(api/report/realtime)
- 账户层级实时数据 [ Advertiser(ctx context.Context, clt *core.SDKClient, req *realtime.AdvertiserRequest, accessToken string) (*report.Metric, error) ]

- 转化追踪(api/conversion)
- 生成点击监测链接 [ ClickMonitorLink(ctx context.Context, req string) (string, error) ]
- 转化回传 [ Conversion(ctx context.Context, clt *core.SDKClient, req *conversion.Request) error ]
- 生成点击监测链接 [ ClickMonitorLink(ctx context.Context, clt *core.SDKClient, req string) (string, error) ]
- 转化回传 [ Conversion(ctx context.Context, clt *core.SDKClient, req *conversion.Request, accessToken string) error ]

17 changes: 17 additions & 0 deletions api/advertiser/balance_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package advertiser

import (
"context"

"github.com/bububa/spotlight-mapi/core"
"github.com/bububa/spotlight-mapi/model/advertiser"
)

// BalanceInfo 获取账号余额接口
func BalanceInfo(ctx context.Context, clt *core.SDKClient, req *advertiser.BalanceInfoRequest, accessToken string) (*advertiser.Balance, error) {
var resp advertiser.BalanceInfoResponse
if err := clt.Get(ctx, "/jg/account/balance/info", req, &resp, accessToken); err != nil {
return nil, err
}
return resp.Data, nil
}
2 changes: 2 additions & 0 deletions api/advertiser/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package advertiser 广告主相关
package advertiser
5 changes: 3 additions & 2 deletions api/conversion/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
// 回传您通过小红书获得的转化信息,我们可以提供如下服务:
// 1.展现回传事件的统计信息,例如回传”商品成单“时间,我们会by计划/创意等维度呈现订单量、订单成本、转化率等指标
// 2.数据进入您的广告模型,优化您的广告效果。
func Conversion(ctx context.Context, clt *core.SDKClient, req *conversion.Request) error {
return clt.Post(ctx, "/conversion", req, nil, "")
func Conversion(ctx context.Context, clt *core.SDKClient, req *conversion.Request, accessToken string) error {
req.AppID = clt.AppID()
return clt.Post(ctx, "/conversion", req, nil, accessToken)
}
20 changes: 20 additions & 0 deletions api/oauth/access_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package oauth

import (
"context"

"github.com/bububa/spotlight-mapi/core"
"github.com/bububa/spotlight-mapi/model/oauth"
)

// AccessToken 获取Token
// 利用授权码 auth_code,请求小红书服务器,获取 access_token 和 refresh_token 及当前账户的广告主 ID。
func AccessToken(ctx context.Context, clt *core.SDKClient, req *oauth.AccessTokenRequest) (*oauth.AccessToken, error) {
req.AppID = clt.AppID()
req.Secret = clt.Secret()
var resp oauth.AccessTokenResponse
if err := clt.Post(ctx, "/oauth2/access_token", req, &resp, ""); err != nil {
return nil, err
}
return resp.Data, nil
}
2 changes: 2 additions & 0 deletions api/oauth/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package oauth 授权相关
package oauth
20 changes: 20 additions & 0 deletions api/oauth/refresh_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package oauth

import (
"context"

"github.com/bububa/spotlight-mapi/core"
"github.com/bububa/spotlight-mapi/model/oauth"
)

// RefreshToken 刷新Token
// 请求小红书服务器,刷新 access_token 和 refresh_token 及 token 过期时间。
func RefreshToken(ctx context.Context, clt *core.SDKClient, req *oauth.RefreshTokenRequest) (*oauth.AccessToken, error) {
req.AppID = clt.AppID()
req.Secret = clt.Secret()
var resp oauth.AccessTokenResponse
if err := clt.Post(ctx, "/oauth2/refresh_token", req, &resp, ""); err != nil {
return nil, err
}
return resp.Data, nil
}
15 changes: 15 additions & 0 deletions api/oauth/url.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package oauth

import (
"context"

"github.com/bububa/spotlight-mapi/core"
"github.com/bububa/spotlight-mapi/model/oauth"
"github.com/bububa/spotlight-mapi/util"
)

// URL 生成oauth授权链接
func URL(ctx context.Context, clt *core.SDKClient, req *oauth.URLRequest) string {
req.AppID = clt.AppID()
return util.StringsJoin(core.OAUTH_URL, "?", req.Encode())
}
2 changes: 2 additions & 0 deletions api/report/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package report 报表相关
package report
18 changes: 18 additions & 0 deletions api/report/realtime/advertiser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package realtime

import (
"context"

"github.com/bububa/spotlight-mapi/core"
"github.com/bububa/spotlight-mapi/model/report"
"github.com/bububa/spotlight-mapi/model/report/realtime"
)

// Advertiser 账户层级实时数据
func Advertiser(ctx context.Context, clt *core.SDKClient, req *realtime.AdvertiserRequest, accessToken string) (*report.Metric, error) {
var resp realtime.AdvertiserResponse
if err := clt.Post(ctx, "/jg/data/report/realtime/account", req, &resp, accessToken); err != nil {
return nil, err
}
return resp.Data, nil
}
3 changes: 3 additions & 0 deletions api/report/realtime/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package realtime 实时报表
package realtime

2 changes: 2 additions & 0 deletions api/unit/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package unit 广告单元相关
package unit
17 changes: 17 additions & 0 deletions api/unit/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package unit

import (
"context"

"github.com/bububa/spotlight-mapi/core"
"github.com/bububa/spotlight-mapi/model/unit"
)

// List 获取单元列表接口
func List(ctx context.Context, clt *core.SDKClient, req *unit.ListRequest, accessToken string) (*unit.ListResult, error) {
var resp unit.ListResponse
if err := clt.Post(ctx, "/jg/unit/list", req, &resp, accessToken); err != nil {
return nil, err
}
return resp.Data, nil
}
52 changes: 26 additions & 26 deletions core/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ import (

// SDKClient sdk client
type SDKClient struct {
AppID string
AccessToken string
debug bool
sandbox bool
limiter RateLimiter
client *http.Client
appID string
secret string
debug bool
sandbox bool
limiter RateLimiter
client *http.Client
}

// NewSDKClient 创建SDKClient
func NewSDKClient(appID string, accessToken string) *SDKClient {
func NewSDKClient(appID string, secret string) *SDKClient {
return &SDKClient{
AppID: appID,
AccessToken: accessToken,
client: http.DefaultClient,
appID: appID,
secret: secret,
client: http.DefaultClient,
}
}

Expand Down Expand Up @@ -58,20 +58,27 @@ func (c *SDKClient) SetRateLimiter(limiter RateLimiter) {
c.limiter = limiter
}

func (c *SDKClient) AppID() string {
return c.appID
}

func (c *SDKClient) Secret() string {
return c.secret
}

// Copy 复制SDKClient
func (c *SDKClient) Copy() *SDKClient {
return &SDKClient{
AppID: c.AppID,
AccessToken: c.AccessToken,
debug: c.debug,
sandbox: c.sandbox,
client: c.client,
appID: c.appID,
secret: c.secret,
debug: c.debug,
sandbox: c.sandbox,
client: c.client,
}
}

// Post post api
func (c *SDKClient) Post(ctx context.Context, gw string, req model.PostRequest, resp model.Response, accessToken string) error {
req.SetApp(c.AppID, c.AccessToken)
var reqBytes []byte
if req != nil {
reqBytes = req.Encode()
Expand Down Expand Up @@ -102,7 +109,6 @@ func (c *SDKClient) Post(ctx context.Context, gw string, req model.PostRequest,

// Get get api
func (c *SDKClient) Get(ctx context.Context, gw string, req model.GetRequest, resp model.Response, accessToken string) error {
req.SetApp(c.AppID, c.AccessToken)
var reqUrl string
if strings.HasPrefix(gw, "https://") {
reqUrl = gw
Expand Down Expand Up @@ -131,7 +137,6 @@ func (c *SDKClient) Get(ctx context.Context, gw string, req model.GetRequest, re

// GetBytes get bytes api
func (c *SDKClient) GetBytes(ctx context.Context, gw string, req model.GetRequest, accessToken string) ([]byte, error) {
req.SetApp(c.AppID, c.AccessToken)
var reqUrl string
if strings.HasPrefix(gw, "https://") {
reqUrl = gw
Expand Down Expand Up @@ -165,9 +170,8 @@ func (c *SDKClient) GetBytes(ctx context.Context, gw string, req model.GetReques

// Upload multipart/form-data post
func (c *SDKClient) Upload(ctx context.Context, gw string, req model.UploadRequest, resp model.Response, accessToken string) error {
req.SetApp(c.AppID, c.AccessToken)
buf := util.GetBufferPool()
defer util.PutBufferPool(buf)
buf := util.NewBufferPool()
defer util.ReleaseBufferPool(buf)
mw := multipart.NewWriter(buf)
params := req.Encode()
mp := make(map[string]string, len(params))
Expand All @@ -182,11 +186,7 @@ func (c *SDKClient) Upload(ctx context.Context, gw string, req model.UploadReque
return err
}
r = v.Reader
builder := util.GetStringsBuilder()
builder.WriteString("@")
builder.WriteString(v.Value)
mp[v.Key] = builder.String()
util.PutStringsBuilder(builder)
mp[v.Key] = util.StringsJoin("@", v.Value)
} else {
if fw, err = mw.CreateFormField(v.Key); err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions core/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ const (
BASE_URL = "https://adapi.xiaohongshu.com/api/open"
// CONVERSION_URL 转化回传API gateway
CONVERSION_URL = "https://adapi.xiaohongshu.com/api/open/conversion"
// OAUTH_URL oauth授权 gateway
OAUTH_URL = "https://ad.xiaohongshu.com/aurora/openApiAuth"
)
12 changes: 6 additions & 6 deletions core/internal/debug/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ func PrintPostJSONRequest(url string, body []byte, debug bool) {
const format = "[DEBUG] [API] JSON POST %s\n" +
"http request body:\n%s\n"

buf := util.GetBufferPool()
defer util.PutBufferPool(buf)
buf := util.NewBufferPool()
defer util.ReleaseBufferPool(buf)
json.Indent(buf, body, "", " ")
log.Printf(format, url, buf.String())
}
Expand All @@ -58,8 +58,8 @@ func PrintJSONRequest(method string, url string, header http.Header, body []byte
"http request header:\n%s\n" +
"http request body:\n%s\n"

buf := util.GetBufferPool()
defer util.PutBufferPool(buf)
buf := util.NewBufferPool()
defer util.ReleaseBufferPool(buf)
json.Indent(buf, body, "", "\t")
headers := make([]string, 0, len(header))
for k := range header {
Expand All @@ -83,8 +83,8 @@ func PrintPostMultipartRequest(url string, mp map[string]string, debug bool) {

// DecodeJSONHttpResponse decode json response with debug
func DecodeJSONHttpResponse(r io.Reader, v interface{}, debug bool) ([]byte, error) {
buf := util.GetBufferPool()
defer util.PutBufferPool(buf)
buf := util.NewBufferPool()
defer util.ReleaseBufferPool(buf)
tee := io.TeeReader(r, buf)
if err := json.NewDecoder(tee).Decode(v); err != nil {
return buf.Bytes(), err
Expand Down
11 changes: 11 additions & 0 deletions enum/approval_role_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package enum

// ApprovalRoleType 授权账号类型
type ApprovalRoleType int

const (
// ApprovalRoleType_BRAND 品牌
ApprovalRoleType_BRAND ApprovalRoleType = 4
// ApprovalRoleType_AGENCY 代理商
ApprovalRoleType_AGENCY ApprovalRoleType = 601
)
9 changes: 9 additions & 0 deletions enum/crowd_action_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package enum

// CrowdActionType 行为类型
type CrowdActionType string

const (
CrowdActionType_IMP CrowdActionType = "imp"
CrowdActionType_READ CrowdActionType = "read"
)
14 changes: 14 additions & 0 deletions enum/developer_role_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package enum

// DeveloperRoleType 应用角色类型
type DeveloperRoleType int

const (

// DeveloperRoleType_BRAND 品牌开发者
DeveloperRoleType_BRAND DeveloperRoleType = 1
// DeveloperRoleType_AGENCY 代理商开发者,
DeveloperRoleType_AGENCY DeveloperRoleType = 2
// DeveloperRoleType_SERVICE_PROVIDER 服务商开发者
DeveloperRoleType_SERVICE_PROVIDER DeveloperRoleType = 3
)
15 changes: 15 additions & 0 deletions enum/keyword_gen_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package enum

// KeywordGenType 单元选词方式
type KeywordGenType int

const (
// KeywordGenType_UNSPECIFIED 无意义默认值
KeywordGenType_UNSPECIFIED KeywordGenType = -1
// KeywordGenType_MANUAL 手动选词
KeywordGenType_MANUAL KeywordGenType = 0
// KeywordGenType_INTELLIGENT 智能拓词
KeywordGenType_INTELLIGENT KeywordGenType = 1
// KeywordGenType_MANUAL_INTELLIGENT 手动+智能
KeywordGenType_MANUAL_INTELLIGENT KeywordGenType = 2
)
13 changes: 13 additions & 0 deletions enum/keyword_target_action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package enum

// KeywordTargetAction 关键词定向行为
type KeywordTargetAction int

const (
// KeywordTargetAction_SEARCH 搜索
KeywordTargetAction_SEARCH KeywordTargetAction = 1
// KeywordTargetAction_INTERACTIVE 互动
KeywordTargetAction_INTERACTIVE KeywordTargetAction = 2
// KeywordTargetAction_READ 阅读
KeywordTargetAction_READ KeywordTargetAction = 3
)
13 changes: 13 additions & 0 deletions enum/landing_page_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package enum

// LandingPageType 落地页链接类型
type LandingPageType int

const (
// LandingPageTYpe_UNSPECIFIED 默认值,无实际意义
LandingPageType_UNSPECIFIED LandingPageType = 0
// LandingPageType_FORM 表单
LandingPageType_FORM LandingPageType = 1
// LandingPageType_LINK 外跳链接
LandingPageType_LINK LandingPageType = 2
)

0 comments on commit 9fe2e7e

Please sign in to comment.