expose additional channel metadata (#4539)

builds out more details for channel messages and replies

---

#### Does this PR need a docs update or release note?

- [x]  No

#### Type of change

- [ ] 🌻 Feature

#### Issue(s)

* #3988

#### Test Plan

- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2023-10-26 12:03:44 -06:00 committed by GitHub
parent eb188e0514
commit 1470776f3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 633 additions and 153 deletions

View File

@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- SharePoint backup would fail if any site had an empty display name
- Fix a bug with exports hanging post completion
### Changed
- Item Details formatting in Groups and Teams backups. Pre-release users will need to run new backups to avoid data corruption.
## [v0.14.2] (beta) - 2023-10-17
### Added

View File

@ -90,10 +90,14 @@ func streamItems(
type (
minimumChannelMessage struct {
// TODO(keepers): remove attachmentNames when better formatting
// of attachments within the content body is implemented.
AttachmentNames []string `json:"attachmentNames"`
Content string `json:"content"`
CreatedDateTime time.Time `json:"createdDateTime"`
From string `json:"from"`
LastModifiedDateTime time.Time `json:"lastModifiedDateTime"`
Subject string `json:"subject"`
}
minimumChannelMessageAndReplies struct {
@ -155,9 +159,11 @@ func makeMinimumChannelMesasge(item models.ChatMessageable) minimumChannelMessag
}
return minimumChannelMessage{
AttachmentNames: api.GetChatMessageAttachmentNames(item),
Content: content,
CreatedDateTime: ptr.Val(item.GetCreatedDateTime()),
From: api.GetChatMessageFrom(item),
LastModifiedDateTime: ptr.Val(item.GetLastModifiedDateTime()),
Subject: ptr.Val(item.GetSubject()),
}
}

View File

@ -37,25 +37,33 @@ func NewGroupsLocationIDer(
// GroupsInfo describes a groups item
type GroupsInfo struct {
Created time.Time `json:"created,omitempty"`
ItemName string `json:"itemName,omitempty"`
ItemType ItemType `json:"itemType,omitempty"`
Modified time.Time `json:"modified,omitempty"`
Owner string `json:"owner,omitempty"`
ParentPath string `json:"parentPath,omitempty"`
Size int64 `json:"size,omitempty"`
ItemType ItemType `json:"itemType,omitempty"`
Modified time.Time `json:"modified,omitempty"`
// Channels Specific
LastReplyAt time.Time `json:"lastResponseAt,omitempty"`
MessageCreator string `json:"messageCreator,omitempty"`
MessagePreview string `json:"messagePreview,omitempty"`
ReplyCount int `json:"replyCount,omitempty"`
Message ChannelMessageInfo `json:"message"`
LastReply ChannelMessageInfo `json:"lastReply"`
// SharePoint specific
DriveName string `json:"driveName,omitempty"`
DriveID string `json:"driveID,omitempty"`
SiteID string `json:"siteID,omitempty"`
WebURL string `json:"webURL,omitempty"`
Created time.Time `json:"created,omitempty"`
DriveName string `json:"driveName,omitempty"`
DriveID string `json:"driveID,omitempty"`
ItemName string `json:"itemName,omitempty"`
Owner string `json:"owner,omitempty"`
ParentPath string `json:"parentPath,omitempty"`
SiteID string `json:"siteID,omitempty"`
Size int64 `json:"size,omitempty"`
WebURL string `json:"webURL,omitempty"`
}
type ChannelMessageInfo struct {
AttachmentNames []string `json:"attachmentNames,omitempty"`
CreatedAt time.Time `json:"createdAt,omitempty"`
Creator string `json:"creator,omitempty"`
Preview string `json:"preview,omitempty"`
ReplyCount int `json:"replyCount"`
Size int64 `json:"size,omitempty"`
Subject string `json:"subject,omitempty"`
}
// Headers returns the human-readable names of properties in a SharePointInfo
@ -65,7 +73,7 @@ func (i GroupsInfo) Headers() []string {
case SharePointLibrary:
return []string{"ItemName", "Library", "ParentPath", "Size", "Owner", "Created", "Modified"}
case GroupsChannelMessage:
return []string{"Message", "Channel", "Replies", "Creator", "Created", "Last Reply"}
return []string{"Message", "Channel", "Subject", "Replies", "Creator", "Created", "Last Reply"}
}
return []string{}
@ -86,17 +94,18 @@ func (i GroupsInfo) Values() []string {
dttm.FormatToTabularDisplay(i.Modified),
}
case GroupsChannelMessage:
lastReply := dttm.FormatToTabularDisplay(i.LastReplyAt)
if i.LastReplyAt.Equal(time.Time{}) {
lastReply := dttm.FormatToTabularDisplay(i.LastReply.CreatedAt)
if i.LastReply.CreatedAt.IsZero() {
lastReply = ""
}
return []string{
i.MessagePreview,
i.Message.Preview,
i.ParentPath,
strconv.Itoa(i.ReplyCount),
i.MessageCreator,
dttm.FormatToTabularDisplay(i.Created),
i.Message.Subject,
strconv.Itoa(i.Message.ReplyCount),
i.Message.Creator,
dttm.FormatToTabularDisplay(i.Message.CreatedAt),
lastReply,
}
}

View File

@ -0,0 +1,58 @@
package details_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/common/dttm"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/backup/details"
)
type GroupsUnitSuite struct {
tester.Suite
}
func TestGroupsUnitSuite(t *testing.T) {
suite.Run(t, &GroupsUnitSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *GroupsUnitSuite) TestGroupsPrintable() {
t := suite.T()
now := time.Now()
then := now.Add(time.Minute)
gi := details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
ParentPath: "parentPath",
Message: details.ChannelMessageInfo{
Preview: "preview",
ReplyCount: 1,
Creator: "creator",
CreatedAt: now,
Subject: "subject",
},
LastReply: details.ChannelMessageInfo{
CreatedAt: then,
},
}
expectVs := []string{
"preview",
"parentPath",
"subject",
"1",
"creator",
dttm.FormatToTabularDisplay(now),
dttm.FormatToTabularDisplay(then),
}
hs := gi.Headers()
vs := gi.Values()
assert.Equal(t, len(hs), len(vs))
assert.Equal(t, expectVs, vs)
}

View File

@ -3,7 +3,6 @@ package selectors
import (
"context"
"fmt"
"time"
"github.com/alcionai/clues"
@ -826,15 +825,15 @@ func (s GroupsScope) matchesInfo(dii details.ItemInfo) bool {
case GroupsInfoLibraryItemModifiedAfter, GroupsInfoLibraryItemModifiedBefore:
i = dttm.Format(info.Modified)
case GroupsInfoChannelMessageCreator:
i = info.MessageCreator
i = info.Message.Creator
case GroupsInfoChannelMessageCreatedAfter, GroupsInfoChannelMessageCreatedBefore:
i = dttm.Format(info.Created)
i = dttm.Format(info.Message.CreatedAt)
case GroupsInfoChannelMessageLastReplyAfter, GroupsInfoChannelMessageLastReplyBefore:
if info.LastReplyAt.Equal(time.Time{}) {
if info.LastReply.CreatedAt.IsZero() {
return false
}
i = dttm.Format(info.LastReplyAt)
i = dttm.Format(info.LastReply.CreatedAt)
}
return s.Matches(infoCat, i) && int(info.ItemType) == acceptableItemType

View File

@ -370,53 +370,67 @@ func (suite *GroupsSelectorSuite) TestGroupsScope_MatchesInfo() {
dspl = details.SharePointLibrary
)
type expectation func(t assert.TestingT, value bool, msg string, args ...any) bool
table := []struct {
name string
itemType details.ItemType
creator string
scope []GroupsScope
expect assert.BoolAssertionFunc
expect expectation
}{
{"file create after the epoch", dspl, user, sel.CreatedAfter(dttm.Format(epoch)), assert.True},
{"file create after the epoch wrong type", dgcm, user, sel.CreatedAfter(dttm.Format(epoch)), assert.False},
{"file create after now", dspl, user, sel.CreatedAfter(dttm.Format(now)), assert.False},
{"file create after later", dspl, user, sel.CreatedAfter(dttm.Format(future)), assert.False},
{"file create before future", dspl, user, sel.CreatedBefore(dttm.Format(future)), assert.True},
{"file create before future wrong type", dgcm, user, sel.CreatedBefore(dttm.Format(future)), assert.False},
{"file create before now", dspl, user, sel.CreatedBefore(dttm.Format(now)), assert.False},
{"file create before modification", dspl, user, sel.CreatedBefore(dttm.Format(mod)), assert.True},
{"file create before epoch", dspl, user, sel.CreatedBefore(dttm.Format(now)), assert.False},
{"file modified after the epoch", dspl, user, sel.ModifiedAfter(dttm.Format(epoch)), assert.True},
{"file modified after now", dspl, user, sel.ModifiedAfter(dttm.Format(now)), assert.True},
{"file modified after later", dspl, user, sel.ModifiedAfter(dttm.Format(future)), assert.False},
{"file modified before future", dspl, user, sel.ModifiedBefore(dttm.Format(future)), assert.True},
{"file modified before now", dspl, user, sel.ModifiedBefore(dttm.Format(now)), assert.False},
{"file modified before epoch", dspl, user, sel.ModifiedBefore(dttm.Format(now)), assert.False},
{"in library", dspl, user, sel.Library("included-library"), assert.True},
{"not in library", dspl, user, sel.Library("not-included-library"), assert.False},
{"site id", dspl, user, sel.Site("site1"), assert.True},
{"web url", dspl, user, sel.Site(user), assert.True},
{"library id", dspl, user, sel.Library("1234"), assert.True},
{"not library id", dspl, user, sel.Library("abcd"), assert.False},
{"file create after the epoch", dspl, user, sel.CreatedAfter(dttm.Format(epoch)), assert.Truef},
{"file create after the epoch wrong type", dgcm, user, sel.CreatedAfter(dttm.Format(epoch)), assert.Falsef},
{"file create after now", dspl, user, sel.CreatedAfter(dttm.Format(now)), assert.Falsef},
{"file create after later", dspl, user, sel.CreatedAfter(dttm.Format(future)), assert.Falsef},
{"file create before future", dspl, user, sel.CreatedBefore(dttm.Format(future)), assert.Truef},
{"file create before future wrong type", dgcm, user, sel.CreatedBefore(dttm.Format(future)), assert.Falsef},
{"file create before now", dspl, user, sel.CreatedBefore(dttm.Format(now)), assert.Falsef},
{"file create before modification", dspl, user, sel.CreatedBefore(dttm.Format(mod)), assert.Truef},
{"file create before epoch", dspl, user, sel.CreatedBefore(dttm.Format(now)), assert.Falsef},
{"file modified after the epoch", dspl, user, sel.ModifiedAfter(dttm.Format(epoch)), assert.Truef},
{"file modified after now", dspl, user, sel.ModifiedAfter(dttm.Format(now)), assert.Truef},
{"file modified after later", dspl, user, sel.ModifiedAfter(dttm.Format(future)), assert.Falsef},
{"file modified before future", dspl, user, sel.ModifiedBefore(dttm.Format(future)), assert.Truef},
{"file modified before now", dspl, user, sel.ModifiedBefore(dttm.Format(now)), assert.Falsef},
{"file modified before epoch", dspl, user, sel.ModifiedBefore(dttm.Format(now)), assert.Falsef},
{"in library", dspl, user, sel.Library("included-library"), assert.Truef},
{"not in library", dspl, user, sel.Library("not-included-library"), assert.Falsef},
{"site id", dspl, user, sel.Site("site1"), assert.Truef},
{"web url", dspl, user, sel.Site(user), assert.Truef},
{"library id", dspl, user, sel.Library("1234"), assert.Truef},
{"not library id", dspl, user, sel.Library("abcd"), assert.Falsef},
{"channel message created by", dgcm, user, sel.MessageCreator(user), assert.True},
{"channel message not created by", dgcm, user, sel.MessageCreator(host), assert.False},
{"chan msg create after the epoch", dgcm, user, sel.MessageCreatedAfter(dttm.Format(epoch)), assert.True},
{"chan msg create after the epoch wrong type", dspl, user, sel.MessageCreatedAfter(dttm.Format(epoch)), assert.False},
{"chan msg create after now", dgcm, user, sel.MessageCreatedAfter(dttm.Format(now)), assert.False},
{"chan msg create after later", dgcm, user, sel.MessageCreatedAfter(dttm.Format(future)), assert.False},
{"chan msg create before future", dgcm, user, sel.MessageCreatedBefore(dttm.Format(future)), assert.True},
{"chan msg create before future wrong type", dspl, user, sel.MessageCreatedBefore(dttm.Format(future)), assert.False},
{"chan msg create before now", dgcm, user, sel.MessageCreatedBefore(dttm.Format(now)), assert.False},
{"chan msg create before reply", dgcm, user, sel.MessageCreatedBefore(dttm.Format(mod)), assert.True},
{"chan msg create before reply wrong type", dspl, user, sel.MessageCreatedBefore(dttm.Format(mod)), assert.False},
{"chan msg create before epoch", dgcm, user, sel.MessageCreatedBefore(dttm.Format(now)), assert.False},
{"chan msg last reply after the epoch", dgcm, user, sel.MessageLastReplyAfter(dttm.Format(epoch)), assert.True},
{"chan msg last reply after now", dgcm, user, sel.MessageLastReplyAfter(dttm.Format(now)), assert.True},
{"chan msg last reply after later", dgcm, user, sel.MessageLastReplyAfter(dttm.Format(future)), assert.False},
{"chan msg last reply before future", dgcm, user, sel.MessageLastReplyBefore(dttm.Format(future)), assert.True},
{"chan msg last reply before now", dgcm, user, sel.MessageLastReplyBefore(dttm.Format(now)), assert.False},
{"chan msg last reply before epoch", dgcm, user, sel.MessageLastReplyBefore(dttm.Format(now)), assert.False},
{"channel message created by", dgcm, user, sel.MessageCreator(user), assert.Truef},
{"channel message not created by", dgcm, user, sel.MessageCreator(host), assert.Falsef},
{"chan msg create after the epoch", dgcm, user, sel.MessageCreatedAfter(dttm.Format(epoch)), assert.Truef},
{
"chan msg create after the epoch wrong type",
dspl,
user,
sel.MessageCreatedAfter(dttm.Format(epoch)),
assert.Falsef,
},
{"chan msg create after now", dgcm, user, sel.MessageCreatedAfter(dttm.Format(now)), assert.Falsef},
{"chan msg create after later", dgcm, user, sel.MessageCreatedAfter(dttm.Format(future)), assert.Falsef},
{"chan msg create before future", dgcm, user, sel.MessageCreatedBefore(dttm.Format(future)), assert.Truef},
{
"chan msg create before future wrong type",
dspl,
user,
sel.MessageCreatedBefore(dttm.Format(future)),
assert.Falsef,
},
{"chan msg create before now", dgcm, user, sel.MessageCreatedBefore(dttm.Format(now)), assert.Falsef},
{"chan msg create before reply", dgcm, user, sel.MessageCreatedBefore(dttm.Format(mod)), assert.Truef},
{"chan msg create before reply wrong type", dspl, user, sel.MessageCreatedBefore(dttm.Format(mod)), assert.Falsef},
{"chan msg create before epoch", dgcm, user, sel.MessageCreatedBefore(dttm.Format(now)), assert.Falsef},
{"chan msg last reply after the epoch", dgcm, user, sel.MessageLastReplyAfter(dttm.Format(epoch)), assert.Truef},
{"chan msg last reply after now", dgcm, user, sel.MessageLastReplyAfter(dttm.Format(now)), assert.Truef},
{"chan msg last reply after later", dgcm, user, sel.MessageLastReplyAfter(dttm.Format(future)), assert.Falsef},
{"chan msg last reply before future", dgcm, user, sel.MessageLastReplyBefore(dttm.Format(future)), assert.Truef},
{"chan msg last reply before now", dgcm, user, sel.MessageLastReplyBefore(dttm.Format(now)), assert.Falsef},
{"chan msg last reply before epoch", dgcm, user, sel.MessageLastReplyBefore(dttm.Format(now)), assert.Falsef},
}
for _, test := range table {
suite.Run(test.name, func() {
@ -424,21 +438,31 @@ func (suite *GroupsSelectorSuite) TestGroupsScope_MatchesInfo() {
itemInfo := details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: test.itemType,
WebURL: test.creator,
MessageCreator: test.creator,
Created: now,
Modified: mod,
LastReplyAt: mod,
DriveName: "included-library",
DriveID: "1234",
SiteID: "site1",
ItemType: test.itemType,
Created: now,
WebURL: test.creator,
Modified: mod,
DriveName: "included-library",
DriveID: "1234",
SiteID: "site1",
Message: details.ChannelMessageInfo{
Creator: test.creator,
CreatedAt: now,
},
LastReply: details.ChannelMessageInfo{
CreatedAt: mod,
},
},
}
scopes := setScopesToDefault(test.scope)
for _, scope := range scopes {
test.expect(t, scope.matchesInfo(itemInfo))
test.expect(
t,
scope.matchesInfo(itemInfo),
"not matching:\nscope:\n\t%+v\ninfo:\n\t%+v",
scope,
itemInfo.Groups)
}
})
}

View File

@ -141,38 +141,58 @@ func channelMessageInfo(
msg models.ChatMessageable,
) *details.GroupsInfo {
var (
lastReply time.Time
modTime = ptr.OrNow(msg.GetLastModifiedDateTime())
content string
lastReply models.ChatMessageable
lastReplyAt time.Time
modTime = ptr.OrNow(msg.GetLastModifiedDateTime())
)
for _, r := range msg.GetReplies() {
replies := msg.GetReplies()
for _, r := range replies {
cdt := ptr.Val(r.GetCreatedDateTime())
if cdt.After(lastReply) {
lastReply = cdt
if cdt.After(lastReplyAt) {
lastReply = r
lastReplyAt = ptr.Val(r.GetCreatedDateTime())
}
}
// if the message hasn't been modified since before the most recent
// reply, set the modified time to the most recent reply. This ensures
// we update the message contents to match changes in replies.
if modTime.Before(lastReply) {
modTime = lastReply
if modTime.Before(lastReplyAt) {
modTime = lastReplyAt
}
if msg.GetBody() != nil {
content = ptr.Val(msg.GetBody().GetContent())
preview, contentLen := GetChatMessageContentPreview(msg)
message := details.ChannelMessageInfo{
AttachmentNames: GetChatMessageAttachmentNames(msg),
CreatedAt: ptr.Val(msg.GetCreatedDateTime()),
Creator: GetChatMessageFrom(msg),
Preview: preview,
ReplyCount: len(replies),
Size: contentLen,
Subject: ptr.Val(msg.GetSubject()),
}
var lr details.ChannelMessageInfo
if lastReply != nil {
preview, contentLen = GetChatMessageContentPreview(lastReply)
lr = details.ChannelMessageInfo{
AttachmentNames: GetChatMessageAttachmentNames(lastReply),
CreatedAt: ptr.Val(lastReply.GetCreatedDateTime()),
Creator: GetChatMessageFrom(lastReply),
Preview: preview,
Size: contentLen,
}
}
return &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Created: ptr.Val(msg.GetCreatedDateTime()),
LastReplyAt: lastReply,
Modified: modTime,
MessageCreator: GetChatMessageFrom(msg),
MessagePreview: str.Preview(content, 128),
ReplyCount: len(msg.GetReplies()),
Size: int64(len(content)),
ItemType: details.GroupsChannelMessage,
Modified: modTime,
Message: message,
LastReply: lr,
}
}
@ -212,3 +232,25 @@ func GetChatMessageFrom(msg models.ChatMessageable) string {
return ""
}
func GetChatMessageContentPreview(msg models.ChatMessageable) (string, int64) {
var content string
if msg.GetBody() != nil {
content = ptr.Val(msg.GetBody().GetContent())
}
return str.Preview(content, 128), int64(len(content))
}
func GetChatMessageAttachmentNames(msg models.ChatMessageable) []string {
names := make([]string, 0, len(msg.GetAttachments()))
for _, a := range msg.GetAttachments() {
if name := ptr.Val(a.GetName()); len(name) > 0 {
names = append(names, name)
}
}
return names
}

View File

@ -106,14 +106,16 @@ func testEnumerateChannelMessageReplies(
require.NoError(t, err, clues.ToCore(err))
var (
lastReply time.Time
replyIDs = map[string]struct{}{}
lastReply models.ChatMessageable
lastReplyAt time.Time
replyIDs = map[string]struct{}{}
)
for _, r := range replies {
cdt := ptr.Val(r.GetCreatedDateTime())
if cdt.After(lastReply) {
lastReply = cdt
if cdt.After(lastReplyAt) {
lastReply = r
lastReplyAt = cdt
}
replyIDs[ptr.Val(r.GetId())] = struct{}{}
@ -122,10 +124,20 @@ func testEnumerateChannelMessageReplies(
assert.Equal(t, messageID, ptr.Val(msg.GetId()))
assert.Equal(t, channelID, ptr.Val(msg.GetChannelIdentity().GetChannelId()))
assert.Equal(t, groupID, ptr.Val(msg.GetChannelIdentity().GetTeamId()))
assert.Equal(t, len(replies), info.ReplyCount)
assert.Equal(t, msg.GetFrom().GetUser().GetDisplayName(), info.MessageCreator)
assert.Equal(t, lastReply, info.LastReplyAt)
assert.Equal(t, str.Preview(ptr.Val(msg.GetBody().GetContent()), 128), info.MessagePreview)
// message
assert.Equal(t, len(msg.GetAttachments()), len(info.Message.AttachmentNames))
assert.Equal(t, len(replies), info.Message.ReplyCount)
assert.Equal(t, lastReplyAt, info.Message.CreatedAt)
assert.Equal(t, msg.GetFrom().GetUser().GetDisplayName(), info.Message.Creator)
assert.Equal(t, str.Preview(ptr.Val(msg.GetBody().GetContent()), 128), info.Message.Preview)
assert.Equal(t, len(ptr.Val(msg.GetBody().GetContent())), info.Message.Size)
// last reply
assert.Equal(t, len(lastReply.GetAttachments()), len(info.LastReply.AttachmentNames))
assert.Zero(t, info.LastReply.ReplyCount)
assert.Equal(t, lastReplyAt, info.LastReply.CreatedAt)
assert.Equal(t, lastReply.GetFrom().GetUser().GetDisplayName(), info.LastReply.Creator)
assert.Equal(t, str.Preview(ptr.Val(lastReply.GetBody().GetContent()), 128), info.LastReply.Preview)
assert.Equal(t, len(ptr.Val(lastReply.GetBody().GetContent())), info.LastReply.Size)
msgReplyIDs := map[string]struct{}{}

View File

@ -17,7 +17,7 @@ type ChannelsAPIUnitSuite struct {
tester.Suite
}
func TestChannelsAPIUnitSuitee(t *testing.T) {
func TestChannelsAPIUnitSuite(t *testing.T) {
suite.Run(t, &ChannelsAPIUnitSuite{Suite: tester.NewUnitSuite(t)})
}
@ -26,12 +26,36 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
initial = time.Now().Add(-24 * time.Hour)
mid = time.Now().Add(-1 * time.Hour)
curr = time.Now()
)
content = "content"
body = models.NewItemBody()
var (
content = "content"
body = models.NewItemBody()
replyContent = "replycontent"
replyBody = models.NewItemBody()
)
body.SetContent(ptr.To(content))
replyBody.SetContent(ptr.To(replyContent))
var (
attach1 = models.NewChatMessageAttachment()
attach2 = models.NewChatMessageAttachment()
replyAttach1 = models.NewChatMessageAttachment()
replyAttach2 = models.NewChatMessageAttachment()
)
attach1.SetName(ptr.To("attach1.ment"))
attach2.SetName(ptr.To("attach2.ment"))
replyAttach1.SetName(ptr.To("replyattach1.ment"))
replyAttach2.SetName(ptr.To("replyattach2.ment"))
var (
attachments = []models.ChatMessageAttachmentable{attach1, attach2}
replyAttachments = []models.ChatMessageAttachmentable{replyAttach1, replyAttach2}
expectAttachNames = []string{"attach1.ment", "attach2.ment"}
expectReplyAttachNames = []string{"replyattach1.ment", "replyattach2.ment"}
)
tests := []struct {
name string
@ -43,6 +67,7 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg := models.NewChatMessage()
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetSubject(ptr.To("subject"))
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("user"))
@ -53,12 +78,52 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetFrom(from)
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Created: initial,
Modified: initial,
LastReplyAt: time.Time{},
ReplyCount: 0,
MessageCreator: "user",
ItemType: details.GroupsChannelMessage,
Modified: initial,
LastReply: details.ChannelMessageInfo{},
Message: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: initial,
Creator: "user",
ReplyCount: 0,
Preview: "",
Size: 0,
Subject: "subject",
},
}
return msg, i
},
},
{
name: "No Subject",
msgAndInfo: func() (models.ChatMessageable, *details.GroupsInfo) {
msg := models.NewChatMessage()
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("user"))
from := models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
msg.SetFrom(from)
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Modified: initial,
LastReply: details.ChannelMessageInfo{},
Message: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: initial,
Creator: "user",
ReplyCount: 0,
Preview: content,
Size: int64(len(content)),
Subject: "",
},
}
return msg, i
@ -71,6 +136,7 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
msg.SetSubject(ptr.To("subject"))
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("user"))
@ -81,14 +147,18 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetFrom(from)
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Created: initial,
Modified: initial,
LastReplyAt: time.Time{},
ReplyCount: 0,
MessageCreator: "user",
Size: int64(len(content)),
MessagePreview: content,
ItemType: details.GroupsChannelMessage,
Modified: initial,
LastReply: details.ChannelMessageInfo{},
Message: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: initial,
Creator: "user",
ReplyCount: 0,
Preview: content,
Size: int64(len(content)),
Subject: "subject",
},
}
return msg, i
@ -101,6 +171,7 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
msg.SetSubject(ptr.To("subject"))
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("app"))
@ -111,14 +182,18 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetFrom(from)
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Created: initial,
Modified: initial,
LastReplyAt: time.Time{},
ReplyCount: 0,
MessageCreator: "app",
Size: int64(len(content)),
MessagePreview: content,
ItemType: details.GroupsChannelMessage,
Modified: initial,
LastReply: details.ChannelMessageInfo{},
Message: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: initial,
Creator: "app",
ReplyCount: 0,
Preview: content,
Size: int64(len(content)),
Subject: "subject",
},
}
return msg, i
@ -131,6 +206,7 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
msg.SetSubject(ptr.To("subject"))
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("device"))
@ -141,14 +217,54 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetFrom(from)
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Created: initial,
Modified: initial,
LastReplyAt: time.Time{},
ReplyCount: 0,
MessageCreator: "device",
Size: int64(len(content)),
MessagePreview: content,
ItemType: details.GroupsChannelMessage,
Modified: initial,
LastReply: details.ChannelMessageInfo{},
Message: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: initial,
Creator: "device",
ReplyCount: 0,
Preview: content,
Size: int64(len(content)),
Subject: "subject",
},
}
return msg, i
},
},
{
name: "No Replies - with attachments",
msgAndInfo: func() (models.ChatMessageable, *details.GroupsInfo) {
msg := models.NewChatMessage()
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
msg.SetSubject(ptr.To("subject"))
msg.SetAttachments(attachments)
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("user"))
from := models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
msg.SetFrom(from)
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Modified: initial,
LastReply: details.ChannelMessageInfo{},
Message: details.ChannelMessageInfo{
AttachmentNames: expectAttachNames,
CreatedAt: initial,
Creator: "user",
ReplyCount: 0,
Preview: content,
Size: int64(len(content)),
Subject: "subject",
},
}
return msg, i
@ -161,6 +277,7 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
msg.SetSubject(ptr.To("subject"))
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("user"))
@ -170,21 +287,42 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetFrom(from)
// reply
iden = models.NewIdentity()
iden.SetDisplayName(ptr.To("replyuser"))
from = models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
reply := models.NewChatMessage()
reply.SetCreatedDateTime(&curr)
reply.SetLastModifiedDateTime(&curr)
reply.SetFrom(from)
reply.SetBody(replyBody)
msg.SetReplies([]models.ChatMessageable{reply})
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Created: initial,
Modified: curr,
LastReplyAt: curr,
ReplyCount: 1,
MessageCreator: "user",
Size: int64(len(content)),
MessagePreview: content,
ItemType: details.GroupsChannelMessage,
Modified: curr,
LastReply: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: curr,
Creator: "replyuser",
ReplyCount: 0,
Preview: replyContent,
Size: int64(len(replyContent)),
},
Message: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: initial,
Creator: "user",
ReplyCount: 1,
Preview: content,
Size: int64(len(content)),
Subject: "subject",
},
}
return msg, i
@ -197,6 +335,7 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
msg.SetSubject(ptr.To("subject"))
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("user"))
@ -206,25 +345,197 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
msg.SetFrom(from)
// replies
iden = models.NewIdentity()
iden.SetDisplayName(ptr.To("reply1user"))
from = models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
reply1 := models.NewChatMessage()
reply1.SetCreatedDateTime(&mid)
reply1.SetLastModifiedDateTime(&mid)
reply1.SetFrom(from)
reply1.SetBody(replyBody)
iden = models.NewIdentity()
iden.SetDisplayName(ptr.To("reply2user"))
from = models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
reply2 := models.NewChatMessage()
reply2.SetCreatedDateTime(&curr)
reply2.SetLastModifiedDateTime(&curr)
reply2.SetFrom(from)
reply2.SetBody(replyBody)
msg.SetReplies([]models.ChatMessageable{reply1, reply2})
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Created: initial,
Modified: curr,
LastReplyAt: curr,
ReplyCount: 2,
MessageCreator: "user",
Size: int64(len(content)),
MessagePreview: content,
ItemType: details.GroupsChannelMessage,
Modified: curr,
LastReply: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: curr,
Creator: "reply2user",
ReplyCount: 0,
Preview: replyContent,
Size: int64(len(replyContent)),
},
Message: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: initial,
Creator: "user",
ReplyCount: 2,
Preview: content,
Size: int64(len(content)),
Subject: "subject",
},
}
return msg, i
},
},
{
name: "Many Replies - not last has attachments",
msgAndInfo: func() (models.ChatMessageable, *details.GroupsInfo) {
msg := models.NewChatMessage()
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
msg.SetSubject(ptr.To("subject"))
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("user"))
from := models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
msg.SetFrom(from)
// replies
iden = models.NewIdentity()
iden.SetDisplayName(ptr.To("reply1user"))
from = models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
reply1 := models.NewChatMessage()
reply1.SetCreatedDateTime(&mid)
reply1.SetLastModifiedDateTime(&mid)
reply1.SetFrom(from)
reply1.SetBody(replyBody)
reply1.SetAttachments(replyAttachments)
iden = models.NewIdentity()
iden.SetDisplayName(ptr.To("reply2user"))
from = models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
reply2 := models.NewChatMessage()
reply2.SetCreatedDateTime(&curr)
reply2.SetLastModifiedDateTime(&curr)
reply2.SetFrom(from)
reply2.SetBody(replyBody)
msg.SetReplies([]models.ChatMessageable{reply1, reply2})
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Modified: curr,
LastReply: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: curr,
Creator: "reply2user",
ReplyCount: 0,
Preview: replyContent,
Size: int64(len(replyContent)),
},
Message: details.ChannelMessageInfo{
AttachmentNames: []string{},
CreatedAt: initial,
Creator: "user",
ReplyCount: 2,
Preview: content,
Size: int64(len(content)),
Subject: "subject",
},
}
return msg, i
},
},
{
name: "Many Replies - last has attachments",
msgAndInfo: func() (models.ChatMessageable, *details.GroupsInfo) {
msg := models.NewChatMessage()
msg.SetCreatedDateTime(&initial)
msg.SetLastModifiedDateTime(&initial)
msg.SetBody(body)
msg.SetSubject(ptr.To("subject"))
msg.SetAttachments(attachments)
iden := models.NewIdentity()
iden.SetDisplayName(ptr.To("user"))
from := models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
msg.SetFrom(from)
// replies
iden = models.NewIdentity()
iden.SetDisplayName(ptr.To("reply1user"))
from = models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
reply1 := models.NewChatMessage()
reply1.SetCreatedDateTime(&mid)
reply1.SetLastModifiedDateTime(&mid)
reply1.SetFrom(from)
reply1.SetBody(replyBody)
iden = models.NewIdentity()
iden.SetDisplayName(ptr.To("reply2user"))
from = models.NewChatMessageFromIdentitySet()
from.SetUser(iden)
reply2 := models.NewChatMessage()
reply2.SetCreatedDateTime(&curr)
reply2.SetLastModifiedDateTime(&curr)
reply2.SetFrom(from)
reply2.SetBody(replyBody)
reply2.SetAttachments(replyAttachments)
msg.SetReplies([]models.ChatMessageable{reply1, reply2})
i := &details.GroupsInfo{
ItemType: details.GroupsChannelMessage,
Modified: curr,
LastReply: details.ChannelMessageInfo{
AttachmentNames: expectReplyAttachNames,
CreatedAt: curr,
Creator: "reply2user",
ReplyCount: 0,
Preview: replyContent,
Size: int64(len(replyContent)),
},
Message: details.ChannelMessageInfo{
AttachmentNames: expectAttachNames,
CreatedAt: initial,
Creator: "user",
ReplyCount: 2,
Preview: content,
Size: int64(len(content)),
Subject: "subject",
},
}
return msg, i
@ -233,8 +544,24 @@ func (suite *ChannelsAPIUnitSuite) TestChannelMessageInfo() {
}
for _, test := range tests {
suite.Run(test.name, func() {
t := suite.T()
chMsg, expected := test.msgAndInfo()
assert.Equal(suite.T(), expected, channelMessageInfo(chMsg))
result := channelMessageInfo(chMsg)
ma := result.Message.AttachmentNames
result.Message.AttachmentNames = nil
ema := expected.Message.AttachmentNames
expected.Message.AttachmentNames = nil
lra := result.LastReply.AttachmentNames
result.LastReply.AttachmentNames = nil
elra := expected.LastReply.AttachmentNames
expected.LastReply.AttachmentNames = nil
assert.Equal(t, expected, result)
assert.ElementsMatch(t, ema, ma)
assert.ElementsMatch(t, elra, lra)
})
}
}