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 15099] direct message notifications on off #62

Merged
merged 45 commits into from
May 24, 2019
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
6ae2768
JIRAv2 initial PR (#36)
levb Apr 25, 2019
a48270e
Update README.md
jasonblais Apr 26, 2019
918faf6
Revert accidental commit
jasonblais Apr 26, 2019
d6d1389
Update README.md (#38)
jasonblais Apr 29, 2019
0c381e4
Update README.md
jasonblais Apr 30, 2019
7b82ff1
quick fix of url
cpoile May 1, 2019
2e85229
correct the menu item used in Jira
cpoile May 1, 2019
f737bf5
Proposed text updates for /jira slash commands (#41)
jasonblais May 2, 2019
4e355c0
Some cleanup for Jira plugin (#42)
jasonblais May 2, 2019
95ffe56
MM-15244 Jira Cloud user connect security (#39)
levb May 3, 2019
7991579
Doc updates for roadmap and Jira Server install docs (#40)
jasonblais May 6, 2019
03acbae
MM-15101 Adding /jira transition (#46)
crspeller May 7, 2019
33b0a3a
MM-15253 Refactor of create-issue modal. (#44)
crspeller May 7, 2019
96bee47
Fixed /jira subcommand parsing consistency (#45)
levb May 8, 2019
8ba8802
Fixed creating server/dist/templates/templates on a 2nd make (#50)
levb May 9, 2019
43eb30e
small fixes to /jira instance delete (#52)
cpoile May 10, 2019
6612955
Some improvments to cloud connect flow. (#55)
crspeller May 10, 2019
815ad08
MM-15096 UI fixes for template pages and menu item (#54)
asaadmahmood May 13, 2019
897cc00
Update Jira application link for Cloud (#48)
jasonblais May 13, 2019
10af812
(no ticket?) Fixed a bug in unescaping webhook secret (#53)
levb May 13, 2019
36c0e69
MM-15400 Added some protections to /installed link (#47)
levb May 13, 2019
b17831b
Update README.md
jasonblais May 14, 2019
4d8f5a7
Update README.md
jasonblais May 14, 2019
f6dbb7f
Add 'subject to change' for timeline in README
jasonblais May 14, 2019
b8fee88
Added response logging for Jira API errors (#59)
levb May 15, 2019
e92470e
* notifications working, added issue_created
cpoile May 16, 2019
924779f
wip
cpoile May 16, 2019
92b691d
* new make lifecycle commands: debug, webapp-debug, reset, stop
cpoile May 3, 2019
b2202a8
[MM-14773] [MM-15440] - simplify settings and setup (#57)
cpoile May 16, 2019
70cfc22
* notification setting persisted, command line updated
cpoile May 16, 2019
ed5e6d3
Merge branch 'jira2' into MM-15099-notifications-on-off
cpoile May 16, 2019
db0932b
* disable notifications working
cpoile May 17, 2019
299c37f
Revert "* new make lifecycle commands: debug, webapp-debug, reset, stop"
cpoile May 17, 2019
acd6315
Fix govet
crspeller May 18, 2019
3502b9f
Adding new CI
crspeller May 17, 2019
05b9957
Updating Makefile and moving to go modules
crspeller May 18, 2019
6e202d9
Temporarily use jira2 as CI branch.
crspeller May 18, 2019
a7e8054
fixing tests
cpoile May 18, 2019
c6c16d5
Merge branch 'jira2' into MM-15099-notifications-on-off
cpoile May 18, 2019
d7c87c3
PR comments
cpoile May 21, 2019
9a64198
Merge remote-tracking branch 'upstream/master' into MM-15099-notifica…
cpoile May 23, 2019
77a60df
fixes needed after The Great Merge
cpoile May 23, 2019
35b6550
updated for firehose webhook (#61) now on master
cpoile May 23, 2019
b176375
Merge remote-tracking branch 'upstream/master' into MM-15099-notifica…
cpoile May 23, 2019
85a4ca2
PR comments
cpoile May 23, 2019
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
35 changes: 34 additions & 1 deletion server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@ const helpText = "###### Mattermost Jira Plugin - Slash Command Help\n" +
"* `/jira disconnect` - Disonnect your Mattermost account from your Jira account\n" +
"* `/jira create <text (optional)>` - Create a new Issue with 'text' inserted into the description field.\n" +
"* `/jira transition <issue-key> <state>` - Changes the state of a Jira issue.\n" +
"* `/jira settings [setting] [value]` - Update your user settings\n" +
" * [setting] can be `notifications`\n" +
" * [value] can be `on` or `off`\n" +
"\nFor system administrators:\n" +
"* `/jira install cloud <URL>` - connect Mattermost to a cloud Jira instance located at <URL>\n" +
"* `/jira install server <URL>` - connect Mattermost to a server Jira instance located at <URL>\n" +
""

// Available settings
const (
settingsNotifications = "notifications"
)

type CommandHandlerFunc func(p *Plugin, c *plugin.Context, header *model.CommandArgs, args ...string) *model.CommandResponse

type CommandHandler struct {
Expand All @@ -33,6 +41,7 @@ var jiraCommandHandler = CommandHandler{
"transition": executeTransition,
"connect": executeConnect,
"disconnect": executeDisconnect,
"settings": executeSettings,
//"webhook": executeWebhookURL,
//"webhook/url": executeWebhookURL,
//"list": executeList,
Expand Down Expand Up @@ -84,6 +93,30 @@ func executeDisconnect(p *Plugin, c *plugin.Context, header *model.CommandArgs,
p.GetPluginURL(), routeUserDisconnect)
}

func executeSettings(p *Plugin, c *plugin.Context, header *model.CommandArgs, args ...string) *model.CommandResponse {
if len(args) != 2 {
crspeller marked this conversation as resolved.
Show resolved Hide resolved
return help()
}

ji, err := p.LoadCurrentJIRAInstance()
if err != nil {
return responsef("Failed to load current Jira instance: %v. Please contact your system administrator.", err)
}

mattermostUserId := header.UserId
jiraUser, err := p.LoadJIRAUser(ji, mattermostUserId)
if err != nil {
return responsef("Your username is not connected to Jira. Please type `jira connect`. %v", err)
}

switch args[0] {
case settingsNotifications:
return p.settingsNotifications(ji, mattermostUserId, jiraUser, args[1:])
default:
return responsef("Unknown setting.")
}
}

func executeList(p *Plugin, c *plugin.Context, header *model.CommandArgs, args ...string) *model.CommandResponse {
authorized, err := authorizedSysAdmin(p, header.UserId)
if err != nil {
Expand Down Expand Up @@ -280,7 +313,7 @@ func getCommand() *model.Command {
DisplayName: "Jira",
Description: "Integration with Jira.",
AutoComplete: true,
AutoCompleteDesc: "Available commands: connect, disconnect, create, transition, install cloud, install server, help",
AutoCompleteDesc: "Available commands: connect, disconnect, create, transition, settings, install cloud, install server, help",
AutoCompleteHint: "[command]",
}
}
Expand Down
41 changes: 41 additions & 0 deletions server/settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import "github.com/mattermost/mattermost-server/model"

const (
settingOn = "on"
settingOff = "off"
)

func (p *Plugin) settingsNotifications(ji Instance, mattermostUserId string, jiraUser JIRAUser, args []string) *model.CommandResponse {
var value bool
switch args[0] {
case settingOn:
value = true
case settingOff:
value = false
default:
return responsef("Invalid value. Accepted values are: `on` or `off`.")
}

if jiraUser.Settings == nil {
jiraUser.Settings = &UserSettings{}
}
jiraUser.Settings.Notifications = value
if err := p.StoreUserInfo(ji, mattermostUserId, jiraUser); err != nil {
p.errorf("settingsNotifications, err: %v", err)
responsef("Could not store new settings. Please contact your system administrator. error: %v", err)
}

// send back the actual value
updatedJiraUser, err := p.LoadJIRAUser(ji, mattermostUserId)
if err != nil {
return responsef("Your username is not connected to Jira. Please type `jira connect`. %v", err)
}
notifications := "off"
if updatedJiraUser.Settings.Notifications {
notifications = "on"
}

return responsef("Settings updated. Notifications %s.", notifications)
}
7 changes: 7 additions & 0 deletions server/subscribe.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,13 @@ func httpSubscribeWebhook(p *Plugin, w http.ResponseWriter, r *http.Request) (in
}
}

// Notify any affected users using a direct channel
err = p.handleNotifications(parsed)
if err != nil {
p.errorf("httpSubscribeWebhook, handleNotifications: %v", err)
return http.StatusBadRequest, err
}

return http.StatusOK, nil
}

Expand Down
94 changes: 93 additions & 1 deletion server/testdata/webhook-comment-created.json
Original file line number Diff line number Diff line change
@@ -1 +1,93 @@
{"timestamp":1550286678321,"webhookEvent":"comment_created","comment":{"self":"https://some-instance-test.atlassian.net/rest/api/2/issue/10040/comment/10019","id":"10019","author":{"self":"https://some-instance-test.atlassian.net/rest/api/2/user?accountId=5c5f880629be9642ba529340","name":"admin","key":"admin","accountId":"5c5f880629be9642ba529340","avatarUrls":{"48x48":"https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=48&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D48%26noRedirect%3Dtrue","24x24":"https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=24&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D24%26noRedirect%3Dtrue","16x16":"https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=16&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D16%26noRedirect%3Dtrue","32x32":"https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D32%26noRedirect%3Dtrue"},"displayName":"Test User","active":true,"timeZone":"America/Los_Angeles"},"body":"Added a comment","updateAuthor":{"self":"https://some-instance-test.atlassian.net/rest/api/2/user?accountId=5c5f880629be9642ba529340","name":"admin","key":"admin","accountId":"5c5f880629be9642ba529340","avatarUrls":{"48x48":"https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=48&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D48%26noRedirect%3Dtrue","24x24":"https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=24&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D24%26noRedirect%3Dtrue","16x16":"https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=16&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D16%26noRedirect%3Dtrue","32x32":"https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D32%26noRedirect%3Dtrue"},"displayName":"Test User","active":true,"timeZone":"America/Los_Angeles"},"created":"2019-02-15T19:11:18.321-0800","updated":"2019-02-15T19:11:18.321-0800","jsdPublic":true},"issue":{"id":"10040","self":"https://some-instance-test.atlassian.net/rest/api/2/issue/10040","key":"TES-41","fields":{"summary":"Unit test summary 1","issuetype":{"self":"https://some-instance-test.atlassian.net/rest/api/2/issuetype/10001","id":"10001","description":"Stories track functionality or features expressed as user goals.","iconUrl":"https://some-instance-test.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10315&avatarType=issuetype","name":"Story","subtask":false,"avatarId":10315},"project":{"self":"https://some-instance-test.atlassian.net/rest/api/2/project/10000","id":"10000","key":"TES","name":"test1","projectTypeKey":"software","avatarUrls":{"48x48":"https://some-instance-test.atlassian.net/secure/projectavatar?avatarId=10324","24x24":"https://some-instance-test.atlassian.net/secure/projectavatar?size=small&avatarId=10324","16x16":"https://some-instance-test.atlassian.net/secure/projectavatar?size=xsmall&avatarId=10324","32x32":"https://some-instance-test.atlassian.net/secure/projectavatar?size=medium&avatarId=10324"}},"assignee":null,"priority":{"self":"https://some-instance-test.atlassian.net/rest/api/2/priority/2","iconUrl":"https://some-instance-test.atlassian.net/images/icons/priorities/high.svg","name":"High","id":"2"},"status":{"self":"https://some-instance-test.atlassian.net/rest/api/2/status/10001","description":"","iconUrl":"https://some-instance-test.atlassian.net/","name":"To Do","id":"10001","statusCategory":{"self":"https://some-instance-test.atlassian.net/rest/api/2/statuscategory/2","id":2,"key":"new","colorName":"blue-gray","name":"To Do"}}}}}
{
"timestamp": 1550286678321,
"webhookEvent": "comment_created",
"comment": {
"self": "https://some-instance-test.atlassian.net/rest/api/2/issue/10040/comment/10019",
"id": "10019",
"author": {
"self": "https://some-instance-test.atlassian.net/rest/api/2/user?accountId=5c5f880629be9642ba529340",
"name": "admin",
"key": "admin",
"accountId": "5c5f880629be9642ba529340",
"avatarUrls": {
"48x48": "https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=48&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D48%26noRedirect%3Dtrue",
"24x24": "https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=24&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D24%26noRedirect%3Dtrue",
"16x16": "https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=16&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D16%26noRedirect%3Dtrue",
"32x32": "https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D32%26noRedirect%3Dtrue"
},
"displayName": "Test User",
"active": true,
"timeZone": "America/Los_Angeles"
},
"body": "Added a comment",
"updateAuthor": {
"self": "https://some-instance-test.atlassian.net/rest/api/2/user?accountId=5c5f880629be9642ba529340",
"name": "admin",
"key": "admin",
"accountId": "5c5f880629be9642ba529340",
"avatarUrls": {
"48x48": "https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=48&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D48%26noRedirect%3Dtrue",
"24x24": "https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=24&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D24%26noRedirect%3Dtrue",
"16x16": "https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=16&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D16%26noRedirect%3Dtrue",
"32x32": "https://avatar-cdn.atlassian.com/d991bc281c0c0ecb0bbb2db3979ddaff?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fd991bc281c0c0ecb0bbb2db3979ddaff%3Fd%3Dmm%26s%3D32%26noRedirect%3Dtrue"
},
"displayName": "Test User",
"active": true,
"timeZone": "America/Los_Angeles"
},
"created": "2019-02-15T19:11:18.321-0800",
"updated": "2019-02-15T19:11:18.321-0800",
"jsdPublic": true
},
"issue": {
"id": "10040",
"self": "https://some-instance-test.atlassian.net/rest/api/2/issue/10040",
"key": "TES-41",
"fields": {
"summary": "Unit test summary 1",
"issuetype": {
"self": "https://some-instance-test.atlassian.net/rest/api/2/issuetype/10001",
"id": "10001",
"description": "Stories track functionality or features expressed as user goals.",
"iconUrl": "https://some-instance-test.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10315&avatarType=issuetype",
"name": "Story",
"subtask": false,
"avatarId": 10315
},
"project": {
"self": "https://some-instance-test.atlassian.net/rest/api/2/project/10000",
"id": "10000",
"key": "TES",
"name": "test1",
"projectTypeKey": "software",
"avatarUrls": {
"48x48": "https://some-instance-test.atlassian.net/secure/projectavatar?avatarId=10324",
"24x24": "https://some-instance-test.atlassian.net/secure/projectavatar?size=small&avatarId=10324",
"16x16": "https://some-instance-test.atlassian.net/secure/projectavatar?size=xsmall&avatarId=10324",
"32x32": "https://some-instance-test.atlassian.net/secure/projectavatar?size=medium&avatarId=10324"
}
},
"assignee": null,
"priority": {
"self": "https://some-instance-test.atlassian.net/rest/api/2/priority/2",
"iconUrl": "https://some-instance-test.atlassian.net/images/icons/priorities/high.svg",
"name": "High",
"id": "2"
},
"status": {
"self": "https://some-instance-test.atlassian.net/rest/api/2/status/10001",
"description": "",
"iconUrl": "https://some-instance-test.atlassian.net/",
"name": "To Do",
"id": "10001",
"statusCategory": {
"self": "https://some-instance-test.atlassian.net/rest/api/2/statuscategory/2",
"id": 2,
"key": "new",
"colorName": "blue-gray",
"name": "To Do"
}
}
}
}
}
Loading