worker/internal/senders/common.go
pasha1coil e46acea3f1
Some checks failed
Deploy / CreateImage (push) Successful in 2m55s
Deploy / ValidateConfig (push) Successful in 27s
Deploy / MigrateDatabase (push) Failing after 57s
Deploy / DeployService (push) Has been skipped
fix var imgs
2025-06-29 18:08:11 +03:00

203 lines
5.3 KiB
Go

package senders
import (
"bytes"
_ "embed"
"encoding/base64"
"encoding/json"
"fmt"
"gitea.pena/SQuiz/common/model"
"golang.org/x/net/html"
"html/template"
"strings"
)
type LeadSender interface {
SendLead(leadData LeadData) error
Name() string
}
type LeadData struct {
To interface{}
Subject string
Template string
TemplateData TemplateData
}
type TemplateData struct {
QuizConfig model.ResultInfo
AnswerContent model.ResultContent
AllAnswers []model.ResultAnswer
QuestionsMap map[uint64]string
AnswerTime string
QuizID int64
}
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{
"keyExists": func(m map[uint64]string, key uint64) bool {
_, ok := m[key]
return ok
},
"renderImage": RenderImage,
}
func RenderImage(content string) template.HTML {
contents := strings.Split(content, "`,`")
var builder strings.Builder
content = strings.ReplaceAll(content, "\n", "<br>")
for i, cnt := range contents {
if i == 0 {
cnt = strings.TrimPrefix(cnt, "`")
}
if i == len(contents)-1 {
cnt = strings.TrimSuffix(cnt, "`")
}
var res model.ImageContent
err := json.Unmarshal([]byte(cnt), &res)
if err != nil {
return SplitContent(content)
} else {
imgURL := res.Image
if strings.HasPrefix(imgURL, "http://") {
imgURL = strings.Replace(imgURL, "http://", "https://", 1)
}
builder.WriteString(
fmt.Sprintf(`<td style="color:#9a9aaf;font-size:20px;font-style:normal;font-weight:400;line-height:normal">
%s<br> <img class="image" style="width:100%%; max-width:250px; max-height:250px;" src="%s" alt="%s"/></td>`,
res.Description, imgURL, res.Description))
}
}
return template.HTML(builder.String())
}
func SplitContent(content string) template.HTML {
parts := strings.Split(content, "|")
if len(parts) == 2 {
url := strings.TrimSpace(parts[0])
filenameBase64 := strings.TrimSpace(parts[1])
filenameBytes, err := base64.StdEncoding.DecodeString(filenameBase64)
if err != nil {
return template.HTML(fmt.Sprintf(`<a href="%s" download>%s</a>`, url, "invalid filename"))
}
filename := string(filenameBytes)
return template.HTML(fmt.Sprintf(`<a href="%s" download>%s</a>`, url, filename))
}
return template.HTML(strings.ReplaceAll(content, "\n", "<br>"))
}
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),
QuizID: data.QuizID,
}
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")
}
}
}
}