Skip to content

Commit

Permalink
Support Retrieving Conversation by Name (#162)
Browse files Browse the repository at this point in the history
* Support Retrieving Conversation by Name


---------

Co-authored-by: Pablo Varela <[email protected]>
  • Loading branch information
itsmechlark and pablovarela authored Mar 16, 2023
1 parent 6ab20c5 commit 1ff81b5
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 52 deletions.
11 changes: 10 additions & 1 deletion docs/data-sources/conversation.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,22 @@ the documentation for the methods above.
data "slack_conversation" "test" {
channel_id = "my-channel"
}
data "slack_conversation" "test-name" {
name = "my-channel-name"
}
```

## Argument Reference

The following arguments are supported:

- `channel_id` - (Required) The ID of the channel
- `channel_id` - (Optional) The ID of the channel
- `name` - (Optional) The name of the public or private channel
- `is_private` - (Optional) The conversation is privileged between two or more members

Either `channel_id` or `name` must be provided. `is_private` only works in conjunction
with `name`.

## Attribute Reference

Expand Down
35 changes: 24 additions & 11 deletions slack/data_source_conversation.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ func dataSourceConversation() *schema.Resource {
Schema: map[string]*schema.Schema{
"channel_id": {
Type: schema.TypeString,
Required: true,
Optional: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"is_private": {
Type: schema.TypeBool,
Optional: true,
},
"topic": {
Type: schema.TypeString,
Expand All @@ -38,10 +42,6 @@ func dataSourceConversation() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"is_private": {
Type: schema.TypeBool,
Computed: true,
},
"is_archived": {
Type: schema.TypeBool,
Computed: true,
Expand Down Expand Up @@ -69,12 +69,25 @@ func dataSourceConversation() *schema.Resource {
func dataSourceSlackConversationRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*slack.Client)
channelID := d.Get("channel_id").(string)
channelName := d.Get("name").(string)
isPrivate := d.Get("is_private").(bool)

channel, err := client.GetConversationInfoContext(ctx, &slack.GetConversationInfoInput{
ChannelID: channelID,
})
if err != nil {
return diag.FromErr(fmt.Errorf("couldn't get conversation info for %s: %w", channelID, err))
var channel *slack.Channel
var err error
if channelID != "" {
channel, err = client.GetConversationInfoContext(ctx, &slack.GetConversationInfoInput{
ChannelID: channelID,
})
if err != nil {
return diag.FromErr(fmt.Errorf("couldn't get conversation info for %s: %w", channelID, err))
}
} else if channelName != "" {
channel, err = findExistingChannel(ctx, client, channelName, isPrivate)
if err != nil {
return diag.FromErr(fmt.Errorf("couldn't get conversation info for %s: %w", channelName, err))
}
} else {
return diag.FromErr(fmt.Errorf("channel_id or name must be set"))
}

users, _, err := client.GetUsersInConversationContext(ctx, &slack.GetUsersInConversationParameters{
Expand Down
80 changes: 57 additions & 23 deletions slack/data_source_conversation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ import (
)

func TestAccSlackConversationDataSource_basic(t *testing.T) {
resourceName := "slack_conversation.test"
dataSourceName := "data.slack_conversation.test"

var providers []*schema.Provider
name := acctest.RandomWithPrefix("test-acc-slack-conversation-test")
members := []string{testUser00.id, testUser01.id}
createChannel := testAccSlackConversationWithMembers(name, members)

nameByID := acctest.RandomWithPrefix("test-acc-slack-conversation-test")
resourceNameByID := fmt.Sprintf("slack_conversation.%s", nameByID)
dataSourceNameByID := fmt.Sprintf("data.slack_conversation.%s", nameByID)
membersByID := []string{testUser00.id, testUser01.id}
createChannelByID := testAccSlackConversationWithMembers(nameByID, membersByID)

nameByName := acctest.RandomWithPrefix("test-acc-slack-conversation-test")
resourceNameByName := fmt.Sprintf("slack_conversation.%s", nameByName)
dataSourceNameByName := fmt.Sprintf("data.slack_conversation.%s", nameByName)
membersByName := []string{testUser00.id, testUser01.id}
createChannelByName := testAccSlackConversationWithMembers(nameByName, membersByName)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand All @@ -30,21 +36,39 @@ func TestAccSlackConversationDataSource_basic(t *testing.T) {
ExpectError: regexp.MustCompile(`channel_not_found`),
},
{
Config: testAccCheckSlackConversationDataSourceConfig(createChannel),
Config: testAccCheckSlackConversationDataSourceConfig(createChannelByID),
Check: resource.ComposeTestCheckFunc(
testAccCheckSlackConversationDataSourceID(dataSourceNameByID),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "channel_id", resourceNameByID, "id"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "name", resourceNameByID, "name"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "topic", resourceNameByID, "topic"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "purpose", resourceNameByID, "purpose"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "creator", resourceNameByID, "creator"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "created", resourceNameByID, "created"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "is_private", resourceNameByID, "is_private"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "is_archived", resourceNameByID, "is_archived"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "is_shared", resourceNameByID, "is_shared"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "is_ext_shared", resourceNameByID, "is_ext_shared"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "is_org_shared", resourceNameByID, "is_org_shared"),
resource.TestCheckResourceAttrPair(dataSourceNameByID, "is_general", resourceNameByID, "is_general"),
),
},
{
Config: testAccCheckSlackConversationDataSourceConfigName(createChannelByName),
Check: resource.ComposeTestCheckFunc(
testAccCheckSlackConversationDataSourceID(dataSourceName),
resource.TestCheckResourceAttrPair(dataSourceName, "channel_id", resourceName, "id"),
resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName, "topic", resourceName, "topic"),
resource.TestCheckResourceAttrPair(dataSourceName, "purpose", resourceName, "purpose"),
resource.TestCheckResourceAttrPair(dataSourceName, "creator", resourceName, "creator"),
resource.TestCheckResourceAttrPair(dataSourceName, "created", resourceName, "created"),
resource.TestCheckResourceAttrPair(dataSourceName, "is_private", resourceName, "is_private"),
resource.TestCheckResourceAttrPair(dataSourceName, "is_archived", resourceName, "is_archived"),
resource.TestCheckResourceAttrPair(dataSourceName, "is_shared", resourceName, "is_shared"),
resource.TestCheckResourceAttrPair(dataSourceName, "is_ext_shared", resourceName, "is_ext_shared"),
resource.TestCheckResourceAttrPair(dataSourceName, "is_org_shared", resourceName, "is_org_shared"),
resource.TestCheckResourceAttrPair(dataSourceName, "is_general", resourceName, "is_general"),
testAccCheckSlackConversationDataSourceID(dataSourceNameByName),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "channel_id", resourceNameByName, "id"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "name", resourceNameByName, "name"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "topic", resourceNameByName, "topic"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "purpose", resourceNameByName, "purpose"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "creator", resourceNameByName, "creator"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "created", resourceNameByName, "created"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "is_private", resourceNameByName, "is_private"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "is_archived", resourceNameByName, "is_archived"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "is_shared", resourceNameByName, "is_shared"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "is_ext_shared", resourceNameByName, "is_ext_shared"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "is_org_shared", resourceNameByName, "is_org_shared"),
resource.TestCheckResourceAttrPair(dataSourceNameByName, "is_general", resourceNameByName, "is_general"),
),
},
},
Expand Down Expand Up @@ -72,12 +96,22 @@ data slack_conversation test {
}
`
testAccCheckSlackConversationDataSourceConfigExistent = `
data slack_conversation test {
channel_id = slack_conversation.test.id
data slack_conversation %s {
channel_id = slack_conversation.%s.id
}
`
testAccCheckSlackConversationDataSourceConfigNameExistent = `
data slack_conversation %s {
name = slack_conversation.%s.name
is_private = true
}
`
)

func testAccCheckSlackConversationDataSourceConfig(channel slack.Channel) string {
return testAccSlackConversationConfig(channel) + testAccCheckSlackConversationDataSourceConfigExistent
return testAccSlackConversationConfig(channel) + fmt.Sprintf(testAccCheckSlackConversationDataSourceConfigExistent, channel.Name, channel.Name)
}

func testAccCheckSlackConversationDataSourceConfigName(channel slack.Channel) string {
return testAccSlackConversationConfig(channel) + fmt.Sprintf(testAccCheckSlackConversationDataSourceConfigNameExistent, channel.Name, channel.Name)
}
17 changes: 12 additions & 5 deletions slack/resource_conversation.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,10 @@ func findExistingChannel(ctx context.Context, client *slack.Client, name string,
}
for !paginationComplete {
channels, nextCursor, err := client.GetConversationsContext(ctx, &slack.GetConversationsParameters{
Cursor: cursor,
Limit: cursorLimit,
Types: types,
Cursor: cursor,
Limit: cursorLimit,
Types: types,
ExcludeArchived: true,
})
tflog.Debug(ctx, "new page of channels",
map[string]interface{}{
Expand All @@ -214,7 +215,7 @@ func findExistingChannel(ctx context.Context, client *slack.Client, name string,
}
// retry current cursor
} else {
return nil, fmt.Errorf("name_taken, but %s trying to find", err)
return nil, fmt.Errorf("couldn't get conversation context: %s", err.Error())
}
} else {
// see if channel in current batch
Expand All @@ -231,7 +232,7 @@ func findExistingChannel(ctx context.Context, client *slack.Client, name string,
}
}
// looked through entire list, but didn't find matching name
return nil, fmt.Errorf("name_taken, but could not find channel")
return nil, fmt.Errorf("could not find channel with name %s", name)
}

func updateChannelMembers(ctx context.Context, d *schema.ResourceData, client *slack.Client, channelID string) error {
Expand Down Expand Up @@ -403,6 +404,12 @@ func updateChannelData(d *schema.ResourceData, channel *slack.Channel, users []s
}
d.SetId(channel.ID)

if d.Get("channel_id") != nil {
if err := d.Set("channel_id", channel.ID); err != nil {
return diag.Errorf("error setting channel_id: %s", err)
}
}

if err := d.Set("name", channel.Name); err != nil {
return diag.Errorf("error setting name: %s", err)
}
Expand Down
28 changes: 16 additions & 12 deletions slack/resource_conversation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func init() {
func TestAccSlackConversationTest(t *testing.T) {
t.Parallel()

resourceName := "slack_conversation.test"
resourceName := "slack_conversation.%s"

t.Run("update name, topic and purpose", func(t *testing.T) {
name := acctest.RandomWithPrefix(conversationNamePrefix)
Expand All @@ -79,7 +79,7 @@ func TestAccSlackConversationTest(t *testing.T) {
updateName := acctest.RandomWithPrefix(conversationNamePrefix)
updateChannel := testAccSlackConversation(updateName)

testSlackConversationUpdate(t, resourceName, createChannel, &updateChannel)
testSlackConversationUpdate(t, fmt.Sprintf(resourceName, name), createChannel, &updateChannel)
})

t.Run("archive channel", func(t *testing.T) {
Expand All @@ -89,7 +89,7 @@ func TestAccSlackConversationTest(t *testing.T) {
updateChannel := createChannel
updateChannel.IsArchived = true

testSlackConversationUpdate(t, resourceName, createChannel, &updateChannel)
testSlackConversationUpdate(t, fmt.Sprintf(resourceName, name), createChannel, &updateChannel)
})

t.Run("unarchive channel", func(t *testing.T) {
Expand All @@ -100,7 +100,7 @@ func TestAccSlackConversationTest(t *testing.T) {
updateChannel := createChannel
updateChannel.IsArchived = false

testSlackConversationUpdate(t, resourceName, createChannel, &updateChannel)
testSlackConversationUpdate(t, fmt.Sprintf(resourceName, name), createChannel, &updateChannel)
})

t.Run("add permanent members", func(t *testing.T) {
Expand All @@ -110,7 +110,7 @@ func TestAccSlackConversationTest(t *testing.T) {
updateChannel := createChannel
updateChannel.Members = []string{testUser00.id, testUser01.id}

testSlackConversationUpdate(t, resourceName, createChannel, &updateChannel)
testSlackConversationUpdate(t, fmt.Sprintf(resourceName, name), createChannel, &updateChannel)
})

t.Run("remove permanent members", func(t *testing.T) {
Expand All @@ -120,23 +120,23 @@ func TestAccSlackConversationTest(t *testing.T) {
updateChannel := createChannel
updateChannel.Members = []string{testUser00.id}

testSlackConversationUpdate(t, resourceName, createChannel, &updateChannel)
testSlackConversationUpdate(t, fmt.Sprintf(resourceName, name), createChannel, &updateChannel)
})

t.Run("invite only the creator to the channel", func(t *testing.T) {
name := acctest.RandomWithPrefix(conversationNamePrefix)
users := []string{testUserCreator.id}
createChannel := testAccSlackConversationWithMembers(name, users)

testSlackConversationUpdate(t, resourceName, createChannel, nil)
testSlackConversationUpdate(t, fmt.Sprintf(resourceName, name), createChannel, nil)
})

t.Run("invite creator and other users to the channel", func(t *testing.T) {
name := acctest.RandomWithPrefix(conversationNamePrefix)
users := []string{testUserCreator.id, testUser00.id, testUser01.id}
createChannel := testAccSlackConversationWithMembers(name, users)

testSlackConversationUpdate(t, resourceName, createChannel, nil)
testSlackConversationUpdate(t, fmt.Sprintf(resourceName, name), createChannel, nil)
})
}

Expand All @@ -160,7 +160,7 @@ func testSlackConversationUpdate(t *testing.T, resourceName string, createChanne

if updateChannel != nil {
steps = append(steps, resource.TestStep{
Config: testAccSlackConversationConfig(*updateChannel),
Config: testAccSlackConversationConfigWithResourceName(*updateChannel, createChannel.Name),
Check: resource.ComposeTestCheckFunc(
testCheckSlackChannelAttributes(t, resourceName, *updateChannel),
testCheckResourceAttrBasic(resourceName, *updateChannel),
Expand Down Expand Up @@ -308,20 +308,24 @@ func testAccCheckConversationDestroy(s *terraform.State) error {
return nil
}

func testAccSlackConversationConfig(c slack.Channel) string {
func testAccSlackConversationConfigWithResourceName(c slack.Channel, resourceName string) string {
var members []string
for _, member := range c.Members {
members = append(members, fmt.Sprintf(`"%s"`, member))
}

return fmt.Sprintf(`
resource slack_conversation test {
resource slack_conversation %s {
name = "%s"
topic = "%s"
purpose = "%s"
permanent_members = [%s]
is_private = %t
is_archived = %t
}
`, c.Name, c.Topic.Value, c.Purpose.Value, strings.Join(members, ","), c.IsPrivate, c.IsArchived)
`, resourceName, c.Name, c.Topic.Value, c.Purpose.Value, strings.Join(members, ","), c.IsPrivate, c.IsArchived)
}

func testAccSlackConversationConfig(c slack.Channel) string {
return testAccSlackConversationConfigWithResourceName(c, c.Name)
}

0 comments on commit 1ff81b5

Please sign in to comment.