From c5ef90eb5811bf3dee32387dc0154d5a86b63a9b Mon Sep 17 00:00:00 2001 From: Bennett Amodio Date: Mon, 14 Oct 2024 08:58:49 -0700 Subject: [PATCH] feat: Add support for external_limited option of inviteShared (#1330) Expose the ability to override the [external_limited option](https://api.slack.com/methods/conversations.inviteShared#arg_external_limited) for inviteShared. Adding the param to all the InviteSharedEmailsToConversation, etc. methods would be a breaking change to those callers, so I opted instead to expose the underlying helper (renamed to InviteSharedToConversation). I feel like the convenience methods (InviteSharedEmailsToConversation/InviteSharedUserIDsToConversation) are not actually that much more convenient than just using the helper, and I think we can eventually remove them in favor of having people call InviteSharedToConversation directly. But that's a future thing. Although it's slightly inconvenient for the caller to use *bool for ExternalLimited, the two alternatives I considered are, I think worse: - Include ExternalLimited as a bool in the InviteSharedParams. I dislike this way because it gives the SDK user of InviteSharedToConversation a different default behavior from inviteShared, since the default value in the API is true. - Add a bool like NonExternalLimited to InviteSharedParams. This way the defaulting is consistent with the API if it's not specified; however, the InviteSharedParams no longer mirror the API args, which I think is confusing. --- conversation.go | 59 +++++++++++++++++++++++++++++++++----------- conversation_test.go | 21 ++++++++++++++++ 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/conversation.go b/conversation.go index bfc17fd3b..6b941b5ee 100644 --- a/conversation.go +++ b/conversation.go @@ -329,42 +329,71 @@ func (api *Client) InviteUsersToConversationContext(ctx context.Context, channel } // InviteSharedEmailsToConversation invites users to a shared channels by email. -// For more details, see InviteSharedEmailsToConversationContext documentation. +// For more details, see InviteSharedToConversationContext documentation. func (api *Client) InviteSharedEmailsToConversation(channelID string, emails ...string) (string, bool, error) { - return api.inviteSharedToConversationHelper(context.Background(), channelID, emails, nil) + return api.InviteSharedToConversationContext(context.Background(), InviteSharedToConversationParams{ + ChannelID: channelID, + Emails: emails, + }) } // InviteSharedEmailsToConversationContext invites users to a shared channels by email using context. -// For more details, see inviteSharedToConversationHelper documentation. +// For more details, see InviteSharedToConversationContext documentation. func (api *Client) InviteSharedEmailsToConversationContext(ctx context.Context, channelID string, emails ...string) (string, bool, error) { - return api.inviteSharedToConversationHelper(ctx, channelID, emails, nil) + return api.InviteSharedToConversationContext(ctx, InviteSharedToConversationParams{ + ChannelID: channelID, + Emails: emails, + }) } // InviteSharedUserIDsToConversation invites users to a shared channels by user id. -// For more details, see InviteSharedUserIDsToConversationContext documentation. +// For more details, see InviteSharedToConversationContext documentation. func (api *Client) InviteSharedUserIDsToConversation(channelID string, userIDs ...string) (string, bool, error) { - return api.inviteSharedToConversationHelper(context.Background(), channelID, nil, userIDs) + return api.InviteSharedToConversationContext(context.Background(), InviteSharedToConversationParams{ + ChannelID: channelID, + UserIDs: userIDs, + }) } // InviteSharedUserIDsToConversationContext invites users to a shared channels by user id with context. -// For more details, see inviteSharedToConversationHelper documentation. +// For more details, see InviteSharedToConversationContext documentation. func (api *Client) InviteSharedUserIDsToConversationContext(ctx context.Context, channelID string, userIDs ...string) (string, bool, error) { - return api.inviteSharedToConversationHelper(ctx, channelID, nil, userIDs) + return api.InviteSharedToConversationContext(ctx, InviteSharedToConversationParams{ + ChannelID: channelID, + UserIDs: userIDs, + }) } -// inviteSharedToConversationHelper invites emails or userIDs to a channel with a custom context. +// InviteSharedToConversationParams defines the parameters for the InviteSharedToConversation and InviteSharedToConversationContext functions. +type InviteSharedToConversationParams struct { + ChannelID string + Emails []string + UserIDs []string + ExternalLimited *bool +} + +// InviteSharedToConversation invites emails or userIDs to a channel. +// For more details, see InviteSharedToConversationContext documentation. +func (api *Client) InviteSharedToConversation(params InviteSharedToConversationParams) (string, bool, error) { + return api.InviteSharedToConversationContext(context.Background(), params) +} + +// InviteSharedToConversationContext invites emails or userIDs to a channel with a custom context. // This is a helper function for InviteSharedEmailsToConversation and InviteSharedUserIDsToConversation. // It accepts either emails or userIDs, but not both. // Slack API docs: https://api.slack.com/methods/conversations.inviteShared -func (api *Client) inviteSharedToConversationHelper(ctx context.Context, channelID string, emails []string, userIDs []string) (string, bool, error) { +func (api *Client) InviteSharedToConversationContext(ctx context.Context, params InviteSharedToConversationParams) (string, bool, error) { values := url.Values{ "token": {api.token}, - "channel": {channelID}, + "channel": {params.ChannelID}, + } + if len(params.Emails) > 0 { + values.Add("emails", strings.Join(params.Emails, ",")) + } else if len(params.UserIDs) > 0 { + values.Add("user_ids", strings.Join(params.UserIDs, ",")) } - if len(emails) > 0 { - values.Add("emails", strings.Join(emails, ",")) - } else if len(userIDs) > 0 { - values.Add("user_ids", strings.Join(userIDs, ",")) + if params.ExternalLimited != nil { + values.Add("external_limited", strconv.FormatBool(*params.ExternalLimited)) } response := struct { SlackResponse diff --git a/conversation_test.go b/conversation_test.go index 77dfd0191..0ee6f4d4b 100644 --- a/conversation_test.go +++ b/conversation_test.go @@ -477,6 +477,27 @@ func TestInviteSharedToConversation(t *testing.T) { t.Error("is legacy shared channel should be false") } }) + + t.Run("external_limited", func(t *testing.T) { + userIDs := []string{"UXXXXXXX1", "UXXXXXXX2"} + externalLimited := true + inviteID, isLegacySharedChannel, err := api.InviteSharedToConversation(InviteSharedToConversationParams{ + ChannelID: "CXXXXXXXX", + UserIDs: userIDs, + ExternalLimited: &externalLimited, + }) + if err != nil { + t.Errorf("Unexpected error: %s", err) + return + } + if inviteID == "" { + t.Error("invite id should have a value") + return + } + if isLegacySharedChannel { + t.Error("is legacy shared channel should be false") + } + }) } func TestKickUserFromConversation(t *testing.T) {