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

[After #443] Feature: add filtering support for twingate_users datasource #456

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b12299a
added new attributes for resources datasource
vmanilo Dec 17, 2023
858c510
added optional name attributes for resources datasource
vmanilo Dec 17, 2023
e203748
added feature branch
vmanilo Dec 17, 2023
ea6a201
fix test
vmanilo Dec 18, 2023
8347c58
remove feature branch
vmanilo Dec 18, 2023
605b1df
enable tests
vmanilo Dec 23, 2023
ac7dbfe
remove feature branch
vmanilo Dec 23, 2023
d0fb2ba
refactore
vmanilo Dec 24, 2023
5ed4cb0
added optional filters to users datasource
vmanilo Jan 1, 2024
1361403
updated docs
vmanilo Jan 1, 2024
7fd9289
Merge branch 'feature/add-filtering-support-for-twingate_resources-da…
vmanilo Jan 1, 2024
a9bd6be
wip: adding acc tests
vmanilo Jan 2, 2024
f1954f2
Merge remote-tracking branch 'upstream/main' into feature/add-filteri…
vmanilo Jan 3, 2024
118a6a7
update resources datasource: allow to list all resources
vmanilo Jan 3, 2024
bf322a6
Merge branch 'feature/add-filtering-support-for-twingate_resources-da…
vmanilo Jan 3, 2024
b755d93
added tests for email filter
vmanilo Jan 3, 2024
c1f33ba
Merge branch 'main' into feature/add-filtering-support-for-twingate_r…
vmanilo Jan 7, 2024
5043500
Merge branch 'main' into feature/add-filtering-support-for-twingate_r…
vmanilo Jan 10, 2024
1c93b93
wip: adding user tests
vmanilo Jan 10, 2024
c7b39a5
Merge remote-tracking branch 'upstream/main' into feature/add-filteri…
vmanilo Jan 10, 2024
3f7e1cf
added acctests for users datasource
vmanilo Jan 10, 2024
71a546b
enable tests
vmanilo Jan 10, 2024
8b8ee92
fix test
vmanilo Jan 10, 2024
4b5f4b6
fix test
vmanilo Jan 10, 2024
061e6f6
fix test
vmanilo Jan 10, 2024
e36c65c
Merge branch 'main' into feature/add-filtering-support-for-twingate_r…
vmanilo Jan 17, 2024
9d385c2
Merge remote-tracking branch 'upstream/main' into feature/add-filteri…
vmanilo Jan 17, 2024
189f369
Merge remote-tracking branch 'upstream/main' into feature/add-filteri…
vmanilo Jan 18, 2024
eb2b8aa
revert ci changes
vmanilo Jan 18, 2024
e846b3e
Merge branch 'main' into feature/add-filtering-support-for-twingate_r…
vmanilo Jan 20, 2024
e39fa34
fix docs
vmanilo Jan 20, 2024
0ba38d1
Merge branch 'feature/add-filtering-support-for-twingate_users-dataso…
vmanilo Jan 20, 2024
43204fa
Merge remote-tracking branch 'origin/feature/add-filtering-support-fo…
vmanilo Jan 20, 2024
5572f68
Merge branch 'main' into feature/add-filtering-support-for-twingate_r…
vmanilo Jan 27, 2024
fa232b6
Merge branch 'main' into feature/add-filtering-support-for-twingate_r…
vmanilo Feb 1, 2024
3dae7f2
Merge branch 'main' into feature/add-filtering-support-for-twingate_r…
vmanilo Feb 16, 2024
5ccb598
Merge remote-tracking branch 'origin/feature/add-filtering-support-fo…
vmanilo Feb 16, 2024
5c5022f
Merge branch 'main' into feature/add-filtering-support-for-twingate_u…
vmanilo Feb 16, 2024
d13324a
Merge remote-tracking branch 'upstream/main' into feature/add-filteri…
vmanilo Feb 20, 2024
02068bc
fix linter issue
vmanilo Feb 20, 2024
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
47 changes: 46 additions & 1 deletion docs/data-sources/users.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,57 @@ Users in Twingate can be given access to Twingate Resources and may either be ad
## Example Usage

```terraform
data "twingate_users" "all" {}
data "twingate_users" "all" {
# email = "<your user's email>"
# email_regexp = "<regular expression of user email>"
# email_contains = "<a string in the user email>"
# email_exclude = "<your user's email to exclude>"
# email_prefix = "<prefix of user email>"
# email_suffix = "<suffix of user email>"

# first_name = "<your user's first name>"
# first_name_regexp = "<regular expression of user first name>"
# first_name_contains = "<a string in the user first name>"
# first_name_exclude = "<your user's first name to exclude>"
# first_name_prefix = "<prefix of user first name>"
# first_name_suffix = "<suffix of user first name>"

# last_name = "<your user's last name>"
# last_name_regexp = "<regular expression of user last name>"
# last_name_contains = "<a string in the user last name>"
# last_name_exclude = "<your user's last name to exclude>"
# last_name_prefix = "<prefix of user last name>"
# last_name_suffix = "<suffix of user last name>"

# roles = ["ADMIN", "DEVOPS", "SUPPORT", "MEMBER"]
}
```

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

### Optional

- `email` (String) Returns only users that exactly match this email.
- `email_contains` (String) Match when the value exist in the email of the user.
- `email_exclude` (String) Match when the value does not exist in the email of the user.
- `email_prefix` (String) The email of the user must start with the value.
- `email_regexp` (String) The regular expression match of the email of the user.
- `email_suffix` (String) The email of the user must end with the value.
- `first_name` (String) Returns only users that exactly match the first name.
- `first_name_contains` (String) Match when the value exist in the first name of the user.
- `first_name_exclude` (String) Match when the value does not exist in the first name of the user.
- `first_name_prefix` (String) The first name of the user must start with the value.
- `first_name_regexp` (String) The regular expression match of the first name of the user.
- `first_name_suffix` (String) The first name of the user must end with the value.
- `last_name` (String) Returns only users that exactly match the last name.
- `last_name_contains` (String) Match when the value exist in the last name of the user.
- `last_name_exclude` (String) Match when the value does not exist in the last name of the user.
- `last_name_prefix` (String) The last name of the user must start with the value.
- `last_name_regexp` (String) The regular expression match of the last name of the user.
- `last_name_suffix` (String) The last name of the user must end with the value.
- `roles` (Set of String) Returns users that match a list of roles. Valid roles: `ADMIN`, `DEVOPS`, `SUPPORT`, `MEMBER`.

### Read-Only

- `id` (String) The ID of this resource.
Expand Down
25 changes: 24 additions & 1 deletion examples/data-sources/twingate_users/data-source.tf
Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
data "twingate_users" "all" {}
data "twingate_users" "all" {
# email = "<your user's email>"
# email_regexp = "<regular expression of user email>"
# email_contains = "<a string in the user email>"
# email_exclude = "<your user's email to exclude>"
# email_prefix = "<prefix of user email>"
# email_suffix = "<suffix of user email>"

# first_name = "<your user's first name>"
# first_name_regexp = "<regular expression of user first name>"
# first_name_contains = "<a string in the user first name>"
# first_name_exclude = "<your user's first name to exclude>"
# first_name_prefix = "<prefix of user first name>"
# first_name_suffix = "<suffix of user first name>"

# last_name = "<your user's last name>"
# last_name_regexp = "<regular expression of user last name>"
# last_name_contains = "<a string in the user last name>"
# last_name_exclude = "<your user's last name to exclude>"
# last_name_prefix = "<prefix of user last name>"
# last_name_suffix = "<suffix of user last name>"

# roles = ["ADMIN", "DEVOPS", "SUPPORT", "MEMBER"]
}
1 change: 1 addition & 0 deletions twingate/internal/attr/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const (
LastName = "last_name"
Email = "email"
Role = "role"
Roles = "roles"
Users = "users"
SendInvite = "send_invite"
State = "state"
Expand Down
13 changes: 7 additions & 6 deletions twingate/internal/client/query/groups-read.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ type GroupFilterInput struct {
}

type StringFilterOperationInput struct {
Eq *string `json:"eq"`
Ne *string `json:"ne"`
StartsWith *string `json:"startsWith"`
EndsWith *string `json:"endsWith"`
Regexp *string `json:"regexp"`
Contains *string `json:"contains"`
Eq *string `json:"eq"`
Ne *string `json:"ne"`
StartsWith *string `json:"startsWith"`
EndsWith *string `json:"endsWith"`
Regexp *string `json:"regexp"`
Contains *string `json:"contains"`
In []string `json:"in"`
}

func NewStringFilterOperationInput(name, filter string) *StringFilterOperationInput {
Expand Down
13 changes: 12 additions & 1 deletion twingate/internal/client/query/users-read.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
const CursorUsers = "usersEndCursor"

type ReadUsers struct {
Users `graphql:"users(after: $usersEndCursor, first: $pageLimit)"`
Users `graphql:"users(filter: $filter, after: $usersEndCursor, first: $pageLimit)"`
}

func (q ReadUsers) IsEmpty() bool {
Expand All @@ -28,3 +28,14 @@ func (u Users) ToModel() []*model.User {
return edge.Node.ToModel()
})
}

type UserFilterInput struct {
FirstName *StringFilterOperationInput `json:"firstName"`
LastName *StringFilterOperationInput `json:"lastName"`
Email *StringFilterOperationInput `json:"email"`
Role *UserRoleFilterOperationInput `json:"role"`
}

type UserRoleFilterOperationInput struct {
In []UserRole `json:"in"`
}
46 changes: 45 additions & 1 deletion twingate/internal/client/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,56 @@ import (

"github.com/Twingate/terraform-provider-twingate/twingate/internal/client/query"
"github.com/Twingate/terraform-provider-twingate/twingate/internal/model"
"github.com/Twingate/terraform-provider-twingate/twingate/internal/utils"
)

func (client *Client) ReadUsers(ctx context.Context) ([]*model.User, error) {
type StringFilter struct {
Name string
Filter string
}

type UsersFilter struct {
Email *StringFilter
FirstName *StringFilter
LastName *StringFilter
Roles []string
}

func NewUserFilterInput(filter *UsersFilter) *query.UserFilterInput {
if filter == nil {
return nil
}

queryFilter := &query.UserFilterInput{}

if filter.FirstName != nil {
queryFilter.FirstName = query.NewStringFilterOperationInput(filter.FirstName.Name, filter.FirstName.Filter)
}

if filter.LastName != nil {
queryFilter.LastName = query.NewStringFilterOperationInput(filter.LastName.Name, filter.LastName.Filter)
}

if filter.Email != nil {
queryFilter.Email = query.NewStringFilterOperationInput(filter.Email.Name, filter.Email.Filter)
}

if len(filter.Roles) > 0 {
queryFilter.Role = &query.UserRoleFilterOperationInput{
In: utils.Map(filter.Roles, func(item string) query.UserRole {
return query.UserRole(item)
}),
}
}

return queryFilter
}

func (client *Client) ReadUsers(ctx context.Context, filter *UsersFilter) ([]*model.User, error) {
opr := resourceUser.read()

variables := newVars(
gqlNullable(NewUserFilterInput(filter), "filter"),
cursor(query.CursorUsers),
pageLimit(client.pageLimit),
)
Expand Down
32 changes: 1 addition & 31 deletions twingate/internal/provider/datasource/connectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ func (d *connectors) Schema(ctx context.Context, req datasource.SchemaRequest, r
}
}

//nolint:cyclop
func (d *connectors) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data connectorsModel

Expand All @@ -132,36 +131,7 @@ func (d *connectors) Read(ctx context.Context, req datasource.ReadRequest, resp
return
}

var name, filter string

if data.Name.ValueString() != "" {
name = data.Name.ValueString()
}

if data.NameRegexp.ValueString() != "" {
name = data.NameRegexp.ValueString()
filter = attr.FilterByRegexp
}

if data.NameContains.ValueString() != "" {
name = data.NameContains.ValueString()
filter = attr.FilterByContains
}

if data.NameExclude.ValueString() != "" {
name = data.NameExclude.ValueString()
filter = attr.FilterByExclude
}

if data.NamePrefix.ValueString() != "" {
name = data.NamePrefix.ValueString()
filter = attr.FilterByPrefix
}

if data.NameSuffix.ValueString() != "" {
name = data.NameSuffix.ValueString()
filter = attr.FilterBySuffix
}
name, filter := getNameFilter(data.Name, data.NameRegexp, data.NameContains, data.NameExclude, data.NamePrefix, data.NameSuffix)

if countOptionalAttributes(data.Name, data.NameRegexp, data.NameContains, data.NameExclude, data.NamePrefix, data.NameSuffix) > 1 {
addErr(&resp.Diagnostics, ErrConnectorsDatasourceShouldSetOneOptionalNameAttribute, TwingateResources)
Expand Down
36 changes: 36 additions & 0 deletions twingate/internal/provider/datasource/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package datasource
import (
"fmt"

"github.com/Twingate/terraform-provider-twingate/twingate/internal/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
)
Expand All @@ -29,3 +30,38 @@ func countOptionalAttributes(attributes ...types.String) int {

return count
}

func getNameFilter(name, nameRegexp, nameContains, nameExclude, namePrefix, nameSuffix types.String) (string, string) {
var value, filter string

if name.ValueString() != "" {
value = name.ValueString()
}

if nameRegexp.ValueString() != "" {
value = nameRegexp.ValueString()
filter = attr.FilterByRegexp
}

if nameContains.ValueString() != "" {
value = nameContains.ValueString()
filter = attr.FilterByContains
}

if nameExclude.ValueString() != "" {
value = nameExclude.ValueString()
filter = attr.FilterByExclude
}

if namePrefix.ValueString() != "" {
value = namePrefix.ValueString()
filter = attr.FilterByPrefix
}

if nameSuffix.ValueString() != "" {
value = nameSuffix.ValueString()
filter = attr.FilterBySuffix
}

return value, filter
}
32 changes: 1 addition & 31 deletions twingate/internal/provider/datasource/remote-networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ func (d *remoteNetworks) Schema(ctx context.Context, req datasource.SchemaReques
}
}

//nolint:cyclop
func (d *remoteNetworks) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data remoteNetworksModel

Expand All @@ -129,36 +128,7 @@ func (d *remoteNetworks) Read(ctx context.Context, req datasource.ReadRequest, r
return
}

var name, filter string

if data.Name.ValueString() != "" {
name = data.Name.ValueString()
}

if data.NameRegexp.ValueString() != "" {
name = data.NameRegexp.ValueString()
filter = attr.FilterByRegexp
}

if data.NameContains.ValueString() != "" {
name = data.NameContains.ValueString()
filter = attr.FilterByContains
}

if data.NameExclude.ValueString() != "" {
name = data.NameExclude.ValueString()
filter = attr.FilterByExclude
}

if data.NamePrefix.ValueString() != "" {
name = data.NamePrefix.ValueString()
filter = attr.FilterByPrefix
}

if data.NameSuffix.ValueString() != "" {
name = data.NameSuffix.ValueString()
filter = attr.FilterBySuffix
}
name, filter := getNameFilter(data.Name, data.NameRegexp, data.NameContains, data.NameExclude, data.NamePrefix, data.NameSuffix)

if countOptionalAttributes(data.Name, data.NameRegexp, data.NameContains, data.NameExclude, data.NamePrefix, data.NameSuffix) > 1 {
addErr(&resp.Diagnostics, ErrRemoteNetworksDatasourceShouldSetOneOptionalNameAttribute, TwingateRemoteNetworks)
Expand Down
32 changes: 1 addition & 31 deletions twingate/internal/provider/datasource/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ func (d *resources) Schema(ctx context.Context, req datasource.SchemaRequest, re
}
}

//nolint:cyclop
func (d *resources) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data resourcesModel

Expand All @@ -161,36 +160,7 @@ func (d *resources) Read(ctx context.Context, req datasource.ReadRequest, resp *
return
}

var name, filter string

if data.Name.ValueString() != "" {
name = data.Name.ValueString()
}

if data.NameRegexp.ValueString() != "" {
name = data.NameRegexp.ValueString()
filter = attr.FilterByRegexp
}

if data.NameContains.ValueString() != "" {
name = data.NameContains.ValueString()
filter = attr.FilterByContains
}

if data.NameExclude.ValueString() != "" {
name = data.NameExclude.ValueString()
filter = attr.FilterByExclude
}

if data.NamePrefix.ValueString() != "" {
name = data.NamePrefix.ValueString()
filter = attr.FilterByPrefix
}

if data.NameSuffix.ValueString() != "" {
name = data.NameSuffix.ValueString()
filter = attr.FilterBySuffix
}
name, filter := getNameFilter(data.Name, data.NameRegexp, data.NameContains, data.NameExclude, data.NamePrefix, data.NameSuffix)

if countOptionalAttributes(data.Name, data.NameRegexp, data.NameContains, data.NameExclude, data.NamePrefix, data.NameSuffix) > 1 {
addErr(&resp.Diagnostics, ErrResourcesDatasourceShouldSetOneOptionalNameAttribute, TwingateResources)
Expand Down
Loading
Loading