Skip to content

Commit

Permalink
1. create and delete WP feature 2. notification webhook handler
Browse files Browse the repository at this point in the history
  • Loading branch information
girish17 committed Sep 23, 2023
1 parent db2de67 commit bdae2cd
Show file tree
Hide file tree
Showing 12 changed files with 589 additions and 64 deletions.
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/girish17/op-mm-plugin
go 1.19

require (
github.com/gorilla/mux v1.8.0
github.com/mattermost/mattermost/server/public v0.0.9
github.com/pkg/errors v0.9.1
github.com/senseyeio/duration v0.0.0-20180430131211-7c2a214ada46
Expand All @@ -15,7 +16,7 @@ require (
github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.3.1 // indirect
Expand Down Expand Up @@ -50,8 +51,8 @@ require (
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.58.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
google.golang.org/grpc v1.58.2 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev
github.com/go-asn1-ber/asn1-ber v1.3.2-0.20191121212151-29be175fc3a3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
Expand Down Expand Up @@ -66,6 +68,8 @@ github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/graphql-go v1.5.1-0.20230110080634-edea822f558a h1:i0+Se9S+2zL5CBxJouqn2Ej6UQMwH1c57ZB6DVnqck4=
Expand Down Expand Up @@ -298,12 +302,16 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o=
google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
Expand Down
37 changes: 37 additions & 0 deletions server/AvailableAssignees.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package main

type AvailableAssignees struct {
Links Links `json:"_links"`
Type string `json:"_type"`
Total int64 `json:"total"`
Count int64 `json:"count"`
Embedded struct {
Elements []AvailableAssigneesElement `json:"elements"`
} `json:"_embedded"`
}

type AvailableAssigneesElement struct {
Links AvailableAssigneeLinks `json:"_links"`
Type string `json:"_type"`
ID int `json:"id"`
Avatar string `json:"avatar"`
Email string `json:"email"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Login string `json:"login"`
Status string `json:"status"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
}

type AvailableAssigneeLinks struct {
Delete Lock `json:"delete"`
Self Self `json:"self"`
Lock Lock `json:"lock"`
}

type Lock struct {
Href string `json:"href"`
Method string `json:"method"`
Title string `json:"title"`
}
43 changes: 43 additions & 0 deletions server/dialog.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,46 @@ func GetOpAuthDlg(pluginURL string, triggerID string, logoURL string) model.Open
},
}
}

func GetWPCreateDlg(pluginURL string, triggerID string, types []*model.PostActionOptions, assignees []*model.PostActionOptions) model.OpenDialogRequest {
return model.OpenDialogRequest{
TriggerId: triggerID,
URL: pluginURL + "/saveWP",
Dialog: model.Dialog{
CallbackId: "create_wp_dlg",
Title: "Create a work package",
IntroductionText: "Create a work package by providing following details",
IconURL: pluginURL + "/public/op_logo.jpg",
Elements: []model.DialogElement{{
DisplayName: "Subject",
Name: "subject",
Type: "text",
Placeholder: "Name of work package",
HelpText: "Please enter date within last one year and in YYYY-MM-DD format",
}, {
DisplayName: "Select Type",
Name: "type",
Type: "select",
Default: types[0].Value,
Placeholder: "Type to search for type",
Options: types,
}, {
DisplayName: "Assignee",
Name: "assignee",
Type: "select",
Placeholder: "Type to search for users",
Options: assignees,
Optional: true,
}, {
DisplayName: "Notify interested users?",
Name: "notify",
Type: "bool",
Placeholder: "Send email",
HelpText: "Note that this controls notifications for all users interested in changes to the work package (e.g. current user, watchers, author and assignee)",
Optional: true,
}},
SubmitLabel: "Create Work Package",
NotifyOnCancel: true,
},
}
}
16 changes: 9 additions & 7 deletions server/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,25 @@ func (p *Plugin) ServeHTTP(_ *plugin.Context, w http.ResponseWriter, r *http.Req
case "/opAuth":
OpAuth(p.MattermostPlugin, r, pluginURL)
case "/createTimeLog":
ShowSelProject(p.MattermostPlugin, r, pluginURL)
ShowSelProject(p.MattermostPlugin, r, pluginURL, "showSelWP")
case "/projSel":
WPHandler(p.MattermostPlugin, w, r, pluginURL)
WPHandler(p.MattermostPlugin, w, r)
case "/wpSel":
LoadTimeLogDlg(p.MattermostPlugin, w, r, pluginURL)
case "/logTime":
HandleSubmission(p.MattermostPlugin, w, r, pluginURL)
HandleSubmission(p.MattermostPlugin, w, r)
case "/getTimeLog":
GetTimeLog(p.MattermostPlugin, r)
case "/delTimeLog":
DeleteTimeLog(p.MattermostPlugin, w, r, pluginURL)
DeleteTimeLog(p.MattermostPlugin, w, r)
case "/createWP":
NotImplemented(w)
ShowSelProject(p.MattermostPlugin, r, pluginURL, "createWP")
case "/saveWP":
NotImplemented(w)
SaveWP(p.MattermostPlugin, r)
case "/delWP":
NotImplemented(w)
DeleteWorkPackage(p.MattermostPlugin, w, r)
case "/notifyChannel":
NotifyChannel(p.MattermostPlugin, w, r)
case "/bye":
Logout(p.MattermostPlugin, w, r)
default:
Expand Down
26 changes: 26 additions & 0 deletions server/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ var messages = struct {
TimeLogDelErrMsg string
InsufficientPrivMsg string
TimeEntryNotExist string
AssigneeFailMsg string
TypesFailMsg string
WPCreateForbiddenMsg string
WPTypeErrMsg string
GenericErrMsg string
SaveWPSuccessMsg string
WPNotExist string
WPLogDelMsg string
WPDelErrMsg string
WPLogSelMsg string
WPFetchFailMsg string
CnfWPLogMsg string
UnknownStatusCode string
}{
OpAuthFailMsg: "OpenProject authentication failed. Please try again.",
ProjectSelMsg: "*Please select a project*",
Expand All @@ -42,4 +55,17 @@ var messages = struct {
TimeLogDelErrMsg: "**That didn't work :pensive: Couldn't delete time log\n Please try again...`/op`**",
InsufficientPrivMsg: "**You don't have sufficient privileges to do that :pensive: **",
TimeEntryNotExist: "** Time entry does not exist or you don't have sufficient privileges to see it :pensive: **",
AssigneeFailMsg: "**That didn't work :pensive: Couldn't to fetch available assignees from OP**",
TypesFailMsg: "**That didn't work :pensive: Couldn't to fetch types from OP**",
WPCreateForbiddenMsg: "**It seems that you don't have permission to create work package for this project :confused: **",
WPTypeErrMsg: "**Work package type is not set to one of the allowed values. Couldn't create work package :pensive: **",
GenericErrMsg: "** Unknown error occurred :pensive: Can you please try again? **",
SaveWPSuccessMsg: "\n**Work package created! You are awesome :sunglasses: **\n To log time for a work package try `/op`",
WPNotExist: "**Work package does not exist or you don't have sufficient privileges to see it :pensive: **",
WPLogDelMsg: "\n**Work package deleted!**",
WPDelErrMsg: "**That didn't work :pensive: Couldn't delete work package\n Please try again... `/op`**",
WPLogSelMsg: "*Please select a work package*",
WPFetchFailMsg: "**That didn't work :pensive: Couldn't fetch work packages from OP**",
CnfWPLogMsg: "**Confirm work package deletion?**",
UnknownStatusCode: "**Unknown status code - error occurred** :pensive:",
}
70 changes: 68 additions & 2 deletions server/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@ func getWPOptAttachmentJSON(pluginURL string, action string, options []Option) [
return attachmentsJSON
}

func getWPOptJSON(pluginURL string, action string, options []Option) []byte {
attachments := OptAttachments{Attachments: []Attachment{
{
Actions: []Action{
{
Name: "Type to search for a work package...",
Integration: Integration{
URL: pluginURL + "/delWP",
Context: Context{
Action: action,
},
},
Type: "select",
Options: options,
},
{
Name: "Cancel search",
Integration: Integration{
URL: pluginURL + "/bye",
},
},
},
},
},
}
attachmentsJSON, _ := json.Marshal(attachments)
return attachmentsJSON
}

func getTimeLogOptJSON(pluginURL string, action string, options []Option) []byte {
attachments := OptAttachments{Attachments: []Attachment{
{
Expand Down Expand Up @@ -177,7 +206,7 @@ func getOptArrayForWPElements(elements []Element) []Option {
id := strconv.Itoa(element.ID)
options = append(options, Option{
Text: element.Subject,
Value: "opt" + id,
Value: element.Subject + "|:-" + id,
})
}
return options
Expand All @@ -197,7 +226,7 @@ func getOptArrayForTimeLogElements(elements []TimeElement) []Option {
text += element.Links.Project.Title
options = append(options, Option{
Text: text,
Value: text + "|" + id,
Value: text + "|:-" + id,
})
}
return options
Expand All @@ -215,6 +244,30 @@ func getOptArrayForAllowedValues(allowedValues []AllowedValues) []*model.PostAct
return postActionOptions
}

func getOptArrayForTypes(types []TypeElement) []*model.PostActionOptions {
var postActionOptions []*model.PostActionOptions
for _, value := range types {
id := strconv.Itoa(value.ID)
postActionOptions = append(postActionOptions, &model.PostActionOptions{
Text: value.Name,
Value: "opt" + id,
})
}
return postActionOptions
}

func getOptArrayForAvailableAssignees(assignees []AvailableAssigneesElement) []*model.PostActionOptions {
var postActionOptions []*model.PostActionOptions
for _, value := range assignees {
id := strconv.Itoa(value.ID)
postActionOptions = append(postActionOptions, &model.PostActionOptions{
Text: value.FirstName + " " + value.LastName,
Value: "opt" + id,
})
}
return postActionOptions
}

func GetAttachmentJSON(pluginURL string) string {
return `{
"attachments": [
Expand Down Expand Up @@ -296,6 +349,19 @@ func GetTimeEntriesBodyJSON(submission map[string]interface{}, loggedHours strin
return json.Marshal(timeEntriesBody)
}

func GetWPBodyJSON(submission map[string]interface{}) ([]byte, error) {
var workPackagePostBody WorkPackagePostBody
workPackagePostBody.Links.Project.Href = apiVersionStr + "projects/" + projectID
typeID = strings.Split(submission["type"].(string), "opt")[1]
workPackagePostBody.Links.Type.Href = apiVersionStr + "types/" + typeID
workPackagePostBody.Subject = submission["subject"].(string)
assigneeID = strings.Split(submission["assignee"].(string), "opt")[1]
if submission["assignee"] != nil {
workPackagePostBody.Assignee.Href = apiVersionStr + "users/" + assigneeID
}
return json.Marshal(workPackagePostBody)
}

func getUpdatePostMsg(userID string, channelID string, msg string) *model.Post {
var post = &model.Post{
Id: menuPost.Id,
Expand Down
9 changes: 9 additions & 0 deletions server/notification.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

type Notification struct {
Action string `json:"action"`
TimeEntry TimeEntries `json:"time_entry"`
Project Projects `json:"project"`
WorkPackage WorkPackages `json:"work_package"`
Attachment Attachment `json:"attachment"`
}
Loading

0 comments on commit bdae2cd

Please sign in to comment.