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

Add status change confirmation #73

Merged
merged 29 commits into from
May 4, 2020

Conversation

larkox
Copy link
Contributor

@larkox larkox commented Apr 3, 2020

Summary

Add confirmation for status change. Whenever the status is about to change, if the user has it configured for so, he will receive a message to confirm whether he wants to change the status.

Ticket Link

#60

@larkox larkox added 2: Dev Review Requires review by a core committer 1: PM Review Requires review by a product manager 3: QA Review Requires review by a QA tester labels Apr 3, 2020
@larkox
Copy link
Contributor Author

larkox commented Apr 3, 2020

There is a big concern regarding the handling of the availability. Since there is no reliable way to distinguish events during the status sync, we are storing the last availability value we found. If the value has not changed, it does not try to update the status. In general this will work fine, but there are some special cases where it will not work. The most prominent I found is the following:

  • A meeting finishes soon, so I change back my status to online. Nevertheless, since the sync status job keeps getting a availability value of busy, I will not get asked to change the status to dnd on the next meeting.

@aaronrothschild How big do you think is this problem?
@levb @mickmister Any idea on how to deal better with this?

@larkox
Copy link
Contributor Author

larkox commented Apr 3, 2020

Tests are failing due to the changes on how we handle the status sync. When all the pieces are there (user config) and the way to avoid asking many times for the user are decided, I will update the tests.

Copy link
Contributor

@mickmister mickmister left a comment

Choose a reason for hiding this comment

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

I have a few suggestions, LGTM other than the pending TODOs. Nice job 👍

server/api/post_action.go Outdated Show resolved Hide resolved
server/mscalendar/availability.go Outdated Show resolved Hide resolved
server/mscalendar/availability.go Outdated Show resolved Hide resolved
@larkox larkox requested a review from mickmister April 6, 2020 11:44
@codecov-io
Copy link

codecov-io commented Apr 6, 2020

Codecov Report

Merging #73 into master will increase coverage by 2.57%.
The diff coverage is 56.71%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #73      +/-   ##
==========================================
+ Coverage   23.04%   25.62%   +2.57%     
==========================================
  Files          62       62              
  Lines        2274     2377     +103     
==========================================
+ Hits          524      609      +85     
- Misses       1692     1693       +1     
- Partials       58       75      +17     
Impacted Files Coverage Δ
server/command/availability.go 0.00% <0.00%> (ø)
server/jobs/status_sync_job.go 0.00% <0.00%> (ø)
server/mscalendar/filters.go 42.42% <0.00%> (+13.47%) ⬆️
server/mscalendar/mscalendar.go 100.00% <ø> (ø)
server/mscalendar/settings.go 0.00% <0.00%> (ø)
server/mscalendar/user.go 16.83% <0.00%> (+11.56%) ⬆️
server/remote/msgraph/get_default_calendar_view.go 0.00% <0.00%> (ø)
server/mscalendar/availability.go 61.83% <65.86%> (+15.47%) ⬆️
server/mscalendar/daily_summary.go 39.09% <100.00%> (-2.21%) ⬇️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5e9f8da...5a698c8. Read the comment docs.

http.Error(w, "No state to change", http.StatusBadRequest)
return
}
stringChangeTo := changeTo.(string)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: can you change this to match the type assertion strategy above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, forgot about that.

return "Status not changed because there is no update since last status change."
}

u.LastStatusUpdateAvailability = currentAvailability
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we need to store more information here to take into account for the user manually changing their status. Here's a proposal

When the user manually changes their status, we take all events that overlap with now, and store them as hashes (eventid-starttime). Those events are now "immune" to an availability change. If an event's start gets moved, it becomes a "new" event as far as the availability changer is concerned.

I think this solves the one-off issue when the user wants to cancel out their most recent status change. If they want it to remain untouched by the automation, then they can disable it in their settings.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One of the main problems is that there is no eventID that I can use to handle this, I can only work with times and availability.

I can do the following:

  • Check if the availability has changed. If changed:
    • Check that mattermost status and handle it
  • If the availability is not changed, check the latest start time registered, and compare it with the elements returned.
  • If there is a new event (an event that starts later than the last registered) check with the current mattermost status.
  • If no event starts later, we assume it is the same event and ignore it.

I will implement this and keep thinking about it. Probably in code make more sense.

Copy link
Contributor

@mickmister mickmister Apr 9, 2020

Choose a reason for hiding this comment

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

Hmm well if we don't have an event id we're kind of at a disadvantage in general. Maybe we shouldn't even be using GetSchedule since we aren't getting the performance we were getting before with it, which was looking at several users' schedules in one request, the main reason why we had the dedicated bot account.

GetSchedule's main purpose is, find some time where one or more of these people are free given some time constraints. That's not really what we're doing here. We just want to know if one specific person is free "right now". We might want to use GetCalendarView with a small time window for this instead.

@larkox Let me know what you think about the shortcomings of using GetSchedule, versus the alternative GetCalendarView. Which reminds me that we have a GetSchedule response json example in the server/testdata folder, but not one for GetCalendarView.

@larkox larkox requested a review from mickmister April 8, 2020 10:38
levb
levb previously approved these changes Apr 8, 2020
Copy link
Contributor

@mickmister mickmister left a comment

Choose a reason for hiding this comment

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

I have a few non-blocking suggestions. @larkox Which PRs need to be merged before completing this one?

server/mscalendar/availability.go Outdated Show resolved Hide resolved
server/remote/schedule.go Outdated Show resolved Hide resolved
server/store/user_store.go Outdated Show resolved Hide resolved
@levb levb added this to the 0.1.0 milestone Apr 13, 2020
@aaronrothschild aaronrothschild removed the 1: PM Review Requires review by a product manager label Apr 13, 2020
@larkox larkox requested a review from mickmister April 14, 2020 12:15
@@ -168,7 +169,18 @@ func (m *mscalendar) GetRemoteUser(mattermostUserID string) (*remote.User, error
}

func (m *mscalendar) IsAuthorizedAdmin(mattermostUserID string) (bool, error) {
return m.Dependencies.IsAuthorizedAdmin(mattermostUserID)
for _, userID := range strings.Split(m.AdminUserIDs, ",") {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a pretty unexpected change, especially for the scope of the PR. Is there value lost by removing the injected dependency here? What packages had access to this functionality that no longer have access?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was implemented on plugin.go, and passed to MSCalendar plugin, and only used from there. Therefore, implementing it here made more sense, and simplified the dependencies.

@mickmister mickmister requested a review from levb April 27, 2020 17:38
@DHaussermann
Copy link

Tested this functionality including the following cases

  • Decline status updates
  • Decline prompts on status updates
    -- Status updates to busy without prompt
    -- Status Return from busy without prompt
  • Update status without notifications when prompt is declined
  • When meeting is canceled / moved after status already set to busy, the user is prompted to flip status back when sync notices they are no longer busy
  • No prompt on back to back or overlapping meeting as status does change from busy.

@larkox this looks really good! Though there are many possible edge cases (not necessarily related to status confirmation) that I will continue testing in master.

There were a couple small UX issues.

  1. @mickmister noticed that when the status is changed after an event has already stated (invited to an in progress meeting for example) the info in the prompt is misleading...
    Notification-Event-in-progress
    Technically accurate that there are no "upcoming" events but there is one in progress. The user was not able to be notified ahead of time. Can we add a a special case for this such that if the event is happening but stated in the past there could be text such as You have an event ongoing. Shall I change your status... ?

  2. Minor point - MS Calendar never refers to the event name as subject maybe drop off the with subject text from this dialogue? This way you have something like "Your event Meet for Dinner will start soon.
    Event-Subject

@asaadmahmood
Copy link

@larkox Based on your case, when a person changes his status to online, can we inform the plugin that the person manually made himself online, so that the next time it can ask me to change my status to dnd.

@larkox larkox linked an issue Apr 28, 2020 that may be closed by this pull request
@mickmister
Copy link
Contributor

mickmister commented Apr 29, 2020

the next time it can ask me to change my status to dnd.

@asaadmahmood So even if they have opted out of confirmations, we would still give them a chance to confirm? That is certainly feasible based on how we currently have things set up.

Edit: Do you mean specifically when a new event starts?

@mickmister
Copy link
Contributor

@DHaussermann Here's how I have it looking with some quick changes, including using a link for the event title

MS Calendar refers to the subject as a title, but in their data model it's called subject, so that's why we have it as that currently. Do you suggest we call it title?

Although the calendar also says (No subject) when an event has no title.

Here's how I have it looking when this is the case:


Also to address your point of "when the status is changed after an event has already stated": Nothing should happen for the rest of that event. The user should not receive any prompts. It is supposed to take into account the fact that you changed your status during the meeting and assume you don't want your status changed at all until a new event comes along. I am unable to reproduce your situation.


Another thing, when the event is currently ongoing, we still have access to the event and its subject. Should we have the event subject and link in the prompt, instead of your suggestion of the ambiguous You have an event ongoing?

@mickmister
Copy link
Contributor

@larkox Here's my code in case it is useful

func renderScheduleItem(event *remote.Event, status string) string {
	if event == nil {
		return fmt.Sprintf("You have an event ongoing.\n Shall I change your status to %s?", prettyStatuses[status])
	}

	subject := "(No subject)"
	if event.Subject != "" {
		subject = event.Subject
	}

	link, _ := url.QueryUnescape(event.Weblink)
	fullSubject := fmt.Sprintf("`%s`", subject)
	if link != "" {
		fullSubject = fmt.Sprintf("[%s](%s)", subject, link)
	}

	resp := fmt.Sprintf("Your event %s will start soon.", fullSubject)
	resp += fmt.Sprintf("\nShall I change your status to %s?", prettyStatuses[status])
	return resp
}

@asaadmahmood
Copy link

@mickmister We should not ask them again for events they have explicitly asked not to receive notifications for, but yes, it can be for any new events.

@DHaussermann
Copy link

Thanks @mickmister Yes I'm in favor of both of these ideas.

  1. Yes, since the field is called subject and it does actually show No subject in the MS Calendar UI when empty, we could show the same in the notification.

  2. If it's not a large amount of effort, we could show the name and link to the current on going event. I just wanted the problem solved where the user see's the unhelpful text of no upcoming events. That said, the UX would be odd if there was the name and the link because once the user selects and option would this info disappear and get replaced by The status has not been changed. or The status has been changed to Do Not Disturb. then the user can't click the link you just showed them.
    We could maybe create a new UX issue to add a link to viewcal or summary in the post confirming your status was changed. Maybe @asaadmahmood also has thoughts on this.

@larkox
Copy link
Contributor Author

larkox commented Apr 29, 2020

@DHaussermann Let me state the expected behaviour, some edge cases and the reasoning behind it.

Case Update status automatically

  • When a user is not DnD, and there is an upcoming event, the status will change to DnD.
  • When the event ends and there are no ongoing or upcoming events (within 10 minutes if I remember correctly), it will change to online.
  • When the event ends, if there are ongoing or upcoming events, the status will stay DnD until those end.
  • If the user sets back the status to online during an event it will stay online until a new upcoming event appears.

Case Get confirmation for status update

  • When a user is not DnD, and there is an upcoming event, it will be asked to change the status to DnD.
    • If the user says no or ignore the message, the user will not receive any new confirmation until a new event appears.
    • If the user says yes, the status will change to DnD.
  • When the event ends and there is no other ongoing or upcoming event, the user will receive a message asking to change back to Online.
  • When the event ends, if there are ongoing or upcoming events, no status change confirmation until those end.
  • If the user sets back the status to online during an event, it will not receive any new change confirmations until a new upcoming event appears.

Edge cases:

  • User was DnD when the event started:

    • Will set back to online (or receive online confirmation) when the event ends. The plugin considers the user free after the event, even if the user was DnD before.
  • User sets the status to online during the event, and then back to DnD during the event.

    • Will set back to online (or receive online confirmation) when the event ends. The plugin considers the user being DnD because of the event, and therefore consider it free when it finishes.
  • Two meetings are apart by 5-10 minutes.

    • Will keep the status as DnD those 5-10 minutes. The plugin consider the new upcoming event to be in the same "busy frame".
    • If user sets the status to Online during those 5-10 minutes, the status will be kept as online along the duration of the second meeting. The plugin consider the new upcoming event to be in the same "busy frame", so it will consider the user set the online status for both.
    • This edge case is highly dependent on when the job runs. The job must run and find the two events, and then you have to change the status after then. For example:
      • Event A finishes at 13:55
      • Event B starts at 14:00
      • Job runs at 13:50. Since it looks for upcoming events 10 minutes ahead, it will find Event A and Event B.
      • Job will see that the user is DnD, so will consider Event B "taken care of"
      • User changes manually the status to online at 13:55
      • Job runs at 14:00. It only finds Event B, but since Event B has already been "taken care of", it does not do anything.

… and add event information to post action result.
@larkox larkox requested a review from mickmister April 30, 2020 10:59
@mickmister
Copy link
Contributor

@larkox I want to know your thoughts on using Your event (No subject) instead of An event with no subject.

Microsoft uses (No subject) to show that an event has no subject.

image

This is relevant to the daily summary when there is an event with no subject. The subject is blank and is therefore not clickable.

image

My proposal is to use (No subject) in both spots in order for the two features to be consistent with each other, and to be consistent with Microsoft. @asaadmahmood @larkox Do you have any thoughts on this?

Copy link
Contributor

@mickmister mickmister left a comment

Choose a reason for hiding this comment

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

LGTM! The above comment is just a suggestion

@larkox
Copy link
Contributor Author

larkox commented Apr 30, 2020

@mickmister
"You event (No Subject)" feels like a bad user experience. If there is no subject, the name of the event is not "(No Subject)", it does not have a subject. I feel my proposal is more user friendly and leave a "more polished final result". Nevertheless, I am open to discuss it.

@mickmister
Copy link
Contributor

If there is no subject, the name of the event is not "(No Subject)", it does not have a subject.

@larkox Makes sense 👍

@DHaussermann
Copy link

Thanks for detailing the cases @larkox This all seems to be working as expected.

I did see once case where the leave the confirmation message had been displayed for hours and then selecting an option no longer worked. Cannot check whether there is an event attached
Confirmation1
I'm not sure how this occurred. Any thoughts?

I tested an edge case where the event is deleted before the recipient selects an option. and cases where the user has disconnected and reconnected their account before selecting an option. these both behave normally.

@mickmister
Copy link
Contributor

mickmister commented May 4, 2020

The Cannot check whether there is an event attached showing up is an error that "shouldn't ever happen" and can be taken care of in a separate ticket. It will require some investigation, but I don't think it's a blocker to get this merged. @DHaussermann What are your thoughts?

Edit: Ticket #110

@DHaussermann
Copy link

@mickmister Given that exploratory testing found no additional issues and I have made sure cases posted above by @larkox have all been covered now - I would be happy to merge this PR and investigate the remaining issue separately.

LGTM!

@DHaussermann DHaussermann added 4: Reviews Complete All reviewers have approved the pull request QA Review Done PR has been approved by QA and removed 3: QA Review Requires review by a QA tester labels May 4, 2020
Copy link

@DHaussermann DHaussermann left a comment

Choose a reason for hiding this comment

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

Testing details posted above.

@mickmister mickmister merged commit 69b1fee into mattermost:master May 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4: Reviews Complete All reviewers have approved the pull request QA Review Done PR has been approved by QA
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve rendering of events Confirmation of a Status Change upcoming
7 participants