Filter out non existent entities in permissions and link shares (#4955)
<!-- PR description--> --- #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [x] ⛔ No #### Type of change <!--- Please check the type of change your PR introduces: ---> - [ ] 🌻 Feature - [x] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * #<issue> #### Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
8067c72904
commit
ca50b1e908
@ -397,7 +397,7 @@ func UpdateLinkShares(
|
||||
|
||||
newLS, err := upils.PostItemLinkShareUpdate(ictx, driveID, itemID, lsbody)
|
||||
if graph.IsErrUsersCannotBeResolved(err) {
|
||||
oldLinkShareIDToNewID.Store(ls.ID, "") // empty to signify that we could not restore
|
||||
oldLinkShareIDToNewID.Store(ls.ID, nonRestorablePermission)
|
||||
logger.CtxErr(ictx, err).Info("unable to restore link share")
|
||||
|
||||
continue
|
||||
@ -449,6 +449,102 @@ func UpdateLinkShares(
|
||||
return alreadyDeleted, nil
|
||||
}
|
||||
|
||||
func filterUnavailableEntitiesInLinkShare(
|
||||
ctx context.Context,
|
||||
linkShares []metadata.LinkShare,
|
||||
availableEntities ResourceIDNames,
|
||||
oldLinkShareIDToNewID syncd.MapTo[string],
|
||||
) []metadata.LinkShare {
|
||||
filtered := []metadata.LinkShare{}
|
||||
|
||||
if availableEntities.Users == nil || availableEntities.Groups == nil {
|
||||
// This should not be happening unless we missed to fill in the caches
|
||||
logger.Ctx(ctx).Info("no available entities, not filtering link shares")
|
||||
return linkShares
|
||||
}
|
||||
|
||||
for _, p := range linkShares {
|
||||
entities := []metadata.Entity{}
|
||||
|
||||
for _, e := range p.Entities {
|
||||
available := false
|
||||
|
||||
switch e.EntityType {
|
||||
case metadata.GV2User:
|
||||
_, ok := availableEntities.Users.NameOf(e.ID)
|
||||
available = available || ok
|
||||
case metadata.GV2Group:
|
||||
_, ok := availableEntities.Groups.NameOf(e.ID)
|
||||
available = available || ok
|
||||
default:
|
||||
// We only know about users and groups
|
||||
available = true
|
||||
}
|
||||
|
||||
if available {
|
||||
entities = append(entities, e)
|
||||
}
|
||||
}
|
||||
|
||||
if len(entities) > 0 {
|
||||
p.Entities = entities
|
||||
filtered = append(filtered, p)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// If we have no entities, we can't restore the link share
|
||||
// and so we have to mark it as not restored.
|
||||
// This is done to make sure we don't try to delete it later.
|
||||
oldLinkShareIDToNewID.Store(p.ID, "")
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
func filterUnavailableEntitiesInPermissions(
|
||||
ctx context.Context,
|
||||
perms []metadata.Permission,
|
||||
availableEntities ResourceIDNames,
|
||||
oldPermIDToNewID syncd.MapTo[string],
|
||||
) []metadata.Permission {
|
||||
if availableEntities.Users == nil || availableEntities.Groups == nil {
|
||||
// This should not be happening unless we missed to fill in the caches
|
||||
logger.Ctx(ctx).Info("no available entities, not filtering link shares")
|
||||
return perms
|
||||
}
|
||||
|
||||
filtered := []metadata.Permission{}
|
||||
|
||||
for _, p := range perms {
|
||||
available := false
|
||||
|
||||
switch p.EntityType {
|
||||
case metadata.GV2User:
|
||||
_, ok := availableEntities.Users.NameOf(p.EntityID)
|
||||
available = available || ok
|
||||
case metadata.GV2Group:
|
||||
_, ok := availableEntities.Groups.NameOf(p.EntityID)
|
||||
available = available || ok
|
||||
default:
|
||||
// We only know about users and groups
|
||||
// TODO: extend the check to other entity types
|
||||
available = true
|
||||
}
|
||||
|
||||
if available {
|
||||
filtered = append(filtered, p)
|
||||
continue
|
||||
}
|
||||
|
||||
// If we have no entities, we can't restore the permission
|
||||
// and so we have to mark it as not restored.
|
||||
oldPermIDToNewID.Store(p.ID, "")
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
// RestorePermissions takes in the permissions of an item, computes
|
||||
// what permissions need to added and removed based on the parent
|
||||
// folder metas and uses that to add/remove the necessary permissions
|
||||
@ -478,6 +574,7 @@ func RestorePermissions(
|
||||
|
||||
if previousLinkShares != nil {
|
||||
lsAdded, lsRemoved := metadata.DiffLinkShares(previousLinkShares, current.LinkShares)
|
||||
lsAdded = filterUnavailableEntitiesInLinkShare(ctx, lsAdded, caches.AvailableEntities, caches.OldLinkShareIDToNewID)
|
||||
|
||||
// Link shares have to be updated before permissions as we have to
|
||||
// use the information about if we had to reset the inheritance to
|
||||
@ -503,6 +600,7 @@ func RestorePermissions(
|
||||
}
|
||||
|
||||
permAdded, permRemoved := metadata.DiffPermissions(previous.Permissions, current.Permissions)
|
||||
permAdded = filterUnavailableEntitiesInPermissions(ctx, permAdded, caches.AvailableEntities, caches.OldPermIDToNewID)
|
||||
|
||||
if didReset {
|
||||
// In case we did a reset of permissions when restoring link
|
||||
|
||||
@ -2,6 +2,7 @@ package drive
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -11,6 +12,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/idname"
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/common/syncd"
|
||||
"github.com/alcionai/corso/src/internal/m365/collection/drive/metadata"
|
||||
@ -326,3 +328,259 @@ func (suite *PermissionsUnitTestSuite) TestLinkShareRestoreNonExistentUser() {
|
||||
expectedSuccessValues := []bool{true, false, false, false}
|
||||
assert.Equal(t, expectedSuccessValues, successValues)
|
||||
}
|
||||
|
||||
func (suite *PermissionsUnitTestSuite) TestFilterUnavailableEntitiesInPermissions() {
|
||||
table := []struct {
|
||||
name string
|
||||
permissions []metadata.Permission
|
||||
expected []metadata.Permission
|
||||
availableEntities ResourceIDNames
|
||||
skippedPermissions []string
|
||||
}{
|
||||
{
|
||||
name: "single item",
|
||||
permissions: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
},
|
||||
expected: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
},
|
||||
availableEntities: ResourceIDNames{
|
||||
Users: idname.NewCache(map[string]string{"e1": "e1"}),
|
||||
Groups: idname.NewCache(map[string]string{}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single item with missing entity",
|
||||
permissions: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
},
|
||||
expected: []metadata.Permission{},
|
||||
availableEntities: ResourceIDNames{
|
||||
Users: idname.NewCache(map[string]string{}),
|
||||
Groups: idname.NewCache(map[string]string{}),
|
||||
},
|
||||
skippedPermissions: []string{"p1"},
|
||||
},
|
||||
{
|
||||
name: "multiple items",
|
||||
permissions: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
{ID: "p2", EntityID: "e2", EntityType: metadata.GV2User},
|
||||
{ID: "p3", EntityID: "e3", EntityType: metadata.GV2User},
|
||||
},
|
||||
expected: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
{ID: "p2", EntityID: "e2", EntityType: metadata.GV2User},
|
||||
{ID: "p3", EntityID: "e3", EntityType: metadata.GV2User},
|
||||
},
|
||||
availableEntities: ResourceIDNames{
|
||||
Users: idname.NewCache(map[string]string{"e1": "e1", "e2": "e2", "e3": "e3"}),
|
||||
Groups: idname.NewCache(map[string]string{}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple items with missing entity",
|
||||
permissions: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
{ID: "p2", EntityID: "e2", EntityType: metadata.GV2User},
|
||||
{ID: "p3", EntityID: "e3", EntityType: metadata.GV2Group},
|
||||
},
|
||||
expected: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
{ID: "p3", EntityID: "e3", EntityType: metadata.GV2Group},
|
||||
},
|
||||
availableEntities: ResourceIDNames{
|
||||
Users: idname.NewCache(map[string]string{"e1": "e1"}),
|
||||
Groups: idname.NewCache(map[string]string{"e3": "e3"}),
|
||||
},
|
||||
skippedPermissions: []string{"p2"},
|
||||
},
|
||||
{
|
||||
name: "multiple items with missing entity and multiple types",
|
||||
permissions: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
{ID: "p2", EntityID: "e2", EntityType: metadata.GV2User},
|
||||
{ID: "p3", EntityID: "e3", EntityType: metadata.GV2Group},
|
||||
{ID: "p4", EntityID: "e4", EntityType: metadata.GV2Group},
|
||||
{ID: "p5", EntityID: "e5", EntityType: metadata.GV2User},
|
||||
},
|
||||
expected: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2User},
|
||||
{ID: "p3", EntityID: "e3", EntityType: metadata.GV2Group},
|
||||
{ID: "p5", EntityID: "e5", EntityType: metadata.GV2User},
|
||||
},
|
||||
availableEntities: ResourceIDNames{
|
||||
Users: idname.NewCache(map[string]string{"e1": "e1", "e5": "e5"}),
|
||||
Groups: idname.NewCache(map[string]string{"e3": "e3"}),
|
||||
},
|
||||
skippedPermissions: []string{"p2", "p4"},
|
||||
},
|
||||
{
|
||||
name: "single item different type",
|
||||
permissions: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2Group},
|
||||
},
|
||||
expected: []metadata.Permission{},
|
||||
availableEntities: ResourceIDNames{
|
||||
Users: idname.NewCache(map[string]string{"e1": "e1"}),
|
||||
Groups: idname.NewCache(map[string]string{}),
|
||||
},
|
||||
skippedPermissions: []string{"p1"},
|
||||
},
|
||||
{
|
||||
name: "unhandled types",
|
||||
permissions: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2Device},
|
||||
{ID: "p2", EntityID: "e2", EntityType: metadata.GV2App},
|
||||
{ID: "p3", EntityID: "e3", EntityType: metadata.GV2SiteUser},
|
||||
{ID: "p4", EntityID: "e4", EntityType: metadata.GV2SiteGroup},
|
||||
},
|
||||
expected: []metadata.Permission{
|
||||
{ID: "p1", EntityID: "e1", EntityType: metadata.GV2Device},
|
||||
{ID: "p2", EntityID: "e2", EntityType: metadata.GV2App},
|
||||
{ID: "p3", EntityID: "e3", EntityType: metadata.GV2SiteUser},
|
||||
{ID: "p4", EntityID: "e4", EntityType: metadata.GV2SiteGroup},
|
||||
},
|
||||
availableEntities: ResourceIDNames{
|
||||
// these are users and not what we have
|
||||
Users: idname.NewCache(map[string]string{"e1": "e1", "e2": "e2", "e3": "e3", "e4": "e4"}),
|
||||
Groups: idname.NewCache(map[string]string{}),
|
||||
},
|
||||
skippedPermissions: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
oldToNew := syncd.NewMapTo[string]()
|
||||
filtered := filterUnavailableEntitiesInPermissions(ctx, test.permissions, test.availableEntities, oldToNew)
|
||||
|
||||
assert.Equal(t, test.expected, filtered, "filtered permissions")
|
||||
|
||||
for _, id := range test.skippedPermissions {
|
||||
_, ok := oldToNew.Load(id)
|
||||
assert.True(t, ok, fmt.Sprintf("skipped id %s", id))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type eidtype struct {
|
||||
id string
|
||||
etype metadata.GV2Type
|
||||
}
|
||||
|
||||
func (suite *PermissionsUnitTestSuite) TestFilterUnavailableEntitiesInLinkShare() {
|
||||
ls := func(lsid string, entities []eidtype) metadata.LinkShare {
|
||||
ents := []metadata.Entity{}
|
||||
for _, e := range entities {
|
||||
ents = append(ents, metadata.Entity{ID: e.id, EntityType: e.etype})
|
||||
}
|
||||
|
||||
return metadata.LinkShare{
|
||||
ID: lsid,
|
||||
Entities: ents,
|
||||
}
|
||||
}
|
||||
|
||||
ae := func(uids, gids []string) ResourceIDNames {
|
||||
users := map[string]string{}
|
||||
for _, id := range uids {
|
||||
users[id] = id
|
||||
}
|
||||
|
||||
groups := map[string]string{}
|
||||
for _, id := range gids {
|
||||
groups[id] = id
|
||||
}
|
||||
|
||||
return ResourceIDNames{
|
||||
Users: idname.NewCache(users),
|
||||
Groups: idname.NewCache(groups),
|
||||
}
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
linkShares []metadata.LinkShare
|
||||
expected []metadata.LinkShare
|
||||
availableEntities ResourceIDNames
|
||||
skippedLinkShares []string
|
||||
}{
|
||||
{
|
||||
name: "single item, single available entity",
|
||||
linkShares: []metadata.LinkShare{ls("ls1", []eidtype{{"e1", metadata.GV2User}})},
|
||||
expected: []metadata.LinkShare{ls("ls1", []eidtype{{"e1", metadata.GV2User}})},
|
||||
availableEntities: ae([]string{"e1"}, []string{}),
|
||||
},
|
||||
{
|
||||
name: "single item, single missing entity",
|
||||
linkShares: []metadata.LinkShare{ls("ls1", []eidtype{{"e1", metadata.GV2User}})},
|
||||
expected: []metadata.LinkShare{},
|
||||
availableEntities: ae([]string{}, []string{}),
|
||||
skippedLinkShares: []string{"ls1"},
|
||||
},
|
||||
{
|
||||
name: "multiple items, multiple available entities",
|
||||
linkShares: []metadata.LinkShare{
|
||||
ls("ls1", []eidtype{{"e1", metadata.GV2User}, {"e2", metadata.GV2User}}),
|
||||
ls("ls2", []eidtype{{"e3", metadata.GV2User}, {"e4", metadata.GV2User}}),
|
||||
},
|
||||
expected: []metadata.LinkShare{
|
||||
ls("ls1", []eidtype{{"e1", metadata.GV2User}, {"e2", metadata.GV2User}}),
|
||||
ls("ls2", []eidtype{{"e3", metadata.GV2User}, {"e4", metadata.GV2User}}),
|
||||
},
|
||||
availableEntities: ae([]string{"e1", "e2", "e3", "e4"}, []string{}),
|
||||
},
|
||||
{
|
||||
name: "multiple items, missing entities",
|
||||
linkShares: []metadata.LinkShare{
|
||||
ls("ls1", []eidtype{{"e1", metadata.GV2User}, {"e2", metadata.GV2Group}}),
|
||||
ls("ls2", []eidtype{{"e3", metadata.GV2User}, {"e4", metadata.GV2Group}}),
|
||||
},
|
||||
expected: []metadata.LinkShare{
|
||||
ls("ls1", []eidtype{{"e1", metadata.GV2User}}),
|
||||
ls("ls2", []eidtype{{"e4", metadata.GV2Group}}),
|
||||
},
|
||||
availableEntities: ae([]string{"e1"}, []string{"e4"}),
|
||||
skippedLinkShares: []string{},
|
||||
},
|
||||
{
|
||||
name: "unhandled items",
|
||||
linkShares: []metadata.LinkShare{
|
||||
ls("ls1", []eidtype{{"e1", metadata.GV2Device}, {"e2", metadata.GV2App}}),
|
||||
ls("ls2", []eidtype{{"e3", metadata.GV2SiteUser}, {"e4", metadata.GV2SiteGroup}}),
|
||||
},
|
||||
expected: []metadata.LinkShare{
|
||||
ls("ls1", []eidtype{{"e1", metadata.GV2Device}, {"e2", metadata.GV2App}}),
|
||||
ls("ls2", []eidtype{{"e3", metadata.GV2SiteUser}, {"e4", metadata.GV2SiteGroup}}),
|
||||
},
|
||||
availableEntities: ae([]string{}, []string{}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
oldToNew := syncd.NewMapTo[string]()
|
||||
filtered := filterUnavailableEntitiesInLinkShare(ctx, test.linkShares, test.availableEntities, oldToNew)
|
||||
|
||||
assert.Equal(t, test.expected, filtered, "filtered link shares")
|
||||
|
||||
for _, id := range test.skippedLinkShares {
|
||||
_, ok := oldToNew.Load(id)
|
||||
assert.True(t, ok, fmt.Sprintf("skipped id %s", id))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/common/syncd"
|
||||
"github.com/alcionai/corso/src/internal/m365/collection/drive/metadata"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
||||
)
|
||||
@ -21,6 +22,11 @@ type driveInfo struct {
|
||||
rootFolderID string
|
||||
}
|
||||
|
||||
type ResourceIDNames struct {
|
||||
Users idname.Cacher
|
||||
Groups idname.Cacher
|
||||
}
|
||||
|
||||
type restoreCaches struct {
|
||||
BackupDriveIDName idname.Cacher
|
||||
collisionKeyToItemID map[string]api.DriveItemIDType
|
||||
@ -30,6 +36,7 @@ type restoreCaches struct {
|
||||
OldLinkShareIDToNewID syncd.MapTo[string]
|
||||
OldPermIDToNewID syncd.MapTo[string]
|
||||
ParentDirToMeta syncd.MapTo[metadata.Metadata]
|
||||
AvailableEntities ResourceIDNames
|
||||
|
||||
pool sync.Pool
|
||||
}
|
||||
@ -59,12 +66,18 @@ func (rc *restoreCaches) AddDrive(
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetAllIDsAndNameser interface {
|
||||
GetAllIDsAndNames(ctx context.Context, errs *fault.Bus) (idname.Cacher, error)
|
||||
}
|
||||
|
||||
// Populate looks up drive items available to the protectedResource
|
||||
// and adds their info to the caches.
|
||||
func (rc *restoreCaches) Populate(
|
||||
ctx context.Context,
|
||||
usersGetter, groupsGetter GetAllIDsAndNameser,
|
||||
gdparf GetDrivePagerAndRootFolderer,
|
||||
protectedResourceID string,
|
||||
errs *fault.Bus,
|
||||
) error {
|
||||
drives, err := api.GetAllDrives(
|
||||
ctx,
|
||||
@ -79,6 +92,19 @@ func (rc *restoreCaches) Populate(
|
||||
}
|
||||
}
|
||||
|
||||
users, err := usersGetter.GetAllIDsAndNames(ctx, errs)
|
||||
if err != nil {
|
||||
return clues.Wrap(err, "getting users")
|
||||
}
|
||||
|
||||
groups, err := groupsGetter.GetAllIDsAndNames(ctx, errs)
|
||||
if err != nil {
|
||||
return clues.Wrap(err, "getting groups")
|
||||
}
|
||||
|
||||
rc.AvailableEntities.Users = users
|
||||
rc.AvailableEntities.Groups = groups
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -428,6 +428,17 @@ func (m *mockGDPARF) NewDrivePager(
|
||||
return m.pager
|
||||
}
|
||||
|
||||
type mockAllIDsAndNamesGetter struct {
|
||||
kvs map[string]string
|
||||
}
|
||||
|
||||
func (m mockAllIDsAndNamesGetter) GetAllIDsAndNames(
|
||||
context.Context,
|
||||
*fault.Bus,
|
||||
) (idname.Cacher, error) {
|
||||
return idname.NewCache(m.kvs), nil
|
||||
}
|
||||
|
||||
func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() {
|
||||
rfID := "this-is-id"
|
||||
driveID := "another-id"
|
||||
@ -443,12 +454,14 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() {
|
||||
table := []struct {
|
||||
name string
|
||||
mock *apiMock.Pager[models.Driveable]
|
||||
users map[string]string
|
||||
groups map[string]string
|
||||
expectErr require.ErrorAssertionFunc
|
||||
expectLen int
|
||||
checkValues bool
|
||||
}{
|
||||
{
|
||||
name: "no results",
|
||||
name: "no drive results",
|
||||
mock: &apiMock.Pager[models.Driveable]{
|
||||
ToReturn: []apiMock.PagerResult[models.Driveable]{
|
||||
{Values: []models.Driveable{}},
|
||||
@ -458,7 +471,7 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() {
|
||||
expectLen: 0,
|
||||
},
|
||||
{
|
||||
name: "one result",
|
||||
name: "one drive result",
|
||||
mock: &apiMock.Pager[models.Driveable]{
|
||||
ToReturn: []apiMock.PagerResult[models.Driveable]{
|
||||
{Values: []models.Driveable{md}},
|
||||
@ -478,6 +491,32 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() {
|
||||
expectErr: require.Error,
|
||||
expectLen: 0,
|
||||
},
|
||||
{
|
||||
name: "multiple users",
|
||||
mock: &apiMock.Pager[models.Driveable]{
|
||||
ToReturn: []apiMock.PagerResult[models.Driveable]{
|
||||
{Values: []models.Driveable{}},
|
||||
},
|
||||
},
|
||||
users: map[string]string{
|
||||
"1": "one",
|
||||
"2": "two",
|
||||
},
|
||||
expectErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "multiple groups",
|
||||
mock: &apiMock.Pager[models.Driveable]{
|
||||
ToReturn: []apiMock.PagerResult[models.Driveable]{
|
||||
{Values: []models.Driveable{}},
|
||||
},
|
||||
},
|
||||
groups: map[string]string{
|
||||
"1": "one",
|
||||
"2": "two",
|
||||
},
|
||||
expectErr: require.NoError,
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
@ -491,8 +530,16 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() {
|
||||
pager: test.mock,
|
||||
}
|
||||
|
||||
errs := fault.New(true)
|
||||
|
||||
rc := NewRestoreCaches(nil)
|
||||
err := rc.Populate(ctx, gdparf, "shmoo")
|
||||
err := rc.Populate(
|
||||
ctx,
|
||||
mockAllIDsAndNamesGetter{test.users},
|
||||
mockAllIDsAndNamesGetter{test.groups},
|
||||
gdparf,
|
||||
"shmoo",
|
||||
errs)
|
||||
test.expectErr(t, err, clues.ToCore(err))
|
||||
|
||||
assert.Equal(t, rc.DriveIDToDriveInfo.Size(), test.expectLen)
|
||||
@ -509,6 +556,16 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() {
|
||||
assert.Equal(t, name, nameResult.name, "drive name")
|
||||
assert.Equal(t, rfID, nameResult.rootFolderID, "root folder id")
|
||||
}
|
||||
|
||||
for key, val := range test.users {
|
||||
name, _ := rc.AvailableEntities.Users.NameOf(key)
|
||||
assert.Equal(t, name, val, "user")
|
||||
}
|
||||
|
||||
for key, val := range test.groups {
|
||||
name, _ := rc.AvailableEntities.Groups.NameOf(key)
|
||||
assert.Equal(t, name, val, "group")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ func ConsumeRestoreCollections(
|
||||
el = errs.Local()
|
||||
)
|
||||
|
||||
err := caches.Populate(ctx, lrh, rcc.ProtectedResource.ID())
|
||||
err := caches.Populate(ctx, ac.Users(), ac.Groups(), lrh, rcc.ProtectedResource.ID(), errs)
|
||||
if err != nil {
|
||||
return nil, clues.Wrap(err, "initializing restore caches")
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ func (h *groupsHandler) ConsumeRestoreCollections(
|
||||
Selector: rcc.Selector,
|
||||
}
|
||||
|
||||
err = caches.Populate(ictx, lrh, srcc.ProtectedResource.ID())
|
||||
err = caches.Populate(ictx, h.apiClient.Users(), h.apiClient.Groups(), lrh, srcc.ProtectedResource.ID(), errs)
|
||||
if err != nil {
|
||||
return nil, nil, clues.Wrap(err, "initializing restore caches")
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ func (h *onedriveHandler) ConsumeRestoreCollections(
|
||||
|
||||
ctx = clues.Add(ctx, "backup_version", rcc.BackupVersion)
|
||||
|
||||
err := caches.Populate(ctx, rh, rcc.ProtectedResource.ID())
|
||||
err := caches.Populate(ctx, h.apiClient.Users(), h.apiClient.Groups(), rh, rcc.ProtectedResource.ID(), errs)
|
||||
if err != nil {
|
||||
return nil, nil, clues.Wrap(err, "initializing restore caches")
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ func (h *sharepointHandler) ConsumeRestoreCollections(
|
||||
|
||||
switch dc.FullPath().Category() {
|
||||
case path.LibrariesCategory:
|
||||
err = caches.Populate(ctx, lrh, rcc.ProtectedResource.ID())
|
||||
err = caches.Populate(ctx, h.apiClient.Users(), h.apiClient.Groups(), lrh, rcc.ProtectedResource.ID(), errs)
|
||||
if err != nil {
|
||||
return nil, nil, clues.Wrap(err, "initializing restore caches")
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/groups"
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/idname"
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/common/str"
|
||||
"github.com/alcionai/corso/src/internal/common/tform"
|
||||
@ -51,6 +52,25 @@ func (c Groups) GetAll(
|
||||
return getGroups(ctx, errs, service)
|
||||
}
|
||||
|
||||
// GetAllIDsAndNames retrieves all groups in the tenant and returns them in an idname.Cacher
|
||||
func (c Groups) GetAllIDsAndNames(ctx context.Context, errs *fault.Bus) (idname.Cacher, error) {
|
||||
all, err := c.GetAll(ctx, errs)
|
||||
if err != nil {
|
||||
return nil, clues.Wrap(err, "getting all users")
|
||||
}
|
||||
|
||||
idToName := make(map[string]string, len(all))
|
||||
|
||||
for _, g := range all {
|
||||
id := strings.ToLower(ptr.Val(g.GetId()))
|
||||
name := ptr.Val(g.GetDisplayName())
|
||||
|
||||
idToName[id] = name
|
||||
}
|
||||
|
||||
return idname.NewCache(idToName), nil
|
||||
}
|
||||
|
||||
// GetAll retrieves all groups.
|
||||
func getGroups(
|
||||
ctx context.Context,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user