Skip to content

Commit

Permalink
feat: implement conversation datasource
Browse files Browse the repository at this point in the history
  • Loading branch information
bosc0 committed Jan 9, 2025
1 parent b927631 commit eee8b24
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 2 deletions.
32 changes: 32 additions & 0 deletions docs/data-sources/conversation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "slack_conversation Data Source - slack"
subcategory: ""
description: |-
Retrieve information about a Slack conversation (channel) by its ID.
---

# slack_conversation (Data Source)

Retrieve information about a Slack conversation (channel) by its ID.



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `channel_id` (String) The Slack channel ID to look up.

### Read-Only

- `created` (Number) UNIX timestamp when the channel was created.
- `creator` (String) User ID of the channel creator.
- `is_archived` (Boolean) True if the channel is archived.
- `is_ext_shared` (Boolean) True if the channel is externally shared.
- `is_general` (Boolean) True if this is the #general channel.
- `is_org_shared` (Boolean) True if the channel is shared across the org.
- `is_shared` (Boolean) True if the channel is shared.
- `purpose` (String) The channel purpose.
- `topic` (String) The channel topic.
145 changes: 145 additions & 0 deletions internal/provider/data_source_conversation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package provider

import (
"context"
"fmt"

"github.com/essent/terraform-provider-slack/internal/slackExt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/slack-go/slack"
)

var _ datasource.DataSource = &ConversationDataSource{}

func NewConversationDataSource() datasource.DataSource {
return &ConversationDataSource{}
}

type ConversationDataSource struct {
client slackExt.Client
}

type ConversationDataSourceModel struct {
ChannelID types.String `tfsdk:"channel_id"`
Topic types.String `tfsdk:"topic"`
Purpose types.String `tfsdk:"purpose"`
Created types.Int64 `tfsdk:"created"`
Creator types.String `tfsdk:"creator"`
IsArchived types.Bool `tfsdk:"is_archived"`
IsShared types.Bool `tfsdk:"is_shared"`
IsExtShared types.Bool `tfsdk:"is_ext_shared"`
IsOrgShared types.Bool `tfsdk:"is_org_shared"`
IsGeneral types.Bool `tfsdk:"is_general"`
}

func (d *ConversationDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_conversation"
}

func (d *ConversationDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Retrieve information about a Slack conversation (channel) by its ID.",
Attributes: map[string]schema.Attribute{
"channel_id": schema.StringAttribute{
MarkdownDescription: "The Slack channel ID to look up.",
Required: true,
},
"topic": schema.StringAttribute{
MarkdownDescription: "The channel topic.",
Computed: true,
},
"purpose": schema.StringAttribute{
MarkdownDescription: "The channel purpose.",
Computed: true,
},
"created": schema.Int64Attribute{
MarkdownDescription: "UNIX timestamp when the channel was created.",
Computed: true,
},
"creator": schema.StringAttribute{
MarkdownDescription: "User ID of the channel creator.",
Computed: true,
},
"is_archived": schema.BoolAttribute{
MarkdownDescription: "True if the channel is archived.",
Computed: true,
},
"is_shared": schema.BoolAttribute{
MarkdownDescription: "True if the channel is shared.",
Computed: true,
},
"is_ext_shared": schema.BoolAttribute{
MarkdownDescription: "True if the channel is externally shared.",
Computed: true,
},
"is_org_shared": schema.BoolAttribute{
MarkdownDescription: "True if the channel is shared across the org.",
Computed: true,
},
"is_general": schema.BoolAttribute{
MarkdownDescription: "True if this is the #general channel.",
Computed: true,
},
},
}
}

func (d *ConversationDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

providerData, ok := req.ProviderData.(*SlackProviderData)
if !ok || providerData.Client == nil {
resp.Diagnostics.AddError(
"Invalid Provider Data",
fmt.Sprintf("Expected *SlackProviderData with initialized client, got: %T", req.ProviderData),
)
return
}

d.client = providerData.Client
}

func (d *ConversationDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data ConversationDataSourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

channel, err := d.client.GetConversationInfo(ctx, &slack.GetConversationInfoInput{
ChannelID: data.ChannelID.ValueString(),
IncludeLocale: false,
IncludeNumMembers: false,
})
if err != nil {
resp.Diagnostics.AddError(
"Client Error",
fmt.Sprintf("Could not get conversation info for channel %s: %s", data.ChannelID.ValueString(), err),
)
return
}

data.ChannelID = types.StringValue(channel.ID)
data.Topic = types.StringValue(channel.Topic.Value)
data.Purpose = types.StringValue(channel.Purpose.Value)
data.Created = types.Int64Value(int64(channel.Created))
data.Creator = types.StringValue(channel.Creator)
data.IsArchived = types.BoolValue(channel.IsArchived)
data.IsShared = types.BoolValue(channel.IsShared)
data.IsExtShared = types.BoolValue(channel.IsExtShared)
data.IsOrgShared = types.BoolValue(channel.IsOrgShared)
data.IsGeneral = types.BoolValue(channel.IsGeneral)

tflog.Trace(ctx, "Fetched Slack channel data", map[string]any{"channel_id": channel.ID})

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func (p *SlackProvider) DataSources(ctx context.Context) []func() datasource.Dat
NewUserDataSource,
NewAllUsersDataSource,
NewAllUserGroupsDataSource,
NewConversationDataSource,
}
}

Expand Down
4 changes: 4 additions & 0 deletions internal/slackExt/client.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package slackExt

import (
Expand All @@ -11,6 +14,7 @@ type Client interface {
GetUserByEmail(ctx context.Context, email string) (*slack.User, error)
GetUsersContext(ctx context.Context) ([]slack.User, error)
GetUserGroups(ctx context.Context, options ...slack.GetUserGroupsOption) ([]slack.UserGroup, error)
GetConversationInfo(ctx context.Context, input *slack.GetConversationInfoInput) (*slack.Channel, error)
}

func New(base *slack.Client) Client {
Expand Down
7 changes: 7 additions & 0 deletions internal/slackExt/client_impl.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package slackExt

import (
Expand Down Expand Up @@ -25,3 +28,7 @@ func (c *clientImpl) GetUsersContext(ctx context.Context) ([]slack.User, error)
func (c *clientImpl) GetUserGroups(ctx context.Context, options ...slack.GetUserGroupsOption) ([]slack.UserGroup, error) {
return c.base.GetUserGroupsContext(ctx, options...)
}

func (c *clientImpl) GetConversationInfo(ctx context.Context, input *slack.GetConversationInfoInput) (*slack.Channel, error) {
return c.base.GetConversationInfoContext(ctx, input)
}
12 changes: 10 additions & 2 deletions internal/slackExt/client_rate_limit.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package slackExt

import (
Expand All @@ -14,7 +17,6 @@ type clientRateLimit struct {
func rateLimit[R any](ctx context.Context, f func() (R, error), getZeroValue func() R) (result R, err error) {
for {
result, err = f()

if err == nil {
return result, nil
}
Expand All @@ -31,7 +33,7 @@ func rateLimit[R any](ctx context.Context, f func() (R, error), getZeroValue fun
}
}

func (c *clientRateLimit) GetUserInfo(ctx context.Context, user string) (result *slack.User, err error) {
func (c *clientRateLimit) GetUserInfo(ctx context.Context, user string) (*slack.User, error) {
return rateLimit(ctx, func() (*slack.User, error) {
return c.base.GetUserInfo(ctx, user)
}, func() *slack.User { return nil })
Expand All @@ -52,3 +54,9 @@ func (c *clientRateLimit) GetUserGroups(ctx context.Context, options ...slack.Ge
return c.base.GetUserGroups(ctx, options...)
}, func() []slack.UserGroup { return []slack.UserGroup{} })
}

func (c *clientRateLimit) GetConversationInfo(ctx context.Context, input *slack.GetConversationInfoInput) (*slack.Channel, error) {
return rateLimit(ctx, func() (*slack.Channel, error) {
return c.base.GetConversationInfo(ctx, input)
}, func() *slack.Channel { return nil })
}

0 comments on commit eee8b24

Please sign in to comment.