1package tfe
2
3import (
4	"context"
5	"fmt"
6	"net/url"
7)
8
9// Compile-time proof of interface implementation.
10var _ AdminUsers = (*adminUsers)(nil)
11
12// AdminUsers describes all the admin user related methods that the Terraform
13// Enterprise  API supports.
14// It contains endpoints to help site administrators manage their users.
15//
16// TFE API docs: https://www.terraform.io/docs/cloud/api/admin/users.html
17type AdminUsers interface {
18	// List all the users of the given installation.
19	List(ctx context.Context, options AdminUserListOptions) (*AdminUserList, error)
20
21	// Delete a user by its ID.
22	Delete(ctx context.Context, userID string) error
23
24	// Suspend a user by its ID.
25	Suspend(ctx context.Context, userID string) (*AdminUser, error)
26
27	// Unsuspend a user by its ID.
28	Unsuspend(ctx context.Context, userID string) (*AdminUser, error)
29
30	// GrantAdmin grants admin privilages to a user by its ID.
31	GrantAdmin(ctx context.Context, userID string) (*AdminUser, error)
32
33	// RevokeAdmin revokees admin privilages to a user by its ID.
34	RevokeAdmin(ctx context.Context, userID string) (*AdminUser, error)
35
36	// Disable2FA disables a user's two-factor authentication in the situation
37	// where they have lost access to their device and recovery codes.
38	Disable2FA(ctx context.Context, userID string) (*AdminUser, error)
39}
40
41// adminUsers implements the AdminUsers interface.
42type adminUsers struct {
43	client *Client
44}
45
46// AdminUser represents a user as seen by an Admin.
47type AdminUser struct {
48	ID               string     `jsonapi:"primary,users"`
49	Email            string     `jsonapi:"attr,email"`
50	Username         string     `jsonapi:"attr,username"`
51	AvatarURL        string     `jsonapi:"attr,avatar-url"`
52	TwoFactor        *TwoFactor `jsonapi:"attr,two-factor"`
53	IsAdmin          bool       `jsonapi:"attr,is-admin"`
54	IsSuspended      bool       `jsonapi:"attr,is-suspended"`
55	IsServiceAccount bool       `jsonapi:"attr,is-service-account"`
56
57	// Relations
58	Organizations []*Organization `jsonapi:"relation,organizations"`
59}
60
61// AdminUserList represents a list of users.
62type AdminUserList struct {
63	*Pagination
64	Items []*AdminUser
65}
66
67// AdminUserListOptions represents the options for listing users.
68// https://www.terraform.io/docs/cloud/api/admin/users.html#query-parameters
69type AdminUserListOptions struct {
70	ListOptions
71
72	// A search query string. Users are searchable by username and email address.
73	Query *string `url:"q,omitempty"`
74
75	// Can be "true" or "false" to show only administrators or non-administrators.
76	Administrators *string `url:"filter[admin]"`
77
78	// Can be "true" or "false" to show only suspended users or users who are not suspended.
79	SuspendedUsers *string `url:"filter[suspended]"`
80
81	// A list of relations to include. See available resources
82	// https://www.terraform.io/docs/cloud/api/admin/users.html#available-related-resources
83	Include *string `url:"include"`
84}
85
86// List all user accounts in the Terraform Enterprise installation
87func (a *adminUsers) List(ctx context.Context, options AdminUserListOptions) (*AdminUserList, error) {
88	u := fmt.Sprintf("admin/users")
89	req, err := a.client.newRequest("GET", u, &options)
90	if err != nil {
91		return nil, err
92	}
93
94	aul := &AdminUserList{}
95	err = a.client.do(ctx, req, aul)
96	if err != nil {
97		return nil, err
98	}
99
100	return aul, nil
101}
102
103// Delete a user by its ID.
104func (a *adminUsers) Delete(ctx context.Context, userID string) error {
105	if !validStringID(&userID) {
106		return ErrInvalidUserValue
107	}
108
109	u := fmt.Sprintf("admin/users/%s", url.QueryEscape(userID))
110	req, err := a.client.newRequest("DELETE", u, nil)
111	if err != nil {
112		return err
113	}
114
115	return a.client.do(ctx, req, nil)
116}
117
118// Suspend a user by its ID.
119func (a *adminUsers) Suspend(ctx context.Context, userID string) (*AdminUser, error) {
120	if !validStringID(&userID) {
121		return nil, ErrInvalidUserValue
122	}
123
124	u := fmt.Sprintf("admin/users/%s/actions/suspend", url.QueryEscape(userID))
125	req, err := a.client.newRequest("POST", u, nil)
126	if err != nil {
127		return nil, err
128	}
129
130	au := &AdminUser{}
131	err = a.client.do(ctx, req, au)
132	if err != nil {
133		return nil, err
134	}
135
136	return au, nil
137}
138
139// Unsuspend a user by its ID.
140func (a *adminUsers) Unsuspend(ctx context.Context, userID string) (*AdminUser, error) {
141	if !validStringID(&userID) {
142		return nil, ErrInvalidUserValue
143	}
144
145	u := fmt.Sprintf("admin/users/%s/actions/unsuspend", url.QueryEscape(userID))
146	req, err := a.client.newRequest("POST", u, nil)
147	if err != nil {
148		return nil, err
149	}
150
151	au := &AdminUser{}
152	err = a.client.do(ctx, req, au)
153	if err != nil {
154		return nil, err
155	}
156
157	return au, nil
158}
159
160// GrantAdmin grants admin privilages to a user by its ID.
161func (a *adminUsers) GrantAdmin(ctx context.Context, userID string) (*AdminUser, error) {
162	if !validStringID(&userID) {
163		return nil, ErrInvalidUserValue
164	}
165
166	u := fmt.Sprintf("admin/users/%s/actions/grant_admin", url.QueryEscape(userID))
167	req, err := a.client.newRequest("POST", u, nil)
168	if err != nil {
169		return nil, err
170	}
171
172	au := &AdminUser{}
173	err = a.client.do(ctx, req, au)
174	if err != nil {
175		return nil, err
176	}
177
178	return au, nil
179}
180
181// RevokeAdmin revokes admin privilages to a user by its ID.
182func (a *adminUsers) RevokeAdmin(ctx context.Context, userID string) (*AdminUser, error) {
183	if !validStringID(&userID) {
184		return nil, ErrInvalidUserValue
185	}
186
187	u := fmt.Sprintf("admin/users/%s/actions/revoke_admin", url.QueryEscape(userID))
188	req, err := a.client.newRequest("POST", u, nil)
189	if err != nil {
190		return nil, err
191	}
192
193	au := &AdminUser{}
194	err = a.client.do(ctx, req, au)
195	if err != nil {
196		return nil, err
197	}
198
199	return au, nil
200}
201
202// Disable2FA disables a user's two-factor authentication in the situation
203// where they have lost access to their device and recovery codes.
204func (a *adminUsers) Disable2FA(ctx context.Context, userID string) (*AdminUser, error) {
205	if !validStringID(&userID) {
206		return nil, ErrInvalidUserValue
207	}
208
209	u := fmt.Sprintf("admin/users/%s/actions/disable_two_factor", url.QueryEscape(userID))
210	req, err := a.client.newRequest("POST", u, nil)
211	if err != nil {
212		return nil, err
213	}
214
215	au := &AdminUser{}
216	err = a.client.do(ctx, req, au)
217	if err != nil {
218		return nil, err
219	}
220
221	return au, nil
222}
223