@@ -66,27 +66,23 @@ func (r *UserResource) Schema(ctx context.Context, req resource.SchemaRequest, r
6666 stringplanmodifier .UseStateForUnknown (),
6767 },
6868 },
69-
7069 "username" : schema.StringAttribute {
7170 MarkdownDescription : "Username of the user." ,
7271 Required : true ,
7372 },
7473 "name" : schema.StringAttribute {
75- Computed : true ,
7674 MarkdownDescription : "Display name of the user. Defaults to username." ,
77- Required : false ,
75+ Computed : true ,
7876 Optional : true ,
79- // Defaulted in Create
8077 },
8178 "email" : schema.StringAttribute {
8279 MarkdownDescription : "Email address of the user." ,
8380 Required : true ,
8481 },
8582 "roles" : schema.SetAttribute {
8683 MarkdownDescription : "Roles assigned to the user. Valid roles are 'owner', 'template-admin', 'user-admin', and 'auditor'." ,
87- Required : false ,
88- Optional : true ,
8984 Computed : true ,
85+ Optional : true ,
9086 ElementType : types .StringType ,
9187 Validators : []validator.Set {
9288 setvalidator .ValueStringsAre (
@@ -97,24 +93,24 @@ func (r *UserResource) Schema(ctx context.Context, req resource.SchemaRequest, r
9793 },
9894 "login_type" : schema.StringAttribute {
9995 MarkdownDescription : "Type of login for the user. Valid types are 'none', 'password', 'github', and 'oidc'." ,
100- Required : false ,
101- Optional : true ,
10296 Computed : true ,
97+ Optional : true ,
10398 Validators : []validator.String {
10499 stringvalidator .OneOf ("none" , "password" , "github" , "oidc" ),
105100 },
106101 Default : stringdefault .StaticString ("none" ),
102+ PlanModifiers : []planmodifier.String {
103+ stringplanmodifier .RequiresReplaceIfConfigured (),
104+ },
107105 },
108106 "password" : schema.StringAttribute {
109107 MarkdownDescription : "Password for the user. Required when login_type is 'password'. Passwords are saved into the state as plain text and should only be used for testing purposes." ,
110- Required : false ,
111108 Optional : true ,
112109 Sensitive : true ,
113110 },
114111 "suspended" : schema.BoolAttribute {
115- Computed : true ,
116112 MarkdownDescription : "Whether the user is suspended." ,
117- Required : false ,
113+ Computed : true ,
118114 Optional : true ,
119115 Default : booldefault .StaticBool (false ),
120116 },
@@ -164,14 +160,15 @@ func (r *UserResource) Create(ctx context.Context, req resource.CreateRequest, r
164160 }
165161
166162 tflog .Trace (ctx , "creating user" )
167- loginType := codersdk .LoginTypeNone
168- if data .LoginType .ValueString () != "" {
169- loginType = codersdk .LoginType (data .LoginType .ValueString ())
170- }
171- if loginType == codersdk .LoginTypePassword && data .Password .ValueString () == "" {
163+ loginType := codersdk .LoginType (data .LoginType .ValueString ())
164+ if loginType == codersdk .LoginTypePassword && data .Password .IsNull () {
172165 resp .Diagnostics .AddError ("Data Error" , "Password is required when login_type is 'password'" )
173166 return
174167 }
168+ if loginType != codersdk .LoginTypePassword && ! data .Password .IsNull () {
169+ resp .Diagnostics .AddError ("Data Error" , "Password is only allowed when login_type is 'password'" )
170+ return
171+ }
175172 user , err := client .CreateUser (ctx , codersdk.CreateUserRequest {
176173 Email : data .Email .ValueString (),
177174 Username : data .Username .ValueString (),
@@ -189,13 +186,13 @@ func (r *UserResource) Create(ctx context.Context, req resource.CreateRequest, r
189186 data .ID = UUIDValue (user .ID )
190187
191188 tflog .Trace (ctx , "updating user profile" )
192- name := data .Username . ValueString ()
189+ name := data .Username
193190 if data .Name .ValueString () != "" {
194- name = data .Name . ValueString ()
191+ name = data .Name
195192 }
196193 user , err = client .UpdateUserProfile (ctx , user .ID .String (), codersdk.UpdateUserProfileRequest {
197194 Username : data .Username .ValueString (),
198- Name : name ,
195+ Name : name . ValueString () ,
199196 })
200197 if err != nil {
201198 resp .Diagnostics .AddError ("Client Error" , fmt .Sprintf ("Unable to update newly created user profile, got error: %s" , err ))
@@ -290,18 +287,23 @@ func (r *UserResource) Update(ctx context.Context, req resource.UpdateRequest, r
290287 return
291288 }
292289
290+ name := data .Username
291+ if data .Name .ValueString () != "" {
292+ name = data .Name
293+ }
293294 tflog .Trace (ctx , "updating user" , map [string ]any {
294295 "new_username" : data .Username .ValueString (),
295- "new_name" : data . Name .ValueString (),
296+ "new_name" : name .ValueString (),
296297 })
297298 _ , err = client .UpdateUserProfile (ctx , user .ID .String (), codersdk.UpdateUserProfileRequest {
298299 Username : data .Username .ValueString (),
299- Name : data . Name .ValueString (),
300+ Name : name .ValueString (),
300301 })
301302 if err != nil {
302303 resp .Diagnostics .AddError ("Client Error" , fmt .Sprintf ("Unable to update user profile, got error: %s" , err ))
303304 return
304305 }
306+ data .Name = name
305307 tflog .Trace (ctx , "successfully updated user profile" )
306308
307309 var roles []string
@@ -320,15 +322,17 @@ func (r *UserResource) Update(ctx context.Context, req resource.UpdateRequest, r
320322 }
321323 tflog .Trace (ctx , "successfully updated user roles" )
322324
323- tflog .Trace (ctx , "updating password" )
324- err = client .UpdateUserPassword (ctx , user .ID .String (), codersdk.UpdateUserPasswordRequest {
325- Password : data .Password .ValueString (),
326- })
327- if err != nil && ! strings .Contains (err .Error (), "New password cannot match old password." ) {
328- resp .Diagnostics .AddError ("Client Error" , fmt .Sprintf ("Unable to update password, got error: %s" , err ))
329- return
325+ if data .LoginType .ValueString () == string (codersdk .LoginTypePassword ) && ! data .Password .IsNull () {
326+ tflog .Trace (ctx , "updating password" )
327+ err = client .UpdateUserPassword (ctx , user .ID .String (), codersdk.UpdateUserPasswordRequest {
328+ Password : data .Password .ValueString (),
329+ })
330+ if err != nil && ! strings .Contains (err .Error (), "New password cannot match old password." ) {
331+ resp .Diagnostics .AddError ("Client Error" , fmt .Sprintf ("Unable to update password, got error: %s" , err ))
332+ return
333+ }
334+ tflog .Trace (ctx , "successfully updated password" )
330335 }
331- tflog .Trace (ctx , "successfully updated password" )
332336
333337 var statusErr error
334338 if data .Suspended .ValueBool () {
0 commit comments