fixup mailbox info (#3189)
#### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [x] 🐛 Bugfix - [x] 🧹 Tech Debt/Cleanup #### Test Plan - [x] 💪 Manual - [x] 💚 E2E
This commit is contained in:
parent
41f742eba2
commit
b331f38654
@ -18,19 +18,19 @@ import (
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||
)
|
||||
|
||||
type DiscoveryIntegrationSuite struct {
|
||||
type DiscoveryIntgSuite struct {
|
||||
tester.Suite
|
||||
}
|
||||
|
||||
func TestDiscoveryIntegrationSuite(t *testing.T) {
|
||||
suite.Run(t, &DiscoveryIntegrationSuite{
|
||||
func TestDiscoveryIntgSuite(t *testing.T) {
|
||||
suite.Run(t, &DiscoveryIntgSuite{
|
||||
Suite: tester.NewIntegrationSuite(
|
||||
t,
|
||||
[][]string{tester.M365AcctCredEnvs}),
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *DiscoveryIntegrationSuite) TestUsers() {
|
||||
func (suite *DiscoveryIntgSuite) TestUsers() {
|
||||
ctx, flush := tester.NewContext()
|
||||
defer flush()
|
||||
|
||||
@ -55,7 +55,7 @@ func (suite *DiscoveryIntegrationSuite) TestUsers() {
|
||||
assert.NotEmpty(t, users)
|
||||
}
|
||||
|
||||
func (suite *DiscoveryIntegrationSuite) TestUsers_InvalidCredentials() {
|
||||
func (suite *DiscoveryIntgSuite) TestUsers_InvalidCredentials() {
|
||||
table := []struct {
|
||||
name string
|
||||
acct func(t *testing.T) account.Account
|
||||
@ -101,7 +101,7 @@ func (suite *DiscoveryIntegrationSuite) TestUsers_InvalidCredentials() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *DiscoveryIntegrationSuite) TestSites() {
|
||||
func (suite *DiscoveryIntgSuite) TestSites() {
|
||||
ctx, flush := tester.NewContext()
|
||||
defer flush()
|
||||
|
||||
@ -120,7 +120,7 @@ func (suite *DiscoveryIntegrationSuite) TestSites() {
|
||||
assert.NotEmpty(t, sites)
|
||||
}
|
||||
|
||||
func (suite *DiscoveryIntegrationSuite) TestSites_InvalidCredentials() {
|
||||
func (suite *DiscoveryIntgSuite) TestSites_InvalidCredentials() {
|
||||
ctx, flush := tester.NewContext()
|
||||
defer flush()
|
||||
|
||||
@ -171,10 +171,9 @@ func (suite *DiscoveryIntegrationSuite) TestSites_InvalidCredentials() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *DiscoveryIntegrationSuite) TestUserInfo() {
|
||||
func (suite *DiscoveryIntgSuite) TestUserInfo() {
|
||||
t := suite.T()
|
||||
acct := tester.NewM365Account(t)
|
||||
userID := tester.M365UserID(t)
|
||||
|
||||
creds, err := acct.M365Config()
|
||||
require.NoError(t, err)
|
||||
@ -188,34 +187,31 @@ func (suite *DiscoveryIntegrationSuite) TestUserInfo() {
|
||||
name string
|
||||
user string
|
||||
expect *api.UserInfo
|
||||
expectErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "standard test user",
|
||||
user: userID,
|
||||
user: tester.M365UserID(t),
|
||||
expect: &api.UserInfo{
|
||||
DiscoveredServices: map[path.ServiceType]struct{}{
|
||||
path.ExchangeService: {},
|
||||
path.OneDriveService: {},
|
||||
},
|
||||
HasMailBox: true,
|
||||
HasOneDrive: true,
|
||||
Mailbox: api.MailboxInfo{
|
||||
Purpose: "user",
|
||||
ErrGetMailBoxSetting: nil,
|
||||
},
|
||||
},
|
||||
expectErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "user does not exist",
|
||||
user: uuid.NewString(),
|
||||
expect: &api.UserInfo{
|
||||
DiscoveredServices: map[path.ServiceType]struct{}{},
|
||||
HasMailBox: false,
|
||||
HasOneDrive: false,
|
||||
Mailbox: api.MailboxInfo{
|
||||
ErrGetMailBoxSetting: api.ErrMailBoxSettingsNotFound,
|
||||
},
|
||||
Mailbox: api.MailboxInfo{},
|
||||
},
|
||||
expectErr: require.NoError,
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
@ -226,15 +222,18 @@ func (suite *DiscoveryIntegrationSuite) TestUserInfo() {
|
||||
t := suite.T()
|
||||
|
||||
result, err := discovery.UserInfo(ctx, uapi, test.user)
|
||||
require.NoError(t, err, clues.ToCore(err))
|
||||
assert.Equal(t, test.expect.HasMailBox, result.HasMailBox)
|
||||
assert.Equal(t, test.expect.HasOneDrive, result.HasOneDrive)
|
||||
test.expectErr(t, err, clues.ToCore(err))
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, test.expect.DiscoveredServices, result.DiscoveredServices)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *DiscoveryIntegrationSuite) TestUserWithoutDrive() {
|
||||
func (suite *DiscoveryIntgSuite) TestUserWithoutDrive() {
|
||||
t := suite.T()
|
||||
acct := tester.NewM365Account(t)
|
||||
userID := tester.M365UserID(t)
|
||||
@ -249,10 +248,8 @@ func (suite *DiscoveryIntegrationSuite) TestUserWithoutDrive() {
|
||||
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,
|
||||
ErrGetMailBoxSetting: []error{api.ErrMailBoxSettingsNotFound},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -264,11 +261,9 @@ func (suite *DiscoveryIntegrationSuite) TestUserWithoutDrive() {
|
||||
path.ExchangeService: {},
|
||||
path.OneDriveService: {},
|
||||
},
|
||||
HasOneDrive: true,
|
||||
HasMailBox: true,
|
||||
Mailbox: api.MailboxInfo{
|
||||
Purpose: "user",
|
||||
ErrGetMailBoxSetting: nil,
|
||||
ErrGetMailBoxSetting: []error{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -283,8 +278,6 @@ func (suite *DiscoveryIntegrationSuite) TestUserWithoutDrive() {
|
||||
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)
|
||||
})
|
||||
|
||||
@ -14,10 +14,10 @@ import (
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
"github.com/alcionai/corso/src/pkg/filters"
|
||||
"github.com/alcionai/corso/src/pkg/logger"
|
||||
)
|
||||
|
||||
@ -25,20 +25,22 @@ import (
|
||||
// Error Interpretation Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type errorCode string
|
||||
|
||||
const (
|
||||
errCodeActivityLimitReached = "activityLimitReached"
|
||||
errCodeItemNotFound = "ErrorItemNotFound"
|
||||
errCodeItemNotFoundShort = "itemNotFound"
|
||||
errCodeEmailFolderNotFound = "ErrorSyncFolderNotFound"
|
||||
errCodeResyncRequired = "ResyncRequired" // alt: resyncRequired
|
||||
errCodeMalwareDetected = "malwareDetected"
|
||||
errCodeSyncFolderNotFound = "ErrorSyncFolderNotFound"
|
||||
errCodeSyncStateNotFound = "SyncStateNotFound"
|
||||
errCodeSyncStateInvalid = "SyncStateInvalid"
|
||||
errCodeResourceNotFound = "ResourceNotFound"
|
||||
errCodeRequestResourceNotFound = "Request_ResourceNotFound"
|
||||
errCodeMailboxNotEnabledForRESTAPI = "MailboxNotEnabledForRESTAPI"
|
||||
errCodeErrorAccessDenied = "ErrorAccessDenied"
|
||||
activityLimitReached errorCode = "activityLimitReached"
|
||||
emailFolderNotFound errorCode = "ErrorSyncFolderNotFound"
|
||||
errorAccessDenied errorCode = "ErrorAccessDenied"
|
||||
itemNotFound errorCode = "ErrorItemNotFound"
|
||||
itemNotFoundShort errorCode = "itemNotFound"
|
||||
mailboxNotEnabledForRESTAPI errorCode = "MailboxNotEnabledForRESTAPI"
|
||||
malwareDetected errorCode = "malwareDetected"
|
||||
requestResourceNotFound errorCode = "Request_ResourceNotFound"
|
||||
resourceNotFound errorCode = "ResourceNotFound"
|
||||
resyncRequired errorCode = "ResyncRequired" // alt: resyncRequired
|
||||
syncFolderNotFound errorCode = "ErrorSyncFolderNotFound"
|
||||
syncStateInvalid errorCode = "SyncStateInvalid"
|
||||
syncStateNotFound errorCode = "SyncStateNotFound"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -84,9 +86,9 @@ func IsErrDeletedInFlight(err error) bool {
|
||||
|
||||
if hasErrorCode(
|
||||
err,
|
||||
errCodeItemNotFound,
|
||||
errCodeItemNotFoundShort,
|
||||
errCodeSyncFolderNotFound,
|
||||
itemNotFound,
|
||||
itemNotFoundShort,
|
||||
syncFolderNotFound,
|
||||
) {
|
||||
return true
|
||||
}
|
||||
@ -95,20 +97,24 @@ func IsErrDeletedInFlight(err error) bool {
|
||||
}
|
||||
|
||||
func IsErrInvalidDelta(err error) bool {
|
||||
return hasErrorCode(err, errCodeSyncStateNotFound, errCodeResyncRequired, errCodeSyncStateInvalid) ||
|
||||
return hasErrorCode(err, syncStateNotFound, resyncRequired, syncStateInvalid) ||
|
||||
errors.Is(err, ErrInvalidDelta)
|
||||
}
|
||||
|
||||
func IsErrExchangeMailFolderNotFound(err error) bool {
|
||||
return hasErrorCode(err, errCodeResourceNotFound, errCodeMailboxNotEnabledForRESTAPI)
|
||||
return hasErrorCode(err, resourceNotFound, mailboxNotEnabledForRESTAPI)
|
||||
}
|
||||
|
||||
func IsErrUserNotFound(err error) bool {
|
||||
return hasErrorCode(err, errCodeRequestResourceNotFound)
|
||||
return hasErrorCode(err, requestResourceNotFound)
|
||||
}
|
||||
|
||||
func IsErrResourceNotFound(err error) bool {
|
||||
return hasErrorCode(err, resourceNotFound)
|
||||
}
|
||||
|
||||
func IsErrAccessDenied(err error) bool {
|
||||
return hasErrorCode(err, errCodeErrorAccessDenied)
|
||||
return hasErrorCode(err, errorAccessDenied) || clues.HasLabel(err, LabelStatus(http.StatusForbidden))
|
||||
}
|
||||
|
||||
func IsErrTimeout(err error) bool {
|
||||
@ -143,7 +149,7 @@ func LabelStatus(statusCode int) string {
|
||||
|
||||
// IsMalware is true if the graphAPI returns a "malware detected" error code.
|
||||
func IsMalware(err error) bool {
|
||||
return hasErrorCode(err, errCodeMalwareDetected)
|
||||
return hasErrorCode(err, malwareDetected)
|
||||
}
|
||||
|
||||
func IsMalwareResp(ctx context.Context, resp *http.Response) bool {
|
||||
@ -159,7 +165,7 @@ func IsMalwareResp(ctx context.Context, resp *http.Response) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if strings.Contains(string(respDump), errCodeMalwareDetected) {
|
||||
if strings.Contains(string(respDump), string(malwareDetected)) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -170,7 +176,7 @@ func IsMalwareResp(ctx context.Context, resp *http.Response) bool {
|
||||
// error parsers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func hasErrorCode(err error, codes ...string) bool {
|
||||
func hasErrorCode(err error, codes ...errorCode) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
@ -180,16 +186,17 @@ func hasErrorCode(err error, codes ...string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if oDataError.GetError().GetCode() == nil {
|
||||
code, ok := ptr.ValOK(oDataError.GetError().GetCode())
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
lcodes := []string{}
|
||||
for _, c := range codes {
|
||||
lcodes = append(lcodes, strings.ToLower(c))
|
||||
cs := make([]string, len(codes))
|
||||
for i, c := range codes {
|
||||
cs[i] = string(c)
|
||||
}
|
||||
|
||||
return slices.Contains(lcodes, strings.ToLower(*oDataError.GetError().GetCode()))
|
||||
return filters.Equal(cs).Compare(code)
|
||||
}
|
||||
|
||||
// Wrap is a helper function that extracts ODataError metadata from
|
||||
|
||||
@ -90,12 +90,12 @@ func (suite *GraphErrorsUnitSuite) TestIsErrDeletedInFlight() {
|
||||
},
|
||||
{
|
||||
name: "not-found oDataErr",
|
||||
err: odErr(errCodeItemNotFound),
|
||||
err: odErr(string(itemNotFound)),
|
||||
expect: assert.True,
|
||||
},
|
||||
{
|
||||
name: "sync-not-found oDataErr",
|
||||
err: odErr(errCodeSyncFolderNotFound),
|
||||
err: odErr(string(syncFolderNotFound)),
|
||||
expect: assert.True,
|
||||
},
|
||||
}
|
||||
@ -134,12 +134,12 @@ func (suite *GraphErrorsUnitSuite) TestIsErrInvalidDelta() {
|
||||
},
|
||||
{
|
||||
name: "resync-required oDataErr",
|
||||
err: odErr(errCodeResyncRequired),
|
||||
err: odErr(string(resyncRequired)),
|
||||
expect: assert.True,
|
||||
},
|
||||
{
|
||||
name: "sync state invalid oDataErr",
|
||||
err: odErr(errCodeSyncStateInvalid),
|
||||
err: odErr(string(syncStateInvalid)),
|
||||
expect: assert.True,
|
||||
},
|
||||
// next two tests are to make sure the checks are case insensitive
|
||||
@ -184,7 +184,7 @@ func (suite *GraphErrorsUnitSuite) TestIsErrUserNotFound() {
|
||||
},
|
||||
{
|
||||
name: "request resource not found oDataErr",
|
||||
err: odErr(errCodeRequestResourceNotFound),
|
||||
err: odErr(string(requestResourceNotFound)),
|
||||
expect: assert.True,
|
||||
},
|
||||
}
|
||||
|
||||
@ -286,8 +286,7 @@ func TestOneDriveDriveSuite(t *testing.T) {
|
||||
suite.Run(t, &OneDriveSuite{
|
||||
Suite: tester.NewIntegrationSuite(
|
||||
t,
|
||||
[][]string{tester.M365AcctCredEnvs},
|
||||
),
|
||||
[][]string{tester.M365AcctCredEnvs}),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/alcionai/clues"
|
||||
abstractions "github.com/microsoft/kiota-abstractions-go"
|
||||
@ -41,8 +42,6 @@ type Users struct {
|
||||
|
||||
type UserInfo struct {
|
||||
DiscoveredServices map[path.ServiceType]struct{}
|
||||
HasMailBox bool
|
||||
HasOneDrive bool
|
||||
Mailbox MailboxInfo
|
||||
}
|
||||
|
||||
@ -56,7 +55,7 @@ type MailboxInfo struct {
|
||||
AutomaticRepliesSetting AutomaticRepliesSettings
|
||||
Language Language
|
||||
WorkingHours WorkingHours
|
||||
ErrGetMailBoxSetting error
|
||||
ErrGetMailBoxSetting []error
|
||||
}
|
||||
|
||||
type AutomaticRepliesSettings struct {
|
||||
@ -229,204 +228,212 @@ func (c Users) GetIDAndName(ctx context.Context, userID string) (string, string,
|
||||
func (c Users) GetInfo(ctx context.Context, userID string) (*UserInfo, error) {
|
||||
// Assume all services are enabled
|
||||
// then filter down to only services the user has enabled
|
||||
var (
|
||||
err error
|
||||
userInfo = newUserInfo()
|
||||
userInfo := newUserInfo()
|
||||
|
||||
requestParameters = &users.ItemMailFoldersRequestBuilderGetQueryParameters{
|
||||
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,
|
||||
}
|
||||
)
|
||||
|
||||
userInfo.HasMailBox = true
|
||||
|
||||
err = c.GetExchange(ctx, userID, options)
|
||||
if err != nil {
|
||||
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")
|
||||
options := users.ItemMailFoldersRequestBuilderGetRequestConfiguration{
|
||||
QueryParameters: &requestParameters,
|
||||
}
|
||||
|
||||
logger.Ctx(ctx).Infof("resource owner does not have a mailbox enabled")
|
||||
if _, err := c.GetMailFolders(ctx, userID, options); err != nil {
|
||||
if graph.IsErrUserNotFound(err) {
|
||||
logger.CtxErr(ctx, err).Error("user not found")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !graph.IsErrExchangeMailFolderNotFound(err) ||
|
||||
clues.HasLabel(err, graph.LabelStatus(http.StatusNotFound)) {
|
||||
logger.CtxErr(ctx, err).Error("getting user's mail folder")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Ctx(ctx).Info("resource owner does not have a mailbox enabled")
|
||||
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 _, err := c.GetDrives(ctx, userID); err != nil {
|
||||
if !clues.HasLabel(err, graph.LabelsMysiteNotFound) {
|
||||
logger.Ctx(ctx).Errorf("err getting user's onedrive's data: %s", err)
|
||||
logger.CtxErr(ctx, err).Error("getting user's drives")
|
||||
|
||||
return nil, graph.Wrap(ctx, err, "getting user's onedrive's data")
|
||||
return nil, graph.Wrap(ctx, err, "getting user's drives")
|
||||
}
|
||||
|
||||
logger.Ctx(ctx).Infof("resource owner does not have a drive")
|
||||
logger.Ctx(ctx).Info("resource owner does not have a drive")
|
||||
|
||||
delete(userInfo.DiscoveredServices, path.OneDriveService)
|
||||
userInfo.HasOneDrive = false
|
||||
}
|
||||
|
||||
err = c.getAdditionalData(ctx, userID, &userInfo.Mailbox)
|
||||
mbxInfo, err := c.getMailboxSettings(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userInfo.Mailbox = mbxInfo
|
||||
|
||||
return userInfo, nil
|
||||
}
|
||||
|
||||
// verify mailbox enabled for user
|
||||
func (c Users) GetExchange(
|
||||
// TODO: remove when exchange api goes into this package
|
||||
func (c Users) GetMailFolders(
|
||||
ctx context.Context,
|
||||
userID string,
|
||||
options users.ItemMailFoldersRequestBuilderGetRequestConfiguration,
|
||||
) error {
|
||||
_, err := c.stable.Client().UsersById(userID).MailFolders().Get(ctx, &options)
|
||||
) (models.MailFolderCollectionResponseable, error) {
|
||||
mailFolders, err := c.stable.Client().UsersById(userID).MailFolders().Get(ctx, &options)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, graph.Wrap(ctx, err, "getting MailFolders")
|
||||
}
|
||||
|
||||
return nil
|
||||
return mailFolders, 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)
|
||||
// TODO: remove when drive api goes into this package
|
||||
func (c Users) GetDrives(ctx context.Context, userID string) (models.DriveCollectionResponseable, error) {
|
||||
drives, err := c.stable.Client().UsersById(userID).Drives().Get(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, graph.Wrap(ctx, err, "getting drives")
|
||||
}
|
||||
|
||||
return nil
|
||||
return drives, nil
|
||||
}
|
||||
|
||||
func (c Users) getAdditionalData(ctx context.Context, userID string, mailbox *MailboxInfo) error {
|
||||
func (c Users) getMailboxSettings(
|
||||
ctx context.Context,
|
||||
userID string,
|
||||
) (MailboxInfo, error) {
|
||||
var (
|
||||
rawURL = fmt.Sprintf("https://graph.microsoft.com/v1.0/users/%s/mailboxSettings", userID)
|
||||
adapter = c.stable.Adapter()
|
||||
mailBoundErr clues.Err
|
||||
mi = MailboxInfo{
|
||||
ErrGetMailBoxSetting: []error{},
|
||||
}
|
||||
)
|
||||
|
||||
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")
|
||||
return mi, 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")
|
||||
mi.ErrGetMailBoxSetting = append(mi.ErrGetMailBoxSetting, clues.New("access denied"))
|
||||
|
||||
return nil
|
||||
return mi, nil
|
||||
}
|
||||
|
||||
if graph.IsErrExchangeMailFolderNotFound(err) {
|
||||
logger.Ctx(ctx).Info("err exchange mail folder not found")
|
||||
logger.Ctx(ctx).Info("mailfolders not found")
|
||||
|
||||
mailbox.ErrGetMailBoxSetting = ErrMailBoxSettingsNotFound
|
||||
mi.ErrGetMailBoxSetting = append(mi.ErrGetMailBoxSetting, ErrMailBoxSettingsNotFound)
|
||||
|
||||
return nil
|
||||
return mi, 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)
|
||||
mi.ArchiveFolder, err = toString(ctx, "archiveFolder", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.Timezone, err = toString(ctx, "timeZone", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.DateFormat, err = toString(ctx, "dateFormat", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.TimeFormat, err = toString(ctx, "timeFormat", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.Purpose, err = toString(ctx, "userPurpose", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.DelegateMeetMsgDeliveryOpt, err = toString(ctx, "delegateMeetingMessageDeliveryOptions", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
// 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)
|
||||
replySetting, err := toT[map[string]any](ctx, "automaticRepliesSetting", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.AutomaticRepliesSetting.Status, err = toString(ctx, "status", replySetting)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.AutomaticRepliesSetting.ExternalAudience, err = toString(ctx, "externalAudience", replySetting)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.AutomaticRepliesSetting.ExternalReplyMessage, err = toString(ctx, "externalReplyMessage", replySetting)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.AutomaticRepliesSetting.InternalReplyMessage, err = toString(ctx, "internalReplyMessage", replySetting)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
// 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)
|
||||
startDateTime, err := toT[map[string]any](ctx, "scheduledStartDateTime", replySetting)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
endDateTime := toMap(ctx, replySetting["scheduledEndDateTime"], &mailBoundErr)
|
||||
mailbox.AutomaticRepliesSetting.ScheduledEndDateTime.DateTime = toString(
|
||||
ctx,
|
||||
endDateTime["dateTime"],
|
||||
&mailBoundErr)
|
||||
mailbox.AutomaticRepliesSetting.ScheduledEndDateTime.Timezone = toString(
|
||||
ctx,
|
||||
endDateTime["timeZone"],
|
||||
&mailBoundErr)
|
||||
mi.AutomaticRepliesSetting.ScheduledStartDateTime.DateTime, err = toString(ctx, "dateTime", startDateTime)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.AutomaticRepliesSetting.ScheduledStartDateTime.Timezone, err = toString(ctx, "timeZone", startDateTime)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
endDateTime, err := toT[map[string]any](ctx, "scheduledEndDateTime", replySetting)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.AutomaticRepliesSetting.ScheduledEndDateTime.DateTime, err = toString(ctx, "dateTime", endDateTime)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.AutomaticRepliesSetting.ScheduledEndDateTime.Timezone, err = toString(ctx, "timeZone", endDateTime)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
// Language decode
|
||||
language := toMap(ctx, additionalData["language"], &mailBoundErr)
|
||||
mailbox.Language.DisplayName = toString(
|
||||
ctx,
|
||||
language["displayName"],
|
||||
&mailBoundErr)
|
||||
mailbox.Language.Locale = toString(ctx, language["locale"], &mailBoundErr)
|
||||
language, err := toT[map[string]any](ctx, "language", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.Language.DisplayName, err = toString(ctx, "displayName", language)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.Language.Locale, err = toString(ctx, "locale", language)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
// working hours
|
||||
workingHours := toMap(ctx, additionalData["workingHours"], &mailBoundErr)
|
||||
mailbox.WorkingHours.StartTime = toString(
|
||||
ctx,
|
||||
workingHours["startTime"],
|
||||
&mailBoundErr)
|
||||
mailbox.WorkingHours.EndTime = toString(
|
||||
ctx,
|
||||
workingHours["endTime"],
|
||||
&mailBoundErr)
|
||||
workingHours, err := toT[map[string]any](ctx, "workingHours", additionalData)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
timeZone := toMap(ctx, workingHours["timeZone"], &mailBoundErr)
|
||||
mailbox.WorkingHours.TimeZone.Name = toString(
|
||||
ctx,
|
||||
timeZone["name"],
|
||||
&mailBoundErr)
|
||||
mi.WorkingHours.StartTime, err = toString(ctx, "startTime", workingHours)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.WorkingHours.EndTime, err = toString(ctx, "endTime", workingHours)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
timeZone, err := toT[map[string]any](ctx, "timeZone", workingHours)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
mi.WorkingHours.TimeZone.Name, err = toString(ctx, "name", timeZone)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
days, err := toT[[]any](ctx, "daysOfWeek", workingHours)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
|
||||
days := toArray(ctx, workingHours["daysOfWeek"], &mailBoundErr)
|
||||
for _, day := range days {
|
||||
mailbox.WorkingHours.DaysOfWeek = append(mailbox.WorkingHours.DaysOfWeek,
|
||||
toString(ctx, day, &mailBoundErr))
|
||||
s, err := anyToString(ctx, "dayOfTheWeek", day)
|
||||
mi.ErrGetMailBoxSetting = appendIfErr(mi.ErrGetMailBoxSetting, err)
|
||||
mi.WorkingHours.DaysOfWeek = append(mi.WorkingHours.DaysOfWeek, s)
|
||||
}
|
||||
|
||||
if mailBoundErr.Core().Msg != "" {
|
||||
mailbox.ErrGetMailBoxSetting = &mailBoundErr
|
||||
return mi, nil
|
||||
}
|
||||
|
||||
return nil
|
||||
func appendIfErr(errs []error, err error) []error {
|
||||
if err == nil {
|
||||
return errs
|
||||
}
|
||||
|
||||
return append(errs, err)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -453,50 +460,52 @@ func validateUser(item any) (models.Userable, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func toString(ctx context.Context, data any, mailBoxErr *clues.Err) string {
|
||||
dataPointer, ok := data.(*string)
|
||||
func toString(ctx context.Context, key string, data map[string]any) (string, error) {
|
||||
ctx = clues.Add(ctx, "setting_name", key)
|
||||
|
||||
if len(data) == 0 {
|
||||
logger.Ctx(ctx).Info("not found: ", key)
|
||||
return "", ErrMailBoxSettingsNotFound
|
||||
}
|
||||
|
||||
return anyToString(ctx, key, data[key])
|
||||
}
|
||||
|
||||
func anyToString(ctx context.Context, key string, val any) (string, error) {
|
||||
if val == nil {
|
||||
logger.Ctx(ctx).Info("nil value: ", key)
|
||||
return "", ErrMailBoxSettingsNotFound
|
||||
}
|
||||
|
||||
sp, ok := val.(*string)
|
||||
if !ok {
|
||||
logger.Ctx(ctx).Info("error getting data from mailboxSettings")
|
||||
|
||||
*mailBoxErr = *ErrMailBoxSettingsNotFound
|
||||
|
||||
return ""
|
||||
logger.Ctx(ctx).Info("value is not a *string: ", key)
|
||||
return "", ErrMailBoxSettingsNotFound
|
||||
}
|
||||
|
||||
value, ok := ptr.ValOK(dataPointer)
|
||||
return ptr.Val(sp), nil
|
||||
}
|
||||
|
||||
func toT[T any](ctx context.Context, key string, data map[string]any) (T, error) {
|
||||
ctx = clues.Add(ctx, "setting_name", key)
|
||||
|
||||
if len(data) == 0 {
|
||||
logger.Ctx(ctx).Info("not found: ", key)
|
||||
return *new(T), ErrMailBoxSettingsNotFound
|
||||
}
|
||||
|
||||
val := data[key]
|
||||
|
||||
if data == nil {
|
||||
logger.Ctx(ctx).Info("nil value: ", key)
|
||||
return *new(T), ErrMailBoxSettingsNotFound
|
||||
}
|
||||
|
||||
value, ok := val.(T)
|
||||
if !ok {
|
||||
logger.Ctx(ctx).Info("error getting value from pointer for mailboxSettings")
|
||||
|
||||
*mailBoxErr = *ErrMailBoxSettingsNotFound
|
||||
|
||||
return ""
|
||||
logger.Ctx(ctx).Info(fmt.Sprintf("unexpected type for %s: %T", key, val))
|
||||
return *new(T), ErrMailBoxSettingsNotFound
|
||||
}
|
||||
|
||||
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
|
||||
return value, nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user