Repository: slack-go/slack
Pull request #1330 (2024-10-06 18:44:15)

feat: Add support for external_limited option of inviteShared
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.


Patch:
diff --git a/conversation.go b/conversation.go
index bfc17fd..6b941b5 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


Test patch:
diff --git a/conversation_test.go b/conversation_test.go
index 77dfd01..0ee6f4d 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) {