Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement conversation datasource #5

Merged
merged 1 commit into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
10 changes: 9 additions & 1 deletion 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 Down Expand Up @@ -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) (result *slack.Channel, err error) {
return rateLimit(ctx, func() (*slack.Channel, error) {
return c.base.GetConversationInfo(ctx, input)
}, func() *slack.Channel { return nil })
}
Loading