feat(api): add new sharing NG create link feature
This commit is contained in:
committed by
Florian Schade
parent
02c6e8f4b8
commit
c035fc80a9
@@ -0,0 +1,141 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/go-chi/render"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/linktype"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
|
||||
)
|
||||
|
||||
func (g Graph) CreateLink(w http.ResponseWriter, r *http.Request) {
|
||||
logger := g.logger.SubloggerWithRequestID(r.Context())
|
||||
logger.Info().Msg("calling create link")
|
||||
driveID, err := parseIDParam(r, "driveID")
|
||||
if err != nil {
|
||||
errorcode.RenderError(w, r, err)
|
||||
return
|
||||
}
|
||||
driveItemID, err := parseIDParam(r, "itemID")
|
||||
if err != nil {
|
||||
errorcode.RenderError(w, r, err)
|
||||
return
|
||||
}
|
||||
if driveID.StorageId != driveItemID.StorageId || driveID.SpaceId != driveItemID.SpaceId {
|
||||
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "Item does not exist")
|
||||
return
|
||||
}
|
||||
var createLink libregraph.DriveItemCreateLink
|
||||
if err := StrictJSONUnmarshal(r.Body, &createLink); err != nil {
|
||||
logger.Error().Err(err).Interface("body", r.Body).Msg("could not create link: invalid body schema definition")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid body schema definition")
|
||||
return
|
||||
}
|
||||
|
||||
createdLink, err := g.createLink(r.Context(), &driveItemID, createLink)
|
||||
if err != nil {
|
||||
errorcode.RenderError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
perm, err := g.libreGraphPermissionFromCS3PublicShare(createdLink)
|
||||
if err != nil {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusCreated)
|
||||
render.JSON(w, r, []libregraph.Permission{*perm})
|
||||
}
|
||||
|
||||
func (g Graph) createLink(ctx context.Context, driveItemID *providerv1beta1.ResourceId, createLink libregraph.DriveItemCreateLink) (*link.PublicShare, error) {
|
||||
gatewayClient, err := g.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("could not select next gateway client")
|
||||
return nil, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
|
||||
statResp, err := gatewayClient.Stat(
|
||||
ctx,
|
||||
&providerv1beta1.StatRequest{
|
||||
Ref: &providerv1beta1.Reference{
|
||||
ResourceId: driveItemID,
|
||||
Path: ".",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("transport error, could not stat resource")
|
||||
return nil, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
if code := statResp.GetStatus().GetCode(); code != rpc.Code_CODE_OK {
|
||||
g.logger.Debug().Interface("itemID", driveItemID).Msg(statResp.GetStatus().GetMessage())
|
||||
return nil, errorcode.New(cs3StatusToErrCode(code), statResp.GetStatus().GetMessage())
|
||||
}
|
||||
permissions, err := linktype.CS3ResourcePermissionsFromSharingLink(createLink, statResp.GetInfo().GetType())
|
||||
if err != nil {
|
||||
g.logger.Debug().Interface("createLink", createLink).Msg(err.Error())
|
||||
return nil, errorcode.New(errorcode.InvalidRequest, "invalid link type")
|
||||
}
|
||||
req := link.CreatePublicShareRequest{
|
||||
ResourceInfo: statResp.GetInfo(),
|
||||
Grant: &link.Grant{
|
||||
Permissions: &link.PublicSharePermissions{
|
||||
Permissions: permissions,
|
||||
},
|
||||
Password: createLink.GetPassword(),
|
||||
},
|
||||
}
|
||||
// set displayname and password protected as arbitrary metadata
|
||||
req.ResourceInfo.ArbitraryMetadata = &providerv1beta1.ArbitraryMetadata{
|
||||
Metadata: map[string]string{
|
||||
"name": createLink.GetDisplayName(),
|
||||
"quicklink": strconv.FormatBool(createLink.GetLibreGraphQuickLink()),
|
||||
},
|
||||
}
|
||||
createResp, err := gatewayClient.CreatePublicShare(ctx, &req)
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("transport error, could not create link")
|
||||
return nil, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
if statusCode := createResp.GetStatus().GetCode(); statusCode != rpc.Code_CODE_OK {
|
||||
return nil, errorcode.New(cs3StatusToErrCode(statusCode), createResp.Status.Message)
|
||||
}
|
||||
return createResp.GetShare(), nil
|
||||
}
|
||||
|
||||
func (g Graph) libreGraphPermissionFromCS3PublicShare(createdLink *link.PublicShare) (*libregraph.Permission, error) {
|
||||
webURL, err := url.Parse(g.config.Spaces.WebDavBase)
|
||||
if err != nil {
|
||||
g.logger.Error().
|
||||
Err(err).
|
||||
Str("url", g.config.Spaces.WebDavBase).
|
||||
Msg("failed to parse webURL base url")
|
||||
return nil, err
|
||||
}
|
||||
lt, actions := linktype.SharingLinkTypeFromCS3Permissions(createdLink.GetPermissions())
|
||||
perm := libregraph.NewPermission()
|
||||
perm.Id = libregraph.PtrString(createdLink.GetId().GetOpaqueId())
|
||||
perm.Link = &libregraph.SharingLink{
|
||||
Type: lt,
|
||||
PreventsDownload: libregraph.PtrBool(false),
|
||||
LibreGraphDisplayName: libregraph.PtrString(createdLink.GetDisplayName()),
|
||||
LibreGraphQuickLink: libregraph.PtrBool(createdLink.GetQuicklink()),
|
||||
}
|
||||
perm.LibreGraphPermissionsActions = actions
|
||||
webURL.Path = path.Join(webURL.Path, "s", createdLink.GetToken())
|
||||
perm.Link.SetWebUrl(webURL.String())
|
||||
|
||||
// set expiration date
|
||||
if createdLink.GetExpiration() != nil {
|
||||
perm.SetExpirationDateTime(cs3TimestampToTime(createdLink.GetExpiration()))
|
||||
}
|
||||
return perm, nil
|
||||
}
|
||||
@@ -107,6 +107,7 @@ type Service interface {
|
||||
GetRootDriveChildren(w http.ResponseWriter, r *http.Request)
|
||||
GetDriveItem(w http.ResponseWriter, r *http.Request)
|
||||
GetDriveItemChildren(w http.ResponseWriter, r *http.Request)
|
||||
CreateLink(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
Invite(w http.ResponseWriter, r *http.Request)
|
||||
DeletePermission(w http.ResponseWriter, r *http.Request)
|
||||
@@ -201,6 +202,7 @@ func NewService(opts ...Option) (Graph, error) {
|
||||
r.Get("/me/drive/sharedWithMe", svc.ListSharedWithMe)
|
||||
r.Route("/drives/{driveID}/items/{itemID}", func(r chi.Router) {
|
||||
r.Post("/invite", svc.Invite)
|
||||
r.Post("/createLink", svc.CreateLink)
|
||||
r.Delete("/permissions/{permissionID}", svc.DeletePermission)
|
||||
})
|
||||
r.Route("/roleManagement/permissions/roleDefinitions", func(r chi.Router) {
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
@@ -193,28 +191,13 @@ func (g Graph) cs3PublicSharesToDriveItems(ctx context.Context, shares []*link.P
|
||||
}
|
||||
item = *itemptr
|
||||
}
|
||||
perm := libregraph.Permission{}
|
||||
perm.SetRoles([]string{})
|
||||
perm.SetId(s.Id.OpaqueId)
|
||||
link := libregraph.SharingLink{}
|
||||
webURL, err := url.Parse(g.config.Spaces.WebDavBase)
|
||||
perm, err := g.libreGraphPermissionFromCS3PublicShare(s)
|
||||
if err != nil {
|
||||
g.logger.Error().
|
||||
Err(err).
|
||||
Str("url", g.config.Spaces.WebDavBase).
|
||||
Msg("failed to parse webURL base url")
|
||||
g.logger.Error().Err(err).Interface("Link", s.ResourceId).Msg("could not convert link to libregraph")
|
||||
return driveItems, err
|
||||
}
|
||||
|
||||
webURL.Path = path.Join(webURL.Path, "s", s.GetToken())
|
||||
link.SetWebUrl(webURL.String())
|
||||
perm.SetLink(link)
|
||||
// set expiration date
|
||||
if s.GetExpiration() != nil {
|
||||
perm.SetExpirationDateTime(cs3TimestampToTime(s.GetExpiration()))
|
||||
}
|
||||
|
||||
item.Permissions = append(item.Permissions, perm)
|
||||
item.Permissions = append(item.Permissions, *perm)
|
||||
driveItems[resIDStr] = item
|
||||
}
|
||||
|
||||
@@ -229,6 +212,8 @@ func cs3StatusToErrCode(code rpc.Code) (errcode errorcode.ErrorCode) {
|
||||
errcode = errorcode.AccessDenied
|
||||
case rpc.Code_CODE_NOT_FOUND:
|
||||
errcode = errorcode.ItemNotFound
|
||||
case rpc.Code_CODE_LOCKED:
|
||||
errcode = errorcode.ItemIsLocked
|
||||
default:
|
||||
errcode = errorcode.GeneralException
|
||||
}
|
||||
|
||||
@@ -23,11 +23,13 @@ import (
|
||||
cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
|
||||
"github.com/owncloud/ocis/v2/services/graph/mocks"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/config/defaults"
|
||||
identitymocks "github.com/owncloud/ocis/v2/services/graph/pkg/identity/mocks"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/linktype"
|
||||
service "github.com/owncloud/ocis/v2/services/graph/pkg/service/v0"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
|
||||
"github.com/stretchr/testify/mock"
|
||||
@@ -36,13 +38,15 @@ import (
|
||||
|
||||
var _ = Describe("sharedbyme", func() {
|
||||
var (
|
||||
svc service.Service
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
gatewayClient *cs3mocks.GatewayAPIClient
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
eventsPublisher mocks.Publisher
|
||||
identityBackend *identitymocks.Backend
|
||||
svc service.Service
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
gatewayClient *cs3mocks.GatewayAPIClient
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
eventsPublisher mocks.Publisher
|
||||
identityBackend *identitymocks.Backend
|
||||
driveItemCreateLink *libregraph.DriveItemCreateLink
|
||||
publicShare link.PublicShare
|
||||
|
||||
rr *httptest.ResponseRecorder
|
||||
)
|
||||
@@ -113,21 +117,29 @@ var _ = Describe("sharedbyme", func() {
|
||||
},
|
||||
Expiration: utils.TimeToTS(expiration),
|
||||
}
|
||||
|
||||
publicShare := link.PublicShare{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: "public-share-id",
|
||||
},
|
||||
Token: "public-share-token",
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
SpaceId: "spaceid",
|
||||
OpaqueId: "public-share-opaqueid",
|
||||
},
|
||||
}
|
||||
driveItemCreateLink = &libregraph.DriveItemCreateLink{}
|
||||
|
||||
BeforeEach(func() {
|
||||
eventsPublisher.On("Publish", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
linkType, err := libregraph.NewSharingLinkTypeFromValue("view")
|
||||
Expect(err).To(BeNil())
|
||||
driveItemCreateLink.Type = linkType
|
||||
driveItemCreateLink.ExpirationDateTime = libregraph.PtrTime(time.Now().Add(time.Hour))
|
||||
permissions, err := linktype.CS3ResourcePermissionsFromSharingLink(*driveItemCreateLink, provider.ResourceType_RESOURCE_TYPE_CONTAINER)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
publicShare = link.PublicShare{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: "public-share-id",
|
||||
},
|
||||
Token: "public-share-token",
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
SpaceId: "spaceid",
|
||||
OpaqueId: "public-share-opaqueid",
|
||||
},
|
||||
Permissions: &link.PublicSharePermissions{Permissions: permissions},
|
||||
}
|
||||
|
||||
rr = httptest.NewRecorder()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user