diff --git a/3.0/connectwise/company.go b/3.0/connectwise/company.go index 4efe5e5..f51cbb8 100644 --- a/3.0/connectwise/company.go +++ b/3.0/connectwise/company.go @@ -148,31 +148,49 @@ type Company struct { //GetCompanyByName expects an exact match, perhaps an improvement could be made to support wildcard characters. //Will return a pointer to a slice of Company's. -func (cw *ConnectwiseSite) GetCompanyByName(companyName string) *[]Company { +func (cw *ConnectwiseSite) GetCompanyByName(companyName string) (*[]Company, error) { + restAction := "/company/companies" + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } - cwurl := cw.BuildURL("/company/companies") parameters := url.Values{} parameters.Add("conditions", "name=\""+companyName+"\"") cwurl.RawQuery = parameters.Encode() - body := cw.GetRequest(cwurl) + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } companies := []Company{} - check(json.Unmarshal(body, &companies)) + err = json.Unmarshal(body, &companies) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - return &companies + return &companies, nil } //GetCompanyByID expects the Connectwise Company ID and returns a pointer to a Company //Does not return a slice like GetCompanyByName as the ID will only ever have one match -func (cw *ConnectwiseSite) GetCompanyByID(companyID int) *Company { +func (cw *ConnectwiseSite) GetCompanyByID(companyID int) (*Company, error) { + restAction := fmt.Sprintf("/company/companies/%d", companyID) + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } + + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } company := Company{} + err = json.Unmarshal(body, &company) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - cwurl := cw.BuildURL(fmt.Sprintf("/company/companies/%d", companyID)) - - body := cw.GetRequest(cwurl) - fmt.Print(string(body)) - check(json.Unmarshal(body, &company)) - - return &company + return &company, nil } diff --git a/3.0/connectwise/connectwise.go b/3.0/connectwise/connectwise.go index c6074e0..239cfb3 100644 --- a/3.0/connectwise/connectwise.go +++ b/3.0/connectwise/connectwise.go @@ -3,7 +3,6 @@ package connectwise import ( "encoding/base64" "fmt" - "log" ) //ConnectwiseSite is a stuct containing the URL of the site and the API authorization token in the format that CW expects it. @@ -12,12 +11,6 @@ type ConnectwiseSite struct { Auth string } -func check(err error) { - if err != nil { - log.Fatal(err) - } -} - //NewSite returns a pointer to a ConnectwiseSite struct with the site and auth string available for use in API requests func NewSite(site string, publicKey string, privateKey string, company string) *ConnectwiseSite { //The auth string must be formatted in this way when used in requests to the API diff --git a/3.0/connectwise/finance.go b/3.0/connectwise/finance.go index 1195741..d8710f3 100644 --- a/3.0/connectwise/finance.go +++ b/3.0/connectwise/finance.go @@ -115,42 +115,70 @@ type Agreement struct { } `json:"billToSite,omitempty"` } -//GetAgreements returns a list of agreements, not paginated and currently not that usefule +//GetAgreements returns a list of agreements, not paginated and currently not that useful //TBD: Pagination and filtering options still need to be considered -func (cw *ConnectwiseSite) GetAgreements() *[]Agreement { +func (cw *ConnectwiseSite) GetAgreements() (*[]Agreement, error) { + restAction := "/finance/agreements" + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } - //Build the request URL - cwurl := cw.BuildURL("/finance/agreements") - - body := cw.GetRequest(cwurl) + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } agreements := []Agreement{} - check(json.Unmarshal(body, &agreements)) + err = json.Unmarshal(body, &agreements) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - return &agreements + return &agreements, nil } -func (cw *ConnectwiseSite) GetAgreementsByCompanyName(companyName string) *[]Agreement { +//GetAgreementsByCompanyName returns a list of agreements that belong to an exact matching company name +//TBD: Pagination and filtering options still need to be considered +func (cw *ConnectwiseSite) GetAgreementsByCompanyName(companyName string) (*[]Agreement, error) { + restAction := "/finance/agreements" + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } - cwurl := cw.BuildURL("/finance/agreements") parameters := url.Values{} parameters.Add("conditions", "company/name=\""+companyName+"\"") cwurl.RawQuery = parameters.Encode() - body := cw.GetRequest(cwurl) + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } agreements := []Agreement{} - check(json.Unmarshal(body, &agreements)) + err = json.Unmarshal(body, &agreements) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - return &agreements + return &agreements, nil } //GetBillingCycles is not complete //TBD: Finish this. +/* func (cw *ConnectwiseSite) GetBillingCycles() { + restAction := "/finance/billingCycles" + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } - cwurl := cw.BuildURL("/finance/billingCycles") - - body := cw.GetRequest(cwurl) + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } fmt.Print(string(body)) // check(json.Unmarshal(body, &ticket)) } +*/ diff --git a/3.0/connectwise/requests.go b/3.0/connectwise/requests.go index fe69149..cdf645d 100644 --- a/3.0/connectwise/requests.go +++ b/3.0/connectwise/requests.go @@ -4,74 +4,99 @@ import ( "fmt" "io" "io/ioutil" - "log" "net/http" "net/url" ) //BuildURL will take a REST action such as "/companies/company/5" and then append the CW site to it and return a pointer to a url.URL -func (cw *ConnectwiseSite) BuildURL(restAction string) *url.URL { +func (cw *ConnectwiseSite) BuildURL(restAction string) (*url.URL, error) { var cwurl *url.URL cwurl, err := url.Parse(cw.Site) - check(err) + if err != nil { + return nil, fmt.Errorf("could not %s as url: %g", cw.Site, err) + } cwurl.Path += restAction - return cwurl + return cwurl, nil } //Checks for HTTP errors, and if all looks good, returns the body of the HTTP response as a byte slice //TBD: Needs to accept 201 and 204 (returned for Create and Delete operations) -func getHTTPResponseBody(resp *http.Response) []byte { +func getHTTPResponseBody(resp *http.Response) ([]byte, error) { if (resp.StatusCode != http.StatusOK) && (resp.StatusCode != http.StatusCreated) && (resp.StatusCode != http.StatusNoContent) { - out := fmt.Sprintf("CW API returned HTTP Status Code %s\n%s", resp.Status, resp.Body) - log.Fatal(out) - return make([]byte, 0) + return nil, fmt.Errorf("cw api returned unexpected http status %i - %s", resp.StatusCode, resp.Status) + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("could not read response body of request") } - body, err := ioutil.ReadAll(resp.Body) - check(err) - - return body + return body, nil } //GetRequest takes a ConnectwiseSite and request URL, and returns the body of the response -func (cw *ConnectwiseSite) GetRequest(cwurl *url.URL) []byte { +func (cw *ConnectwiseSite) GetRequest(cwurl *url.URL) ([]byte, error) { client := &http.Client{} req, err := http.NewRequest("GET", cwurl.String(), nil) - check(err) + if err != nil { + return nil, fmt.Errorf("could not construct http request: %g", err) + } req.Header.Set("Authorization", cw.Auth) req.Header.Set("Content-Type", "application/json") response, err := client.Do(req) - check(err) - defer response.Body.Close() + if err != nil { + return nil, fmt.Errorf("could not perform http get request: %g", err) + } - return getHTTPResponseBody(response) + body, err := getHTTPResponseBody(response) + if err != nil { + return nil, fmt.Errorf("could not get http response body: %g", err) + } + + return body, nil } //PostRequest takes a ConnectwiseSite and request URL, and returns the body of the response -func (cw *ConnectwiseSite) PostRequest(cwurl *url.URL, body io.Reader) []byte { +func (cw *ConnectwiseSite) PostRequest(cwurl *url.URL, reqBody io.Reader) ([]byte, error) { client := &http.Client{} - req, err := http.NewRequest("POST", cwurl.String(), body) - check(err) + req, err := http.NewRequest("POST", cwurl.String(), reqBody) + if err != nil { + return nil, fmt.Errorf("could not construct http request: %g", err) + } req.Header.Set("Authorization", cw.Auth) req.Header.Set("Content-Type", "application/json") response, err := client.Do(req) - check(err) - defer response.Body.Close() + if err != nil { + return nil, fmt.Errorf("could not perform http post request: %g", err) + } - return getHTTPResponseBody(response) + body, err := getHTTPResponseBody(response) + if err != nil { + return nil, fmt.Errorf("could not get http response body: %g", err) + } + + return body, nil } //DeleteRequest takes a ConnectwiseSite and request URL, and returns the body of the response -func (cw *ConnectwiseSite) DeleteRequest(cwurl *url.URL) []byte { +func (cw *ConnectwiseSite) DeleteRequest(cwurl *url.URL) ([]byte, error) { client := &http.Client{} req, err := http.NewRequest("DELETE", cwurl.String(), nil) - check(err) + if err != nil { + return nil, fmt.Errorf("could not construct http request: %g", err) + } req.Header.Set("Authorization", cw.Auth) req.Header.Set("Content-Type", "application/json") response, err := client.Do(req) - check(err) - defer response.Body.Close() + if err != nil { + return nil, fmt.Errorf("could not perform http delete request: %g", err) + } - return getHTTPResponseBody(response) + body, err := getHTTPResponseBody(response) + if err != nil { + return nil, fmt.Errorf("could not get http response body: %g", err) + } + + return body, nil } diff --git a/3.0/connectwise/service.go b/3.0/connectwise/service.go index b326670..2600cc5 100644 --- a/3.0/connectwise/service.go +++ b/3.0/connectwise/service.go @@ -192,36 +192,63 @@ type ConfigurationReference struct { } //GetTicketByID expects a ticket ID and returns a pointer to a Ticket struct -func (cw *ConnectwiseSite) GetTicketByID(ticketID int) *Ticket { +func (cw *ConnectwiseSite) GetTicketByID(ticketID int) (*Ticket, error) { + restAction := fmt.Sprintf("/service/tickets/%d", ticketID) + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } - cwurl := cw.BuildURL(fmt.Sprintf("/service/tickets/%d", ticketID)) - - body := cw.GetRequest(cwurl) + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } ticket := Ticket{} - check(json.Unmarshal(body, &ticket)) + err = json.Unmarshal(body, &ticket) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - return &ticket + return &ticket, nil } //GetTicketTimeEntriesByID expects a ticket ID and returns a pointer a to a slice of TimeEntryReference's, all the time entries attached to that ticket -func (cw *ConnectwiseSite) GetTicketTimeEntriesByID(ticketID int) *[]TimeEntryReference { +func (cw *ConnectwiseSite) GetTicketTimeEntriesByID(ticketID int) (*[]TimeEntryReference, error) { + restAction := fmt.Sprintf("/service/tickets/%d/timeentries", ticketID) + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } - cwurl := cw.BuildURL(fmt.Sprintf("/service/tickets/%d/timeentries", ticketID)) - - body := cw.GetRequest(cwurl) + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } timeEntryReference := []TimeEntryReference{} - check(json.Unmarshal(body, &timeEntryReference)) // *[]TimeEntryReference + err = json.Unmarshal(body, &timeEntryReference) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - return &timeEntryReference + return &timeEntryReference, nil } -func (cw *ConnectwiseSite) GetTicketConfigurationsByID(ticketID int) *[]ConfigurationReference { +func (cw *ConnectwiseSite) GetTicketConfigurationsByID(ticketID int) (*[]ConfigurationReference, error) { + restAction := fmt.Sprintf("/service/tickets/%d/configurations", ticketID) + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } - cwurl := cw.BuildURL(fmt.Sprintf("/service/tickets/%d/configurations", ticketID)) - - body := cw.GetRequest(cwurl) + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } configurationReference := []ConfigurationReference{} - check(json.Unmarshal(body, &configurationReference)) + err = json.Unmarshal(body, &configurationReference) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - return &configurationReference + return &configurationReference, nil } diff --git a/3.0/connectwise/system.go b/3.0/connectwise/system.go index c5d4fb8..028b450 100644 --- a/3.0/connectwise/system.go +++ b/3.0/connectwise/system.go @@ -17,35 +17,61 @@ type Callback struct { InactiveFlag bool } -func (cw *ConnectwiseSite) GetCallbacks() *[]Callback { - - URL := cw.BuildURL("/system/callbacks") - body := cw.GetRequest(URL) +func (cw *ConnectwiseSite) GetCallbacks() (*[]Callback, error) { + restAction := "/system/callbacks" + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } callbacks := []Callback{} - check(json.Unmarshal(body, &callbacks)) + err = json.Unmarshal(body, &callbacks) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - return &callbacks + return &callbacks, nil } -//TBD: This should return something? -func (cw *ConnectwiseSite) NewCallback(callback Callback) { +//TBD: This should return something useful, response body?? +func (cw *ConnectwiseSite) NewCallback(callback Callback) error { + restAction := "/system/callbacks" + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return fmt.Errorf("could not build url %s: %g", restAction, err) + } - URL := cw.BuildURL("/system/callbacks") jsonCallback, err := json.Marshal(callback) - check(err) + if err != nil { + return fmt.Errorf("could not marshal json data: %g", err) + } jsonBuffer := bytes.NewReader(jsonCallback) - cw.PostRequest(URL, jsonBuffer) + _, err = cw.PostRequest(cwurl, jsonBuffer) + if err != nil { + return fmt.Errorf("could not post request %s: %g", cwurl, err) + } + return nil } -func (cw *ConnectwiseSite) DeleteCallback(callback int) { - - URL := cw.BuildURL(fmt.Sprintf("/system/callbacks/%d", callback)) - body := cw.DeleteRequest(URL) - fmt.Print(string(body)) +//TBD: This should return something useful, response body?? +func (cw *ConnectwiseSite) DeleteCallback(callback int) error { + restAction := fmt.Sprintf("/system/callbacks/%d", callback) + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return fmt.Errorf("could not build url %s: %g", restAction, err) + } + _, err = cw.DeleteRequest(cwurl) + if err != nil { + return fmt.Errorf("could not delete request %s: %g", cwurl, err) + } + return nil } diff --git a/3.0/connectwise/time.go b/3.0/connectwise/time.go index 1291fd3..985c8cc 100644 --- a/3.0/connectwise/time.go +++ b/3.0/connectwise/time.go @@ -83,15 +83,23 @@ type TimeEntry struct { } } -func (cw *ConnectwiseSite) GetTimeEntryByID(timeEntryID int) *TimeEntry { +func (cw *ConnectwiseSite) GetTimeEntryByID(timeEntryID int) (*TimeEntry, error) { + restAction := fmt.Sprintf("/time/entries/%d", timeEntryID) + cwurl, err := cw.BuildURL(restAction) + if err != nil { + return nil, fmt.Errorf("could not build url %s: %g", restAction, err) + } - Url := cw.BuildURL(fmt.Sprintf("/time/entries/%d", timeEntryID)) - - body := cw.GetRequest(Url) - fmt.Print(string(body)) + body, err := cw.GetRequest(cwurl) + if err != nil { + return nil, fmt.Errorf("could not get request %s: %g", cwurl, err) + } timeEntry := TimeEntry{} - check(json.Unmarshal(body, &timeEntry)) + err = json.Unmarshal(body, &timeEntry) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal body into struct: %g", err) + } - return &timeEntry + return &timeEntry, nil }