teamcity/user_data_source.go (147 lines of code) (raw):
package teamcity
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"strconv"
"terraform-provider-teamcity/client"
)
var (
_ datasource.DataSource = &userDataSource{}
_ datasource.DataSourceWithConfigure = &userDataSource{}
)
type userDataSource struct {
client *client.Client
}
func NewUserDataSource() datasource.DataSource {
return &userDataSource{}
}
func (d *userDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_user"
}
type userDataSourceModel struct {
Id types.String `tfsdk:"id"`
Username types.String `tfsdk:"username"`
Github types.String `tfsdk:"github_username"`
Roles []roleAssignment `tfsdk:"roles"`
}
func (d *userDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Use this data source to get information about an existing TeamCity user.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Optional: true,
Computed: true,
Description: "The internal ID of the user. Either id or username must be specified.",
},
"username": schema.StringAttribute{
Optional: true,
Computed: true,
Description: "The username of the user. Either id or username must be specified.",
},
"github_username": schema.StringAttribute{
Computed: true,
Description: "The GitHub username associated with the user.",
},
"roles": schema.SetNestedAttribute{
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
Description: "The role ID.",
},
"global": schema.BoolAttribute{
Computed: true,
Description: "Whether the role is assigned globally.",
},
"project": schema.StringAttribute{
Computed: true,
Description: "The project ID if the role is project-specific.",
},
},
},
Description: "List of roles assigned to the user.",
},
},
}
}
func (d *userDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
d.client = req.ProviderData.(*client.Client)
}
func (d *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var config userDataSourceModel
diags := req.Config.Get(ctx, &config)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
// Validate that either id or username is specified
if config.Id.IsNull() && config.Username.IsNull() {
resp.Diagnostics.AddError(
"Invalid configuration",
"Either 'id' or 'username' must be specified",
)
return
}
var user *client.User
var err error
// Get user by id or username
if !config.Id.IsNull() {
user, err = d.client.GetUser(config.Id.ValueString())
} else {
user, err = d.client.GetUserByName(config.Username.ValueString())
}
if err != nil {
resp.Diagnostics.AddError(
"Error reading user",
err.Error(),
)
return
}
if user == nil {
identifier := config.Id.ValueString()
if config.Id.IsNull() {
identifier = config.Username.ValueString()
}
resp.Diagnostics.AddError(
"User not found",
"The user '"+identifier+"' was not found",
)
return
}
// Map response to model
state := userDataSourceModel{
Id: types.StringValue(strconv.FormatInt(*user.Id, 10)),
Username: types.StringValue(user.Username),
}
// Extract GitHub username from properties
if user.Properties != nil {
for _, p := range user.Properties.Property {
if p.Name == "plugin:auth:GitHubApp-oauth:userName" {
state.Github = types.StringValue(p.Value)
break
}
}
}
if state.Github.IsNull() {
state.Github = types.StringNull()
}
// Map roles
if user.Roles != nil && len(user.Roles.RoleAssignment) > 0 {
state.Roles = []roleAssignment{}
for _, role := range user.Roles.RoleAssignment {
assignment := roleAssignment{
Id: types.StringValue(role.Id),
}
if role.Scope == "g" {
assignment.Global = types.BoolValue(true)
} else {
assignment.Global = types.BoolValue(false)
assignment.Project = types.StringValue(role.Scope[2:])
}
state.Roles = append(state.Roles, assignment)
}
}
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
}