diff --git a/base.go b/base.go index 5be13af..f9d88d6 100644 --- a/base.go +++ b/base.go @@ -11,7 +11,8 @@ import ( ) const ( - baseUrl = "https://adwords.google.com/api/adwords/cm/v201409" + 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/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/conversion_tracker.go b/conversion_tracker.go index 052297a..b2b5e59 100644 --- a/conversion_tracker.go +++ b/conversion_tracker.go @@ -1,5 +1,9 @@ package gads +import ( + "encoding/xml" +) + type ConversionTrackerService struct { Auth } @@ -7,3 +11,44 @@ type ConversionTrackerService struct { func NewConversionTrackerService(auth *Auth) *ConversionTrackerService { return &ConversionTrackerService{Auth: *auth} } + +type ConversionTracker struct { + Id int64 `xml:"id"` + OriginalConversionTypeId int64 `xml:"originalConversionTypeId"` + Name string `xml:"name"` + Status string `xml:"status"` + Category string `xml:"category"` + GoogleEventSnippet string `xml:"googleEventSnippet"` + GoogleGlobalSiteTag string `xml:"googleGlobalSiteTag"` +} + +func (c *ConversionTrackerService) Get(selector Selector) (conversions []ConversionTracker, totalCount int64, err error) { + selector.XMLName = xml.Name{"", "serviceSelector"} + respBody, err := c.Auth.request( + conversionTrackerServiceUrl, + "get", + struct { + XMLName xml.Name + Sel Selector + }{ + XMLName: xml.Name{ + Space: baseUrl, + Local: "get", + }, + Sel: selector, + }, + ) + if err != nil { + return conversions, totalCount, err + } + getResp := struct { + Size int64 `xml:"rval>totalNumEntries"` + Conversions []ConversionTracker `xml:"rval>entries"` + }{} + + err = xml.Unmarshal([]byte(respBody), &getResp) + if err != nil { + return conversions, totalCount, err + } + return getResp.Conversions, getResp.Size, err +} 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) { diff --git a/offline_conversion_feed.go b/offline_conversion_feed.go index bd932c3..01af9a6 100644 --- a/offline_conversion_feed.go +++ b/offline_conversion_feed.go @@ -1,9 +1,67 @@ package gads +import "encoding/xml" + type OfflineConversionService struct { Auth } +const ( + uploadConversionAction = "ADD" +) + +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 _, conversion := range conversionOperations { + for _, con := range conversion { + ops = append(ops, + conversionOperation{ + Action: uploadConversionAction, + 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(offlineConversionFeedServiceUrl, "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 +}