moved email-tester from gitlab to gitlab tools
This commit is contained in:
parent
4a2f581a40
commit
e9043bc198
1
email-tester/.gitignore
vendored
Normal file
1
email-tester/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.idea/
|
11
email-tester/README.md
Normal file
11
email-tester/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# email-tester
|
||||
|
||||
нужен для тестирования текущей логики отправки формы, все что нужно это запустить в терминале проект, вписать тип события - toClient или reminder, а также что config.yaml находящийся в проекте в той же директории заполенен и все выходящие из него штуки, таки как шаблоны и файл json должны быть заполены
|
||||
|
||||
процесс работы:
|
||||
- установить конфигурационный файл, пример в проекте
|
||||
- поставить шаблоны, пример в проекте
|
||||
- при запуске указать тип работы, toClient или reminder
|
||||
- после этого произойдет логика работы с шаблоном и проведется отправка на почту данных
|
||||
- далее информация в консоль выведется, если произойдет ошибка в консоли выведется
|
||||
- в конце нужно прописать exit чтобы выйти из текущего сеанса и консоли, далее запуск снова и т.д.
|
121
email-tester/client/mail.go
Normal file
121
email-tester/client/mail.go
Normal file
@ -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)
|
||||
}
|
144
email-tester/client/tools.go
Normal file
144
email-tester/client/tools.go
Normal file
@ -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("<td>%s<br><img class=\"image\" style=\"width:100%%; max-width:250px; max-height:250px\" src=\"%s\"/></td>", 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(`<a href="%s" download>%s</a>`, 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
email-tester/config.yaml
Normal file
10
email-tester/config.yaml
Normal file
@ -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"
|
||||
|
||||
|
23
email-tester/go.mod
Normal file
23
email-tester/go.mod
Normal file
@ -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
|
||||
)
|
33
email-tester/go.sum
Normal file
33
email-tester/go.sum
Normal file
@ -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=
|
81
email-tester/main.go
Normal file
81
email-tester/main.go
Normal file
@ -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
|
||||
}
|
81
email-tester/model/model.go
Normal file
81
email-tester/model/model.go
Normal file
@ -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
|
||||
}
|
30
email-tester/senders/reminder.go
Normal file
30
email-tester/senders/reminder.go
Normal file
@ -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
|
||||
}
|
56
email-tester/senders/toClient.go
Normal file
56
email-tester/senders/toClient.go
Normal file
@ -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
|
||||
}
|
191
email-tester/template/reminder_base.tmpl
Normal file
191
email-tester/template/reminder_base.tmpl
Normal file
@ -0,0 +1,191 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
<style>
|
||||
/* Сброс стилей */
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p,
|
||||
div,
|
||||
img,
|
||||
button,
|
||||
table,
|
||||
th,
|
||||
td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f2f2f7;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
@media (max-width: 400px) {
|
||||
h1 {
|
||||
font-size: 25px !important;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
|
||||
.balance {
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
.image {
|
||||
max-width: 223px;
|
||||
height: 208px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="background-color: #f2f2f7; font-family: Arial, sans-serif">
|
||||
<table style="width: 100%; padding: 16px">
|
||||
<tr>
|
||||
<td>
|
||||
<img class="image" style="width: 103px; height: 40px" src="https://storage.yandexcloud.net/squizimages/logo-email-squiz.png" />
|
||||
</td>
|
||||
<td>
|
||||
<p style="text-align: end; color: #9a9aaf; font-size: 14px">Квиз для вашего бизнеса</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<h1
|
||||
style="
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 13px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
margin-bottom: 16px;
|
||||
margin-top: 50px;
|
||||
"
|
||||
>
|
||||
Поступила новая заявка с квиза “{{ .QuizConfig.Theme }}”!
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<p class="balance" style="color: #4d4d4d; font-size: 20px; margin-bottom: 30px">
|
||||
Но у вас закончились средства на балансе :(
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: center; padding: 0">
|
||||
<img class="image" style="width: 100%; max-width: 440px; height: 280px; margin-bottom: 40px" src="https://storage.yandexcloud.net/squizimages/img_wallet.png" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<h1
|
||||
style="font-size: 25px; font-weight: 600; margin-bottom: 15px; width: 100%; margin: 0; margin-bottom: 13px"
|
||||
>
|
||||
Аккаунт
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="padding: 0">
|
||||
<table
|
||||
style="
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
text-align: left;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
margin-bottom: 40px;
|
||||
"
|
||||
>
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Email
|
||||
</th>
|
||||
<td style="word-break: break-word">
|
||||
<p
|
||||
style="
|
||||
text-align: start;
|
||||
color: #7e2aea;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
margin-bottom: 15px;
|
||||
"
|
||||
>
|
||||
{{ .QuizConfig.Reply }}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<p class="balance" style="color: #9a9aaf; font-size: 20px; margin-bottom: 30px; text-align: center">
|
||||
Пополните баланс и посмотрите заявку в личном кабинете:
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%; text-align: center">
|
||||
<a
|
||||
style="
|
||||
max-width: 312px;
|
||||
color: #f2f3f7;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #7e2aea;
|
||||
background: #7e2aea;
|
||||
padding: 10px 43px;
|
||||
"
|
||||
>
|
||||
Посмотреть в личном кабинете
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: center; padding: 30px 0 0 0">
|
||||
<hr style="border-top: 2px solid rgba(126, 42, 234, 0.2); margin: 0 0 10px" />
|
||||
<a style="color: #7e2aea; font-size: 20px; font-style: normal; font-weight: 400; line-height: normal">
|
||||
quiz.pena.digital
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
57
email-tester/template/templateData.json
Normal file
57
email-tester/template/templateData.json
Normal file
@ -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"
|
||||
}
|
537
email-tester/template/to_client_base.tmpl
Normal file
537
email-tester/template/to_client_base.tmpl
Normal file
@ -0,0 +1,537 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
<style>
|
||||
/* Сброс стилей */
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p,
|
||||
div,
|
||||
img,
|
||||
button,
|
||||
table,
|
||||
th,
|
||||
td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f2f2f7;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
h1 {
|
||||
font-size: 25px !important;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="background-color: #f2f2f7; font-family: Arial, sans-serif">
|
||||
<table style="width: 100%; padding: 16px">
|
||||
<tr>
|
||||
<td>
|
||||
<img class="image" style="width: 103px; height: 40px" src="https://storage.yandexcloud.net/squizimages/logo-email-squiz.png" />
|
||||
</td>
|
||||
<td>
|
||||
<p style="text-align: end; color: #9a9aaf; font-size: 14px">Квиз для вашего бизнеса</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<h1
|
||||
style="
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 13px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
margin-bottom: 13px;
|
||||
margin-top: 50px;
|
||||
"
|
||||
>
|
||||
Поступила новая заявка с квиза “{{.QuizConfig.Theme}}”!
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<p style="color: #9a9aaf; font-size: 20px; margin-bottom: 50px">
|
||||
Время заявки: {{ .AnswerTime }}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<a
|
||||
style="
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
color: #f2f3f7;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #7e2aea;
|
||||
background: #7e2aea;
|
||||
padding: 10px 43px;
|
||||
max-height: 63px;
|
||||
margin-bottom: 50px;
|
||||
"
|
||||
>
|
||||
Посмотреть в личном кабинете
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<h1
|
||||
style="font-size: 25px; font-weight: 600; margin-bottom: 15px; width: 100%; margin: 0; margin-bottom: 13px"
|
||||
>
|
||||
Контакты
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="padding: 0">
|
||||
<table
|
||||
style="
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
text-align: left;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
margin-bottom: 30px;
|
||||
"
|
||||
>
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Имя
|
||||
</th>
|
||||
<td>
|
||||
<p
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
margin-bottom: 15px;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Name}}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{ if .AnswerContent.Email }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Email
|
||||
</th>
|
||||
<td style="word-break: break-word">
|
||||
<p
|
||||
style="
|
||||
text-align: start;
|
||||
color: #7e2aea;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
margin-bottom: 15px;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Email }}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ if .AnswerContent.Phone }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Телефон
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Phone }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
|
||||
{{ if .AnswerContent.Telegram }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Telegram
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Telegram }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ if .AnswerContent.Wechat }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Wechat
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Wechat }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ if .AnswerContent.Viber }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Viber
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Viber }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ if .AnswerContent.Vk }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Vk
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Vk }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ if .AnswerContent.Skype }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Skype
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Skype }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ if .AnswerContent.Whatsup }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Whatsup
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Whatsup }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ if .AnswerContent.Messenger }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Messenger
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Messenger }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ if .AnswerContent.Address }}
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
Адрес
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ .AnswerContent.Address }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ range $key, $value := .AnswerContent.Custom }}
|
||||
|
||||
<tr>
|
||||
<th
|
||||
style="
|
||||
text-align: start;
|
||||
color: #9a9aaf;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ $key }}
|
||||
</th>
|
||||
<td
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
"
|
||||
>
|
||||
{{ $value }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="height: 100%">
|
||||
<h1
|
||||
style="font-size: 25px; font-weight: 600; margin-bottom: 15px; width: 100%; margin: 0; margin-bottom: 13px"
|
||||
>
|
||||
Ответы
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{ range .AllAnswers }}
|
||||
{{ if index $.QuestionsMap .AnswerID }}
|
||||
<tr>
|
||||
<td colspan="2" style="padding: 0">
|
||||
<table
|
||||
style="
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
text-align: left;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
margin-bottom: 15px;
|
||||
"
|
||||
>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
<p
|
||||
style="
|
||||
text-align: start;
|
||||
color: #4d4d4d;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
margin-bottom: 10px;
|
||||
"
|
||||
>
|
||||
{{ index $.QuestionsMap .AnswerID }}
|
||||
</p>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="color: #9a9aaf; font-size: 20px; font-style: normal; font-weight: 400; line-height: normal">
|
||||
{{ renderImage .Content }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{end}}
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: center; padding: 0">
|
||||
<a style="color: #7e2aea; font-size: 20px; font-style: normal; font-weight: 400; line-height: normal">
|
||||
quiz.pena.digital
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user