channels and messages API
This commit is contained in:
parent
5fbc37fbc1
commit
54d5e05950
@ -13,6 +13,5 @@ type BackupMessagesHandler interface {
|
||||
GetMessage(ctx context.Context, teamID, channelID, itemID string) (models.ChatMessageable, error)
|
||||
NewMessagePager(teamID, channelID string) api.MessageItemDeltaEnumerator
|
||||
GetChannel(ctx context.Context, teamID, channelID string) (models.Channelable, error)
|
||||
NewChannelPager(teamID, channelID string) api.ChannelItemDeltaEnumerator
|
||||
GetReply(ctx context.Context, teamID, channelID, messageID string) (serialization.Parsable, error)
|
||||
}
|
||||
|
||||
@ -36,6 +36,9 @@ const (
|
||||
|
||||
// Folder Management(30x)
|
||||
FolderItem ItemType = 306
|
||||
|
||||
// GroupChannel(40x)
|
||||
GroupChannel ItemType = 407
|
||||
)
|
||||
|
||||
func UpdateItem(item *ItemInfo, newLocPath *path.Builder) {
|
||||
|
||||
@ -1 +1,376 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
// prefer GetChannelByID where possible.
|
||||
// use this only in cases where the models.Channelable
|
||||
// is required.
|
||||
func (c Channels) GetChannel(
|
||||
ctx context.Context,
|
||||
teamID, containerID string,
|
||||
) (models.Channelable, error) {
|
||||
config := &teams.ItemChannelsChannelItemRequestBuilderGetRequestConfiguration{
|
||||
QueryParameters: &teams.ItemChannelsChannelItemRequestBuilderGetQueryParameters{
|
||||
Select: idAnd("name", "owner"),
|
||||
},
|
||||
}
|
||||
|
||||
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 calendar by name
|
||||
func (c Channels) GetChannelByName(
|
||||
ctx context.Context,
|
||||
teamID, _, containerName string,
|
||||
) (graph.Container, error) {
|
||||
|
||||
ctx = clues.Add(ctx, "channel_name", containerName)
|
||||
|
||||
resp, err := c.Stable.
|
||||
Client().
|
||||
Teams().
|
||||
ByTeamId(teamID).
|
||||
Channels().
|
||||
Get(ctx, nil)
|
||||
|
||||
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 calendar with the provided name.
|
||||
// If we match multiples, we'll eagerly return the first one.
|
||||
logger.Ctx(ctx).Debugw("calendars matched the name search", "calendar_count", len(gv))
|
||||
|
||||
// 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 event calendar")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -2,6 +2,9 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/teams"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -9,31 +12,59 @@ import (
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type MessageItemDeltaEnumerator interface {
|
||||
GetPage(context.Context) (DeltaPageLinker, error)
|
||||
GetPage(context.Context) (PageLinker, error)
|
||||
SetNext(nextLink string)
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
// var _ MessageItemDeltaEnumerator = &messagePageCtrl{}
|
||||
var _ MessageItemDeltaEnumerator = &messagePageCtrl{}
|
||||
|
||||
// type messagePageCtrl struct {
|
||||
// gs graph.Servicer
|
||||
// builder *teams.ItemChannelsItemMessagesRequestBuilder
|
||||
// options *teams.ItemChannelsItemMessagesRequestBuilderGetRequestConfiguration
|
||||
// }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// channel pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type ChannelItemDeltaEnumerator interface {
|
||||
GetPage(context.Context) (DeltaPageLinker, error)
|
||||
type messagePageCtrl struct {
|
||||
gs graph.Servicer
|
||||
builder *teams.ItemChannelsItemMessagesDeltaRequestBuilder
|
||||
options *teams.ItemChannelsItemMessagesDeltaRequestBuilderGetRequestConfiguration
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
// var _ ChannelsItemDeltaEnumerator = &channelsPageCtrl{}
|
||||
func (c Channels) NewMessagePager(
|
||||
teamID,
|
||||
channelID string,
|
||||
fields []string,
|
||||
) *messagePageCtrl {
|
||||
requestConfig := &teams.ItemChannelsItemMessagesDeltaRequestBuilderGetRequestConfiguration{
|
||||
QueryParameters: &teams.ItemChannelsItemMessagesDeltaRequestBuilderGetQueryParameters{
|
||||
Select: fields,
|
||||
},
|
||||
}
|
||||
|
||||
// type channelsPageCtrl struct {
|
||||
// gs graph.Servicer
|
||||
// builder *teams.ItemChannelsChannelItemRequestBuilder
|
||||
// options *teams.ItemChannelsChannelItemRequestBuilderGetRequestConfiguration
|
||||
// }
|
||||
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) (PageLinker, error) {
|
||||
var (
|
||||
resp PageLinker
|
||||
err error
|
||||
)
|
||||
|
||||
resp, err = p.builder.Get(ctx, p.options)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user