github.com/argoproj/argo-events@v1.9.1/sensors/triggers/slack/slack.go (about) 1 /* 2 Copyright 2020 BlackRock, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 package slack 17 18 import ( 19 "context" 20 "encoding/json" 21 "fmt" 22 "net/http" 23 "strings" 24 25 notifications "github.com/argoproj/notifications-engine/pkg/services" 26 "go.uber.org/zap" 27 28 "github.com/argoproj/argo-events/common" 29 "github.com/argoproj/argo-events/common/logging" 30 apicommon "github.com/argoproj/argo-events/pkg/apis/common" 31 "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1" 32 "github.com/argoproj/argo-events/sensors/triggers" 33 ) 34 35 type SlackTrigger struct { 36 // Sensor refer to the sensor object 37 Sensor *v1alpha1.Sensor 38 // Trigger refers to the trigger resource 39 Trigger *v1alpha1.Trigger 40 // Logger to log stuff 41 Logger *zap.SugaredLogger 42 // http client to invoke function. 43 httpClient *http.Client 44 // slackSvc refers to the Slack notification service. 45 slackSvc notifications.NotificationService 46 } 47 48 // NewSlackTrigger returns a new Slack trigger context 49 func NewSlackTrigger(sensor *v1alpha1.Sensor, trigger *v1alpha1.Trigger, logger *zap.SugaredLogger, httpClient *http.Client) (*SlackTrigger, error) { 50 slackTrigger := trigger.Template.Slack 51 slackToken, err := common.GetSecretFromVolume(slackTrigger.SlackToken) 52 if err != nil { 53 return nil, fmt.Errorf("failed to retrieve the slack token, %w", err) 54 } 55 56 slackSvc := notifications.NewSlackService(notifications.SlackOptions{ 57 Token: slackToken, 58 Username: slackTrigger.Sender.Username, 59 Icon: slackTrigger.Sender.Icon, 60 }) 61 62 return &SlackTrigger{ 63 Sensor: sensor, 64 Trigger: trigger, 65 Logger: logger.With(logging.LabelTriggerType, apicommon.SlackTrigger), 66 httpClient: httpClient, 67 slackSvc: slackSvc, 68 }, nil 69 } 70 71 // GetTriggerType returns the type of the trigger 72 func (t *SlackTrigger) GetTriggerType() apicommon.TriggerType { 73 return apicommon.SlackTrigger 74 } 75 76 func (t *SlackTrigger) FetchResource(ctx context.Context) (interface{}, error) { 77 return t.Trigger.Template.Slack, nil 78 } 79 80 func (t *SlackTrigger) ApplyResourceParameters(events map[string]*v1alpha1.Event, resource interface{}) (interface{}, error) { 81 resourceBytes, err := json.Marshal(resource) 82 if err != nil { 83 return nil, fmt.Errorf("failed to marshal the Slack trigger resource, %w", err) 84 } 85 parameters := t.Trigger.Template.Slack.Parameters 86 87 if parameters != nil { 88 updatedResourceBytes, err := triggers.ApplyParams(resourceBytes, t.Trigger.Template.Slack.Parameters, events) 89 if err != nil { 90 return nil, err 91 } 92 93 var st *v1alpha1.SlackTrigger 94 if err := json.Unmarshal(updatedResourceBytes, &st); err != nil { 95 return nil, fmt.Errorf("failed to unmarshal the updated Slack trigger resource after applying resource parameters, %w", err) 96 } 97 98 return st, nil 99 } 100 101 return resource, nil 102 } 103 104 // Execute executes the trigger 105 func (t *SlackTrigger) Execute(ctx context.Context, events map[string]*v1alpha1.Event, resource interface{}) (interface{}, error) { 106 t.Logger.Info("executing SlackTrigger") 107 _, ok := resource.(*v1alpha1.SlackTrigger) 108 if !ok { 109 return nil, fmt.Errorf("failed to marshal the Slack trigger resource") 110 } 111 112 slackTrigger := t.Trigger.Template.Slack 113 114 channel := slackTrigger.Channel 115 if channel == "" { 116 return nil, fmt.Errorf("no slack channel provided") 117 } 118 channel = strings.TrimPrefix(channel, "#") 119 120 message := slackTrigger.Message 121 attachments := slackTrigger.Attachments 122 blocks := slackTrigger.Blocks 123 if message == "" && attachments == "" && blocks == "" { 124 return nil, fmt.Errorf("no text to post: At least one of message/attachments/blocks should be provided") 125 } 126 127 t.Logger.Infow("posting to channel...", zap.Any("channelName", channel)) 128 129 notification := notifications.Notification{ 130 Message: message, 131 Slack: ¬ifications.SlackNotification{ 132 GroupingKey: slackTrigger.Thread.MessageAggregationKey, 133 NotifyBroadcast: slackTrigger.Thread.BroadcastMessageToChannel, 134 Blocks: blocks, 135 Attachments: attachments, 136 }, 137 } 138 destination := notifications.Destination{ 139 Service: "slack", 140 Recipient: channel, 141 } 142 err := t.slackSvc.Send(notification, destination) 143 if err != nil { 144 t.Logger.Errorw("unable to post to channel", zap.Any("channelName", channel), zap.Error(err)) 145 return nil, fmt.Errorf("failed to post to channel %s, %w", channel, err) 146 } 147 148 t.Logger.Infow("message successfully sent to channel", zap.Any("message", message), zap.Any("channelName", channel)) 149 t.Logger.Info("finished executing SlackTrigger") 150 return nil, nil 151 } 152 153 // No Policies for SlackTrigger 154 func (t *SlackTrigger) ApplyPolicy(ctx context.Context, resource interface{}) error { 155 return nil 156 }