add boilerplate chats api calls
standard graph api boilerplate.
This commit is contained in:
parent
0a6355eeb1
commit
c999a3072f
89
src/pkg/services/m365/api/teamdChats_test.go
Normal file
89
src/pkg/services/m365/api/teamdChats_test.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatsAPIUnitSuite struct {
|
||||||
|
tester.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChatsAPIUnitSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &ChatsAPIUnitSuite{Suite: tester.NewUnitSuite(t)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ChatsAPIUnitSuite) TestChatsInfo() {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
chatAndExpected func() (models.Chatable, *details.TeamsChatsInfo)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Empty chat",
|
||||||
|
chatAndExpected: func() (models.Chatable, *details.TeamsChatsInfo) {
|
||||||
|
chat := models.NewChat()
|
||||||
|
|
||||||
|
i := &details.TeamsChatsInfo{
|
||||||
|
ItemType: details.TeamsChat,
|
||||||
|
Chat: details.ChatInfo{},
|
||||||
|
}
|
||||||
|
|
||||||
|
return chat, i
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "All fields",
|
||||||
|
chatAndExpected: func() (models.Chatable, *details.TeamsChatsInfo) {
|
||||||
|
now := time.Now()
|
||||||
|
then := now.Add(1 * time.Hour)
|
||||||
|
|
||||||
|
chat := models.NewChat()
|
||||||
|
chat.SetTopic(ptr.To("Hello world"))
|
||||||
|
chat.SetCreatedDateTime(&now)
|
||||||
|
chat.SetLastUpdatedDateTime(&then)
|
||||||
|
|
||||||
|
i := &details.TeamsChatsInfo{
|
||||||
|
ItemType: details.TeamsChat,
|
||||||
|
Chat: details.ChatInfo{
|
||||||
|
Name: "Hello world",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return chat, i
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
t := suite.T()
|
||||||
|
chat, expected := test.chatAndExpected()
|
||||||
|
result := TeamsChatInfo(chat)
|
||||||
|
|
||||||
|
assert.Equal(t, expected.Chat.Name, result.Chat.Name)
|
||||||
|
|
||||||
|
expectLastUpdated := chat.GetLastUpdatedDateTime()
|
||||||
|
if expectLastUpdated != nil {
|
||||||
|
assert.Equal(t, ptr.Val(expectLastUpdated), result.Modified)
|
||||||
|
} else {
|
||||||
|
assert.True(t, result.Modified.After(start))
|
||||||
|
}
|
||||||
|
|
||||||
|
expectCreated := chat.GetCreatedDateTime()
|
||||||
|
if expectCreated != nil {
|
||||||
|
assert.Equal(t, ptr.Val(expectCreated), result.Chat.CreatedAt)
|
||||||
|
} else {
|
||||||
|
assert.True(t, result.Chat.CreatedAt.After(start))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/pkg/services/m365/api/teamsChats.go
Normal file
74
src/pkg/services/m365/api/teamsChats.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/chats"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// controller
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (c Client) Chats() Chats {
|
||||||
|
return Chats{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chats is an interface-compliant provider of the client.
|
||||||
|
type Chats struct {
|
||||||
|
Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Chats
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (c Chats) GetChatByID(
|
||||||
|
ctx context.Context,
|
||||||
|
chatID string,
|
||||||
|
cc CallConfig,
|
||||||
|
) (models.Chatable, *details.TeamsChatsInfo, error) {
|
||||||
|
config := &chats.ChatItemRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &chats.ChatItemRequestBuilderGetQueryParameters{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cc.Select) > 0 {
|
||||||
|
config.QueryParameters.Select = cc.Select
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cc.Expand) > 0 {
|
||||||
|
config.QueryParameters.Expand = cc.Expand
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Chats().
|
||||||
|
ByChatId(chatID).
|
||||||
|
Get(ctx, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, TeamsChatInfo(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func TeamsChatInfo(chat models.Chatable) *details.TeamsChatsInfo {
|
||||||
|
return &details.TeamsChatsInfo{
|
||||||
|
ItemType: details.TeamsChat,
|
||||||
|
Modified: ptr.OrNow(chat.GetLastUpdatedDateTime()),
|
||||||
|
|
||||||
|
Chat: details.ChatInfo{
|
||||||
|
CreatedAt: ptr.OrNow(chat.GetCreatedDateTime()),
|
||||||
|
Name: ptr.Val(chat.GetTopic()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
172
src/pkg/services/m365/api/teamsChats_pager.go
Normal file
172
src/pkg/services/m365/api/teamsChats_pager.go
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/chats"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/users"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// chat message pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// delta queries are not supported
|
||||||
|
var _ pagers.NonDeltaHandler[models.ChatMessageable] = &chatMessagePageCtrl{}
|
||||||
|
|
||||||
|
type chatMessagePageCtrl struct {
|
||||||
|
chatID string
|
||||||
|
gs graph.Servicer
|
||||||
|
builder *chats.ItemMessagesRequestBuilder
|
||||||
|
options *chats.ItemMessagesRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatMessagePageCtrl) SetNextLink(nextLink string) {
|
||||||
|
p.builder = chats.NewItemMessagesRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatMessagePageCtrl) GetPage(
|
||||||
|
ctx context.Context,
|
||||||
|
) (pagers.NextLinkValuer[models.ChatMessageable], error) {
|
||||||
|
resp, err := p.builder.Get(ctx, p.options)
|
||||||
|
return resp, graph.Stack(ctx, err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatMessagePageCtrl) ValidModTimes() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Chats) NewChatMessagePager(
|
||||||
|
chatID string,
|
||||||
|
cc CallConfig,
|
||||||
|
) *chatMessagePageCtrl {
|
||||||
|
builder := c.Stable.
|
||||||
|
Client().
|
||||||
|
Chats().
|
||||||
|
ByChatId(chatID).
|
||||||
|
Messages()
|
||||||
|
|
||||||
|
options := &chats.ItemMessagesRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &chats.ItemMessagesRequestBuilderGetQueryParameters{},
|
||||||
|
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 &chatMessagePageCtrl{
|
||||||
|
chatID: chatID,
|
||||||
|
builder: builder,
|
||||||
|
gs: c.Stable,
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChatMessages fetches a delta of all messages in the chat.
|
||||||
|
func (c Chats) GetChatMessages(
|
||||||
|
ctx context.Context,
|
||||||
|
chatID string,
|
||||||
|
cc CallConfig,
|
||||||
|
) ([]models.ChatMessageable, error) {
|
||||||
|
ctx = clues.Add(ctx, "chat_id", chatID)
|
||||||
|
pager := c.NewChatMessagePager(chatID, cc)
|
||||||
|
items, err := pagers.BatchEnumerateItems[models.ChatMessageable](ctx, pager)
|
||||||
|
|
||||||
|
return items, graph.Stack(ctx, err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChatMessageIDs fetches a delta of all messages in the chat.
|
||||||
|
// returns two maps: addedItems, deletedItems
|
||||||
|
func (c Chats) GetChatMessageIDs(
|
||||||
|
ctx context.Context,
|
||||||
|
chatID string,
|
||||||
|
cc CallConfig,
|
||||||
|
) (pagers.AddedAndRemoved, error) {
|
||||||
|
aar, err := pagers.GetAddedAndRemovedItemIDs[models.ChatMessageable](
|
||||||
|
ctx,
|
||||||
|
c.NewChatMessagePager(chatID, CallConfig{}),
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
false, // delta queries are not supported
|
||||||
|
0,
|
||||||
|
pagers.AddedAndRemovedByDeletedDateTime[models.ChatMessageable],
|
||||||
|
IsNotSystemMessage)
|
||||||
|
|
||||||
|
return aar, clues.Stack(err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// chat pager
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var _ pagers.NonDeltaHandler[models.Chatable] = &chatPageCtrl{}
|
||||||
|
|
||||||
|
type chatPageCtrl struct {
|
||||||
|
gs graph.Servicer
|
||||||
|
builder *users.ItemChatsRequestBuilder
|
||||||
|
options *users.ItemChatsRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatPageCtrl) SetNextLink(nextLink string) {
|
||||||
|
p.builder = users.NewItemChatsRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatPageCtrl) GetPage(
|
||||||
|
ctx context.Context,
|
||||||
|
) (pagers.NextLinkValuer[models.Chatable], error) {
|
||||||
|
resp, err := p.builder.Get(ctx, p.options)
|
||||||
|
return resp, graph.Stack(ctx, err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chatPageCtrl) ValidModTimes() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Chats) NewChatPager(
|
||||||
|
userID string,
|
||||||
|
cc CallConfig,
|
||||||
|
) *chatPageCtrl {
|
||||||
|
options := &users.ItemChatsRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &users.ItemChatsRequestBuilderGetQueryParameters{},
|
||||||
|
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize)),
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cc.Select) > 0 {
|
||||||
|
options.QueryParameters.Select = cc.Select
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cc.Expand) > 0 {
|
||||||
|
options.QueryParameters.Expand = cc.Expand
|
||||||
|
}
|
||||||
|
|
||||||
|
res := &chatPageCtrl{
|
||||||
|
gs: c.Stable,
|
||||||
|
options: options,
|
||||||
|
builder: c.Stable.
|
||||||
|
Client().
|
||||||
|
Users().
|
||||||
|
ByUserId(userID).
|
||||||
|
Chats(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChats fetches all chats in the team.
|
||||||
|
func (c Chats) GetChats(
|
||||||
|
ctx context.Context,
|
||||||
|
userID string,
|
||||||
|
cc CallConfig,
|
||||||
|
) ([]models.Chatable, error) {
|
||||||
|
return pagers.BatchEnumerateItems[models.Chatable](ctx, c.NewChatPager(userID, cc))
|
||||||
|
}
|
||||||
128
src/pkg/services/m365/api/teamsChats_pager_test.go
Normal file
128
src/pkg/services/m365/api/teamsChats_pager_test.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
"github.com/alcionai/corso/src/internal/tester/tconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatsPagerIntgSuite struct {
|
||||||
|
tester.Suite
|
||||||
|
its intgTesterSetup
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChatsPagerIntgSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &ChatsPagerIntgSuite{
|
||||||
|
Suite: tester.NewIntegrationSuite(
|
||||||
|
t,
|
||||||
|
[][]string{tconfig.M365AcctCredEnvs}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ChatsPagerIntgSuite) SetupSuite() {
|
||||||
|
suite.its = newIntegrationTesterSetup(suite.T())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ChatsPagerIntgSuite) TestEnumerateChats() {
|
||||||
|
var (
|
||||||
|
t = suite.T()
|
||||||
|
ac = suite.its.ac.Chats()
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cc := CallConfig{
|
||||||
|
Expand: []string{"lastMessagePreview"},
|
||||||
|
}
|
||||||
|
|
||||||
|
chats, err := ac.GetChats(ctx, suite.its.user.id, cc)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
require.NotEmpty(t, chats)
|
||||||
|
|
||||||
|
for _, chat := range chats {
|
||||||
|
chatID := ptr.Val(chat.GetId())
|
||||||
|
|
||||||
|
suite.Run("chat_"+chatID, func() {
|
||||||
|
testGetChatByID(suite.T(), ac, chatID)
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.Run("chat_messages_"+chatID, func() {
|
||||||
|
testEnumerateChatMessages(
|
||||||
|
suite.T(),
|
||||||
|
ac,
|
||||||
|
chatID,
|
||||||
|
chat.GetLastMessagePreview())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetChatByID(
|
||||||
|
t *testing.T,
|
||||||
|
ac Chats,
|
||||||
|
chatID string,
|
||||||
|
) {
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cc := CallConfig{}
|
||||||
|
|
||||||
|
chat, _, err := ac.GetChatByID(ctx, chatID, cc)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
require.NotNil(t, chat)
|
||||||
|
}
|
||||||
|
|
||||||
|
var attachmentHtmlRegexp = regexp.MustCompile("<attachment id=\"[a-zA-Z0-9].*\"></attachment>")
|
||||||
|
|
||||||
|
func testEnumerateChatMessages(
|
||||||
|
t *testing.T,
|
||||||
|
ac Chats,
|
||||||
|
chatID string,
|
||||||
|
lastMessagePreview models.ChatMessageInfoable,
|
||||||
|
) {
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cc := CallConfig{}
|
||||||
|
|
||||||
|
messages, err := ac.GetChatMessages(ctx, chatID, cc)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
var lastID string
|
||||||
|
if lastMessagePreview != nil {
|
||||||
|
lastID = ptr.Val(lastMessagePreview.GetId())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, msg := range messages {
|
||||||
|
msgID := ptr.Val(msg.GetId())
|
||||||
|
|
||||||
|
assert.Equal(
|
||||||
|
t,
|
||||||
|
chatID,
|
||||||
|
ptr.Val(msg.GetChatId()),
|
||||||
|
"message:",
|
||||||
|
msgID)
|
||||||
|
|
||||||
|
if msgID == lastID {
|
||||||
|
previewContent := ptr.Val(lastMessagePreview.GetBody().GetContent())
|
||||||
|
msgContent := ptr.Val(msg.GetBody().GetContent())
|
||||||
|
|
||||||
|
previewContent = replaceAttachmentMarkup(previewContent, nil)
|
||||||
|
msgContent = replaceAttachmentMarkup(msgContent, nil)
|
||||||
|
|
||||||
|
assert.Equal(
|
||||||
|
t,
|
||||||
|
previewContent,
|
||||||
|
msgContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user