[Bugfix] Fixing getting owner email (#4538)
Owner data might have email and ID, or only one of them, or none. Fixing the code to handle this and adding a unit test. --- #### 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.--> - [x] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
cb6c56783b
commit
73202dad63
52
src/pkg/services/m365/api/mock/site.go
Normal file
52
src/pkg/services/m365/api/mock/site.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package mock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UserIdentity(userID string, userEmail string) models.IdentitySetable {
|
||||||
|
user := models.NewIdentitySet()
|
||||||
|
userIdentity := models.NewUserIdentity()
|
||||||
|
userIdentity.SetId(ptr.To(userID))
|
||||||
|
|
||||||
|
if len(userEmail) > 0 {
|
||||||
|
userIdentity.SetAdditionalData(map[string]any{
|
||||||
|
"email": userEmail,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
user.SetUser(userIdentity)
|
||||||
|
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
func GroupIdentitySet(groupID string, groupEmail string) models.IdentitySetable {
|
||||||
|
groupData := map[string]any{}
|
||||||
|
if len(groupEmail) > 0 {
|
||||||
|
groupData["email"] = groupEmail
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(groupID) > 0 {
|
||||||
|
groupData["id"] = groupID
|
||||||
|
}
|
||||||
|
|
||||||
|
group := models.NewIdentitySet()
|
||||||
|
group.SetAdditionalData(map[string]any{"group": groupData})
|
||||||
|
|
||||||
|
return group
|
||||||
|
}
|
||||||
|
|
||||||
|
func DummySite(owner models.IdentitySetable) models.Siteable {
|
||||||
|
site := models.NewSite()
|
||||||
|
site.SetId(ptr.To("id"))
|
||||||
|
site.SetWebUrl(ptr.To("weburl"))
|
||||||
|
site.SetDisplayName(ptr.To("displayname"))
|
||||||
|
|
||||||
|
drive := models.NewDrive()
|
||||||
|
drive.SetOwner(owner)
|
||||||
|
site.SetDrive(drive)
|
||||||
|
|
||||||
|
return site
|
||||||
|
}
|
||||||
@ -117,7 +117,7 @@ func SitesInGroup(
|
|||||||
result := make([]*Site, 0, len(sites))
|
result := make([]*Site, 0, len(sites))
|
||||||
|
|
||||||
for _, site := range sites {
|
for _, site := range sites {
|
||||||
result = append(result, ParseSite(site))
|
result = append(result, ParseSite(ctx, site))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||||
"github.com/alcionai/corso/src/pkg/account"
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
)
|
)
|
||||||
@ -20,7 +21,7 @@ import (
|
|||||||
type SiteOwnerType string
|
type SiteOwnerType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SiteOwnerUnknown SiteOwnerType = ""
|
SiteOwnerUnknown SiteOwnerType = "unknown"
|
||||||
SiteOwnerUser SiteOwnerType = "user"
|
SiteOwnerUser SiteOwnerType = "user"
|
||||||
SiteOwnerGroup SiteOwnerType = "group"
|
SiteOwnerGroup SiteOwnerType = "group"
|
||||||
)
|
)
|
||||||
@ -65,12 +66,21 @@ func SiteByID(
|
|||||||
Expand: []string{"drive"},
|
Expand: []string{"drive"},
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := ac.Sites().GetByID(ctx, id, cc)
|
return getSiteByID(ctx, ac.Sites(), id, cc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSiteByID(
|
||||||
|
ctx context.Context,
|
||||||
|
ga api.GetByIDer[models.Siteable],
|
||||||
|
id string,
|
||||||
|
cc api.CallConfig,
|
||||||
|
) (*Site, error) {
|
||||||
|
s, err := ga.GetByID(ctx, id, cc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, clues.Stack(err)
|
return nil, clues.Stack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseSite(s), nil
|
return ParseSite(ctx, s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sites returns a list of Sites in a specified M365 tenant
|
// Sites returns a list of Sites in a specified M365 tenant
|
||||||
@ -99,14 +109,14 @@ func getAllSites(
|
|||||||
ret := make([]*Site, 0, len(sites))
|
ret := make([]*Site, 0, len(sites))
|
||||||
|
|
||||||
for _, s := range sites {
|
for _, s := range sites {
|
||||||
ret = append(ret, ParseSite(s))
|
ret = append(ret, ParseSite(ctx, s))
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseSite extracts the information from `models.Siteable` we care about
|
// ParseSite extracts the information from `models.Siteable` we care about
|
||||||
func ParseSite(item models.Siteable) *Site {
|
func ParseSite(ctx context.Context, item models.Siteable) *Site {
|
||||||
s := &Site{
|
s := &Site{
|
||||||
ID: ptr.Val(item.GetId()),
|
ID: ptr.Val(item.GetId()),
|
||||||
WebURL: ptr.Val(item.GetWebUrl()),
|
WebURL: ptr.Val(item.GetWebUrl()),
|
||||||
@ -145,14 +155,16 @@ func ParseSite(item models.Siteable) *Site {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore the errors, these might or might not exist
|
||||||
|
// if they don't exist, we'll just have an empty string
|
||||||
s.OwnerID, err = str.AnyValueToString("id", group)
|
s.OwnerID, err = str.AnyValueToString("id", group)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s
|
logger.CtxErr(ctx, err).Info("could not parse owner ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.OwnerEmail, err = str.AnyValueToString("email", group)
|
s.OwnerEmail, err = str.AnyValueToString("email", group)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s
|
logger.CtxErr(ctx, err).Info("could not parse owner email")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/account"
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
"github.com/alcionai/corso/src/pkg/credentials"
|
"github.com/alcionai/corso/src/pkg/credentials"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"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/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
type siteIntegrationSuite struct {
|
type siteIntegrationSuite struct {
|
||||||
@ -81,10 +83,7 @@ func (suite *siteIntegrationSuite) TestSites_GetByID() {
|
|||||||
assert.NotEmpty(t, site.WebURL)
|
assert.NotEmpty(t, site.WebURL)
|
||||||
assert.NotEmpty(t, site.ID)
|
assert.NotEmpty(t, site.ID)
|
||||||
assert.NotEmpty(t, site.DisplayName)
|
assert.NotEmpty(t, site.DisplayName)
|
||||||
if site.OwnerType != SiteOwnerUnknown {
|
assert.NotEmpty(t, site.OwnerType)
|
||||||
assert.NotEmpty(t, site.OwnerID)
|
|
||||||
assert.NotEmpty(t, site.OwnerType)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,6 +155,14 @@ func (m mockGASites) GetAll(context.Context, *fault.Bus) ([]models.Siteable, err
|
|||||||
return m.response, m.err
|
return m.response, m.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m mockGASites) GetByID(context.Context, string, api.CallConfig) (models.Siteable, error) {
|
||||||
|
if len(m.response) == 0 {
|
||||||
|
return nil, m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.response[0], m.err
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *siteUnitSuite) TestGetAllSites() {
|
func (suite *siteUnitSuite) TestGetAllSites() {
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
@ -216,3 +223,93 @@ func (suite *siteUnitSuite) TestGetAllSites() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *siteUnitSuite) TestGetSites() {
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
mock func(context.Context) api.GetByIDer[models.Siteable]
|
||||||
|
expectErr assert.ErrorAssertionFunc
|
||||||
|
expectSite func(*testing.T, *Site)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ok - no owner",
|
||||||
|
mock: func(ctx context.Context) api.GetByIDer[models.Siteable] {
|
||||||
|
return mockGASites{[]models.Siteable{
|
||||||
|
mock.DummySite(nil),
|
||||||
|
}, nil}
|
||||||
|
},
|
||||||
|
expectErr: assert.NoError,
|
||||||
|
expectSite: func(t *testing.T, site *Site) {
|
||||||
|
assert.NotEmpty(t, site.ID)
|
||||||
|
assert.NotEmpty(t, site.WebURL)
|
||||||
|
assert.NotEmpty(t, site.DisplayName)
|
||||||
|
assert.Empty(t, site.OwnerID)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ok - owner user",
|
||||||
|
mock: func(ctx context.Context) api.GetByIDer[models.Siteable] {
|
||||||
|
return mockGASites{[]models.Siteable{
|
||||||
|
mock.DummySite(mock.UserIdentity("userid", "useremail")),
|
||||||
|
}, nil}
|
||||||
|
},
|
||||||
|
expectErr: assert.NoError,
|
||||||
|
expectSite: func(t *testing.T, site *Site) {
|
||||||
|
assert.NotEmpty(t, site.ID)
|
||||||
|
assert.NotEmpty(t, site.WebURL)
|
||||||
|
assert.NotEmpty(t, site.DisplayName)
|
||||||
|
assert.Equal(t, site.OwnerID, "userid")
|
||||||
|
assert.Equal(t, site.OwnerEmail, "useremail")
|
||||||
|
assert.Equal(t, site.OwnerType, SiteOwnerUser)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ok - group user with ID and email",
|
||||||
|
mock: func(ctx context.Context) api.GetByIDer[models.Siteable] {
|
||||||
|
return mockGASites{[]models.Siteable{
|
||||||
|
mock.DummySite(mock.GroupIdentitySet("groupid", "groupemail")),
|
||||||
|
}, nil}
|
||||||
|
},
|
||||||
|
expectErr: assert.NoError,
|
||||||
|
expectSite: func(t *testing.T, site *Site) {
|
||||||
|
assert.NotEmpty(t, site.ID)
|
||||||
|
assert.NotEmpty(t, site.WebURL)
|
||||||
|
assert.NotEmpty(t, site.DisplayName)
|
||||||
|
assert.Equal(t, SiteOwnerGroup, site.OwnerType)
|
||||||
|
assert.Equal(t, "groupid", site.OwnerID)
|
||||||
|
assert.Equal(t, "groupemail", site.OwnerEmail)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ok - group user with no ID but email",
|
||||||
|
mock: func(ctx context.Context) api.GetByIDer[models.Siteable] {
|
||||||
|
return mockGASites{[]models.Siteable{
|
||||||
|
mock.DummySite(mock.GroupIdentitySet("", "groupemail")),
|
||||||
|
}, nil}
|
||||||
|
},
|
||||||
|
expectErr: assert.NoError,
|
||||||
|
expectSite: func(t *testing.T, site *Site) {
|
||||||
|
assert.NotEmpty(t, site.ID)
|
||||||
|
assert.NotEmpty(t, site.WebURL)
|
||||||
|
assert.NotEmpty(t, site.DisplayName)
|
||||||
|
assert.Equal(t, SiteOwnerGroup, site.OwnerType)
|
||||||
|
assert.Equal(t, "", site.OwnerID)
|
||||||
|
assert.Equal(t, "groupemail", site.OwnerEmail)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
gas := test.mock(ctx)
|
||||||
|
|
||||||
|
site, err := getSiteByID(ctx, gas, "id", api.CallConfig{})
|
||||||
|
test.expectSite(t, site)
|
||||||
|
test.expectErr(t, err, clues.ToCore(err))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user