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  }