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-2481]:Fixed issue #613 on github #12

Merged
merged 4 commits into from
Dec 30, 2022
Merged
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
67 changes: 42 additions & 25 deletions server/plugin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ type PRDetails struct {
Reviews []*github.PullRequestReview `json:"reviews"`
}

type FilteredNotification struct {
github.Notification
HTMLURL string `json:"html_url"`
}

type SidebarContent struct {
Reviews []*github.Issue `json:"reviews"`
PRs []*github.Issue `json:"prs"`
Assignments []*github.Issue `json:"assignments"`
Unreads []*FilteredNotification `json:"unreads"`
}

type Context struct {
Ctx context.Context
UserID string
Expand Down Expand Up @@ -133,22 +145,19 @@ func (p *Plugin) initializeAPI() {

apiRouter.HandleFunc("/user", p.checkAuth(p.attachContext(p.getGitHubUser), ResponseTypeJSON)).Methods(http.MethodPost)
apiRouter.HandleFunc("/todo", p.checkAuth(p.attachUserContext(p.postToDo), ResponseTypeJSON)).Methods(http.MethodPost)
apiRouter.HandleFunc("/reviews", p.checkAuth(p.attachUserContext(p.getReviews), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/yourprs", p.checkAuth(p.attachUserContext(p.getYourPrs), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/prsdetails", p.checkAuth(p.attachUserContext(p.getPrsDetails), ResponseTypePlain)).Methods(http.MethodPost)
apiRouter.HandleFunc("/searchissues", p.checkAuth(p.attachUserContext(p.searchIssues), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/yourassignments", p.checkAuth(p.attachUserContext(p.getYourAssignments), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/createissue", p.checkAuth(p.attachUserContext(p.createIssue), ResponseTypePlain)).Methods(http.MethodPost)
apiRouter.HandleFunc("/createissuecomment", p.checkAuth(p.attachUserContext(p.createIssueComment), ResponseTypePlain)).Methods(http.MethodPost)
apiRouter.HandleFunc("/mentions", p.checkAuth(p.attachUserContext(p.getMentions), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/unreads", p.checkAuth(p.attachUserContext(p.getUnreads), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/labels", p.checkAuth(p.attachUserContext(p.getLabels), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/milestones", p.checkAuth(p.attachUserContext(p.getMilestones), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/assignees", p.checkAuth(p.attachUserContext(p.getAssignees), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/repositories", p.checkAuth(p.attachUserContext(p.getRepositories), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/settings", p.checkAuth(p.attachUserContext(p.updateSettings), ResponseTypePlain)).Methods(http.MethodPost)
apiRouter.HandleFunc("/issue", p.checkAuth(p.attachUserContext(p.getIssueByNumber), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/pr", p.checkAuth(p.attachUserContext(p.getPrByNumber), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/sidebar-content", p.checkAuth(p.attachUserContext(p.getSidebarContent), ResponseTypePlain)).Methods(http.MethodGet)

apiRouter.HandleFunc("/config", checkPluginRequest(p.getConfig)).Methods(http.MethodGet)
apiRouter.HandleFunc("/token", checkPluginRequest(p.getToken)).Methods(http.MethodGet)
Expand Down Expand Up @@ -658,22 +667,16 @@ func (p *Plugin) getMentions(c *UserContext, w http.ResponseWriter, r *http.Requ
p.writeJSON(w, result.Issues)
}

func (p *Plugin) getUnreads(c *UserContext, w http.ResponseWriter, r *http.Request) {
func (p *Plugin) getUnreadsData(c *UserContext) []*FilteredNotification {
githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo)

notifications, _, err := githubClient.Activity.ListNotifications(c.Ctx, &github.NotificationListOptions{})
if err != nil {
c.Log.WithError(err).Warnf("Failed to list notifications")
return
return nil
}

type filteredNotification struct {
github.Notification

HTMLUrl string `json:"html_url"`
}

filteredNotifications := []*filteredNotification{}
filteredNotifications := []*FilteredNotification{}
for _, n := range notifications {
if n.GetReason() == notificationReasonSubscribed {
continue
Expand All @@ -691,16 +694,16 @@ func (p *Plugin) getUnreads(c *UserContext, w http.ResponseWriter, r *http.Reque
subjectURL = n.GetSubject().GetLatestCommentURL()
}

filteredNotifications = append(filteredNotifications, &filteredNotification{
filteredNotifications = append(filteredNotifications, &FilteredNotification{
Notification: *n,
HTMLUrl: fixGithubNotificationSubjectURL(subjectURL, issueNum),
HTMLURL: fixGithubNotificationSubjectURL(subjectURL, issueNum),
})
}

p.writeJSON(w, filteredNotifications)
return filteredNotifications
}

func (p *Plugin) getReviews(c *UserContext, w http.ResponseWriter, r *http.Request) {
func (p *Plugin) getReviewsData(c *UserContext) []*github.Issue {
config := p.getConfiguration()

githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo)
Expand All @@ -710,13 +713,13 @@ func (p *Plugin) getReviews(c *UserContext, w http.ResponseWriter, r *http.Reque
result, _, err := githubClient.Search.Issues(c.Ctx, query, &github.SearchOptions{})
if err != nil {
c.Log.WithError(err).With(logger.LogContext{"query": query}).Warnf("Failed to search for review")
return
return nil
}

p.writeJSON(w, result.Issues)
return result.Issues
}

func (p *Plugin) getYourPrs(c *UserContext, w http.ResponseWriter, r *http.Request) {
func (p *Plugin) getYourPrsData(c *UserContext) []*github.Issue {
config := p.getConfiguration()

githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo)
Expand All @@ -726,10 +729,10 @@ func (p *Plugin) getYourPrs(c *UserContext, w http.ResponseWriter, r *http.Reque
result, _, err := githubClient.Search.Issues(c.Ctx, query, &github.SearchOptions{})
if err != nil {
c.Log.WithError(err).With(logger.LogContext{"query": query}).Warnf("Failed to search for PRs")
return
return nil
}

p.writeJSON(w, result.Issues)
return result.Issues
}

func (p *Plugin) getPrsDetails(c *UserContext, w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -974,7 +977,7 @@ func (p *Plugin) createIssueComment(c *UserContext, w http.ResponseWriter, r *ht
p.writeJSON(w, result)
}

func (p *Plugin) getYourAssignments(c *UserContext, w http.ResponseWriter, r *http.Request) {
func (p *Plugin) getYourAssignmentsData(c *UserContext) []*github.Issue {
config := p.getConfiguration()

githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo)
Expand All @@ -984,10 +987,24 @@ func (p *Plugin) getYourAssignments(c *UserContext, w http.ResponseWriter, r *ht
result, _, err := githubClient.Search.Issues(c.Ctx, query, &github.SearchOptions{})
if err != nil {
c.Log.WithError(err).With(logger.LogContext{"query": query}).Warnf("Failed to search for assignments")
return
return nil
}

p.writeJSON(w, result.Issues)
return result.Issues
}

func (p *Plugin) getSidebarData(c *UserContext) *SidebarContent {
return &SidebarContent{
Assignments: p.getYourAssignmentsData(c),
PRs: p.getYourPrsData(c),
Reviews: p.getReviewsData(c),
Unreads: p.getUnreadsData(c),
}
}

func (p *Plugin) getSidebarContent(c *UserContext, w http.ResponseWriter, r *http.Request) {
sidebarContent := p.getSidebarData(c)
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
p.writeJSON(w, sidebarContent)
}

func (p *Plugin) postToDo(c *UserContext, w http.ResponseWriter, r *http.Request) {
Expand Down
2 changes: 1 addition & 1 deletion server/plugin/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestPlugin_ServeHTTP(t *testing.T) {
httpTest: httpTestString,
request: testutils.Request{
Method: http.MethodGet,
URL: "/api/v1/reviews",
URL: "/api/v1/sidebar-content",
Body: nil,
},
expectedResponse: testutils.ExpectedResponse{
Expand Down
54 changes: 53 additions & 1 deletion server/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/google/go-github/v41/github"
"github.com/gorilla/mux"
pluginapi "github.com/mattermost/mattermost-plugin-api"
"github.com/mattermost/mattermost-plugin-api/experimental/bot/logger"
"github.com/mattermost/mattermost-plugin-api/experimental/bot/poster"
"github.com/mattermost/mattermost-plugin-api/experimental/telemetry"
"github.com/mattermost/mattermost-server/v6/model"
Expand Down Expand Up @@ -783,13 +784,64 @@ func (p *Plugin) isOrganizationLocked() bool {
}

func (p *Plugin) sendRefreshEvent(userID string) {
eventLogger := logger.New(p.API).With(logger.LogContext{
"userid": userID,
})

ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)

context := &Context{
Ctx: ctx,
UserID: userID,
Log: eventLogger,
}

defer cancel()

info, apiErr := p.getGitHubUserInfo(context.UserID)
if apiErr != nil {
p.API.LogWarn("Failed to get github user info", "error", apiErr.Error())
return
}

context.Log = context.Log.With(logger.LogContext{
"github username": info.GitHubUsername,
})

userContext := &UserContext{
Context: *context,
GHInfo: info,
}

sidebarContent := p.getSidebarData(userContext)

contentMap, err := convertContentToMap(sidebarContent)
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
p.API.LogWarn("Failed to convert sidebar content to map", "error", apiErr.Error())
return
}

p.API.PublishWebSocketEvent(
wsEventRefresh,
nil,
contentMap,
&model.WebsocketBroadcast{UserId: userID},
)
}

func convertContentToMap(sidebarContent *SidebarContent) (map[string]interface{}, error) {
var m map[string]interface{}
bytes, err := json.Marshal(&sidebarContent)
if err != nil {
return nil, err
}

if err = json.Unmarshal(bytes, &m); err != nil {
return nil, err
}

return m, nil
}

// getUsername returns the GitHub username for a given Mattermost user,
// if the user is connected to GitHub via this plugin.
// Otherwise it return the Mattermost username. It will be escaped via backticks.
Expand Down
5 changes: 1 addition & 4 deletions webapp/src/action_types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ import {id as pluginId} from '../manifest';

export default {
RECEIVED_REPOSITORIES: pluginId + '_received_repositories',
RECEIVED_REVIEWS: pluginId + '_received_reviews',
RECEIVED_REVIEWS_DETAILS: pluginId + '_received_reviews_details',
RECEIVED_YOUR_PRS: pluginId + '_received_your_prs',
RECEIVED_YOUR_PRS_DETAILS: pluginId + '_received_your_prs_details',
RECEIVED_YOUR_ASSIGNMENTS: pluginId + '_received_your_assignments',
RECEIVED_MENTIONS: pluginId + '_received_mentions',
RECEIVED_UNREADS: pluginId + '_received_unreads',
RECEIVED_CONNECTED: pluginId + '_received_connected',
RECEIVED_CONFIGURATION: pluginId + '_received_configuration',
RECEIVED_GITHUB_USER: pluginId + '_received_github_user',
Expand All @@ -23,4 +19,5 @@ export default {
CLOSE_ATTACH_COMMENT_TO_ISSUE_MODAL: pluginId + '_close_attach_modal',
OPEN_ATTACH_COMMENT_TO_ISSUE_MODAL: pluginId + '_open_attach_modal',
RECEIVED_ATTACH_COMMENT_RESULT: pluginId + '_received_attach_comment',
RECEIVED_SIDEBAR_CONTENT: pluginId + '_received_sidebar_content',
};
75 changes: 3 additions & 72 deletions webapp/src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,6 @@ function checkAndHandleNotConnected(data) {
};
}

export function getReviews() {
return async (dispatch, getState) => {
let data;
try {
data = await Client.getReviews();
} catch (error) {
return {error};
}

const connected = await checkAndHandleNotConnected(data)(dispatch, getState);
if (!connected) {
return {error: data};
}

dispatch({
type: ActionTypes.RECEIVED_REVIEWS,
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
data,
});

return {data};
};
}

export function getReviewsDetails(prList) {
return async (dispatch, getState) => {
let data;
Expand Down Expand Up @@ -111,11 +88,11 @@ export function getRepos() {
};
}

export function getYourPrs() {
export function getSidebarContent() {
return async (dispatch, getState) => {
let data;
try {
data = await Client.getYourPrs();
data = await Client.getSidebarContent();
} catch (error) {
return {error};
}
Expand All @@ -126,7 +103,7 @@ export function getYourPrs() {
}

dispatch({
type: ActionTypes.RECEIVED_YOUR_PRS,
type: ActionTypes.RECEIVED_SIDEBAR_CONTENT,
data,
});

Expand Down Expand Up @@ -211,29 +188,6 @@ export function getMilestoneOptions(repo) {
};
}

export function getYourAssignments() {
return async (dispatch, getState) => {
let data;
try {
data = await Client.getYourAssignments();
} catch (error) {
return {error};
}

const connected = await checkAndHandleNotConnected(data)(dispatch, getState);
if (!connected) {
return {error: data};
}

dispatch({
type: ActionTypes.RECEIVED_YOUR_ASSIGNMENTS,
data,
});

return {data};
};
}

export function getMentions() {
return async (dispatch, getState) => {
let data;
Expand All @@ -257,29 +211,6 @@ export function getMentions() {
};
}

export function getUnreads() {
return async (dispatch, getState) => {
let data;
try {
data = await Client.getUnreads();
} catch (error) {
return {error};
}

const connected = await checkAndHandleNotConnected(data)(dispatch, getState);
if (!connected) {
return {error: data};
}

dispatch({
type: ActionTypes.RECEIVED_UNREADS,
data,
});

return {data};
};
}

const GITHUB_USER_GET_TIMEOUT_MILLISECONDS = 1000 * 60 * 60; // 1 hour

export function getGitHubUser(userID) {
Expand Down
Loading