diff --git a/README.md b/README.md index db51008..aff9df3 100644 --- a/README.md +++ b/README.md @@ -182,4 +182,13 @@ Delete an existing ticket ``` client.ZendeskApi().DeleteTicket(1) -``` \ No newline at end of file +``` + +## Search function available + +#### TicketSearch +Return a Search result containing only tickets + +``` +client.ZendeskApi().TicketSearch("Test") +``` diff --git a/adapter.go b/adapter.go index 7d1cab1..bdf8be7 100644 --- a/adapter.go +++ b/adapter.go @@ -1,6 +1,6 @@ package zendesk -import "gopkg.in/resty.v0" +import resty "gopkg.in/resty.v0" type ZendeskApi interface { GetById(id int) (interface{}, error) @@ -14,4 +14,4 @@ type ZendeskApi interface { // Parse response parseSingleObject(response *resty.Response) interface{} parseMultiObjects(response *resty.Response) []interface{} -} \ No newline at end of file +} diff --git a/builder.go b/builder.go index 99ad46a..2065379 100644 --- a/builder.go +++ b/builder.go @@ -3,9 +3,10 @@ package zendesk import ( "fmt" "io/ioutil" + "os" - "gopkg.in/yaml.v2" - "gopkg.in/resty.v0" + resty "gopkg.in/resty.v0" + yaml "gopkg.in/yaml.v2" ) func FromToken(config ZendeskConfiguration) Client { @@ -16,12 +17,24 @@ func FromToken(config ZendeskConfiguration) Client { restyClient.SetHeader("Content-Type", "application/json") return Client{ - domain: config.Domain, + domain: config.Domain, apiVersion: config.ApiVersion, - client: restyClient, + client: restyClient, } } +func FromEnv() Client { + zendeskConfiguration := ZendeskConfiguration{} + zendeskConfiguration.ApiVersion = os.Getenv("ZENDESK_API_VERSION") + zendeskConfiguration.Domain = os.Getenv("ZENDESK_DOMAIN") + zendeskConfiguration.Email = os.Getenv("ZENDESK_EMAIL") + zendeskConfiguration.Password = os.Getenv("ZENDESK_PASSWORD") + zendeskConfiguration.Token = os.Getenv("ZENDESK_TOKEN") + + fmt.Println(zendeskConfiguration) + return FromToken(zendeskConfiguration) +} + func LoadConfiguration(path string) ZendeskConfiguration { zendeskConfiguration := ZendeskConfiguration{} zendeskConfigurationFile, err := ioutil.ReadFile(path) diff --git a/client.go b/client.go index 426bb1c..5551b4d 100644 --- a/client.go +++ b/client.go @@ -1,14 +1,16 @@ package zendesk import ( - "gopkg.in/resty.v0" - "fmt" "encoding/json" + "fmt" + "strings" + + resty "gopkg.in/resty.v0" ) type Client struct { - domain string - client *resty.Client + domain string + client *resty.Client apiVersion string } @@ -20,10 +22,27 @@ func (c Client) Ticket() TicketApiHandler { return TicketApiHandler{c} } +func (c Client) Search() SearchApiHandler { + return SearchApiHandler{c} +} + +func (c Client) TicketMetric() TicketMetricApiHandler { + return TicketMetricApiHandler{c} +} + +func (c Client) SatisfactionRating() SatisfactionRatingApiHandler { + return SatisfactionRatingApiHandler{c} +} + func (c Client) toFullUrl(path string) string { return fmt.Sprintf("https://%v.zendesk.com/api/%s/%s", c.domain, c.apiVersion, path) } +func (c Client) toPath(path string) string { + baseURL := fmt.Sprintf("https://%v.zendesk.com/api/%s", c.domain, c.apiVersion) + return strings.Replace(path, baseURL, "", -1) +} + func (c Client) get(path string, params map[string]string) (*resty.Response, error) { resp, err := c.client.R().SetQueryParams(params).Get(c.toFullUrl(path)) @@ -60,4 +79,4 @@ func (c Client) delete(path string) (*resty.Response, error) { func (c Client) parseResponseToInterface(response *resty.Response, v interface{}) { json.Unmarshal(response.Body(), &v) -} \ No newline at end of file +} diff --git a/glide.lock b/glide.lock new file mode 100644 index 0000000..f4b2da8 --- /dev/null +++ b/glide.lock @@ -0,0 +1,20 @@ +hash: 27115a2a0af1c783ee899e7a74cf9af7591d1879b16f937a41529aae79d3df79 +updated: 2018-12-17T17:14:56.669947868+01:00 +imports: +- name: github.com/golang/protobuf + version: f0a097ddac24fb00e07d2ac17f8671423f3ea47c + subpackages: + - proto +- name: github.com/ttacon/builder + version: 7f152c3cf4714fd6318739f8f3dbcd14c2a18b39 +- name: github.com/ttacon/libphonenumber + version: 1197dfb91fa03c779576ad248ad5ca0a43fb3a31 +- name: golang.org/x/net + version: 4876518f9e71663000c348837735820161a42df7 + subpackages: + - publicsuffix +- name: gopkg.in/resty.v0 + version: aed15a666de54595af7d8895aa7299ceff5635f8 +- name: gopkg.in/yaml.v2 + version: a83829b6f1293c91addabc89d0571c246397bbf4 +testImports: [] diff --git a/glide.yaml b/glide.yaml new file mode 100644 index 0000000..667a2e5 --- /dev/null +++ b/glide.yaml @@ -0,0 +1,18 @@ +package: github.com/smartfrog-oss/zendesk-go +import: +- package: github.com/golang/protobuf + version: f0a097ddac24fb00e07d2ac17f8671423f3ea47c + subpackages: + - proto +- package: github.com/ttacon/builder + version: 7f152c3cf4714fd6318739f8f3dbcd14c2a18b39 +- package: github.com/ttacon/libphonenumber + version: 1197dfb91fa03c779576ad248ad5ca0a43fb3a31 +- package: golang.org/x/net + version: 4876518f9e71663000c348837735820161a42df7 + subpackages: + - publicsuffix +- package: gopkg.in/resty.v0 + version: ~0.6.0 +- package: gopkg.in/yaml.v2 + version: a83829b6f1293c91addabc89d0571c246397bbf4 diff --git a/satisfaction_ratings.go b/satisfaction_ratings.go new file mode 100644 index 0000000..63629f8 --- /dev/null +++ b/satisfaction_ratings.go @@ -0,0 +1,39 @@ +package zendesk + +import ( + "fmt" + "time" + + resty "gopkg.in/resty.v0" +) + +type SatisfactionRatingApiHandler struct { + client Client +} + +func (s SatisfactionRatingApiHandler) SatisfactionRatings(score string, startDate *time.Time, stopDate *time.Time) (SatisfactionRatings, error) { + urlString := fmt.Sprintf("/satisfaction_ratings.json?start_time=%d&end_time=%d", startDate.Unix(), stopDate.Unix()) + + if len(score) > 0 { + urlString = fmt.Sprintf(urlString+"&score=%s", score) + } + + response, err := s.client.get( + urlString, + nil, + ) + + if err != nil { + + } + + return s.parseResults(response), err +} + +func (s SatisfactionRatingApiHandler) parseResults(response *resty.Response) SatisfactionRatings { + var object SatisfactionRatings + + s.client.parseResponseToInterface(response, &object) + + return object +} diff --git a/satisfaction_ratings_struct.go b/satisfaction_ratings_struct.go new file mode 100644 index 0000000..01cb7aa --- /dev/null +++ b/satisfaction_ratings_struct.go @@ -0,0 +1,22 @@ +package zendesk + +import "time" + +type SatisfactionRatings struct { + Count int `json:"count,omitempty"` + NextPage string `json:"next_page,omitempty"` + PrevPage string `json:"prev_page,omitempty"` + SatisfactionRatings []SatisfactionRating `json:"satisfaction_ratings,omitempty"` +} + +type SatisfactionRating struct { + Id int `json:"id,omitempty"` + Url string `json:"url,omitempty"` + AssigneeId int `json:"assignee_id,omitempty"` + GroupId int `json:"group_id,omitempty"` + RequesterId int `json:"requester_id,omitempty"` + TicketId int `json:"ticket_id,omitempty"` + Score string `json:"score,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` +} diff --git a/search.go b/search.go new file mode 100644 index 0000000..7e38345 --- /dev/null +++ b/search.go @@ -0,0 +1,68 @@ +package zendesk + +import ( + "fmt" + + resty "gopkg.in/resty.v0" +) + +type SearchApiHandler struct { + client Client +} + +func (s SearchApiHandler) SearchTickets(searchString string, sortBy string, sortOrder string) (TicketSearch, error) { + urlString := fmt.Sprintf("/search.json?query=type:ticket %s", searchString) + + if len(sortBy) > 0 { + urlString = fmt.Sprintf(urlString+"&sort_by=%s", sortBy) + } + + if len(sortBy) > 0 { + urlString = fmt.Sprintf(urlString+"&sort_order=%s", sortOrder) + } + + response, err := s.client.get( + urlString, + nil, + ) + + if err != nil { + + } + + return s.parseResults(response), err +} + +func (s SearchApiHandler) NextPage(t TicketSearch) (TicketSearch, error) { + response, err := s.client.get( + s.client.toPath(t.NextPage), + nil, + ) + + if err != nil { + return TicketSearch{}, err + } + + return s.parseResults(response), err +} + +func (s SearchApiHandler) PrevPage(t TicketSearch) (TicketSearch, error) { + response, err := s.client.get( + s.client.toPath(t.PrevPage), + nil, + ) + + if err != nil { + return TicketSearch{}, err + } + + return s.parseResults(response), err +} + +func (s SearchApiHandler) parseResults(response *resty.Response) TicketSearch { + var object TicketSearch + + s.client.parseResponseToInterface(response, &object) + + return object +} diff --git a/search_struct.go b/search_struct.go new file mode 100644 index 0000000..3e9d733 --- /dev/null +++ b/search_struct.go @@ -0,0 +1,8 @@ +package zendesk + +type TicketSearch struct { + Count int `json:"count,omitempty"` + NextPage string `json:"next_page,omitempty"` + PrevPage string `json:"prev_page,omitempty"` + Tickets []Ticket `json:"results,omitempty"` +} diff --git a/test/zendesk_test.go b/test/zendesk_test.go index d3eba4b..147da2e 100644 --- a/test/zendesk_test.go +++ b/test/zendesk_test.go @@ -2,12 +2,13 @@ package test import ( "testing" - "github.com/hellofresh/zendesk-go" + + zendesk "github.com/smartfrog-oss/zendesk-go" ) var client = zendesk.FromToken( zendesk.LoadConfiguration("./../config/configuration.yml"), -); +) var id int @@ -38,7 +39,7 @@ func TestUserApiHandler_GetById(t *testing.T) { func TestUserApiHandler_Create(t *testing.T) { user := zendesk.User{ - Name: "Felipe Pieretti Umpierre", + Name: "Felipe Pieretti Umpierre", Email: "fum@hellofresh.com", } @@ -52,7 +53,7 @@ func TestUserApiHandler_Create(t *testing.T) { func TestUserApiHandler_CreateOrUpdate(t *testing.T) { user := zendesk.User{ - Name: "Felipe Pieretti Umpierre = Updated", + Name: "Felipe Pieretti Umpierre = Updated", Email: "fum@hellofresh.com", } @@ -68,12 +69,12 @@ func TestUserApiHandler_CreateOrUpdateMany(t *testing.T) { var many zendesk.ManyUsers many.AppendUsers(zendesk.User{ - Name: "User 1", + Name: "User 1", Email: "user-1@hellofresh.com", }) many.AppendUsers(zendesk.User{ - Name: "User-2", + Name: "User-2", Email: "user-2@hellofresh.com", }) @@ -96,8 +97,8 @@ func TestUserApiHandler_Delete(t *testing.T) { func TestUserApiHandler_Update(t *testing.T) { user := zendesk.User{ - Id: id, - Name: "Felipe Pieretti Umpierre - hallo", + Id: id, + Name: "Felipe Pieretti Umpierre - hallo", Email: "fum@hellofresh.com", } @@ -109,6 +110,22 @@ func TestUserApiHandler_Update(t *testing.T) { } } +// --------- SEARCH -------- + +func TestSearchApiHandler_Search(t *testing.T) { + tickets, err := client.Search().SearchTickets("TEST") + + if err != nil { + t.Errorf("Error: %s", err) + t.Fail() + } + + for _, ticket := range tickets.Tickets { + id = ticket.Id + break + } +} + // --------- TICKET -------- func TestTicketApiHandler_GetAll(t *testing.T) { @@ -171,7 +188,7 @@ func TestTicketApiHandler_Delete(t *testing.T) { func TestTicketApiHandler_Update(t *testing.T) { ticket := zendesk.Ticket{ - Id: id, + Id: id, Description: "Test ticket", } @@ -181,4 +198,4 @@ func TestTicketApiHandler_Update(t *testing.T) { t.Errorf("Error: %s", err) t.Fail() } -} \ No newline at end of file +} diff --git a/ticket.go b/ticket.go index dcf4a5a..b1a1fa8 100644 --- a/ticket.go +++ b/ticket.go @@ -2,7 +2,8 @@ package zendesk import ( "fmt" - "gopkg.in/resty.v0" + + resty "gopkg.in/resty.v0" ) type TicketApiHandler struct { @@ -97,4 +98,4 @@ func (t TicketApiHandler) parseSingleObject(response *resty.Response) Ticket { t.client.parseResponseToInterface(response, &object) return object.Response -} \ No newline at end of file +} diff --git a/ticket_metrics.go b/ticket_metrics.go new file mode 100644 index 0000000..310c5e0 --- /dev/null +++ b/ticket_metrics.go @@ -0,0 +1,58 @@ +package zendesk + +import ( + "fmt" + + resty "gopkg.in/resty.v0" +) + +type TicketMetricApiHandler struct { + client Client +} + +func (s TicketMetricApiHandler) TicketMetrics() (TicketMetrics, error) { + response, err := s.client.get( + fmt.Sprintf("/ticket_metrics.json"), + nil, + ) + + if err != nil { + + } + + return s.parseResults(response), err +} + +func (s TicketMetricApiHandler) TicketMetricsPage(page int) (TicketMetrics, error) { + response, err := s.client.get( + fmt.Sprintf("/ticket_metrics.json?page=%d", page), + nil, + ) + + if err != nil { + + } + + return s.parseResults(response), err +} + +func (s TicketMetricApiHandler) TicketMetricsByName(metricName string) (TicketMetrics, error) { + response, err := s.client.get( + fmt.Sprintf("/ticket_metrics/%s.json", metricName), + nil, + ) + + if err != nil { + + } + + return s.parseResults(response), err +} + +func (s TicketMetricApiHandler) parseResults(response *resty.Response) TicketMetrics { + var object TicketMetrics + + s.client.parseResponseToInterface(response, &object) + + return object +} diff --git a/ticket_metrics_struct.go b/ticket_metrics_struct.go new file mode 100644 index 0000000..d761211 --- /dev/null +++ b/ticket_metrics_struct.go @@ -0,0 +1,41 @@ +package zendesk + +import ( + "time" +) + +type TicketMetrics struct { + Count int `json:"count,omitempty"` + NextPage string `json:"next_page,omitempty"` + PrevPage string `json:"prev_page,omitempty"` + TicketMetrics []TicketMetric `json:"ticket_metrics,omitempty"` +} + +type InMinutes struct { + Calendar int `json:"calendar,omitempty"` + Business int `json:"business,omitempty"` +} + +type TicketMetric struct { + Id int `json:"id,omitempty"` + TicketId int `json:"ticket_id,omitempty"` + Url string `json:"url,omitempty"` + GroupStations int `json:"group_stations,omitempty"` + AssigneeStations int `json:"assignee_stations,omitempty"` + Reopens int `json:"reopens,omitempty"` + Replies int `json:"replies,omitempty"` + AssigneeUpdatedAt *time.Time `json:"assignee_updated_at,omitempty"` + RequesterUpdatedAt *time.Time `json:"requester_updated_at,omitempty"` + StausUpdatedAt *time.Time `json:"status_updated_at,omitempty"` + InitiallyAssignedAt *time.Time `json:"initially_assigned_at,omitempty"` + AssignedAt *time.Time `json:"assigned_at,omitempty"` + SolvedAt *time.Time `json:"solved_at,omitempty"` + LastCommentAddedAt *time.Time `json:"last_comment_added_at,omitempty"` + FirstResolutionTimeInMinutes InMinutes `json:"first_resolution_time_in_minutes,omitempty"` + ReplyTimeInMinutes InMinutes `json:"reply_time_in_minutes,omitempty"` + FullResolutionTimeInMinutes InMinutes `json:"full_resolution_time_in_minutes,omitempty"` + AgentWaitTimeInMinutes InMinutes `json:"agent_wait_time_in_minutes,omitempty"` + RequesterWaitTimeInMinutes InMinutes `json:"requester_wait_time_in_minutes,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` +} diff --git a/ticket_struct.go b/ticket_struct.go index 1d70c13..9aa34a0 100644 --- a/ticket_struct.go +++ b/ticket_struct.go @@ -1,36 +1,43 @@ package zendesk +import "time" + type Via struct{} +type CustomFields struct { + Id int `json:"id,omitempty"` + Value string `json:"value,omitempty"` +} + type Ticket struct { - Id int `json:"id,omitempty"` - Url string `json:"url,omitempty"` - ExternalId string `json:"external_id,omitempty"` - Type string `json:"type,omitempty"` - Subject string `json:"subject,omitempty"` - RawSubject string `json:"raw_subject,omitempty"` - Description string `json:"description,omitempty"` - Priority string `json:"priority,omitempty"` - Status string `json:"status,omitempty"` - Recipient string `json:"recipient,omitempty"` - RequesterId int `json:"requester_id,omitempty"` - SubmitterId int `json:"submitter_id,omitempty"` - AssigneeId int `json:"assignee_id,omitempty"` - OrganizationId int `json:"organization_id,omitempty"` - GroupId int `json:"group_id,omitempty"` - CollaboratorsId []int `json:"collaborators_id,omitempty"` - ForumTopicId int `json:"forum_topic_id,omitempty"` - ProblemId int `json:"problem_id,omitempty"` - HasIncidents bool `json:"has_incidents,omitempty"` - DueAt string `json:"due_at,omitempty"` - Tags []string `json:"tags,omitempty"` - Via *Via `json:"via,omitempty"` - CustomFields []string `json:"custom_fields,omitempty"` - SatisfactionRating []string `json:"satisfaction_rating,omitempty"` - SharingAgreementIds []int `json:"sharing_agreement_ids,omitempty"` - FollowupIds []int `json:"followup_ids,omitempty"` - TicketFormId int `json:"ticket_form_id,omitempty"` - BrandId int `json:"brand_id,omitempty"` - CreatedAt string `json:"created_at,omitempty"` - UpdatedAt string `json:"updated_at,omitempty"` + Id int `json:"id,omitempty"` + Url string `json:"url,omitempty"` + ExternalId string `json:"external_id,omitempty"` + Type string `json:"type,omitempty"` + Subject string `json:"subject,omitempty"` + RawSubject string `json:"raw_subject,omitempty"` + Description string `json:"description,omitempty"` + Priority string `json:"priority,omitempty"` + Status string `json:"status,omitempty"` + Recipient string `json:"recipient,omitempty"` + RequesterId int `json:"requester_id,omitempty"` + SubmitterId int `json:"submitter_id,omitempty"` + AssigneeId int `json:"assignee_id,omitempty"` + OrganizationId int `json:"organization_id,omitempty"` + GroupId int `json:"group_id,omitempty"` + CollaboratorsId []int `json:"collaborators_id,omitempty"` + ForumTopicId int `json:"forum_topic_id,omitempty"` + ProblemId int `json:"problem_id,omitempty"` + HasIncidents bool `json:"has_incidents,omitempty"` + DueAt string `json:"due_at,omitempty"` + Tags []string `json:"tags,omitempty"` + Via *Via `json:"via,omitempty"` + CustomFields []CustomFields `json:"custom_fields,omitempty"` + SatisfactionRating map[string]string `json:"satisfaction_rating,omitempty"` + SharingAgreementIds []int `json:"sharing_agreement_ids,omitempty"` + FollowupIds []int `json:"followup_ids,omitempty"` + TicketFormId int `json:"ticket_form_id,omitempty"` + BrandId int `json:"brand_id,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` } diff --git a/user_struct.go b/user_struct.go index 27a853c..6a5d3f4 100644 --- a/user_struct.go +++ b/user_struct.go @@ -1,8 +1,9 @@ package zendesk import ( - "github.com/ttacon/libphonenumber" "strings" + + "github.com/ttacon/libphonenumber" ) type ManyUsers struct { @@ -10,36 +11,36 @@ type ManyUsers struct { } type User struct { - Id int`json:"id,omitempty"` - Url string `json:"url,omitempty"` - Name string `json:"name,omitempty"` - ExternalId string `json:"external_id,omitempty"` - Alias string `json:"alias,omitempty"` - CreatedAt string `json:"created_at,omitempty"` - UpdatedAt string `json:"updated_at,omitempty"` - Active bool `json:"active,omitempty"` - Verified bool `json:"verified,omitempty"` - Shared bool `json:"shared,omitempty"` - SharedAgent bool `json:"shared_agent,omitempty"` - Locale string `json:"locale,omitempty"` - LocaleId int `json:"locale_id,omitempty"` - TimeZone string `json:"time_zone,omitempty"` - LastLoginAt string `json:"last_login_at,omitempty"` - Email string `json:"email,omitempty"` - Phone string `json:"phone,omitempty"` - Signature string `json:"signature,omitempty"` - Details string `json:"details,omitempty"` - Notes string `json:"notes,omitempty"` - OrganizationId int `json:"organization_id,omitempty"` - Role string `json:"role,omitempty"` - CustomRoleId string `json:"custom_role_id,omitempty"` - Moderator bool `json:"moderator,omitempty"` - TicketRestriction string `json:"ticket_restriction,omitempty"` - OnlyPrivateComments bool `json:"only_private_comments,omitempty"` - Tags []string `json:"tags,omitempty"` - Suspended bool `json:"suspended,omitempty"` - RestrictedAgent bool `json:"restricted_agent,omitempty"` - Photo *Attachment `json:"photo,omitempty"` + Id int `json:"id,omitempty"` + Url string `json:"url,omitempty"` + Name string `json:"name,omitempty"` + ExternalId string `json:"external_id,omitempty"` + Alias string `json:"alias,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + UpdatedAt string `json:"updated_at,omitempty"` + Active bool `json:"active,omitempty"` + Verified bool `json:"verified,omitempty"` + Shared bool `json:"shared,omitempty"` + SharedAgent bool `json:"shared_agent,omitempty"` + Locale string `json:"locale,omitempty"` + LocaleId int `json:"locale_id,omitempty"` + TimeZone string `json:"time_zone,omitempty"` + LastLoginAt string `json:"last_login_at,omitempty"` + Email string `json:"email,omitempty"` + Phone string `json:"phone,omitempty"` + Signature string `json:"signature,omitempty"` + Details string `json:"details,omitempty"` + Notes string `json:"notes,omitempty"` + OrganizationId int `json:"organization_id,omitempty"` + Role string `json:"role,omitempty"` + CustomRoleId string `json:"custom_role_id,omitempty"` + Moderator bool `json:"moderator,omitempty"` + TicketRestriction string `json:"ticket_restriction,omitempty"` + OnlyPrivateComments bool `json:"only_private_comments,omitempty"` + Tags []string `json:"tags,omitempty"` + Suspended bool `json:"suspended,omitempty"` + RestrictedAgent bool `json:"restricted_agent,omitempty"` + Photo *Attachment `json:"photo,omitempty"` UserFields map[string]interface{} `json:"user_fields,omitempty"` } @@ -56,4 +57,4 @@ func (users *ManyUsers) AppendUsers(user User) []User { users.Users = append(users.Users, user) return users.Users -} \ No newline at end of file +}