// FundraisingPageURLCheck checks the availability of a JustGiving fundraising page func (svc *Service) FundraisingPageURLCheck(pageShortName string) (avail bool, suggestions []string, err error) { // if page is not available we return some suggestions var suggs []string method := "HEAD" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/fundraising/pages/") path.WriteString(pageShortName) req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), nil) if err != nil { return false, suggs, err } res, _, err := api.Do(svc.client, svc.origin, "FundraisingPageURLCheck", req, "", svc.HTTPLogger) if err != nil { return false, suggs, err } // 404 is success, which is a bit dangerous, so we first make sure we have the correct JustGiving response header if res.Header.Get("X-Justgiving-Operation") != "FundraisingApi:FundraisingPageUrlCheck" { return false, suggs, fmt.Errorf("invalid response, expected X-Justgiving-Operation response header to be FundraisingApi:FundraisingPageUrlCheck but recieved %s", res.Header.Get("X-Justgiving-Operation")) } if res.StatusCode == 404 { return true, suggs, nil } if res.StatusCode != 200 { return false, suggs, fmt.Errorf("invalid response %s", res.Status) } // 200 - Page short name already registered // Return a list of suggestions path = bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/fundraising/pages/suggest?preferredName=") path.WriteString(url.QueryEscape(pageShortName)) req, err = api.BuildRequest(UserAgent, ContentType, "GET", path.String(), nil) res, resBody, err := api.Do(svc.client, svc.origin, "FundraisingPageURLCheck", req, "", svc.HTTPLogger) if err != nil { return false, suggs, err } var result = struct { Names []string }{} if err := json.Unmarshal([]byte(resBody), &result); err != nil { return false, suggs, fmt.Errorf("invalid response %v", err) } return false, result.Names, nil }
// Event returns the specified JustGiving event func (svc *Service) Event(eventID uint) (*models.Event, error) { var result models.Event method := "GET" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/event/") path.WriteString(strconv.FormatUint(uint64(eventID), 10)) req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), nil) if err != nil { return nil, err } res, resBody, err := api.Do(svc.client, svc.origin, "Event", req, "", svc.HTTPLogger) if err != nil { return nil, err } if res.StatusCode == 404 { return nil, nil } if res.StatusCode != 200 { return nil, fmt.Errorf("invalid response %s", res.Status) } if err = json.Unmarshal([]byte(resBody), &result); err != nil { return nil, fmt.Errorf("invalid response %v", err) } return &result, nil }
// FundraisingPagesForCharityAndUser returns the charity's fundraising pages registered with the specified JustGiving user account func (svc *Service) FundraisingPagesForCharityAndUser(charityID uint, account mail.Address) ([]*FundraisingPageRef, error) { var results []*FundraisingPageRef // mail.Address stores email in the format <*****@*****.**>, this simply removes the `<` `>` em := account.String() if em != "" { em = em[1 : len(em)-1] } method := "GET" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/account/") path.WriteString(em) path.WriteString("/pages/?charityId=") path.WriteString(strconv.FormatUint(uint64(charityID), 10)) req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), nil) if err != nil { return nil, err } res, resBody, err := api.Do(svc.client, svc.origin, "FundraisingPagesForCharityAndUser", req, "", svc.HTTPLogger) if err != nil { return nil, err } if res.StatusCode == 404 { return results, nil } if res.StatusCode != 200 { return nil, fmt.Errorf("invalid response %s", res.Status) } var result = []struct { EventID uint `json:"eventId"` PageID uint `json:"pageId"` PageShortName string `json:"pageShortName"` }{} if err := json.Unmarshal([]byte(resBody), &result); err != nil { return nil, fmt.Errorf("invalid response %v", err) } for _, p := range result { if p.PageID > 0 { results = append(results, &FundraisingPageRef{ charityID: charityID, eventID: p.EventID, id: p.PageID, shortName: p.PageShortName, }) } } return results, nil }
// RequestPasswordReminder requests JustGiving to send a password reset email func (svc *Service) RequestPasswordReminder(account mail.Address) error { method := "GET" // mail.Address stores email in the format <*****@*****.**>, we don't want the `<` `>` em := account.String() em = em[1 : len(em)-1] path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/account/") path.WriteString(em) path.WriteString("/requestpasswordreminder") req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), nil) if err != nil { return err } res, _, err := api.Do(svc.client, svc.origin, "RequestPasswordReminder", req, "", svc.HTTPLogger) if err != nil { return err } if res.StatusCode != 200 { return fmt.Errorf("invalid response %s", res.Status) } return nil }
func paginatedFundraisingPagesForEvent(svc *Service, eventID uint, pagination uint) (results []*FundraisingPageRef, totalPagination uint, totalFundraisingPages uint, err error) { method := "GET" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/event/") path.WriteString(strconv.FormatUint(uint64(eventID), 10)) path.WriteString("/pages/?pageSize=100") // set pagination pg := "1" if pagination > 0 { pg = strconv.FormatUint(uint64(pagination), 10) } req, err := api.BuildRequest(UserAgent, ContentType, method, path.String()+"&page="+pg, nil) if err != nil { return nil, 0, 0, err } res, resBody, err := api.Do(svc.client, svc.origin, "FundraisingPagesForEvent", req, "", svc.HTTPLogger) if err != nil { return nil, 0, 0, err } if res.StatusCode != 200 { return nil, 0, 0, fmt.Errorf("invalid response %s", res.Status) } type page struct { CharityID uint `json:"charityId"` PageID uint `json:"pageId"` PageShortName string `json:"pageShortName"` } var result = struct { TotalPagination uint `json:"totalPages"` TotalFundraisingPages uint `json:"totalFundraisingPages"` FundraisingPages []page `json:"fundraisingPages"` }{} if err := json.Unmarshal([]byte(resBody), &result); err != nil { return nil, 0, 0, fmt.Errorf("invalid response %v", err) } for _, p := range result.FundraisingPages { if p.PageID > 0 { results = append(results, &FundraisingPageRef{ charityID: p.CharityID, eventID: eventID, id: p.PageID, shortName: p.PageShortName, }) } } return results, result.TotalPagination, result.TotalFundraisingPages, nil }
// Validate a set of supplied user credentials against the JustGiving database func (svc *Service) Validate(account mail.Address, password string) (valid bool, err error) { method := "POST" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/account/validate") // mail.Address stores email in the format <*****@*****.**>, we don't want the `<` `>` em := account.String() em = em[1 : len(em)-1] data := struct { Email string Password string }{em, password} sBody, body, err := api.BuildBody("Validate", data, ContentType) if err != nil { return false, err } req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), body) if err != nil { return false, err } res, resBody, err := api.Do(svc.client, svc.origin, "Validate", req, sBody, svc.HTTPLogger) if err != nil { return false, err } if res.StatusCode != 200 { return false, fmt.Errorf("invalid response %s", res.Status) } var result = struct { IsValid bool `json:"isValid"` }{} if err := json.Unmarshal([]byte(resBody), &result); err != nil { return false, fmt.Errorf("invalid response %v", err) } return result.IsValid, nil }
// IsValidCountry checks the Country used by models.Account is in the published JustGiving countries list func (svc *Service) IsValidCountry(name string) (bool, error) { method := "GET" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/countries") req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), nil) if err != nil { return false, err } res, resBody, err := api.Do(svc.client, svc.origin, "IsValidCountry", req, "", svc.HTTPLogger) if err != nil { return false, err } if res.StatusCode != 200 { return false, fmt.Errorf("invalid response %s", res.Status) } var result = []struct { Name string `json:"name"` }{} if err := json.Unmarshal([]byte(resBody), &result); err != nil { return false, fmt.Errorf("invalid response %v", err) } for _, c := range result { if name == c.Name { return true, nil } } return false, nil }
// AccountRegistration registers a new user account with JustGiving func (svc *Service) AccountRegistration(account models.Account) (err error) { method := "PUT" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/account/") sBody, body, err := api.BuildBody("AccountRegistration", account, ContentType) if err != nil { return err } req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), body) if err != nil { return err } res, _, err := api.Do(svc.client, svc.origin, "AccountRegistration", req, sBody, svc.HTTPLogger) if err != nil { return err } if res.StatusCode != 200 { // run request validation on failure info := "no errors found" valid, err := account.HasValidCountry(svc) if err != nil { info = fmt.Sprintf("errors running validation %v", err) } else { if !valid { info = "invalid Country" } } return fmt.Errorf("invalid response %s, result of running validation on request payload was: %s", res.Status, info) } return nil }
// AccountAvailabilityCheck checks the availability of a JustGiving account by email address func (svc *Service) AccountAvailabilityCheck(account mail.Address) (avail bool, err error) { method := "HEAD" // mail.Address stores email in the format <*****@*****.**>, we don't want the `<` `>` em := account.String() em = em[1 : len(em)-1] path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/account/") path.WriteString(em) req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), nil) if err != nil { return false, err } res, _, err := api.Do(svc.client, svc.origin, "AccountAvailabilityCheck", req, "", svc.HTTPLogger) if err != nil { return false, err } // 404 is success (available), which is a bit dangerous, so we first make sure we have the correct JustGiving response header if res.Header.Get("X-Justgiving-Operation") != "AccountApi:AccountAvailabilityCheck" { return false, fmt.Errorf("invalid response, expected X-Justgiving-Operation response header to be AccountApi:AccountAvailabilityCheck but recieved %s", res.Header.Get("X-Justgiving-Operation")) } if res.StatusCode == 404 { return true, nil } if res.StatusCode != 200 { return false, fmt.Errorf("invalid response %s", res.Status) } // 200 - account exists return false, nil }
// FundraisingPageResults returns the current fundraising results for the specified JustGiving page func (svc *Service) FundraisingPageResults(page *FundraisingPageRef) (models.FundraisingResults, error) { var result models.FundraisingResults method := "GET" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/fundraising/pages/") path.WriteString(page.shortName) req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), nil) if err != nil { return result, err } res, resBody, err := api.Do(svc.client, svc.origin, "FundraisingPageResults", req, "", svc.HTTPLogger) if err != nil { return result, err } if res.StatusCode == 410 { result.PageCancelled = true return result, nil } if res.StatusCode != 200 { return result, fmt.Errorf("invalid response %s", res.Status) } result = models.FundraisingResults{} if err = json.Unmarshal([]byte(resBody), &result); err != nil { return result, fmt.Errorf("invalid response %v", err) } return result, nil }
// RegisterFundraisingPageForEvent registers a fundraising page on the JustGiving website func (svc *Service) RegisterFundraisingPageForEvent(account mail.Address, password string, page models.FundraisingPageForEvent) (pageURL *url.URL, signOnURL *url.URL, err error) { method := "PUT" path := bytes.NewBuffer([]byte(svc.BasePath)) path.WriteString("/") path.WriteString(svc.APIKey) path.WriteString("/v1/fundraising/pages") sBody, body, err := api.BuildBody("RegisterFundraisingPageForEvent", page, ContentType) if err != nil { return nil, nil, err } req, err := api.BuildRequest(UserAgent, ContentType, method, path.String(), body) if err != nil { return nil, nil, err } // This request requires authentication // mail.Address stores email in the format <*****@*****.**>, we don't want the `<` `>` em := account.String() em = em[1 : len(em)-1] req.SetBasicAuth(em, password) res, resBody, err := api.Do(svc.client, svc.origin, "RegisterFundraisingPageForEvent", req, sBody, svc.HTTPLogger) if err != nil { return nil, nil, err } //201 Created if res.StatusCode != 201 { // run request validation on failure var info string var valid bool valid, err = page.HasValidCurrencyCode(svc) if err != nil { info = fmt.Sprintf("errors running CurrencyCode validation %v; ", err) } else { if !valid { info = "invalid CurrencyCode; " } } valid = page.HasValidTargetAmount() if !valid { info += "invalid TargetAmount" } if info == "" { info = "no errors found" } return nil, nil, fmt.Errorf("invalid response %s, result of running validation on request payload was: %s", res.Status, info) } // Read page URL and signon URL from response var result = struct { SignOnURL string `json:"signOnUrl"` Page struct { URL string `json:"uri"` } `json:"next"` }{} if err = json.Unmarshal([]byte(resBody), &result); err != nil { return nil, nil, fmt.Errorf("invalid response %v", err) } pageURL, err = url.Parse(result.Page.URL) if err != nil { return nil, nil, fmt.Errorf("invalid response %v", err) } signOnURL, err = url.Parse(result.SignOnURL) if err != nil { return nil, nil, fmt.Errorf("invalid response %v", err) } return pageURL, signOnURL, nil }