Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

lazily fetch messages in chat #5114

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions src/internal/m365/collection/teamschats/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,13 @@ func (bh mockBackupHandler) CanonicalPath() (path.Path, error) {
func (bh mockBackupHandler) getItem(
_ context.Context,
_ string,
itemID string,
chat models.Chatable,
) (models.Chatable, *details.TeamsChatsInfo, error) {
chat := models.NewChat()
chatID := ptr.Val(chat.GetId())

chat.SetId(ptr.To(itemID))
chat.SetTopic(ptr.To(itemID))
chat.SetMessages(bh.chatMessages[itemID])
chat.SetMessages(bh.chatMessages[chatID])

return chat, bh.info[itemID], bh.getMessageErr[itemID]
return chat, bh.info[chatID], bh.getMessageErr[chatID]
}

// ---------------------------------------------------------------------------
Expand Down
23 changes: 20 additions & 3 deletions src/internal/m365/collection/teamschats/chat_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/errs/core"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365/api"
Expand Down Expand Up @@ -80,10 +81,26 @@ func (bh usersChatsBackupHandler) CanonicalPath() (path.Path, error) {
func (bh usersChatsBackupHandler) getItem(
ctx context.Context,
userID string,
chatID string,
chat models.Chatable,
) (models.Chatable, *details.TeamsChatsInfo, error) {
// FIXME: should retrieve and populate all messages in the chat.
return nil, nil, clues.New("not implemented")
if chat == nil {
return nil, nil, clues.Stack(core.ErrNotFound)
}

chatID := ptr.Val(chat.GetId())

cc := api.CallConfig{
Expand: []string{"lastMessagePreview"},
}

msgs, err := bh.ac.GetChatMessages(ctx, chatID, cc)
if err != nil {
return nil, nil, clues.Stack(err)
}

chat.SetMessages(msgs)

return chat, api.TeamsChatInfo(chat), nil
}

//lint:ignore U1000 false linter issue due to generics
Expand Down
19 changes: 8 additions & 11 deletions src/internal/m365/collection/teamschats/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,33 +152,30 @@ func (col *lazyFetchCollection[I]) streamItems(ctx context.Context, errs *fault.
break
}

itemID := ptr.Val(item.GetId())
modTime := ptr.Val(item.GetLastUpdatedDateTime())

wg.Add(1)
semaphoreCh <- struct{}{}

go func(id string, modTime time.Time) {
go func(item I, modTime time.Time) {
defer wg.Done()
defer func() { <-semaphoreCh }()

ictx := clues.Add(
ctx,
"item_id", id,
"parent_path", path.LoggableDir(col.LocationPath().String()))
itemID := ptr.Val(item.GetId())
ictx := clues.Add(ctx, "item_id", itemID)

col.stream <- data.NewLazyItemWithInfo(
ictx,
&lazyItemGetter[I]{
modTime: modTime,
getAndAugment: col.getAndAugment,
resourceID: col.protectedResource,
itemID: id,
item: item,
containerIDs: col.FullPath().Folders(),
contains: col.contains,
parentPath: col.LocationPath().String(),
},
id,
itemID,
modTime,
col.Counter,
el)
Expand All @@ -188,7 +185,7 @@ func (col *lazyFetchCollection[I]) streamItems(ctx context.Context, errs *fault.
if progressMessage != nil {
progressMessage <- struct{}{}
}
}(itemID, modTime)
}(item, modTime)
}

wg.Wait()
Expand All @@ -197,7 +194,7 @@ func (col *lazyFetchCollection[I]) streamItems(ctx context.Context, errs *fault.
type lazyItemGetter[I chatsItemer] struct {
getAndAugment getItemAndAugmentInfoer[I]
resourceID string
itemID string
item I
parentPath string
containerIDs path.Elements
modTime time.Time
Expand All @@ -214,7 +211,7 @@ func (lig *lazyItemGetter[I]) GetData(
item, info, err := lig.getAndAugment.getItem(
ctx,
lig.resourceID,
lig.itemID)
lig.item)
if err != nil {
// For items that were deleted in flight, add the skip label so that
// they don't lead to recoverable failures during backup.
Expand Down
24 changes: 14 additions & 10 deletions src/internal/m365/collection/teamschats/collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"github.com/alcionai/clues"
"github.com/google/uuid"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -155,11 +156,9 @@ type getAndAugmentChat struct {
func (m getAndAugmentChat) getItem(
_ context.Context,
_ string,
itemID string,
chat models.Chatable,
) (models.Chatable, *details.TeamsChatsInfo, error) {
chat := models.NewChat()
chat.SetId(ptr.To(itemID))
chat.SetTopic(ptr.To(itemID))
chat.SetTopic(chat.GetId())

return chat, &details.TeamsChatsInfo{}, m.err
}
Expand Down Expand Up @@ -277,6 +276,8 @@ func (suite *CollectionUnitSuite) TestLazyItem_GetDataErrors() {
ctx, flush := tester.NewContext(t)
defer flush()

chat := testdata.StubChats(uuid.NewString())[0]

m := getAndAugmentChat{
err: test.getErr,
}
Expand All @@ -285,12 +286,12 @@ func (suite *CollectionUnitSuite) TestLazyItem_GetDataErrors() {
ctx,
&lazyItemGetter[models.Chatable]{
resourceID: "resourceID",
itemID: "itemID",
item: chat,
getAndAugment: &m,
modTime: now,
parentPath: parentPath,
},
"itemID",
ptr.Val(chat.GetId()),
now,
count.New(),
fault.New(true))
Expand Down Expand Up @@ -319,6 +320,8 @@ func (suite *CollectionUnitSuite) TestLazyItem_ReturnsEmptyReaderOnDeletedInFlig
ctx, flush := tester.NewContext(t)
defer flush()

chat := testdata.StubChats(uuid.NewString())[0]

m := getAndAugmentChat{
err: core.ErrNotFound,
}
Expand All @@ -327,12 +330,12 @@ func (suite *CollectionUnitSuite) TestLazyItem_ReturnsEmptyReaderOnDeletedInFlig
ctx,
&lazyItemGetter[models.Chatable]{
resourceID: "resourceID",
itemID: "itemID",
item: chat,
getAndAugment: &m,
modTime: now,
parentPath: parentPath,
},
"itemID",
ptr.Val(chat.GetId()),
now,
count.New(),
fault.New(true))
Expand All @@ -359,18 +362,19 @@ func (suite *CollectionUnitSuite) TestLazyItem() {
ctx, flush := tester.NewContext(t)
defer flush()

chat := testdata.StubChats(uuid.NewString())[0]
m := getAndAugmentChat{}

li := data.NewLazyItemWithInfo(
ctx,
&lazyItemGetter[models.Chatable]{
resourceID: "resourceID",
itemID: "itemID",
item: chat,
getAndAugment: &m,
modTime: now,
parentPath: parentPath,
},
"itemID",
ptr.Val(chat.GetId()),
now,
count.New(),
fault.New(true))
Expand Down
2 changes: 1 addition & 1 deletion src/internal/m365/collection/teamschats/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ type getItemer[I chatsItemer] interface {
getItem(
ctx context.Context,
protectedResource string,
itemID string,
i I,
) (I, *details.TeamsChatsInfo, error)
}

Expand Down
33 changes: 25 additions & 8 deletions src/internal/m365/collection/teamschats/testdata/chats.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ func StubChats(ids ...string) []models.Chatable {
sl := make([]models.Chatable, 0, len(ids))

for _, id := range ids {
ch := models.NewChat()
ch.SetTopic(ptr.To(id))
ch.SetId(ptr.To(id))
chat := models.NewChat()
chat.SetTopic(ptr.To(id))
chat.SetId(ptr.To(id))

sl = append(sl, ch)
// we should expect to get the latest message preview by default
lastMsgPrv := models.NewChatMessageInfo()
lastMsgPrv.SetId(ptr.To(uuid.NewString()))

body := models.NewItemBody()
body.SetContent(ptr.To(id))
lastMsgPrv.SetBody(body)

chat.SetLastMessagePreview(lastMsgPrv)

sl = append(sl, chat)
}

return sl
Expand All @@ -24,17 +34,24 @@ func StubChats(ids ...string) []models.Chatable {
func StubChatMessages(ids ...string) []models.ChatMessageable {
sl := make([]models.ChatMessageable, 0, len(ids))

var lastMsg models.ChatMessageable

for _, id := range ids {
cm := models.NewChatMessage()
cm.SetId(ptr.To(uuid.NewString()))
msg := models.NewChatMessage()
msg.SetId(ptr.To(uuid.NewString()))

body := models.NewItemBody()
body.SetContent(ptr.To(id))

cm.SetBody(body)
msg.SetBody(body)

sl = append(sl, cm)
sl = append(sl, msg)
lastMsg = msg
}

lastMsgPrv := models.NewChatMessageInfo()
lastMsgPrv.SetId(lastMsg.GetId())
lastMsgPrv.SetBody(lastMsg.GetBody())

return sl
}
28 changes: 22 additions & 6 deletions src/pkg/services/m365/api/channels.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func channelMessageInfo(
modTime = lastReplyAt
}

preview, contentLen, err := getChatMessageContentPreview(msg)
preview, contentLen, err := getChatMessageContentPreview(msg, msg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
preview, contentLen, err := getChatMessageContentPreview(msg, msg)
preview, contentLen, err := getChatMessageContentPreview(msg, msg.GetAttachments())

if err != nil {
preview = "malformed or unparseable html" + preview
}
Expand All @@ -180,7 +180,7 @@ func channelMessageInfo(
var lr details.ChannelMessageInfo

if lastReply != nil {
preview, contentLen, err = getChatMessageContentPreview(lastReply)
preview, contentLen, err = getChatMessageContentPreview(lastReply, lastReply)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
preview, contentLen, err = getChatMessageContentPreview(lastReply, lastReply)
preview, contentLen, err = getChatMessageContentPreview(lastReply, lastReply.GetAttachments())

if err != nil {
preview = "malformed or unparseable html: " + preview
}
Expand Down Expand Up @@ -239,12 +239,28 @@ func GetChatMessageFrom(msg models.ChatMessageable) string {
return ""
}

func getChatMessageContentPreview(msg models.ChatMessageable) (string, int64, error) {
content, origSize, err := stripChatMessageHTML(msg)
// a hack for fulfilling getAttachmentser when the model doesn't
// provide GetAttachments()
type noAttachments struct{}

func (noAttachments) GetAttachments() []models.ChatMessageAttachmentable {
return []models.ChatMessageAttachmentable{}
}

type getBodyer interface {
GetBody() models.ItemBodyable
}

type getAttachmentser interface {
GetAttachments() []models.ChatMessageAttachmentable
}

func getChatMessageContentPreview(msg getBodyer, atts getAttachmentser) (string, int64, error) {
content, origSize, err := stripChatMessageHTML(msg, atts)
return str.Preview(content, 128), origSize, clues.Stack(err).OrNil()
}

func stripChatMessageHTML(msg models.ChatMessageable) (string, int64, error) {
func stripChatMessageHTML(msg getBodyer, atts getAttachmentser) (string, int64, error) {
Copy link
Contributor

@HiteshRepo HiteshRepo Jan 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func stripChatMessageHTML(msg getBodyer, atts getAttachmentser) (string, int64, error) {
func stripChatMessageHTML(msg getBodyer, atts []models.ChatMessageAttachmentable) (string, int64, error)
{

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea!

var (
content string
origSize int64
Expand All @@ -256,7 +272,7 @@ func stripChatMessageHTML(msg models.ChatMessageable) (string, int64, error) {

origSize = int64(len(content))

content = replaceAttachmentMarkup(content, msg.GetAttachments())
content = replaceAttachmentMarkup(content, atts.GetAttachments())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
content = replaceAttachmentMarkup(content, atts.GetAttachments())
content = replaceAttachmentMarkup(content, atts)

content, err := html2text.FromString(content)

return content, origSize, clues.Stack(err).OrNil()
Expand Down
2 changes: 1 addition & 1 deletion src/pkg/services/m365/api/channels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ func (suite *ChannelsAPIUnitSuite) TestStripChatMessageContent() {
msg.SetAttachments(test.attachments)

// not testing len; it's effectively covered by the content assertion
result, _, err := stripChatMessageHTML(msg)
result, _, err := stripChatMessageHTML(msg, msg)
assert.Equal(t, test.expect, result)
test.expectErr(t, err, clues.ToCore(err))
})
Expand Down
Loading
Loading