Merge pull request #2510 from aduffeck/add-favorite-flag-to-search-results

Add the favorite flag to REPORT results
This commit is contained in:
Andre Duffeck
2026-03-23 16:53:51 +01:00
committed by GitHub
2 changed files with 46 additions and 19 deletions
+29 -8
View File
@@ -8,9 +8,11 @@ import (
"net/http"
"net/url"
"path"
"slices"
"strconv"
"strings"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
merrors "go-micro.dev/v4/errors"
"go-micro.dev/v4/metadata"
@@ -37,6 +39,22 @@ const (
// Search is the endpoint for retrieving search results for REPORT requests
func (g Webdav) Search(w http.ResponseWriter, r *http.Request) {
logger := g.log.SubloggerWithRequestID(r.Context())
t := r.Header.Get(revactx.TokenHeader)
gatewayClient, err := g.gatewaySelector.Next()
if err != nil {
logger.Error().Err(err).Msg("could not get reva gatewayClient")
renderError(w, r, errInternalError("could not get reva gatewayClient"))
return
}
user, err := whoami(gatewayClient, r.Context(), t)
if err != nil {
logger.Error().Err(err).Msg("could not get user")
renderError(w, r, errInternalError("could not get user"))
return
}
rep, err := readReport(r.Body)
if err != nil {
renderError(w, r, errBadRequest(err.Error()))
@@ -50,7 +68,6 @@ func (g Webdav) Search(w http.ResponseWriter, r *http.Request) {
return
}
t := r.Header.Get(revactx.TokenHeader)
ctx := revactx.ContextSetToken(r.Context(), t)
ctx = metadata.Set(ctx, revactx.TokenHeader, t)
@@ -88,13 +105,12 @@ func (g Webdav) Search(w http.ResponseWriter, r *http.Request) {
logger.Error().Err(err).Msg("could not get search results")
return
}
g.sendSearchResponse(rsp, w, r)
g.sendSearchResponse(rsp, w, r, user)
}
func (g Webdav) sendSearchResponse(rsp *searchsvc.SearchResponse, w http.ResponseWriter, r *http.Request) {
func (g Webdav) sendSearchResponse(rsp *searchsvc.SearchResponse, w http.ResponseWriter, r *http.Request, user *userv1beta1.User) {
logger := g.log.SubloggerWithRequestID(r.Context())
responsesXML, err := multistatusResponse(r.Context(), g.config.OpenCloudPublicURL, rsp.Matches)
responsesXML, err := multistatusResponse(r.Context(), g.config.OpenCloudPublicURL, rsp.Matches, user)
if err != nil {
logger.Error().Err(err).Msg("error formatting propfind")
w.WriteHeader(http.StatusInternalServerError)
@@ -112,10 +128,10 @@ func (g Webdav) sendSearchResponse(rsp *searchsvc.SearchResponse, w http.Respons
}
// multistatusResponse converts a list of matches into a multistatus response string
func multistatusResponse(ctx context.Context, publicURL string, matches []*searchmsg.Match) ([]byte, error) {
func multistatusResponse(ctx context.Context, publicURL string, matches []*searchmsg.Match, user *userv1beta1.User) ([]byte, error) {
responses := make([]*propfind.ResponseXML, 0, len(matches))
for i := range matches {
res, err := matchToPropResponse(ctx, publicURL, matches[i])
res, err := matchToPropResponse(ctx, publicURL, matches[i], user)
if err != nil {
return nil, err
}
@@ -131,7 +147,7 @@ func multistatusResponse(ctx context.Context, publicURL string, matches []*searc
return msg, nil
}
func matchToPropResponse(ctx context.Context, publicURL string, match *searchmsg.Match) (*propfind.ResponseXML, error) {
func matchToPropResponse(ctx context.Context, publicURL string, match *searchmsg.Match, user *userv1beta1.User) (*propfind.ResponseXML, error) {
// unfortunately, search uses own versions of ResourceId and Ref. So we need to assert them here
var (
ref string
@@ -234,6 +250,11 @@ func matchToPropResponse(ctx context.Context, publicURL string, match *searchmsg
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:privatelink", privateURL.String()))
}
// enrich results with favorite flag for the user performing the search
if slices.Contains(match.Entity.Favorites, user.Id.OpaqueId) {
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:favorite", "1"))
}
if len(propstatOK.Prop) > 0 {
response.Propstat = append(response.Propstat, propstatOK)
}
+17 -11
View File
@@ -3,6 +3,7 @@ package svc
import (
"context"
"encoding/xml"
"fmt"
"io"
"math/rand/v2"
"net/http"
@@ -277,6 +278,20 @@ func (g Webdav) SpacesThumbnail(w http.ResponseWriter, r *http.Request) {
g.sendThumbnailResponse(rsp, w, r)
}
func whoami(gatewayClient gatewayv1beta1.GatewayAPIClient, ctx context.Context, token string) (*userv1beta1.User, error) {
// look up user from token via WhoAmI
userRes, err := gatewayClient.WhoAmI(ctx, &gatewayv1beta1.WhoAmIRequest{
Token: token,
})
if err != nil {
return nil, err
}
if userRes.Status.Code != rpcv1beta1.Code_CODE_OK {
return nil, fmt.Errorf("could not get user: %s", userRes.GetStatus().GetMessage())
}
return userRes.GetUser(), nil
}
// Thumbnail implements the Service interface.
func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) {
logger := g.log.SubloggerWithRequestID(r.Context())
@@ -298,21 +313,12 @@ func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) {
var user *userv1beta1.User
if tr.Identifier == "" {
// look up user from token via WhoAmI
userRes, err := gatewayClient.WhoAmI(r.Context(), &gatewayv1beta1.WhoAmIRequest{
Token: t,
})
user, err = whoami(gatewayClient, r.Context(), t)
if err != nil {
logger.Error().Err(err).Msg("could not get user: transport error")
logger.Error().Err(err).Msg("could not get user")
renderError(w, r, errInternalError("could not get user"))
return
}
if userRes.Status.Code != rpcv1beta1.Code_CODE_OK {
logger.Debug().Str("grpcmessage", userRes.GetStatus().GetMessage()).Msg("could not get user")
renderError(w, r, errInternalError("could not get user"))
return
}
user = userRes.GetUser()
} else {
// look up user from URL via GetUserByClaim
ctx := grpcmetadata.AppendToOutgoingContext(r.Context(), revactx.TokenHeader, t)