feat: better for simple authorization.
This commit is contained in:
parent
5410765b3b
commit
eaad1cbc06
6 changed files with 171 additions and 14 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
||||||
*.exe
|
*.exe
|
||||||
*.exe~
|
*.exe~
|
||||||
|
.env
|
||||||
|
|
15
amocrm.go
15
amocrm.go
|
@ -19,19 +19,24 @@ type IAmoClient interface {
|
||||||
UpdateContact(contact *contacts.Contact) error
|
UpdateContact(contact *contacts.Contact) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TokenPair = api.TokenPair
|
||||||
|
type Options = api.ClientOptions
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Api *api.Client
|
Api *api.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAmoClient(options *api.ClientOptions) (*Client, error) {
|
type OauthTokenResponse = api.OauthTokenResponse
|
||||||
apiClient, err := api.NewClient(options)
|
|
||||||
|
func NewAmoClient(options *Options ) (*Client, *TokenPair, error) {
|
||||||
|
apiClient, pair, err := api.NewClient(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Client{
|
return &Client{
|
||||||
Api: apiClient,
|
Api: apiClient,
|
||||||
}, nil
|
}, pair, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) updateEntity(url string, id int, body interface{}) error {
|
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) {
|
func (client *Client) GetContact(contactId string, query string) (*contacts.Contact, error) {
|
||||||
deal := new(contacts.Contact)
|
deal := new(contacts.Contact)
|
||||||
resource := fmt.Sprintf("/api/v4/contacts/%s", contactId)
|
resource := fmt.Sprintf("/api/v4/contacts/%s", contactId)
|
||||||
if len(query) != 0 {
|
if query != "" {
|
||||||
resource = resource + "?" + query
|
resource = resource + "?" + query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
80
api/api.go
80
api/api.go
|
@ -18,8 +18,13 @@ const (
|
||||||
|
|
||||||
type ClientOptions struct {
|
type ClientOptions struct {
|
||||||
Url string
|
Url string
|
||||||
|
RedirectUrl string
|
||||||
|
|
||||||
|
AuthCode string
|
||||||
|
|
||||||
ClientId string
|
ClientId string
|
||||||
ClientSecret string
|
ClientSecret string
|
||||||
|
|
||||||
AccessToken string
|
AccessToken string
|
||||||
RefreshToken string
|
RefreshToken string
|
||||||
}
|
}
|
||||||
|
@ -42,20 +47,37 @@ type OauthTokenResponse struct {
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(options *ClientOptions) (*Client, error) {
|
type TokenPair struct {
|
||||||
if len(options.AccessToken) == 0 || len(options.RefreshToken) == 0 || len(options.Url) == 0 {
|
Access, Refresh string
|
||||||
return nil, errors.New("AmoCrm: Invalid options")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
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)
|
resolvedUrl, err := url.Parse(options.Url)
|
||||||
if err != nil {
|
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{
|
return &Client{
|
||||||
options: options,
|
options: options,
|
||||||
BaseUrl: resolvedUrl,
|
BaseUrl: resolvedUrl,
|
||||||
}, nil
|
}, pair, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, result interface{}) error {
|
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)
|
response, err := http.DefaultClient.Do(request)
|
||||||
if err != nil {
|
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()
|
defer response.Body.Close()
|
||||||
|
|
||||||
if response.StatusCode >= 400 {
|
if response.StatusCode >= 400 {
|
||||||
bodyBytes, _ := ioutil.ReadAll(response.Body)
|
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 {
|
if result != nil {
|
||||||
|
@ -107,6 +141,36 @@ func (api *Client) doRequest(resourceUrl string, requestParams requestOptions, r
|
||||||
return nil
|
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) {
|
func (api *Client) RefreshToken() (*OauthTokenResponse, error) {
|
||||||
result := new(OauthTokenResponse)
|
result := new(OauthTokenResponse)
|
||||||
request := map[string]string{
|
request := map[string]string{
|
||||||
|
|
77
cmd/test/main.go
Normal file
77
cmd/test/main.go
Normal file
|
@ -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)
|
||||||
|
}
|
5
env.sh
Normal file
5
env.sh
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
lines=$(cat .env)
|
||||||
|
for line in $lines ; do
|
||||||
|
echo $line
|
||||||
|
eval "export $line"
|
||||||
|
done
|
6
taskfile.yml
Normal file
6
taskfile.yml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
version: 3
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
btest:
|
||||||
|
cmds:
|
||||||
|
- go build ./cmd/test
|
Loading…
Reference in a new issue