diff --git a/ee/server/calendar/google_calendar.go b/ee/server/calendar/google_calendar.go
index 69bbe07012..09fe94a832 100644
--- a/ee/server/calendar/google_calendar.go
+++ b/ee/server/calendar/google_calendar.go
@@ -261,7 +261,7 @@ func (c *GoogleCalendar) Configure(userEmail string) error {
return nil
}
-func (c *GoogleCalendar) GetAndUpdateEvent(event *fleet.CalendarEvent, genBodyFn func(conflict bool) (body string, ok bool, err error)) (
+func (c *GoogleCalendar) GetAndUpdateEvent(event *fleet.CalendarEvent, genBodyFn func(conflict bool) (body string, updated bool, err error)) (
*fleet.CalendarEvent, bool, error,
) {
// We assume that the Fleet event has not already ended. We will simply return it if it has not been modified.
@@ -269,11 +269,26 @@ func (c *GoogleCalendar) GetAndUpdateEvent(event *fleet.CalendarEvent, genBodyFn
if err != nil {
return nil, false, err
}
+
+ // Set current calendar instance timezone to the latest from google calendar.
+ c.location, err = getTimezone(c)
+ if err != nil {
+ return nil, false, err
+ }
+ tzUpdated := c.location.String() != event.TimeZone
+
gEvent, err := c.config.API.GetEvent(details.ID, details.ETag)
+
var deleted, channelStopped bool
switch {
// http.StatusNotModified is returned sometimes, but not always, so we need to check ETag explicitly later
case googleapi.IsNotModified(err):
+ if tzUpdated {
+ // this condition occurs when the event itself hasn't been updated, but the calendar timezone
+ // has been, so update the Fleet event's timezone
+ event.TimeZone = c.location.String()
+ return event, true, nil
+ }
return event, false, nil
// http.StatusNotFound should be very rare -- Google keeps events for a while after they are deleted
case isNotFound(err):
@@ -284,6 +299,12 @@ func (c *GoogleCalendar) GetAndUpdateEvent(event *fleet.CalendarEvent, genBodyFn
if !deleted && gEvent.Status != "cancelled" {
if details.ETag != "" && details.ETag == gEvent.Etag {
// Event was not modified
+ if tzUpdated {
+ // this condition occurs when the event itself hasn't been updated, but the calendar timezone
+ // has been, so just update the event's timezone
+ event.TimeZone = c.location.String()
+ return event, true, nil
+ }
return event, false, nil
}
if gEvent.End == nil || (gEvent.End.DateTime == "" && gEvent.End.Date == "") {
@@ -593,12 +614,12 @@ func adjustEventTimes(endTime time.Time, dayEnd time.Time) (eventStart time.Time
func getTimezone(gCal *GoogleCalendar) (location *time.Location, err error) {
config := gCal.config
// "The ID of the user’s timezone." https://developers.google.com/calendar/api/v3/reference/settings
- tz, err := config.API.GetSetting("timezone")
+ gCalTz, err := config.API.GetSetting("timezone")
if err != nil {
return nil, ctxerr.Wrap(config.Context, err, "retrieving Google calendar timezone")
}
- return getLocation(tz.Value, config), nil
+ return getLocation(gCalTz.Value, config), nil
}
func getLocation(tz string, config *GoogleCalendarConfig) *time.Location {
@@ -616,6 +637,7 @@ func (c *GoogleCalendar) googleEventToFleetEvent(startTime time.Time, endTime ti
resourceID string) (
*fleet.CalendarEvent, error,
) {
+
fleetEvent := &fleet.CalendarEvent{}
fleetEvent.StartTime = startTime
fleetEvent.EndTime = endTime
diff --git a/ee/server/calendar/google_calendar_test.go b/ee/server/calendar/google_calendar_test.go
index 848be3693b..5cd96bfb67 100644
--- a/ee/server/calendar/google_calendar_test.go
+++ b/ee/server/calendar/google_calendar_test.go
@@ -2,16 +2,17 @@ package calendar
import (
"context"
+ "net/http"
+ "os"
+ "testing"
+ "time"
+
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/go-kit/log"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/api/calendar/v3"
"google.golang.org/api/googleapi"
- "net/http"
- "os"
- "testing"
- "time"
)
const (
@@ -202,6 +203,8 @@ func TestGoogleCalendar_GetAndUpdateEvent(t *testing.T) {
const baseETag = "event-eTag"
const baseEventID = "event-id"
const baseResourceID = "resource-id"
+ const baseTzName = "America/New_York"
+ baseTzLocation, _ := time.LoadLocation(baseTzName)
mockAPI.GetEventFunc = func(id, eTag string) (*calendar.Event, error) {
assert.Equal(t, baseEventID, id)
assert.Equal(t, baseETag, eTag)
@@ -209,6 +212,9 @@ func TestGoogleCalendar_GetAndUpdateEvent(t *testing.T) {
Etag: baseETag, // ETag matches -- no modifications to event
}, nil
}
+ mockAPI.GetSettingFunc = func(name string) (*calendar.Setting, error) {
+ return &calendar.Setting{Value: baseTzName}, nil
+ }
genBodyFn := func(bool) (string, bool, error) {
t.Error("genBodyFn should not be called")
return "event-body", false, nil
@@ -217,11 +223,12 @@ func TestGoogleCalendar_GetAndUpdateEvent(t *testing.T) {
err := cal.Configure(baseUserEmail)
assert.NoError(t, err)
- eventStartTime := time.Now().UTC()
+ eventStartTime := time.Now().In(baseTzLocation)
event := &fleet.CalendarEvent{
StartTime: eventStartTime,
- EndTime: time.Now().Add(time.Hour),
+ EndTime: time.Now().Add(time.Hour).In(baseTzLocation),
Data: []byte(`{"ID":"` + baseEventID + `","ETag":"` + baseETag + `"}`),
+ TimeZone: baseTzName,
}
// ETag matches
@@ -316,16 +323,19 @@ func TestGoogleCalendar_GetAndUpdateEvent(t *testing.T) {
assert.Error(t, err)
// Event has been modified, with custom timezone.
- tzId := "Africa/Kinshasa"
- location, _ := time.LoadLocation(tzId)
- startTime = time.Now().Add(time.Minute).Truncate(time.Second).In(location)
- endTime = time.Now().Add(time.Hour).Truncate(time.Second).In(location)
+ newTzName := "Africa/Kinshasa"
+ newTzLocation, _ := time.LoadLocation(newTzName)
+ mockAPI.GetSettingFunc = func(name string) (*calendar.Setting, error) {
+ return &calendar.Setting{Value: newTzName}, nil
+ }
+ startTime = time.Now().Add(time.Minute).Truncate(time.Second).In(newTzLocation)
+ endTime = time.Now().Add(time.Hour).Truncate(time.Second).In(newTzLocation)
mockAPI.GetEventFunc = func(id, eTag string) (*calendar.Event, error) {
return &calendar.Event{
Id: baseEventID,
Etag: "new-eTag",
- Start: &calendar.EventDateTime{DateTime: startTime.UTC().Format(time.RFC3339), TimeZone: tzId},
- End: &calendar.EventDateTime{DateTime: endTime.Format(time.RFC3339), TimeZone: tzId},
+ Start: &calendar.EventDateTime{DateTime: startTime.UTC().Format(time.RFC3339), TimeZone: newTzName},
+ End: &calendar.EventDateTime{DateTime: endTime.Format(time.RFC3339), TimeZone: newTzName},
}, nil
}
retrievedEvent, updated, err = cal.GetAndUpdateEvent(event, genBodyFn)
@@ -341,9 +351,6 @@ func TestGoogleCalendar_GetAndUpdateEvent(t *testing.T) {
mockAPI.GetEventFunc = func(id, eTag string) (*calendar.Event, error) {
return nil, &googleapi.Error{Code: http.StatusNotFound}
}
- mockAPI.GetSettingFunc = func(name string) (*calendar.Setting, error) {
- return &calendar.Setting{Value: "UTC"}, nil
- }
mockAPI.ListEventsFunc = func(timeMin, timeMax string) (*calendar.Events, error) {
return &calendar.Events{}, nil
}
@@ -383,7 +390,7 @@ func TestGoogleCalendar_GetAndUpdateEvent(t *testing.T) {
assert.Equal(t, uuid, retrievedEvent.UUID)
assert.Equal(t, baseUserEmail, retrievedEvent.Email)
newEventDate := calculateNewEventDate(eventStartTime)
- expectedStartTime := time.Date(newEventDate.Year(), newEventDate.Month(), newEventDate.Day(), startHour, 0, 0, 0, time.UTC)
+ expectedStartTime := time.Date(newEventDate.Year(), newEventDate.Month(), newEventDate.Day(), startHour, 0, 0, 0, newTzLocation)
assert.Equal(t, expectedStartTime.UTC(), retrievedEvent.StartTime.UTC())
assert.Equal(t, expectedStartTime.Add(eventLength).UTC(), retrievedEvent.EndTime.UTC())
assert.True(t, eventCreated)
diff --git a/frontend/pages/DashboardPage/DashboardPage.tsx b/frontend/pages/DashboardPage/DashboardPage.tsx
index 321ba4c2c7..345e6eb7b6 100644
--- a/frontend/pages/DashboardPage/DashboardPage.tsx
+++ b/frontend/pages/DashboardPage/DashboardPage.tsx
@@ -660,7 +660,6 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => {
isSoftwareEnabled={isSoftwareEnabled}
software={software}
teamId={currentTeamId}
- pageIndex={softwarePageIndex}
navTabIndex={softwareNavTabIndex}
onTabChange={onSoftwareTabChange}
onQueryChange={onSoftwareQueryChange}
diff --git a/frontend/pages/DashboardPage/cards/Software/Software.tsx b/frontend/pages/DashboardPage/cards/Software/Software.tsx
index 86e0836ef7..0b2af37375 100644
--- a/frontend/pages/DashboardPage/cards/Software/Software.tsx
+++ b/frontend/pages/DashboardPage/cards/Software/Software.tsx
@@ -23,7 +23,6 @@ interface ISoftwareCardProps {
isSoftwareEnabled?: boolean;
software?: ISoftwareResponse;
teamId?: number;
- pageIndex: number;
navTabIndex: number;
onTabChange: (index: number, last: number, event: Event) => boolean | void;
onQueryChange?:
diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx
index 146809ad56..b3d272d95f 100644
--- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx
+++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx
@@ -364,19 +364,20 @@ const HostSummary = ({
DATE_FNS_FORMAT_STRINGS.dateAtTime
);
- const tip = timezone ? (
- <>
- End user's time zone:
-
- (GMT{starts_at.slice(-6)}) {timezone.replace("_", " ")}
- >
- ) : (
- <>
- End user's timezone unavailable.
-
- Displaying in UTC.
- >
- );
+ const tip =
+ timezone && timezone !== "UTC" ? (
+ <>
+ End user's time zone:
+
+ (GMT{starts_at.slice(-6)}) {timezone.replace("_", " ")}
+ >
+ ) : (
+ <>
+ End user's timezone unavailable.
+
+ Displaying in UTC.
+ >
+ );
return (