Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MM-228] Add feature to update custom status and status of the user during meeting #359

Merged
merged 23 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ed87b58
[MM-188] Add feature to update custom status and status of the user d…
ayusht2810 Feb 6, 2024
b696601
[MM-188] Add test case for custom status change
ayusht2810 Feb 6, 2024
d1c271b
Fix test cases
raghavaggarwal2308 Mar 4, 2024
a9c4531
[MM-188] Review fixes: Update constant name, add some comments and re…
ayusht2810 Feb 16, 2024
10d6649
[MM-252] Review fixes
raghavaggarwal2308 Feb 27, 2024
3c2ed2b
[MM-250] Review fixes
raghavaggarwal2308 Feb 28, 2024
56441cc
fix link error
raghavaggarwal2308 Mar 4, 2024
8fd8412
Fix failing test
raghavaggarwal2308 Mar 4, 2024
642b212
[MM-256] Added test cases for back-to-back event and non overlapping …
raghavaggarwal2308 Mar 4, 2024
59f5951
Merge branch 'master' into MM-188-fix
fmartingr May 21, 2024
85fe326
Merge branch 'master' into MM-188-fix
raghavaggarwal2308 Jun 11, 2024
ef5152e
Merge branch 'master' into MM-188-fix
hanzei Jun 26, 2024
67c24e7
Merge branch 'master' into MM-188-fix
raghavaggarwal2308 Jul 2, 2024
dbd3e5d
[MM-188] Fix review fixes: Use legacy settings, update and add new te…
ayusht2810 Jul 4, 2024
14eddb0
[MM-188] Update case to filter events on attendee as well
ayusht2810 Jul 4, 2024
8f503b1
Merge branch 'master' into MM-188-fix
ayusht2810 Jul 4, 2024
0ad2bb8
Merge branch 'master' into MM-188-fix
wiggin77 Jul 4, 2024
03b1d25
Merge branch 'master' into MM-188-fix
raghavaggarwal2308 Jul 10, 2024
5b08060
[MM-188] Add comments to the code
ayusht2810 Jul 10, 2024
c7441e0
Merge branch 'master' into MM-188-fix
wiggin77 Aug 1, 2024
f287370
Merge branch 'master' into MM-188-fix
raghavaggarwal2308 Aug 5, 2024
b851b21
Merge branch 'master' into MM-188-fix
raghavaggarwal2308 Aug 8, 2024
716ebcc
Merge branch 'master' of github.com:mattermost/mattermost-plugin-msca…
raghavaggarwal2308 Aug 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/custom.mk
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ GO_BUILD_FLAGS = -ldflags '$(LDFLAGS)'
mock:
ifneq ($(HAS_SERVER),)
go install github.com/golang/mock/[email protected]
mockgen -destination calendar/jobs/mock_cluster/mock_cluster.go github.com/mattermost/mattermost-plugin-api/cluster JobPluginAPI
mockgen -destination calendar/jobs/mock_cluster/mock_cluster.go github.com/mattermost/mattermost/server/public/pluginapi/cluster JobPluginAPI
mockgen -destination calendar/engine/mock_engine/mock_engine.go $(REPOSITORY_URL)/calendar/engine Engine
mockgen -destination calendar/engine/mock_welcomer/mock_welcomer.go -package mock_welcomer $(REPOSITORY_URL)/calendar/engine Welcomer
mockgen -destination calendar/engine/mock_plugin_api/mock_plugin_api.go -package mock_plugin_api $(REPOSITORY_URL)/calendar/engine PluginAPI
Expand Down
142 changes: 127 additions & 15 deletions calendar/engine/availability.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package engine

import (
"fmt"
"sort"
"time"

"github.com/mattermost/mattermost/server/public/model"
Expand Down Expand Up @@ -109,7 +110,7 @@ func (m *mscalendar) retrieveUsersToSync(userIndex store.UserIndex, syncJobSumma
}

// If user does not have the proper features enabled, just go to the next one
if !(user.Settings.UpdateStatus || user.Settings.ReceiveReminders) {
if !(user.Settings.UpdateStatusFromOptions != NotSetStatusOption || user.Settings.ReceiveReminders || user.Settings.SetCustomStatus) {
ayusht2810 marked this conversation as resolved.
Show resolved Hide resolved
continue
}

Expand Down Expand Up @@ -230,7 +231,7 @@ func (m *mscalendar) setUserStatuses(users []*store.User, calendarViews []*remot
numberOfLogs, numberOfUserStatusChange, numberOfUserErrorInStatusChange := 0, 0, 0
toUpdate := []*store.User{}
for _, u := range users {
if u.Settings.UpdateStatus {
if u.Settings.UpdateStatusFromOptions != NotSetStatusOption || u.Settings.SetCustomStatus {
ayusht2810 marked this conversation as resolved.
Show resolved Hide resolved
toUpdate = append(toUpdate, u)
}
}
Expand Down Expand Up @@ -279,37 +280,124 @@ func (m *mscalendar) setUserStatuses(users []*store.User, calendarViews []*remot
}

var err error
res, isStatusChanged, err = m.setStatusFromCalendarView(user, status, view)
if err != nil {
if numberOfLogs < logTruncateLimit {
m.Logger.Warnf("Error setting user %s status. err=%v", user.MattermostUserID, err)
} else if numberOfLogs == logTruncateLimit {
m.Logger.Warnf(logTruncateMsg)
if user.Settings.UpdateStatusFromOptions != NotSetStatusOption {
res, isStatusChanged, err = m.setStatusFromCalendarView(user, status, view)
if err != nil {
if numberOfLogs < logTruncateLimit {
m.Logger.Warnf("Error setting user %s status. err=%v", user.MattermostUserID, err)
} else if numberOfLogs == logTruncateLimit {
m.Logger.Warnf(logTruncateMsg)
}
numberOfLogs++
numberOfUserErrorInStatusChange++
}
if isStatusChanged {
numberOfUserStatusChange++
}
numberOfLogs++
numberOfUserErrorInStatusChange++
}
if isStatusChanged {
numberOfUserStatusChange++

if user.Settings.SetCustomStatus {
res, isStatusChanged, err = m.setCustomStatusFromCalendarView(user, view)
if err != nil {
if numberOfLogs < logTruncateLimit {
m.Logger.Warnf("Error setting user %s status. err=%v", user.MattermostUserID, err)
} else if numberOfLogs == logTruncateLimit {
m.Logger.Warnf(logTruncateMsg)
}
numberOfLogs++
numberOfUserErrorInStatusChange++
}

// Increment count only when we have not updated the status of the user from the options to have status change count per user.
if isStatusChanged && user.Settings.UpdateStatusFromOptions == NotSetStatusOption {
numberOfUserStatusChange++
}
}
}

if res != "" {
return res, numberOfUserStatusChange, numberOfUserErrorInStatusChange, nil
}

return utils.JSONBlock(calendarViews), numberOfUserStatusChange, numberOfUserErrorInStatusChange, nil
}

func (m *mscalendar) setCustomStatusFromCalendarView(user *store.User, res *remote.ViewCalendarResponse) (string, bool, error) {
isStatusChanged := false
if !user.Settings.SetCustomStatus {
return "User doesn't want to set custom status", isStatusChanged, nil
}

events := filterBusyEvents(res.Events)
if len(events) == 0 {
if user.IsCustomStatusSet {
if err := m.PluginAPI.RemoveMattermostUserCustomStatus(user.MattermostUserID); err != nil {
m.Logger.Warnf("Error removing user %s custom status. err=%v", user.MattermostUserID, err)
}

if err := m.Store.StoreUserCustomStatusUpdates(user.MattermostUserID, false); err != nil {
return "", isStatusChanged, err
}
}

return "No event present to set custom status", isStatusChanged, nil
}

if checkOverlappingEvents(events) {
return "Overlapping events, not setting a custom status", isStatusChanged, nil
}
ayusht2810 marked this conversation as resolved.
Show resolved Hide resolved

// Not setting custom status for events without attendees since those are unlikely to be meetings.
if len(events[0].Attendees) < 1 {
return "No attendee present, not setting custom status", isStatusChanged, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if a meeting other than the first one has attendees?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flow is updated now. We consider other meetings as well now.


currentUser, err := m.PluginAPI.GetMattermostUser(user.MattermostUserID)
if err != nil {
return "", isStatusChanged, err
}

currentCustomStatus := currentUser.GetCustomStatus()
if currentCustomStatus != nil && !user.IsCustomStatusSet {
return "User already have a custom status set, ignoring custom status change", isStatusChanged, nil
ayusht2810 marked this conversation as resolved.
Show resolved Hide resolved
}

if appErr := m.PluginAPI.UpdateMattermostUserCustomStatus(user.MattermostUserID, &model.CustomStatus{
Emoji: "calendar",
Text: "In a meeting",
ExpiresAt: events[0].End.Time(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is an event at events[1] not important here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the flow now

Duration: "date_and_time",
}); appErr != nil {
return "", isStatusChanged, appErr
}

isStatusChanged = true
if err := m.Store.StoreUserCustomStatusUpdates(user.MattermostUserID, true); err != nil {
return "", isStatusChanged, err
}

return "", isStatusChanged, nil
}

func (m *mscalendar) setStatusFromCalendarView(user *store.User, status *model.Status, res *remote.ViewCalendarResponse) (string, bool, error) {
isStatusChanged := false
currentStatus := status.Status
if user.Settings.UpdateStatusFromOptions == "" {
return "No value set from options to update status", isStatusChanged, nil
}

if currentStatus == model.StatusOffline && !user.Settings.GetConfirmation {
return "User offline and does not want status change confirmations. No status change", isStatusChanged, nil
}

events := filterBusyEvents(res.Events)

sort.Slice(events, func(i, j int) bool {
return events[i].Start.Time().UnixMicro() < events[j].Start.Time().UnixMicro()
})
ayusht2810 marked this conversation as resolved.
Show resolved Hide resolved

busyStatus := model.StatusDnd
if user.Settings.ReceiveNotificationsDuringMeeting {
if user.Settings.UpdateStatusFromOptions == AwayStatusOption {
busyStatus = model.StatusAway
}

Expand Down Expand Up @@ -338,6 +426,15 @@ func (m *mscalendar) setStatusFromCalendarView(user *store.User, status *model.S
return message, isStatusChanged, nil
}

if checkOverlappingEvents(events) {
return "Overlapping events, not updating status", isStatusChanged, nil
}

// Not setting custom status for events without attendees since those are unlikely to be meetings.
if len(events[0].Attendees) < 1 {
return "No attendee present, not updating status", isStatusChanged, nil
}

remoteHashes := []string{}
for _, e := range events {
if e.IsCancelled {
Expand Down Expand Up @@ -424,7 +521,7 @@ func (m *mscalendar) setStatusOrAskUser(user *store.User, currentStatus *model.S

if !isFree {
toSet = model.StatusDnd
if user.Settings.ReceiveNotificationsDuringMeeting {
if user.Settings.UpdateStatusFromOptions == AwayStatusOption {
toSet = model.StatusAway
}
if !user.Settings.GetConfirmation {
Expand Down Expand Up @@ -566,9 +663,24 @@ func (m *mscalendar) notifyUpcomingEvents(mattermostUserID string, events []*rem
func filterBusyEvents(events []*remote.Event) []*remote.Event {
result := []*remote.Event{}
for _, e := range events {
if e.ShowAs == "busy" {
if e.ShowAs == "busy" && !e.IsCancelled {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll want to make sure this works with google calendar as well. i.e. make sure IsCancelled is populated beforehand properly

result = append(result, e)
}
}
return result
}

// Function to check for overlapping events.
func checkOverlappingEvents(events []*remote.Event) bool {
ayusht2810 marked this conversation as resolved.
Show resolved Hide resolved
if len(events) <= 1 {
return false
}

for i := 1; i < len(events); i++ {
if events[i-1].End.Time().UnixMicro() > events[i].Start.Time().UnixMicro() {
return true
}
}

return false
ayusht2810 marked this conversation as resolved.
Show resolved Hide resolved
}
Loading