diff --git a/pkg/clients/clients.go b/pkg/clients/clients.go index 68a8416052..1278675533 100644 --- a/pkg/clients/clients.go +++ b/pkg/clients/clients.go @@ -78,8 +78,8 @@ type Repository interface { // RetrieveAll retrieves all clients. RetrieveAll(ctx context.Context, pm Page) (ClientsPage, error) - // SearchBasicInfo list all clients only with basic information. - SearchBasicInfo(ctx context.Context, pm Page) (ClientsPage, error) + // SearchClients retrieves clients based on search criteria. + SearchClients(ctx context.Context, pm Page) (ClientsPage, error) // RetrieveAllByIDs retrieves for given client IDs . RetrieveAllByIDs(ctx context.Context, pm Page) (ClientsPage, error) diff --git a/pkg/clients/postgres/clients.go b/pkg/clients/postgres/clients.go index d9cf9e337c..ad1aeddd4b 100644 --- a/pkg/clients/postgres/clients.go +++ b/pkg/clients/postgres/clients.go @@ -143,6 +143,7 @@ func (repo *Repository) RetrieveAll(ctx context.Context, pm clients.Page) (clien if err != nil { return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err) } + query = applyOrdering(query, pm) q := fmt.Sprintf(`SELECT c.id, c.name, c.tags, c.identity, c.metadata, COALESCE(c.domain_id, '') AS domain_id, c.status, c.created_at, c.updated_at, COALESCE(c.updated_by, '') AS updated_by FROM clients c %s ORDER BY c.created_at LIMIT :limit OFFSET :offset;`, query) @@ -190,10 +191,16 @@ func (repo *Repository) RetrieveAll(ctx context.Context, pm clients.Page) (clien return page, nil } -func (repo *Repository) SearchBasicInfo(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) { - sq, tq := ConstructSearchQuery(pm) +func (repo *Repository) SearchClients(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) { + query, err := PageQuery(pm) + if err != nil { + return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err) + } - q := fmt.Sprintf(`SELECT c.id, c.name, c.created_at, c.updated_at FROM clients c %s LIMIT :limit OFFSET :offset;`, sq) + tq := query + query = applyOrdering(query, pm) + + q := fmt.Sprintf(`SELECT c.id, c.name, c.created_at, c.updated_at FROM clients c %s LIMIT :limit OFFSET :offset;`, query) dbPage, err := ToDBClientsPage(pm) if err != nil { @@ -249,6 +256,7 @@ func (repo *Repository) RetrieveAllByIDs(ctx context.Context, pm clients.Page) ( if err != nil { return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err) } + query = applyOrdering(query, pm) q := fmt.Sprintf(`SELECT c.id, c.name, c.tags, c.identity, c.metadata, COALESCE(c.domain_id, '') AS domain_id, c.status, c.created_at, c.updated_at, COALESCE(c.updated_by, '') AS updated_by FROM clients c %s ORDER BY c.created_at LIMIT :limit OFFSET :offset;`, query) @@ -334,24 +342,6 @@ func (repo *Repository) Delete(ctx context.Context, id string) error { return nil } -func (repo *Repository) CheckSuperAdmin(ctx context.Context, adminID string) error { - q := "SELECT 1 FROM clients WHERE id = $1 AND role = $2" - rows, err := repo.DB.QueryContext(ctx, q, adminID, clients.AdminRole) - if err != nil { - return postgres.HandleError(repoerr.ErrViewEntity, err) - } - defer rows.Close() - - if rows.Next() { - if err := rows.Err(); err != nil { - return postgres.HandleError(repoerr.ErrViewEntity, err) - } - return nil - } - - return repoerr.ErrNotFound -} - type DBClient struct { ID string `db:"id"` Name string `db:"name,omitempty"` @@ -487,14 +477,8 @@ func PageQuery(pm clients.Page) (string, error) { if err != nil { return "", errors.Wrap(errors.ErrMalformedEntity, err) } + var query []string - var emq string - if mq != "" { - query = append(query, mq) - } - if len(pm.IDs) != 0 { - query = append(query, fmt.Sprintf("id IN ('%s')", strings.Join(pm.IDs, "','"))) - } if pm.Name != "" { query = append(query, "name ILIKE '%' || :name || '%'") } @@ -505,45 +489,38 @@ func PageQuery(pm clients.Page) (string, error) { query = append(query, "id ILIKE '%' || :id || '%'") } if pm.Tag != "" { - query = append(query, ":tag = ANY(c.tags)") - } - if pm.Status != clients.AllStatus { - query = append(query, "c.status = :status") - } - if pm.Domain != "" { - query = append(query, "c.domain_id = :domain_id") + query = append(query, "EXISTS (SELECT 1 FROM unnest(tags) AS tag WHERE tag ILIKE '%' || :tag || '%')") } - if pm.Role != clients.AllRole { query = append(query, "c.role = :role") } - if len(query) > 0 { - emq = fmt.Sprintf("WHERE %s", strings.Join(query, " AND ")) + // If there are search params presents, use search and ignore other options. + // Always combine role with search params, so len(query) > 1. + if len(query) > 1 { + return fmt.Sprintf("WHERE %s", strings.Join(query, " AND ")), nil } - return emq, nil -} -func ConstructSearchQuery(pm clients.Page) (string, string) { - var query []string - var emq string - var tq string + if mq != "" { + query = append(query, mq) + } - if pm.Name != "" { - query = append(query, "name ILIKE '%' || :name || '%'") + if len(pm.IDs) != 0 { + query = append(query, fmt.Sprintf("id IN ('%s')", strings.Join(pm.IDs, "','"))) } - if pm.Identity != "" { - query = append(query, "identity ILIKE '%' || :identity || '%'") + if pm.Status != clients.AllStatus { + query = append(query, "c.status = :status") } - if pm.Id != "" { - query = append(query, "id ILIKE '%' || :id || '%'") + if pm.Domain != "" { + query = append(query, "c.domain_id = :domain_id") } - + var emq string if len(query) > 0 { emq = fmt.Sprintf("WHERE %s", strings.Join(query, " AND ")) } + return emq, nil +} - tq = emq - +func applyOrdering(emq string, pm clients.Page) string { switch pm.Order { case "name", "identity", "created_at", "updated_at": emq = fmt.Sprintf("%s ORDER BY %s", emq, pm.Order) @@ -551,6 +528,5 @@ func ConstructSearchQuery(pm clients.Page) (string, string) { emq = fmt.Sprintf("%s %s", emq, pm.Dir) } } - - return emq, tq + return emq } diff --git a/pkg/clients/postgres/clients_test.go b/pkg/clients/postgres/clients_test.go index a5c0c01bbd..e381b48eae 100644 --- a/pkg/clients/postgres/clients_test.go +++ b/pkg/clients/postgres/clients_test.go @@ -927,7 +927,7 @@ func TestRetrieveByIDs(t *testing.T) { } } -func TestSearchBasicInfo(t *testing.T) { +func TestSearchClients(t *testing.T) { t.Cleanup(func() { _, err := db.Exec("DELETE FROM clients") require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err)) @@ -1289,7 +1289,7 @@ func TestSearchBasicInfo(t *testing.T) { } for _, c := range cases { t.Run(c.desc, func(t *testing.T) { - switch response, err := repo.SearchBasicInfo(context.Background(), c.page); { + switch response, err := repo.SearchClients(context.Background(), c.page); { case err == nil: if c.page.Order != "" && c.page.Dir != "" { c.response = response diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index 2c56c988d9..cd51f3b8bb 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -471,7 +471,7 @@ func TestListThings(t *testing.T) { repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false}, svcerr.ErrAuthorization) repoCall2 = auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{}, svcerr.ErrAuthorization) } - repoCall3 := cRepo.On("RetrieveAllByIDs", mock.Anything, mock.Anything).Return(mgclients.ClientsPage{Page: convertClientPage(pm), Clients: convertThings(tc.response...)}, tc.err) + repoCall3 := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(mgclients.ClientsPage{Page: convertClientPage(pm), Clients: convertThings(tc.response...)}, tc.err) page, err := mgsdk.Things(pm, validToken) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err)) assert.Equal(t, tc.response, page.Things, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page)) @@ -1042,7 +1042,7 @@ func TestEnableThing(t *testing.T) { repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false}, svcerr.ErrAuthorization) } repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{Policies: toIDs(tc.response.Things)}, nil) - repoCall3 := cRepo.On("RetrieveAllByIDs", mock.Anything, mock.Anything).Return(convertThingsPage(tc.response), nil) + repoCall3 := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(convertThingsPage(tc.response), nil) clientsPage, err := mgsdk.Things(pm, validToken) assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err)) size := uint64(len(clientsPage.Things)) @@ -1179,7 +1179,7 @@ func TestDisableThing(t *testing.T) { repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false}, svcerr.ErrAuthorization) } repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{Policies: toIDs(tc.response.Things)}, nil) - repoCall3 := cRepo.On("RetrieveAllByIDs", mock.Anything, mock.Anything).Return(convertThingsPage(tc.response), nil) + repoCall3 := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(convertThingsPage(tc.response), nil) page, err := mgsdk.Things(pm, validToken) assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err)) size := uint64(len(page.Things)) diff --git a/things/api/http/clients.go b/things/api/http/clients.go index 759e2f169c..24652c4680 100644 --- a/things/api/http/clients.go +++ b/things/api/http/clients.go @@ -181,6 +181,10 @@ func decodeListClients(_ context.Context, r *http.Request) (interface{}, error) if err != nil { return nil, errors.Wrap(apiutil.ErrValidation, err) } + id, err := apiutil.ReadStringQuery(r, api.IDOrder, "") + if err != nil { + return nil, errors.Wrap(apiutil.ErrValidation, err) + } p, err := apiutil.ReadStringQuery(r, api.PermissionKey, api.DefPermission) if err != nil { return nil, errors.Wrap(apiutil.ErrValidation, err) @@ -205,6 +209,7 @@ func decodeListClients(_ context.Context, r *http.Request) (interface{}, error) permission: p, listPerms: lp, userID: chi.URLParam(r, "userID"), + id: id, } return req, nil } diff --git a/things/api/http/endpoints.go b/things/api/http/endpoints.go index 8e6d8d28b1..ff70689a3a 100644 --- a/things/api/http/endpoints.go +++ b/things/api/http/endpoints.go @@ -109,6 +109,7 @@ func listClientsEndpoint(svc things.Service) endpoint.Endpoint { Metadata: req.metadata, ListPerms: req.listPerms, Role: mgclients.AllRole, // retrieve all things since things don't have roles + Id: req.id, } page, err := svc.ListClients(ctx, req.token, req.userID, pm) if err != nil { diff --git a/things/api/http/requests.go b/things/api/http/requests.go index 42ef86424b..41746442cb 100644 --- a/things/api/http/requests.go +++ b/things/api/http/requests.go @@ -98,6 +98,7 @@ type listClientsReq struct { userID string listPerms bool metadata mgclients.Metadata + id string } func (req listClientsReq) validate() error { diff --git a/things/api/http/requests_test.go b/things/api/http/requests_test.go index e3d9ee5010..74fccf2c8e 100644 --- a/things/api/http/requests_test.go +++ b/things/api/http/requests_test.go @@ -19,6 +19,7 @@ import ( const ( valid = "valid" invalid = "invalid" + name = "client" ) var validID = testsutil.GenerateUUID(&testing.T{}) diff --git a/things/mocks/repository.go b/things/mocks/repository.go index 0d5429af14..ab254b064b 100644 --- a/things/mocks/repository.go +++ b/things/mocks/repository.go @@ -240,12 +240,12 @@ func (_m *Repository) Save(ctx context.Context, client ...clients.Client) ([]cli return r0, r1 } -// SearchBasicInfo provides a mock function with given fields: ctx, pm -func (_m *Repository) SearchBasicInfo(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) { +// SearchClients provides a mock function with given fields: ctx, pm +func (_m *Repository) SearchClients(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) { ret := _m.Called(ctx, pm) if len(ret) == 0 { - panic("no return value specified for SearchBasicInfo") + panic("no return value specified for SearchClients") } var r0 clients.ClientsPage diff --git a/things/service.go b/things/service.go index 8e11233cdb..8ece3b59b5 100644 --- a/things/service.go +++ b/things/service.go @@ -181,7 +181,7 @@ func (svc service) ListClients(ctx context.Context, token, reqUserID string, pm pm.IDs = ids - tp, err := svc.clients.RetrieveAllByIDs(ctx, pm) + tp, err := svc.clients.SearchClients(ctx, pm) if err != nil { return mgclients.ClientsPage{}, errors.Wrap(svcerr.ErrViewEntity, err) } diff --git a/things/service_test.go b/things/service_test.go index 810bcda99d..721c147e0a 100644 --- a/things/service_test.go +++ b/things/service_test.go @@ -28,7 +28,7 @@ import ( var ( secret = "strongsecret" validCMetadata = mgclients.Metadata{"role": "client"} - ID = testsutil.GenerateUUID(&testing.T{}) + ID = "6e5e10b3-d4df-4758-b426-4929d55ad740" client = mgclients.Client{ ID: ID, Name: "clientname", @@ -428,6 +428,7 @@ func TestListClients(t *testing.T) { identifyResponse *magistrala.IdentityRes authorizeResponse *magistrala.AuthorizeRes authorizeResponse1 *magistrala.AuthorizeRes + authorizeResponse2 *magistrala.AuthorizeRes listObjectsResponse *magistrala.ListObjectsRes listObjectsResponse1 *magistrala.ListObjectsRes retrieveAllResponse mgclients.ClientsPage @@ -438,6 +439,7 @@ func TestListClients(t *testing.T) { identifyErr error authorizeErr error authorizeErr1 error + authorizeErr2 error listObjectsErr error retrieveAllErr error listPermissionsErr error @@ -455,6 +457,7 @@ func TestListClients(t *testing.T) { }, identifyResponse: &magistrala.IdentityRes{Id: nonAdminID, UserId: nonAdminID, DomainId: domainID}, authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + authorizeResponse2: &magistrala.AuthorizeRes{Authorized: true}, listObjectsResponse: &magistrala.ListObjectsRes{}, retrieveAllResponse: mgclients.ClientsPage{ Page: mgclients.Page{ @@ -531,8 +534,9 @@ func TestListClients(t *testing.T) { Limit: 100, ListPerms: true, }, - identifyResponse: &magistrala.IdentityRes{Id: nonAdminID, UserId: nonAdminID, DomainId: domainID}, - authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + identifyResponse: &magistrala.IdentityRes{Id: nonAdminID, UserId: nonAdminID, DomainId: domainID}, + authorizeResponse: &magistrala.AuthorizeRes{Authorized: true}, + authorizeResponse2: &magistrala.AuthorizeRes{Authorized: true}, retrieveAllResponse: mgclients.ClientsPage{ Page: mgclients.Page{ Total: 2, @@ -619,7 +623,7 @@ func TestListClients(t *testing.T) { Object: tc.identifyResponse.DomainId, }).Return(tc.authorizeResponse1, tc.authorizeErr1) listAllObjectsCall := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(tc.listObjectsResponse, tc.listObjectsErr) - retrieveAllCall := cRepo.On("RetrieveAllByIDs", mock.Anything, mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) + retrieveAllCall := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) listPermissionsCall := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionsErr) page, err := svc.ListClients(context.Background(), tc.token, tc.id, tc.page) @@ -799,7 +803,7 @@ func TestListClients(t *testing.T) { Permission: "", ObjectType: authsvc.ThingType, }).Return(tc.listObjectsResponse1, tc.listObjectsErr1) - retrieveAllCall := cRepo.On("RetrieveAllByIDs", mock.Anything, mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) + retrieveAllCall := cRepo.On("SearchClients", mock.Anything, mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) listPermissionsCall := auth.On("ListPermissions", mock.Anything, mock.Anything).Return(tc.listPermissionsResponse, tc.listPermissionsErr) page, err := svc.ListClients(context.Background(), tc.token, tc.id, tc.page) @@ -1193,7 +1197,7 @@ func TestEnableClient(t *testing.T) { repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{Policies: getIDs(tc.response.Clients)}, nil) - repoCall3 := cRepo.On("RetrieveAllByIDs", context.Background(), mock.Anything).Return(tc.response, nil) + repoCall3 := cRepo.On("SearchClients", context.Background(), mock.Anything).Return(tc.response, nil) page, err := svc.ListClients(context.Background(), validToken, "", pm) require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err)) size := uint64(len(page.Clients)) @@ -1363,7 +1367,7 @@ func TestDisableClient(t *testing.T) { repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil) repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil) repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&magistrala.ListObjectsRes{Policies: getIDs(tc.response.Clients)}, nil) - repoCall3 := cRepo.On("RetrieveAllByIDs", context.Background(), mock.Anything).Return(tc.response, nil) + repoCall3 := cRepo.On("SearchClients", context.Background(), mock.Anything).Return(tc.response, nil) page, err := svc.ListClients(context.Background(), validToken, "", pm) require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err)) size := uint64(len(page.Clients)) diff --git a/users/api/logging.go b/users/api/logging.go index 0e0af94ba5..7ed01bcbe7 100644 --- a/users/api/logging.go +++ b/users/api/logging.go @@ -381,27 +381,6 @@ func (lm *loggingMiddleware) ListMembers(ctx context.Context, token, objectKind, return lm.svc.ListMembers(ctx, token, objectKind, objectID, cp) } -// SearchClients logs the search_clients request. It logs the page metadata and the time it took to complete the request. -func (lm *loggingMiddleware) SearchUsers(ctx context.Context, token string, cp mgclients.Page) (mp mgclients.ClientsPage, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - 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("Search clients failed to complete successfully", args...) - return - } - lm.logger.Info("Search clients completed successfully", args...) - }(time.Now()) - return lm.svc.SearchUsers(ctx, token, cp) -} - // Identify logs the identify request. It logs the time it took to complete the request. func (lm *loggingMiddleware) Identify(ctx context.Context, token string) (id string, err error) { defer func(begin time.Time) { diff --git a/users/api/metrics.go b/users/api/metrics.go index 667826180f..ccf231adda 100644 --- a/users/api/metrics.go +++ b/users/api/metrics.go @@ -183,15 +183,6 @@ func (ms *metricsMiddleware) ListMembers(ctx context.Context, token, objectKind, return ms.svc.ListMembers(ctx, token, objectKind, objectID, pm) } -// SearchClients instruments SearchClients method with metrics. -func (ms *metricsMiddleware) SearchUsers(ctx context.Context, token string, pm mgclients.Page) (mp mgclients.ClientsPage, err error) { - defer func(begin time.Time) { - ms.counter.With("method", "search_clients").Add(1) - ms.latency.With("method", "search_clients").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.SearchUsers(ctx, token, pm) -} - // Identify instruments Identify method with metrics. func (ms *metricsMiddleware) Identify(ctx context.Context, token string) (string, error) { defer func(begin time.Time) { diff --git a/users/clients.go b/users/clients.go index 078f8ce4fb..e40c4f226d 100644 --- a/users/clients.go +++ b/users/clients.go @@ -31,9 +31,6 @@ type Service interface { // ListMembers retrieves everything that is assigned to a group/thing identified by objectID. ListMembers(ctx context.Context, token, objectKind, objectID string, pm clients.Page) (clients.MembersPage, error) - // SearchClients searches for users with provided filters for a valid auth token. - SearchUsers(ctx context.Context, token string, pm clients.Page) (clients.ClientsPage, error) - // UpdateClient updates the client's name and metadata. UpdateClient(ctx context.Context, token string, client clients.Client) (clients.Client, error) diff --git a/users/events/events.go b/users/events/events.go index 5fe80b455d..dda7a669a6 100644 --- a/users/events/events.go +++ b/users/events/events.go @@ -19,7 +19,6 @@ const ( profileView = clientPrefix + "view_profile" clientList = clientPrefix + "list" clientListByGroup = clientPrefix + "list_by_group" - clientSearch = clientPrefix + "search" clientIdentify = clientPrefix + "identify" generateResetToken = clientPrefix + "generate_reset_token" issueToken = clientPrefix + "issue_token" @@ -308,27 +307,6 @@ func (lcge listClientByGroupEvent) Encode() (map[string]interface{}, error) { return val, nil } -type searchClientEvent struct { - mgclients.Page -} - -func (sce searchClientEvent) Encode() (map[string]interface{}, error) { - val := map[string]interface{}{ - "operation": clientSearch, - "total": sce.Total, - "offset": sce.Offset, - "limit": sce.Limit, - } - if sce.Name != "" { - val["name"] = sce.Name - } - if sce.Identity != "" { - val["identity"] = sce.Identity - } - - return val, nil -} - type identifyClientEvent struct { userID string } diff --git a/users/events/streams.go b/users/events/streams.go index df479505f3..5563d89478 100644 --- a/users/events/streams.go +++ b/users/events/streams.go @@ -176,22 +176,6 @@ func (es *eventStore) ListMembers(ctx context.Context, token, objectKind, object return mp, nil } -func (es *eventStore) SearchUsers(ctx context.Context, token string, pm mgclients.Page) (mgclients.ClientsPage, error) { - cp, err := es.svc.SearchUsers(ctx, token, pm) - if err != nil { - return cp, err - } - event := searchClientEvent{ - pm, - } - - if err := es.Publish(ctx, event); err != nil { - return cp, err - } - - return cp, nil -} - func (es *eventStore) EnableClient(ctx context.Context, token, id string) (mgclients.Client, error) { user, err := es.svc.EnableClient(ctx, token, id) if err != nil { diff --git a/users/mocks/repository.go b/users/mocks/repository.go index f543e44c2e..8470e6e9a8 100644 --- a/users/mocks/repository.go +++ b/users/mocks/repository.go @@ -221,12 +221,12 @@ func (_m *Repository) Save(ctx context.Context, client clients.Client) (clients. return r0, r1 } -// SearchBasicInfo provides a mock function with given fields: ctx, pm -func (_m *Repository) SearchBasicInfo(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) { +// SearchClients provides a mock function with given fields: ctx, pm +func (_m *Repository) SearchClients(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) { ret := _m.Called(ctx, pm) if len(ret) == 0 { - panic("no return value specified for SearchBasicInfo") + panic("no return value specified for SearchClients") } var r0 clients.ClientsPage diff --git a/users/mocks/service.go b/users/mocks/service.go index f143cef06c..cd769feeca 100644 --- a/users/mocks/service.go +++ b/users/mocks/service.go @@ -331,34 +331,6 @@ func (_m *Service) ResetSecret(ctx context.Context, resetToken string, secret st return r0 } -// SearchUsers provides a mock function with given fields: ctx, token, pm -func (_m *Service) SearchUsers(ctx context.Context, token string, pm clients.Page) (clients.ClientsPage, error) { - ret := _m.Called(ctx, token, pm) - - if len(ret) == 0 { - panic("no return value specified for SearchUsers") - } - - var r0 clients.ClientsPage - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, clients.Page) (clients.ClientsPage, error)); ok { - return rf(ctx, token, pm) - } - if rf, ok := ret.Get(0).(func(context.Context, string, clients.Page) clients.ClientsPage); ok { - r0 = rf(ctx, token, pm) - } else { - r0 = ret.Get(0).(clients.ClientsPage) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, clients.Page) error); ok { - r1 = rf(ctx, token, pm) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // SendPasswordReset provides a mock function with given fields: ctx, host, email, user, token func (_m *Service) SendPasswordReset(ctx context.Context, host string, email string, user string, token string) error { ret := _m.Called(ctx, host, email, user, token) diff --git a/users/service.go b/users/service.go index 6195a6b2c8..07ec3b972f 100644 --- a/users/service.go +++ b/users/service.go @@ -181,6 +181,7 @@ func (svc service) ListClients(ctx context.Context, token string, pm mgclients.P return mgclients.ClientsPage{}, err } if err := svc.checkSuperAdmin(ctx, userID); err == nil { + pm.Role = mgclients.AllRole pg, err := svc.clients.RetrieveAll(ctx, pm) if err != nil { return mgclients.ClientsPage{}, errors.Wrap(svcerr.ErrViewEntity, err) @@ -188,15 +189,7 @@ func (svc service) ListClients(ctx context.Context, token string, pm mgclients.P return pg, err } - p := mgclients.Page{ - Status: mgclients.EnabledStatus, - Offset: pm.Offset, - Limit: pm.Limit, - Name: pm.Name, - Identity: pm.Identity, - Role: mgclients.UserRole, - } - pg, err := svc.clients.SearchBasicInfo(ctx, p) + pg, err := svc.clients.SearchClients(ctx, pm) if err != nil { return mgclients.ClientsPage{}, errors.Wrap(svcerr.ErrViewEntity, err) } @@ -553,20 +546,6 @@ func (svc service) ListMembers(ctx context.Context, token, objectKind, objectID }, nil } -func (svc service) SearchUsers(ctx context.Context, token string, pm mgclients.Page) (mgclients.ClientsPage, error) { - _, err := svc.identify(ctx, token) - if err != nil { - return mgclients.ClientsPage{}, err - } - - cp, err := svc.clients.SearchBasicInfo(ctx, pm) - if err != nil { - return mgclients.ClientsPage{}, errors.Wrap(svcerr.ErrSearch, err) - } - - return cp, nil -} - func (svc service) retrieveObjectUsersPermissions(ctx context.Context, domainID, objectType, objectID string, client *mgclients.Client) error { userID := auth.EncodeDomainUserID(domainID, client.ID) permissions, err := svc.listObjectUserPermission(ctx, userID, objectType, objectID) diff --git a/users/service_test.go b/users/service_test.go index abb18a7799..404e8e8b00 100644 --- a/users/service_test.go +++ b/users/service_test.go @@ -597,7 +597,7 @@ func TestListClients(t *testing.T) { authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr) repoCall := cRepo.On("CheckSuperAdmin", context.Background(), mock.Anything).Return(tc.superAdminErr) repoCall1 := cRepo.On("RetrieveAll", context.Background(), mock.Anything).Return(tc.retrieveAllResponse, tc.retrieveAllErr) - repoCall2 := cRepo.On("SearchBasicInfo", context.Background(), mock.Anything).Return(tc.response, tc.err) + repoCall2 := cRepo.On("SearchClients", context.Background(), mock.Anything).Return(tc.response, tc.err) page, err := svc.ListClients(context.Background(), tc.token, 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)) @@ -2169,79 +2169,6 @@ func TestListMembers(t *testing.T) { } } -func TestSearchUsers(t *testing.T) { - svc, cRepo, auth, _ := newService(true) - cases := []struct { - desc string - token string - page mgclients.Page - identifyResp *magistrala.IdentityRes - response mgclients.ClientsPage - responseErr error - identifyErr error - err error - }{ - { - desc: "search clients with valid token", - token: validToken, - page: mgclients.Page{Offset: 0, Name: "clientname", Limit: 100}, - response: mgclients.ClientsPage{ - Page: mgclients.Page{Total: 1, Offset: 0, Limit: 100}, - Clients: []mgclients.Client{client}, - }, - identifyResp: &magistrala.IdentityRes{UserId: client.ID}, - }, - { - desc: "search clients with invalid token", - token: inValidToken, - page: mgclients.Page{Offset: 0, Name: "clientname", Limit: 100}, - response: mgclients.ClientsPage{}, - responseErr: svcerr.ErrAuthentication, - err: svcerr.ErrAuthentication, - }, - { - desc: "search clients with id", - token: validToken, - page: mgclients.Page{Offset: 0, Id: "d8dd12ef-aa2a-43fe-8ef2-2e4fe514360f", Limit: 100}, - response: mgclients.ClientsPage{ - Page: mgclients.Page{Total: 1, Offset: 0, Limit: 100}, - Clients: []mgclients.Client{client}, - }, - identifyResp: &magistrala.IdentityRes{UserId: client.ID}, - }, - { - desc: "search clients with username", - token: validToken, - page: mgclients.Page{Offset: 0, Identity: "clientidentity", Limit: 100}, - response: mgclients.ClientsPage{ - Page: mgclients.Page{Total: 1, Offset: 0, Limit: 100}, - Clients: []mgclients.Client{client}, - }, - identifyResp: &magistrala.IdentityRes{UserId: client.ID}, - }, - { - desc: "search clients with random name", - token: validToken, - page: mgclients.Page{Offset: 0, Name: "randomname", Limit: 100}, - response: mgclients.ClientsPage{ - Page: mgclients.Page{Total: 0, Offset: 0, Limit: 100}, - Clients: []mgclients.Client{}, - }, - identifyResp: &magistrala.IdentityRes{UserId: client.ID}, - }, - } - - for _, tc := range cases { - authCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResp, tc.identifyErr) - repoCall := cRepo.On("SearchBasicInfo", context.Background(), tc.page).Return(tc.response, tc.responseErr) - page, err := svc.SearchUsers(context.Background(), tc.token, 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)) - authCall.Unset() - repoCall.Unset() - } -} - func TestIssueToken(t *testing.T) { svc, cRepo, auth, _ := newService(true) diff --git a/users/tracing/tracing.go b/users/tracing/tracing.go index 7d4674c219..ff93c915b6 100644 --- a/users/tracing/tracing.go +++ b/users/tracing/tracing.go @@ -185,14 +185,6 @@ func (tm *tracingMiddleware) ListMembers(ctx context.Context, token, objectKind, return tm.svc.ListMembers(ctx, token, objectKind, objectID, pm) } -// SearchClients traces the "SearchClients" operation of the wrapped clients.Service. -func (tm *tracingMiddleware) SearchUsers(ctx context.Context, token string, pm mgclients.Page) (mgclients.ClientsPage, error) { - ctx, span := tm.tracer.Start(ctx, "svc_search_clients", trace.WithAttributes(attribute.String("token", token))) - defer span.End() - - return tm.svc.SearchUsers(ctx, token, pm) -} - // Identify traces the "Identify" operation of the wrapped clients.Service. func (tm *tracingMiddleware) Identify(ctx context.Context, token string) (string, error) { ctx, span := tm.tracer.Start(ctx, "svc_identify", trace.WithAttributes(attribute.String("token", token)))