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 support for DM subscriptions based on "watching" an issue in Jira… #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions server/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type SearchService interface {
type IssueService interface {
GetIssue(key string, options *jira.GetQueryOptions) (*jira.Issue, error)
CreateIssue(issue *jira.Issue) (*jira.Issue, error)
GetWatchers(issueKey string) (*[]jira.User, error)

AddAttachment(api plugin.API, issueKey, fileID string, maxSize utils.ByteSize) (mattermostName, jiraName, mime string, err error)
AddComment(issueKey string, comment *jira.Comment) (*jira.Comment, error)
Expand Down Expand Up @@ -195,6 +196,15 @@ func (client JiraClient) GetIssue(key string, options *jira.GetQueryOptions) (*j
return issue, nil
}

// GetWatchers returns an Issue watchers by issueKey.
func (client JiraClient) GetWatchers(issueKey string) (*[]jira.User, error) {
issue, resp, err := client.Jira.Issue.GetWatchers(issueKey)
if err != nil {
return nil, userFriendlyJiraError(resp, err)
}
return issue, nil
}

// GetTransitions returns transitions for an issue with issueKey.
func (client JiraClient) GetTransitions(issueKey string) ([]jira.Transition, error) {
transitions, resp, err := client.Jira.Issue.GetTransitions(issueKey)
Expand Down
2 changes: 2 additions & 0 deletions server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@ func executeSettings(p *Plugin, c *plugin.Context, header *model.CommandArgs, ar
return p.responsef(header, "Current settings:\n%s", conn.Settings.String())
case "notifications":
return p.settingsNotifications(header, instance.GetID(), user.MattermostUserID, conn, args)
case "watching":
return p.settingsWatching(header, instance.GetID(), user.MattermostUserID, conn, args)
default:
return p.responsef(header, "Unknown setting.")
}
Expand Down
39 changes: 39 additions & 0 deletions server/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,42 @@ func (p *Plugin) settingsNotifications(header *model.CommandArgs, instanceID, ma

return p.responsef(header, "Settings updated. Notifications %s.", notifications)
}

func (p *Plugin) settingsWatching(header *model.CommandArgs, instanceID, mattermostUserID types.ID, connection *Connection, args []string) *model.CommandResponse {
const helpText = "`/jira watching watching [value]`\n* Invalid value. Accepted values are: `on` or `off`."

if len(args) != 2 {
return p.responsef(header, helpText)
}

var value bool
switch args[1] {
case settingOn:
value = true
case settingOff:
value = false
default:
return p.responsef(header, helpText)
}

if connection.Settings == nil {
connection.Settings = &ConnectionSettings{}
}
connection.Settings.Watching = value
if err := p.userStore.StoreConnection(instanceID, mattermostUserID, connection); err != nil {
p.errorf("settingsWatching, err: %v", err)
p.responsef(header, "Could not store new settings. Please contact your system administrator. error: %v", err)
}

// send back the actual value
updatedConnection, err := p.userStore.LoadConnection(instanceID, mattermostUserID)
if err != nil {
return p.responsef(header, "Your username is not connected to Jira. Please type `jira connect`. %v", err)
}
watching := settingOff
if updatedConnection.Settings.Watching {
watching = settingOn
}

return p.responsef(header, "Settings updated. Watching %s.", watching)
}
1 change: 1 addition & 0 deletions server/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func (c *Connection) JiraAccountID() types.ID {

type ConnectionSettings struct {
Notifications bool `json:"notifications"`
Watching bool `json:"watching"`
}

func (s *ConnectionSettings) String() string {
Expand Down
78 changes: 78 additions & 0 deletions server/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main

import (
"fmt"
"github.com/andygrunwald/go-jira"
"net/http"
"net/url"

Expand Down Expand Up @@ -97,6 +98,81 @@ func (wh webhook) PostToChannel(p *Plugin, instanceID types.ID, channelID, fromU
return post, http.StatusOK, nil
}

func (wh *webhook) getConnection(p *Plugin, instance Instance, notification webhookUserNotification) (con *Connection, err error) {
var mattermostUserID types.ID

// prefer accountId to username when looking up UserIds
if notification.jiraAccountID != "" {
mattermostUserID, err = p.userStore.LoadMattermostUserID(instance.GetID(), notification.jiraAccountID)
} else {
mattermostUserID, err = p.userStore.LoadMattermostUserID(instance.GetID(), notification.jiraUsername)
}
if err != nil {
return
}

// Check if the user has permissions.
con, err = p.userStore.LoadConnection(instance.GetID(), mattermostUserID)
if err != nil {
// Not connected to Jira, so can't check permissions
return
}

return
}

func (wh *webhook) checkWatcherUser(p *Plugin, instance Instance) {
watcherUsers := &[]jira.User{}
for _, notification := range wh.notifications {
c, err := wh.getConnection(p, instance, notification)
if err != nil {
continue
}
client, err2 := instance.GetClient(c)
if err2 != nil {
continue
}
watcherUsers, err = client.GetWatchers(wh.Issue.ID)
if err != nil {
continue
}
}

for _, watcherUser := range *watcherUsers {
whUserNotification := &webhookUserNotification{}
postType := ""
message := ""
for _, notification := range wh.notifications {
if notification.jiraAccountID == watcherUser.AccountID || notification.jiraUsername == watcherUser.Name {
whUserNotification = &notification
}
postType = notification.postType
message = notification.message
}
if whUserNotification == nil {
whUserNotification = &webhookUserNotification{
jiraUsername: watcherUser.Name,
jiraAccountID: watcherUser.AccountID,
message: message,
postType: postType,
commentSelf: watcherUser.Self,
}

c, err := wh.getConnection(p, instance, *whUserNotification)
if err != nil {
continue
}

// if setting watching value is false don't put into webhookUserNotification
if c.Settings == nil || !c.Settings.Watching || err != nil {
continue
}

wh.notifications = append(wh.notifications, *whUserNotification)
}
}
}

func (wh *webhook) PostNotifications(p *Plugin, instanceID types.ID) ([]*model.Post, int, error) {
if len(wh.notifications) == 0 {
return nil, http.StatusOK, nil
Expand All @@ -109,6 +185,8 @@ func (wh *webhook) PostNotifications(p *Plugin, instanceID types.ID) ([]*model.P
return nil, http.StatusOK, nil
}

wh.checkWatcherUser(p, instance)

posts := []*model.Post{}
for _, notification := range wh.notifications {
var mattermostUserID types.ID
Expand Down