add chats boilerplate to details

This commit is contained in:
ryanfkeepers 2024-01-18 17:58:08 -07:00
parent eefce75f1d
commit 07997b0987
5 changed files with 221 additions and 2 deletions

View File

@ -0,0 +1,120 @@
package details
import (
"fmt"
"strconv"
"time"
"github.com/alcionai/clues"
"github.com/alcionai/corso/src/pkg/dttm"
"github.com/alcionai/corso/src/pkg/path"
)
// NewChatsLocationIDer builds a LocationIDer for the chats.
func NewChatsLocationIDer(
category path.CategoryType,
escapedFolders ...string,
) (uniqueLoc, error) {
if err := path.ValidateServiceAndCategory(path.TeamsChatsService, category); err != nil {
return uniqueLoc{}, clues.Wrap(err, "making chats LocationIDer")
}
pb := path.Builder{}.Append(category.String()).Append(escapedFolders...)
return uniqueLoc{
pb: pb,
prefixElems: 1,
}, nil
}
// TeamsChatsInfo describes a chat within teams chats.
type TeamsChatsInfo struct {
ItemType ItemType `json:"itemType,omitempty"`
Modified time.Time `json:"modified,omitempty"`
ParentPath string `json:"parentPath,omitempty"`
Chat ChatInfo `json:"chat,omitempty"`
}
type ChatInfo struct {
CreatedAt time.Time `json:"createdAt,omitempty"`
HasExternalMembers bool `json:"hasExternalMemebers,omitempty"`
LastMessageAt time.Time `json:"lastMessageAt,omitempty"`
LastMessagePreview string `json:"preview,omitempty"`
Members []string `json:"members,omitempty"`
MessageCount int `json:"size,omitempty"`
Name string `json:"name,omitempty"`
}
// Headers returns the human-readable names of properties in a ChatsInfo
// for printing out to a terminal in a columnar display.
func (i TeamsChatsInfo) Headers() []string {
switch i.ItemType {
case TeamsChat:
return []string{"Name", "Last message", "Last message at", "Message count", "Created", "Members"}
}
return []string{}
}
// Values returns the values matching the Headers list for printing
// out to a terminal in a columnar display.
func (i TeamsChatsInfo) Values() []string {
switch i.ItemType {
case TeamsChat:
members := ""
icmLen := len(i.Chat.Members)
if icmLen > 0 {
members = i.Chat.Members[0]
}
if icmLen > 1 {
members = fmt.Sprintf("%s, and %d more", members, icmLen-1)
}
return []string{
i.Chat.Name,
i.Chat.LastMessagePreview,
dttm.FormatToTabularDisplay(i.Chat.LastMessageAt),
strconv.Itoa(i.Chat.MessageCount),
dttm.FormatToTabularDisplay(i.Chat.CreatedAt),
members,
}
}
return []string{}
}
func (i *TeamsChatsInfo) UpdateParentPath(newLocPath *path.Builder) {
i.ParentPath = newLocPath.String()
}
func (i *TeamsChatsInfo) uniqueLocation(baseLoc *path.Builder) (*uniqueLoc, error) {
var category path.CategoryType
switch i.ItemType {
case TeamsChat:
category = path.ChatsCategory
}
loc, err := NewChatsLocationIDer(category, baseLoc.Elements()...)
return &loc, err
}
func (i *TeamsChatsInfo) updateFolder(f *FolderInfo) error {
// Use a switch instead of a rather large if-statement. Just make sure it's an
// Exchange type. If it's not return an error.
switch i.ItemType {
case TeamsChat:
default:
return clues.New("unsupported non-Chats ItemType").
With("item_type", i.ItemType)
}
f.DataType = i.ItemType
return nil
}

View File

@ -0,0 +1,71 @@
package details_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/dttm"
)
type ChatsUnitSuite struct {
tester.Suite
}
func TestChatsUnitSuite(t *testing.T) {
suite.Run(t, &ChatsUnitSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *ChatsUnitSuite) TestChatsPrintable() {
now := time.Now()
then := now.Add(time.Minute)
table := []struct {
name string
info details.TeamsChatsInfo
expectHs []string
expectVs []string
}{
{
name: "channel message",
info: details.TeamsChatsInfo{
ItemType: details.TeamsChat,
ParentPath: "parentpath",
Chat: details.ChatInfo{
CreatedAt: now,
HasExternalMembers: true,
LastMessageAt: then,
LastMessagePreview: "last message preview",
Members: []string{"foo@bar.baz", "fnords@smarf.zoomba"},
MessageCount: 42,
Name: "chat name",
},
},
expectHs: []string{"Name", "Last message", "Last message at", "Message count", "Created", "Members"},
expectVs: []string{
"chat name",
"last message preview",
dttm.FormatToTabularDisplay(then),
"42",
dttm.FormatToTabularDisplay(now),
"foo@bar.baz, and 1 more",
},
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
hs := test.info.Headers()
vs := test.info.Values()
assert.Equal(t, len(hs), len(vs))
assert.Equal(t, test.expectHs, hs)
assert.Equal(t, test.expectVs, vs)
})
}
}

View File

@ -78,7 +78,7 @@ type ChannelMessageInfo struct {
Subject string `json:"subject,omitempty"` Subject string `json:"subject,omitempty"`
} }
// Headers returns the human-readable names of properties in a SharePointInfo // Headers returns the human-readable names of properties in a gropusInfo
// for printing out to a terminal in a columnar display. // for printing out to a terminal in a columnar display.
func (i GroupsInfo) Headers() []string { func (i GroupsInfo) Headers() []string {
switch i.ItemType { switch i.ItemType {

View File

@ -41,6 +41,9 @@ const (
// Groups/Teams(40x) // Groups/Teams(40x)
GroupsChannelMessage ItemType = 401 GroupsChannelMessage ItemType = 401
GroupsConversationPost ItemType = 402 GroupsConversationPost ItemType = 402
// Teams Chat
TeamsChat ItemType = 501
) )
func UpdateItem(item *ItemInfo, newLocPath *path.Builder) { func UpdateItem(item *ItemInfo, newLocPath *path.Builder) {
@ -73,6 +76,7 @@ type ItemInfo struct {
SharePoint *SharePointInfo `json:"sharePoint,omitempty"` SharePoint *SharePointInfo `json:"sharePoint,omitempty"`
OneDrive *OneDriveInfo `json:"oneDrive,omitempty"` OneDrive *OneDriveInfo `json:"oneDrive,omitempty"`
Groups *GroupsInfo `json:"groups,omitempty"` Groups *GroupsInfo `json:"groups,omitempty"`
TeamsChats *TeamsChatsInfo `json:"teamsChats,omitempty"`
// Optional item extension data // Optional item extension data
Extension *ExtensionData `json:"extension,omitempty"` Extension *ExtensionData `json:"extension,omitempty"`
} }
@ -99,6 +103,9 @@ func (i ItemInfo) infoType() ItemType {
case i.Groups != nil: case i.Groups != nil:
return i.Groups.ItemType return i.Groups.ItemType
case i.TeamsChats != nil:
return i.TeamsChats.ItemType
} }
return UnknownType return UnknownType
@ -120,6 +127,9 @@ func (i ItemInfo) size() int64 {
case i.Folder != nil: case i.Folder != nil:
return i.Folder.Size return i.Folder.Size
case i.TeamsChats != nil:
return int64(i.TeamsChats.Chat.MessageCount)
} }
return 0 return 0
@ -141,6 +151,9 @@ func (i ItemInfo) Modified() time.Time {
case i.Folder != nil: case i.Folder != nil:
return i.Folder.Modified return i.Folder.Modified
case i.TeamsChats != nil:
return i.TeamsChats.Modified
} }
return time.Time{} return time.Time{}
@ -160,6 +173,9 @@ func (i ItemInfo) uniqueLocation(baseLoc *path.Builder) (*uniqueLoc, error) {
case i.Groups != nil: case i.Groups != nil:
return i.Groups.uniqueLocation(baseLoc) return i.Groups.uniqueLocation(baseLoc)
case i.TeamsChats != nil:
return i.TeamsChats.uniqueLocation(baseLoc)
default: default:
return nil, clues.New("unsupported type") return nil, clues.New("unsupported type")
} }
@ -179,6 +195,9 @@ func (i ItemInfo) updateFolder(f *FolderInfo) error {
case i.Groups != nil: case i.Groups != nil:
return i.Groups.updateFolder(f) return i.Groups.updateFolder(f)
case i.TeamsChats != nil:
return i.TeamsChats.updateFolder(f)
default: default:
return clues.New("unsupported type") return clues.New("unsupported type")
} }

View File

@ -71,12 +71,21 @@ func (suite *ItemInfoUnitSuite) TestItemInfo_IsDriveItem() {
{ {
name: "exchange anything", name: "exchange anything",
ii: ItemInfo{ ii: ItemInfo{
Groups: &GroupsInfo{ Exchange: &ExchangeInfo{
ItemType: ExchangeMail, ItemType: ExchangeMail,
}, },
}, },
expect: assert.False, expect: assert.False,
}, },
{
name: "teams chat",
ii: ItemInfo{
TeamsChats: &TeamsChatsInfo{
ItemType: TeamsChat,
},
},
expect: assert.False,
},
} }
for _, test := range table { for _, test := range table {
suite.Run(test.name, func() { suite.Run(test.name, func() {