376 lines
10 KiB
Go
376 lines
10 KiB
Go
package answerwc
|
||
|
||
import (
|
||
"context"
|
||
_ "embed"
|
||
"encoding/json"
|
||
"fmt"
|
||
"github.com/themakers/hlog"
|
||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||
"penahub.gitlab.yandexcloud.net/backend/quiz/worker.git/clients/customer"
|
||
"penahub.gitlab.yandexcloud.net/backend/quiz/worker.git/clients/mailclient"
|
||
"penahub.gitlab.yandexcloud.net/backend/quiz/worker.git/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
|
||
}
|
||
}
|