diff --git a/mattermost-plugin/server/notifications.go b/mattermost-plugin/server/notifications.go index 93e8c8722..4c300fb30 100644 --- a/mattermost-plugin/server/notifications.go +++ b/mattermost-plugin/server/notifications.go @@ -121,3 +121,7 @@ func (da *pluginAPIAdapter) GetChannelByID(channelID string) (*model.Channel, er func (da *pluginAPIAdapter) GetChannelMember(channelID string, userID string) (*model.ChannelMember, error) { return da.client.Channel.GetMember(channelID, userID) } + +func (da *pluginAPIAdapter) CreateMember(teamID string, userID string) (*model.TeamMember, error) { + return da.client.Team.CreateMember(teamID, userID) +} diff --git a/server/services/notify/notifysubscriptions/delivery.go b/server/services/notify/notifysubscriptions/delivery.go index cab2688f3..17e63c896 100644 --- a/server/services/notify/notifysubscriptions/delivery.go +++ b/server/services/notify/notifysubscriptions/delivery.go @@ -12,6 +12,6 @@ import ( // SubscriptionDelivery provides an interface for delivering subscription notifications to other systems, such as // channels server via plugin API. type SubscriptionDelivery interface { - SubscriptionDeliverSlackAttachments(subscriberID string, subscriberType model.SubscriberType, + SubscriptionDeliverSlackAttachments(teamID string, subscriberID string, subscriberType model.SubscriberType, attachments []*mm_model.SlackAttachment) error } diff --git a/server/services/notify/notifysubscriptions/notifier.go b/server/services/notify/notifysubscriptions/notifier.go index 61dd3474e..ee7faa938 100644 --- a/server/services/notify/notifysubscriptions/notifier.go +++ b/server/services/notify/notifysubscriptions/notifier.go @@ -243,7 +243,7 @@ func (n *notifier) notifySubscribers(hint *model.NotificationHint) error { mlog.String("subscriber_type", string(sub.SubscriberType)), ) - if err = n.delivery.SubscriptionDeliverSlackAttachments(sub.SubscriberID, sub.SubscriberType, attachments); err != nil { + if err = n.delivery.SubscriptionDeliverSlackAttachments(board.TeamID, sub.SubscriberID, sub.SubscriberType, attachments); err != nil { merr.Append(fmt.Errorf("cannot deliver notification to subscriber %s [%s]: %w", sub.SubscriberID, sub.SubscriberType, err)) } diff --git a/server/services/notify/plugindelivery/mention_deliver.go b/server/services/notify/plugindelivery/mention_deliver.go index 6a3089f24..4cb48a619 100644 --- a/server/services/notify/plugindelivery/mention_deliver.go +++ b/server/services/notify/plugindelivery/mention_deliver.go @@ -19,7 +19,7 @@ func (pd *PluginDelivery) MentionDeliver(mentionedUser *mm_model.User, extract s return "", fmt.Errorf("cannot find user: %w", err) } - channel, err := pd.api.GetDirectChannel(mentionedUser.Id, pd.botID) + channel, err := pd.getDirectChannel(evt.TeamID, mentionedUser.Id, pd.botID) if err != nil { return "", fmt.Errorf("cannot get direct channel: %w", err) } diff --git a/server/services/notify/plugindelivery/plugin_delivery.go b/server/services/notify/plugindelivery/plugin_delivery.go index 9af59306d..a7ee34aba 100644 --- a/server/services/notify/plugindelivery/plugin_delivery.go +++ b/server/services/notify/plugindelivery/plugin_delivery.go @@ -29,6 +29,10 @@ type PluginAPI interface { // GetChannelMember gets a channel member by userID. GetChannelMember(channelID string, userID string) (*mm_model.ChannelMember, error) + + // CreateMember adds a user to the specified team. Safe to call if the user is + // already a member of the team. + CreateMember(teamID string, userID string) (*mm_model.TeamMember, error) } // PluginDelivery provides ability to send notifications to direct message channels via Mattermost plugin API. @@ -38,6 +42,7 @@ type PluginDelivery struct { api PluginAPI } +// New creates a PluginDelivery instance. func New(botID string, serverRoot string, api PluginAPI) *PluginDelivery { return &PluginDelivery{ botID: botID, diff --git a/server/services/notify/plugindelivery/subscription_deliver.go b/server/services/notify/plugindelivery/subscription_deliver.go index a8cfda413..b916a6690 100644 --- a/server/services/notify/plugindelivery/subscription_deliver.go +++ b/server/services/notify/plugindelivery/subscription_deliver.go @@ -17,7 +17,7 @@ var ( ) // SubscriptionDeliverSlashAttachments notifies a user that changes were made to a block they are subscribed to. -func (pd *PluginDelivery) SubscriptionDeliverSlackAttachments(subscriberID string, subscriptionType model.SubscriberType, +func (pd *PluginDelivery) SubscriptionDeliverSlackAttachments(teamID string, subscriberID string, subscriptionType model.SubscriberType, attachments []*mm_model.SlackAttachment) error { // check subscriber is member of channel _, err := pd.api.GetUserByID(subscriberID) @@ -29,7 +29,7 @@ func (pd *PluginDelivery) SubscriptionDeliverSlackAttachments(subscriberID strin return fmt.Errorf("cannot fetch channel member for user %s: %w", subscriberID, err) } - channelID, err := pd.getDirectChannelID(subscriberID, subscriptionType, pd.botID) + channelID, err := pd.getDirectChannelID(teamID, subscriberID, subscriptionType, pd.botID) if err != nil { return err } @@ -44,14 +44,14 @@ func (pd *PluginDelivery) SubscriptionDeliverSlackAttachments(subscriberID strin return pd.api.CreatePost(post) } -func (pd *PluginDelivery) getDirectChannelID(subscriberID string, subscriberType model.SubscriberType, botID string) (string, error) { +func (pd *PluginDelivery) getDirectChannelID(teamID string, subscriberID string, subscriberType model.SubscriberType, botID string) (string, error) { switch subscriberType { case model.SubTypeUser: user, err := pd.api.GetUserByID(subscriberID) if err != nil { return "", fmt.Errorf("cannot find user: %w", err) } - channel, err := pd.api.GetDirectChannel(user.Id, botID) + channel, err := pd.getDirectChannel(teamID, user.Id, botID) if err != nil { return "", fmt.Errorf("cannot get direct channel: %w", err) } @@ -62,3 +62,12 @@ func (pd *PluginDelivery) getDirectChannelID(subscriberID string, subscriberType return "", ErrUnsupportedSubscriberType } } + +func (pd *PluginDelivery) getDirectChannel(teamID string, userID string, botID string) (*mm_model.Channel, error) { + // first ensure the bot is a member of the team. + _, err := pd.api.CreateMember(teamID, botID) + if err != nil { + return nil, fmt.Errorf("cannot add bot to team %s: %w", teamID, err) + } + return pd.api.GetDirectChannel(userID, botID) +} diff --git a/server/services/notify/plugindelivery/user_test.go b/server/services/notify/plugindelivery/user_test.go index 690eeb378..0792dd359 100644 --- a/server/services/notify/plugindelivery/user_test.go +++ b/server/services/notify/plugindelivery/user_test.go @@ -138,3 +138,11 @@ func (m pluginAPIMock) GetChannelByID(channelID string) (*mm_model.Channel, erro func (m pluginAPIMock) GetChannelMember(channelID string, userID string) (*mm_model.ChannelMember, error) { return nil, model.NewErrNotFound(userID) } + +func (m pluginAPIMock) CreateMember(teamID string, userID string) (*mm_model.TeamMember, error) { + member := &mm_model.TeamMember{ + UserId: userID, + TeamId: teamID, + } + return member, nil +}