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

[MI-1993] Correct failing CI #13

Merged
merged 15 commits into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from 12 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
70 changes: 37 additions & 33 deletions server/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,75 +7,79 @@ const (
BotDescription = "A bot account created by the Azure Devops plugin."

// Plugin configs
PluginID = "mattermost-plugin-azure-devops"
// TODO: Change later according to the needs.
PluginID = "mattermost-plugin-azure-devops"
HeaderMattermostUserID = "Mattermost-User-ID"
ChannelID = "channel_id"
// TODO: Change later according to the needs.
HeaderMattermostUserIDAPI = "User-ID"
ChannelID = "channel_id"

// Command configs
CommandTriggerName = "azuredevops"
HelpText = "###### Mattermost Azure Devops Plugin - Slash Command Help\n"
InvalidCommand = "Invalid command parameters. Please use `/azuredevops help` for more information."

// Azure API Routes
// TODO: Remove later if not needed.
// TODO: WIP.
// GetProjects = "/%s/_apis/projects"
GetTasksID = "/%s/_apis/wit/wiql"
GetTasks = "/%s/_apis/wit/workitems"
CreateTask = "/%s/%s/_apis/wit/workitems/$%s"
// GetTasksID = "/%s/_apis/wit/wiql"
// GetTasks = "/%s/_apis/wit/workitems"
CreateTask = "/%s/%s/_apis/wit/workitems/$%s?api-version=7.1-preview.3"

// Azure API versions
// TODO: Remove later if not needed.
// TODO: WIP.
// ProjectAPIVersion = "7.1-preview.4"
TasksIDAPIVersion = "5.1"
TasksAPIVersion = "6.0"
CreateTaskAPIVersion = "7.1-preview.3"
// TasksIDAPIVersion = "5.1"
// TasksAPIVersion = "6.0"
// CreateTaskAPIVersion = "7.1-preview.3"

// Authorization constants
Bearer = "Bearer %s"
Authorization = "Authorization"

// Limits
// TODO: Remove later if not needed.
// TODO: WIP.
// ProjectLimit = 10
TaskLimit = 10
// TaskLimit = 10

// TODO: WIP.
// URL filters
Organization = "organization"
Project = "project"
Status = "status"
AssignedTo = "assigned_to"
Page = "page"
// Organization = "organization"
// Project = "project"
// Status = "status"
// AssignedTo = "assigned_to"
// Page = "page"

// TODO: WIP.
// Tasks status
Doing = "doing"
Todo = "to-do"
Done = "done"
// Doing = "doing"
// Todo = "to-do"
// Done = "done"

// Query params constants
PageQueryParam = "$top"
APIVersionQueryParam = "api-version"
IDsQueryParam = "ids"
// TODO: WIP.
// PageQueryParam = "$top"
// IDsQueryParam = "ids"

// Generic messages
// TODO: all these messages are to be verified from Mike at the end
ConnectAccount = "[Click here to link your Azure DevOps account](%s%s?channel_id=%s)"
ConnectAccountFirst = "You do not have any Azure Devops account connected, kindly link the account first"
UserConnected = "Your Azure Devops account is succesfully connected!"
UserConnected = "Your Azure Devops account is successfully connected!"
UserAlreadyConnected = "Your Azure Devops account is already connected"
UserDisconnected = "Your Azure Devops account is now disconnected"
CreatedTask = "Link for new created task: %s"
CreatedTask = "Link for newly created task: %s"

// Error messages
Error = "error"
GenericErrorMessage = "something went wrong, please try again later"
NotAuthorized = "not authorized"
InvalidPageNumber = "invalid page number"
Error = "error"
GenericErrorMessage = "something went wrong, please try again later"
NotAuthorized = "not authorized"
// TODO: WIP.
// InvalidPageNumber = "invalid page number"
// InvalidStatus = "invalid status"
// InvalidAssignedTo = "you can only see tasks assigned to yourself"
// NoResultPresent = "no results are present"
OrganizationRequired = "organization is required"
ProjectRequired = "project is required"
InvalidStatus = "invalid status"
InvalidAssignedTo = "you can only see tasks assigned to yourself"
NoResultPresent = "no results are present"
TaskTypeRequired = "task type is required"
TaskTitleRequired = "task title is required"
)
3 changes: 2 additions & 1 deletion server/constants/oAuth_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
BaseOauthURL = "https://app.vssps.visualstudio.com"

// Paths
PathAuth = "/oauth2/authorize"
PathAuth = "/oauth2/authorize"
// #nosec G101 -- This is a false positive
Copy link
Contributor

Choose a reason for hiding this comment

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

why added this

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 giving a lint error as it was considering it as a confidential information

PathToken = "/oauth2/token"
)
13 changes: 7 additions & 6 deletions server/constants/taskQuery.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package constants

const (
// TaskQuery
TaskQuery = "Select [System.Id] From WorkItems Where [System.TeamProject] = '%s'"
TaskQueryStatusFilter = " and [System.State] = '%s'"
TaskQueryAssignedToFilter = " and [System.AssignedTo] = @me"
)
// TODO: WIP.
// const (
// // TaskQuery
// TaskQuery = "Select [System.Id] From WorkItems Where [System.TeamProject] = '%s'"
// TaskQueryStatusFilter = " and [System.State] = '%s'"
// TaskQueryAssignedToFilter = " and [System.AssignedTo] = @me"
// )
162 changes: 75 additions & 87 deletions server/plugin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package plugin

import (
"encoding/json"
"fmt"
"net/http"
"path/filepath"
"runtime/debug"

"github.com/gorilla/mux"
"github.com/pkg/errors"

"github.com/Brightscout/mattermost-plugin-azure-devops/server/constants"
"github.com/Brightscout/mattermost-plugin-azure-devops/server/serializers"
Expand All @@ -31,18 +33,16 @@ func (p *Plugin) InitRoutes() {
// OAuth
s.HandleFunc(constants.PathOAuthConnect, p.OAuthConnect).Methods(http.MethodGet)
s.HandleFunc(constants.PathOAuthCallback, p.OAuthComplete).Methods(http.MethodGet)
// TODO: Remove later if not needed.
// TODO: WIP.
// s.HandleFunc("/projects", p.handleAuthRequired(p.handleGetProjects)).Methods(http.MethodGet)
s.HandleFunc("/tasks", p.handleAuthRequired(p.handleGetTasks)).Methods(http.MethodGet)
// s.HandleFunc("/tasks", p.handleAuthRequired(p.handleGetTasks)).Methods(http.MethodGet)
s.HandleFunc("/tasks", p.handleAuthRequired(p.handleCreateTask)).Methods(http.MethodPost)
// TODO: for testing purpose, remove later
s.HandleFunc("/test", p.testAPI).Methods(http.MethodGet)
}

// handleAuthRequired verifies if provided request is performed by an authorized source.
func (p *Plugin) handleAuthRequired(handleFunc func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
mattermostUserID := r.Header.Get(constants.HeaderMattermostUserID)
mattermostUserID := r.Header.Get(constants.HeaderMattermostUserIDAPI)
if mattermostUserID == "" {
error := serializers.Error{Code: http.StatusUnauthorized, Message: constants.NotAuthorized}
p.handleError(w, r, &error)
Expand All @@ -63,7 +63,7 @@ func (p *Plugin) handleError(w http.ResponseWriter, r *http.Request, error *seri
}
}

// TODO: Remove later if not needed.
// TODO: WIP.
// API to get projects in an organization.
// func (p *Plugin) handleGetProjects(w http.ResponseWriter, r *http.Request) {
// mattermostUserID := r.Header.Get(constants.HeaderMattermostUserID)
Expand Down Expand Up @@ -110,75 +110,75 @@ func (p *Plugin) handleError(w http.ResponseWriter, r *http.Request, error *seri
// }

// API to get tasks of a projects in an organization.
func (p *Plugin) handleGetTasks(w http.ResponseWriter, r *http.Request) {
mattermostUserID := r.Header.Get(constants.HeaderMattermostUserID)
statusData := map[string]string{
constants.Doing: "doing",
constants.Todo: "To Do",
constants.Done: "done",
}
organization := r.URL.Query().Get(constants.Organization)
if organization == "" {
error := serializers.Error{Code: http.StatusBadRequest, Message: constants.OrganizationRequired}
p.handleError(w, r, &error)
return
}
project := r.URL.Query().Get(constants.Project)
if project == "" {
error := serializers.Error{Code: http.StatusBadRequest, Message: constants.ProjectRequired}
p.handleError(w, r, &error)
return
}
status := r.URL.Query().Get(constants.Status)
if status != "" && statusData[status] == "" {
error := serializers.Error{Code: http.StatusBadRequest, Message: constants.InvalidStatus}
p.handleError(w, r, &error)
return
}
assignedTo := r.URL.Query().Get(constants.AssignedTo)
if assignedTo != "" && assignedTo != "me" {
error := serializers.Error{Code: http.StatusBadRequest, Message: constants.InvalidAssignedTo}
p.handleError(w, r, &error)
return
}
page := StringToInt(r.URL.Query().Get(constants.Page))
if page <= 0 {
error := serializers.Error{Code: http.StatusBadRequest, Message: constants.InvalidPageNumber}
p.handleError(w, r, &error)
return
}
// func (p *Plugin) handleGetTasks(w http.ResponseWriter, r *http.Request) {
// mattermostUserID := r.Header.Get(constants.HeaderMattermostUserID)
// statusData := map[string]string{
// constants.Doing: "doing",
// constants.Todo: "To Do",
// constants.Done: "done",
// }
// organization := r.URL.Query().Get(constants.Organization)
// if organization == "" {
// error := serializers.Error{Code: http.StatusBadRequest, Message: constants.OrganizationRequired}
// p.handleError(w, r, &error)
// return
// }
// project := r.URL.Query().Get(constants.Project)
// if project == "" {
// error := serializers.Error{Code: http.StatusBadRequest, Message: constants.ProjectRequired}
// p.handleError(w, r, &error)
// return
// }
// status := r.URL.Query().Get(constants.Status)
// if status != "" && statusData[status] == "" {
// error := serializers.Error{Code: http.StatusBadRequest, Message: constants.InvalidStatus}
// p.handleError(w, r, &error)
// return
// }
// assignedTo := r.URL.Query().Get(constants.AssignedTo)
// if assignedTo != "" && assignedTo != "me" {
// error := serializers.Error{Code: http.StatusBadRequest, Message: constants.InvalidAssignedTo}
// p.handleError(w, r, &error)
// return
// }
// page := StringToInt(r.URL.Query().Get(constants.Page))
// if page <= 0 {
// error := serializers.Error{Code: http.StatusBadRequest, Message: constants.InvalidPageNumber}
// p.handleError(w, r, &error)
// return
// }

// Wrap all query params.
queryParams := map[string]interface{}{
constants.Organization: organization,
constants.Project: project,
constants.Status: statusData[status],
constants.AssignedTo: assignedTo,
constants.Page: page,
}
// // Wrap all query params.
// queryParams := map[string]interface{}{
// constants.Organization: organization,
// constants.Project: project,
// constants.Status: statusData[status],
// constants.AssignedTo: assignedTo,
// constants.Page: page,
// }

tasks, err := p.Client.GetTaskList(queryParams, mattermostUserID)
if err != nil {
error := serializers.Error{Code: http.StatusInternalServerError, Message: err.Error()}
p.handleError(w, r, &error)
return
}
// tasks, err := p.Client.GetTaskList(queryParams, mattermostUserID)
// if err != nil {
// error := serializers.Error{Code: http.StatusInternalServerError, Message: err.Error()}
// p.handleError(w, r, &error)
// return
// }

response, err := json.Marshal(tasks)
if err != nil {
error := serializers.Error{Code: http.StatusInternalServerError, Message: err.Error()}
p.handleError(w, r, &error)
return
}
w.Header().Add("Content-Type", "application/json")
if _, err := w.Write(response); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// response, err := json.Marshal(tasks)
// if err != nil {
// error := serializers.Error{Code: http.StatusInternalServerError, Message: err.Error()}
// p.handleError(w, r, &error)
// return
// }
// w.Header().Add("Content-Type", "application/json")
// if _, err := w.Write(response); err != nil {
// http.Error(w, err.Error(), http.StatusInternalServerError)
// }
// }

// API to create task of a project in an organization.
func (p *Plugin) handleCreateTask(w http.ResponseWriter, r *http.Request) {
mattermostUserID := r.Header.Get(constants.HeaderMattermostUserID)
mattermostUserID := r.Header.Get(constants.HeaderMattermostUserIDAPI)
var body *serializers.TaskCreateRequestPayload
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&body); err != nil {
Expand Down Expand Up @@ -208,13 +208,15 @@ func (p *Plugin) handleCreateTask(w http.ResponseWriter, r *http.Request) {
}
w.WriteHeader(http.StatusOK)
w.Header().Add("Content-Type", "application/json")
if _, err := w.Write(response); err != nil {
if _, err = w.Write(response); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}

// channelID := "e4zyegem4pnb3mrsihtxdrpwba"
// message := fmt.Sprintf(constants.CreatedTask, task.Link.Html.Href)
// p.createPost(channelID, message)
message := fmt.Sprintf(constants.CreatedTask, task.Link.HTML.Href)

// Send message to DM.
_, err = p.DM(mattermostUserID, message)
_ = errors.Wrap(err, "failed to DM the created Task")
avas27JTG marked this conversation as resolved.
Show resolved Hide resolved
}

func (p *Plugin) WithRecovery(next http.Handler) http.Handler {
Expand All @@ -232,20 +234,6 @@ func (p *Plugin) WithRecovery(next http.Handler) http.Handler {
})
}

// TODO: for testing purpose, remove later
func (p *Plugin) testAPI(w http.ResponseWriter, r *http.Request) {
// TODO: remove later
response, err := p.Client.TestApi()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
res, _ := json.Marshal(response)
w.Header().Add("Content-Type", "application/json")
w.Write(res)
}

// Handles the static files under the assets directory.
func (p *Plugin) HandleStaticFiles() {
bundlePath, err := p.API.GetBundlePath()
Expand Down
Loading