From b612718723224eaa7fdfe449902a1f9cbf8c0435 Mon Sep 17 00:00:00 2001 From: ashmrtn Date: Fri, 30 Sep 2022 15:38:43 -0700 Subject: [PATCH] Update time parser to handle OneDrive format (#1013) ## Description OneDrive format uses '-' in place of ':'. Purge command needs to be able to clear folders with this format as well. ## Type of change - [ ] :sunflower: Feature - [x] :bug: Bugfix - [ ] :world_map: Documentation - [ ] :robot: Test - [ ] :computer: CI/Deployment - [ ] :hamster: Trivial/Minor ## Issue(s) * closes #1012 ## Test Plan - [ ] :muscle: Manual - [x] :zap: Unit test - [ ] :green_heart: E2E --- src/internal/common/time.go | 46 +++++++++++++++++++-------- src/internal/common/time_test.go | 53 ++++++++++++++++---------------- 2 files changed, 60 insertions(+), 39 deletions(-) diff --git a/src/internal/common/time.go b/src/internal/common/time.go index 3213ce583..25e7e5755 100644 --- a/src/internal/common/time.go +++ b/src/internal/common/time.go @@ -9,9 +9,10 @@ import ( const ( // the clipped format occurs when m365 removes the :00 second suffix - ClippedSimpleTimeFormat = "02-Jan-2006_15:04" - LegacyTimeFormat = time.RFC3339 - SimpleDateTimeFormat = "02-Jan-2006_15:04:05" + ClippedSimpleTimeFormat = "02-Jan-2006_15:04" + ClippedSimpleTimeFormatOneDrive = "02-Jan-2006_15-04" + LegacyTimeFormat = time.RFC3339 + SimpleDateTimeFormat = "02-Jan-2006_15:04:05" // SimpleDateTimeFormatOneDrive is similar to `SimpleDateTimeFormat` // but uses `-` instead of `:` which is a reserved character in // OneDrive @@ -21,11 +22,13 @@ const ( ) var ( - clippedSimpleTimeRE = regexp.MustCompile(`.*(\d{2}-[a-zA-Z]{3}-\d{4}_\d{2}:\d{2}).*`) - legacyTimeRE = regexp.MustCompile( + clippedSimpleTimeRE = regexp.MustCompile(`.*(\d{2}-[a-zA-Z]{3}-\d{4}_\d{2}:\d{2}).*`) + clippedSimpleTimeOneDriveRE = regexp.MustCompile(`.*(\d{2}-[a-zA-Z]{3}-\d{4}_\d{2}-\d{2}).*`) + legacyTimeRE = regexp.MustCompile( `.*(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?([Zz]|[a-zA-Z]{2}|([\+|\-]([01]\d|2[0-3])))).*`) - simpleDateTimeRE = regexp.MustCompile(`.*(\d{2}-[a-zA-Z]{3}-\d{4}_\d{2}:\d{2}:\d{2}).*`) - standardTimeRE = regexp.MustCompile( + simpleDateTimeRE = regexp.MustCompile(`.*(\d{2}-[a-zA-Z]{3}-\d{4}_\d{2}:\d{2}:\d{2}).*`) + simpleDateTimeOneDriveRE = regexp.MustCompile(`.*(\d{2}-[a-zA-Z]{3}-\d{4}_\d{2}-\d{2}-\d{2}).*`) + standardTimeRE = regexp.MustCompile( `.*(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[a-zA-Z]{2}|([\+|\-]([01]\d|2[0-3])))).*`) tabularOutputTimeRE = regexp.MustCompile(`.*(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}([Zz]|[a-zA-Z]{2})).*`) ) @@ -33,10 +36,22 @@ var ( var ( // clipped formats must appear last, else they take priority over the regular Simple format. formats = []string{ - StandardTimeFormat, SimpleDateTimeFormat, LegacyTimeFormat, TabularOutputTimeFormat, ClippedSimpleTimeFormat, + StandardTimeFormat, + SimpleDateTimeFormat, + SimpleDateTimeFormatOneDrive, + LegacyTimeFormat, + TabularOutputTimeFormat, + ClippedSimpleTimeFormat, + ClippedSimpleTimeFormatOneDrive, } regexes = []*regexp.Regexp{ - standardTimeRE, simpleDateTimeRE, legacyTimeRE, tabularOutputTimeRE, clippedSimpleTimeRE, + standardTimeRE, + simpleDateTimeRE, + simpleDateTimeOneDriveRE, + legacyTimeRE, + tabularOutputTimeRE, + clippedSimpleTimeRE, + clippedSimpleTimeOneDriveRE, } ) @@ -48,29 +63,34 @@ func FormatNow(fmt string) string { return time.Now().UTC().Format(fmt) } +// FormatTimeWith produces the a datetime with the given format. +func FormatTimeWith(t time.Time, fmt string) string { + return t.UTC().Format(fmt) +} + // FormatTime produces the standard format for corso time values. // Always formats into the UTC timezone. func FormatTime(t time.Time) string { - return t.UTC().Format(StandardTimeFormat) + return FormatTimeWith(t, StandardTimeFormat) } // FormatSimpleDateTime produces a simple datetime of the format // "02-Jan-2006_15:04:05" func FormatSimpleDateTime(t time.Time) string { - return t.UTC().Format(SimpleDateTimeFormat) + return FormatTimeWith(t, SimpleDateTimeFormat) } // FormatTabularDisplayTime produces the standard format for displaying // a timestamp as part of user-readable cli output. // "2016-01-02T15:04:05Z" func FormatTabularDisplayTime(t time.Time) string { - return t.UTC().Format(TabularOutputTimeFormat) + return FormatTimeWith(t, TabularOutputTimeFormat) } // FormatLegacyTime produces standard format for string values // that are placed in SingleValueExtendedProperty tags func FormatLegacyTime(t time.Time) string { - return t.UTC().Format(LegacyTimeFormat) + return FormatTimeWith(t, LegacyTimeFormat) } // ParseTime makes a best attempt to produce a time value from diff --git a/src/internal/common/time_test.go b/src/internal/common/time_test.go index 652426e53..1c46ce7fa 100644 --- a/src/internal/common/time_test.go +++ b/src/internal/common/time_test.go @@ -57,15 +57,11 @@ func (suite *CommonTimeUnitSuite) TestParseTime() { } func (suite *CommonTimeUnitSuite) TestExtractTime() { - clipSimpleTime := func(t string) string { - return t[:len(t)-3] - } - - comparable := func(t *testing.T, tt time.Time, clipped bool) time.Time { + comparable := func(t *testing.T, tt time.Time, clippedFormat string) time.Time { ts := common.FormatLegacyTime(tt.UTC()) - if clipped { - ts = tt.UTC().Format(common.ClippedSimpleTimeFormat) + if len(clippedFormat) > 0 { + ts = tt.UTC().Format(clippedFormat) } c, err := common.ParseTime(ts) @@ -95,16 +91,15 @@ func (suite *CommonTimeUnitSuite) TestExtractTime() { type timeFormatter func(time.Time) string - var ( - clippedF = func(t time.Time) string { - return clipSimpleTime(common.FormatSimpleDateTime(t)) - } - legacyF = common.FormatLegacyTime - simpleF = common.FormatSimpleDateTime - stdF = common.FormatTime - tabularF = common.FormatTabularDisplayTime - formatters = []timeFormatter{legacyF, simpleF, stdF, tabularF, clippedF} - ) + formats := []string{ + common.ClippedSimpleTimeFormat, + common.ClippedSimpleTimeFormatOneDrive, + common.LegacyTimeFormat, + common.SimpleDateTimeFormat, + common.SimpleDateTimeFormatOneDrive, + common.StandardTimeFormat, + common.TabularOutputTimeFormat, + } type presuf struct { prefix string @@ -119,23 +114,29 @@ func (suite *CommonTimeUnitSuite) TestExtractTime() { } type testable struct { - input string - expect time.Time - clipped bool + input string + clippedFormat string + expect time.Time } table := []testable{} // test matrix: for each input, in each format, with each prefix/suffix, run the test. for _, in := range inputs { - for i, f := range formatters { - v := f(in) + for _, f := range formats { + clippedFormat := f + + if f != common.ClippedSimpleTimeFormat && f != common.ClippedSimpleTimeFormatOneDrive { + clippedFormat = "" + } + + v := common.FormatTimeWith(in, f) for _, ps := range pss { table = append(table, testable{ - input: ps.prefix + v + ps.suffix, - expect: comparable(suite.T(), in, i == 4), - clipped: i == 4, + input: ps.prefix + v + ps.suffix, + expect: comparable(suite.T(), in, clippedFormat), + clippedFormat: clippedFormat, }) } } @@ -145,7 +146,7 @@ func (suite *CommonTimeUnitSuite) TestExtractTime() { suite.T().Run(test.input, func(t *testing.T) { result, err := common.ExtractTime(test.input) require.NoError(t, err) - assert.Equal(t, test.expect, comparable(t, result, test.clipped)) + assert.Equal(t, test.expect, comparable(t, result, test.clippedFormat)) }) } }