Repository: slack-go/slack
Pull request #1401 (2025-03-23 15:05:49)

Add some missing admin.conversations endpoints
This PR introduces three new methods for:

* `admin.conversations.setTeams`
* `admin.conversations.convertToPrivate`
* `admin.conversations.convertToPublic`

I've left some comments in-line below.


Patch:
diff --git a/admin_conversations.go b/admin_conversations.go
new file mode 100644
index 0000000..6f76568
--- /dev/null
+++ b/admin_conversations.go
@@ -0,0 +1,85 @@
+package slack
+
+import (
+	"context"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+// AdminConversationsSetTeamsParams contains arguments for AdminConversationsSetTeams
+// method calls.
+type AdminConversationsSetTeamsParams struct {
+	ChannelID     string
+	OrgChannel    *bool
+	TargetTeamIDs []string
+	TeamID        *string
+}
+
+// Set the workspaces in an Enterprise Grid organisation that connect to a public or
+// private channel.
+// See: https://api.slack.com/methods/admin.conversations.setTeams
+func (api *Client) AdminConversationsSetTeams(ctx context.Context, params AdminConversationsSetTeamsParams) error {
+	values := url.Values{
+		"token":      {api.token},
+		"channel_id": {params.ChannelID},
+	}
+
+	if params.OrgChannel != nil {
+		values.Add("org_channel", strconv.FormatBool(*params.OrgChannel))
+	}
+
+	if len(params.TargetTeamIDs) > 0 {
+		values.Add("target_team_ids", strings.Join(params.TargetTeamIDs, ",")) // ["T123", "T456"] - > "T123,T456"
+	}
+
+	if params.TeamID != nil {
+		values.Add("team_id", *params.TeamID)
+	}
+
+	response := &SlackResponse{}
+	err := api.postMethod(ctx, "admin.conversations.setTeams", values, response)
+	if err != nil {
+		return err
+	}
+
+	return response.Err()
+}
+
+// ConversationsConvertToPrivate converts a public channel to a private channel. To do
+// this, you must have the admin.conversations:write scope. There are other requirements:
+// you should read the Slack documentation for more details.
+// See: https://api.slack.com/methods/admin.conversations.convertToPrivate
+func (api *Client) AdminConversationsConvertToPrivate(ctx context.Context, channelID string) error {
+	values := url.Values{
+		"token":      []string{api.token},
+		"channel_id": []string{channelID},
+	}
+
+	response := &SlackResponse{}
+	err := api.postMethod(ctx, "admin.conversations.convertToPrivate", values, response)
+	if err != nil {
+		return err
+	}
+
+	return response.Err()
+}
+
+// ConversationsConvertToPublic converts a private channel to a public channel. To do
+// this, you must have the admin.conversations:write scope. There are other requirements:
+// you should read the Slack documentation for more details.
+// See: https://api.slack.com/methods/admin.conversations.convertToPublic
+func (api *Client) AdminConversationsConvertToPublic(ctx context.Context, channelID string) error {
+	values := url.Values{
+		"token":      []string{api.token},
+		"channel_id": []string{channelID},
+	}
+
+	response := &SlackResponse{}
+	err := api.postMethod(ctx, "admin.conversations.convertToPublic", values, response)
+	if err != nil {
+		return err
+	}
+
+	return response.Err()
+}


Test patch:
diff --git a/admin_conversations_test.go b/admin_conversations_test.go
new file mode 100644
index 0000000..66ad862
--- /dev/null
+++ b/admin_conversations_test.go
@@ -0,0 +1,82 @@
+package slack
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"testing"
+)
+
+func TestAdminConversationsSetTeams(t *testing.T) {
+	http.DefaultServeMux = new(http.ServeMux)
+	http.HandleFunc("/admin.conversations.setTeams", mockAdminChannelIDHandler(t))
+	once.Do(startServer)
+	api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))
+
+	orgChannel := true
+	teamID := "T789"
+
+	err := api.AdminConversationsSetTeams(context.Background(), AdminConversationsSetTeamsParams{
+		ChannelID:     "C1234567890",
+		OrgChannel:    &orgChannel,
+		TargetTeamIDs: []string{"T123", "T456"},
+		TeamID:        &teamID,
+	})
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+		return
+	}
+}
+
+func TestAdminConversationsConvertToPrivate(t *testing.T) {
+	http.DefaultServeMux = new(http.ServeMux)
+	http.HandleFunc("/admin.conversations.convertToPrivate", mockAdminChannelIDHandler(t))
+	once.Do(startServer)
+	api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))
+
+	err := api.AdminConversationsConvertToPrivate(context.Background(), "C1234567890")
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+		return
+	}
+}
+
+func TestAdminConversationsConvertToPublic(t *testing.T) {
+	http.DefaultServeMux = new(http.ServeMux)
+	http.HandleFunc("/admin.conversations.convertToPublic", mockAdminChannelIDHandler(t))
+	once.Do(startServer)
+	api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))
+
+	err := api.AdminConversationsConvertToPublic(context.Background(), "C1234567890")
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+		return
+	}
+}
+
+// mockAdminChannelIDHandler returns a handler which expects a channel_id to be present
+// in the request, and will fail the test if it isn't present.
+func mockAdminChannelIDHandler(t *testing.T) func(rw http.ResponseWriter, r *http.Request) {
+	return func(rw http.ResponseWriter, r *http.Request) {
+		if r.Method != http.MethodPost {
+			t.Errorf("expected POST request, got %s", r.Method)
+		}
+
+		if err := r.ParseForm(); err != nil {
+			t.Errorf("unexpected error: %s", err)
+			return
+		}
+
+		if len(r.Form["channel_id"]) == 0 {
+			t.Error("missing channel_id in request")
+			return
+		}
+
+		rw.Header().Set("Content-Type", "application/json")
+		response, _ := json.Marshal(SlackResponse{
+			Ok: true,
+		})
+
+		rw.Write(response)
+	}
+}