GC: Restore: Retrieve CalendarID Feature (#687)
Feature added to be able to retrieve containerID for `exchange.Event` types.
This commit is contained in:
parent
7a8c6eaf78
commit
b5a5378113
28
src/internal/connector/exchange/calendar.go
Normal file
28
src/internal/connector/exchange/calendar.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// calendarDisplayable is a transformative struct that aligns
|
||||||
|
// models.Calendarable interface with the displayable interface.
|
||||||
|
type calendarDisplayable struct {
|
||||||
|
models.Calendarable
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDisplayName returns the *string of the calendar name
|
||||||
|
func (c calendarDisplayable) GetDisplayName() *string {
|
||||||
|
return c.GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateCalendarDisplayable helper function to create the
|
||||||
|
// calendarDisplayable during msgraph-sdk-go iterative process
|
||||||
|
// @param entry is the input supplied by pageIterator.Iterate()
|
||||||
|
func CreateCalendarDisplayable(entry any) *calendarDisplayable {
|
||||||
|
calendar, ok := entry.(models.Calendarable)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &calendarDisplayable{calendar}
|
||||||
|
}
|
||||||
@ -86,6 +86,41 @@ func (suite *ExchangeServiceSuite) TestCreateService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *ExchangeServiceSuite) TestOptionsForCalendars() {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
params []string
|
||||||
|
checkError assert.ErrorAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Empty Literal",
|
||||||
|
params: []string{},
|
||||||
|
checkError: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid Parameter",
|
||||||
|
params: []string{"status"},
|
||||||
|
checkError: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid Parameters",
|
||||||
|
params: []string{"status", "height", "month"},
|
||||||
|
checkError: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Valid Parameters",
|
||||||
|
params: []string{"changeKey", "events", "owner"},
|
||||||
|
checkError: assert.NoError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
_, err := optionsForCalendars(test.params)
|
||||||
|
test.checkError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestOptionsForMessages checks to ensure approved query
|
// TestOptionsForMessages checks to ensure approved query
|
||||||
// options are added to the type specific RequestBuildConfiguration. Expected
|
// options are added to the type specific RequestBuildConfiguration. Expected
|
||||||
// will be +1 on all select parameters
|
// will be +1 on all select parameters
|
||||||
@ -255,6 +290,10 @@ func (suite *ExchangeServiceSuite) TestGraphQueryFunctions() {
|
|||||||
name: "GraphQuery: Get All Events for User",
|
name: "GraphQuery: Get All Events for User",
|
||||||
function: GetAllEventsForUser,
|
function: GetAllEventsForUser,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "GraphQuery: Get All Calendars for User",
|
||||||
|
function: GetAllCalendarNamesForUser,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
@ -311,49 +350,61 @@ func (suite *ExchangeServiceSuite) TestParseCalendarIDFromEvent() {
|
|||||||
|
|
||||||
// TestGetMailFolderID verifies the ability to retrieve folder ID of folders
|
// TestGetMailFolderID verifies the ability to retrieve folder ID of folders
|
||||||
// at the top level of the file tree
|
// at the top level of the file tree
|
||||||
func (suite *ExchangeServiceSuite) TestGetFolderID() {
|
func (suite *ExchangeServiceSuite) TestGetContainerID() {
|
||||||
userID := tester.M365UserID(suite.T())
|
userID := tester.M365UserID(suite.T())
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
folderName string
|
containerName string
|
||||||
// category references the current optionId :: TODO --> use selector fields
|
// category references the current optionId :: TODO --> use selector fields
|
||||||
category optionIdentifier
|
category optionIdentifier
|
||||||
checkError assert.ErrorAssertionFunc
|
checkError assert.ErrorAssertionFunc
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Mail Valid",
|
name: "Mail Valid",
|
||||||
folderName: "Inbox",
|
containerName: "Inbox",
|
||||||
category: messages,
|
category: messages,
|
||||||
checkError: assert.NoError,
|
checkError: assert.NoError,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Mail Invalid",
|
name: "Mail Invalid",
|
||||||
folderName: "FolderThatIsNotHere",
|
containerName: "FolderThatIsNotHere",
|
||||||
category: messages,
|
category: messages,
|
||||||
checkError: assert.Error,
|
checkError: assert.Error,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Contact Invalid",
|
name: "Contact Invalid",
|
||||||
folderName: "FolderThatIsNotHereContacts",
|
containerName: "FolderThatIsNotHereContacts",
|
||||||
category: contacts,
|
category: contacts,
|
||||||
checkError: assert.Error,
|
checkError: assert.Error,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Contact Valid",
|
name: "Contact Valid",
|
||||||
folderName: "TrialFolder",
|
containerName: "TrialFolder",
|
||||||
category: contacts,
|
category: contacts,
|
||||||
checkError: assert.NoError,
|
checkError: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Event Invalid",
|
||||||
|
containerName: "NotAValid?@V'vCalendar",
|
||||||
|
category: events,
|
||||||
|
checkError: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Event Valid",
|
||||||
|
containerName: "Calendar",
|
||||||
|
category: events,
|
||||||
|
checkError: assert.NoError,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
_, err := GetFolderID(
|
_, err := GetContainerID(
|
||||||
suite.es,
|
suite.es,
|
||||||
test.folderName,
|
test.containerName,
|
||||||
userID,
|
userID,
|
||||||
test.category)
|
test.category)
|
||||||
test.checkError(t, err, "Unable to find folder: "+test.folderName)
|
test.checkError(t, err, "error with container: "+test.containerName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,15 +10,16 @@ func _() {
|
|||||||
var x [1]struct{}
|
var x [1]struct{}
|
||||||
_ = x[unknown-0]
|
_ = x[unknown-0]
|
||||||
_ = x[folders-1]
|
_ = x[folders-1]
|
||||||
_ = x[events-2]
|
_ = x[calendars-2]
|
||||||
_ = x[messages-3]
|
_ = x[events-3]
|
||||||
_ = x[users-4]
|
_ = x[messages-4]
|
||||||
_ = x[contacts-5]
|
_ = x[users-5]
|
||||||
|
_ = x[contacts-6]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _optionIdentifier_name = "unknownfolderseventsmessagesuserscontacts"
|
const _optionIdentifier_name = "unknownfolderscalendarseventsmessagesuserscontacts"
|
||||||
|
|
||||||
var _optionIdentifier_index = [...]uint8{0, 7, 14, 20, 28, 33, 41}
|
var _optionIdentifier_index = [...]uint8{0, 7, 14, 23, 29, 37, 42, 50}
|
||||||
|
|
||||||
func (i optionIdentifier) String() string {
|
func (i optionIdentifier) String() string {
|
||||||
if i < 0 || i >= optionIdentifier(len(_optionIdentifier_index)-1) {
|
if i < 0 || i >= optionIdentifier(len(_optionIdentifier_index)-1) {
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package exchange
|
package exchange
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
msuser "github.com/microsoftgraph/msgraph-sdk-go/users"
|
msuser "github.com/microsoftgraph/msgraph-sdk-go/users"
|
||||||
|
mscalendars "github.com/microsoftgraph/msgraph-sdk-go/users/item/calendars"
|
||||||
mscontactfolder "github.com/microsoftgraph/msgraph-sdk-go/users/item/contactfolders"
|
mscontactfolder "github.com/microsoftgraph/msgraph-sdk-go/users/item/contactfolders"
|
||||||
mscontacts "github.com/microsoftgraph/msgraph-sdk-go/users/item/contacts"
|
mscontacts "github.com/microsoftgraph/msgraph-sdk-go/users/item/contacts"
|
||||||
msevents "github.com/microsoftgraph/msgraph-sdk-go/users/item/events"
|
msevents "github.com/microsoftgraph/msgraph-sdk-go/users/item/events"
|
||||||
@ -17,6 +20,15 @@ import (
|
|||||||
// selectors for M365 objects
|
// selectors for M365 objects
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
var (
|
var (
|
||||||
|
fieldsForCalendars = map[string]int{
|
||||||
|
"changeKey": 1,
|
||||||
|
"events": 2,
|
||||||
|
"id": 3,
|
||||||
|
"isDefaultCalendar": 4,
|
||||||
|
"name": 5,
|
||||||
|
"owner": 6,
|
||||||
|
}
|
||||||
|
|
||||||
fieldsForEvents = map[string]int{
|
fieldsForEvents = map[string]int{
|
||||||
"calendar": 1,
|
"calendar": 1,
|
||||||
"end": 2,
|
"end": 2,
|
||||||
@ -79,6 +91,7 @@ type optionIdentifier int
|
|||||||
const (
|
const (
|
||||||
unknown optionIdentifier = iota
|
unknown optionIdentifier = iota
|
||||||
folders
|
folders
|
||||||
|
calendars
|
||||||
events
|
events
|
||||||
messages
|
messages
|
||||||
users
|
users
|
||||||
@ -104,9 +117,12 @@ func categoryToOptionIdentifier(category string) optionIdentifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// exchange.Query Option Section
|
// exchange.Query Option Section
|
||||||
//------------------------------------------------
|
// These functions can be used to filter a response on M365
|
||||||
|
// Graph queries and reduce / filter the amount of data returned
|
||||||
|
// which reduces the overall latency of complex calls
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
// optionsForMessages - used to select allowable options for exchange.Mail types
|
// optionsForMessages - used to select allowable options for exchange.Mail types
|
||||||
// @param moreOps is []string of options(e.g. "parentFolderId, subject")
|
// @param moreOps is []string of options(e.g. "parentFolderId, subject")
|
||||||
@ -146,6 +162,30 @@ func OptionsForSingleMessage(moreOps []string) (*msitem.MessageItemRequestBuilde
|
|||||||
return options, nil
|
return options, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optionsForCalendars places allowed options for exchange.Calendar object
|
||||||
|
// @param moreOps should reflect elements from fieldsForCalendars
|
||||||
|
// @return is first call in Calendars().GetWithRequestConfigurationAndResponseHandler
|
||||||
|
func optionsForCalendars(moreOps []string) (
|
||||||
|
*mscalendars.CalendarsRequestBuilderGetRequestConfiguration,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
selecting, err := buildOptions(moreOps, calendars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
requestParams := &mscalendars.CalendarsRequestBuilderGetQueryParameters{
|
||||||
|
Select: selecting,
|
||||||
|
}
|
||||||
|
options := &mscalendars.CalendarsRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: requestParams,
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// optionsForContactFolders places allowed options for exchange.ContactFolder object
|
||||||
|
// @return is first call in ContactFolders().GetWithRequestConfigurationAndResponseHandler
|
||||||
func optionsForContactFolders(moreOps []string) (
|
func optionsForContactFolders(moreOps []string) (
|
||||||
*mscontactfolder.ContactFoldersRequestBuilderGetRequestConfiguration,
|
*mscontactfolder.ContactFoldersRequestBuilderGetRequestConfiguration,
|
||||||
error,
|
error,
|
||||||
@ -246,10 +286,12 @@ func buildOptions(options []string, optID optionIdentifier) ([]string, error) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
switch optID {
|
switch optID {
|
||||||
case events:
|
case calendars:
|
||||||
allowedOptions = fieldsForEvents
|
allowedOptions = fieldsForCalendars
|
||||||
case contacts:
|
case contacts:
|
||||||
allowedOptions = fieldsForContacts
|
allowedOptions = fieldsForContacts
|
||||||
|
case events:
|
||||||
|
allowedOptions = fieldsForEvents
|
||||||
case folders:
|
case folders:
|
||||||
allowedOptions = fieldsForFolders
|
allowedOptions = fieldsForFolders
|
||||||
case users:
|
case users:
|
||||||
@ -265,7 +307,7 @@ func buildOptions(options []string, optID optionIdentifier) ([]string, error) {
|
|||||||
for _, entry := range options {
|
for _, entry := range options {
|
||||||
_, ok := allowedOptions[entry]
|
_, ok := allowedOptions[entry]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("unsupported option")
|
return nil, fmt.Errorf("unsupported option: %v", entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
returnedOptions = append(returnedOptions, entry)
|
returnedOptions = append(returnedOptions, entry)
|
||||||
|
|||||||
@ -151,16 +151,17 @@ func GetAllMailFolders(gs graph.Service, user, nameContains string) ([]MailFolde
|
|||||||
return mfs, err
|
return mfs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFolderID query function to retrieve the M365 ID based on the folder's displayName.
|
// GetContainerID query function to retrieve a container's M365 ID.
|
||||||
// @param folderName the target folder's display name. Case sensitive
|
// @param containerName is the target's name, user-readable and case sensitive
|
||||||
// @param category switches query and iteration to support multiple exchange applications
|
// @param category switches query and iteration to support multiple exchange applications
|
||||||
// @returns a *string if the folder exists. If the folder does not exist returns nil, error-> folder not found
|
// @returns a *string if the folder exists. If the folder does not exist returns nil, error-> folder not found
|
||||||
func GetFolderID(service graph.Service, folderName, user string, category optionIdentifier) (*string, error) {
|
func GetContainerID(service graph.Service, containerName, user string, category optionIdentifier) (*string, error) {
|
||||||
var (
|
var (
|
||||||
errs error
|
errs error
|
||||||
folderID *string
|
targetID *string
|
||||||
query GraphQuery
|
query GraphQuery
|
||||||
transform absser.ParsableFactory
|
transform absser.ParsableFactory
|
||||||
|
isCalendar bool
|
||||||
)
|
)
|
||||||
|
|
||||||
switch category {
|
switch category {
|
||||||
@ -170,6 +171,10 @@ func GetFolderID(service graph.Service, folderName, user string, category option
|
|||||||
case contacts:
|
case contacts:
|
||||||
query = GetAllContactFolderNamesForUser
|
query = GetAllContactFolderNamesForUser
|
||||||
transform = models.CreateContactFolderFromDiscriminatorValue
|
transform = models.CreateContactFolderFromDiscriminatorValue
|
||||||
|
case events:
|
||||||
|
query = GetAllCalendarNamesForUser
|
||||||
|
transform = models.CreateCalendarCollectionResponseFromDiscriminatorValue
|
||||||
|
isCalendar = true
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported category %s for GetFolderID()", category)
|
return nil, fmt.Errorf("unsupported category %s for GetFolderID()", category)
|
||||||
}
|
}
|
||||||
@ -192,10 +197,11 @@ func GetFolderID(service graph.Service, folderName, user string, category option
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
callbackFunc := iterateFindFolderID(category,
|
callbackFunc := iterateFindFolderID(
|
||||||
&folderID,
|
&targetID,
|
||||||
folderName,
|
containerName,
|
||||||
service.Adapter().GetBaseUrl(),
|
service.Adapter().GetBaseUrl(),
|
||||||
|
isCalendar,
|
||||||
errs,
|
errs,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -203,11 +209,11 @@ func GetFolderID(service graph.Service, folderName, user string, category option
|
|||||||
return nil, support.WrapAndAppend(service.Adapter().GetBaseUrl(), err, errs)
|
return nil, support.WrapAndAppend(service.Adapter().GetBaseUrl(), err, errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if folderID == nil {
|
if targetID == nil {
|
||||||
return nil, ErrFolderNotFound
|
return nil, ErrFolderNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return folderID, errs
|
return targetID, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseCalendarIDFromEvent returns the M365 ID for a calendar
|
// parseCalendarIDFromEvent returns the M365 ID for a calendar
|
||||||
@ -298,7 +304,7 @@ func establishFolder(
|
|||||||
folderName, user string,
|
folderName, user string,
|
||||||
optID optionIdentifier,
|
optID optionIdentifier,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
folderID, err := GetFolderID(service, folderName, user, optID)
|
folderID, err := GetContainerID(service, folderName, user, optID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return *folderID, nil
|
return *folderID, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -305,44 +305,45 @@ func IterateFilterFolderDirectoriesForCollections(
|
|||||||
// the displayable interface. If folder exists, the function updates the
|
// the displayable interface. If folder exists, the function updates the
|
||||||
// folderID memory address that was passed in.
|
// folderID memory address that was passed in.
|
||||||
func iterateFindFolderID(
|
func iterateFindFolderID(
|
||||||
category optionIdentifier,
|
|
||||||
folderID **string,
|
folderID **string,
|
||||||
folderName, errorIdentifier string,
|
folderName, errorIdentifier string,
|
||||||
|
isCalendar bool,
|
||||||
errs error,
|
errs error,
|
||||||
) func(any) bool {
|
) func(any) bool {
|
||||||
return func(entry any) bool {
|
return func(entry any) bool {
|
||||||
switch category {
|
if isCalendar {
|
||||||
case messages, contacts:
|
entry = CreateCalendarDisplayable(entry)
|
||||||
folder, ok := entry.(displayable)
|
|
||||||
if !ok {
|
|
||||||
errs = support.WrapAndAppend(
|
|
||||||
errorIdentifier,
|
|
||||||
errors.New("struct does not implement displayable"),
|
|
||||||
errs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
if entry == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Display name not set on folder
|
}
|
||||||
if folder.GetDisplayName() == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
name := *folder.GetDisplayName()
|
folder, ok := entry.(displayable)
|
||||||
if folderName == name {
|
if !ok {
|
||||||
if folder.GetId() == nil {
|
errs = support.WrapAndAppend(
|
||||||
return true // invalid folder
|
errorIdentifier,
|
||||||
}
|
errors.New("struct does not implement displayable"),
|
||||||
|
errs,
|
||||||
*folderID = folder.GetId()
|
)
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
|
// Display name not set on folder
|
||||||
|
if folder.GetDisplayName() == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if folderName == *folder.GetDisplayName() {
|
||||||
|
if folder.GetId() == nil {
|
||||||
|
return true // invalid folder
|
||||||
|
}
|
||||||
|
|
||||||
|
*folderID = folder.GetId()
|
||||||
|
|
||||||
default:
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,6 +55,15 @@ func GetAllFolderNamesForUser(gs graph.Service, user string) (absser.Parsable, e
|
|||||||
return gs.Client().UsersById(user).MailFolders().GetWithRequestConfigurationAndResponseHandler(options, nil)
|
return gs.Client().UsersById(user).MailFolders().GetWithRequestConfigurationAndResponseHandler(options, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAllCalendarNamesForUser(gs graph.Service, user string) (absser.Parsable, error) {
|
||||||
|
options, err := optionsForCalendars([]string{"name"})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gs.Client().UsersById(user).Calendars().GetWithRequestConfigurationAndResponseHandler(options, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// GetAllContactFolderNamesForUser is a GraphQuery function for getting ContactFolderId
|
// GetAllContactFolderNamesForUser is a GraphQuery function for getting ContactFolderId
|
||||||
// and display names for contacts. All other information is omitted.
|
// and display names for contacts. All other information is omitted.
|
||||||
// Does not return the primary Contact Folder
|
// Does not return the primary Contact Folder
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user