GC: Restore: SharePoint: List restore API (#1961)

## Description
Restore function for `SharePoint.List` logic within PR. Mock data changed as `SetName` is not allowed on item creation. Format for list restore is verified as below:
```java
 TestSharePointCollectionSuite/TestRestoreList
    collection_test.go:126: List created: Corso_Restore_26-Dec-2022_21-53-01.459183_MockListing
```
The expectation is that the correct folder name is passed to the function from the CLI. The restore pipeline is not connected for `SharePoint.List`. 
<!-- Insert PR description-->

## Does this PR need a docs update or release note?

- [x]  No 

## 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. -->
* Related to #1935 #<issue>

## Test Plan

- [x]  Unit test
This commit is contained in:
Danny 2022-12-27 13:26:10 -05:00 committed by GitHub
parent 43edf06db3
commit 20ec708ea3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 114 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package connector
import (
"bytes"
"io"
"testing"
"github.com/stretchr/testify/assert"
@ -334,6 +335,20 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
cols, err := gc.DataCollections(ctx, test.sel(), nil, control.Options{})
require.NoError(t, err)
test.comparator(t, 0, len(cols))
if test.name == "SharePoint.Lists" {
for _, collection := range cols {
t.Logf("Path: %s\n", collection.FullPath().String())
for item := range collection.Items() {
t.Log("File: " + item.UUID())
bytes, err := io.ReadAll(item.ToReader())
require.NoError(t, err)
t.Log(string(bytes))
}
}
}
})
}
}

View File

@ -87,6 +87,45 @@ func (suite *SharePointCollectionSuite) TestSharePointListCollection() {
assert.Equal(t, testName, shareInfo.Info().SharePoint.ItemName)
}
func (suite *SharePointCollectionSuite) TestRestoreList() {
ctx, flush := tester.NewContext()
defer flush()
t := suite.T()
a := tester.NewM365Account(t)
account, err := a.M365Config()
require.NoError(t, err)
service, err := createTestService(account)
require.NoError(t, err)
siteID := tester.M365SiteID(t)
ow := kw.NewJsonSerializationWriter()
listing := mockconnector.GetMockList("Mock List")
testName := "MockListing"
listing.SetDisplayName(&testName)
err = ow.WriteObjectValue("", listing)
require.NoError(t, err)
byteArray, err := ow.GetSerializedContent()
require.NoError(t, err)
require.NoError(t, err)
listData := &Item{
id: testName,
data: io.NopCloser(bytes.NewReader(byteArray)),
info: sharePointListInfo(listing, int64(len(byteArray))),
}
destName := "Corso_Restore_" + common.FormatNow(common.SimpleTimeTesting)
deets, err := restoreListItem(ctx, service, listData, siteID, destName)
assert.NoError(t, err)
t.Logf("List created: %s\n", deets.SharePoint.ItemName)
}
// TestRestoreLocation temporary test for greater restore operation
// TODO delete after full functionality tested in GraphConnector
func (suite *SharePointCollectionSuite) TestRestoreLocation() {

View File

@ -2,6 +2,8 @@ package sharepoint
import (
"context"
"fmt"
"io"
"github.com/pkg/errors"
@ -9,6 +11,7 @@ import (
"github.com/alcionai/corso/src/internal/connector/onedrive"
"github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/data"
D "github.com/alcionai/corso/src/internal/diagnostics"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/path"
@ -85,3 +88,60 @@ func createRestoreFolders(ctx context.Context, service graph.Servicer, siteID st
return onedrive.CreateRestoreFolders(ctx, service, *mainDrive.GetId(), restoreFolders)
}
// restoreListItem utility function restores a List to the siteID.
// The name is changed to to Corso_Restore_{timeStame}_name
// API Reference: https://learn.microsoft.com/en-us/graph/api/list-create?view=graph-rest-1.0&tabs=http
// Restored List can be verified within the Site contents
func restoreListItem(
ctx context.Context,
service graph.Servicer,
itemData data.Stream,
siteID, destName string,
) (details.ItemInfo, error) {
ctx, end := D.Span(ctx, "gc:sharepoint:restoreList", D.Label("item_uuid", itemData.UUID()))
defer end()
var (
dii = details.ItemInfo{}
itemName = itemData.UUID()
displayName = itemName
)
byteArray, err := io.ReadAll(itemData.ToReader())
if err != nil {
return dii, errors.Wrap(err, "sharepoint restoreItem failed to retrieve bytes from data.Stream")
}
// Create Item
newItem, err := support.CreateListFromBytes(byteArray)
if err != nil {
return dii, errors.Wrapf(err, "failed to construct list item %s", itemName)
}
// If field "name" is set, this will trigger the following error:
// invalidRequest Cannot define a 'name' for a list as it is assigned by the server. Instead, provide 'displayName'
if newItem.GetName() != nil {
adtlData := newItem.GetAdditionalData()
adtlData["list_name"] = *newItem.GetName()
newItem.SetName(nil)
}
if newItem.GetDisplayName() != nil {
displayName = *newItem.GetDisplayName()
}
newName := fmt.Sprintf("%s_%s", destName, displayName)
newItem.SetDisplayName(&newName)
// Restore to M365 store
restoredList, err := service.Client().SitesById(siteID).Lists().Post(ctx, newItem, nil)
if err != nil {
return dii, errors.Wrap(err, support.ConnectorStackErrorTrace(err))
}
written := int64(len(byteArray))
dii.SharePoint = sharePointListInfo(restoredList, written)
return dii, nil
}