package handlers import ( "amocrm_templategen_back/amo" "amocrm_templategen_back/dal/model" "amocrm_templategen_back/templategen" "errors" "fmt" "github.com/gorilla/schema" docTemp "github.com/opencontrol/doc-template" "golang.org/x/oauth2" "io/ioutil" "net/http" "net/url" "strconv" "time" ) type ReqAmoSaveToken struct { AccessToken string `json:"access_token" schema:"access_token"` Code string `json:"code" schema:"code"` ClientID string `json:"client_id" schema:"client_id"` ExpiresIn int64 `json:"expires_in" schema:"expires_in"` TokenType string `json:"token_type" schema:"token_type"` RefreshToken string `json:"refresh_token" schema:"refresh_token"` State string `json:"state" schema:"state"` FromWidget string `json:"from_widget" schema:"from_widget"` Referer string `json:"referer" schema:"referer"` } func (h *Handlers) AmoSaveToken(w http.ResponseWriter, r *http.Request) { var resp ReqAmoSaveToken err := r.ParseForm() if err != nil { h.reportError(w, err, http.StatusBadRequest) return } err = schema.NewDecoder().Decode(&resp, r.Form) if err != nil { h.reportError(w, err, 500) return } if resp.AccessToken == "" && resp.Code == "" { err = errors.New("AmoErr: got empty token") h.reportError(w, err, http.StatusBadRequest) return } token := &oauth2.Token{ AccessToken: resp.AccessToken, RefreshToken: resp.RefreshToken, TokenType: resp.TokenType, Expiry: time.Now().Add(time.Duration(resp.ExpiresIn) * time.Second), } var amoClient *amo.Client if resp.Code != "" { amoClient = h.Amo.NewClient(resp.Referer, resp.Code) token, err = amoClient.AuthCode() if err != nil { h.reportError(w, err, 500) return } } user := getJwtUser(r) if user == nil { h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) return } amoAcc, err := amoClient.GetAccount() if err != nil { h.reportError(w, err, 200) } if amoAcc == nil { return } else { fmt.Println(amoAcc) } // Insert/Update token in DB _, err = h.dal.Amo.InsertOrUpdate(r.Context(), &model.Amo{ UserID: user.UserID, AccountID: strconv.FormatInt(amoAcc.Id, 10), AccessToken: token.AccessToken, RefreshToken: token.RefreshToken, Code: resp.Code, FromWidget: resp.FromWidget, Referer: resp.Referer, Subdomain: amoAcc.Subdomain, ExpiresIn: token.Expiry, TokenType: token.TokenType, }) if err != nil { h.reportError(w, err, 500) return } err = sendResponse(w, 200, map[string]string{"accessToken": resp.AccessToken}) if err != nil { h.reportError(w, err, 500) } } func (h *Handlers) AmoWebhook(w http.ResponseWriter, r *http.Request) { fmt.Println(" -------------------- AMO WEBHOOK ------------------------") //resp := map[string]interface{}{} user := getJwtUser(r) if user != nil { fmt.Println("USER:", user) } reqBody, err := ioutil.ReadAll(r.Body) if err != nil { h.reportError(w, err, 200) return } p, err := url.ParseQuery(string(reqBody)) if err != nil { h.reportError(w, err, 200) return } fmt.Println("RESPONSE:") fmt.Println(p.Encode()) sendResponse(w, 200, nil) } func (h *Handlers) AmoWebhook2(w http.ResponseWriter, r *http.Request) { fmt.Println(" -------------------- AMO WEBHOOK 2------------------------") reqBody, err := ioutil.ReadAll(r.Body) if err != nil { h.reportError(w, err, 200) return } p, err := url.ParseQuery(string(reqBody)) if err != nil { h.reportError(w, err, 200) return } leadId := p.Get("leads[status][0][id]") subdomain := p.Get("account[subdomain]") accId := p.Get("account[id]") // Запрашиваем данные по аккаунту amoData, err := h.dal.Amo.GetByAccountID(r.Context(), accId) if err != nil { h.reportError(w, err, 200) return } amoClient := h.Amo.NewClient(subdomain+".amocrm.ru", amoData.Code) amoClient.SetToken(&oauth2.Token{ AccessToken: amoData.AccessToken, TokenType: amoData.TokenType, RefreshToken: amoData.RefreshToken, Expiry: amoData.ExpiresIn, }) lead, err := amoClient.GetLeadById(leadId) if err != nil { h.reportError(w, err, 200) 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 } filename := fmt.Sprintf("%v", dataTemplate["Filename"]) // Добавялем инфо контактов 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) //user := getJwtUser(r) //if user != nil { // // //} fmt.Printf("dataTemplate: %+v\r\n", dataTemplate) user, err := h.dal.User.GetByID(r.Context(), amoData.UserID) if err != nil { h.reportError(w, err, 200) } // PARSING yaDiskData, err := h.dal.YaDisk.GetByUserID(r.Context(), user.ID) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } if yaDiskData == nil { h.reportError(w, errors.New("YaDisk not found"), 200) return } token := &oauth2.Token{ AccessToken: yaDiskData.AccessToken, TokenType: yaDiskData.TokenType, RefreshToken: yaDiskData.RefreshToken, Expiry: yaDiskData.ExpiresIn, } if !token.Valid() { h.reportError(w, errors.New("yandex token invalid"), http.StatusForbidden) return } // download file client := h.YaDisk.NewClient(token) res, err := client.GetResources(yaDiskData.TemplateFolder + "/" + filename) if res == nil { h.reportError(w, errors.New("resource in yandex disk not found"), http.StatusNotFound) return } downloadFileName := fmt.Sprintf("./tmp/downloaded/%v_%v", user.ID, filename) err = templategen.DownloadDocument(downloadFileName, res.File) if err != nil { h.reportError(w, err, 200) return } // parsing file dc, err := docTemp.GetTemplate(downloadFileName) if err != nil { h.reportError(w, err, 200) return } dc.Parse() saveFilename := fmt.Sprintf("%v_%v_%v", user.ID, time.Now().Unix(), filename) err = dc.Execute("./tmp/parsed/"+saveFilename, dataTemplate) if err != nil { h.reportError(w, err, 200) return } // Send to Yandex Disk err = client.ResourcesUpload(yaDiskData.SaveFolder+"/"+saveFilename, "https://solweb.site/tmp/parsed/"+saveFilename) if err != nil { h.reportError(w, err, 200) return } //err := decodePost(&resp, r) //if err != nil { // h.reportError(w, err, 200) //} //err := r.ParseForm() //if err != nil { // h.reportError(w, err, 200) //} // //err = schema.NewDecoder().Decode(&resp, r.Form) //if err != nil { // h.reportError(w, err, 200) //} //fmt.Println("RESPONSE:", r.PostForm.Encode()) sendResponse(w, 200, nil) } type RespAmoSettingsGetData struct { Service struct { IsAuth bool `json:"is_auth"` IsActivated bool `json:"isActivated"` } `json:"service"` Google struct { IsAuth bool `json:"is_auth"` AuthUrl string `json:"auth_url,omitempty"` } `json:"google"` Yandex struct { IsAuth bool `json:"is_auth"` AuthUrl string `json:"auth_url,omitempty"` } `json:"yandex"` } func (h *Handlers) AmoSettingsGetData(w http.ResponseWriter, r *http.Request) { amoData := getAmoByJwt(r) if amoData == nil { h.reportError(w, errors.New("amo account not found"), http.StatusUnauthorized) return } user, err := h.dal.User.GetByID(r.Context(), amoData.UserID) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } if user == nil { h.reportError(w, errors.New("user not found"), http.StatusUnauthorized) return } resp := RespAmoSettingsGetData{} resp.Service.IsAuth = true yandexData, err := h.dal.YaDisk.GetByUserID(r.Context(), user.ID) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } if yandexData != nil { resp.Yandex.IsAuth = time.Now().Before(yandexData.ExpiresIn) && yandexData.AccessToken != "" } if !resp.Yandex.IsAuth { resp.Yandex.AuthUrl = h.YaDisk.GenerateOAuthUrl() } googleData, err := h.dal.GDisk.GetByUserID(r.Context(), user.ID) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } if googleData != nil { resp.Google.IsAuth = time.Now().Before(googleData.ExpiresIn) && googleData.AccessToken != "" } if !resp.Google.IsAuth { resp.Google.AuthUrl = h.GDisk.GenerateOAuthUrl() } sendResponse(w, 200, resp) } type RespAmoState struct { Visibility []int64 `json:"visibility"` Creation []int64 `json:"creation"` Delete []int64 `json:"delete"` } func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { amoData := getAmoByJwt(r) if amoData == nil { h.reportError(w, errors.New("amo account not found"), http.StatusUnauthorized) return } resp := RespAmoState{ Visibility: amoData.AccessRules.Visibility, Creation: amoData.AccessRules.Creation, Delete: amoData.AccessRules.Delete, } sendResponse(w, 200, resp) } type ReqAmoGetTemplate struct { LeadId int64 `json:"lead_id"` TemplateId string `json:"template_id"` } func (h *Handlers) AmoGetTemplate(w http.ResponseWriter, r *http.Request) { var req ReqAmoGetTemplate amoData := getAmoByJwt(r) if amoData == nil { h.reportError(w, errors.New("amo account not found"), http.StatusUnauthorized) return } err := decodePost(&req, r) if err != nil { h.reportError(w, err, http.StatusBadRequest) return } if req.TemplateId == "" && strconv.FormatInt(req.LeadId, 10) == "" { h.reportError(w, err, http.StatusBadRequest) return } var template *model.Template if req.TemplateId != "" { template, err = h.dal.Template.GetByID(r.Context(), req.TemplateId) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } } if strconv.FormatInt(req.LeadId, 10) != "" { template, err = h.dal.Template.GetByLeadId(r.Context(), strconv.FormatInt(req.LeadId, 10)) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } } if template == nil { templateId, err := h.dal.Template.Insert(r.Context(), &model.Template{ UserID: amoData.UserID, LeadId: strconv.FormatInt(req.LeadId, 10), }) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } template = &model.Template{ID: templateId} } sendResponse(w, 200, template) } type ReqAmoSetTemplate struct { LeadId int64 `json:"lead_id"` TemplateId string `json:"template_id"` Filename string `json:"filename"` FileID string `json:"file_id"` // for Google Drive Storage string `json:"storage"` // google or yandex } type RespAmoSetTemplate struct { TemplateId string `json:"template_id"` } func (h *Handlers) AmoSetTemplate(w http.ResponseWriter, r *http.Request) { var req ReqAmoSetTemplate amoData := getAmoByJwt(r) if amoData == nil { h.reportError(w, errors.New("amo account not found"), http.StatusUnauthorized) return } err := decodePost(&req, r) if err != nil { h.reportError(w, err, http.StatusBadRequest) return } if strconv.FormatInt(req.LeadId, 10) == "" || req.Storage == "" { h.reportError(w, err, http.StatusBadRequest) return } if req.Filename == "" && req.FileID == "" { h.reportError(w, err, http.StatusBadRequest) return } // Search/update template var template *model.Template update := &model.Template{ ID: req.TemplateId, UserID: amoData.UserID, LeadId: strconv.FormatInt(req.LeadId, 10), Name: "Sample", Filename: req.Filename, Storage: req.Storage, FileID: req.FileID, IsDeleted: false, } templateId := "" if req.TemplateId == "" { template, err = h.dal.Template.GetByLeadId(r.Context(), strconv.FormatInt(req.LeadId, 10)) fmt.Println(0, template) if template != nil { fmt.Println("1", update) err = h.dal.Template.UpdateByLeadID(r.Context(), update) } else { fmt.Println("2", update) templateId, err = h.dal.Template.Insert(r.Context(), update) } } else { err = h.dal.Template.UpdateByID(r.Context(), update) } if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } sendResponse(w, 200, RespAmoSetTemplate{templateId}) } type ReqAmoGenerateDoc struct { LeadId int64 `json:"lead_id"` Filename string `json:"filename"` } func (h *Handlers) AmoGenerateDoc(w http.ResponseWriter, r *http.Request) { var req ReqAmoGenerateDoc amoData := getAmoByJwt(r) if amoData == nil { h.reportError(w, errors.New("amo account not found"), 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, err, http.StatusBadRequest) return } 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 } // Получить данные по лиду amoClient := h.Amo.NewClient(amoData.Subdomain+".amocrm.ru", amoData.Code) amoClient.SetToken(&oauth2.Token{ AccessToken: amoData.AccessToken, TokenType: amoData.TokenType, RefreshToken: amoData.RefreshToken, Expiry: amoData.ExpiresIn, }) lead, err := amoClient.GetLeadById(leadId) if err != nil { h.reportError(w, err, 200) return } if lead.Id == 0 { fmt.Println("Lead empty") } dataTemplate := map[string]interface{}{} // Добавляем Инфо Лида for k, v := range templategen.AmoLeadFieldsToRuMap(lead) { dataTemplate[k] = v } filename := fmt.Sprintf("%v_%v_%v.docx", req.Filename, amoData.UserID, time.Now().Unix()) // Добавялем инфо контактов 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) fmt.Printf("TemplateInfo:%+v\r\n", dataTemplate) // Скачать файл // Google OAuth googleData, err := h.dal.GDisk.GetByUserID(r.Context(), amoData.UserID) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } if googleData == nil { h.reportError(w, errors.New("google data not found"), http.StatusForbidden) return } if googleData.Token() == nil { h.reportError(w, errors.New("invalid google token"), http.StatusForbidden) return } googleClient, err := h.GDisk.NewClient(r.Context(), googleData.Token()) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } err = googleClient.DownloadFile("./tmp/downloaded/"+filename, template.FileID) if err != nil { h.reportError(w, err, 500) return } // Сгенерировать // parsing file dc, err := docTemp.GetTemplate("./tmp/downloaded/" + filename) if err != nil { h.reportError(w, err, 500) return } dc.Parse() err = dc.Execute("./tmp/parsed/"+filename, dataTemplate) if err != nil { h.reportError(w, err, 500) return } // Загрузить // application/vnd.openxmlformats-officedocument.wordprocessingml.document or application/msword err = googleClient.UploadFile("./tmp/parsed/"+filename, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", googleData.SaveFolderID) if err != nil { h.reportError(w, err, 500) return } fmt.Println("Parsing Done") } type ReqAmoAccessRules struct { Visibility []int64 `json:"visibility"` Creation []int64 `json:"creation"` Delete []int64 `json:"delete"` } func (h *Handlers) AmoAccessRules(w http.ResponseWriter, r *http.Request) { var req ReqAmoAccessRules amoData := getAmoByJwt(r) if amoData == nil { h.reportError(w, errors.New("amo account not found"), http.StatusUnauthorized) return } err := decodePost(&req, r) if err != nil { h.reportError(w, err, http.StatusBadRequest) return } if (req.Visibility == nil || len(req.Visibility) == 0) && (req.Creation == nil || len(req.Creation) == 0) && (req.Delete == nil || len(req.Delete) == 0) { h.reportError(w, errors.New("empty request"), http.StatusBadRequest) return } err = h.dal.Amo.UpdateAccessRules(r.Context(), amoData.ID, &model.AmoAccessRules{ Visibility: req.Visibility, Creation: req.Creation, Delete: req.Delete, }) if err != nil { h.reportError(w, err, http.StatusInternalServerError) return } w.WriteHeader(200) }