Files
opencloud/services/graph/pkg/service/v0/api_driveitem_permissions.go
T
jkoberg b174b005e7 remove resharing
Signed-off-by: jkoberg <jkoberg@owncloud.com>
2024-04-05 10:19:14 +02:00

691 lines
26 KiB
Go

package svc
import (
"context"
"net/http"
"net/url"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/publicshare"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/share"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
libregraph "github.com/owncloud/libre-graph-api-go"
"github.com/owncloud/ocis/v2/ocis-pkg/conversions"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
"github.com/owncloud/ocis/v2/services/graph/pkg/validate"
)
const (
invalidIdMsg = "invalid driveID or itemID"
parseDriveIDErrMsg = "could not parse driveID"
)
// DriveItemPermissionsProvider contains the methods related to handling permissions on drive items
type DriveItemPermissionsProvider interface {
Invite(ctx context.Context, resourceId storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error)
SpaceRootInvite(ctx context.Context, driveID storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error)
ListPermissions(ctx context.Context, itemID storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)
ListSpaceRootPermissions(ctx context.Context, driveID storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)
DeletePermission(ctx context.Context, itemID storageprovider.ResourceId, permissionID string) error
DeleteSpaceRootPermission(ctx context.Context, driveID storageprovider.ResourceId, permissionID string) error
UpdatePermission(ctx context.Context, itemID storageprovider.ResourceId, permissionID string, newPermission libregraph.Permission) (libregraph.Permission, error)
UpdateSpaceRootPermission(ctx context.Context, driveID storageprovider.ResourceId, permissionID string, newPermission libregraph.Permission) (libregraph.Permission, error)
CreateLink(ctx context.Context, driveItemID storageprovider.ResourceId, createLink libregraph.DriveItemCreateLink) (libregraph.Permission, error)
CreateSpaceRootLink(ctx context.Context, driveID storageprovider.ResourceId, createLink libregraph.DriveItemCreateLink) (libregraph.Permission, error)
SetPublicLinkPassword(ctx context.Context, driveItemID storageprovider.ResourceId, permissionID string, password string) (libregraph.Permission, error)
SetPublicLinkPasswordOnSpaceRoot(ctx context.Context, driveID storageprovider.ResourceId, permissionID string, password string) (libregraph.Permission, error)
}
// DriveItemPermissionsService contains the production business logic for everything that relates to permissions on drive items.
type DriveItemPermissionsService struct {
BaseGraphService
}
type permissionType int
const (
Unknown permissionType = iota
Public
User
Space
)
// NewDriveItemPermissionsService creates a new DriveItemPermissionsService
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, config *config.Config) (DriveItemPermissionsService, error) {
return DriveItemPermissionsService{
BaseGraphService: BaseGraphService{
logger: &log.Logger{Logger: logger.With().Str("graph api", "DrivesDriveItemService").Logger()},
gatewaySelector: gatewaySelector,
identityCache: identityCache,
config: config,
},
}, nil
}
// Invite invites a user to a drive item.
func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error) {
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return libregraph.Permission{}, err
}
statResponse, err := gatewayClient.Stat(ctx, &storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: &resourceId}})
if errCode := errorcode.FromStat(statResponse, err); errCode != nil {
s.logger.Warn().Err(errCode).Interface("stat.res", statResponse).Msg("stat failed")
return libregraph.Permission{}, *errCode
}
resourceInfo := statResponse.GetInfo()
condition := unifiedrole.UnifiedRoleConditionGrantee
if IsSpaceRoot(resourceInfo.GetId()) {
condition = unifiedrole.UnifiedRoleConditionOwner
}
unifiedRolePermissions := []*libregraph.UnifiedRolePermission{{AllowedResourceActions: invite.LibreGraphPermissionsActions}}
for _, roleID := range invite.GetRoles() {
role, err := unifiedrole.NewUnifiedRoleFromID(roleID)
if err != nil {
s.logger.Debug().Err(err).Interface("role", invite.GetRoles()[0]).Msg("unable to convert requested role")
return libregraph.Permission{}, err
}
allowedResourceActions := unifiedrole.GetAllowedResourceActions(role, condition)
if len(allowedResourceActions) == 0 {
return libregraph.Permission{}, errorcode.New(errorcode.InvalidRequest, "role not applicable to this resource")
}
unifiedRolePermissions = append(unifiedRolePermissions, conversions.ToPointerSlice(role.GetRolePermissions())...)
}
driveRecipient := invite.GetRecipients()[0]
objectID := driveRecipient.GetObjectId()
cs3ResourcePermissions := unifiedrole.PermissionsToCS3ResourcePermissions(unifiedRolePermissions)
createShareRequest := &collaboration.CreateShareRequest{
ResourceInfo: resourceInfo,
Grant: &collaboration.ShareGrant{
Permissions: &collaboration.SharePermissions{
Permissions: cs3ResourcePermissions,
},
},
}
permission := &libregraph.Permission{}
if role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(*cs3ResourcePermissions, condition); role != nil {
permission.Roles = []string{role.GetId()}
}
if len(permission.GetRoles()) == 0 {
permission.LibreGraphPermissionsActions = unifiedrole.CS3ResourcePermissionsToLibregraphActions(*cs3ResourcePermissions)
}
switch driveRecipient.GetLibreGraphRecipientType() {
case "group":
group, err := s.identityCache.GetGroup(ctx, objectID)
if err != nil {
s.logger.Debug().Err(err).Interface("groupId", objectID).Msg("failed group lookup")
return libregraph.Permission{}, errorcode.New(errorcode.InvalidRequest, err.Error())
}
createShareRequest.GetGrant().Grantee = &storageprovider.Grantee{
Type: storageprovider.GranteeType_GRANTEE_TYPE_GROUP,
Id: &storageprovider.Grantee_GroupId{GroupId: &grouppb.GroupId{
OpaqueId: group.GetId(),
}},
}
permission.GrantedToV2 = &libregraph.SharePointIdentitySet{
Group: &libregraph.Identity{
DisplayName: group.GetDisplayName(),
Id: conversions.ToPointer(group.GetId()),
},
}
default:
user, err := s.identityCache.GetUser(ctx, objectID)
if err != nil {
s.logger.Debug().Err(err).Interface("userId", objectID).Msg("failed user lookup")
return libregraph.Permission{}, errorcode.New(errorcode.InvalidRequest, err.Error())
}
createShareRequest.GetGrant().Grantee = &storageprovider.Grantee{
Type: storageprovider.GranteeType_GRANTEE_TYPE_USER,
Id: &storageprovider.Grantee_UserId{UserId: &userpb.UserId{
OpaqueId: user.GetId(),
}},
}
permission.GrantedToV2 = &libregraph.SharePointIdentitySet{
User: &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: conversions.ToPointer(user.GetId()),
},
}
}
if invite.ExpirationDateTime != nil {
createShareRequest.GetGrant().Expiration = utils.TimeToTS(*invite.ExpirationDateTime)
}
createShareResponse, err := gatewayClient.CreateShare(ctx, createShareRequest)
if errCode := errorcode.FromCS3Status(createShareResponse.GetStatus(), err); errCode != nil {
s.logger.Debug().Err(err).Msg("share creation failed")
return libregraph.Permission{}, *errCode
}
if id := createShareResponse.GetShare().GetId().GetOpaqueId(); id != "" {
permission.Id = conversions.ToPointer(id)
} else if IsSpaceRoot(resourceInfo.GetId()) {
// permissions on a space root are not handled by a share manager so
// they don't get a share-id
permission.SetId(identitySetToSpacePermissionID(permission.GetGrantedToV2()))
}
if expiration := createShareResponse.GetShare().GetExpiration(); expiration != nil {
permission.SetExpirationDateTime(utils.TSToTime(expiration))
}
return *permission, nil
}
// SpaceRootInvite handles invitation request on project spaces
func (s DriveItemPermissionsService) SpaceRootInvite(ctx context.Context, driveID storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error) {
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return libregraph.Permission{}, err
}
space, err := utils.GetSpace(ctx, storagespace.FormatResourceID(driveID), gatewayClient)
if err != nil {
return libregraph.Permission{}, err
}
if space.SpaceType != _spaceTypeProject {
return libregraph.Permission{}, errorcode.New(errorcode.InvalidRequest, "unsupported space type")
}
rootResourceID := space.GetRoot()
return s.Invite(ctx, *rootResourceID, invite)
}
// ListPermissions lists the permissions of a driveItem
func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
collectionOfPermissions := libregraph.CollectionOfPermissionsWithAllowedValues{}
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return collectionOfPermissions, err
}
statResponse, err := gatewayClient.Stat(ctx, &storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: &itemID}})
if errCode := errorcode.FromStat(statResponse, err); errCode != nil {
s.logger.Warn().Err(errCode).Interface("stat.res", statResponse).Msg("stat failed")
return collectionOfPermissions, err
}
condition := unifiedrole.UnifiedRoleConditionGrantee
if IsSpaceRoot(statResponse.GetInfo().GetId()) {
condition = unifiedrole.UnifiedRoleConditionOwner
}
permissionSet := *statResponse.GetInfo().GetPermissionSet()
allowedActions := unifiedrole.CS3ResourcePermissionsToLibregraphActions(permissionSet)
collectionOfPermissions = libregraph.CollectionOfPermissionsWithAllowedValues{
LibreGraphPermissionsActionsAllowedValues: allowedActions,
LibreGraphPermissionsRolesAllowedValues: conversions.ToValueSlice(
unifiedrole.GetApplicableRoleDefinitionsForActions(
allowedActions,
condition,
false,
),
),
}
for i, definition := range collectionOfPermissions.LibreGraphPermissionsRolesAllowedValues {
// the openapi spec defines that the rolePermissions should not be part of the response
definition.RolePermissions = nil
collectionOfPermissions.LibreGraphPermissionsRolesAllowedValues[i] = definition
}
driveItems := make(driveItemsByResourceID)
if IsSpaceRoot(statResponse.GetInfo().GetId()) {
permissions, err := s.getSpaceRootPermissions(ctx, statResponse.GetInfo().GetSpace().GetId())
if err != nil {
return collectionOfPermissions, err
}
collectionOfPermissions.Value = permissions
} else {
// "normal" driveItem, populate user permissions via share providers
driveItems, err = s.listUserShares(ctx, []*collaboration.Filter{
share.ResourceIDFilter(conversions.ToPointer(itemID)),
}, driveItems)
if err != nil {
return collectionOfPermissions, err
}
}
// finally get public shares, which are possible for spaceroots and "normal" resources
driveItems, err = s.listPublicShares(ctx, []*link.ListPublicSharesRequest_Filter{
publicshare.ResourceIDFilter(conversions.ToPointer(itemID)),
}, driveItems)
if err != nil {
return collectionOfPermissions, err
}
for _, driveItem := range driveItems {
collectionOfPermissions.Value = append(collectionOfPermissions.Value, driveItem.Permissions...)
}
return collectionOfPermissions, nil
}
// ListSpaceRootPermissions handles ListPermissions request on project spaces
func (s DriveItemPermissionsService) ListSpaceRootPermissions(ctx context.Context, driveID storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
collectionOfPermissions := libregraph.CollectionOfPermissionsWithAllowedValues{}
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return collectionOfPermissions, err
}
space, err := utils.GetSpace(ctx, storagespace.FormatResourceID(driveID), gatewayClient)
if err != nil {
return collectionOfPermissions, err
}
if space.SpaceType != _spaceTypeProject {
return collectionOfPermissions, errorcode.New(errorcode.InvalidRequest, "unsupported space type")
}
rootResourceID := space.GetRoot()
return s.ListPermissions(ctx, *rootResourceID)
}
// DeletePermission deletes a permission from a drive item
func (s DriveItemPermissionsService) DeletePermission(ctx context.Context, itemID storageprovider.ResourceId, permissionID string) error {
var permissionType permissionType
sharedResourceID, err := s.getLinkPermissionResourceID(ctx, permissionID)
switch {
// Check if the ID is referring to a public share
case err == nil:
permissionType = Public
// If the item id is referring to a space root and this is not a public share
// we have to deal with space permissions
case IsSpaceRoot(&itemID):
permissionType = Space
sharedResourceID = &itemID
err = nil
// If this is neither a public share nor a space permission, check if this is a
// user share
default:
sharedResourceID, err = s.getUserPermissionResourceID(ctx, permissionID)
if err == nil {
permissionType = User
}
}
switch {
case err != nil:
return err
case permissionType == Unknown:
return errorcode.New(errorcode.ItemNotFound, "permission not found")
case sharedResourceID == nil:
return errorcode.New(errorcode.ItemNotFound, "failed to resolve resource id for shared resource")
}
// The resourceID of the shared resource need to match the item ID from the Request Path
// otherwise this is an invalid Request.
if !utils.ResourceIDEqual(sharedResourceID, &itemID) {
s.logger.Debug().Msg("resourceID of shared does not match itemID")
return errorcode.New(errorcode.InvalidRequest, "permissionID and itemID do not match")
}
switch permissionType {
case User:
return s.removeUserShare(ctx, permissionID)
case Public:
return s.removePublicShare(ctx, permissionID)
case Space:
return s.removeSpacePermission(ctx, permissionID, sharedResourceID)
}
// This should never be reached
return errorcode.New(errorcode.GeneralException, "failed to delete permission")
}
// DeleteSpaceRootPermission deletes a permission on the root item of a project space
func (s DriveItemPermissionsService) DeleteSpaceRootPermission(ctx context.Context, driveID storageprovider.ResourceId, permissionID string) error {
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return err
}
space, err := utils.GetSpace(ctx, storagespace.FormatResourceID(driveID), gatewayClient)
if err != nil {
return err
}
if space.SpaceType != _spaceTypeProject {
return errorcode.New(errorcode.InvalidRequest, "unsupported space type")
}
rootResourceID := space.GetRoot()
return s.DeletePermission(ctx, *rootResourceID, permissionID)
}
// UpdatePermission updates a permission on a drive item
func (s DriveItemPermissionsService) UpdatePermission(ctx context.Context, itemID storageprovider.ResourceId, permissionID string, newPermission libregraph.Permission) (libregraph.Permission, error) {
oldPermission, sharedResourceID, err := s.getPermissionByID(ctx, permissionID, &itemID)
if err != nil {
return libregraph.Permission{}, err
}
// The resourceID of the shared resource need to match the item ID from the Request Path
// otherwise this is an invalid Request.
if !utils.ResourceIDEqual(sharedResourceID, &itemID) {
s.logger.Debug().Msg("resourceID of shared does not match itemID")
return libregraph.Permission{}, errorcode.New(errorcode.InvalidRequest, "permissionID and itemID do not match")
}
// This is a public link
if _, ok := oldPermission.GetLinkOk(); ok {
updatedPermission, err := s.updatePublicLinkPermission(ctx, permissionID, &itemID, &newPermission)
if err != nil {
return libregraph.Permission{}, err
}
return *updatedPermission, nil
}
// This is a user share
updatedPermission, err := s.updateUserShare(ctx, permissionID, sharedResourceID, &newPermission)
if err != nil {
return libregraph.Permission{}, err
}
return *updatedPermission, nil
}
// UpdateSpaceRootPermission updates a permission on the root item of a project space
func (s DriveItemPermissionsService) UpdateSpaceRootPermission(ctx context.Context, driveID storageprovider.ResourceId, permissionID string, newPermission libregraph.Permission) (libregraph.Permission, error) {
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return libregraph.Permission{}, err
}
space, err := utils.GetSpace(ctx, storagespace.FormatResourceID(driveID), gatewayClient)
if err != nil {
return libregraph.Permission{}, err
}
if space.SpaceType != _spaceTypeProject {
return libregraph.Permission{}, errorcode.New(errorcode.InvalidRequest, "unsupported space type")
}
rootResourceID := space.GetRoot()
return s.UpdatePermission(ctx, *rootResourceID, permissionID, newPermission)
}
// DriveItemPermissionsService is the api that registers the http endpoints which expose needed operation to the graph api.
// the business logic is delegated to the permissions service and further down to the cs3 client.
type DriveItemPermissionsApi struct {
logger log.Logger
driveItemPermissionsService DriveItemPermissionsProvider
}
// NewDriveItemPermissionsApi creates a new DriveItemPermissionsApi
func NewDriveItemPermissionsApi(driveItemPermissionService DriveItemPermissionsProvider, logger log.Logger) (DriveItemPermissionsApi, error) {
return DriveItemPermissionsApi{
logger: log.Logger{Logger: logger.With().Str("graph api", "DrivesDriveItemApi").Logger()},
driveItemPermissionsService: driveItemPermissionService,
}, nil
}
// Invite handles DriveItemInvite requests
func (api DriveItemPermissionsApi) Invite(w http.ResponseWriter, r *http.Request) {
_, itemID, err := GetDriveAndItemIDParam(r, &api.logger)
if err != nil {
api.logger.Debug().Err(err).Msg(invalidIdMsg)
errorcode.InvalidRequest.Render(w, r, http.StatusUnprocessableEntity, invalidIdMsg)
return
}
driveItemInvite := &libregraph.DriveItemInvite{}
if err = StrictJSONUnmarshal(r.Body, driveItemInvite); err != nil {
api.logger.Debug().Err(err).Interface("Body", r.Body).Msg("failed unmarshalling request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid request body")
return
}
ctx := r.Context()
if err = validate.StructCtx(ctx, driveItemInvite); err != nil {
api.logger.Debug().Err(err).Interface("Body", r.Body).Msg("invalid request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
return
}
permission, err := api.driveItemPermissionsService.Invite(ctx, itemID, *driveItemInvite)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusOK)
render.JSON(w, r, &ListResponse{Value: []interface{}{permission}})
}
// SpaceRootInvite handles DriveItemInvite requests on a space root
func (api DriveItemPermissionsApi) SpaceRootInvite(w http.ResponseWriter, r *http.Request) {
driveID, err := parseIDParam(r, "driveID")
if err != nil {
api.logger.Debug().Err(err).Msg(parseDriveIDErrMsg)
errorcode.InvalidRequest.Render(w, r, http.StatusUnprocessableEntity, parseDriveIDErrMsg)
return
}
driveItemInvite := &libregraph.DriveItemInvite{}
if err = StrictJSONUnmarshal(r.Body, driveItemInvite); err != nil {
api.logger.Debug().Err(err).Interface("Body", r.Body).Msg("failed unmarshalling request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid request body")
return
}
ctx := r.Context()
if err = validate.StructCtx(ctx, driveItemInvite); err != nil {
api.logger.Debug().Err(err).Interface("Body", r.Body).Msg("invalid request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
return
}
permission, err := api.driveItemPermissionsService.SpaceRootInvite(ctx, driveID, *driveItemInvite)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusOK)
render.JSON(w, r, &ListResponse{Value: []interface{}{permission}})
}
// ListPermissions handles ListPermissions requests
func (api DriveItemPermissionsApi) ListPermissions(w http.ResponseWriter, r *http.Request) {
_, itemID, err := GetDriveAndItemIDParam(r, &api.logger)
if err != nil {
api.logger.Debug().Err(err).Msg(invalidIdMsg)
errorcode.RenderError(w, r, err)
return
}
ctx := r.Context()
permissions, err := api.driveItemPermissionsService.ListPermissions(ctx, itemID)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusOK)
render.JSON(w, r, permissions)
}
// ListSpaceRootPermissions handles ListPermissions requests on a space root
func (api DriveItemPermissionsApi) ListSpaceRootPermissions(w http.ResponseWriter, r *http.Request) {
driveID, err := parseIDParam(r, "driveID")
if err != nil {
api.logger.Debug().Err(err).Msg(parseDriveIDErrMsg)
errorcode.InvalidRequest.Render(w, r, http.StatusUnprocessableEntity, parseDriveIDErrMsg)
return
}
ctx := r.Context()
permissions, err := api.driveItemPermissionsService.ListSpaceRootPermissions(ctx, driveID)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusOK)
render.JSON(w, r, permissions)
}
// DeletePermission handles DeletePermission requests
func (api DriveItemPermissionsApi) DeletePermission(w http.ResponseWriter, r *http.Request) {
_, itemID, err := GetDriveAndItemIDParam(r, &api.logger)
if err != nil {
api.logger.Debug().Err(err).Msg(invalidIdMsg)
errorcode.RenderError(w, r, err)
return
}
permissionID, err := url.PathUnescape(chi.URLParam(r, "permissionID"))
if err != nil {
api.logger.Debug().Err(err).Msg("could not parse permissionID")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid permissionID")
return
}
ctx := r.Context()
err = api.driveItemPermissionsService.DeletePermission(ctx, itemID, permissionID)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusNoContent)
render.NoContent(w, r)
}
// DeleteSpaceRootPermission handles DeletePermission requests on a space root
func (api DriveItemPermissionsApi) DeleteSpaceRootPermission(w http.ResponseWriter, r *http.Request) {
driveID, err := parseIDParam(r, "driveID")
if err != nil {
api.logger.Debug().Err(err).Msg(parseDriveIDErrMsg)
errorcode.InvalidRequest.Render(w, r, http.StatusUnprocessableEntity, parseDriveIDErrMsg)
return
}
permissionID, err := url.PathUnescape(chi.URLParam(r, "permissionID"))
if err != nil {
api.logger.Debug().Err(err).Msg("could not parse permissionID")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid permissionID")
return
}
ctx := r.Context()
err = api.driveItemPermissionsService.DeleteSpaceRootPermission(ctx, driveID, permissionID)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusNoContent)
render.NoContent(w, r)
}
// UpdatePermission handles UpdatePermission requests
func (api DriveItemPermissionsApi) UpdatePermission(w http.ResponseWriter, r *http.Request) {
_, itemID, err := GetDriveAndItemIDParam(r, &api.logger)
if err != nil {
api.logger.Debug().Err(err).Msg(invalidIdMsg)
errorcode.RenderError(w, r, err)
return
}
permissionID, err := url.PathUnescape(chi.URLParam(r, "permissionID"))
if err != nil {
api.logger.Debug().Err(err).Msg("could not parse permissionID")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid permissionID")
return
}
permission := libregraph.Permission{}
if err = StrictJSONUnmarshal(r.Body, &permission); err != nil {
api.logger.Debug().Err(err).Interface("Body", r.Body).Msg("failed unmarshalling request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid request body")
return
}
ctx := r.Context()
if err = validate.StructCtx(ctx, permission); err != nil {
api.logger.Debug().Err(err).Interface("Body", r.Body).Msg("invalid request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
return
}
updatedPermission, err := api.driveItemPermissionsService.UpdatePermission(ctx, itemID, permissionID, permission)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusOK)
render.JSON(w, r, &updatedPermission)
}
// UpdateSpaceRootPermission handles UpdatePermission requests on a space root
func (api DriveItemPermissionsApi) UpdateSpaceRootPermission(w http.ResponseWriter, r *http.Request) {
driveID, err := parseIDParam(r, "driveID")
if err != nil {
api.logger.Debug().Err(err).Msg(parseDriveIDErrMsg)
errorcode.InvalidRequest.Render(w, r, http.StatusUnprocessableEntity, parseDriveIDErrMsg)
return
}
permissionID, err := url.PathUnescape(chi.URLParam(r, "permissionID"))
if err != nil {
api.logger.Debug().Err(err).Msg("could not parse permissionID")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid permissionID")
return
}
permission := libregraph.Permission{}
if err = StrictJSONUnmarshal(r.Body, &permission); err != nil {
api.logger.Debug().Err(err).Interface("Body", r.Body).Msg("failed unmarshalling request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid request body")
return
}
ctx := r.Context()
if err = validate.StructCtx(ctx, permission); err != nil {
api.logger.Debug().Err(err).Interface("Body", r.Body).Msg("invalid request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
return
}
updatedPermission, err := api.driveItemPermissionsService.UpdateSpaceRootPermission(ctx, driveID, permissionID, permission)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusOK)
render.JSON(w, r, &updatedPermission)
}