get details working (and other cleanup) (#5116)
details wasn't properly listing backed up items. This fixes the details display, and contains some code clean-up that occurred along the way.
This commit is contained in:
parent
316e5f0195
commit
0efe25bb71
@ -213,7 +213,6 @@ func runDetailsTeamsChatsCmd(cmd *cobra.Command) error {
|
|||||||
opts := utils.MakeTeamsChatsOpts(cmd)
|
opts := utils.MakeTeamsChatsOpts(cmd)
|
||||||
|
|
||||||
sel := utils.IncludeTeamsChatsRestoreDataSelectors(ctx, opts)
|
sel := utils.IncludeTeamsChatsRestoreDataSelectors(ctx, opts)
|
||||||
sel.Configure(selectors.Config{OnlyMatchItemNames: true})
|
|
||||||
utils.FilterTeamsChatsRestoreInfoSelectors(sel, opts)
|
utils.FilterTeamsChatsRestoreInfoSelectors(sel, opts)
|
||||||
|
|
||||||
ds, err := genericDetailsCommand(cmd, flags.BackupIDFV, sel.Selector)
|
ds, err := genericDetailsCommand(cmd, flags.BackupIDFV, sel.Selector)
|
||||||
|
|||||||
@ -89,7 +89,10 @@ func IncludeTeamsChatsRestoreDataSelectors(ctx context.Context, opts TeamsChatsO
|
|||||||
users = selectors.Any()
|
users = selectors.Any()
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectors.NewTeamsChatsRestore(users)
|
sel := selectors.NewTeamsChatsRestore(users)
|
||||||
|
sel.Include(sel.Chats(selectors.Any()))
|
||||||
|
|
||||||
|
return sel
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterTeamsChatsRestoreInfoSelectors builds the common info-selector filters.
|
// FilterTeamsChatsRestoreInfoSelectors builds the common info-selector filters.
|
||||||
|
|||||||
@ -115,11 +115,8 @@ func populateCollection[I chatsItemer](
|
|||||||
)
|
)
|
||||||
|
|
||||||
ctx = clues.AddLabelCounter(ctx, cl.PlainAdder())
|
ctx = clues.AddLabelCounter(ctx, cl.PlainAdder())
|
||||||
cc := api.CallConfig{
|
|
||||||
CanMakeDeltaQueries: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
items, err := bh.getItemIDs(ctx, cc)
|
items, err := bh.getItemIDs(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.AddRecoverable(ctx, clues.Stack(err))
|
errs.AddRecoverable(ctx, clues.Stack(err))
|
||||||
return collection, clues.Stack(errs.Failure()).OrNil()
|
return collection, clues.Stack(errs.Failure()).OrNil()
|
||||||
|
|||||||
@ -49,14 +49,6 @@ type mockBackupHandler struct {
|
|||||||
doNotInclude bool
|
doNotInclude bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//lint:ignore U1000 false linter issue due to generics
|
|
||||||
func (bh mockBackupHandler) augmentItemInfo(
|
|
||||||
*details.TeamsChatsInfo,
|
|
||||||
models.Chatable,
|
|
||||||
) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bh mockBackupHandler) container() container[models.Chatable] {
|
func (bh mockBackupHandler) container() container[models.Chatable] {
|
||||||
return chatContainer()
|
return chatContainer()
|
||||||
}
|
}
|
||||||
@ -71,7 +63,6 @@ func (bh mockBackupHandler) getContainer(
|
|||||||
|
|
||||||
func (bh mockBackupHandler) getItemIDs(
|
func (bh mockBackupHandler) getItemIDs(
|
||||||
_ context.Context,
|
_ context.Context,
|
||||||
_ api.CallConfig,
|
|
||||||
) ([]models.Chatable, error) {
|
) ([]models.Chatable, error) {
|
||||||
return bh.chats, bh.chatsErr
|
return bh.chats, bh.chatsErr
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,8 +46,11 @@ func (bh usersChatsBackupHandler) getContainer(
|
|||||||
//lint:ignore U1000 required for interface compliance
|
//lint:ignore U1000 required for interface compliance
|
||||||
func (bh usersChatsBackupHandler) getItemIDs(
|
func (bh usersChatsBackupHandler) getItemIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
cc api.CallConfig,
|
|
||||||
) ([]models.Chatable, error) {
|
) ([]models.Chatable, error) {
|
||||||
|
cc := api.CallConfig{
|
||||||
|
Expand: []string{"lastMessagePreview"},
|
||||||
|
}
|
||||||
|
|
||||||
return bh.ac.GetChats(
|
return bh.ac.GetChats(
|
||||||
ctx,
|
ctx,
|
||||||
bh.protectedResourceID,
|
bh.protectedResourceID,
|
||||||
@ -89,26 +92,21 @@ func (bh usersChatsBackupHandler) getItem(
|
|||||||
|
|
||||||
chatID := ptr.Val(chat.GetId())
|
chatID := ptr.Val(chat.GetId())
|
||||||
|
|
||||||
cc := api.CallConfig{
|
msgs, err := bh.ac.GetChatMessages(ctx, chatID, api.CallConfig{})
|
||||||
Expand: []string{"lastMessagePreview"},
|
|
||||||
}
|
|
||||||
|
|
||||||
msgs, err := bh.ac.GetChatMessages(ctx, chatID, cc)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, clues.Stack(err)
|
return nil, nil, clues.Stack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chat.SetMessages(msgs)
|
chat.SetMessages(msgs)
|
||||||
|
|
||||||
return chat, api.TeamsChatInfo(chat), nil
|
members, err := bh.ac.GetChatMembers(ctx, chatID, api.CallConfig{})
|
||||||
}
|
if err != nil {
|
||||||
|
return nil, nil, clues.Stack(err)
|
||||||
|
}
|
||||||
|
|
||||||
//lint:ignore U1000 false linter issue due to generics
|
chat.SetMembers(members)
|
||||||
func (bh usersChatsBackupHandler) augmentItemInfo(
|
|
||||||
dgi *details.TeamsChatsInfo,
|
return chat, api.TeamsChatInfo(chat), nil
|
||||||
c models.Chatable,
|
|
||||||
) {
|
|
||||||
// no-op
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatContainer() container[models.Chatable] {
|
func chatContainer() container[models.Chatable] {
|
||||||
|
|||||||
@ -66,7 +66,7 @@ func updateStatus(
|
|||||||
// or notMoved (if they match).
|
// or notMoved (if they match).
|
||||||
func NewCollection[I chatsItemer](
|
func NewCollection[I chatsItemer](
|
||||||
baseCol data.BaseCollection,
|
baseCol data.BaseCollection,
|
||||||
getAndAugment getItemAndAugmentInfoer[I],
|
getter getItemer[I],
|
||||||
protectedResource string,
|
protectedResource string,
|
||||||
items []I,
|
items []I,
|
||||||
contains container[I],
|
contains container[I],
|
||||||
@ -76,7 +76,7 @@ func NewCollection[I chatsItemer](
|
|||||||
BaseCollection: baseCol,
|
BaseCollection: baseCol,
|
||||||
items: items,
|
items: items,
|
||||||
contains: contains,
|
contains: contains,
|
||||||
getAndAugment: getAndAugment,
|
getter: getter,
|
||||||
statusUpdater: statusUpdater,
|
statusUpdater: statusUpdater,
|
||||||
stream: make(chan data.Item, collectionChannelBufferSize),
|
stream: make(chan data.Item, collectionChannelBufferSize),
|
||||||
protectedResource: protectedResource,
|
protectedResource: protectedResource,
|
||||||
@ -96,7 +96,7 @@ type lazyFetchCollection[I chatsItemer] struct {
|
|||||||
|
|
||||||
items []I
|
items []I
|
||||||
|
|
||||||
getAndAugment getItemAndAugmentInfoer[I]
|
getter getItemer[I]
|
||||||
|
|
||||||
statusUpdater support.StatusUpdater
|
statusUpdater support.StatusUpdater
|
||||||
}
|
}
|
||||||
@ -167,13 +167,13 @@ func (col *lazyFetchCollection[I]) streamItems(ctx context.Context, errs *fault.
|
|||||||
col.stream <- data.NewLazyItemWithInfo(
|
col.stream <- data.NewLazyItemWithInfo(
|
||||||
ictx,
|
ictx,
|
||||||
&lazyItemGetter[I]{
|
&lazyItemGetter[I]{
|
||||||
modTime: modTime,
|
modTime: modTime,
|
||||||
getAndAugment: col.getAndAugment,
|
getter: col.getter,
|
||||||
resourceID: col.protectedResource,
|
resourceID: col.protectedResource,
|
||||||
item: item,
|
item: item,
|
||||||
containerIDs: col.FullPath().Folders(),
|
containerIDs: col.FullPath().Folders(),
|
||||||
contains: col.contains,
|
contains: col.contains,
|
||||||
parentPath: col.LocationPath().String(),
|
parentPath: col.LocationPath().String(),
|
||||||
},
|
},
|
||||||
itemID,
|
itemID,
|
||||||
modTime,
|
modTime,
|
||||||
@ -192,13 +192,13 @@ func (col *lazyFetchCollection[I]) streamItems(ctx context.Context, errs *fault.
|
|||||||
}
|
}
|
||||||
|
|
||||||
type lazyItemGetter[I chatsItemer] struct {
|
type lazyItemGetter[I chatsItemer] struct {
|
||||||
getAndAugment getItemAndAugmentInfoer[I]
|
getter getItemer[I]
|
||||||
resourceID string
|
resourceID string
|
||||||
item I
|
item I
|
||||||
parentPath string
|
parentPath string
|
||||||
containerIDs path.Elements
|
containerIDs path.Elements
|
||||||
modTime time.Time
|
modTime time.Time
|
||||||
contains container[I]
|
contains container[I]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lig *lazyItemGetter[I]) GetData(
|
func (lig *lazyItemGetter[I]) GetData(
|
||||||
@ -208,7 +208,7 @@ func (lig *lazyItemGetter[I]) GetData(
|
|||||||
writer := kjson.NewJsonSerializationWriter()
|
writer := kjson.NewJsonSerializationWriter()
|
||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
|
|
||||||
item, info, err := lig.getAndAugment.getItem(
|
item, info, err := lig.getter.getItem(
|
||||||
ctx,
|
ctx,
|
||||||
lig.resourceID,
|
lig.resourceID,
|
||||||
lig.item)
|
lig.item)
|
||||||
@ -229,8 +229,6 @@ func (lig *lazyItemGetter[I]) GetData(
|
|||||||
return nil, nil, false, err
|
return nil, nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
lig.getAndAugment.augmentItemInfo(info, lig.contains.container)
|
|
||||||
|
|
||||||
if err := writer.WriteObjectValue("", item); err != nil {
|
if err := writer.WriteObjectValue("", item); err != nil {
|
||||||
err = clues.WrapWC(ctx, err, "writing item to serializer").Label(fault.LabelForceNoBackupCreation)
|
err = clues.WrapWC(ctx, err, "writing item to serializer").Label(fault.LabelForceNoBackupCreation)
|
||||||
errs.AddRecoverable(ctx, err)
|
errs.AddRecoverable(ctx, err)
|
||||||
|
|||||||
@ -163,11 +163,6 @@ func (m getAndAugmentChat) getItem(
|
|||||||
return chat, &details.TeamsChatsInfo{}, m.err
|
return chat, &details.TeamsChatsInfo{}, m.err
|
||||||
}
|
}
|
||||||
|
|
||||||
//lint:ignore U1000 false linter issue due to generics
|
|
||||||
func (getAndAugmentChat) augmentItemInfo(*details.TeamsChatsInfo, models.Chatable) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *CollectionUnitSuite) TestLazyFetchCollection_Items_LazyFetch() {
|
func (suite *CollectionUnitSuite) TestLazyFetchCollection_Items_LazyFetch() {
|
||||||
var (
|
var (
|
||||||
t = suite.T()
|
t = suite.T()
|
||||||
@ -225,7 +220,7 @@ func (suite *CollectionUnitSuite) TestLazyFetchCollection_Items_LazyFetch() {
|
|||||||
count.New()),
|
count.New()),
|
||||||
items: test.items,
|
items: test.items,
|
||||||
contains: container[models.Chatable]{},
|
contains: container[models.Chatable]{},
|
||||||
getAndAugment: getterAugmenter,
|
getter: getterAugmenter,
|
||||||
stream: make(chan data.Item),
|
stream: make(chan data.Item),
|
||||||
statusUpdater: statusUpdater,
|
statusUpdater: statusUpdater,
|
||||||
}
|
}
|
||||||
@ -285,11 +280,11 @@ func (suite *CollectionUnitSuite) TestLazyItem_GetDataErrors() {
|
|||||||
li := data.NewLazyItemWithInfo(
|
li := data.NewLazyItemWithInfo(
|
||||||
ctx,
|
ctx,
|
||||||
&lazyItemGetter[models.Chatable]{
|
&lazyItemGetter[models.Chatable]{
|
||||||
resourceID: "resourceID",
|
resourceID: "resourceID",
|
||||||
item: chat,
|
item: chat,
|
||||||
getAndAugment: &m,
|
getter: &m,
|
||||||
modTime: now,
|
modTime: now,
|
||||||
parentPath: parentPath,
|
parentPath: parentPath,
|
||||||
},
|
},
|
||||||
ptr.Val(chat.GetId()),
|
ptr.Val(chat.GetId()),
|
||||||
now,
|
now,
|
||||||
@ -329,11 +324,11 @@ func (suite *CollectionUnitSuite) TestLazyItem_ReturnsEmptyReaderOnDeletedInFlig
|
|||||||
li := data.NewLazyItemWithInfo(
|
li := data.NewLazyItemWithInfo(
|
||||||
ctx,
|
ctx,
|
||||||
&lazyItemGetter[models.Chatable]{
|
&lazyItemGetter[models.Chatable]{
|
||||||
resourceID: "resourceID",
|
resourceID: "resourceID",
|
||||||
item: chat,
|
item: chat,
|
||||||
getAndAugment: &m,
|
getter: &m,
|
||||||
modTime: now,
|
modTime: now,
|
||||||
parentPath: parentPath,
|
parentPath: parentPath,
|
||||||
},
|
},
|
||||||
ptr.Val(chat.GetId()),
|
ptr.Val(chat.GetId()),
|
||||||
now,
|
now,
|
||||||
@ -368,11 +363,11 @@ func (suite *CollectionUnitSuite) TestLazyItem() {
|
|||||||
li := data.NewLazyItemWithInfo(
|
li := data.NewLazyItemWithInfo(
|
||||||
ctx,
|
ctx,
|
||||||
&lazyItemGetter[models.Chatable]{
|
&lazyItemGetter[models.Chatable]{
|
||||||
resourceID: "resourceID",
|
resourceID: "resourceID",
|
||||||
item: chat,
|
item: chat,
|
||||||
getAndAugment: &m,
|
getter: &m,
|
||||||
modTime: now,
|
modTime: now,
|
||||||
parentPath: parentPath,
|
parentPath: parentPath,
|
||||||
},
|
},
|
||||||
ptr.Val(chat.GetId()),
|
ptr.Val(chat.GetId()),
|
||||||
now,
|
now,
|
||||||
|
|||||||
@ -22,7 +22,7 @@ type chatsItemer interface {
|
|||||||
|
|
||||||
type backupHandler[I chatsItemer] interface {
|
type backupHandler[I chatsItemer] interface {
|
||||||
getContainerer[I]
|
getContainerer[I]
|
||||||
getItemAndAugmentInfoer[I]
|
getItemer[I]
|
||||||
getItemer[I]
|
getItemer[I]
|
||||||
getItemIDser[I]
|
getItemIDser[I]
|
||||||
includeItemer[I]
|
includeItemer[I]
|
||||||
@ -39,22 +39,10 @@ type getContainerer[I chatsItemer] interface {
|
|||||||
) (container[I], error)
|
) (container[I], error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type getItemAndAugmentInfoer[I chatsItemer] interface {
|
|
||||||
getItemer[I]
|
|
||||||
augmentItemInfoer[I]
|
|
||||||
}
|
|
||||||
|
|
||||||
type augmentItemInfoer[I chatsItemer] interface {
|
|
||||||
// augmentItemInfo completes the teamChatsInfo population with any data
|
|
||||||
// owned by the container and not accessible to the item.
|
|
||||||
augmentItemInfo(*details.TeamsChatsInfo, I)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets all item IDs in the container
|
// gets all item IDs in the container
|
||||||
type getItemIDser[I chatsItemer] interface {
|
type getItemIDser[I chatsItemer] interface {
|
||||||
getItemIDs(
|
getItemIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
cc api.CallConfig,
|
|
||||||
) ([]I, error)
|
) ([]I, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -103,6 +103,12 @@ func (de Entry) ToLocationIDer(backupVersion int) (LocationIDer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
baseLoc = path.Builder{}.Append(p.Root).Append(p.Folders...)
|
baseLoc = path.Builder{}.Append(p.Root).Append(p.Folders...)
|
||||||
|
|
||||||
|
case TeamsChat:
|
||||||
|
baseLoc = &path.Builder{}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, clues.New("undentified item type").With("item_type", de.ItemInfo.infoType())
|
||||||
}
|
}
|
||||||
|
|
||||||
if baseLoc == nil {
|
if baseLoc == nil {
|
||||||
@ -141,26 +147,23 @@ func (de Entry) MinimumPrintable() any {
|
|||||||
// Headers returns the human-readable names of properties in a DetailsEntry
|
// Headers returns the human-readable names of properties in a DetailsEntry
|
||||||
// for printing out to a terminal in a columnar display.
|
// for printing out to a terminal in a columnar display.
|
||||||
func (de Entry) Headers(skipID bool) []string {
|
func (de Entry) Headers(skipID bool) []string {
|
||||||
hs := []string{}
|
var hs []string
|
||||||
|
|
||||||
if de.ItemInfo.Folder != nil {
|
switch {
|
||||||
|
case de.ItemInfo.Folder != nil:
|
||||||
hs = de.ItemInfo.Folder.Headers()
|
hs = de.ItemInfo.Folder.Headers()
|
||||||
}
|
case de.ItemInfo.Exchange != nil:
|
||||||
|
|
||||||
if de.ItemInfo.Exchange != nil {
|
|
||||||
hs = de.ItemInfo.Exchange.Headers()
|
hs = de.ItemInfo.Exchange.Headers()
|
||||||
}
|
case de.ItemInfo.SharePoint != nil:
|
||||||
|
|
||||||
if de.ItemInfo.SharePoint != nil {
|
|
||||||
hs = de.ItemInfo.SharePoint.Headers()
|
hs = de.ItemInfo.SharePoint.Headers()
|
||||||
}
|
case de.ItemInfo.OneDrive != nil:
|
||||||
|
|
||||||
if de.ItemInfo.OneDrive != nil {
|
|
||||||
hs = de.ItemInfo.OneDrive.Headers()
|
hs = de.ItemInfo.OneDrive.Headers()
|
||||||
}
|
case de.ItemInfo.Groups != nil:
|
||||||
|
|
||||||
if de.ItemInfo.Groups != nil {
|
|
||||||
hs = de.ItemInfo.Groups.Headers()
|
hs = de.ItemInfo.Groups.Headers()
|
||||||
|
case de.ItemInfo.TeamsChats != nil:
|
||||||
|
hs = de.ItemInfo.TeamsChats.Headers()
|
||||||
|
default:
|
||||||
|
hs = []string{"ERROR - Service not recognized"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if skipID {
|
if skipID {
|
||||||
@ -172,26 +175,23 @@ func (de Entry) Headers(skipID bool) []string {
|
|||||||
|
|
||||||
// Values returns the values matching the Headers list.
|
// Values returns the values matching the Headers list.
|
||||||
func (de Entry) Values(skipID bool) []string {
|
func (de Entry) Values(skipID bool) []string {
|
||||||
vs := []string{}
|
var vs []string
|
||||||
|
|
||||||
if de.ItemInfo.Folder != nil {
|
switch {
|
||||||
|
case de.ItemInfo.Folder != nil:
|
||||||
vs = de.ItemInfo.Folder.Values()
|
vs = de.ItemInfo.Folder.Values()
|
||||||
}
|
case de.ItemInfo.Exchange != nil:
|
||||||
|
|
||||||
if de.ItemInfo.Exchange != nil {
|
|
||||||
vs = de.ItemInfo.Exchange.Values()
|
vs = de.ItemInfo.Exchange.Values()
|
||||||
}
|
case de.ItemInfo.SharePoint != nil:
|
||||||
|
|
||||||
if de.ItemInfo.SharePoint != nil {
|
|
||||||
vs = de.ItemInfo.SharePoint.Values()
|
vs = de.ItemInfo.SharePoint.Values()
|
||||||
}
|
case de.ItemInfo.OneDrive != nil:
|
||||||
|
|
||||||
if de.ItemInfo.OneDrive != nil {
|
|
||||||
vs = de.ItemInfo.OneDrive.Values()
|
vs = de.ItemInfo.OneDrive.Values()
|
||||||
}
|
case de.ItemInfo.Groups != nil:
|
||||||
|
|
||||||
if de.ItemInfo.Groups != nil {
|
|
||||||
vs = de.ItemInfo.Groups.Values()
|
vs = de.ItemInfo.Groups.Values()
|
||||||
|
case de.ItemInfo.TeamsChats != nil:
|
||||||
|
vs = de.ItemInfo.TeamsChats.Values()
|
||||||
|
default:
|
||||||
|
vs = []string{"ERROR - Service not recognized"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if skipID {
|
if skipID {
|
||||||
|
|||||||
@ -91,19 +91,14 @@ func (i ItemInfo) infoType() ItemType {
|
|||||||
switch {
|
switch {
|
||||||
case i.Folder != nil:
|
case i.Folder != nil:
|
||||||
return i.Folder.ItemType
|
return i.Folder.ItemType
|
||||||
|
|
||||||
case i.Exchange != nil:
|
case i.Exchange != nil:
|
||||||
return i.Exchange.ItemType
|
return i.Exchange.ItemType
|
||||||
|
|
||||||
case i.SharePoint != nil:
|
case i.SharePoint != nil:
|
||||||
return i.SharePoint.ItemType
|
return i.SharePoint.ItemType
|
||||||
|
|
||||||
case i.OneDrive != nil:
|
case i.OneDrive != nil:
|
||||||
return i.OneDrive.ItemType
|
return i.OneDrive.ItemType
|
||||||
|
|
||||||
case i.Groups != nil:
|
case i.Groups != nil:
|
||||||
return i.Groups.ItemType
|
return i.Groups.ItemType
|
||||||
|
|
||||||
case i.TeamsChats != nil:
|
case i.TeamsChats != nil:
|
||||||
return i.TeamsChats.ItemType
|
return i.TeamsChats.ItemType
|
||||||
}
|
}
|
||||||
@ -115,19 +110,14 @@ func (i ItemInfo) size() int64 {
|
|||||||
switch {
|
switch {
|
||||||
case i.Exchange != nil:
|
case i.Exchange != nil:
|
||||||
return i.Exchange.Size
|
return i.Exchange.Size
|
||||||
|
|
||||||
case i.OneDrive != nil:
|
case i.OneDrive != nil:
|
||||||
return i.OneDrive.Size
|
return i.OneDrive.Size
|
||||||
|
|
||||||
case i.SharePoint != nil:
|
case i.SharePoint != nil:
|
||||||
return i.SharePoint.Size
|
return i.SharePoint.Size
|
||||||
|
|
||||||
case i.Groups != nil:
|
case i.Groups != nil:
|
||||||
return i.Groups.Size
|
return i.Groups.Size
|
||||||
|
|
||||||
case i.Folder != nil:
|
case i.Folder != nil:
|
||||||
return i.Folder.Size
|
return i.Folder.Size
|
||||||
|
|
||||||
case i.TeamsChats != nil:
|
case i.TeamsChats != nil:
|
||||||
return int64(i.TeamsChats.Chat.MessageCount)
|
return int64(i.TeamsChats.Chat.MessageCount)
|
||||||
}
|
}
|
||||||
@ -139,19 +129,14 @@ func (i ItemInfo) Modified() time.Time {
|
|||||||
switch {
|
switch {
|
||||||
case i.Exchange != nil:
|
case i.Exchange != nil:
|
||||||
return i.Exchange.Modified
|
return i.Exchange.Modified
|
||||||
|
|
||||||
case i.OneDrive != nil:
|
case i.OneDrive != nil:
|
||||||
return i.OneDrive.Modified
|
return i.OneDrive.Modified
|
||||||
|
|
||||||
case i.SharePoint != nil:
|
case i.SharePoint != nil:
|
||||||
return i.SharePoint.Modified
|
return i.SharePoint.Modified
|
||||||
|
|
||||||
case i.Groups != nil:
|
case i.Groups != nil:
|
||||||
return i.Groups.Modified
|
return i.Groups.Modified
|
||||||
|
|
||||||
case i.Folder != nil:
|
case i.Folder != nil:
|
||||||
return i.Folder.Modified
|
return i.Folder.Modified
|
||||||
|
|
||||||
case i.TeamsChats != nil:
|
case i.TeamsChats != nil:
|
||||||
return i.TeamsChats.Modified
|
return i.TeamsChats.Modified
|
||||||
}
|
}
|
||||||
@ -163,19 +148,14 @@ func (i ItemInfo) uniqueLocation(baseLoc *path.Builder) (*uniqueLoc, error) {
|
|||||||
switch {
|
switch {
|
||||||
case i.Exchange != nil:
|
case i.Exchange != nil:
|
||||||
return i.Exchange.uniqueLocation(baseLoc)
|
return i.Exchange.uniqueLocation(baseLoc)
|
||||||
|
|
||||||
case i.OneDrive != nil:
|
case i.OneDrive != nil:
|
||||||
return i.OneDrive.uniqueLocation(baseLoc)
|
return i.OneDrive.uniqueLocation(baseLoc)
|
||||||
|
|
||||||
case i.SharePoint != nil:
|
case i.SharePoint != nil:
|
||||||
return i.SharePoint.uniqueLocation(baseLoc)
|
return i.SharePoint.uniqueLocation(baseLoc)
|
||||||
|
|
||||||
case i.Groups != nil:
|
case i.Groups != nil:
|
||||||
return i.Groups.uniqueLocation(baseLoc)
|
return i.Groups.uniqueLocation(baseLoc)
|
||||||
|
|
||||||
case i.TeamsChats != nil:
|
case i.TeamsChats != nil:
|
||||||
return i.TeamsChats.uniqueLocation(baseLoc)
|
return i.TeamsChats.uniqueLocation(baseLoc)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, clues.New("unsupported type")
|
return nil, clues.New("unsupported type")
|
||||||
}
|
}
|
||||||
@ -185,19 +165,14 @@ func (i ItemInfo) updateFolder(f *FolderInfo) error {
|
|||||||
switch {
|
switch {
|
||||||
case i.Exchange != nil:
|
case i.Exchange != nil:
|
||||||
return i.Exchange.updateFolder(f)
|
return i.Exchange.updateFolder(f)
|
||||||
|
|
||||||
case i.OneDrive != nil:
|
case i.OneDrive != nil:
|
||||||
return i.OneDrive.updateFolder(f)
|
return i.OneDrive.updateFolder(f)
|
||||||
|
|
||||||
case i.SharePoint != nil:
|
case i.SharePoint != nil:
|
||||||
return i.SharePoint.updateFolder(f)
|
return i.SharePoint.updateFolder(f)
|
||||||
|
|
||||||
case i.Groups != nil:
|
case i.Groups != nil:
|
||||||
return i.Groups.updateFolder(f)
|
return i.Groups.updateFolder(f)
|
||||||
|
|
||||||
case i.TeamsChats != nil:
|
case i.TeamsChats != nil:
|
||||||
return i.TeamsChats.updateFolder(f)
|
return i.TeamsChats.updateFolder(f)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return clues.New("unsupported type")
|
return clues.New("unsupported type")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,7 @@ type ChatInfo struct {
|
|||||||
LastMessagePreview string `json:"preview,omitempty"`
|
LastMessagePreview string `json:"preview,omitempty"`
|
||||||
Members []string `json:"members,omitempty"`
|
Members []string `json:"members,omitempty"`
|
||||||
MessageCount int `json:"messageCount,omitempty"`
|
MessageCount int `json:"messageCount,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Topic string `json:"topic,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headers returns the human-readable names of properties in a ChatsInfo
|
// Headers returns the human-readable names of properties in a ChatsInfo
|
||||||
@ -52,7 +52,7 @@ type ChatInfo struct {
|
|||||||
func (i TeamsChatsInfo) Headers() []string {
|
func (i TeamsChatsInfo) Headers() []string {
|
||||||
switch i.ItemType {
|
switch i.ItemType {
|
||||||
case TeamsChat:
|
case TeamsChat:
|
||||||
return []string{"Name", "Last message", "Last message at", "Message count", "Created", "Members"}
|
return []string{"Topic", "Last message", "Last message at", "Message count", "Created", "Members"}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{}
|
return []string{}
|
||||||
@ -75,7 +75,7 @@ func (i TeamsChatsInfo) Values() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return []string{
|
return []string{
|
||||||
i.Chat.Name,
|
i.Chat.Topic,
|
||||||
i.Chat.LastMessagePreview,
|
i.Chat.LastMessagePreview,
|
||||||
dttm.FormatToTabularDisplay(i.Chat.LastMessageAt),
|
dttm.FormatToTabularDisplay(i.Chat.LastMessageAt),
|
||||||
strconv.Itoa(i.Chat.MessageCount),
|
strconv.Itoa(i.Chat.MessageCount),
|
||||||
|
|||||||
@ -42,7 +42,7 @@ func (suite *ChatsUnitSuite) TestChatsPrintable() {
|
|||||||
LastMessagePreview: "last message preview",
|
LastMessagePreview: "last message preview",
|
||||||
Members: []string{"foo@bar.baz", "fnords@smarf.zoomba"},
|
Members: []string{"foo@bar.baz", "fnords@smarf.zoomba"},
|
||||||
MessageCount: 42,
|
MessageCount: 42,
|
||||||
Name: "chat name",
|
Topic: "chat name",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectHs: []string{"Name", "Last message", "Last message at", "Message count", "Created", "Members"},
|
expectHs: []string{"Name", "Last message", "Last message at", "Message count", "Created", "Members"},
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/identity"
|
"github.com/alcionai/corso/src/pkg/backup/identity"
|
||||||
|
"github.com/alcionai/corso/src/pkg/dttm"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/filters"
|
"github.com/alcionai/corso/src/pkg/filters"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
@ -254,21 +255,81 @@ func (sr *TeamsChatsRestore) ChatMember(memberID string) []TeamsChatsScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChatName produces one or more teamsChats chat name info scopes.
|
// ChatTopic produces one or more teamsChats chat name info scopes.
|
||||||
// Matches any chat whose name contains the provided string.
|
// Matches any chat whose name contains the provided string.
|
||||||
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
|
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
|
||||||
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
||||||
// If any slice is empty, it defaults to [selectors.None]
|
// If any slice is empty, it defaults to [selectors.None]
|
||||||
func (sr *TeamsChatsRestore) ChatName(memberID string) []TeamsChatsScope {
|
func (sr *TeamsChatsRestore) ChatTopic(topic string) []TeamsChatsScope {
|
||||||
return []TeamsChatsScope{
|
return []TeamsChatsScope{
|
||||||
makeInfoScope[TeamsChatsScope](
|
makeInfoScope[TeamsChatsScope](
|
||||||
TeamsChatsChat,
|
TeamsChatsChat,
|
||||||
TeamsChatsInfoChatName,
|
TeamsChatsInfoChatTopic,
|
||||||
[]string{memberID},
|
[]string{topic},
|
||||||
filters.In),
|
filters.In),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChatCreatedBefore produces one or more teamsChats chat name info scopes.
|
||||||
|
// Matches any chat whose creation datetime is before the given datetime.
|
||||||
|
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
|
||||||
|
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
||||||
|
// If any slice is empty, it defaults to [selectors.None]
|
||||||
|
func (sr *TeamsChatsRestore) ChatCreatedBefore(datetime string) []TeamsChatsScope {
|
||||||
|
return []TeamsChatsScope{
|
||||||
|
makeInfoScope[TeamsChatsScope](
|
||||||
|
TeamsChatsChat,
|
||||||
|
TeamsChatsInfoChatCreatedBefore,
|
||||||
|
[]string{datetime},
|
||||||
|
filters.Greater),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatCreatedBefore produces one or more teamsChats chat name info scopes.
|
||||||
|
// Matches any chat whose creation datetime is after the given datetime.
|
||||||
|
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
|
||||||
|
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
||||||
|
// If any slice is empty, it defaults to [selectors.None]
|
||||||
|
func (sr *TeamsChatsRestore) ChatCreatedAfter(datetime string) []TeamsChatsScope {
|
||||||
|
return []TeamsChatsScope{
|
||||||
|
makeInfoScope[TeamsChatsScope](
|
||||||
|
TeamsChatsChat,
|
||||||
|
TeamsChatsInfoChatCreatedAfter,
|
||||||
|
[]string{datetime},
|
||||||
|
filters.Less),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatLastMessageBefore produces one or more teamsChats chat name info scopes.
|
||||||
|
// Matches any chat whose most recent message (if it has messages) is before the given datetime.
|
||||||
|
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
|
||||||
|
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
||||||
|
// If any slice is empty, it defaults to [selectors.None]
|
||||||
|
func (sr *TeamsChatsRestore) ChatLastMessageBefore(datetime string) []TeamsChatsScope {
|
||||||
|
return []TeamsChatsScope{
|
||||||
|
makeInfoScope[TeamsChatsScope](
|
||||||
|
TeamsChatsChat,
|
||||||
|
TeamsChatsInfoChatLastMessageBefore,
|
||||||
|
[]string{datetime},
|
||||||
|
filters.Greater),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatCreatedBefore produces one or more teamsChats chat name info scopes.
|
||||||
|
// Matches any chat whose most recent message (if it has messages) is after the given datetime.
|
||||||
|
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
|
||||||
|
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
||||||
|
// If any slice is empty, it defaults to [selectors.None]
|
||||||
|
func (sr *TeamsChatsRestore) ChatLastMessageAfter(datetime string) []TeamsChatsScope {
|
||||||
|
return []TeamsChatsScope{
|
||||||
|
makeInfoScope[TeamsChatsScope](
|
||||||
|
TeamsChatsChat,
|
||||||
|
TeamsChatsInfoChatLastMesasgeAfter,
|
||||||
|
[]string{datetime},
|
||||||
|
filters.Less),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Categories
|
// Categories
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -288,8 +349,12 @@ const (
|
|||||||
TeamsChatsChat teamsChatsCategory = "TeamsChatsChat"
|
TeamsChatsChat teamsChatsCategory = "TeamsChatsChat"
|
||||||
|
|
||||||
// data contained within details.ItemInfo
|
// data contained within details.ItemInfo
|
||||||
TeamsChatsInfoChatMember teamsChatsCategory = "TeamsChatsInfoChatMember"
|
TeamsChatsInfoChatCreatedBefore teamsChatsCategory = "TeamsChatsInfoChatCreatedBefore"
|
||||||
TeamsChatsInfoChatName teamsChatsCategory = "TeamsChatsInfoChatName"
|
TeamsChatsInfoChatCreatedAfter teamsChatsCategory = "TeamsChatsInfoChatCreatedAfter"
|
||||||
|
TeamsChatsInfoChatLastMessageBefore teamsChatsCategory = "TeamsChatsInfoChatLastMessageBefore"
|
||||||
|
TeamsChatsInfoChatLastMesasgeAfter teamsChatsCategory = "TeamsChatsInfoChatLastMesasgeAfter"
|
||||||
|
TeamsChatsInfoChatMember teamsChatsCategory = "TeamsChatsInfoChatMember"
|
||||||
|
TeamsChatsInfoChatTopic teamsChatsCategory = "TeamsChatsInfoChatName"
|
||||||
)
|
)
|
||||||
|
|
||||||
// teamsChatsLeafProperties describes common metadata of the leaf categories
|
// teamsChatsLeafProperties describes common metadata of the leaf categories
|
||||||
@ -317,7 +382,9 @@ func (ec teamsChatsCategory) String() string {
|
|||||||
// Ex: TeamsChatsUser.leafCat() => TeamsChatsUser
|
// Ex: TeamsChatsUser.leafCat() => TeamsChatsUser
|
||||||
func (ec teamsChatsCategory) leafCat() categorizer {
|
func (ec teamsChatsCategory) leafCat() categorizer {
|
||||||
switch ec {
|
switch ec {
|
||||||
case TeamsChatsChat, TeamsChatsInfoChatMember, TeamsChatsInfoChatName:
|
case TeamsChatsChat, TeamsChatsInfoChatMember, TeamsChatsInfoChatTopic,
|
||||||
|
TeamsChatsInfoChatCreatedBefore, TeamsChatsInfoChatCreatedAfter,
|
||||||
|
TeamsChatsInfoChatLastMessageBefore, TeamsChatsInfoChatLastMesasgeAfter:
|
||||||
return TeamsChatsChat
|
return TeamsChatsChat
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,8 +572,16 @@ func (s TeamsChatsScope) matchesInfo(dii details.ItemInfo) bool {
|
|||||||
switch infoCat {
|
switch infoCat {
|
||||||
case TeamsChatsInfoChatMember:
|
case TeamsChatsInfoChatMember:
|
||||||
i = strings.Join(info.Chat.Members, ",")
|
i = strings.Join(info.Chat.Members, ",")
|
||||||
case TeamsChatsInfoChatName:
|
case TeamsChatsInfoChatTopic:
|
||||||
i = info.Chat.Name
|
i = info.Chat.Topic
|
||||||
|
case TeamsChatsInfoChatCreatedBefore, TeamsChatsInfoChatCreatedAfter:
|
||||||
|
i = dttm.Format(info.Chat.CreatedAt)
|
||||||
|
case TeamsChatsInfoChatLastMessageBefore, TeamsChatsInfoChatLastMesasgeAfter:
|
||||||
|
if info.Chat.MessageCount < 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
i = dttm.Format(info.Chat.LastMessageAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.Matches(infoCat, i)
|
return s.Matches(infoCat, i)
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/tester"
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
|
"github.com/alcionai/corso/src/pkg/dttm"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/filters"
|
"github.com/alcionai/corso/src/pkg/filters"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
@ -252,14 +253,16 @@ func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_MatchesInfo() {
|
|||||||
cs := NewTeamsChatsRestore(Any())
|
cs := NewTeamsChatsRestore(Any())
|
||||||
|
|
||||||
const (
|
const (
|
||||||
name = "smarf mcfnords"
|
topic = "smarf mcfnords"
|
||||||
member = "cooks@2many.smarf"
|
member = "cooks@2many.smarf"
|
||||||
subject = "I have seen the fnords!"
|
subject = "I have seen the fnords!"
|
||||||
|
dtype = details.TeamsChat
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
now = time.Now()
|
now = time.Now()
|
||||||
future = now.Add(1 * time.Minute)
|
past = dttm.Format(now.Add(-1 * time.Minute))
|
||||||
|
future = dttm.Format(now.Add(1 * time.Minute))
|
||||||
)
|
)
|
||||||
|
|
||||||
infoWith := func(itype details.ItemType) details.ItemInfo {
|
infoWith := func(itype details.ItemType) details.ItemInfo {
|
||||||
@ -269,11 +272,11 @@ func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_MatchesInfo() {
|
|||||||
Chat: details.ChatInfo{
|
Chat: details.ChatInfo{
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
HasExternalMembers: false,
|
HasExternalMembers: false,
|
||||||
LastMessageAt: future,
|
LastMessageAt: now,
|
||||||
LastMessagePreview: "preview",
|
LastMessagePreview: "preview",
|
||||||
Members: []string{member},
|
Members: []string{member},
|
||||||
MessageCount: 1,
|
MessageCount: 1,
|
||||||
Name: name,
|
Topic: topic,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -285,12 +288,20 @@ func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_MatchesInfo() {
|
|||||||
scope []TeamsChatsScope
|
scope []TeamsChatsScope
|
||||||
expect assert.BoolAssertionFunc
|
expect assert.BoolAssertionFunc
|
||||||
}{
|
}{
|
||||||
{"chat with a different member", details.TeamsChat, cs.ChatMember("blarps"), assert.False},
|
{"chat with a different member", dtype, cs.ChatMember("blarps"), assert.False},
|
||||||
{"chat with the same member", details.TeamsChat, cs.ChatMember(member), assert.True},
|
{"chat with the same member", dtype, cs.ChatMember(member), assert.True},
|
||||||
{"chat with a member submatch search", details.TeamsChat, cs.ChatMember(member[2:5]), assert.True},
|
{"chat with a member submatch search", dtype, cs.ChatMember(member[2:5]), assert.True},
|
||||||
{"chat with a different name", details.TeamsChat, cs.ChatName("blarps"), assert.False},
|
{"chat with a different topic", dtype, cs.ChatTopic("blarps"), assert.False},
|
||||||
{"chat with the same name", details.TeamsChat, cs.ChatName(name), assert.True},
|
{"chat with the same topic", dtype, cs.ChatTopic(topic), assert.True},
|
||||||
{"chat with a subname search", details.TeamsChat, cs.ChatName(name[2:5]), assert.True},
|
{"chat with a subtopic search", dtype, cs.ChatTopic(topic[2:5]), assert.True},
|
||||||
|
{"chat created after", dtype, cs.ChatCreatedAfter(past), assert.True},
|
||||||
|
{"chat not created after", dtype, cs.ChatCreatedAfter(future), assert.False},
|
||||||
|
{"chat created before", dtype, cs.ChatCreatedBefore(future), assert.True},
|
||||||
|
{"chat not created before", dtype, cs.ChatCreatedBefore(past), assert.False},
|
||||||
|
{"chat last message after", dtype, cs.ChatLastMessageAfter(past), assert.True},
|
||||||
|
{"chat last message not after", dtype, cs.ChatLastMessageAfter(future), assert.False},
|
||||||
|
{"chat last message before", dtype, cs.ChatLastMessageBefore(future), assert.True},
|
||||||
|
{"chat last message not before", dtype, cs.ChatLastMessageBefore(past), assert.False},
|
||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.Run(test.name, func() {
|
suite.Run(test.name, func() {
|
||||||
|
|||||||
@ -103,7 +103,7 @@ func TeamsChatInfo(chat models.Chatable) *details.TeamsChatsInfo {
|
|||||||
LastMessagePreview: preview,
|
LastMessagePreview: preview,
|
||||||
Members: memberNames,
|
Members: memberNames,
|
||||||
MessageCount: len(msgs),
|
MessageCount: len(msgs),
|
||||||
Name: ptr.Val(chat.GetTopic()),
|
Topic: ptr.Val(chat.GetTopic()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,79 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
|
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// chat members pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// delta queries are not supported
|
||||||
|
var _ pagers.NonDeltaHandler[models.ConversationMemberable] = &chatMembersPageCtrl{}
|
||||||
|
|
||||||
|
type chatMembersPageCtrl struct {
|
||||||
|
chatID string
|
||||||
|
gs graph.Servicer
|
||||||
|
builder *chats.ItemMembersRequestBuilder
|
||||||
|
options *chats.ItemMembersRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatMembersPageCtrl) SetNextLink(nextLink string) {
|
||||||
|
p.builder = chats.NewItemMembersRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatMembersPageCtrl) GetPage(
|
||||||
|
ctx context.Context,
|
||||||
|
) (pagers.NextLinkValuer[models.ConversationMemberable], error) {
|
||||||
|
resp, err := p.builder.Get(ctx, p.options)
|
||||||
|
return resp, graph.Stack(ctx, err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatMembersPageCtrl) ValidModTimes() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Chats) NewChatMembersPager(
|
||||||
|
chatID string,
|
||||||
|
cc CallConfig,
|
||||||
|
) *chatMembersPageCtrl {
|
||||||
|
builder := c.Stable.
|
||||||
|
Client().
|
||||||
|
Chats().
|
||||||
|
ByChatId(chatID).
|
||||||
|
Members()
|
||||||
|
|
||||||
|
options := &chats.ItemMembersRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &chats.ItemMembersRequestBuilderGetQueryParameters{},
|
||||||
|
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize)),
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cc.Select) > 0 {
|
||||||
|
options.QueryParameters.Select = cc.Select
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cc.Expand) > 0 {
|
||||||
|
options.QueryParameters.Expand = cc.Expand
|
||||||
|
}
|
||||||
|
|
||||||
|
return &chatMembersPageCtrl{
|
||||||
|
chatID: chatID,
|
||||||
|
builder: builder,
|
||||||
|
gs: c.Stable,
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChatMembers fetches a delta of all members in the chat.
|
||||||
|
func (c Chats) GetChatMembers(
|
||||||
|
ctx context.Context,
|
||||||
|
chatID string,
|
||||||
|
cc CallConfig,
|
||||||
|
) ([]models.ConversationMemberable, error) {
|
||||||
|
ctx = clues.Add(ctx, "chat_id", chatID)
|
||||||
|
pager := c.NewChatMembersPager(chatID, cc)
|
||||||
|
items, err := pagers.BatchEnumerateItems[models.ConversationMemberable](ctx, pager)
|
||||||
|
|
||||||
|
return items, graph.Stack(ctx, err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// chat message pager
|
// chat message pager
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@ -61,6 +61,11 @@ func (suite *ChatsPagerIntgSuite) TestEnumerateChats() {
|
|||||||
ac,
|
ac,
|
||||||
chatID,
|
chatID,
|
||||||
chat.GetLastMessagePreview())
|
chat.GetLastMessagePreview())
|
||||||
|
|
||||||
|
testEnumerateChatMembers(
|
||||||
|
suite.T(),
|
||||||
|
ac,
|
||||||
|
chatID)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,3 +128,22 @@ func testEnumerateChatMessages(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testEnumerateChatMembers(
|
||||||
|
t *testing.T,
|
||||||
|
ac Chats,
|
||||||
|
chatID string,
|
||||||
|
) {
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cc := CallConfig{}
|
||||||
|
|
||||||
|
members, err := ac.GetChatMembers(ctx, chatID, cc)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// no good way to test members right now. Even though
|
||||||
|
// the graph api response contains the `userID` and `email`
|
||||||
|
// properties, we can't access them in the sdk model
|
||||||
|
assert.NotEmpty(t, members)
|
||||||
|
}
|
||||||
|
|||||||
@ -64,7 +64,7 @@ func (suite *ChatsAPIUnitSuite) TestChatsInfo() {
|
|||||||
ItemType: details.TeamsChat,
|
ItemType: details.TeamsChat,
|
||||||
Modified: then,
|
Modified: then,
|
||||||
Chat: details.ChatInfo{
|
Chat: details.ChatInfo{
|
||||||
Name: "Hello world",
|
Topic: "Hello world",
|
||||||
LastMessageAt: then,
|
LastMessageAt: then,
|
||||||
LastMessagePreview: id,
|
LastMessagePreview: id,
|
||||||
Members: []string{},
|
Members: []string{},
|
||||||
@ -92,7 +92,7 @@ func (suite *ChatsAPIUnitSuite) TestChatsInfo() {
|
|||||||
ItemType: details.TeamsChat,
|
ItemType: details.TeamsChat,
|
||||||
Modified: then,
|
Modified: then,
|
||||||
Chat: details.ChatInfo{
|
Chat: details.ChatInfo{
|
||||||
Name: "Hello world",
|
Topic: "Hello world",
|
||||||
LastMessageAt: then,
|
LastMessageAt: then,
|
||||||
LastMessagePreview: id,
|
LastMessagePreview: id,
|
||||||
Members: []string{},
|
Members: []string{},
|
||||||
@ -120,7 +120,7 @@ func (suite *ChatsAPIUnitSuite) TestChatsInfo() {
|
|||||||
ItemType: details.TeamsChat,
|
ItemType: details.TeamsChat,
|
||||||
Modified: then,
|
Modified: then,
|
||||||
Chat: details.ChatInfo{
|
Chat: details.ChatInfo{
|
||||||
Name: "Hello world",
|
Topic: "Hello world",
|
||||||
LastMessageAt: time.Time{},
|
LastMessageAt: time.Time{},
|
||||||
LastMessagePreview: "",
|
LastMessagePreview: "",
|
||||||
Members: []string{},
|
Members: []string{},
|
||||||
@ -138,7 +138,7 @@ func (suite *ChatsAPIUnitSuite) TestChatsInfo() {
|
|||||||
chat, expected := test.expected()
|
chat, expected := test.expected()
|
||||||
result := TeamsChatInfo(chat)
|
result := TeamsChatInfo(chat)
|
||||||
|
|
||||||
assert.Equal(t, expected.Chat.Name, result.Chat.Name)
|
assert.Equal(t, expected.Chat.Topic, result.Chat.Topic)
|
||||||
|
|
||||||
expectCreated := chat.GetCreatedDateTime()
|
expectCreated := chat.GetCreatedDateTime()
|
||||||
if expectCreated != nil {
|
if expectCreated != nil {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user