docxTemplater/handlers/generator.go
Danil Solovyov fba01b2518 Changes:
- Добавлена проверка токенов при запросе /amo/state
  - Исправлена работа с amo oauth-токенами
  - Добавлены примеры шаблонизатора
  - Добавлена возможность генерации и создания шаблонов из примеров
  - В ответ генератора добавлены ссылки для скачивания сгенерированных файлов
  - Вернул очиску temp после загрузки файла в Яндекс.Диск
  - yadisk.UploadResources - добавлено ожидание окончания отправки файла и таймаут в 5 секунд для отправки файла
  - Добавлены эндпоинты для загрузки файлов в хранилища
  - Актуализирован генератор по вебхуку
  - Обновлены генератор по данным
  - Обновлен генератор по лиду
2022-11-25 00:37:47 +05:00

346 lines
9.4 KiB
Go

package handlers
import (
"errors"
"fmt"
"github.com/Pena-Co-Ltd/amocrm_templategen_back/amo"
"github.com/Pena-Co-Ltd/amocrm_templategen_back/templategen"
"io"
"net/http"
"net/url"
"strconv"
"strings"
)
type ReqGeneratorByAmoLead struct {
File string `json:"file"` // Путь до файла в Yandex Disk, либо ID файла в Google Disk
StorageID string `json:"storage_id"`
StorageType string `json:"storage_type"`
LeadId int64 `json:"lead_id"` // Required.
}
type RespGenerated struct {
DownloadUrl string `json:"download_url"`
}
// GeneratorByAmoLead - сгенерировать файл по lead_id и указанному файлу если он установлен,
// или по шаблону если файл не указан
func (h *Handlers) GeneratorByAmoLead(w http.ResponseWriter, r *http.Request) {
var req ReqGeneratorByAmoLead
amoData := getAmoByJwt(r)
if amoData == nil {
h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized)
return
}
err := decodePost(&req, r)
if err != nil {
h.reportError(w, err, http.StatusBadRequest)
return
}
leadId := strconv.FormatInt(req.LeadId, 10)
if leadId == "" {
h.reportError(w, errors.New("lead_id required"), http.StatusBadRequest)
return
}
// Получить данные по лиду
amoClient, err := h.Amo.NewClient(r.Context(), amoData.Referer, amoData.Token(), "")
if err != nil {
h.reportError(w, err, http.StatusForbidden)
return
}
lead, err := amoClient.GetLeadById(leadId)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
return
}
if lead.Id == 0 {
fmt.Println("Lead empty")
}
dataTemplate := map[string]interface{}{}
// Добавляем Инфо Лида
for k, v := range templategen.AmoLeadFieldsToRuMap(lead) {
dataTemplate[k] = v
}
// Добавляем инфо контактов
contacts := []amo.Contact{}
for _, data := range lead.Embedded.Contacts {
contact, err := amoClient.GetContactById(strconv.Itoa(data.Id))
if err == nil {
contacts = append(contacts, *contact)
} else {
fmt.Println("Something Wrong1:", err)
}
}
dataTemplate["Контакты"] = templategen.AmoContactsFieldsToRuMap(contacts)
// Добавляем инфо компаний
companies := []amo.Company{}
for _, data := range lead.Embedded.Companies {
company, err := amoClient.GetCompanyById(strconv.Itoa(data.Id))
if err == nil {
companies = append(companies, *company)
} else {
fmt.Println("Something Wrong2:", err)
}
}
dataTemplate["Компании"] = templategen.AmoCompaniesFieldsToRuMap(companies)
var file, storageType, storageID, name string
if req.File != "" {
if req.StorageType == "" {
h.reportError(w, errors.New("storage required"), http.StatusBadRequest)
return
}
if req.StorageID == "" {
h.reportError(w, errors.New("storage_id required"), http.StatusBadRequest)
return
}
file = req.File
storageType = req.StorageType
storageID = req.StorageID
name = lead.Name
} else {
template, err := h.dal.Template.GetByLeadId(r.Context(), leadId)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
return
}
if template == nil {
h.reportError(w, err, http.StatusNotFound)
return
}
file = template.File
storageType = template.StorageType
storageID = template.StorageID
name = template.Name
}
exportUrl, err := h.generate(w, r, file, name, storageID, storageType, amoData.UserID, dataTemplate)
sendResponse(w, http.StatusOK, RespGenerated{DownloadUrl: exportUrl})
}
type ReqGeneratorByData struct {
File string `json:"file"`
StorageID string `json:"storage_id"`
StorageType string `json:"storage_type"`
TemplateID string `json:"template_id"`
Name string `json:"name"`
Data map[string]any `json:"data"`
}
// GeneratorByData - сгенерировать файл по данным и указанному файлу или шаблону
func (h *Handlers) GeneratorByData(w http.ResponseWriter, r *http.Request) {
var req ReqGeneratorByData
amoData := getAmoByJwt(r)
if amoData == nil {
h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized)
return
}
err := decodePost(&req, r)
if err != nil {
h.reportError(w, err, http.StatusBadRequest)
return
}
if req.StorageType == "" {
h.reportError(w, errors.New("storage required"), http.StatusBadRequest)
return
}
if req.StorageID == "" {
h.reportError(w, errors.New("storage_id required"), http.StatusBadRequest)
return
}
exportUrl, err := h.generate(w, r, req.File, req.Name, req.StorageID, req.StorageType, amoData.UserID, req.Data)
sendResponse(w, http.StatusOK, RespGenerated{DownloadUrl: exportUrl})
}
// GeneratorByAmoWebhook - эндпоинт для вебхука amo. Генерирует файл по ранее заданному шаблону
func (h *Handlers) GeneratorByAmoWebhook(w http.ResponseWriter, r *http.Request) {
reqBody, err := io.ReadAll(r.Body)
if err != nil {
h.reportError(w, err, http.StatusBadRequest)
return
}
body := string(reqBody)
fmt.Println()
bodyUnescaped, err := url.QueryUnescape(body)
fmt.Println("WEBHOOK BODY:", bodyUnescaped)
fmt.Println()
p, err := url.ParseQuery(body)
if err != nil {
h.reportError(w, err, http.StatusBadRequest)
return
}
leadId := p.Get("event[data][id]")
//subdomain := p.Get("subdomain")
accId := p.Get("account_id")
templateId := p.Get("action[settings][widget][settings][template_id]")
// pipelineId := p.Get("event[data][pipeline_id]")
// Запрашиваем данные по аккаунту
amoData, err := h.dal.Amo.GetByAccountID(r.Context(), accId)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
return
}
amoClient, err := h.Amo.NewClient(r.Context(), amoData.Referer, amoData.Token(), "")
if err != nil {
h.reportError(w, err, http.StatusForbidden)
return
}
lead, err := amoClient.GetLeadById(leadId)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
return
}
if lead != nil {
// fmt.Printf("Lead RESP:%+v\r\n", lead)
} else {
fmt.Println("Lead empty")
}
dataTemplate := map[string]interface{}{}
// Добавляем Инфо Лида
for k, v := range templategen.AmoLeadFieldsToRuMap(lead) {
dataTemplate[k] = v
}
// Добавялем инфо контактов
contacts := []amo.Contact{}
for _, data := range lead.Embedded.Contacts {
contact, err := amoClient.GetContactById(strconv.Itoa(data.Id))
if err == nil {
contacts = append(contacts, *contact)
} else {
fmt.Println("Something Wrong1:", err)
}
}
dataTemplate["Контакты"] = templategen.AmoContactsFieldsToRuMap(contacts)
// Добавляем инфо компаний
companies := []amo.Company{}
for _, data := range lead.Embedded.Companies {
company, err := amoClient.GetCompanyById(strconv.Itoa(data.Id))
if err == nil {
companies = append(companies, *company)
} else {
fmt.Println("Something Wrong2:", err)
}
}
dataTemplate["Компании"] = templategen.AmoCompaniesFieldsToRuMap(companies)
//template, err := h.dal.Template.GetByLeadId(r.Context(), leadId)
//if err != nil {
// h.reportError(w, err, http.StatusInternalServerError)
// return
//}
template, err := h.dal.Template.GetByID(r.Context(), templateId)
if template == nil {
h.reportError(w, err, http.StatusNotFound)
return
}
exportUrl, err := h.generate(w, r, template.File, template.Name, template.StorageID, template.StorageType,
amoData.UserID, dataTemplate)
sendResponse(w, 200, RespGenerated{DownloadUrl: exportUrl})
}
// generate - локальная функция, для генерации файла, возвращает ссылку для скачивания сгенерированного файла
func (h *Handlers) generate(w http.ResponseWriter, r *http.Request, file, name, storageID, storageType, userID string,
data any,
) (string, error) {
var exportUrl string
// Генерируем файл и загружаем в хранилище
switch storageType {
case "gdisk":
gdiskData, err := h.dal.GDisk.GetByID(r.Context(), storageID)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
return "", nil
}
if gdiskData == nil {
h.reportError(w, err, http.StatusInternalServerError)
return "", nil
}
client, err := h.GDisk.NewClient(r.Context(), gdiskData.Token())
exportUrl, err = templategen.GDiskGenerateDoc(file, name, userID, gdiskData.SaveFolderID, client,
data)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
return "", nil
}
case "yadisk":
yaDiskData, err := h.dal.YaDisk.GetByID(r.Context(), storageID)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
return "", nil
}
client, err := h.YaDisk.NewClient(r.Context(), yaDiskData.Token(), "")
exportUrl, err = templategen.YaDiskGenerateDoc(file, name, userID, yaDiskData.SaveFolder, client,
data)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
return "", nil
}
case "example":
generatedFile, err := templategen.ExampleGenerate(file, data)
if err != nil {
h.reportError(w, err, http.StatusInternalServerError)
}
generatedFile = strings.TrimPrefix(generatedFile, "./")
exportUrl = fmt.Sprintf("https://%v/%v", h.opts.Domain, generatedFile)
default:
h.reportError(w, errors.New("got unknown storage"), http.StatusInternalServerError)
return "", nil
}
// Обновляем счетчик генераций
return exportUrl, nil
}