Add sorting to GraphAPI users and groups
The GraphAPI endpoints for users and groups support ordering now. User can be ordered by displayName, onPremisesSamAccountName and mail. Groups can be ordered by displayName. Example: https://localhost:9200/graph/v1.0/groups?$orderby=displayName asc Closes #3360
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
Enhancement: Add sorting to GraphAPI users and groups
|
||||
|
||||
The GraphAPI endpoints for users and groups support ordering now.
|
||||
User can be ordered by displayName, onPremisesSamAccountName and mail.
|
||||
Groups can be ordered by displayName.
|
||||
|
||||
Example:
|
||||
https://localhost:9200/graph/v1.0/groups?$orderby=displayName asc
|
||||
|
||||
https://github.com/owncloud/ocis/issues/3360
|
||||
@@ -6,8 +6,10 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/CiscoM31/godata"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"
|
||||
|
||||
@@ -19,6 +21,14 @@ const memberRefsLimit = 20
|
||||
|
||||
// GetGroups implements the Service interface.
|
||||
func (g Graph) GetGroups(w http.ResponseWriter, r *http.Request) {
|
||||
sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
|
||||
odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
|
||||
if err != nil {
|
||||
g.logger.Err(err).Interface("query", r.URL.Query()).Msg("query error")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
groups, err := g.identityBackend.GetGroups(r.Context(), r.URL.Query())
|
||||
|
||||
if err != nil {
|
||||
@@ -29,6 +39,17 @@ func (g Graph) GetGroups(w http.ResponseWriter, r *http.Request) {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
groups, err = sortGroups(odataReq, groups)
|
||||
if err != nil {
|
||||
var errcode errorcode.Error
|
||||
if errors.As(err, &errcode) {
|
||||
errcode.Render(w, r)
|
||||
} else {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, &listResponse{Value: groups})
|
||||
}
|
||||
@@ -318,3 +339,22 @@ func (g Graph) parseMemberRef(ref string) (string, string, error) {
|
||||
memberType := segments[len(segments)-2]
|
||||
return memberType, id, nil
|
||||
}
|
||||
|
||||
func sortGroups(req *godata.GoDataRequest, groups []*libregraph.Group) ([]*libregraph.Group, error) {
|
||||
var sorter sort.Interface
|
||||
if req.Query.OrderBy == nil || len(req.Query.OrderBy.OrderByItems) != 1 {
|
||||
return groups, nil
|
||||
}
|
||||
switch req.Query.OrderBy.OrderByItems[0].Field.Value {
|
||||
case "displayName":
|
||||
sorter = groupsByDisplayName{groups}
|
||||
default:
|
||||
return nil, fmt.Errorf("we do not support <%s> as a order parameter", req.Query.OrderBy.OrderByItems[0].Field.Value)
|
||||
}
|
||||
|
||||
if req.Query.OrderBy.OrderByItems[0].Order == "asc" {
|
||||
sorter = sort.Reverse(sorter)
|
||||
}
|
||||
sort.Sort(sorter)
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
@@ -45,3 +45,59 @@ func (s spacesByLastModifiedDateTime) Less(i, j int) bool {
|
||||
// fallback to name if no dateTime is set on both items
|
||||
return strings.ToLower(*s.spacesSlice[i].Name) > strings.ToLower(*s.spacesSlice[j].Name)
|
||||
}
|
||||
|
||||
type userSlice []*libregraph.User
|
||||
|
||||
// Len is the number of elements in the collection.
|
||||
func (d userSlice) Len() int { return len(d) }
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
func (d userSlice) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||
|
||||
type usersByDisplayName struct {
|
||||
userSlice
|
||||
}
|
||||
|
||||
type usersByMail struct {
|
||||
userSlice
|
||||
}
|
||||
|
||||
type usersByOnPremisesSamAccountName struct {
|
||||
userSlice
|
||||
}
|
||||
|
||||
// Less reports whether the element with index i
|
||||
// must sort before the element with index j.
|
||||
func (u usersByDisplayName) Less(i, j int) bool {
|
||||
return strings.ToLower(u.userSlice[i].GetDisplayName()) > strings.ToLower(u.userSlice[j].GetDisplayName())
|
||||
}
|
||||
|
||||
// Less reports whether the element with index i
|
||||
// must sort before the element with index j.
|
||||
func (u usersByMail) Less(i, j int) bool {
|
||||
return strings.ToLower(u.userSlice[i].GetMail()) > strings.ToLower(u.userSlice[j].GetMail())
|
||||
}
|
||||
|
||||
// Less reports whether the element with index i
|
||||
// must sort before the element with index j.
|
||||
func (u usersByOnPremisesSamAccountName) Less(i, j int) bool {
|
||||
return strings.ToLower(u.userSlice[i].GetOnPremisesSamAccountName()) > strings.ToLower(u.userSlice[j].GetOnPremisesSamAccountName())
|
||||
}
|
||||
|
||||
type groupSlice []*libregraph.Group
|
||||
|
||||
// Len is the number of elements in the collection.
|
||||
func (d groupSlice) Len() int { return len(d) }
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
func (d groupSlice) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||
|
||||
type groupsByDisplayName struct {
|
||||
groupSlice
|
||||
}
|
||||
|
||||
// Less reports whether the element with index i
|
||||
// must sort before the element with index j.
|
||||
func (g groupsByDisplayName) Less(i, j int) bool {
|
||||
return strings.ToLower(g.groupSlice[i].GetDisplayName()) > strings.ToLower(g.groupSlice[j].GetDisplayName())
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/CiscoM31/godata"
|
||||
revactx "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
@@ -38,6 +41,13 @@ func (g Graph) GetMe(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// GetUsers implements the Service interface.
|
||||
func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
|
||||
odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
|
||||
if err != nil {
|
||||
g.logger.Err(err).Interface("query", r.URL.Query()).Msg("query error")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
users, err := g.identityBackend.GetUsers(r.Context(), r.URL.Query())
|
||||
if err != nil {
|
||||
var errcode errorcode.Error
|
||||
@@ -48,6 +58,17 @@ func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
users, err = sortUsers(odataReq, users)
|
||||
if err != nil {
|
||||
var errcode errorcode.Error
|
||||
if errors.As(err, &errcode) {
|
||||
errcode.Render(w, r)
|
||||
} else {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, &listResponse{Value: users})
|
||||
}
|
||||
@@ -234,3 +255,26 @@ func isValidEmail(e string) bool {
|
||||
}
|
||||
return emailRegex.MatchString(e)
|
||||
}
|
||||
|
||||
func sortUsers(req *godata.GoDataRequest, users []*libregraph.User) ([]*libregraph.User, error) {
|
||||
var sorter sort.Interface
|
||||
if req.Query.OrderBy == nil || len(req.Query.OrderBy.OrderByItems) != 1 {
|
||||
return users, nil
|
||||
}
|
||||
switch req.Query.OrderBy.OrderByItems[0].Field.Value {
|
||||
case "displayName":
|
||||
sorter = usersByDisplayName{users}
|
||||
case "mail":
|
||||
sorter = usersByMail{users}
|
||||
case "onPremisesSamAccountName":
|
||||
sorter = usersByOnPremisesSamAccountName{users}
|
||||
default:
|
||||
return nil, fmt.Errorf("we do not support <%s> as a order parameter", req.Query.OrderBy.OrderByItems[0].Field.Value)
|
||||
}
|
||||
|
||||
if req.Query.OrderBy.OrderByItems[0].Order == "asc" {
|
||||
sorter = sort.Reverse(sorter)
|
||||
}
|
||||
sort.Sort(sorter)
|
||||
return users, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user