mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-09-16 07:45:09 -04:00
Merge pull request #3471 from opencloud-eu/feat/graph-expand-thumbnails
feat(graph): expand thumbnails on driveItems
This commit is contained in:
5 files changed
+168
-61
No files matched your search
@@ -45,7 +45,10 @@ const (
|
||||
var shareTypesFieldMask = &fieldmaskpb.FieldMask{Paths: []string{"share-types"}}
|
||||
|
||||
// opt-in driveItem relations, returned only when requested via $expand
|
||||
const _expandChildren = "children"
|
||||
const (
|
||||
_expandChildren = "children"
|
||||
_expandThumbnails = "thumbnails"
|
||||
)
|
||||
|
||||
func odataListContains(r *http.Request, parameter, value string) bool {
|
||||
for _, values := range r.URL.Query()[parameter] {
|
||||
@@ -253,6 +256,7 @@ func (g Graph) GetRootDriveChildren(w http.ResponseWriter, r *http.Request) {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
g.setDriveItemsThumbnails(r, files, lRes.GetInfos())
|
||||
|
||||
if driveItemPropertySelected(r, _selectAllowedValues) {
|
||||
for i, info := range lRes.GetInfos() {
|
||||
@@ -346,6 +350,10 @@ func (g Graph) GetDriveItem(w http.ResponseWriter, r *http.Request) {
|
||||
driveItem.LibreGraphShareTypes = shareTypesOf(res.GetInfo(), g.listLinkShares(ctx, infos))
|
||||
}
|
||||
|
||||
if driveItemRelationExpanded(r, _expandThumbnails) {
|
||||
setDriveItemThumbnails(driveItem, res.GetInfo(), g.config.Commons.OpenCloudURL)
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, &driveItem)
|
||||
}
|
||||
@@ -432,6 +440,8 @@ func (g Graph) listDriveItemChildren(w http.ResponseWriter, r *http.Request, dri
|
||||
g.addShareTypes(r.Context(), files, res.GetInfos())
|
||||
}
|
||||
|
||||
g.setDriveItemsThumbnails(r, files, res.GetInfos())
|
||||
|
||||
return files, true
|
||||
}
|
||||
|
||||
|
||||
@@ -208,6 +208,40 @@ var _ = Describe("Driveitems", func() {
|
||||
Expect(res.Value[0].LibreGraphPermissionsActionsAllowedValues).To(BeNil())
|
||||
})
|
||||
|
||||
It("returns the thumbnails when requested via $expand", func() {
|
||||
cfg.Commons.OpenCloudURL = "https://cloud.test"
|
||||
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&provider.ListStorageSpacesResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
StorageSpaces: []*provider.StorageSpace{{Owner: currentUser, Root: &provider.ResourceId{}}},
|
||||
}, nil)
|
||||
gatewayClient.On("ListContainer", mock.Anything, mock.Anything).Return(&provider.ListContainerResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
Infos: []*provider.ResourceInfo{
|
||||
{
|
||||
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
|
||||
Id: &provider.ResourceId{StorageId: "storageid", SpaceId: "spaceid", OpaqueId: "opaqueid"},
|
||||
MimeType: "image/jpeg",
|
||||
Mtime: utils.TimeToTS(time.Now()),
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drive/root/children?$expand=thumbnails", nil)
|
||||
r = r.WithContext(revactx.ContextSetUser(ctx, currentUser))
|
||||
svc.GetRootDriveChildren(rr, r)
|
||||
Expect(rr.Code).To(Equal(http.StatusOK))
|
||||
data, err := io.ReadAll(rr.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
res := itemsList{}
|
||||
Expect(json.Unmarshal(data, &res)).To(Succeed())
|
||||
Expect(len(res.Value)).To(Equal(1))
|
||||
Expect(res.Value[0].Thumbnails).To(HaveLen(1))
|
||||
Expect(res.Value[0].Thumbnails[0].Small.GetUrl()).To(Equal(
|
||||
"https://cloud.test/dav/spaces/storageid$spaceid!opaqueid" +
|
||||
"?scalingup=0&preview=1&processor=thumbnail&x=36&y=36",
|
||||
))
|
||||
})
|
||||
|
||||
It("returns the allowed actions when requested via $select", func() {
|
||||
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&provider.ListStorageSpacesResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
@@ -248,6 +282,7 @@ var _ = Describe("Driveitems", func() {
|
||||
Describe("GetDriveItem", func() {
|
||||
var (
|
||||
folderInfo *provider.ResourceInfo
|
||||
childInfo *provider.ResourceInfo
|
||||
mtime = time.Now()
|
||||
)
|
||||
|
||||
@@ -281,16 +316,15 @@ var _ = Describe("Driveitems", func() {
|
||||
Status: status.NewOK(ctx),
|
||||
Info: folderInfo,
|
||||
}, nil)
|
||||
childInfo = &provider.ResourceInfo{
|
||||
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
|
||||
Id: &provider.ResourceId{StorageId: "storageid", SpaceId: "spaceid", OpaqueId: "opaqueid"},
|
||||
Etag: "etag",
|
||||
Mtime: utils.TimeToTS(mtime),
|
||||
}
|
||||
gatewayClient.On("ListContainer", mock.Anything, mock.Anything).Return(&provider.ListContainerResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
Infos: []*provider.ResourceInfo{
|
||||
{
|
||||
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
|
||||
Id: &provider.ResourceId{StorageId: "storageid", SpaceId: "spaceid", OpaqueId: "opaqueid"},
|
||||
Etag: "etag",
|
||||
Mtime: utils.TimeToTS(mtime),
|
||||
},
|
||||
},
|
||||
Infos: []*provider.ResourceInfo{childInfo},
|
||||
}, nil)
|
||||
})
|
||||
|
||||
@@ -312,6 +346,49 @@ var _ = Describe("Driveitems", func() {
|
||||
Expect(getItem(newRequest("?$expand=children")).Children).To(BeNil())
|
||||
gatewayClient.AssertNotCalled(GinkgoT(), "ListContainer", mock.Anything, mock.Anything)
|
||||
})
|
||||
|
||||
Context("$expand=thumbnails", func() {
|
||||
const previewURL = "https://cloud.test/dav/spaces/storageid$spaceid!nodeid" +
|
||||
"?scalingup=0&preview=1&processor=thumbnail"
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg.Commons.OpenCloudURL = "https://cloud.test"
|
||||
folderInfo.Type = provider.ResourceType_RESOURCE_TYPE_FILE
|
||||
folderInfo.MimeType = "image/jpeg"
|
||||
})
|
||||
|
||||
It("leaves thumbnails unset without $expand", func() {
|
||||
Expect(getItem(newRequest("")).Thumbnails).To(BeNil())
|
||||
})
|
||||
|
||||
It("returns the thumbnail urls when requested", func() {
|
||||
thumbnails := getItem(newRequest("?$expand=thumbnails")).Thumbnails
|
||||
|
||||
Expect(thumbnails).To(HaveLen(1))
|
||||
Expect(thumbnails[0].Small.GetUrl()).To(Equal(previewURL + "&x=36&y=36"))
|
||||
Expect(thumbnails[0].Medium.GetUrl()).To(Equal(previewURL + "&x=48&y=48"))
|
||||
Expect(thumbnails[0].Large.GetUrl()).To(Equal(previewURL + "&x=96&y=96"))
|
||||
})
|
||||
|
||||
It("leaves thumbnails unset for a mime type the thumbnailer cannot render", func() {
|
||||
folderInfo.MimeType = "application/zip"
|
||||
|
||||
Expect(getItem(newRequest("?$expand=thumbnails")).Thumbnails).To(BeNil())
|
||||
})
|
||||
|
||||
It("adds them to expanded children as well", func() {
|
||||
folderInfo.Type = provider.ResourceType_RESOURCE_TYPE_CONTAINER
|
||||
folderInfo.MimeType = ""
|
||||
childInfo.MimeType = "image/jpeg"
|
||||
|
||||
item := getItem(newRequest("?$expand=children,thumbnails"))
|
||||
|
||||
// a folder has no preview of its own
|
||||
Expect(item.Thumbnails).To(BeNil())
|
||||
Expect(item.Children).To(HaveLen(1))
|
||||
Expect(item.Children[0].Thumbnails).To(HaveLen(1))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("GetDriveItem $expand=children error", func() {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
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"
|
||||
)
|
||||
@@ -44,30 +42,8 @@ func (g Graph) GetSharedByMe(w http.ResponseWriter, r *http.Request) {
|
||||
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
|
||||
}
|
||||
setShareThumbnails(&item, item.GetId(), g.config.Commons.OpenCloudURL)
|
||||
driveItems[k] = item
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package svc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@@ -13,7 +12,6 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/share"
|
||||
|
||||
"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.
|
||||
@@ -73,30 +71,8 @@ func (g Graph) listSharedWithMe(ctx context.Context, expandThumbnails bool) ([]l
|
||||
|
||||
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
|
||||
}
|
||||
setShareThumbnails(&item, item.RemoteItem.GetId(), g.config.Commons.OpenCloudURL)
|
||||
driveItems[k] = item
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/services/thumbnails/pkg/thumbnail"
|
||||
)
|
||||
|
||||
const (
|
||||
thumbnailBoxSmall = 36
|
||||
thumbnailBoxMedium = 48
|
||||
thumbnailBoxLarge = 96
|
||||
)
|
||||
|
||||
func (g Graph) setDriveItemsThumbnails(r *http.Request, items []libregraph.DriveItem, infos []*provider.ResourceInfo) {
|
||||
if !driveItemRelationExpanded(r, _expandThumbnails) {
|
||||
return
|
||||
}
|
||||
for i := range items {
|
||||
if i < len(infos) {
|
||||
setDriveItemThumbnails(&items[i], infos[i], g.config.Commons.OpenCloudURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setDriveItemThumbnails(item *libregraph.DriveItem, res *provider.ResourceInfo, baseURL string) {
|
||||
if set := previewThumbnailSet(res, baseURL); set != nil {
|
||||
item.SetThumbnails([]libregraph.ThumbnailSet{*set})
|
||||
}
|
||||
}
|
||||
|
||||
// previewThumbnailSet returns nil when the thumbnailer cannot render the resource.
|
||||
func previewThumbnailSet(res *provider.ResourceInfo, baseURL string) *libregraph.ThumbnailSet {
|
||||
if !thumbnail.IsMimeTypeSupported(res.GetMimeType()) {
|
||||
return nil
|
||||
}
|
||||
return thumbnailSetFor(baseURL, storagespace.FormatResourceID(res.GetId()))
|
||||
}
|
||||
|
||||
// thumbnailSetFor builds the urls of the WebDAV preview endpoint.
|
||||
func thumbnailSetFor(baseURL, itemID string) *libregraph.ThumbnailSet {
|
||||
base := fmt.Sprintf("%s/dav/spaces/%s?scalingup=0&preview=1&processor=thumbnail", baseURL, itemID)
|
||||
return &libregraph.ThumbnailSet{
|
||||
Small: previewThumbnail(base, thumbnailBoxSmall),
|
||||
Medium: previewThumbnail(base, thumbnailBoxMedium),
|
||||
Large: previewThumbnail(base, thumbnailBoxLarge),
|
||||
}
|
||||
}
|
||||
|
||||
func previewThumbnail(base string, box int32) *libregraph.Thumbnail {
|
||||
url := fmt.Sprintf("%s&x=%d&y=%d", base, box, box)
|
||||
return &libregraph.Thumbnail{Url: &url}
|
||||
}
|
||||
|
||||
// setShareThumbnails works off the driveItem, the share listings have no resource
|
||||
// info. The id comes separately, a received share carries it on its remote item.
|
||||
func setShareThumbnails(item *libregraph.DriveItem, itemID, baseURL string) {
|
||||
mimeType := item.GetFile().MimeType
|
||||
if itemID == "" || mimeType == nil || !thumbnail.IsMimeTypeSupported(*mimeType) {
|
||||
return
|
||||
}
|
||||
item.SetThumbnails([]libregraph.ThumbnailSet{*thumbnailSetFor(baseURL, itemID)})
|
||||
}
|
||||
Reference in new issue
Block a user