amocrm/pkg/amoClient/amo.go

388 lines
13 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package amoClient
import (
"amocrm/internal/models"
"encoding/json"
"fmt"
"net/url"
"time"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
)
type Amo struct {
baseApiURL string
userInfoURL string
fiberClient *fiber.Client
logger *zap.Logger
redirectionURL string
integrationID string
integrationSecret string
rateLimiter *RateLimiter
}
type AmoDeps struct {
BaseApiURL string
UserInfoURL string
FiberClient *fiber.Client
Logger *zap.Logger
RedirectionURL string
IntegrationID string
IntegrationSecret string
RateLimiter *RateLimiter
}
func NewAmoClient(deps AmoDeps) *Amo {
if deps.FiberClient == nil {
deps.FiberClient = fiber.AcquireClient()
}
return &Amo{
baseApiURL: deps.BaseApiURL,
userInfoURL: deps.UserInfoURL,
fiberClient: deps.FiberClient,
logger: deps.Logger,
redirectionURL: deps.RedirectionURL,
integrationSecret: deps.IntegrationSecret,
integrationID: deps.IntegrationID,
rateLimiter: deps.RateLimiter,
}
}
// токен должен быть с правами администратора
// https://www.amocrm.ru/developers/content/crm_platform/users-api#users-list
func (a *Amo) GetUserList(req models.RequestGetListUsers, accesToken string) (*models.ResponseGetListUsers, error) {
for {
if a.rateLimiter.Check() {
uri := fmt.Sprintf("%s/api/v4/users?page=%d&limit=%d&with=role,group,uuid", a.baseApiURL, req.Page, req.Limit)
agent := a.fiberClient.Get(uri)
agent.Set("Authorization", "Bearer "+accesToken)
statusCode, resBody, errs := agent.Bytes()
if len(errs) > 0 {
for _, err := range errs {
a.logger.Error("error sending request in GetUserList", zap.Error(err))
}
return nil, fmt.Errorf("request GetUserList failed: %v", errs[0])
}
if statusCode != fiber.StatusOK {
switch statusCode {
case fiber.StatusForbidden:
errorMessage := fmt.Sprintf("error GetUserList StatusForbidden - %d", statusCode)
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
case fiber.StatusUnauthorized:
errorMessage := fmt.Sprintf("error GetUserList StatusUnauthorized - %d", statusCode)
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
default:
errorMessage := fmt.Sprintf("error GetUserList statusCode - %d", statusCode)
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
}
}
var userListResponse models.ResponseGetListUsers
err := json.Unmarshal(resBody, &userListResponse)
if err != nil {
a.logger.Error("error unmarshal ResponseGetListUsers:", zap.Error(err))
return nil, err
}
return &userListResponse, nil
}
time.Sleep(a.rateLimiter.interval)
}
}
// https://www.amocrm.ru/developers/content/oauth/step-by-step
// POST /oauth2/access_token
// тут и создание по коду и обновление по рефрешу в этом клиенте
func (a *Amo) CreateWebHook(req models.WebHookRequest) (*models.CreateWebHookResp, error) {
for {
if a.rateLimiter.Check() {
req.SetClientID(a.integrationID)
req.SetClientSecret(a.integrationSecret)
req.SetRedirectURL(a.redirectionURL)
bodyBytes, err := json.Marshal(req)
if err != nil {
a.logger.Error("error marshal req in CreateWebHook:", zap.Error(err))
return nil, err
}
agent := a.fiberClient.Post(a.baseApiURL + "/oauth2/access_token")
agent.Set("Content-Type", "application/json").Body(bodyBytes)
statusCode, resBody, errs := agent.Bytes()
if len(errs) > 0 {
for _, err = range errs {
a.logger.Error("error sending request in CreateWebHook for create or update tokens", zap.Error(err))
}
return nil, fmt.Errorf("request failed: %v", errs[0])
}
if statusCode != fiber.StatusOK {
errorMessage := fmt.Sprintf("received an incorrect response from CreateWebHook: %s", string(resBody))
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
}
var tokens models.CreateWebHookResp
err = json.Unmarshal(resBody, &tokens)
if err != nil {
a.logger.Error("error unmarshal CreateWebHookResp:", zap.Error(err))
return nil, err
}
return &tokens, nil
}
time.Sleep(a.rateLimiter.interval)
}
}
// https://www.amocrm.ru/developers/content/oauth/step-by-step#%D0%A5%D1%83%D0%BA-%D0%BE%D0%B1-%D0%BE%D1%82%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B8-%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D0%B8
func (a *Amo) DeleteWebHook() {
for {
if a.rateLimiter.Check() {
return
}
time.Sleep(a.rateLimiter.interval)
}
}
// https://www.amocrm.ru/developers/content/crm_platform/leads_pipelines#%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D1%81%D1%82%D0%B0%D1%82%D1%83%D1%81%D0%BE%D0%B2-%D0%B2%D0%BE%D1%80%D0%BE%D0%BD%D0%BA%D0%B8-%D1%81%D0%B4%D0%B5%D0%BB%D0%BE%D0%BA
// GET /api/v4/leads/pipelines/{pipeline_id}/statuses
func (a *Amo) GetListSteps(pipelineID int, accessToken string) (*models.ResponseGetListSteps, error) {
for {
if a.rateLimiter.Check() {
uri := fmt.Sprintf("%s/api/v4/leads/pipelines/%d/statuses", a.baseApiURL, pipelineID)
agent := a.fiberClient.Get(uri)
agent.Set("Authorization", "Bearer "+accessToken)
statusCode, resBody, errs := agent.Bytes()
if len(errs) > 0 {
for _, err := range errs {
a.logger.Error("error sending request in GetListSteps", zap.Error(err))
}
return nil, fmt.Errorf("request GetListSteps failed: %v", errs[0])
}
if statusCode != fiber.StatusOK {
errorMessage := fmt.Sprintf("received an incorrect response from GetListSteps: %s", string(resBody))
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
}
var listSteps models.ResponseGetListSteps
err := json.Unmarshal(resBody, &listSteps)
if err != nil {
a.logger.Error("error unmarshal ResponseGetListSteps:", zap.Error(err))
return nil, err
}
return &listSteps, nil
}
time.Sleep(a.rateLimiter.interval)
}
}
// https://www.amocrm.ru/developers/content/crm_platform/custom-fields#%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9-%D1%81%D1%83%D1%89%D0%BD%D0%BE%D1%81%D1%82%D0%B8
// GET /api/v4/leads/custom_fields
// GET /api/v4/contacts/custom_fields
// GET /api/v4/companies/custom_fields
// GET /api/v4/customers/custom_fields
// пока без этих двух
// GET /api/v4/customers/segments/custom_fields
// GET /api/v4/catalogs/{catalog_id}/custom_fields
// эти методы все относятся к одному и тому же, поэтому на вход будет урл и рек стуктура, выход у них один и тот же
func (a *Amo) GetListFields(req models.GetListFieldsReq, accessToken string) (*models.ResponseGetListFields, error) {
for {
if a.rateLimiter.Check() {
fullURL := fmt.Sprintf("%s/api/v4/%s/custom_fields?limit=%d&page=%d", a.baseApiURL, req.EntityType, req.Limit, req.Page)
agent := a.fiberClient.Get(fullURL)
agent.Set("Authorization", "Bearer "+accessToken)
statusCode, resBody, errs := agent.Bytes()
if len(errs) > 0 {
for _, err := range errs {
a.logger.Error("error sending request in GetListFields", zap.Error(err))
}
return nil, fmt.Errorf("request GetListFields failed: %v", errs[0])
}
if statusCode != fiber.StatusOK {
errorMessage := fmt.Sprintf("received an incorrect response from GetListFields: %s", string(resBody))
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
}
var listFields models.ResponseGetListFields
err := json.Unmarshal(resBody, &listFields)
if err != nil {
a.logger.Error("error unmarshal ResponseGetListFields:", zap.Error(err))
return nil, err
}
return &listFields, nil
}
time.Sleep(a.rateLimiter.interval)
}
}
// https://www.amocrm.ru/developers/content/crm_platform/tags-api#%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D1%82%D0%B5%D0%B3%D0%BE%D0%B2-%D0%B4%D0%BB%D1%8F-%D1%81%D1%83%D1%89%D0%BD%D0%BE%D1%81%D1%82%D0%B8
// GET /api/v4/{entity_type:leads|contacts|companies|customers}/tags
func (a *Amo) GetListTags(req models.GetListTagsReq, accessToken string) (*models.ResponseGetListTags, error) {
for {
if a.rateLimiter.Check() {
fullURL := fmt.Sprintf("%s/api/v4/%s/tags?", a.baseApiURL, req.EntityType)
if req.Filter.Name != "" {
fullURL += "&filter[name]=" + url.QueryEscape(req.Filter.Name)
}
if len(req.Filter.ID) > 0 {
for _, id := range req.Filter.ID {
fullURL += fmt.Sprintf("&filter[id][]=%d", id)
}
}
if req.Filter.Query != "" {
fullURL += "&filter[query]=" + url.QueryEscape(req.Filter.Query)
}
fullURL += fmt.Sprintf("&page=%d&limit=%d", req.Page, req.Limit)
agent := a.fiberClient.Get(fullURL)
agent.Set("Authorization", "Bearer "+accessToken)
statusCode, resBody, errs := agent.Bytes()
if len(errs) > 0 {
for _, err := range errs {
a.logger.Error("error sending request in GetListTags", zap.Error(err))
}
return nil, fmt.Errorf("request GetListTags failed: %v", errs[0])
}
if statusCode != fiber.StatusOK {
errorMessage := fmt.Sprintf("received an incorrect response from GetListTags: %s", string(resBody))
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
}
var listTags models.ResponseGetListTags
err := json.Unmarshal(resBody, &listTags)
if err != nil {
a.logger.Error("error unmarshal ResponseGetListTags:", zap.Error(err))
return nil, err
}
return &listTags, nil
}
time.Sleep(a.rateLimiter.interval)
}
}
// https://www.amocrm.ru/developers/content/crm_platform/account-info
// GET /api/v4/account
func (a *Amo) GetUserInfo(accessToken string) (*models.AmocrmUserInformation, error) {
for {
if a.rateLimiter.Check() {
agent := a.fiberClient.Get(a.userInfoURL)
agent.Set("Authorization", "Bearer "+accessToken)
statusCode, resBody, errs := agent.Bytes()
if len(errs) > 0 {
for _, err := range errs {
a.logger.Error("error sending request in GetUserInfo", zap.Error(err))
}
return nil, fmt.Errorf("request GetUserInfo failed: %v", errs[0])
}
if statusCode != fiber.StatusOK {
errorMessage := fmt.Sprintf("received an incorrect response from GetUserInfo: %s", string(resBody))
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
}
var userInfo models.AmocrmUserInformation
err := json.Unmarshal(resBody, &userInfo)
if err != nil {
a.logger.Error("error unmarshal AmocrmUserInformation:", zap.Error(err))
return nil, err
}
return &userInfo, nil
}
time.Sleep(a.rateLimiter.interval)
}
}
// https://www.amocrm.ru/developers/content/crm_platform/leads_pipelines#%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%B2%D0%BE%D1%80%D0%BE%D0%BD%D0%BE%D0%BA-%D1%81%D0%B4%D0%B5%D0%BB%D0%BE%D0%BA
// GET /api/v4/leads/pipelines
func (a *Amo) GetListPipelines(accessToken string) (*models.PipelineResponse, error) {
for {
if a.rateLimiter.Check() {
uri := fmt.Sprintf("%s/api/v4/leads/pipelines", a.baseApiURL)
agent := a.fiberClient.Get(uri)
agent.Set("Authorization", "Bearer "+accessToken)
statusCode, resBody, errs := agent.Bytes()
if len(errs) > 0 {
for _, err := range errs {
a.logger.Error("error sending request in GetListPipelines", zap.Error(err))
}
return nil, fmt.Errorf("request GetListPipelines failed: %v", errs[0])
}
if statusCode != fiber.StatusOK {
errorMessage := fmt.Sprintf("received an incorrect response from GetListPipelines: %s", string(resBody))
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
}
var userInfo models.PipelineResponse
err := json.Unmarshal(resBody, &userInfo)
if err != nil {
a.logger.Error("error unmarshal PipelineResponse:", zap.Error(err))
return nil, err
}
return &userInfo, nil
}
time.Sleep(a.rateLimiter.interval)
}
}
// токен должен быть с правами администратора
// https://www.amocrm.ru/developers/content/crm_platform/users-api#user-detail
// GET /api/v4/users/{id
func (a *Amo) GetUserByID(id int32, accessToken string) (*models.OneUserInfo, error) {
for {
if a.rateLimiter.Check() {
uri := fmt.Sprintf("%s/api/v4/users/%d?with=role,uuid", a.baseApiURL, id)
agent := a.fiberClient.Get(uri)
agent.Set("Authorization", "Bearer "+accessToken)
statusCode, resBody, errs := agent.Bytes()
if len(errs) > 0 {
for _, err := range errs {
a.logger.Error("error sending request in GetUserByID", zap.Error(err))
}
return nil, fmt.Errorf("request GetUserByID failed: %v", errs[0])
}
if statusCode != fiber.StatusOK {
errorMessage := fmt.Sprintf("received an incorrect response from GetUserByID:%s", string(resBody))
a.logger.Error(errorMessage, zap.Int("status", statusCode))
return nil, fmt.Errorf(errorMessage)
}
var userInfo models.OneUserInfo
err := json.Unmarshal(resBody, &userInfo)
if err != nil {
a.logger.Error("error unmarshal OneUserInfo:", zap.Error(err))
return nil, err
}
return &userInfo, nil
}
time.Sleep(a.rateLimiter.interval)
}
}