diff --git a/openstack/identity/v3/groups/requests.go b/openstack/identity/v3/groups/requests.go index b4551b252..fe3b20c7c 100644 --- a/openstack/identity/v3/groups/requests.go +++ b/openstack/identity/v3/groups/requests.go @@ -64,7 +64,6 @@ type CreateOpts struct { // DomainID is the ID of the domain the group belongs to. DomainID string `json:"domain_id,omitempty"` - // Extra is free-form extra key/value pairs to describe the group. Extra map[string]interface{} `json:"-"` } @@ -94,7 +93,7 @@ func Create(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateRe return } _, r.Err = client.Post(createURL(client), &b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{201}, + OkCodes: []int{200}, }) return } diff --git a/openstack/identity/v3/groups/testing/fixtures.go b/openstack/identity/v3/groups/testing/fixtures.go index 6e8ccbf94..1bb9bf0c2 100644 --- a/openstack/identity/v3/groups/testing/fixtures.go +++ b/openstack/identity/v3/groups/testing/fixtures.go @@ -186,7 +186,7 @@ func HandleCreateGroupSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestJSONRequest(t, r, CreateRequest) - w.WriteHeader(http.StatusCreated) + w.WriteHeader(http.StatusOK) fmt.Fprintf(w, GetOutput) }) } diff --git a/openstack/identity/v3/projects/requests.go b/openstack/identity/v3/projects/requests.go index 8260a6aac..406db5bdb 100644 --- a/openstack/identity/v3/projects/requests.go +++ b/openstack/identity/v3/projects/requests.go @@ -16,13 +16,6 @@ type ListOpts struct { // DomainID filters the response by a domain ID. DomainID string `q:"domain_id"` - // Enabled filters the response by enabled projects. - Enabled *bool `q:"enabled"` - - // IsDomain filters the response by projects that are domains. - // Setting this to true is effectively listing domains. - IsDomain *bool `q:"is_domain"` - // Name filters the response by project name. Name string `q:"name"` @@ -68,12 +61,6 @@ type CreateOpts struct { // DomainID is the ID this project will belong under. DomainID string `json:"domain_id,omitempty"` - // Enabled sets the project status to enabled or disabled. - Enabled *bool `json:"enabled,omitempty"` - - // IsDomain indicates if this project is a domain. - IsDomain *bool `json:"is_domain,omitempty"` - // Name is the name of the project. Name string `json:"name" required:"true"` @@ -114,21 +101,9 @@ type UpdateOptsBuilder interface { // UpdateOpts represents parameters to update a project. type UpdateOpts struct { - // DomainID is the ID this project will belong under. - DomainID string `json:"domain_id,omitempty"` - - // Enabled sets the project status to enabled or disabled. - Enabled *bool `json:"enabled,omitempty"` - - // IsDomain indicates if this project is a domain. - IsDomain *bool `json:"is_domain,omitempty"` - // Name is the name of the project. Name string `json:"name,omitempty"` - // ParentID specifies the parent project of this new project. - ParentID string `json:"parent_id,omitempty"` - // Description is the description of the project. Description string `json:"description,omitempty"` } diff --git a/openstack/identity/v3/users/requests.go b/openstack/identity/v3/users/requests.go index dea3a9852..6c6f74bc0 100644 --- a/openstack/identity/v3/users/requests.go +++ b/openstack/identity/v3/users/requests.go @@ -33,20 +33,8 @@ type ListOpts struct { // Enabled filters the response by enabled users. Enabled *bool `q:"enabled"` - // IdpID filters the response by an Identity Provider ID. - IdPID string `q:"idp_id"` - // Name filters the response by username. Name string `q:"name"` - - // PasswordExpiresAt filters the response based on expiring passwords. - PasswordExpiresAt string `q:"password_expires_at"` - - // ProtocolID filters the response by protocol ID. - ProtocolID string `q:"protocol_id"` - - // UniqueID filters the response by unique ID. - UniqueID string `q:"unique_id"` } // ToUserListQuery formats a ListOpts into a query string. @@ -90,21 +78,12 @@ type CreateOpts struct { // DefaultProjectID is the ID of the default project of the user. DefaultProjectID string `json:"default_project_id,omitempty"` - // Description is a description of the user. - Description string `json:"description,omitempty"` - // DomainID is the ID of the domain the user belongs to. DomainID string `json:"domain_id,omitempty"` // Enabled sets the user status to enabled or disabled. Enabled *bool `json:"enabled,omitempty"` - // Extra is free-form extra key/value pairs to describe the user. - Extra map[string]interface{} `json:"-"` - - // Options are defined options in the API to enable certain features. - Options map[Option]interface{} `json:"options,omitempty"` - // Password is the password of the new user. Password string `json:"password,omitempty"` } @@ -116,14 +95,6 @@ func (opts CreateOpts) ToUserCreateMap() (map[string]interface{}, error) { return nil, err } - if opts.Extra != nil { - if v, ok := b["user"].(map[string]interface{}); ok { - for key, value := range opts.Extra { - v[key] = value - } - } - } - return b, nil } @@ -154,21 +125,12 @@ type UpdateOpts struct { // DefaultProjectID is the ID of the default project of the user. DefaultProjectID string `json:"default_project_id,omitempty"` - // Description is a description of the user. - Description string `json:"description,omitempty"` - // DomainID is the ID of the domain the user belongs to. DomainID string `json:"domain_id,omitempty"` // Enabled sets the user status to enabled or disabled. Enabled *bool `json:"enabled,omitempty"` - // Extra is free-form extra key/value pairs to describe the user. - Extra map[string]interface{} `json:"-"` - - // Options are defined options in the API to enable certain features. - Options map[Option]interface{} `json:"options,omitempty"` - // Password is the password of the new user. Password string `json:"password,omitempty"` } @@ -180,14 +142,6 @@ func (opts UpdateOpts) ToUserUpdateMap() (map[string]interface{}, error) { return nil, err } - if opts.Extra != nil { - if v, ok := b["user"].(map[string]interface{}); ok { - for key, value := range opts.Extra { - v[key] = value - } - } - } - return b, nil } @@ -240,3 +194,17 @@ func ListInGroup(client *golangsdk.ServiceClient, groupID string, opts ListOptsB return UserPage{pagination.LinkedPageBase{PageResult: r}} }) } + +// Add a user into one group +func AddToGroup(client *golangsdk.ServiceClient, groupID string, userID string) (r AddMembershipResult) { + _, r.Err = client.Put(membershipURL(client, groupID, userID), nil, nil, &golangsdk.RequestOpts{ + OkCodes: []int{204}, + }) + return +} + +// Remove user from group +func RemoveFromGroup(client *golangsdk.ServiceClient, groupID string, userID string) (r DeleteResult) { + _, r.Err = client.Delete(membershipURL(client, groupID, userID), nil) + return +} diff --git a/openstack/identity/v3/users/results.go b/openstack/identity/v3/users/results.go index d3e434b97..969a9f889 100644 --- a/openstack/identity/v3/users/results.go +++ b/openstack/identity/v3/users/results.go @@ -5,7 +5,6 @@ import ( "time" "github.com/huaweicloud/golangsdk" - "github.com/huaweicloud/golangsdk/internal" "github.com/huaweicloud/golangsdk/pagination" ) @@ -14,18 +13,12 @@ type User struct { // DefaultProjectID is the ID of the default project of the user. DefaultProjectID string `json:"default_project_id"` - // Description is the description of the user. - Description string `json:"description"` - // DomainID is the domain ID the user belongs to. DomainID string `json:"domain_id"` // Enabled is whether or not the user is enabled. Enabled bool `json:"enabled"` - // Extra is a collection of miscellaneous key/values. - Extra map[string]interface{} `json:"-"` - // ID is the unique ID of the user. ID string `json:"id"` @@ -35,9 +28,6 @@ type User struct { // Name is the name of the user. Name string `json:"name"` - // Options are a set of defined options of the user. - Options map[string]interface{} `json:"options"` - // PasswordExpiresAt is the timestamp when the user's password expires. PasswordExpiresAt time.Time `json:"-"` } @@ -46,7 +36,6 @@ func (r *User) UnmarshalJSON(b []byte) error { type tmp User var s struct { tmp - Extra map[string]interface{} `json:"extra"` PasswordExpiresAt golangsdk.JSONRFC3339MilliNoZ `json:"password_expires_at"` } err := json.Unmarshal(b, &s) @@ -57,22 +46,6 @@ func (r *User) UnmarshalJSON(b []byte) error { r.PasswordExpiresAt = time.Time(s.PasswordExpiresAt) - // Collect other fields and bundle them into Extra - // but only if a field titled "extra" wasn't sent. - if s.Extra != nil { - r.Extra = s.Extra - } else { - var result interface{} - err := json.Unmarshal(b, &result) - if err != nil { - return err - } - if resultMap, ok := result.(map[string]interface{}); ok { - delete(resultMap, "password_expires_at") - r.Extra = internal.RemainingKeys(User{}, resultMap) - } - } - return err } @@ -147,3 +120,7 @@ func (r userResult) Extract() (*User, error) { err := r.ExtractInto(&s) return s.User, err } + +type AddMembershipResult struct { + golangsdk.ErrResult +} diff --git a/openstack/identity/v3/users/testing/fixtures.go b/openstack/identity/v3/users/testing/fixtures.go index 7b5067dc7..a029f8ab0 100644 --- a/openstack/identity/v3/users/testing/fixtures.go +++ b/openstack/identity/v3/users/testing/fixtures.go @@ -27,31 +27,14 @@ const ListOutput = ` "domain_id": "default", "enabled": true, "id": "2844b2a08be147a08ef58317d6471f1f", - "links": { - "self": "http://example.com/identity/v3/users/2844b2a08be147a08ef58317d6471f1f" - }, - "name": "glance", - "password_expires_at": null, - "description": "some description", - "extra": { - "email": "glance@localhost" - } + "name": "glance" }, { "default_project_id": "263fd9", "domain_id": "1789d1", "enabled": true, "id": "9fe1d3", - "links": { - "self": "https://example.com/identity/v3/users/9fe1d3" - }, - "name": "jsmith", - "password_expires_at": "2016-11-06T15:32:17.000000", - "email": "jsmith@example.com", - "options": { - "ignore_password_expiry": true, - "multi_factor_auth_rules": [["password", "totp"], ["password", "custom-auth-method"]] - } + "name": "jsmith" } ] } @@ -65,16 +48,7 @@ const GetOutput = ` "domain_id": "1789d1", "enabled": true, "id": "9fe1d3", - "links": { - "self": "https://example.com/identity/v3/users/9fe1d3" - }, - "name": "jsmith", - "password_expires_at": "2016-11-06T15:32:17.000000", - "email": "jsmith@example.com", - "options": { - "ignore_password_expiry": true, - "multi_factor_auth_rules": [["password", "totp"], ["password", "custom-auth-method"]] - } + "name": "jsmith" } } ` @@ -87,12 +61,7 @@ const GetOutputNoOptions = ` "domain_id": "1789d1", "enabled": true, "id": "9fe1d3", - "links": { - "self": "https://example.com/identity/v3/users/9fe1d3" - }, - "name": "jsmith", - "password_expires_at": "2016-11-06T15:32:17.000000", - "email": "jsmith@example.com" + "name": "jsmith" } } ` @@ -105,12 +74,7 @@ const CreateRequest = ` "domain_id": "1789d1", "enabled": true, "name": "jsmith", - "password": "secretsecret", - "email": "jsmith@example.com", - "options": { - "ignore_password_expiry": true, - "multi_factor_auth_rules": [["password", "totp"], ["password", "custom-auth-method"]] - } + "password": "secretsecret" } } ` @@ -123,8 +87,7 @@ const CreateNoOptionsRequest = ` "domain_id": "1789d1", "enabled": true, "name": "jsmith", - "password": "secretsecret", - "email": "jsmith@example.com" + "password": "secretsecret" } } ` @@ -133,11 +96,7 @@ const CreateNoOptionsRequest = ` const UpdateRequest = ` { "user": { - "enabled": false, - "disabled_reason": "DDOS", - "options": { - "multi_factor_auth_rules": null - } + "enabled": false } } ` @@ -150,16 +109,7 @@ const UpdateOutput = ` "domain_id": "1789d1", "enabled": false, "id": "9fe1d3", - "links": { - "self": "https://example.com/identity/v3/users/9fe1d3" - }, - "name": "jsmith", - "password_expires_at": "2016-11-06T15:32:17.000000", - "email": "jsmith@example.com", - "disabled_reason": "DDOS", - "options": { - "ignore_password_expiry": true - } + "name": "jsmith" } } ` @@ -237,15 +187,7 @@ var FirstUser = users.User{ DomainID: "default", Enabled: true, ID: "2844b2a08be147a08ef58317d6471f1f", - Links: map[string]interface{}{ - "self": "http://example.com/identity/v3/users/2844b2a08be147a08ef58317d6471f1f", - }, - Name: "glance", - PasswordExpiresAt: nilTime, - Description: "some description", - Extra: map[string]interface{}{ - "email": "glance@localhost", - }, + Name: "glance", } // SecondUser is the second user in the List request. @@ -255,21 +197,7 @@ var SecondUser = users.User{ DomainID: "1789d1", Enabled: true, ID: "9fe1d3", - Links: map[string]interface{}{ - "self": "https://example.com/identity/v3/users/9fe1d3", - }, - Name: "jsmith", - PasswordExpiresAt: SecondUserPasswordExpiresAt, - Extra: map[string]interface{}{ - "email": "jsmith@example.com", - }, - Options: map[string]interface{}{ - "ignore_password_expiry": true, - "multi_factor_auth_rules": []interface{}{ - []string{"password", "totp"}, - []string{"password", "custom-auth-method"}, - }, - }, + Name: "jsmith", } var SecondUserNoOptions = users.User{ @@ -277,14 +205,7 @@ var SecondUserNoOptions = users.User{ DomainID: "1789d1", Enabled: true, ID: "9fe1d3", - Links: map[string]interface{}{ - "self": "https://example.com/identity/v3/users/9fe1d3", - }, - Name: "jsmith", - PasswordExpiresAt: SecondUserPasswordExpiresAt, - Extra: map[string]interface{}{ - "email": "jsmith@example.com", - }, + Name: "jsmith", } // SecondUserUpdated is how SecondUser should look after an Update. @@ -293,18 +214,7 @@ var SecondUserUpdated = users.User{ DomainID: "1789d1", Enabled: false, ID: "9fe1d3", - Links: map[string]interface{}{ - "self": "https://example.com/identity/v3/users/9fe1d3", - }, - Name: "jsmith", - PasswordExpiresAt: SecondUserPasswordExpiresAt, - Extra: map[string]interface{}{ - "email": "jsmith@example.com", - "disabled_reason": "DDOS", - }, - Options: map[string]interface{}{ - "ignore_password_expiry": true, - }, + Name: "jsmith", } // ExpectedUsersSlice is the slice of users expected to be returned from ListOutput. diff --git a/openstack/identity/v3/users/testing/requests_test.go b/openstack/identity/v3/users/testing/requests_test.go index bbef95fc6..487c10674 100644 --- a/openstack/identity/v3/users/testing/requests_test.go +++ b/openstack/identity/v3/users/testing/requests_test.go @@ -41,8 +41,6 @@ func TestListUsersAllPages(t *testing.T) { actual, err := users.ExtractUsers(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedUsersSlice, actual) - th.AssertEquals(t, ExpectedUsersSlice[0].Extra["email"], "glance@localhost") - th.AssertEquals(t, ExpectedUsersSlice[1].Extra["email"], "jsmith@example.com") } func TestGetUser(t *testing.T) { @@ -53,7 +51,6 @@ func TestGetUser(t *testing.T) { actual, err := users.Get(client.ServiceClient(), "9fe1d3").Extract() th.AssertNoErr(t, err) th.CheckDeepEquals(t, SecondUser, *actual) - th.AssertEquals(t, SecondUser.Extra["email"], "jsmith@example.com") } func TestCreateUser(t *testing.T) { @@ -68,16 +65,6 @@ func TestCreateUser(t *testing.T) { Enabled: &iTrue, Password: "secretsecret", DefaultProjectID: "263fd9", - Options: map[users.Option]interface{}{ - users.IgnorePasswordExpiry: true, - users.MultiFactorAuthRules: []interface{}{ - []string{"password", "totp"}, - []string{"password", "custom-auth-method"}, - }, - }, - Extra: map[string]interface{}{ - "email": "jsmith@example.com", - }, } actual, err := users.Create(client.ServiceClient(), createOpts).Extract() @@ -97,9 +84,6 @@ func TestCreateNoOptionsUser(t *testing.T) { Enabled: &iTrue, Password: "secretsecret", DefaultProjectID: "263fd9", - Extra: map[string]interface{}{ - "email": "jsmith@example.com", - }, } actual, err := users.Create(client.ServiceClient(), createOpts).Extract() @@ -115,12 +99,6 @@ func TestUpdateUser(t *testing.T) { iFalse := false updateOpts := users.UpdateOpts{ Enabled: &iFalse, - Options: map[users.Option]interface{}{ - users.MultiFactorAuthRules: nil, - }, - Extra: map[string]interface{}{ - "disabled_reason": "DDOS", - }, } actual, err := users.Update(client.ServiceClient(), "9fe1d3", updateOpts).Extract() diff --git a/openstack/identity/v3/users/urls.go b/openstack/identity/v3/users/urls.go index d3ae819c6..128aad49e 100644 --- a/openstack/identity/v3/users/urls.go +++ b/openstack/identity/v3/users/urls.go @@ -33,3 +33,7 @@ func listProjectsURL(client *golangsdk.ServiceClient, userID string) string { func listInGroupURL(client *golangsdk.ServiceClient, groupID string) string { return client.ServiceURL("groups", groupID, "users") } + +func membershipURL(client *golangsdk.ServiceClient, groupID string, userID string) string { + return client.ServiceURL("groups", groupID, "users", userID) +}