## Description Upgrades Graph API to the newest version. Breaking change from the previous version, all functionality needs to be inspected to ensure operation. <!-- Insert PR description--> ## Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🌻 Feature ## Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> *closes #828<issue> ## Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
142 lines
4.1 KiB
Go
142 lines
4.1 KiB
Go
package onedrive
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/microsoftgraph/msgraph-sdk-go/drives/item/root/delta"
|
|
"github.com/microsoftgraph/msgraph-sdk-go/me/drives/item/items"
|
|
"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/connector/support"
|
|
"github.com/alcionai/corso/src/pkg/logger"
|
|
)
|
|
|
|
var errFolderNotFound = errors.New("folder not found")
|
|
|
|
const (
|
|
// nextLinkKey is used to find the next link in a paged
|
|
// graph response
|
|
nextLinkKey = "@odata.nextLink"
|
|
itemChildrenRawURLFmt = "https://graph.microsoft.com/v1.0/drives/%s/items/%s/children"
|
|
)
|
|
|
|
// Enumerates the drives for the specified user
|
|
func drives(ctx context.Context, service graph.Service, user string) ([]models.Driveable, error) {
|
|
r, err := service.Client().UsersById(user).Drives().Get(ctx, nil)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to retrieve user drives. user: %s, details: %s",
|
|
user, support.ConnectorStackErrorTrace(err))
|
|
}
|
|
|
|
logger.Ctx(ctx).Debugf("Found %d drives for user %s", len(r.GetValue()), user)
|
|
|
|
return r.GetValue(), nil
|
|
}
|
|
|
|
// itemCollector functions collect the items found in a drive
|
|
type itemCollector func(ctx context.Context, driveID string, driveItems []models.DriveItemable) error
|
|
|
|
// collectItems will enumerate all items in the specified drive and hand them to the
|
|
// provided `collector` method
|
|
func collectItems(
|
|
ctx context.Context,
|
|
service graph.Service,
|
|
driveID string,
|
|
collector itemCollector,
|
|
) error {
|
|
// TODO: Specify a timestamp in the delta query
|
|
// https://docs.microsoft.com/en-us/graph/api/driveitem-delta?
|
|
// view=graph-rest-1.0&tabs=http#example-4-retrieving-delta-results-using-a-timestamp
|
|
builder := service.Client().DrivesById(driveID).Root().Delta()
|
|
|
|
for {
|
|
r, err := builder.Get(ctx, nil)
|
|
if err != nil {
|
|
return errors.Wrapf(
|
|
err,
|
|
"failed to query drive items. details: %s",
|
|
support.ConnectorStackErrorTrace(err),
|
|
)
|
|
}
|
|
|
|
err = collector(ctx, driveID, r.GetValue())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check if there are more items
|
|
if _, found := r.GetAdditionalData()[nextLinkKey]; !found {
|
|
break
|
|
}
|
|
|
|
nextLink := r.GetAdditionalData()[nextLinkKey].(*string)
|
|
logger.Ctx(ctx).Debugf("Found %s nextLink", *nextLink)
|
|
builder = delta.NewDeltaRequestBuilder(*nextLink, service.Adapter())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// getFolder will lookup the specified folder name under `parentFolderID`
|
|
func getFolder(ctx context.Context, service graph.Service, driveID string, parentFolderID string,
|
|
folderName string,
|
|
) (models.DriveItemable, error) {
|
|
children, err := service.Client().DrivesById(driveID).ItemsById(parentFolderID).Children().Get(ctx, nil)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(
|
|
err,
|
|
"failed to get children. details: %s",
|
|
support.ConnectorStackErrorTrace(err),
|
|
)
|
|
}
|
|
|
|
for _, item := range children.GetValue() {
|
|
if item.GetFolder() == nil || item.GetName() == nil || *item.GetName() != folderName {
|
|
continue
|
|
}
|
|
|
|
return item, nil
|
|
}
|
|
|
|
return nil, errors.WithStack(errFolderNotFound)
|
|
}
|
|
|
|
// Create a new item in the specified folder
|
|
func createItem(ctx context.Context, service graph.Service, driveID string, parentFolderID string,
|
|
item models.DriveItemable,
|
|
) (models.DriveItemable, error) {
|
|
// Graph SDK doesn't yet provide a POST method for `/children` so we set the `rawUrl` ourselves as recommended
|
|
// here: https://github.com/microsoftgraph/msgraph-sdk-go/issues/155#issuecomment-1136254310
|
|
rawURL := fmt.Sprintf(itemChildrenRawURLFmt, driveID, parentFolderID)
|
|
|
|
builder := items.NewItemsRequestBuilder(rawURL, service.Adapter())
|
|
|
|
newItem, err := builder.Post(ctx, item, nil)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(
|
|
err,
|
|
"failed to create item. details: %s",
|
|
support.ConnectorStackErrorTrace(err),
|
|
)
|
|
}
|
|
|
|
return newItem, nil
|
|
}
|
|
|
|
// newItem initializes a `models.DriveItemable` that can be used as input to `createItem`
|
|
func newItem(name string, folder bool) models.DriveItemable {
|
|
item := models.NewDriveItem()
|
|
item.SetName(&name)
|
|
|
|
if folder {
|
|
item.SetFolder(models.NewFolder())
|
|
} else {
|
|
item.SetFile(models.NewFile())
|
|
}
|
|
|
|
return item
|
|
}
|