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:
parent
43edf06db3
commit
20ec708ea3
@ -2,6 +2,7 @@ package connector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -334,6 +335,20 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
|
|||||||
cols, err := gc.DataCollections(ctx, test.sel(), nil, control.Options{})
|
cols, err := gc.DataCollections(ctx, test.sel(), nil, control.Options{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
test.comparator(t, 0, len(cols))
|
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))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,6 +87,45 @@ func (suite *SharePointCollectionSuite) TestSharePointListCollection() {
|
|||||||
assert.Equal(t, testName, shareInfo.Info().SharePoint.ItemName)
|
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
|
// TestRestoreLocation temporary test for greater restore operation
|
||||||
// TODO delete after full functionality tested in GraphConnector
|
// TODO delete after full functionality tested in GraphConnector
|
||||||
func (suite *SharePointCollectionSuite) TestRestoreLocation() {
|
func (suite *SharePointCollectionSuite) TestRestoreLocation() {
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package sharepoint
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
@ -9,6 +11,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/connector/onedrive"
|
"github.com/alcionai/corso/src/internal/connector/onedrive"
|
||||||
"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"
|
||||||
|
D "github.com/alcionai/corso/src/internal/diagnostics"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"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)
|
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
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user