From ca7af6ed103f79e020e71422debe53fd001c402e Mon Sep 17 00:00:00 2001 From: Arvindh Date: Thu, 30 Jan 2025 22:14:56 +0530 Subject: [PATCH] remove listing in users Signed-off-by: Arvindh --- api/http/common.go | 106 ++- api/http/util/errors.go | 2 +- apidocs/openapi/clients.yml | 30 + apidocs/openapi/domains.yml | 29 + apidocs/openapi/groups.yml | 30 + apidocs/openapi/schemas/roles.yml | 84 ++ apidocs/openapi/users.yml | 183 +--- cli/channels.go | 2 +- cli/clients.go | 2 +- cli/clients_test.go | 100 +-- cli/commands_test.go | 11 - cli/domains.go | 2 +- cli/domains_test.go | 85 -- domains/api/http/responses.go | 30 - pkg/sdk/channels.go | 4 + pkg/sdk/clients.go | 4 + pkg/sdk/domains.go | 4 + pkg/sdk/groups.go | 4 + pkg/sdk/mocks/sdk.go | 120 +-- pkg/sdk/responses.go | 19 + pkg/sdk/roles.go | 23 + pkg/sdk/sdk.go | 91 +- pkg/sdk/setup_test.go | 1 - pkg/sdk/users.go | 73 -- pkg/sdk/users_test.go | 666 +-------------- users/api/endpoint_test.go | 1323 ----------------------------- users/api/endpoints.go | 106 --- users/api/requests.go | 101 --- users/api/requests_test.go | 238 +----- users/api/responses.go | 30 - users/api/users.go | 160 ---- users/events/events.go | 58 -- users/events/streams.go | 19 - users/middleware/authorization.go | 67 -- users/middleware/logging.go | 26 - users/middleware/metrics.go | 9 - users/mocks/service.go | 28 - users/service.go | 108 +-- users/service_test.go | 292 ------- users/tracing/tracing.go | 8 - users/users.go | 3 - 41 files changed, 402 insertions(+), 3879 deletions(-) diff --git a/api/http/common.go b/api/http/common.go index 7f3bc69df3..4401daac77 100644 --- a/api/http/common.go +++ b/api/http/common.go @@ -20,63 +20,63 @@ import ( ) const ( - MemberKindKey = "member_kind" - PermissionKey = "permission" - RelationKey = "relation" - StatusKey = "status" - OffsetKey = "offset" - OrderKey = "order" - LimitKey = "limit" - MetadataKey = "metadata" - ParentKey = "parent_id" - OwnerKey = "owner_id" - ClientKey = "client" - UsernameKey = "username" - NameKey = "name" - GroupKey = "group" + OffsetKey = "offset" + DirKey = "dir" + OrderKey = "order" + LimitKey = "limit" + + NameOrder = "name" + IDOrder = "id" + AscDir = "asc" + DescDir = "desc" + + MetadataKey = "metadata" + NameKey = "name" + TagKey = "tag" + StatusKey = "status" + + ClientKey = "client" + ChannelKey = "channel" + ConnTypeKey = "connection_type" + GroupKey = "group" + DomainKey = "domain" + + StartLevelKey = "start_level" + EndLevelKey = "end_level" + TreeKey = "tree" + ParentKey = "parent_id" + LevelKey = "level" + + TokenKey = "token" + SubjectKey = "subject" + ObjectKey = "object" + ActionKey = "action" ActionsKey = "actions" RoleIDKey = "role_id" RoleNameKey = "role_name" AccessProviderIDKey = "access_provider_id" AccessTypeKey = "access_type" - TagKey = "tag" - FirstNameKey = "first_name" - LastNameKey = "last_name" - TotalKey = "total" - SubjectKey = "subject" - ObjectKey = "object" - LevelKey = "level" - StartLevelKey = "start_level" - EndLevelKey = "end_level" - TreeKey = "tree" - DirKey = "dir" - ListPerms = "list_perms" - VisibilityKey = "visibility" - EmailKey = "email" - SharedByKey = "shared_by" - TokenKey = "token" - UserKey = "user" - DomainKey = "domain" - ChannelKey = "channel" - ConnTypeKey = "connection_type" - DefPermission = "read_permission" - DefTotal = uint64(100) - DefOffset = 0 - DefOrder = "updated_at" - DefDir = "asc" - DefLimit = 10 - DefLevel = 0 - DefStartLevel = 1 - DefEndLevel = 0 - DefStatus = "enabled" - DefClientStatus = clients.Enabled - DefUserStatus = users.Enabled - DefGroupStatus = groups.Enabled - DefListPerms = false - SharedVisibility = "shared" - MyVisibility = "mine" - AllVisibility = "all" + + UsernameKey = "username" + UserKey = "user" + EmailKey = "email" + FirstNameKey = "first_name" + LastNameKey = "last_name" + + DefTotal = uint64(100) + DefOffset = 0 + DefOrder = "updated_at" + DefDir = "asc" + DefLimit = 10 + DefLevel = 0 + DefStartLevel = 1 + DefEndLevel = 0 + DefStatus = "enabled" + DefClientStatus = clients.Enabled + DefUserStatus = users.Enabled + DefGroupStatus = groups.Enabled + // ContentType represents JSON content type. ContentType = "application/json" @@ -84,10 +84,6 @@ const ( MaxLimitSize = 100 MaxNameSize = 1024 MaxIDSize = 36 - NameOrder = "name" - IDOrder = "id" - AscDir = "asc" - DescDir = "desc" ) // ValidateUUID validates UUID format. diff --git a/api/http/util/errors.go b/api/http/util/errors.go index ab493fec80..6113c2b8ae 100644 --- a/api/http/util/errors.go +++ b/api/http/util/errors.go @@ -141,7 +141,7 @@ var ( // ErrInvalidComparator indicates an invalid comparator. ErrInvalidComparator = errors.New("invalid comparator") - // ErrMissingMemberIDs indicates missing group member type. + // ErrMissingMemberIDs indicates missing member ids. ErrMissingMemberIDs = errors.New("missing member ids") // ErrMissingMemberType indicates missing group member type. diff --git a/apidocs/openapi/clients.yml b/apidocs/openapi/clients.yml index ffb666bda3..20aca26007 100644 --- a/apidocs/openapi/clients.yml +++ b/apidocs/openapi/clients.yml @@ -520,6 +520,36 @@ paths: "500": $ref: "#/components/responses/ServiceError" + /{domainID}/clients/{clientID}/roles/members: + get: + operationId: getClientMembers + tags: + - Roles + summary: Retrieves client members from all roles. + description: | + Retrieves members from role for the specific client. + parameters: + - $ref: "auth.yml#/components/parameters/DomainID" + - $ref: "#/components/parameters/clientID" + security: + - bearerAuth: [] + responses: + "200": + $ref: "./schemas/roles.yml#/components/responses/ListEntityMembersRes" + "400": + description: Failed due to malformed query parameters. + "401": + description: | + Missing or invalid access token provided. + "403": + description: Failed to perform authorization over the entity. + "404": + description: A non-existent entity request. + "422": + description: Database can't process request. + "500": + $ref: "#/components/responses/ServiceError" + /{domainID}/clients/{clientID}/roles/{roleID}: get: operationId: getClientRole diff --git a/apidocs/openapi/domains.yml b/apidocs/openapi/domains.yml index a683e9b824..02f63f9ac3 100644 --- a/apidocs/openapi/domains.yml +++ b/apidocs/openapi/domains.yml @@ -379,6 +379,35 @@ paths: "500": $ref: "#/components/responses/ServiceError" + /domain/{domainID}/roles/members: + get: + operationId: getDomainMembers + tags: + - Roles + summary: Retrieves domain members from all roles. + description: | + Retrieves members from role for the specific domain. + parameters: + - $ref: "auth.yml#/components/parameters/DomainID" + security: + - bearerAuth: [] + responses: + "200": + $ref: "./schemas/roles.yml#/components/responses/ListEntityMembersRes" + "400": + description: Failed due to malformed query parameters. + "401": + description: | + Missing or invalid access token provided. + "403": + description: Failed to perform authorization over the entity. + "404": + description: A non-existent entity request. + "422": + description: Database can't process request. + "500": + $ref: "#/components/responses/ServiceError" + /domains/{domainID}/roles/{roleID}/actions: post: operationId: addDomainRoleAction diff --git a/apidocs/openapi/groups.yml b/apidocs/openapi/groups.yml index b460047d5b..be03e9bda5 100644 --- a/apidocs/openapi/groups.yml +++ b/apidocs/openapi/groups.yml @@ -564,6 +564,36 @@ paths: "500": $ref: "#/components/responses/ServiceError" + /{domainID}/groups/{groupID}/roles/members: + get: + operationId: getGroupMembers + tags: + - Roles + summary: Retrieves group members from all roles. + description: | + Retrieves members from role for the specific group. + parameters: + - $ref: "auth.yml#/components/parameters/DomainID" + - $ref: "#/components/parameters/GroupID" + security: + - bearerAuth: [] + responses: + "200": + $ref: "./schemas/roles.yml#/components/responses/ListEntityMembersRes" + "400": + description: Failed due to malformed query parameters. + "401": + description: | + Missing or invalid access token provided. + "403": + description: Failed to perform authorization over the entity. + "404": + description: A non-existent entity request. + "422": + description: Database can't process request. + "500": + $ref: "#/components/responses/ServiceError" + /{domainID}/groups/{groupID}/roles/{roleID}: get: operationId: getGroupRole diff --git a/apidocs/openapi/schemas/roles.yml b/apidocs/openapi/schemas/roles.yml index 5b90992928..589833d5e1 100644 --- a/apidocs/openapi/schemas/roles.yml +++ b/apidocs/openapi/schemas/roles.yml @@ -135,6 +135,31 @@ components: example: 10 description: Maximum number of items to return in one page. + EntityMembersPage: + type: object + properties: + groups: + type: array + minItems: 0 + uniqueItems: true + items: + $ref: "#/components/schemas/EntityMembersObj" + total: + type: integer + example: 1 + description: Total number of items. + offset: + type: integer + description: Number of items to skip during retrieval. + limit: + type: integer + example: 10 + description: Maximum number of items to return in one page. + required: + - groups + - total + - offset + RoleActionsObj: type: object properties: @@ -163,6 +188,57 @@ components: "c01ed106-e52d-4aa4-bed3-39f360177cfa", ] + EntityMembersObj: + type: object + properties: + members: + type: array + description: List of members with assigned roles and actions. + items: + type: object + properties: + id: + type: string + format: uuid + description: Unique identifier of the member. + roles: + type: array + description: List of roles assigned to the member. + items: + type: object + properties: + id: + type: string + format: uuid + description: Unique identifier of the role. + name: + type: string + description: Name of the role. + actions: + type: array + description: List of actions the member can perform. + items: + type: string + access_type: + type: string + description: Type of access granted. + enum: [read, write, admin] # Adjust based on your actual access types. + example: + members: + - id: "5dc1ce4b-7cc9-4f12-98a6-9d74cc4980bb" + roles: + - id: "a1b2c3d4-e5f6-7890-1234-56789abcdef0" + name: "Admin" + actions: ["create", "update", "delete"] + access_type: "admin" + - id: "c01ed106-e52d-4aa4-bed3-39f360177cfa" + roles: + - id: "b2c3d4e5-f678-9012-3456-789abcdef012" + name: "Editor" + actions: ["read", "update"] + access_type: "write" + + AvailableActionsObj: type: object properties: @@ -284,3 +360,11 @@ components: application/json: schema: $ref: '#/components/schemas/AvailableActionsObj' + + + ListEntityMembersRes: + description: Entity members retrieved successfully. + content: + application/json: + schema: + $ref: '#/components/schemas/EntityMembersObj' diff --git a/apidocs/openapi/users.yml b/apidocs/openapi/users.yml index e246b96565..738bfe5318 100644 --- a/apidocs/openapi/users.yml +++ b/apidocs/openapi/users.yml @@ -550,155 +550,6 @@ paths: "500": $ref: "#/components/responses/ServiceError" - /{domainID}/groups/{groupID}/users: - get: - operationId: listUsersInGroup - tags: - - Users - summary: List users in a group - description: | - Retrieves a list of users in a group. Due to performance concerns, data - is retrieved in subsets. The API must ensure that the entire - dataset is consumed either by making subsequent requests, or by - increasing the subset size of the initial request. - parameters: - - $ref: "auth.yml#/components/parameters/DomainID" - - $ref: "#/components/parameters/GroupID" - - $ref: "#/components/parameters/Limit" - - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Level" - - $ref: "#/components/parameters/Tree" - - $ref: "#/components/parameters/Metadata" - - $ref: "#/components/parameters/GroupName" - - $ref: "#/components/parameters/ParentID" - responses: - "200": - $ref: "#/components/responses/MembersPageRes" - "400": - description: Failed due to malformed query parameters. - "401": - description: | - Missing or invalid access token provided. - This endpoint is available only for administrators. - "403": - description: Failed to perform authorization over the entity. - "404": - description: A non-existent entity request. - "422": - description: Database can't process request. - "500": - $ref: "#/components/responses/ServiceError" - - /{domainID}/channels/{channelID}/users: - get: - operationId: listUsersInChannel - tags: - - Users - summary: List users in a channel - description: | - Retrieves a list of users in a channel. Due to performance concerns, data - is retrieved in subsets. The API must ensure that the entire - dataset is consumed either by making subsequent requests, or by - increasing the subset size of the initial request. - parameters: - - $ref: "auth.yml#/components/parameters/DomainID" - - $ref: "#/components/parameters/ChannelID" - - $ref: "#/components/parameters/Limit" - - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Level" - - $ref: "#/components/parameters/Tree" - - $ref: "#/components/parameters/Metadata" - - $ref: "#/components/parameters/ChannelName" - - $ref: "#/components/parameters/ParentID" - responses: - "200": - $ref: "#/components/responses/MembersPageRes" - "400": - description: Failed due to malformed query parameters. - "401": - description: | - Missing or invalid access token provided. - This endpoint is available only for administrators. - "403": - description: Failed to perform authorization over the entity. - "404": - description: A non-existent entity request. - "422": - description: Database can't process request. - "500": - $ref: "#/components/responses/ServiceError" - - /{domainID}/clients/{clientID}/users: - get: - operationId: listUsersInClient - tags: - - Users - summary: List users associated with a client - description: | - Retrieves a list of users associated with a client. Due to performance concerns, data - is retrieved in subsets. The API must ensure that the entire - dataset is consumed either by making subsequent requests, or by - increasing the subset size of the initial request. - parameters: - - $ref: "auth.yml#/components/parameters/DomainID" - - $ref: "#/components/parameters/ClientID" - - $ref: "#/components/parameters/Limit" - - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Level" - - $ref: "#/components/parameters/Tree" - - $ref: "#/components/parameters/Metadata" - - $ref: "#/components/parameters/ChannelName" - - $ref: "#/components/parameters/ParentID" - responses: - "200": - $ref: "#/components/responses/MembersPageRes" - "400": - description: Failed due to malformed query parameters. - "401": - description: | - Missing or invalid access token provided. - This endpoint is available only for administrators. - "403": - description: Failed to perform authorization over the entity. - "404": - description: A non-existent entity request. - "422": - description: Database can't process request. - "500": - $ref: "#/components/responses/ServiceError" - - /{domainID}/users: - get: - summary: List users assigned to domain - description: | - List users assigned to domain that is identified by the domain ID. - tags: - - Users - parameters: - - $ref: "auth.yml#/components/parameters/DomainID" - - $ref: "#/components/parameters/Limit" - - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Metadata" - - $ref: "#/components/parameters/Status" - security: - - bearerAuth: [] - responses: - "200": - $ref: "#/components/responses/UserPageRes" - description: List of users assigned to domain. - "400": - description: Failed due to malformed domain's ID. - "401": - description: Missing or invalid access token provided. - "403": - description: Unauthorized access the domain ID. - "404": - description: A non-existent entity request. - "422": - description: Database can't process request. - "500": - $ref: "#/components/responses/ServiceError" - /users/tokens/issue: post: operationId: issueToken @@ -963,31 +814,6 @@ components: - total - offset - MembersPage: - type: object - properties: - members: - type: array - minItems: 0 - uniqueItems: true - items: - $ref: "#/components/schemas/Members" - total: - type: integer - example: 1 - description: Total number of items. - offset: - type: integer - description: Number of items to skip during retrieval. - limit: - type: integer - example: 10 - description: Maximum number of items to return in one page. - required: - - members - - total - - level - UserUpdate: type: object properties: @@ -1310,7 +1136,7 @@ components: pattern: "^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$" required: true example: bb7edb32-2eac-4aad-aebe-ed96fe073879 - + ClientID: name: clientID description: Unique client identifier. @@ -1629,13 +1455,6 @@ components: schema: $ref: "#/components/schemas/UsersPage" - MembersPageRes: - description: Group members retrieved. - content: - application/json: - schema: - $ref: "#/components/schemas/MembersPage" - TokenRes: description: JSON-formated document describing the user access token used for authenticating into the syetem and refresh token used for generating another access token content: diff --git a/cli/channels.go b/cli/channels.go index e65053d5e0..68c1aead5a 100644 --- a/cli/channels.go +++ b/cli/channels.go @@ -177,7 +177,7 @@ var cmdChannels = []cobra.Command{ Offset: Offset, Limit: Limit, } - ul, err := sdk.ListChannelUsers(args[0], args[1], pm, args[2]) + ul, err := sdk.ListChannelMembers(args[0], args[1], pm, args[2]) if err != nil { logErrorCmd(*cmd, err) return diff --git a/cli/clients.go b/cli/clients.go index c6f4fff2b0..1c72f66b7b 100644 --- a/cli/clients.go +++ b/cli/clients.go @@ -275,7 +275,7 @@ var cmdClients = []cobra.Command{ Offset: Offset, Limit: Limit, } - ul, err := sdk.ListClientUsers(args[0], args[1], pm, args[2]) + ul, err := sdk.ListClientMembers(args[0], args[1], pm, args[2]) if err != nil { logErrorCmd(*cmd, err) return diff --git a/cli/clients_test.go b/cli/clients_test.go index 40ecc6ba9a..8c38aa124f 100644 --- a/cli/clients_test.go +++ b/cli/clients_test.go @@ -23,12 +23,11 @@ import ( ) var ( - token = "valid" + "domaintoken" - domainID = "domain-id" - tokenWithoutDomain = "valid" - relation = "administrator" - all = "all" - conntype = `["publish","subscribe"]` + token = "valid" + "domaintoken" + domainID = "domain-id" + relation = "administrator" + all = "all" + conntype = `["publish","subscribe"]` ) var client = smqsdk.Client{ @@ -711,95 +710,6 @@ func TestDisableclientCmd(t *testing.T) { } } -func TestUsersClientCmd(t *testing.T) { - sdkMock := new(sdkmocks.SDK) - cli.SetSDK(sdkMock) - clientsCmd := cli.NewClientsCmd() - rootCmd := setFlags(clientsCmd) - - page := smqsdk.UsersPage{} - - cases := []struct { - desc string - args []string - logType outputLog - errLogMessage string - page smqsdk.UsersPage - sdkErr errors.SDKError - }{ - { - desc: "get client's users successfully", - args: []string{ - client.ID, - domainID, - token, - }, - page: smqsdk.UsersPage{ - PageRes: smqsdk.PageRes{ - Total: 1, - Offset: 0, - Limit: 10, - }, - Users: []smqsdk.User{user}, - }, - logType: entityLog, - }, - { - desc: "list client users' with invalid args", - args: []string{ - client.ID, - domainID, - token, - extraArg, - }, - logType: usageLog, - }, - { - desc: "list client users' with invalid domain", - args: []string{ - client.ID, - invalidID, - token, - }, - sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden), - errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden)), - logType: errLog, - }, - { - desc: "list client users with invalid id", - args: []string{ - invalidID, - domainID, - token, - }, - sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden), - errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)), - logType: errLog, - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - sdkCall := sdkMock.On("ListClientUsers", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.page, tc.sdkErr) - out := executeCommand(t, rootCmd, append([]string{usrCmd}, tc.args...)...) - - switch tc.logType { - case entityLog: - err := json.Unmarshal([]byte(out), &page) - if err != nil { - t.Fatalf("Failed to unmarshal JSON: %v", err) - } - assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page)) - case usageLog: - assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out)) - case errLog: - assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out)) - } - sdkCall.Unset() - }) - } -} - func TestConnectClientCmd(t *testing.T) { sdkMock := new(sdkmocks.SDK) cli.SetSDK(sdkMock) diff --git a/cli/commands_test.go b/cli/commands_test.go index 46f2153124..3f40ce1947 100644 --- a/cli/commands_test.go +++ b/cli/commands_test.go @@ -37,17 +37,6 @@ const ( unshrCmd = "unshare" ) -// Groups and channels commands -const ( - chansCmd = "channels" - grpCmd = "groups" - childCmd = "children" - parentCmd = "parents" - usrCmd = "users" - assignCmd = "assign" - unassignCmd = "unassign" -) - // Certs commands const ( revokeCmd = "revoke" diff --git a/cli/domains.go b/cli/domains.go index 4ce4918ccd..a59fe97bfe 100644 --- a/cli/domains.go +++ b/cli/domains.go @@ -96,7 +96,7 @@ var cmdDomains = []cobra.Command{ Status: Status, } - l, err := sdk.ListDomainUsers(args[0], pageMetadata, args[1]) + l, err := sdk.ListDomainMembers(args[0], pageMetadata, args[1]) if err != nil { logErrorCmd(*cmd, err) return diff --git a/cli/domains_test.go b/cli/domains_test.go index 0b205e8bb0..323a53f869 100644 --- a/cli/domains_test.go +++ b/cli/domains_test.go @@ -197,91 +197,6 @@ func TestGetDomainsCmd(t *testing.T) { } } -func TestListDomainUsers(t *testing.T) { - sdkMock := new(sdkmocks.SDK) - cli.SetSDK(sdkMock) - domainsCmd := cli.NewDomainsCmd() - rootCmd := setFlags(domainsCmd) - - page := smqsdk.UsersPage{} - - cases := []struct { - desc string - args []string - logType outputLog - errLogMessage string - page smqsdk.UsersPage - sdkErr errors.SDKError - }{ - { - desc: "list domain users successfully", - args: []string{ - domain.ID, - token, - }, - page: smqsdk.UsersPage{ - PageRes: smqsdk.PageRes{ - Total: 1, - Offset: 0, - Limit: 10, - }, - Users: []smqsdk.User{user}, - }, - logType: entityLog, - }, - { - desc: "list domain users with invalid args", - args: []string{ - domain.ID, - token, - extraArg, - }, - logType: usageLog, - }, - { - desc: "list domain users without domain token", - args: []string{ - domain.ID, - tokenWithoutDomain, - }, - sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden), - errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden)), - logType: errLog, - }, - { - desc: "list domain users with invalid id", - args: []string{ - invalidID, - token, - }, - sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden), - errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)), - logType: errLog, - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - sdkCall := sdkMock.On("ListDomainUsers", tc.args[0], mock.Anything, tc.args[1]).Return(tc.page, tc.sdkErr) - out := executeCommand(t, rootCmd, append([]string{usrCmd}, tc.args...)...) - - switch tc.logType { - case entityLog: - err := json.Unmarshal([]byte(out), &page) - if err != nil { - t.Fatalf("Failed to unmarshal JSON: %v", err) - } - assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page)) - case usageLog: - assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out)) - case errLog: - assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out)) - } - sdkCall.Unset() - }) - } -} - func TestUpdateDomainCmd(t *testing.T) { sdkMock := new(sdkmocks.SDK) cli.SetSDK(sdkMock) diff --git a/domains/api/http/responses.go b/domains/api/http/responses.go index e55616ea0b..ae8e076363 100644 --- a/domains/api/http/responses.go +++ b/domains/api/http/responses.go @@ -13,8 +13,6 @@ import ( var ( _ supermq.Response = (*createDomainRes)(nil) _ supermq.Response = (*retrieveDomainRes)(nil) - _ supermq.Response = (*assignUsersRes)(nil) - _ supermq.Response = (*unassignUsersRes)(nil) _ supermq.Response = (*listDomainsRes)(nil) ) @@ -123,31 +121,3 @@ func (res freezeDomainRes) Headers() map[string]string { func (res freezeDomainRes) Empty() bool { return true } - -type assignUsersRes struct{} - -func (res assignUsersRes) Code() int { - return http.StatusCreated -} - -func (res assignUsersRes) Headers() map[string]string { - return map[string]string{} -} - -func (res assignUsersRes) Empty() bool { - return true -} - -type unassignUsersRes struct{} - -func (res unassignUsersRes) Code() int { - return http.StatusNoContent -} - -func (res unassignUsersRes) Headers() map[string]string { - return map[string]string{} -} - -func (res unassignUsersRes) Empty() bool { - return true -} diff --git a/pkg/sdk/channels.go b/pkg/sdk/channels.go index d8ae98ab42..91b1e62a95 100644 --- a/pkg/sdk/channels.go +++ b/pkg/sdk/channels.go @@ -276,3 +276,7 @@ func (sdk mgSDK) RemoveChannelParent(id, domainID, groupID, token string) errors return sdkerr } + +func (sdk mgSDK) ListChannelMembers(channelID, domainID string, pm PageMetadata, token string) (EntityMembersPage, errors.SDKError) { + return sdk.listEntityMembers(sdk.channelsURL, domainID, channelsEndpoint, channelID, token, pm) +} diff --git a/pkg/sdk/clients.go b/pkg/sdk/clients.go index c3f4c971a8..a4cc2367b9 100644 --- a/pkg/sdk/clients.go +++ b/pkg/sdk/clients.go @@ -307,3 +307,7 @@ func (sdk mgSDK) RemoveAllClientRoleMembers(id, roleID, domainID, token string) func (sdk mgSDK) AvailableClientRoleActions(domainID, token string) ([]string, errors.SDKError) { return sdk.listAvailableRoleActions(sdk.clientsURL, clientsEndpoint, domainID, token) } + +func (sdk mgSDK) ListClientMembers(clientID, domainID string, pm PageMetadata, token string) (EntityMembersPage, errors.SDKError) { + return sdk.listEntityMembers(sdk.clientsURL, domainID, clientsEndpoint, clientID, token, pm) +} diff --git a/pkg/sdk/domains.go b/pkg/sdk/domains.go index 0e1e965a0e..4534fcd0e1 100644 --- a/pkg/sdk/domains.go +++ b/pkg/sdk/domains.go @@ -188,3 +188,7 @@ func (sdk mgSDK) RemoveAllDomainRoleMembers(id, roleID, token string) errors.SDK func (sdk mgSDK) AvailableDomainRoleActions(token string) ([]string, errors.SDKError) { return sdk.listAvailableRoleActions(sdk.domainsURL, domainsEndpoint, "", token) } + +func (sdk mgSDK) ListDomainMembers(domainID string, pm PageMetadata, token string) (EntityMembersPage, errors.SDKError) { + return sdk.listEntityMembers(sdk.domainsURL, domainID, domainsEndpoint, domainID, token, pm) +} diff --git a/pkg/sdk/groups.go b/pkg/sdk/groups.go index 7dc9d30269..549eec3ba6 100644 --- a/pkg/sdk/groups.go +++ b/pkg/sdk/groups.go @@ -318,3 +318,7 @@ func (sdk mgSDK) RemoveAllGroupRoleMembers(id, roleID, domainID, token string) e func (sdk mgSDK) AvailableGroupRoleActions(domainID, token string) ([]string, errors.SDKError) { return sdk.listAvailableRoleActions(sdk.groupsURL, groupsEndpoint, domainID, token) } + +func (sdk mgSDK) ListGroupMembers(groupID, domainID string, pm PageMetadata, token string) (EntityMembersPage, errors.SDKError) { + return sdk.listEntityMembers(sdk.groupsURL, domainID, groupsEndpoint, groupID, token, pm) +} diff --git a/pkg/sdk/mocks/sdk.go b/pkg/sdk/mocks/sdk.go index e4229814fd..60b33a401e 100644 --- a/pkg/sdk/mocks/sdk.go +++ b/pkg/sdk/mocks/sdk.go @@ -4211,23 +4211,23 @@ func (_c *SDK_Journal_Call) RunAndReturn(run func(string, string, string, sdk.Pa return _c } -// ListChannelUsers provides a mock function with given fields: channelID, domainID, pm, token -func (_m *SDK) ListChannelUsers(channelID string, domainID string, pm sdk.PageMetadata, token string) (sdk.UsersPage, errors.SDKError) { +// ListChannelMembers provides a mock function with given fields: channelID, domainID, pm, token +func (_m *SDK) ListChannelMembers(channelID string, domainID string, pm sdk.PageMetadata, token string) (sdk.EntityMembersPage, errors.SDKError) { ret := _m.Called(channelID, domainID, pm, token) if len(ret) == 0 { - panic("no return value specified for ListChannelUsers") + panic("no return value specified for ListChannelMembers") } - var r0 sdk.UsersPage + var r0 sdk.EntityMembersPage var r1 errors.SDKError - if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) (sdk.UsersPage, errors.SDKError)); ok { + if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) (sdk.EntityMembersPage, errors.SDKError)); ok { return rf(channelID, domainID, pm, token) } - if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) sdk.UsersPage); ok { + if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) sdk.EntityMembersPage); ok { r0 = rf(channelID, domainID, pm, token) } else { - r0 = ret.Get(0).(sdk.UsersPage) + r0 = ret.Get(0).(sdk.EntityMembersPage) } if rf, ok := ret.Get(1).(func(string, string, sdk.PageMetadata, string) errors.SDKError); ok { @@ -4241,54 +4241,54 @@ func (_m *SDK) ListChannelUsers(channelID string, domainID string, pm sdk.PageMe return r0, r1 } -// SDK_ListChannelUsers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListChannelUsers' -type SDK_ListChannelUsers_Call struct { +// SDK_ListChannelMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListChannelMembers' +type SDK_ListChannelMembers_Call struct { *mock.Call } -// ListChannelUsers is a helper method to define mock.On call +// ListChannelMembers is a helper method to define mock.On call // - channelID string // - domainID string // - pm sdk.PageMetadata // - token string -func (_e *SDK_Expecter) ListChannelUsers(channelID interface{}, domainID interface{}, pm interface{}, token interface{}) *SDK_ListChannelUsers_Call { - return &SDK_ListChannelUsers_Call{Call: _e.mock.On("ListChannelUsers", channelID, domainID, pm, token)} +func (_e *SDK_Expecter) ListChannelMembers(channelID interface{}, domainID interface{}, pm interface{}, token interface{}) *SDK_ListChannelMembers_Call { + return &SDK_ListChannelMembers_Call{Call: _e.mock.On("ListChannelMembers", channelID, domainID, pm, token)} } -func (_c *SDK_ListChannelUsers_Call) Run(run func(channelID string, domainID string, pm sdk.PageMetadata, token string)) *SDK_ListChannelUsers_Call { +func (_c *SDK_ListChannelMembers_Call) Run(run func(channelID string, domainID string, pm sdk.PageMetadata, token string)) *SDK_ListChannelMembers_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(string), args[1].(string), args[2].(sdk.PageMetadata), args[3].(string)) }) return _c } -func (_c *SDK_ListChannelUsers_Call) Return(_a0 sdk.UsersPage, _a1 errors.SDKError) *SDK_ListChannelUsers_Call { +func (_c *SDK_ListChannelMembers_Call) Return(_a0 sdk.EntityMembersPage, _a1 errors.SDKError) *SDK_ListChannelMembers_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *SDK_ListChannelUsers_Call) RunAndReturn(run func(string, string, sdk.PageMetadata, string) (sdk.UsersPage, errors.SDKError)) *SDK_ListChannelUsers_Call { +func (_c *SDK_ListChannelMembers_Call) RunAndReturn(run func(string, string, sdk.PageMetadata, string) (sdk.EntityMembersPage, errors.SDKError)) *SDK_ListChannelMembers_Call { _c.Call.Return(run) return _c } -// ListClientUsers provides a mock function with given fields: clientID, domainID, pm, token -func (_m *SDK) ListClientUsers(clientID string, domainID string, pm sdk.PageMetadata, token string) (sdk.UsersPage, errors.SDKError) { +// ListClientMembers provides a mock function with given fields: clientID, domainID, pm, token +func (_m *SDK) ListClientMembers(clientID string, domainID string, pm sdk.PageMetadata, token string) (sdk.EntityMembersPage, errors.SDKError) { ret := _m.Called(clientID, domainID, pm, token) if len(ret) == 0 { - panic("no return value specified for ListClientUsers") + panic("no return value specified for ListClientMembers") } - var r0 sdk.UsersPage + var r0 sdk.EntityMembersPage var r1 errors.SDKError - if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) (sdk.UsersPage, errors.SDKError)); ok { + if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) (sdk.EntityMembersPage, errors.SDKError)); ok { return rf(clientID, domainID, pm, token) } - if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) sdk.UsersPage); ok { + if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) sdk.EntityMembersPage); ok { r0 = rf(clientID, domainID, pm, token) } else { - r0 = ret.Get(0).(sdk.UsersPage) + r0 = ret.Get(0).(sdk.EntityMembersPage) } if rf, ok := ret.Get(1).(func(string, string, sdk.PageMetadata, string) errors.SDKError); ok { @@ -4302,54 +4302,54 @@ func (_m *SDK) ListClientUsers(clientID string, domainID string, pm sdk.PageMeta return r0, r1 } -// SDK_ListClientUsers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListClientUsers' -type SDK_ListClientUsers_Call struct { +// SDK_ListClientMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListClientMembers' +type SDK_ListClientMembers_Call struct { *mock.Call } -// ListClientUsers is a helper method to define mock.On call +// ListClientMembers is a helper method to define mock.On call // - clientID string // - domainID string // - pm sdk.PageMetadata // - token string -func (_e *SDK_Expecter) ListClientUsers(clientID interface{}, domainID interface{}, pm interface{}, token interface{}) *SDK_ListClientUsers_Call { - return &SDK_ListClientUsers_Call{Call: _e.mock.On("ListClientUsers", clientID, domainID, pm, token)} +func (_e *SDK_Expecter) ListClientMembers(clientID interface{}, domainID interface{}, pm interface{}, token interface{}) *SDK_ListClientMembers_Call { + return &SDK_ListClientMembers_Call{Call: _e.mock.On("ListClientMembers", clientID, domainID, pm, token)} } -func (_c *SDK_ListClientUsers_Call) Run(run func(clientID string, domainID string, pm sdk.PageMetadata, token string)) *SDK_ListClientUsers_Call { +func (_c *SDK_ListClientMembers_Call) Run(run func(clientID string, domainID string, pm sdk.PageMetadata, token string)) *SDK_ListClientMembers_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(string), args[1].(string), args[2].(sdk.PageMetadata), args[3].(string)) }) return _c } -func (_c *SDK_ListClientUsers_Call) Return(_a0 sdk.UsersPage, _a1 errors.SDKError) *SDK_ListClientUsers_Call { +func (_c *SDK_ListClientMembers_Call) Return(_a0 sdk.EntityMembersPage, _a1 errors.SDKError) *SDK_ListClientMembers_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *SDK_ListClientUsers_Call) RunAndReturn(run func(string, string, sdk.PageMetadata, string) (sdk.UsersPage, errors.SDKError)) *SDK_ListClientUsers_Call { +func (_c *SDK_ListClientMembers_Call) RunAndReturn(run func(string, string, sdk.PageMetadata, string) (sdk.EntityMembersPage, errors.SDKError)) *SDK_ListClientMembers_Call { _c.Call.Return(run) return _c } -// ListDomainUsers provides a mock function with given fields: domainID, pm, token -func (_m *SDK) ListDomainUsers(domainID string, pm sdk.PageMetadata, token string) (sdk.UsersPage, errors.SDKError) { +// ListDomainMembers provides a mock function with given fields: domainID, pm, token +func (_m *SDK) ListDomainMembers(domainID string, pm sdk.PageMetadata, token string) (sdk.EntityMembersPage, errors.SDKError) { ret := _m.Called(domainID, pm, token) if len(ret) == 0 { - panic("no return value specified for ListDomainUsers") + panic("no return value specified for ListDomainMembers") } - var r0 sdk.UsersPage + var r0 sdk.EntityMembersPage var r1 errors.SDKError - if rf, ok := ret.Get(0).(func(string, sdk.PageMetadata, string) (sdk.UsersPage, errors.SDKError)); ok { + if rf, ok := ret.Get(0).(func(string, sdk.PageMetadata, string) (sdk.EntityMembersPage, errors.SDKError)); ok { return rf(domainID, pm, token) } - if rf, ok := ret.Get(0).(func(string, sdk.PageMetadata, string) sdk.UsersPage); ok { + if rf, ok := ret.Get(0).(func(string, sdk.PageMetadata, string) sdk.EntityMembersPage); ok { r0 = rf(domainID, pm, token) } else { - r0 = ret.Get(0).(sdk.UsersPage) + r0 = ret.Get(0).(sdk.EntityMembersPage) } if rf, ok := ret.Get(1).(func(string, sdk.PageMetadata, string) errors.SDKError); ok { @@ -4363,53 +4363,53 @@ func (_m *SDK) ListDomainUsers(domainID string, pm sdk.PageMetadata, token strin return r0, r1 } -// SDK_ListDomainUsers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListDomainUsers' -type SDK_ListDomainUsers_Call struct { +// SDK_ListDomainMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListDomainMembers' +type SDK_ListDomainMembers_Call struct { *mock.Call } -// ListDomainUsers is a helper method to define mock.On call +// ListDomainMembers is a helper method to define mock.On call // - domainID string // - pm sdk.PageMetadata // - token string -func (_e *SDK_Expecter) ListDomainUsers(domainID interface{}, pm interface{}, token interface{}) *SDK_ListDomainUsers_Call { - return &SDK_ListDomainUsers_Call{Call: _e.mock.On("ListDomainUsers", domainID, pm, token)} +func (_e *SDK_Expecter) ListDomainMembers(domainID interface{}, pm interface{}, token interface{}) *SDK_ListDomainMembers_Call { + return &SDK_ListDomainMembers_Call{Call: _e.mock.On("ListDomainMembers", domainID, pm, token)} } -func (_c *SDK_ListDomainUsers_Call) Run(run func(domainID string, pm sdk.PageMetadata, token string)) *SDK_ListDomainUsers_Call { +func (_c *SDK_ListDomainMembers_Call) Run(run func(domainID string, pm sdk.PageMetadata, token string)) *SDK_ListDomainMembers_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(string), args[1].(sdk.PageMetadata), args[2].(string)) }) return _c } -func (_c *SDK_ListDomainUsers_Call) Return(_a0 sdk.UsersPage, _a1 errors.SDKError) *SDK_ListDomainUsers_Call { +func (_c *SDK_ListDomainMembers_Call) Return(_a0 sdk.EntityMembersPage, _a1 errors.SDKError) *SDK_ListDomainMembers_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *SDK_ListDomainUsers_Call) RunAndReturn(run func(string, sdk.PageMetadata, string) (sdk.UsersPage, errors.SDKError)) *SDK_ListDomainUsers_Call { +func (_c *SDK_ListDomainMembers_Call) RunAndReturn(run func(string, sdk.PageMetadata, string) (sdk.EntityMembersPage, errors.SDKError)) *SDK_ListDomainMembers_Call { _c.Call.Return(run) return _c } -// Members provides a mock function with given fields: groupID, domainID, pm, token -func (_m *SDK) Members(groupID string, domainID string, pm sdk.PageMetadata, token string) (sdk.UsersPage, errors.SDKError) { +// ListGroupMembers provides a mock function with given fields: groupID, domainID, pm, token +func (_m *SDK) ListGroupMembers(groupID string, domainID string, pm sdk.PageMetadata, token string) (sdk.EntityMembersPage, errors.SDKError) { ret := _m.Called(groupID, domainID, pm, token) if len(ret) == 0 { - panic("no return value specified for Members") + panic("no return value specified for ListGroupMembers") } - var r0 sdk.UsersPage + var r0 sdk.EntityMembersPage var r1 errors.SDKError - if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) (sdk.UsersPage, errors.SDKError)); ok { + if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) (sdk.EntityMembersPage, errors.SDKError)); ok { return rf(groupID, domainID, pm, token) } - if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) sdk.UsersPage); ok { + if rf, ok := ret.Get(0).(func(string, string, sdk.PageMetadata, string) sdk.EntityMembersPage); ok { r0 = rf(groupID, domainID, pm, token) } else { - r0 = ret.Get(0).(sdk.UsersPage) + r0 = ret.Get(0).(sdk.EntityMembersPage) } if rf, ok := ret.Get(1).(func(string, string, sdk.PageMetadata, string) errors.SDKError); ok { @@ -4423,33 +4423,33 @@ func (_m *SDK) Members(groupID string, domainID string, pm sdk.PageMetadata, tok return r0, r1 } -// SDK_Members_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Members' -type SDK_Members_Call struct { +// SDK_ListGroupMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListGroupMembers' +type SDK_ListGroupMembers_Call struct { *mock.Call } -// Members is a helper method to define mock.On call +// ListGroupMembers is a helper method to define mock.On call // - groupID string // - domainID string // - pm sdk.PageMetadata // - token string -func (_e *SDK_Expecter) Members(groupID interface{}, domainID interface{}, pm interface{}, token interface{}) *SDK_Members_Call { - return &SDK_Members_Call{Call: _e.mock.On("Members", groupID, domainID, pm, token)} +func (_e *SDK_Expecter) ListGroupMembers(groupID interface{}, domainID interface{}, pm interface{}, token interface{}) *SDK_ListGroupMembers_Call { + return &SDK_ListGroupMembers_Call{Call: _e.mock.On("ListGroupMembers", groupID, domainID, pm, token)} } -func (_c *SDK_Members_Call) Run(run func(groupID string, domainID string, pm sdk.PageMetadata, token string)) *SDK_Members_Call { +func (_c *SDK_ListGroupMembers_Call) Run(run func(groupID string, domainID string, pm sdk.PageMetadata, token string)) *SDK_ListGroupMembers_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(string), args[1].(string), args[2].(sdk.PageMetadata), args[3].(string)) }) return _c } -func (_c *SDK_Members_Call) Return(_a0 sdk.UsersPage, _a1 errors.SDKError) *SDK_Members_Call { +func (_c *SDK_ListGroupMembers_Call) Return(_a0 sdk.EntityMembersPage, _a1 errors.SDKError) *SDK_ListGroupMembers_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *SDK_Members_Call) RunAndReturn(run func(string, string, sdk.PageMetadata, string) (sdk.UsersPage, errors.SDKError)) *SDK_Members_Call { +func (_c *SDK_ListGroupMembers_Call) RunAndReturn(run func(string, string, sdk.PageMetadata, string) (sdk.EntityMembersPage, errors.SDKError)) *SDK_ListGroupMembers_Call { _c.Call.Return(run) return _c } diff --git a/pkg/sdk/responses.go b/pkg/sdk/responses.go index 6b2185a897..21e768721f 100644 --- a/pkg/sdk/responses.go +++ b/pkg/sdk/responses.go @@ -101,3 +101,22 @@ type RoleMembersPage struct { Limit uint64 `json:"limit"` Members []string `json:"members"` } + +type MemberRole struct { + Actions []string `json:"actions,omitempty"` + RoleName string `json:"role_name,omitempty"` + RoleID string `json:"role_id,omitempty"` + AccessType string `json:"access_type,omitempty"` + AccessProviderID string `json:"access_provider_id,omitempty"` + AccessProviderPath string `json:"access_provider_path,omitempty"` +} +type MemberRoles struct { + MemberID string `json:"member_id"` + Roles []MemberRole `json:"roles"` +} +type EntityMembersPage struct { + Total uint64 `json:"total"` + Offset uint64 `json:"offset"` + Limit uint64 `json:"limit"` + Members []MemberRoles `json:"members"` +} diff --git a/pkg/sdk/roles.go b/pkg/sdk/roles.go index fd87d9178b..7c56df9f5e 100644 --- a/pkg/sdk/roles.go +++ b/pkg/sdk/roles.go @@ -266,3 +266,26 @@ func (sdk mgSDK) listAvailableRoleActions(entityURL, entityEndpoint, domainID, t return res.AvailableActions, nil } + +func (sdk mgSDK) listEntityMembers(entityURL, domainID, entityEndpoint, id, token string, pm PageMetadata) (EntityMembersPage, errors.SDKError) { + ep := fmt.Sprintf("%s/%s/%s/%s/%s", domainID, entityEndpoint, id, rolesEndpoint, membersEndpoint) + if entityEndpoint == domainsEndpoint { + ep = fmt.Sprintf("%s/%s/%s/%s", entityEndpoint, id, rolesEndpoint, membersEndpoint) + } + url, err := sdk.withQueryParams(entityURL, ep, pm) + if err != nil { + return EntityMembersPage{}, errors.NewSDKError(err) + } + + _, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK) + if sdkerr != nil { + return EntityMembersPage{}, sdkerr + } + + res := EntityMembersPage{} + if err := json.Unmarshal(body, &res); err != nil { + return EntityMembersPage{}, errors.NewSDKError(err) + } + + return res, nil +} diff --git a/pkg/sdk/sdk.go b/pkg/sdk/sdk.go index f16dd92385..9f257c1c73 100644 --- a/pkg/sdk/sdk.go +++ b/pkg/sdk/sdk.go @@ -196,17 +196,6 @@ type SDK interface { // fmt.Println(users) Users(pm PageMetadata, token string) (UsersPage, errors.SDKError) - // Members returns list of users that are members of a group. - // - // example: - // pm := sdk.PageMetadata{ - // Offset: 0, - // Limit: 10, - // } - // members, _ := sdk.Members("groupID","domainID", pm, "token") - // fmt.Println(members) - Members(groupID, domainID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) - // UserProfile returns user logged in. // // example: @@ -359,42 +348,6 @@ type SDK interface { // fmt.Println(users) SearchUsers(pm PageMetadata, token string) (UsersPage, errors.SDKError) - // ListClientUsers all users in a client. - // - // example: - // pm := sdk.PageMetadata{ - // Offset: 0, - // Limit: 10, - // Permission: "edit", // available Options: "administrator", "administrator", "delete", edit", "view", "share", "owner", "owner", "admin", "editor", "contributor", "editor", "viewer", "guest", "create" - // } - // users, _ := sdk.ListClientUsers("client_id", pm, "domainID", "token") - // fmt.Println(users) - ListClientUsers(clientID, domainID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) - - // ListChannelUsers list all users in a channel . - // - // example: - // pm := sdk.PageMetadata{ - // Offset: 0, - // Limit: 10, - // Permission: "edit", // available Options: "administrator", "administrator", "delete", edit", "view", "share", "owner", "owner", "admin", "editor", "contributor", "editor", "viewer", "guest", "create" - // } - // users, _ := sdk.ListChannelUsers("channel_id","domainID", pm, "token") - // fmt.Println(users) - ListChannelUsers(channelID, domainID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) - - // ListDomainUsers returns list of users for the given domain ID and filters. - // - // example: - // pm := sdk.PageMetadata{ - // Offset: 0, - // Limit: 10, - // Permission : "view" - // } - // users, _ := sdk.ListDomainUsers("domainID", pm, "token") - // fmt.Println(users) - ListDomainUsers(domainID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) - // CreateClient registers new client and returns its id. // // example: @@ -630,6 +583,17 @@ type SDK interface { // fmt.Println(actions) AvailableClientRoleActions(domainID, token string) ([]string, errors.SDKError) + // ListClientMembers list all members from all roles in a client . + // + // example: + // pm := sdk.PageMetadata{ + // Offset: 0, + // Limit: 10, + // } + // members, _ := sdk.ListClientMembers("client_id","domainID", pm, "token") + // fmt.Println(members) + ListClientMembers(clientID, domainID string, pm PageMetadata, token string) (EntityMembersPage, errors.SDKError) + // CreateGroup creates new group and returns its id. // // example: @@ -872,6 +836,17 @@ type SDK interface { // fmt.Println(actions) AvailableGroupRoleActions(id, token string) ([]string, errors.SDKError) + // ListGroupMembers list all members from all roles in a group . + // + // example: + // pm := sdk.PageMetadata{ + // Offset: 0, + // Limit: 10, + // } + // members, _ := sdk.ListGroupMembers("group_id","domainID", pm, "token") + // fmt.Println(members) + ListGroupMembers(groupID, domainID string, pm PageMetadata, token string) (EntityMembersPage, errors.SDKError) + // CreateChannel creates new channel and returns its id. // // example: @@ -1025,6 +1000,17 @@ type SDK interface { // fmt.Println(err) DisconnectClients(channelID string, clientIDs, connTypes []string, domainID, token string) errors.SDKError + // ListChannelMembers list all members from all roles in a channel . + // + // example: + // pm := sdk.PageMetadata{ + // Offset: 0, + // Limit: 10, + // } + // members, _ := sdk.ListChannelMembers("channel_id","domainID", pm, "token") + // fmt.Println(members) + ListChannelMembers(channelID, domainID string, pm PageMetadata, token string) (EntityMembersPage, errors.SDKError) + // SendMessage send message to specified channel. // // example: @@ -1258,6 +1244,17 @@ type SDK interface { // fmt.Println(actions) AvailableDomainRoleActions(token string) ([]string, errors.SDKError) + // ListDomainUsers returns list of users for the given domain ID and filters. + // + // example: + // pm := sdk.PageMetadata{ + // Offset: 0, + // Limit: 10, + // } + // members, _ := sdk.ListDomainMembers("domain_id", pm, "token") + // fmt.Println(members) + ListDomainMembers(domainID string, pm PageMetadata, token string) (EntityMembersPage, errors.SDKError) + // SendInvitation sends an invitation to the email address associated with the given user. // // For example: diff --git a/pkg/sdk/setup_test.go b/pkg/sdk/setup_test.go index 4d3ba83a4c..df71d50069 100644 --- a/pkg/sdk/setup_test.go +++ b/pkg/sdk/setup_test.go @@ -33,7 +33,6 @@ const ( contentType = "application/senml+json" invalid = "invalid" wrongID = "wrongID" - defPermission = "read_permission" roleName = "roleName" ) diff --git a/pkg/sdk/users.go b/pkg/sdk/users.go index d5b6f6f133..eb9982dc6a 100644 --- a/pkg/sdk/users.go +++ b/pkg/sdk/users.go @@ -15,8 +15,6 @@ import ( const ( usersEndpoint = "users" - assignEndpoint = "assign" - unassignEndpoint = "unassign" enableEndpoint = "enable" disableEndpoint = "disable" issueTokenEndpoint = "tokens/issue" @@ -81,25 +79,6 @@ func (sdk mgSDK) Users(pm PageMetadata, token string) (UsersPage, errors.SDKErro return cp, nil } -func (sdk mgSDK) Members(groupID, domainID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) { - url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s/%s/%s", domainID, groupsEndpoint, groupID, usersEndpoint), pm) - if err != nil { - return UsersPage{}, errors.NewSDKError(err) - } - - _, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK) - if sdkerr != nil { - return UsersPage{}, sdkerr - } - - var up UsersPage - if err := json.Unmarshal(body, &up); err != nil { - return UsersPage{}, errors.NewSDKError(err) - } - - return up, nil -} - func (sdk mgSDK) User(id, token string) (User, errors.SDKError) { if id == "" { return User{}, errors.NewSDKError(apiutil.ErrMissingID) @@ -372,55 +351,3 @@ func (sdk mgSDK) DeleteUser(id, token string) errors.SDKError { _, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, nil, nil, http.StatusNoContent) return sdkerr } - -func (sdk mgSDK) ListClientUsers(clientID, domainID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) { - url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s/%s/%s", domainID, clientsEndpoint, clientID, usersEndpoint), pm) - if err != nil { - return UsersPage{}, errors.NewSDKError(err) - } - - _, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK) - if sdkerr != nil { - return UsersPage{}, sdkerr - } - up := UsersPage{} - if err := json.Unmarshal(body, &up); err != nil { - return UsersPage{}, errors.NewSDKError(err) - } - - return up, nil -} - -func (sdk mgSDK) ListDomainUsers(domainID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) { - url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s", domainID, usersEndpoint), pm) - if err != nil { - return UsersPage{}, errors.NewSDKError(err) - } - _, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK) - if sdkerr != nil { - return UsersPage{}, sdkerr - } - var up UsersPage - if err := json.Unmarshal(body, &up); err != nil { - return UsersPage{}, errors.NewSDKError(err) - } - - return up, nil -} - -func (sdk mgSDK) ListChannelUsers(channelID, domainID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) { - url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s/%s/%s", domainID, channelsEndpoint, channelID, usersEndpoint), pm) - if err != nil { - return UsersPage{}, errors.NewSDKError(err) - } - _, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK) - if sdkerr != nil { - return UsersPage{}, sdkerr - } - up := UsersPage{} - if err := json.Unmarshal(body, &up); err != nil { - return UsersPage{}, errors.NewSDKError(err) - } - - return up, nil -} diff --git a/pkg/sdk/users_test.go b/pkg/sdk/users_test.go index f0eecb2d70..4bb6267728 100644 --- a/pkg/sdk/users_test.go +++ b/pkg/sdk/users_test.go @@ -31,9 +31,8 @@ import ( ) var ( - id = generateUUID(&testing.T{}) - domainID = "c717fa97-ffd9-40cb-8cf9-7c2859059395" - membershipPermission = "membership" + id = generateUUID(&testing.T{}) + domainID = "c717fa97-ffd9-40cb-8cf9-7c2859059395" ) func setupUsers() (*httptest.Server, *umocks.Service, *authnmocks.Authentication) { @@ -2314,190 +2313,6 @@ func TestDisableUser(t *testing.T) { } } -func TestListMembers(t *testing.T) { - ts, svc, auth := setupUsers() - defer ts.Close() - - member := generateTestUser(t) - conf := sdk.Config{ - UsersURL: ts.URL, - } - mgsdk := sdk.NewSDK(conf) - - cases := []struct { - desc string - token string - session smqauthn.Session - groupID string - pageMeta sdk.PageMetadata - svcReq users.Page - svcRes users.MembersPage - svcErr error - authenticateErr error - response sdk.UsersPage - err errors.SDKError - }{ - { - desc: "list members successfully", - token: validToken, - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcRes: users.MembersPage{ - Page: users.Page{ - Total: 1, - }, - Members: []users.User{convertUser(member)}, - }, - svcErr: nil, - response: sdk.UsersPage{ - PageRes: sdk.PageRes{ - Total: 1, - }, - Users: []sdk.User{member}, - }, - }, - { - desc: "list members with invalid token", - token: invalidToken, - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - authenticateErr: svcerr.ErrAuthentication, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized), - }, - { - desc: "list members with empty token", - token: "", - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{}, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized), - }, - { - desc: "list members with invalid group id", - token: validToken, - groupID: wrongID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcErr: svcerr.ErrViewEntity, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(svcerr.ErrViewEntity, http.StatusBadRequest), - }, - { - desc: "list members with empty group id", - token: validToken, - groupID: "", - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{}, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID), http.StatusBadRequest), - }, - { - desc: "list members with page metadata that can't be marshalled", - token: validToken, - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - Metadata: map[string]interface{}{ - "test": make(chan int), - }, - }, - svcReq: users.Page{}, - svcRes: users.MembersPage{}, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKError(errors.New("json: unsupported type: chan int")), - }, - { - desc: "list members with response that can't be unmarshalled", - token: validToken, - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcRes: users.MembersPage{ - Page: users.Page{ - Total: 1, - }, - Members: []users.User{{ - ID: member.ID, - FirstName: member.FirstName, - Metadata: map[string]interface{}{ - "key": make(chan int), - }, - }}, - }, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKError(errors.New("unexpected end of JSON input")), - }, - } - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - if tc.token == validToken { - tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID} - } - authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr) - svcCall := svc.On("ListMembers", mock.Anything, tc.session, "groups", tc.groupID, tc.svcReq).Return(tc.svcRes, tc.svcErr) - resp, err := mgsdk.Members(tc.groupID, domainID, tc.pageMeta, tc.token) - assert.Equal(t, tc.err, err) - assert.Equal(t, tc.response, resp) - if tc.err == nil { - ok := svcCall.Parent.AssertCalled(t, "ListMembers", mock.Anything, tc.session, "groups", tc.groupID, tc.svcReq) - assert.True(t, ok) - } - svcCall.Unset() - authCall.Unset() - }) - } -} - func TestDeleteUser(t *testing.T) { ts, svc, auth := setupUsers() defer ts.Close() @@ -2570,480 +2385,3 @@ func TestDeleteUser(t *testing.T) { }) } } - -func TestListClientUsers(t *testing.T) { - ts, svc, auth := setupUsers() - defer ts.Close() - - clientUser := generateTestUser(t) - conf := sdk.Config{ - UsersURL: ts.URL, - } - mgsdk := sdk.NewSDK(conf) - - cases := []struct { - desc string - token string - session smqauthn.Session - clientID string - pageMeta sdk.PageMetadata - svcReq users.Page - svcRes users.MembersPage - svcErr error - authenticateErr error - response sdk.UsersPage - err errors.SDKError - }{ - { - desc: "list client users successfully", - token: validToken, - clientID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcRes: users.MembersPage{ - Page: users.Page{ - Total: 1, - }, - Members: []users.User{convertUser(clientUser)}, - }, - svcErr: nil, - response: sdk.UsersPage{ - PageRes: sdk.PageRes{ - Total: 1, - }, - Users: []sdk.User{clientUser}, - }, - }, - { - desc: "list client users with invalid token", - token: invalidToken, - clientID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - authenticateErr: svcerr.ErrAuthentication, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized), - }, - { - desc: "list client users with empty token", - token: "", - clientID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{}, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized), - }, - { - desc: "list client users with invalid client id", - token: validToken, - clientID: wrongID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcErr: svcerr.ErrViewEntity, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(svcerr.ErrViewEntity, http.StatusBadRequest), - }, - { - desc: "list clients users with request that cannot be marshalled", - token: validToken, - clientID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - Metadata: map[string]interface{}{ - "test": make(chan int), - }, - }, - err: errors.NewSDKError(errors.New("json: unsupported type: chan int")), - }, - { - desc: "list clients users with response that cannot be unmarshalled", - token: validToken, - clientID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcRes: users.MembersPage{ - Page: users.Page{ - Total: 1, - }, - Members: []users.User{{ - ID: clientUser.ID, - FirstName: clientUser.FirstName, - Metadata: map[string]interface{}{ - "key": make(chan int), - }, - }}, - }, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKError(errors.New("unexpected end of JSON input")), - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - if tc.token == validToken { - tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID} - } - authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr) - svcCall := svc.On("ListMembers", mock.Anything, tc.session, "clients", tc.clientID, tc.svcReq).Return(tc.svcRes, tc.svcErr) - resp, err := mgsdk.ListClientUsers(tc.clientID, domainID, tc.pageMeta, tc.token) - assert.Equal(t, tc.err, err) - assert.Equal(t, tc.response, resp) - if tc.err == nil { - ok := svcCall.Parent.AssertCalled(t, "ListMembers", mock.Anything, tc.session, "clients", tc.clientID, tc.svcReq) - assert.True(t, ok) - } - svcCall.Unset() - authCall.Unset() - }) - } -} - -func TestListGroupUsers(t *testing.T) { - ts, svc, auth := setupUsers() - defer ts.Close() - - groupUser := generateTestUser(t) - conf := sdk.Config{ - UsersURL: ts.URL, - } - mgsdk := sdk.NewSDK(conf) - - cases := []struct { - desc string - token string - session smqauthn.Session - groupID string - pageMeta sdk.PageMetadata - svcReq users.Page - svcRes users.MembersPage - svcErr error - authenticateErr error - response sdk.UsersPage - err errors.SDKError - }{ - { - desc: "list client users successfully", - token: validToken, - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcRes: users.MembersPage{ - Page: users.Page{ - Total: 1, - }, - Members: []users.User{convertUser(groupUser)}, - }, - svcErr: nil, - response: sdk.UsersPage{ - PageRes: sdk.PageRes{ - Total: 1, - }, - Users: []sdk.User{groupUser}, - }, - }, - { - desc: "list client users with invalid token", - token: invalidToken, - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - authenticateErr: svcerr.ErrAuthentication, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized), - }, - { - desc: "list client users with empty token", - token: "", - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{}, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized), - }, - { - desc: "list client users with invalid client id", - token: validToken, - groupID: wrongID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcErr: svcerr.ErrViewEntity, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(svcerr.ErrViewEntity, http.StatusBadRequest), - }, - { - desc: "list clients users with request that cannot be marshalled", - token: validToken, - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - Metadata: map[string]interface{}{ - "test": make(chan int), - }, - }, - err: errors.NewSDKError(errors.New("json: unsupported type: chan int")), - }, - { - desc: "list clients users with response that cannot be unmarshalled", - token: validToken, - groupID: validID, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: defPermission, - }, - svcRes: users.MembersPage{ - Page: users.Page{ - Total: 1, - }, - Members: []users.User{{ - ID: groupUser.ID, - FirstName: groupUser.FirstName, - Metadata: map[string]interface{}{ - "key": make(chan int), - }, - }}, - }, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKError(errors.New("unexpected end of JSON input")), - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - if tc.token == validToken { - tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID} - } - authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr) - svcCall := svc.On("ListMembers", mock.Anything, tc.session, "groups", tc.groupID, tc.svcReq).Return(tc.svcRes, tc.svcErr) - resp, err := mgsdk.ListChannelUsers(tc.groupID, domainID, tc.pageMeta, tc.token) - assert.Equal(t, tc.err, err) - assert.Equal(t, tc.response, resp) - if tc.err == nil { - ok := svcCall.Parent.AssertCalled(t, "ListMembers", mock.Anything, tc.session, "groups", tc.groupID, tc.svcReq) - assert.True(t, ok) - } - svcCall.Unset() - authCall.Unset() - }) - } -} - -func TestListDomainUser(t *testing.T) { - ts, svc, auth := setupUsers() - defer ts.Close() - - user := generateTestUser(t) - conf := sdk.Config{ - UsersURL: ts.URL, - } - mgsdk := sdk.NewSDK(conf) - - cases := []struct { - desc string - token string - session smqauthn.Session - pageMeta sdk.PageMetadata - svcReq users.Page - svcRes users.MembersPage - svcErr error - authenticateErr error - response sdk.UsersPage - err errors.SDKError - }{ - { - desc: "list domain users successfully", - token: validToken, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: membershipPermission, - }, - svcRes: users.MembersPage{ - Page: users.Page{ - Total: 1, - }, - Members: []users.User{convertUser(user)}, - }, - svcErr: nil, - response: sdk.UsersPage{ - PageRes: sdk.PageRes{ - Total: 1, - }, - Users: []sdk.User{user}, - }, - }, - { - desc: "list domain users with invalid token", - token: invalidToken, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: membershipPermission, - }, - authenticateErr: svcerr.ErrAuthentication, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized), - }, - { - desc: "list domain users with empty token", - token: "", - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{}, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized), - }, - { - desc: "list domain users with request that cannot be marshalled", - token: validToken, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - Metadata: map[string]interface{}{ - "test": make(chan int), - }, - }, - err: errors.NewSDKError(errors.New("json: unsupported type: chan int")), - }, - { - desc: "list domain users with response that cannot be unmarshalled", - token: validToken, - pageMeta: sdk.PageMetadata{ - Offset: 0, - Limit: 10, - DomainID: domainID, - }, - svcReq: users.Page{ - Offset: 0, - Limit: 10, - Permission: membershipPermission, - }, - svcRes: users.MembersPage{ - Page: users.Page{ - Total: 1, - }, - Members: []users.User{{ - ID: user.ID, - FirstName: user.FirstName, - Metadata: map[string]interface{}{ - "key": make(chan int), - }, - }}, - }, - svcErr: nil, - response: sdk.UsersPage{}, - err: errors.NewSDKError(errors.New("unexpected end of JSON input")), - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - if tc.token == validToken { - tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID} - } - authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr) - svcCall := svc.On("ListMembers", mock.Anything, tc.session, "domains", domainID, tc.svcReq).Return(tc.svcRes, tc.svcErr) - resp, err := mgsdk.ListDomainUsers(domainID, tc.pageMeta, tc.token) - assert.Equal(t, tc.err, err) - assert.Equal(t, tc.response, resp) - if tc.err == nil { - ok := svcCall.Parent.AssertCalled(t, "ListMembers", mock.Anything, tc.session, "domains", domainID, tc.svcReq) - assert.True(t, ok) - } - svcCall.Unset() - authCall.Unset() - }) - } -} diff --git a/users/api/endpoint_test.go b/users/api/endpoint_test.go index fc7a48b517..8410d94711 100644 --- a/users/api/endpoint_test.go +++ b/users/api/endpoint_test.go @@ -2565,1329 +2565,6 @@ func TestDelete(t *testing.T) { } } -func TestListUsersByUserGroupId(t *testing.T) { - us, svc, authn := newUsersServer() - defer us.Close() - - cases := []struct { - desc string - token string - groupID string - domainID string - page users.Page - status int - query string - listUsersResponse users.UsersPage - authnRes smqauthn.Session - authnErr error - err error - }{ - { - desc: "list users with valid token", - token: validToken, - groupID: validID, - domainID: validID, - status: http.StatusOK, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with empty id", - token: validToken, - groupID: "", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrMissingID, - }, - { - desc: "list users with empty token", - token: "", - groupID: validID, - status: http.StatusUnauthorized, - authnErr: svcerr.ErrAuthentication, - err: apiutil.ErrBearerToken, - }, - { - desc: "list users with invalid token", - token: inValidToken, - groupID: validID, - status: http.StatusUnauthorized, - authnErr: svcerr.ErrAuthentication, - err: svcerr.ErrAuthentication, - }, - { - desc: "list users with offset", - token: validToken, - groupID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Offset: 1, - Total: 1, - }, - Users: []users.User{user}, - }, - query: "offset=1", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid offset", - token: validToken, - groupID: validID, - query: "offset=invalid", - status: http.StatusBadRequest, - err: apiutil.ErrValidation, - }, - { - desc: "list users with limit", - token: validToken, - groupID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Limit: 1, - Total: 1, - }, - Users: []users.User{user}, - }, - query: "limit=1", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid limit", - token: validToken, - groupID: validID, - query: "limit=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with limit greater than max", - token: validToken, - groupID: validID, - query: fmt.Sprintf("limit=%d", api.MaxLimitSize+1), - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with user name", - token: validToken, - groupID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "username=username", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid user name", - token: validToken, - groupID: validID, - query: "username=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate user name", - token: validToken, - groupID: validID, - query: "username=1&username=2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with status", - token: validToken, - groupID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "status=enabled", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid status", - token: validToken, - groupID: validID, - query: "status=invalid", - status: http.StatusBadRequest, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate status", - token: validToken, - groupID: validID, - query: "status=enabled&status=disabled", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with tags", - token: validToken, - groupID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "tag=tag1,tag2", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid tags", - token: validToken, - groupID: validID, - query: "tag=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate tags", - token: validToken, - groupID: validID, - query: "tag=tag1&tag=tag2", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with metadata", - token: validToken, - groupID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid metadata", - token: validToken, - groupID: validID, - query: "metadata=invalid", - status: http.StatusBadRequest, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate metadata", - token: validToken, - groupID: validID, - query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&metadata=%7B%22domain%22%3A%20%22example.com%22%7D", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with permissions", - token: validToken, - groupID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "permission=view", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with duplicate permissions", - token: validToken, - groupID: validID, - query: "permission=view&permission=view", - status: http.StatusBadRequest, - listUsersResponse: users.UsersPage{}, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with email", - token: validToken, - groupID: validID, - query: fmt.Sprintf("email=%s", user.Email), - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{ - user, - }, - }, - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid email", - token: validToken, - groupID: validID, - query: "email=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate email", - token: validToken, - groupID: validID, - query: "email=1&email=2", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrInvalidQueryParams, - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - req := testRequest{ - user: us.Client(), - method: http.MethodGet, - url: fmt.Sprintf("%s/%s/groups/%s/users?", us.URL, validID, tc.groupID) + tc.query, - token: tc.token, - } - authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr) - svcCall := svc.On("ListMembers", mock.Anything, smqauthn.Session{UserID: validID, DomainID: validID, DomainUserID: validID + "_" + validID}, mock.Anything, mock.Anything, mock.Anything).Return( - users.MembersPage{ - Page: tc.listUsersResponse.Page, - Members: tc.listUsersResponse.Users, - }, - tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() - authnCall.Unset() - }) - } -} - -func TestListUsersByChannelID(t *testing.T) { - us, svc, authn := newUsersServer() - defer us.Close() - - cases := []struct { - desc string - token string - channelID string - page users.Page - status int - query string - listUsersResponse users.UsersPage - authnRes smqauthn.Session - authnErr error - err error - }{ - { - desc: "list users with valid token", - token: validToken, - status: http.StatusOK, - channelID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with empty token", - token: "", - channelID: validID, - status: http.StatusUnauthorized, - authnErr: svcerr.ErrAuthentication, - err: apiutil.ErrBearerToken, - }, - { - desc: "list users with invalid token", - token: inValidToken, - channelID: validID, - status: http.StatusUnauthorized, - authnErr: svcerr.ErrAuthentication, - err: svcerr.ErrAuthentication, - }, - { - desc: "list users with offset", - token: validToken, - channelID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Offset: 1, - Total: 1, - }, - Users: []users.User{user}, - }, - query: "offset=1", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid offset", - token: validToken, - channelID: validID, - query: "offset=invalid", - status: http.StatusBadRequest, - err: apiutil.ErrValidation, - }, - { - desc: "list users with limit", - token: validToken, - channelID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Limit: 1, - Total: 1, - }, - Users: []users.User{user}, - }, - query: "limit=1", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid limit", - token: validToken, - channelID: validID, - query: "limit=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with limit greater than max", - token: validToken, - channelID: validID, - query: fmt.Sprintf("limit=%d", api.MaxLimitSize+1), - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with user name", - token: validToken, - channelID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "username=username", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid user name", - token: validToken, - channelID: validID, - query: "username=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate user name", - token: validToken, - query: "username=1&username=2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with status", - token: validToken, - channelID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "status=enabled", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid status", - token: validToken, - channelID: validID, - query: "status=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate status", - token: validToken, - query: "status=enabled&status=disabled", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with tags", - token: validToken, - channelID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "tag=tag1,tag2", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid tags", - token: validToken, - channelID: validID, - query: "tag=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate tags", - token: validToken, - channelID: validID, - query: "tag=tag1&tag=tag2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with metadata", - token: validToken, - channelID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid metadata", - token: validToken, - channelID: validID, - query: "metadata=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate metadata", - token: validToken, - query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&metadata=%7B%22domain%22%3A%20%22example.com%22%7D", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with permissions", - token: validToken, - channelID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "permission=view", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with duplicate permissions", - token: validToken, - channelID: validID, - query: "permission=view&permission=view", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with email", - token: validToken, - channelID: validID, - query: fmt.Sprintf("email=%s", user.Email), - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{ - user, - }, - }, - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid email", - token: validToken, - channelID: validID, - query: "email=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate email", - token: validToken, - channelID: validID, - query: "email=1&email=2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with list_perms", - token: validToken, - channelID: validID, - query: "list_perms=true", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid list_perms", - token: validToken, - channelID: validID, - query: "list_perms=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate list_perms", - token: validToken, - query: "list_perms=true&list_perms=false", - status: http.StatusBadRequest, - err: apiutil.ErrValidation, - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - req := testRequest{ - user: us.Client(), - method: http.MethodGet, - url: fmt.Sprintf("%s/%s/channels/%s/users?", us.URL, validID, validID) + tc.query, - token: tc.token, - } - - authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr) - svcCall := svc.On("ListMembers", mock.Anything, smqauthn.Session{UserID: validID, DomainID: validID, DomainUserID: validID + "_" + validID}, mock.Anything, mock.Anything, mock.Anything).Return( - users.MembersPage{ - Page: tc.listUsersResponse.Page, - Members: tc.listUsersResponse.Users, - }, - tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() - authnCall.Unset() - }) - } -} - -func TestListUsersByDomainID(t *testing.T) { - us, svc, authn := newUsersServer() - defer us.Close() - - cases := []struct { - desc string - token string - domainID string - page users.Page - status int - query string - listUsersResponse users.UsersPage - authnRes smqauthn.Session - authnErr error - err error - }{ - { - desc: "list users with valid token", - token: validToken, - domainID: validID, - status: http.StatusOK, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with empty token", - token: "", - status: http.StatusUnauthorized, - authnErr: svcerr.ErrAuthentication, - err: apiutil.ErrBearerToken, - }, - { - desc: "list users with invalid token", - token: inValidToken, - status: http.StatusUnauthorized, - authnErr: svcerr.ErrAuthentication, - err: svcerr.ErrAuthentication, - }, - { - desc: "list users with offset", - token: validToken, - domainID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Offset: 1, - Total: 1, - }, - Users: []users.User{user}, - }, - query: "offset=1", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid offset", - token: validToken, - domainID: validID, - query: "offset=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with limit", - token: validToken, - domainID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Limit: 1, - Total: 1, - }, - Users: []users.User{user}, - }, - query: "limit=1", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid limit", - token: validToken, - domainID: validID, - query: "limit=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with limit greater than max", - token: validToken, - domainID: validID, - query: fmt.Sprintf("limit=%d", api.MaxLimitSize+1), - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with user name", - token: validToken, - domainID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "username=username", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid user name", - token: validToken, - domainID: validID, - query: "username=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate user name", - token: validToken, - domainID: validID, - query: "username=1&username=2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with status", - token: validToken, - domainID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "status=enabled", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid status", - token: validToken, - domainID: validID, - query: "status=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate status", - token: validToken, - query: "status=enabled&status=disabled", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with tags", - token: validToken, - domainID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "tag=tag1,tag2", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid tags", - token: validToken, - domainID: validID, - query: "tag=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate tags", - token: validToken, - query: "tag=tag1&tag=tag2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with metadata", - token: validToken, - domainID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid metadata", - token: validToken, - domainID: validID, - query: "metadata=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate metadata", - token: validToken, - query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&metadata=%7B%22domain%22%3A%20%22example.com%22%7D", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with permissions", - token: validToken, - domainID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "permission=membership", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with duplicate permissions", - token: validToken, - domainID: validID, - query: "permission=view&permission=view", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with email", - token: validToken, - domainID: validID, - query: fmt.Sprintf("email=%s", user.Email), - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{ - user, - }, - }, - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid email", - token: validToken, - domainID: validID, - query: "email=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate email", - token: validToken, - query: "email=1&email=2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users wiith list permissions", - token: validToken, - domainID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{ - user, - }, - }, - query: "list_perms=true", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid list_perms", - token: validToken, - domainID: validID, - query: "list_perms=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate list_perms", - token: validToken, - query: "list_perms=true&list_perms=false", - status: http.StatusBadRequest, - err: apiutil.ErrValidation, - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - req := testRequest{ - user: us.Client(), - method: http.MethodGet, - url: fmt.Sprintf("%s/%s/users?", us.URL, validID) + tc.query, - token: tc.token, - } - - authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr) - svcCall := svc.On("ListMembers", mock.Anything, smqauthn.Session{UserID: validID, DomainID: validID, DomainUserID: validID + "_" + validID}, mock.Anything, mock.Anything, mock.Anything).Return( - users.MembersPage{ - Page: tc.listUsersResponse.Page, - Members: tc.listUsersResponse.Users, - }, - tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() - authnCall.Unset() - }) - } -} - -func TestListUsersByClientID(t *testing.T) { - us, svc, authn := newUsersServer() - defer us.Close() - - cases := []struct { - desc string - token string - clientID string - page users.Page - status int - query string - listUsersResponse users.UsersPage - authnRes smqauthn.Session - authnErr error - err error - }{ - { - desc: "list users with valid token", - token: validToken, - clientID: validID, - status: http.StatusOK, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with empty token", - token: "", - clientID: validID, - status: http.StatusUnauthorized, - authnErr: svcerr.ErrAuthentication, - err: apiutil.ErrBearerToken, - }, - { - desc: "list users with invalid token", - token: inValidToken, - clientID: validID, - status: http.StatusUnauthorized, - authnErr: svcerr.ErrAuthentication, - err: svcerr.ErrAuthentication, - }, - { - desc: "list users with offset", - token: validToken, - clientID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Offset: 1, - Total: 1, - }, - Users: []users.User{user}, - }, - query: "offset=1", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid offset", - token: validToken, - clientID: validID, - query: "offset=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with limit", - token: validToken, - clientID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Limit: 1, - Total: 1, - }, - Users: []users.User{user}, - }, - query: "limit=1", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid limit", - token: validToken, - clientID: validID, - query: "limit=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with limit greater than max", - token: validToken, - clientID: validID, - query: fmt.Sprintf("limit=%d", api.MaxLimitSize+1), - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with name", - token: validToken, - clientID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "name=username", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid user name", - token: validToken, - clientID: validID, - query: "username=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate user name", - token: validToken, - clientID: validID, - query: "username=1&username=2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with status", - token: validToken, - clientID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "status=enabled", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid status", - token: validToken, - clientID: validID, - query: "status=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate status", - token: validToken, - query: "status=enabled&status=disabled", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with tags", - token: validToken, - clientID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "tag=tag1,tag2", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid tags", - token: validToken, - clientID: validID, - query: "tag=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate tags", - token: validToken, - query: "tag=tag1&tag=tag2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with metadata", - token: validToken, - clientID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid metadata", - token: validToken, - clientID: validID, - query: "metadata=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate metadata", - token: validToken, - clientID: validID, - query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&metadata=%7B%22domain%22%3A%20%22example.com%22%7D", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with permissions", - token: validToken, - clientID: validID, - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{user}, - }, - query: "permission=view", - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with duplicate permissions", - token: validToken, - query: "permission=view&permission=view", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - { - desc: "list users with email", - token: validToken, - clientID: validID, - query: fmt.Sprintf("email=%s", user.Email), - listUsersResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - }, - Users: []users.User{ - user, - }, - }, - status: http.StatusOK, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: nil, - }, - { - desc: "list users with invalid email", - token: validToken, - clientID: validID, - query: "email=invalid", - status: http.StatusBadRequest, - authnRes: smqauthn.Session{UserID: validID, DomainID: domainID}, - err: apiutil.ErrValidation, - }, - { - desc: "list users with duplicate email", - token: validToken, - query: "email=1&email=2", - status: http.StatusBadRequest, - err: apiutil.ErrInvalidQueryParams, - }, - } - - for _, tc := range cases { - t.Run(tc.desc, func(t *testing.T) { - req := testRequest{ - user: us.Client(), - method: http.MethodGet, - url: fmt.Sprintf("%s/%s/clients/%s/users?", us.URL, validID, validID) + tc.query, - token: tc.token, - } - - authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr) - svcCall := svc.On("ListMembers", mock.Anything, smqauthn.Session{UserID: validID, DomainID: validID, DomainUserID: validID + "_" + validID}, mock.Anything, mock.Anything, mock.Anything).Return( - users.MembersPage{ - Page: tc.listUsersResponse.Page, - Members: tc.listUsersResponse.Users, - }, - tc.err) - res, err := req.make() - assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) - assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode)) - svcCall.Unset() - authnCall.Unset() - }) - } -} - type respBody struct { Err string `json:"error"` Message string `json:"message"` diff --git a/users/api/endpoints.go b/users/api/endpoints.go index 3641dddb87..6729b91eac 100644 --- a/users/api/endpoints.go +++ b/users/api/endpoints.go @@ -164,95 +164,6 @@ func searchUsersEndpoint(svc users.Service) endpoint.Endpoint { } } -func listMembersByGroupEndpoint(svc users.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (interface{}, error) { - req := request.(listMembersByObjectReq) - req.objectKind = "groups" - if err := req.validate(); err != nil { - return nil, errors.Wrap(apiutil.ErrValidation, err) - } - - session, ok := ctx.Value(api.SessionKey).(authn.Session) - if !ok { - return nil, svcerr.ErrAuthentication - } - - page, err := svc.ListMembers(ctx, session, req.objectKind, req.objectID, req.Page) - if err != nil { - return nil, err - } - - return buildUsersResponse(page), nil - } -} - -func listMembersByChannelEndpoint(svc users.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (interface{}, error) { - req := request.(listMembersByObjectReq) - // In spiceDB schema, using the same 'group' type for both channels and groups, rather than having a separate type for channels. - req.objectKind = "groups" - if err := req.validate(); err != nil { - return nil, errors.Wrap(apiutil.ErrValidation, err) - } - - session, ok := ctx.Value(api.SessionKey).(authn.Session) - if !ok { - return nil, svcerr.ErrAuthentication - } - - page, err := svc.ListMembers(ctx, session, req.objectKind, req.objectID, req.Page) - if err != nil { - return nil, err - } - - return buildUsersResponse(page), nil - } -} - -func listMembersByClientEndpoint(svc users.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (interface{}, error) { - req := request.(listMembersByObjectReq) - req.objectKind = "clients" - if err := req.validate(); err != nil { - return nil, errors.Wrap(apiutil.ErrValidation, err) - } - - session, ok := ctx.Value(api.SessionKey).(authn.Session) - if !ok { - return nil, svcerr.ErrAuthentication - } - - page, err := svc.ListMembers(ctx, session, req.objectKind, req.objectID, req.Page) - if err != nil { - return nil, err - } - - return buildUsersResponse(page), nil - } -} - -func listMembersByDomainEndpoint(svc users.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (interface{}, error) { - req := request.(listMembersByObjectReq) - req.objectKind = "domains" - if err := req.validate(); err != nil { - return nil, errors.Wrap(apiutil.ErrValidation, err) - } - - session, ok := ctx.Value(api.SessionKey).(authn.Session) - if !ok { - return nil, svcerr.ErrAuthentication - } - - page, err := svc.ListMembers(ctx, session, req.objectKind, req.objectID, req.Page) - if err != nil { - return nil, err - } - - return buildUsersResponse(page), nil - } -} - func updateEndpoint(svc users.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(updateUserReq) @@ -574,20 +485,3 @@ func deleteEndpoint(svc users.Service) endpoint.Endpoint { return deleteUserRes{true}, nil } } - -func buildUsersResponse(cp users.MembersPage) usersPageRes { - res := usersPageRes{ - pageRes: pageRes{ - Total: cp.Total, - Offset: cp.Offset, - Limit: cp.Limit, - }, - Users: []viewUserRes{}, - } - - for _, user := range cp.Members { - res.Users = append(res.Users, viewUserRes{User: user}) - } - - return res -} diff --git a/users/api/requests.go b/users/api/requests.go index db71551ea8..b180f08407 100644 --- a/users/api/requests.go +++ b/users/api/requests.go @@ -121,23 +121,6 @@ func (req searchUsersReq) validate() error { return nil } -type listMembersByObjectReq struct { - users.Page - objectKind string - objectID string -} - -func (req listMembersByObjectReq) validate() error { - if req.objectID == "" { - return apiutil.ErrMissingID - } - if req.objectKind == "" { - return apiutil.ErrMissingMemberKind - } - - return nil -} - type updateUserReq struct { id string FirstName string `json:"first_name,omitempty"` @@ -327,87 +310,3 @@ func (req resetTokenReq) validate() error { return nil } - -type assignUsersReq struct { - groupID string - Relation string `json:"relation"` - UserIDs []string `json:"user_ids"` -} - -func (req assignUsersReq) validate() error { - if req.Relation == "" { - return apiutil.ErrMissingRelation - } - - if req.groupID == "" { - return apiutil.ErrMissingID - } - - if len(req.UserIDs) == 0 { - return apiutil.ErrEmptyList - } - - return nil -} - -type unassignUsersReq struct { - groupID string - Relation string `json:"relation"` - UserIDs []string `json:"user_ids"` -} - -func (req unassignUsersReq) validate() error { - if req.groupID == "" { - return apiutil.ErrMissingID - } - - if len(req.UserIDs) == 0 { - return apiutil.ErrEmptyList - } - - return nil -} - -type assignGroupsReq struct { - groupID string - domainID string - GroupIDs []string `json:"group_ids"` -} - -func (req assignGroupsReq) validate() error { - if req.domainID == "" { - return apiutil.ErrMissingDomainID - } - - if req.groupID == "" { - return apiutil.ErrMissingID - } - - if len(req.GroupIDs) == 0 { - return apiutil.ErrEmptyList - } - - return nil -} - -type unassignGroupsReq struct { - groupID string - domainID string - GroupIDs []string `json:"group_ids"` -} - -func (req unassignGroupsReq) validate() error { - if req.domainID == "" { - return apiutil.ErrMissingDomainID - } - - if req.groupID == "" { - return apiutil.ErrMissingID - } - - if len(req.GroupIDs) == 0 { - return apiutil.ErrEmptyList - } - - return nil -} diff --git a/users/api/requests_test.go b/users/api/requests_test.go index a437373c8f..22cac99862 100644 --- a/users/api/requests_test.go +++ b/users/api/requests_test.go @@ -22,10 +22,7 @@ const ( name = "user" ) -var ( - validID = testsutil.GenerateUUID(&testing.T{}) - domain = testsutil.GenerateUUID(&testing.T{}) -) +var validID = testsutil.GenerateUUID(&testing.T{}) func TestCreateUserReqValidate(t *testing.T) { cases := []struct { @@ -207,43 +204,6 @@ func TestSearchUsersReqValidate(t *testing.T) { } } -func TestListMembersByObjectReqValidate(t *testing.T) { - cases := []struct { - desc string - req listMembersByObjectReq - err error - }{ - { - desc: "valid request", - req: listMembersByObjectReq{ - objectKind: "group", - objectID: validID, - }, - err: nil, - }, - { - desc: "empty object kind", - req: listMembersByObjectReq{ - objectKind: "", - objectID: validID, - }, - err: apiutil.ErrMissingMemberKind, - }, - { - desc: "empty object id", - req: listMembersByObjectReq{ - objectKind: "group", - objectID: "", - }, - err: apiutil.ErrMissingID, - }, - } - for _, c := range cases { - err := c.req.validate() - assert.Equal(t, c.err, err) - } -} - func TestUpdateUserReqValidate(t *testing.T) { cases := []struct { desc string @@ -660,199 +620,3 @@ func TestResetTokenReqValidate(t *testing.T) { assert.Equal(t, c.err, err) } } - -func TestAssignUsersRequestValidate(t *testing.T) { - cases := []struct { - desc string - req assignUsersReq - err error - }{ - { - desc: "valid request", - req: assignUsersReq{ - groupID: validID, - UserIDs: []string{validID}, - Relation: valid, - }, - err: nil, - }, - { - desc: "empty id", - req: assignUsersReq{ - groupID: "", - UserIDs: []string{validID}, - Relation: valid, - }, - err: apiutil.ErrMissingID, - }, - { - desc: "empty users", - req: assignUsersReq{ - groupID: validID, - UserIDs: []string{}, - Relation: valid, - }, - err: apiutil.ErrEmptyList, - }, - { - desc: "empty relation", - req: assignUsersReq{ - groupID: validID, - UserIDs: []string{validID}, - Relation: "", - }, - err: apiutil.ErrMissingRelation, - }, - } - for _, c := range cases { - err := c.req.validate() - assert.Equal(t, c.err, err, "%s: expected %s got %s\n", c.desc, c.err, err) - } -} - -func TestUnassignUsersRequestValidate(t *testing.T) { - cases := []struct { - desc string - req unassignUsersReq - err error - }{ - { - desc: "valid request", - req: unassignUsersReq{ - groupID: validID, - UserIDs: []string{validID}, - Relation: valid, - }, - err: nil, - }, - { - desc: "empty id", - req: unassignUsersReq{ - groupID: "", - UserIDs: []string{validID}, - Relation: valid, - }, - err: apiutil.ErrMissingID, - }, - { - desc: "empty users", - req: unassignUsersReq{ - groupID: validID, - UserIDs: []string{}, - Relation: valid, - }, - err: apiutil.ErrEmptyList, - }, - { - desc: "empty relation", - req: unassignUsersReq{ - groupID: validID, - UserIDs: []string{validID}, - Relation: "", - }, - err: nil, - }, - } - for _, c := range cases { - err := c.req.validate() - assert.Equal(t, c.err, err, "%s: expected %s got %s\n", c.desc, c.err, err) - } -} - -func TestAssignGroupsRequestValidate(t *testing.T) { - cases := []struct { - desc string - req assignGroupsReq - err error - }{ - { - desc: "valid request", - req: assignGroupsReq{ - domainID: domain, - groupID: validID, - GroupIDs: []string{validID}, - }, - err: nil, - }, - { - desc: "empty group id", - req: assignGroupsReq{ - domainID: domain, - groupID: "", - GroupIDs: []string{validID}, - }, - err: apiutil.ErrMissingID, - }, - { - desc: "empty user group ids", - req: assignGroupsReq{ - domainID: domain, - groupID: validID, - GroupIDs: []string{}, - }, - err: apiutil.ErrEmptyList, - }, - { - desc: "empty domain id", - req: assignGroupsReq{ - domainID: "", - groupID: validID, - GroupIDs: []string{validID}, - }, - err: apiutil.ErrMissingDomainID, - }, - } - for _, c := range cases { - err := c.req.validate() - assert.Equal(t, c.err, err, "%s: expected %s got %s\n", c.desc, c.err, err) - } -} - -func TestUnassignGroupsRequestValidate(t *testing.T) { - cases := []struct { - desc string - req unassignGroupsReq - err error - }{ - { - desc: "valid request", - req: unassignGroupsReq{ - domainID: domain, - groupID: validID, - GroupIDs: []string{validID}, - }, - err: nil, - }, - { - desc: "empty group id", - req: unassignGroupsReq{ - domainID: domain, - groupID: "", - GroupIDs: []string{validID}, - }, - err: apiutil.ErrMissingID, - }, - { - desc: "empty user group ids", - req: unassignGroupsReq{ - domainID: domain, - groupID: validID, - GroupIDs: []string{}, - }, - err: apiutil.ErrEmptyList, - }, - { - desc: "empty domain id", - req: unassignGroupsReq{ - domainID: "", - groupID: validID, - GroupIDs: []string{valid}, - }, - err: apiutil.ErrMissingDomainID, - }, - } - for _, c := range cases { - err := c.req.validate() - assert.Equal(t, c.err, err, "%s: expected %s got %s\n", c.desc, c.err, err) - } -} diff --git a/users/api/responses.go b/users/api/responses.go index e964836959..41aaa8e042 100644 --- a/users/api/responses.go +++ b/users/api/responses.go @@ -23,8 +23,6 @@ var ( _ supermq.Response = (*viewMembersRes)(nil) _ supermq.Response = (*passwResetReqRes)(nil) _ supermq.Response = (*passwChangeRes)(nil) - _ supermq.Response = (*assignUsersRes)(nil) - _ supermq.Response = (*unassignUsersRes)(nil) _ supermq.Response = (*updateUserRes)(nil) _ supermq.Response = (*tokenRes)(nil) _ supermq.Response = (*deleteUserRes)(nil) @@ -192,34 +190,6 @@ func (res passwChangeRes) Empty() bool { return false } -type assignUsersRes struct{} - -func (res assignUsersRes) Code() int { - return http.StatusCreated -} - -func (res assignUsersRes) Headers() map[string]string { - return map[string]string{} -} - -func (res assignUsersRes) Empty() bool { - return true -} - -type unassignUsersRes struct{} - -func (res unassignUsersRes) Code() int { - return http.StatusNoContent -} - -func (res unassignUsersRes) Headers() map[string]string { - return map[string]string{} -} - -func (res unassignUsersRes) Empty() bool { - return true -} - type deleteUserRes struct { deleted bool } diff --git a/users/api/users.go b/users/api/users.go index 1e107d2b28..6c195b984c 100644 --- a/users/api/users.go +++ b/users/api/users.go @@ -18,7 +18,6 @@ import ( smqauthn "github.com/absmach/supermq/pkg/authn" "github.com/absmach/supermq/pkg/errors" "github.com/absmach/supermq/pkg/oauth2" - "github.com/absmach/supermq/pkg/policies" "github.com/absmach/supermq/users" "github.com/go-chi/chi/v5" kithttp "github.com/go-kit/kit/transport/http" @@ -173,48 +172,6 @@ func usersHandler(svc users.Service, authn smqauthn.Authentication, tokenClient ), "password_reset").ServeHTTP) }) - r.Group(func(r chi.Router) { - r.Use(api.AuthenticateMiddleware(authn, true)) - - // Ideal location: users service, groups endpoint. - // Reason for placing here : - // SpiceDB provides list of user ids in given user_group_id - // and users service can access spiceDB and get the user list with user_group_id. - // Request to get list of users present in the user_group_id {groupID} - r.Get("/{domainID}/groups/{groupID}/users", otelhttp.NewHandler(kithttp.NewServer( - listMembersByGroupEndpoint(svc), - decodeListMembersByGroup, - api.EncodeResponse, - opts..., - ), "list_users_by_user_group_id").ServeHTTP) - - // Ideal location: clients service, channels endpoint. - // Reason for placing here : - // SpiceDB provides list of user ids in given channel_id - // and users service can access spiceDB and get the user list with channel_id. - // Request to get list of users present in the user_group_id {channelID} - r.Get("/{domainID}/channels/{channelID}/users", otelhttp.NewHandler(kithttp.NewServer( - listMembersByChannelEndpoint(svc), - decodeListMembersByChannel, - api.EncodeResponse, - opts..., - ), "list_users_by_channel_id").ServeHTTP) - - r.Get("/{domainID}/clients/{clientID}/users", otelhttp.NewHandler(kithttp.NewServer( - listMembersByClientEndpoint(svc), - decodeListMembersByClient, - api.EncodeResponse, - opts..., - ), "list_users_by_client_id").ServeHTTP) - - r.Get("/{domainID}/users", otelhttp.NewHandler(kithttp.NewServer( - listMembersByDomainEndpoint(svc), - decodeListMembersByDomain, - api.EncodeResponse, - opts..., - ), "list_users_by_domain_id").ServeHTTP) - }) - r.Post("/users/tokens/issue", otelhttp.NewHandler(kithttp.NewServer( issueTokenEndpoint(svc), decodeCredentials, @@ -550,123 +507,6 @@ func decodeChangeUserStatus(_ context.Context, r *http.Request) (interface{}, er return req, nil } -func decodeListMembersByGroup(_ context.Context, r *http.Request) (interface{}, error) { - page, err := queryPageParams(r, api.DefPermission) - if err != nil { - return nil, err - } - req := listMembersByObjectReq{ - Page: page, - objectID: chi.URLParam(r, "groupID"), - } - - return req, nil -} - -func decodeListMembersByChannel(_ context.Context, r *http.Request) (interface{}, error) { - page, err := queryPageParams(r, api.DefPermission) - if err != nil { - return nil, err - } - req := listMembersByObjectReq{ - Page: page, - objectID: chi.URLParam(r, "channelID"), - } - - return req, nil -} - -func decodeListMembersByClient(_ context.Context, r *http.Request) (interface{}, error) { - page, err := queryPageParams(r, api.DefPermission) - if err != nil { - return nil, err - } - req := listMembersByObjectReq{ - Page: page, - objectID: chi.URLParam(r, "clientID"), - } - - return req, nil -} - -func decodeListMembersByDomain(_ context.Context, r *http.Request) (interface{}, error) { - page, err := queryPageParams(r, policies.MembershipPermission) - if err != nil { - return nil, err - } - - req := listMembersByObjectReq{ - Page: page, - objectID: chi.URLParam(r, "domainID"), - } - - return req, nil -} - -func queryPageParams(r *http.Request, defPermission string) (users.Page, error) { - s, err := apiutil.ReadStringQuery(r, api.StatusKey, api.DefClientStatus) - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - o, err := apiutil.ReadNumQuery[uint64](r, api.OffsetKey, api.DefOffset) - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - l, err := apiutil.ReadNumQuery[uint64](r, api.LimitKey, api.DefLimit) - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - m, err := apiutil.ReadMetadataQuery(r, api.MetadataKey, nil) - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - n, err := apiutil.ReadStringQuery(r, api.UsernameKey, "") - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - f, err := apiutil.ReadStringQuery(r, api.FirstNameKey, "") - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - a, err := apiutil.ReadStringQuery(r, api.LastNameKey, "") - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - i, err := apiutil.ReadStringQuery(r, api.EmailKey, "") - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - t, err := apiutil.ReadStringQuery(r, api.TagKey, "") - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - st, err := users.ToStatus(s) - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - p, err := apiutil.ReadStringQuery(r, api.PermissionKey, defPermission) - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - lp, err := apiutil.ReadBoolQuery(r, api.ListPerms, api.DefListPerms) - if err != nil { - return users.Page{}, errors.Wrap(apiutil.ErrValidation, err) - } - return users.Page{ - Status: st, - Offset: o, - Limit: l, - Metadata: m, - FirstName: f, - Username: n, - LastName: a, - Email: i, - Tag: t, - Permission: p, - ListPerms: lp, - }, nil -} - // oauth2CallbackHandler is a http.HandlerFunc that handles OAuth2 callbacks. func oauth2CallbackHandler(oauth oauth2.Provider, svc users.Service, tokenClient grpcTokenV1.TokenServiceClient) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { diff --git a/users/events/events.go b/users/events/events.go index d9f781333e..2d9296ca01 100644 --- a/users/events/events.go +++ b/users/events/events.go @@ -43,7 +43,6 @@ var ( _ events.Event = (*viewUserEvent)(nil) _ events.Event = (*viewProfileEvent)(nil) _ events.Event = (*listUserEvent)(nil) - _ events.Event = (*listUserByGroupEvent)(nil) _ events.Event = (*searchUserEvent)(nil) _ events.Event = (*identifyUserEvent)(nil) _ events.Event = (*generateResetTokenEvent)(nil) @@ -359,63 +358,6 @@ func (lue listUserEvent) Encode() (map[string]interface{}, error) { return val, nil } -type listUserByGroupEvent struct { - users.Page - objectKind string - objectID string - authn.Session -} - -func (lcge listUserByGroupEvent) Encode() (map[string]interface{}, error) { - val := map[string]interface{}{ - "operation": userListByGroup, - "total": lcge.Total, - "offset": lcge.Offset, - "limit": lcge.Limit, - "object_kind": lcge.objectKind, - "object_id": lcge.objectID, - "domain": lcge.DomainID, - "token_type": lcge.Type.String(), - "super_admin": lcge.SuperAdmin, - } - - if lcge.Username != "" { - val["username"] = lcge.Username - } - if lcge.Order != "" { - val["order"] = lcge.Order - } - if lcge.Dir != "" { - val["dir"] = lcge.Dir - } - if lcge.Metadata != nil { - val["metadata"] = lcge.Metadata - } - if lcge.Domain != "" { - val["domain"] = lcge.Domain - } - if lcge.Tag != "" { - val["tag"] = lcge.Tag - } - if lcge.Permission != "" { - val["permission"] = lcge.Permission - } - if lcge.Status.String() != "" { - val["status"] = lcge.Status.String() - } - if lcge.FirstName != "" { - val["first_name"] = lcge.FirstName - } - if lcge.LastName != "" { - val["last_name"] = lcge.LastName - } - if lcge.Email != "" { - val["email"] = lcge.Email - } - - return val, nil -} - type searchUserEvent struct { users.Page } diff --git a/users/events/streams.go b/users/events/streams.go index 49833bc23c..a59dd40df2 100644 --- a/users/events/streams.go +++ b/users/events/streams.go @@ -216,25 +216,6 @@ func (es *eventStore) SearchUsers(ctx context.Context, pm users.Page) (users.Use return cp, nil } -func (es *eventStore) ListMembers(ctx context.Context, session authn.Session, objectKind, objectID string, pm users.Page) (users.MembersPage, error) { - mp, err := es.svc.ListMembers(ctx, session, objectKind, objectID, pm) - if err != nil { - return mp, err - } - event := listUserByGroupEvent{ - Page: pm, - objectKind: objectKind, - objectID: objectID, - Session: session, - } - - if err := es.Publish(ctx, event); err != nil { - return mp, err - } - - return mp, nil -} - func (es *eventStore) Enable(ctx context.Context, session authn.Session, id string) (users.User, error) { user, err := es.svc.Enable(ctx, session, id) if err != nil { diff --git a/users/middleware/authorization.go b/users/middleware/authorization.go index a1dd1d6dd2..db84ad71bc 100644 --- a/users/middleware/authorization.go +++ b/users/middleware/authorization.go @@ -100,73 +100,6 @@ func (am *authorizationMiddleware) ListUsers(ctx context.Context, session authn. return am.svc.ListUsers(ctx, session, pm) } -func (am *authorizationMiddleware) ListMembers(ctx context.Context, session authn.Session, objectKind, objectID string, pm users.Page) (users.MembersPage, error) { - if session.Type == authn.PersonalAccessToken { - switch objectKind { - case policies.GroupsKind: - if err := am.authz.AuthorizePAT(ctx, smqauthz.PatReq{ - UserID: session.UserID, - PatID: session.PatID, - OptionalDomainID: session.DomainID, - PlatformEntityType: smqauth.PlatformUsersScope, - OptionalDomainEntityType: smqauth.DomainGroupsScope, - Operation: smqauth.ListOp, - EntityIDs: smqauth.AnyIDs{}.Values(), - }); err != nil { - return users.MembersPage{}, errors.Wrap(svcerr.ErrUnauthorizedPAT, err) - } - case policies.DomainsKind: - if err := am.authz.AuthorizePAT(ctx, smqauthz.PatReq{ - UserID: session.UserID, - PatID: session.PatID, - OptionalDomainID: session.DomainID, - PlatformEntityType: smqauth.PlatformUsersScope, - OptionalDomainEntityType: smqauth.DomainManagementScope, - Operation: smqauth.ListOp, - EntityIDs: smqauth.AnyIDs{}.Values(), - }); err != nil { - return users.MembersPage{}, errors.Wrap(svcerr.ErrUnauthorizedPAT, err) - } - case policies.ClientsKind: - if err := am.authz.AuthorizePAT(ctx, smqauthz.PatReq{ - UserID: session.UserID, - PatID: session.PatID, - OptionalDomainID: session.DomainID, - PlatformEntityType: smqauth.PlatformUsersScope, - OptionalDomainEntityType: smqauth.DomainClientsScope, - Operation: smqauth.ListOp, - EntityIDs: smqauth.AnyIDs{}.Values(), - }); err != nil { - return users.MembersPage{}, errors.Wrap(svcerr.ErrUnauthorizedPAT, err) - } - default: - return users.MembersPage{}, svcerr.ErrAuthorization - } - } - - if session.DomainUserID == "" { - return users.MembersPage{}, svcerr.ErrDomainAuthorization - } - switch objectKind { - case policies.GroupsKind: - if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, smqauth.SwitchToPermission(pm.Permission), policies.GroupType, objectID); err != nil { - return users.MembersPage{}, err - } - case policies.DomainsKind: - if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, smqauth.SwitchToPermission(pm.Permission), policies.DomainType, objectID); err != nil { - return users.MembersPage{}, err - } - case policies.ClientsKind: - if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.UserID, smqauth.SwitchToPermission(pm.Permission), policies.ClientType, objectID); err != nil { - return users.MembersPage{}, err - } - default: - return users.MembersPage{}, svcerr.ErrAuthorization - } - - return am.svc.ListMembers(ctx, session, objectKind, objectID, pm) -} - func (am *authorizationMiddleware) SearchUsers(ctx context.Context, pm users.Page) (users.UsersPage, error) { return am.svc.SearchUsers(ctx, pm) } diff --git a/users/middleware/logging.go b/users/middleware/logging.go index 5319944e05..3f3ea4eb77 100644 --- a/users/middleware/logging.go +++ b/users/middleware/logging.go @@ -414,32 +414,6 @@ func (lm *loggingMiddleware) Disable(ctx context.Context, session authn.Session, return lm.svc.Disable(ctx, session, id) } -// ListMembers logs the list_members request. It logs the group id, and the time it took to complete the request. -// If the request fails, it logs the error. -func (lm *loggingMiddleware) ListMembers(ctx context.Context, session authn.Session, objectKind, objectID string, cp users.Page) (mp users.MembersPage, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.Group("object", - slog.String("kind", objectKind), - slog.String("id", objectID), - ), - slog.Group("page", - slog.Uint64("limit", cp.Limit), - slog.Uint64("offset", cp.Offset), - slog.Uint64("total", mp.Total), - ), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("List members failed", args...) - return - } - lm.logger.Info("List members completed successfully", args...) - }(time.Now()) - return lm.svc.ListMembers(ctx, session, objectKind, objectID, cp) -} - // Identify logs the identify request. It logs the time it took to complete the request. func (lm *loggingMiddleware) Identify(ctx context.Context, session authn.Session) (id string, err error) { defer func(begin time.Time) { diff --git a/users/middleware/metrics.go b/users/middleware/metrics.go index 6fe1f999d7..d7380382ce 100644 --- a/users/middleware/metrics.go +++ b/users/middleware/metrics.go @@ -201,15 +201,6 @@ func (ms *metricsMiddleware) Disable(ctx context.Context, session authn.Session, return ms.svc.Disable(ctx, session, id) } -// ListMembers instruments ListMembers method with metrics. -func (ms *metricsMiddleware) ListMembers(ctx context.Context, session authn.Session, objectKind, objectID string, pm users.Page) (mp users.MembersPage, err error) { - defer func(begin time.Time) { - ms.counter.With("method", "list_members").Add(1) - ms.latency.With("method", "list_members").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.ListMembers(ctx, session, objectKind, objectID, pm) -} - // Identify instruments Identify method with metrics. func (ms *metricsMiddleware) Identify(ctx context.Context, session authn.Session) (string, error) { defer func(begin time.Time) { diff --git a/users/mocks/service.go b/users/mocks/service.go index a7a2fd6f94..49d070c2ee 100644 --- a/users/mocks/service.go +++ b/users/mocks/service.go @@ -171,34 +171,6 @@ func (_m *Service) IssueToken(ctx context.Context, identity string, secret strin return r0, r1 } -// ListMembers provides a mock function with given fields: ctx, session, objectKind, objectID, pm -func (_m *Service) ListMembers(ctx context.Context, session authn.Session, objectKind string, objectID string, pm users.Page) (users.MembersPage, error) { - ret := _m.Called(ctx, session, objectKind, objectID, pm) - - if len(ret) == 0 { - panic("no return value specified for ListMembers") - } - - var r0 users.MembersPage - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, users.Page) (users.MembersPage, error)); ok { - return rf(ctx, session, objectKind, objectID, pm) - } - if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, users.Page) users.MembersPage); ok { - r0 = rf(ctx, session, objectKind, objectID, pm) - } else { - r0 = ret.Get(0).(users.MembersPage) - } - - if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, users.Page) error); ok { - r1 = rf(ctx, session, objectKind, objectID, pm) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // ListUsers provides a mock function with given fields: ctx, session, pm func (_m *Service) ListUsers(ctx context.Context, session authn.Session, pm users.Page) (users.UsersPage, error) { ret := _m.Called(ctx, session, pm) diff --git a/users/service.go b/users/service.go index 1a8f28d81e..2ea3f90760 100644 --- a/users/service.go +++ b/users/service.go @@ -17,14 +17,12 @@ import ( repoerr "github.com/absmach/supermq/pkg/errors/repository" svcerr "github.com/absmach/supermq/pkg/errors/service" "github.com/absmach/supermq/pkg/policies" - "golang.org/x/sync/errgroup" ) var ( - errIssueToken = errors.New("failed to issue token") - errFailedPermissionsList = errors.New("failed to list permissions") - errRecoveryToken = errors.New("failed to generate password recovery token") - errLoginDisableUser = errors.New("failed to login in disabled user") + errIssueToken = errors.New("failed to issue token") + errRecoveryToken = errors.New("failed to generate password recovery token") + errLoginDisableUser = errors.New("failed to login in disabled user") ) type service struct { @@ -469,106 +467,6 @@ func (svc service) Delete(ctx context.Context, session authn.Session, id string) return nil } -func (svc service) ListMembers(ctx context.Context, session authn.Session, objectKind, objectID string, pm Page) (MembersPage, error) { - var objectType string - switch objectKind { - case policies.ClientsKind: - objectType = policies.ClientType - case policies.DomainsKind: - objectType = policies.DomainType - case policies.GroupsKind: - fallthrough - default: - objectType = policies.GroupType - } - - duids, err := svc.policies.ListAllSubjects(ctx, policies.Policy{ - SubjectType: policies.UserType, - Permission: pm.Permission, - Object: objectID, - ObjectType: objectType, - }) - if err != nil { - return MembersPage{}, errors.Wrap(svcerr.ErrNotFound, err) - } - if len(duids.Policies) == 0 { - return MembersPage{ - Page: Page{Total: 0, Offset: pm.Offset, Limit: pm.Limit}, - }, nil - } - - var userIDs []string - - for _, domainUserID := range duids.Policies { - _, userID := smqauth.DecodeDomainUserID(domainUserID) - userIDs = append(userIDs, userID) - } - pm.IDs = userIDs - - up, err := svc.users.RetrieveAll(ctx, pm) - if err != nil { - return MembersPage{}, errors.Wrap(svcerr.ErrViewEntity, err) - } - - for i, u := range up.Users { - up.Users[i] = User{ - ID: u.ID, - FirstName: u.FirstName, - LastName: u.LastName, - Credentials: Credentials{ - Username: u.Credentials.Username, - }, - CreatedAt: u.CreatedAt, - UpdatedAt: u.UpdatedAt, - Status: u.Status, - } - } - - if pm.ListPerms && len(up.Users) > 0 { - g, ctx := errgroup.WithContext(ctx) - - for i := range up.Users { - // Copying loop variable "i" to avoid "loop variable captured by func literal" - iter := i - g.Go(func() error { - return svc.retrieveObjectUsersPermissions(ctx, session.DomainID, objectType, objectID, &up.Users[iter]) - }) - } - - if err := g.Wait(); err != nil { - return MembersPage{}, err - } - } - - return MembersPage{ - Page: up.Page, - Members: up.Users, - }, nil -} - -func (svc service) retrieveObjectUsersPermissions(ctx context.Context, domainID, objectType, objectID string, user *User) error { - userID := smqauth.EncodeDomainUserID(domainID, user.ID) - permissions, err := svc.listObjectUserPermission(ctx, userID, objectType, objectID) - if err != nil { - return errors.Wrap(svcerr.ErrAuthorization, err) - } - user.Permissions = permissions - return nil -} - -func (svc service) listObjectUserPermission(ctx context.Context, userID, objectType, objectID string) ([]string, error) { - permissions, err := svc.policies.ListPermissions(ctx, policies.Policy{ - SubjectType: policies.UserType, - Subject: userID, - Object: objectID, - ObjectType: objectType, - }, []string{}) - if err != nil { - return []string{}, errors.Wrap(errFailedPermissionsList, err) - } - return permissions, nil -} - func (svc *service) checkSuperAdmin(ctx context.Context, session authn.Session) error { if !session.SuperAdmin { if err := svc.users.CheckSuperAdmin(ctx, session.UserID); err != nil { diff --git a/users/service_test.go b/users/service_test.go index 881ae25b05..fee974fd1a 100644 --- a/users/service_test.go +++ b/users/service_test.go @@ -17,7 +17,6 @@ import ( "github.com/absmach/supermq/pkg/errors" repoerr "github.com/absmach/supermq/pkg/errors/repository" svcerr "github.com/absmach/supermq/pkg/errors/service" - policysvc "github.com/absmach/supermq/pkg/policies" policymocks "github.com/absmach/supermq/pkg/policies/mocks" "github.com/absmach/supermq/pkg/uuid" "github.com/absmach/supermq/users" @@ -1330,297 +1329,6 @@ func TestDeleteUser(t *testing.T) { } } -func TestListMembers(t *testing.T) { - svc, _, cRepo, policies, _ := newService() - - validPolicy := fmt.Sprintf("%s_%s", validID, user.ID) - permissionsUser := basicUser - permissionsUser.Permissions = []string{"read"} - - cases := []struct { - desc string - groupID string - objectKind string - objectID string - page users.Page - listAllSubjectsReq policysvc.Policy - listAllSubjectsResponse policysvc.PolicyPage - retrieveAllResponse users.UsersPage - listPermissionsResponse policysvc.Permissions - response users.MembersPage - listAllSubjectsErr error - retrieveAllErr error - identifyErr error - listPermissionErr error - err error - }{ - { - desc: "list members with no policies successfully of the clients kind", - groupID: validID, - objectKind: policysvc.ClientsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read"}, - listAllSubjectsResponse: policysvc.PolicyPage{}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.ClientType, - }, - response: users.MembersPage{ - Page: users.Page{ - Total: 0, - Offset: 0, - Limit: 100, - }, - }, - err: nil, - }, - { - desc: "list members with policies successsfully of the clients kind", - groupID: validID, - objectKind: policysvc.ClientsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read"}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.ClientType, - }, - listAllSubjectsResponse: policysvc.PolicyPage{Policies: []string{validPolicy}}, - retrieveAllResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Users: []users.User{user}, - }, - response: users.MembersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Members: []users.User{basicUser}, - }, - err: nil, - }, - { - desc: "list members with policies successsfully of the clients kind with permissions", - groupID: validID, - objectKind: policysvc.ClientsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read", ListPerms: true}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.ClientType, - }, - listAllSubjectsResponse: policysvc.PolicyPage{Policies: []string{validPolicy}}, - retrieveAllResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Users: []users.User{basicUser}, - }, - listPermissionsResponse: []string{"read"}, - response: users.MembersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Members: []users.User{permissionsUser}, - }, - err: nil, - }, - { - desc: "list members with policies of the clients kind with permissionswith failed list permissions", - groupID: validID, - objectKind: policysvc.ClientsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read", ListPerms: true}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.ClientType, - }, - listAllSubjectsResponse: policysvc.PolicyPage{Policies: []string{validPolicy}}, - retrieveAllResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Users: []users.User{user}, - }, - listPermissionsResponse: []string{}, - response: users.MembersPage{}, - listPermissionErr: svcerr.ErrNotFound, - err: svcerr.ErrNotFound, - }, - { - desc: "list members with of the clients kind with failed to list all subjects", - groupID: validID, - objectKind: policysvc.ClientsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read"}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.ClientType, - }, - listAllSubjectsErr: repoerr.ErrNotFound, - listAllSubjectsResponse: policysvc.PolicyPage{}, - err: repoerr.ErrNotFound, - }, - { - desc: "list members with of the clients kind with failed to retrieve all", - groupID: validID, - objectKind: policysvc.ClientsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read"}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.ClientType, - }, - listAllSubjectsResponse: policysvc.PolicyPage{Policies: []string{validPolicy}}, - retrieveAllResponse: users.UsersPage{}, - response: users.MembersPage{}, - retrieveAllErr: repoerr.ErrNotFound, - err: repoerr.ErrNotFound, - }, - { - desc: "list members with no policies successfully of the domain kind", - groupID: validID, - objectKind: policysvc.DomainsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read"}, - listAllSubjectsResponse: policysvc.PolicyPage{}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.DomainType, - }, - response: users.MembersPage{ - Page: users.Page{ - Total: 0, - Offset: 0, - Limit: 100, - }, - }, - err: nil, - }, - { - desc: "list members with policies successsfully of the domains kind", - groupID: validID, - objectKind: policysvc.DomainsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read"}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.DomainType, - }, - listAllSubjectsResponse: policysvc.PolicyPage{Policies: []string{validPolicy}}, - retrieveAllResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Users: []users.User{basicUser}, - }, - response: users.MembersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Members: []users.User{basicUser}, - }, - err: nil, - }, - { - desc: "list members with no policies successfully of the groups kind", - groupID: validID, - objectKind: policysvc.GroupsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read"}, - listAllSubjectsResponse: policysvc.PolicyPage{}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.GroupType, - }, - response: users.MembersPage{ - Page: users.Page{ - Total: 0, - Offset: 0, - Limit: 100, - }, - }, - err: nil, - }, - { - desc: "list members with policies successsfully of the groups kind", - - groupID: validID, - objectKind: policysvc.GroupsKind, - objectID: validID, - page: users.Page{Offset: 0, Limit: 100, Permission: "read"}, - listAllSubjectsReq: policysvc.Policy{ - SubjectType: policysvc.UserType, - Permission: "read", - Object: validID, - ObjectType: policysvc.GroupType, - }, - listAllSubjectsResponse: policysvc.PolicyPage{Policies: []string{validPolicy}}, - retrieveAllResponse: users.UsersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Users: []users.User{user}, - }, - response: users.MembersPage{ - Page: users.Page{ - Total: 1, - Offset: 0, - Limit: 100, - }, - Members: []users.User{basicUser}, - }, - err: nil, - }, - } - - for _, tc := range cases { - policyCall := policies.On("ListAllSubjects", context.Background(), tc.listAllSubjectsReq).Return(tc.listAllSubjectsResponse, tc.listAllSubjectsErr) - repoCall := cRepo.On("RetrieveAll", context.Background(), mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) - policyCall1 := policies.On("ListPermissions", mock.Anything, mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionErr) - page, err := svc.ListMembers(context.Background(), authn.Session{}, tc.objectKind, tc.objectID, tc.page) - assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - assert.Equal(t, tc.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) - policyCall.Unset() - repoCall.Unset() - policyCall1.Unset() - } -} - func TestIssueToken(t *testing.T) { svc, auth, cRepo, _, _ := newService() diff --git a/users/tracing/tracing.go b/users/tracing/tracing.go index 02c92c1925..0ef1f36708 100644 --- a/users/tracing/tracing.go +++ b/users/tracing/tracing.go @@ -210,14 +210,6 @@ func (tm *tracingMiddleware) Disable(ctx context.Context, session authn.Session, return tm.svc.Disable(ctx, session, id) } -// ListMembers traces the "ListMembers" operation of the wrapped users.Service. -func (tm *tracingMiddleware) ListMembers(ctx context.Context, session authn.Session, objectKind, objectID string, pm users.Page) (users.MembersPage, error) { - ctx, span := tm.tracer.Start(ctx, "svc_list_members", trace.WithAttributes(attribute.String("object_kind", objectKind)), trace.WithAttributes(attribute.String("object_id", objectID))) - defer span.End() - - return tm.svc.ListMembers(ctx, session, objectKind, objectID, pm) -} - // Identify traces the "Identify" operation of the wrapped users.Service. func (tm *tracingMiddleware) Identify(ctx context.Context, session authn.Session) (string, error) { ctx, span := tm.tracer.Start(ctx, "svc_identify", trace.WithAttributes(attribute.String("user_id", session.UserID))) diff --git a/users/users.go b/users/users.go index e01be1f535..a8e52598c9 100644 --- a/users/users.go +++ b/users/users.go @@ -151,9 +151,6 @@ type Service interface { // ListUsers retrieves users list for a valid auth token. ListUsers(ctx context.Context, session authn.Session, pm Page) (UsersPage, error) - // ListMembers retrieves everything that is assigned to a group/client identified by objectID. - ListMembers(ctx context.Context, session authn.Session, objectKind, objectID string, pm Page) (MembersPage, error) - // SearchUsers searches for users with provided filters for a valid auth token. SearchUsers(ctx context.Context, pm Page) (UsersPage, error)