go-common/app/job/main/mcn/service/email.go

291 lines
7.4 KiB
Go
Raw Normal View History

2019-04-22 10:49:16 +00:00
package service
import (
"bytes"
"context"
"fmt"
"html/template"
"time"
"go-common/app/job/main/mcn/conf"
"go-common/app/job/main/mcn/model"
accgrpc "go-common/app/service/main/account/api"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
// var .
var (
// ErrNoAdminName no admin name
ErrNoAdminName = errors.New("no admin name")
tmplSignDueTitle *template.Template
tmplSignDueContent *template.Template
tmplPayDueTitle *template.Template
tmplPayDueContent *template.Template
)
// use for template function call
var funcHelper = template.FuncMap{
"Now": time.Now,
}
func (s *Service) initEmailTemplate() (err error) {
if conf.Conf.MailTemplateConf.SignTmplTitle == "" ||
conf.Conf.MailTemplateConf.SignTmplContent == "" ||
conf.Conf.MailTemplateConf.PayTmplTitle == "" ||
conf.Conf.MailTemplateConf.PayTmplContent == "" {
err = fmt.Errorf(`mail template conf is invalid, check mail-template.toml file, make sure all the following has value:
TaskTmplContent
TaskTmplTitle
PayTmplContent
PayTmplTitle`)
return
}
tmplSignDueTitle, err = template.New("signTitle").Funcs(funcHelper).Parse(conf.Conf.MailTemplateConf.SignTmplTitle)
if err != nil {
log.Error("parse template fail, err=%v", err)
return
}
tmplSignDueContent, err = template.New("signContent").Funcs(funcHelper).Parse(conf.Conf.MailTemplateConf.SignTmplContent)
if err != nil {
log.Error("parse template fail, err=%v", err)
return
}
tmplPayDueTitle, err = template.New("payTitle").Funcs(funcHelper).Parse(conf.Conf.MailTemplateConf.PayTmplTitle)
if err != nil {
log.Error("parse template fail, err=%v", err)
return
}
tmplPayDueContent, err = template.New("payContent").Funcs(funcHelper).Parse(conf.Conf.MailTemplateConf.PayTmplContent)
if err != nil {
log.Error("parse template fail, err=%v", err)
return
}
return
}
// CheckDateDueCron .
func (s *Service) CheckDateDueCron() {
log.Info("start run CheckDateDueJob, date=%s", time.Now().Format(model.TimeFormatSec))
s.checkSignUpDue()
log.Info("finish run CheckDateDueJob, date=%s", time.Now().Format(model.TimeFormatSec))
}
type stateFunc func(context.Context, []int64) (int64, error)
type emailData struct {
IDs []int64
AdminName []string
Data interface{}
UpStateFunc stateFunc
Title, Content *template.Template
}
func (e *emailData) addEmailDatas(es *[]*emailData) {
*es = append(*es, e)
}
// buildEmail .
func buildEmail(ids []int64, data interface{}, title, content *template.Template, upStateFunc stateFunc, adminName ...string) *emailData {
return &emailData{
IDs: ids,
Data: data,
Title: title,
Content: content,
UpStateFunc: upStateFunc,
AdminName: adminName,
}
}
type dueData struct {
Signs []*model.MCNSignInfo
Pays []*model.SignPayInfo
Sids, Pids []int64
}
func (d *dueData) addSign(sign *model.MCNSignInfo) {
d.Signs = append(d.Signs, sign)
d.Sids = append(d.Sids, sign.SignID)
}
func (d *dueData) addPay(pay *model.SignPayInfo) {
d.Pays = append(d.Pays, pay)
d.Pids = append(d.Pids, pay.SignPayID)
}
func (d *dueData) addName(infoMap map[int64]*accgrpc.Info) {
for _, v := range d.Signs {
v.McnName = getName(infoMap, v.McnMid)
}
for _, v := range d.Pays {
v.McnName = getName(infoMap, v.McnMid)
}
}
// func getOrCreate(dataMap map[string]*dueData, key string) *dueData {
// var data, ok = dataMap[key]
// if !ok {
// data = &dueData{}
// dataMap[key] = data
// }
// return data
// }
func getName(infoMap map[int64]*accgrpc.Info, mid int64) string {
if info, ok := infoMap[mid]; ok {
return info.Name
}
return ""
}
func (s *Service) checkSignUpDue() {
var (
mids []int64
emailDatas []*emailData
data = &dueData{}
c = context.Background()
infoMap map[int64]*accgrpc.Info
)
// 30天内到期 sign
listDue, err := s.dao.McnSignDues(c)
if err != nil {
log.Error("s.dao.McnSignDues error(%+v)", err)
return
}
for _, v := range listDue {
mids = append(mids, v.McnMid)
data.addSign(v)
}
// 7天内到期的pay
listPayDue, err := s.dao.McnSignPayDues(c)
if err != nil {
log.Error("s.dao.McnSignPayDues error(%+v)", err)
return
}
for _, v := range listPayDue {
mids = append(mids, v.McnMid)
data.addPay(v)
}
mids = uniqNoEmpty(mids)
infosReply, err := s.accGRPC.Infos3(c, &accgrpc.MidsReq{Mids: mids})
if err != nil {
log.Error("s.accGRPC.Infos3(%s) error(%+v)", xstr.JoinInts(mids), err)
err = nil
} else {
infoMap = infosReply.Infos
}
emailDatas = make([]*emailData, 0)
data.addName(infoMap)
buildEmail(data.Sids, data.Signs, tmplSignDueTitle, tmplSignDueContent, s.dao.UpMcnSignEmailState, conf.Conf.MailConf.DueAuthorityGroups...).addEmailDatas(&emailDatas)
buildEmail(data.Pids, data.Pays, tmplPayDueTitle, tmplPayDueContent, s.dao.UpMcnSignPayEmailState, conf.Conf.MailConf.DueAuthorityGroups...).addEmailDatas(&emailDatas)
for _, e := range emailDatas {
s.doSendEmailFunc(c, e)
}
}
func (s *Service) doSendEmailFunc(c context.Context, e *emailData) {
s.worker.Do(c, func(c context.Context) {
if len(e.IDs) == 0 {
log.Warn("not need to update")
return
}
var err error
if err = s.sendMailWithTemplate(e.Data, e.Title, e.Content, e.AdminName...); err != nil {
log.Error("s.sendMailWithTemplate(%+v,%+v,%+v,%+v) error(%+v)", e.Data, e.Title, e.Content, e.AdminName, err)
return
}
if _, err = e.UpStateFunc(c, e.IDs); err != nil {
log.Error("upfunc(%+v,%s) error(%+v)", e.UpStateFunc, xstr.JoinInts(e.IDs), err)
return
}
log.Info("func(%s) update succ", xstr.JoinInts(e.IDs))
})
}
// data, data to generate email content
// contentTmpl, template to generate email content
// adminname, slice for all admin name
//
func (s *Service) sendMailWithTemplate(data interface{}, subjectTmpl, contentTmpl *template.Template, adminName ...string) (err error) {
if contentTmpl == nil {
err = fmt.Errorf("template for email is nil, data=%+v", data)
log.Error("%s", err)
return
}
var contentBuf = bytes.NewBuffer(nil)
err = contentTmpl.Execute(contentBuf, data)
if err != nil {
log.Error("template fail to execute, err=%v", err)
return
}
var subjectBuf = bytes.NewBuffer(nil)
err = subjectTmpl.Execute(subjectBuf, data)
if err != nil {
log.Error("template fail to execute, err=%v", err)
return
}
var addrs []string
for _, v := range adminName {
if v == "" {
log.Warn("admin name is empty")
continue
}
addrs = append(addrs, v)
}
if len(addrs) == 0 {
log.Error("admin name is empty, cannot send email, data=%+v", data)
err = ErrNoAdminName
return
}
if err = s.dao.SendMail(contentBuf.String(), subjectBuf.String(), addrs); err != nil {
log.Error("s.dao.SendMail(%s,%s,%+v) error(%+v)", contentBuf.String(), subjectBuf.String(), addrs, err)
return
}
log.Info("email send succ, sub=%s, admin=%s", subjectBuf.String(), adminName)
return
}
func chain(ids ...[]int64) []int64 {
res := make([]int64, 0, len(ids))
for _, l := range ids {
res = append(res, l...)
}
return res
}
// func uniq(ids ...[]int64) []int64 {
// hm := make(map[int64]struct{})
// for _, i := range chain(ids...) {
// hm[i] = struct{}{}
// }
// res := make([]int64, 0, len(ids))
// for i := range hm {
// res = append(res, i)
// }
// return res
// }
func uniqNoEmpty(ids ...[]int64) []int64 {
hm := make(map[int64]struct{})
for _, i := range chain(ids...) {
hm[i] = struct{}{}
}
res := make([]int64, 0, len(ids))
for i := range hm {
if i > 0 {
res = append(res, i)
}
}
return res
}