## Does this PR need a docs update or release note? - [ ] ⛔ No ## Type of change - [x] 🧹 Tech Debt/Cleanup ## Issue(s) * #1970 ## Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
226 lines
5.7 KiB
Go
226 lines
5.7 KiB
Go
package onedrive
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/alcionai/clues"
|
|
msdrive "github.com/microsoftgraph/msgraph-sdk-go/drive"
|
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/alcionai/corso/src/internal/connector/graph"
|
|
"github.com/alcionai/corso/src/internal/data"
|
|
"github.com/alcionai/corso/src/internal/version"
|
|
"github.com/alcionai/corso/src/pkg/path"
|
|
)
|
|
|
|
func getParentPermissions(
|
|
parentPath path.Path,
|
|
parentPermissions map[string][]UserPermission,
|
|
) ([]UserPermission, error) {
|
|
parentPerms, ok := parentPermissions[parentPath.String()]
|
|
if !ok {
|
|
onedrivePath, err := path.ToOneDrivePath(parentPath)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "invalid restore path")
|
|
}
|
|
|
|
if len(onedrivePath.Folders) != 0 {
|
|
return nil, errors.Wrap(err, "computing item permissions")
|
|
}
|
|
|
|
parentPerms = []UserPermission{}
|
|
}
|
|
|
|
return parentPerms, nil
|
|
}
|
|
|
|
func getParentAndCollectionPermissions(
|
|
ctx context.Context,
|
|
drivePath *path.DrivePath,
|
|
dc data.RestoreCollection,
|
|
permissions map[string][]UserPermission,
|
|
backupVersion int,
|
|
restorePerms bool,
|
|
) ([]UserPermission, []UserPermission, error) {
|
|
if !restorePerms || backupVersion < version.OneDrive1DataAndMetaFiles {
|
|
return nil, nil, nil
|
|
}
|
|
|
|
var (
|
|
err error
|
|
parentPerms []UserPermission
|
|
colPerms []UserPermission
|
|
collectionPath = dc.FullPath()
|
|
)
|
|
|
|
// Only get parent permissions if we're not restoring the root.
|
|
if len(drivePath.Folders) > 0 {
|
|
parentPath, err := collectionPath.Dir()
|
|
if err != nil {
|
|
return nil, nil, clues.Wrap(err, "getting parent path")
|
|
}
|
|
|
|
parentPerms, err = getParentPermissions(parentPath, permissions)
|
|
if err != nil {
|
|
return nil, nil, clues.Wrap(err, "getting parent permissions")
|
|
}
|
|
}
|
|
|
|
if backupVersion < version.OneDrive4DirIncludesPermissions {
|
|
colPerms, err = getParentPermissions(collectionPath, permissions)
|
|
if err != nil {
|
|
return nil, nil, clues.Wrap(err, "getting collection permissions")
|
|
}
|
|
} else if len(drivePath.Folders) > 0 {
|
|
// Root folder doesn't have a metadata file associated with it.
|
|
folders := collectionPath.Folders()
|
|
|
|
meta, err := fetchAndReadMetadata(
|
|
ctx,
|
|
dc,
|
|
folders[len(folders)-1]+DirMetaFileSuffix)
|
|
if err != nil {
|
|
return nil, nil, clues.Wrap(err, "collection permissions")
|
|
}
|
|
|
|
colPerms = meta.Permissions
|
|
}
|
|
|
|
return parentPerms, colPerms, nil
|
|
}
|
|
|
|
// createRestoreFoldersWithPermissions creates the restore folder hierarchy in
|
|
// the specified drive and returns the folder ID of the last folder entry in the
|
|
// hierarchy. Permissions are only applied to the last folder in the hierarchy.
|
|
// Passing nil for the permissions results in just creating the folder(s).
|
|
func createRestoreFoldersWithPermissions(
|
|
ctx context.Context,
|
|
service graph.Servicer,
|
|
driveID string,
|
|
restoreFolders []string,
|
|
parentPermissions []UserPermission,
|
|
folderPermissions []UserPermission,
|
|
permissionIDMappings map[string]string,
|
|
) (string, error) {
|
|
id, err := CreateRestoreFolders(ctx, service, driveID, restoreFolders)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
err = restorePermissions(
|
|
ctx,
|
|
service,
|
|
driveID,
|
|
id,
|
|
parentPermissions,
|
|
folderPermissions,
|
|
permissionIDMappings)
|
|
|
|
return id, err
|
|
}
|
|
|
|
// getChildPermissions is to filter out permissions present in the
|
|
// parent from the ones that are available for child. This is
|
|
// necessary as we store the nested permissions in the child. We
|
|
// cannot avoid storing the nested permissions as it is possible that
|
|
// a file in a folder can remove the nested permission that is present
|
|
// on itself.
|
|
func getChildPermissions(
|
|
childPermissions, parentPermissions []UserPermission,
|
|
) ([]UserPermission, []UserPermission) {
|
|
var (
|
|
addedPermissions = []UserPermission{}
|
|
removedPermissions = []UserPermission{}
|
|
)
|
|
|
|
for _, cp := range childPermissions {
|
|
found := false
|
|
|
|
for _, pp := range parentPermissions {
|
|
if cp.ID == pp.ID {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
addedPermissions = append(addedPermissions, cp)
|
|
}
|
|
}
|
|
|
|
for _, pp := range parentPermissions {
|
|
found := false
|
|
|
|
for _, cp := range childPermissions {
|
|
if pp.ID == cp.ID {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
removedPermissions = append(removedPermissions, pp)
|
|
}
|
|
}
|
|
|
|
return addedPermissions, removedPermissions
|
|
}
|
|
|
|
// restorePermissions takes in the permissions that were added and the
|
|
// removed(ones present in parent but not in child) and adds/removes
|
|
// the necessary permissions on onedrive objects.
|
|
func restorePermissions(
|
|
ctx context.Context,
|
|
service graph.Servicer,
|
|
driveID string,
|
|
itemID string,
|
|
parentPerms []UserPermission,
|
|
childPerms []UserPermission,
|
|
permissionIDMappings map[string]string,
|
|
) error {
|
|
permAdded, permRemoved := getChildPermissions(childPerms, parentPerms)
|
|
|
|
ctx = clues.Add(ctx, "permission_item_id", itemID)
|
|
|
|
for _, p := range permRemoved {
|
|
err := service.Client().
|
|
DrivesById(driveID).
|
|
ItemsById(itemID).
|
|
PermissionsById(permissionIDMappings[p.ID]).
|
|
Delete(ctx, nil)
|
|
if err != nil {
|
|
return clues.Wrap(err, "removing permissions").WithClues(ctx).With(graph.ErrData(err)...)
|
|
}
|
|
}
|
|
|
|
for _, p := range permAdded {
|
|
pbody := msdrive.NewItemsItemInvitePostRequestBody()
|
|
pbody.SetRoles(p.Roles)
|
|
|
|
if p.Expiration != nil {
|
|
expiry := p.Expiration.String()
|
|
pbody.SetExpirationDateTime(&expiry)
|
|
}
|
|
|
|
si := false
|
|
pbody.SetSendInvitation(&si)
|
|
|
|
rs := true
|
|
pbody.SetRequireSignIn(&rs)
|
|
|
|
rec := models.NewDriveRecipient()
|
|
rec.SetEmail(&p.Email)
|
|
pbody.SetRecipients([]models.DriveRecipientable{rec})
|
|
|
|
np, err := service.Client().DrivesById(driveID).ItemsById(itemID).Invite().Post(ctx, pbody, nil)
|
|
if err != nil {
|
|
return clues.Wrap(err, "setting permissions").WithClues(ctx).With(graph.ErrData(err)...)
|
|
}
|
|
|
|
permissionIDMappings[p.ID] = *np.GetValue()[0].GetId()
|
|
}
|
|
|
|
return nil
|
|
}
|