239 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
| package mailchimp
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"regexp"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	reports_endpoint          string = "/3.0/reports"
 | |
| 	reports_endpoint_campaign string = "/3.0/reports/%s"
 | |
| )
 | |
| 
 | |
| var mailchimp_datacenter = regexp.MustCompile("[a-z]+[0-9]+$")
 | |
| 
 | |
| type ChimpAPI struct {
 | |
| 	Transport http.RoundTripper
 | |
| 	Debug     bool
 | |
| 
 | |
| 	sync.Mutex
 | |
| 
 | |
| 	url *url.URL
 | |
| }
 | |
| 
 | |
| type ReportsParams struct {
 | |
| 	Count          string
 | |
| 	Offset         string
 | |
| 	SinceSendTime  string
 | |
| 	BeforeSendTime string
 | |
| }
 | |
| 
 | |
| func (p *ReportsParams) String() string {
 | |
| 	v := url.Values{}
 | |
| 	if p.Count != "" {
 | |
| 		v.Set("count", p.Count)
 | |
| 	}
 | |
| 	if p.Offset != "" {
 | |
| 		v.Set("offset", p.Offset)
 | |
| 	}
 | |
| 	if p.BeforeSendTime != "" {
 | |
| 		v.Set("before_send_time", p.BeforeSendTime)
 | |
| 	}
 | |
| 	if p.SinceSendTime != "" {
 | |
| 		v.Set("since_send_time", p.SinceSendTime)
 | |
| 	}
 | |
| 	return v.Encode()
 | |
| }
 | |
| 
 | |
| func NewChimpAPI(apiKey string) *ChimpAPI {
 | |
| 	u := &url.URL{}
 | |
| 	u.Scheme = "https"
 | |
| 	u.Host = fmt.Sprintf("%s.api.mailchimp.com", mailchimp_datacenter.FindString(apiKey))
 | |
| 	u.User = url.UserPassword("", apiKey)
 | |
| 	return &ChimpAPI{url: u}
 | |
| }
 | |
| 
 | |
| type APIError struct {
 | |
| 	Status   int    `json:"status"`
 | |
| 	Type     string `json:"type"`
 | |
| 	Title    string `json:"title"`
 | |
| 	Detail   string `json:"detail"`
 | |
| 	Instance string `json:"instance"`
 | |
| }
 | |
| 
 | |
| func (e APIError) Error() string {
 | |
| 	return fmt.Sprintf("ERROR %v: %v. See %v", e.Status, e.Title, e.Type)
 | |
| }
 | |
| 
 | |
| func chimpErrorCheck(body []byte) error {
 | |
| 	var e APIError
 | |
| 	json.Unmarshal(body, &e)
 | |
| 	if e.Title != "" || e.Status != 0 {
 | |
| 		return e
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (a *ChimpAPI) GetReports(params ReportsParams) (ReportsResponse, error) {
 | |
| 	a.Lock()
 | |
| 	defer a.Unlock()
 | |
| 	a.url.Path = reports_endpoint
 | |
| 
 | |
| 	var response ReportsResponse
 | |
| 	rawjson, err := runChimp(a, params)
 | |
| 	if err != nil {
 | |
| 		return response, err
 | |
| 	}
 | |
| 
 | |
| 	err = json.Unmarshal(rawjson, &response)
 | |
| 	if err != nil {
 | |
| 		return response, err
 | |
| 	}
 | |
| 
 | |
| 	return response, nil
 | |
| }
 | |
| 
 | |
| func (a *ChimpAPI) GetReport(campaignID string) (Report, error) {
 | |
| 	a.Lock()
 | |
| 	defer a.Unlock()
 | |
| 	a.url.Path = fmt.Sprintf(reports_endpoint_campaign, campaignID)
 | |
| 
 | |
| 	var response Report
 | |
| 	rawjson, err := runChimp(a, ReportsParams{})
 | |
| 	if err != nil {
 | |
| 		return response, err
 | |
| 	}
 | |
| 
 | |
| 	err = json.Unmarshal(rawjson, &response)
 | |
| 	if err != nil {
 | |
| 		return response, err
 | |
| 	}
 | |
| 
 | |
| 	return response, nil
 | |
| }
 | |
| 
 | |
| func runChimp(api *ChimpAPI, params ReportsParams) ([]byte, error) {
 | |
| 	client := &http.Client{
 | |
| 		Transport: api.Transport,
 | |
| 		Timeout:   time.Duration(4 * time.Second),
 | |
| 	}
 | |
| 
 | |
| 	var b bytes.Buffer
 | |
| 	req, err := http.NewRequest("GET", api.url.String(), &b)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	req.URL.RawQuery = params.String()
 | |
| 	req.Header.Set("User-Agent", "Telegraf-MailChimp-Plugin")
 | |
| 	if api.Debug {
 | |
| 		log.Printf("D! [inputs.mailchimp] request URL: %s", req.URL.String())
 | |
| 	}
 | |
| 
 | |
| 	resp, err := client.Do(req)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	defer resp.Body.Close()
 | |
| 
 | |
| 	body, err := ioutil.ReadAll(resp.Body)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if api.Debug {
 | |
| 		log.Printf("D! [inputs.mailchimp] response Body: %q", string(body))
 | |
| 	}
 | |
| 
 | |
| 	if err = chimpErrorCheck(body); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return body, nil
 | |
| }
 | |
| 
 | |
| type ReportsResponse struct {
 | |
| 	Reports    []Report `json:"reports"`
 | |
| 	TotalItems int      `json:"total_items"`
 | |
| }
 | |
| 
 | |
| type Report struct {
 | |
| 	ID            string `json:"id"`
 | |
| 	CampaignTitle string `json:"campaign_title"`
 | |
| 	Type          string `json:"type"`
 | |
| 	EmailsSent    int    `json:"emails_sent"`
 | |
| 	AbuseReports  int    `json:"abuse_reports"`
 | |
| 	Unsubscribed  int    `json:"unsubscribed"`
 | |
| 	SendTime      string `json:"send_time"`
 | |
| 
 | |
| 	TimeSeries    []TimeSerie
 | |
| 	Bounces       Bounces       `json:"bounces"`
 | |
| 	Forwards      Forwards      `json:"forwards"`
 | |
| 	Opens         Opens         `json:"opens"`
 | |
| 	Clicks        Clicks        `json:"clicks"`
 | |
| 	FacebookLikes FacebookLikes `json:"facebook_likes"`
 | |
| 	IndustryStats IndustryStats `json:"industry_stats"`
 | |
| 	ListStats     ListStats     `json:"list_stats"`
 | |
| }
 | |
| 
 | |
| type Bounces struct {
 | |
| 	HardBounces  int `json:"hard_bounces"`
 | |
| 	SoftBounces  int `json:"soft_bounces"`
 | |
| 	SyntaxErrors int `json:"syntax_errors"`
 | |
| }
 | |
| 
 | |
| type Forwards struct {
 | |
| 	ForwardsCount int `json:"forwards_count"`
 | |
| 	ForwardsOpens int `json:"forwards_opens"`
 | |
| }
 | |
| 
 | |
| type Opens struct {
 | |
| 	OpensTotal  int     `json:"opens_total"`
 | |
| 	UniqueOpens int     `json:"unique_opens"`
 | |
| 	OpenRate    float64 `json:"open_rate"`
 | |
| 	LastOpen    string  `json:"last_open"`
 | |
| }
 | |
| 
 | |
| type Clicks struct {
 | |
| 	ClicksTotal            int     `json:"clicks_total"`
 | |
| 	UniqueClicks           int     `json:"unique_clicks"`
 | |
| 	UniqueSubscriberClicks int     `json:"unique_subscriber_clicks"`
 | |
| 	ClickRate              float64 `json:"click_rate"`
 | |
| 	LastClick              string  `json:"last_click"`
 | |
| }
 | |
| 
 | |
| type FacebookLikes struct {
 | |
| 	RecipientLikes int `json:"recipient_likes"`
 | |
| 	UniqueLikes    int `json:"unique_likes"`
 | |
| 	FacebookLikes  int `json:"facebook_likes"`
 | |
| }
 | |
| 
 | |
| type IndustryStats struct {
 | |
| 	Type       string  `json:"type"`
 | |
| 	OpenRate   float64 `json:"open_rate"`
 | |
| 	ClickRate  float64 `json:"click_rate"`
 | |
| 	BounceRate float64 `json:"bounce_rate"`
 | |
| 	UnopenRate float64 `json:"unopen_rate"`
 | |
| 	UnsubRate  float64 `json:"unsub_rate"`
 | |
| 	AbuseRate  float64 `json:"abuse_rate"`
 | |
| }
 | |
| 
 | |
| type ListStats struct {
 | |
| 	SubRate   float64 `json:"sub_rate"`
 | |
| 	UnsubRate float64 `json:"unsub_rate"`
 | |
| 	OpenRate  float64 `json:"open_rate"`
 | |
| 	ClickRate float64 `json:"click_rate"`
 | |
| }
 | |
| 
 | |
| type TimeSerie struct {
 | |
| 	TimeStamp       string `json:"timestamp"`
 | |
| 	EmailsSent      int    `json:"emails_sent"`
 | |
| 	UniqueOpens     int    `json:"unique_opens"`
 | |
| 	RecipientsClick int    `json:"recipients_click"`
 | |
| }
 |