From eaad1cbc063092fbcc541c67ab77a8e1be37e065 Mon Sep 17 00:00:00 2001 From: surdeus Date: Mon, 15 Jan 2024 03:48:01 +0300 Subject: [PATCH] feat: better for simple authorization. --- .gitignore | 2 +- amocrm.go | 15 ++++++--- api/api.go | 80 +++++++++++++++++++++++++++++++++++++++++++----- cmd/test/main.go | 77 ++++++++++++++++++++++++++++++++++++++++++++++ env.sh | 5 +++ taskfile.yml | 6 ++++ 6 files changed, 171 insertions(+), 14 deletions(-) create mode 100644 cmd/test/main.go create mode 100644 env.sh create mode 100644 taskfile.yml diff --git a/.gitignore b/.gitignore index 0d80f2f..b04b0f3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.exe *.exe~ - +.env diff --git a/amocrm.go b/amocrm.go index 8ff0cff..35f716b 100644 --- a/amocrm.go +++ b/amocrm.go @@ -19,19 +19,24 @@ type IAmoClient interface { UpdateContact(contact *contacts.Contact) error } +type TokenPair = api.TokenPair +type Options = api.ClientOptions + type Client struct { Api *api.Client } -func NewAmoClient(options *api.ClientOptions) (*Client, error) { - apiClient, err := api.NewClient(options) +type OauthTokenResponse = api.OauthTokenResponse + +func NewAmoClient(options *Options ) (*Client, *TokenPair, error) { + apiClient, pair, err := api.NewClient(options) if err != nil { - return nil, err + return nil, nil, err } return &Client{ Api: apiClient, - }, nil + }, pair, nil } func (client *Client) updateEntity(url string, id int, body interface{}) error { @@ -78,7 +83,7 @@ func (client *Client) UpdateCompany(company *companies.Company) error { func (client *Client) GetContact(contactId string, query string) (*contacts.Contact, error) { deal := new(contacts.Contact) resource := fmt.Sprintf("/api/v4/contacts/%s", contactId) - if len(query) != 0 { + if query != "" { resource = resource + "?" + query } diff --git a/api/api.go b/api/api.go index 741dcb1..ced96a5 100644 --- a/api/api.go +++ b/api/api.go @@ -18,8 +18,13 @@ const ( type ClientOptions struct { Url string + RedirectUrl string + + AuthCode string + ClientId string ClientSecret string + AccessToken string RefreshToken string } @@ -42,20 +47,37 @@ type OauthTokenResponse struct { RefreshToken string `json:"refresh_token"` } -func NewClient(options *ClientOptions) (*Client, error) { - if len(options.AccessToken) == 0 || len(options.RefreshToken) == 0 || len(options.Url) == 0 { - return nil, errors.New("AmoCrm: Invalid options") - } +type TokenPair struct { + Access, Refresh string +} +func NewClient(options *ClientOptions) (*Client, *TokenPair, error) { + if options.Url == "" { + return nil, nil, errors.New("AmoCrm: Invalid options: Url") + } resolvedUrl, err := url.Parse(options.Url) if err != nil { - return nil, err + return nil, nil, err } + ret := &Client{ + options: options, + } + ret.BaseUrl = resolvedUrl + + var pair *TokenPair + if options.AccessToken == "" || options.RefreshToken == "" { + pair, err = ret.ExchangeAuth() + if err != nil { + return nil, nil, err + } + } + + return &Client{ options: options, BaseUrl: resolvedUrl, - }, nil + }, pair, nil } func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, result interface{}) error { @@ -87,13 +109,25 @@ func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, r response, err := http.DefaultClient.Do(request) if err != nil { - return errors.New(fmt.Sprintf("Request error: %s %d %s %s", err.Error(), response.StatusCode, requestParams.HttpMethod, resourceUrl)) + return errors.New(fmt.Sprintf( + "Request error: %s %d %s %s", + err.Error(), + response.StatusCode, + requestParams.HttpMethod, + resourceUrl, + )) } defer response.Body.Close() if response.StatusCode >= 400 { bodyBytes, _ := ioutil.ReadAll(response.Body) - return errors.New(fmt.Sprintf("%s %d %s %s", string(bodyBytes), response.StatusCode, requestParams.HttpMethod, resourceUrl)) + return errors.New(fmt.Sprintf( + "%s %d %s %s", + string(bodyBytes), + response.StatusCode, + requestParams.HttpMethod, + resourceUrl, + )) } if result != nil { @@ -107,6 +141,36 @@ func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, r return nil } + +func (api *Client) ExchangeAuth() (*TokenPair, error) { + result := &OauthTokenResponse{} + request := map[string] string { + "client_id": api.options.ClientId, + "client_secret": api.options.ClientSecret, + "grant_type": "authorization_code", + "code": api.options.AuthCode, + "redirect_uri": api.options.RedirectUrl, + } + + err := api.doRequest("/oauth2/access_token", requestOptions{ + HttpMethod: http.MethodPost, + Body: request, + Headers: getHeaders(""), + }, result) + if err != nil { + return nil, err + } + + ret := &TokenPair{ + Access: result.AccessToken, + Refresh: result.RefreshToken, + } + + api.options.AccessToken = result.AccessToken + api.options.RefreshToken = result.RefreshToken + return ret, nil +} + func (api *Client) RefreshToken() (*OauthTokenResponse, error) { result := new(OauthTokenResponse) request := map[string]string{ diff --git a/cmd/test/main.go b/cmd/test/main.go new file mode 100644 index 0000000..ead4c2e --- /dev/null +++ b/cmd/test/main.go @@ -0,0 +1,77 @@ +package main + +import ( + "vultras.su/core/amo" + "vultras.su/core/bond" + "vultras.su/core/bond/statuses" + "os" + "fmt" + "io" +) + +type Context = bond.Context + +var root = bond.Root(bond.Path(). +Def( + "hook", + bond.Func(func(c *Context){ + v := map[string]any{} + c.Scan(&v) + if c.ScanErr() != nil { + fmt.Println("scan-err:", c.ScanErr()) + } + fmt.Println("request:", v) + + c.SetStatus(statuses.OK) + }), +).Def( + "auth", + bond.Func(func(c *Context){ + fmt.Println("header:", c.R.Header) + fmt.Println("content-type:", c.ContentType()) + bts, _ := io.ReadAll(c.R.Body) + fmt.Println("request:", string(bts)) + c.SetStatus(statuses.OK) + return + v := map[string]any{} + c.Scan(&v) + if c.ScanErr() != nil { + fmt.Println("scan-err:", c.ScanErr()) + } + fmt.Println("request:", v) + + c.SetStatus(statuses.OK) + }), +)) + +func main() { + srv := bond.Server{ + Addr: ":15080", + Handler: root, + } + go srv.ListenAndServe() + + opts := &amo.Options{ + Url: os.Getenv("AMO_URL"), + RedirectUrl: os.Getenv("AMO_REDIRECT_URL"), + AccessToken: os.Getenv("AMO_ACCESS"), + RefreshToken: os.Getenv("AMO_REFRESH"), + ClientSecret: os.Getenv("AMO_CLIENT_SECRET"), + ClientId: os.Getenv("AMO_CLIENT_ID"), + AuthCode: os.Getenv("AMO_AUTH_CODE"), + } + fmt.Println(opts) + client, pair, err := amo.NewAmoClient(opts) + if err != nil { + panic(err) + } + if pair != nil { + fmt.Println("%q", pair) + } + + company, err := client.GetCompany("80699047", "") + if err != nil { + panic(err) + } + fmt.Println(company) +} diff --git a/env.sh b/env.sh new file mode 100644 index 0000000..6a56466 --- /dev/null +++ b/env.sh @@ -0,0 +1,5 @@ +lines=$(cat .env) +for line in $lines ; do + echo $line + eval "export $line" +done diff --git a/taskfile.yml b/taskfile.yml new file mode 100644 index 0000000..307c96c --- /dev/null +++ b/taskfile.yml @@ -0,0 +1,6 @@ +version: 3 + +tasks: + btest: + cmds: + - go build ./cmd/test