Add EndTime to Exchange events (#1446)
## Description Add EndTime to Exchange events. Also fixes a testcase around start time. ## Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🐹 Trivial/Minor ## Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * https://github.com/alcionai/corso/issues/1366 ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
f197396455
commit
5089f9d949
@ -38,6 +38,10 @@ const (
|
|||||||
// SimpleTimeTesting is used for testing restore destination folders.
|
// SimpleTimeTesting is used for testing restore destination folders.
|
||||||
// Microsecond granularity prevents collisions in parallel package or workflow runs.
|
// Microsecond granularity prevents collisions in parallel package or workflow runs.
|
||||||
SimpleTimeTesting TimeFormat = SimpleDateTimeOneDrive + ".000000"
|
SimpleTimeTesting TimeFormat = SimpleDateTimeOneDrive + ".000000"
|
||||||
|
|
||||||
|
// M365dateTimeTimeZoneTimeFormat is the format used by M365 for datetimetimezone resource
|
||||||
|
// https://learn.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0
|
||||||
|
M365DateTimeTimeZone TimeFormat = "2006-01-02T15:04:05.000000"
|
||||||
)
|
)
|
||||||
|
|
||||||
// these regexes are used to extract time formats from strings. Their primary purpose is to
|
// these regexes are used to extract time formats from strings. Their primary purpose is to
|
||||||
|
|||||||
@ -15,6 +15,7 @@ func EventInfo(evt models.Eventable) *details.ExchangeInfo {
|
|||||||
organizer, subject string
|
organizer, subject string
|
||||||
recurs bool
|
recurs bool
|
||||||
start = time.Time{}
|
start = time.Time{}
|
||||||
|
end = time.Time{}
|
||||||
)
|
)
|
||||||
|
|
||||||
if evt.GetOrganizer() != nil &&
|
if evt.GetOrganizer() != nil &&
|
||||||
@ -37,19 +38,32 @@ func EventInfo(evt models.Eventable) *details.ExchangeInfo {
|
|||||||
evt.GetStart().GetDateTime() != nil {
|
evt.GetStart().GetDateTime() != nil {
|
||||||
// timeString has 'Z' literal added to ensure the stored
|
// timeString has 'Z' literal added to ensure the stored
|
||||||
// DateTime is not: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
|
// DateTime is not: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
timeString := *evt.GetStart().GetDateTime() + "Z"
|
startTime := *evt.GetStart().GetDateTime() + "Z"
|
||||||
|
|
||||||
output, err := common.ParseTime(timeString)
|
output, err := common.ParseTime(startTime)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
start = output
|
start = output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if evt.GetEnd() != nil &&
|
||||||
|
evt.GetEnd().GetDateTime() != nil {
|
||||||
|
// timeString has 'Z' literal added to ensure the stored
|
||||||
|
// DateTime is not: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
endTime := *evt.GetEnd().GetDateTime() + "Z"
|
||||||
|
|
||||||
|
output, err := common.ParseTime(endTime)
|
||||||
|
if err == nil {
|
||||||
|
end = output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &details.ExchangeInfo{
|
return &details.ExchangeInfo{
|
||||||
ItemType: details.ExchangeEvent,
|
ItemType: details.ExchangeEvent,
|
||||||
Organizer: organizer,
|
Organizer: organizer,
|
||||||
Subject: subject,
|
Subject: subject,
|
||||||
EventStart: start,
|
EventStart: start,
|
||||||
|
EventEnd: end,
|
||||||
EventRecurs: recurs,
|
EventRecurs: recurs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ func TestEventSuite(t *testing.T) {
|
|||||||
// can be properly retrieved from a models.Eventable object
|
// can be properly retrieved from a models.Eventable object
|
||||||
func (suite *EventSuite) TestEventInfo() {
|
func (suite *EventSuite) TestEventInfo() {
|
||||||
initial := time.Now()
|
initial := time.Now()
|
||||||
now := common.FormatTime(initial)
|
now := common.FormatTimeWith(initial, common.M365DateTimeTimeZone)
|
||||||
|
|
||||||
suite.T().Logf("Initial: %v\nFormatted: %v\n", initial, now)
|
suite.T().Logf("Initial: %v\nFormatted: %v\n", initial, now)
|
||||||
|
|
||||||
@ -47,19 +47,41 @@ func (suite *EventSuite) TestEventInfo() {
|
|||||||
name: "Start time only",
|
name: "Start time only",
|
||||||
evtAndRP: func() (models.Eventable, *details.ExchangeInfo) {
|
evtAndRP: func() (models.Eventable, *details.ExchangeInfo) {
|
||||||
var (
|
var (
|
||||||
event = models.NewEvent()
|
event = models.NewEvent()
|
||||||
dateTime = models.NewDateTimeTimeZone()
|
dateTime = models.NewDateTimeTimeZone()
|
||||||
full, err = common.ParseTime(now)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require.NoError(suite.T(), err)
|
|
||||||
|
|
||||||
dateTime.SetDateTime(&now)
|
dateTime.SetDateTime(&now)
|
||||||
event.SetStart(dateTime)
|
event.SetStart(dateTime)
|
||||||
|
|
||||||
return event, &details.ExchangeInfo{
|
return event, &details.ExchangeInfo{
|
||||||
ItemType: details.ExchangeEvent,
|
ItemType: details.ExchangeEvent,
|
||||||
Received: full,
|
Received: initial,
|
||||||
|
EventStart: initial,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start and end time only",
|
||||||
|
evtAndRP: func() (models.Eventable, *details.ExchangeInfo) {
|
||||||
|
var (
|
||||||
|
event = models.NewEvent()
|
||||||
|
startTime = models.NewDateTimeTimeZone()
|
||||||
|
endTime = models.NewDateTimeTimeZone()
|
||||||
|
)
|
||||||
|
|
||||||
|
startTime.SetDateTime(&now)
|
||||||
|
event.SetStart(startTime)
|
||||||
|
|
||||||
|
nowp30m := common.FormatTimeWith(initial.Add(30*time.Minute), common.M365DateTimeTimeZone)
|
||||||
|
endTime.SetDateTime(&nowp30m)
|
||||||
|
event.SetEnd(endTime)
|
||||||
|
|
||||||
|
return event, &details.ExchangeInfo{
|
||||||
|
ItemType: details.ExchangeEvent,
|
||||||
|
Received: initial,
|
||||||
|
EventStart: initial,
|
||||||
|
EventEnd: initial.Add(30 * time.Minute),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -83,12 +105,13 @@ func (suite *EventSuite) TestEventInfo() {
|
|||||||
name: "Using mockable",
|
name: "Using mockable",
|
||||||
evtAndRP: func() (models.Eventable, *details.ExchangeInfo) {
|
evtAndRP: func() (models.Eventable, *details.ExchangeInfo) {
|
||||||
var (
|
var (
|
||||||
organizer = "foobar3@8qzvrj.onmicrosoft.com"
|
organizer = "foobar3@8qzvrj.onmicrosoft.com"
|
||||||
subject = " Test Mock Review + Lunch"
|
subject = " Test Mock Review + Lunch"
|
||||||
bytes = mockconnector.GetDefaultMockEventBytes("Test Mock")
|
bytes = mockconnector.GetDefaultMockEventBytes("Test Mock")
|
||||||
future = time.Now().UTC().AddDate(0, 0, 1)
|
future = time.Now().UTC().AddDate(0, 0, 1)
|
||||||
eventTime = time.Date(future.Year(), future.Month(), future.Day(), future.Hour(), 0, 0, 0, time.UTC)
|
eventTime = time.Date(future.Year(), future.Month(), future.Day(), future.Hour(), 0, 0, 0, time.UTC)
|
||||||
event, err = support.CreateEventFromBytes(bytes)
|
eventEndTime = eventTime.Add(30 * time.Minute)
|
||||||
|
event, err = support.CreateEventFromBytes(bytes)
|
||||||
)
|
)
|
||||||
|
|
||||||
require.NoError(suite.T(), err)
|
require.NoError(suite.T(), err)
|
||||||
@ -98,6 +121,7 @@ func (suite *EventSuite) TestEventInfo() {
|
|||||||
Subject: subject,
|
Subject: subject,
|
||||||
Organizer: organizer,
|
Organizer: organizer,
|
||||||
EventStart: eventTime,
|
EventStart: eventTime,
|
||||||
|
EventEnd: eventEndTime,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -110,16 +134,27 @@ func (suite *EventSuite) TestEventInfo() {
|
|||||||
assert.Equal(t, expected.Subject, result.Subject, "subject")
|
assert.Equal(t, expected.Subject, result.Subject, "subject")
|
||||||
assert.Equal(t, expected.Sender, result.Sender, "sender")
|
assert.Equal(t, expected.Sender, result.Sender, "sender")
|
||||||
|
|
||||||
expYear, expMonth, _ := expected.EventStart.Date() // Day not used at certain times of the day
|
expStartYear, expStartMonth, _ := expected.EventStart.Date() // Day not used at certain times of the day
|
||||||
expHr, expMin, expSec := expected.EventStart.Clock()
|
expStartHr, expStartMin, expStartSec := expected.EventStart.Clock()
|
||||||
recvYear, recvMonth, _ := result.EventStart.Date()
|
recvStartYear, recvStartMonth, _ := result.EventStart.Date()
|
||||||
recvHr, recvMin, recvSec := result.EventStart.Clock()
|
recvStartHr, recvStartMin, recvStartSec := result.EventStart.Clock()
|
||||||
|
|
||||||
assert.Equal(t, expYear, recvYear, "year")
|
assert.Equal(t, expStartYear, recvStartYear, "year")
|
||||||
assert.Equal(t, expMonth, recvMonth, "month")
|
assert.Equal(t, expStartMonth, recvStartMonth, "month")
|
||||||
assert.Equal(t, expHr, recvHr, "hour")
|
assert.Equal(t, expStartHr, recvStartHr, "hour")
|
||||||
assert.Equal(t, expMin, recvMin, "minute")
|
assert.Equal(t, expStartMin, recvStartMin, "minute")
|
||||||
assert.Equal(t, expSec, recvSec, "second")
|
assert.Equal(t, expStartSec, recvStartSec, "second")
|
||||||
|
|
||||||
|
expEndYear, expEndMonth, _ := expected.EventEnd.Date() // Day not used at certain times of the day
|
||||||
|
expEndHr, expEndMin, expEndSec := expected.EventEnd.Clock()
|
||||||
|
recvEndYear, recvEndMonth, _ := result.EventEnd.Date()
|
||||||
|
recvEndHr, recvEndMin, recvEndSec := result.EventEnd.Clock()
|
||||||
|
|
||||||
|
assert.Equal(t, expEndYear, recvEndYear, "year")
|
||||||
|
assert.Equal(t, expEndMonth, recvEndMonth, "month")
|
||||||
|
assert.Equal(t, expEndHr, recvEndHr, "hour")
|
||||||
|
assert.Equal(t, expEndMin, recvEndMin, "minute")
|
||||||
|
assert.Equal(t, expEndSec, recvEndSec, "second")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,11 +176,12 @@ func GetMockEventWithSubjectBytes(subject string) []byte {
|
|||||||
tomorrow := time.Now().UTC().AddDate(0, 0, 1)
|
tomorrow := time.Now().UTC().AddDate(0, 0, 1)
|
||||||
at := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), tomorrow.Hour(), 0, 0, 0, time.UTC)
|
at := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), tomorrow.Hour(), 0, 0, 0, time.UTC)
|
||||||
atTime := common.FormatTime(at)
|
atTime := common.FormatTime(at)
|
||||||
|
endTime := common.FormatTime(at.Add(30 * time.Minute))
|
||||||
|
|
||||||
return GetMockEventWith(
|
return GetMockEventWith(
|
||||||
defaultEventOrganizer, subject,
|
defaultEventOrganizer, subject,
|
||||||
defaultEventBody, defaultEventBodyPreview,
|
defaultEventBody, defaultEventBodyPreview,
|
||||||
atTime, atTime, false,
|
atTime, endTime, false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -298,6 +298,7 @@ type ExchangeInfo struct {
|
|||||||
Subject string `json:"subject,omitempty"`
|
Subject string `json:"subject,omitempty"`
|
||||||
Received time.Time `json:"received,omitempty"`
|
Received time.Time `json:"received,omitempty"`
|
||||||
EventStart time.Time `json:"eventStart,omitempty"`
|
EventStart time.Time `json:"eventStart,omitempty"`
|
||||||
|
EventEnd time.Time `json:"eventEnd,omitempty"`
|
||||||
Organizer string `json:"organizer,omitempty"`
|
Organizer string `json:"organizer,omitempty"`
|
||||||
ContactName string `json:"contactName,omitempty"`
|
ContactName string `json:"contactName,omitempty"`
|
||||||
EventRecurs bool `json:"eventRecurs,omitempty"`
|
EventRecurs bool `json:"eventRecurs,omitempty"`
|
||||||
@ -308,7 +309,7 @@ type ExchangeInfo struct {
|
|||||||
func (i ExchangeInfo) Headers() []string {
|
func (i ExchangeInfo) Headers() []string {
|
||||||
switch i.ItemType {
|
switch i.ItemType {
|
||||||
case ExchangeEvent:
|
case ExchangeEvent:
|
||||||
return []string{"Organizer", "Subject", "Starts", "Recurring"}
|
return []string{"Organizer", "Subject", "Starts", "Ends", "Recurring"}
|
||||||
|
|
||||||
case ExchangeContact:
|
case ExchangeContact:
|
||||||
return []string{"Contact Name"}
|
return []string{"Contact Name"}
|
||||||
@ -329,6 +330,7 @@ func (i ExchangeInfo) Values() []string {
|
|||||||
i.Organizer,
|
i.Organizer,
|
||||||
i.Subject,
|
i.Subject,
|
||||||
common.FormatTabularDisplayTime(i.EventStart),
|
common.FormatTabularDisplayTime(i.EventStart),
|
||||||
|
common.FormatTabularDisplayTime(i.EventEnd),
|
||||||
strconv.FormatBool(i.EventRecurs),
|
strconv.FormatBool(i.EventRecurs),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,14 +52,15 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &details.ExchangeInfo{
|
||||||
ItemType: details.ExchangeEvent,
|
ItemType: details.ExchangeEvent,
|
||||||
EventStart: now,
|
EventStart: now,
|
||||||
|
EventEnd: now,
|
||||||
Organizer: "organizer",
|
Organizer: "organizer",
|
||||||
EventRecurs: true,
|
EventRecurs: true,
|
||||||
Subject: "subject",
|
Subject: "subject",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectHs: []string{"ID", "Organizer", "Subject", "Starts", "Recurring"},
|
expectHs: []string{"ID", "Organizer", "Subject", "Starts", "Ends", "Recurring"},
|
||||||
expectVs: []string{"deadbeef", "organizer", "subject", nowStr, "true"},
|
expectVs: []string{"deadbeef", "organizer", "subject", nowStr, nowStr, "true"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "exchange contact info",
|
name: "exchange contact info",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user