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: &notifications.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  }