Skip to content

Commit

Permalink
feat(conversion): 增加回传路径
Browse files Browse the repository at this point in the history
  • Loading branch information
bububa committed Feb 28, 2024
1 parent 732335f commit f0ee5ee
Show file tree
Hide file tree
Showing 18 changed files with 280 additions and 44 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

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

- 广告投放
Expand All @@ -40,5 +41,11 @@

- 转化追踪(api/conversion)
- 生成点击监测链接 [ ClickMonitorLink(ctx context.Context, clt *core.SDKClient, req string) (string, error) ]
- 转化回传 [ Conversion(ctx context.Context, clt *core.SDKClient, req *conversion.Request, accessToken string) error ]
- 外链落地页
- 外链线索数据回传 [ Conversion(ctx context.Context, clt *core.SDKClient, req *conversion.Request, accessToken string) error ]
- 线索转化数据回传 [ AuroraLeads(ctx context.Context, clt *core.SDKClient, req *conversion.AuroraLeadsRequest) error ]
- 聚光落地页
- 聚光落地页线索数据回传 [ HawkingLeads(ctx context.Context, clt *core.SDKClient, req *conversion.HawkingLeadsRequest) error ]
- 口令码
- APP口令码数据回传 [ App(ctx context.Context, clt *core.SDKClient, req *conversion.AppRequest) error ]

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

import (
"context"

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

// AccessToken 获取accessToken
func AccessToken(ctx context.Context, clt *core.SDKClient, advertiserID uint64) (*oauth.AccessToken, error) {
req := model.CommonRequest{
AdvertiserID: advertiserID,
Method: "oauth.getAccessToken",
}
var ret oauth.AccessTokenResponse
if err := clt.Post(ctx, "/common", req, &ret, ""); err != nil {
return nil, err
}
return ret.Data, nil
}
13 changes: 13 additions & 0 deletions api/conversion/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package conversion

import (
"context"

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

// App APP口令码数据回传
func App(ctx context.Context, clt *core.SDKClient, req *conversion.AppRequest) error {
return clt.Post(ctx, "/app", req, nil, "")
}
13 changes: 13 additions & 0 deletions api/conversion/aurora_leads.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package conversion

import (
"context"

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

// AuroraLeads 线索转化数据回传
func AuroraLeads(ctx context.Context, clt *core.SDKClient, req *conversion.AuroraLeadsRequest) error {
return clt.Post(ctx, "/common", req, nil, "")
}
4 changes: 2 additions & 2 deletions api/conversion/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
// 回传您通过小红书获得的转化信息,我们可以提供如下服务:
// 1.展现回传事件的统计信息,例如回传”商品成单“时间,我们会by计划/创意等维度呈现订单量、订单成本、转化率等指标
// 2.数据进入您的广告模型,优化您的广告效果。
func Conversion(ctx context.Context, clt *core.SDKClient, req *conversion.Request, accessToken string) error {
func Conversion(ctx context.Context, clt *core.SDKClient, req *conversion.Request) error {
req.AppID = clt.AppID()
return clt.Post(ctx, "/conversion", req, nil, accessToken)
return clt.Post(ctx, "/conversion", req, nil, "")
}
13 changes: 13 additions & 0 deletions api/conversion/hawking_leads.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package conversion

import (
"context"

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

// HawkingLeads 聚光落地页线索数据回传
func HawkingLeads(ctx context.Context, clt *core.SDKClient, req *conversion.HawkingLeadsRequest) error {
return clt.PostHawkingLeads(ctx, req)
}
54 changes: 21 additions & 33 deletions core/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,39 +135,6 @@ func (c *SDKClient) Get(ctx context.Context, gw string, req model.GetRequest, re
return c.fetch(ctx, httpReq, resp)
}

// GetBytes get bytes api
func (c *SDKClient) GetBytes(ctx context.Context, gw string, req model.GetRequest, accessToken string) ([]byte, error) {
var reqUrl string
if strings.HasPrefix(gw, "https://") {
reqUrl = gw
} else {
reqUrl = util.StringsJoin(BASE_URL, gw)
}
if req != nil {
reqUrl = util.StringsJoin(reqUrl, "?", req.Encode())
}
debug.PrintGetRequest(reqUrl, c.debug)
httpReq, err := http.NewRequest("GET", reqUrl, nil)
if err != nil {
return nil, err
}
if accessToken != "" {
httpReq.Header.Add("Access-Token", accessToken)
}
if c.sandbox {
httpReq.Header.Add("X-Debug-Mode", "1")
}
if c.limiter != nil {
c.limiter.Take()
}
httpResp, err := c.client.Do(httpReq)
if err != nil {
return nil, err
}
defer httpResp.Body.Close()
return io.ReadAll(httpResp.Body)
}

// Upload multipart/form-data post
func (c *SDKClient) Upload(ctx context.Context, gw string, req model.UploadRequest, resp model.Response, accessToken string) error {
buf := util.NewBufferPool()
Expand Down Expand Up @@ -223,6 +190,27 @@ func (c *SDKClient) Upload(ctx context.Context, gw string, req model.UploadReque
return c.fetch(ctx, httpReq, resp)
}

// PostHawkingLeads
func (c *SDKClient) PostHawkingLeads(ctx context.Context, req model.PostRequest) error {
var reqBytes []byte
if req != nil {
reqBytes = req.Encode()
}
httpReq, err := http.NewRequest("POST", HAWKLING_LEADS_URL, bytes.NewReader(reqBytes))
if err != nil {
return err
}
httpReq.Header.Add("Content-Type", "application/json")
if c.sandbox {
httpReq.Header.Add("X-Debug-Mode", "1")
}
if c.limiter != nil {
c.limiter.Take()
}
debug.PrintJSONRequest("POST", HAWKLING_LEADS_URL, httpReq.Header, reqBytes, c.debug)
return c.fetch(ctx, httpReq, nil)
}

// fetch execute http request
func (c *SDKClient) fetch(ctx context.Context, httpReq *http.Request, resp model.Response) error {
httpReq = httpReq.WithContext(ctx)
Expand Down
6 changes: 3 additions & 3 deletions core/const.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package core

const (
// BASE_URL 默认APIgateway
// BASE_URL 默认API gateway
BASE_URL = "https://adapi.xiaohongshu.com/api/open"
// CONVERSION_URL 转化回传API gateway
CONVERSION_URL = "https://adapi.xiaohongshu.com/api/open/conversion"
// HAWKLING_LEADS_URL 聚光落地页线索数据回传API gateway
HAWKLING_LEADS_URL = "http://www.xiaohongshu.com/api/hawking/leads/return"
// OAUTH_URL oauth授权 gateway
OAUTH_URL = "https://ad.xiaohongshu.com/aurora/openApiAuth"
)
26 changes: 25 additions & 1 deletion enum/event_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,34 @@ const (
EventType_PAGE_VIEW EventType = 2
// EventType_PAGE_CLICK 中间页点击
EventType_PAGE_CLICK EventType = 3
// EventType_WECHAT_FOLLOW 微信加好友
// EventType_FORM_SUBMIT 表单提交; 用户在页面内完成表单填写并提交,可以作为优化目标
EventType_FORM_SUBMIT EventType = 101
// EventType_FORM_EFFICIENT 有效表单; 提交线索的用户进一步完成了一次有价值的行为,具体行为取决于广告主业务模式,如预约到店等
EventType_FORM_EFFICIENT EventType = 102
// EventType_PHONE_CALL 电话拨打; 用户点击给商家拨打电话,可以作为优化目标
EventType_PHONE_CALL EventType = 103
// EventType_PHONE_EFFECIENT 电话接通; 商家给用户拨打电话,可接通
EventType_PHONE_EFFECIENT EventType = 104
// EventType_WECHAT_COPY 微信复制; 用户完成个人或公众号微信复制行为,引导用户微信加粉,可以作为优化目标
EventType_WECHAT_COPY EventType = 121
// EventType_WECHAT_FOLLOW 微信加好友; 用户完成个人或公众号微信加粉
EventType_WECHAT_FOLLOW EventType = 122
// EventType_REGISTER 注册
EventType_REGISTER EventType = 123
// EventType_WECHAT_MINIAPP 微信小程序访问
EventType_WECHAT_MINIAPP EventType = 124
// EventType_IDCERT 身份认证; 用户完成身份认证,比如金融类可能会用身份证号、人脸识别做身份认证
EventType_IDCERT EventType = 131
// EventType_PURCHASE 付费; 用户完成商品购买行为,可以作为优化目标
EventType_PURCHASE EventType = 141
// EventType_NEGATIVE 负向样本; 不可直接作为广告的优化目标使用,但回传后将有利于优化整体广告效果
EventType_NEGATIVE EventType = 200
// EventType_APP_OPEN APP打开; APP端内口令码搜索
EventType_APP_OPEN EventType = 401
// EventType_APP_ENTER_SHOP APP进店; 平台客户内店铺详情页浏览量
EventType_APP_ENTER_SHOP EventType = 402
// EventType_APP_INTERACT APP互动; 店铺内产生互动行为(用户明确表达转化意愿)
EventType_APP_INTERACT EventType = 403
// EventType_APP_PAY APP支付; 线上订单付款成功
EventType_APP_PAY EventType = 404
)
4 changes: 4 additions & 0 deletions model/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ func (u64 JSONUint64) Value() uint64 {
return uint64(u64)
}

func (u64 JSONUint64) String() string {
return strconv.FormatUint(u64.Value(), 10)
}

// Int64 support string quoted number in json
type Int64 int64

Expand Down
50 changes: 50 additions & 0 deletions model/conversion/app_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package conversion

import (
"strconv"
"time"

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

// AppRequest APP口令码数据回传 API Request
type AppRequest struct {
// AdvertiserID 广告主id
AdvertiserID model.JSONUint64 `json:"advertiser_id,omitempty"`
// Version 接口版本, 固定为"1.0"
Version string `json:"version,omitempty"`
// Timestamp 当前时间戳, 时间戳格式,毫秒
Timestamp int64 `json:"timestamp,omitempty"`
// OaidMd5 安卓广告标识符, 高版本,32位大写md5加密
OaidMd5 string `json:"oaid_md5,omitempty"`
// CaidMd5 苹果广告标识符(20230330版), 高版本,32位大写md5加密
CaidMd5 string `json:"caid_md5,omitempty"`
// TokenCode 口令码
TokenCode string `json:"token_code,omitempty"`
// EventType 转化事件类型id
EventType enum.EventType `json:"event_type,omitempty"`
// ConvTime 转化事件发生时间
ConvTime int64 `json:"conv_time,omitempty"`
// ReportSource 数据来源
ReportSource string `json:"report_source,omitempty"`
// ForTest 是否是联调环境
ForTest bool `json:"for_test,omitempty"`
// AccessToken access_token
AccessToken string `json:"access_token,omitempty"`
// Sign 签名
Sign string `json:"sign,omitempty"`
}

// Encode implement PostRequest interface
func (r AppRequest) Encode() []byte {
r.Timestamp = time.Now().UnixMilli()
r.Sign = r.sign()
return util.JSONMarshal(r)
}

func (r AppRequest) sign() string {
raw := util.StringsJoin("advertiser_id", r.AdvertiserID.String(), "&timestamp", strconv.FormatInt(r.Timestamp, 10), "&version", r.Version)
return util.Md5String(raw)
}
48 changes: 48 additions & 0 deletions model/conversion/aurora_leads_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package conversion

import (
"strconv"
"time"

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

// AuroraLeadsRequest 回传数据接口 API Request
type AuroraLeadsRequest struct {
// AdvertiserID 广告主id
AdvertiserID model.JSONUint64 `json:"advertiser_id,omitempty"`
// Version 接口版本, 固定为"1.0"
Version string `json:"version,omitempty"`
// Timestamp 当前时间戳, 时间戳格式,毫秒
Timestamp int64 `json:"timestamp,omitempty"`
// Method 转发方法, 固定为"aurora.leads"
Method string ` json:"method,omitempty"`
// Token access_token
Token string `json:"token,omitempty"`
// EventType 转化事件类型 id
EventType enum.EventType `json:"event_type,omitempty"`
// ConvTime 转化发生时间, 时间戳格式,毫秒
ConvTime int64 `json:"conv_time,omitempty"`
// ClickID 事件对应的click_id,同页面跳转click_id
ClickID string `json:"click_id,omitempty"`
// AccessToken access_token
AccessToken string `json:"access_token,omitempty"`
// Sign 签名
Sign string `json:"sign,omitempty"`
}

// Encode implement PostRequest
func (r AuroraLeadsRequest) Encode() []byte {
r.Version = "1.0"
r.Method = "aurora.leads"
r.Timestamp = time.Now().UnixMilli()
r.Sign = r.sign()
return util.JSONMarshal(r)
}

func (r AuroraLeadsRequest) sign() string {
raw := util.StringsJoin("advertiser_id", r.AdvertiserID.String(), "&method", r.Method, "&timestamp", strconv.FormatInt(r.Timestamp, 10), "&version", r.Version)
return util.Md5String(raw)
}
20 changes: 20 additions & 0 deletions model/conversion/hawking_leads_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package conversion

import "github.com/bububa/spotlight-mapi/util"

// HawkingLeadsRequest 聚光落地页线索数据回传 API Request
type HawkingLeadsRequest struct {
// CampaignID 计划ID
CampaignID uint64 `json:"campaignId,omitempty"`
// UnitID 单元ID
UnitID uint64 `json:"unitId,omitempty"`
// CreativityID 创意ID
CreativityID uint64 `json:"creativityId,omitempty"`
// LeadsID
LeadsID string `json:"leadsId,omitempty"`
}

// Encode implement PostRequest interface
func (r HawkingLeadsRequest) Encode() []byte {
return util.JSONMarshal(r)
}
6 changes: 4 additions & 2 deletions model/conversion/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package conversion

import (
"github.com/bububa/spotlight-mapi/enum"
"github.com/bububa/spotlight-mapi/model"
"github.com/bububa/spotlight-mapi/util"
)

// Request 转化回传请求
type Request struct {
model.BaseRequest
// AppID
AppID string `json:"app_id,omitempty"`
// AccessToken
AccessToken string `json:"access_token,omitempty"`
// EventType 事件类型
EventType enum.EventType `json:"event_type,omitempty"`
// Timestamp 事件发生时间, 时间戳格式,毫秒
Expand Down
3 changes: 1 addition & 2 deletions model/oauth/access_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package oauth
import (
"github.com/bububa/spotlight-mapi/enum"
"github.com/bububa/spotlight-mapi/model"
"github.com/bububa/spotlight-mapi/model/advertiser"
"github.com/bububa/spotlight-mapi/util"
)

Expand All @@ -26,7 +25,7 @@ type AccessToken struct {
// PlatformType 平台类型,1:聚光,2:蒲公英
PlatformType enum.PlatformType `json:"platform_type,omitempty"`
// ApprovalAdvertisers 授权广告主账号,品牌开发者与服务商开发者时有值
ApprovalAdvertisers []advertiser.Advertiser `json:"approval_advertisers,omitempty"`
ApprovalAdvertisers []Advertiser `json:"approval_advertisers,omitempty"`
}

// AccessTokenRequest 获取Token API Request
Expand Down
9 changes: 9 additions & 0 deletions model/oauth/advertiser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package oauth

// Advertiser 广告主
type Advertiser struct {
// ID 广告主ID
ID uint64 `json:"advertiser_id,omitempty"`
// Name 广告主名称
Name string `json:"advertiser_name,omitempty"`
}

0 comments on commit f0ee5ee

Please sign in to comment.