@@ -41,13 +41,14 @@ type UserResource struct {
4141type UserResourceModel struct {
4242ID types.String `tfsdk:"id"`
4343
44- Username types.String `tfsdk:"username"`
45- Name types.String `tfsdk:"name"`
46- Email types.String `tfsdk:"email"`
47- Roles types.Set `tfsdk:"roles"` // owner, template-admin, user-admin, auditor (member is implicit)
48- LoginType types.String `tfsdk:"login_type"` // none, password, github, oidc
49- Password types.String `tfsdk:"password"` // only when login_type is password
50- Suspended types.Bool `tfsdk:"suspended"`
44+ Username types.String `tfsdk:"username"`
45+ Name types.String `tfsdk:"name"`
46+ Email types.String `tfsdk:"email"`
47+ Roles types.Set `tfsdk:"roles"` // owner, template-admin, user-admin, auditor (member is implicit)
48+ LoginType types.String `tfsdk:"login_type"` // none, password, github, oidc
49+ Password types.String `tfsdk:"password"` // only when login_type is password
50+ Suspended types.Bool `tfsdk:"suspended"`
51+ CascadeDelete types.Bool `tfsdk:"cascade_delete"`
5152}
5253
5354func (r * UserResource )Metadata (ctx context.Context ,req resource.MetadataRequest ,resp * resource.MetadataResponse ) {
@@ -79,7 +80,7 @@ func (r *UserResource) Schema(ctx context.Context, req resource.SchemaRequest, r
7980// Defaulted in Create
8081},
8182"email" : schema.StringAttribute {
82- MarkdownDescription :"Email address of the user." ,
83+ MarkdownDescription :"Email address of the user. Modifying this field will trigger a resource replacement. " ,
8384Required :true ,
8485PlanModifiers : []planmodifier.String {
8586stringplanmodifier .RequiresReplace (),
@@ -121,6 +122,13 @@ func (r *UserResource) Schema(ctx context.Context, req resource.SchemaRequest, r
121122Optional :true ,
122123Default :booldefault .StaticBool (false ),
123124},
125+ "cascade_delete" : schema.BoolAttribute {
126+ Computed :true ,
127+ MarkdownDescription :"Whether to delete owned workspaces when this resource is deleted or replaced." ,
128+ Required :false ,
129+ Optional :true ,
130+ Default :booldefault .StaticBool (false ),
131+ },
124132},
125133}
126134}
@@ -366,6 +374,29 @@ func (r *UserResource) Delete(ctx context.Context, req resource.DeleteRequest, r
366374resp .Diagnostics .AddError ("Data Error" ,fmt .Sprintf ("Unable to parse user ID, got error: %s" ,err ))
367375return
368376}
377+
378+ if data .CascadeDelete .ValueBool () {
379+ tflog .Trace (ctx ,"deleting user workspaces" )
380+ workspaces ,err := client .Workspaces (ctx , codersdk.WorkspaceFilter {
381+ Owner :data .Username .ValueString (),
382+ })
383+ if err != nil {
384+ resp .Diagnostics .AddError ("Client Error" ,fmt .Sprintf ("Unable to get user workspaces, got error: %s" ,err ))
385+ return
386+ }
387+ for _ ,workspace := range workspaces .Workspaces {
388+ _ ,err := client .CreateWorkspaceBuild (ctx ,workspace .ID , codersdk.CreateWorkspaceBuildRequest {
389+ Transition :codersdk .WorkspaceTransitionDelete ,
390+ })
391+ if err != nil {
392+ resp .Diagnostics .AddError ("Client Error" ,fmt .Sprintf ("Unable to delete user workspace, got error: %s" ,err ))
393+ return
394+ }
395+ }
396+ //TODO: Wait for builds to finish
397+ tflog .Trace (ctx ,"successfully deleted user workspaces" )
398+ }
399+
369400tflog .Trace (ctx ,"deleting user" )
370401err = client .DeleteUser (ctx ,id )
371402if err != nil {