Adding two new apis to corso for validating a user has exchange or one drive is enabled (#3447)

Adds two new apis that expose calls to check whether a user has one drive or exchange enabled

---

#### 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: --->
- [x] 🌻 Feature
- [ ] 🐛 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
- [x] 💚 E2E
This commit is contained in:
jules 2023-05-18 13:25:32 -07:00 committed by GitHub
parent 6b7745745a
commit 7057d94e35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 102 additions and 10 deletions

View File

@ -2,13 +2,16 @@ package m365
import ( import (
"context" "context"
"net/http"
"github.com/alcionai/clues" "github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/microsoftgraph/msgraph-sdk-go/users"
"github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/common/idname"
"github.com/alcionai/corso/src/internal/common/ptr" "github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/internal/connector/discovery" "github.com/alcionai/corso/src/internal/connector/discovery"
"github.com/alcionai/corso/src/internal/connector/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/services/m365/api" "github.com/alcionai/corso/src/pkg/services/m365/api"
@ -47,12 +50,12 @@ type UserNoInfo struct {
func UsersCompat(ctx context.Context, acct account.Account) ([]*User, error) { func UsersCompat(ctx context.Context, acct account.Account) ([]*User, error) {
errs := fault.New(true) errs := fault.New(true)
users, err := Users(ctx, acct, errs) us, err := Users(ctx, acct, errs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return users, errs.Failure() return us, errs.Failure()
} }
// UsersCompatNoInfo returns a list of users in the specified M365 tenant. // UsersCompatNoInfo returns a list of users in the specified M365 tenant.
@ -61,12 +64,71 @@ func UsersCompat(ctx context.Context, acct account.Account) ([]*User, error) {
func UsersCompatNoInfo(ctx context.Context, acct account.Account) ([]*UserNoInfo, error) { func UsersCompatNoInfo(ctx context.Context, acct account.Account) ([]*UserNoInfo, error) {
errs := fault.New(true) errs := fault.New(true)
users, err := usersNoInfo(ctx, acct, errs) us, err := usersNoInfo(ctx, acct, errs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return users, errs.Failure() return us, errs.Failure()
}
// UserHasMailbox returns true if the user has an exchange mailbox enabled
// false otherwise, and a nil pointer and an error in case of error
func UserHasMailbox(ctx context.Context, acct account.Account, userID string) (bool, error) {
uapi, err := makeUserAPI(acct)
if err != nil {
return false, clues.Wrap(err, "getting mailbox").WithClues(ctx)
}
requestParameters := users.ItemMailFoldersRequestBuilderGetQueryParameters{
Select: []string{"id"},
Top: ptr.To[int32](1), // if we get any folders, then we have access.
}
options := users.ItemMailFoldersRequestBuilderGetRequestConfiguration{
QueryParameters: &requestParameters,
}
_, err = uapi.GetMailFolders(ctx, userID, options)
if err != nil {
if graph.IsErrUserNotFound(err) {
return false, clues.Stack(graph.ErrResourceOwnerNotFound, err)
}
if !graph.IsErrExchangeMailFolderNotFound(err) ||
clues.HasLabel(err, graph.LabelStatus(http.StatusNotFound)) {
return false, err
}
return false, nil
}
return true, nil
}
// UserHasDrives returns true if the user has any drives
// false otherwise, and a nil pointer and an error in case of error
func UserHasDrives(ctx context.Context, acct account.Account, userID string) (bool, error) {
uapi, err := makeUserAPI(acct)
if err != nil {
return false, clues.Wrap(err, "getting drives").WithClues(ctx)
}
_, err = uapi.GetDrives(ctx, userID)
if err != nil {
if graph.IsErrUserNotFound(err) {
return false, clues.Stack(graph.ErrResourceOwnerNotFound, err)
}
if !graph.IsErrExchangeMailFolderNotFound(err) ||
clues.HasLabel(err, graph.LabelStatus(http.StatusNotFound)) {
return false, err
}
return false, nil
}
return true, nil
} }
// usersNoInfo returns a list of users in the specified M365 tenant - with no info // usersNoInfo returns a list of users in the specified M365 tenant - with no info
@ -78,14 +140,14 @@ func usersNoInfo(ctx context.Context, acct account.Account, errs *fault.Bus) ([]
return nil, clues.Wrap(err, "getting users").WithClues(ctx) return nil, clues.Wrap(err, "getting users").WithClues(ctx)
} }
users, err := discovery.Users(ctx, uapi, errs) us, err := discovery.Users(ctx, uapi, errs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ret := make([]*UserNoInfo, 0, len(users)) ret := make([]*UserNoInfo, 0, len(us))
for _, u := range users { for _, u := range us {
pu, err := parseUser(u) pu, err := parseUser(u)
if err != nil { if err != nil {
return nil, clues.Wrap(err, "formatting user data") return nil, clues.Wrap(err, "formatting user data")
@ -110,14 +172,14 @@ func Users(ctx context.Context, acct account.Account, errs *fault.Bus) ([]*User,
return nil, clues.Wrap(err, "getting users").WithClues(ctx) return nil, clues.Wrap(err, "getting users").WithClues(ctx)
} }
users, err := discovery.Users(ctx, uapi, errs) us, err := discovery.Users(ctx, uapi, errs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ret := make([]*User, 0, len(users)) ret := make([]*User, 0, len(us))
for _, u := range users { for _, u := range us {
pu, err := parseUser(u) pu, err := parseUser(u)
if err != nil { if err != nil {
return nil, clues.Wrap(err, "formatting user data") return nil, clues.Wrap(err, "formatting user data")

View File

@ -102,6 +102,36 @@ func (suite *M365IntegrationSuite) TestGetUserInfo() {
assert.Equal(t, "user", info.Mailbox.Purpose) assert.Equal(t, "user", info.Mailbox.Purpose)
} }
func (suite *M365IntegrationSuite) TestUserHasMailbox() {
ctx, flush := tester.NewContext()
defer flush()
var (
t = suite.T()
acct = tester.NewM365Account(t)
uid = tester.M365UserID(t)
)
enabled, err := m365.UserHasMailbox(ctx, acct, uid)
require.NoError(t, err, clues.ToCore(err))
assert.True(t, enabled)
}
func (suite *M365IntegrationSuite) TestUserHasDrive() {
ctx, flush := tester.NewContext()
defer flush()
var (
t = suite.T()
acct = tester.NewM365Account(t)
uid = tester.M365UserID(t)
)
enabled, err := m365.UserHasDrives(ctx, acct, uid)
require.NoError(t, err, clues.ToCore(err))
assert.True(t, enabled)
}
func (suite *M365IntegrationSuite) TestSites() { func (suite *M365IntegrationSuite) TestSites() {
ctx, flush := tester.NewContext() ctx, flush := tester.NewContext()
defer flush() defer flush()