mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
feat(notify): advanced notify config and robot
1. Notify config has now become a domain resource, so that each domain can have its own configuration about notify. The domains has no configuration will use system config. 2. Robot separates from config and becomes a shared project resource. Sending information to robot can choose which robot to send to.
This commit is contained in:
@@ -15,121 +15,16 @@
|
||||
package notifyv2
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
options "yunion.io/x/onecloud/pkg/mcclient/options/notify"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type ConfigListOptions struct {
|
||||
options.BaseListOptions
|
||||
}
|
||||
R(&ConfigListOptions{}, "notify-config-list", "List notify config", func(s *mcclient.ClientSession, args *ConfigListOptions) error {
|
||||
params, err := options.ListStructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.NotifyConfig.List(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(result, modules.NotifyConfig.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
type ConfigCreateOptions struct {
|
||||
TYPE string `help:"Type contact config"`
|
||||
Configs []string `help:"Config content, format: 'key:value'"`
|
||||
}
|
||||
R(&ConfigCreateOptions{}, "notify-config-create", "Create notify config", func(s *mcclient.ClientSession, args *ConfigCreateOptions) error {
|
||||
configs := jsonutils.NewDict()
|
||||
for _, kv := range args.Configs {
|
||||
index := strings.IndexByte(kv, ':')
|
||||
configs.Set(kv[:index], jsonutils.NewString(kv[index+1:]))
|
||||
}
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("type", jsonutils.NewString(args.TYPE))
|
||||
params.Set("content", configs)
|
||||
ret, err := modules.NotifyConfig.Create(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ret)
|
||||
return nil
|
||||
})
|
||||
R(&ConfigCreateOptions{}, "notify-config-update", "Update notify config", func(s *mcclient.ClientSession, args *ConfigCreateOptions) error {
|
||||
configs := jsonutils.NewDict()
|
||||
for _, kv := range args.Configs {
|
||||
index := strings.IndexByte(kv, ':')
|
||||
configs.Set(kv[:index], jsonutils.NewString(kv[index+1:]))
|
||||
}
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("content", configs)
|
||||
|
||||
id, err := configIdFromType(s, args.TYPE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ret, err := modules.NotifyConfig.Update(s, id, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ret)
|
||||
return nil
|
||||
})
|
||||
type ConfigOptions struct {
|
||||
TYPE string `help:"Type contact config"`
|
||||
}
|
||||
R(&ConfigOptions{}, "notify-config-delete", "Delete notify config", func(s *mcclient.ClientSession, args *ConfigOptions) error {
|
||||
id, err := configIdFromType(s, args.TYPE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ret, err := modules.NotifyConfig.Delete(s, id, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ret)
|
||||
return nil
|
||||
})
|
||||
R(&ConfigOptions{}, "notify-config-show", "Show notify config", func(s *mcclient.ClientSession, args *ConfigOptions) error {
|
||||
listParams := jsonutils.NewDict()
|
||||
listParams.Set("type", jsonutils.NewString(args.TYPE))
|
||||
list, err := modules.NotifyConfig.List(s, listParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := list.Data[0]
|
||||
printObject(data)
|
||||
return nil
|
||||
})
|
||||
type ConfigGetTypesOptions struct {
|
||||
Robot string `json:"robot" choices:"yes|no|only"`
|
||||
}
|
||||
R(&ConfigGetTypesOptions{}, "notify-config-get-types", "Get all Config types", func(s *mcclient.ClientSession, args *ConfigGetTypesOptions) error {
|
||||
param := jsonutils.Marshal(args)
|
||||
result, err := modules.NotifyReceiver.PerformClassAction(s, "get-types", param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func configIdFromType(s *mcclient.ClientSession, t string) (string, error) {
|
||||
listParams := jsonutils.NewDict()
|
||||
listParams.Set("type", jsonutils.NewString(t))
|
||||
list, err := modules.NotifyConfig.List(s, listParams)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
id, err := list.Data[0].GetString("id")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return id, nil
|
||||
cmd := shell.NewResourceCmd(&modules.NotifyConfig).WithKeyword("notify-config")
|
||||
cmd.List(new(options.ConfigListOptions))
|
||||
cmd.Create(new(options.ConfigCreateOptions))
|
||||
cmd.Update(new(options.ConfigUpdateOptions))
|
||||
cmd.Show(new(options.ConfigOptions))
|
||||
cmd.Delete(new(options.ConfigOptions))
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
func init() {
|
||||
type NotificationCreateInput struct {
|
||||
Receivers []string `help:"ID or Name of Receiver"`
|
||||
Robots []string `help:"ID or Name of Robot"`
|
||||
ContactType string `help:"Contact type of receiver"`
|
||||
TOPIC string `help:"Topic"`
|
||||
Priority string `help:"Priority"`
|
||||
@@ -41,6 +42,7 @@ func init() {
|
||||
if args.Oldsdk {
|
||||
msg := notify.SNotifyMessage{
|
||||
Uid: args.Receivers,
|
||||
Robots: args.Robots,
|
||||
ContactType: notify.TNotifyChannel(args.ContactType),
|
||||
Topic: args.TOPIC,
|
||||
Priority: notify.TNotifyPriority(args.Priority),
|
||||
@@ -55,6 +57,7 @@ func init() {
|
||||
} else {
|
||||
input := api.NotificationCreateInput{
|
||||
Receivers: args.Receivers,
|
||||
Robots: args.Robots,
|
||||
ContactType: args.ContactType,
|
||||
Topic: args.TOPIC,
|
||||
Priority: args.Priority,
|
||||
|
||||
@@ -32,4 +32,5 @@ func init() {
|
||||
cmd.Perform("trigger-verify", new(options.ReceiverTriggerVerifyOptions))
|
||||
cmd.Perform("verify", new(options.ReceiverVerifyOptions))
|
||||
cmd.PerformClass("intellij-get", new(options.ReceiverIntellijGetOptions))
|
||||
cmd.PerformClass("get-types", new(options.ReceiverGetTypeOptions))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package notifyv2
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
options "yunion.io/x/onecloud/pkg/mcclient/options/notify"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd := shell.NewResourceCmd(&modules.NotifyRobot).WithKeyword("notify-robot")
|
||||
cmd.List(new(options.RobotListOptions))
|
||||
cmd.Create(new(options.RobotCreateOptions))
|
||||
cmd.Update(new(options.RobotUpdateOptions))
|
||||
cmd.Show(new(options.RobotOptions))
|
||||
cmd.Delete(new(options.RobotOptions))
|
||||
cmd.Perform("enable", new(options.RobotOptions))
|
||||
cmd.Perform("disable", new(options.RobotOptions))
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
type ConfigCreateInput struct {
|
||||
apis.StandaloneResourceCreateInput
|
||||
apis.DomainizedResourceInput
|
||||
|
||||
// description: config type
|
||||
// required: true
|
||||
@@ -32,6 +33,12 @@ type ConfigCreateInput struct {
|
||||
// required: true
|
||||
// example: {"app_id": "123456", "app_secret": "feishu_nihao"}
|
||||
Content jsonutils.JSONObject `json:"content"`
|
||||
|
||||
// description: attribution
|
||||
// required: true
|
||||
// enum: system,domain
|
||||
// example: system
|
||||
Attribution string `json:"attribution"`
|
||||
}
|
||||
|
||||
type ConfigUpdateInput struct {
|
||||
@@ -43,13 +50,16 @@ type ConfigUpdateInput struct {
|
||||
|
||||
type ConfigDetails struct {
|
||||
apis.StandaloneResourceDetails
|
||||
apis.DomainizedResourceInfo
|
||||
|
||||
SConfig
|
||||
}
|
||||
|
||||
type ConfigListInput struct {
|
||||
apis.StandaloneResourceListInput
|
||||
Type string `json:"type"`
|
||||
apis.DomainizedResourceListInput
|
||||
Type string `json:"type"`
|
||||
Attribution string `json:"attribution"`
|
||||
}
|
||||
|
||||
type ConfigValidateInput struct {
|
||||
@@ -70,10 +80,9 @@ type ConfigValidateOutput struct {
|
||||
}
|
||||
|
||||
type ConfigManagerGetTypesInput struct {
|
||||
// description: Filter about robot
|
||||
// enum: no,yes,only
|
||||
// example: yes
|
||||
Robot string `json:"robot"`
|
||||
// description: domain where in config
|
||||
// example: default
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type ConfigManagerGetTypesOutput struct {
|
||||
|
||||
@@ -70,6 +70,20 @@ const (
|
||||
CTYPE_ROBOT_YES = "yes"
|
||||
CTYPE_ROBOT_ONLY = "only"
|
||||
|
||||
CONFIG_ATTRIBUTION_SYSTEM = "system"
|
||||
CONFIG_ATTRIBUTION_DOMAIN = "domain"
|
||||
|
||||
ROBOT_TYPE_FEISHU = "feishu"
|
||||
ROBOT_TYPE_DINGTALK = "dingtalk"
|
||||
ROBOT_TYPE_WORKWX = "workwx"
|
||||
ROBOT_TYPE_WEBHOOK = "webhook"
|
||||
|
||||
ROBOT_STATUS_READY = "ready"
|
||||
|
||||
RECEIVER_TYPE_USER = "user"
|
||||
RECEIVER_TYPE_CONTACT = "contact"
|
||||
RECEIVER_TYPE_ROBOT = "robot"
|
||||
|
||||
SUBSCRIPTION_RESOURCE_CREATE_DELETE = "resource create delete"
|
||||
SUBSCRIPTION_RESOURCE_CHANGECONFIG = "resource change config"
|
||||
SUBSCRIPTION_RESOURCE_UPDATE = "resource udpate"
|
||||
|
||||
@@ -32,6 +32,9 @@ type NotificationCreateInput struct {
|
||||
// description: direct contact, admin privileges required
|
||||
// required: false
|
||||
Contacts []string `json:"contacts"`
|
||||
// description: robots
|
||||
// example: feishu robot
|
||||
Robots []string `json:"robots"`
|
||||
// description: contact type
|
||||
// required: ture
|
||||
// example: email
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package notify
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/apis"
|
||||
|
||||
type RobotCreateInput struct {
|
||||
apis.SharableVirtualResourceCreateInput
|
||||
// description: robot type
|
||||
// enum: feishu,dingtalk,workwx,webhook
|
||||
// example: webhook
|
||||
Type string `json:"type"`
|
||||
// description: address
|
||||
// example: http://helloworld.io/test/webhook
|
||||
Address string `json:"address"`
|
||||
// description: Language preference
|
||||
// example: zh_CN
|
||||
Lang string `json:"lang"`
|
||||
}
|
||||
|
||||
type RobotDetails struct {
|
||||
apis.SharableVirtualResourceDetails
|
||||
}
|
||||
|
||||
type RobotListInput struct {
|
||||
apis.SharableVirtualResourceListInput
|
||||
apis.EnabledResourceBaseListInput
|
||||
// description: robot type
|
||||
// enum: feishu,dingtalk,workwx,webhook
|
||||
// example: webhook
|
||||
Type string `json:"type"`
|
||||
// description: Language preference
|
||||
// example: en
|
||||
Lang string `json:"lang"`
|
||||
}
|
||||
|
||||
type RobotUpdateInput struct {
|
||||
apis.SharableVirtualResourceBaseUpdateInput
|
||||
// description: address
|
||||
// example: http://helloworld.io/test/webhook
|
||||
Address string `json:"address"`
|
||||
// description: Language preference
|
||||
// example: en
|
||||
Lang string `json:"lang"`
|
||||
}
|
||||
@@ -119,22 +119,29 @@ func NotifyCriticalWithCtx(ctx context.Context, recipientId []string, isGroup bo
|
||||
|
||||
// NotifyAllWithoutRobot will send messages via all contacnt type from exclude robot contact type such as dingtalk-robot.
|
||||
func NotifyAllWithoutRobot(recipientId []string, isGroup bool, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
|
||||
return notifyRobot(context.Background(), "no", recipientId, isGroup, priority, event, data)
|
||||
return notifyAll(context.Background(), recipientId, isGroup, priority, event, data)
|
||||
}
|
||||
|
||||
// NotifyAllWithoutRobot will send messages via all contacnt type from exclude robot contact type such as dingtalk-robot.
|
||||
func NotifyAllWithoutRobotWithCtx(ctx context.Context, recipientId []string, isGroup bool, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
|
||||
return notifyRobot(ctx, "no", recipientId, isGroup, priority, event, data)
|
||||
return notifyAll(ctx, recipientId, isGroup, priority, event, data)
|
||||
}
|
||||
|
||||
// NotifyRobot will send messages via all robot contact type such as dingtalk-robot.
|
||||
func NotifyRobot(recipientId []string, isGroup bool, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
|
||||
return notifyRobot(context.Background(), "only", recipientId, isGroup, priority, event, data)
|
||||
func NotifyRobot(robotIds []string, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
|
||||
return NotifyRobotWithCtx(context.Background(), robotIds, priority, event, data)
|
||||
}
|
||||
|
||||
// NotifyRobot will send messages via all robot contact type such as dingtalk-robot.
|
||||
func NotifyRobotWithCtx(ctx context.Context, recipientId []string, isGroup bool, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
|
||||
return notifyRobot(ctx, "only", recipientId, isGroup, priority, event, data)
|
||||
func NotifyRobotWithCtx(ctx context.Context, robotIds []string, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
|
||||
rawNotify(context.Background(), sNotifyParams{
|
||||
robots: robotIds,
|
||||
channel: npk.NotifyByRobot,
|
||||
priority: priority,
|
||||
event: event,
|
||||
data: data,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func SystemNotify(priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) {
|
||||
|
||||
@@ -57,13 +57,12 @@ func systemNotify(ctx context.Context, priority npk.TNotifyPriority, event strin
|
||||
notify(ctx, notifyAdminGroups, true, priority, event, data)
|
||||
}
|
||||
|
||||
func notifyRobot(ctx context.Context, robot string, recipientId []string, isGroup bool, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
|
||||
func notifyAll(ctx context.Context, recipientId []string, isGroup bool, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
|
||||
s, err := AdminSessionGenerator(ctx, consts.GetRegion(), "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("robot", jsonutils.NewString(robot))
|
||||
result, err := modules.NotifyReceiver.PerformClassAction(s, "get-types", params)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -85,6 +84,30 @@ func notifyRobot(ctx context.Context, robot string, recipientId []string, isGrou
|
||||
type sTarget struct {
|
||||
reIds []string
|
||||
contacts []string
|
||||
robots []string
|
||||
}
|
||||
|
||||
func langRobot(ctx context.Context, robots []string) (map[language.Tag]*sTarget, error) {
|
||||
contextLang := i18n.Lang(ctx)
|
||||
robotLang, err := getRobotLang(robots)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := make(map[language.Tag]*sTarget)
|
||||
for robot, langStr := range robotLang {
|
||||
lang, err := language.Parse(langStr)
|
||||
if err != nil {
|
||||
log.Errorf("can't parse %s to language.Tag: %v", langStr, err)
|
||||
lang = contextLang
|
||||
}
|
||||
t := ret[lang]
|
||||
if t == nil {
|
||||
ret[lang] = &sTarget{}
|
||||
t = ret[lang]
|
||||
}
|
||||
t.robots = append(t.robots, robot)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func lang(ctx context.Context, contactType npk.TNotifyChannel, reIds []string, contacts []string) (map[language.Tag]*sTarget, error) {
|
||||
@@ -175,6 +198,7 @@ func genMsgViaLang(ctx context.Context, p sNotifyParams) ([]npk.SNotifyMessage,
|
||||
msg := npk.SNotifyMessage{}
|
||||
msg.Uid = reIds
|
||||
msg.Priority = p.priority
|
||||
msg.Robots = p.robots
|
||||
msg.Contacts = p.contacts
|
||||
msg.ContactType = p.channel
|
||||
msg.Topic = p.event
|
||||
@@ -185,9 +209,15 @@ func genMsgViaLang(ctx context.Context, p sNotifyParams) ([]npk.SNotifyMessage,
|
||||
return []npk.SNotifyMessage{msg}, nil
|
||||
}
|
||||
|
||||
langMap, err := lang(ctx, p.channel, reIds, p.contacts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var langMap map[language.Tag]*sTarget
|
||||
|
||||
if p.channel == npk.NotifyByRobot {
|
||||
langMap, err = langRobot(ctx, p.robots)
|
||||
} else {
|
||||
langMap, err = lang(ctx, p.channel, reIds, p.contacts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
msgs := make([]npk.SNotifyMessage, 0, len(langMap))
|
||||
@@ -196,6 +226,7 @@ func genMsgViaLang(ctx context.Context, p sNotifyParams) ([]npk.SNotifyMessage,
|
||||
msg := npk.SNotifyMessage{}
|
||||
msg.Uid = t.reIds
|
||||
msg.Priority = p.priority
|
||||
msg.Robots = p.robots
|
||||
msg.Contacts = t.contacts
|
||||
msg.ContactType = p.channel
|
||||
topic, _ := getContent(langSuffix, p.event, "title", p.channel, p.data)
|
||||
@@ -218,6 +249,7 @@ func genMsgViaLang(ctx context.Context, p sNotifyParams) ([]npk.SNotifyMessage,
|
||||
|
||||
type sNotifyParams struct {
|
||||
recipientId []string
|
||||
robots []string
|
||||
isGroup bool
|
||||
contacts []string
|
||||
channel npk.TNotifyChannel
|
||||
|
||||
@@ -64,6 +64,29 @@ func getUserLang(uids []string) (map[string]string, error) {
|
||||
return uidLang, nil
|
||||
}
|
||||
|
||||
func getRobotLang(robots []string) (map[string]string, error) {
|
||||
s, err := AdminSessionGenerator(context.Background(), consts.GetRegion(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
robotLang := make(map[string]string)
|
||||
if len(robots) > 0 {
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("filter", jsonutils.NewString(fmt.Sprintf("id.in(%s)", strings.Join(robots, ","))))
|
||||
params.Set("scope", jsonutils.NewString("system"))
|
||||
ret, err := modules.NotifyRobot.List(s, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range ret.Data {
|
||||
id, _ := ret.Data[i].GetString("id")
|
||||
langStr, _ := ret.Data[i].GetString("lang")
|
||||
robotLang[id] = langStr
|
||||
}
|
||||
}
|
||||
return robotLang, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
templatesTableLock = &sync.Mutex{}
|
||||
templatesTable = make(map[string]*template.Template)
|
||||
|
||||
@@ -23,6 +23,7 @@ type ConfigsManager struct {
|
||||
var (
|
||||
NotifyReceiver modulebase.ResourceManager
|
||||
NotifyConfig modulebase.ResourceManager
|
||||
NotifyRobot modulebase.ResourceManager
|
||||
Notification modulebase.ResourceManager
|
||||
NotifyTemplate modulebase.ResourceManager
|
||||
NotifySubscription modulebase.ResourceManager
|
||||
@@ -41,11 +42,19 @@ func init() {
|
||||
NotifyConfig = NewNotifyv2Manager(
|
||||
"notifyconfig",
|
||||
"notifyconfigs",
|
||||
[]string{"Type", "Content"},
|
||||
[]string{"Name", "Type", "Content", "Attribution", "Project_Domain"},
|
||||
[]string{},
|
||||
)
|
||||
register(&NotifyConfig)
|
||||
|
||||
NotifyRobot = NewNotifyv2Manager(
|
||||
"robot",
|
||||
"robots",
|
||||
[]string{"ID", "Name", "Type", "Address", "Lang"},
|
||||
[]string{},
|
||||
)
|
||||
register(&NotifyRobot)
|
||||
|
||||
Notification = NewNotifyv2Manager(
|
||||
"notification",
|
||||
"notifications",
|
||||
|
||||
@@ -29,6 +29,7 @@ const (
|
||||
NotifyByWebConsole = TNotifyChannel("webconsole")
|
||||
NotifyByFeishu = TNotifyChannel("feishu")
|
||||
NotifyByWorkwx = TNotifyChannel("workwx")
|
||||
NotifyByRobot = TNotifyChannel("robot")
|
||||
|
||||
NotifyFeishuRobot = TNotifyChannel("feishu-robot")
|
||||
NotifyByDingTalkRobot = TNotifyChannel("dingtalk-robot")
|
||||
|
||||
@@ -31,6 +31,7 @@ var (
|
||||
type SNotifyMessage struct {
|
||||
Uid []string `json:"uid,omitempty"`
|
||||
Gid []string `json:"gid,omitempty"`
|
||||
Robots []string `json:"robots,omitempty"`
|
||||
ContactType TNotifyChannel `json:"contact_type,omitempty"`
|
||||
Contacts []string `json:"contracts"`
|
||||
Topic string `json:"topic,omitempty"`
|
||||
@@ -46,6 +47,7 @@ type SNotifyMessage struct {
|
||||
type SNotifyV2Message struct {
|
||||
Receivers []string `json:"receivers"`
|
||||
Contacts []string `json:"contacts"`
|
||||
Robots []string `json:"robots"`
|
||||
ContactType string `json:"contact_type"`
|
||||
Topic string `json:"topic"`
|
||||
Priority string `json:"priority"`
|
||||
@@ -83,6 +85,7 @@ func (manager *NotificationManager) Send(s *mcclient.ClientSession, msg SNotifyM
|
||||
v2msg := SNotifyV2Message{
|
||||
Receivers: receiverIds,
|
||||
Contacts: msg.Contacts,
|
||||
Robots: msg.Robots,
|
||||
ContactType: string(msg.ContactType),
|
||||
Topic: msg.Topic,
|
||||
Priority: string(msg.Priority),
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package notify
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
|
||||
type ConfigListOptions struct {
|
||||
options.BaseListOptions
|
||||
Type string `json:"type"`
|
||||
Attribution string `json:"attribution"`
|
||||
}
|
||||
|
||||
func (cl *ConfigListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return options.ListStructToParams(cl)
|
||||
}
|
||||
|
||||
type ConfigCreateOptions struct {
|
||||
NAME string `help:"Name of Config"`
|
||||
Domain string `help:"which domain create for, required if attribution is 'domain'"`
|
||||
Type string `help:"The type of config"`
|
||||
Configs []string `help:"Config content, format: 'key:value'"`
|
||||
Attribution string `help:"Attribution" choices:"system|domain"`
|
||||
}
|
||||
|
||||
func (cc *ConfigCreateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
jo := jsonutils.Marshal(cc)
|
||||
d := jo.(*jsonutils.JSONDict)
|
||||
d.Remove("configs")
|
||||
configs := jsonutils.NewDict()
|
||||
for _, kv := range cc.Configs {
|
||||
index := strings.IndexByte(kv, ':')
|
||||
configs.Set(kv[:index], jsonutils.NewString(kv[index+1:]))
|
||||
}
|
||||
d.Set("content", configs)
|
||||
return d, nil
|
||||
}
|
||||
|
||||
type ConfigOptions struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (c *ConfigOptions) GetId() string {
|
||||
return c.ID
|
||||
}
|
||||
|
||||
func (c *ConfigOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type ConfigUpdateOptions struct {
|
||||
ConfigOptions
|
||||
Configs []string
|
||||
}
|
||||
|
||||
func (cu *ConfigUpdateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
configs := jsonutils.NewDict()
|
||||
for _, kv := range cu.Configs {
|
||||
index := strings.IndexByte(kv, ':')
|
||||
configs.Set(kv[:index], jsonutils.NewString(kv[index+1:]))
|
||||
}
|
||||
d := jsonutils.NewDict()
|
||||
d.Set("content", configs)
|
||||
return d, nil
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func (rc *ReceiverCreateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
d := jsonutils.NewDict()
|
||||
d.Set("uid", jsonutils.NewString(rc.UID))
|
||||
d.Set("email", jsonutils.NewString(rc.Email))
|
||||
d.Set("enabled_contact_type", jsonutils.NewStringArray(rc.EnabledContactTypes))
|
||||
d.Set("enabled_contact_types", jsonutils.NewStringArray(rc.EnabledContactTypes))
|
||||
d.Add(jsonutils.NewString(rc.Mobile), "international_mobile", "mobile")
|
||||
d.Add(jsonutils.NewString(rc.MobileAreaCode), "international_mobile", "area_code")
|
||||
return d, nil
|
||||
@@ -110,3 +110,11 @@ type ReceiverIntellijGetOptions struct {
|
||||
func (ri *ReceiverIntellijGetOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(ri), nil
|
||||
}
|
||||
|
||||
type ReceiverGetTypeOptions struct {
|
||||
Domain string `help:"Domain under where available contact methods"`
|
||||
}
|
||||
|
||||
func (rg *ReceiverGetTypeOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(rg), nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package notify
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
|
||||
type RobotListOptions struct {
|
||||
options.BaseListOptions
|
||||
Lang string
|
||||
Type string `choices:"feishu|dingtalk|workwx|webhook"`
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
func (rl *RobotListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return options.ListStructToParams(rl)
|
||||
}
|
||||
|
||||
type RobotCreateOptions struct {
|
||||
NAME string
|
||||
Type string `choices:"feishu|dingtalk|workwx|webhook"`
|
||||
Address string
|
||||
Lang string
|
||||
}
|
||||
|
||||
func (rc *RobotCreateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(rc), nil
|
||||
}
|
||||
|
||||
type RobotOptions struct {
|
||||
ID string `help:"Id or Name of robot"`
|
||||
}
|
||||
|
||||
func (r *RobotOptions) GetId() string {
|
||||
return r.ID
|
||||
}
|
||||
|
||||
func (r *RobotOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type RobotUpdateOptions struct {
|
||||
RobotOptions
|
||||
SrobotUpdateOptions
|
||||
}
|
||||
|
||||
type SrobotUpdateOptions struct {
|
||||
Address string
|
||||
Lang string
|
||||
}
|
||||
|
||||
func (ru *RobotUpdateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(ru.SrobotUpdateOptions), nil
|
||||
}
|
||||
+14
-5
@@ -27,10 +27,13 @@ type INotifyService interface {
|
||||
InitAll() error
|
||||
StopAll()
|
||||
UpdateServices(ctx context.Context, userCred mcclient.TokenCredential, isStart bool)
|
||||
RestartService(ctx context.Context, config SConfig, serviceName string)
|
||||
UpdateConfig(ctx context.Context, service string, config SConfig) error
|
||||
Send(ctx context.Context, contactType string, args apis.SendParams) error
|
||||
ContactByMobile(ctx context.Context, mobile, serviceName string) (string, error)
|
||||
ContactByMobile(ctx context.Context, mobile, serviceName, domainId string) (string, error)
|
||||
BatchSend(ctx context.Context, contactType string, args apis.BatchSendParams) ([]*apis.FailedRecord, error)
|
||||
SendRobotMessage(ctx context.Context, rType string, receivers []*apis.SReceiver, title string, message string) ([]*apis.FailedRecord, error)
|
||||
AddConfig(ctx context.Context, service string, config SConfig) error
|
||||
DeleteConfig(ctx context.Context, service, domainId string) error
|
||||
ValidateConfig(ctx context.Context, cType string, configs map[string]string) (isValid bool, message string, err error)
|
||||
}
|
||||
|
||||
@@ -53,8 +56,11 @@ type SBatchSendParams struct {
|
||||
}
|
||||
|
||||
type IServiceConfigStore interface {
|
||||
GetConfig(serviceName string) (SConfig, error)
|
||||
SetConfig(serviceName string, config SConfig) error
|
||||
GetConfigs(service string) ([]SConfig, error)
|
||||
GetConfig(service, domainId string) (SConfig, error)
|
||||
SetConfig(service string, config SConfig) error
|
||||
HasSystemConfig(service string) (bool, error)
|
||||
BatchCheckConfig(service string, domainIds []string) ([]bool, error)
|
||||
}
|
||||
|
||||
type SNotification struct {
|
||||
@@ -70,7 +76,10 @@ type ITemplateStore interface {
|
||||
FillWithTemplate(ctx context.Context, lang string, notification SNotification) (params apis.SendParams, err error)
|
||||
}
|
||||
|
||||
type SConfig map[string]string
|
||||
type SConfig struct {
|
||||
Config map[string]string
|
||||
DomainId string
|
||||
}
|
||||
|
||||
var (
|
||||
ErrNoSuchMobile = errors.Error("no such mobile")
|
||||
|
||||
+205
-29
@@ -26,8 +26,10 @@ import (
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/notify"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
@@ -40,6 +42,7 @@ import (
|
||||
|
||||
type SConfigManager struct {
|
||||
db.SStandaloneResourceBaseManager
|
||||
db.SDomainizedResourceBaseManager
|
||||
}
|
||||
|
||||
var ConfigManager *SConfigManager
|
||||
@@ -58,9 +61,11 @@ func init() {
|
||||
|
||||
type SConfig struct {
|
||||
db.SStandaloneResourceBase
|
||||
db.SDomainizedResourceBase
|
||||
|
||||
Type string `width:"15" nullable:"false" create:"required" get:"admin" list:"admin"`
|
||||
Content jsonutils.JSONObject `nullable:"false" create:"required" update:"admin" get:"admin" list:"admin"`
|
||||
Type string `width:"15" nullable:"false" create:"required" get:"domain" list:"domain"`
|
||||
Content jsonutils.JSONObject `nullable:"false" create:"required" update:"domain" get:"domain" list:"domain"`
|
||||
Attribution string `width:"8" nullable:"false" default:"system" get:"domain" list:"domain"`
|
||||
}
|
||||
|
||||
func (cm *SConfigManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.ConfigCreateInput) (api.ConfigCreateInput, error) {
|
||||
@@ -69,13 +74,29 @@ func (cm *SConfigManager) ValidateCreateData(ctx context.Context, userCred mccli
|
||||
if err != nil {
|
||||
return input, err
|
||||
}
|
||||
if !utils.IsInStringArray(input.Type, []string{api.EMAIL, api.MOBILE, api.DINGTALK, api.FEISHU, api.WEBCONSOLE, api.WORKWX, api.FEISHU_ROBOT, api.DINGTALK_ROBOT, api.WORKWX_ROBOT, api.WEBHOOK}) {
|
||||
log.Infof("input: %s", jsonutils.Marshal(input))
|
||||
if len(input.ProjectDomainId) > 0 {
|
||||
_, input.DomainizedResourceInput, err = db.ValidateDomainizedResourceInput(ctx, input.DomainizedResourceInput)
|
||||
if err != nil {
|
||||
return input, err
|
||||
}
|
||||
}
|
||||
if !utils.IsInStringArray(input.Type, []string{api.EMAIL, api.MOBILE, api.DINGTALK, api.FEISHU, api.WEBCONSOLE, api.WORKWX}) {
|
||||
return input, httperrors.NewInputParameterError("unkown type %q", input.Type)
|
||||
}
|
||||
if !utils.IsInStringArray(input.Attribution, []string{api.CONFIG_ATTRIBUTION_SYSTEM, api.CONFIG_ATTRIBUTION_DOMAIN}) {
|
||||
return input, httperrors.NewInputParameterError("invalid attribution, need %q or %q", api.CONFIG_ATTRIBUTION_SYSTEM, api.CONFIG_ATTRIBUTION_DOMAIN)
|
||||
}
|
||||
if input.Attribution == api.CONFIG_ATTRIBUTION_SYSTEM {
|
||||
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), ConfigManager.KeywordPlural(), policy.PolicyActionCreate)
|
||||
if allowScope != rbacutils.ScopeSystem {
|
||||
return input, httperrors.NewInputParameterError("No permission to set %q attribution", api.CONFIG_ATTRIBUTION_SYSTEM)
|
||||
}
|
||||
}
|
||||
if input.Content == nil {
|
||||
return input, httperrors.NewMissingParameterError("content")
|
||||
}
|
||||
config, err := cm.GetConfigByType(input.Type)
|
||||
config, err := cm.Config(input.Type, input.ProjectDomainId)
|
||||
if err == nil && config != nil {
|
||||
return input, httperrors.NewDuplicateResourceError("duplicate type %q", input.Type)
|
||||
}
|
||||
@@ -104,6 +125,21 @@ func (cm *SConfigManager) ValidateCreateData(ctx context.Context, userCred mccli
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (c *SConfig) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
||||
err := c.SStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Attribution == api.CONFIG_ATTRIBUTION_DOMAIN || c.Attribution == "" {
|
||||
c.Attribution = api.CONFIG_ATTRIBUTION_DOMAIN
|
||||
c.DomainId, _ = data.GetString("project_domain_id")
|
||||
if c.DomainId == "" {
|
||||
c.DomainId = userCred.GetProjectDomainId()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *SConfig) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ConfigUpdateInput) (api.ConfigUpdateInput, error) {
|
||||
// validate
|
||||
configs := make(map[string]string)
|
||||
@@ -129,7 +165,18 @@ func (c *SConfig) ValidateUpdateData(ctx context.Context, userCred mcclient.Toke
|
||||
}
|
||||
|
||||
func (c *SConfig) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
err := c.StartRepullSubcontactTask(ctx, userCred)
|
||||
c.SStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
|
||||
configMap := make(map[string]string)
|
||||
err := c.Content.Unmarshal(&configMap)
|
||||
if err != nil {
|
||||
log.Errorf("unable to unmarshal: %v", err)
|
||||
return
|
||||
}
|
||||
NotifyService.AddConfig(ctx, c.Type, notifyv2.SConfig{
|
||||
Config: configMap,
|
||||
DomainId: c.DomainId,
|
||||
})
|
||||
err = c.StartRepullSubcontactTask(ctx, userCred)
|
||||
if err != nil {
|
||||
log.Errorf("unable to StartRepullSubcontactTask: %v", err)
|
||||
}
|
||||
@@ -143,13 +190,27 @@ func (c *SConfig) PostUpdate(ctx context.Context, userCred mcclient.TokenCredent
|
||||
log.Errorf("unable to unmarshal: %v", err)
|
||||
return
|
||||
}
|
||||
NotifyService.RestartService(ctx, configMap, c.Type)
|
||||
NotifyService.UpdateConfig(ctx, c.Type, notifyv2.SConfig{
|
||||
Config: configMap,
|
||||
DomainId: c.DomainId,
|
||||
})
|
||||
err = c.StartRepullSubcontactTask(ctx, userCred)
|
||||
if err != nil {
|
||||
log.Errorf("unable to StartRepullSubcontactTask: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *SConfig) PreDelete(ctx context.Context, userCred mcclient.TokenCredential) {
|
||||
c.SStandaloneResourceBase.PreDelete(ctx, userCred)
|
||||
NotifyService.DeleteConfig(ctx, c.Type, c.DomainId)
|
||||
}
|
||||
func (c *SConfig) PostDelete(ctx context.Context, userCred mcclient.TokenCredential) {
|
||||
err := c.StartRepullSubcontactTask(ctx, userCred)
|
||||
if err != nil {
|
||||
log.Errorf("unable to StartRepullSubcontactTask: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *SConfig) StartRepullSubcontactTask(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
task, err := taskman.TaskManager.NewTask(ctx, "RepullSuncontactTask", c, userCred, nil, "", "")
|
||||
if err != nil {
|
||||
@@ -159,19 +220,8 @@ func (c *SConfig) StartRepullSubcontactTask(ctx context.Context, userCred mcclie
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *SConfigManager) filterContactType(cTypes []string, robot string) []string {
|
||||
switch robot {
|
||||
case api.CTYPE_ROBOT_ONLY:
|
||||
return intersection(cTypes, RobotContactTypes)
|
||||
case api.CTYPE_ROBOT_YES:
|
||||
return cTypes
|
||||
default:
|
||||
return difference(cTypes, RobotContactTypes)
|
||||
}
|
||||
}
|
||||
|
||||
var sortedCTypes = []string{
|
||||
api.WEBCONSOLE, api.EMAIL, api.MOBILE, api.DINGTALK, api.FEISHU, api.WORKWX, api.DINGTALK_ROBOT, api.FEISHU_ROBOT, api.WORKWX_ROBOT,
|
||||
api.WEBCONSOLE, api.EMAIL, api.MOBILE, api.DINGTALK, api.FEISHU, api.WORKWX,
|
||||
}
|
||||
|
||||
func sortContactType(ctypes []string) []string {
|
||||
@@ -185,6 +235,25 @@ func sortContactType(ctypes []string) []string {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (cm *SConfigManager) availableContactTypes(domainId string) ([]string, error) {
|
||||
q := cm.Query("type")
|
||||
q = q.Filter(sqlchemy.OR(sqlchemy.AND(sqlchemy.Equals(q.Field("attribution"), api.CONFIG_ATTRIBUTION_DOMAIN), sqlchemy.Equals(q.Field("domain_id"), domainId)), sqlchemy.Equals(q.Field("attribution"), api.CONFIG_ATTRIBUTION_SYSTEM)))
|
||||
|
||||
allTypes := make([]struct {
|
||||
Type string
|
||||
}, 0, 3)
|
||||
err := q.All(&allTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := make([]string, len(allTypes))
|
||||
for i := range ret {
|
||||
ret[i] = allTypes[i].Type
|
||||
}
|
||||
// De-duplication
|
||||
return sets.NewString(ret...).UnsortedList(), nil
|
||||
}
|
||||
|
||||
func (cm *SConfigManager) allContactType() ([]string, error) {
|
||||
q := cm.Query("type")
|
||||
allTypes := make([]struct {
|
||||
@@ -206,10 +275,18 @@ func (self *SConfigManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQue
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q, err = self.SDomainizedResourceBaseManager.ListItemFilter(ctx, q, userCred, input.DomainizedResourceListInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q = q.NotEquals("type", api.WEBCONSOLE)
|
||||
if len(input.Type) > 0 {
|
||||
q.Filter(sqlchemy.Equals(q.Field("type"), input.Type))
|
||||
}
|
||||
if len(input.Attribution) > 0 {
|
||||
q = q.Equals("attribution", input.Attribution)
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
@@ -226,9 +303,11 @@ func (cm *SConfigManager) FetchCustomizeColumns(
|
||||
isList bool,
|
||||
) []api.ConfigDetails {
|
||||
sRows := cm.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
dRows := cm.SDomainizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
rows := make([]api.ConfigDetails, len(objs))
|
||||
for i := range rows {
|
||||
rows[i].StandaloneResourceDetails = sRows[i]
|
||||
rows[i].DomainizedResourceInfo = dRows[i]
|
||||
}
|
||||
return rows
|
||||
}
|
||||
@@ -238,6 +317,10 @@ func (cm *SConfigManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field stri
|
||||
if err != nil {
|
||||
return q, nil
|
||||
}
|
||||
q, err = cm.SDomainizedResourceBaseManager.QueryDistinctExtraField(q, field)
|
||||
if err != nil {
|
||||
return q, nil
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
@@ -246,6 +329,10 @@ func (cm *SConfigManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q, err = cm.SDomainizedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DomainizedResourceListInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
@@ -378,7 +465,18 @@ func (self *SConfigManager) InitializeData() error {
|
||||
}
|
||||
|
||||
func (cm *SConfigManager) ResourceScope() rbacutils.TRbacScope {
|
||||
return rbacutils.ScopeSystem
|
||||
return rbacutils.ScopeDomain
|
||||
}
|
||||
|
||||
func (cm *SConfigManager) FilterByOwner(q *sqlchemy.SQuery, owner mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
|
||||
switch scope {
|
||||
case rbacutils.ScopeDomain, rbacutils.ScopeProject:
|
||||
q = q.Equals("attribution", api.CONFIG_ATTRIBUTION_DOMAIN)
|
||||
if owner != nil {
|
||||
q = q.Equals("domain_id", owner.GetProjectDomainId())
|
||||
}
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (cm *SConfigManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
@@ -398,36 +496,114 @@ func (c *SConfig) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCr
|
||||
}
|
||||
|
||||
// Fetch all SConfig struct which type is contactType.
|
||||
func (self *SConfigManager) GetConfigByType(contactType string) (*SConfig, error) {
|
||||
var config SConfig
|
||||
func (self *SConfigManager) Configs(contactType string) ([]SConfig, error) {
|
||||
var configs = make([]SConfig, 0, 2)
|
||||
q := self.Query()
|
||||
q.Filter(sqlchemy.Equals(q.Field("type"), contactType))
|
||||
err := q.All(&configs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "fail to fetch SConfigs by type %s", contactType)
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func (self *SConfigManager) Config(contactType, domainId string) (*SConfig, error) {
|
||||
q := self.Query()
|
||||
q = q.Equals("type", contactType)
|
||||
if len(domainId) == 0 {
|
||||
q = q.Equals("attribution", api.CONFIG_ATTRIBUTION_SYSTEM)
|
||||
} else {
|
||||
q = q.Equals("domain_id", domainId).Equals("attribution", api.CONFIG_ATTRIBUTION_DOMAIN)
|
||||
}
|
||||
var config SConfig
|
||||
err := q.First(&config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fail to fetch SConfigs by type")
|
||||
return nil, errors.Wrapf(err, "fail to fetch SConfig by type %s and domain %s", contactType, domainId)
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func (self *SConfigManager) GetConfig(contactType string) (notifyv2.SConfig, error) {
|
||||
config, err := self.GetConfigByType(contactType)
|
||||
func (self *SConfigManager) HasSystemConfig(contactType string) (bool, error) {
|
||||
q := self.Query().Equals("type", contactType).Equals("attribution", "system")
|
||||
c, err := q.CountWithError()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return false, err
|
||||
}
|
||||
ret := make(map[string]string)
|
||||
err = config.Content.Unmarshal(&ret)
|
||||
return c > 0, nil
|
||||
}
|
||||
|
||||
func (self *SConfigManager) BatchCheckConfig(contactType string, domainIds []string) ([]bool, error) {
|
||||
domainIdSet := sets.NewString(domainIds...)
|
||||
var configs = make([]SConfig, 0, 2)
|
||||
q := self.Query().Equals("type", contactType).Equals("attribution", "domain").In("domain_id", domainIdSet.UnsortedList())
|
||||
err := q.All(&configs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fail unmarshal config content")
|
||||
return nil, errors.Wrapf(err, "fail to fetch SConfigs by type %s", contactType)
|
||||
}
|
||||
for i := range configs {
|
||||
if domainIdSet.Has(configs[i].DomainId) {
|
||||
domainIdSet.Delete(configs[i].DomainId)
|
||||
}
|
||||
}
|
||||
ret := make([]bool, len(domainIds))
|
||||
for i := range domainIds {
|
||||
if domainIdSet.Has(domainIds[i]) {
|
||||
// no config of domainId, use default one
|
||||
ret[i] = false
|
||||
}
|
||||
ret[i] = true
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SConfigManager) GetConfigs(contactType string) ([]notifyv2.SConfig, error) {
|
||||
configs, err := self.Configs(contactType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := make([]notifyv2.SConfig, 0, len(configs))
|
||||
for i := range configs {
|
||||
c := make(map[string]string)
|
||||
err := configs[i].Content.Unmarshal(&c)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fail unmarshal config content")
|
||||
}
|
||||
ret = append(ret, notifyv2.SConfig{
|
||||
Config: c,
|
||||
DomainId: configs[i].DomainId,
|
||||
})
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SConfigManager) GetConfig(contactType, domainId string) (notifyv2.SConfig, error) {
|
||||
config, err := self.Config(contactType, domainId)
|
||||
if err != nil {
|
||||
return notifyv2.SConfig{}, err
|
||||
}
|
||||
ret := make(map[string]string)
|
||||
err = config.Content.Unmarshal(&ret)
|
||||
if err != nil {
|
||||
return notifyv2.SConfig{}, errors.Wrap(err, "fail unmarshal config content")
|
||||
}
|
||||
return notifyv2.SConfig{
|
||||
Config: ret,
|
||||
DomainId: config.DomainId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *SConfigManager) SetConfig(contactType string, config notifyv2.SConfig) error {
|
||||
content := jsonutils.Marshal(config)
|
||||
content := jsonutils.Marshal(config.Config)
|
||||
sConfig := &SConfig{
|
||||
Type: contactType,
|
||||
Content: content,
|
||||
}
|
||||
sConfig.DomainId = config.DomainId
|
||||
if sConfig.DomainId == "" {
|
||||
sConfig.Attribution = api.CONFIG_ATTRIBUTION_SYSTEM
|
||||
} else {
|
||||
sConfig.Attribution = api.CONFIG_ATTRIBUTION_DOMAIN
|
||||
}
|
||||
return self.TableSpec().InsertOrUpdate(context.Background(), sConfig)
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ func InitDB() error {
|
||||
TemplateManager,
|
||||
ReceiverNotificationManager,
|
||||
SubscriptionManager,
|
||||
RobotManager,
|
||||
} {
|
||||
err := manager.InitializeData()
|
||||
if err != nil {
|
||||
|
||||
@@ -80,25 +80,44 @@ const (
|
||||
)
|
||||
|
||||
func (nm *SNotificationManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NotificationCreateInput) (api.NotificationCreateInput, error) {
|
||||
if len(input.Tag) == 0 && utils.IsInStringArray(input.Tag, []string{api.NOTIFICATION_TAG_ALERT}) {
|
||||
if len(input.Tag) > 0 && !utils.IsInStringArray(input.Tag, []string{api.NOTIFICATION_TAG_ALERT}) {
|
||||
return input, httperrors.NewInputParameterError("invalid tag")
|
||||
}
|
||||
if len(input.Receivers) == 0 {
|
||||
if len(input.Contacts) > 0 {
|
||||
if !userCred.IsAllow(rbacutils.ScopeSystem, api.SERVICE_TYPE, nm.KeywordPlural(), policy.PolicyActionPerform, SendByContact) {
|
||||
return input, httperrors.NewForbiddenError("can't send notification by contact, need receiver")
|
||||
return input, httperrors.NewForbiddenError("only admin can send notification by contact")
|
||||
}
|
||||
if len(input.Contacts) == 0 {
|
||||
input.Contacts = []string{""}
|
||||
}
|
||||
}
|
||||
log.Infof("notify input: %s", jsonutils.Marshal(input))
|
||||
|
||||
// check contact type enabled
|
||||
allContactType, err := ConfigManager.allContactType()
|
||||
if err != nil {
|
||||
return input, err
|
||||
}
|
||||
if !utils.IsInStringArray(input.ContactType, allContactType) {
|
||||
return input, httperrors.NewInputParameterError("Unconfigured contact type %q", input.ContactType)
|
||||
// check robot
|
||||
if len(input.Robots) > 0 {
|
||||
input.ContactType = api.ROBOT
|
||||
robots, err := RobotManager.FetchByIdOrNames(ctx, input.Robots...)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "RobotManager.FetchByIdOrNames")
|
||||
}
|
||||
idSet := sets.NewString()
|
||||
nameSet := sets.NewString()
|
||||
for i := range robots {
|
||||
idSet.Insert(robots[i].Id)
|
||||
nameSet.Insert(robots[i].Name)
|
||||
}
|
||||
for _, re := range input.Receivers {
|
||||
if idSet.Has(re) || nameSet.Has(re) {
|
||||
continue
|
||||
}
|
||||
if !input.IgnoreNonexistentReceiver {
|
||||
return input, httperrors.NewInputParameterError("no such robot whose id is %q", re)
|
||||
}
|
||||
}
|
||||
input.Robots = idSet.UnsortedList()
|
||||
if len(input.Robots) == 0 {
|
||||
return input, httperrors.NewInputParameterError("no valid receiver or contact")
|
||||
}
|
||||
}
|
||||
// check receivers
|
||||
if len(input.Receivers) > 0 {
|
||||
@@ -138,10 +157,12 @@ func (nm *SNotificationManager) ValidateCreateData(ctx context.Context, userCred
|
||||
length = len(input.Topic)
|
||||
}
|
||||
name := fmt.Sprintf("%s-%s-%s", input.Topic[:length], input.ContactType, nowStr)
|
||||
var err error
|
||||
input.Name, err = db.GenerateName(ctx, nm, ownerId, name)
|
||||
if err != nil {
|
||||
return input, errors.Wrapf(err, "unable to generate name for %s", name)
|
||||
}
|
||||
log.Infof("after validatecreate input: %s", jsonutils.Marshal(input))
|
||||
return input, nil
|
||||
}
|
||||
|
||||
@@ -160,9 +181,15 @@ func (n *SNotification) CustomizeCreate(ctx context.Context, userCred mcclient.T
|
||||
}
|
||||
}
|
||||
for i := range input.Contacts {
|
||||
_, err := ReceiverNotificationManager.CreateWithoutReceiver(ctx, userCred, input.Contacts[i], n.Id)
|
||||
_, err := ReceiverNotificationManager.CreateContact(ctx, userCred, input.Contacts[i], n.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ReceiverNotificationManager.Create")
|
||||
return errors.Wrap(err, "ReceiverNotificationManager.CreateContact")
|
||||
}
|
||||
}
|
||||
for i := range input.Robots {
|
||||
_, err := ReceiverNotificationManager.CreateRobot(ctx, userCred, input.Robots[i], n.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ReceiverNotificationManager.CreateRobot")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -345,7 +372,7 @@ func (nm *SNotificationManager) create(ctx context.Context, userCred mcclient.To
|
||||
}
|
||||
}
|
||||
for i := range contacts {
|
||||
_, err := ReceiverNotificationManager.CreateWithoutReceiver(ctx, userCred, contacts[i], n.Id)
|
||||
_, err := ReceiverNotificationManager.CreateContact(ctx, userCred, contacts[i], n.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ReceiverNotificationManager.Create")
|
||||
}
|
||||
|
||||
@@ -284,6 +284,10 @@ func (rm *SReceiverManager) ValidateCreateData(ctx context.Context, userCred mcc
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (r *SReceiver) IsEnabled() bool {
|
||||
return r.Enabled.Bool()
|
||||
}
|
||||
|
||||
var LaxMobileRegexp = regexp.MustCompile(`[0-9]{6,14}`)
|
||||
|
||||
func (r *SReceiver) IsEnabledContactType(ct string) (bool, error) {
|
||||
@@ -689,13 +693,18 @@ func (r *SReceiverManager) AllowPerformGetTypes(ctx context.Context, userCred mc
|
||||
return true
|
||||
}
|
||||
|
||||
func (cm *SReceiverManager) PerformGetTypes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ConfigManagerGetTypesInput) (api.ConfigManagerGetTypesOutput, error) {
|
||||
func (rm *SReceiverManager) PerformGetTypes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ConfigManagerGetTypesInput) (api.ConfigManagerGetTypesOutput, error) {
|
||||
output := api.ConfigManagerGetTypesOutput{}
|
||||
allContactType, err := ConfigManager.allContactType()
|
||||
t, err := db.TenantCacheManager.FetchDomainByIdOrName(ctx, input.Domain)
|
||||
if err != nil {
|
||||
return output, err
|
||||
return output, errors.Wrap(err, "unable to FetchDomainByIdOrName")
|
||||
}
|
||||
output.Types = sortContactType(ConfigManager.filterContactType(allContactType, input.Robot))
|
||||
ret, err := ConfigManager.availableContactTypes(t.Id)
|
||||
if err != nil {
|
||||
return output, errors.Wrap(err, "unable to get available contact types")
|
||||
}
|
||||
|
||||
output.Types = sortContactType(ret)
|
||||
return output, nil
|
||||
}
|
||||
|
||||
@@ -1183,12 +1192,10 @@ func (rm *SReceiverManager) FetchByIDs(ctx context.Context, ids ...string) ([]SR
|
||||
return contacts, nil
|
||||
}
|
||||
|
||||
func (rm *SReceiverManager) FetchByIdOrNames(ctx context.Context, idOrNames ...string) ([]SReceiver, error) {
|
||||
func idOrNameFilter(q *sqlchemy.SQuery, idOrNames ...string) *sqlchemy.SQuery {
|
||||
if len(idOrNames) == 0 {
|
||||
return nil, nil
|
||||
return q
|
||||
}
|
||||
var err error
|
||||
q := rm.Query()
|
||||
var conds []sqlchemy.ICondition
|
||||
for _, idOrName := range idOrNames {
|
||||
conds = append(conds, sqlchemy.Equals(q.Field("name"), idOrName))
|
||||
@@ -1201,6 +1208,15 @@ func (rm *SReceiverManager) FetchByIdOrNames(ctx context.Context, idOrNames ...s
|
||||
} else if len(conds) > 1 {
|
||||
q = q.Filter(sqlchemy.OR(conds...))
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (rm *SReceiverManager) FetchByIdOrNames(ctx context.Context, idOrNames ...string) ([]SReceiver, error) {
|
||||
if len(idOrNames) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var err error
|
||||
q := idOrNameFilter(rm.Query(), idOrNames...)
|
||||
receivers := make([]SReceiver, 0, len(idOrNames))
|
||||
err = db.FetchModelObjects(rm, q, &receivers)
|
||||
if err != nil {
|
||||
@@ -1255,3 +1271,7 @@ func (r *SReceiver) GetContact(cType string) (string, error) {
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (r *SReceiver) GetDomainId() string {
|
||||
return r.DomainId
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ type SReceiverNotification struct {
|
||||
NotificationID string `width:"128" charset:"ascii" nullable:"false" index:"true"`
|
||||
// ignore if ReceiverID is not empty or default
|
||||
Contact string `width:"128" nullable:"false" index:"true"`
|
||||
ReceiverType string `width:"16"`
|
||||
SendAt time.Time `nullable:"false"`
|
||||
SendBy string `width:"128" nullable:"false"`
|
||||
Status string `width:"36" charset:"ascii"`
|
||||
@@ -57,6 +58,18 @@ func (rnm *SReceiverNotificationManager) Create(ctx context.Context, userCred mc
|
||||
rn := &SReceiverNotification{
|
||||
ReceiverID: receiverID,
|
||||
NotificationID: notificationID,
|
||||
ReceiverType: api.RECEIVER_TYPE_USER,
|
||||
Status: api.RECEIVER_NOTIFICATION_RECEIVED,
|
||||
SendBy: userCred.GetUserId(),
|
||||
}
|
||||
return rn, rnm.TableSpec().Insert(ctx, rn)
|
||||
}
|
||||
|
||||
func (rnm *SReceiverNotificationManager) CreateRobot(ctx context.Context, userCred mcclient.TokenCredential, RobotID, notificationID string) (*SReceiverNotification, error) {
|
||||
rn := &SReceiverNotification{
|
||||
ReceiverID: RobotID,
|
||||
NotificationID: notificationID,
|
||||
ReceiverType: api.RECEIVER_TYPE_ROBOT,
|
||||
Status: api.RECEIVER_NOTIFICATION_RECEIVED,
|
||||
SendBy: userCred.GetUserId(),
|
||||
}
|
||||
@@ -71,10 +84,10 @@ func (rnm *SReceiverNotificationManager) GetSlaveFieldName() string {
|
||||
return "receiver_id"
|
||||
}
|
||||
|
||||
func (rnm *SReceiverNotificationManager) CreateWithoutReceiver(ctx context.Context, userCred mcclient.TokenCredential, contact, notificationID string) (*SReceiverNotification, error) {
|
||||
func (rnm *SReceiverNotificationManager) CreateContact(ctx context.Context, userCred mcclient.TokenCredential, contact, notificationID string) (*SReceiverNotification, error) {
|
||||
rn := &SReceiverNotification{
|
||||
NotificationID: notificationID,
|
||||
ReceiverID: ReceiverIdDefault,
|
||||
ReceiverType: api.RECEIVER_TYPE_CONTACT,
|
||||
Contact: contact,
|
||||
Status: api.RECEIVER_NOTIFICATION_RECEIVED,
|
||||
SendBy: userCred.GetUserId(),
|
||||
@@ -82,7 +95,18 @@ func (rnm *SReceiverNotificationManager) CreateWithoutReceiver(ctx context.Conte
|
||||
return rn, rnm.TableSpec().Insert(ctx, rn)
|
||||
}
|
||||
|
||||
func (rn *SReceiverNotification) Receiver() (*SReceiver, error) {
|
||||
// func (rn *SReceiverNotification) Receiver() (*SReceiver, error) {
|
||||
// q := ReceiverManager.Query().Equals("id", rn.ReceiverID)
|
||||
// var receiver SReceiver
|
||||
// err := q.First(&receiver)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// receiver.SetModelManager(ReceiverManager, &receiver)
|
||||
// return &receiver, nil
|
||||
// }
|
||||
|
||||
func (rn *SReceiverNotification) receiver() (*SReceiver, error) {
|
||||
q := ReceiverManager.Query().Equals("id", rn.ReceiverID)
|
||||
var receiver SReceiver
|
||||
err := q.First(&receiver)
|
||||
@@ -93,6 +117,34 @@ func (rn *SReceiverNotification) Receiver() (*SReceiver, error) {
|
||||
return &receiver, nil
|
||||
}
|
||||
|
||||
func (rn *SReceiverNotification) robot() (*SRobot, error) {
|
||||
q := RobotManager.Query().Equals("id", rn.ReceiverID)
|
||||
var robot SRobot
|
||||
err := q.First(&robot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
robot.SetModelManager(RobotManager, &robot)
|
||||
return &robot, nil
|
||||
}
|
||||
|
||||
func (rn *SReceiverNotification) Receiver() (IReceiver, error) {
|
||||
switch rn.ReceiverType {
|
||||
case api.RECEIVER_TYPE_USER:
|
||||
return rn.receiver()
|
||||
case api.RECEIVER_TYPE_CONTACT:
|
||||
return &SContact{contact: rn.Contact}, nil
|
||||
case api.RECEIVER_TYPE_ROBOT:
|
||||
return rn.robot()
|
||||
default:
|
||||
// compatible
|
||||
if rn.ReceiverID != "" && rn.ReceiverID != ReceiverIdDefault {
|
||||
return rn.receiver()
|
||||
}
|
||||
return &SContact{contact: rn.Contact}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (rn *SReceiverNotification) BeforeSend(ctx context.Context, sendTime time.Time) error {
|
||||
if sendTime.IsZero() {
|
||||
sendTime = time.Now()
|
||||
@@ -117,3 +169,44 @@ func (rn *SReceiverNotification) AfterSend(ctx context.Context, success bool, re
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
type IReceiver interface {
|
||||
IsEnabled() bool
|
||||
GetDomainId() string
|
||||
IsEnabledContactType(string) (bool, error)
|
||||
IsVerifiedContactType(string) (bool, error)
|
||||
GetContact(string) (string, error)
|
||||
GetTemplateLang(context.Context) (string, error)
|
||||
}
|
||||
|
||||
type SReceiverBase struct {
|
||||
}
|
||||
|
||||
func (s SReceiverBase) IsEnabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s SReceiverBase) GetDomainId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s SReceiverBase) IsEnabledContactType(_ string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s SReceiverBase) IsVerifiedContactType(_ string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s SReceiverBase) GetTemplateLang(ctx context.Context) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
type SContact struct {
|
||||
SReceiverBase
|
||||
contact string
|
||||
}
|
||||
|
||||
func (s *SContact) GetContact(_ string) (string, error) {
|
||||
return s.contact, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/text/language"
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/utils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
idenapi "yunion.io/x/onecloud/pkg/apis/identity"
|
||||
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/mcclient"
|
||||
rpcapi "yunion.io/x/onecloud/pkg/notify/rpc/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
type SRobotManager struct {
|
||||
db.SSharableVirtualResourceBaseManager
|
||||
db.SEnabledResourceBaseManager
|
||||
}
|
||||
|
||||
var RobotManager *SRobotManager
|
||||
|
||||
func init() {
|
||||
RobotManager = &SRobotManager{
|
||||
SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
|
||||
SRobot{},
|
||||
"robots_tbl",
|
||||
"robot",
|
||||
"robots",
|
||||
),
|
||||
}
|
||||
RobotManager.SetVirtualObject(RobotManager)
|
||||
}
|
||||
|
||||
type SRobot struct {
|
||||
db.SSharableVirtualResourceBase
|
||||
db.SEnabledResourceBase
|
||||
|
||||
Type string `width:"16" nullable:"false" create:"required" get:"user" list:"user" index:"true"`
|
||||
Address string `nullable:"false" create:"required" update:"user" get:"user" list:"user"`
|
||||
Lang string `width:"16" nullable:"false" create:"required" update:"user" get:"user" list:"user"`
|
||||
}
|
||||
|
||||
func (rm *SRobotManager) InitializeData() error {
|
||||
log.Infof("start to init data for notify robot")
|
||||
// convert robot config
|
||||
q := ConfigManager.Query().In("type", append(RobotContactTypes, api.WEBHOOK))
|
||||
var configs []SConfig
|
||||
err := db.FetchModelObjects(ConfigManager, q, &configs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(configs) == 0 {
|
||||
return nil
|
||||
}
|
||||
robots := make([]SRobot, len(configs))
|
||||
for i := range configs {
|
||||
webhook, _ := configs[i].Content.GetString("webhook")
|
||||
robot := SRobot{
|
||||
Address: webhook,
|
||||
Lang: "zh_CN",
|
||||
}
|
||||
robot.IsPublic = true
|
||||
robot.PublicScope = string(rbacutils.ScopeSystem)
|
||||
robot.DomainId = idenapi.DEFAULT_DOMAIN_ID
|
||||
robot.Status = api.RECEIVER_STATUS_READY
|
||||
switch configs[i].Type {
|
||||
case api.FEISHU_ROBOT:
|
||||
robot.Type = api.ROBOT_TYPE_FEISHU
|
||||
robot.Name = "Feishu Robot"
|
||||
case api.DINGTALK_ROBOT:
|
||||
robot.Type = api.ROBOT_TYPE_DINGTALK
|
||||
robot.Name = "Dingtalk Robot"
|
||||
case api.WORKWX_ROBOT:
|
||||
robot.Type = api.ROBOT_TYPE_WORKWX
|
||||
robot.Name = "Workwx Robot"
|
||||
case api.WEBHOOK:
|
||||
robot.Type = api.ROBOT_TYPE_WEBHOOK
|
||||
robot.Name = "Webhook"
|
||||
addresses := strings.Split(robot.Address, ",")
|
||||
for i := 1; i < len(addresses); i++ {
|
||||
robotn := robot
|
||||
robotn.Address = strings.TrimSpace(addresses[i])
|
||||
robots = append(robots, robotn)
|
||||
}
|
||||
robot.Address = addresses[0]
|
||||
}
|
||||
robots = append(robots, robot)
|
||||
}
|
||||
ctx := context.Background()
|
||||
// insert new robot
|
||||
for i := range robots {
|
||||
err := rm.TableSpec().Insert(ctx, &robots[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// delete old configs
|
||||
for i := range configs {
|
||||
config := &configs[i]
|
||||
_, err := db.Update(config, func() error {
|
||||
return config.MarkDelete()
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rm *SRobotManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.RobotCreateInput) (api.RobotCreateInput, error) {
|
||||
var err error
|
||||
input.SharableVirtualResourceCreateInput, err = rm.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ValidateCreateData")
|
||||
}
|
||||
// check type
|
||||
if !utils.IsInStringArray(input.Type, []string{api.ROBOT_TYPE_FEISHU, api.ROBOT_TYPE_WORKWX, api.ROBOT_TYPE_DINGTALK, api.ROBOT_TYPE_WEBHOOK}) {
|
||||
return input, httperrors.NewInputParameterError("unkown type %q", input.Type)
|
||||
}
|
||||
// check lang
|
||||
_, err = language.Parse(input.Lang)
|
||||
if err != nil {
|
||||
return input, httperrors.NewInputParameterError("invalid lang %q: %s", input.Lang, err.Error())
|
||||
}
|
||||
// check Address
|
||||
records, err := NotifyService.SendRobotMessage(ctx, input.Type, []*rpcapi.SReceiver{
|
||||
{
|
||||
Contact: input.Address,
|
||||
DomainId: input.ProjectDomainId,
|
||||
},
|
||||
}, "Validate", "This is a verification message, please ignore.")
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "unable to validate address")
|
||||
}
|
||||
if len(records) > 0 {
|
||||
return input, httperrors.NewInputParameterError("invalid address: %s", records[0].Reason)
|
||||
}
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (r *SRobot) Receiver() *rpcapi.SReceiver {
|
||||
return &rpcapi.SReceiver{
|
||||
Contact: r.Address,
|
||||
DomainId: r.DomainId,
|
||||
}
|
||||
}
|
||||
|
||||
func (rm *SRobotManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool) []api.RobotDetails {
|
||||
sRows := rm.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
rows := make([]api.RobotDetails, len(objs))
|
||||
for i := range rows {
|
||||
rows[i].SharableVirtualResourceDetails = sRows[i]
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
func (rm *SRobotManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.RobotListInput) (*sqlchemy.SQuery, error) {
|
||||
q, err := rm.SSharableBaseResourceManager.ListItemFilter(ctx, q, userCred, input.SharableResourceBaseListInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q, err = rm.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred, input.EnabledResourceBaseListInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(input.Type) > 0 {
|
||||
q = q.Equals("type", input.Type)
|
||||
}
|
||||
if len(input.Lang) > 0 {
|
||||
q = q.Equals("lang", input.Lang)
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (r *SRobot) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RobotUpdateInput) (api.RobotUpdateInput, error) {
|
||||
var err error
|
||||
input.SharableVirtualResourceBaseUpdateInput, err = r.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.SharableVirtualResourceBaseUpdateInput)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "SSharableVirtualResourceBase.ValidateUpdateData")
|
||||
}
|
||||
// check lang
|
||||
_, err = language.Parse(input.Lang)
|
||||
if err != nil {
|
||||
return input, httperrors.NewInputParameterError("invalid lang %q: %s", input.Lang, err.Error())
|
||||
}
|
||||
// check Address
|
||||
records, err := NotifyService.SendRobotMessage(ctx, r.Type, []*rpcapi.SReceiver{
|
||||
{
|
||||
Contact: input.Address,
|
||||
DomainId: r.DomainId,
|
||||
},
|
||||
}, "Validate", "This is a verification message, please ignore.")
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "unable to validate address")
|
||||
}
|
||||
if len(records) > 0 {
|
||||
return input, httperrors.NewInputParameterError("invalid address: %s", records[0].Reason)
|
||||
}
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (r *SRobot) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
||||
r.Status = api.ROBOT_STATUS_READY
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rm *SRobotManager) FetchByIdOrNames(ctx context.Context, idOrNames ...string) ([]SRobot, error) {
|
||||
if len(idOrNames) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var err error
|
||||
q := idOrNameFilter(rm.Query(), idOrNames...)
|
||||
robots := make([]SRobot, 0, len(idOrNames))
|
||||
err = db.FetchModelObjects(rm, q, &robots)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return robots, nil
|
||||
}
|
||||
|
||||
func (r *SRobot) IsEnabled() bool {
|
||||
return r.Enabled.Bool()
|
||||
}
|
||||
|
||||
func (r *SRobot) IsEnabledContactType(ctype string) (bool, error) {
|
||||
return ctype == api.ROBOT, nil
|
||||
}
|
||||
|
||||
func (r *SRobot) IsVerifiedContactType(ctype string) (bool, error) {
|
||||
return ctype == api.ROBOT, nil
|
||||
}
|
||||
|
||||
func (r *SRobot) GetContact(ctype string) (string, error) {
|
||||
return r.Address, nil
|
||||
}
|
||||
|
||||
func (r *SRobot) GetTemplateLang(ctx context.Context) (string, error) {
|
||||
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
|
||||
}
|
||||
|
||||
func (r *SRobot) GetDomainId() string {
|
||||
return r.DomainId
|
||||
}
|
||||
|
||||
func (r *SRobot) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
||||
return r.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, r, "enable")
|
||||
}
|
||||
|
||||
func (r *SRobot) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) {
|
||||
err := db.EnabledPerformEnable(r, ctx, userCred, true)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "EnabledPerformEnable")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *SRobot) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
||||
return r.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, r, "disable")
|
||||
}
|
||||
|
||||
func (r *SRobot) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) {
|
||||
err := db.EnabledPerformEnable(r, ctx, userCred, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "EnabledPerformEnable")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -41,13 +41,31 @@ func (c *SendNotificationClient) Send(ctx context.Context, in *SendParams, opts
|
||||
return c.sendAgentClient.Send(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (c *SendNotificationClient) UpdateConfig(ctx context.Context, in *UpdateConfigParams, opts ...grpc.CallOption) (*Empty, error) {
|
||||
func (c *SendNotificationClient) AddConfig(ctx context.Context, in *AddConfigInput, opts ...grpc.CallOption) (*Empty, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
|
||||
defer cancel()
|
||||
return c.sendAgentClient.AddConfig(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (c *SendNotificationClient) DeleteConfig(ctx context.Context, in *DeleteConfigInput, opts ...grpc.CallOption) (*Empty, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
|
||||
defer cancel()
|
||||
return c.sendAgentClient.DeleteConfig(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (c *SendNotificationClient) UpdateConfig(ctx context.Context, in *UpdateConfigInput, opts ...grpc.CallOption) (*Empty, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
|
||||
defer cancel()
|
||||
return c.sendAgentClient.UpdateConfig(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (c *SendNotificationClient) ValidateConfig(ctx context.Context, in *UpdateConfigParams, opts ...grpc.CallOption) (*ValidateConfigReply, error) {
|
||||
func (c *SendNotificationClient) CompleteConfig(ctx context.Context, in *CompleteConfigInput, opts ...grpc.CallOption) (*Empty, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
|
||||
defer cancel()
|
||||
return c.sendAgentClient.CompleteConfig(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (c *SendNotificationClient) ValidateConfig(ctx context.Context, in *ValidateConfigInput, opts ...grpc.CallOption) (*ValidateConfigReply, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
|
||||
defer cancel()
|
||||
return c.sendAgentClient.ValidateConfig(ctx, in, opts...)
|
||||
@@ -59,6 +77,12 @@ func (c *SendNotificationClient) UseridByMobile(ctx context.Context, in *UseridB
|
||||
return c.sendAgentClient.UseridByMobile(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (c *SendNotificationClient) Ready(ctx context.Context, in *ReadyInput, opts ...grpc.CallOption) (*ReadyOutput, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
|
||||
defer cancel()
|
||||
return c.sendAgentClient.Ready(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (c *SendNotificationClient) BatchSend(ctx context.Context, in *BatchSendParams, opts ...grpc.CallOption) (*BatchSendReply, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
|
||||
defer cancel()
|
||||
|
||||
@@ -6,12 +6,11 @@ package apis
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -26,15 +25,15 @@ var _ = math.Inf
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type SendParams struct {
|
||||
Contact string `protobuf:"bytes,1,opt,name=Contact,proto3" json:"Contact,omitempty"`
|
||||
Topic string `protobuf:"bytes,2,opt,name=Topic,proto3" json:"Topic,omitempty"`
|
||||
Title string `protobuf:"bytes,3,opt,name=Title,proto3" json:"Title,omitempty"`
|
||||
Message string `protobuf:"bytes,4,opt,name=Message,proto3" json:"Message,omitempty"`
|
||||
Priority string `protobuf:"bytes,5,opt,name=Priority,proto3" json:"Priority,omitempty"`
|
||||
RemoteTemplate string `protobuf:"bytes,6,opt,name=RemoteTemplate,proto3" json:"RemoteTemplate,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Receiver *SReceiver `protobuf:"bytes,1,opt,name=Receiver,proto3" json:"Receiver,omitempty"`
|
||||
Topic string `protobuf:"bytes,2,opt,name=Topic,proto3" json:"Topic,omitempty"`
|
||||
Title string `protobuf:"bytes,3,opt,name=Title,proto3" json:"Title,omitempty"`
|
||||
Message string `protobuf:"bytes,4,opt,name=Message,proto3" json:"Message,omitempty"`
|
||||
Priority string `protobuf:"bytes,5,opt,name=Priority,proto3" json:"Priority,omitempty"`
|
||||
RemoteTemplate string `protobuf:"bytes,6,opt,name=RemoteTemplate,proto3" json:"RemoteTemplate,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *SendParams) Reset() { *m = SendParams{} }
|
||||
@@ -62,11 +61,11 @@ func (m *SendParams) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_SendParams proto.InternalMessageInfo
|
||||
|
||||
func (m *SendParams) GetContact() string {
|
||||
func (m *SendParams) GetReceiver() *SReceiver {
|
||||
if m != nil {
|
||||
return m.Contact
|
||||
return m.Receiver
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SendParams) GetTopic() string {
|
||||
@@ -104,47 +103,220 @@ func (m *SendParams) GetRemoteTemplate() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type UpdateConfigParams struct {
|
||||
type ValidateConfigInput struct {
|
||||
Configs map[string]string `protobuf:"bytes,1,rep,name=configs,proto3" json:"configs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *UpdateConfigParams) Reset() { *m = UpdateConfigParams{} }
|
||||
func (m *UpdateConfigParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateConfigParams) ProtoMessage() {}
|
||||
func (*UpdateConfigParams) Descriptor() ([]byte, []int) {
|
||||
func (m *ValidateConfigInput) Reset() { *m = ValidateConfigInput{} }
|
||||
func (m *ValidateConfigInput) String() string { return proto.CompactTextString(m) }
|
||||
func (*ValidateConfigInput) ProtoMessage() {}
|
||||
func (*ValidateConfigInput) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{1}
|
||||
}
|
||||
|
||||
func (m *UpdateConfigParams) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_UpdateConfigParams.Unmarshal(m, b)
|
||||
func (m *ValidateConfigInput) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ValidateConfigInput.Unmarshal(m, b)
|
||||
}
|
||||
func (m *UpdateConfigParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_UpdateConfigParams.Marshal(b, m, deterministic)
|
||||
func (m *ValidateConfigInput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ValidateConfigInput.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *UpdateConfigParams) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_UpdateConfigParams.Merge(m, src)
|
||||
func (m *ValidateConfigInput) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ValidateConfigInput.Merge(m, src)
|
||||
}
|
||||
func (m *UpdateConfigParams) XXX_Size() int {
|
||||
return xxx_messageInfo_UpdateConfigParams.Size(m)
|
||||
func (m *ValidateConfigInput) XXX_Size() int {
|
||||
return xxx_messageInfo_ValidateConfigInput.Size(m)
|
||||
}
|
||||
func (m *UpdateConfigParams) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_UpdateConfigParams.DiscardUnknown(m)
|
||||
func (m *ValidateConfigInput) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ValidateConfigInput.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_UpdateConfigParams proto.InternalMessageInfo
|
||||
var xxx_messageInfo_ValidateConfigInput proto.InternalMessageInfo
|
||||
|
||||
func (m *UpdateConfigParams) GetConfigs() map[string]string {
|
||||
func (m *ValidateConfigInput) GetConfigs() map[string]string {
|
||||
if m != nil {
|
||||
return m.Configs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AddConfigInput struct {
|
||||
Configs map[string]string `protobuf:"bytes,1,rep,name=configs,proto3" json:"configs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
DomainId string `protobuf:"bytes,2,opt,name=domainId,proto3" json:"domainId,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *AddConfigInput) Reset() { *m = AddConfigInput{} }
|
||||
func (m *AddConfigInput) String() string { return proto.CompactTextString(m) }
|
||||
func (*AddConfigInput) ProtoMessage() {}
|
||||
func (*AddConfigInput) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{2}
|
||||
}
|
||||
|
||||
func (m *AddConfigInput) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_AddConfigInput.Unmarshal(m, b)
|
||||
}
|
||||
func (m *AddConfigInput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_AddConfigInput.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *AddConfigInput) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_AddConfigInput.Merge(m, src)
|
||||
}
|
||||
func (m *AddConfigInput) XXX_Size() int {
|
||||
return xxx_messageInfo_AddConfigInput.Size(m)
|
||||
}
|
||||
func (m *AddConfigInput) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_AddConfigInput.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_AddConfigInput proto.InternalMessageInfo
|
||||
|
||||
func (m *AddConfigInput) GetConfigs() map[string]string {
|
||||
if m != nil {
|
||||
return m.Configs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddConfigInput) GetDomainId() string {
|
||||
if m != nil {
|
||||
return m.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UpdateConfigInput struct {
|
||||
Configs map[string]string `protobuf:"bytes,1,rep,name=configs,proto3" json:"configs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
DomainId string `protobuf:"bytes,2,opt,name=domainId,proto3" json:"domainId,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *UpdateConfigInput) Reset() { *m = UpdateConfigInput{} }
|
||||
func (m *UpdateConfigInput) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateConfigInput) ProtoMessage() {}
|
||||
func (*UpdateConfigInput) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{3}
|
||||
}
|
||||
|
||||
func (m *UpdateConfigInput) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_UpdateConfigInput.Unmarshal(m, b)
|
||||
}
|
||||
func (m *UpdateConfigInput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_UpdateConfigInput.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *UpdateConfigInput) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_UpdateConfigInput.Merge(m, src)
|
||||
}
|
||||
func (m *UpdateConfigInput) XXX_Size() int {
|
||||
return xxx_messageInfo_UpdateConfigInput.Size(m)
|
||||
}
|
||||
func (m *UpdateConfigInput) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_UpdateConfigInput.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_UpdateConfigInput proto.InternalMessageInfo
|
||||
|
||||
func (m *UpdateConfigInput) GetConfigs() map[string]string {
|
||||
if m != nil {
|
||||
return m.Configs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UpdateConfigInput) GetDomainId() string {
|
||||
if m != nil {
|
||||
return m.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type DeleteConfigInput struct {
|
||||
DomainId string `protobuf:"bytes,1,opt,name=domainId,proto3" json:"domainId,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *DeleteConfigInput) Reset() { *m = DeleteConfigInput{} }
|
||||
func (m *DeleteConfigInput) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteConfigInput) ProtoMessage() {}
|
||||
func (*DeleteConfigInput) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{4}
|
||||
}
|
||||
|
||||
func (m *DeleteConfigInput) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_DeleteConfigInput.Unmarshal(m, b)
|
||||
}
|
||||
func (m *DeleteConfigInput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_DeleteConfigInput.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *DeleteConfigInput) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_DeleteConfigInput.Merge(m, src)
|
||||
}
|
||||
func (m *DeleteConfigInput) XXX_Size() int {
|
||||
return xxx_messageInfo_DeleteConfigInput.Size(m)
|
||||
}
|
||||
func (m *DeleteConfigInput) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_DeleteConfigInput.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_DeleteConfigInput proto.InternalMessageInfo
|
||||
|
||||
func (m *DeleteConfigInput) GetDomainId() string {
|
||||
if m != nil {
|
||||
return m.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CompleteConfigInput struct {
|
||||
ConfigInput []*AddConfigInput `protobuf:"bytes,1,rep,name=ConfigInput,proto3" json:"ConfigInput,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CompleteConfigInput) Reset() { *m = CompleteConfigInput{} }
|
||||
func (m *CompleteConfigInput) String() string { return proto.CompactTextString(m) }
|
||||
func (*CompleteConfigInput) ProtoMessage() {}
|
||||
func (*CompleteConfigInput) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{5}
|
||||
}
|
||||
|
||||
func (m *CompleteConfigInput) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CompleteConfigInput.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CompleteConfigInput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CompleteConfigInput.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CompleteConfigInput) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CompleteConfigInput.Merge(m, src)
|
||||
}
|
||||
func (m *CompleteConfigInput) XXX_Size() int {
|
||||
return xxx_messageInfo_CompleteConfigInput.Size(m)
|
||||
}
|
||||
func (m *CompleteConfigInput) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CompleteConfigInput.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CompleteConfigInput proto.InternalMessageInfo
|
||||
|
||||
func (m *CompleteConfigInput) GetConfigInput() []*AddConfigInput {
|
||||
if m != nil {
|
||||
return m.ConfigInput
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UseridByMobileParams struct {
|
||||
Mobile string `protobuf:"bytes,1,opt,name=mobile,proto3" json:"mobile,omitempty"`
|
||||
DomainId string `protobuf:"bytes,2,opt,name=domainId,proto3" json:"domainId,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -154,7 +326,7 @@ func (m *UseridByMobileParams) Reset() { *m = UseridByMobileParams{} }
|
||||
func (m *UseridByMobileParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*UseridByMobileParams) ProtoMessage() {}
|
||||
func (*UseridByMobileParams) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{2}
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{6}
|
||||
}
|
||||
|
||||
func (m *UseridByMobileParams) XXX_Unmarshal(b []byte) error {
|
||||
@@ -182,6 +354,13 @@ func (m *UseridByMobileParams) GetMobile() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *UseridByMobileParams) GetDomainId() string {
|
||||
if m != nil {
|
||||
return m.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Empty struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -192,7 +371,7 @@ func (m *Empty) Reset() { *m = Empty{} }
|
||||
func (m *Empty) String() string { return proto.CompactTextString(m) }
|
||||
func (*Empty) ProtoMessage() {}
|
||||
func (*Empty) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{3}
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{7}
|
||||
}
|
||||
|
||||
func (m *Empty) XXX_Unmarshal(b []byte) error {
|
||||
@@ -224,7 +403,7 @@ func (m *UseridByMobileReply) Reset() { *m = UseridByMobileReply{} }
|
||||
func (m *UseridByMobileReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*UseridByMobileReply) ProtoMessage() {}
|
||||
func (*UseridByMobileReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{4}
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{8}
|
||||
}
|
||||
|
||||
func (m *UseridByMobileReply) XXX_Unmarshal(b []byte) error {
|
||||
@@ -264,7 +443,7 @@ func (m *ValidateConfigReply) Reset() { *m = ValidateConfigReply{} }
|
||||
func (m *ValidateConfigReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*ValidateConfigReply) ProtoMessage() {}
|
||||
func (*ValidateConfigReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{5}
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{9}
|
||||
}
|
||||
|
||||
func (m *ValidateConfigReply) XXX_Unmarshal(b []byte) error {
|
||||
@@ -299,22 +478,69 @@ func (m *ValidateConfigReply) GetMsg() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type BatchSendParams struct {
|
||||
Contacts []string `protobuf:"bytes,1,rep,name=Contacts,proto3" json:"Contacts,omitempty"`
|
||||
Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"Title,omitempty"`
|
||||
Message string `protobuf:"bytes,3,opt,name=Message,proto3" json:"Message,omitempty"`
|
||||
Priority string `protobuf:"bytes,4,opt,name=Priority,proto3" json:"Priority,omitempty"`
|
||||
RemoteTemplate string `protobuf:"bytes,5,opt,name=RemoteTemplate,proto3" json:"RemoteTemplate,omitempty"`
|
||||
type SReceiver struct {
|
||||
Contact string `protobuf:"bytes,1,opt,name=Contact,proto3" json:"Contact,omitempty"`
|
||||
DomainId string `protobuf:"bytes,2,opt,name=DomainId,proto3" json:"DomainId,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *SReceiver) Reset() { *m = SReceiver{} }
|
||||
func (m *SReceiver) String() string { return proto.CompactTextString(m) }
|
||||
func (*SReceiver) ProtoMessage() {}
|
||||
func (*SReceiver) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{10}
|
||||
}
|
||||
|
||||
func (m *SReceiver) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SReceiver.Unmarshal(m, b)
|
||||
}
|
||||
func (m *SReceiver) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_SReceiver.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *SReceiver) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SReceiver.Merge(m, src)
|
||||
}
|
||||
func (m *SReceiver) XXX_Size() int {
|
||||
return xxx_messageInfo_SReceiver.Size(m)
|
||||
}
|
||||
func (m *SReceiver) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SReceiver.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SReceiver proto.InternalMessageInfo
|
||||
|
||||
func (m *SReceiver) GetContact() string {
|
||||
if m != nil {
|
||||
return m.Contact
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *SReceiver) GetDomainId() string {
|
||||
if m != nil {
|
||||
return m.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type BatchSendParams struct {
|
||||
Receivers []*SReceiver `protobuf:"bytes,1,rep,name=Receivers,proto3" json:"Receivers,omitempty"`
|
||||
Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"Title,omitempty"`
|
||||
Message string `protobuf:"bytes,3,opt,name=Message,proto3" json:"Message,omitempty"`
|
||||
Priority string `protobuf:"bytes,4,opt,name=Priority,proto3" json:"Priority,omitempty"`
|
||||
RemoteTemplate string `protobuf:"bytes,5,opt,name=RemoteTemplate,proto3" json:"RemoteTemplate,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *BatchSendParams) Reset() { *m = BatchSendParams{} }
|
||||
func (m *BatchSendParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*BatchSendParams) ProtoMessage() {}
|
||||
func (*BatchSendParams) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{6}
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{11}
|
||||
}
|
||||
|
||||
func (m *BatchSendParams) XXX_Unmarshal(b []byte) error {
|
||||
@@ -335,9 +561,9 @@ func (m *BatchSendParams) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_BatchSendParams proto.InternalMessageInfo
|
||||
|
||||
func (m *BatchSendParams) GetContacts() []string {
|
||||
func (m *BatchSendParams) GetReceivers() []*SReceiver {
|
||||
if m != nil {
|
||||
return m.Contacts
|
||||
return m.Receivers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -371,18 +597,18 @@ func (m *BatchSendParams) GetRemoteTemplate() string {
|
||||
}
|
||||
|
||||
type FailedRecord struct {
|
||||
Contact string `protobuf:"bytes,1,opt,name=Contact,proto3" json:"Contact,omitempty"`
|
||||
Reason string `protobuf:"bytes,2,opt,name=Reason,proto3" json:"Reason,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Receiver *SReceiver `protobuf:"bytes,1,opt,name=Receiver,proto3" json:"Receiver,omitempty"`
|
||||
Reason string `protobuf:"bytes,2,opt,name=Reason,proto3" json:"Reason,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *FailedRecord) Reset() { *m = FailedRecord{} }
|
||||
func (m *FailedRecord) String() string { return proto.CompactTextString(m) }
|
||||
func (*FailedRecord) ProtoMessage() {}
|
||||
func (*FailedRecord) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{7}
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{12}
|
||||
}
|
||||
|
||||
func (m *FailedRecord) XXX_Unmarshal(b []byte) error {
|
||||
@@ -403,11 +629,11 @@ func (m *FailedRecord) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_FailedRecord proto.InternalMessageInfo
|
||||
|
||||
func (m *FailedRecord) GetContact() string {
|
||||
func (m *FailedRecord) GetReceiver() *SReceiver {
|
||||
if m != nil {
|
||||
return m.Contact
|
||||
return m.Receiver
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FailedRecord) GetReason() string {
|
||||
@@ -428,7 +654,7 @@ func (m *BatchSendReply) Reset() { *m = BatchSendReply{} }
|
||||
func (m *BatchSendReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*BatchSendReply) ProtoMessage() {}
|
||||
func (*BatchSendReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{8}
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{13}
|
||||
}
|
||||
|
||||
func (m *BatchSendReply) XXX_Unmarshal(b []byte) error {
|
||||
@@ -456,55 +682,156 @@ func (m *BatchSendReply) GetFailedRecords() []*FailedRecord {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ReadyInput struct {
|
||||
DomainIds []string `protobuf:"bytes,1,rep,name=DomainIds,proto3" json:"DomainIds,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ReadyInput) Reset() { *m = ReadyInput{} }
|
||||
func (m *ReadyInput) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadyInput) ProtoMessage() {}
|
||||
func (*ReadyInput) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{14}
|
||||
}
|
||||
|
||||
func (m *ReadyInput) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ReadyInput.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ReadyInput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ReadyInput.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ReadyInput) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ReadyInput.Merge(m, src)
|
||||
}
|
||||
func (m *ReadyInput) XXX_Size() int {
|
||||
return xxx_messageInfo_ReadyInput.Size(m)
|
||||
}
|
||||
func (m *ReadyInput) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ReadyInput.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ReadyInput proto.InternalMessageInfo
|
||||
|
||||
func (m *ReadyInput) GetDomainIds() []string {
|
||||
if m != nil {
|
||||
return m.DomainIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ReadyOutput struct {
|
||||
Ok bool `protobuf:"varint,1,opt,name=Ok,proto3" json:"Ok,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ReadyOutput) Reset() { *m = ReadyOutput{} }
|
||||
func (m *ReadyOutput) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadyOutput) ProtoMessage() {}
|
||||
func (*ReadyOutput) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_63fdd68f7eb311f9, []int{15}
|
||||
}
|
||||
|
||||
func (m *ReadyOutput) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ReadyOutput.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ReadyOutput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ReadyOutput.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ReadyOutput) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ReadyOutput.Merge(m, src)
|
||||
}
|
||||
func (m *ReadyOutput) XXX_Size() int {
|
||||
return xxx_messageInfo_ReadyOutput.Size(m)
|
||||
}
|
||||
func (m *ReadyOutput) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ReadyOutput.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ReadyOutput proto.InternalMessageInfo
|
||||
|
||||
func (m *ReadyOutput) GetOk() bool {
|
||||
if m != nil {
|
||||
return m.Ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*SendParams)(nil), "apis.SendParams")
|
||||
proto.RegisterType((*UpdateConfigParams)(nil), "apis.UpdateConfigParams")
|
||||
proto.RegisterMapType((map[string]string)(nil), "apis.UpdateConfigParams.ConfigsEntry")
|
||||
proto.RegisterType((*ValidateConfigInput)(nil), "apis.ValidateConfigInput")
|
||||
proto.RegisterMapType((map[string]string)(nil), "apis.ValidateConfigInput.ConfigsEntry")
|
||||
proto.RegisterType((*AddConfigInput)(nil), "apis.AddConfigInput")
|
||||
proto.RegisterMapType((map[string]string)(nil), "apis.AddConfigInput.ConfigsEntry")
|
||||
proto.RegisterType((*UpdateConfigInput)(nil), "apis.UpdateConfigInput")
|
||||
proto.RegisterMapType((map[string]string)(nil), "apis.UpdateConfigInput.ConfigsEntry")
|
||||
proto.RegisterType((*DeleteConfigInput)(nil), "apis.DeleteConfigInput")
|
||||
proto.RegisterType((*CompleteConfigInput)(nil), "apis.CompleteConfigInput")
|
||||
proto.RegisterType((*UseridByMobileParams)(nil), "apis.UseridByMobileParams")
|
||||
proto.RegisterType((*Empty)(nil), "apis.Empty")
|
||||
proto.RegisterType((*UseridByMobileReply)(nil), "apis.UseridByMobileReply")
|
||||
proto.RegisterType((*ValidateConfigReply)(nil), "apis.ValidateConfigReply")
|
||||
proto.RegisterType((*SReceiver)(nil), "apis.SReceiver")
|
||||
proto.RegisterType((*BatchSendParams)(nil), "apis.BatchSendParams")
|
||||
proto.RegisterType((*FailedRecord)(nil), "apis.FailedRecord")
|
||||
proto.RegisterType((*BatchSendReply)(nil), "apis.BatchSendReply")
|
||||
proto.RegisterType((*ReadyInput)(nil), "apis.ReadyInput")
|
||||
proto.RegisterType((*ReadyOutput)(nil), "apis.ReadyOutput")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("send_server.proto", fileDescriptor_63fdd68f7eb311f9) }
|
||||
|
||||
var fileDescriptor_63fdd68f7eb311f9 = []byte{
|
||||
// 497 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0xdd, 0x6a, 0xd4, 0x40,
|
||||
0x14, 0xc7, 0xc9, 0x7e, 0xef, 0xe9, 0xba, 0xd6, 0xe9, 0x5a, 0xc6, 0x5c, 0x95, 0x40, 0xa5, 0x37,
|
||||
0xe6, 0xa2, 0x22, 0x2c, 0xbd, 0xd1, 0xb6, 0xac, 0x82, 0x50, 0x28, 0xb1, 0xf5, 0x56, 0xa6, 0xc9,
|
||||
0x71, 0x1d, 0x4c, 0x32, 0x21, 0x33, 0x2d, 0xe4, 0x31, 0x7c, 0x04, 0xdf, 0x40, 0xf0, 0x05, 0x65,
|
||||
0x3e, 0xb2, 0x9b, 0xac, 0xbb, 0xed, 0x5d, 0x7e, 0xe7, 0x8b, 0x39, 0xe7, 0xff, 0x27, 0xf0, 0x42,
|
||||
0x62, 0x9e, 0x7c, 0x93, 0x58, 0x3e, 0x60, 0x19, 0x16, 0xa5, 0x50, 0x82, 0xf4, 0x58, 0xc1, 0x65,
|
||||
0xf0, 0xc7, 0x03, 0xf8, 0x82, 0x79, 0x72, 0xcd, 0x4a, 0x96, 0x49, 0x42, 0x61, 0x78, 0x29, 0x72,
|
||||
0xc5, 0x62, 0x45, 0xbd, 0x23, 0xef, 0x64, 0x1c, 0xd5, 0x48, 0x66, 0xd0, 0xbf, 0x11, 0x05, 0x8f,
|
||||
0x69, 0xc7, 0xc4, 0x2d, 0x98, 0x28, 0x57, 0x29, 0xd2, 0xae, 0x8b, 0x6a, 0xd0, 0x53, 0xae, 0x50,
|
||||
0x4a, 0xb6, 0x44, 0xda, 0xb3, 0x53, 0x1c, 0x12, 0x1f, 0x46, 0xd7, 0x25, 0x17, 0x25, 0x57, 0x15,
|
||||
0xed, 0x9b, 0xd4, 0x8a, 0xc9, 0x6b, 0x98, 0x46, 0x98, 0x09, 0x85, 0x37, 0x98, 0x15, 0x29, 0x53,
|
||||
0x48, 0x07, 0xa6, 0x62, 0x23, 0x1a, 0xfc, 0xf2, 0x80, 0xdc, 0x16, 0x09, 0x53, 0x78, 0x29, 0xf2,
|
||||
0xef, 0x7c, 0xe9, 0x9e, 0xfe, 0x1e, 0x86, 0xb1, 0x61, 0x49, 0xbd, 0xa3, 0xee, 0xc9, 0xde, 0xe9,
|
||||
0x71, 0xa8, 0x37, 0x0c, 0xff, 0x2f, 0x0d, 0x2d, 0xc8, 0x45, 0xae, 0xca, 0x2a, 0xaa, 0xbb, 0xfc,
|
||||
0x33, 0x98, 0x34, 0x13, 0x64, 0x1f, 0xba, 0x3f, 0xb1, 0x72, 0x77, 0xd0, 0x9f, 0x7a, 0xdb, 0x07,
|
||||
0x96, 0xde, 0x63, 0x7d, 0x03, 0x03, 0x67, 0x9d, 0xb9, 0x17, 0x84, 0x30, 0xbb, 0x95, 0x58, 0xf2,
|
||||
0xe4, 0xa2, 0xba, 0x12, 0x77, 0x3c, 0x45, 0xf7, 0xa8, 0x43, 0x18, 0x64, 0x86, 0xdd, 0x18, 0x47,
|
||||
0xc1, 0x10, 0xfa, 0x8b, 0xac, 0x50, 0x55, 0xf0, 0x06, 0x0e, 0xda, 0x8d, 0x11, 0x16, 0x69, 0xa5,
|
||||
0xfb, 0xee, 0x4d, 0xb8, 0xee, 0xb3, 0x14, 0x9c, 0xc3, 0xc1, 0x57, 0x96, 0xf2, 0xf5, 0x46, 0xb6,
|
||||
0x9c, 0xc2, 0x90, 0x4b, 0x93, 0x30, 0xf5, 0xa3, 0xa8, 0x46, 0xbd, 0x44, 0x26, 0x97, 0xee, 0xc1,
|
||||
0xfa, 0x33, 0xf8, 0xed, 0xc1, 0xf3, 0x0b, 0xa6, 0xe2, 0x1f, 0x0d, 0xd9, 0x7d, 0x18, 0x39, 0x9d,
|
||||
0xed, 0xf1, 0xc6, 0xd1, 0x8a, 0xd7, 0x12, 0x77, 0x76, 0x48, 0xdc, 0xdd, 0x2d, 0x71, 0xef, 0x49,
|
||||
0x89, 0xfb, 0x5b, 0x25, 0xfe, 0x00, 0x93, 0x8f, 0x8c, 0xa7, 0x98, 0x44, 0x18, 0x8b, 0x32, 0x79,
|
||||
0xc4, 0x96, 0x87, 0x30, 0x88, 0x90, 0x49, 0x91, 0xbb, 0xe7, 0x39, 0x0a, 0x3e, 0xc3, 0x74, 0xb5,
|
||||
0xa4, 0xbd, 0xd1, 0x1c, 0x9e, 0x35, 0x67, 0xd6, 0x2e, 0x21, 0xd6, 0x25, 0xcd, 0x54, 0xd4, 0x2e,
|
||||
0x3c, 0xfd, 0xdb, 0x81, 0xb1, 0x9e, 0x73, 0xbe, 0xc4, 0x5c, 0x91, 0x63, 0xe8, 0x69, 0x20, 0xfb,
|
||||
0xb6, 0x71, 0x7d, 0x45, 0x7f, 0xcf, 0x46, 0x8c, 0xb0, 0xe4, 0x1d, 0x4c, 0x9a, 0xce, 0x23, 0x74,
|
||||
0x97, 0x1b, 0xdb, 0x6d, 0x0b, 0x98, 0xb6, 0x05, 0x7e, 0xa4, 0xf1, 0x95, 0xcd, 0x6c, 0x33, 0xc4,
|
||||
0x27, 0x98, 0xb6, 0x6d, 0x45, 0x7c, 0x37, 0x66, 0x8b, 0x4b, 0xeb, 0x41, 0xdb, 0x8c, 0x38, 0x87,
|
||||
0xf1, 0xea, 0x8e, 0xe4, 0xa5, 0xad, 0xdb, 0x70, 0x8f, 0x3f, 0xdb, 0x08, 0x9b, 0xce, 0xbb, 0x81,
|
||||
0xf9, 0xcd, 0xbc, 0xfd, 0x17, 0x00, 0x00, 0xff, 0xff, 0x71, 0x6f, 0x12, 0x61, 0x7b, 0x04, 0x00,
|
||||
0x00,
|
||||
// 722 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x5d, 0x6b, 0xd4, 0x4c,
|
||||
0x14, 0x26, 0xfb, 0xd9, 0x9c, 0xed, 0xbb, 0xed, 0x4e, 0xf7, 0xed, 0x9b, 0x77, 0x51, 0xa8, 0x41,
|
||||
0x4b, 0x51, 0xbb, 0x42, 0x15, 0x59, 0x2a, 0x88, 0xdb, 0x2f, 0x69, 0xa1, 0xb4, 0x4c, 0x5b, 0x6f,
|
||||
0x65, 0xba, 0x39, 0xae, 0xa1, 0xf9, 0x22, 0x99, 0x2d, 0xe4, 0xd2, 0xdf, 0xe0, 0x6f, 0xf0, 0xca,
|
||||
0x5b, 0xff, 0x81, 0x7f, 0x4c, 0x32, 0x93, 0xc9, 0x26, 0xd9, 0x54, 0x11, 0xc1, 0xbb, 0x3c, 0x67,
|
||||
0x9e, 0x73, 0xce, 0x93, 0x93, 0x39, 0x4f, 0xa0, 0x17, 0xa1, 0x67, 0xbd, 0x8f, 0x30, 0xbc, 0xc5,
|
||||
0x70, 0x18, 0x84, 0x3e, 0xf7, 0x49, 0x83, 0x05, 0x76, 0x64, 0x7e, 0xd7, 0x00, 0x2e, 0xd0, 0xb3,
|
||||
0xce, 0x59, 0xc8, 0xdc, 0x88, 0x3c, 0x81, 0x25, 0x8a, 0x13, 0xb4, 0x6f, 0x31, 0x34, 0xb4, 0x0d,
|
||||
0x6d, 0xab, 0xb3, 0xb3, 0x32, 0x4c, 0x78, 0xc3, 0x0b, 0x15, 0xa6, 0x19, 0x81, 0xf4, 0xa1, 0x79,
|
||||
0xe9, 0x07, 0xf6, 0xc4, 0xa8, 0x6d, 0x68, 0x5b, 0x3a, 0x95, 0x40, 0x44, 0x6d, 0xee, 0xa0, 0x51,
|
||||
0x4f, 0xa3, 0x09, 0x20, 0x06, 0xb4, 0x4f, 0x31, 0x8a, 0xd8, 0x14, 0x8d, 0x86, 0x88, 0x2b, 0x48,
|
||||
0x06, 0xb0, 0x74, 0x1e, 0xda, 0x7e, 0x68, 0xf3, 0xd8, 0x68, 0x8a, 0xa3, 0x0c, 0x93, 0x4d, 0xe8,
|
||||
0x52, 0x74, 0x7d, 0x8e, 0x97, 0xe8, 0x06, 0x0e, 0xe3, 0x68, 0xb4, 0x04, 0xa3, 0x14, 0x35, 0x3f,
|
||||
0x6b, 0xb0, 0xf6, 0x8e, 0x39, 0xb6, 0xc5, 0x38, 0xee, 0xfb, 0xde, 0x07, 0x7b, 0x7a, 0xec, 0x05,
|
||||
0x33, 0x4e, 0xde, 0x40, 0x7b, 0x22, 0x60, 0x64, 0x68, 0x1b, 0xf5, 0xad, 0xce, 0xce, 0xa6, 0x7c,
|
||||
0x9b, 0x0a, 0xee, 0x50, 0x3e, 0x47, 0x87, 0x1e, 0x0f, 0x63, 0xaa, 0xd2, 0x06, 0xbb, 0xb0, 0x9c,
|
||||
0x3f, 0x20, 0xab, 0x50, 0xbf, 0xc1, 0x58, 0xcc, 0x46, 0xa7, 0xc9, 0x63, 0xf2, 0xbe, 0xb7, 0xcc,
|
||||
0x99, 0xa1, 0x9a, 0x82, 0x00, 0xbb, 0xb5, 0x91, 0x66, 0x7e, 0xd1, 0xa0, 0x3b, 0xb6, 0xac, 0xbc,
|
||||
0xa0, 0x57, 0x65, 0x41, 0x0f, 0xa4, 0xa0, 0x22, 0xad, 0x5a, 0x4b, 0x32, 0x29, 0xcb, 0x77, 0x99,
|
||||
0xed, 0x1d, 0x5b, 0x69, 0xb3, 0x0c, 0xff, 0x91, 0xce, 0xaf, 0x1a, 0xf4, 0xae, 0x82, 0xf2, 0xec,
|
||||
0x5e, 0x97, 0xa5, 0x3e, 0x94, 0x52, 0x17, 0x98, 0x7f, 0x59, 0xed, 0x33, 0xe8, 0x1d, 0xa0, 0x83,
|
||||
0x45, 0xb1, 0xf9, 0x66, 0x5a, 0xb1, 0x99, 0x79, 0x0a, 0x6b, 0xfb, 0xbe, 0x1b, 0x94, 0x53, 0x5e,
|
||||
0x42, 0x27, 0x07, 0xd3, 0x77, 0xec, 0x57, 0x7d, 0x0e, 0x9a, 0x27, 0x9a, 0x27, 0xd0, 0xbf, 0x8a,
|
||||
0x30, 0xb4, 0xad, 0xbd, 0xf8, 0xd4, 0xbf, 0xb6, 0x1d, 0x4c, 0x57, 0x67, 0x1d, 0x5a, 0xae, 0xc0,
|
||||
0xa9, 0x80, 0x14, 0xfd, 0x6c, 0x0e, 0x66, 0x1b, 0x9a, 0x87, 0x6e, 0xc0, 0x63, 0x73, 0x1b, 0xd6,
|
||||
0x8a, 0x45, 0x29, 0x06, 0x4e, 0x9c, 0xd4, 0x9c, 0x89, 0xb0, 0xaa, 0x29, 0x91, 0x39, 0x2e, 0x5f,
|
||||
0x77, 0x49, 0x37, 0xa0, 0x6d, 0x47, 0xe2, 0x40, 0xf0, 0x97, 0xa8, 0x82, 0xc9, 0x80, 0xdd, 0x68,
|
||||
0x9a, 0xf6, 0x4f, 0x1e, 0xcd, 0x31, 0xe8, 0xd9, 0x4e, 0x27, 0x89, 0xfb, 0xbe, 0xc7, 0xd9, 0x84,
|
||||
0xa7, 0x8d, 0x14, 0x4c, 0xd4, 0x1f, 0x94, 0xd4, 0x2b, 0x6c, 0x7e, 0xd3, 0x60, 0x65, 0x8f, 0xf1,
|
||||
0xc9, 0xc7, 0x9c, 0x81, 0x6c, 0x83, 0xae, 0xaa, 0xaa, 0x7b, 0xb3, 0xe0, 0x20, 0x73, 0xc6, 0xdc,
|
||||
0x2c, 0x6a, 0x77, 0x98, 0x45, 0xfd, 0x6e, 0xb3, 0x68, 0xfc, 0xd2, 0x2c, 0x9a, 0x95, 0x66, 0x71,
|
||||
0x01, 0xcb, 0x47, 0xcc, 0x76, 0xd0, 0xa2, 0x38, 0xf1, 0x43, 0xeb, 0xf7, 0x3c, 0x6f, 0x1d, 0x5a,
|
||||
0x14, 0x59, 0xe4, 0x7b, 0xa9, 0xe2, 0x14, 0x99, 0x27, 0xd0, 0xcd, 0x46, 0x21, 0x3f, 0xc6, 0x08,
|
||||
0xfe, 0xc9, 0xb7, 0x51, 0xd3, 0x20, 0xb2, 0x76, 0xfe, 0x88, 0x16, 0x89, 0xe6, 0x63, 0x00, 0x8a,
|
||||
0xcc, 0x8a, 0xe5, 0x3d, 0xbd, 0x07, 0xba, 0x9a, 0xb8, 0xac, 0xa1, 0xd3, 0x79, 0xc0, 0xbc, 0x0f,
|
||||
0x1d, 0xc1, 0x3d, 0x9b, 0xf1, 0x84, 0xdc, 0x85, 0xda, 0xd9, 0x4d, 0xfa, 0xf1, 0x6b, 0x67, 0x37,
|
||||
0x3b, 0x9f, 0x1a, 0xa0, 0x27, 0x92, 0xc6, 0x53, 0xf4, 0x38, 0x79, 0x0a, 0x4d, 0x41, 0x26, 0xab,
|
||||
0x52, 0xc4, 0xbc, 0xcb, 0xa0, 0x97, 0x8b, 0xa4, 0xb5, 0x1e, 0x41, 0x23, 0x49, 0x55, 0xe4, 0xf9,
|
||||
0x47, 0x1e, 0x74, 0x64, 0x44, 0x5c, 0x5d, 0x32, 0x04, 0x3d, 0x5b, 0x17, 0x52, 0xb9, 0x3f, 0x45,
|
||||
0xfe, 0x08, 0xba, 0xc5, 0x75, 0x24, 0xff, 0xcb, 0xe3, 0x8a, 0x25, 0x2d, 0x66, 0xbe, 0x80, 0xe5,
|
||||
0xbc, 0xf9, 0x90, 0xff, 0xee, 0x30, 0xa4, 0x85, 0xac, 0xbc, 0x5f, 0xa8, 0xac, 0x05, 0x0f, 0x29,
|
||||
0x66, 0x1d, 0x41, 0xb7, 0xb8, 0x61, 0x4a, 0x65, 0xc5, 0xaf, 0x63, 0x50, 0x79, 0x24, 0x6f, 0xc1,
|
||||
0x5b, 0xe8, 0x16, 0x17, 0x9b, 0x0c, 0x52, 0xd5, 0x15, 0x1e, 0xa2, 0x0a, 0x55, 0x59, 0xc1, 0x08,
|
||||
0xf4, 0xec, 0x82, 0x91, 0x7f, 0x25, 0xaf, 0xb4, 0x7c, 0x83, 0x7e, 0x29, 0x2c, 0x32, 0xaf, 0x5b,
|
||||
0xe2, 0x7f, 0xff, 0xfc, 0x47, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x44, 0xad, 0xbd, 0x04, 0x08,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -519,9 +846,13 @@ const _ = grpc.SupportPackageIsVersion4
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type SendAgentClient interface {
|
||||
Ready(ctx context.Context, in *ReadyInput, opts ...grpc.CallOption) (*ReadyOutput, error)
|
||||
Send(ctx context.Context, in *SendParams, opts ...grpc.CallOption) (*Empty, error)
|
||||
UpdateConfig(ctx context.Context, in *UpdateConfigParams, opts ...grpc.CallOption) (*Empty, error)
|
||||
ValidateConfig(ctx context.Context, in *UpdateConfigParams, opts ...grpc.CallOption) (*ValidateConfigReply, error)
|
||||
AddConfig(ctx context.Context, in *AddConfigInput, opts ...grpc.CallOption) (*Empty, error)
|
||||
CompleteConfig(ctx context.Context, in *CompleteConfigInput, opts ...grpc.CallOption) (*Empty, error)
|
||||
UpdateConfig(ctx context.Context, in *UpdateConfigInput, opts ...grpc.CallOption) (*Empty, error)
|
||||
DeleteConfig(ctx context.Context, in *DeleteConfigInput, opts ...grpc.CallOption) (*Empty, error)
|
||||
ValidateConfig(ctx context.Context, in *ValidateConfigInput, opts ...grpc.CallOption) (*ValidateConfigReply, error)
|
||||
UseridByMobile(ctx context.Context, in *UseridByMobileParams, opts ...grpc.CallOption) (*UseridByMobileReply, error)
|
||||
BatchSend(ctx context.Context, in *BatchSendParams, opts ...grpc.CallOption) (*BatchSendReply, error)
|
||||
}
|
||||
@@ -534,6 +865,15 @@ func NewSendAgentClient(cc *grpc.ClientConn) SendAgentClient {
|
||||
return &sendAgentClient{cc}
|
||||
}
|
||||
|
||||
func (c *sendAgentClient) Ready(ctx context.Context, in *ReadyInput, opts ...grpc.CallOption) (*ReadyOutput, error) {
|
||||
out := new(ReadyOutput)
|
||||
err := c.cc.Invoke(ctx, "/apis.SendAgent/Ready", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sendAgentClient) Send(ctx context.Context, in *SendParams, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/apis.SendAgent/Send", in, out, opts...)
|
||||
@@ -543,7 +883,25 @@ func (c *sendAgentClient) Send(ctx context.Context, in *SendParams, opts ...grpc
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sendAgentClient) UpdateConfig(ctx context.Context, in *UpdateConfigParams, opts ...grpc.CallOption) (*Empty, error) {
|
||||
func (c *sendAgentClient) AddConfig(ctx context.Context, in *AddConfigInput, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/apis.SendAgent/AddConfig", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sendAgentClient) CompleteConfig(ctx context.Context, in *CompleteConfigInput, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/apis.SendAgent/CompleteConfig", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sendAgentClient) UpdateConfig(ctx context.Context, in *UpdateConfigInput, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/apis.SendAgent/UpdateConfig", in, out, opts...)
|
||||
if err != nil {
|
||||
@@ -552,7 +910,16 @@ func (c *sendAgentClient) UpdateConfig(ctx context.Context, in *UpdateConfigPara
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sendAgentClient) ValidateConfig(ctx context.Context, in *UpdateConfigParams, opts ...grpc.CallOption) (*ValidateConfigReply, error) {
|
||||
func (c *sendAgentClient) DeleteConfig(ctx context.Context, in *DeleteConfigInput, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/apis.SendAgent/DeleteConfig", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sendAgentClient) ValidateConfig(ctx context.Context, in *ValidateConfigInput, opts ...grpc.CallOption) (*ValidateConfigReply, error) {
|
||||
out := new(ValidateConfigReply)
|
||||
err := c.cc.Invoke(ctx, "/apis.SendAgent/ValidateConfig", in, out, opts...)
|
||||
if err != nil {
|
||||
@@ -581,9 +948,13 @@ func (c *sendAgentClient) BatchSend(ctx context.Context, in *BatchSendParams, op
|
||||
|
||||
// SendAgentServer is the server API for SendAgent service.
|
||||
type SendAgentServer interface {
|
||||
Ready(context.Context, *ReadyInput) (*ReadyOutput, error)
|
||||
Send(context.Context, *SendParams) (*Empty, error)
|
||||
UpdateConfig(context.Context, *UpdateConfigParams) (*Empty, error)
|
||||
ValidateConfig(context.Context, *UpdateConfigParams) (*ValidateConfigReply, error)
|
||||
AddConfig(context.Context, *AddConfigInput) (*Empty, error)
|
||||
CompleteConfig(context.Context, *CompleteConfigInput) (*Empty, error)
|
||||
UpdateConfig(context.Context, *UpdateConfigInput) (*Empty, error)
|
||||
DeleteConfig(context.Context, *DeleteConfigInput) (*Empty, error)
|
||||
ValidateConfig(context.Context, *ValidateConfigInput) (*ValidateConfigReply, error)
|
||||
UseridByMobile(context.Context, *UseridByMobileParams) (*UseridByMobileReply, error)
|
||||
BatchSend(context.Context, *BatchSendParams) (*BatchSendReply, error)
|
||||
}
|
||||
@@ -592,13 +963,25 @@ type SendAgentServer interface {
|
||||
type UnimplementedSendAgentServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedSendAgentServer) Ready(ctx context.Context, req *ReadyInput) (*ReadyOutput, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Ready not implemented")
|
||||
}
|
||||
func (*UnimplementedSendAgentServer) Send(ctx context.Context, req *SendParams) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Send not implemented")
|
||||
}
|
||||
func (*UnimplementedSendAgentServer) UpdateConfig(ctx context.Context, req *UpdateConfigParams) (*Empty, error) {
|
||||
func (*UnimplementedSendAgentServer) AddConfig(ctx context.Context, req *AddConfigInput) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddConfig not implemented")
|
||||
}
|
||||
func (*UnimplementedSendAgentServer) CompleteConfig(ctx context.Context, req *CompleteConfigInput) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CompleteConfig not implemented")
|
||||
}
|
||||
func (*UnimplementedSendAgentServer) UpdateConfig(ctx context.Context, req *UpdateConfigInput) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateConfig not implemented")
|
||||
}
|
||||
func (*UnimplementedSendAgentServer) ValidateConfig(ctx context.Context, req *UpdateConfigParams) (*ValidateConfigReply, error) {
|
||||
func (*UnimplementedSendAgentServer) DeleteConfig(ctx context.Context, req *DeleteConfigInput) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteConfig not implemented")
|
||||
}
|
||||
func (*UnimplementedSendAgentServer) ValidateConfig(ctx context.Context, req *ValidateConfigInput) (*ValidateConfigReply, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ValidateConfig not implemented")
|
||||
}
|
||||
func (*UnimplementedSendAgentServer) UseridByMobile(ctx context.Context, req *UseridByMobileParams) (*UseridByMobileReply, error) {
|
||||
@@ -612,6 +995,24 @@ func RegisterSendAgentServer(s *grpc.Server, srv SendAgentServer) {
|
||||
s.RegisterService(&_SendAgent_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _SendAgent_Ready_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ReadyInput)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SendAgentServer).Ready(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/apis.SendAgent/Ready",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SendAgentServer).Ready(ctx, req.(*ReadyInput))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SendAgent_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SendParams)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -630,8 +1031,44 @@ func _SendAgent_Send_Handler(srv interface{}, ctx context.Context, dec func(inte
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SendAgent_AddConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AddConfigInput)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SendAgentServer).AddConfig(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/apis.SendAgent/AddConfig",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SendAgentServer).AddConfig(ctx, req.(*AddConfigInput))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SendAgent_CompleteConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CompleteConfigInput)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SendAgentServer).CompleteConfig(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/apis.SendAgent/CompleteConfig",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SendAgentServer).CompleteConfig(ctx, req.(*CompleteConfigInput))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SendAgent_UpdateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateConfigParams)
|
||||
in := new(UpdateConfigInput)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -643,13 +1080,31 @@ func _SendAgent_UpdateConfig_Handler(srv interface{}, ctx context.Context, dec f
|
||||
FullMethod: "/apis.SendAgent/UpdateConfig",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SendAgentServer).UpdateConfig(ctx, req.(*UpdateConfigParams))
|
||||
return srv.(SendAgentServer).UpdateConfig(ctx, req.(*UpdateConfigInput))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SendAgent_DeleteConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteConfigInput)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SendAgentServer).DeleteConfig(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/apis.SendAgent/DeleteConfig",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SendAgentServer).DeleteConfig(ctx, req.(*DeleteConfigInput))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SendAgent_ValidateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateConfigParams)
|
||||
in := new(ValidateConfigInput)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -661,7 +1116,7 @@ func _SendAgent_ValidateConfig_Handler(srv interface{}, ctx context.Context, dec
|
||||
FullMethod: "/apis.SendAgent/ValidateConfig",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SendAgentServer).ValidateConfig(ctx, req.(*UpdateConfigParams))
|
||||
return srv.(SendAgentServer).ValidateConfig(ctx, req.(*ValidateConfigInput))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
@@ -706,14 +1161,30 @@ var _SendAgent_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "apis.SendAgent",
|
||||
HandlerType: (*SendAgentServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Ready",
|
||||
Handler: _SendAgent_Ready_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Send",
|
||||
Handler: _SendAgent_Send_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "AddConfig",
|
||||
Handler: _SendAgent_AddConfig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CompleteConfig",
|
||||
Handler: _SendAgent_CompleteConfig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateConfig",
|
||||
Handler: _SendAgent_UpdateConfig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DeleteConfig",
|
||||
Handler: _SendAgent_DeleteConfig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ValidateConfig",
|
||||
Handler: _SendAgent_ValidateConfig_Handler,
|
||||
|
||||
@@ -17,7 +17,7 @@ syntax = "proto3";
|
||||
package apis;
|
||||
|
||||
message SendParams {
|
||||
string Contact = 1;
|
||||
SReceiver Receiver = 1;
|
||||
string Topic = 2;
|
||||
string Title = 3;
|
||||
string Message = 4;
|
||||
@@ -25,12 +25,31 @@ message SendParams {
|
||||
string RemoteTemplate = 6;
|
||||
}
|
||||
|
||||
message UpdateConfigParams {
|
||||
message ValidateConfigInput {
|
||||
map<string, string> configs = 1;
|
||||
}
|
||||
|
||||
message AddConfigInput {
|
||||
map<string, string> configs = 1;
|
||||
string domainId = 2;
|
||||
}
|
||||
|
||||
message UpdateConfigInput {
|
||||
map<string, string> configs = 1;
|
||||
string domainId = 2;
|
||||
}
|
||||
|
||||
message DeleteConfigInput {
|
||||
string domainId = 1;
|
||||
}
|
||||
|
||||
message CompleteConfigInput {
|
||||
repeated AddConfigInput ConfigInput = 1;
|
||||
}
|
||||
|
||||
message UseridByMobileParams {
|
||||
string mobile = 1;
|
||||
string domainId = 2;
|
||||
}
|
||||
|
||||
message Empty {
|
||||
@@ -45,8 +64,13 @@ message ValidateConfigReply {
|
||||
string msg = 2;
|
||||
}
|
||||
|
||||
message SReceiver {
|
||||
string Contact = 1;
|
||||
string DomainId = 2;
|
||||
}
|
||||
|
||||
message BatchSendParams {
|
||||
repeated string Contacts = 1;
|
||||
repeated SReceiver Receivers = 1;
|
||||
string Title = 2;
|
||||
string Message = 3;
|
||||
string Priority = 4;
|
||||
@@ -54,7 +78,7 @@ message BatchSendParams {
|
||||
}
|
||||
|
||||
message FailedRecord {
|
||||
string Contact = 1;
|
||||
SReceiver Receiver = 1;
|
||||
string Reason = 2;
|
||||
}
|
||||
|
||||
@@ -62,10 +86,23 @@ message BatchSendReply {
|
||||
repeated FailedRecord FailedRecords = 1;
|
||||
}
|
||||
|
||||
message ReadyInput {
|
||||
repeated string DomainIds = 1;
|
||||
}
|
||||
|
||||
message ReadyOutput {
|
||||
bool Ok = 1;
|
||||
}
|
||||
|
||||
service SendAgent {
|
||||
rpc Send(SendParams) returns (Empty);
|
||||
rpc UpdateConfig(UpdateConfigParams) returns (Empty);
|
||||
rpc ValidateConfig(UpdateConfigParams) returns (ValidateConfigReply);
|
||||
rpc UseridByMobile(UseridByMobileParams) returns (UseridByMobileReply);
|
||||
rpc Ready(ReadyInput) returns (ReadyOutput);
|
||||
rpc Send (SendParams) returns (Empty);
|
||||
rpc AddConfig (AddConfigInput) returns (Empty);
|
||||
rpc CompleteConfig (CompleteConfigInput) returns (Empty);
|
||||
rpc UpdateConfig (UpdateConfigInput) returns (Empty);
|
||||
rpc DeleteConfig (DeleteConfigInput) returns (Empty);
|
||||
rpc ValidateConfig (ValidateConfigInput) returns (ValidateConfigReply);
|
||||
rpc UseridByMobile (UseridByMobileParams) returns (UseridByMobileReply);
|
||||
rpc BatchSend (BatchSendParams) returns (BatchSendReply);
|
||||
}
|
||||
|
||||
|
||||
+199
-67
@@ -34,7 +34,6 @@ import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/notify"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
notifyv2 "yunion.io/x/onecloud/pkg/notify"
|
||||
"yunion.io/x/onecloud/pkg/notify/models"
|
||||
"yunion.io/x/onecloud/pkg/notify/rpc/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
)
|
||||
@@ -135,11 +134,57 @@ func (self *SRpcService) BatchSend(ctx context.Context, contactType string, args
|
||||
if len(args.RemoteTemplate) == 0 && contactType == api.MOBILE {
|
||||
return nil, fmt.Errorf("empty remote template for mobile type notification")
|
||||
}
|
||||
domainIds := make([]string, len(args.Receivers))
|
||||
for i := range domainIds {
|
||||
domainIds[i] = args.Receivers[i].DomainId
|
||||
}
|
||||
checks, err := self.configStore.BatchCheckConfig(contactType, domainIds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "BatchCheckConfig")
|
||||
}
|
||||
hasSystem, err := self.configStore.HasSystemConfig(contactType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "HasSystemConfig")
|
||||
}
|
||||
ret := make([]*apis.FailedRecord, 0)
|
||||
receiverIndex := 0
|
||||
for i := range checks {
|
||||
if checks[i] {
|
||||
receiverIndex++
|
||||
continue
|
||||
}
|
||||
if hasSystem {
|
||||
args.Receivers[receiverIndex].DomainId = ""
|
||||
receiverIndex++
|
||||
continue
|
||||
}
|
||||
ret = append(ret, &apis.FailedRecord{
|
||||
Receiver: args.Receivers[i],
|
||||
Reason: fmt.Sprintf("no %q config for in domain %q and system", contactType, domainIds[i]),
|
||||
})
|
||||
args.Receivers = append(args.Receivers[:receiverIndex], args.Receivers[receiverIndex+1:]...)
|
||||
}
|
||||
f := func(service *apis.SendNotificationClient) (interface{}, error) {
|
||||
// check ready
|
||||
domainIds := make([]string, len(args.Receivers))
|
||||
for i := range domainIds {
|
||||
domainIds[i] = args.Receivers[i].DomainId
|
||||
}
|
||||
output, err := service.Ready(ctx, &apis.ReadyInput{DomainIds: domainIds})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !output.Ok {
|
||||
// if NOINIT, try to restart server and send again
|
||||
service, err = self.restartService(ctx, contactType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "restart service %s failed", contactType)
|
||||
}
|
||||
}
|
||||
return service.BatchSend(ctx, &args)
|
||||
}
|
||||
|
||||
ret, err := self.execute(ctx, f, contactType)
|
||||
i, err := self.execute(ctx, f, contactType)
|
||||
if err != nil {
|
||||
s, ok := status.FromError(err)
|
||||
if !ok {
|
||||
@@ -147,29 +192,54 @@ func (self *SRpcService) BatchSend(ctx context.Context, contactType string, args
|
||||
}
|
||||
return nil, errors.Error(s.Message())
|
||||
}
|
||||
reply := ret.(*apis.BatchSendReply)
|
||||
return reply.FailedRecords, nil
|
||||
reply := i.(*apis.BatchSendReply)
|
||||
return append(ret, reply.FailedRecords...), nil
|
||||
}
|
||||
|
||||
// RestartService can restart remote rpc server and pass config info.
|
||||
// This function should be call immediately after init notify server firstly
|
||||
// This function should be call immediately after accept the request about changing config.
|
||||
func (self *SRpcService) RestartService(ctx context.Context, config notifyv2.SConfig, serviceName string) {
|
||||
_, err := self.restartWithConfig(ctx, serviceName, config)
|
||||
if err != nil {
|
||||
log.Debugf("restart service failed: %s", err)
|
||||
// UpdateConfig can update config for rpc service with domainId
|
||||
func (self *SRpcService) UpdateConfig(ctx context.Context, service string, config notifyv2.SConfig) error {
|
||||
var (
|
||||
sendService *apis.SendNotificationClient
|
||||
err error
|
||||
)
|
||||
|
||||
sendService, ok := self.SendServices.Get(service)
|
||||
if !ok {
|
||||
return fmt.Errorf("no such service %s", service)
|
||||
}
|
||||
|
||||
args := apis.UpdateConfigInput{
|
||||
Configs: config.Config,
|
||||
DomainId: config.DomainId,
|
||||
}
|
||||
_, err = sendService.UpdateConfig(ctx, &args)
|
||||
if err != nil {
|
||||
st := status.Convert(err)
|
||||
if st.Code() != codes.NotFound {
|
||||
return errors.Error(st.Message())
|
||||
}
|
||||
_, err = sendService.AddConfig(ctx, &apis.AddConfigInput{
|
||||
Configs: config.Config,
|
||||
DomainId: config.DomainId,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "try to add config but failed")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRpcService) ContactByMobile(ctx context.Context, mobile, serviceName string) (string, error) {
|
||||
func (self *SRpcService) ContactByMobile(ctx context.Context, mobile, serviceName string, domainId string) (string, error) {
|
||||
|
||||
iMobile := api.ParseInternationalMobile(mobile)
|
||||
// compatible
|
||||
if iMobile.AreaCode == "86" {
|
||||
mobile = iMobile.Mobile
|
||||
}
|
||||
args := apis.UseridByMobileParams{}
|
||||
args.Mobile = mobile
|
||||
args := apis.UseridByMobileParams{
|
||||
Mobile: mobile,
|
||||
DomainId: domainId,
|
||||
}
|
||||
|
||||
f := func(service *apis.SendNotificationClient) (interface{}, error) {
|
||||
return service.UseridByMobile(ctx, &args)
|
||||
@@ -246,40 +316,47 @@ func (self *SRpcService) execute(ctx context.Context, f func(client *apis.SendNo
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// restartSrevice fetch config from IServiceConfigStore and Call rpc.UpdateConfig
|
||||
func (self *SRpcService) restartService(ctx context.Context, serviceName string) (*apis.SendNotificationClient, error) {
|
||||
var ErrGetConfig = errors.Error("Get Config Failed")
|
||||
|
||||
config, err := self.configStore.GetConfig(serviceName)
|
||||
func (self *SRpcService) completeConfig(ctx context.Context, serviceName string, sendService *apis.SendNotificationClient) error {
|
||||
// get config
|
||||
configs, err := self.configStore.GetConfigs(serviceName)
|
||||
if err != nil {
|
||||
log.Debugf("getConfig of serveice %s from database error", serviceName)
|
||||
return nil, models.ErrGetConfig
|
||||
log.Errorf("getConfig of serveice %s from database error", serviceName)
|
||||
return ErrGetConfig
|
||||
}
|
||||
return self.restartWithConfig(ctx, serviceName, config)
|
||||
|
||||
// update config for service
|
||||
configInput := make([]*apis.AddConfigInput, len(configs))
|
||||
for i := range configInput {
|
||||
configInput[i] = &apis.AddConfigInput{
|
||||
Configs: configs[i].Config,
|
||||
DomainId: configs[i].DomainId,
|
||||
}
|
||||
}
|
||||
_, err = sendService.CompleteConfig(ctx, &apis.CompleteConfigInput{
|
||||
ConfigInput: configInput,
|
||||
})
|
||||
if err != nil {
|
||||
st := status.Convert(err)
|
||||
if st.Code() == codes.FailedPrecondition {
|
||||
// no such rpc serve
|
||||
err = fmt.Errorf(st.Message())
|
||||
}
|
||||
if st.Code() == codes.Unavailable {
|
||||
err = fmt.Errorf("service is unavailable for now: %s", st.Message())
|
||||
}
|
||||
return errors.Wrap(err, "UpdateConfig")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRpcService) restartWithConfig(ctx context.Context, serviceName string,
|
||||
config map[string]string) (*apis.SendNotificationClient, error) {
|
||||
|
||||
var (
|
||||
sendService *apis.SendNotificationClient
|
||||
err error
|
||||
)
|
||||
|
||||
sendService, ok := self.SendServices.Get(serviceName)
|
||||
|
||||
func (self *SRpcService) restartService(ctx context.Context, service string) (*apis.SendNotificationClient, error) {
|
||||
sendService, ok := self.SendServices.Get(service)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no such service, please start new service")
|
||||
}
|
||||
|
||||
args := apis.UpdateConfigParams{}
|
||||
args.Configs = config
|
||||
_, err = sendService.UpdateConfig(ctx, &args)
|
||||
if err != nil {
|
||||
st := status.Convert(err)
|
||||
return nil, errors.Error(st.Message())
|
||||
}
|
||||
|
||||
return sendService, nil
|
||||
return sendService, self.completeConfig(ctx, service, sendService)
|
||||
}
|
||||
|
||||
// startNewService try to start a new rpc service named serviceName
|
||||
@@ -308,30 +385,7 @@ func (self *SRpcService) startNewService(ctx context.Context, serviceName string
|
||||
return sendService, nil
|
||||
}
|
||||
|
||||
// get config
|
||||
config, err := self.configStore.GetConfig(serviceName)
|
||||
if err != nil {
|
||||
log.Errorf("getConfig of serveice %s from database error", serviceName)
|
||||
return nil, models.ErrGetConfig
|
||||
}
|
||||
|
||||
// update config for service
|
||||
args := apis.UpdateConfigParams{}
|
||||
args.Configs = config
|
||||
_, err = sendService.UpdateConfig(ctx, &args)
|
||||
if err != nil {
|
||||
st := status.Convert(err)
|
||||
if st.Code() == codes.FailedPrecondition {
|
||||
// no such rpc serve
|
||||
err = fmt.Errorf(st.Message())
|
||||
}
|
||||
if st.Code() == codes.Unavailable {
|
||||
err = fmt.Errorf("service is unavailable for now: %s", st.Message())
|
||||
}
|
||||
return nil, errors.Wrap(err, "UpdateConfig")
|
||||
}
|
||||
|
||||
return sendService, nil
|
||||
return sendService, self.completeConfig(ctx, serviceName, sendService)
|
||||
}
|
||||
|
||||
// closeService will remove service record from self.SendServices and try to remove sock file
|
||||
@@ -374,8 +428,48 @@ func (self *SRpcService) updateService(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRpcService) ValidateConfig(ctx context.Context, cType string, configs map[string]string) (isValid bool,
|
||||
message string, err error) {
|
||||
func (self *SRpcService) AddConfig(ctx context.Context, service string, config notifyv2.SConfig) error {
|
||||
var (
|
||||
sendService *apis.SendNotificationClient
|
||||
err error
|
||||
)
|
||||
|
||||
sendService, ok := self.SendServices.Get(service)
|
||||
if !ok {
|
||||
return fmt.Errorf("no such service %s", service)
|
||||
}
|
||||
args := apis.AddConfigInput{
|
||||
DomainId: config.DomainId,
|
||||
Configs: config.Config,
|
||||
}
|
||||
_, err = sendService.AddConfig(ctx, &args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRpcService) DeleteConfig(ctx context.Context, service, domainId string) error {
|
||||
var (
|
||||
sendService *apis.SendNotificationClient
|
||||
err error
|
||||
)
|
||||
|
||||
sendService, ok := self.SendServices.Get(service)
|
||||
if !ok {
|
||||
return fmt.Errorf("no such service %s", service)
|
||||
}
|
||||
args := apis.DeleteConfigInput{
|
||||
DomainId: domainId,
|
||||
}
|
||||
_, err = sendService.DeleteConfig(ctx, &args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRpcService) ValidateConfig(ctx context.Context, cType string, configs map[string]string) (isValid bool, message string, err error) {
|
||||
|
||||
sendService, ok := self.SendServices.Get(cType)
|
||||
|
||||
@@ -389,7 +483,7 @@ func (self *SRpcService) ValidateConfig(ctx context.Context, cType string, confi
|
||||
return
|
||||
}
|
||||
}
|
||||
param := apis.UpdateConfigParams{
|
||||
param := apis.ValidateConfigInput{
|
||||
Configs: configs,
|
||||
}
|
||||
rep, err := sendService.ValidateConfig(ctx, ¶m)
|
||||
@@ -405,6 +499,44 @@ func (self *SRpcService) ValidateConfig(ctx context.Context, cType string, confi
|
||||
return rep.IsValid, rep.Msg, nil
|
||||
}
|
||||
|
||||
func robotType2ContactType(rType string) string {
|
||||
switch rType {
|
||||
case api.ROBOT_TYPE_FEISHU:
|
||||
return api.FEISHU_ROBOT
|
||||
case api.ROBOT_TYPE_DINGTALK:
|
||||
return api.DINGTALK_ROBOT
|
||||
case api.ROBOT_TYPE_WORKWX:
|
||||
return api.DINGTALK_ROBOT
|
||||
case api.ROBOT_TYPE_WEBHOOK:
|
||||
return api.WEBHOOK
|
||||
}
|
||||
return rType
|
||||
}
|
||||
|
||||
func (self *SRpcService) SendRobotMessage(ctx context.Context, rType string, receivers []*apis.SReceiver, title string, message string) ([]*apis.FailedRecord, error) {
|
||||
log.Infof("rType: %s", rType)
|
||||
contactType := robotType2ContactType(rType)
|
||||
args := apis.BatchSendParams{
|
||||
Receivers: receivers,
|
||||
Title: title,
|
||||
Message: message,
|
||||
}
|
||||
f := func(service *apis.SendNotificationClient) (interface{}, error) {
|
||||
return service.BatchSend(ctx, &args)
|
||||
}
|
||||
|
||||
ret, err := self.execute(ctx, f, contactType)
|
||||
if err != nil {
|
||||
s, ok := status.FromError(err)
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errors.Error(s.Message())
|
||||
}
|
||||
reply := ret.(*apis.BatchSendReply)
|
||||
return reply.FailedRecords, nil
|
||||
}
|
||||
|
||||
func grpcDialWithUnixSocket(ctx context.Context, socketPath string) (*grpc.ClientConn, error) {
|
||||
return grpc.DialContext(ctx, socketPath, grpc.WithInsecure(), grpc.WithTimeout(time.Second*5), grpc.WithDialer(
|
||||
func(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
|
||||
@@ -37,6 +37,7 @@ func InitHandlers(app *appsrv.Application) {
|
||||
db.TenantCacheManager,
|
||||
db.RoleCacheManager,
|
||||
models.SubContactManager,
|
||||
db.SharedResourceManager,
|
||||
models.VerificationManager,
|
||||
models.SubscriptionReceiverManager,
|
||||
} {
|
||||
@@ -51,6 +52,7 @@ func InitHandlers(app *appsrv.Application) {
|
||||
models.ConfigManager,
|
||||
models.TemplateManager,
|
||||
models.SubscriptionManager,
|
||||
models.RobotManager,
|
||||
} {
|
||||
db.RegisterModelManager(manager)
|
||||
handler := db.NewModelHandler(manager)
|
||||
|
||||
@@ -37,6 +37,16 @@ func (self *NotificationSendTask) taskFailed(ctx context.Context, notification *
|
||||
self.SetStageFailed(ctx, jsonutils.NewString(reason))
|
||||
}
|
||||
|
||||
type DomainContact struct {
|
||||
DomainId string
|
||||
Contact string
|
||||
}
|
||||
|
||||
type ReceiverSpec struct {
|
||||
receiver models.IReceiver
|
||||
rNotificaion *models.SReceiverNotification
|
||||
}
|
||||
|
||||
func (self *NotificationSendTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
|
||||
notification := obj.(*models.SNotification)
|
||||
if notification.Status == apis.NOTIFICATION_STATUS_OK {
|
||||
@@ -50,20 +60,6 @@ func (self *NotificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
|
||||
}
|
||||
notification.SetStatus(self.UserCred, apis.NOTIFICATION_STATUS_SENDING, "")
|
||||
|
||||
// split rns
|
||||
var (
|
||||
rnsWithReceiver []*models.SReceiverNotification
|
||||
rnsWithoutReceiver []*models.SReceiverNotification
|
||||
)
|
||||
|
||||
for i := range rns {
|
||||
if rns[i].ReceiverID == models.ReceiverIdDefault {
|
||||
rnsWithoutReceiver = append(rnsWithoutReceiver, &rns[i])
|
||||
} else {
|
||||
rnsWithReceiver = append(rnsWithReceiver, &rns[i])
|
||||
}
|
||||
}
|
||||
|
||||
failedRecord := make([]string, 0)
|
||||
sendFail := func(rn *models.SReceiverNotification, reason string) {
|
||||
rn.AfterSend(ctx, false, reason)
|
||||
@@ -71,79 +67,80 @@ 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]
|
||||
continue
|
||||
}
|
||||
receiver, err := rnsWithReceiver[i].Receiver()
|
||||
receivers := make([]ReceiverSpec, 0, 0)
|
||||
receiversEn := make([]ReceiverSpec, 0, len(rns)/2)
|
||||
receiversCn := make([]ReceiverSpec, 0, len(rns)/2)
|
||||
for i := range rns {
|
||||
receiver, err := rns[i].Receiver()
|
||||
if err != nil {
|
||||
sendFail(rnsWithReceiver[i], fmt.Sprintf("fail to fetch Receiver: %s", err.Error()))
|
||||
sendFail(&rns[i], fmt.Sprintf("fail to fetch Receiver: %s", err.Error()))
|
||||
continue
|
||||
}
|
||||
// check receiver enabled
|
||||
if receiver.Enabled.IsFalse() {
|
||||
sendFail(rnsWithReceiver[i], fmt.Sprintf("disabled receiver"))
|
||||
if !receiver.IsEnabled() {
|
||||
sendFail(&rns[i], fmt.Sprintf("disabled receiver"))
|
||||
continue
|
||||
}
|
||||
// check contact enabled
|
||||
enabled, err := receiver.IsEnabledContactType(notification.ContactType)
|
||||
if err != nil {
|
||||
sendFail(rnsWithReceiver[i], fmt.Sprintf("IsEnabledContactType error for receiver: %s", err.Error()))
|
||||
sendFail(&rns[i], fmt.Sprintf("IsEnabledContactType error for receiver: %s", err.Error()))
|
||||
continue
|
||||
}
|
||||
if !enabled {
|
||||
sendFail(rnsWithReceiver[i], fmt.Sprintf("disabled contactType %q", notification.ContactType))
|
||||
sendFail(&rns[i], fmt.Sprintf("disabled contactType %q", notification.ContactType))
|
||||
continue
|
||||
}
|
||||
|
||||
// check contact verified
|
||||
verified, err := receiver.IsVerifiedContactType(notification.ContactType)
|
||||
if err != nil {
|
||||
sendFail(rnsWithReceiver[i], fmt.Sprintf("IsVerifiedContactType error for receiver: %s", err.Error()))
|
||||
sendFail(&rns[i], fmt.Sprintf("IsVerifiedContactType error for receiver: %s", err.Error()))
|
||||
continue
|
||||
}
|
||||
if !verified {
|
||||
sendFail(rnsWithReceiver[i], fmt.Sprintf("unverified contactType %q", notification.ContactType))
|
||||
sendFail(&rns[i], fmt.Sprintf("unverified contactType %q", notification.ContactType))
|
||||
continue
|
||||
}
|
||||
|
||||
contact, err := receiver.GetContact(notification.ContactType)
|
||||
if err != nil {
|
||||
reason := fmt.Sprintf("fail to fetch contact: %s", err.Error())
|
||||
sendFail(rnsWithReceiver[i], reason)
|
||||
continue
|
||||
}
|
||||
// contact, err := receiver.GetContact(notification.ContactType)
|
||||
// if err != nil {
|
||||
// reason := fmt.Sprintf("fail to fetch contact: %s", err.Error())
|
||||
// sendFail(&rns[i], reason)
|
||||
// continue
|
||||
// }
|
||||
lang, err := receiver.GetTemplateLang(ctx)
|
||||
if err != nil {
|
||||
reason := fmt.Sprintf("fail to GetTemplateLang: %s", err.Error())
|
||||
sendFail(rnsWithReceiver[i], reason)
|
||||
sendFail(&rns[i], reason)
|
||||
continue
|
||||
}
|
||||
switch lang {
|
||||
case "":
|
||||
contactMap[contact] = rnsWithReceiver[i]
|
||||
receivers = append(receivers, ReceiverSpec{
|
||||
receiver: receiver,
|
||||
rNotificaion: &rns[i],
|
||||
})
|
||||
case apis.TEMPLATE_LANG_EN:
|
||||
contactMapEn[contact] = rnsWithReceiver[i]
|
||||
receiversEn = append(receiversEn, ReceiverSpec{
|
||||
receiver: receiver,
|
||||
rNotificaion: &rns[i],
|
||||
})
|
||||
case apis.TEMPLATE_LANG_CN:
|
||||
contactmapCn[contact] = rnsWithReceiver[i]
|
||||
receiversCn = append(receiversCn, ReceiverSpec{
|
||||
receiver: receiver,
|
||||
rNotificaion: &rns[i],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for i := range rnsWithoutReceiver {
|
||||
contactMap[rnsWithoutReceiver[i].Contact] = rnsWithoutReceiver[i]
|
||||
}
|
||||
|
||||
var contactLen int
|
||||
for lang, contactMap := range map[string]map[string]*models.SReceiverNotification{
|
||||
"": contactMap,
|
||||
apis.TEMPLATE_LANG_CN: contactmapCn,
|
||||
apis.TEMPLATE_LANG_EN: contactMapEn,
|
||||
for lang, receivers := range map[string][]ReceiverSpec{
|
||||
"": receivers,
|
||||
apis.TEMPLATE_LANG_CN: receiversCn,
|
||||
apis.TEMPLATE_LANG_EN: receiversEn,
|
||||
} {
|
||||
if len(contactMap) == 0 {
|
||||
if len(receivers) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -154,40 +151,35 @@ func (self *NotificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
|
||||
}
|
||||
// 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)
|
||||
for _, rn := range receivers {
|
||||
rn.rNotificaion.BeforeSend(ctx, now)
|
||||
}
|
||||
|
||||
contactLen += len(contacts)
|
||||
contactLen += len(receivers)
|
||||
|
||||
// send
|
||||
fds, err := models.NotifyService.BatchSend(ctx, notification.ContactType, rpcapi.BatchSendParams{
|
||||
Contacts: contacts,
|
||||
Title: p.Title,
|
||||
Message: p.Message,
|
||||
Priority: p.Priority,
|
||||
RemoteTemplate: p.RemoteTemplate,
|
||||
})
|
||||
fds, err := self.batchSend(ctx, notification.ContactType, receivers, p)
|
||||
if err != nil {
|
||||
for _, rn := range contactMap {
|
||||
sendFail(rn, err.Error())
|
||||
for _, r := range receivers {
|
||||
sendFail(r.rNotificaion, err.Error())
|
||||
}
|
||||
continue
|
||||
}
|
||||
// check result
|
||||
failedRnIds := make(map[int64]struct{}, 0)
|
||||
for _, fd := range fds {
|
||||
rn := contactMap[fd.Contact]
|
||||
sendFail(rn, fd.Reason)
|
||||
delete(contactMap, fd.Contact)
|
||||
sendFail(fd.rNotificaion, fd.Reason)
|
||||
failedRnIds[fd.rNotificaion.RowId] = struct{}{}
|
||||
}
|
||||
// after send for successful notify
|
||||
for _, rn := range contactMap {
|
||||
rn.AfterSend(ctx, true, "")
|
||||
for _, r := range receivers {
|
||||
if _, ok := failedRnIds[r.rNotificaion.RowId]; ok {
|
||||
continue
|
||||
}
|
||||
r.rNotificaion.AfterSend(ctx, true, "")
|
||||
}
|
||||
}
|
||||
if len(failedRecord) > 0 && len(failedRecord) == contactLen {
|
||||
if len(failedRecord) > 0 && len(failedRecord) >= len(rns) {
|
||||
self.taskFailed(ctx, notification, strings.Join(failedRecord, "; "), true)
|
||||
return
|
||||
}
|
||||
@@ -199,3 +191,83 @@ func (self *NotificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
|
||||
logclient.AddActionLogWithContext(ctx, notification, logclient.ACT_SEND_NOTIFICATION, "", self.UserCred, true)
|
||||
self.SetStageComplete(ctx, nil)
|
||||
}
|
||||
|
||||
type FailedReceiverSpec struct {
|
||||
ReceiverSpec
|
||||
Reason string
|
||||
}
|
||||
|
||||
func (self *NotificationSendTask) batchSend(ctx context.Context, contactType string, receivers []ReceiverSpec, params rpcapi.SendParams) (fails []FailedReceiverSpec, err error) {
|
||||
log.Infof("contactType: %s, receivers: %s, params: %s", contactType, receivers, jsonutils.Marshal(params))
|
||||
if contactType != apis.ROBOT {
|
||||
return self._batchSend(ctx, contactType, receivers, func(res []*rpcapi.SReceiver) ([]*rpcapi.FailedRecord, error) {
|
||||
return models.NotifyService.BatchSend(ctx, contactType, rpcapi.BatchSendParams{
|
||||
Receivers: res,
|
||||
Title: params.Title,
|
||||
Message: params.Message,
|
||||
Priority: params.Priority,
|
||||
RemoteTemplate: params.RemoteTemplate,
|
||||
})
|
||||
})
|
||||
}
|
||||
robots := make(map[string][]ReceiverSpec)
|
||||
for i := range receivers {
|
||||
robot := receivers[i].receiver.(*models.SRobot)
|
||||
robots[robot.Type] = append(robots[robot.Type], receivers[i])
|
||||
}
|
||||
for rType, robots := range robots {
|
||||
_fails, err := self._batchSend(ctx, contactType, robots, func(res []*rpcapi.SReceiver) ([]*rpcapi.FailedRecord, error) {
|
||||
return models.NotifyService.SendRobotMessage(ctx, rType, res, params.Title, params.Message)
|
||||
})
|
||||
if err != nil {
|
||||
for i := range robots {
|
||||
fails = append(fails, FailedReceiverSpec{
|
||||
ReceiverSpec: robots[i],
|
||||
Reason: err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
fails = append(fails, _fails...)
|
||||
}
|
||||
return fails, nil
|
||||
}
|
||||
|
||||
func (self *NotificationSendTask) _batchSend(ctx context.Context, contactType string, receivers []ReceiverSpec, send func([]*rpcapi.SReceiver) ([]*rpcapi.FailedRecord, error)) (fails []FailedReceiverSpec, err error) {
|
||||
rpcReceivers := make([]*rpcapi.SReceiver, len(receivers))
|
||||
rpc2Receiver := make(map[DomainContact]ReceiverSpec, len(receivers))
|
||||
for i := range receivers {
|
||||
contact, err := receivers[i].receiver.GetContact(contactType)
|
||||
if err != nil {
|
||||
fails = append(fails, FailedReceiverSpec{
|
||||
ReceiverSpec: receivers[i],
|
||||
Reason: fmt.Sprintf("fail to fetch contact: %s", err.Error()),
|
||||
})
|
||||
continue
|
||||
}
|
||||
rpcReceivers[i] = &rpcapi.SReceiver{
|
||||
DomainId: receivers[i].receiver.GetDomainId(),
|
||||
Contact: contact,
|
||||
}
|
||||
rpc2Receiver[DomainContact{
|
||||
DomainId: receivers[i].receiver.GetDomainId(),
|
||||
Contact: contact,
|
||||
}] = receivers[i]
|
||||
}
|
||||
fds, err := send(rpcReceivers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// check result
|
||||
for _, fd := range fds {
|
||||
dc := DomainContact{
|
||||
DomainId: fd.Receiver.DomainId,
|
||||
Contact: fd.Receiver.Contact,
|
||||
}
|
||||
receiver := rpc2Receiver[dc]
|
||||
fails = append(fails, FailedReceiverSpec{
|
||||
ReceiverSpec: receiver,
|
||||
Reason: fd.Reason,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/notify/models"
|
||||
"yunion.io/x/onecloud/pkg/apis/notify"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
@@ -61,6 +62,13 @@ func (self *RepullSuncontactTask) OnInit(ctx context.Context, obj db.IStandalone
|
||||
}
|
||||
subq := models.SubContactManager.Query("receiver_id").Equals("type", config.Type).SubQuery()
|
||||
q := models.ReceiverManager.Query()
|
||||
if config.Attribution == notify.CONFIG_ATTRIBUTION_DOMAIN {
|
||||
q = q.Equals("domain_id", config.DomainId)
|
||||
} else {
|
||||
// The system-level config update should not affect the receiver under the domain with config
|
||||
configq := models.ConfigManager.Query("domain_id").Equals("attribution", notify.CONFIG_ATTRIBUTION_DOMAIN).SubQuery()
|
||||
q = q.Join(configq, sqlchemy.NotEquals(q.Field("domain_id"), configq.Field("domain_id")))
|
||||
}
|
||||
q.Join(subq, sqlchemy.Equals(q.Field("id"), subq.Field("receiver_id")))
|
||||
rs := make([]models.SReceiver, 0)
|
||||
err := db.FetchModelObjects(models.ReceiverManager, q, &rs)
|
||||
|
||||
@@ -72,7 +72,7 @@ func (self *SubcontactPullTask) OnInit(ctx context.Context, obj db.IStandaloneMo
|
||||
if !utils.IsInStringArray(cType, PullContactType) {
|
||||
continue
|
||||
}
|
||||
userid, err := models.NotifyService.ContactByMobile(ctx, receiver.Mobile, cType)
|
||||
userid, err := models.NotifyService.ContactByMobile(ctx, receiver.Mobile, cType, receiver.GetDomainId())
|
||||
if err != nil {
|
||||
var reason string
|
||||
if errors.Cause(err) == notify.ErrNoSuchMobile {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
notifyv2 "yunion.io/x/onecloud/pkg/notify"
|
||||
"yunion.io/x/onecloud/pkg/notify/models"
|
||||
"yunion.io/x/onecloud/pkg/notify/rpc/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
@@ -81,7 +82,10 @@ func (self *VerificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
|
||||
self.taskFailed(ctx, receiver, err.Error())
|
||||
return
|
||||
}
|
||||
param.Contact = contact
|
||||
param.Receiver = &apis.SReceiver{
|
||||
Contact: contact,
|
||||
DomainId: receiver.DomainId,
|
||||
}
|
||||
err = models.NotifyService.Send(ctx, contactType, param)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, receiver, err.Error())
|
||||
|
||||
Reference in New Issue
Block a user