restore/backup tests for events (#995)
## Description Test restoring a single calendar and multiple calendars of events Manually compare Location models because they have some fields that are marked as for internal use and appear to be overwritten/controlled by M365 ## Type of change <!--- Please check the type of change your PR introduces: ---> - [ ] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [x] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🐹 Trivial/Minor ## Issue(s) * #913 ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
526cc8fa9b
commit
88af7f9b7c
@ -50,7 +50,16 @@ func mustToDataLayerPath(
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func emptyOrEqual[T any](t *testing.T, expected *T, got *T, msg string) {
|
func emptyOrEqual[T any](expected *T, got *T) bool {
|
||||||
|
if expected == nil || got == nil {
|
||||||
|
// Creates either the zero value or gets the value pointed to.
|
||||||
|
return reflect.DeepEqual(reflect.ValueOf(expected).Elem(), reflect.ValueOf(got).Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.DeepEqual(*expected, *got)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEmptyOrEqual[T any](t *testing.T, expected *T, got *T, msg string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
if expected == nil || got == nil {
|
if expected == nil || got == nil {
|
||||||
@ -90,7 +99,7 @@ func checkMessage(
|
|||||||
) {
|
) {
|
||||||
assert.Equal(t, expected.GetBccRecipients(), got.GetBccRecipients(), "BccRecipients")
|
assert.Equal(t, expected.GetBccRecipients(), got.GetBccRecipients(), "BccRecipients")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetBody().GetContentType(), got.GetBody().GetContentType(), "Body.ContentType")
|
testEmptyOrEqual(t, expected.GetBody().GetContentType(), got.GetBody().GetContentType(), "Body.ContentType")
|
||||||
|
|
||||||
// Skip Body.Content as there may be display formatting that changes.
|
// Skip Body.Content as there may be display formatting that changes.
|
||||||
|
|
||||||
@ -114,44 +123,44 @@ func checkMessage(
|
|||||||
|
|
||||||
assert.Equal(t, expected.GetFrom(), got.GetFrom(), "From")
|
assert.Equal(t, expected.GetFrom(), got.GetFrom(), "From")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetHasAttachments(), got.GetHasAttachments(), "HasAttachments")
|
testEmptyOrEqual(t, expected.GetHasAttachments(), got.GetHasAttachments(), "HasAttachments")
|
||||||
|
|
||||||
// Skip Id as it's tied to this specific instance of the item.
|
// Skip Id as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetImportance(), got.GetImportance(), "Importance")
|
testEmptyOrEqual(t, expected.GetImportance(), got.GetImportance(), "Importance")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetInferenceClassification(), got.GetInferenceClassification(), "InferenceClassification")
|
testEmptyOrEqual(t, expected.GetInferenceClassification(), got.GetInferenceClassification(), "InferenceClassification")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetInternetMessageHeaders(), got.GetInternetMessageHeaders(), "InternetMessageHeaders")
|
assert.Equal(t, expected.GetInternetMessageHeaders(), got.GetInternetMessageHeaders(), "InternetMessageHeaders")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetInternetMessageId(), got.GetInternetMessageId(), "InternetMessageId")
|
testEmptyOrEqual(t, expected.GetInternetMessageId(), got.GetInternetMessageId(), "InternetMessageId")
|
||||||
|
|
||||||
emptyOrEqual(
|
testEmptyOrEqual(
|
||||||
t,
|
t,
|
||||||
expected.GetIsDeliveryReceiptRequested(),
|
expected.GetIsDeliveryReceiptRequested(),
|
||||||
got.GetIsDeliveryReceiptRequested(),
|
got.GetIsDeliveryReceiptRequested(),
|
||||||
"IsDeliverReceiptRequested",
|
"IsDeliverReceiptRequested",
|
||||||
)
|
)
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetIsDraft(), got.GetIsDraft(), "IsDraft")
|
testEmptyOrEqual(t, expected.GetIsDraft(), got.GetIsDraft(), "IsDraft")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetIsRead(), got.GetIsRead(), "IsRead")
|
testEmptyOrEqual(t, expected.GetIsRead(), got.GetIsRead(), "IsRead")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetIsReadReceiptRequested(), got.GetIsReadReceiptRequested(), "IsReadReceiptRequested")
|
testEmptyOrEqual(t, expected.GetIsReadReceiptRequested(), got.GetIsReadReceiptRequested(), "IsReadReceiptRequested")
|
||||||
|
|
||||||
// Skip LastModifiedDateTime as it's tied to this specific instance of the item.
|
// Skip LastModifiedDateTime as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
// Skip ParentFolderId as we restore to a different folder by default.
|
// Skip ParentFolderId as we restore to a different folder by default.
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetReceivedDateTime(), got.GetReceivedDateTime(), "ReceivedDateTime")
|
testEmptyOrEqual(t, expected.GetReceivedDateTime(), got.GetReceivedDateTime(), "ReceivedDateTime")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetReplyTo(), got.GetReplyTo(), "ReplyTo")
|
assert.Equal(t, expected.GetReplyTo(), got.GetReplyTo(), "ReplyTo")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetSender(), got.GetSender(), "Sender")
|
assert.Equal(t, expected.GetSender(), got.GetSender(), "Sender")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetSentDateTime(), got.GetSentDateTime(), "SentDateTime")
|
testEmptyOrEqual(t, expected.GetSentDateTime(), got.GetSentDateTime(), "SentDateTime")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetSubject(), got.GetSubject(), "Subject")
|
testEmptyOrEqual(t, expected.GetSubject(), got.GetSubject(), "Subject")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetToRecipients(), got.GetToRecipients(), "ToRecipients")
|
assert.Equal(t, expected.GetToRecipients(), got.GetToRecipients(), "ToRecipients")
|
||||||
|
|
||||||
@ -165,13 +174,13 @@ func checkContact(
|
|||||||
expected models.Contactable,
|
expected models.Contactable,
|
||||||
got models.Contactable,
|
got models.Contactable,
|
||||||
) {
|
) {
|
||||||
emptyOrEqual(t, expected.GetAssistantName(), got.GetAssistantName(), "AssistantName")
|
testEmptyOrEqual(t, expected.GetAssistantName(), got.GetAssistantName(), "AssistantName")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetBirthday(), got.GetBirthday(), "Birthday")
|
testEmptyOrEqual(t, expected.GetBirthday(), got.GetBirthday(), "Birthday")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetBusinessAddress(), got.GetBusinessAddress())
|
assert.Equal(t, expected.GetBusinessAddress(), got.GetBusinessAddress())
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetBusinessHomePage(), got.GetBusinessHomePage(), "BusinessHomePage")
|
testEmptyOrEqual(t, expected.GetBusinessHomePage(), got.GetBusinessHomePage(), "BusinessHomePage")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetBusinessPhones(), got.GetBusinessPhones())
|
assert.Equal(t, expected.GetBusinessPhones(), got.GetBusinessPhones())
|
||||||
|
|
||||||
@ -181,21 +190,21 @@ func checkContact(
|
|||||||
|
|
||||||
assert.Equal(t, expected.GetChildren(), got.GetChildren())
|
assert.Equal(t, expected.GetChildren(), got.GetChildren())
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetCompanyName(), got.GetCompanyName(), "CompanyName")
|
testEmptyOrEqual(t, expected.GetCompanyName(), got.GetCompanyName(), "CompanyName")
|
||||||
|
|
||||||
// Skip CreatedDateTime as it's tied to this specific instance of the item.
|
// Skip CreatedDateTime as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetDepartment(), got.GetDepartment(), "Department")
|
testEmptyOrEqual(t, expected.GetDepartment(), got.GetDepartment(), "Department")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetDisplayName(), got.GetDisplayName(), "DisplayName")
|
testEmptyOrEqual(t, expected.GetDisplayName(), got.GetDisplayName(), "DisplayName")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetEmailAddresses(), got.GetEmailAddresses())
|
assert.Equal(t, expected.GetEmailAddresses(), got.GetEmailAddresses())
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetFileAs(), got.GetFileAs(), "FileAs")
|
testEmptyOrEqual(t, expected.GetFileAs(), got.GetFileAs(), "FileAs")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetGeneration(), got.GetGeneration(), "Generation")
|
testEmptyOrEqual(t, expected.GetGeneration(), got.GetGeneration(), "Generation")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetGivenName(), got.GetGivenName(), "GivenName")
|
testEmptyOrEqual(t, expected.GetGivenName(), got.GetGivenName(), "GivenName")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetHomeAddress(), got.GetHomeAddress())
|
assert.Equal(t, expected.GetHomeAddress(), got.GetHomeAddress())
|
||||||
|
|
||||||
@ -205,43 +214,252 @@ func checkContact(
|
|||||||
|
|
||||||
assert.Equal(t, expected.GetImAddresses(), got.GetImAddresses())
|
assert.Equal(t, expected.GetImAddresses(), got.GetImAddresses())
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetInitials(), got.GetInitials(), "Initials")
|
testEmptyOrEqual(t, expected.GetInitials(), got.GetInitials(), "Initials")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetJobTitle(), got.GetJobTitle(), "JobTitle")
|
testEmptyOrEqual(t, expected.GetJobTitle(), got.GetJobTitle(), "JobTitle")
|
||||||
|
|
||||||
// Skip CreatedDateTime as it's tied to this specific instance of the item.
|
// Skip CreatedDateTime as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetManager(), got.GetManager(), "Manager")
|
testEmptyOrEqual(t, expected.GetManager(), got.GetManager(), "Manager")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetMiddleName(), got.GetMiddleName(), "MiddleName")
|
testEmptyOrEqual(t, expected.GetMiddleName(), got.GetMiddleName(), "MiddleName")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetMobilePhone(), got.GetMobilePhone(), "MobilePhone")
|
testEmptyOrEqual(t, expected.GetMobilePhone(), got.GetMobilePhone(), "MobilePhone")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetNickName(), got.GetNickName(), "NickName")
|
testEmptyOrEqual(t, expected.GetNickName(), got.GetNickName(), "NickName")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetOfficeLocation(), got.GetOfficeLocation(), "OfficeLocation")
|
testEmptyOrEqual(t, expected.GetOfficeLocation(), got.GetOfficeLocation(), "OfficeLocation")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetOtherAddress(), got.GetOtherAddress())
|
assert.Equal(t, expected.GetOtherAddress(), got.GetOtherAddress())
|
||||||
|
|
||||||
// Skip ParentFolderId as it's tied to this specific instance of the item.
|
// Skip ParentFolderId as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetPersonalNotes(), got.GetPersonalNotes(), "PersonalNotes")
|
testEmptyOrEqual(t, expected.GetPersonalNotes(), got.GetPersonalNotes(), "PersonalNotes")
|
||||||
|
|
||||||
assert.Equal(t, expected.GetPhoto(), got.GetPhoto())
|
assert.Equal(t, expected.GetPhoto(), got.GetPhoto())
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetProfession(), got.GetProfession(), "Profession")
|
testEmptyOrEqual(t, expected.GetProfession(), got.GetProfession(), "Profession")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetSpouseName(), got.GetSpouseName(), "SpouseName")
|
testEmptyOrEqual(t, expected.GetSpouseName(), got.GetSpouseName(), "SpouseName")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetSurname(), got.GetSurname(), "Surname")
|
testEmptyOrEqual(t, expected.GetSurname(), got.GetSurname(), "Surname")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetTitle(), got.GetTitle(), "Title")
|
testEmptyOrEqual(t, expected.GetTitle(), got.GetTitle(), "Title")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetYomiCompanyName(), got.GetYomiCompanyName(), "YomiCompanyName")
|
testEmptyOrEqual(t, expected.GetYomiCompanyName(), got.GetYomiCompanyName(), "YomiCompanyName")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetYomiGivenName(), got.GetYomiGivenName(), "YomiGivenName")
|
testEmptyOrEqual(t, expected.GetYomiGivenName(), got.GetYomiGivenName(), "YomiGivenName")
|
||||||
|
|
||||||
emptyOrEqual(t, expected.GetYomiSurname(), got.GetYomiSurname(), "YomiSurname")
|
testEmptyOrEqual(t, expected.GetYomiSurname(), got.GetYomiSurname(), "YomiSurname")
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkLocations(
|
||||||
|
t *testing.T,
|
||||||
|
expected []models.Locationable,
|
||||||
|
got []models.Locationable,
|
||||||
|
) {
|
||||||
|
pending := make([]*models.Locationable, len(expected))
|
||||||
|
for i := 0; i < len(expected); i++ {
|
||||||
|
pending[i] = &expected[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
unexpected := []models.Locationable{}
|
||||||
|
|
||||||
|
for i := 0; i < len(got); i++ {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for j, maybe := range pending {
|
||||||
|
if maybe == nil {
|
||||||
|
// Already matched with something in got.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item matched, break out of inner loop and move to next item in got.
|
||||||
|
if locationEqual(*maybe, got[i]) {
|
||||||
|
pending[j] = nil
|
||||||
|
found = true
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
unexpected = append(unexpected, got[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print differences.
|
||||||
|
missing := []models.Locationable{}
|
||||||
|
|
||||||
|
for _, p := range pending {
|
||||||
|
if p == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
missing = append(missing, *p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(unexpected) == 0 && len(missing) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Failf(
|
||||||
|
t,
|
||||||
|
"contain different elements",
|
||||||
|
"missing items: (%T)%v\nunexpected items: (%T)%v\n",
|
||||||
|
expected,
|
||||||
|
missing,
|
||||||
|
got,
|
||||||
|
unexpected,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func locationEqual(expected, got models.Locationable) bool {
|
||||||
|
if !reflect.DeepEqual(expected.GetAddress(), got.GetAddress()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expected.GetCoordinates(), got.GetCoordinates()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !emptyOrEqual(expected.GetDisplayName(), got.GetDisplayName()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !emptyOrEqual(expected.GetLocationEmailAddress(), got.GetLocationEmailAddress()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !emptyOrEqual(expected.GetLocationType(), got.GetLocationType()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip checking UniqueId as it's marked as for internal use only.
|
||||||
|
|
||||||
|
// Skip checking UniqueIdType as it's marked as for internal use only.
|
||||||
|
|
||||||
|
if !emptyOrEqual(expected.GetLocationUri(), got.GetLocationUri()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkEvent(
|
||||||
|
t *testing.T,
|
||||||
|
expected models.Eventable,
|
||||||
|
got models.Eventable,
|
||||||
|
) {
|
||||||
|
testEmptyOrEqual(t, expected.GetAllowNewTimeProposals(), got.GetAllowNewTimeProposals(), "AllowNewTimeProposals")
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetAttachments(), got.GetAttachments(), "Attachments")
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetAttendees(), got.GetAttendees(), "Attendees")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetBody().GetContentType(), got.GetBody().GetContentType(), "Body.ContentType")
|
||||||
|
|
||||||
|
// Skip checking Body.Content for now as M365 may have different formatting.
|
||||||
|
|
||||||
|
// Skip checking BodyPreview for now as M365 may have different formatting.
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetCalendar(), got.GetCalendar(), "Calendar")
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetCategories(), got.GetCategories(), "Categories")
|
||||||
|
|
||||||
|
// Skip ChangeKey as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
|
// Skip CreatedDateTime as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetEnd(), got.GetEnd(), "End")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetHasAttachments(), got.GetHasAttachments(), "HasAttachments")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetHideAttendees(), got.GetHideAttendees(), "HideAttendees")
|
||||||
|
|
||||||
|
// TODO(ashmrtn): Uncomment when we figure out how to connect to the original
|
||||||
|
// event.
|
||||||
|
// testEmptyOrEqual(t, expected.GetICalUId(), got.GetICalUId(), "ICalUId")
|
||||||
|
|
||||||
|
// Skip Id as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetImportance(), got.GetImportance(), "Importance")
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetInstances(), got.GetInstances(), "Instances")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetIsAllDay(), got.GetIsAllDay(), "IsAllDay")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetIsCancelled(), got.GetIsCancelled(), "IsCancelled")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetIsDraft(), got.GetIsDraft(), "IsDraft")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetIsOnlineMeeting(), got.GetIsOnlineMeeting(), "IsOnlineMeeting")
|
||||||
|
|
||||||
|
// TODO(ashmrtn): Uncomment when we figure out how to delegate event creation
|
||||||
|
// to another user.
|
||||||
|
// testEmptyOrEqual(t, expected.GetIsOrganizer(), got.GetIsOrganizer(), "IsOrganizer")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetIsReminderOn(), got.GetIsReminderOn(), "IsReminderOn")
|
||||||
|
|
||||||
|
// Skip LastModifiedDateTime as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
|
// Cheating a little here in the name of code-reuse. model.Location needs
|
||||||
|
// custom compare logic because it has fields marked as "internal use only"
|
||||||
|
// that seem to change.
|
||||||
|
checkLocations(
|
||||||
|
t,
|
||||||
|
[]models.Locationable{expected.GetLocation()},
|
||||||
|
[]models.Locationable{got.GetLocation()},
|
||||||
|
)
|
||||||
|
|
||||||
|
checkLocations(t, expected.GetLocations(), got.GetLocations())
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetOnlineMeeting(), got.GetOnlineMeeting(), "OnlineMeeting")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetOnlineMeetingProvider(), got.GetOnlineMeetingProvider(), "OnlineMeetingProvider")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetOnlineMeetingUrl(), got.GetOnlineMeetingUrl(), "OnlineMeetingUrl")
|
||||||
|
|
||||||
|
// TODO(ashmrtn): Uncomment when we figure out how to delegate event creation
|
||||||
|
// to another user.
|
||||||
|
// assert.Equal(t, expected.GetOrganizer(), got.GetOrganizer(), "Organizer")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetOriginalEndTimeZone(), got.GetOriginalEndTimeZone(), "OriginalEndTimeZone")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetOriginalStart(), got.GetOriginalStart(), "OriginalStart")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetOriginalStartTimeZone(), got.GetOriginalStartTimeZone(), "OriginalStartTimeZone")
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetRecurrence(), got.GetRecurrence(), "Recurrence")
|
||||||
|
|
||||||
|
testEmptyOrEqual(
|
||||||
|
t,
|
||||||
|
expected.GetReminderMinutesBeforeStart(),
|
||||||
|
got.GetReminderMinutesBeforeStart(),
|
||||||
|
"ReminderMinutesBeforeStart",
|
||||||
|
)
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetResponseRequested(), got.GetResponseRequested(), "ResponseRequested")
|
||||||
|
|
||||||
|
// TODO(ashmrtn): Uncomment when we figure out how to connect to the original
|
||||||
|
// event.
|
||||||
|
// assert.Equal(t, expected.GetResponseStatus(), got.GetResponseStatus(), "ResponseStatus")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetSensitivity(), got.GetSensitivity(), "Sensitivity")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetSeriesMasterId(), got.GetSeriesMasterId(), "SeriesMasterId")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetShowAs(), got.GetShowAs(), "ShowAs")
|
||||||
|
|
||||||
|
assert.Equal(t, expected.GetStart(), got.GetStart(), "Start")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetSubject(), got.GetSubject(), "Subject")
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetTransactionId(), got.GetTransactionId(), "TransactionId")
|
||||||
|
|
||||||
|
// Skip LastModifiedDateTime as it's tied to this specific instance of the item.
|
||||||
|
|
||||||
|
testEmptyOrEqual(t, expected.GetType(), got.GetType(), "Type")
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareExchangeEmail(
|
func compareExchangeEmail(
|
||||||
@ -296,6 +514,32 @@ func compareExchangeContact(
|
|||||||
checkContact(t, expectedContact, itemContact)
|
checkContact(t, expectedContact, itemContact)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compareExchangeEvent(
|
||||||
|
t *testing.T,
|
||||||
|
expected map[string][]byte,
|
||||||
|
item data.Stream,
|
||||||
|
) {
|
||||||
|
itemData, err := io.ReadAll(item.ToReader())
|
||||||
|
if !assert.NoError(t, err, "reading collection item: %s", item.UUID()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
itemEvent, err := support.CreateEventFromBytes(itemData)
|
||||||
|
if !assert.NoError(t, err, "deserializing backed up contact") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedBytes, ok := expected[*itemEvent.GetSubject()]
|
||||||
|
if !assert.True(t, ok, "unexpected item with subject %q", *itemEvent.GetSubject()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedEvent, err := support.CreateEventFromBytes(expectedBytes)
|
||||||
|
assert.NoError(t, err, "deserializing source contact")
|
||||||
|
|
||||||
|
checkEvent(t, expectedEvent, itemEvent)
|
||||||
|
}
|
||||||
|
|
||||||
func compareItem(
|
func compareItem(
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
expected map[string][]byte,
|
expected map[string][]byte,
|
||||||
@ -310,6 +554,8 @@ func compareItem(
|
|||||||
compareExchangeEmail(t, expected, item)
|
compareExchangeEmail(t, expected, item)
|
||||||
case path.ContactsCategory:
|
case path.ContactsCategory:
|
||||||
compareExchangeContact(t, expected, item)
|
compareExchangeContact(t, expected, item)
|
||||||
|
case path.EventsCategory:
|
||||||
|
compareExchangeEvent(t, expected, item)
|
||||||
default:
|
default:
|
||||||
assert.FailNowf(t, "unexpected Exchange category: %s", category.String())
|
assert.FailNowf(t, "unexpected Exchange category: %s", category.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -569,6 +569,100 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() {
|
|||||||
[]string{dest.ContainerName},
|
[]string{dest.ContainerName},
|
||||||
))
|
))
|
||||||
|
|
||||||
|
return backupSel.Selector
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "MultipleEventsSingleCalendar",
|
||||||
|
service: path.ExchangeService,
|
||||||
|
expectedRestoreFolders: 1,
|
||||||
|
collections: []colInfo{
|
||||||
|
{
|
||||||
|
pathElements: []string{"Work"},
|
||||||
|
category: path.EventsCategory,
|
||||||
|
items: []itemInfo{
|
||||||
|
{
|
||||||
|
name: "someencodeditemID",
|
||||||
|
data: mockconnector.GetMockEventWithSubjectBytes("Ghimley"),
|
||||||
|
lookupKey: "Ghimley",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "someencodeditemID2",
|
||||||
|
data: mockconnector.GetMockEventWithSubjectBytes("Irgot"),
|
||||||
|
lookupKey: "Irgot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "someencodeditemID3",
|
||||||
|
data: mockconnector.GetMockEventWithSubjectBytes("Jannes"),
|
||||||
|
lookupKey: "Jannes",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// TODO(ashmrtn): Generalize this once we know the path transforms that
|
||||||
|
// occur during restore.
|
||||||
|
backupSelFunc: func(dest control.RestoreDestination, backupUser string) selectors.Selector {
|
||||||
|
backupSel := selectors.NewExchangeBackup()
|
||||||
|
backupSel.Include(backupSel.EventCalendars(
|
||||||
|
[]string{backupUser},
|
||||||
|
[]string{dest.ContainerName},
|
||||||
|
))
|
||||||
|
|
||||||
|
return backupSel.Selector
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "MultipleEventsMultipleCalendars",
|
||||||
|
service: path.ExchangeService,
|
||||||
|
expectedRestoreFolders: 2,
|
||||||
|
collections: []colInfo{
|
||||||
|
{
|
||||||
|
pathElements: []string{"Work"},
|
||||||
|
category: path.EventsCategory,
|
||||||
|
items: []itemInfo{
|
||||||
|
{
|
||||||
|
name: "someencodeditemID",
|
||||||
|
data: mockconnector.GetMockEventWithSubjectBytes("Ghimley"),
|
||||||
|
lookupKey: "Ghimley",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "someencodeditemID2",
|
||||||
|
data: mockconnector.GetMockEventWithSubjectBytes("Irgot"),
|
||||||
|
lookupKey: "Irgot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "someencodeditemID3",
|
||||||
|
data: mockconnector.GetMockEventWithSubjectBytes("Jannes"),
|
||||||
|
lookupKey: "Jannes",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pathElements: []string{"Personal"},
|
||||||
|
category: path.EventsCategory,
|
||||||
|
items: []itemInfo{
|
||||||
|
{
|
||||||
|
name: "someencodeditemID4",
|
||||||
|
data: mockconnector.GetMockEventWithSubjectBytes("Argon"),
|
||||||
|
lookupKey: "Argon",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "someencodeditemID5",
|
||||||
|
data: mockconnector.GetMockEventWithSubjectBytes("Bernard"),
|
||||||
|
lookupKey: "Bernard",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// TODO(ashmrtn): Generalize this once we know the path transforms that
|
||||||
|
// occur during restore.
|
||||||
|
backupSelFunc: func(dest control.RestoreDestination, backupUser string) selectors.Selector {
|
||||||
|
backupSel := selectors.NewExchangeBackup()
|
||||||
|
backupSel.Include(backupSel.EventCalendars(
|
||||||
|
[]string{backupUser},
|
||||||
|
[]string{dest.ContainerName},
|
||||||
|
))
|
||||||
|
|
||||||
return backupSel.Selector
|
return backupSel.Selector
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -619,7 +713,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() {
|
|||||||
checkCollections(t, totalItems, expectedData, dcs)
|
checkCollections(t, totalItems, expectedData, dcs)
|
||||||
|
|
||||||
status = backupGC.AwaitStatus()
|
status = backupGC.AwaitStatus()
|
||||||
assert.Equal(t, test.expectedRestoreFolders, status.FolderCount, "status.FolderCount")
|
// TODO(ashmrtn): This will need to change when the restore layout is
|
||||||
|
// updated.
|
||||||
|
assert.Equal(t, 1, status.FolderCount, "status.FolderCount")
|
||||||
assert.Equal(t, totalItems, status.ObjectCount, "status.ObjectCount")
|
assert.Equal(t, totalItems, status.ObjectCount, "status.ObjectCount")
|
||||||
assert.Equal(t, totalItems, status.Successful, "status.Successful")
|
assert.Equal(t, totalItems, status.Successful, "status.Successful")
|
||||||
})
|
})
|
||||||
|
|||||||
@ -4,13 +4,10 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/common"
|
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
@ -144,96 +141,6 @@ func (med *MockExchangeData) Size() int64 {
|
|||||||
return med.size
|
return med.size
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMockContactBytes returns bytes for Contactable item.
|
|
||||||
// When hydrated: contact.GetGivenName() shows differences
|
|
||||||
func GetMockContactBytes(middleName string) []byte {
|
|
||||||
phone := generatePhoneNumber()
|
|
||||||
//nolint:lll
|
|
||||||
contact := "{\"id\":\"AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAEOAADSEBNbUIB9RL6ePDeF3FIYAABS7DZnAAA=\",\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#users('foobar%408qzvrj.onmicrosoft.com')/contacts/$entity\"," +
|
|
||||||
"\"@odata.etag\":\"W/\\\"EQAAABYAAADSEBNbUIB9RL6ePDeF3FIYAABSx4Tr\\\"\",\"categories\":[],\"changeKey\":\"EQAAABYAAADSEBNbUIB9RL6ePDeF3FIYAABSx4Tr\",\"createdDateTime\":\"2019-08-04T06:55:33Z\",\"lastModifiedDateTime\":\"2019-08-04T06:55:33Z\",\"businessAddress\":{},\"businessPhones\":[],\"children\":[]," +
|
|
||||||
"\"displayName\":\"Santiago Quail\",\"emailAddresses\":[],\"fileAs\":\"Quail, Santiago\",\"mobilePhone\": \"" + phone + "\"," +
|
|
||||||
"\"givenName\":\"Santiago\",\"homeAddress\":{},\"homePhones\":[],\"imAddresses\":[],\"otherAddress\":{},\"parentFolderId\":\"AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwAuAAAAAADCNgjhM9FIYAAAAAAEOAAA=\",\"personalNotes\":\"\",\"middleName\":\"" + middleName + "\",\"surname\":\"Quail\"}"
|
|
||||||
|
|
||||||
return []byte(contact)
|
|
||||||
}
|
|
||||||
|
|
||||||
// generatePhoneNumber creates a random phone number
|
|
||||||
// @return string representation in format (xxx)xxx-xxxx
|
|
||||||
func generatePhoneNumber() string {
|
|
||||||
numbers := make([]string, 0)
|
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
temp := rand.Intn(10)
|
|
||||||
value := strconv.Itoa(temp)
|
|
||||||
numbers = append(numbers, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
area := strings.Join(numbers[:3], "")
|
|
||||||
prefix := strings.Join(numbers[3:6], "")
|
|
||||||
suffix := strings.Join(numbers[6:], "")
|
|
||||||
phoneNo := "(" + area + ")" + prefix + "-" + suffix
|
|
||||||
|
|
||||||
return phoneNo
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMockEventBytes returns test byte array representative of full Eventable item.
|
|
||||||
func GetMockEventBytes(subject string) []byte {
|
|
||||||
newTime := time.Now().AddDate(0, 0, 1)
|
|
||||||
conversion := common.FormatTime(newTime)
|
|
||||||
timeSlice := strings.Split(conversion, "T")
|
|
||||||
|
|
||||||
//nolint:lll
|
|
||||||
event := "{\"id\":\"AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAADSEBNbUIB9RL6ePDeF3FIYAAAAAG76AAA=\",\"calendar@odata.navigationLink\":" +
|
|
||||||
"\"https://graph.microsoft.com/v1.0/users('foobar@8qzvrj.onmicrosoft.com')/calendars('AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwAuAAAAAADCNgjhM9QmQYWNcI7hCpPrAQDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAAA=')\"," +
|
|
||||||
"\"calendar@odata.associationLink\":\"https://graph.microsoft.com/v1.0/users('foobar@8qzvrj.onmicrosoft.com')/calendars('AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwAuAAAAAADCNgjhM9QmQYWNcI7hCpPrAQDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAAA=')/$ref\"," +
|
|
||||||
"\"@odata.etag\":\"W/\\\"0hATW1CAfUS+njw3hdxSGAAAJIxNug==\\\"\",\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#users('foobar%408qzvrj.onmicrosoft.com')/events/$entity\",\"categories\":[],\"changeKey\":\"0hATW1CAfUS+njw3hdxSGAAAJIxNug==\"," +
|
|
||||||
"\"createdDateTime\":\"2022-03-28T03:42:03Z\",\"lastModifiedDateTime\":\"2022-05-26T19:25:58Z\",\"allowNewTimeProposals\":true,\"attendees\"" +
|
|
||||||
":[],\"body\":{\"content\":\"<html>\\r\\n<head>\\r\\n<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=utf-8\\\">\\r\\n</head>\\r\\n<body>\\r\\n" +
|
|
||||||
"<p>This meeting is to review the latest Tailspin Toys project proposal.<br>\\r\\nBut why not eat some sushi while we’re at it? :)</p>\\r\\n</body>\\r\\n</html>\\r\\n\"" +
|
|
||||||
",\"contentType\":\"html\"},\"bodyPreview\":\"This meeting is to review the latest Tailspin Toys project proposal.\\r\\nBut why not eat some sushi while we’re at it? :)\"," +
|
|
||||||
"\"end\":{\"dateTime\":\"" + timeSlice[0] + "T07:00:00.0000000\",\"timeZone\":\"UTC\"},\"hasAttachments\":false,\"hideAttendees\":false,\"iCalUId\":" +
|
|
||||||
"\"040000008200E00074C5B7101A82E0080000000035723BC75542D801000000000000000010000000E1E7C8F785242E4894DA13AEFB947B85\",\"importance\":\"normal\",\"isAllDay\":false,\"isCancelled\":false," +
|
|
||||||
"\"isDraft\":false,\"isOnlineMeeting\":false,\"isOrganizer\":false,\"isReminderOn\":true," +
|
|
||||||
"\"location\":{\"displayName\":\"Umi Sake House (2230 1st Ave, Seattle, WA 98121 US)\",\"locationType\":\"default\",\"uniqueId\":\"Umi Sake House (2230 1st Ave, Seattle, WA 98121 US)\"," +
|
|
||||||
"\"uniqueIdType\":\"private\"},\"locations\":[{\"displayName\":\"Umi Sake House (2230 1st Ave, Seattle, WA 98121 US)\",\"locationType\":\"default\",\"uniqueId\":\"\",\"uniqueIdType\":\"unknown\"}],\"onlineMeetingProvider\":\"unknown\",\"organizer\"" +
|
|
||||||
":{\"emailAddress\":{\"address\":\"foobar3@8qzvrj.onmicrosoft.com\",\"name\":\"Anu Pierson\"}},\"originalEndTimeZone\":\"UTC\",\"originalStartTimeZone\":\"UTC\"," +
|
|
||||||
"\"reminderMinutesBeforeStart\":15,\"responseRequested\":true,\"responseStatus\":{\"response\":\"notResponded\",\"time\":\"0001-01-01T00:00:00Z\"},\"sensitivity\":\"normal\",\"showAs\":\"tentative\"," +
|
|
||||||
"\"start\":{\"dateTime\":\"" + timeSlice[0] + "T06:00:00.0000000\",\"timeZone\":\"UTC\"}," +
|
|
||||||
"\"subject\":\" " + subject +
|
|
||||||
" Review + Lunch\",\"type\":\"singleInstance\",\"webLink\":\"https://outlook.office365.com/owa/?itemid=AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAADSEBNbUIB9RL6ePDeF3FIYAAAAAG76AAA%3D&exvsurl=1&path=/calendar/item\"}"
|
|
||||||
|
|
||||||
return []byte(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
type errReader struct {
|
type errReader struct {
|
||||||
readErr error
|
readErr error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,10 @@ package mockconnector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/common"
|
"github.com/alcionai/corso/src/internal/common"
|
||||||
)
|
)
|
||||||
@ -33,6 +37,28 @@ const (
|
|||||||
"\"replyTo\":[],\"sender\":{\"emailAddress\":{\"address\":\"foobar@8qzvrj.onmicrosoft.com\",\"name\":\"A Stranger\"}},\"sentDateTime\":\"2022-09-26T23:15:46Z\"," +
|
"\"replyTo\":[],\"sender\":{\"emailAddress\":{\"address\":\"foobar@8qzvrj.onmicrosoft.com\",\"name\":\"A Stranger\"}},\"sentDateTime\":\"2022-09-26T23:15:46Z\"," +
|
||||||
"\"subject\":\"%s\",\"toRecipients\":[{\"emailAddress\":{\"address\":\"LidiaH@8qzvrj.onmicrosoft.com\",\"name\":\"Lidia Holloway\"}}]," +
|
"\"subject\":\"%s\",\"toRecipients\":[{\"emailAddress\":{\"address\":\"LidiaH@8qzvrj.onmicrosoft.com\",\"name\":\"Lidia Holloway\"}}]," +
|
||||||
"\"webLink\":\"https://outlook.office365.com/owa/?ItemID=AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAEMAADSEBNbUIB9RL6ePDeF3FIYAAB3XwIkAAA%%3D&exvsurl=1&viewmodel=ReadMessageItem\"}"
|
"\"webLink\":\"https://outlook.office365.com/owa/?ItemID=AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAEMAADSEBNbUIB9RL6ePDeF3FIYAAB3XwIkAAA%%3D&exvsurl=1&viewmodel=ReadMessageItem\"}"
|
||||||
|
|
||||||
|
// Order of fields to fill in:
|
||||||
|
// 1. start/end date
|
||||||
|
// 2. subject
|
||||||
|
eventTmpl = "{\"id\":\"AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAADSEBNbUIB9RL6ePDeF3FIYAAAAAG76AAA=\",\"calendar@odata.navigationLink\":" +
|
||||||
|
"\"https://graph.microsoft.com/v1.0/users('foobar@8qzvrj.onmicrosoft.com')/calendars('AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwAuAAAAAADCNgjhM9QmQYWNcI7hCpPrAQDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAAA=')\"," +
|
||||||
|
"\"calendar@odata.associationLink\":\"https://graph.microsoft.com/v1.0/users('foobar@8qzvrj.onmicrosoft.com')/calendars('AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwAuAAAAAADCNgjhM9QmQYWNcI7hCpPrAQDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAAA=')/$ref\"," +
|
||||||
|
"\"@odata.etag\":\"W/\\\"0hATW1CAfUS+njw3hdxSGAAAJIxNug==\\\"\",\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#users('foobar%%408qzvrj.onmicrosoft.com')/events/$entity\",\"categories\":[],\"changeKey\":\"0hATW1CAfUS+njw3hdxSGAAAJIxNug==\"," +
|
||||||
|
"\"createdDateTime\":\"2022-03-28T03:42:03Z\",\"lastModifiedDateTime\":\"2022-05-26T19:25:58Z\",\"allowNewTimeProposals\":true,\"attendees\"" +
|
||||||
|
":[],\"body\":{\"content\":\"<html>\\r\\n<head>\\r\\n<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=utf-8\\\">\\r\\n</head>\\r\\n<body>\\r\\n" +
|
||||||
|
"<p>This meeting is to review the latest Tailspin Toys project proposal.<br>\\r\\nBut why not eat some sushi while we’re at it? :)</p>\\r\\n</body>\\r\\n</html>\\r\\n\"" +
|
||||||
|
",\"contentType\":\"html\"},\"bodyPreview\":\"This meeting is to review the latest Tailspin Toys project proposal.\\r\\nBut why not eat some sushi while we’re at it? :)\"," +
|
||||||
|
"\"end\":{\"dateTime\":\"%[1]sT07:00:00.0000000\",\"timeZone\":\"UTC\"},\"hasAttachments\":false,\"hideAttendees\":false,\"iCalUId\":" +
|
||||||
|
"\"040000008200E00074C5B7101A82E0080000000035723BC75542D801000000000000000010000000E1E7C8F785242E4894DA13AEFB947B85\",\"importance\":\"normal\",\"isAllDay\":false,\"isCancelled\":false," +
|
||||||
|
"\"isDraft\":false,\"isOnlineMeeting\":false,\"isOrganizer\":false,\"isReminderOn\":true," +
|
||||||
|
"\"location\":{\"displayName\":\"Umi Sake House (2230 1st Ave, Seattle, WA 98121 US)\",\"locationType\":\"default\",\"uniqueId\":\"Umi Sake House (2230 1st Ave, Seattle, WA 98121 US)\"," +
|
||||||
|
"\"uniqueIdType\":\"private\"},\"locations\":[{\"displayName\":\"Umi Sake House (2230 1st Ave, Seattle, WA 98121 US)\",\"locationType\":\"default\",\"uniqueId\":\"\",\"uniqueIdType\":\"unknown\"}],\"onlineMeetingProvider\":\"unknown\",\"organizer\"" +
|
||||||
|
":{\"emailAddress\":{\"address\":\"foobar3@8qzvrj.onmicrosoft.com\",\"name\":\"Anu Pierson\"}},\"originalEndTimeZone\":\"UTC\",\"originalStartTimeZone\":\"UTC\"," +
|
||||||
|
"\"reminderMinutesBeforeStart\":15,\"responseRequested\":true,\"responseStatus\":{\"response\":\"notResponded\",\"time\":\"0001-01-01T00:00:00Z\"},\"sensitivity\":\"normal\",\"showAs\":\"tentative\"," +
|
||||||
|
"\"start\":{\"dateTime\":\"%[1]sT06:00:00.0000000\",\"timeZone\":\"UTC\"}," +
|
||||||
|
"\"subject\":\"%s\"," +
|
||||||
|
"\"type\":\"singleInstance\",\"webLink\":\"https://outlook.office365.com/owa/?itemid=AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAENAADSEBNbUIB9RL6ePDeF3FIYAAAAAG76AAA%%3D&exvsurl=1&path=/calendar/item\"}"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetMockMessageBytes returns bytes for Messageable item.
|
// GetMockMessageBytes returns bytes for Messageable item.
|
||||||
@ -159,3 +185,86 @@ func GetMessageWithOneDriveAttachment(subject string) []byte {
|
|||||||
|
|
||||||
return []byte(message)
|
return []byte(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMockContactBytes returns bytes for Contactable item.
|
||||||
|
// When hydrated: contact.GetGivenName() shows differences
|
||||||
|
func GetMockContactBytes(middleName string) []byte {
|
||||||
|
phone := generatePhoneNumber()
|
||||||
|
//nolint:lll
|
||||||
|
contact := "{\"id\":\"AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwBGAAAAAADCNgjhM9QmQYWNcI7hCpPrBwDSEBNbUIB9RL6ePDeF3FIYAAAAAAEOAADSEBNbUIB9RL6ePDeF3FIYAABS7DZnAAA=\",\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#users('foobar%408qzvrj.onmicrosoft.com')/contacts/$entity\"," +
|
||||||
|
"\"@odata.etag\":\"W/\\\"EQAAABYAAADSEBNbUIB9RL6ePDeF3FIYAABSx4Tr\\\"\",\"categories\":[],\"changeKey\":\"EQAAABYAAADSEBNbUIB9RL6ePDeF3FIYAABSx4Tr\",\"createdDateTime\":\"2019-08-04T06:55:33Z\",\"lastModifiedDateTime\":\"2019-08-04T06:55:33Z\",\"businessAddress\":{},\"businessPhones\":[],\"children\":[]," +
|
||||||
|
"\"displayName\":\"Santiago Quail\",\"emailAddresses\":[],\"fileAs\":\"Quail, Santiago\",\"mobilePhone\": \"" + phone + "\"," +
|
||||||
|
"\"givenName\":\"Santiago\",\"homeAddress\":{},\"homePhones\":[],\"imAddresses\":[],\"otherAddress\":{},\"parentFolderId\":\"AAMkAGZmNjNlYjI3LWJlZWYtNGI4Mi04YjMyLTIxYThkNGQ4NmY1MwAuAAAAAADCNgjhM9FIYAAAAAAEOAAA=\",\"personalNotes\":\"\",\"middleName\":\"" + middleName + "\",\"surname\":\"Quail\"}"
|
||||||
|
|
||||||
|
return []byte(contact)
|
||||||
|
}
|
||||||
|
|
||||||
|
// generatePhoneNumber creates a random phone number
|
||||||
|
// @return string representation in format (xxx)xxx-xxxx
|
||||||
|
func generatePhoneNumber() string {
|
||||||
|
numbers := make([]string, 0)
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
temp := rand.Intn(10)
|
||||||
|
value := strconv.Itoa(temp)
|
||||||
|
numbers = append(numbers, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
area := strings.Join(numbers[:3], "")
|
||||||
|
prefix := strings.Join(numbers[3:6], "")
|
||||||
|
suffix := strings.Join(numbers[6:], "")
|
||||||
|
phoneNo := "(" + area + ")" + prefix + "-" + suffix
|
||||||
|
|
||||||
|
return phoneNo
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMockEventBytes returns test byte array representative of full Eventable item.
|
||||||
|
func GetMockEventBytes(subject string) []byte {
|
||||||
|
newTime := time.Now().AddDate(0, 0, 1)
|
||||||
|
conversion := common.FormatTime(newTime)
|
||||||
|
timeSlice := strings.Split(conversion, "T")
|
||||||
|
fullSubject := " " + subject + " Review + Lunch"
|
||||||
|
|
||||||
|
formatted := fmt.Sprintf(eventTmpl, timeSlice[0], fullSubject)
|
||||||
|
|
||||||
|
return []byte(formatted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMockEventWithSubjectBytes(subject string) []byte {
|
||||||
|
newTime := time.Now().AddDate(0, 0, 1)
|
||||||
|
conversion := common.FormatTime(newTime)
|
||||||
|
timeSlice := strings.Split(conversion, "T")
|
||||||
|
|
||||||
|
formatted := fmt.Sprintf(eventTmpl, timeSlice[0], subject)
|
||||||
|
|
||||||
|
return []byte(formatted)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user