From 70f2635db824a9f1124cfd67b0e39d5998b18abf Mon Sep 17 00:00:00 2001
From: atoni <50518795+bosc0@users.noreply.github.com>
Date: Thu, 2 Jan 2025 12:09:05 +0100
Subject: [PATCH 1/7] data_source_user.go: allow either email or userid to be
set
---
docs/data-sources/user_data.md | 8 ++++----
go.mod | 1 +
go.sum | 2 ++
internal/provider/data_source_user.go | 29 ++++++++++++++++++++++-----
4 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/docs/data-sources/user_data.md b/docs/data-sources/user_data.md
index 01aa7a9..99847e8 100644
--- a/docs/data-sources/user_data.md
+++ b/docs/data-sources/user_data.md
@@ -3,25 +3,25 @@
page_title: "slack_user_data Data Source - slack"
subcategory: ""
description: |-
- Retrieve Slack user information.
+ Retrieve Slack user information. Either user_id or email must be specified, but not both.
---
# slack_user_data (Data Source)
-Retrieve Slack user information.
+Retrieve Slack user information. Either `user_id` or `email` must be specified, but not both.
## Schema
-### Required
+### Optional
+- `email` (String) Email of the user to look up.
- `user_id` (String) Slack user ID to look up.
### Read-Only
- `display_name` (String) User's display name.
-- `email` (String) Email of the user.
- `id` (String) Unique identifier for Terraform state.
- `real_name` (String) User's real name.
diff --git a/go.mod b/go.mod
index a5816e0..b2e2357 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.23.4
require (
github.com/hashicorp/terraform-plugin-framework v1.13.0
+ github.com/hashicorp/terraform-plugin-framework-validators v0.16.0
github.com/hashicorp/terraform-plugin-go v0.25.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-testing v1.11.0
diff --git a/go.sum b/go.sum
index 8680fdf..e8342f7 100644
--- a/go.sum
+++ b/go.sum
@@ -81,6 +81,8 @@ github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2
github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c=
github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw=
github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU=
+github.com/hashicorp/terraform-plugin-framework-validators v0.16.0 h1:O9QqGoYDzQT7lwTXUsZEtgabeWW96zUBh47Smn2lkFA=
+github.com/hashicorp/terraform-plugin-framework-validators v0.16.0/go.mod h1:Bh89/hNmqsEWug4/XWKYBwtnw3tbz5BAy1L1OgvbIaY=
github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks=
github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
diff --git a/internal/provider/data_source_user.go b/internal/provider/data_source_user.go
index 536a508..0ad2108 100644
--- a/internal/provider/data_source_user.go
+++ b/internal/provider/data_source_user.go
@@ -7,8 +7,11 @@ import (
"context"
"fmt"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/slack-go/slack"
@@ -38,15 +41,21 @@ func (d *UserDataSource) Metadata(ctx context.Context, req datasource.MetadataRe
func (d *UserDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
- MarkdownDescription: "Retrieve Slack user information.",
+ MarkdownDescription: "Retrieve Slack user information. Either `user_id` or `email` must be specified, but not both.",
Attributes: map[string]schema.Attribute{
"user_id": schema.StringAttribute{
MarkdownDescription: "Slack user ID to look up.",
- Required: true,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("email")),
+ },
},
"email": schema.StringAttribute{
- MarkdownDescription: "Email of the user.",
- Computed: true,
+ MarkdownDescription: "Email of the user to look up.",
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("user_id")),
+ },
},
"real_name": schema.StringAttribute{
MarkdownDescription: "User's real name.",
@@ -90,7 +99,17 @@ func (d *UserDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
return
}
- user, err := d.client.GetUserInfo(data.UserID.ValueString())
+ var (
+ user *slack.User
+ err error
+ )
+
+ if !data.UserID.IsNull() {
+ user, err = d.client.GetUserInfo(data.UserID.ValueString())
+ } else {
+ user, err = d.client.GetUserByEmail(data.Email.ValueString())
+ }
+
if err != nil {
resp.Diagnostics.AddError(
"Client Error",
From 1cb83c8d3966bccd704cd34fd17d0b8d5a5e868d Mon Sep 17 00:00:00 2001
From: atoni <50518795+bosc0@users.noreply.github.com>
Date: Thu, 2 Jan 2025 12:29:16 +0100
Subject: [PATCH 2/7] data_source_user.go: dont return deactivated users
---
internal/provider/data_source_user.go | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/internal/provider/data_source_user.go b/internal/provider/data_source_user.go
index 0ad2108..8f32752 100644
--- a/internal/provider/data_source_user.go
+++ b/internal/provider/data_source_user.go
@@ -118,6 +118,14 @@ func (d *UserDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
return
}
+ if user.Deleted {
+ resp.Diagnostics.AddError(
+ "User is deactivated",
+ "User is deactivated in Slack",
+ )
+ return
+ }
+
data.Email = types.StringValue(user.Profile.Email)
data.RealName = types.StringValue(user.RealName)
data.DisplayName = types.StringValue(user.Profile.DisplayName)
From 395b674552eb33cba10c1b9a30d15a19eb5d8bf3 Mon Sep 17 00:00:00 2001
From: atoni <50518795+bosc0@users.noreply.github.com>
Date: Thu, 2 Jan 2025 14:44:32 +0100
Subject: [PATCH 3/7] refactor: simplify data_source_user.go
---
docs/data-sources/user.md | 25 ++++++++++++++++++
docs/data-sources/user_data.md | 27 -------------------
internal/provider/data_source_user.go | 37 ++++++++++-----------------
3 files changed, 38 insertions(+), 51 deletions(-)
create mode 100644 docs/data-sources/user.md
delete mode 100644 docs/data-sources/user_data.md
diff --git a/docs/data-sources/user.md b/docs/data-sources/user.md
new file mode 100644
index 0000000..8fb0cb4
--- /dev/null
+++ b/docs/data-sources/user.md
@@ -0,0 +1,25 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "slack_user Data Source - slack"
+subcategory: ""
+description: |-
+ Retrieve Slack user information. Either id or email must be specified, but not both.
+---
+
+# slack_user (Data Source)
+
+Retrieve Slack user information. Either `id` or `email` must be specified, but not both.
+
+
+
+
+## Schema
+
+### Optional
+
+- `email` (String) Email of the user to look up.
+- `id` (String) Slack user ID to look up.
+
+### Read-Only
+
+- `name` (String) User's name.
diff --git a/docs/data-sources/user_data.md b/docs/data-sources/user_data.md
deleted file mode 100644
index 99847e8..0000000
--- a/docs/data-sources/user_data.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "slack_user_data Data Source - slack"
-subcategory: ""
-description: |-
- Retrieve Slack user information. Either user_id or email must be specified, but not both.
----
-
-# slack_user_data (Data Source)
-
-Retrieve Slack user information. Either `user_id` or `email` must be specified, but not both.
-
-
-
-
-## Schema
-
-### Optional
-
-- `email` (String) Email of the user to look up.
-- `user_id` (String) Slack user ID to look up.
-
-### Read-Only
-
-- `display_name` (String) User's display name.
-- `id` (String) Unique identifier for Terraform state.
-- `real_name` (String) User's real name.
diff --git a/internal/provider/data_source_user.go b/internal/provider/data_source_user.go
index 8f32752..f263932 100644
--- a/internal/provider/data_source_user.go
+++ b/internal/provider/data_source_user.go
@@ -28,22 +28,20 @@ type UserDataSource struct {
}
type UserDataSourceModel struct {
- UserID types.String `tfsdk:"user_id"`
- Email types.String `tfsdk:"email"`
- RealName types.String `tfsdk:"real_name"`
- DisplayName types.String `tfsdk:"display_name"`
- ID types.String `tfsdk:"id"`
+ Email types.String `tfsdk:"email"`
+ Name types.String `tfsdk:"name"`
+ ID types.String `tfsdk:"id"`
}
func (d *UserDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_user_data"
+ resp.TypeName = req.ProviderTypeName + "_user"
}
func (d *UserDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
- MarkdownDescription: "Retrieve Slack user information. Either `user_id` or `email` must be specified, but not both.",
+ MarkdownDescription: "Retrieve Slack user information. Either `id` or `email` must be specified, but not both.",
Attributes: map[string]schema.Attribute{
- "user_id": schema.StringAttribute{
+ "id": schema.StringAttribute{
MarkdownDescription: "Slack user ID to look up.",
Optional: true,
Validators: []validator.String{
@@ -54,19 +52,11 @@ func (d *UserDataSource) Schema(ctx context.Context, req datasource.SchemaReques
MarkdownDescription: "Email of the user to look up.",
Optional: true,
Validators: []validator.String{
- stringvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("user_id")),
+ stringvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("id")),
},
},
- "real_name": schema.StringAttribute{
- MarkdownDescription: "User's real name.",
- Computed: true,
- },
- "display_name": schema.StringAttribute{
- MarkdownDescription: "User's display name.",
- Computed: true,
- },
- "id": schema.StringAttribute{
- MarkdownDescription: "Unique identifier for Terraform state.",
+ "name": schema.StringAttribute{
+ MarkdownDescription: "User's name.",
Computed: true,
},
},
@@ -104,8 +94,8 @@ func (d *UserDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
err error
)
- if !data.UserID.IsNull() {
- user, err = d.client.GetUserInfo(data.UserID.ValueString())
+ if !data.ID.IsNull() {
+ user, err = d.client.GetUserInfo(data.ID.ValueString())
} else {
user, err = d.client.GetUserByEmail(data.Email.ValueString())
}
@@ -127,11 +117,10 @@ func (d *UserDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
}
data.Email = types.StringValue(user.Profile.Email)
- data.RealName = types.StringValue(user.RealName)
- data.DisplayName = types.StringValue(user.Profile.DisplayName)
+ data.Name = types.StringValue(user.Profile.DisplayNameNormalized)
data.ID = types.StringValue(user.ID)
- tflog.Trace(ctx, "Fetched Slack user data", map[string]any{"user_id": user.ID})
+ tflog.Trace(ctx, "Fetched Slack user data", map[string]any{"id": user.ID})
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
From eaeac1287ffc7d6084dda0b700a93e9e8b114dcb Mon Sep 17 00:00:00 2001
From: atoni <50518795+bosc0@users.noreply.github.com>
Date: Thu, 2 Jan 2025 14:44:56 +0100
Subject: [PATCH 4/7] feat: introduce data_source_all_users.go
---
docs/data-sources/all_users.md | 30 +++++
internal/provider/data_source_all_users.go | 122 +++++++++++++++++++++
internal/provider/provider.go | 1 +
3 files changed, 153 insertions(+)
create mode 100644 docs/data-sources/all_users.md
create mode 100644 internal/provider/data_source_all_users.go
diff --git a/docs/data-sources/all_users.md b/docs/data-sources/all_users.md
new file mode 100644
index 0000000..50fc63c
--- /dev/null
+++ b/docs/data-sources/all_users.md
@@ -0,0 +1,30 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "slack_all_users Data Source - slack"
+subcategory: ""
+description: |-
+
+---
+
+# slack_all_users (Data Source)
+
+
+
+
+
+
+## Schema
+
+### Read-Only
+
+- `total_users` (Number) Number of users returned.
+- `users` (Attributes List) List of activated and non-bot Slack users. (see [below for nested schema](#nestedatt--users))
+
+
+### Nested Schema for `users`
+
+Read-Only:
+
+- `email` (String) User's email address.
+- `id` (String) User's Slack ID.
+- `name` (String) User's name.
diff --git a/internal/provider/data_source_all_users.go b/internal/provider/data_source_all_users.go
new file mode 100644
index 0000000..0970ffc
--- /dev/null
+++ b/internal/provider/data_source_all_users.go
@@ -0,0 +1,122 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+ "context"
+ "fmt"
+
+ "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 = &AllUsersDataSource{}
+
+func NewAllUsersDataSource() datasource.DataSource {
+ return &AllUsersDataSource{}
+}
+
+type AllUsersDataSource struct {
+ client *slack.Client
+}
+
+type AllUsersDataSourceModel struct {
+ Totalusers types.Int64 `tfsdk:"total_users"`
+ Users []AllUsersDataSourceModelUserItem `tfsdk:"users"`
+}
+
+type AllUsersDataSourceModelUserItem struct {
+ ID types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ Email types.String `tfsdk:"email"`
+}
+
+func (d *AllUsersDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_all_users"
+}
+
+func (d *AllUsersDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Attributes: map[string]schema.Attribute{
+ "total_users": schema.Int64Attribute{
+ Description: "Number of users returned.",
+ Computed: true,
+ },
+ "users": schema.ListNestedAttribute{
+ Description: "List of activated and non-bot Slack users.",
+ Computed: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ Description: "User's Slack ID.",
+ Computed: true,
+ },
+ "name": schema.StringAttribute{
+ Description: "User's name.",
+ Computed: true,
+ },
+ "email": schema.StringAttribute{
+ Description: "User's email address.",
+ Computed: true,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func (d *AllUsersDataSource) 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 *AllUsersDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ var data AllUsersDataSourceModel
+
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ users, err := d.client.GetUsersContext(ctx)
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Client Error",
+ fmt.Sprintf("Unable to fetch Slack users: %s", err),
+ )
+ return
+ }
+
+ tflog.Trace(ctx, "Fetched Slack users", map[string]any{"total_users": len(users)})
+
+ var resultingList []AllUsersDataSourceModelUserItem
+ for _, user := range users {
+ if !user.Deleted && !user.IsBot {
+ resultingList = append(resultingList, AllUsersDataSourceModelUserItem{
+ ID: types.StringValue(user.ID),
+ Name: types.StringValue(user.Profile.RealName),
+ Email: types.StringValue(user.Profile.Email),
+ })
+ }
+ }
+
+ data.Users = resultingList
+ data.Totalusers = types.Int64Value(int64(len(resultingList)))
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index ea2d037..e27be37 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -87,6 +87,7 @@ func (p *SlackProvider) Resources(ctx context.Context) []func() resource.Resourc
func (p *SlackProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
NewUserDataSource,
+ NewAllUsersDataSource,
}
}
From 64e6e9d60973423f188015d1f8a0d0428219618f Mon Sep 17 00:00:00 2001
From: atoni <50518795+bosc0@users.noreply.github.com>
Date: Fri, 3 Jan 2025 11:53:54 +0100
Subject: [PATCH 5/7] feat: allow providing api key as env var
---
docs/index.md | 4 ++--
internal/provider/provider.go | 27 ++++++++++++++++++---------
2 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/docs/index.md b/docs/index.md
index 7ec4404..637e08c 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -21,6 +21,6 @@ provider "scaffolding" {
## Schema
-### Required
+### Optional
-- `slack_token` (String, Sensitive) Slack token to authenticate API calls.
+- `slack_token` (String, Sensitive) Slack token to authenticate API calls. Can also be set with the `SLACK_TOKEN` environment variable.
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index e27be37..40b50a7 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -6,6 +6,7 @@ package provider
import (
"context"
"fmt"
+ "os"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/function"
@@ -41,8 +42,8 @@ func (p *SlackProvider) Schema(ctx context.Context, req provider.SchemaRequest,
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"slack_token": schema.StringAttribute{
- MarkdownDescription: "Slack token to authenticate API calls.",
- Required: true,
+ MarkdownDescription: "Slack token to authenticate API calls. Can also be set with the `SLACK_TOKEN` environment variable.",
+ Optional: true,
Sensitive: true,
},
},
@@ -56,15 +57,23 @@ func (p *SlackProvider) Configure(ctx context.Context, req provider.ConfigureReq
return
}
- if data.SlackToken.IsNull() || data.SlackToken.IsUnknown() {
- resp.Diagnostics.AddError(
- "Missing Slack Token",
- "The `slack_token` must be provided to authenticate API calls.",
- )
- return
+ slackToken := data.SlackToken.ValueString()
+
+ // If slack_token was not set in the provider block, check the environment variable.
+ if slackToken == "" {
+ envToken, ok := os.LookupEnv("SLACK_TOKEN")
+ if !ok || envToken == "" {
+ resp.Diagnostics.AddError(
+ "Missing Slack Token",
+ "`slack_token` was not set in the provider block, and `SLACK_TOKEN` is not set in the environment.",
+ )
+ return
+ }
+ slackToken = envToken
}
+
tflog.Info(ctx, "Configuring slack client")
- client := slack.New(data.SlackToken.ValueString())
+ client := slack.New(slackToken)
_, err := client.AuthTest()
if err != nil {
resp.Diagnostics.AddError(
From 3b1259f6840859993b5173c85afa1ba8314ca20a Mon Sep 17 00:00:00 2001
From: atoni <50518795+bosc0@users.noreply.github.com>
Date: Fri, 3 Jan 2025 12:01:46 +0100
Subject: [PATCH 6/7] fix: use correct name field
---
internal/provider/data_source_all_users.go | 2 +-
internal/provider/data_source_user.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/internal/provider/data_source_all_users.go b/internal/provider/data_source_all_users.go
index 0970ffc..c28c0cb 100644
--- a/internal/provider/data_source_all_users.go
+++ b/internal/provider/data_source_all_users.go
@@ -109,7 +109,7 @@ func (d *AllUsersDataSource) Read(ctx context.Context, req datasource.ReadReques
if !user.Deleted && !user.IsBot {
resultingList = append(resultingList, AllUsersDataSourceModelUserItem{
ID: types.StringValue(user.ID),
- Name: types.StringValue(user.Profile.RealName),
+ Name: types.StringValue(user.Name),
Email: types.StringValue(user.Profile.Email),
})
}
diff --git a/internal/provider/data_source_user.go b/internal/provider/data_source_user.go
index f263932..163fceb 100644
--- a/internal/provider/data_source_user.go
+++ b/internal/provider/data_source_user.go
@@ -117,7 +117,7 @@ func (d *UserDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
}
data.Email = types.StringValue(user.Profile.Email)
- data.Name = types.StringValue(user.Profile.DisplayNameNormalized)
+ data.Name = types.StringValue(user.Name)
data.ID = types.StringValue(user.ID)
tflog.Trace(ctx, "Fetched Slack user data", map[string]any{"id": user.ID})
From 101931db71e1599694aaf168fbffaff18420bd07 Mon Sep 17 00:00:00 2001
From: atoni <50518795+bosc0@users.noreply.github.com>
Date: Fri, 3 Jan 2025 14:32:11 +0100
Subject: [PATCH 7/7] feat: add data_source_all_usergroups.go
---
docs/data-sources/all_usergroups.md | 33 ++++
.../provider/data_source_all_usergroups.go | 155 ++++++++++++++++++
internal/provider/provider.go | 1 +
3 files changed, 189 insertions(+)
create mode 100644 docs/data-sources/all_usergroups.md
create mode 100644 internal/provider/data_source_all_usergroups.go
diff --git a/docs/data-sources/all_usergroups.md b/docs/data-sources/all_usergroups.md
new file mode 100644
index 0000000..0fb9d7f
--- /dev/null
+++ b/docs/data-sources/all_usergroups.md
@@ -0,0 +1,33 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "slack_all_usergroups Data Source - slack"
+subcategory: ""
+description: |-
+ Retrieve all Slack user groups.
+---
+
+# slack_all_usergroups (Data Source)
+
+Retrieve all Slack user groups.
+
+
+
+
+## Schema
+
+### Read-Only
+
+- `total_usergroups` (Number) Total number of user groups retrieved.
+- `usergroups` (Attributes List) List of Slack user groups. (see [below for nested schema](#nestedatt--usergroups))
+
+
+### Nested Schema for `usergroups`
+
+Read-Only:
+
+- `channels` (List of String) Channels shared by the user group.
+- `description` (String) Description of the user group.
+- `handle` (String) Handle of the user group (unique identifier).
+- `id` (String) User group's Slack ID.
+- `name` (String) Name of the user group.
+- `users` (List of String) List of user IDs in the user group.
diff --git a/internal/provider/data_source_all_usergroups.go b/internal/provider/data_source_all_usergroups.go
new file mode 100644
index 0000000..4504347
--- /dev/null
+++ b/internal/provider/data_source_all_usergroups.go
@@ -0,0 +1,155 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+ "context"
+ "fmt"
+
+ "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 = &AllUserGroupsDataSource{}
+
+func NewAllUserGroupsDataSource() datasource.DataSource {
+ return &AllUserGroupsDataSource{}
+}
+
+type AllUserGroupsDataSource struct {
+ client *slack.Client
+}
+
+type AllUserGroupsDataSourceModel struct {
+ TotalUserGroups types.Int64 `tfsdk:"total_usergroups"`
+ UserGroups []AllUserGroupsDataSourceGroupItem `tfsdk:"usergroups"`
+}
+
+type AllUserGroupsDataSourceGroupItem struct {
+ ID types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ Handle types.String `tfsdk:"handle"`
+ Channels []types.String `tfsdk:"channels"`
+ Users []types.String `tfsdk:"users"`
+}
+
+func (d *AllUserGroupsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_all_usergroups"
+}
+
+func (d *AllUserGroupsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Description: "Retrieve all Slack user groups.",
+ Attributes: map[string]schema.Attribute{
+ "total_usergroups": schema.Int64Attribute{
+ Description: "Total number of user groups retrieved.",
+ Computed: true,
+ },
+ "usergroups": schema.ListNestedAttribute{
+ Description: "List of Slack user groups.",
+ Computed: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ Description: "User group's Slack ID.",
+ Computed: true,
+ },
+ "name": schema.StringAttribute{
+ Description: "Name of the user group.",
+ Computed: true,
+ },
+ "description": schema.StringAttribute{
+ Description: "Description of the user group.",
+ Computed: true,
+ },
+ "handle": schema.StringAttribute{
+ Description: "Handle of the user group (unique identifier).",
+ Computed: true,
+ },
+ "channels": schema.ListAttribute{
+ Description: "Channels shared by the user group.",
+ ElementType: types.StringType,
+ Computed: true,
+ },
+ "users": schema.ListAttribute{
+ Description: "List of user IDs in the user group.",
+ ElementType: types.StringType,
+ Computed: true,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func (d *AllUserGroupsDataSource) 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 *AllUserGroupsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ var data AllUserGroupsDataSourceModel
+
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ userGroups, err := d.client.GetUserGroups(slack.GetUserGroupsOptionIncludeUsers(true))
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Client Error",
+ fmt.Sprintf("Unable to fetch Slack user groups: %s", err),
+ )
+ return
+ }
+
+ tflog.Trace(ctx, "Fetched Slack user groups", map[string]any{"total_usergroups": len(userGroups)})
+
+ var resultingList []AllUserGroupsDataSourceGroupItem
+ for _, group := range userGroups {
+ groupItem := AllUserGroupsDataSourceGroupItem{
+ ID: types.StringValue(group.ID),
+ Name: types.StringValue(group.Name),
+ Description: types.StringValue(group.Description),
+ Handle: types.StringValue(group.Handle),
+ }
+
+ channels := make([]types.String, len(group.Prefs.Channels))
+ for i, ch := range group.Prefs.Channels {
+ channels[i] = types.StringValue(ch)
+ }
+ groupItem.Channels = channels
+
+ users := make([]types.String, len(group.Users))
+ for i, u := range group.Users {
+ users[i] = types.StringValue(u)
+ }
+ groupItem.Users = users
+
+ resultingList = append(resultingList, groupItem)
+ }
+
+ data.UserGroups = resultingList
+ data.TotalUserGroups = types.Int64Value(int64(len(resultingList)))
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 40b50a7..a7bce2d 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -97,6 +97,7 @@ func (p *SlackProvider) DataSources(ctx context.Context) []func() datasource.Dat
return []func() datasource.DataSource{
NewUserDataSource,
NewAllUsersDataSource,
+ NewAllUserGroupsDataSource,
}
}