Skip to content

Commit e1b78a2

Browse files
authored
Auto pagination org users (#26)
* Add auto-pagination for organization users data resource * Include plugindocs * Set default batch size to 100, for org users data
1 parent 64176c2 commit e1b78a2

File tree

6 files changed

+54
-83
lines changed

6 files changed

+54
-83
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ cd terraform-provider-openai
8181
# Install dependencies and build
8282
make install
8383

84+
# or make install-dev, to avoid conflicts with published version
85+
8486
# Run tests
8587
make test
8688
```
@@ -158,6 +160,10 @@ export OPENAI_ADMIN_KEY="your-admin-key" # For admin operations
158160
export OPENAI_ORGANIZATION_ID="your-org-id" # Optional
159161
```
160162

163+
#### Documentation
164+
165+
Make sure to run `tfplugindocs` if resources are updated.
166+
161167
## Testing
162168

163169
### Environment Setup

docs/data-sources/organization_users.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,12 @@ output "all_users_count" {
3333

3434
### Optional
3535

36-
- `after` (String) A cursor for use in pagination. 'after' is an object ID that defines your place in the list.
3736
- `emails` (List of String) Filter by the email address of users.
38-
- `limit` (Number) A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20.
3937
- `user_id` (String) The ID of a specific user to retrieve. If provided, other filter parameters are ignored.
4038

4139
### Read-Only
4240

43-
- `first_id` (String) The ID of the first user in the list
44-
- `has_more` (Boolean) Whether there are more users that can be retrieved by paginating
4541
- `id` (String) The ID of this resource.
46-
- `last_id` (String) The ID of the last user in the list
4742
- `users` (List of Object) List of users in the organization (see [below for nested schema](#nestedatt--users))
4843

4944
<a id="nestedatt--users"></a>

internal/provider/data_source_openai_organization_users.go

Lines changed: 39 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,6 @@ func dataSourceOpenAIOrganizationUsers() *schema.Resource {
2020
Optional: true,
2121
Description: "The ID of a specific user to retrieve. If provided, other filter parameters are ignored.",
2222
},
23-
"after": {
24-
Type: schema.TypeString,
25-
Optional: true,
26-
Description: "A cursor for use in pagination. 'after' is an object ID that defines your place in the list.",
27-
},
28-
"limit": {
29-
Type: schema.TypeInt,
30-
Optional: true,
31-
Default: 20,
32-
Description: "A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20.",
33-
},
3423
"emails": {
3524
Type: schema.TypeList,
3625
Optional: true,
@@ -78,21 +67,6 @@ func dataSourceOpenAIOrganizationUsers() *schema.Resource {
7867
},
7968
Description: "List of users in the organization",
8069
},
81-
"first_id": {
82-
Type: schema.TypeString,
83-
Computed: true,
84-
Description: "The ID of the first user in the list",
85-
},
86-
"last_id": {
87-
Type: schema.TypeString,
88-
Computed: true,
89-
Description: "The ID of the last user in the list",
90-
},
91-
"has_more": {
92-
Type: schema.TypeBool,
93-
Computed: true,
94-
Description: "Whether there are more users that can be retrieved by paginating",
95-
},
9670
},
9771
}
9872
}
@@ -139,27 +113,9 @@ func dataSourceOpenAIOrganizationUsersRead(ctx context.Context, d *schema.Resour
139113
return diag.FromErr(fmt.Errorf("error setting users: %s", err))
140114
}
141115

142-
// For a single user, has_more is always false
143-
if err := d.Set("has_more", false); err != nil {
144-
return diag.FromErr(fmt.Errorf("error setting has_more: %s", err))
145-
}
146-
147-
// Set first_id and last_id to the user's ID
148-
if err := d.Set("first_id", user.ID); err != nil {
149-
return diag.FromErr(fmt.Errorf("error setting first_id: %s", err))
150-
}
151-
152-
if err := d.Set("last_id", user.ID); err != nil {
153-
return diag.FromErr(fmt.Errorf("error setting last_id: %s", err))
154-
}
155-
156116
return nil
157117
}
158118

159-
// If no specific user ID, list users with filters
160-
after := d.Get("after").(string)
161-
limit := d.Get("limit").(int)
162-
163119
// Extract the emails filter if provided
164120
var emails []string
165121
if rawEmails, ok := d.GetOk("emails"); ok {
@@ -168,46 +124,53 @@ func dataSourceOpenAIOrganizationUsersRead(ctx context.Context, d *schema.Resour
168124
}
169125
}
170126

171-
tflog.Debug(ctx, fmt.Sprintf("Listing organization users with limit: %d", limit))
127+
// Automatic pagination - fetch all users with default batch size
128+
const batchSize = 100
129+
tflog.Debug(ctx, fmt.Sprintf("Fetching all organization users with batch size: %d", batchSize))
172130

173-
// Call the API using the provider's API key
174-
resp, err := c.ListUsers(after, limit, emails)
175-
if err != nil {
176-
return diag.Errorf("error listing organization users: %s", err)
177-
}
131+
var allUsers []map[string]interface{}
132+
var after string
133+
hasMore := true
134+
pageCount := 0
178135

179-
// Set a unique ID based on the query parameters
180-
d.SetId(fmt.Sprintf("organization-users-%s-%d", after, limit))
181-
182-
// Prepare the users list
183-
users := make([]map[string]interface{}, 0, len(resp.Data))
184-
for _, user := range resp.Data {
185-
u := map[string]interface{}{
186-
"id": user.ID,
187-
"object": user.Object,
188-
"email": user.Email,
189-
"name": user.Name,
190-
"role": user.Role,
191-
"added_at": user.AddedAt,
136+
// Paginate through all results
137+
for hasMore {
138+
pageCount++
139+
tflog.Debug(ctx, fmt.Sprintf("Fetching page %d with after: %s", pageCount, after))
140+
141+
resp, err := c.ListUsers(after, batchSize, emails)
142+
if err != nil {
143+
return diag.Errorf("error listing organization users (page %d): %s", pageCount, err)
192144
}
193-
users = append(users, u)
194-
}
195145

196-
// Set the computed values
197-
if err := d.Set("users", users); err != nil {
198-
return diag.FromErr(fmt.Errorf("error setting users: %s", err))
199-
}
146+
// Add users from this page to the collection
147+
for _, user := range resp.Data {
148+
u := map[string]interface{}{
149+
"id": user.ID,
150+
"object": user.Object,
151+
"email": user.Email,
152+
"name": user.Name,
153+
"role": user.Role,
154+
"added_at": user.AddedAt,
155+
}
156+
allUsers = append(allUsers, u)
157+
}
200158

201-
if err := d.Set("has_more", resp.HasMore); err != nil {
202-
return diag.FromErr(fmt.Errorf("error setting has_more: %s", err))
159+
// Check if there are more pages
160+
hasMore = resp.HasMore
161+
if hasMore && resp.LastID != "" {
162+
after = resp.LastID
163+
}
203164
}
204165

205-
if err := d.Set("first_id", resp.FirstID); err != nil {
206-
return diag.FromErr(fmt.Errorf("error setting first_id: %s", err))
207-
}
166+
tflog.Debug(ctx, fmt.Sprintf("Fetched %d total users across %d pages", len(allUsers), pageCount))
167+
168+
// Set a unique ID for the data source
169+
d.SetId(fmt.Sprintf("organization-users-all-%d", len(allUsers)))
208170

209-
if err := d.Set("last_id", resp.LastID); err != nil {
210-
return diag.FromErr(fmt.Errorf("error setting last_id: %s", err))
171+
// Set the computed values
172+
if err := d.Set("users", allUsers); err != nil {
173+
return diag.FromErr(fmt.Errorf("error setting users: %s", err))
211174
}
212175

213176
return nil

internal/provider/resource_openai_model_response.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ func resourceOpenAIModelResponseCreate(ctx context.Context, d *schema.ResourceDa
254254

255255
// Use the /v1/responses endpoint
256256
path := "/v1/responses"
257-
257+
258258
// Make the request using the client's method
259259
respBody, err := providerClient.DoRequest("POST", path, requestBody)
260260
if err != nil {

internal/provider/resource_openai_organization_user.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,3 @@ func resourceOpenAIOrganizationUserDelete(ctx context.Context, d *schema.Resourc
199199
d.SetId("")
200200
return nil
201201
}
202-

tools/tools.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//go:build tools
2+
3+
package tools
4+
5+
import (
6+
// Documentation generation
7+
_ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
8+
)

0 commit comments

Comments
 (0)