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

View file

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