Skip to content

Commit

Permalink
feat(graph): add support for filtering users by type
Browse files Browse the repository at this point in the history
This add support for equality filters on the `userType` property of users
for the /users endpoint.

It also changes the behavior of the /users endpoint to only return
federated users when explicitly request via a `userType` filter.

E.g. to search for federated users with matching "albert" you can use:

`$filter=userType eq 'Federated'&$search="albert"`

Related Issue: owncloud#9702
  • Loading branch information
rhafer committed Aug 12, 2024
1 parent 7fb79e6 commit b78352c
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 40 deletions.
64 changes: 24 additions & 40 deletions services/graph/pkg/service/v0/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,25 +269,6 @@ func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
return
}

if g.config.IncludeOCMSharees {
ocmUsers, err := g.searchOCMAcceptedUsers(r.Context(), odataReq)
var errcode errorcode.Error
var godataerr *godata.GoDataError
switch {
case err == nil:
users = append(users, ocmUsers...)
case errors.As(err, &errcode):
errcode.Render(w, r)
return
case errors.As(err, &godataerr):
errorcode.GeneralException.Render(w, r, godataerr.ResponseCode, err.Error())
return
default:
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
}

// If the user isn't admin, we'll show just the minimum user attibutes
if !ctxHasFullPerms {
finalUsers := make([]*libregraph.User, len(users))
Expand Down Expand Up @@ -1007,29 +988,32 @@ func isValidUserType(userType string) bool {
}

func (g Graph) searchOCMAcceptedUsers(ctx context.Context, odataReq *godata.GoDataRequest) ([]*libregraph.User, error) {
gwc, err := g.gatewaySelector.Next()
if err != nil {
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
term, err := identity.GetSearchValues(odataReq.Query)
if err != nil {
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
}
users := []*libregraph.User{}
if g.config.IncludeOCMSharees {
gwc, err := g.gatewaySelector.Next()
if err != nil {
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
term, err := identity.GetSearchValues(odataReq.Query)
if err != nil {
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
}

remoteUsersRes, err := gwc.FindAcceptedUsers(ctx, &invitepb.FindAcceptedUsersRequest{Filter: term})
if err != nil {
// TODO grpc FindAcceptedUsers call failed
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
if remoteUsersRes.Status.Code != cs3rpc.Code_CODE_OK {
// TODO "error searching remote users"
return nil, errorcode.New(errorcode.GeneralException, remoteUsersRes.Status.Message)
}
remoteUsersRes, err := gwc.FindAcceptedUsers(ctx, &invitepb.FindAcceptedUsersRequest{Filter: term})
if err != nil {
// TODO grpc FindAcceptedUsers call failed
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
if remoteUsersRes.Status.Code != cs3rpc.Code_CODE_OK {
// TODO "error searching remote users"
return nil, errorcode.New(errorcode.GeneralException, remoteUsersRes.Status.Message)
}

cs3Users := remoteUsersRes.GetAcceptedUsers()
users := make([]*libregraph.User, 0, len(cs3Users))
for _, user := range cs3Users {
users = append(users, identity.CreateUserModelFromCS3(user))
cs3Users := remoteUsersRes.GetAcceptedUsers()
users = make([]*libregraph.User, 0, len(cs3Users))
for _, user := range cs3Users {
users = append(users, identity.CreateUserModelFromCS3(user))
}
}
return users, nil
}
25 changes: 25 additions & 0 deletions services/graph/pkg/service/v0/users_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ func (g Graph) applyFilterLogical(ctx context.Context, req *godata.GoDataRequest
return g.applyFilterLogicalAnd(ctx, req, root.Children[0], root.Children[1])
case "or":
return g.applyFilterLogicalOr(ctx, req, root.Children[0], root.Children[1])
case "eq":
return g.applyFilterEq(ctx, req, root.Children[0], root.Children[1])
}
logger.Debug().Str("Token", root.Token.Value).Msg("unsupported logical filter")
return users, unsupportedFilterError()
Expand Down Expand Up @@ -220,6 +222,29 @@ func (g Graph) applyFilterLogicalOr(ctx context.Context, req *godata.GoDataReque
}
return filteredUsers, nil
}

func (g Graph) applyFilterEq(ctx context.Context, req *godata.GoDataRequest, operand1 *godata.ParseNode, operand2 *godata.ParseNode) (users []*libregraph.User, err error) {
// We only support the 'eq' on 'userType' for now
switch {
case operand1.Token.Type != godata.ExpressionTokenLiteral:
fallthrough
case operand1.Token.Value != "userType":
fallthrough
case operand2.Token.Type != godata.ExpressionTokenString:
return users, unsupportedFilterError()
}

// unquote
value := strings.Trim(operand2.Token.Value, "'")
switch value {
case "Member", "Guest":
return g.identityBackend.GetUsers(ctx, req)
case "Federated":
return g.searchOCMAcceptedUsers(ctx, req)
}
return users, unsupportedFilterError()
}

func (g Graph) applyFilterLambda(ctx context.Context, req *godata.GoDataRequest, nodes []*godata.ParseNode) (users []*libregraph.User, err error) {
logger := g.logger.SubloggerWithRequestID(ctx)
if len(nodes) != 2 {
Expand Down

0 comments on commit b78352c

Please sign in to comment.