Merge pull request #1257 from dragonchaser/has-preview-in-shares

Add thumbnails to sharedWithMe and sharedByMe requests
This commit is contained in:
Christian Richter
2025-07-25 10:34:14 +02:00
committed by GitHub
8 changed files with 120 additions and 11 deletions

2
go.mod
View File

@@ -63,7 +63,7 @@ require (
github.com/onsi/ginkgo/v2 v2.23.4
github.com/onsi/gomega v1.37.0
github.com/open-policy-agent/opa v1.6.0
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250707143759-32eaae12b2ce
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
github.com/opencloud-eu/reva/v2 v2.35.0
github.com/orcaman/concurrent-map v1.0.0
github.com/pkg/errors v0.9.1

4
go.sum
View File

@@ -866,8 +866,8 @@ github.com/open-policy-agent/opa v1.6.0 h1:/S/cnNQJ2MUMNzizHPbisTWBHowmLkPrugY5j
github.com/open-policy-agent/opa v1.6.0/go.mod h1:zFmw4P+W62+CWGYRDDswfVYSCnPo6oYaktQnfIaRFC4=
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M=
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250707143759-32eaae12b2ce h1:tjbIYsW5CFsEbCf5B/KN0Mo1oKU/K+oipgFm2B6wzG4=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250707143759-32eaae12b2ce/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
github.com/opencloud-eu/reva/v2 v2.35.0 h1:lKxGiI9yFD7MTeyFJa68BQD+DiB1rQvhC8QePa/Vlc4=
github.com/opencloud-eu/reva/v2 v2.35.0/go.mod h1:UVPwuMjfgPekuh7unWavJSiPihgmk1GYF3xct0q3+X0=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=

View File

@@ -1,11 +1,14 @@
package svc
import (
"fmt"
"net/http"
"strings"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/go-chi/render"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/opencloud-eu/opencloud/services/thumbnails/pkg/thumbnail"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
)
@@ -17,9 +20,7 @@ func (g Graph) GetSharedByMe(w http.ResponseWriter, r *http.Request) {
g.logger.Debug().Msg("Calling GetRootDriveChildren")
ctx := r.Context()
driveItems := make(driveItemsByResourceID)
var err error
driveItems, err = g.listUserShares(ctx, nil, driveItems)
driveItems, err := g.listUserShares(ctx, nil, make(driveItemsByResourceID))
if err != nil {
errorcode.RenderError(w, r, err)
return
@@ -39,6 +40,37 @@ func (g Graph) GetSharedByMe(w http.ResponseWriter, r *http.Request) {
return
}
expand := r.URL.Query().Get("$expand")
expandThumbnails := strings.Contains(expand, "thumbnails")
if expandThumbnails {
for k, item := range driveItems {
mt := item.GetFile().MimeType
if mt == nil {
continue
}
_, match := thumbnail.SupportedMimeTypes[*mt]
if match {
baseUrl := fmt.Sprintf("%s/dav/spaces/%s?scalingup=0&preview=1&processor=thumbnail",
g.config.Commons.OpenCloudURL,
item.GetId())
smallUrl := baseUrl + "&x=36&y=36"
mediumUrl := baseUrl + "&x=48&y=48"
largeUrl := baseUrl + "&x=96&y=96"
item.SetThumbnails([]libregraph.ThumbnailSet{
{
Small: &libregraph.Thumbnail{Url: &smallUrl},
Medium: &libregraph.Thumbnail{Url: &mediumUrl},
Large: &libregraph.Thumbnail{Url: &largeUrl},
},
})
driveItems[k] = item // assign modified item back to the map
}
}
}
res := make([]libregraph.DriveItem, 0, len(driveItems))
for _, v := range driveItems {
res = append(res, v)

View File

@@ -2,7 +2,9 @@ package svc
import (
"context"
"fmt"
"net/http"
"strings"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
@@ -10,12 +12,17 @@ import (
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/thumbnails/pkg/thumbnail"
)
// ListSharedWithMe lists the files shared with the current user.
func (g Graph) ListSharedWithMe(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
driveItems, err := g.listSharedWithMe(ctx)
expand := r.URL.Query().Get("$expand")
expandThumbnails := strings.Contains(expand, "thumbnails")
driveItems, err := g.listSharedWithMe(ctx, expandThumbnails)
if err != nil {
g.logger.Error().Err(err).Msg("listSharedWithMe failed")
errorcode.RenderError(w, r, err)
@@ -27,7 +34,7 @@ func (g Graph) ListSharedWithMe(w http.ResponseWriter, r *http.Request) {
}
// listSharedWithMe is a helper function that lists the drive items shared with the current user.
func (g Graph) listSharedWithMe(ctx context.Context) ([]libregraph.DriveItem, error) {
func (g Graph) listSharedWithMe(ctx context.Context, expandThumbnails bool) ([]libregraph.DriveItem, error) {
gatewayClient, err := g.gatewaySelector.Next()
if err != nil {
g.logger.Error().Err(err).Msg("could not select next gateway client")
@@ -59,5 +66,34 @@ func (g Graph) listSharedWithMe(ctx context.Context) ([]libregraph.DriveItem, er
driveItems = append(driveItems, ocmDriveItems...)
}
if expandThumbnails {
for k, item := range driveItems {
mt := item.GetFile().MimeType
if mt == nil {
continue
}
_, match := thumbnail.SupportedMimeTypes[*mt]
if match {
baseUrl := fmt.Sprintf("%s/dav/spaces/%s?scalingup=0&preview=1&processor=thumbnail",
g.config.Commons.OpenCloudURL,
item.RemoteItem.GetId())
smallUrl := baseUrl + "&x=36&y=36"
mediumUrl := baseUrl + "&x=48&y=48"
largeUrl := baseUrl + "&x=96&y=96"
item.SetThumbnails([]libregraph.ThumbnailSet{
{
Small: &libregraph.Thumbnail{Url: &smallUrl},
Medium: &libregraph.Thumbnail{Url: &mediumUrl},
Large: &libregraph.Thumbnail{Url: &largeUrl},
},
})
driveItems[k] = item // assign modified item back to the map
}
}
}
return driveItems, err
}

View File

@@ -117,8 +117,13 @@ func (s Thumbnails) GetThumbnail(w http.ResponseWriter, r *http.Request) {
// TransferTokenValidator validates a transfer token
func (s Thumbnails) TransferTokenValidator(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger := s.logger.SubloggerWithRequestID(r.Context())
tokenString := r.Header.Get("Transfer-Token")
if tokenString == "" {
next.ServeHTTP(w, r)
return
}
logger := s.logger.SubloggerWithRequestID(r.Context())
token, err := jwt.ParseWithClaims(tokenString, &tjwt.ThumbnailClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])

View File

@@ -22,6 +22,7 @@ import (
searchmsg "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/search/v0"
searchsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/search/v0"
"github.com/opencloud-eu/opencloud/services/thumbnails/pkg/thumbnail"
"github.com/opencloud-eu/opencloud/services/webdav/pkg/constants"
"github.com/opencloud-eu/opencloud/services/webdav/pkg/net"
"github.com/opencloud-eu/opencloud/services/webdav/pkg/prop"
@@ -195,9 +196,15 @@ func matchToPropResponse(ctx context.Context, publicURL string, match *searchmsg
}
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:name", match.Entity.Name))
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getlastmodified", match.Entity.LastModifiedTime.AsTime().Format(constants.RFC1123)))
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getcontenttype", match.Entity.MimeType))
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:permissions", match.Entity.Permissions))
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:highlights", match.Entity.Highlights))
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getcontenttype", match.Entity.MimeType))
_, isSupportedMimeType := thumbnail.SupportedMimeTypes[match.Entity.MimeType]
if isSupportedMimeType {
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:has-preview", "1"))
} else {
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:has-preview", "0"))
}
t := tags.New(match.Entity.Tags...)
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:tags", t.AsList()))
@@ -234,6 +241,15 @@ func matchToPropResponse(ctx context.Context, publicURL string, match *searchmsg
return &response, nil
}
func hasPreview(md *provider.ResourceInfo, appendToOK func(p ...prop.PropertyXML)) {
_, match := thumbnail.SupportedMimeTypes[md.MimeType]
if match {
appendToOK(prop.Escaped("oc:has-preview", "1"))
} else {
appendToOK(prop.Escaped("oc:has-preview", "0"))
}
}
type report struct {
SearchFiles *reportSearchFiles
// FilterFiles TODO add this for tag based search

View File

@@ -130,6 +130,13 @@ func (a *MeDriveApiService) GetHomeExecute(r ApiGetHomeRequest) (*Drive, *http.R
type ApiListSharedByMeRequest struct {
ctx context.Context
ApiService *MeDriveApiService
expand *[]string
}
// Expand related entities
func (r ApiListSharedByMeRequest) Expand(expand []string) ApiListSharedByMeRequest {
r.expand = &expand
return r
}
func (r ApiListSharedByMeRequest) Execute() (*CollectionOfDriveItems1, *http.Response, error) {
@@ -173,6 +180,9 @@ func (a *MeDriveApiService) ListSharedByMeExecute(r ApiListSharedByMeRequest) (*
localVarQueryParams := url.Values{}
localVarFormParams := url.Values{}
if r.expand != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "$expand", r.expand, "form", "csv")
}
// to determine the Content-Type header
localVarHTTPContentTypes := []string{}
@@ -238,6 +248,13 @@ func (a *MeDriveApiService) ListSharedByMeExecute(r ApiListSharedByMeRequest) (*
type ApiListSharedWithMeRequest struct {
ctx context.Context
ApiService *MeDriveApiService
expand *[]string
}
// Expand related entities
func (r ApiListSharedWithMeRequest) Expand(expand []string) ApiListSharedWithMeRequest {
r.expand = &expand
return r
}
func (r ApiListSharedWithMeRequest) Execute() (*CollectionOfDriveItems1, *http.Response, error) {
@@ -281,6 +298,9 @@ func (a *MeDriveApiService) ListSharedWithMeExecute(r ApiListSharedWithMeRequest
localVarQueryParams := url.Values{}
localVarFormParams := url.Values{}
if r.expand != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "$expand", r.expand, "form", "csv")
}
// to determine the Content-Type header
localVarHTTPContentTypes := []string{}

2
vendor/modules.txt vendored
View File

@@ -1210,7 +1210,7 @@ github.com/open-policy-agent/opa/v1/types
github.com/open-policy-agent/opa/v1/util
github.com/open-policy-agent/opa/v1/util/decoding
github.com/open-policy-agent/opa/v1/version
# github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250707143759-32eaae12b2ce
# github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
## explicit; go 1.18
github.com/opencloud-eu/libre-graph-api-go
# github.com/opencloud-eu/reva/v2 v2.35.0