Sanitize recurrenceTimezone prior to restoring calendar event (#3064)
<!-- PR description--> * Do not specify recurrenceTimeZone if it's not set in the item being restored. "" is not a valid value --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🐛 Bugfix #### Issue(s) * COR-53 #### Test Plan <!-- How will this be tested prior to merging.--> - [x] 💚 E2E
This commit is contained in:
parent
89ac00e64e
commit
2300727b09
@ -115,7 +115,7 @@ func handleExchangeCalendarEventFactory(cmd *cobra.Command, args []string) error
|
|||||||
func(id, now, subject, body string) []byte {
|
func(id, now, subject, body string) []byte {
|
||||||
return mockconnector.GetMockEventWith(
|
return mockconnector.GetMockEventWith(
|
||||||
User, subject, body, body,
|
User, subject, body, body,
|
||||||
now, now, false)
|
now, now, mockconnector.NoRecurrence, mockconnector.NoAttendees, false)
|
||||||
},
|
},
|
||||||
control.Options{},
|
control.Options{},
|
||||||
errs)
|
errs)
|
||||||
|
|||||||
@ -100,12 +100,12 @@ func (suite *ExchangeRestoreSuite) TestRestoreEvent() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
t = suite.T()
|
t = suite.T()
|
||||||
userID = tester.M365UserID(t)
|
userID = tester.M365UserID(t)
|
||||||
name = "TestRestoreEvent: " + common.FormatSimpleDateTime(time.Now())
|
subject = "TestRestoreEvent: " + common.FormatSimpleDateTime(time.Now())
|
||||||
)
|
)
|
||||||
|
|
||||||
calendar, err := suite.ac.Events().CreateCalendar(ctx, userID, name)
|
calendar, err := suite.ac.Events().CreateCalendar(ctx, userID, subject)
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
calendarID := ptr.Val(calendar.GetId())
|
calendarID := ptr.Val(calendar.GetId())
|
||||||
@ -116,15 +116,39 @@ func (suite *ExchangeRestoreSuite) TestRestoreEvent() {
|
|||||||
assert.NoError(t, err, clues.ToCore(err))
|
assert.NoError(t, err, clues.ToCore(err))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
info, err := RestoreExchangeEvent(ctx,
|
tests := []struct {
|
||||||
mockconnector.GetMockEventWithAttendeesBytes(name),
|
name string
|
||||||
suite.gs,
|
bytes []byte
|
||||||
control.Copy,
|
}{
|
||||||
calendarID,
|
{
|
||||||
userID,
|
name: "Test Event With Attendees",
|
||||||
fault.New(true))
|
bytes: mockconnector.GetMockEventWithAttendeesBytes(subject),
|
||||||
assert.NoError(t, err, clues.ToCore(err))
|
},
|
||||||
assert.NotNil(t, info, "event item info")
|
{
|
||||||
|
name: "Test recurrenceTimeZone: Empty",
|
||||||
|
bytes: mockconnector.GetMockEventWithRecurrenceBytes(subject, `""`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext()
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
info, err := RestoreExchangeEvent(
|
||||||
|
ctx,
|
||||||
|
test.bytes,
|
||||||
|
suite.gs,
|
||||||
|
control.Copy,
|
||||||
|
calendarID,
|
||||||
|
userID,
|
||||||
|
fault.New(true))
|
||||||
|
assert.NoError(t, err, clues.ToCore(err))
|
||||||
|
assert.NotNil(t, info, "event item info")
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type containerDeleter interface {
|
type containerDeleter interface {
|
||||||
|
|||||||
@ -19,7 +19,9 @@ import (
|
|||||||
// 6. subject
|
// 6. subject
|
||||||
// 7. hasAttachments
|
// 7. hasAttachments
|
||||||
// 8. attachments
|
// 8. attachments
|
||||||
//
|
// 9. recurrence
|
||||||
|
// 10. attendees
|
||||||
|
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
eventTmpl = `{
|
eventTmpl = `{
|
||||||
@ -33,7 +35,6 @@ const (
|
|||||||
"createdDateTime":"2022-03-28T03:42:03Z",
|
"createdDateTime":"2022-03-28T03:42:03Z",
|
||||||
"lastModifiedDateTime":"2022-05-26T19:25:58Z",
|
"lastModifiedDateTime":"2022-05-26T19:25:58Z",
|
||||||
"allowNewTimeProposals":true,
|
"allowNewTimeProposals":true,
|
||||||
"attendees":[],
|
|
||||||
"body":{
|
"body":{
|
||||||
"content":"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body>` +
|
"content":"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body>` +
|
||||||
`<p>%s</p></body></html>",
|
`<p>%s</p></body></html>",
|
||||||
@ -92,7 +93,9 @@ const (
|
|||||||
"type":"singleInstance",
|
"type":"singleInstance",
|
||||||
"hasAttachments":%v,
|
"hasAttachments":%v,
|
||||||
%s
|
%s
|
||||||
"webLink":"https://outlook.office365.com/owa/?itemid=AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAADSEBNbUIB9RL6ePDeF3FIYAAAAAG76AAA%%3D&exvsurl=1&path=/calendar/item"
|
"webLink":"https://outlook.office365.com/owa/?itemid=AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAADSEBNbUIB9RL6ePDeF3FIYAAAAAG76AAA%%3D&exvsurl=1&path=/calendar/item",
|
||||||
|
"recurrence":%s,
|
||||||
|
"attendees":%s
|
||||||
}`
|
}`
|
||||||
|
|
||||||
defaultEventBody = "This meeting is to review the latest Tailspin Toys project proposal.<br>\\r\\nBut why not eat some sushi while we’re at it? :)"
|
defaultEventBody = "This meeting is to review the latest Tailspin Toys project proposal.<br>\\r\\nBut why not eat some sushi while we’re at it? :)"
|
||||||
@ -147,6 +150,48 @@ const (
|
|||||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
||||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
||||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"}],"
|
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"}],"
|
||||||
|
|
||||||
|
NoRecurrence = `null`
|
||||||
|
recurrenceTmpl = `{
|
||||||
|
"pattern": {
|
||||||
|
"type": "absoluteYearly",
|
||||||
|
"interval": 1,
|
||||||
|
"month": 1,
|
||||||
|
"dayOfMonth": 1,
|
||||||
|
"firstDayOfWeek": "sunday",
|
||||||
|
"index": "first"
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"type": "noEnd",
|
||||||
|
"startDate": "%s",
|
||||||
|
"endDate": "0001-01-01",
|
||||||
|
"numberOfOccurrences": 0,
|
||||||
|
"recurrenceTimeZone": %s
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
NoAttendees = `[]`
|
||||||
|
attendeesTmpl = `[{
|
||||||
|
"emailAddress": {
|
||||||
|
"address": "george.martinez@8qzvrj.onmicrosoft.com",
|
||||||
|
"name": "George Martinez"
|
||||||
|
},
|
||||||
|
"type": "required",
|
||||||
|
"status": {
|
||||||
|
"response": "none",
|
||||||
|
"time": "0001-01-01T00:00:00Z"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"emailAddress": {
|
||||||
|
"address": "LeeG@8qzvrj.onmicrosoft.com",
|
||||||
|
"name": "Lee Gu"
|
||||||
|
},
|
||||||
|
"type": "required",
|
||||||
|
"status": {
|
||||||
|
"response": "none",
|
||||||
|
"time": "0001-01-01T00:00:00Z"
|
||||||
|
}
|
||||||
|
}]`
|
||||||
)
|
)
|
||||||
|
|
||||||
// generatePhoneNumber creates a random phone number
|
// generatePhoneNumber creates a random phone number
|
||||||
@ -182,7 +227,7 @@ func GetMockEventWithSubjectBytes(subject string) []byte {
|
|||||||
return GetMockEventWith(
|
return GetMockEventWith(
|
||||||
defaultEventOrganizer, subject,
|
defaultEventOrganizer, subject,
|
||||||
defaultEventBody, defaultEventBodyPreview,
|
defaultEventBody, defaultEventBodyPreview,
|
||||||
atTime, endTime, false,
|
atTime, endTime, NoRecurrence, NoAttendees, false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,19 +239,49 @@ func GetMockEventWithAttachment(subject string) []byte {
|
|||||||
return GetMockEventWith(
|
return GetMockEventWith(
|
||||||
defaultEventOrganizer, subject,
|
defaultEventOrganizer, subject,
|
||||||
defaultEventBody, defaultEventBodyPreview,
|
defaultEventBody, defaultEventBodyPreview,
|
||||||
atTime, atTime, true,
|
atTime, atTime, NoRecurrence, NoAttendees, true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMockEventWithRecurrenceBytes(subject, recurrenceTimeZone string) []byte {
|
||||||
|
tomorrow := time.Now().UTC().AddDate(0, 0, 1)
|
||||||
|
at := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), tomorrow.Hour(), 0, 0, 0, time.UTC)
|
||||||
|
atTime := common.FormatTime(at)
|
||||||
|
timeSlice := strings.Split(atTime, "T")
|
||||||
|
|
||||||
|
recurrence := string(fmt.Sprintf(
|
||||||
|
recurrenceTmpl,
|
||||||
|
timeSlice[0],
|
||||||
|
recurrenceTimeZone,
|
||||||
|
))
|
||||||
|
|
||||||
|
return GetMockEventWith(
|
||||||
|
defaultEventOrganizer, subject,
|
||||||
|
defaultEventBody, defaultEventBodyPreview,
|
||||||
|
atTime, atTime, recurrence, attendeesTmpl, true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMockEventWithAttendeesBytes(subject string) []byte {
|
||||||
|
tomorrow := time.Now().UTC().AddDate(0, 0, 1)
|
||||||
|
at := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), tomorrow.Hour(), 0, 0, 0, time.UTC)
|
||||||
|
atTime := common.FormatTime(at)
|
||||||
|
|
||||||
|
return GetMockEventWith(
|
||||||
|
defaultEventOrganizer, subject,
|
||||||
|
defaultEventBody, defaultEventBodyPreview,
|
||||||
|
atTime, atTime, NoRecurrence, attendeesTmpl, true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMockEventWith returns bytes for an Eventable item.
|
// GetMockEventWith returns bytes for an Eventable item.
|
||||||
// The event has no attendees.
|
|
||||||
// start and end times should be in the format 2006-01-02T15:04:05.0000000Z.
|
// start and end times should be in the format 2006-01-02T15:04:05.0000000Z.
|
||||||
// The timezone (Z) will be automatically stripped. A non-utc timezone may
|
// The timezone (Z) will be automatically stripped. A non-utc timezone may
|
||||||
// produce unexpected results.
|
// produce unexpected results.
|
||||||
// Body must contain a well-formatted string, consumable in a json payload. IE: no unescaped newlines.
|
// Body must contain a well-formatted string, consumable in a json payload. IE: no unescaped newlines.
|
||||||
func GetMockEventWith(
|
func GetMockEventWith(
|
||||||
organizer, subject, body, bodyPreview,
|
organizer, subject, body, bodyPreview,
|
||||||
startDateTime, endDateTime string,
|
startDateTime, endDateTime, recurrence, attendees string,
|
||||||
hasAttachments bool,
|
hasAttachments bool,
|
||||||
) []byte {
|
) []byte {
|
||||||
var attachments string
|
var attachments string
|
||||||
@ -235,34 +310,7 @@ func GetMockEventWith(
|
|||||||
subject,
|
subject,
|
||||||
hasAttachments,
|
hasAttachments,
|
||||||
attachments,
|
attachments,
|
||||||
|
recurrence,
|
||||||
|
attendees,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMockEventWithAttendeesBytes(subject string) []byte {
|
|
||||||
newTime := time.Now().AddDate(0, 0, 1)
|
|
||||||
conversion := common.FormatTime(newTime)
|
|
||||||
timeSlice := strings.Split(conversion, "T")
|
|
||||||
|
|
||||||
//nolint:lll
|
|
||||||
event := "{\"id\":\"AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAADSEBNbUIB9RL6ePDeF3FIYAABU_FdvAAA=\",\"@odata.etag\":\"W/\\\"0hATW1CAfUS+njw3hdxSGAAAVK7j9A==\\\"\"," +
|
|
||||||
"\"calendar@odata.associationLink\":\"https://graph.microsoft.com/v1.0/users('a4a472f8-ccb0-43ec-bf52-3697a91b926c')/calendars('AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwAuAAAAAADCNgjhM9QmQYWNcI7hCpPrAQDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAAA=')/$ref\"," +
|
|
||||||
"\"calendar@odata.navigationLink\":\"https://graph.microsoft.com/v1.0/users('a4a472f8-ccb0-43ec-bf52-3697a91b926c')/calendars('AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwAuAAAAAADCNgjhM9QmQYWNcI7hCpPrAQDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAAA=')\"," +
|
|
||||||
"\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#users('a4a472f8-ccb0-43ec-bf52-3697a91b926c')/events/$entity\",\"categories\":[],\"changeKey\":\"0hATW1CAfUS+njw3hdxSGAAAVK7j9A==\",\"createdDateTime\":\"2022-08-06T12:47:56Z\",\"lastModifiedDateTime\":\"2022-08-06T12:49:59Z\",\"allowNewTimeProposals\":true," +
|
|
||||||
"\"attendees\":[{\"emailAddress\":{\"address\":\"george.martinez@8qzvrj.onmicrosoft.com\",\"name\":\"George Martinez\"},\"type\":\"required\",\"status\":{\"response\":\"none\",\"time\":\"0001-01-01T00:00:00Z\"}},{\"emailAddress\":{\"address\":\"LeeG@8qzvrj.onmicrosoft.com\",\"name\":\"Lee Gu\"},\"type\":\"required\",\"status\":{\"response\":\"none\",\"time\":\"0001-01-01T00:00:00Z\"}}]," +
|
|
||||||
"\"body\":{\"content\":\"<html>\\n<head>\\n<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=utf-8\\\">\\n</head>\\n<body>\\n<div class=\\\"elementToProof\\\" style=\\\"font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0); background-color:rgb(255,255,255)\\\">\\nDiscuss matters concerning stock options and early release of quarterly earnings.</div>\\n<br> " +
|
|
||||||
"\\n<div style=\\\"width:100%; height:20px\\\"><span style=\\\"white-space:nowrap; color:#5F5F5F; opacity:.36\\\">________________________________________________________________________________</span>\\n</div>\\n<div class=\\\"me-email-text\\\" lang=\\\"en-GB\\\" style=\\\"color:#252424; font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif\\\"> " +
|
|
||||||
"\\n<div style=\\\"margin-top:24px; margin-bottom:20px\\\"><span style=\\\"font-size:24px; color:#252424\\\">Microsoft Teams meeting</span>\\n</div>\\n<div style=\\\"margin-bottom:20px\\\">\\n<div style=\\\"margin-top:0px; margin-bottom:0px; font-weight:bold\\\"><span style=\\\"font-size:14px; color:#252424\\\">Join on your computer or mobile app</span>" +
|
|
||||||
"\\n</div>\\n<a href=\\\"https://teams.microsoft.com/l/meetup-join/19%3ameeting_YWNhMzAxZjItMzE2My00ZGQzLTkzMDUtNjQ3NTY0NjNjMTZi%40thread.v2/0?context=%7b%22Tid%22%3a%224d603060-18d6-4764-b9be-4cb794d32b69%22%2c%22Oid%22%3a%22a4a472f8-ccb0-43ec-bf52-3697a91b926c%22%7d\\\" class=\\\"me-email-headline\\\" style=\\\"font-size:14px; font-family:'Segoe UI Semibold','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif; text-decoration:underline; color:#6264a7\\\">Click\\n here to join the meeting</a> </div>" +
|
|
||||||
"\\n<div style=\\\"margin-bottom:20px; margin-top:20px\\\">\\n<div style=\\\"margin-bottom:4px\\\"><span style=\\\"font-size:14px; color:#252424\\\">Meeting ID:\\n<span style=\\\"font-size:16px; color:#252424\\\">292 784 521 247</span> </span><br>\\n<span style=\\\"font-size:14px; color:#252424\\\">Passcode: </span><span style=\\\"font-size:16px; color:#252424\\\">SzBkfK\\n</span>" +
|
|
||||||
"\\n<div style=\\\"font-size:14px\\\"><a href=\\\"https://www.microsoft.com/en-us/microsoft-teams/download-app\\\" class=\\\"me-email-link\\\" style=\\\"font-size:14px; text-decoration:underline; color:#6264a7; font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif\\\">Download\\n Teams</a> | <a href=\\\"https://www.microsoft.com/microsoft-teams/join-a-meeting\\\" class=\\\"me-email-link\\\" style=\\\"font-size:14px; text-decoration:underline; color:#6264a7; font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif\\\">" +
|
|
||||||
"\\nJoin on the web</a></div>\\n</div>\\n</div>\\n<div style=\\\"margin-bottom:24px; margin-top:20px\\\"><a href=\\\"https://aka.ms/JoinTeamsMeeting\\\" class=\\\"me-email-link\\\" style=\\\"font-size:14px; text-decoration:underline; color:#6264a7; font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif\\\">Learn more</a>" +
|
|
||||||
"\\n | <a href=\\\"https://teams.microsoft.com/meetingOptions/?organizerId=a4a472f8-ccb0-43ec-bf52-3697a91b926c&tenantId=4d603060-18d6-4764-b9be-4cb794d32b69&threadId=19_meeting_YWNhMzAxZjItMzE2My00ZGQzLTkzMDUtNjQ3NTY0NjNjMTZi@thread.v2&messageId=0&language=en-GB\\\" class=\\\"me-email-link\\\" style=\\\"font-size:14px; text-decoration:underline; color:#6264a7; font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif\\\">" +
|
|
||||||
"\\nMeeting options</a> </div>\\n</div>\\n<div style=\\\"font-size:14px; margin-bottom:4px; font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif\\\">\\n</div>\\n<div style=\\\"font-size:12px\\\"></div>\\n<div></div>\\n<div style=\\\"width:100%; height:20px\\\"><span style=\\\"white-space:nowrap; color:#5F5F5F; opacity:.36\\\">________________________________________________________________________________</span>" +
|
|
||||||
"\\n</div>\\n</body>\\n</html>\\n\",\"contentType\":\"html\"},\"bodyPreview\":\"Discuss matters concerning stock options and early release of quarterly earnings.\\n\\n\", " +
|
|
||||||
"\"end\":{\"dateTime\":\"" + timeSlice[0] + "T16:00:00.0000000\",\"timeZone\":\"UTC\"},\"hasAttachments\":false,\"hideAttendees\":false,\"iCalUId\":\"040000008200E00074C5B7101A82E0080000000010A45EC092A9D801000000000000000010000000999C7C6281C2B24A91D5502392B8EF38\",\"importance\":\"normal\",\"isAllDay\":false,\"isCancelled\":false,\"isDraft\":false,\"isOnlineMeeting\":true,\"isOrganizer\":true,\"isReminderOn\":true," +
|
|
||||||
"\"location\":{\"address\":{},\"coordinates\":{},\"displayName\":\"\",\"locationType\":\"default\",\"uniqueIdType\":\"unknown\"},\"locations\":[],\"onlineMeeting\":{\"joinUrl\":\"https://teams.microsoft.com/l/meetup-join/19%3ameeting_YWNhMzAxZjItMzE2My00ZGQzLTkzMDUtNjQ3NTY0NjNjMTZi%40thread.v2/0?context=%7b%22Tid%22%3a%224d603060-18d6-4764-b9be-4cb794d32b69%22%2c%22Oid%22%3a%22a4a472f8-ccb0-43ec-bf52-3697a91b926c%22%7d\"},\"onlineMeetingProvider\":\"teamsForBusiness\"," +
|
|
||||||
"\"organizer\":{\"emailAddress\":{\"address\":\"LidiaH@8qzvrj.onmicrosoft.com\",\"name\":\"Lidia Holloway\"}},\"originalEndTimeZone\":\"Eastern Standard Time\",\"originalStartTimeZone\":\"Eastern Standard Time\",\"reminderMinutesBeforeStart\":15,\"responseRequested\":true,\"responseStatus\":{\"response\":\"organizer\",\"time\":\"0001-01-01T00:00:00Z\"},\"sensitivity\":\"normal\",\"showAs\":\"busy\"," +
|
|
||||||
"\"start\":{\"dateTime\":\"" + timeSlice[0] + "T15:30:00.0000000\",\"timeZone\":\"UTC\"},\"subject\":\"Board " + subject + " Meeting\",\"transactionId\":\"28b36295-6cd3-952f-d8f5-deb313444a51\",\"type\":\"singleInstance\",\"webLink\":\"https://outlook.office365.com/owa/?itemid=AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAADSEBNbUIB9RL6ePDeF3FIYAABU%2BFdvAAA%3D&exvsurl=1&path=/calendar/item\"}"
|
|
||||||
|
|
||||||
return []byte(event)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -88,6 +88,14 @@ func ToEventSimplified(orig models.Eventable) models.Eventable {
|
|||||||
orig.SetICalUId(nil)
|
orig.SetICalUId(nil)
|
||||||
orig.SetId(nil)
|
orig.SetId(nil)
|
||||||
|
|
||||||
|
// Sanitize recurrence timezone.
|
||||||
|
if orig.GetRecurrence() != nil {
|
||||||
|
recurrenceTimezone := ptr.Val(orig.GetRecurrence().GetRange().GetRecurrenceTimeZone())
|
||||||
|
if len(recurrenceTimezone) == 0 {
|
||||||
|
orig.GetRecurrence().GetRange().SetRecurrenceTimeZone(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return orig
|
return orig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ func (suite *SupportTestSuite) TestToMessage() {
|
|||||||
assert.NotEqual(t, message.GetId(), clone.GetId())
|
assert.NotEqual(t, message.GetId(), clone.GetId())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SupportTestSuite) TestToEventSimplified() {
|
func (suite *SupportTestSuite) TestToEventSimplified_attendees() {
|
||||||
t := suite.T()
|
t := suite.T()
|
||||||
bytes := mockconnector.GetMockEventWithAttendeesBytes("M365 Event Support Test")
|
bytes := mockconnector.GetMockEventWithAttendeesBytes("M365 Event Support Test")
|
||||||
event, err := CreateEventFromBytes(bytes)
|
event, err := CreateEventFromBytes(bytes)
|
||||||
@ -57,6 +57,80 @@ func (suite *SupportTestSuite) TestToEventSimplified() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *SupportTestSuite) TestToEventSimplified_recurrence() {
|
||||||
|
var (
|
||||||
|
t = suite.T()
|
||||||
|
subject = "M365 Event Support Test"
|
||||||
|
)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
event func() models.Eventable
|
||||||
|
validateOutput func(e models.Eventable) bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test recurrence: Unspecified",
|
||||||
|
event: func() models.Eventable {
|
||||||
|
bytes := mockconnector.GetMockEventWithSubjectBytes(subject)
|
||||||
|
e, err := CreateEventFromBytes(bytes)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
return e
|
||||||
|
},
|
||||||
|
|
||||||
|
validateOutput: func(e models.Eventable) bool {
|
||||||
|
return e.GetRecurrence() == nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test recurrenceTimeZone: Unspecified",
|
||||||
|
event: func() models.Eventable {
|
||||||
|
bytes := mockconnector.GetMockEventWithRecurrenceBytes(subject, `null`)
|
||||||
|
e, err := CreateEventFromBytes(bytes)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
return e
|
||||||
|
},
|
||||||
|
|
||||||
|
validateOutput: func(e models.Eventable) bool {
|
||||||
|
return e.GetRecurrence().GetRange().GetRecurrenceTimeZone() == nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test recurrenceTimeZone: Empty",
|
||||||
|
event: func() models.Eventable {
|
||||||
|
bytes := mockconnector.GetMockEventWithRecurrenceBytes(subject, `""`)
|
||||||
|
event, err := CreateEventFromBytes(bytes)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
return event
|
||||||
|
},
|
||||||
|
|
||||||
|
validateOutput: func(e models.Eventable) bool {
|
||||||
|
return e.GetRecurrence().GetRange().GetRecurrenceTimeZone() == nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test recurrenceTimeZone: Valid",
|
||||||
|
event: func() models.Eventable {
|
||||||
|
bytes := mockconnector.GetMockEventWithRecurrenceBytes(subject, `"Pacific Standard Time"`)
|
||||||
|
event, err := CreateEventFromBytes(bytes)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
return event
|
||||||
|
},
|
||||||
|
|
||||||
|
validateOutput: func(e models.Eventable) bool {
|
||||||
|
return ptr.Val(e.GetRecurrence().GetRange().GetRecurrenceTimeZone()) == "Pacific Standard Time"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
event := test.event()
|
||||||
|
newEvent := ToEventSimplified(event)
|
||||||
|
assert.True(t, test.validateOutput(newEvent), test.name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type mockContenter struct {
|
type mockContenter struct {
|
||||||
content *string
|
content *string
|
||||||
contentType *models.BodyType
|
contentType *models.BodyType
|
||||||
|
|||||||
@ -790,7 +790,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchangeIncrementals() {
|
|||||||
eventDBF := func(id, timeStamp, subject, body string) []byte {
|
eventDBF := func(id, timeStamp, subject, body string) []byte {
|
||||||
return mockconnector.GetMockEventWith(
|
return mockconnector.GetMockEventWith(
|
||||||
suite.user, subject, body, body,
|
suite.user, subject, body, body,
|
||||||
now, now, false)
|
now, now, mockconnector.NoRecurrence, mockconnector.NoAttendees, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test data set
|
// test data set
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user