diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4f2ee4d..0000000 --- a/.travis.yml +++ /dev/null @@ -1 +0,0 @@ -language: go diff --git a/LICENSE b/LICENSE index 61fba26..f4ec9f6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 1a58734..db0c9cb 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Gobilla +# Usabilla -Gobilla is a Go client for [Usabilla API](https://usabilla.com/api). +This is a Go client for [Usabilla API](https://usabilla.com/api). -[![Build Status](https://travis-ci.org/usabilla/gobilla.svg?branch=master)](https://travis-ci.org/usabilla/gobilla) -[![GoDoc](http://godoc.org/github.com/usabilla/gobilla?status.svg)](http://godoc.org/github.com/usabilla/gobilla) +[![CircleCI](https://circleci.com/gh/usabilla/api-go.svg?style=svg)](https://circleci.com/gh/usabilla/api-go) +[![GoDoc](http://godoc.org/github.com/usabilla/api-go?status.svg)](http://godoc.org/github.com/usabilla/api-go) ## Getting Started @@ -16,7 +16,7 @@ import ( "os" "fmt" - "github.com/usabilla/gobilla" + "github.com/usabilla/api-go" ) func main() { @@ -24,14 +24,14 @@ func main() { secret := os.Getenv("USABILLA_API_SECRET") // Pass the key and secret which should be defined as ENV vars - gb := gobilla.New(key, secret) - - b := gb.Buttons() + usabilla := usabilla.New(key, secret) + + resource := usabilla.Buttons() // Get the first ten buttons params := map[string]string{"limit": "10"} - buttons, _ := b.Get(params) - + buttons, _ := resource.Get(params) + // Print all feedback items for each button for _, button := range buttons.Items { feedback, _ := b.Feedback().Get(button.ID, nil) @@ -40,13 +40,13 @@ func main() { } ``` -Then install Gobilla package +Then install usabilla package - go get github.com/usabilla/gobilla + go get github.com/usabilla/api-go Run the file - go run main.go + go run main.go And you will get all feedback items for each button. diff --git a/auth.go b/auth.go index 1a39c42..07d48e2 100644 --- a/auth.go +++ b/auth.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import "fmt" diff --git a/auth_test.go b/auth_test.go index 0aed847..c2f3f10 100644 --- a/auth_test.go +++ b/auth_test.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,12 +21,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "testing" - "github.com/usabilla/gobilla/internal" + "github.com/usabilla/api-go/internal" ) var testData = map[string]string{ diff --git a/date.go b/date.go index 12a640e..12b77ae 100644 --- a/date.go +++ b/date.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "time" diff --git a/date_test.go b/date_test.go index 8e405ed..7b0ba25 100644 --- a/date_test.go +++ b/date_test.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,13 +21,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "testing" "time" - "github.com/usabilla/gobilla/internal" + "github.com/usabilla/api-go/internal" ) var ( diff --git a/example/main.go b/example/main.go index bfd22b2..cd6a5df 100644 --- a/example/main.go +++ b/example/main.go @@ -4,11 +4,11 @@ import ( "fmt" "os" - "github.com/usabilla/gobilla" + "github.com/usabilla/api-go" ) -func buttons(gb *gobilla.Gobilla) { - b := gb.Buttons() +func buttons(usabilla *usabilla.Usabilla) { + b := usabilla.Buttons() buttons, err := b.Get(nil) if err != nil { @@ -31,8 +31,8 @@ func buttons(gb *gobilla.Gobilla) { fmt.Printf("RECEIVED FEEDBACK FROM %d BUTTONS\n", buttons.Count) } -func buttonsIterator(gb *gobilla.Gobilla) { - b := gb.Buttons() +func buttonsIterator(usabilla *usabilla.Usabilla) { + b := usabilla.Buttons() buttons, err := b.Get(nil) if err != nil { @@ -51,19 +51,43 @@ func buttonsIterator(gb *gobilla.Gobilla) { fmt.Printf("RECEIVED FEEDBACK FROM %d BUTTONS\n", buttons.Count) } +func appCampaigns(usabilla *usabilla.Usabilla) { + resource := usabilla.AppCampaigns() + + campaigns, err := resource.Get(nil) + if err != nil { + fmt.Errorf("%s", err) + } + + for _, campaign := range campaigns.Items { + count := 0 + fmt.Printf("START PRINTING RESULTS FOR CAMPAIGN: %s\n", campaign.ID) + for result := range resource.Results().Iterate(campaign.ID, nil) { + fmt.Printf("Result %s\n", result.ID) + count++ + } + fmt.Printf("Received %d results\n", count) + } + + fmt.Printf("FOUND %d CAMPAIGNS IN TOTAL\n", campaigns.Count) +} + func main() { key := os.Getenv("USABILLA_API_KEY") secret := os.Getenv("USABILLA_API_SECRET") // You can pass a custom http.Client // We pass nil to use the http.DefaultClient - gb := gobilla.New(key, secret, nil) + usabilla := usabilla.New(key, secret, nil) // Uses a simple GET to get all feedback items for all buttons. - buttons(gb) + buttons(usabilla) // Uses a channel of feedback items, and once all items have been // consumed and the response HasMore then it fires a new request // for all feedback items for all buttons. - buttonsIterator(gb) + buttonsIterator(usabilla) + + // Display App campaigns and their results + appCampaigns(usabilla) } diff --git a/l4a.go b/l4a.go index 262917c..cab2574 100644 --- a/l4a.go +++ b/l4a.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "encoding/json" @@ -32,11 +32,13 @@ import ( // Canonical URI constants. const ( - appsURI = "/live/apps" + appsURI = "/live/apps" + appsCampaignURI = appsURI + "/campaign" ) var ( - appFeedbackURI = appsURI + "/%s/feedback" + appFeedbackURI = appsURI + "/%s/feedback" + appCampaignResultsURI = appsCampaignURI + "/%s/results" ) // App represents an app item. @@ -75,6 +77,28 @@ type AppFeedbackItem struct { BatteryLevel float32 `json:"batteryLevel"` } +// AppCampaignStruct represents a campaign item. +type AppCampaignStruct struct { + ID string `json:"id"` + CreatedAt string `json:"createdAt"` + LastModifiedAt string `json:"lastModifiedAt"` + Status string `json:"status"` + Name string `json:"name"` + AppIds []string `json:"appIds"` +} + +// AppCampaignResultStruct represents a campaign result item. +type AppCampaignResultStruct struct { + ID string `json:"id"` + Date string `json:"date"` + CampaignID string `json:"campaignId"` + AppID string `json:"appId"` + Data map[string]interface{} `json:"data"` + Context map[string]interface{} `json:"context"` + Metadata map[string]interface{} `json:"metadata"` + Complete bool `json:"complete"` +} + // Apps represents the app resource of Usabilla API. type Apps struct { resource @@ -87,6 +111,18 @@ type AppFeedbackItems struct { client *http.Client } +// AppCampaigns represents a App Campaign resource. +type AppCampaigns struct { + resource + client *http.Client +} + +// AppCampaignResults represents a App Campaign Results resource. +type AppCampaignResults struct { + resource + client *http.Client +} + // AppResponse is a response that contains app data. type AppResponse struct { response @@ -99,6 +135,18 @@ type AppFeedbackResponse struct { Items []AppFeedbackItem `json:"items"` } +// AppCampaignResponse is a response that contains App campaign data. +type AppCampaignResponse struct { + response + Items []AppCampaignStruct `json:"items"` +} + +// AppCampaignResults is a response that contains App campaign results data. +type AppCampaignResultsResponse struct { + response + Items []AppCampaignResultStruct `json:"items"` +} + // Get function of Apps resource returns all apps // taking into account the specified query parameters. // @@ -173,6 +221,97 @@ func (af *AppFeedbackItems) Iterate(appID string, params map[string]string) chan return afic } +// Get function of AppCampaigns resource returns all the campaigns +func (ac *AppCampaigns) Get(params map[string]string) (*AppCampaignResponse, error) { + request := &request{ + method: "GET", + auth: ac.auth, + uri: appsCampaignURI, + params: params, + client: ac.client, + } + + data, err := request.get() + if err != nil { + panic(err) + } + + return newAppCampaignResponse(data) +} + +// Results encapsulates the App Campaign Results resource +func (ac *AppCampaigns) Results() *AppCampaignResults { + return &AppCampaignResults{ + resource: resource{ + auth: ac.auth, + }, + client: ac.client, + } +} + +// Get function of AppCampaignResults resource returns all the campaign results +func (acr *AppCampaignResults) Get(campaignID string, params map[string]string) (*AppCampaignResultsResponse, error) { + uri := fmt.Sprintf(appCampaignResultsURI, campaignID) + + request := &request{ + method: "GET", + auth: acr.auth, + uri: uri, + params: params, + client: acr.client, + } + + data, err := request.get() + if err != nil { + panic(err) + } + + return newAppCampaignResultsResponse(data) +} + +// Iterate uses a channel which transparently uses the HasMore field to fire a new API request. Once all results +// have consumed on the channel it closes the chanel. +func (ac *AppCampaignResults) Iterate(campaignID string, params map[string]string) chan AppCampaignResultStruct { + resp, err := ac.Get(campaignID, params) + + if err != nil { + panic(err) + } + + acrc := make(chan AppCampaignResultStruct) + + go appCampaignResults(acrc, resp, ac, campaignID) + + return acrc +} + +// appCampaignResults feeds the results channel with items. While HasMore is true it makes new API requests +// and sends them through the channel. Once it is false it closes the channel. +func appCampaignResults(acrc chan AppCampaignResultStruct, resp *AppCampaignResultsResponse, acr *AppCampaignResults, campaignID string) { + for { + for _, item := range resp.Items { + acrc <- item + } + if !resp.HasMore { + close(acrc) + return + } + params := map[string]string{ + "since": strconv.FormatInt(resp.LastTimestamp, 10), + } + + resp, err := acr.Get(campaignID, params) + + if err != nil { + panic(err) + } + + appCampaignResults(acrc, resp, acr, campaignID) + + return + } +} + // appItems feeds a feedback item channel with items. // // While hasMore is true and all items have been consumed in the channel @@ -230,3 +369,27 @@ func newAppFeedbackResponse(data []byte) (*AppFeedbackResponse, error) { return response, nil } + +// newAppCampaignResponse creates a response and unmarshals the JSON into a Struct. +func newAppCampaignResponse(data []byte) (*AppCampaignResponse, error) { + response := &AppCampaignResponse{} + + err := json.Unmarshal(data, &response) + if err != nil { + return response, err + } + + return response, nil +} + +// newAppCampaignResultsResponse creates a response and unmarshals the JSON into a Struct. +func newAppCampaignResultsResponse(data []byte) (*AppCampaignResultsResponse, error) { + response := &AppCampaignResultsResponse{} + + err := json.Unmarshal(data, &response) + if err != nil { + return response, err + } + + return response, nil +} diff --git a/l4e.go b/l4e.go index c629616..8b86ae9 100644 --- a/l4e.go +++ b/l4e.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "encoding/json" diff --git a/l4w.go b/l4w.go index a807011..ee5db09 100644 --- a/l4w.go +++ b/l4w.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "encoding/json" @@ -104,17 +104,17 @@ type CampaignStatStruct struct { } type InpageWidgetStruct struct { - ID string `json:"id"` - Date time.Time `json:"date"` - Name string `json:"name"` + ID string `json:"id"` + Date time.Time `json:"date"` + Name string `json:"name"` } type InpageWidgetFeedbackStruct struct { - ID string `json:"id"` + ID string `json:"id"` Date time.Time `json:"date"` Data map[string]interface{} `json:"data"` CustomData map[string]interface{} `json:"customData"` - Widget_ID string `json:"widgetId"` + Widget_ID string `json:"widgetId"` Rating float64 `json:"rating"` Mood int `json:"mood"` Nps int `json:"nps,omitempty"` @@ -600,17 +600,6 @@ func yieldCampaignStats(csc chan CampaignStatStruct, resp *CampaignStatsResponse } } - - - - - - - - - - - ////////////// Inpage ////////////// // Get function of Inpage resource returns all the Inpage Widgets // taking into account the provided query parameters. @@ -715,4 +704,4 @@ func yieldInpageWidgetFeedbackItems(crc chan InpageWidgetFeedbackStruct, resp *I yieldInpageWidgetFeedbackItems(crc, resp, r, inpageID) return } -} \ No newline at end of file +} diff --git a/request.go b/request.go index 48d0a9d..2333259 100644 --- a/request.go +++ b/request.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "fmt" diff --git a/request_test.go b/request_test.go index f014ae3..c0365c7 100644 --- a/request_test.go +++ b/request_test.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "encoding/json" @@ -32,7 +32,7 @@ import ( "reflect" "testing" - "github.com/usabilla/gobilla/internal" + "github.com/usabilla/api-go/internal" ) func mockRequest(method, uri string, params map[string]string, client *http.Client) *request { diff --git a/resource.go b/resource.go index ea5e552..4b12d77 100644 --- a/resource.go +++ b/resource.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla // Resource provides auth for every API resource. type resource struct { diff --git a/response.go b/response.go index 0236ce8..38460d3 100644 --- a/response.go +++ b/response.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla // Response contains common data for an API response. type response struct { diff --git a/signing.go b/signing.go index 04093b0..5d30307 100644 --- a/signing.go +++ b/signing.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "crypto/hmac" diff --git a/signing_test.go b/signing_test.go index c6af383..b4d5e7d 100644 --- a/signing_test.go +++ b/signing_test.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,12 +21,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package gobilla +package usabilla import ( "testing" - "github.com/usabilla/gobilla/internal" + "github.com/usabilla/api-go/internal" ) func Test_Hash(t *testing.T) { diff --git a/gobilla.go b/usabilla.go similarity index 64% rename from gobilla.go rename to usabilla.go index 1ad8503..e16b988 100644 --- a/gobilla.go +++ b/usabilla.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2016 Usabilla +Copyright (c) 2018 Usabilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21,29 +21,29 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -// Package gobilla provides a wrapper around Usabilla Public API. +// Package usabilla provides a wrapper around Usabilla Public API. // // https://usabilla.com/api -package gobilla +package usabilla import "net/http" -// Gobilla is the client that exposes all the resources of the Usabilla API. +// Usabilla is the client that exposes all the resources of the Usabilla API. // You can provide a custom http client to change the way the client works. -type Gobilla struct { +type Usabilla struct { auth auth Client *http.Client } -// New creates a new Gobilla instance and sets the auth with key and secret. +// New creates a new Usabilla instance and sets the auth with key and secret. // Client is the default http client. To change the way the client works // provide a custom http client. Passing nil will use the http.DefaultClient -func New(key, secret string, customClient *http.Client) *Gobilla { +func New(key, secret string, customClient *http.Client) *Usabilla { client := http.DefaultClient if customClient != nil { client = customClient } - return &Gobilla{ + return &Usabilla{ auth: auth{ key: key, secret: secret, @@ -53,51 +53,61 @@ func New(key, secret string, customClient *http.Client) *Gobilla { } // Buttons encapsulates the button resource. -func (gb *Gobilla) Buttons() *Buttons { +func (usabilla *Usabilla) Buttons() *Buttons { return &Buttons{ resource: resource{ - auth: gb.auth, + auth: usabilla.auth, }, - client: gb.Client, + client: usabilla.Client, } } // Campaigns encapsulates the campaign resource. -func (gb *Gobilla) Campaigns() *Campaigns { +func (usabilla *Usabilla) Campaigns() *Campaigns { return &Campaigns{ resource: resource{ - auth: gb.auth, + auth: usabilla.auth, }, - client: gb.Client, + client: usabilla.Client, } } // Apps encapsulates the app resource. -func (gb *Gobilla) Apps() *Apps { +func (usabilla *Usabilla) Apps() *Apps { return &Apps{ resource: resource{ - auth: gb.auth, + auth: usabilla.auth, }, - client: gb.Client, + client: usabilla.Client, + } +} + +// AppsCampaigns encapsulates the AppCampaigns resource +func (usabilla *Usabilla) AppCampaigns() *AppCampaigns { + return &AppCampaigns{ + resource: resource{ + auth: usabilla.auth, + }, + client: usabilla.Client, } } // EmailButtons encapsulates the email button resource. -func (gb *Gobilla) EmailButtons() *EmailButtons { +func (usabilla *Usabilla) EmailButtons() *EmailButtons { return &EmailButtons{ resource: resource{ - auth: gb.auth, + auth: usabilla.auth, }, - client: gb.Client, + client: usabilla.Client, } } // Inpage encapsulates the app resource. -func (gb *Gobilla) InpageWidgets() *InpageWidgets { +func (usabilla *Usabilla) InpageWidgets() *InpageWidgets { return &InpageWidgets{ resource: resource{ - auth: gb.auth, + auth: usabilla.auth, }, - client: gb.Client, + client: usabilla.Client, } -} \ No newline at end of file +}