mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-26 13:48:53 +08:00
NOISSUE - Add ListUsers, ViewUser and ViewProfile methods (#1262)
* NOISSUE - Add admin method in users service to return users list Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix loggings and metrics Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add email and metadata filters Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add comment Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Retrieve User infos by ID if Admin Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Remove admin checks and fix comments Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix missing query Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Use generic funccs to create email and metadata queries Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add /users/profile endpoint Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Simplify db helpers Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix View, List, Retrieve prefix methods naming Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix tracer endpoints naming Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix comment Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Add tests and remove TODO comments Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
This commit is contained in:
parent
420b598ac7
commit
1c298d8f27
@ -81,7 +81,7 @@ func viewUserEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := svc.User(ctx, req.token)
|
||||
u, err := svc.ViewUser(ctx, req.token, req.userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -93,6 +93,39 @@ func viewUserEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
func viewProfileEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(viewUserReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := svc.ViewProfile(ctx, req.token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return viewUserRes{
|
||||
ID: u.ID,
|
||||
Email: u.Email,
|
||||
Metadata: u.Metadata,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listUsersEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listUsersReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return users.UserPage{}, err
|
||||
}
|
||||
up, err := svc.ListUsers(ctx, req.token, req.offset, req.limit, req.email, req.metadata)
|
||||
if err != nil {
|
||||
return users.UserPage{}, err
|
||||
}
|
||||
return buildUsersResponse(up), nil
|
||||
}
|
||||
}
|
||||
|
||||
func updateUserEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(updateUserReq)
|
||||
@ -194,13 +227,13 @@ func removeUserFromGroup(svc users.Service) endpoint.Endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
func listUsersForGroupEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
func listMembersEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listUserGroupReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return users.UserPage{}, err
|
||||
}
|
||||
up, err := svc.Members(ctx, req.token, req.groupID, req.offset, req.limit, req.metadata)
|
||||
up, err := svc.ListMembers(ctx, req.token, req.groupID, req.offset, req.limit, req.metadata)
|
||||
if err != nil {
|
||||
return users.UserPage{}, err
|
||||
}
|
||||
@ -208,13 +241,13 @@ func listUsersForGroupEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
func listUserGroupsEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
func listMembershipsEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listUserGroupReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return users.UserPage{}, err
|
||||
}
|
||||
gp, err := svc.Memberships(ctx, req.token, req.userID, req.offset, req.limit, req.metadata)
|
||||
gp, err := svc.ListMemberships(ctx, req.token, req.userID, req.offset, req.limit, req.metadata)
|
||||
if err != nil {
|
||||
return groupPageRes{}, err
|
||||
}
|
||||
@ -252,7 +285,7 @@ func viewGroupEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
if err := req.validate(); err != nil {
|
||||
return viewGroupRes{}, err
|
||||
}
|
||||
group, err := svc.Group(ctx, req.token, req.groupID)
|
||||
group, err := svc.ViewGroup(ctx, req.token, req.groupID)
|
||||
if err != nil {
|
||||
return viewGroupRes{}, err
|
||||
}
|
||||
@ -271,7 +304,7 @@ func listGroupsEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
if err := req.validate(); err != nil {
|
||||
return groupPageRes{}, err
|
||||
}
|
||||
gp, err := svc.Groups(ctx, req.token, req.groupID, req.offset, req.limit, req.metadata)
|
||||
gp, err := svc.ListGroups(ctx, req.token, req.groupID, req.offset, req.limit, req.metadata)
|
||||
if err != nil {
|
||||
return groupPageRes{}, err
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ func TestUser(t *testing.T) {
|
||||
ts := newServer(svc)
|
||||
defer ts.Close()
|
||||
client := ts.Client()
|
||||
_, err := svc.Register(context.Background(), user)
|
||||
userID, err := svc.Register(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("register user got unexpected error: %s", err))
|
||||
|
||||
auth := mocks.NewAuthService(map[string]string{user.Email: user.Email})
|
||||
@ -210,7 +210,7 @@ func TestUser(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: client,
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/users", ts.URL),
|
||||
url: fmt.Sprintf("%s/users/%s", ts.URL, userID),
|
||||
token: tc.token,
|
||||
}
|
||||
res, err := req.make()
|
||||
|
@ -51,7 +51,7 @@ func (lm *loggingMiddleware) Login(ctx context.Context, user users.User) (token
|
||||
return lm.svc.Login(ctx, user)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) User(ctx context.Context, token string) (u users.User, err error) {
|
||||
func (lm *loggingMiddleware) ViewUser(ctx context.Context, token, id string) (u users.User, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method view_user for user %s took %s to complete", u.Email, time.Since(begin))
|
||||
if err != nil {
|
||||
@ -61,7 +61,33 @@ func (lm *loggingMiddleware) User(ctx context.Context, token string) (u users.Us
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.User(ctx, token)
|
||||
return lm.svc.ViewUser(ctx, token, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ViewProfile(ctx context.Context, token string) (u users.User, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method view_profile for usser %s took %s to complete", u.Email, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.ViewProfile(ctx, token)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ListUsers(ctx context.Context, token string, offset, limit uint64, email string, um users.Metadata) (e users.UserPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method list_users for token %s took %s to complete", token, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.ListUsers(ctx, token, offset, limit, email, um)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UpdateUser(ctx context.Context, token string, u users.User) (err error) {
|
||||
@ -142,9 +168,9 @@ func (lm *loggingMiddleware) CreateGroup(ctx context.Context, token string, grou
|
||||
return lm.svc.CreateGroup(ctx, token, group)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Groups(ctx context.Context, token, id string, offset, limit uint64, meta users.Metadata) (e users.GroupPage, err error) {
|
||||
func (lm *loggingMiddleware) ListGroups(ctx context.Context, token, id string, offset, limit uint64, um users.Metadata) (e users.GroupPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method groups for parent %s took %s to complete", id, time.Since(begin))
|
||||
message := fmt.Sprintf("Method list_groups for parent %s took %s to complete", id, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
@ -152,12 +178,12 @@ func (lm *loggingMiddleware) Groups(ctx context.Context, token, id string, offse
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Groups(ctx, token, id, offset, limit, meta)
|
||||
return lm.svc.ListGroups(ctx, token, id, offset, limit, um)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Members(ctx context.Context, token, id string, offset, limit uint64, meta users.Metadata) (e users.UserPage, err error) {
|
||||
func (lm *loggingMiddleware) ListMembers(ctx context.Context, token, id string, offset, limit uint64, um users.Metadata) (e users.UserPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method members for parent %s took %s to complete", id, time.Since(begin))
|
||||
message := fmt.Sprintf("Method list_members for parent %s took %s to complete", id, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
@ -165,7 +191,7 @@ func (lm *loggingMiddleware) Members(ctx context.Context, token, id string, offs
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Members(ctx, token, id, offset, limit, meta)
|
||||
return lm.svc.ListMembers(ctx, token, id, offset, limit, um)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) RemoveGroup(ctx context.Context, token, id string) (err error) {
|
||||
@ -194,9 +220,9 @@ func (lm *loggingMiddleware) UpdateGroup(ctx context.Context, token string, grou
|
||||
return lm.svc.UpdateGroup(ctx, token, group)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Group(ctx context.Context, token, id string) (u users.Group, err error) {
|
||||
func (lm *loggingMiddleware) ViewGroup(ctx context.Context, token, id string) (u users.Group, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method group with id %s took %s to complete", id, time.Since(begin))
|
||||
message := fmt.Sprintf("Method view_group with id %s took %s to complete", id, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
@ -204,7 +230,7 @@ func (lm *loggingMiddleware) Group(ctx context.Context, token, id string) (u use
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Group(ctx, token, id)
|
||||
return lm.svc.ViewGroup(ctx, token, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Assign(ctx context.Context, token, userID, groupID string) (err error) {
|
||||
@ -233,9 +259,9 @@ func (lm *loggingMiddleware) Unassign(ctx context.Context, token, userID, groupI
|
||||
return lm.svc.Unassign(ctx, token, userID, groupID)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Memberships(ctx context.Context, token, id string, offset, limit uint64, meta users.Metadata) (e users.GroupPage, err error) {
|
||||
func (lm *loggingMiddleware) ListMemberships(ctx context.Context, token, id string, offset, limit uint64, um users.Metadata) (e users.GroupPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method memberships for user %s took %s to complete", id, time.Since(begin))
|
||||
message := fmt.Sprintf("Method list_memberships for user %s took %s to complete", id, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
@ -243,5 +269,5 @@ func (lm *loggingMiddleware) Memberships(ctx context.Context, token, id string,
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Memberships(ctx, token, id, offset, limit, meta)
|
||||
return lm.svc.ListMemberships(ctx, token, id, offset, limit, um)
|
||||
}
|
||||
|
@ -47,13 +47,31 @@ func (ms *metricsMiddleware) Login(ctx context.Context, user users.User) (string
|
||||
return ms.svc.Login(ctx, user)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) User(ctx context.Context, token string) (users.User, error) {
|
||||
func (ms *metricsMiddleware) ViewUser(ctx context.Context, token, id string) (users.User, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "view_user").Add(1)
|
||||
ms.latency.With("method", "view_user").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.User(ctx, token)
|
||||
return ms.svc.ViewUser(ctx, token, id)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ViewProfile(ctx context.Context, token string) (users.User, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "view_profile").Add(1)
|
||||
ms.latency.With("method", "view_profile").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.ViewProfile(ctx, token)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ListUsers(ctx context.Context, token string, offset, limit uint64, email string, um users.Metadata) (users.UserPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_users").Add(1)
|
||||
ms.latency.With("method", "list_users").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.ListUsers(ctx, token, offset, limit, email, um)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) UpdateUser(ctx context.Context, token string, u users.User) (err error) {
|
||||
@ -110,22 +128,22 @@ func (ms *metricsMiddleware) CreateGroup(ctx context.Context, token string, grou
|
||||
return ms.svc.CreateGroup(ctx, token, group)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Groups(ctx context.Context, token, id string, offset, limit uint64, meta users.Metadata) (users.GroupPage, error) {
|
||||
func (ms *metricsMiddleware) ListGroups(ctx context.Context, token, id string, offset, limit uint64, um users.Metadata) (users.GroupPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "groups").Add(1)
|
||||
ms.latency.With("method", "groups").Observe(time.Since(begin).Seconds())
|
||||
ms.counter.With("method", "list_groups").Add(1)
|
||||
ms.latency.With("method", "list_groups").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Groups(ctx, token, id, offset, limit, meta)
|
||||
return ms.svc.ListGroups(ctx, token, id, offset, limit, um)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Members(ctx context.Context, token, id string, offset, limit uint64, meta users.Metadata) (users.UserPage, error) {
|
||||
func (ms *metricsMiddleware) ListMembers(ctx context.Context, token, id string, offset, limit uint64, um users.Metadata) (users.UserPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "members").Add(1)
|
||||
ms.latency.With("method", "members").Observe(time.Since(begin).Seconds())
|
||||
ms.counter.With("method", "list_members").Add(1)
|
||||
ms.latency.With("method", "list_members").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Members(ctx, token, id, offset, limit, meta)
|
||||
return ms.svc.ListMembers(ctx, token, id, offset, limit, um)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) RemoveGroup(ctx context.Context, token, id string) error {
|
||||
@ -146,14 +164,14 @@ func (ms *metricsMiddleware) UpdateGroup(ctx context.Context, token string, grou
|
||||
return ms.svc.UpdateGroup(ctx, token, group)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Group(ctx context.Context, token, name string) (users.Group, error) {
|
||||
func (ms *metricsMiddleware) ViewGroup(ctx context.Context, token, name string) (users.Group, error) {
|
||||
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "group").Add(1)
|
||||
ms.latency.With("method", "group").Observe(time.Since(begin).Seconds())
|
||||
ms.counter.With("method", "view_group").Add(1)
|
||||
ms.latency.With("method", "view_group").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Group(ctx, token, name)
|
||||
return ms.svc.ViewGroup(ctx, token, name)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Assign(ctx context.Context, token, userID, groupID string) error {
|
||||
@ -174,11 +192,11 @@ func (ms *metricsMiddleware) Unassign(ctx context.Context, token, userID, groupI
|
||||
return ms.svc.Unassign(ctx, token, userID, groupID)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Memberships(ctx context.Context, token, id string, offset, limit uint64, meta users.Metadata) (users.GroupPage, error) {
|
||||
func (ms *metricsMiddleware) ListMemberships(ctx context.Context, token, id string, offset, limit uint64, um users.Metadata) (users.GroupPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "memberships").Add(1)
|
||||
ms.latency.With("method", "memberships").Observe(time.Since(begin).Seconds())
|
||||
ms.counter.With("method", "list_memberships").Add(1)
|
||||
ms.latency.With("method", "list_memberships").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Memberships(ctx, token, id, offset, limit, meta)
|
||||
return ms.svc.ListMemberships(ctx, token, id, offset, limit, um)
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ func (req userReq) validate() error {
|
||||
}
|
||||
|
||||
type viewUserReq struct {
|
||||
token string
|
||||
token string
|
||||
userID string
|
||||
}
|
||||
|
||||
func (req viewUserReq) validate() error {
|
||||
@ -31,6 +32,21 @@ func (req viewUserReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type listUsersReq struct {
|
||||
token string
|
||||
offset uint64
|
||||
limit uint64
|
||||
email string
|
||||
metadata users.Metadata
|
||||
}
|
||||
|
||||
func (req listUsersReq) validate() error {
|
||||
if req.token == "" {
|
||||
return users.ErrUnauthorizedAccess
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type updateUserReq struct {
|
||||
token string
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
|
@ -28,6 +28,7 @@ const (
|
||||
offsetKey = "offset"
|
||||
limitKey = "limit"
|
||||
nameKey = "name"
|
||||
emailKey = "email"
|
||||
metadataKey = "metadata"
|
||||
|
||||
defOffset = 0
|
||||
@ -59,13 +60,27 @@ func MakeHandler(svc users.Service, tracer opentracing.Tracer) http.Handler {
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Get("/users", kithttp.NewServer(
|
||||
mux.Get("/users/profile", kithttp.NewServer(
|
||||
kitot.TraceServer(tracer, "view_profile")(viewProfileEndpoint(svc)),
|
||||
decodeViewProfile,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Get("/users/:userID", kithttp.NewServer(
|
||||
kitot.TraceServer(tracer, "view_user")(viewUserEndpoint(svc)),
|
||||
decodeViewUser,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Get("/users", kithttp.NewServer(
|
||||
kitot.TraceServer(tracer, "list_users")(listUsersEndpoint(svc)),
|
||||
decodeListUsers,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
mux.Put("/users", kithttp.NewServer(
|
||||
kitot.TraceServer(tracer, "update_user")(updateUserEndpoint(svc)),
|
||||
decodeUpdateUser,
|
||||
@ -74,7 +89,7 @@ func MakeHandler(svc users.Service, tracer opentracing.Tracer) http.Handler {
|
||||
))
|
||||
|
||||
mux.Get("/users/:userID/groups", kithttp.NewServer(
|
||||
kitot.TraceServer(tracer, "memberships")(listUserGroupsEndpoint(svc)),
|
||||
kitot.TraceServer(tracer, "list_memberships")(listMembershipsEndpoint(svc)),
|
||||
decodeListUserGroupsRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
@ -109,7 +124,7 @@ func MakeHandler(svc users.Service, tracer opentracing.Tracer) http.Handler {
|
||||
))
|
||||
|
||||
mux.Get("/groups", kithttp.NewServer(
|
||||
kitot.TraceServer(tracer, "groups")(listGroupsEndpoint(svc)),
|
||||
kitot.TraceServer(tracer, "list_groups")(listGroupsEndpoint(svc)),
|
||||
decodeListUserGroupsRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
@ -137,7 +152,7 @@ func MakeHandler(svc users.Service, tracer opentracing.Tracer) http.Handler {
|
||||
))
|
||||
|
||||
mux.Get("/groups/:groupID/users", kithttp.NewServer(
|
||||
kitot.TraceServer(tracer, "members")(listUsersForGroupEndpoint(svc)),
|
||||
kitot.TraceServer(tracer, "list_members")(listMembersEndpoint(svc)),
|
||||
decodeListUserGroupsRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
@ -178,12 +193,51 @@ func MakeHandler(svc users.Service, tracer opentracing.Tracer) http.Handler {
|
||||
}
|
||||
|
||||
func decodeViewUser(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := viewUserReq{
|
||||
token: r.Header.Get("Authorization"),
|
||||
userID: bone.GetValue(r, "userID"),
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeViewProfile(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := viewUserReq{
|
||||
token: r.Header.Get("Authorization"),
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListUsers(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
o, err := readUintQuery(r, offsetKey, defOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l, err := readUintQuery(r, limitKey, defLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e, err := readStringQuery(r, emailKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m, err := readMetadataQuery(r, metadataKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := listUsersReq{
|
||||
token: r.Header.Get("Authorization"),
|
||||
offset: o,
|
||||
limit: l,
|
||||
email: e,
|
||||
metadata: m,
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeUpdateUser(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
var req updateUserReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
|
@ -35,10 +35,10 @@ type GroupRepository interface {
|
||||
RetrieveByName(ctx context.Context, name string) (Group, error)
|
||||
|
||||
// RetrieveAllWithAncestors retrieves all groups if groupID == "", if groupID is specified returns children groups
|
||||
RetrieveAllWithAncestors(ctx context.Context, groupID string, offset, limit uint64, gm Metadata) (GroupPage, error)
|
||||
RetrieveAllWithAncestors(ctx context.Context, groupID string, offset, limit uint64, m Metadata) (GroupPage, error)
|
||||
|
||||
// Memberships retrieves all groups that user belongs to
|
||||
Memberships(ctx context.Context, userID string, offset, limit uint64, gm Metadata) (GroupPage, error)
|
||||
// RetrieveMemberships retrieves all groups that user belongs to
|
||||
RetrieveMemberships(ctx context.Context, userID string, offset, limit uint64, m Metadata) (GroupPage, error)
|
||||
|
||||
// Assign adds user to group.
|
||||
Assign(ctx context.Context, userID, groupID string) error
|
||||
|
@ -166,7 +166,7 @@ func (grm *groupRepositoryMock) Assign(ctx context.Context, userID, groupID stri
|
||||
|
||||
}
|
||||
|
||||
func (grm *groupRepositoryMock) Memberships(ctx context.Context, userID string, offset, limit uint64, gm users.Metadata) (users.GroupPage, error) {
|
||||
func (grm *groupRepositoryMock) RetrieveMemberships(ctx context.Context, userID string, offset, limit uint64, um users.Metadata) (users.GroupPage, error) {
|
||||
grm.mu.Lock()
|
||||
defer grm.mu.Unlock()
|
||||
var items []users.Group
|
||||
@ -187,7 +187,7 @@ func (grm *groupRepositoryMock) Memberships(ctx context.Context, userID string,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (grm *groupRepositoryMock) RetrieveAllWithAncestors(ctx context.Context, groupID string, offset, limit uint64, gm users.Metadata) (users.GroupPage, error) {
|
||||
func (grm *groupRepositoryMock) RetrieveAllWithAncestors(ctx context.Context, groupID string, offset, limit uint64, um users.Metadata) (users.GroupPage, error) {
|
||||
grm.mu.Lock()
|
||||
defer grm.mu.Unlock()
|
||||
var items []users.Group
|
||||
|
@ -89,7 +89,28 @@ func (urm *userRepositoryMock) RetrieveByID(ctx context.Context, id string) (use
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (urm *userRepositoryMock) Members(ctx context.Context, groupID string, offset, limit uint64, gm users.Metadata) (users.UserPage, error) {
|
||||
func (urm *userRepositoryMock) RetrieveAll(ctx context.Context, offset, limit uint64, email string, um users.Metadata) (users.UserPage, error) {
|
||||
urm.mu.Lock()
|
||||
defer urm.mu.Unlock()
|
||||
|
||||
up := users.UserPage{}
|
||||
i := uint64(0)
|
||||
|
||||
for _, u := range urm.users {
|
||||
if i >= offset && i < (limit+offset) {
|
||||
up.Users = append(up.Users, u)
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
up.Offset = offset
|
||||
up.Limit = limit
|
||||
up.Total = uint64(i)
|
||||
|
||||
return up, nil
|
||||
}
|
||||
|
||||
func (urm *userRepositoryMock) RetrieveMembers(ctx context.Context, groupID string, offset, limit uint64, um users.Metadata) (users.UserPage, error) {
|
||||
urm.mu.Lock()
|
||||
defer urm.mu.Unlock()
|
||||
|
||||
|
@ -148,8 +148,8 @@ func (gr groupRepository) RetrieveByName(ctx context.Context, name string) (user
|
||||
return group, nil
|
||||
}
|
||||
|
||||
func (gr groupRepository) RetrieveAllWithAncestors(ctx context.Context, groupID string, offset, limit uint64, gm users.Metadata) (users.GroupPage, error) {
|
||||
_, mq, err := getGroupsMetadataQuery(gm)
|
||||
func (gr groupRepository) RetrieveAllWithAncestors(ctx context.Context, groupID string, offset, limit uint64, um users.Metadata) (users.GroupPage, error) {
|
||||
_, mq, err := getGroupsMetadataQuery(um)
|
||||
if err != nil {
|
||||
return users.GroupPage{}, errors.Wrap(errRetrieveDB, err)
|
||||
}
|
||||
@ -166,17 +166,17 @@ func (gr groupRepository) RetrieveAllWithAncestors(ctx context.Context, groupID
|
||||
`WITH RECURSIVE subordinates AS (
|
||||
SELECT id, owner_id, parent_id, name, description, metadata
|
||||
FROM groups
|
||||
WHERE id = :id
|
||||
WHERE id = :id
|
||||
UNION
|
||||
SELECT groups.id, groups.owner_id, groups.parent_id, groups.name, groups.description, groups.metadata
|
||||
FROM groups
|
||||
FROM groups
|
||||
INNER JOIN subordinates s ON s.id = groups.parent_id %s
|
||||
)`, mq)
|
||||
q = fmt.Sprintf("%s SELECT * FROM subordinates ORDER BY id LIMIT :limit OFFSET :offset", sq)
|
||||
cq = fmt.Sprintf("%s SELECT COUNT(*) FROM subordinates", sq)
|
||||
}
|
||||
|
||||
dbPage, err := toDBGroupPage("", groupID, offset, limit, gm)
|
||||
dbPage, err := toDBGroupPage("", groupID, offset, limit, um)
|
||||
if err != nil {
|
||||
return users.GroupPage{}, errors.Wrap(errSelectDb, err)
|
||||
}
|
||||
@ -217,8 +217,8 @@ func (gr groupRepository) RetrieveAllWithAncestors(ctx context.Context, groupID
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (gr groupRepository) Memberships(ctx context.Context, userID string, offset, limit uint64, gm users.Metadata) (users.GroupPage, error) {
|
||||
m, mq, err := getGroupsMetadataQuery(gm)
|
||||
func (gr groupRepository) RetrieveMemberships(ctx context.Context, userID string, offset, limit uint64, um users.Metadata) (users.GroupPage, error) {
|
||||
m, mq, err := getGroupsMetadataQuery(um)
|
||||
if err != nil {
|
||||
return users.GroupPage{}, errors.Wrap(errRetrieveDB, err)
|
||||
}
|
||||
@ -226,9 +226,9 @@ func (gr groupRepository) Memberships(ctx context.Context, userID string, offset
|
||||
if mq != "" {
|
||||
mq = fmt.Sprintf("AND %s", mq)
|
||||
}
|
||||
q := fmt.Sprintf(`SELECT g.id, g.owner_id, g.parent_id, g.name, g.description, g.metadata
|
||||
q := fmt.Sprintf(`SELECT g.id, g.owner_id, g.parent_id, g.name, g.description, g.metadata
|
||||
FROM group_relations gr, groups g
|
||||
WHERE gr.group_id = g.id and gr.user_id = :userID
|
||||
WHERE gr.group_id = g.id and gr.user_id = :userID
|
||||
%s ORDER BY id LIMIT :limit OFFSET :offset;`, mq)
|
||||
|
||||
params := map[string]interface{}{
|
||||
@ -257,7 +257,7 @@ func (gr groupRepository) Memberships(ctx context.Context, userID string, offset
|
||||
items = append(items, gr)
|
||||
}
|
||||
|
||||
cq := fmt.Sprintf(`SELECT COUNT(*)
|
||||
cq := fmt.Sprintf(`SELECT COUNT(*)
|
||||
FROM group_relations gr, groups g
|
||||
WHERE gr.group_id = g.id and gr.user_id = :userID %s;`, mq)
|
||||
|
||||
@ -372,7 +372,7 @@ func toDBGroup(g users.Group) (dbGroup, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toDBGroupPage(ownerID, groupID string, offset, limit uint64, metadata users.Metadata) (dbGroupPage, error) {
|
||||
func toDBGroupPage(ownerID, groupID string, offset, limit uint64, um users.Metadata) (dbGroupPage, error) {
|
||||
owner, err := toUUID(ownerID)
|
||||
if err != nil {
|
||||
return dbGroupPage{}, err
|
||||
@ -386,7 +386,7 @@ func toDBGroupPage(ownerID, groupID string, offset, limit uint64, metadata users
|
||||
}
|
||||
return dbGroupPage{
|
||||
ID: group,
|
||||
Metadata: dbMetadata(metadata),
|
||||
Metadata: dbMetadata(um),
|
||||
OwnerID: owner,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
@ -424,13 +424,13 @@ func toDBGroupRelation(userID, groupID string) (dbGroupRelation, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getGroupsMetadataQuery(m users.Metadata) ([]byte, string, error) {
|
||||
func getGroupsMetadataQuery(um users.Metadata) ([]byte, string, error) {
|
||||
mq := ""
|
||||
mb := []byte("{}")
|
||||
if len(m) > 0 {
|
||||
if len(um) > 0 {
|
||||
mq = `groups.metadata @> :metadata`
|
||||
|
||||
b, err := json.Marshal(m)
|
||||
b, err := json.Marshal(um)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ type userRepository struct {
|
||||
db Database
|
||||
}
|
||||
|
||||
// New instantiates a PostgreSQL implementation of user
|
||||
// NewUserRepo instantiates a PostgreSQL implementation of user
|
||||
// repository.
|
||||
func NewUserRepo(db Database) users.UserRepository {
|
||||
return &userRepository{
|
||||
@ -124,7 +124,7 @@ func (ur userRepository) RetrieveByEmail(ctx context.Context, email string) (use
|
||||
}
|
||||
|
||||
func (ur userRepository) RetrieveByID(ctx context.Context, id string) (users.User, error) {
|
||||
q := `SELECT id, password, metadata FROM users WHERE id = $1`
|
||||
q := `SELECT email, password, metadata FROM users WHERE id = $1`
|
||||
|
||||
dbu := dbUser{
|
||||
ID: id,
|
||||
@ -141,6 +141,77 @@ func (ur userRepository) RetrieveByID(ctx context.Context, id string) (users.Use
|
||||
return toUser(dbu)
|
||||
}
|
||||
|
||||
func (ur userRepository) RetrieveAll(ctx context.Context, offset, limit uint64, email string, um users.Metadata) (users.UserPage, error) {
|
||||
eq, ep, err := createEmailQuery("", email)
|
||||
if err != nil {
|
||||
return users.UserPage{}, errors.Wrap(errRetrieveDB, err)
|
||||
}
|
||||
|
||||
mq, mp, err := createMetadataQuery("", um)
|
||||
if err != nil {
|
||||
return users.UserPage{}, errors.Wrap(errRetrieveDB, err)
|
||||
}
|
||||
|
||||
emq := ""
|
||||
if eq != "" && mq == "" {
|
||||
emq = fmt.Sprintf("WHERE %s", eq)
|
||||
}
|
||||
if eq == "" && mq != "" {
|
||||
emq = fmt.Sprintf("WHERE %s", mq)
|
||||
}
|
||||
if eq != "" && mq != "" {
|
||||
emq = fmt.Sprintf("WHERE %s AND %s", eq, mq)
|
||||
}
|
||||
|
||||
q := fmt.Sprintf(`SELECT id, email, metadata FROM users %s ORDER BY email LIMIT :limit OFFSET :offset;`, emq)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
"email": ep,
|
||||
"metadata": mp,
|
||||
}
|
||||
|
||||
rows, err := ur.db.NamedQueryContext(ctx, q, params)
|
||||
if err != nil {
|
||||
return users.UserPage{}, errors.Wrap(errSelectDb, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var items []users.User
|
||||
for rows.Next() {
|
||||
dbusr := dbUser{}
|
||||
if err := rows.StructScan(&dbusr); err != nil {
|
||||
return users.UserPage{}, errors.Wrap(errSelectDb, err)
|
||||
}
|
||||
|
||||
user, err := toUser(dbusr)
|
||||
if err != nil {
|
||||
return users.UserPage{}, err
|
||||
}
|
||||
|
||||
items = append(items, user)
|
||||
}
|
||||
|
||||
cq := fmt.Sprintf(`SELECT COUNT(*) FROM users %s;`, emq)
|
||||
|
||||
total, err := total(ctx, ur.db, cq, params)
|
||||
if err != nil {
|
||||
return users.UserPage{}, errors.Wrap(errSelectDb, err)
|
||||
}
|
||||
|
||||
page := users.UserPage{
|
||||
Users: items,
|
||||
PageMetadata: users.PageMetadata{
|
||||
Total: total,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
},
|
||||
}
|
||||
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (ur userRepository) UpdatePassword(ctx context.Context, email, password string) error {
|
||||
q := `UPDATE users SET password = :password WHERE email = :email`
|
||||
|
||||
@ -156,21 +227,25 @@ func (ur userRepository) UpdatePassword(ctx context.Context, email, password str
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ur userRepository) Members(ctx context.Context, groupID string, offset, limit uint64, gm users.Metadata) (users.UserPage, error) {
|
||||
m, mq, err := getUsersMetadataQuery(gm)
|
||||
func (ur userRepository) RetrieveMembers(ctx context.Context, groupID string, offset, limit uint64, um users.Metadata) (users.UserPage, error) {
|
||||
mq, mp, err := createMetadataQuery("users.", um)
|
||||
if err != nil {
|
||||
return users.UserPage{}, errors.Wrap(errRetrieveDB, err)
|
||||
}
|
||||
|
||||
if mq != "" {
|
||||
mq = fmt.Sprintf(" AND %s", mq)
|
||||
}
|
||||
|
||||
q := fmt.Sprintf(`SELECT u.id, u.email, u.metadata FROM users u, group_relations g
|
||||
WHERE u.id = g.user_id AND g.group_id = :group
|
||||
WHERE u.id = g.user_id AND g.group_id = :group
|
||||
%s ORDER BY id LIMIT :limit OFFSET :offset;`, mq)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"group": groupID,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
"metadata": m,
|
||||
"metadata": mp,
|
||||
}
|
||||
|
||||
rows, err := ur.db.NamedQueryContext(ctx, q, params)
|
||||
@ -249,11 +324,12 @@ func (m dbMetadata) Value() (driver.Value, error) {
|
||||
}
|
||||
|
||||
type dbUser struct {
|
||||
ID string `db:"id"`
|
||||
Owner string `db:"owner"`
|
||||
Email string `db:"email"`
|
||||
Password string `db:"password"`
|
||||
Metadata []byte `db:"metadata"`
|
||||
ID string `db:"id"`
|
||||
Owner string `db:"owner"`
|
||||
Email string `db:"email"`
|
||||
Password string `db:"password"`
|
||||
Metadata []byte `db:"metadata"`
|
||||
Groups []users.Group `db:"groups"`
|
||||
}
|
||||
|
||||
func toDBUser(u users.User) (dbUser, error) {
|
||||
@ -290,17 +366,28 @@ func toUser(dbu dbUser) (users.User, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getUsersMetadataQuery(m users.Metadata) ([]byte, string, error) {
|
||||
mq := ""
|
||||
mb := []byte("{}")
|
||||
if len(m) > 0 {
|
||||
mq = ` AND users.metadata @> :metadata`
|
||||
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
mb = b
|
||||
func createEmailQuery(entity string, email string) (string, string, error) {
|
||||
if email == "" {
|
||||
return "", "", nil
|
||||
}
|
||||
return mb, mq, nil
|
||||
|
||||
// Create LIKE operator to search Users with email containing a given string
|
||||
param := fmt.Sprintf(`%%%s%%`, email)
|
||||
query := fmt.Sprintf("%semail LIKE :email", entity)
|
||||
|
||||
return query, param, nil
|
||||
}
|
||||
|
||||
func createMetadataQuery(entity string, um users.Metadata) (string, []byte, error) {
|
||||
if len(um) == 0 {
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
param, err := json.Marshal(um)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
query := fmt.Sprintf("%smetadata @> :metadata", entity)
|
||||
|
||||
return query, param, nil
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ func TestUserSave(t *testing.T) {
|
||||
email := "user-save@example.com"
|
||||
|
||||
uid, err := uuid.New().ID()
|
||||
require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@ -63,7 +63,7 @@ func TestSingleUserRetrieval(t *testing.T) {
|
||||
email := "user-retrieval@example.com"
|
||||
|
||||
uid, err := uuid.New().ID()
|
||||
require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
user := users.User{
|
||||
ID: uid,
|
||||
@ -88,7 +88,7 @@ func TestSingleUserRetrieval(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMembers(t *testing.T) {
|
||||
func TestRetrieveMembers(t *testing.T) {
|
||||
dbMiddleware := postgres.NewDatabase(db)
|
||||
groupRepo := postgres.NewGroupRepo(dbMiddleware)
|
||||
userRepo := postgres.NewUserRepo(dbMiddleware)
|
||||
@ -96,8 +96,8 @@ func TestMembers(t *testing.T) {
|
||||
var usrs []users.User
|
||||
for i := uint64(0); i < nUsers; i++ {
|
||||
uid, err := uuid.New().ID()
|
||||
require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
|
||||
email := fmt.Sprintf("retrieve-all-for-group%d@example.com", i)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
email := fmt.Sprintf("TestRetrieveMembers%d@example.com", i)
|
||||
user := users.User{
|
||||
ID: uid,
|
||||
Email: email,
|
||||
@ -141,10 +141,60 @@ func TestMembers(t *testing.T) {
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
page, err := userRepo.Members(context.Background(), tc.group, tc.offset, tc.limit, tc.metadata)
|
||||
page, err := userRepo.RetrieveMembers(context.Background(), tc.group, tc.offset, tc.limit, tc.metadata)
|
||||
size := uint64(len(usrs))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", desc, tc.size, size))
|
||||
assert.Equal(t, tc.total, page.Total, fmt.Sprintf("%s: expected total %d got %d\n", desc, tc.total, page.Total))
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: expected no error got %d\n", desc, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveAll(t *testing.T) {
|
||||
dbMiddleware := postgres.NewDatabase(db)
|
||||
userRepo := postgres.NewUserRepo(dbMiddleware)
|
||||
var nUsers = uint64(10)
|
||||
|
||||
for i := uint64(0); i < nUsers; i++ {
|
||||
uid, err := uuid.New().ID()
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
email := fmt.Sprintf("TestRetrieveAll%d@example.com", i)
|
||||
user := users.User{
|
||||
ID: uid,
|
||||
Email: email,
|
||||
Password: "pass",
|
||||
}
|
||||
_, err = userRepo.Save(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
email string
|
||||
offset uint64
|
||||
limit uint64
|
||||
size uint64
|
||||
total uint64
|
||||
metadata users.Metadata
|
||||
}{
|
||||
"retrieve all users filtered by email": {
|
||||
email: "All",
|
||||
offset: 0,
|
||||
limit: nUsers,
|
||||
size: nUsers,
|
||||
total: nUsers,
|
||||
},
|
||||
"retrieve all users by email with limit and offset": {
|
||||
email: "All",
|
||||
offset: 2,
|
||||
limit: 5,
|
||||
size: 5,
|
||||
total: nUsers,
|
||||
},
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
page, err := userRepo.RetrieveAll(context.Background(), tc.offset, tc.limit, tc.email, tc.metadata)
|
||||
size := uint64(len(page.Users))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", desc, tc.size, size))
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: expected no error got %d\n", desc, err))
|
||||
}
|
||||
}
|
||||
|
238
users/service.go
238
users/service.go
@ -78,8 +78,14 @@ type Service interface {
|
||||
// identified by the non-nil error values in the response.
|
||||
Login(ctx context.Context, user User) (string, error)
|
||||
|
||||
// User authenticated user info for the given token.
|
||||
User(ctx context.Context, token string) (User, error)
|
||||
// ViewUser retrieves user info for a given user ID and an authorized token.
|
||||
ViewUser(ctx context.Context, token, id string) (User, error)
|
||||
|
||||
// ViewProfile retrieves user info for a given token.
|
||||
ViewProfile(ctx context.Context, token string) (User, error)
|
||||
|
||||
// ListUsers retrieves users list for a valid admin token.
|
||||
ListUsers(ctx context.Context, token string, offset, limit uint64, email string, m Metadata) (UserPage, error)
|
||||
|
||||
// UpdateUser updates the user metadata.
|
||||
UpdateUser(ctx context.Context, token string, user User) error
|
||||
@ -104,18 +110,18 @@ type Service interface {
|
||||
// UpdateGroup updates the group identified by the provided ID.
|
||||
UpdateGroup(ctx context.Context, token string, group Group) error
|
||||
|
||||
// Group retrieves data about the group identified by ID.
|
||||
Group(ctx context.Context, token, id string) (Group, error)
|
||||
// ViewGroup retrieves data about the group identified by ID.
|
||||
ViewGroup(ctx context.Context, token, id string) (Group, error)
|
||||
|
||||
// ListGroups retrieves groups that are children to group identified by parenID
|
||||
// if parentID is empty all groups are listed.
|
||||
Groups(ctx context.Context, token, parentID string, offset, limit uint64, meta Metadata) (GroupPage, error)
|
||||
ListGroups(ctx context.Context, token, parentID string, offset, limit uint64, m Metadata) (GroupPage, error)
|
||||
|
||||
// Members retrieves users that are assigned to a group identified by groupID.
|
||||
Members(ctx context.Context, token, groupID string, offset, limit uint64, meta Metadata) (UserPage, error)
|
||||
ListMembers(ctx context.Context, token, groupID string, offset, limit uint64, m Metadata) (UserPage, error)
|
||||
|
||||
// Memberships retrieves groups that user identified with userID belongs to.
|
||||
Memberships(ctx context.Context, token, groupID string, offset, limit uint64, meta Metadata) (GroupPage, error)
|
||||
// ListMemberships retrieves groups that user identified with userID belongs to.
|
||||
ListMemberships(ctx context.Context, token, groupID string, offset, limit uint64, m Metadata) (GroupPage, error)
|
||||
|
||||
// RemoveGroup removes the group identified with the provided ID.
|
||||
RemoveGroup(ctx context.Context, token, id string) error
|
||||
@ -135,11 +141,13 @@ type PageMetadata struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// GroupPage contains a page of groups.
|
||||
type GroupPage struct {
|
||||
PageMetadata
|
||||
Groups []Group
|
||||
}
|
||||
|
||||
// UserPage contains a page of users.
|
||||
type UserPage struct {
|
||||
PageMetadata
|
||||
Users []User
|
||||
@ -198,15 +206,36 @@ func (svc usersService) Login(ctx context.Context, user User) (string, error) {
|
||||
return svc.issue(ctx, dbUser.Email, authn.UserKey)
|
||||
}
|
||||
|
||||
func (svc usersService) User(ctx context.Context, token string) (User, error) {
|
||||
func (svc usersService) ViewUser(ctx context.Context, token, id string) (User, error) {
|
||||
_, err := svc.identify(ctx, token)
|
||||
if err != nil {
|
||||
return User{}, err
|
||||
}
|
||||
|
||||
dbUser, err := svc.users.RetrieveByID(ctx, id)
|
||||
if err != nil {
|
||||
return User{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
|
||||
return User{
|
||||
ID: id,
|
||||
Email: dbUser.Email,
|
||||
Password: "",
|
||||
Metadata: dbUser.Metadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (svc usersService) ViewProfile(ctx context.Context, token string) (User, error) {
|
||||
email, err := svc.identify(ctx, token)
|
||||
if err != nil {
|
||||
return User{}, err
|
||||
}
|
||||
|
||||
dbUser, err := svc.users.RetrieveByEmail(ctx, email)
|
||||
if err != nil {
|
||||
return User{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
|
||||
return User{
|
||||
ID: dbUser.ID,
|
||||
Email: email,
|
||||
@ -215,12 +244,13 @@ func (svc usersService) User(ctx context.Context, token string) (User, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (svc usersService) ListUsers(ctx context.Context, token string, groupID string, offset, limit uint64, um Metadata) (UserPage, error) {
|
||||
func (svc usersService) ListUsers(ctx context.Context, token string, offset, limit uint64, email string, m Metadata) (UserPage, error) {
|
||||
_, err := svc.identify(ctx, token)
|
||||
if err != nil {
|
||||
return UserPage{}, err
|
||||
}
|
||||
return svc.users.Members(ctx, groupID, offset, limit, um)
|
||||
|
||||
return svc.users.RetrieveAll(ctx, offset, limit, email, m)
|
||||
}
|
||||
|
||||
func (svc usersService) UpdateUser(ctx context.Context, token string, u User) error {
|
||||
@ -287,12 +317,103 @@ func (svc usersService) ChangePassword(ctx context.Context, authToken, password,
|
||||
return svc.users.UpdatePassword(ctx, email, password)
|
||||
}
|
||||
|
||||
// SendPasswordReset sends password recovery link to user
|
||||
func (svc usersService) SendPasswordReset(_ context.Context, host, email, token string) error {
|
||||
to := []string{email}
|
||||
return svc.email.SendPasswordReset(to, host, token)
|
||||
}
|
||||
|
||||
func (svc usersService) CreateGroup(ctx context.Context, token string, group Group) (Group, error) {
|
||||
if group.Name == "" || !groupRegexp.MatchString(group.Name) {
|
||||
return Group{}, ErrMalformedEntity
|
||||
}
|
||||
|
||||
email, err := svc.identify(ctx, token)
|
||||
if err != nil {
|
||||
return Group{}, err
|
||||
}
|
||||
|
||||
user, err := svc.users.RetrieveByEmail(ctx, email)
|
||||
if err != nil {
|
||||
return Group{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
|
||||
uid, err := uuidProvider.New().ID()
|
||||
if err != nil {
|
||||
return Group{}, errors.Wrap(ErrCreateUser, err)
|
||||
}
|
||||
|
||||
group.ID = uid
|
||||
group.OwnerID = user.ID
|
||||
|
||||
return svc.groups.Save(ctx, group)
|
||||
}
|
||||
|
||||
func (svc usersService) ListGroups(ctx context.Context, token string, parentID string, offset, limit uint64, m Metadata) (GroupPage, error) {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return GroupPage{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.groups.RetrieveAllWithAncestors(ctx, parentID, offset, limit, m)
|
||||
}
|
||||
|
||||
func (svc usersService) ListMembers(ctx context.Context, token, groupID string, offset, limit uint64, m Metadata) (UserPage, error) {
|
||||
if _, err := svc.identify(ctx, token); err != nil {
|
||||
return UserPage{}, err
|
||||
}
|
||||
return svc.users.RetrieveMembers(ctx, groupID, offset, limit, m)
|
||||
}
|
||||
|
||||
func (svc usersService) RemoveGroup(ctx context.Context, token, id string) error {
|
||||
if _, err := svc.identify(ctx, token); err != nil {
|
||||
return err
|
||||
}
|
||||
return svc.groups.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (svc usersService) Unassign(ctx context.Context, token, userID, groupID string) error {
|
||||
if _, err := svc.identify(ctx, token); err != nil {
|
||||
return err
|
||||
}
|
||||
return svc.groups.Unassign(ctx, userID, groupID)
|
||||
}
|
||||
|
||||
func (svc usersService) UpdateGroup(ctx context.Context, token string, group Group) error {
|
||||
if _, err := svc.identify(ctx, token); err != nil {
|
||||
return err
|
||||
}
|
||||
return svc.groups.Update(ctx, group)
|
||||
}
|
||||
|
||||
func (svc usersService) ViewGroup(ctx context.Context, token, id string) (Group, error) {
|
||||
if _, err := svc.identify(ctx, token); err != nil {
|
||||
return Group{}, err
|
||||
}
|
||||
return svc.groups.RetrieveByID(ctx, id)
|
||||
}
|
||||
|
||||
func (svc usersService) Assign(ctx context.Context, token, userID, groupID string) error {
|
||||
if _, err := svc.identify(ctx, token); err != nil {
|
||||
return err
|
||||
}
|
||||
return svc.groups.Assign(ctx, userID, groupID)
|
||||
}
|
||||
|
||||
func (svc usersService) ListMemberships(ctx context.Context, token, userID string, offset, limit uint64, m Metadata) (GroupPage, error) {
|
||||
if _, err := svc.identify(ctx, token); err != nil {
|
||||
return GroupPage{}, err
|
||||
}
|
||||
return svc.groups.RetrieveMemberships(ctx, userID, offset, limit, m)
|
||||
}
|
||||
|
||||
// Auth helpers
|
||||
func (svc usersService) issue(ctx context.Context, email string, keyType uint32) (string, error) {
|
||||
key, err := svc.auth.Issue(ctx, &mainflux.IssueReq{Issuer: email, Type: keyType})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrUserNotFound, err)
|
||||
}
|
||||
return key.GetValue(), nil
|
||||
}
|
||||
|
||||
func (svc usersService) identify(ctx context.Context, token string) (string, error) {
|
||||
email, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
@ -300,96 +421,3 @@ func (svc usersService) identify(ctx context.Context, token string) (string, err
|
||||
}
|
||||
return email.GetValue(), nil
|
||||
}
|
||||
|
||||
func (svc usersService) CreateGroup(ctx context.Context, token string, group Group) (Group, error) {
|
||||
if group.Name == "" || !groupRegexp.MatchString(group.Name) {
|
||||
return Group{}, ErrMalformedEntity
|
||||
}
|
||||
userID, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return Group{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
user, err := svc.users.RetrieveByEmail(ctx, userID.Value)
|
||||
if err != nil {
|
||||
return Group{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
uid, err := uuidProvider.New().ID()
|
||||
if err != nil {
|
||||
return Group{}, errors.Wrap(ErrCreateUser, err)
|
||||
}
|
||||
group.ID = uid
|
||||
group.OwnerID = user.ID
|
||||
return svc.groups.Save(ctx, group)
|
||||
}
|
||||
|
||||
func (svc usersService) Groups(ctx context.Context, token string, parentID string, offset, limit uint64, meta Metadata) (GroupPage, error) {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return GroupPage{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.groups.RetrieveAllWithAncestors(ctx, parentID, offset, limit, meta)
|
||||
}
|
||||
|
||||
func (svc usersService) Members(ctx context.Context, token, groupID string, offset, limit uint64, meta Metadata) (UserPage, error) {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return UserPage{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.users.Members(ctx, groupID, offset, limit, meta)
|
||||
}
|
||||
|
||||
func (svc usersService) RemoveGroup(ctx context.Context, token, id string) error {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.groups.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (svc usersService) Unassign(ctx context.Context, token, userID, groupID string) error {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.groups.Unassign(ctx, userID, groupID)
|
||||
}
|
||||
|
||||
func (svc usersService) UpdateGroup(ctx context.Context, token string, group Group) error {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.groups.Update(ctx, group)
|
||||
}
|
||||
|
||||
func (svc usersService) Group(ctx context.Context, token, id string) (Group, error) {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return Group{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.groups.RetrieveByID(ctx, id)
|
||||
}
|
||||
|
||||
func (svc usersService) Assign(ctx context.Context, token, userID, groupID string) error {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.groups.Assign(ctx, userID, groupID)
|
||||
}
|
||||
|
||||
func (svc usersService) issue(ctx context.Context, email string, keyType uint32) (string, error) {
|
||||
key, err := svc.auth.Issue(ctx, &mainflux.IssueReq{Issuer: email, Type: keyType})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrUserNotFound, err)
|
||||
}
|
||||
return key.GetValue(), nil
|
||||
}
|
||||
|
||||
func (svc usersService) Memberships(ctx context.Context, token, userID string, offset, limit uint64, meta Metadata) (GroupPage, error) {
|
||||
_, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token})
|
||||
if err != nil {
|
||||
return GroupPage{}, errors.Wrap(ErrUnauthorizedAccess, err)
|
||||
}
|
||||
return svc.groups.Memberships(ctx, userID, offset, limit, meta)
|
||||
}
|
||||
|
@ -115,7 +115,50 @@ func TestLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUser(t *testing.T) {
|
||||
func TestViewUser(t *testing.T) {
|
||||
svc := newService()
|
||||
id, err := svc.Register(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
token, err := svc.Login(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
u := user
|
||||
u.Password = ""
|
||||
|
||||
cases := map[string]struct {
|
||||
user users.User
|
||||
token string
|
||||
userID string
|
||||
err error
|
||||
}{
|
||||
"view user with authorized token": {
|
||||
user: u,
|
||||
token: token,
|
||||
userID: id,
|
||||
err: nil,
|
||||
},
|
||||
"view user with unauthorized token": {
|
||||
user: users.User{},
|
||||
token: "",
|
||||
userID: id,
|
||||
err: users.ErrUnauthorizedAccess,
|
||||
},
|
||||
"view user with authorized token and invalid user id": {
|
||||
user: users.User{},
|
||||
token: token,
|
||||
userID: "",
|
||||
err: users.ErrUnauthorizedAccess,
|
||||
},
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
_, err := svc.ViewUser(context.Background(), tc.token, tc.userID)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewProfile(t *testing.T) {
|
||||
svc := newService()
|
||||
_, err := svc.Register(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
@ -144,7 +187,61 @@ func TestUser(t *testing.T) {
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
_, err := svc.User(context.Background(), tc.token)
|
||||
_, err := svc.ViewProfile(context.Background(), tc.token)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
func TestListUsers(t *testing.T) {
|
||||
svc := newService()
|
||||
|
||||
_, err := svc.Register(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
token, err := svc.Login(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
var nUsers = uint64(10)
|
||||
|
||||
for i := uint64(1); i < nUsers; i++ {
|
||||
email := fmt.Sprintf("TestListUsers%d@example.com", i)
|
||||
user := users.User{
|
||||
Email: email,
|
||||
Password: "passpass",
|
||||
}
|
||||
_, err := svc.Register(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
token string
|
||||
offset uint64
|
||||
limit uint64
|
||||
email string
|
||||
size uint64
|
||||
err error
|
||||
}{
|
||||
"list users with authorized token": {
|
||||
token: token,
|
||||
size: 0,
|
||||
err: nil,
|
||||
},
|
||||
"list user with unauthorized token": {
|
||||
token: "",
|
||||
size: 0,
|
||||
err: users.ErrUnauthorizedAccess,
|
||||
},
|
||||
"list users with offset and limit": {
|
||||
token: token,
|
||||
offset: 6,
|
||||
limit: nUsers,
|
||||
size: nUsers - 6,
|
||||
},
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
page, err := svc.ListUsers(context.Background(), tc.token, tc.offset, tc.limit, tc.email, nil)
|
||||
size := uint64(len(page.Users))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", desc, tc.size, size))
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
@ -344,7 +441,7 @@ func TestUpdateGroup(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
err := svc.UpdateGroup(context.Background(), token, tc.group)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
g, err := svc.Group(context.Background(), token, saved.ID)
|
||||
g, err := svc.ViewGroup(context.Background(), token, saved.ID)
|
||||
assert.Nil(t, err, fmt.Sprintf("retrieve group failed: %s", err))
|
||||
assert.Equal(t, tc.group.Description, g.Description, tc.desc, tc.err)
|
||||
assert.Equal(t, tc.group.Name, g.Name, tc.desc, tc.err)
|
||||
|
@ -77,20 +77,20 @@ func (grm groupRepositoryMiddleware) RetrieveByName(ctx context.Context, name st
|
||||
return grm.repo.RetrieveByName(ctx, name)
|
||||
}
|
||||
|
||||
func (grm groupRepositoryMiddleware) RetrieveAllWithAncestors(ctx context.Context, groupID string, offset, limit uint64, gm users.Metadata) (users.GroupPage, error) {
|
||||
func (grm groupRepositoryMiddleware) RetrieveAllWithAncestors(ctx context.Context, groupID string, offset, limit uint64, um users.Metadata) (users.GroupPage, error) {
|
||||
span := createSpan(ctx, grm.tracer, retrieveAll)
|
||||
defer span.Finish()
|
||||
ctx = opentracing.ContextWithSpan(ctx, span)
|
||||
|
||||
return grm.repo.RetrieveAllWithAncestors(ctx, groupID, offset, limit, gm)
|
||||
return grm.repo.RetrieveAllWithAncestors(ctx, groupID, offset, limit, um)
|
||||
}
|
||||
|
||||
func (grm groupRepositoryMiddleware) Memberships(ctx context.Context, userID string, offset, limit uint64, gm users.Metadata) (users.GroupPage, error) {
|
||||
func (grm groupRepositoryMiddleware) RetrieveMemberships(ctx context.Context, userID string, offset, limit uint64, um users.Metadata) (users.GroupPage, error) {
|
||||
span := createSpan(ctx, grm.tracer, memberships)
|
||||
defer span.Finish()
|
||||
ctx = opentracing.ContextWithSpan(ctx, span)
|
||||
|
||||
return grm.repo.Memberships(ctx, userID, offset, limit, gm)
|
||||
return grm.repo.RetrieveMemberships(ctx, userID, offset, limit, um)
|
||||
}
|
||||
|
||||
func (grm groupRepositoryMiddleware) Unassign(ctx context.Context, userID, groupID string) error {
|
||||
|
@ -75,12 +75,20 @@ func (urm userRepositoryMiddleware) UpdatePassword(ctx context.Context, email, p
|
||||
return urm.repo.UpdatePassword(ctx, email, password)
|
||||
}
|
||||
|
||||
func (urm userRepositoryMiddleware) Members(ctx context.Context, groupID string, offset, limit uint64, gm users.Metadata) (users.UserPage, error) {
|
||||
func (urm userRepositoryMiddleware) RetrieveAll(ctx context.Context, offset, limit uint64, email string, um users.Metadata) (users.UserPage, error) {
|
||||
span := createSpan(ctx, urm.tracer, members)
|
||||
defer span.Finish()
|
||||
ctx = opentracing.ContextWithSpan(ctx, span)
|
||||
|
||||
return urm.repo.Members(ctx, groupID, offset, limit, gm)
|
||||
return urm.repo.RetrieveAll(ctx, offset, limit, email, um)
|
||||
}
|
||||
|
||||
func (urm userRepositoryMiddleware) RetrieveMembers(ctx context.Context, groupID string, offset, limit uint64, um users.Metadata) (users.UserPage, error) {
|
||||
span := createSpan(ctx, urm.tracer, members)
|
||||
defer span.Finish()
|
||||
ctx = opentracing.ContextWithSpan(ctx, span)
|
||||
|
||||
return urm.repo.RetrieveMembers(ctx, groupID, offset, limit, um)
|
||||
}
|
||||
|
||||
func createSpan(ctx context.Context, tracer opentracing.Tracer, opName string) opentracing.Span {
|
||||
|
@ -72,11 +72,14 @@ type UserRepository interface {
|
||||
// RetrieveByID retrieves user by its unique identifier ID.
|
||||
RetrieveByID(ctx context.Context, id string) (User, error)
|
||||
|
||||
// RetrieveAll retrieves all users
|
||||
RetrieveAll(ctx context.Context, offset, limit uint64, email string, m Metadata) (UserPage, error)
|
||||
|
||||
// UpdatePassword updates password for user with given email
|
||||
UpdatePassword(ctx context.Context, email, password string) error
|
||||
|
||||
// Members retrieves all users that belong to a group
|
||||
Members(ctx context.Context, groupID string, offset, limit uint64, um Metadata) (UserPage, error)
|
||||
// RetrieveMembers retrieves all users that belong to a group
|
||||
RetrieveMembers(ctx context.Context, groupID string, offset, limit uint64, m Metadata) (UserPage, error)
|
||||
}
|
||||
|
||||
func isEmail(email string) bool {
|
||||
|
Loading…
x
Reference in New Issue
Block a user