separate pager and plain apis for exchange (#3627)
Separates the pager and enumerattion functionality from the rest of the exchange api funcs for each category. Purely code movement, no logic changes. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [x] 🧹 Tech Debt/Cleanup #### Issue(s) * #3562 #### Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
416383a99c
commit
c70207b1f8
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/selectors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -137,79 +136,6 @@ func (c Contacts) PatchFolder(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// container pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// EnumerateContainers iterates through all of the users current
|
|
||||||
// contacts folders, converting each to a graph.CacheFolder, and calling
|
|
||||||
// fn(cf) on each one.
|
|
||||||
// Folder hierarchy is represented in its current state, and does
|
|
||||||
// not contain historical data.
|
|
||||||
func (c Contacts) EnumerateContainers(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, baseContainerID string,
|
|
||||||
fn func(graph.CachedContainer) error,
|
|
||||||
errs *fault.Bus,
|
|
||||||
) error {
|
|
||||||
config := &users.ItemContactFoldersItemChildFoldersRequestBuilderGetRequestConfiguration{
|
|
||||||
QueryParameters: &users.ItemContactFoldersItemChildFoldersRequestBuilderGetQueryParameters{
|
|
||||||
Select: idAnd(displayName, parentFolderID),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
el := errs.Local()
|
|
||||||
builder := c.Stable.
|
|
||||||
Client().
|
|
||||||
Users().
|
|
||||||
ByUserId(userID).
|
|
||||||
ContactFolders().
|
|
||||||
ByContactFolderId(baseContainerID).
|
|
||||||
ChildFolders()
|
|
||||||
|
|
||||||
for {
|
|
||||||
if el.Failure() != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := builder.Get(ctx, config)
|
|
||||||
if err != nil {
|
|
||||||
return graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fold := range resp.GetValue() {
|
|
||||||
if el.Failure() != nil {
|
|
||||||
return el.Failure()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := graph.CheckIDNameAndParentFolderID(fold); err != nil {
|
|
||||||
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fctx := clues.Add(
|
|
||||||
ctx,
|
|
||||||
"container_id", ptr.Val(fold.GetId()),
|
|
||||||
"container_display_name", ptr.Val(fold.GetDisplayName()))
|
|
||||||
|
|
||||||
temp := graph.NewCacheFolder(fold, nil, nil)
|
|
||||||
if err := fn(&temp); err != nil {
|
|
||||||
errs.AddRecoverable(ctx, graph.Stack(fctx, err).Label(fault.LabelForceNoBackupCreation))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
link, ok := ptr.ValOK(resp.GetOdataNextLink())
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
builder = users.NewItemContactFoldersItemChildFoldersRequestBuilder(link, c.Stable.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
return el.Failure()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// items
|
// items
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -284,145 +210,6 @@ func (c Contacts) DeleteItem(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// item pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
var _ itemPager = &contactPager{}
|
|
||||||
|
|
||||||
type contactPager struct {
|
|
||||||
gs graph.Servicer
|
|
||||||
builder *users.ItemContactFoldersItemContactsRequestBuilder
|
|
||||||
options *users.ItemContactFoldersItemContactsRequestBuilderGetRequestConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Contacts) NewContactPager(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID string,
|
|
||||||
immutableIDs bool,
|
|
||||||
) itemPager {
|
|
||||||
config := &users.ItemContactFoldersItemContactsRequestBuilderGetRequestConfiguration{
|
|
||||||
QueryParameters: &users.ItemContactFoldersItemContactsRequestBuilderGetQueryParameters{
|
|
||||||
Select: idAnd(parentFolderID),
|
|
||||||
},
|
|
||||||
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
|
||||||
}
|
|
||||||
|
|
||||||
builder := c.Stable.
|
|
||||||
Client().
|
|
||||||
Users().
|
|
||||||
ByUserId(userID).
|
|
||||||
ContactFolders().
|
|
||||||
ByContactFolderId(containerID).
|
|
||||||
Contacts()
|
|
||||||
|
|
||||||
return &contactPager{c.Stable, builder, config}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *contactPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
|
||||||
resp, err := p.builder.Get(ctx, p.options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return EmptyDeltaLinker[models.Contactable]{PageLinkValuer: resp}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *contactPager) setNext(nextLink string) {
|
|
||||||
p.builder = users.NewItemContactFoldersItemContactsRequestBuilder(nextLink, p.gs.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
// non delta pagers don't need reset
|
|
||||||
func (p *contactPager) reset(context.Context) {}
|
|
||||||
|
|
||||||
func (p *contactPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
|
||||||
return toValues[models.Contactable](pl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// delta item pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
var _ itemPager = &contactDeltaPager{}
|
|
||||||
|
|
||||||
type contactDeltaPager struct {
|
|
||||||
gs graph.Servicer
|
|
||||||
userID string
|
|
||||||
containerID string
|
|
||||||
builder *users.ItemContactFoldersItemContactsDeltaRequestBuilder
|
|
||||||
options *users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
func getContactDeltaBuilder(
|
|
||||||
ctx context.Context,
|
|
||||||
gs graph.Servicer,
|
|
||||||
userID, containerID string,
|
|
||||||
options *users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration,
|
|
||||||
) *users.ItemContactFoldersItemContactsDeltaRequestBuilder {
|
|
||||||
builder := gs.Client().Users().ByUserId(userID).ContactFolders().ByContactFolderId(containerID).Contacts().Delta()
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Contacts) NewContactDeltaPager(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID, oldDelta string,
|
|
||||||
immutableIDs bool,
|
|
||||||
) itemPager {
|
|
||||||
options := &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration{
|
|
||||||
QueryParameters: &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetQueryParameters{
|
|
||||||
Select: idAnd(parentFolderID),
|
|
||||||
},
|
|
||||||
Headers: newPreferHeaders(preferPageSize(maxDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
|
||||||
}
|
|
||||||
|
|
||||||
var builder *users.ItemContactFoldersItemContactsDeltaRequestBuilder
|
|
||||||
if oldDelta != "" {
|
|
||||||
builder = users.NewItemContactFoldersItemContactsDeltaRequestBuilder(oldDelta, c.Stable.Adapter())
|
|
||||||
} else {
|
|
||||||
builder = getContactDeltaBuilder(ctx, c.Stable, userID, containerID, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &contactDeltaPager{c.Stable, userID, containerID, builder, options}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *contactDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
|
||||||
resp, err := p.builder.Get(ctx, p.options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *contactDeltaPager) setNext(nextLink string) {
|
|
||||||
p.builder = users.NewItemContactFoldersItemContactsDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *contactDeltaPager) reset(ctx context.Context) {
|
|
||||||
p.builder = getContactDeltaBuilder(ctx, p.gs, p.userID, p.containerID, p.options)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *contactDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
|
||||||
return toValues[models.Contactable](pl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Contacts) GetAddedAndRemovedItemIDs(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID, oldDelta string,
|
|
||||||
immutableIDs bool,
|
|
||||||
canMakeDeltaQueries bool,
|
|
||||||
) ([]string, []string, DeltaUpdate, error) {
|
|
||||||
ctx = clues.Add(
|
|
||||||
ctx,
|
|
||||||
"category", selectors.ExchangeContact,
|
|
||||||
"container_id", containerID)
|
|
||||||
|
|
||||||
pager := c.NewContactPager(ctx, userID, containerID, immutableIDs)
|
|
||||||
deltaPager := c.NewContactDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
|
||||||
|
|
||||||
return getAddedAndRemovedItemIDs(ctx, c.Stable, pager, deltaPager, oldDelta, canMakeDeltaQueries)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Serialization
|
// Serialization
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
226
src/pkg/services/m365/api/contacts_pager.go
Normal file
226
src/pkg/services/m365/api/contacts_pager.go
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/users"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// container pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// EnumerateContainers iterates through all of the users current
|
||||||
|
// contacts folders, converting each to a graph.CacheFolder, and calling
|
||||||
|
// fn(cf) on each one.
|
||||||
|
// Folder hierarchy is represented in its current state, and does
|
||||||
|
// not contain historical data.
|
||||||
|
func (c Contacts) EnumerateContainers(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, baseContainerID string,
|
||||||
|
fn func(graph.CachedContainer) error,
|
||||||
|
errs *fault.Bus,
|
||||||
|
) error {
|
||||||
|
config := &users.ItemContactFoldersItemChildFoldersRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &users.ItemContactFoldersItemChildFoldersRequestBuilderGetQueryParameters{
|
||||||
|
Select: idAnd(displayName, parentFolderID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
el := errs.Local()
|
||||||
|
builder := c.Stable.
|
||||||
|
Client().
|
||||||
|
Users().
|
||||||
|
ByUserId(userID).
|
||||||
|
ContactFolders().
|
||||||
|
ByContactFolderId(baseContainerID).
|
||||||
|
ChildFolders()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if el.Failure() != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := builder.Get(ctx, config)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fold := range resp.GetValue() {
|
||||||
|
if el.Failure() != nil {
|
||||||
|
return el.Failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := graph.CheckIDNameAndParentFolderID(fold); err != nil {
|
||||||
|
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fctx := clues.Add(
|
||||||
|
ctx,
|
||||||
|
"container_id", ptr.Val(fold.GetId()),
|
||||||
|
"container_display_name", ptr.Val(fold.GetDisplayName()))
|
||||||
|
|
||||||
|
temp := graph.NewCacheFolder(fold, nil, nil)
|
||||||
|
if err := fn(&temp); err != nil {
|
||||||
|
errs.AddRecoverable(ctx, graph.Stack(fctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
link, ok := ptr.ValOK(resp.GetOdataNextLink())
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
builder = users.NewItemContactFoldersItemChildFoldersRequestBuilder(link, c.Stable.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
return el.Failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// item pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var _ itemPager = &contactPager{}
|
||||||
|
|
||||||
|
type contactPager struct {
|
||||||
|
gs graph.Servicer
|
||||||
|
builder *users.ItemContactFoldersItemContactsRequestBuilder
|
||||||
|
options *users.ItemContactFoldersItemContactsRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Contacts) NewContactPager(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID string,
|
||||||
|
immutableIDs bool,
|
||||||
|
) itemPager {
|
||||||
|
config := &users.ItemContactFoldersItemContactsRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &users.ItemContactFoldersItemContactsRequestBuilderGetQueryParameters{
|
||||||
|
Select: idAnd(parentFolderID),
|
||||||
|
},
|
||||||
|
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
||||||
|
}
|
||||||
|
|
||||||
|
builder := c.Stable.
|
||||||
|
Client().
|
||||||
|
Users().
|
||||||
|
ByUserId(userID).
|
||||||
|
ContactFolders().
|
||||||
|
ByContactFolderId(containerID).
|
||||||
|
Contacts()
|
||||||
|
|
||||||
|
return &contactPager{c.Stable, builder, config}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *contactPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||||
|
resp, err := p.builder.Get(ctx, p.options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return EmptyDeltaLinker[models.Contactable]{PageLinkValuer: resp}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *contactPager) setNext(nextLink string) {
|
||||||
|
p.builder = users.NewItemContactFoldersItemContactsRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
// non delta pagers don't need reset
|
||||||
|
func (p *contactPager) reset(context.Context) {}
|
||||||
|
|
||||||
|
func (p *contactPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||||
|
return toValues[models.Contactable](pl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// delta item pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var _ itemPager = &contactDeltaPager{}
|
||||||
|
|
||||||
|
type contactDeltaPager struct {
|
||||||
|
gs graph.Servicer
|
||||||
|
userID string
|
||||||
|
containerID string
|
||||||
|
builder *users.ItemContactFoldersItemContactsDeltaRequestBuilder
|
||||||
|
options *users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func getContactDeltaBuilder(
|
||||||
|
ctx context.Context,
|
||||||
|
gs graph.Servicer,
|
||||||
|
userID, containerID string,
|
||||||
|
options *users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration,
|
||||||
|
) *users.ItemContactFoldersItemContactsDeltaRequestBuilder {
|
||||||
|
builder := gs.Client().Users().ByUserId(userID).ContactFolders().ByContactFolderId(containerID).Contacts().Delta()
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Contacts) NewContactDeltaPager(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
|
) itemPager {
|
||||||
|
options := &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetQueryParameters{
|
||||||
|
Select: idAnd(parentFolderID),
|
||||||
|
},
|
||||||
|
Headers: newPreferHeaders(preferPageSize(maxDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder *users.ItemContactFoldersItemContactsDeltaRequestBuilder
|
||||||
|
if oldDelta != "" {
|
||||||
|
builder = users.NewItemContactFoldersItemContactsDeltaRequestBuilder(oldDelta, c.Stable.Adapter())
|
||||||
|
} else {
|
||||||
|
builder = getContactDeltaBuilder(ctx, c.Stable, userID, containerID, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &contactDeltaPager{c.Stable, userID, containerID, builder, options}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *contactDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||||
|
resp, err := p.builder.Get(ctx, p.options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *contactDeltaPager) setNext(nextLink string) {
|
||||||
|
p.builder = users.NewItemContactFoldersItemContactsDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *contactDeltaPager) reset(ctx context.Context) {
|
||||||
|
p.builder = getContactDeltaBuilder(ctx, p.gs, p.userID, p.containerID, p.options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *contactDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||||
|
return toValues[models.Contactable](pl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Contacts) GetAddedAndRemovedItemIDs(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
|
canMakeDeltaQueries bool,
|
||||||
|
) ([]string, []string, DeltaUpdate, error) {
|
||||||
|
ctx = clues.Add(
|
||||||
|
ctx,
|
||||||
|
"category", selectors.ExchangeContact,
|
||||||
|
"container_id", containerID)
|
||||||
|
|
||||||
|
pager := c.NewContactPager(ctx, userID, containerID, immutableIDs)
|
||||||
|
deltaPager := c.NewContactDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||||
|
|
||||||
|
return getAddedAndRemovedItemIDs(ctx, c.Stable, pager, deltaPager, oldDelta, canMakeDeltaQueries)
|
||||||
|
}
|
||||||
@ -18,7 +18,6 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -190,86 +189,6 @@ func (c Events) PatchCalendar(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// container pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// EnumerateContainers iterates through all of the users current
|
|
||||||
// calendars, converting each to a graph.CacheFolder, and
|
|
||||||
// calling fn(cf) on each one.
|
|
||||||
// Folder hierarchy is represented in its current state, and does
|
|
||||||
// not contain historical data.
|
|
||||||
func (c Events) EnumerateContainers(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, baseContainerID string,
|
|
||||||
fn func(graph.CachedContainer) error,
|
|
||||||
errs *fault.Bus,
|
|
||||||
) error {
|
|
||||||
var (
|
|
||||||
el = errs.Local()
|
|
||||||
config = &users.ItemCalendarsRequestBuilderGetRequestConfiguration{
|
|
||||||
QueryParameters: &users.ItemCalendarsRequestBuilderGetQueryParameters{
|
|
||||||
Select: idAnd("name"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
builder = c.Stable.
|
|
||||||
Client().
|
|
||||||
Users().
|
|
||||||
ByUserId(userID).
|
|
||||||
Calendars()
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
if el.Failure() != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := builder.Get(ctx, config)
|
|
||||||
if err != nil {
|
|
||||||
return graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, cal := range resp.GetValue() {
|
|
||||||
if el.Failure() != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
cd := CalendarDisplayable{Calendarable: cal}
|
|
||||||
if err := graph.CheckIDAndName(cd); err != nil {
|
|
||||||
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fctx := clues.Add(
|
|
||||||
ctx,
|
|
||||||
"container_id", ptr.Val(cal.GetId()),
|
|
||||||
"container_name", ptr.Val(cal.GetName()))
|
|
||||||
|
|
||||||
temp := graph.NewCacheFolder(
|
|
||||||
cd,
|
|
||||||
path.Builder{}.Append(ptr.Val(cd.GetId())), // storage path
|
|
||||||
path.Builder{}.Append(ptr.Val(cd.GetDisplayName()))) // display location
|
|
||||||
if err := fn(&temp); err != nil {
|
|
||||||
errs.AddRecoverable(ctx, graph.Stack(fctx, err).Label(fault.LabelForceNoBackupCreation))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
link, ok := ptr.ValOK(resp.GetOdataNextLink())
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
builder = users.NewItemCalendarsRequestBuilder(link, c.Stable.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
return el.Failure()
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
eventBetaDeltaURLTemplate = "https://graph.microsoft.com/beta/users/%s/calendars/%s/events/delta"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// items
|
// items
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -434,154 +353,6 @@ func (c Events) PostLargeAttachment(
|
|||||||
return us, nil
|
return us, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// item pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
var _ itemPager = &eventPager{}
|
|
||||||
|
|
||||||
type eventPager struct {
|
|
||||||
gs graph.Servicer
|
|
||||||
builder *users.ItemCalendarsItemEventsRequestBuilder
|
|
||||||
options *users.ItemCalendarsItemEventsRequestBuilderGetRequestConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Events) NewEventPager(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID string,
|
|
||||||
immutableIDs bool,
|
|
||||||
) (itemPager, error) {
|
|
||||||
options := &users.ItemCalendarsItemEventsRequestBuilderGetRequestConfiguration{
|
|
||||||
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
|
||||||
}
|
|
||||||
|
|
||||||
builder := c.Stable.
|
|
||||||
Client().
|
|
||||||
Users().
|
|
||||||
ByUserId(userID).
|
|
||||||
Calendars().
|
|
||||||
ByCalendarId(containerID).
|
|
||||||
Events()
|
|
||||||
|
|
||||||
return &eventPager{c.Stable, builder, options}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *eventPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
|
||||||
resp, err := p.builder.Get(ctx, p.options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return EmptyDeltaLinker[models.Eventable]{PageLinkValuer: resp}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *eventPager) setNext(nextLink string) {
|
|
||||||
p.builder = users.NewItemCalendarsItemEventsRequestBuilder(nextLink, p.gs.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
// non delta pagers don't need reset
|
|
||||||
func (p *eventPager) reset(context.Context) {}
|
|
||||||
|
|
||||||
func (p *eventPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
|
||||||
return toValues[models.Eventable](pl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// delta item pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
var _ itemPager = &eventDeltaPager{}
|
|
||||||
|
|
||||||
type eventDeltaPager struct {
|
|
||||||
gs graph.Servicer
|
|
||||||
userID string
|
|
||||||
containerID string
|
|
||||||
builder *users.ItemCalendarsItemEventsDeltaRequestBuilder
|
|
||||||
options *users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Events) NewEventDeltaPager(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID, oldDelta string,
|
|
||||||
immutableIDs bool,
|
|
||||||
) (itemPager, error) {
|
|
||||||
options := &users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration{
|
|
||||||
Headers: newPreferHeaders(preferPageSize(maxDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
|
||||||
}
|
|
||||||
|
|
||||||
var builder *users.ItemCalendarsItemEventsDeltaRequestBuilder
|
|
||||||
|
|
||||||
if oldDelta == "" {
|
|
||||||
builder = getEventDeltaBuilder(ctx, c.Stable, userID, containerID, options)
|
|
||||||
} else {
|
|
||||||
builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(oldDelta, c.Stable.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
return &eventDeltaPager{c.Stable, userID, containerID, builder, options}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEventDeltaBuilder(
|
|
||||||
ctx context.Context,
|
|
||||||
gs graph.Servicer,
|
|
||||||
userID, containerID string,
|
|
||||||
options *users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration,
|
|
||||||
) *users.ItemCalendarsItemEventsDeltaRequestBuilder {
|
|
||||||
// Graph SDK only supports delta queries against events on the beta version, so we're
|
|
||||||
// manufacturing use of the beta version url to make the call instead.
|
|
||||||
// See: https://learn.microsoft.com/ko-kr/graph/api/event-delta?view=graph-rest-beta&tabs=http
|
|
||||||
// Note that the delta item body is skeletal compared to the actual event struct. Lucky
|
|
||||||
// for us, we only need the item ID. As a result, even though we hacked the version, the
|
|
||||||
// response body parses properly into the v1.0 structs and complies with our wanted interfaces.
|
|
||||||
// Likewise, the NextLink and DeltaLink odata tags carry our hack forward, so the rest of the code
|
|
||||||
// works as intended (until, at least, we want to _not_ call the beta anymore).
|
|
||||||
rawURL := fmt.Sprintf(eventBetaDeltaURLTemplate, userID, containerID)
|
|
||||||
builder := users.NewItemCalendarsItemEventsDeltaRequestBuilder(rawURL, gs.Adapter())
|
|
||||||
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *eventDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
|
||||||
resp, err := p.builder.Get(ctx, p.options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *eventDeltaPager) setNext(nextLink string) {
|
|
||||||
p.builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *eventDeltaPager) reset(ctx context.Context) {
|
|
||||||
p.builder = getEventDeltaBuilder(ctx, p.gs, p.userID, p.containerID, p.options)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *eventDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
|
||||||
return toValues[models.Eventable](pl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Events) GetAddedAndRemovedItemIDs(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID, oldDelta string,
|
|
||||||
immutableIDs bool,
|
|
||||||
canMakeDeltaQueries bool,
|
|
||||||
) ([]string, []string, DeltaUpdate, error) {
|
|
||||||
ctx = clues.Add(ctx, "container_id", containerID)
|
|
||||||
|
|
||||||
pager, err := c.NewEventPager(ctx, userID, containerID, immutableIDs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, DeltaUpdate{}, graph.Wrap(ctx, err, "creating non-delta pager")
|
|
||||||
}
|
|
||||||
|
|
||||||
deltaPager, err := c.NewEventDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, DeltaUpdate{}, graph.Wrap(ctx, err, "creating delta pager")
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAddedAndRemovedItemIDs(ctx, c.Stable, pager, deltaPager, oldDelta, canMakeDeltaQueries)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Serialization
|
// Serialization
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
243
src/pkg/services/m365/api/events_pager.go
Normal file
243
src/pkg/services/m365/api/events_pager.go
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/users"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
eventBetaDeltaURLTemplate = "https://graph.microsoft.com/beta/users/%s/calendars/%s/events/delta"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// container pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// EnumerateContainers iterates through all of the users current
|
||||||
|
// calendars, converting each to a graph.CacheFolder, and
|
||||||
|
// calling fn(cf) on each one.
|
||||||
|
// Folder hierarchy is represented in its current state, and does
|
||||||
|
// not contain historical data.
|
||||||
|
func (c Events) EnumerateContainers(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, baseContainerID string,
|
||||||
|
fn func(graph.CachedContainer) error,
|
||||||
|
errs *fault.Bus,
|
||||||
|
) error {
|
||||||
|
var (
|
||||||
|
el = errs.Local()
|
||||||
|
config = &users.ItemCalendarsRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &users.ItemCalendarsRequestBuilderGetQueryParameters{
|
||||||
|
Select: idAnd("name"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
builder = c.Stable.
|
||||||
|
Client().
|
||||||
|
Users().
|
||||||
|
ByUserId(userID).
|
||||||
|
Calendars()
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if el.Failure() != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := builder.Get(ctx, config)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cal := range resp.GetValue() {
|
||||||
|
if el.Failure() != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
cd := CalendarDisplayable{Calendarable: cal}
|
||||||
|
if err := graph.CheckIDAndName(cd); err != nil {
|
||||||
|
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fctx := clues.Add(
|
||||||
|
ctx,
|
||||||
|
"container_id", ptr.Val(cal.GetId()),
|
||||||
|
"container_name", ptr.Val(cal.GetName()))
|
||||||
|
|
||||||
|
temp := graph.NewCacheFolder(
|
||||||
|
cd,
|
||||||
|
path.Builder{}.Append(ptr.Val(cd.GetId())), // storage path
|
||||||
|
path.Builder{}.Append(ptr.Val(cd.GetDisplayName()))) // display location
|
||||||
|
if err := fn(&temp); err != nil {
|
||||||
|
errs.AddRecoverable(ctx, graph.Stack(fctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
link, ok := ptr.ValOK(resp.GetOdataNextLink())
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
builder = users.NewItemCalendarsRequestBuilder(link, c.Stable.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
return el.Failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// item pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var _ itemPager = &eventPager{}
|
||||||
|
|
||||||
|
type eventPager struct {
|
||||||
|
gs graph.Servicer
|
||||||
|
builder *users.ItemCalendarsItemEventsRequestBuilder
|
||||||
|
options *users.ItemCalendarsItemEventsRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Events) NewEventPager(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID string,
|
||||||
|
immutableIDs bool,
|
||||||
|
) (itemPager, error) {
|
||||||
|
options := &users.ItemCalendarsItemEventsRequestBuilderGetRequestConfiguration{
|
||||||
|
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
||||||
|
}
|
||||||
|
|
||||||
|
builder := c.Stable.
|
||||||
|
Client().
|
||||||
|
Users().
|
||||||
|
ByUserId(userID).
|
||||||
|
Calendars().
|
||||||
|
ByCalendarId(containerID).
|
||||||
|
Events()
|
||||||
|
|
||||||
|
return &eventPager{c.Stable, builder, options}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *eventPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||||
|
resp, err := p.builder.Get(ctx, p.options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return EmptyDeltaLinker[models.Eventable]{PageLinkValuer: resp}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *eventPager) setNext(nextLink string) {
|
||||||
|
p.builder = users.NewItemCalendarsItemEventsRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
// non delta pagers don't need reset
|
||||||
|
func (p *eventPager) reset(context.Context) {}
|
||||||
|
|
||||||
|
func (p *eventPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||||
|
return toValues[models.Eventable](pl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// delta item pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var _ itemPager = &eventDeltaPager{}
|
||||||
|
|
||||||
|
type eventDeltaPager struct {
|
||||||
|
gs graph.Servicer
|
||||||
|
userID string
|
||||||
|
containerID string
|
||||||
|
builder *users.ItemCalendarsItemEventsDeltaRequestBuilder
|
||||||
|
options *users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Events) NewEventDeltaPager(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
|
) (itemPager, error) {
|
||||||
|
options := &users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration{
|
||||||
|
Headers: newPreferHeaders(preferPageSize(maxDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder *users.ItemCalendarsItemEventsDeltaRequestBuilder
|
||||||
|
|
||||||
|
if oldDelta == "" {
|
||||||
|
builder = getEventDeltaBuilder(ctx, c.Stable, userID, containerID, options)
|
||||||
|
} else {
|
||||||
|
builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(oldDelta, c.Stable.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
return &eventDeltaPager{c.Stable, userID, containerID, builder, options}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEventDeltaBuilder(
|
||||||
|
ctx context.Context,
|
||||||
|
gs graph.Servicer,
|
||||||
|
userID, containerID string,
|
||||||
|
options *users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration,
|
||||||
|
) *users.ItemCalendarsItemEventsDeltaRequestBuilder {
|
||||||
|
// Graph SDK only supports delta queries against events on the beta version, so we're
|
||||||
|
// manufacturing use of the beta version url to make the call instead.
|
||||||
|
// See: https://learn.microsoft.com/ko-kr/graph/api/event-delta?view=graph-rest-beta&tabs=http
|
||||||
|
// Note that the delta item body is skeletal compared to the actual event struct. Lucky
|
||||||
|
// for us, we only need the item ID. As a result, even though we hacked the version, the
|
||||||
|
// response body parses properly into the v1.0 structs and complies with our wanted interfaces.
|
||||||
|
// Likewise, the NextLink and DeltaLink odata tags carry our hack forward, so the rest of the code
|
||||||
|
// works as intended (until, at least, we want to _not_ call the beta anymore).
|
||||||
|
rawURL := fmt.Sprintf(eventBetaDeltaURLTemplate, userID, containerID)
|
||||||
|
builder := users.NewItemCalendarsItemEventsDeltaRequestBuilder(rawURL, gs.Adapter())
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *eventDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||||
|
resp, err := p.builder.Get(ctx, p.options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *eventDeltaPager) setNext(nextLink string) {
|
||||||
|
p.builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *eventDeltaPager) reset(ctx context.Context) {
|
||||||
|
p.builder = getEventDeltaBuilder(ctx, p.gs, p.userID, p.containerID, p.options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *eventDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||||
|
return toValues[models.Eventable](pl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Events) GetAddedAndRemovedItemIDs(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
|
canMakeDeltaQueries bool,
|
||||||
|
) ([]string, []string, DeltaUpdate, error) {
|
||||||
|
ctx = clues.Add(ctx, "container_id", containerID)
|
||||||
|
|
||||||
|
pager, err := c.NewEventPager(ctx, userID, containerID, immutableIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, DeltaUpdate{}, graph.Wrap(ctx, err, "creating non-delta pager")
|
||||||
|
}
|
||||||
|
|
||||||
|
deltaPager, err := c.NewEventDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, DeltaUpdate{}, graph.Wrap(ctx, err, "creating delta pager")
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAddedAndRemovedItemIDs(ctx, c.Stable, pager, deltaPager, oldDelta, canMakeDeltaQueries)
|
||||||
|
}
|
||||||
@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"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/logger"
|
||||||
"github.com/alcionai/corso/src/pkg/selectors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -188,109 +187,6 @@ func (c Mail) PatchFolder(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// container pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type mailFolderPager struct {
|
|
||||||
service graph.Servicer
|
|
||||||
builder *users.ItemMailFoldersRequestBuilder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Mail) NewMailFolderPager(userID string) mailFolderPager {
|
|
||||||
// v1.0 non delta /mailFolders endpoint does not return any of the nested folders
|
|
||||||
rawURL := fmt.Sprintf(mailFoldersBetaURLTemplate, userID)
|
|
||||||
builder := users.NewItemMailFoldersRequestBuilder(rawURL, c.Stable.Adapter())
|
|
||||||
|
|
||||||
return mailFolderPager{c.Stable, builder}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailFolderPager) getPage(ctx context.Context) (PageLinker, error) {
|
|
||||||
page, err := p.builder.Get(ctx, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return page, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailFolderPager) setNext(nextLink string) {
|
|
||||||
p.builder = users.NewItemMailFoldersRequestBuilder(nextLink, p.service.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailFolderPager) valuesIn(pl PageLinker) ([]models.MailFolderable, error) {
|
|
||||||
// Ideally this should be `users.ItemMailFoldersResponseable`, but
|
|
||||||
// that is not a thing as stable returns different result
|
|
||||||
page, ok := pl.(models.MailFolderCollectionResponseable)
|
|
||||||
if !ok {
|
|
||||||
return nil, clues.New("converting to ItemMailFoldersResponseable")
|
|
||||||
}
|
|
||||||
|
|
||||||
return page.GetValue(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnumerateContainers iterates through all of the users current
|
|
||||||
// mail folders, converting each to a graph.CacheFolder, and calling
|
|
||||||
// fn(cf) on each one.
|
|
||||||
// Folder hierarchy is represented in its current state, and does
|
|
||||||
// not contain historical data.
|
|
||||||
func (c Mail) EnumerateContainers(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, baseContainerID string,
|
|
||||||
fn func(graph.CachedContainer) error,
|
|
||||||
errs *fault.Bus,
|
|
||||||
) error {
|
|
||||||
el := errs.Local()
|
|
||||||
pgr := c.NewMailFolderPager(userID)
|
|
||||||
|
|
||||||
for {
|
|
||||||
if el.Failure() != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
page, err := pgr.getPage(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := pgr.valuesIn(page)
|
|
||||||
if err != nil {
|
|
||||||
return graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fold := range resp {
|
|
||||||
if el.Failure() != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := graph.CheckIDNameAndParentFolderID(fold); err != nil {
|
|
||||||
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fctx := clues.Add(
|
|
||||||
ctx,
|
|
||||||
"container_id", ptr.Val(fold.GetId()),
|
|
||||||
"container_name", ptr.Val(fold.GetDisplayName()))
|
|
||||||
|
|
||||||
temp := graph.NewCacheFolder(fold, nil, nil)
|
|
||||||
if err := fn(&temp); err != nil {
|
|
||||||
errs.AddRecoverable(ctx, graph.Stack(fctx, err).Label(fault.LabelForceNoBackupCreation))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
link, ok := ptr.ValOK(page.GetOdataNextLink())
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
pgr.setNext(link)
|
|
||||||
}
|
|
||||||
|
|
||||||
return el.Failure()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// items
|
// items
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -549,161 +445,6 @@ func (c Mail) PostLargeAttachment(
|
|||||||
return us, nil
|
return us, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// item pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
var _ itemPager = &mailPager{}
|
|
||||||
|
|
||||||
type mailPager struct {
|
|
||||||
gs graph.Servicer
|
|
||||||
builder *users.ItemMailFoldersItemMessagesRequestBuilder
|
|
||||||
options *users.ItemMailFoldersItemMessagesRequestBuilderGetRequestConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Mail) NewMailPager(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID string,
|
|
||||||
immutableIDs bool,
|
|
||||||
) itemPager {
|
|
||||||
config := &users.ItemMailFoldersItemMessagesRequestBuilderGetRequestConfiguration{
|
|
||||||
QueryParameters: &users.ItemMailFoldersItemMessagesRequestBuilderGetQueryParameters{
|
|
||||||
Select: idAnd("isRead"),
|
|
||||||
},
|
|
||||||
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
|
||||||
}
|
|
||||||
|
|
||||||
builder := c.Stable.
|
|
||||||
Client().
|
|
||||||
Users().
|
|
||||||
ByUserId(userID).
|
|
||||||
MailFolders().
|
|
||||||
ByMailFolderId(containerID).
|
|
||||||
Messages()
|
|
||||||
|
|
||||||
return &mailPager{c.Stable, builder, config}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
|
||||||
page, err := p.builder.Get(ctx, p.options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return EmptyDeltaLinker[models.Messageable]{PageLinkValuer: page}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailPager) setNext(nextLink string) {
|
|
||||||
p.builder = users.NewItemMailFoldersItemMessagesRequestBuilder(nextLink, p.gs.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
// non delta pagers don't have reset
|
|
||||||
func (p *mailPager) reset(context.Context) {}
|
|
||||||
|
|
||||||
func (p *mailPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
|
||||||
return toValues[models.Messageable](pl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// delta item pager
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
var _ itemPager = &mailDeltaPager{}
|
|
||||||
|
|
||||||
type mailDeltaPager struct {
|
|
||||||
gs graph.Servicer
|
|
||||||
userID string
|
|
||||||
containerID string
|
|
||||||
builder *users.ItemMailFoldersItemMessagesDeltaRequestBuilder
|
|
||||||
options *users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMailDeltaBuilder(
|
|
||||||
ctx context.Context,
|
|
||||||
gs graph.Servicer,
|
|
||||||
user, containerID string,
|
|
||||||
options *users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration,
|
|
||||||
) *users.ItemMailFoldersItemMessagesDeltaRequestBuilder {
|
|
||||||
builder := gs.
|
|
||||||
Client().
|
|
||||||
Users().
|
|
||||||
ByUserId(user).
|
|
||||||
MailFolders().
|
|
||||||
ByMailFolderId(containerID).
|
|
||||||
Messages().
|
|
||||||
Delta()
|
|
||||||
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Mail) NewMailDeltaPager(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID, oldDelta string,
|
|
||||||
immutableIDs bool,
|
|
||||||
) itemPager {
|
|
||||||
config := &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration{
|
|
||||||
QueryParameters: &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetQueryParameters{
|
|
||||||
Select: idAnd("isRead"),
|
|
||||||
},
|
|
||||||
Headers: newPreferHeaders(preferPageSize(maxDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
|
||||||
}
|
|
||||||
|
|
||||||
var builder *users.ItemMailFoldersItemMessagesDeltaRequestBuilder
|
|
||||||
|
|
||||||
if len(oldDelta) > 0 {
|
|
||||||
builder = users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(oldDelta, c.Stable.Adapter())
|
|
||||||
} else {
|
|
||||||
builder = getMailDeltaBuilder(ctx, c.Stable, userID, containerID, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mailDeltaPager{c.Stable, userID, containerID, builder, config}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
|
||||||
page, err := p.builder.Get(ctx, p.options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, graph.Stack(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return page, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailDeltaPager) setNext(nextLink string) {
|
|
||||||
p.builder = users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailDeltaPager) reset(ctx context.Context) {
|
|
||||||
p.builder = p.gs.
|
|
||||||
Client().
|
|
||||||
Users().
|
|
||||||
ByUserId(p.userID).
|
|
||||||
MailFolders().
|
|
||||||
ByMailFolderId(p.containerID).
|
|
||||||
Messages().
|
|
||||||
Delta()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mailDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
|
||||||
return toValues[models.Messageable](pl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Mail) GetAddedAndRemovedItemIDs(
|
|
||||||
ctx context.Context,
|
|
||||||
userID, containerID, oldDelta string,
|
|
||||||
immutableIDs bool,
|
|
||||||
canMakeDeltaQueries bool,
|
|
||||||
) ([]string, []string, DeltaUpdate, error) {
|
|
||||||
ctx = clues.Add(
|
|
||||||
ctx,
|
|
||||||
"category", selectors.ExchangeMail,
|
|
||||||
"container_id", containerID)
|
|
||||||
|
|
||||||
pager := c.NewMailPager(ctx, userID, containerID, immutableIDs)
|
|
||||||
deltaPager := c.NewMailDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
|
||||||
|
|
||||||
return getAddedAndRemovedItemIDs(ctx, c.Stable, pager, deltaPager, oldDelta, canMakeDeltaQueries)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Serialization
|
// Serialization
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
273
src/pkg/services/m365/api/mail_pager.go
Normal file
273
src/pkg/services/m365/api/mail_pager.go
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/users"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// container pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type mailFolderPager struct {
|
||||||
|
service graph.Servicer
|
||||||
|
builder *users.ItemMailFoldersRequestBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Mail) NewMailFolderPager(userID string) mailFolderPager {
|
||||||
|
// v1.0 non delta /mailFolders endpoint does not return any of the nested folders
|
||||||
|
rawURL := fmt.Sprintf(mailFoldersBetaURLTemplate, userID)
|
||||||
|
builder := users.NewItemMailFoldersRequestBuilder(rawURL, c.Stable.Adapter())
|
||||||
|
|
||||||
|
return mailFolderPager{c.Stable, builder}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailFolderPager) getPage(ctx context.Context) (PageLinker, error) {
|
||||||
|
page, err := p.builder.Get(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return page, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailFolderPager) setNext(nextLink string) {
|
||||||
|
p.builder = users.NewItemMailFoldersRequestBuilder(nextLink, p.service.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailFolderPager) valuesIn(pl PageLinker) ([]models.MailFolderable, error) {
|
||||||
|
// Ideally this should be `users.ItemMailFoldersResponseable`, but
|
||||||
|
// that is not a thing as stable returns different result
|
||||||
|
page, ok := pl.(models.MailFolderCollectionResponseable)
|
||||||
|
if !ok {
|
||||||
|
return nil, clues.New("converting to ItemMailFoldersResponseable")
|
||||||
|
}
|
||||||
|
|
||||||
|
return page.GetValue(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnumerateContainers iterates through all of the users current
|
||||||
|
// mail folders, converting each to a graph.CacheFolder, and calling
|
||||||
|
// fn(cf) on each one.
|
||||||
|
// Folder hierarchy is represented in its current state, and does
|
||||||
|
// not contain historical data.
|
||||||
|
func (c Mail) EnumerateContainers(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, baseContainerID string,
|
||||||
|
fn func(graph.CachedContainer) error,
|
||||||
|
errs *fault.Bus,
|
||||||
|
) error {
|
||||||
|
el := errs.Local()
|
||||||
|
pgr := c.NewMailFolderPager(userID)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if el.Failure() != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
page, err := pgr.getPage(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := pgr.valuesIn(page)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fold := range resp {
|
||||||
|
if el.Failure() != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := graph.CheckIDNameAndParentFolderID(fold); err != nil {
|
||||||
|
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fctx := clues.Add(
|
||||||
|
ctx,
|
||||||
|
"container_id", ptr.Val(fold.GetId()),
|
||||||
|
"container_name", ptr.Val(fold.GetDisplayName()))
|
||||||
|
|
||||||
|
temp := graph.NewCacheFolder(fold, nil, nil)
|
||||||
|
if err := fn(&temp); err != nil {
|
||||||
|
errs.AddRecoverable(ctx, graph.Stack(fctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
link, ok := ptr.ValOK(page.GetOdataNextLink())
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
pgr.setNext(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
return el.Failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// item pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var _ itemPager = &mailPager{}
|
||||||
|
|
||||||
|
type mailPager struct {
|
||||||
|
gs graph.Servicer
|
||||||
|
builder *users.ItemMailFoldersItemMessagesRequestBuilder
|
||||||
|
options *users.ItemMailFoldersItemMessagesRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Mail) NewMailPager(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID string,
|
||||||
|
immutableIDs bool,
|
||||||
|
) itemPager {
|
||||||
|
config := &users.ItemMailFoldersItemMessagesRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &users.ItemMailFoldersItemMessagesRequestBuilderGetQueryParameters{
|
||||||
|
Select: idAnd("isRead"),
|
||||||
|
},
|
||||||
|
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
||||||
|
}
|
||||||
|
|
||||||
|
builder := c.Stable.
|
||||||
|
Client().
|
||||||
|
Users().
|
||||||
|
ByUserId(userID).
|
||||||
|
MailFolders().
|
||||||
|
ByMailFolderId(containerID).
|
||||||
|
Messages()
|
||||||
|
|
||||||
|
return &mailPager{c.Stable, builder, config}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||||
|
page, err := p.builder.Get(ctx, p.options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return EmptyDeltaLinker[models.Messageable]{PageLinkValuer: page}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailPager) setNext(nextLink string) {
|
||||||
|
p.builder = users.NewItemMailFoldersItemMessagesRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
// non delta pagers don't have reset
|
||||||
|
func (p *mailPager) reset(context.Context) {}
|
||||||
|
|
||||||
|
func (p *mailPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||||
|
return toValues[models.Messageable](pl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// delta item pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var _ itemPager = &mailDeltaPager{}
|
||||||
|
|
||||||
|
type mailDeltaPager struct {
|
||||||
|
gs graph.Servicer
|
||||||
|
userID string
|
||||||
|
containerID string
|
||||||
|
builder *users.ItemMailFoldersItemMessagesDeltaRequestBuilder
|
||||||
|
options *users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMailDeltaBuilder(
|
||||||
|
ctx context.Context,
|
||||||
|
gs graph.Servicer,
|
||||||
|
user, containerID string,
|
||||||
|
options *users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration,
|
||||||
|
) *users.ItemMailFoldersItemMessagesDeltaRequestBuilder {
|
||||||
|
builder := gs.
|
||||||
|
Client().
|
||||||
|
Users().
|
||||||
|
ByUserId(user).
|
||||||
|
MailFolders().
|
||||||
|
ByMailFolderId(containerID).
|
||||||
|
Messages().
|
||||||
|
Delta()
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Mail) NewMailDeltaPager(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
|
) itemPager {
|
||||||
|
config := &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetQueryParameters{
|
||||||
|
Select: idAnd("isRead"),
|
||||||
|
},
|
||||||
|
Headers: newPreferHeaders(preferPageSize(maxDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder *users.ItemMailFoldersItemMessagesDeltaRequestBuilder
|
||||||
|
|
||||||
|
if len(oldDelta) > 0 {
|
||||||
|
builder = users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(oldDelta, c.Stable.Adapter())
|
||||||
|
} else {
|
||||||
|
builder = getMailDeltaBuilder(ctx, c.Stable, userID, containerID, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &mailDeltaPager{c.Stable, userID, containerID, builder, config}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||||
|
page, err := p.builder.Get(ctx, p.options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return page, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailDeltaPager) setNext(nextLink string) {
|
||||||
|
p.builder = users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailDeltaPager) reset(ctx context.Context) {
|
||||||
|
p.builder = p.gs.
|
||||||
|
Client().
|
||||||
|
Users().
|
||||||
|
ByUserId(p.userID).
|
||||||
|
MailFolders().
|
||||||
|
ByMailFolderId(p.containerID).
|
||||||
|
Messages().
|
||||||
|
Delta()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mailDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||||
|
return toValues[models.Messageable](pl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Mail) GetAddedAndRemovedItemIDs(
|
||||||
|
ctx context.Context,
|
||||||
|
userID, containerID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
|
canMakeDeltaQueries bool,
|
||||||
|
) ([]string, []string, DeltaUpdate, error) {
|
||||||
|
ctx = clues.Add(
|
||||||
|
ctx,
|
||||||
|
"category", selectors.ExchangeMail,
|
||||||
|
"container_id", containerID)
|
||||||
|
|
||||||
|
pager := c.NewMailPager(ctx, userID, containerID, immutableIDs)
|
||||||
|
deltaPager := c.NewMailDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||||
|
|
||||||
|
return getAddedAndRemovedItemIDs(ctx, c.Stable, pager, deltaPager, oldDelta, canMakeDeltaQueries)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user