github.com/gophercloud/gophercloud@v1.11.0/openstack/identity/v3/users/requests.go (about) 1 package users 2 3 import ( 4 "net/url" 5 "strings" 6 7 "github.com/gophercloud/gophercloud" 8 "github.com/gophercloud/gophercloud/openstack/identity/v3/groups" 9 "github.com/gophercloud/gophercloud/openstack/identity/v3/projects" 10 "github.com/gophercloud/gophercloud/pagination" 11 ) 12 13 // Option is a specific option defined at the API to enable features 14 // on a user account. 15 type Option string 16 17 const ( 18 IgnoreChangePasswordUponFirstUse Option = "ignore_change_password_upon_first_use" 19 IgnorePasswordExpiry Option = "ignore_password_expiry" 20 IgnoreLockoutFailureAttempts Option = "ignore_lockout_failure_attempts" 21 MultiFactorAuthRules Option = "multi_factor_auth_rules" 22 MultiFactorAuthEnabled Option = "multi_factor_auth_enabled" 23 ) 24 25 // ListOptsBuilder allows extensions to add additional parameters to 26 // the List request 27 type ListOptsBuilder interface { 28 ToUserListQuery() (string, error) 29 } 30 31 // ListOpts provides options to filter the List results. 32 type ListOpts struct { 33 // DomainID filters the response by a domain ID. 34 DomainID string `q:"domain_id"` 35 36 // Enabled filters the response by enabled users. 37 Enabled *bool `q:"enabled"` 38 39 // IdpID filters the response by an Identity Provider ID. 40 IdPID string `q:"idp_id"` 41 42 // Name filters the response by username. 43 Name string `q:"name"` 44 45 // PasswordExpiresAt filters the response based on expiring passwords. 46 PasswordExpiresAt string `q:"password_expires_at"` 47 48 // ProtocolID filters the response by protocol ID. 49 ProtocolID string `q:"protocol_id"` 50 51 // UniqueID filters the response by unique ID. 52 UniqueID string `q:"unique_id"` 53 54 // Filters filters the response by custom filters such as 55 // 'name__contains=foo' 56 Filters map[string]string `q:"-"` 57 } 58 59 // ToUserListQuery formats a ListOpts into a query string. 60 func (opts ListOpts) ToUserListQuery() (string, error) { 61 q, err := gophercloud.BuildQueryString(opts) 62 if err != nil { 63 return "", err 64 } 65 66 params := q.Query() 67 for k, v := range opts.Filters { 68 i := strings.Index(k, "__") 69 if i > 0 && i < len(k)-2 { 70 params.Add(k, v) 71 } else { 72 return "", InvalidListFilter{FilterName: k} 73 } 74 } 75 76 q = &url.URL{RawQuery: params.Encode()} 77 return q.String(), err 78 } 79 80 // List enumerates the Users to which the current token has access. 81 func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { 82 url := listURL(client) 83 if opts != nil { 84 query, err := opts.ToUserListQuery() 85 if err != nil { 86 return pagination.Pager{Err: err} 87 } 88 url += query 89 } 90 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { 91 return UserPage{pagination.LinkedPageBase{PageResult: r}} 92 }) 93 } 94 95 // Get retrieves details on a single user, by ID. 96 func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { 97 resp, err := client.Get(getURL(client, id), &r.Body, nil) 98 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 99 return 100 } 101 102 // CreateOptsBuilder allows extensions to add additional parameters to 103 // the Create request. 104 type CreateOptsBuilder interface { 105 ToUserCreateMap() (map[string]interface{}, error) 106 } 107 108 // CreateOpts provides options used to create a user. 109 type CreateOpts struct { 110 // Name is the name of the new user. 111 Name string `json:"name" required:"true"` 112 113 // DefaultProjectID is the ID of the default project of the user. 114 DefaultProjectID string `json:"default_project_id,omitempty"` 115 116 // Description is a description of the user. 117 Description string `json:"description,omitempty"` 118 119 // DomainID is the ID of the domain the user belongs to. 120 DomainID string `json:"domain_id,omitempty"` 121 122 // Enabled sets the user status to enabled or disabled. 123 Enabled *bool `json:"enabled,omitempty"` 124 125 // Extra is free-form extra key/value pairs to describe the user. 126 Extra map[string]interface{} `json:"-"` 127 128 // Options are defined options in the API to enable certain features. 129 Options map[Option]interface{} `json:"options,omitempty"` 130 131 // Password is the password of the new user. 132 Password string `json:"password,omitempty"` 133 } 134 135 // ToUserCreateMap formats a CreateOpts into a create request. 136 func (opts CreateOpts) ToUserCreateMap() (map[string]interface{}, error) { 137 b, err := gophercloud.BuildRequestBody(opts, "user") 138 if err != nil { 139 return nil, err 140 } 141 142 if opts.Extra != nil { 143 if v, ok := b["user"].(map[string]interface{}); ok { 144 for key, value := range opts.Extra { 145 v[key] = value 146 } 147 } 148 } 149 150 return b, nil 151 } 152 153 // Create creates a new User. 154 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { 155 b, err := opts.ToUserCreateMap() 156 if err != nil { 157 r.Err = err 158 return 159 } 160 resp, err := client.Post(createURL(client), &b, &r.Body, &gophercloud.RequestOpts{ 161 OkCodes: []int{201}, 162 }) 163 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 164 return 165 } 166 167 // UpdateOptsBuilder allows extensions to add additional parameters to 168 // the Update request. 169 type UpdateOptsBuilder interface { 170 ToUserUpdateMap() (map[string]interface{}, error) 171 } 172 173 // UpdateOpts provides options for updating a user account. 174 type UpdateOpts struct { 175 // Name is the name of the new user. 176 Name string `json:"name,omitempty"` 177 178 // DefaultProjectID is the ID of the default project of the user. 179 DefaultProjectID string `json:"default_project_id,omitempty"` 180 181 // Description is a description of the user. 182 Description *string `json:"description,omitempty"` 183 184 // DomainID is the ID of the domain the user belongs to. 185 DomainID string `json:"domain_id,omitempty"` 186 187 // Enabled sets the user status to enabled or disabled. 188 Enabled *bool `json:"enabled,omitempty"` 189 190 // Extra is free-form extra key/value pairs to describe the user. 191 Extra map[string]interface{} `json:"-"` 192 193 // Options are defined options in the API to enable certain features. 194 Options map[Option]interface{} `json:"options,omitempty"` 195 196 // Password is the password of the new user. 197 Password string `json:"password,omitempty"` 198 } 199 200 // ToUserUpdateMap formats a UpdateOpts into an update request. 201 func (opts UpdateOpts) ToUserUpdateMap() (map[string]interface{}, error) { 202 b, err := gophercloud.BuildRequestBody(opts, "user") 203 if err != nil { 204 return nil, err 205 } 206 207 if opts.Extra != nil { 208 if v, ok := b["user"].(map[string]interface{}); ok { 209 for key, value := range opts.Extra { 210 v[key] = value 211 } 212 } 213 } 214 215 return b, nil 216 } 217 218 // Update updates an existing User. 219 func Update(client *gophercloud.ServiceClient, userID string, opts UpdateOptsBuilder) (r UpdateResult) { 220 b, err := opts.ToUserUpdateMap() 221 if err != nil { 222 r.Err = err 223 return 224 } 225 resp, err := client.Patch(updateURL(client, userID), &b, &r.Body, &gophercloud.RequestOpts{ 226 OkCodes: []int{200}, 227 }) 228 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 229 return 230 } 231 232 // ChangePasswordOptsBuilder allows extensions to add additional parameters to 233 // the ChangePassword request. 234 type ChangePasswordOptsBuilder interface { 235 ToUserChangePasswordMap() (map[string]interface{}, error) 236 } 237 238 // ChangePasswordOpts provides options for changing password for a user. 239 type ChangePasswordOpts struct { 240 // OriginalPassword is the original password of the user. 241 OriginalPassword string `json:"original_password"` 242 243 // Password is the new password of the user. 244 Password string `json:"password"` 245 } 246 247 // ToUserChangePasswordMap formats a ChangePasswordOpts into a ChangePassword request. 248 func (opts ChangePasswordOpts) ToUserChangePasswordMap() (map[string]interface{}, error) { 249 b, err := gophercloud.BuildRequestBody(opts, "user") 250 if err != nil { 251 return nil, err 252 } 253 254 return b, nil 255 } 256 257 // ChangePassword changes password for a user. 258 func ChangePassword(client *gophercloud.ServiceClient, userID string, opts ChangePasswordOptsBuilder) (r ChangePasswordResult) { 259 b, err := opts.ToUserChangePasswordMap() 260 if err != nil { 261 r.Err = err 262 return 263 } 264 265 resp, err := client.Post(changePasswordURL(client, userID), &b, nil, &gophercloud.RequestOpts{ 266 OkCodes: []int{204}, 267 }) 268 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 269 return 270 } 271 272 // Delete deletes a user. 273 func Delete(client *gophercloud.ServiceClient, userID string) (r DeleteResult) { 274 resp, err := client.Delete(deleteURL(client, userID), nil) 275 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 276 return 277 } 278 279 // ListGroups enumerates groups user belongs to. 280 func ListGroups(client *gophercloud.ServiceClient, userID string) pagination.Pager { 281 url := listGroupsURL(client, userID) 282 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { 283 return groups.GroupPage{LinkedPageBase: pagination.LinkedPageBase{PageResult: r}} 284 }) 285 } 286 287 // AddToGroup adds a user to a group. 288 func AddToGroup(client *gophercloud.ServiceClient, groupID, userID string) (r AddToGroupResult) { 289 url := addToGroupURL(client, groupID, userID) 290 resp, err := client.Put(url, nil, nil, &gophercloud.RequestOpts{ 291 OkCodes: []int{204}, 292 }) 293 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 294 return 295 } 296 297 // IsMemberOfGroup checks whether a user belongs to a group. 298 func IsMemberOfGroup(client *gophercloud.ServiceClient, groupID, userID string) (r IsMemberOfGroupResult) { 299 url := isMemberOfGroupURL(client, groupID, userID) 300 resp, err := client.Head(url, &gophercloud.RequestOpts{ 301 OkCodes: []int{204, 404}, 302 }) 303 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 304 if r.Err == nil { 305 if resp.StatusCode == 204 { 306 r.isMember = true 307 } 308 } 309 return 310 } 311 312 // RemoveFromGroup removes a user from a group. 313 func RemoveFromGroup(client *gophercloud.ServiceClient, groupID, userID string) (r RemoveFromGroupResult) { 314 url := removeFromGroupURL(client, groupID, userID) 315 resp, err := client.Delete(url, &gophercloud.RequestOpts{ 316 OkCodes: []int{204}, 317 }) 318 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 319 return 320 } 321 322 // ListProjects enumerates groups user belongs to. 323 func ListProjects(client *gophercloud.ServiceClient, userID string) pagination.Pager { 324 url := listProjectsURL(client, userID) 325 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { 326 return projects.ProjectPage{LinkedPageBase: pagination.LinkedPageBase{PageResult: r}} 327 }) 328 } 329 330 // ListInGroup enumerates users that belong to a group. 331 func ListInGroup(client *gophercloud.ServiceClient, groupID string, opts ListOptsBuilder) pagination.Pager { 332 url := listInGroupURL(client, groupID) 333 if opts != nil { 334 query, err := opts.ToUserListQuery() 335 if err != nil { 336 return pagination.Pager{Err: err} 337 } 338 url += query 339 } 340 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { 341 return UserPage{pagination.LinkedPageBase{PageResult: r}} 342 }) 343 }