diff --git a/build/notify/root/opt/yunion/share/template/content/IMAGE_ACTIVED b/build/notify/root/opt/yunion/share/template/content@cn/IMAGE_ACTIVED
similarity index 100%
rename from build/notify/root/opt/yunion/share/template/content/IMAGE_ACTIVED
rename to build/notify/root/opt/yunion/share/template/content@cn/IMAGE_ACTIVED
diff --git a/build/notify/root/opt/yunion/share/template/content/VERIFY.email b/build/notify/root/opt/yunion/share/template/content@cn/VERIFY.email
similarity index 96%
rename from build/notify/root/opt/yunion/share/template/content/VERIFY.email
rename to build/notify/root/opt/yunion/share/template/content@cn/VERIFY.email
index 042ae56740..69ca135634 100644
--- a/build/notify/root/opt/yunion/share/template/content/VERIFY.email
+++ b/build/notify/root/opt/yunion/share/template/content@cn/VERIFY.email
@@ -47,7 +47,7 @@
- | 您正在验证邮箱,请在验证码输入框中输入:{{.code}},已完成验证。 |
+ 您正在验证邮箱,请在验证码输入框中输入:{{.code}},以完成验证。 |
diff --git a/build/notify/root/opt/yunion/share/template/content@en/IMAGE_ACTIVED b/build/notify/root/opt/yunion/share/template/content@en/IMAGE_ACTIVED
new file mode 100644
index 0000000000..e6b7f366a5
--- /dev/null
+++ b/build/notify/root/opt/yunion/share/template/content@en/IMAGE_ACTIVED
@@ -0,0 +1 @@
+{{.os_type}} image {{.name}} upload completed
diff --git a/build/notify/root/opt/yunion/share/template/content@en/VERIFY.email b/build/notify/root/opt/yunion/share/template/content@en/VERIFY.email
new file mode 100644
index 0000000000..5bf1019e19
--- /dev/null
+++ b/build/notify/root/opt/yunion/share/template/content@en/VERIFY.email
@@ -0,0 +1,66 @@
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+ Dear {{.name}}:
+ |
+
+
+ | You are verifying your email, please enter the following code on the email verification page: |
+
+
+ | {{.code}} |
+
+
+ |
+
+
+ | If you are not operating by yourself, please log in to the platform in time and change your password to ensure the security of your account. |
+
+
+ | Copyrights © {{.copyright}}. All rights reserved. |
+
+
+
+
diff --git a/build/notify/root/opt/yunion/share/template/title/IMAGE_ACTIVED b/build/notify/root/opt/yunion/share/template/title@cn/IMAGE_ACTIVED
similarity index 100%
rename from build/notify/root/opt/yunion/share/template/title/IMAGE_ACTIVED
rename to build/notify/root/opt/yunion/share/template/title@cn/IMAGE_ACTIVED
diff --git a/build/notify/root/opt/yunion/share/template/title/VERIFY.email b/build/notify/root/opt/yunion/share/template/title@cn/VERIFY.email
similarity index 100%
rename from build/notify/root/opt/yunion/share/template/title/VERIFY.email
rename to build/notify/root/opt/yunion/share/template/title@cn/VERIFY.email
diff --git a/build/notify/root/opt/yunion/share/template/title@en/IMAGE_ACTIVED b/build/notify/root/opt/yunion/share/template/title@en/IMAGE_ACTIVED
new file mode 100644
index 0000000000..66ea80efb0
--- /dev/null
+++ b/build/notify/root/opt/yunion/share/template/title@en/IMAGE_ACTIVED
@@ -0,0 +1 @@
+Image {{.name}} upload completed
diff --git a/build/notify/root/opt/yunion/share/template/title@en/VERIFY.email b/build/notify/root/opt/yunion/share/template/title@en/VERIFY.email
new file mode 100644
index 0000000000..ab70a85680
--- /dev/null
+++ b/build/notify/root/opt/yunion/share/template/title@en/VERIFY.email
@@ -0,0 +1 @@
+{{.copyright}} Verify
diff --git a/pkg/apis/notify/const.go b/pkg/apis/notify/const.go
index 63238685b9..dd34a96246 100644
--- a/pkg/apis/notify/const.go
+++ b/pkg/apis/notify/const.go
@@ -62,6 +62,9 @@ const (
TEMPLATE_TYPE_CONTENT = "content"
TEMPLATE_TYPE_REMOTE = "remote"
+ TEMPLATE_LANG_EN = "en"
+ TEMPLATE_LANG_CN = "cn"
+
CTYPE_ROBOT_YES = "yes"
CTYPE_ROBOT_ONLY = "only"
)
diff --git a/pkg/notify/interface.go b/pkg/notify/interface.go
index 49c382e28b..971342edbd 100644
--- a/pkg/notify/interface.go
+++ b/pkg/notify/interface.go
@@ -28,19 +28,37 @@ type INotifyService interface {
StopAll()
UpdateServices(ctx context.Context, userCred mcclient.TokenCredential, isStart bool)
RestartService(ctx context.Context, config SConfig, serviceName string)
- Send(ctx context.Context, contactType, contact, topic, msg, priority string) error
+ Send(ctx context.Context, p SSendParams) error
ContactByMobile(ctx context.Context, mobile, serviceName string) (string, error)
- BatchSend(ctx context.Context, contacts []string, contactType, topic, message, priority string) ([]*apis.FailedRecord, error)
+ BatchSend(ctx context.Context, p SBatchSendParams) ([]*apis.FailedRecord, error)
ValidateConfig(ctx context.Context, cType string, configs map[string]string) (isValid bool, message string, err error)
}
+type SSendParams struct {
+ ContactType string
+ Contact string
+ Topic string
+ Message string
+ Priority string
+ Lang string
+}
+
+type SBatchSendParams struct {
+ ContactType string
+ Contacts []string
+ Topic string
+ Message string
+ Priority string
+ Lang string
+}
+
type IServiceConfigStore interface {
GetConfig(serviceName string) (SConfig, error)
SetConfig(serviceName string, config SConfig) error
}
type ITemplateStore interface {
- NotifyFilter(contactType, topic, msg string) (params apis.SendParams, err error)
+ NotifyFilter(contactType, topic, msg, lang string) (params apis.SendParams, err error)
}
type SConfig map[string]string
diff --git a/pkg/notify/models/notification.go b/pkg/notify/models/notification.go
index b5ab8b68b4..9dafa0e853 100644
--- a/pkg/notify/models/notification.go
+++ b/pkg/notify/models/notification.go
@@ -231,7 +231,7 @@ func (n *SNotification) ReceiveDetails() ([]api.ReceiveDetail, error) {
func (n *SNotification) getMoreDetails(ctx context.Context, query jsonutils.JSONObject, out api.NotificationDetails) (api.NotificationDetails, error) {
// get title adn content
- p, err := TemplateManager.NotifyFilter(n.ContactType, n.Topic, n.Message)
+ p, err := TemplateManager.NotifyFilter(n.ContactType, n.Topic, n.Message, getTemplateLangFromCtx(ctx))
if err != nil {
return out, err
}
diff --git a/pkg/notify/models/receiver.go b/pkg/notify/models/receiver.go
index fd1d829298..53312f6537 100644
--- a/pkg/notify/models/receiver.go
+++ b/pkg/notify/models/receiver.go
@@ -20,6 +20,8 @@ import (
"regexp"
"time"
+ "golang.org/x/text/language"
+
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
@@ -97,6 +99,7 @@ type SReceiver struct {
Email string `width:"64" nullable:"false" create:"optional" update:"user" get:"user" list:"user"`
Mobile string `width:"16" nullable:"false" create:"optional" update:"user" get:"user" list:"user"`
+ Lang string `width:"8" charset:"ascii" nullable:"false" list:"user" update:"user"`
// swagger:ignore
EnabledEmail tristate.TriState `nullable:"false" default:"false" update:"user"`
@@ -910,6 +913,51 @@ func (r *SReceiver) PerformDisable(ctx context.Context, userCred mcclient.TokenC
return nil, nil
}
+func (r *SReceiver) Sync(ctx context.Context) error {
+ session := auth.GetAdminSessionWithInternal(ctx, "", "")
+ params := jsonutils.NewDict()
+ params.Set("scope", jsonutils.NewString("system"))
+ params.Set("system", jsonutils.JSONTrue)
+ data, err := modules.UsersV3.GetById(session, r.Id, params)
+ if err != nil {
+ jerr := err.(*httputils.JSONClientError)
+ if jerr.Code == 404 {
+ err := r.Delete(ctx, session.GetToken())
+ if err != nil {
+ return errors.Wrapf(err, "unable to delete receiver %s", r.Id)
+ }
+ return errors.Wrapf(errors.ErrNotFound, "no such receiver %s", r.Id)
+ }
+ return err
+ }
+ uname, _ := data.GetString("name")
+ domainId, _ := data.GetString("domain_id")
+ lang, _ := data.GetString("lang")
+ _, err = db.Update(r, func() error {
+ r.Name = uname
+ r.DomainId = domainId
+ r.Lang = lang
+ return nil
+ })
+ return errors.Wrap(err, "unable to update")
+}
+
+func (r *SReceiver) GetTemplateLang(ctx context.Context) (string, error) {
+ if len(r.Lang) == 0 {
+ err := r.Sync(ctx)
+ if err != nil {
+ return "", err
+ }
+ }
+ log.Infof("lang: %s", r.Lang)
+ lang, err := language.Parse(r.Lang)
+ if err != nil {
+ return "", errors.Wrapf(err, "unable to prase language %q", r.Lang)
+ }
+ tLang := notifyclientI18nTable.LookupByLang(lang, tempalteLang)
+ return tLang, nil
+}
+
// Implemente interface EventHandler
func (rm *SReceiverManager) OnAdd(obj *jsonutils.JSONDict) {
// do nothing
diff --git a/pkg/notify/models/template.go b/pkg/notify/models/template.go
index 0d76581cc7..1f70b18cc2 100644
--- a/pkg/notify/models/template.go
+++ b/pkg/notify/models/template.go
@@ -33,6 +33,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/notify"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/httperrors"
+ "yunion.io/x/onecloud/pkg/i18n"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
@@ -72,6 +73,7 @@ type STemplate struct {
// title | content | remote
TemplateType string `width:"10" nullable:"false" create:"required" update:"user" list:"user"`
Content string `length:"text" nullable:"false" create:"required" get:"user" list:"user" update:"user"`
+ Lang string `width:"8" charset:"ascii" nullable:"false" list:"user" update:"user"`
Example string `nullable:"false" created:"required" get:"user" list:"user" update:"user"`
}
@@ -88,32 +90,35 @@ func (tm *STemplateManager) defaultTemplate() ([]STemplate, error) {
templates := make([]STemplate, 0, 4)
for _, templateType := range []string{"title", "content"} {
- contactType, topic := CONTACTTYPE_ALL, ""
- titleTemplatePath := fmt.Sprintf("%s/%s", templatePath, templateType)
- files, err := ioutil.ReadDir(titleTemplatePath)
- if err != nil {
- return templates, errors.Wrapf(err, "Read Dir '%s'", titleTemplatePath)
- }
- for _, file := range files {
- if file.IsDir() {
- continue
- }
- spliteName := strings.Split(file.Name(), ".")
- topic = spliteName[0]
- if len(spliteName) > 1 {
- contactType = spliteName[1]
- }
- fullPath := filepath.Join(titleTemplatePath, file.Name())
- content, err := ioutil.ReadFile(fullPath)
+ for _, lang := range []string{api.TEMPLATE_LANG_CN, api.TEMPLATE_LANG_EN} {
+ contactType, topic := CONTACTTYPE_ALL, ""
+ titleTemplatePath := fmt.Sprintf("%s/%s@%s", templatePath, templateType, lang)
+ files, err := ioutil.ReadDir(titleTemplatePath)
if err != nil {
- return templates, err
+ return templates, errors.Wrapf(err, "Read Dir '%s'", titleTemplatePath)
+ }
+ for _, file := range files {
+ if file.IsDir() {
+ continue
+ }
+ spliteName := strings.Split(file.Name(), ".")
+ topic = spliteName[0]
+ if len(spliteName) > 1 {
+ contactType = spliteName[1]
+ }
+ fullPath := filepath.Join(titleTemplatePath, file.Name())
+ content, err := ioutil.ReadFile(fullPath)
+ if err != nil {
+ return templates, err
+ }
+ templates = append(templates, STemplate{
+ ContactType: contactType,
+ Topic: topic,
+ Lang: lang,
+ TemplateType: templateType,
+ Content: string(content),
+ })
}
- templates = append(templates, STemplate{
- ContactType: contactType,
- Topic: topic,
- TemplateType: templateType,
- Content: string(content),
- })
}
}
return templates, nil
@@ -144,15 +149,43 @@ var (
ForceInitType = []string{
api.EMAIL,
}
+ notifyclientI18nTable = i18n.Table{}
+ defaultLang = api.TEMPLATE_LANG_CN
+ tempalteLang = "lang"
)
+func init() {
+ notifyclientI18nTable.Set(tempalteLang, i18n.NewTableEntry().EN(api.TEMPLATE_LANG_EN).CN(api.TEMPLATE_LANG_CN))
+}
+
+func getTemplateLangFromCtx(ctx context.Context) string {
+ return notifyclientI18nTable.Lookup(ctx, tempalteLang)
+}
+
func (tm *STemplateManager) InitializeData() error {
+ // init lang
+ q := tm.Query().IsEmpty("lang")
+ var noLangTemplates []STemplate
+ err := db.FetchModelObjects(tm, q, &noLangTemplates)
+ if err != nil {
+ return errors.Wrap(err, "unable to fetch templates")
+ }
+ for i := range noLangTemplates {
+ t := &noLangTemplates[i]
+ _, err := db.Update(t, func() error {
+ t.Lang = defaultLang
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+ }
templates, err := tm.defaultTemplate()
if err != nil {
return err
}
for _, template := range templates {
- q := tm.Query().Equals("contact_type", template.ContactType).Equals("topic", template.Topic).Equals("template_type", template.TemplateType)
+ q := tm.Query().Equals("contact_type", template.ContactType).Equals("topic", template.Topic).Equals("template_type", template.TemplateType).Equals("lang", template.Lang)
count, _ := q.CountWithError()
if count > 0 && !utils.IsInStringArray(template.ContactType, ForceInitType) {
continue
@@ -195,10 +228,15 @@ func (tm *STemplateManager) InitializeData() error {
// NotifyFilter will return the title and content generated by corresponding template.
// Local cache about common template will be considered in case of performance issues.
-func (tm *STemplateManager) NotifyFilter(contactType, topic, msg string) (params apis.SendParams, err error) {
+func (tm *STemplateManager) NotifyFilter(contactType, topic, msg, lang string) (params apis.SendParams, err error) {
params.Topic = topic
+ if len(lang) == 0 {
+ params.Title = topic
+ params.Message = msg
+ return
+ }
templates := make([]STemplate, 0, 3)
- q := tm.Query().Equals("topic", strings.ToUpper(topic)).In("contact_type", []string{CONTACTTYPE_ALL, contactType})
+ q := tm.Query().Equals("topic", strings.ToUpper(topic)).Equals("lang", lang).In("contact_type", []string{CONTACTTYPE_ALL, contactType})
err = db.FetchModelObjects(tm, q, &templates)
if errors.Cause(err) == sql.ErrNoRows || len(templates) == 0 {
// no such template, return as is
diff --git a/pkg/notify/rpc/send.go b/pkg/notify/rpc/send.go
index 761ffd23cb..4b0710f5b8 100644
--- a/pkg/notify/rpc/send.go
+++ b/pkg/notify/rpc/send.go
@@ -32,6 +32,7 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/mcclient"
+ "yunion.io/x/onecloud/pkg/notify"
notifyv2 "yunion.io/x/onecloud/pkg/notify"
"yunion.io/x/onecloud/pkg/notify/models"
"yunion.io/x/onecloud/pkg/notify/rpc/apis"
@@ -107,22 +108,22 @@ func (self *SRpcService) StopAll() {
}
// Send call the corresponding rpc server to send messager.
-func (self *SRpcService) Send(ctx context.Context, contactType, contact, topic, msg, priority string) error {
+func (self *SRpcService) Send(ctx context.Context, p notify.SSendParams) error {
- args, err := self.templateStore.NotifyFilter(contactType, topic, msg)
+ args, err := self.templateStore.NotifyFilter(p.ContactType, p.Topic, p.Message, p.Lang)
if err != nil {
return errors.Wrap(err, "templateStore.NotifyFilter")
}
- args.Contact = contact
- args.Priority = priority
+ args.Contact = p.Contact
+ args.Priority = p.Priority
f := func(service *apis.SendNotificationClient) (interface{}, error) {
log.Debugf("send one")
return service.Send(ctx, &args)
}
- _, err = self.execute(ctx, f, contactType)
+ _, err = self.execute(ctx, f, p.ContactType)
if err != nil {
s, ok := status.FromError(err)
if !ok {
@@ -133,14 +134,14 @@ func (self *SRpcService) Send(ctx context.Context, contactType, contact, topic,
return nil
}
-func (self *SRpcService) BatchSend(ctx context.Context, contacts []string, contactType, topic, message, priority string) ([]*apis.FailedRecord, error) {
- args, err := self.templateStore.NotifyFilter(contactType, topic, message)
+func (self *SRpcService) BatchSend(ctx context.Context, p notify.SBatchSendParams) ([]*apis.FailedRecord, error) {
+ args, err := self.templateStore.NotifyFilter(p.ContactType, p.Topic, p.Message, p.Lang)
if err != nil {
return nil, errors.Wrap(err, "templateStore.NotifyFilter")
}
batchSendParams := apis.BatchSendParams{
- Contacts: contacts,
+ Contacts: p.Contacts,
Title: args.Title,
Message: args.Message,
Priority: args.Priority,
@@ -151,7 +152,7 @@ func (self *SRpcService) BatchSend(ctx context.Context, contacts []string, conta
return service.BatchSend(ctx, &batchSendParams)
}
- ret, err := self.execute(ctx, f, contactType)
+ ret, err := self.execute(ctx, f, p.ContactType)
if err != nil {
s, ok := status.FromError(err)
if !ok {
diff --git a/pkg/notify/tasks/notifications_send_task.go b/pkg/notify/tasks/notifications_send_task.go
index 80ee236e14..8b037c6b73 100644
--- a/pkg/notify/tasks/notifications_send_task.go
+++ b/pkg/notify/tasks/notifications_send_task.go
@@ -12,7 +12,9 @@ import (
apis "yunion.io/x/onecloud/pkg/apis/notify"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
+ "yunion.io/x/onecloud/pkg/notify"
"yunion.io/x/onecloud/pkg/notify/models"
+ rpcapi "yunion.io/x/onecloud/pkg/notify/rpc/apis"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -71,6 +73,8 @@ func (self *NotificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
// build contactMap
contactMap := make(map[string]*models.SReceiverNotification)
+ contactMapEn := make(map[string]*models.SReceiverNotification)
+ contactmapCn := make(map[string]*models.SReceiverNotification)
for i := range rnsWithReceiver {
if len(rnsWithReceiver[i].ReceiverID) == 0 {
contactMap[rnsWithReceiver[i].Contact] = rnsWithReceiver[i]
@@ -114,32 +118,69 @@ func (self *NotificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
sendFail(rnsWithReceiver[i], reason)
continue
}
- contactMap[contact] = rnsWithReceiver[i]
+ lang, err := receiver.GetTemplateLang(ctx)
+ if err != nil {
+ reason := fmt.Sprintf("fail to GetTemplateLang: %s", err.Error())
+ sendFail(rnsWithReceiver[i], reason)
+ continue
+ }
+ switch lang {
+ case "":
+ contactMap[contact] = rnsWithReceiver[i]
+ case apis.TEMPLATE_LANG_EN:
+ contactMapEn[contact] = rnsWithReceiver[i]
+ case apis.TEMPLATE_LANG_CN:
+ contactmapCn[contact] = rnsWithReceiver[i]
+ }
}
for i := range rnsWithoutReceiver {
contactMap[rnsWithoutReceiver[i].Contact] = rnsWithoutReceiver[i]
}
- // set status before send
- now := time.Now()
- contacts := make([]string, 0, len(contactMap))
- for c, rn := range contactMap {
- rn.BeforeSend(ctx, now)
- contacts = append(contacts, c)
- }
+ var (
+ ret []*rpcapi.FailedRecord
+ contactLen int
+ )
- // send
- ret, err := models.NotifyService.BatchSend(ctx, contacts, notification.ContactType, notification.Topic, notification.Message, notification.Priority)
- if err != nil {
- for _, rn := range contactMap {
- rn.AfterSend(ctx, false, err.Error())
+ for lang, contactMap := range map[string]map[string]*models.SReceiverNotification{
+ "": contactMap,
+ apis.TEMPLATE_LANG_CN: contactmapCn,
+ apis.TEMPLATE_LANG_EN: contactMapEn,
+ } {
+ if len(contactMap) == 0 {
+ return
+ }
+ // set status before send
+ now := time.Now()
+ contacts := make([]string, 0, len(contactMap))
+ for c, rn := range contactMap {
+ rn.BeforeSend(ctx, now)
+ contacts = append(contacts, c)
}
- failedRecord = append(failedRecord, fmt.Sprintf("others: %s", err.Error()))
- self.taskFailed(ctx, notification, strings.Join(failedRecord, "; "), true)
- return
- }
+ contactLen += len(contacts)
+
+ p := notify.SBatchSendParams{
+ Contacts: contacts,
+ ContactType: notification.ContactType,
+ Topic: notification.Topic,
+ Message: notification.Message,
+ Priority: notification.Priority,
+ Lang: lang,
+ }
+ // send
+ fds, err := models.NotifyService.BatchSend(ctx, p)
+ if err != nil {
+ for _, rn := range contactMap {
+ rn.AfterSend(ctx, false, err.Error())
+ }
+ failedRecord = append(failedRecord, fmt.Sprintf("others: %s", err.Error()))
+ self.taskFailed(ctx, notification, strings.Join(failedRecord, "; "), true)
+ return
+ }
+ ret = append(ret, fds...)
+ }
// check result
for _, fd := range ret {
rn := contactMap[fd.Contact]
@@ -151,7 +192,7 @@ func (self *NotificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
for _, rn := range contactMap {
rn.AfterSend(ctx, true, "")
}
- if len(failedRecord) > 0 && len(failedRecord) == len(contacts) {
+ if len(failedRecord) > 0 && len(failedRecord) == contactLen {
self.taskFailed(ctx, notification, strings.Join(failedRecord, "; "), true)
return
}
diff --git a/pkg/notify/tasks/verification_send_task.go b/pkg/notify/tasks/verification_send_task.go
index 5b7e52ffce..b66910ff34 100644
--- a/pkg/notify/tasks/verification_send_task.go
+++ b/pkg/notify/tasks/verification_send_task.go
@@ -10,6 +10,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/notify"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
+ "yunion.io/x/onecloud/pkg/notify"
"yunion.io/x/onecloud/pkg/notify/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -66,7 +67,19 @@ func (self *VerificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
default:
// no way
}
- err = models.NotifyService.Send(ctx, contactType, contact, "verify", message, "")
+ tLang, err := receiver.GetTemplateLang(ctx)
+ if err != nil {
+ self.taskFailed(ctx, receiver, fmt.Sprintf("unable to GetTemplateLang for receiver %q: %v", receiver.Id, err))
+ }
+ sendP := notify.SSendParams{
+ ContactType: contactType,
+ Contact: contact,
+ Message: message,
+ Topic: "verify",
+ Priority: "",
+ Lang: tLang,
+ }
+ err = models.NotifyService.Send(ctx, sendP)
if err != nil {
self.taskFailed(ctx, receiver, err.Error())
return