-
Notifications
You must be signed in to change notification settings - Fork 71
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
GitHub Issue #170 - Update status when starting/ending a zoom meeting #171
Changes from 8 commits
1c65449
3d3971f
58c00b7
b69fba9
95008bd
fedc699
c92363d
ff80b69
da42848
b844efe
45db34d
756a614
c3b3ac5
ec0a039
077e049
70102a6
52060a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -22,7 +22,12 @@ import ( | |||||||||||||||||
"github.com/mattermost/mattermost-plugin-zoom/server/zoom" | ||||||||||||||||||
) | ||||||||||||||||||
|
||||||||||||||||||
const defaultMeetingTopic = "Zoom Meeting" | ||||||||||||||||||
const ( | ||||||||||||||||||
defaultMeetingTopic = "Zoom Meeting" | ||||||||||||||||||
postActionPath = "/action/status" | ||||||||||||||||||
yes = "yes" | ||||||||||||||||||
no = "no" | ||||||||||||||||||
) | ||||||||||||||||||
|
||||||||||||||||||
func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) { | ||||||||||||||||||
config := p.getConfiguration() | ||||||||||||||||||
|
@@ -42,11 +47,52 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req | |||||||||||||||||
p.completeUserOAuthToZoom(w, r) | ||||||||||||||||||
case "/deauthorization": | ||||||||||||||||||
p.deauthorizeUser(w, r) | ||||||||||||||||||
case postActionPath: | ||||||||||||||||||
p.postActionConfirm(w, r) | ||||||||||||||||||
default: | ||||||||||||||||||
http.NotFound(w, r) | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
func (p *Plugin) postActionConfirm(w http.ResponseWriter, r *http.Request) { | ||||||||||||||||||
userID := r.Header.Get("Mattermost-User-ID") | ||||||||||||||||||
response := model.PostActionIntegrationResponse{} | ||||||||||||||||||
request := model.PostActionIntegrationRequestFromJson(r.Body) | ||||||||||||||||||
accepted := request.Context["accept"].(bool) | ||||||||||||||||||
meetingID := request.Context["meetingId"].(float64) | ||||||||||||||||||
cvhariharan marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
|
||||||||||||||||||
post := &model.Post{} | ||||||||||||||||||
key := fmt.Sprintf("%v_%v", changeStatusKey, userID) | ||||||||||||||||||
|
||||||||||||||||||
message := "Ok, the status won't be updated automatically" | ||||||||||||||||||
changeStatus := no | ||||||||||||||||||
if accepted { | ||||||||||||||||||
changeStatus = yes | ||||||||||||||||||
message = "You have accepted automatic status change. Yay!" | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
appErr := p.API.KVSet(key, []byte(changeStatus)) | ||||||||||||||||||
if appErr != nil { | ||||||||||||||||||
p.API.LogDebug("failed to set status change preference", "error", appErr.Error()) | ||||||||||||||||||
} | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should return here instead of proceeding after the if statement. Maybe have this function return an error, and call this function with a smaller function that handles the error. Any error that occurs in this function should cause the function to return early. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mickmister Here if we don't return early, the next call is to setUserStatus which would automatically send another slack attachment for user confirmation on automatic status change. Won't that be more convenient? Also, if I understand this correctly, you are suggesting we remove the |
||||||||||||||||||
|
||||||||||||||||||
err := p.setUserStatus(userID, int(meetingID), false) | ||||||||||||||||||
if appErr != nil { | ||||||||||||||||||
p.API.LogDebug("failed to change user status", "error", err) | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+90
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
sa := &model.SlackAttachment{ | ||||||||||||||||||
Title: "Status Change", | ||||||||||||||||||
Text: message, | ||||||||||||||||||
} | ||||||||||||||||||
model.ParseSlackAttachment(post, []*model.SlackAttachment{sa}) | ||||||||||||||||||
response.Update = post | ||||||||||||||||||
_, err = w.Write(response.ToJson()) | ||||||||||||||||||
if err != nil { | ||||||||||||||||||
p.API.LogDebug("failed to write response") | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
func (p *Plugin) connectUserToZoom(w http.ResponseWriter, r *http.Request) { | ||||||||||||||||||
userID := r.Header.Get("Mattermost-User-ID") | ||||||||||||||||||
if userID == "" { | ||||||||||||||||||
|
@@ -288,13 +334,18 @@ func (p *Plugin) handleMeetingEnded(w http.ResponseWriter, r *http.Request, webh | |||||||||||||||||
return | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
err := p.setUserStatus(post.UserId, int(meetingID), true) | ||||||||||||||||||
if err != nil { | ||||||||||||||||||
p.API.LogDebug("failed to change user status", "error", err) | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we return the error, and handle it on the caller's side? I think we will need to make a separate small function to do so. |
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
appErr = p.API.KVDelete(key) | ||||||||||||||||||
if appErr != nil { | ||||||||||||||||||
p.API.LogWarn("failed to delete db entry", "error", appErr.Error()) | ||||||||||||||||||
return | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
_, err := w.Write([]byte(post.ToJson())) | ||||||||||||||||||
_, err = w.Write([]byte(post.ToJson())) | ||||||||||||||||||
if err != nil { | ||||||||||||||||||
p.API.LogWarn("failed to write response", "error", err.Error()) | ||||||||||||||||||
} | ||||||||||||||||||
|
@@ -341,6 +392,23 @@ func (p *Plugin) postMeeting(creator *model.User, meetingID int, channelID strin | |||||||||||||||||
return appErr | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
storedStatusPref, appErr := p.API.KVGet(fmt.Sprintf("%v_%v", changeStatusKey, creator.Id)) | ||||||||||||||||||
if appErr != nil { | ||||||||||||||||||
p.API.LogDebug("Could not get stored status preference from KV ", appErr) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
if storedStatusPref == nil { | ||||||||||||||||||
err := p.sendStatusChangeAttachment(creator.Id, p.botUserID, meetingID) | ||||||||||||||||||
if err != nil { | ||||||||||||||||||
p.API.LogDebug("could not send status change attachment ", "error", err) | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
larkox marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
|
||||||||||||||||||
err := p.setUserStatus(creator.Id, meetingID, false) | ||||||||||||||||||
if err != nil { | ||||||||||||||||||
p.API.LogDebug("failed to change user status", "error", err) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
appErr = p.API.KVSetWithExpiry(fmt.Sprintf("%v%v", postMeetingKey, meetingID), []byte(createdPost.Id), meetingPostIDTTL) | ||||||||||||||||||
if appErr != nil { | ||||||||||||||||||
p.API.LogDebug("failed to store post id", "err", appErr) | ||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -24,7 +24,9 @@ import ( | |||||||
) | ||||||||
|
||||||||
const ( | ||||||||
postMeetingKey = "post_meeting_" | ||||||||
postMeetingKey = "post_meeting_" | ||||||||
oldStatusKey = "old_status_" | ||||||||
changeStatusKey = "zoom_status_change" | ||||||||
|
||||||||
botUserName = "zoom" | ||||||||
botDisplayName = "Zoom" | ||||||||
|
@@ -42,6 +44,7 @@ const ( | |||||||
meetingPostIDTTL = 60 * 60 * 24 // One day | ||||||||
|
||||||||
zoomProviderName = "Zoom" | ||||||||
pluginURLPath = "/plugins/" + botUserName | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we compute the URL in a separate function like this? https://github.com/mattermost/mattermost-plugin-jira/blob/dc4266c61871200cc79d5a9feb97676aa330d50b/server/plugin.go#L396 |
||||||||
) | ||||||||
|
||||||||
type Plugin struct { | ||||||||
|
@@ -394,3 +397,112 @@ func (p *Plugin) dm(userID string, message string) error { | |||||||
} | ||||||||
return nil | ||||||||
} | ||||||||
|
||||||||
func (p *Plugin) setUserStatus(userID string, meetingID int, meetingEnd bool) error { | ||||||||
statusChangePrefkey := fmt.Sprintf("%v_%v", changeStatusKey, userID) | ||||||||
changeStatus, err := p.API.KVGet(statusChangePrefkey) | ||||||||
if err != nil { | ||||||||
p.API.LogDebug("Could not get old status from KVStore", "err", err.Error()) | ||||||||
return err | ||||||||
} | ||||||||
|
||||||||
if string(changeStatus) != yes { | ||||||||
return nil | ||||||||
} | ||||||||
|
||||||||
statusKey := fmt.Sprintf("%v%v", oldStatusKey, meetingID) | ||||||||
if meetingEnd { | ||||||||
b, appErr := p.API.KVGet(statusKey) | ||||||||
cvhariharan marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
if appErr != nil { | ||||||||
p.API.LogDebug("Could not get old status from KVStore", "err", appErr.Error()) | ||||||||
return appErr | ||||||||
} | ||||||||
|
||||||||
newStatus := string(b) | ||||||||
if newStatus == "" { | ||||||||
newStatus = model.STATUS_ONLINE | ||||||||
} | ||||||||
|
||||||||
_, appErr = p.API.UpdateUserStatus(userID, newStatus) | ||||||||
if appErr != nil { | ||||||||
p.API.LogDebug("Could not get update status", "err", appErr.Error()) | ||||||||
return appErr | ||||||||
} | ||||||||
|
||||||||
return nil | ||||||||
} | ||||||||
|
||||||||
currentStatus, appErr := p.API.GetUserStatus(userID) | ||||||||
if appErr != nil { | ||||||||
p.API.LogDebug("Failed to update user status", "err", appErr) | ||||||||
return appErr | ||||||||
} | ||||||||
|
||||||||
oldStatus := "" | ||||||||
if currentStatus.Manual { | ||||||||
oldStatus = currentStatus.Status | ||||||||
} | ||||||||
|
||||||||
appErr = p.API.KVSetWithExpiry(statusKey, []byte(oldStatus), meetingPostIDTTL) | ||||||||
if appErr != nil { | ||||||||
p.API.LogDebug("failed to store old status", "err", appErr) | ||||||||
return appErr | ||||||||
} | ||||||||
|
||||||||
_, appErr = p.API.UpdateUserStatus(userID, model.STATUS_DND) | ||||||||
if appErr != nil { | ||||||||
p.API.LogDebug("Failed to update user status", "err", appErr) | ||||||||
return appErr | ||||||||
Comment on lines
+272
to
+273
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use |
||||||||
} | ||||||||
|
||||||||
return nil | ||||||||
} | ||||||||
|
||||||||
func (p *Plugin) sendStatusChangeAttachment(userID, botUserID string, meetingID int) error { | ||||||||
url := pluginURLPath + postActionPath | ||||||||
actionYes := &model.PostAction{ | ||||||||
Name: "Yes", | ||||||||
Integration: &model.PostActionIntegration{ | ||||||||
URL: url, | ||||||||
Context: map[string]interface{}{ | ||||||||
"accept": true, | ||||||||
"meetingId": meetingID, | ||||||||
}, | ||||||||
}, | ||||||||
} | ||||||||
|
||||||||
actionNo := &model.PostAction{ | ||||||||
Name: "No", | ||||||||
Integration: &model.PostActionIntegration{ | ||||||||
URL: url, | ||||||||
Context: map[string]interface{}{ | ||||||||
"accept": false, | ||||||||
"meetingId": meetingID, | ||||||||
}, | ||||||||
}, | ||||||||
} | ||||||||
|
||||||||
sa := &model.SlackAttachment{ | ||||||||
Title: "Status change", | ||||||||
Text: "Allow Zoom plugin to automatically change status", | ||||||||
Actions: []*model.PostAction{actionYes, actionNo}, | ||||||||
} | ||||||||
|
||||||||
attachmentPost := model.Post{} | ||||||||
model.ParseSlackAttachment(&attachmentPost, []*model.SlackAttachment{sa}) | ||||||||
directChannel, appErr := p.API.GetDirectChannel(userID, botUserID) | ||||||||
larkox marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
if appErr != nil { | ||||||||
p.API.LogDebug("Create Attachment: ", appErr) | ||||||||
return appErr | ||||||||
Comment on lines
+313
to
+314
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
} | ||||||||
attachmentPost.ChannelId = directChannel.Id | ||||||||
attachmentPost.UserId = botUserID | ||||||||
|
||||||||
_, appErr = p.API.CreatePost(&attachmentPost) | ||||||||
if appErr != nil { | ||||||||
p.API.LogDebug("Create Attachment: ", appErr) | ||||||||
return appErr | ||||||||
Comment on lines
+321
to
+322
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
} | ||||||||
|
||||||||
return nil | ||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this message convey the fact of "Your status will be updated" or "Your status will not be updated"?