add fields with files need work
This commit is contained in:
parent
75970295b3
commit
74dfb8d4be
2
go.mod
2
go.mod
@ -13,7 +13,7 @@ require (
|
||||
github.com/twmb/franz-go v1.16.1
|
||||
go.uber.org/zap v1.27.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240507175756-10399fe4c21f
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240510090920-72cb7d7da6e9
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af
|
||||
)
|
||||
|
||||
|
4
go.sum
4
go.sum
@ -169,7 +169,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6 h1:oV+/HNX+JPoQ3/GUx08hio7d45WpY0AMGrFs7j70QlA=
|
||||
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM=
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240507175756-10399fe4c21f h1:xUo4CsauxNgFhiTfv+5BKfF4Ekk6SHeR+ohwrBuJIrU=
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240507175756-10399fe4c21f/go.mod h1:oRyhT55ctjqp/7ZxIzkR7OsQ7T/NLibsfrbb7Ytns64=
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240510090920-72cb7d7da6e9 h1:rEOS5bsCduPSYv5QNvU8YvXroTOeqeSNP/833ZvCUAA=
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240510090920-72cb7d7da6e9/go.mod h1:oRyhT55ctjqp/7ZxIzkR7OsQ7T/NLibsfrbb7Ytns64=
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af h1:jQ7HaXSutDX5iepU7VRImxhikK7lV/lBKkiloOZ4Emo=
|
||||
penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af/go.mod h1:5S5YwjSXWmnEKjBjG6MtyGtFmljjukDRS8CwHk/CF/I=
|
||||
|
@ -72,7 +72,6 @@ func Run(ctx context.Context, config initialize.Config, logger *zap.Logger) erro
|
||||
|
||||
amoClient := amoClient.NewAmoClient(amoClient.AmoDeps{
|
||||
BaseApiURL: config.ApiURL,
|
||||
UserInfoURL: config.UserInfoURL,
|
||||
Logger: logger,
|
||||
RedirectionURL: config.ReturnURL,
|
||||
IntegrationID: config.IntegrationID,
|
||||
|
@ -26,8 +26,6 @@ type Config struct {
|
||||
IntegrationID string `env:"INTEGRATION_ID" envDefault:"2dbd6329-9be6-41f2-aa5f-964b9e723e49"`
|
||||
// секрет интеграции
|
||||
IntegrationSecret string `env:"INTEGRATION_SECRET" envDefault:"tNK3LwL4ovP0OBK4jKDHJ3646PqRJDOKQYgY6P2t6DCuV8LEzDzszTDY0Fhwmzc8"`
|
||||
// uri о которому получать информацию о пользователе https://www.amocrm.ru/developers/content/crm_platform/account-info
|
||||
UserInfoURL string `env:"USER_INFO_URL" envDefault:"https://penadigitaltech.amocrm.ru/api/v4/account"`
|
||||
}
|
||||
|
||||
func LoadConfig() (*Config, error) {
|
||||
|
@ -19,14 +19,24 @@ type DealReq struct {
|
||||
}
|
||||
|
||||
type FieldsValues struct {
|
||||
FieldID int `json:"field_id"`
|
||||
Values []Values `json:"values"`
|
||||
FieldID int `json:"field_id"`
|
||||
Values []interface{} `json:"values"`
|
||||
}
|
||||
|
||||
type Values struct {
|
||||
Value string `json:"value"` // пока так пока не понятно
|
||||
}
|
||||
|
||||
type ValuesFile struct {
|
||||
Value ValueFile `json:"value"`
|
||||
}
|
||||
type ValueFile struct {
|
||||
FileUUID string `json:"file_uuid"`
|
||||
VersionUUID string `json:"version_uuid"`
|
||||
FileName string `json:"file_name"`
|
||||
FileSize int64 `json:"file_size"`
|
||||
}
|
||||
|
||||
type Embedd struct {
|
||||
Tags []Tag `json:"tags"` // Данные тегов, добавляемых к сделке
|
||||
Contact []Contact `json:"contacts"` // Данные контактов, которые будет прикреплены к сделке
|
||||
@ -110,3 +120,53 @@ type EmbeddedCreateCustomers struct {
|
||||
RequestID string `json:"request_id"`
|
||||
}
|
||||
}
|
||||
|
||||
type CreateSession struct {
|
||||
FileName string `json:"file_name"` // обязательное поле
|
||||
FileSize int64 `json:"file_size"` // обязательное поле
|
||||
FileUUID string `json:"file_uuid"` // UUID файла, для которого загружается новая версия файла. Если UUID не задан, то будет создан новый файл.
|
||||
ContentType string `json:"content_type"` // MIME-тип файла
|
||||
WithPreview bool `json:"with_preview"` // При установке данного флага для файла будет сгенерировано превью
|
||||
}
|
||||
|
||||
// представляет данные о созданной сессии загрузки файла
|
||||
type UploadSession struct {
|
||||
SessionID int `json:"session_id"`
|
||||
UploadURL string `json:"upload_url"`
|
||||
MaxFileSize int64 `json:"max_file_size"`
|
||||
MaxPartSize int64 `json:"max_part_size"`
|
||||
}
|
||||
|
||||
// представляет информацию о загруженном файле
|
||||
type UploadedFile struct {
|
||||
UUID string `json:"uuid"`
|
||||
Type string `json:"type"`
|
||||
IsTrashed bool `json:"is_trashed"`
|
||||
Name string `json:"name"`
|
||||
SanitizedName string `json:"sanitized_name"`
|
||||
Size int64 `json:"size"`
|
||||
SourceID int `json:"source_id"`
|
||||
VersionUUID string `json:"version_uuid"`
|
||||
HasMultipleVersions bool `json:"has_multiple_versions"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
CreatedBy struct {
|
||||
ID int `json:"id"`
|
||||
Type string `json:"type"`
|
||||
} `json:"created_by"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
DeletedAt int64 `json:"deleted_at"`
|
||||
DeletedBy interface{} `json:"deleted_by"`
|
||||
Metadata Metadata `json:"metadata"`
|
||||
Previews []PreviewFile `json:"previews"`
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
Extension string `json:"extension"`
|
||||
MIMEType string `json:"mime_type"`
|
||||
}
|
||||
|
||||
type PreviewFile struct {
|
||||
DownloadLink string `json:"download_link"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
}
|
||||
|
@ -2,11 +2,9 @@ package tools
|
||||
|
||||
import (
|
||||
"amocrm/internal/models"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
@ -69,105 +67,6 @@ func ToField(amoField []models.CustomField, entity model.EntityType) []model.Fie
|
||||
return fields
|
||||
}
|
||||
|
||||
func ConstructField(allAnswers []model.ResultAnswer, result model.AmoUsersTrueResults) ([]models.FieldsValues, []models.Contact, []models.Company, []models.Customer, error) {
|
||||
dateCreating := time.Now().Unix()
|
||||
|
||||
entityFieldsMap := make(map[model.EntityType]map[int][]models.Values)
|
||||
entityFieldsMap[model.LeadsType] = make(map[int][]models.Values)
|
||||
entityFieldsMap[model.CompaniesType] = make(map[int][]models.Values)
|
||||
entityFieldsMap[model.CustomersType] = make(map[int][]models.Values)
|
||||
|
||||
entityRules := make(map[model.EntityType][]model.FieldRule)
|
||||
entityRules[model.LeadsType] = result.FieldsRule.Lead
|
||||
entityRules[model.CompaniesType] = result.FieldsRule.Company
|
||||
entityRules[model.CustomersType] = result.FieldsRule.Customer
|
||||
|
||||
for entityType, ruleList := range entityRules {
|
||||
for _, rule := range ruleList {
|
||||
for _, data := range allAnswers {
|
||||
if fieldID, ok := rule.Questionid[int(data.QuestionID)]; ok {
|
||||
values := entityFieldsMap[entityType][fieldID]
|
||||
values = append(values, models.Values{Value: emojiUnicode(data.Content)})
|
||||
entityFieldsMap[entityType][fieldID] = values
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var leadFields []models.FieldsValues
|
||||
var contactFields []models.FieldsValues
|
||||
var companyFields []models.FieldsValues
|
||||
var customerFields []models.FieldsValues
|
||||
|
||||
for entityType, fieldMap := range entityFieldsMap {
|
||||
for fieldID, values := range fieldMap {
|
||||
field := models.FieldsValues{
|
||||
FieldID: fieldID,
|
||||
Values: values,
|
||||
}
|
||||
switch entityType {
|
||||
case model.LeadsType:
|
||||
leadFields = append(leadFields, field)
|
||||
case model.CompaniesType:
|
||||
companyFields = append(companyFields, field)
|
||||
case model.CustomersType:
|
||||
customerFields = append(customerFields, field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var resultInfo model.ResultContent
|
||||
err := json.Unmarshal([]byte(result.Content), &resultInfo)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
name := resultInfo.Name
|
||||
if name == "" {
|
||||
name = fmt.Sprintf("empty name, quiz %d, triggered by answer - %d", result.QuizID, result.AnswerID)
|
||||
}
|
||||
|
||||
contactRuleMap := result.FieldsRule.Contact.ContactRuleMap
|
||||
|
||||
contactFields = addContactField(contactFields, resultInfo.Name, model.TypeContactName, contactRuleMap)
|
||||
contactFields = addContactField(contactFields, resultInfo.Phone, model.TypeContactPhone, contactRuleMap)
|
||||
contactFields = addContactField(contactFields, resultInfo.Text, model.TypeContactText, contactRuleMap)
|
||||
contactFields = addContactField(contactFields, resultInfo.Email, model.TypeContactEmail, contactRuleMap)
|
||||
contactFields = addContactField(contactFields, resultInfo.Address, model.TypeContactAddress, contactRuleMap)
|
||||
|
||||
return leadFields, []models.Contact{
|
||||
{
|
||||
Name: name,
|
||||
ResponsibleUserID: result.PerformerID,
|
||||
CreatedBy: 0,
|
||||
UpdatedBy: 0,
|
||||
CreatedAt: dateCreating,
|
||||
CustomFieldsValues: contactFields,
|
||||
},
|
||||
}, []models.Company{
|
||||
{
|
||||
Name: fmt.Sprintf("Компания %d", result.AnswerID),
|
||||
ResponsibleUserID: result.PerformerID,
|
||||
CreatedBy: 0,
|
||||
UpdatedBy: 0,
|
||||
CreatedAt: dateCreating,
|
||||
CustomFieldsValues: companyFields,
|
||||
},
|
||||
}, []models.Customer{
|
||||
{
|
||||
// в амо имя покупателя не может быть пустым, надо как то с этим жить
|
||||
Name: name,
|
||||
ResponsibleUserID: result.PerformerID,
|
||||
//StatusID: ,
|
||||
CreatedBy: 0,
|
||||
UpdatedBy: 0,
|
||||
CreatedAt: dateCreating,
|
||||
CustomFields: customerFields,
|
||||
RequestID: fmt.Sprint(result.AnswerID),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func isEmoji(r rune) bool {
|
||||
// https://symbl.cc/ru/unicode/blocks/emoticons/
|
||||
|
||||
@ -194,7 +93,7 @@ func isEmoji(r rune) bool {
|
||||
(r >= 0xE0100 && r <= 0xE01EF) // Дополнение к селекторам вариантов начертания
|
||||
}
|
||||
|
||||
func emojiUnicode(text string) string {
|
||||
func EmojiUnicode(text string) string {
|
||||
var result strings.Builder
|
||||
for len(text) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(text)
|
||||
@ -213,15 +112,14 @@ func emojiUnicode(text string) string {
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func addContactField(contactFields []models.FieldsValues, fieldValue string, fieldType model.ContactQuizConfig, fieldMap map[string]int) []models.FieldsValues {
|
||||
func AddContactFields(contactFields []models.FieldsValues, fieldValue string, fieldType model.ContactQuizConfig, fieldMap map[string]int) []models.FieldsValues {
|
||||
if fieldValue != "" {
|
||||
values := make([]interface{}, 0)
|
||||
values = append(values, models.Values{Value: fieldValue})
|
||||
|
||||
contactFields = append(contactFields, models.FieldsValues{
|
||||
FieldID: fieldMap[string(fieldType)],
|
||||
Values: []models.Values{
|
||||
{
|
||||
Value: fieldValue,
|
||||
},
|
||||
},
|
||||
Values: values,
|
||||
})
|
||||
}
|
||||
return contactFields
|
||||
|
@ -6,9 +6,11 @@ import (
|
||||
"amocrm/internal/tools"
|
||||
"amocrm/pkg/amoClient"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/amo"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -87,9 +89,9 @@ func (wc *PostDeals) startFetching(ctx context.Context) {
|
||||
RequestID: strconv.Itoa(int(result.AnswerID)),
|
||||
}
|
||||
|
||||
leadFields, contactData, companyData, customerToCreate, err := tools.ConstructField(allAnswers, result)
|
||||
leadFields, contactData, companyData, customerToCreate, err := wc.constructField(ctx, allAnswers, result)
|
||||
if err != nil {
|
||||
wc.logger.Error("error serialization resultContent to model ResultContent", zap.Error(err))
|
||||
wc.logger.Error("error construct fields", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -176,6 +178,124 @@ func (wc *PostDeals) saveDealToDB(ctx context.Context, resp []models.DealResp, a
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wc *PostDeals) constructField(ctx context.Context, allAnswers []model.ResultAnswer, result model.AmoUsersTrueResults) ([]models.FieldsValues, []models.Contact, []models.Company, []models.Customer, error) {
|
||||
dateCreating := time.Now().Unix()
|
||||
|
||||
entityFieldsMap := make(map[model.EntityType]map[int][]interface{})
|
||||
entityFieldsMap[model.LeadsType] = make(map[int][]interface{})
|
||||
entityFieldsMap[model.CompaniesType] = make(map[int][]interface{})
|
||||
entityFieldsMap[model.CustomersType] = make(map[int][]interface{})
|
||||
|
||||
entityRules := make(map[model.EntityType][]model.FieldRule)
|
||||
entityRules[model.LeadsType] = result.FieldsRule.Lead
|
||||
entityRules[model.CompaniesType] = result.FieldsRule.Company
|
||||
entityRules[model.CustomersType] = result.FieldsRule.Customer
|
||||
|
||||
for entityType, ruleList := range entityRules {
|
||||
for _, rule := range ruleList {
|
||||
for _, data := range allAnswers {
|
||||
if fieldID, ok := rule.Questionid[int(data.QuestionID)]; ok {
|
||||
|
||||
fieldData, err := wc.amoRepo.AmoRepo.GetFieldByID(ctx, int32(fieldID))
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
if fieldData.Type == model.TypeAmoText {
|
||||
values := entityFieldsMap[entityType][fieldID]
|
||||
values = append(values, models.Values{Value: tools.EmojiUnicode(data.Content)})
|
||||
entityFieldsMap[entityType][fieldID] = values
|
||||
continue
|
||||
}
|
||||
|
||||
if fieldData.Type == model.TypeFile && data.Content != "" {
|
||||
value, err := wc.amoClient.UploadFileToAmo(data.Content, result.AccessToken)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
values := entityFieldsMap[entityType][fieldID]
|
||||
values = append(values, value)
|
||||
entityFieldsMap[entityType][fieldID] = values
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var leadFields []models.FieldsValues
|
||||
var contactFields []models.FieldsValues
|
||||
var companyFields []models.FieldsValues
|
||||
var customerFields []models.FieldsValues
|
||||
|
||||
for entityType, fieldMap := range entityFieldsMap {
|
||||
for fieldID, values := range fieldMap {
|
||||
field := models.FieldsValues{
|
||||
FieldID: fieldID,
|
||||
Values: values,
|
||||
}
|
||||
switch entityType {
|
||||
case model.LeadsType:
|
||||
leadFields = append(leadFields, field)
|
||||
case model.CompaniesType:
|
||||
companyFields = append(companyFields, field)
|
||||
case model.CustomersType:
|
||||
customerFields = append(customerFields, field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var resultInfo model.ResultContent
|
||||
err := json.Unmarshal([]byte(result.Content), &resultInfo)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
name := resultInfo.Name
|
||||
if name == "" {
|
||||
name = fmt.Sprintf("empty name, quiz %d, triggered by answer - %d", result.QuizID, result.AnswerID)
|
||||
}
|
||||
|
||||
contactRuleMap := result.FieldsRule.Contact.ContactRuleMap
|
||||
|
||||
contactFields = tools.AddContactFields(contactFields, resultInfo.Name, model.TypeContactName, contactRuleMap)
|
||||
contactFields = tools.AddContactFields(contactFields, resultInfo.Phone, model.TypeContactPhone, contactRuleMap)
|
||||
contactFields = tools.AddContactFields(contactFields, resultInfo.Text, model.TypeContactText, contactRuleMap)
|
||||
contactFields = tools.AddContactFields(contactFields, resultInfo.Email, model.TypeContactEmail, contactRuleMap)
|
||||
contactFields = tools.AddContactFields(contactFields, resultInfo.Address, model.TypeContactAddress, contactRuleMap)
|
||||
|
||||
return leadFields, []models.Contact{
|
||||
{
|
||||
Name: name,
|
||||
ResponsibleUserID: result.PerformerID,
|
||||
CreatedBy: 0,
|
||||
UpdatedBy: 0,
|
||||
CreatedAt: dateCreating,
|
||||
CustomFieldsValues: contactFields,
|
||||
},
|
||||
}, []models.Company{
|
||||
{
|
||||
Name: fmt.Sprintf("Компания %d", result.AnswerID),
|
||||
ResponsibleUserID: result.PerformerID,
|
||||
CreatedBy: 0,
|
||||
UpdatedBy: 0,
|
||||
CreatedAt: dateCreating,
|
||||
CustomFieldsValues: companyFields,
|
||||
},
|
||||
}, []models.Customer{
|
||||
{
|
||||
// в амо имя покупателя не может быть пустым, надо как то с этим жить
|
||||
Name: name,
|
||||
ResponsibleUserID: result.PerformerID,
|
||||
CreatedBy: 0,
|
||||
UpdatedBy: 0,
|
||||
CreatedAt: dateCreating,
|
||||
CustomFields: customerFields,
|
||||
RequestID: fmt.Sprint(result.AnswerID),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (wc *PostDeals) Stop(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -3,9 +3,13 @@ package amoClient
|
||||
import (
|
||||
"amocrm/internal/models"
|
||||
"amocrm/internal/workers/limiter"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||
"time"
|
||||
|
||||
@ -15,7 +19,6 @@ import (
|
||||
|
||||
type Amo struct {
|
||||
baseApiURL string
|
||||
userInfoURL string
|
||||
fiberClient *fiber.Client
|
||||
logger *zap.Logger
|
||||
redirectionURL string
|
||||
@ -26,7 +29,6 @@ type Amo struct {
|
||||
|
||||
type AmoDeps struct {
|
||||
BaseApiURL string
|
||||
UserInfoURL string
|
||||
FiberClient *fiber.Client
|
||||
Logger *zap.Logger
|
||||
RedirectionURL string
|
||||
@ -41,7 +43,6 @@ func NewAmoClient(deps AmoDeps) *Amo {
|
||||
}
|
||||
return &Amo{
|
||||
baseApiURL: deps.BaseApiURL,
|
||||
userInfoURL: deps.UserInfoURL,
|
||||
fiberClient: deps.FiberClient,
|
||||
logger: deps.Logger,
|
||||
redirectionURL: deps.RedirectionURL,
|
||||
@ -277,7 +278,8 @@ func (a *Amo) GetListTags(req models.GetListTagsReq, accessToken string) (*model
|
||||
func (a *Amo) GetUserInfo(accessToken string) (*models.AmocrmUserInformation, error) {
|
||||
for {
|
||||
if a.rateLimiter.Check() {
|
||||
agent := a.fiberClient.Get(a.userInfoURL)
|
||||
url := fmt.Sprintf("%s/api/v4/account", a.baseApiURL)
|
||||
agent := a.fiberClient.Get(url)
|
||||
agent.Set("Authorization", "Bearer "+accessToken)
|
||||
statusCode, resBody, errs := agent.Bytes()
|
||||
if len(errs) > 0 {
|
||||
@ -539,3 +541,170 @@ func (a *Amo) CreatingCustomer(req []models.Customer, accessToken string) (*mode
|
||||
time.Sleep(a.rateLimiter.Interval)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Amo) downloadFile(urlFile string) (*os.File, error) {
|
||||
var err error
|
||||
agent := a.fiberClient.Get(urlFile)
|
||||
|
||||
statusCode, resBody, errs := agent.Bytes()
|
||||
if len(errs) > 0 {
|
||||
for _, err = range errs {
|
||||
a.logger.Error("error sending request for getting file by url", zap.Error(err))
|
||||
}
|
||||
return nil, fmt.Errorf("request failed: %v", errs[0])
|
||||
}
|
||||
|
||||
if statusCode != fiber.StatusOK {
|
||||
errorMessage := fmt.Sprintf("received an incorrect response from getting file by url: %s", string(resBody))
|
||||
a.logger.Error(errorMessage, zap.Int("status", statusCode))
|
||||
return nil, fmt.Errorf(errorMessage)
|
||||
}
|
||||
|
||||
tmpFile, err := os.CreateTemp("", "downloaded_file_*")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
|
||||
_, err = io.Copy(tmpFile, bytes.NewReader(resBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tmpFile, nil
|
||||
}
|
||||
|
||||
func (a *Amo) UploadFileToAmo(urlFile string, accessToken string) (*models.ValuesFile, error) {
|
||||
fmt.Println(urlFile)
|
||||
localFile, err := a.downloadFile(urlFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer os.Remove(localFile.Name())
|
||||
|
||||
fileInfo, err := os.Stat(localFile.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileSize := fileInfo.Size()
|
||||
createSessionData := &models.CreateSession{
|
||||
FileName: urlFile,
|
||||
FileSize: fileSize,
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/v1.0/sessions", "https://drive-b.amocrm.ru")
|
||||
bodyBytes, err := json.Marshal(createSessionData)
|
||||
if err != nil {
|
||||
a.logger.Error("error marshal create session data:", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
agent := a.fiberClient.Post(uri)
|
||||
agent.Set("Content-Type", "application/json").Body(bodyBytes)
|
||||
agent.Set("Authorization", "Bearer "+accessToken)
|
||||
|
||||
statusCode, resBody, errs := agent.Bytes()
|
||||
if len(errs) > 0 {
|
||||
for _, err = range errs {
|
||||
a.logger.Error("error sending request to create session for upload file in amo", zap.Error(err))
|
||||
}
|
||||
return nil, fmt.Errorf("request failed: %v", errs[0])
|
||||
}
|
||||
|
||||
if statusCode != fiber.StatusOK {
|
||||
errorMessage := fmt.Sprintf("received an incorrect response from creating upload file session: %s", string(resBody))
|
||||
a.logger.Error(errorMessage, zap.Int("status", statusCode))
|
||||
return nil, fmt.Errorf(errorMessage)
|
||||
}
|
||||
|
||||
var resp models.UploadSession
|
||||
err = json.Unmarshal(resBody, &resp)
|
||||
if err != nil {
|
||||
a.logger.Error("error unmarshal response body in creating upload file session:", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := a.createPart(resp, localFile)
|
||||
|
||||
return &models.ValuesFile{
|
||||
Value: models.ValueFile{
|
||||
FileUUID: response.UUID,
|
||||
VersionUUID: response.VersionUUID,
|
||||
FileName: response.Name,
|
||||
FileSize: response.Size,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *Amo) createPart(uploadData models.UploadSession, file *os.File) (*models.UploadedFile, error) {
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileSize := fileInfo.Size()
|
||||
|
||||
var uploadedFile models.UploadedFile
|
||||
var remainingSize = fileSize
|
||||
var start int64 = 0
|
||||
|
||||
for remainingSize > 0 {
|
||||
end := start + uploadData.MaxPartSize
|
||||
if end > fileSize {
|
||||
end = fileSize
|
||||
}
|
||||
|
||||
partSize := end - start
|
||||
|
||||
partFile, err := os.OpenFile(file.Name(), os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer partFile.Close()
|
||||
|
||||
_, err = partFile.Seek(start, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buffer := make([]byte, partSize)
|
||||
_, err = partFile.Read(buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
agent := a.fiberClient.Post(uploadData.UploadURL).Body(buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
statusCode, resBody, errs := agent.Bytes()
|
||||
if len(errs) > 0 {
|
||||
for _, err = range errs {
|
||||
a.logger.Error("error sending request to upload part file to amo", zap.Error(err))
|
||||
}
|
||||
return nil, fmt.Errorf("request failed: %v", errs[0])
|
||||
}
|
||||
|
||||
if statusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to upload part file to amo, status: %d", statusCode)
|
||||
}
|
||||
|
||||
start = end
|
||||
remainingSize -= partSize
|
||||
|
||||
var newUploadData models.UploadSession
|
||||
if err := json.Unmarshal(resBody, &newUploadData); err == nil {
|
||||
uploadData = newUploadData
|
||||
} else {
|
||||
if err := json.Unmarshal(resBody, &uploadedFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &uploadedFile, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user