interface implementation
This commit is contained in:
commit
4d0d66bec0
@ -11,8 +11,8 @@ import (
|
|||||||
|
|
||||||
type BackupMessagesHandler interface {
|
type BackupMessagesHandler interface {
|
||||||
GetMessageByID(ctx context.Context, teamID, channelID, itemID string) (models.ChatMessageable, error)
|
GetMessageByID(ctx context.Context, teamID, channelID, itemID string) (models.ChatMessageable, error)
|
||||||
NewMessagePager(teamID, channelID string) api.MessageItemDeltaEnumerator
|
NewMessagePager(teamID, channelID string) api.ChannelMessageDeltaEnumerator
|
||||||
GetChannelByID(ctx context.Context, teamID, channelID string) (models.Channelable, error)
|
GetChannelByID(ctx context.Context, teamID, channelID string) (models.Channelable, error)
|
||||||
NewChannelPager(teamID, channelID string) api.ChannelItemDeltaEnumerator
|
NewChannelPager(teamID, channelID string) api.ChannelDeltaEnumerator
|
||||||
GetReplyByID(ctx context.Context, teamID, channelID, messageID string) (serialization.Parsable, error)
|
GetReplyByID(ctx context.Context, teamID, channelID, messageID string) (serialization.Parsable, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@ const (
|
|||||||
TestCfgSiteURL = "m365siteurl"
|
TestCfgSiteURL = "m365siteurl"
|
||||||
TestCfgTeamID = "m365teamid"
|
TestCfgTeamID = "m365teamid"
|
||||||
TestCfgGroupID = "m365groupid"
|
TestCfgGroupID = "m365groupid"
|
||||||
|
TestCfgChannelID = "m365channelid"
|
||||||
TestCfgUserID = "m365userid"
|
TestCfgUserID = "m365userid"
|
||||||
TestCfgSecondaryUserID = "secondarym365userid"
|
TestCfgSecondaryUserID = "secondarym365userid"
|
||||||
TestCfgSecondaryGroupID = "secondarym365groupid"
|
TestCfgSecondaryGroupID = "secondarym365groupid"
|
||||||
@ -46,6 +47,7 @@ const (
|
|||||||
EnvCorsoM365TestSiteURL = "CORSO_M365_TEST_SITE_URL"
|
EnvCorsoM365TestSiteURL = "CORSO_M365_TEST_SITE_URL"
|
||||||
EnvCorsoM365TestTeamID = "CORSO_M365_TEST_TEAM_ID"
|
EnvCorsoM365TestTeamID = "CORSO_M365_TEST_TEAM_ID"
|
||||||
EnvCorsoM365TestGroupID = "CORSO_M365_TEST_GROUP_ID"
|
EnvCorsoM365TestGroupID = "CORSO_M365_TEST_GROUP_ID"
|
||||||
|
EnvCorsoM365TestChannelID = "CORSO_M365_TEST_CHANNEL_ID"
|
||||||
EnvCorsoM365TestUserID = "CORSO_M365_TEST_USER_ID"
|
EnvCorsoM365TestUserID = "CORSO_M365_TEST_USER_ID"
|
||||||
EnvCorsoSecondaryM365TestSiteID = "CORSO_SECONDARY_M365_TEST_SITE_ID"
|
EnvCorsoSecondaryM365TestSiteID = "CORSO_SECONDARY_M365_TEST_SITE_ID"
|
||||||
EnvCorsoSecondaryM365TestUserID = "CORSO_SECONDARY_M365_TEST_USER_ID"
|
EnvCorsoSecondaryM365TestUserID = "CORSO_SECONDARY_M365_TEST_USER_ID"
|
||||||
@ -167,6 +169,12 @@ func ReadTestConfig() (map[string]string, error) {
|
|||||||
os.Getenv(EnvCorsoM365TestGroupID),
|
os.Getenv(EnvCorsoM365TestGroupID),
|
||||||
vpr.GetString(TestCfgGroupID),
|
vpr.GetString(TestCfgGroupID),
|
||||||
"6f24b40d-b13d-4752-980f-f5fb9fba7aa0")
|
"6f24b40d-b13d-4752-980f-f5fb9fba7aa0")
|
||||||
|
fallbackTo(
|
||||||
|
testEnv,
|
||||||
|
TestCfgChannelID,
|
||||||
|
os.Getenv(EnvCorsoM365TestChannelID),
|
||||||
|
vpr.GetString(TestCfgChannelID),
|
||||||
|
"19:nY6QHZ3hnHJ6ylarBxPjCOLRJNvrL3oKI5iW15QxTPA1@thread.tacv2")
|
||||||
fallbackTo(
|
fallbackTo(
|
||||||
testEnv,
|
testEnv,
|
||||||
TestCfgSiteURL,
|
TestCfgSiteURL,
|
||||||
|
|||||||
@ -246,3 +246,14 @@ func M365GroupID(t *testing.T) string {
|
|||||||
|
|
||||||
return strings.ToLower(cfg[TestCfgTeamID])
|
return strings.ToLower(cfg[TestCfgTeamID])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// M365ChannelID returns a channelID string representing the m365TeamsID described
|
||||||
|
// by either the env var CORSO_M365_TEST_CHANNEL_ID, the corso_test.toml config
|
||||||
|
// file or the default value (in that order of priority). The default is a
|
||||||
|
// last-attempt fallback that will only work on alcion's testing org.
|
||||||
|
func M365ChannelID(t *testing.T) string {
|
||||||
|
cfg, err := ReadTestConfig()
|
||||||
|
require.NoError(t, err, "retrieving m365 channel id from test configuration: %+v", clues.ToCore(err))
|
||||||
|
|
||||||
|
return cfg[TestCfgChannelID]
|
||||||
|
}
|
||||||
|
|||||||
@ -37,6 +37,9 @@ const (
|
|||||||
|
|
||||||
// Folder Management(30x)
|
// Folder Management(30x)
|
||||||
FolderItem ItemType = 306
|
FolderItem ItemType = 306
|
||||||
|
|
||||||
|
// GroupChannel(40x)
|
||||||
|
GroupChannel ItemType = 407
|
||||||
)
|
)
|
||||||
|
|
||||||
func UpdateItem(item *ItemInfo, newLocPath *path.Builder) {
|
func UpdateItem(item *ItemInfo, newLocPath *path.Builder) {
|
||||||
|
|||||||
@ -1 +1,380 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
|
"github.com/microsoft/kiota-abstractions-go/serialization"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/teams"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// controller
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (c Client) Channels() Channels {
|
||||||
|
return Channels{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channels is an interface-compliant provider of the client.
|
||||||
|
type Channels struct {
|
||||||
|
Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// containers
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// CreateContainer makes an channels with the name in the team
|
||||||
|
func (c Channels) CreateChannel(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, containerName string,
|
||||||
|
) (graph.Container, error) {
|
||||||
|
body := models.NewChannel()
|
||||||
|
body.SetDisplayName(&containerName)
|
||||||
|
|
||||||
|
container, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
Post(ctx, body, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Wrap(ctx, err, "creating channel")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChannelsDisplayable{Channelable: container}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteChannel removes a channel from user's M365 account
|
||||||
|
func (c Channels) DeleteChannel(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, containerID string,
|
||||||
|
) error {
|
||||||
|
// deletes require unique http clients
|
||||||
|
// https://github.com/alcionai/corso/issues/2707
|
||||||
|
srv, err := NewService(c.Credentials)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = srv.Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(containerID).
|
||||||
|
Delete(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Channels) GetChannel(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, containerID string,
|
||||||
|
) (models.Channelable, error) {
|
||||||
|
config := &teams.ItemChannelsChannelItemRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &teams.ItemChannelsChannelItemRequestBuilderGetQueryParameters{
|
||||||
|
Select: idAnd("displayName"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(containerID).
|
||||||
|
Get(ctx, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Channels) GetChannelByID(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, containerID string,
|
||||||
|
) (graph.Container, error) {
|
||||||
|
channel, err := c.GetChannel(ctx, teamID, containerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChannelsDisplayable{Channelable: channel}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChannelByName fetches a channel by name
|
||||||
|
func (c Channels) GetChannelByName(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, containerName string,
|
||||||
|
) (graph.Container, error) {
|
||||||
|
ctx = clues.Add(ctx, "channel_name", containerName)
|
||||||
|
|
||||||
|
filter := fmt.Sprintf("displayName eq '%s'", containerName)
|
||||||
|
options := &teams.ItemChannelsRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &teams.ItemChannelsRequestBuilderGetQueryParameters{
|
||||||
|
Filter: &filter,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
Get(ctx, options)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err).WithClues(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
gv := resp.GetValue()
|
||||||
|
|
||||||
|
if len(gv) == 0 {
|
||||||
|
return nil, clues.New("channel not found").WithClues(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only allow the api to match one channel with the provided name.
|
||||||
|
// If we match multiples, we'll eagerly return the first one.
|
||||||
|
logger.Ctx(ctx).Debugw("channels matched the name search")
|
||||||
|
|
||||||
|
// Sanity check ID and name
|
||||||
|
cal := gv[0]
|
||||||
|
container := ChannelsDisplayable{Channelable: cal}
|
||||||
|
|
||||||
|
if err := graph.CheckIDAndName(container); err != nil {
|
||||||
|
return nil, clues.Stack(err).WithClues(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return container, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Channels) PatchChannel(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, containerID string,
|
||||||
|
body models.Channelable,
|
||||||
|
) error {
|
||||||
|
_, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(containerID).
|
||||||
|
Patch(ctx, body, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return graph.Wrap(ctx, err, "patching channel")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// message
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// GetItem retrieves a Messageable item.
|
||||||
|
func (c Channels) GetMessage(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, channelID, itemID string,
|
||||||
|
immutableIDs bool,
|
||||||
|
errs *fault.Bus,
|
||||||
|
) (serialization.Parsable, *details.GroupsInfo, error) {
|
||||||
|
var (
|
||||||
|
size int64
|
||||||
|
)
|
||||||
|
|
||||||
|
// is preferImmutableIDs headers required here
|
||||||
|
message, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(channelID).
|
||||||
|
Messages().
|
||||||
|
ByChatMessageId(itemID).
|
||||||
|
Get(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return message, MessageInfo(message, size), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Channels) PostMessage(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, containerID string,
|
||||||
|
body models.ChatMessageable,
|
||||||
|
) (models.ChatMessageable, error) {
|
||||||
|
itm, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(containerID).
|
||||||
|
Messages().
|
||||||
|
Post(ctx, body, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Wrap(ctx, err, "creating mail message")
|
||||||
|
}
|
||||||
|
|
||||||
|
if itm == nil {
|
||||||
|
return nil, clues.New("nil response mail message creation").WithClues(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return itm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Channels) DeleteMessage(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, itemID, containerID string,
|
||||||
|
) error {
|
||||||
|
// deletes require unique http clients
|
||||||
|
// https://github.com/alcionai/corso/issues/2707
|
||||||
|
srv, err := NewService(c.Credentials)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = srv.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(containerID).
|
||||||
|
Messages().
|
||||||
|
ByChatMessageId(itemID).
|
||||||
|
Delete(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Wrap(ctx, err, "deleting mail message")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// replies
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// GetReplies retrieves a Messageable item.
|
||||||
|
func (c Channels) GetReplies(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, channelID, itemID string,
|
||||||
|
) (serialization.Parsable, error) {
|
||||||
|
replies, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(channelID).
|
||||||
|
Messages().
|
||||||
|
ByChatMessageId(itemID).
|
||||||
|
Replies().
|
||||||
|
Get(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return replies, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Channels) PostReply(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, containerID, messageID string,
|
||||||
|
body models.ChatMessageable,
|
||||||
|
) (models.ChatMessageable, error) {
|
||||||
|
itm, err := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(containerID).
|
||||||
|
Messages().
|
||||||
|
ByChatMessageId(messageID).
|
||||||
|
Replies().
|
||||||
|
Post(ctx, body, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Wrap(ctx, err, "creating reply message")
|
||||||
|
}
|
||||||
|
|
||||||
|
if itm == nil {
|
||||||
|
return nil, clues.New("nil response reply to message creation").WithClues(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return itm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Channels) DeleteReply(
|
||||||
|
ctx context.Context,
|
||||||
|
teamID, itemID, containerID, replyID string,
|
||||||
|
) error {
|
||||||
|
// deletes require unique http clients
|
||||||
|
// https://github.com/alcionai/corso/issues/2707
|
||||||
|
srv, err := NewService(c.Credentials)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = srv.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(containerID).
|
||||||
|
Messages().
|
||||||
|
ByChatMessageId(itemID).
|
||||||
|
Replies().
|
||||||
|
ByChatMessageId1(replyID).
|
||||||
|
Delete(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return graph.Wrap(ctx, err, "deleting mail message")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func MessageInfo(msg models.ChatMessageable, size int64) *details.GroupsInfo {
|
||||||
|
var (
|
||||||
|
created = ptr.Val(msg.GetCreatedDateTime())
|
||||||
|
)
|
||||||
|
|
||||||
|
return &details.GroupsInfo{
|
||||||
|
ItemType: details.GroupChannel,
|
||||||
|
Size: size,
|
||||||
|
Created: created,
|
||||||
|
Modified: ptr.OrNow(msg.GetLastModifiedDateTime()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// helper funcs
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ChannelsDisplayable is a wrapper that complies with the
|
||||||
|
// models.Channelable interface with the graph.Container
|
||||||
|
// interfaces.
|
||||||
|
type ChannelsDisplayable struct {
|
||||||
|
models.Channelable
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetParentFolderId returns the default channe name address
|
||||||
|
|
||||||
|
//nolint:revive
|
||||||
|
func (c ChannelsDisplayable) GetParentFolderId() *string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import "github.com/microsoftgraph/msgraph-sdk-go/models"
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/teams"
|
||||||
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// item pager
|
// item pager
|
||||||
@ -12,18 +20,66 @@ type ChannelMessageDeltaEnumerator interface {
|
|||||||
SetNextLinker
|
SetNextLinker
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement
|
var _ ChannelMessageDeltaEnumerator = &MessagePageCtrl{}
|
||||||
// var _ ChannelMessageDeltaEnumerator = &messagePageCtrl{}
|
|
||||||
|
|
||||||
// type messagePageCtrl struct {
|
type MessagePageCtrl struct {
|
||||||
// gs graph.Servicer
|
gs graph.Servicer
|
||||||
// builder *teams.ItemChannelsItemMessagesRequestBuilder
|
builder *teams.ItemChannelsItemMessagesDeltaRequestBuilder
|
||||||
// options *teams.ItemChannelsItemMessagesRequestBuilderGetRequestConfiguration
|
options *teams.ItemChannelsItemMessagesDeltaRequestBuilderGetRequestConfiguration
|
||||||
// }
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
func (c Channels) NewMessagePager(
|
||||||
// channel pager
|
teamID,
|
||||||
// ---------------------------------------------------------------------------
|
channelID string,
|
||||||
|
fields []string,
|
||||||
|
) *MessagePageCtrl {
|
||||||
|
requestConfig := &teams.ItemChannelsItemMessagesDeltaRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &teams.ItemChannelsItemMessagesDeltaRequestBuilderGetQueryParameters{
|
||||||
|
Select: fields,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
res := &MessagePageCtrl{
|
||||||
|
gs: c.Stable,
|
||||||
|
options: requestConfig,
|
||||||
|
builder: c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(channelID).
|
||||||
|
Messages().
|
||||||
|
Delta(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *MessagePageCtrl) SetNext(nextLink string) {
|
||||||
|
p.builder = teams.NewItemChannelsItemMessagesDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *MessagePageCtrl) GetPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||||
|
var (
|
||||||
|
resp DeltaPageLinker
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
resp, err = p.builder.Get(ctx, p.options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *MessagePageCtrl) ValuesIn(l PageLinker) ([]models.ChatMessageable, error) {
|
||||||
|
return getValues[models.ChatMessageable](l)
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageItemIDType struct {
|
||||||
|
ItemID string
|
||||||
|
}
|
||||||
|
|
||||||
type ChannelDeltaEnumerator interface {
|
type ChannelDeltaEnumerator interface {
|
||||||
DeltaGetPager
|
DeltaGetPager
|
||||||
@ -33,9 +89,69 @@ type ChannelDeltaEnumerator interface {
|
|||||||
|
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
// var _ ChannelDeltaEnumerator = &channelsPageCtrl{}
|
// var _ ChannelDeltaEnumerator = &channelsPageCtrl{}
|
||||||
|
type channelItemPageCtrl struct {
|
||||||
|
gs graph.Servicer
|
||||||
|
builder *teams.ItemChannelsItemMessagesRequestBuilder
|
||||||
|
options *teams.ItemChannelsItemMessagesRequestBuilderGetRequestConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
// type channelsPageCtrl struct {
|
func (c Channels) GetItemIDsInContainer(
|
||||||
// gs graph.Servicer
|
ctx context.Context,
|
||||||
// builder *teams.ItemChannelsChannelItemRequestBuilder
|
teamID, channelID string,
|
||||||
// options *teams.ItemChannelsChannelItemRequestBuilderGetRequestConfiguration
|
) (map[string]MessageItemIDType, error) {
|
||||||
// }
|
ctx = clues.Add(ctx, "channel_id", channelID)
|
||||||
|
pager := c.NewChannelItemPager(teamID, channelID)
|
||||||
|
|
||||||
|
items, err := enumerateItems(ctx, pager)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Wrap(ctx, err, "enumerating contacts")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]MessageItemIDType{}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
m[ptr.Val(item.GetId())] = MessageItemIDType{
|
||||||
|
ItemID: ptr.Val(item.GetId()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Channels) NewChannelItemPager(
|
||||||
|
teamID, containerID string,
|
||||||
|
selectProps ...string,
|
||||||
|
) itemPager[models.ChatMessageable] {
|
||||||
|
options := &teams.ItemChannelsItemMessagesRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &teams.ItemChannelsItemMessagesRequestBuilderGetQueryParameters{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selectProps) > 0 {
|
||||||
|
options.QueryParameters.Select = selectProps
|
||||||
|
}
|
||||||
|
|
||||||
|
builder := c.Stable.
|
||||||
|
Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(containerID).
|
||||||
|
Messages()
|
||||||
|
|
||||||
|
return &channelItemPageCtrl{c.Stable, builder, options}
|
||||||
|
}
|
||||||
|
|
||||||
|
//lint:ignore U1000 False Positive
|
||||||
|
func (p *channelItemPageCtrl) getPage(ctx context.Context) (PageLinkValuer[models.ChatMessageable], error) {
|
||||||
|
page, err := p.builder.Get(ctx, p.options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graph.Stack(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return EmptyDeltaLinker[models.ChatMessageable]{PageLinkValuer: page}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//lint:ignore U1000 False Positive
|
||||||
|
func (p *channelItemPageCtrl) setNext(nextLink string) {
|
||||||
|
p.builder = teams.NewItemChannelsItemMessagesRequestBuilder(nextLink, p.gs.Adapter())
|
||||||
|
}
|
||||||
|
|||||||
167
src/pkg/services/m365/api/channels_pager_test.go
Normal file
167
src/pkg/services/m365/api/channels_pager_test.go
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
package api_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
"github.com/alcionai/corso/src/internal/tester/tconfig"
|
||||||
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChannelPagerIntgSuite struct {
|
||||||
|
tester.Suite
|
||||||
|
its intgTesterSetup
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChannelPagerIntgSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &ChannelPagerIntgSuite{
|
||||||
|
Suite: tester.NewIntegrationSuite(
|
||||||
|
t,
|
||||||
|
[][]string{tconfig.M365AcctCredEnvs}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ChannelPagerIntgSuite) SetupSuite() {
|
||||||
|
suite.its = newIntegrationTesterSetup(suite.T())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ChannelPagerIntgSuite) TestChannels_GetPage() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
teamID := tconfig.M365TeamID(t)
|
||||||
|
channelID := tconfig.M365ChannelID(t)
|
||||||
|
pager := suite.its.ac.Channels().NewMessagePager(teamID, channelID, []string{})
|
||||||
|
a, err := pager.GetPage(ctx)
|
||||||
|
assert.NoError(t, err, clues.ToCore(err))
|
||||||
|
assert.NotNil(t, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ChannelPagerIntgSuite) TestChannels_CreateGetAndDelete() {
|
||||||
|
t := suite.T()
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
var (
|
||||||
|
yy, mm, dd = time.Now().Date()
|
||||||
|
hh = time.Now().Hour()
|
||||||
|
min = time.Now().Minute()
|
||||||
|
ss = time.Now().Second()
|
||||||
|
containerName = fmt.Sprintf("testChannel%d%d%d%d%d%d", yy, mm, dd, hh, min, ss)
|
||||||
|
teamID = tconfig.M365TeamID(t)
|
||||||
|
credentials = suite.its.ac.Credentials
|
||||||
|
chanClient = suite.its.ac.Channels()
|
||||||
|
)
|
||||||
|
|
||||||
|
// GET channel - should be not found
|
||||||
|
_, err := suite.its.ac.Channels().GetChannelByName(ctx, teamID, containerName)
|
||||||
|
assert.Error(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// POST channel
|
||||||
|
channelPost, err := suite.its.ac.Channels().CreateChannel(ctx, teamID, containerName)
|
||||||
|
assert.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
postChannelID := ptr.Val(channelPost.GetId())
|
||||||
|
|
||||||
|
// DELETE channel
|
||||||
|
defer func() {
|
||||||
|
_, err := chanClient.GetChannelByID(ctx, teamID, postChannelID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("could not find channel: ", err)
|
||||||
|
} else {
|
||||||
|
deleteChannel(ctx, credentials, teamID, postChannelID)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// GET channel -should be found
|
||||||
|
channel, err := chanClient.GetChannelByName(ctx, teamID, containerName)
|
||||||
|
assert.NoError(t, err, clues.ToCore(err))
|
||||||
|
assert.Equal(t, ptr.Val(channel.GetDisplayName()), containerName)
|
||||||
|
|
||||||
|
// PATCH channel
|
||||||
|
patchBody := models.NewChannel()
|
||||||
|
patchName := fmt.Sprintf("othername%d%d%d%d%d%d", yy, mm, dd, hh, min, ss)
|
||||||
|
patchBody.SetDisplayName(ptr.To(patchName))
|
||||||
|
err = chanClient.PatchChannel(ctx, teamID, postChannelID, patchBody)
|
||||||
|
assert.NoError(t, err, clues.ToCore(err))
|
||||||
|
assert.Equal(t, ptr.Val(channel.GetDisplayName()), containerName)
|
||||||
|
|
||||||
|
// GET channel -should not be found with old name
|
||||||
|
_, err = chanClient.GetChannelByName(ctx, teamID, containerName)
|
||||||
|
assert.Error(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// GET channel -should be found with new name
|
||||||
|
channel, err = chanClient.GetChannelByName(ctx, teamID, patchName)
|
||||||
|
assert.NoError(t, err, clues.ToCore(err))
|
||||||
|
assert.Equal(t, ptr.Val(channel.GetDisplayName()), patchName)
|
||||||
|
assert.Equal(t, ptr.Val(channel.GetId()), postChannelID)
|
||||||
|
|
||||||
|
// GET channel -should not be found with old name
|
||||||
|
err = chanClient.DeleteChannel(ctx, teamID, postChannelID)
|
||||||
|
assert.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// GET channel -should not be found anymore
|
||||||
|
_, err = chanClient.GetChannel(ctx, teamID, postChannelID)
|
||||||
|
assert.Error(t, err, clues.ToCore(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteChannel(ctx context.Context, credentials account.M365Config, teamID, postChannelID string) {
|
||||||
|
srv, err := api.NewService(credentials)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error found in getting creds")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error found in getting creds")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = srv.Client().
|
||||||
|
Teams().
|
||||||
|
ByTeamId(teamID).
|
||||||
|
Channels().
|
||||||
|
ByChannelId(postChannelID).
|
||||||
|
Delete(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("channel could not be delete in defer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (suite *ChannelPagerIntgSuite) TestMessages_CreateGetAndDelete() {
|
||||||
|
// t := suite.T()
|
||||||
|
// ctx, flush := tester.NewContext(t)
|
||||||
|
// defer flush()
|
||||||
|
|
||||||
|
// var (
|
||||||
|
// teamID = tconfig.M365TeamsID(t)
|
||||||
|
// channelID = tconfig.M365ChannelID(t)
|
||||||
|
// credentials = suite.its.ac.Credentials
|
||||||
|
// chanClient = suite.its.ac.Channels()
|
||||||
|
// )
|
||||||
|
|
||||||
|
// // GET channel - should be not found
|
||||||
|
// message, _, err := chanClient.GetMessage(ctx, teamID, channelID, "", "")
|
||||||
|
// assert.Error(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// // POST channel
|
||||||
|
// // patchBody := models.NewChatMessage()
|
||||||
|
// // body := models.NewItemBody()
|
||||||
|
// // content := "Hello World"
|
||||||
|
// // body.SetContent(&content)
|
||||||
|
// // patchBody.SetBody(body)
|
||||||
|
|
||||||
|
// // _, := suite.its.ac.Channels().PostMessage(ctx, teamID, channelID, patchBody)
|
||||||
|
// // assert.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// }
|
||||||
Loading…
x
Reference in New Issue
Block a user