mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-05 19:09:56 -05:00
Merge pull request #3379 from rhafer/graph-user-sort
Add sorting to GraphAPI users and groups
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
|
||||
@@ -791,7 +791,7 @@ func sortSpaces(req *godata.GoDataRequest, spaces []*libregraph.Drive) ([]*libre
|
||||
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" {
|
||||
if req.Query.OrderBy.OrderByItems[0].Order == "desc" {
|
||||
sorter = sort.Reverse(sorter)
|
||||
}
|
||||
sort.Sort(sorter)
|
||||
|
||||
@@ -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 == "desc" {
|
||||
sorter = sort.Reverse(sorter)
|
||||
}
|
||||
sort.Sort(sorter)
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type spacesByLastModifiedDateTime struct {
|
||||
// Less reports whether the element with index i
|
||||
// must sort before the element with index j.
|
||||
func (s spacesByName) Less(i, j int) bool {
|
||||
return strings.ToLower(*s.spacesSlice[i].Name) > strings.ToLower(*s.spacesSlice[j].Name)
|
||||
return strings.ToLower(*s.spacesSlice[i].Name) < strings.ToLower(*s.spacesSlice[j].Name)
|
||||
}
|
||||
|
||||
// Less reports whether the element with index i
|
||||
@@ -32,16 +32,72 @@ func (s spacesByName) Less(i, j int) bool {
|
||||
func (s spacesByLastModifiedDateTime) Less(i, j int) bool {
|
||||
// compare the items when both dates are set
|
||||
if s.spacesSlice[i].LastModifiedDateTime != nil && s.spacesSlice[j].LastModifiedDateTime != nil {
|
||||
return s.spacesSlice[i].LastModifiedDateTime.After(*s.spacesSlice[j].LastModifiedDateTime)
|
||||
return s.spacesSlice[i].LastModifiedDateTime.Before(*s.spacesSlice[j].LastModifiedDateTime)
|
||||
}
|
||||
// move left item down if it has no value
|
||||
// an item without a timestamp is considered "less than" an item with a timestamp
|
||||
if s.spacesSlice[i].LastModifiedDateTime == nil && s.spacesSlice[j].LastModifiedDateTime != nil {
|
||||
return false
|
||||
}
|
||||
// move right item down if it has no value
|
||||
if s.spacesSlice[i].LastModifiedDateTime != nil && s.spacesSlice[j].LastModifiedDateTime == nil {
|
||||
return true
|
||||
}
|
||||
// an item without a timestamp is considered "less than" an item with a timestamp
|
||||
if s.spacesSlice[i].LastModifiedDateTime != nil && s.spacesSlice[j].LastModifiedDateTime == nil {
|
||||
return false
|
||||
}
|
||||
// fallback to name if no dateTime is set on both items
|
||||
return strings.ToLower(*s.spacesSlice[i].Name) > strings.ToLower(*s.spacesSlice[j].Name)
|
||||
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 == "desc" {
|
||||
sorter = sort.Reverse(sorter)
|
||||
}
|
||||
sort.Sort(sorter)
|
||||
return users, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user