worker/answerwc/to_client.go
2025-02-27 16:04:47 +03:00

376 lines
9.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package answerwc
import (
"context"
_ "embed"
"encoding/json"
"fmt"
"github.com/themakers/hlog"
"gitea.pena/SQuiz/common/dal"
"gitea.pena/SQuiz/common/model"
"gitea.pena/SQuiz/worker/clients/customer"
"gitea.pena/SQuiz/worker/clients/mailclient"
"gitea.pena/SQuiz/worker/wctools"
"time"
"github.com/go-redis/redis/v8"
)
type DepsSendToClient struct {
Redis *redis.Client
Dal *dal.DAL
MailClient *mailclient.Client
CustomerService customer.CustomerServiceClient
}
type SendToClient struct {
deps DepsSendToClient
logger hlog.Logger
errChan chan<- error
}
type PendingTasks struct {
Count int64
QuizConfig model.QuizConfig
}
//go:embed mail/to_client.tmpl
var toClientTemplate string
//go:embed mail/reminder.tmpl
var reminderTemplate string
func NewSendToClient(deps DepsSendToClient, logger hlog.Logger, errChan chan<- error) *SendToClient {
return &SendToClient{
deps: deps,
logger: logger,
errChan: errChan,
}
}
func (w *SendToClient) Start(ctx context.Context) {
answerTicker := time.NewTicker(30 * time.Second)
defer answerTicker.Stop()
for {
select {
case <-answerTicker.C:
w.processPendingAnswer(ctx)
case <-ctx.Done():
w.logger.Module("To client worker terminated")
return
}
}
}
func (w *SendToClient) processPendingAnswer(ctx context.Context) {
pendingAnswers, err := w.deps.Redis.Keys(ctx, "answer:*").Result()
if err != nil {
fmt.Println("Error getting keys from redis")
w.errChan <- err
return
}
fmt.Println("ANS")
for _, key := range pendingAnswers {
func() {
fmt.Println("ANS1", key)
answerJSON, err := w.deps.Redis.GetDel(ctx, key).Result()
if err == redis.Nil {
return
} else if err != nil {
w.reportError(err, "Error getting and deleting data from redis")
return
}
defer func() {
if r := recover(); r != nil {
w.reportError(nil, fmt.Sprintf("recovering from panic or error setting redis value %v", r))
fmt.Println("ANS1ERRR", r)
_ = w.deps.Redis.Set(ctx, key, answerJSON, 0).Err()
}
}()
var answer model.Answer
err = json.Unmarshal([]byte(answerJSON), &answer)
fmt.Println("ANS2", err)
if err != nil {
w.reportError(err, "Error unmarshal answer")
return
}
answerContent, err := wctools.ProcessAnswer(answer.Content)
fmt.Println("ANS3", err)
if err != nil {
w.reportError(err, "Error unmarshal answer content")
return
}
allAnswers, err := w.deps.Dal.WorkerAnsRepo.GetAllAnswersByQuizID(ctx, answer.Session)
fmt.Println("ANS4", err)
if err != nil {
w.reportError(err, "Error getting all answers by quizID")
return
}
questionsMap, sortedallAnswers, err := w.deps.Dal.QuestionRepo.GetMapQuestions(ctx, allAnswers)
fmt.Println("ANS5", err)
if err != nil {
w.reportError(err, "Error getting questionsMap")
return
}
if answer.QuizId == 0 {
return
}
quizConfig, accountId, err := w.deps.Dal.QuizRepo.GetQuizConfig(ctx, answer.QuizId)
fmt.Println("ANS6", err)
if err != nil {
w.reportError(err, "Error getting quiz config")
return
}
quiz, err := w.deps.Dal.QuizRepo.GetQuizById(ctx, accountId, answer.QuizId)
fmt.Println("ANS60", err, accountId, answer.QuizId)
if err != nil {
w.reportError(err, "Error getting quiz")
return
}
quizConfig.Mailing.Reply = quiz.Name
if quizConfig.Mailing.Theme == "" {
quizConfig.Mailing.Theme = quiz.Name
}
account, privileges, err := w.deps.Dal.AccountRepo.GetAccAndPrivilegeByEmail(ctx, accountId)
fmt.Println("ANS7", err)
if err != nil {
w.reportError(err, "Error getting account and privileges by email")
return
}
result, err := w.processAnswerWithPrivileges(ctx, quiz.Name, quizConfig, questionsMap, privileges, account, sortedallAnswers, answerContent, answer.CreatedAt, answer.QuizId)
fmt.Println("ANS8", err, result, privileges)
if err != nil {
w.reportError(err, "Error process answer with privileges")
return
}
if !result {
err = w.deps.Redis.Set(ctx, fmt.Sprintf("%s:%s", account.ID, key), answerJSON, 0).Err()
if err != nil {
w.reportError(err, "Error setting redis value")
return
}
}
}()
}
}
func (w *SendToClient) processAnswerWithPrivileges(ctx context.Context, quizName string, quizConfig model.QuizConfig,
questionsMap map[uint64]string, privileges []model.ShortPrivilege, account model.Account, allAnswers []model.ResultAnswer,
answerContent model.ResultContent, answerTime time.Time, quizID uint64) (bool, error) {
err := w.notificationCustomer(account, privileges)
fmt.Println("ANS81", err)
if err != nil {
return false, err
}
if wctools.HasUnlimitedPrivilege(privileges) {
err := w.ProcessMessageToClient(quizConfig, questionsMap, account, allAnswers, answerContent, answerTime, quizID)
if err != nil {
return false, err
}
return true, nil
}
privilege := wctools.HasQuizCntPrivilege(privileges)
if privilege != nil {
err := w.ProcessMessageToClient(quizConfig, questionsMap, account, allAnswers, answerContent, answerTime, quizID)
fmt.Println("PMC", err)
if err != nil {
return true, err
}
privilege.Amount--
err = w.deps.Dal.AccountRepo.UpdatePrivilegeAmount(ctx, privilege.ID, privilege.Amount)
if err != nil {
return false, err
}
return true, nil
} else {
w.checkAndSendTaskReminders(ctx, sendTaskRemindersDeps{
email: account.Email,
theme: quizName,
config: model.QuizConfig{
Mailing: model.ResultInfo{
When: "email",
Theme: fmt.Sprintf("не удалось отправить заявку по опросу\"%s\"", quizName),
Reply: "noreply@pena.digital",
ReplName: "Reminder",
},
},
})
return false, nil
}
}
func (w *SendToClient) recordPendingTasks(ctx context.Context, Email string, quizConfig model.QuizConfig) error {
key := fmt.Sprintf("pending_tasks:%s", Email)
var pendingTasks PendingTasks
val, err := w.deps.Redis.HGet(ctx, key, "data").Result()
if err == nil {
err := json.Unmarshal([]byte(val), &pendingTasks)
if err != nil {
return err
}
pendingTasks.Count++
} else {
pendingTasks = PendingTasks{
Count: 1,
QuizConfig: quizConfig,
}
}
pendingTasksJSON, err := json.Marshal(pendingTasks)
if err != nil {
return err
}
err = w.deps.Redis.HSet(ctx, key, "data", string(pendingTasksJSON)).Err()
if err != nil {
return err
}
return nil
}
type sendTaskRemindersDeps struct {
email, theme string
config model.QuizConfig
}
func (w *SendToClient) checkAndSendTaskReminders(ctx context.Context, deps sendTaskRemindersDeps) {
err := w.processReminderToClient(deps.email, deps.config)
fmt.Println("PMC1", err)
if err != nil {
w.reportError(err, "Error sending tasks reminder email")
}
}
func (w *SendToClient) notificationCustomer(account model.Account, privileges []model.ShortPrivilege) error {
for _, privilege := range privileges {
fmt.Println("NOTIFIC", privilege.PrivilegeID, privilege.Amount, !wctools.IsPrivilegeExpired(privilege))
if privilege.PrivilegeID == "quizUnlimTime" && !wctools.IsPrivilegeExpired(privilege) {
rawDetail, err := wctools.ToJSON(privilege)
historyData := &customer.History{
UserID: account.UserID,
Comment: fmt.Sprintf("Привилегия %s просрочена", privilege.PrivilegeID),
Key: "privilege_expired",
RawDetails: rawDetail,
}
_, err = w.deps.CustomerService.InsertHistory(context.Background(), historyData)
if err != nil {
return err
}
}
if privilege.PrivilegeID == "quizCnt" && privilege.Amount == 0 {
rawDetail, err := wctools.ToJSON(privilege)
if err != nil {
return err
}
historyData := &customer.History{
UserID: account.UserID,
Comment: fmt.Sprintf("У привилегии %s истек amount", privilege.PrivilegeID),
Key: "privilege_expired",
RawDetails: rawDetail,
}
_, err = w.deps.CustomerService.InsertHistory(context.Background(), historyData)
if err != nil {
return err
}
}
}
return nil
}
// сделал экспортируемым для теста
func (w *SendToClient) ProcessMessageToClient(quizConfig model.QuizConfig, questionsMap map[uint64]string, account model.Account, allAnswers []model.ResultAnswer, answerContent model.ResultContent, answerTime time.Time, quizID uint64) error {
theme := quizConfig.Mailing.Theme
quizConfig.Mailing.Theme = quizConfig.Mailing.Reply
data := mailclient.EmailTemplateData{
QuizConfig: quizConfig.Mailing,
AnswerContent: answerContent,
AllAnswers: allAnswers,
QuestionsMap: questionsMap,
QuizID: quizID,
}
dayOfWeek := wctools.DaysOfWeek[answerTime.Format("Monday")]
monthOfYear := wctools.MonthsOfYear[answerTime.Format("January")]
formattedTime := fmt.Sprintf("%s, %d %s %d г., %02d:%02d (UTC%s)",
dayOfWeek,
answerTime.Day(),
monthOfYear,
answerTime.Year(),
answerTime.Hour(),
answerTime.Minute(),
answerTime.Format("-07:00"),
)
data.AnswerTime = formattedTime
fmt.Println("SUBJECT", theme, account.Email)
err := w.deps.MailClient.SendMailWithAttachment(account.Email, theme, toClientTemplate, data, nil)
if err != nil {
return err
}
return nil
}
func (w *SendToClient) processReminderToClient(email string, quizConfig model.QuizConfig) error {
data := mailclient.EmailTemplateData{
QuizConfig: model.ResultInfo{
When: quizConfig.Mailing.When,
Theme: quizConfig.Mailing.Theme,
Reply: email,
ReplName: quizConfig.Mailing.ReplName,
},
AnswerContent: model.ResultContent{},
AllAnswers: []model.ResultAnswer{},
QuestionsMap: nil,
}
fmt.Println("PRTC", data, email, quizConfig)
err := w.deps.MailClient.SendMailWithAttachment(email, quizConfig.Mailing.Theme, reminderTemplate, data, nil)
if err != nil {
return err
}
return nil
}
func (w *SendToClient) reportError(err error, message string) {
if err != nil {
fmt.Println(message + ": " + err.Error())
w.errChan <- err
}
}