diff --git a/email-tester/.gitignore b/email-tester/.gitignore new file mode 100644 index 0000000..62c8935 --- /dev/null +++ b/email-tester/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file diff --git a/email-tester/README.md b/email-tester/README.md new file mode 100644 index 0000000..36557c5 --- /dev/null +++ b/email-tester/README.md @@ -0,0 +1,11 @@ +# email-tester + +нужен для тестирования текущей логики отправки формы, все что нужно это запустить в терминале проект, вписать тип события - toClient или reminder, а также что config.yaml находящийся в проекте в той же директории заполенен и все выходящие из него штуки, таки как шаблоны и файл json должны быть заполены + +процесс работы: +- установить конфигурационный файл, пример в проекте +- поставить шаблоны, пример в проекте +- при запуске указать тип работы, toClient или reminder +- после этого произойдет логика работы с шаблоном и проведется отправка на почту данных +- далее информация в консоль выведется, если произойдет ошибка в консоли выведется +- в конце нужно прописать exit чтобы выйти из текущего сеанса и консоли, далее запуск снова и т.д. \ No newline at end of file diff --git a/email-tester/client/mail.go b/email-tester/client/mail.go new file mode 100644 index 0000000..341de8a --- /dev/null +++ b/email-tester/client/mail.go @@ -0,0 +1,121 @@ +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/gofiber/fiber/v2" + "mime/multipart" + "penahub.gitlab.yandexcloud.net/pena-services/email-tester/model" +) + +type Deps struct { + SmtpApiUrl string + SmtpSender string + ApiKey string + FiberClient *fiber.Client +} + +type SmtpClient struct { + smtpApiUrl string + smtpSender string + apiKey string + fiberClient *fiber.Client +} + +func NewSmtpClient(deps Deps) *SmtpClient { + if deps.FiberClient == nil { + deps.FiberClient = fiber.AcquireClient() + } + return &SmtpClient{ + smtpApiUrl: deps.SmtpApiUrl, + smtpSender: deps.SmtpSender, + apiKey: deps.ApiKey, + fiberClient: deps.FiberClient, + } +} + +type Message struct { + To string + Subject string + HtmlBody string + Attachments []Attachment +} + +type Attachment struct { + Name string `json:"name"` + // data в base64 это файл + Data string `json:"body"` +} + +type TemplateData struct { + QuizConfig model.ResultInfo + AnswerContent model.ResultContent + AllAnswers []model.ResultAnswer + QuestionsMap map[uint64]string + AnswerTime string +} + +func (m *SmtpClient) MailSender(data Message) error { + form := new(bytes.Buffer) + writer := multipart.NewWriter(form) + + fields := map[string]string{ + "from": m.smtpSender, + "to": data.To, + "subject": data.Subject, + "html": data.HtmlBody, + } + + if data.Attachments != nil && len(data.Attachments) > 0 { + attachmentJson, err := json.Marshal(data.Attachments) + if err != nil { + return err + } + fields["files"] = string(attachmentJson) + } + + for key, value := range fields { + if err := writer.WriteField(key, value); err != nil { + return err + } + } + + if err := writer.Close(); err != nil { + return err + } + + req := m.fiberClient.Post(m.smtpApiUrl).Body(form.Bytes()).ContentType(writer.FormDataContentType()) + if m.apiKey != "" { + req.Set("Authorization", m.apiKey) + } + + statusCode, body, errs := req.Bytes() + if errs != nil { + return errs[0] + } + + if statusCode != fiber.StatusOK { + err := fmt.Errorf("the SMTP service returned an error: %d Response body: %s", statusCode, body) + return err + } + + return nil +} + +func (m *SmtpClient) SendMailWithAttachment(recipient, subject string, emailTemplate string, data TemplateData, attachments []Attachment) error { + sanitizedData := sanitizeHTMLData(data) + text, err := generateTextFromTemplate(sanitizedData, emailTemplate) + if err != nil { + return err + } + + msg := Message{ + To: recipient, + Subject: subject, + HtmlBody: text, + Attachments: attachments, + } + + return m.MailSender(msg) +} diff --git a/email-tester/client/tools.go b/email-tester/client/tools.go new file mode 100644 index 0000000..637d11e --- /dev/null +++ b/email-tester/client/tools.go @@ -0,0 +1,144 @@ +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "golang.org/x/net/html" + "html/template" + "penahub.gitlab.yandexcloud.net/pena-services/email-tester/model" + "strings" +) + +func generateTextFromTemplate(data TemplateData, tpl string) (string, error) { + t, err := template.New("email").Funcs(tmplFuncs).Parse(tpl) + if err != nil { + return "", fmt.Errorf("error parsing template: %w", err) + } + + var text bytes.Buffer + if err := t.Execute(&text, TemplateData{ + QuizConfig: data.QuizConfig, + AnswerContent: data.AnswerContent, + AllAnswers: data.AllAnswers, + QuestionsMap: data.QuestionsMap, + AnswerTime: data.AnswerTime, + }); err != nil { + return "", fmt.Errorf("error executing template: %w", err) + } + + return text.String(), nil +} + +var tmplFuncs = template.FuncMap{ + "renderImage": RenderImage, +} + +func RenderImage(content string) template.HTML { + var res model.ImageContent + err := json.Unmarshal([]byte(content), &res) + if err != nil { + return SplitContent(content) + } + tpl := template.HTML(fmt.Sprintf("%s
", res.Description, res.Image)) + return tpl +} + +func SplitContent(content string) template.HTML { + parts := strings.Split(content, "|") + if len(parts) == 2 { + url := strings.TrimSpace(parts[0]) + filename := strings.TrimSpace(parts[1]) + return template.HTML(fmt.Sprintf(`%s`, url, filename)) + } + return template.HTML(content) +} + +func sanitizeHTMLData(data TemplateData) TemplateData { + sanitized := TemplateData{ + QuizConfig: stripHTMLResultInfo(data.QuizConfig), + AnswerContent: stripHTMLResultContent(data.AnswerContent), + AllAnswers: stripHTMLResultAnswers(data.AllAnswers), + QuestionsMap: stripHTMLResultMap(data.QuestionsMap), + AnswerTime: StripHTML(data.AnswerTime), + } + return sanitized +} + +func stripHTMLResultInfo(input model.ResultInfo) model.ResultInfo { + return model.ResultInfo{ + When: StripHTML(input.When), + Theme: StripHTML(input.Theme), + Reply: StripHTML(input.Reply), + ReplName: StripHTML(input.ReplName), + } +} + +func stripHTMLResultContent(input model.ResultContent) model.ResultContent { + return model.ResultContent{ + Text: StripHTML(input.Text), + Name: StripHTML(input.Name), + Email: StripHTML(input.Email), + Phone: StripHTML(input.Phone), + Address: StripHTML(input.Address), + Telegram: StripHTML(input.Telegram), + Wechat: StripHTML(input.Wechat), + Viber: StripHTML(input.Viber), + Vk: StripHTML(input.Vk), + Skype: StripHTML(input.Skype), + Whatsup: StripHTML(input.Whatsup), + Messenger: StripHTML(input.Messenger), + Custom: stripHTMLCustom(input.Custom), + } +} + +func stripHTMLResultAnswers(answers []model.ResultAnswer) []model.ResultAnswer { + sanitized := make([]model.ResultAnswer, len(answers)) + for i, j := range answers { + sanitized[i] = model.ResultAnswer{ + Content: StripHTML(j.Content), + CreatedAt: j.CreatedAt, + QuestionID: j.QuestionID, + AnswerID: j.AnswerID, + } + } + return sanitized +} + +func stripHTMLResultMap(questionsMap map[uint64]string) map[uint64]string { + sanitized := make(map[uint64]string) + for i, j := range questionsMap { + sanitized[i] = StripHTML(j) + } + return sanitized +} + +func stripHTMLCustom(custom map[string]string) map[string]string { + sanitized := make(map[string]string) + for i, j := range custom { + sanitized[i] = StripHTML(j) + } + return sanitized +} + +func StripHTML(htmlString string) string { + tokenizer := html.NewTokenizer(bytes.NewBufferString(htmlString)) + var result bytes.Buffer + for { + tokenType := tokenizer.Next() + switch tokenType { + case html.ErrorToken: + return strings.TrimSpace(result.String()) + case html.TextToken: + result.WriteString(tokenizer.Token().Data) + result.WriteString("\n") + case html.StartTagToken, html.EndTagToken: + tagName, _ := tokenizer.TagName() + if string(tagName) == "a" { + _, attrVal, _ := tokenizer.TagAttr() + result.WriteString(string(attrVal)) + result.WriteString("\n") + } + } + } +} diff --git a/email-tester/config.yaml b/email-tester/config.yaml new file mode 100644 index 0000000..e0ad1df --- /dev/null +++ b/email-tester/config.yaml @@ -0,0 +1,10 @@ +apiUrl: "https://api.smtp.bz/v1/smtp/send" +apiKey: "P0YsjUB137upXrr1NiJefHmXVKW1hmBWlpev" +subject: "test" +sender: "noreply@mailing.pena.digital" +to: "pashamullin2001@gmail.com" +pathToTemplateData: "template/templateData.json" +pathToReminderTemplate: "template/reminder_base.tmpl" +pathToToClientTemplate: "template/to_client_base.tmpl" + + diff --git a/email-tester/go.mod b/email-tester/go.mod new file mode 100644 index 0000000..a70ca92 --- /dev/null +++ b/email-tester/go.mod @@ -0,0 +1,23 @@ +module penahub.gitlab.yandexcloud.net/pena-services/email-tester + +go 1.22.4 + +require ( + github.com/gofiber/fiber/v2 v2.52.5 + golang.org/x/net v0.17.0 + gopkg.in/yaml.v2 v2.4.0 +) + +require ( + github.com/andybalholm/brotli v1.0.5 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/klauspost/compress v1.17.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/sys v0.15.0 // indirect +) diff --git a/email-tester/go.sum b/email-tester/go.sum new file mode 100644 index 0000000..bdf88e3 --- /dev/null +++ b/email-tester/go.sum @@ -0,0 +1,33 @@ +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= +github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/email-tester/main.go b/email-tester/main.go new file mode 100644 index 0000000..9d09ac1 --- /dev/null +++ b/email-tester/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" + "os" + "penahub.gitlab.yandexcloud.net/pena-services/email-tester/model" + "penahub.gitlab.yandexcloud.net/pena-services/email-tester/senders" +) + +type event string + +var toClient event = "toClient" +var reminder event = "reminder" + +func main() { + fmt.Println("Need event type 'toClient' or 'reminder':") + var eventFlag string + fmt.Scanln(&eventFlag) + defer func() { + fmt.Println("if you want exit write 'exit'") + var exit string + fmt.Scanln(&exit) + if exit == "exit" { + return + } + }() + config, err := loadConfig("config.yaml") + if err != nil { + fmt.Println(err) + return + } + err = config.Validate() + if err != nil { + fmt.Println("failed validate config:", err) + return + } + switch eventFlag { + case string(toClient): + fmt.Println("Processing 'toClient' event") + err = senders.ToClientTesting(config) + if err != nil { + fmt.Println("error process task for toClient test:", err) + return + } + fmt.Println("OK check mailbox") + case string(reminder): + fmt.Println("Processing 'reminder' event") + err = senders.ReminderTesting(config) + if err != nil { + fmt.Println("error process task for reminder test:", err) + return + } + fmt.Println("OK check mailbox") + default: + fmt.Println("No event type or unknown event type specified need 'toClient' or 'reminder'") + } +} + +func loadConfig(filename string) (model.Config, error) { + var config model.Config + + file, err := os.Open(filename) + if err != nil { + return config, err + } + defer file.Close() + + data, err := ioutil.ReadAll(file) + if err != nil { + return config, err + } + + err = yaml.Unmarshal(data, &config) + if err != nil { + return config, err + } + + return config, nil +} diff --git a/email-tester/model/model.go b/email-tester/model/model.go new file mode 100644 index 0000000..14e75f7 --- /dev/null +++ b/email-tester/model/model.go @@ -0,0 +1,81 @@ +package model + +import ( + "errors" + "time" +) + +type Config struct { + ApiURL string `yaml:"apiUrl"` + ApiKey string `yaml:"apiKey"` + Subject string `yaml:"subject"` + Sender string `yaml:"sender"` + PathToTemplateData string `yaml:"pathToTemplateData"` + PathToReminderTemplate string `yaml:"pathToReminderTemplate"` + PathToToClientTemplate string `yaml:"pathToToClientTemplate"` + To string `yaml:"to"` +} + +func (c *Config) Validate() error { + if c.ApiURL == "" { + return errors.New("ApiURL dont be nil") + } + if c.ApiKey == "" { + return errors.New("ApiKey dont be nil") + } + if c.Subject == "" { + return errors.New("Subject dont be nil") + } + if c.Sender == "" { + return errors.New("Sender dont be nil") + } + if c.PathToTemplateData == "" { + return errors.New("PathToTemplateData dont be nil") + } + if c.PathToReminderTemplate == "" { + return errors.New("PathToReminderTemplate dont be nil") + } + if c.PathToToClientTemplate == "" { + return errors.New("PathToToClientTemplate dont be nil") + } + if c.To == "" { + return errors.New("To dont be nil") + } + return nil +} + +type ResultInfo struct { + When string `json:"when"` // before|after|email + Theme string `json:"theme"` // тема письма + Reply string `json:"reply"` // email для ответов, указывается в создании письма + ReplName string `json:"repl_name"` // имя отправителя +} + +type ResultContent struct { + Text string `json:"text"` + Name string `json:"name"` + Email string `json:"email"` + Phone string `json:"phone"` + Address string `json:"address"` + Telegram string `json:"telegram"` + Wechat string `json:"wechat"` + Viber string `json:"viber"` + Vk string `json:"vk"` + Skype string `json:"skype"` + Whatsup string `json:"whatsup"` + Messenger string `json:"messenger"` + Custom map[string]string `json:"customs"` + Start bool `json:"start"` +} + +type ResultAnswer struct { + Content string + CreatedAt time.Time + QuestionID uint64 + AnswerID uint64 +} + +type ImageContent struct { + Description string + Image string +} diff --git a/email-tester/senders/reminder.go b/email-tester/senders/reminder.go new file mode 100644 index 0000000..91661bd --- /dev/null +++ b/email-tester/senders/reminder.go @@ -0,0 +1,30 @@ +package senders + +import ( + "penahub.gitlab.yandexcloud.net/pena-services/email-tester/client" + "penahub.gitlab.yandexcloud.net/pena-services/email-tester/model" +) + +func ReminderTesting(config model.Config) error { + smtpClient := client.NewSmtpClient(client.Deps{ + SmtpApiUrl: config.ApiURL, + SmtpSender: config.Sender, + ApiKey: config.ApiKey, + }) + + templateData, err := parseTemplateData(config.PathToTemplateData) + if err != nil { + return err + } + + body, err := loadTemplate(config.PathToReminderTemplate) + if err != nil { + return err + } + + err = smtpClient.SendMailWithAttachment(config.To, config.Subject, body, templateData, nil) + if err != nil { + return err + } + return nil +} diff --git a/email-tester/senders/toClient.go b/email-tester/senders/toClient.go new file mode 100644 index 0000000..15a841b --- /dev/null +++ b/email-tester/senders/toClient.go @@ -0,0 +1,56 @@ +package senders + +import ( + "encoding/json" + "io/ioutil" + "penahub.gitlab.yandexcloud.net/pena-services/email-tester/client" + "penahub.gitlab.yandexcloud.net/pena-services/email-tester/model" +) + +func ToClientTesting(config model.Config) error { + smtpClient := client.NewSmtpClient(client.Deps{ + SmtpApiUrl: config.ApiURL, + SmtpSender: config.Sender, + ApiKey: config.ApiKey, + }) + + templateData, err := parseTemplateData(config.PathToTemplateData) + if err != nil { + return err + } + + body, err := loadTemplate(config.PathToToClientTemplate) + if err != nil { + return err + } + + err = smtpClient.SendMailWithAttachment(config.To, config.Subject, body, templateData, nil) + if err != nil { + return err + } + return nil +} + +func parseTemplateData(filePath string) (client.TemplateData, error) { + var data client.TemplateData + + file, err := ioutil.ReadFile(filePath) + if err != nil { + return data, err + } + + err = json.Unmarshal(file, &data) + if err != nil { + return data, err + } + + return data, nil +} + +func loadTemplate(filePath string) (string, error) { + fileContent, err := ioutil.ReadFile(filePath) + if err != nil { + return "", err + } + return string(fileContent), nil +} diff --git a/email-tester/template/reminder_base.tmpl b/email-tester/template/reminder_base.tmpl new file mode 100644 index 0000000..f966af0 --- /dev/null +++ b/email-tester/template/reminder_base.tmpl @@ -0,0 +1,191 @@ + + + + + + Document + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

Квиз для вашего бизнеса

+
+

+ Поступила новая заявка с квиза “{{ .QuizConfig.Theme }}”! +

+
+

+ Но у вас закончились средства на балансе :( +

+
+ +
+

+ Аккаунт +

+
+ + + + + +
+ Email + +

+ {{ .QuizConfig.Reply }} +

+
+
+

+ Пополните баланс и посмотрите заявку в личном кабинете: +

+
+ + Посмотреть в личном кабинете + +
+
+ + quiz.pena.digital + +
+ + diff --git a/email-tester/template/templateData.json b/email-tester/template/templateData.json new file mode 100644 index 0000000..d6e5c5e --- /dev/null +++ b/email-tester/template/templateData.json @@ -0,0 +1,57 @@ +{ + "QuizConfig": { + "when": "test@example.com", + "theme": "Taemplste Quiz", + "reply": "test@example.com", + "repl_name": "test@example.com" + }, + "AnswerContent": { + "text": "", + "name": "test", + "email": "test@example.com", + "phone": "+723456789", + "address": "", + "telegram": "@test", + "wechat": "test_wechat", + "viber": "+723456789", + "vk": "test_vk", + "skype": "test_skype", + "whatsup": "test_whatsup", + "messenger": "test_messenger", + "customs": {}, + "start": false + }, + "AllAnswers": [ + { + "Content": "https://www.google.com/search?q=ku,n", + "CreatedAt": "2024-07-05T18:54:37Z", + "QuestionID": 1, + "AnswerID": 1 + }, + { + "Content": "From a friend", + "CreatedAt": "2024-07-05T18:54:37Z", + "QuestionID": 2, + "AnswerID": 2 + }, + { + "Content": "From a friend", + "CreatedAt": "2024-07-05T18:54:37Z", + "QuestionID": 3, + "AnswerID": 3 + }, + { + "Content": "{\"Image\": \"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTZvq8kZl7QhYC_7f0jMlepfnLkr8Y94tJY1g&s\", \"Description\": \"Gekon\"}", + "CreatedAt": "2024-07-05T18:54:37Z", + "QuestionID": 4, + "AnswerID": 4 + } + ], + "QuestionsMap": { + "1": "?", + "2": "How did you hear about us?", + "3": "que 3", + "4": "que 4" + }, + "AnswerTime": "2024-07-05T18:54:37Z" +} \ No newline at end of file diff --git a/email-tester/template/to_client_base.tmpl b/email-tester/template/to_client_base.tmpl new file mode 100644 index 0000000..fe36b93 --- /dev/null +++ b/email-tester/template/to_client_base.tmpl @@ -0,0 +1,537 @@ + + + + + + Document + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ range .AllAnswers }} + {{ if index $.QuestionsMap .AnswerID }} + + + + {{ end }} + {{end}} + + + + +
+ + +

Квиз для вашего бизнеса

+
+

+ Поступила новая заявка с квиза “{{.QuizConfig.Theme}}”! +

+
+

+ Время заявки: {{ .AnswerTime }} +

+
+ + Посмотреть в личном кабинете + +
+

+ Контакты +

+
+ + + + + + {{ if .AnswerContent.Email }} + + + + + {{ end }} + {{ if .AnswerContent.Phone }} + + + + + {{ end }} + + {{ if .AnswerContent.Telegram }} + + + + + {{ end }} + {{ if .AnswerContent.Wechat }} + + + + + {{ end }} + {{ if .AnswerContent.Viber }} + + + + + {{ end }} + {{ if .AnswerContent.Vk }} + + + + + {{ end }} + {{ if .AnswerContent.Skype }} + + + + + {{ end }} + {{ if .AnswerContent.Whatsup }} + + + + + {{ end }} + {{ if .AnswerContent.Messenger }} + + + + + {{ end }} + {{ if .AnswerContent.Address }} + + + + + {{ end }} + {{ range $key, $value := .AnswerContent.Custom }} + + + + + + {{ end }} +
+ Имя + +

+ {{ .AnswerContent.Name}} +

+
+ Email + +

+ {{ .AnswerContent.Email }} +

+
+ Телефон + + {{ .AnswerContent.Phone }} +
+ Telegram + + {{ .AnswerContent.Telegram }} +
+ Wechat + + {{ .AnswerContent.Wechat }} +
+ Viber + + {{ .AnswerContent.Viber }} +
+ Vk + + {{ .AnswerContent.Vk }} +
+ Skype + + {{ .AnswerContent.Skype }} +
+ Whatsup + + {{ .AnswerContent.Whatsup }} +
+ Messenger + + {{ .AnswerContent.Messenger }} +
+ Адрес + + {{ .AnswerContent.Address }} +
+ {{ $key }} + + {{ $value }} +
+
+

+ Ответы +

+
+ + + + + + + + +
+

+ {{ index $.QuestionsMap .AnswerID }} +

+
+ {{ renderImage .Content }} +
+
+ + quiz.pena.digital + +
+ +