worker/clients/mailclient/utils.go
2024-10-10 22:18:39 +03:00

184 lines
4.4 KiB
Go

package mailclient
import (
"bytes"
"crypto/rand"
"encoding/json"
"fmt"
"golang.org/x/net/html"
"html/template"
"io"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"strings"
)
type LineWriter struct {
w io.Writer
length int
}
func NewLineWriter(w io.Writer, length int) *LineWriter {
return &LineWriter{
w: w,
length: length,
}
}
func (r *LineWriter) Write(p []byte) (n int, err error) {
for i := 0; i < len(p); i += r.length {
end := i + r.length
if end > len(p) {
end = len(p) - 1
}
var chunk []byte
chunk = append(chunk, p[i:end]...)
if len(p) >= end+r.length {
chunk = append(chunk, []byte("\r\n")...)
}
addN, err := r.w.Write(chunk)
if err != nil {
return n, err
}
n += addN
}
return n, nil
}
func (r *LineWriter) WriteString(s string) (n int, err error) {
p := []byte(s)
return r.Write(p)
}
func (r *LineWriter) WriteFormatString(format string, a ...any) (n int, err error) {
p := []byte(fmt.Sprintf(format, a...))
return r.Write(p)
}
func randomBoundary() string {
var buf [30]byte
_, err := io.ReadFull(rand.Reader, buf[:])
if err != nil {
panic(err)
}
return fmt.Sprintf("%x", buf[:])
}
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 EmailTemplateData) EmailTemplateData {
sanitized := EmailTemplateData{
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")
}
}
}
}