feat: added support for longterm access tokens.

This commit is contained in:
Andrey Parhomenko 2024-02-22 10:05:33 +05:00
parent dfa4fcb54e
commit ebd4866455
2 changed files with 36 additions and 29 deletions

View file

@ -29,7 +29,8 @@ type ClientOptions struct {
ClientSecret string `json:"client_secret"` ClientSecret string `json:"client_secret"`
AccessToken string `json:"access_token"` AccessToken string `json:"access_token"`
ExpirationAt time.Time `json:"expiration_at"`
ExpirationAt time.Time `json:"expiration_at,omitempty"`
RefreshToken string `json:"refresh_token"` RefreshToken string `json:"refresh_token"`
} }
@ -66,6 +67,7 @@ func NewApi(secretPath string) (*Client, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
fmt.Println("opts:", options)
if options.Url == "" || options.RedirectUrl == "" { if options.Url == "" || options.RedirectUrl == "" {
return nil, errors.New("AmoCrm: Invalid options: Url") return nil, errors.New("AmoCrm: Invalid options: Url")
@ -87,7 +89,7 @@ func NewApi(secretPath string) (*Client, error) {
exchangeErr error exchangeErr error
exchanged bool exchanged bool
) )
if ret.options.AccessToken == "" || ret.options.RefreshToken == "" { if ret.options.AccessToken == "" && ret.options.RefreshToken == "" {
if ret.options.ClientSecret == "" || if ret.options.ClientSecret == "" ||
ret.options.ClientId == "" || ret.options.ClientId == "" ||
ret.options.AuthCode == "" { ret.options.AuthCode == "" {
@ -97,7 +99,7 @@ func NewApi(secretPath string) (*Client, error) {
exchanged = true exchanged = true
} }
if !exchanged || exchangeErr != nil { if (!exchanged || exchangeErr != nil) && options.RefreshToken != "" {
// Refreshing token before the work. // Refreshing token before the work.
// Should think of how often should refresh // Should think of how often should refresh
// the token. (see the ExpiresIn) // the token. (see the ExpiresIn)
@ -147,7 +149,7 @@ func (api *Client) writeSecret() error {
return err return err
} }
func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, result interface{}) error { func (api *Client) rdoRequest(resourceUrl string, requestParams requestOptions, result interface{}) error {
var ( var (
requestUrl *url.URL requestUrl *url.URL
err error err error
@ -190,6 +192,9 @@ func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, r
if api.Debug { if api.Debug {
fmt.Printf("\nAmo request: %+v\nAmo repsonse: %+v\n", request, response) fmt.Printf("\nAmo request: %+v\nAmo repsonse: %+v\n", request, response)
} }
if response == nil {
return NoInternetErr
}
if err != nil { if err != nil {
return errors.New(fmt.Sprintf( return errors.New(fmt.Sprintf(
"Request error: %s %d %s %s", "Request error: %s %d %s %s",
@ -205,17 +210,9 @@ func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, r
} }
if response.StatusCode >= 400 { if response.StatusCode >= 400 {
/*if response.StatusCode == 401 { if response.StatusCode == 401 {
_, err := api.RefreshToken() return NoAuthErr
if err != nil { }
return err
}
return api.doRequest(
resourceUrl,
requestParams,
result,
)
}*/
bodyBytes, _ := ioutil.ReadAll(response.Body) bodyBytes, _ := ioutil.ReadAll(response.Body)
return errors.New(fmt.Sprintf( return errors.New(fmt.Sprintf(
@ -237,7 +234,23 @@ func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, r
return nil return nil
} }
func (api *Client) doRequest(
resourceUrl string, requestParams requestOptions, result any,
) error {
var err error
err = api.rdoRequest(resourceUrl, requestParams, result)
if err == NoAuthErr && api.options.RefreshToken != "" {
_, err = api.RefreshToken()
if err != nil {
return nil
}
return api.rdoRequest(resourceUrl, requestParams, result)
} else if err != nil {
return err
}
return nil
}
func (api *Client) ExchangeAuth() (*TokenPair, error) { func (api *Client) ExchangeAuth() (*TokenPair, error) {
result := &OauthTokenResponse{} result := &OauthTokenResponse{}
@ -249,7 +262,7 @@ func (api *Client) ExchangeAuth() (*TokenPair, error) {
"redirect_uri": api.options.RedirectUrl, "redirect_uri": api.options.RedirectUrl,
} }
err := api.doRequest("/oauth2/access_token", requestOptions{ err := api.rdoRequest("/oauth2/access_token", requestOptions{
HttpMethod: http.MethodPost, HttpMethod: http.MethodPost,
Body: request, Body: request,
Headers: getHeaders(""), Headers: getHeaders(""),
@ -277,6 +290,10 @@ func (api *Client) ExchangeAuth() (*TokenPair, error) {
} }
func (api *Client) RefreshTokenIfExpired() error { func (api *Client) RefreshTokenIfExpired() error {
if api.options.RefreshToken == "" {
return nil
}
now := time.Now() now := time.Now()
if now.After(api.options.ExpirationAt) || now.Equal(api.options.ExpirationAt){ if now.After(api.options.ExpirationAt) || now.Equal(api.options.ExpirationAt){
_, err := api.RefreshToken() _, err := api.RefreshToken()
@ -297,7 +314,7 @@ func (api *Client) RefreshToken() (*OauthTokenResponse, error) {
"redirect_uri": api.options.RedirectUrl, "redirect_uri": api.options.RedirectUrl,
} }
err := api.doRequest("/oauth2/access_token", requestOptions{ err := api.rdoRequest("/oauth2/access_token", requestOptions{
HttpMethod: http.MethodPost, HttpMethod: http.MethodPost,
Body: request, Body: request,
Headers: getHeaders(""), Headers: getHeaders(""),
@ -325,10 +342,6 @@ func (api *Client) Get(resource string, result interface{}, abs ...bool) error {
if len(abs) > 0 { if len(abs) > 0 {
a = abs[0] a = abs[0]
} }
err := api.RefreshTokenIfExpired()
if err != nil {
return err
}
return api.doRequest(resource, requestOptions{ return api.doRequest(resource, requestOptions{
HttpMethod: http.MethodGet, HttpMethod: http.MethodGet,
Body: nil, Body: nil,
@ -338,10 +351,6 @@ func (api *Client) Get(resource string, result interface{}, abs ...bool) error {
} }
func (api *Client) Post(resource string, request interface{}, result interface{}) error { func (api *Client) Post(resource string, request interface{}, result interface{}) error {
err := api.RefreshTokenIfExpired()
if err != nil {
return err
}
return api.doRequest(resource, requestOptions{ return api.doRequest(resource, requestOptions{
HttpMethod: http.MethodPost, HttpMethod: http.MethodPost,
Body: request, Body: request,
@ -350,10 +359,6 @@ func (api *Client) Post(resource string, request interface{}, result interface{}
} }
func (api *Client) Patch(resource string, request interface{}, result interface{}) error { func (api *Client) Patch(resource string, request interface{}, result interface{}) error {
err := api.RefreshTokenIfExpired()
if err != nil {
return err
}
return api.doRequest(resource, requestOptions{ return api.doRequest(resource, requestOptions{
HttpMethod: http.MethodPatch, HttpMethod: http.MethodPatch,
Body: request, Body: request,

View file

@ -6,4 +6,6 @@ import (
var ( var (
NoContentErr = errors.New("no content") NoContentErr = errors.New("no content")
NoAuthErr = errors.New("not authorized")
NoInternetErr = errors.New("no Internet provided")
) )