Shared mailbox (#3106)
<!-- PR description--> Handle user's API to provide user purpose of users #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [x] 🕐 Yes, but in a later PR - [ ] ⛔ 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:
parent
dbf14644ad
commit
de1ae9f30a
@ -69,6 +69,22 @@ func Users(
|
|||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserDetails fetches detailed info like - userPurpose for all users in the tenant.
|
||||||
|
func GetUserInfo(
|
||||||
|
ctx context.Context,
|
||||||
|
acct account.Account,
|
||||||
|
userID string,
|
||||||
|
errs *fault.Bus,
|
||||||
|
) (*api.UserInfo, error) {
|
||||||
|
client, err := apiClient(ctx, acct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Users().GetInfo(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// User fetches a single user's data.
|
||||||
func User(
|
func User(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gwi getWithInfoer,
|
gwi getWithInfoer,
|
||||||
|
|||||||
@ -197,14 +197,23 @@ func (suite *DiscoveryIntegrationSuite) TestUserInfo() {
|
|||||||
path.ExchangeService: {},
|
path.ExchangeService: {},
|
||||||
path.OneDriveService: {},
|
path.OneDriveService: {},
|
||||||
},
|
},
|
||||||
|
HasMailBox: true,
|
||||||
|
HasOneDrive: true,
|
||||||
|
Mailbox: api.MailboxInfo{
|
||||||
|
Purpose: "user",
|
||||||
|
ErrGetMailBoxSetting: nil,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "user does not exist",
|
name: "user does not exist",
|
||||||
user: uuid.NewString(),
|
user: uuid.NewString(),
|
||||||
expect: &api.UserInfo{
|
expect: &api.UserInfo{
|
||||||
DiscoveredServices: map[path.ServiceType]struct{}{
|
DiscoveredServices: map[path.ServiceType]struct{}{},
|
||||||
path.OneDriveService: {}, // currently statically populated
|
HasMailBox: false,
|
||||||
|
HasOneDrive: false,
|
||||||
|
Mailbox: api.MailboxInfo{
|
||||||
|
ErrGetMailBoxSetting: api.ErrMailBoxSettingsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -218,7 +227,66 @@ func (suite *DiscoveryIntegrationSuite) TestUserInfo() {
|
|||||||
|
|
||||||
result, err := discovery.UserInfo(ctx, uapi, test.user)
|
result, err := discovery.UserInfo(ctx, uapi, test.user)
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
assert.Equal(t, test.expect, result)
|
assert.Equal(t, test.expect.HasMailBox, result.HasMailBox)
|
||||||
|
assert.Equal(t, test.expect.HasOneDrive, result.HasOneDrive)
|
||||||
|
assert.Equal(t, test.expect.DiscoveredServices, result.DiscoveredServices)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DiscoveryIntegrationSuite) TestUserWithoutDrive() {
|
||||||
|
t := suite.T()
|
||||||
|
acct := tester.NewM365Account(t)
|
||||||
|
userID := tester.M365UserID(t)
|
||||||
|
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
user string
|
||||||
|
expect *api.UserInfo
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "user without drive and exchange",
|
||||||
|
user: "a53c26f7-5100-4acb-a910-4d20960b2c19", // User: testevents@10rqc2.onmicrosoft.com
|
||||||
|
expect: &api.UserInfo{
|
||||||
|
DiscoveredServices: map[path.ServiceType]struct{}{},
|
||||||
|
HasOneDrive: false,
|
||||||
|
HasMailBox: false,
|
||||||
|
Mailbox: api.MailboxInfo{
|
||||||
|
ErrGetMailBoxSetting: api.ErrMailBoxSettingsNotFound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user with drive and exchange",
|
||||||
|
user: userID,
|
||||||
|
expect: &api.UserInfo{
|
||||||
|
DiscoveredServices: map[path.ServiceType]struct{}{
|
||||||
|
path.ExchangeService: {},
|
||||||
|
path.OneDriveService: {},
|
||||||
|
},
|
||||||
|
HasOneDrive: true,
|
||||||
|
HasMailBox: true,
|
||||||
|
Mailbox: api.MailboxInfo{
|
||||||
|
Purpose: "user",
|
||||||
|
ErrGetMailBoxSetting: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
ctx, flush := tester.NewContext()
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
result, err := discovery.GetUserInfo(ctx, acct, test.user, fault.New(true))
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
assert.Equal(t, test.expect.DiscoveredServices, result.DiscoveredServices)
|
||||||
|
assert.Equal(t, test.expect.HasOneDrive, result.HasOneDrive)
|
||||||
|
assert.Equal(t, test.expect.HasMailBox, result.HasMailBox)
|
||||||
|
assert.Equal(t, test.expect.Mailbox.ErrGetMailBoxSetting, result.Mailbox.ErrGetMailBoxSetting)
|
||||||
|
assert.Equal(t, test.expect.Mailbox.Purpose, result.Mailbox.Purpose)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@ const (
|
|||||||
errCodeResourceNotFound = "ResourceNotFound"
|
errCodeResourceNotFound = "ResourceNotFound"
|
||||||
errCodeRequestResourceNotFound = "Request_ResourceNotFound"
|
errCodeRequestResourceNotFound = "Request_ResourceNotFound"
|
||||||
errCodeMailboxNotEnabledForRESTAPI = "MailboxNotEnabledForRESTAPI"
|
errCodeMailboxNotEnabledForRESTAPI = "MailboxNotEnabledForRESTAPI"
|
||||||
|
errCodeErrorAccessDenied = "ErrorAccessDenied"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -106,6 +107,10 @@ func IsErrUserNotFound(err error) bool {
|
|||||||
return hasErrorCode(err, errCodeRequestResourceNotFound)
|
return hasErrorCode(err, errCodeRequestResourceNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsErrAccessDenied(err error) bool {
|
||||||
|
return hasErrorCode(err, errCodeErrorAccessDenied)
|
||||||
|
}
|
||||||
|
|
||||||
func IsErrTimeout(err error) bool {
|
func IsErrTimeout(err error) bool {
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
case *url.Error:
|
case *url.Error:
|
||||||
|
|||||||
@ -13,9 +13,15 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
"github.com/alcionai/corso/src/internal/connector/graph"
|
"github.com/alcionai/corso/src/internal/connector/graph"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
var (
|
||||||
|
ErrMailBoxSettingsNotFound = clues.New("mailbox settings not found")
|
||||||
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// controller
|
// controller
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -35,6 +41,50 @@ type Users struct {
|
|||||||
|
|
||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
DiscoveredServices map[path.ServiceType]struct{}
|
DiscoveredServices map[path.ServiceType]struct{}
|
||||||
|
HasMailBox bool
|
||||||
|
HasOneDrive bool
|
||||||
|
Mailbox MailboxInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type MailboxInfo struct {
|
||||||
|
Purpose string
|
||||||
|
ArchiveFolder string
|
||||||
|
DateFormat string
|
||||||
|
TimeFormat string
|
||||||
|
DelegateMeetMsgDeliveryOpt string
|
||||||
|
Timezone string
|
||||||
|
AutomaticRepliesSetting AutomaticRepliesSettings
|
||||||
|
Language Language
|
||||||
|
WorkingHours WorkingHours
|
||||||
|
ErrGetMailBoxSetting error
|
||||||
|
}
|
||||||
|
|
||||||
|
type AutomaticRepliesSettings struct {
|
||||||
|
ExternalAudience string
|
||||||
|
ExternalReplyMessage string
|
||||||
|
InternalReplyMessage string
|
||||||
|
ScheduledEndDateTime timeInfo
|
||||||
|
ScheduledStartDateTime timeInfo
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
|
||||||
|
type timeInfo struct {
|
||||||
|
DateTime string
|
||||||
|
Timezone string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Language struct {
|
||||||
|
Locale string
|
||||||
|
DisplayName string
|
||||||
|
}
|
||||||
|
|
||||||
|
type WorkingHours struct {
|
||||||
|
DaysOfWeek []string
|
||||||
|
StartTime string
|
||||||
|
EndTime string
|
||||||
|
TimeZone struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUserInfo() *UserInfo {
|
func newUserInfo() *UserInfo {
|
||||||
@ -193,19 +243,192 @@ func (c Users) GetInfo(ctx context.Context, userID string) (*UserInfo, error) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: OneDrive
|
userInfo.HasMailBox = true
|
||||||
_, err = c.stable.Client().UsersById(userID).MailFolders().Get(ctx, &options)
|
|
||||||
|
err = c.GetExchange(ctx, userID, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !graph.IsErrExchangeMailFolderNotFound(err) {
|
if !graph.IsErrExchangeMailFolderNotFound(err) {
|
||||||
|
logger.Ctx(ctx).Errorf("err getting user's mail folder: %s", err)
|
||||||
|
|
||||||
return nil, graph.Wrap(ctx, err, "getting user's mail folder")
|
return nil, graph.Wrap(ctx, err, "getting user's mail folder")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Ctx(ctx).Infof("resource owner does not have a mailbox enabled")
|
||||||
delete(userInfo.DiscoveredServices, path.ExchangeService)
|
delete(userInfo.DiscoveredServices, path.ExchangeService)
|
||||||
|
|
||||||
|
userInfo.HasMailBox = false
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo.HasOneDrive = true
|
||||||
|
|
||||||
|
err = c.GetOnedrive(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
err = graph.Stack(ctx, err)
|
||||||
|
|
||||||
|
if !clues.HasLabel(err, graph.LabelsMysiteNotFound) {
|
||||||
|
logger.Ctx(ctx).Errorf("err getting user's onedrive's data: %s", err)
|
||||||
|
|
||||||
|
return nil, graph.Wrap(ctx, err, "getting user's onedrive's data")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Ctx(ctx).Infof("resource owner does not have a drive")
|
||||||
|
|
||||||
|
delete(userInfo.DiscoveredServices, path.OneDriveService)
|
||||||
|
userInfo.HasOneDrive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.getAdditionalData(ctx, userID, &userInfo.Mailbox)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return userInfo, nil
|
return userInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verify mailbox enabled for user
|
||||||
|
func (c Users) GetExchange(
|
||||||
|
ctx context.Context,
|
||||||
|
userID string,
|
||||||
|
options users.ItemMailFoldersRequestBuilderGetRequestConfiguration,
|
||||||
|
) error {
|
||||||
|
_, err := c.stable.Client().UsersById(userID).MailFolders().Get(ctx, &options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify onedrive enabled for user
|
||||||
|
func (c Users) GetOnedrive(ctx context.Context, userID string) error {
|
||||||
|
_, err := c.stable.Client().UsersById(userID).Drives().Get(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Users) getAdditionalData(ctx context.Context, userID string, mailbox *MailboxInfo) error {
|
||||||
|
var (
|
||||||
|
rawURL = fmt.Sprintf("https://graph.microsoft.com/v1.0/users/%s/mailboxSettings", userID)
|
||||||
|
adapter = c.stable.Adapter()
|
||||||
|
mailBoundErr clues.Err
|
||||||
|
)
|
||||||
|
|
||||||
|
settings, err := users.NewUserItemRequestBuilder(rawURL, adapter).Get(ctx, nil)
|
||||||
|
if err != nil && !(graph.IsErrAccessDenied(err) || graph.IsErrExchangeMailFolderNotFound(err)) {
|
||||||
|
logger.CtxErr(ctx, err).Error("getting mailbox settings")
|
||||||
|
|
||||||
|
return graph.Wrap(ctx, err, "getting additional data")
|
||||||
|
}
|
||||||
|
|
||||||
|
if graph.IsErrAccessDenied(err) {
|
||||||
|
logger.Ctx(ctx).Info("err getting additional data: access denied")
|
||||||
|
|
||||||
|
mailbox.ErrGetMailBoxSetting = clues.New("access denied")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if graph.IsErrExchangeMailFolderNotFound(err) {
|
||||||
|
logger.Ctx(ctx).Info("err exchange mail folder not found")
|
||||||
|
|
||||||
|
mailbox.ErrGetMailBoxSetting = ErrMailBoxSettingsNotFound
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalData := settings.GetAdditionalData()
|
||||||
|
|
||||||
|
mailbox.ArchiveFolder = toString(ctx, additionalData["archiveFolder"], &mailBoundErr)
|
||||||
|
mailbox.Timezone = toString(ctx, additionalData["timeZone"], &mailBoundErr)
|
||||||
|
mailbox.DateFormat = toString(ctx, additionalData["dateFormat"], &mailBoundErr)
|
||||||
|
mailbox.TimeFormat = toString(ctx, additionalData["timeFormat"], &mailBoundErr)
|
||||||
|
mailbox.Purpose = toString(ctx, additionalData["userPurpose"], &mailBoundErr)
|
||||||
|
mailbox.DelegateMeetMsgDeliveryOpt = toString(
|
||||||
|
ctx,
|
||||||
|
additionalData["delegateMeetingMessageDeliveryOptions"],
|
||||||
|
&mailBoundErr)
|
||||||
|
|
||||||
|
// decode automatic replies settings
|
||||||
|
replySetting := toMap(ctx, additionalData["automaticRepliesSetting"], &mailBoundErr)
|
||||||
|
mailbox.AutomaticRepliesSetting.Status = toString(
|
||||||
|
ctx,
|
||||||
|
replySetting["status"],
|
||||||
|
&mailBoundErr)
|
||||||
|
mailbox.AutomaticRepliesSetting.ExternalAudience = toString(
|
||||||
|
ctx,
|
||||||
|
replySetting["externalAudience"],
|
||||||
|
&mailBoundErr)
|
||||||
|
mailbox.AutomaticRepliesSetting.ExternalReplyMessage = toString(
|
||||||
|
ctx,
|
||||||
|
replySetting["externalReplyMessage"],
|
||||||
|
&mailBoundErr)
|
||||||
|
mailbox.AutomaticRepliesSetting.InternalReplyMessage = toString(
|
||||||
|
ctx,
|
||||||
|
replySetting["internalReplyMessage"],
|
||||||
|
&mailBoundErr)
|
||||||
|
|
||||||
|
// decode scheduledStartDateTime
|
||||||
|
startDateTime := toMap(ctx, replySetting["scheduledStartDateTime"], &mailBoundErr)
|
||||||
|
mailbox.AutomaticRepliesSetting.ScheduledStartDateTime.DateTime = toString(
|
||||||
|
ctx,
|
||||||
|
startDateTime["dateTime"],
|
||||||
|
&mailBoundErr)
|
||||||
|
mailbox.AutomaticRepliesSetting.ScheduledStartDateTime.Timezone = toString(
|
||||||
|
ctx,
|
||||||
|
startDateTime["timeZone"],
|
||||||
|
&mailBoundErr)
|
||||||
|
|
||||||
|
endDateTime := toMap(ctx, replySetting["scheduledEndDateTime"], &mailBoundErr)
|
||||||
|
mailbox.AutomaticRepliesSetting.ScheduledEndDateTime.DateTime = toString(
|
||||||
|
ctx,
|
||||||
|
endDateTime["dateTime"],
|
||||||
|
&mailBoundErr)
|
||||||
|
mailbox.AutomaticRepliesSetting.ScheduledEndDateTime.Timezone = toString(
|
||||||
|
ctx,
|
||||||
|
endDateTime["timeZone"],
|
||||||
|
&mailBoundErr)
|
||||||
|
|
||||||
|
// Language decode
|
||||||
|
language := toMap(ctx, additionalData["language"], &mailBoundErr)
|
||||||
|
mailbox.Language.DisplayName = toString(
|
||||||
|
ctx,
|
||||||
|
language["displayName"],
|
||||||
|
&mailBoundErr)
|
||||||
|
mailbox.Language.Locale = toString(ctx, language["locale"], &mailBoundErr)
|
||||||
|
|
||||||
|
// working hours
|
||||||
|
workingHours := toMap(ctx, additionalData["workingHours"], &mailBoundErr)
|
||||||
|
mailbox.WorkingHours.StartTime = toString(
|
||||||
|
ctx,
|
||||||
|
workingHours["startTime"],
|
||||||
|
&mailBoundErr)
|
||||||
|
mailbox.WorkingHours.EndTime = toString(
|
||||||
|
ctx,
|
||||||
|
workingHours["endTime"],
|
||||||
|
&mailBoundErr)
|
||||||
|
|
||||||
|
timeZone := toMap(ctx, workingHours["timeZone"], &mailBoundErr)
|
||||||
|
mailbox.WorkingHours.TimeZone.Name = toString(
|
||||||
|
ctx,
|
||||||
|
timeZone["name"],
|
||||||
|
&mailBoundErr)
|
||||||
|
|
||||||
|
days := toArray(ctx, workingHours["daysOfWeek"], &mailBoundErr)
|
||||||
|
for _, day := range days {
|
||||||
|
mailbox.WorkingHours.DaysOfWeek = append(mailbox.WorkingHours.DaysOfWeek,
|
||||||
|
toString(ctx, day, &mailBoundErr))
|
||||||
|
}
|
||||||
|
|
||||||
|
if mailBoundErr.Core().Msg != "" {
|
||||||
|
mailbox.ErrGetMailBoxSetting = &mailBoundErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// helpers
|
// helpers
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -229,3 +452,51 @@ func validateUser(item any) (models.Userable, error) {
|
|||||||
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toString(ctx context.Context, data any, mailBoxErr *clues.Err) string {
|
||||||
|
dataPointer, ok := data.(*string)
|
||||||
|
if !ok {
|
||||||
|
logger.Ctx(ctx).Info("error getting data from mailboxSettings")
|
||||||
|
|
||||||
|
*mailBoxErr = *ErrMailBoxSettingsNotFound
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
value, ok := ptr.ValOK(dataPointer)
|
||||||
|
if !ok {
|
||||||
|
logger.Ctx(ctx).Info("error getting value from pointer for mailboxSettings")
|
||||||
|
|
||||||
|
*mailBoxErr = *ErrMailBoxSettingsNotFound
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func toMap(ctx context.Context, data any, mailBoxErr *clues.Err) map[string]interface{} {
|
||||||
|
value, ok := data.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
logger.Ctx(ctx).Info("error getting mailboxSettings")
|
||||||
|
|
||||||
|
*mailBoxErr = *clues.New("mailbox settings not found")
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func toArray(ctx context.Context, data any, mailBoxErr *clues.Err) []interface{} {
|
||||||
|
value, ok := data.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
logger.Ctx(ctx).Info("error getting mailboxSettings")
|
||||||
|
|
||||||
|
*mailBoxErr = *clues.New("mailbox settings not found")
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ type User struct {
|
|||||||
PrincipalName string
|
PrincipalName string
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
|
Info api.UserInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
@ -72,6 +73,13 @@ func Users(ctx context.Context, acct account.Account, errs *fault.Bus) ([]*User,
|
|||||||
return nil, clues.Wrap(err, "formatting user data")
|
return nil, clues.Wrap(err, "formatting user data")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userInfo, err := discovery.GetUserInfo(ctx, acct, pu.ID, errs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, clues.Wrap(err, "getting user details")
|
||||||
|
}
|
||||||
|
|
||||||
|
pu.Info = *userInfo
|
||||||
|
|
||||||
ret = append(ret, pu)
|
ret = append(ret, pu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,7 @@ func (suite *M365IntegrationSuite) TestUsers() {
|
|||||||
assert.NotEmpty(t, u.ID)
|
assert.NotEmpty(t, u.ID)
|
||||||
assert.NotEmpty(t, u.PrincipalName)
|
assert.NotEmpty(t, u.PrincipalName)
|
||||||
assert.NotEmpty(t, u.Name)
|
assert.NotEmpty(t, u.Name)
|
||||||
|
assert.NotEmpty(t, u.Info)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user