Add additional OneDrive metadata to backup details (#952)
## Description Adds file size and timestamps to enable selectors using this metadata ## Type of change - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🐹 Trivial/Minor ## Issue(s) * #594 ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
ea73873ffb
commit
1df48997ae
@ -45,7 +45,7 @@ type itemReaderFunc func(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
service graph.Service,
|
service graph.Service,
|
||||||
driveID, itemID string,
|
driveID, itemID string,
|
||||||
) (name string, itemData io.ReadCloser, err error)
|
) (itemInfo *details.OneDriveInfo, itemData io.ReadCloser, err error)
|
||||||
|
|
||||||
// NewCollection creates a Collection
|
// NewCollection creates a Collection
|
||||||
func NewCollection(
|
func NewCollection(
|
||||||
@ -113,7 +113,7 @@ func (oc *Collection) populateItems(ctx context.Context) {
|
|||||||
|
|
||||||
for _, itemID := range oc.driveItemIDs {
|
for _, itemID := range oc.driveItemIDs {
|
||||||
// Read the item
|
// Read the item
|
||||||
itemName, itemData, err := oc.itemReader(ctx, oc.service, oc.driveID, itemID)
|
itemInfo, itemData, err := oc.itemReader(ctx, oc.service, oc.driveID, itemID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = support.WrapAndAppendf(itemID, err, errs)
|
errs = support.WrapAndAppendf(itemID, err, errs)
|
||||||
|
|
||||||
@ -125,14 +125,13 @@ func (oc *Collection) populateItems(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
// Item read successfully, add to collection
|
// Item read successfully, add to collection
|
||||||
itemsRead++
|
itemsRead++
|
||||||
|
|
||||||
|
itemInfo.ParentPath = oc.folderPath.String()
|
||||||
|
|
||||||
oc.data <- &Item{
|
oc.data <- &Item{
|
||||||
id: itemName,
|
id: itemInfo.ItemName,
|
||||||
data: itemData,
|
data: itemData,
|
||||||
info: &details.OneDriveInfo{
|
info: itemInfo,
|
||||||
ItemType: details.OneDriveItem,
|
|
||||||
ItemName: itemName,
|
|
||||||
ParentPath: oc.folderPath.String(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/connector/graph"
|
"github.com/alcionai/corso/src/internal/connector/graph"
|
||||||
"github.com/alcionai/corso/src/internal/connector/support"
|
"github.com/alcionai/corso/src/internal/connector/support"
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OneDriveCollectionSuite struct {
|
type OneDriveCollectionSuite struct {
|
||||||
@ -73,8 +74,8 @@ func (suite *OneDriveCollectionSuite) TestOneDriveCollection() {
|
|||||||
// Set a item reader, add an item and validate we get the item back
|
// Set a item reader, add an item and validate we get the item back
|
||||||
coll.Add(testItemID)
|
coll.Add(testItemID)
|
||||||
|
|
||||||
coll.itemReader = func(context.Context, graph.Service, string, string) (string, io.ReadCloser, error) {
|
coll.itemReader = func(context.Context, graph.Service, string, string) (*details.OneDriveInfo, io.ReadCloser, error) {
|
||||||
return testItemName, io.NopCloser(bytes.NewReader(testItemData)), nil
|
return &details.OneDriveInfo{ItemName: testItemName}, io.NopCloser(bytes.NewReader(testItemData)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read items from the collection
|
// Read items from the collection
|
||||||
@ -122,8 +123,8 @@ func (suite *OneDriveCollectionSuite) TestOneDriveCollectionReadError() {
|
|||||||
|
|
||||||
readError := errors.New("Test error")
|
readError := errors.New("Test error")
|
||||||
|
|
||||||
coll.itemReader = func(context.Context, graph.Service, string, string) (name string, data io.ReadCloser, err error) {
|
coll.itemReader = func(context.Context, graph.Service, string, string) (*details.OneDriveInfo, io.ReadCloser, error) {
|
||||||
return "", nil, readError
|
return nil, nil, readError
|
||||||
}
|
}
|
||||||
|
|
||||||
coll.Items()
|
coll.Items()
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/connector/graph"
|
"github.com/alcionai/corso/src/internal/connector/graph"
|
||||||
"github.com/alcionai/corso/src/internal/connector/support"
|
"github.com/alcionai/corso/src/internal/connector/support"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/logger"
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,19 +31,19 @@ func driveItemReader(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
service graph.Service,
|
service graph.Service,
|
||||||
driveID, itemID string,
|
driveID, itemID string,
|
||||||
) (string, io.ReadCloser, error) {
|
) (*details.OneDriveInfo, io.ReadCloser, error) {
|
||||||
logger.Ctx(ctx).Debugf("Reading Item %s at %s", itemID, time.Now())
|
logger.Ctx(ctx).Debugf("Reading Item %s at %s", itemID, time.Now())
|
||||||
|
|
||||||
item, err := service.Client().DrivesById(driveID).ItemsById(itemID).Get(ctx, nil)
|
item, err := service.Client().DrivesById(driveID).ItemsById(itemID).Get(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, errors.Wrapf(err, "failed to get item %s", itemID)
|
return nil, nil, errors.Wrapf(err, "failed to get item %s", itemID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the download URL - https://docs.microsoft.com/en-us/graph/api/driveitem-get-content
|
// Get the download URL - https://docs.microsoft.com/en-us/graph/api/driveitem-get-content
|
||||||
// These URLs are pre-authenticated and can be used to download the data using the standard
|
// These URLs are pre-authenticated and can be used to download the data using the standard
|
||||||
// http client
|
// http client
|
||||||
if _, found := item.GetAdditionalData()[downloadURLKey]; !found {
|
if _, found := item.GetAdditionalData()[downloadURLKey]; !found {
|
||||||
return "", nil, errors.Errorf("file does not have a download URL. ID: %s, %#v",
|
return nil, nil, errors.Errorf("file does not have a download URL. ID: %s, %#v",
|
||||||
itemID, item.GetAdditionalData())
|
itemID, item.GetAdditionalData())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +53,16 @@ func driveItemReader(
|
|||||||
// middleware/options configured
|
// middleware/options configured
|
||||||
resp, err := http.Get(*downloadURL)
|
resp, err := http.Get(*downloadURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, errors.Wrapf(err, "failed to download file from %s", *downloadURL)
|
return nil, nil, errors.Wrapf(err, "failed to download file from %s", *downloadURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
return *item.GetName(), resp.Body, nil
|
return &details.OneDriveInfo{
|
||||||
|
ItemType: details.OneDriveItem,
|
||||||
|
ItemName: *item.GetName(),
|
||||||
|
Created: *item.GetCreatedDateTime(),
|
||||||
|
LastModified: *item.GetLastModifiedDateTime(),
|
||||||
|
Size: *item.GetSize(),
|
||||||
|
}, resp.Body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// driveItemWriter is used to initialize and return an io.Writer to upload data for the specified item
|
// driveItemWriter is used to initialize and return an io.Writer to upload data for the specified item
|
||||||
|
|||||||
@ -102,14 +102,16 @@ func (suite *ItemIntegrationSuite) TestItemReader() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Read data for the file
|
// Read data for the file
|
||||||
name, itemData, err := driveItemReader(ctx, suite, driveID, driveItemID)
|
itemInfo, itemData, err := driveItemReader(ctx, suite, driveID, driveItemID)
|
||||||
require.NoError(suite.T(), err)
|
require.NoError(suite.T(), err)
|
||||||
require.NotEmpty(suite.T(), name)
|
require.NotNil(suite.T(), itemInfo)
|
||||||
|
require.NotEmpty(suite.T(), itemInfo.ItemName)
|
||||||
|
|
||||||
size, err := io.Copy(io.Discard, itemData)
|
size, err := io.Copy(io.Discard, itemData)
|
||||||
require.NoError(suite.T(), err)
|
require.NoError(suite.T(), err)
|
||||||
require.NotZero(suite.T(), size)
|
require.NotZero(suite.T(), size)
|
||||||
suite.T().Logf("Read %d bytes from file %s.", size, name)
|
require.Equal(suite.T(), size, itemInfo.Size)
|
||||||
|
suite.T().Logf("Read %d bytes from file %s.", size, itemInfo.ItemName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestItemWriter is an integration test for uploading data to OneDrive
|
// TestItemWriter is an integration test for uploading data to OneDrive
|
||||||
|
|||||||
@ -364,16 +364,22 @@ type OneDriveInfo struct {
|
|||||||
ItemType ItemType `json:"itemType,omitempty"`
|
ItemType ItemType `json:"itemType,omitempty"`
|
||||||
ParentPath string `json:"parentPath"`
|
ParentPath string `json:"parentPath"`
|
||||||
ItemName string `json:"itemName"`
|
ItemName string `json:"itemName"`
|
||||||
|
Size int64 `json:"size,omitempty"`
|
||||||
|
Created time.Time `json:"created,omitempty"`
|
||||||
|
LastModified time.Time `json:"lastModified,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headers returns the human-readable names of properties in a OneDriveInfo
|
// Headers returns the human-readable names of properties in a OneDriveInfo
|
||||||
// for printing out to a terminal in a columnar display.
|
// for printing out to a terminal in a columnar display.
|
||||||
func (i OneDriveInfo) Headers() []string {
|
func (i OneDriveInfo) Headers() []string {
|
||||||
return []string{"ItemName", "ParentPath"}
|
return []string{"ItemName", "ParentPath", "Size", "Created", "LastModified"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values returns the values matching the Headers list for printing
|
// Values returns the values matching the Headers list for printing
|
||||||
// out to a terminal in a columnar display.
|
// out to a terminal in a columnar display.
|
||||||
func (i OneDriveInfo) Values() []string {
|
func (i OneDriveInfo) Values() []string {
|
||||||
return []string{i.ItemName, i.ParentPath}
|
return []string{
|
||||||
|
i.ItemName, i.ParentPath, strconv.FormatInt(i.Size, 10),
|
||||||
|
common.FormatTabularDisplayTime(i.Created), common.FormatTabularDisplayTime(i.LastModified),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -114,11 +114,14 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
OneDrive: &details.OneDriveInfo{
|
OneDrive: &details.OneDriveInfo{
|
||||||
ItemName: "itemName",
|
ItemName: "itemName",
|
||||||
ParentPath: "parentPath",
|
ParentPath: "parentPath",
|
||||||
|
Size: 1000,
|
||||||
|
Created: now,
|
||||||
|
LastModified: now,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectHs: []string{"Reference", "ItemName", "ParentPath"},
|
expectHs: []string{"Reference", "ItemName", "ParentPath", "Size", "Created", "LastModified"},
|
||||||
expectVs: []string{"deadbeef", "itemName", "parentPath"},
|
expectVs: []string{"deadbeef", "itemName", "parentPath", "1000", nowStr, nowStr},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user