From 1a91c55504e8723dd84f24fa027ce5c7cdd0bf4b Mon Sep 17 00:00:00 2001 From: paulaan Date: Tue, 12 Mar 2019 10:17:51 +0700 Subject: [PATCH 1/3] [offline-conversion-upload] Add Mutate for Offline conversion upload --- base.go | 2 +- base_test.go | 2 +- offline_conversion_feed.go | 54 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/base.go b/base.go index 5be13af..309224d 100644 --- a/base.go +++ b/base.go @@ -11,7 +11,7 @@ import ( ) const ( - baseUrl = "https://adwords.google.com/api/adwords/cm/v201409" + baseUrl = "https://adwords.google.com/api/adwords/cm/v201809" ) type ServiceUrl struct { diff --git a/base_test.go b/base_test.go index 298df9c..df898bf 100644 --- a/base_test.go +++ b/base_test.go @@ -26,7 +26,7 @@ func rand_word(str_size int) string { return string(bytes) } -func testAuthSetup(t *testing.T) Auth { +func testAuthSetup(t *testing.T) *Auth { config, err := NewCredentials(context.TODO()) if err != nil { t.Fatal(err) diff --git a/offline_conversion_feed.go b/offline_conversion_feed.go index bd932c3..1a6b935 100644 --- a/offline_conversion_feed.go +++ b/offline_conversion_feed.go @@ -1,9 +1,63 @@ package gads +import "encoding/xml" + type OfflineConversionService struct { Auth } +type OfflineConversionFeed struct { + GoogleClickId string `xml:"googleClickId"` + ConversionName string `xml:"conversionName"` + ConversionTime string `xml:"conversionTime"` + ConversionCurrencyCode string `xml:"conversionCurrencyCode"` + ExternalAttributionModel string `xml:"externalAttributionModel"` + ConversionValue float32 `xml:"conversionValue"` + ExternalAttributionCredit float32 `xml:"externalAttributionCredit"` +} + +type OfflineConversionOperations map[string][]OfflineConversionFeed + func NewOfflineConversionService(auth *Auth) *OfflineConversionService { return &OfflineConversionService{Auth: *auth} } + +func (o *OfflineConversionService) Mutate(conversionOperations OfflineConversionOperations) (conversion []OfflineConversionFeed, error error) { + type conversionOperation struct { + Action string `xml:"operator"` + Conversion OfflineConversionFeed `xml:"operand"` + } + var ops []conversionOperation + + for action, conversion := range conversionOperations { + for _, con := range conversion { + ops = append(ops, + conversionOperation{ + Action: action, + Conversion: con, + }, + ) + } + } + mutation := struct { + XMLName xml.Name + Ops []conversionOperation `xml:"operations"` + }{ + XMLName: xml.Name{ + Space: baseUrl, + Local: "mutate", + }, + Ops: ops} + respBody, err := o.Auth.request(campaignServiceUrl, "mutate", mutation) + if err != nil { + return conversion, err + } + mutateResp := struct { + Conversions []OfflineConversionFeed `xml:"rval>value"` + }{} + err = xml.Unmarshal([]byte(respBody), &mutateResp) + if err != nil { + return conversion, err + } + return mutateResp.Conversions, nil +} From 514bae2fbb2d3fb2e1f7d4cea612f4bcfa91da1c Mon Sep 17 00:00:00 2001 From: paulaan Date: Tue, 12 Mar 2019 12:39:34 +0700 Subject: [PATCH 2/3] [offline-conversion-upload] Conversion Upload --- offline_conversion_feed.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/offline_conversion_feed.go b/offline_conversion_feed.go index 1a6b935..01af9a6 100644 --- a/offline_conversion_feed.go +++ b/offline_conversion_feed.go @@ -6,6 +6,10 @@ type OfflineConversionService struct { Auth } +const ( + uploadConversionAction = "ADD" +) + type OfflineConversionFeed struct { GoogleClickId string `xml:"googleClickId"` ConversionName string `xml:"conversionName"` @@ -29,11 +33,11 @@ func (o *OfflineConversionService) Mutate(conversionOperations OfflineConversion } var ops []conversionOperation - for action, conversion := range conversionOperations { + for _, conversion := range conversionOperations { for _, con := range conversion { ops = append(ops, conversionOperation{ - Action: action, + Action: uploadConversionAction, Conversion: con, }, ) @@ -48,7 +52,7 @@ func (o *OfflineConversionService) Mutate(conversionOperations OfflineConversion Local: "mutate", }, Ops: ops} - respBody, err := o.Auth.request(campaignServiceUrl, "mutate", mutation) + respBody, err := o.Auth.request(offlineConversionFeedServiceUrl, "mutate", mutation) if err != nil { return conversion, err } From 9ec8c4770f931983e17e30e2c093d8f1c4ed8d87 Mon Sep 17 00:00:00 2001 From: paulaan Date: Thu, 21 Mar 2019 18:56:49 +0700 Subject: [PATCH 3/3] [managed-customer] Managed customer --- base.go | 3 ++- managed_customer.go | 50 +++++++++++++++++++++++++++++++++++++++++++++ oauth2.go | 2 +- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/base.go b/base.go index 309224d..f9d88d6 100644 --- a/base.go +++ b/base.go @@ -12,6 +12,7 @@ import ( const ( baseUrl = "https://adwords.google.com/api/adwords/cm/v201809" + mcmUrl = "https://adwords.google.com/api/adwords/mcm/v201809" ) type ServiceUrl struct { @@ -56,7 +57,7 @@ var ( geoLocationServiceUrl = ServiceUrl{baseUrl, "GeoLocationService"} labelServiceUrl = ServiceUrl{baseUrl, "LabelService"} locationCriterionServiceUrl = ServiceUrl{baseUrl, "LocationCriterionService"} - managedCustomerServiceUrl = ServiceUrl{baseUrl, "ManagedCustomerService"} + managedCustomerServiceUrl = ServiceUrl{mcmUrl, "ManagedCustomerService"} mediaServiceUrl = ServiceUrl{baseUrl, "MediaService"} mutateJobServiceUrl = ServiceUrl{baseUrl, "Mutate_JOB_Service"} offlineConversionFeedServiceUrl = ServiceUrl{baseUrl, "OfflineConversionFeedService"} diff --git a/managed_customer.go b/managed_customer.go index c6de762..aa3f98f 100644 --- a/managed_customer.go +++ b/managed_customer.go @@ -1,5 +1,9 @@ package gads +import ( + "encoding/xml" +) + type ManagedCustomerService struct { Auth } @@ -7,3 +11,49 @@ type ManagedCustomerService struct { func NewManagedCustomerService(auth *Auth) *ManagedCustomerService { return &ManagedCustomerService{Auth: *auth} } + +type AccountLabel struct { + Id string `xml:"id"` + Name string `xml:"name"` +} + +type Account struct { + Name string `xml:"name,omitempty"` + CanManageClients bool `xml:"canManageClients,omitempty"` + ExcludeHiddenAccounts bool `xml:"excludeHiddenAccounts,omitempty"` + CustomerId string `xml:"customerId,omitempty"` + DateTimeZone string `xml:"dateTimeZone,omitempty"` + CurrencyCode string `xml:"currencyCode,omitempty"` + AccountLabels []AccountLabel `xml:"accountLabels,omitempty"` +} + +func (m *ManagedCustomerService) Get(selector Selector) (accounts []Account, totalCount int64, err error) { + selector.XMLName = xml.Name{"", "serviceSelector"} + respBody, err := m.Auth.request( + managedCustomerServiceUrl, + "get", + struct { + XMLName xml.Name + Sel Selector + }{ + XMLName: xml.Name{ + Space: mcmUrl, + Local: "get", + }, + Sel: selector, + }, + ) + if err != nil { + return accounts, totalCount, err + } + getResp := struct { + Size int64 `xml:"rval>totalNumEntries"` + Accounts []Account `xml:"rval>entries"` + }{} + + err = xml.Unmarshal([]byte(respBody), &getResp) + if err != nil { + return accounts, totalCount, err + } + return getResp.Accounts, getResp.Size, err +} diff --git a/oauth2.go b/oauth2.go index 63d2775..25b1750 100644 --- a/oauth2.go +++ b/oauth2.go @@ -13,7 +13,7 @@ type AuthConfig struct { OAuth2Config *oauth2.Config `json:"oauth2.Config"` OAuth2Token *oauth2.Token `json:"oauth2.Token"` tokenSource oauth2.TokenSource `json:"-"` - Auth Auth `json:"gads.Auth"` + Auth *Auth `json:"gads.Auth"` } func NewCredentialsFromFile(pathToFile string, ctx context.Context) (ac AuthConfig, err error) {