From 88cfc1aa307255eccbb0a30c7f9c03ce33101859 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Sun, 17 Jul 2022 03:33:01 +0530 Subject: [PATCH 1/8] Upate Helper Message --- github/lib/helperMessage.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/github/lib/helperMessage.ts b/github/lib/helperMessage.ts index d3b403a..078e0a3 100644 --- a/github/lib/helperMessage.ts +++ b/github/lib/helperMessage.ts @@ -29,9 +29,10 @@ export async function helperMessage({ 5) Get Recent Pull Request of a Repository -> /github Username/RepositoryName pulls 6) Review a Pull Request -> /github Username/RepositoryName pulls pullNumber 7) Login to GitHub -> /github login - 8) View/Add/Delete/Update Repository Subscriptions -> /github subscribe - 9) Subscribe to all repository events -> /github Username/RepositoryName subscribe - 10) Unsubscribe to all repository events -> /github Username/RepositoryName unsubscribe + 8) Logout from GitHub -> /github logout + 9) View/Add/Delete/Update Repository Subscriptions -> /github subscribe + 10) Subscribe to all repository events -> /github Username/RepositoryName subscribe + 11) Unsubscribe to all repository events -> /github Username/RepositoryName unsubscribe `; From a9f98c99fa5dfb573978a7962745e02d57ab7979 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Sun, 17 Jul 2022 02:05:19 +0530 Subject: [PATCH 2/8] Creaet new Issue modal --- github/commands/GithubCommand.ts | 3 + github/enum/Modals.ts | 3 + github/enum/Subcommands.ts | 3 +- github/modals/newIssueModal.ts | 161 +++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 github/modals/newIssueModal.ts diff --git a/github/commands/GithubCommand.ts b/github/commands/GithubCommand.ts index cf3c242..45ec916 100644 --- a/github/commands/GithubCommand.ts +++ b/github/commands/GithubCommand.ts @@ -100,6 +100,9 @@ export class GithubCommand implements ISlashCommand { } break; } + case SubcommandEnum.NEW_ISSUE :{ + + } default:{ await helperMessage({room,read, persistence, modify, http}); break; diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index f7e9184..1137fbf 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -40,4 +40,7 @@ export enum ModalsEnum { ADD_SUBSCRIPTION_EVENT_INPUT='add-repo-subscription-events', SUBSCRIPTION_REFRESH_LABEL="Refresh", SUBSCRIPTION_REFRESH_ACTION="subscription-refresh", + NEW_ISSUE_VIEW="new-issue-view", + NEW_ISSUE_TITLE = 'New GitHub Issue', + } \ No newline at end of file diff --git a/github/enum/Subcommands.ts b/github/enum/Subcommands.ts index 5311664..5dc0efa 100644 --- a/github/enum/Subcommands.ts +++ b/github/enum/Subcommands.ts @@ -4,5 +4,6 @@ export enum SubcommandEnum { HELP = 'help', SUBSCRIBE = 'subscribe', UNSUBSCRIBE = 'unsubscribe', - TEST = 'test' + TEST = 'test', + NEW_ISSUE = 'new-issue' } \ No newline at end of file diff --git a/github/modals/newIssueModal.ts b/github/modals/newIssueModal.ts new file mode 100644 index 0000000..3c94779 --- /dev/null +++ b/github/modals/newIssueModal.ts @@ -0,0 +1,161 @@ +import { + IHttp, + IModify, + IPersistence, + IRead, +} from "@rocket.chat/apps-engine/definition/accessors"; +import { TextObjectType } from "@rocket.chat/apps-engine/definition/uikit/blocks"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { IUser } from "@rocket.chat/apps-engine/definition/users"; +import { ModalsEnum } from "../enum/Modals"; +import { AppEnum } from "../enum/App"; +// import { getRoomTasks, getUIData, persistUIData } from '../lib/persistence'; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { + UIKitBlockInteractionContext, + UIKitInteractionContext, +} from "@rocket.chat/apps-engine/definition/uikit"; +import { + storeInteractionRoomData, + getInteractionRoomData, +} from "../persistance/roomInteraction"; +import { Subscription } from "../persistance/subscriptions"; +import { ISubscription } from "../definitions/subscription"; + +export async function NewIssueModal({ + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext, +}: { + modify: IModify; + read: IRead; + persistence: IPersistence; + http: IHttp; + slashcommandcontext?: SlashCommandContext; + uikitcontext?: UIKitInteractionContext; +}): Promise { + const viewId = ModalsEnum.NEW_ISSUE_VIEW; + const block = modify.getCreator().getBlockBuilder(); + const room = slashcommandcontext?.getRoom() || uikitcontext?.getInteractionData().room; + const user = slashcommandcontext?.getSender() || uikitcontext?.getInteractionData().user; + + if (user?.id) { + let roomId; + + if (room?.id) { + roomId = room.id; + await storeInteractionRoomData(persistence, user.id, roomId); + } else { + roomId = ( + await getInteractionRoomData( + read.getPersistenceReader(), + user.id + ) + ).roomId; + } + + + + // shows indentations in input blocks but not inn section block + block.addInputBlock({ + blockId: ModalsEnum.REPO_NAME_INPUT, + label: { + text: ModalsEnum.REPO_NAME_LABEL, + type: TextObjectType.PLAINTEXT, + }, + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.REPO_NAME_INPUT_ACTION, + placeholder: { + text: ModalsEnum.REPO_NAME_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, + }, + }), + }); + + let newMultiStaticElemnt = block.newMultiStaticElement({ + actionId: ModalsEnum.ADD_SUBSCRIPTION_EVENT_OPTIONS, + options: [ + { + value: "issues", + text: { + type: TextObjectType.PLAINTEXT, + text: "New Issues", + emoji: true, + }, + }, + { + value: "pull_request", + text: { + type: TextObjectType.PLAINTEXT, + text: "New Pull Request", + emoji: true, + }, + }, + { + value: "push", + text: { + type: TextObjectType.PLAINTEXT, + text: "New Commits", + emoji: true, + }, + }, + { + value: "deployment_status", + text: { + type: TextObjectType.PLAINTEXT, + text: "Deployment", + emoji: true, + }, + }, + { + value: "star", + text: { + type: TextObjectType.PLAINTEXT, + text: "New Stars", + emoji: true, + }, + }, + ], + placeholder: { + type: TextObjectType.PLAINTEXT, + text: "Select Events", + }, + }); + + block.addInputBlock({ + label: { + text: ModalsEnum.ADD_SUBSCRIPTION_EVENT_LABEL, + type: TextObjectType.PLAINTEXT, + }, + element: newMultiStaticElemnt, + blockId: ModalsEnum.ADD_SUBSCRIPTION_EVENT_INPUT, + }); + } + + block.addDividerBlock(); + + return { + id: viewId, + title: { + type: TextObjectType.PLAINTEXT, + text: ModalsEnum.ADD_SUBSCIPTIONS_TITLE, + }, + close: block.newButtonElement({ + text: { + type: TextObjectType.PLAINTEXT, + text: "Close", + }, + }), + submit: block.newButtonElement({ + actionId: ModalsEnum.ADD_SUBSCRIPTION_ACTION, + text: { + type: TextObjectType.PLAINTEXT, + text: "Subscribe", + }, + }), + blocks: block.getBlocks(), + }; +} From e867069e79e400a8b2df2c889bb7258022f96200 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Sun, 17 Jul 2022 04:40:07 +0530 Subject: [PATCH 3/8] Add GitHub New Issues Modal --- github/commands/GithubCommand.ts | 15 ++- github/enum/Modals.ts | 20 +++- github/handlers/ExecuteViewClosedHandler.ts | 1 + github/modals/newIssueModal.ts | 107 ++++++++++---------- 4 files changed, 85 insertions(+), 58 deletions(-) diff --git a/github/commands/GithubCommand.ts b/github/commands/GithubCommand.ts index 45ec916..f61d5fe 100644 --- a/github/commands/GithubCommand.ts +++ b/github/commands/GithubCommand.ts @@ -26,6 +26,7 @@ import { createSubscription, deleteSubscription, updateSubscription } from "../h import { Subscription } from "../persistance/subscriptions"; import { ISubscription } from "../definitions/subscription"; import { subsciptionsModal } from "../modals/subscriptionsModal"; +import { NewIssueModal } from "../modals/newIssueModal"; export class GithubCommand implements ISlashCommand { @@ -101,7 +102,19 @@ export class GithubCommand implements ISlashCommand { break; } case SubcommandEnum.NEW_ISSUE :{ - + let accessToken = await getAccessTokenForUser(read,context.getSender(),this.app.oauth2Config); + if(accessToken && accessToken.token){ + const triggerId= context.getTriggerId(); + if(triggerId){ + const modal = await NewIssueModal({modify,read,persistence,http,slashcommandcontext:context}); + await modify.getUiController().openModalView(modal,{triggerId},context.getSender()); + }else{ + console.log("Inavlid Trigger ID !"); + } + }else{ + await sendNotification(read,modify,context.getSender(),room,"Login to subscribe to repository events ! `/github login`"); + } + break; } default:{ await helperMessage({room,read, persistence, modify, http}); diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index 1137fbf..885c337 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -41,6 +41,22 @@ export enum ModalsEnum { SUBSCRIPTION_REFRESH_LABEL="Refresh", SUBSCRIPTION_REFRESH_ACTION="subscription-refresh", NEW_ISSUE_VIEW="new-issue-view", - NEW_ISSUE_TITLE = 'New GitHub Issue', - + NEW_ISSUE_TITLE = 'New GitHub Issue', + NEW_ISSUE_ACTION = "new-issue-action", + ISSUE_TITLE_INPUT = "new-issue-title-input", + ISSUE_TITLE_LABEL = "New Issue Title", + ISSUE_TITLE_ACTION = "new-issue-title-action", + ISSUE_TITLE_PLACEHOLDER = "[Bug/Feature] Issue Title", + ISSUE_BODY_INPUT = "issue-body-input", + ISSUE_BODY_INPUT_LABEL = "New Issue Text", + ISSUE_BODY_INPUT_ACTION = "new-issue-body-action", + ISSUE_BODY_INPUT_PLACEHOLDER = "Leave a comment", + ISSUE_LABELS_INPUT = "issue-labels-input", + ISSUE_LABELS_INPUT_LABEL = "Add Issue Labels", + ISSUE_LABELS_INPUT_ACTION = "issue-labels-input-action", + ISSUE_LABELS_INPUT_PLACEHOLDER = "ui/ux bug feature-request", + ISSUE_ASSIGNEES_INPUT = "issue-assignees-input", + ISSUE_ASSIGNEES_INPUT_LABEL = "Add Assignees", + ISSUE_ASSIGNEES_INPUT_ACTION = "issue-assignee-input-action", + ISSUE_ASSIGNEES_INPUT_PLACEHOLDER = "samad-yar-khan RonLek Sing-Li" } \ No newline at end of file diff --git a/github/handlers/ExecuteViewClosedHandler.ts b/github/handlers/ExecuteViewClosedHandler.ts index 07a58f2..a70f023 100644 --- a/github/handlers/ExecuteViewClosedHandler.ts +++ b/github/handlers/ExecuteViewClosedHandler.ts @@ -24,6 +24,7 @@ export class ExecuteViewClosedHandler { case ModalsEnum.PULL_VIEW || ModalsEnum.CODE_VIEW || ModalsEnum.ADD_SUBSCRIPTION_VIEW || + ModalsEnum.NEW_ISSUE_VIEW || ModalsEnum.SUBSCRIPTION_VIEW: const modal = await pullDetailsModal({ modify: this.modify, diff --git a/github/modals/newIssueModal.ts b/github/modals/newIssueModal.ts index 3c94779..a1666d5 100644 --- a/github/modals/newIssueModal.ts +++ b/github/modals/newIssueModal.ts @@ -9,7 +9,6 @@ import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/ import { IUser } from "@rocket.chat/apps-engine/definition/users"; import { ModalsEnum } from "../enum/Modals"; import { AppEnum } from "../enum/App"; -// import { getRoomTasks, getUIData, persistUIData } from '../lib/persistence'; import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; import { UIKitBlockInteractionContext, @@ -19,8 +18,6 @@ import { storeInteractionRoomData, getInteractionRoomData, } from "../persistance/roomInteraction"; -import { Subscription } from "../persistance/subscriptions"; -import { ISubscription } from "../definitions/subscription"; export async function NewIssueModal({ modify, @@ -57,8 +54,6 @@ export async function NewIssueModal({ ).roomId; } - - // shows indentations in input blocks but not inn section block block.addInputBlock({ blockId: ModalsEnum.REPO_NAME_INPUT, @@ -75,63 +70,65 @@ export async function NewIssueModal({ }), }); - let newMultiStaticElemnt = block.newMultiStaticElement({ - actionId: ModalsEnum.ADD_SUBSCRIPTION_EVENT_OPTIONS, - options: [ - { - value: "issues", - text: { - type: TextObjectType.PLAINTEXT, - text: "New Issues", - emoji: true, - }, - }, - { - value: "pull_request", - text: { - type: TextObjectType.PLAINTEXT, - text: "New Pull Request", - emoji: true, - }, - }, - { - value: "push", - text: { - type: TextObjectType.PLAINTEXT, - text: "New Commits", - emoji: true, - }, - }, - { - value: "deployment_status", - text: { - type: TextObjectType.PLAINTEXT, - text: "Deployment", - emoji: true, - }, + block.addInputBlock({ + blockId: ModalsEnum.ISSUE_TITLE_INPUT, + label: { + text: ModalsEnum.ISSUE_TITLE_LABEL, + type: TextObjectType.PLAINTEXT, + }, + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.ISSUE_TITLE_ACTION, + placeholder: { + text: ModalsEnum.ISSUE_TITLE_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, }, - { - value: "star", - text: { - type: TextObjectType.PLAINTEXT, - text: "New Stars", - emoji: true, - }, + }), + }); + + block.addInputBlock({ + blockId: ModalsEnum.ISSUE_BODY_INPUT, + label: { + text: ModalsEnum.ISSUE_BODY_INPUT_LABEL, + type: TextObjectType.PLAINTEXT, + }, + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.ISSUE_BODY_INPUT_ACTION, + placeholder: { + text: ModalsEnum.ISSUE_BODY_INPUT_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, }, - ], - placeholder: { + multiline: true + }), + }); + + block.addInputBlock({ + blockId: ModalsEnum.ISSUE_LABELS_INPUT, + label: { + text: ModalsEnum.ISSUE_LABELS_INPUT_LABEL, type: TextObjectType.PLAINTEXT, - text: "Select Events", }, + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.ISSUE_LABELS_INPUT_ACTION, + placeholder: { + text: ModalsEnum.ISSUE_LABELS_INPUT_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, + }, + }), }); block.addInputBlock({ + blockId: ModalsEnum.ISSUE_ASSIGNEES_INPUT, label: { - text: ModalsEnum.ADD_SUBSCRIPTION_EVENT_LABEL, + text: ModalsEnum.ISSUE_ASSIGNEES_INPUT_LABEL, type: TextObjectType.PLAINTEXT, }, - element: newMultiStaticElemnt, - blockId: ModalsEnum.ADD_SUBSCRIPTION_EVENT_INPUT, + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.ISSUE_ASSIGNEES_INPUT_ACTION, + placeholder: { + text: ModalsEnum.ISSUE_ASSIGNEES_INPUT_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, + }, + }), }); } @@ -141,7 +138,7 @@ export async function NewIssueModal({ id: viewId, title: { type: TextObjectType.PLAINTEXT, - text: ModalsEnum.ADD_SUBSCIPTIONS_TITLE, + text: ModalsEnum.NEW_ISSUE_TITLE, }, close: block.newButtonElement({ text: { @@ -150,10 +147,10 @@ export async function NewIssueModal({ }, }), submit: block.newButtonElement({ - actionId: ModalsEnum.ADD_SUBSCRIPTION_ACTION, + actionId: ModalsEnum.NEW_ISSUE_ACTION, text: { type: TextObjectType.PLAINTEXT, - text: "Subscribe", + text: "Create Issue", }, }), blocks: block.getBlocks(), From dae395fcbd6fcb1a55728a38f63b6c95a9ac3ed7 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Sun, 17 Jul 2022 06:13:05 +0530 Subject: [PATCH 4/8] Add github issue logic --- github/handlers/ExecuteViewSubmitHandler.ts | 35 ++++++++++++++++++++- github/helpers/githubSDK.ts | 17 ++++++++++ github/lib/issuesListMessage.ts | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/github/handlers/ExecuteViewSubmitHandler.ts b/github/handlers/ExecuteViewSubmitHandler.ts index 1e99dd7..20d9cb5 100644 --- a/github/handlers/ExecuteViewSubmitHandler.ts +++ b/github/handlers/ExecuteViewSubmitHandler.ts @@ -7,7 +7,7 @@ import { getInteractionRoomData } from '../persistance/roomInteraction'; import { Subscription } from '../persistance/subscriptions'; import { GithubApp } from '../GithubApp'; import { getWebhookUrl } from '../helpers/getWebhookURL'; -import { addSubscribedEvents, createSubscription, updateSubscription } from '../helpers/githubSDK'; +import { addSubscribedEvents, createSubscription, updateSubscription, createNewIssue } from '../helpers/githubSDK'; import { getAccessTokenForUser } from '../persistance/auth'; import { subsciptionsModal } from '../modals/subscriptionsModal'; @@ -101,6 +101,39 @@ export class ExecuteViewSubmitHandler { } } break; + case ModalsEnum.NEW_ISSUE_VIEW: { + const { roomId } = await getInteractionRoomData(this.read.getPersistenceReader(), user.id); + if (roomId) { + let room = await this.read.getRoomReader().getById(roomId) as IRoom; + let repository = view.state?.[ModalsEnum.REPO_NAME_INPUT]?.[ModalsEnum.REPO_NAME_INPUT_ACTION] as string; + let title = view.state?.[ModalsEnum.ISSUE_TITLE_INPUT]?.[ModalsEnum.ISSUE_TITLE_ACTION] as string; + let issueBody = view.state?.[ModalsEnum.ISSUE_BODY_INPUT]?.[ModalsEnum.ISSUE_BODY_INPUT_ACTION]; + let issueLabels = view.state?.[ModalsEnum.ISSUE_LABELS_INPUT]?.[ModalsEnum.ISSUE_LABELS_INPUT_ACTION] as string; + issueLabels = issueLabels.trim(); + let issueAssignees = view.state?.[ModalsEnum.ISSUE_ASSIGNEES_INPUT]?.[ModalsEnum.ISSUE_ASSIGNEES_INPUT_ACTION] as string; + repository = repository.trim(); + title = title.trim(); + issueAssignees = issueAssignees.trim(); + let issueLabelsArray:Array = issueLabels.split(" "); + let issueAssigneesArray:Array = issueAssignees.split(" "); + if(title && title?.length){ + let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config); + if (!accessToken) { + await sendNotification(this.read, this.modify, user, room, "Login To Github !"); + } else { + let reponse = await createNewIssue(this.http,repository,title,issueBody,issueLabelsArray,issueAssigneesArray,accessToken?.token) + if(reponse && reponse?.id){ + await sendNotification(this.read,this.modify,user,room,`Created New Issue | [#${reponse.number} ](${reponse.html_url}) *[${reponse.title}](${reponse.html_url})*`) + }else{ + await sendNotification(this.read,this.modify,user,room,`Invalid Issue !`); + } + } + }else{ + await sendNotification(this.read,this.modify,user,room,`Invalid Issue !`); + } + } + break; + } default: break; } diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index be4513d..c91ebbc 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -153,3 +153,20 @@ export async function removeSubscribedEvents( } ); } + +export async function createNewIssue( + http: IHttp, + repoName: string, + issueTitle: string, + issueBody: string, + issueLabels: Array, + issueAssignees : Array, + access_token: string, +) { + return postReqeust(http, access_token, BaseApiHost + repoName + "/issues", { + title: issueTitle, + body: issueBody, + assignees: issueAssignees, + labels: issueLabels + }); +} \ No newline at end of file diff --git a/github/lib/issuesListMessage.ts b/github/lib/issuesListMessage.ts index 43ddf97..a113695 100644 --- a/github/lib/issuesListMessage.ts +++ b/github/lib/issuesListMessage.ts @@ -48,7 +48,7 @@ export async function issueListMessage({ .getCreator() .startMessage() .setText( - `[ #${issue.number} ](${issue.html_url}) *${issue.title}*` + `[ #${issue.number} ](${issue.html_url}) *[${issue.title}](${issue.html_url})*` ); if (room) { textSender.setRoom(room); From 5454148da886f6ba5122bba7a1599ef8238e28d3 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Sun, 17 Jul 2022 15:37:38 +0530 Subject: [PATCH 5/8] Add Repository name check --- github/handlers/ExecuteViewSubmitHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/handlers/ExecuteViewSubmitHandler.ts b/github/handlers/ExecuteViewSubmitHandler.ts index 20d9cb5..78e883e 100644 --- a/github/handlers/ExecuteViewSubmitHandler.ts +++ b/github/handlers/ExecuteViewSubmitHandler.ts @@ -116,7 +116,7 @@ export class ExecuteViewSubmitHandler { issueAssignees = issueAssignees.trim(); let issueLabelsArray:Array = issueLabels.split(" "); let issueAssigneesArray:Array = issueAssignees.split(" "); - if(title && title?.length){ + if(repository && repository?.length && title && title?.length){ let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config); if (!accessToken) { await sendNotification(this.read, this.modify, user, room, "Login To Github !"); From 7b9985a2ca399f47dca79a8b7d72445a774d02dc Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Mon, 18 Jul 2022 05:39:48 +0530 Subject: [PATCH 6/8] UPdate helper message --- github/lib/helperMessage.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/github/lib/helperMessage.ts b/github/lib/helperMessage.ts index 078e0a3..6cb3e26 100644 --- a/github/lib/helperMessage.ts +++ b/github/lib/helperMessage.ts @@ -33,6 +33,7 @@ export async function helperMessage({ 9) View/Add/Delete/Update Repository Subscriptions -> /github subscribe 10) Subscribe to all repository events -> /github Username/RepositoryName subscribe 11) Unsubscribe to all repository events -> /github Username/RepositoryName unsubscribe + 12) Add New Issues to GitHub Repository -> /github new-issue `; From 873d51e30ddeb7de72ed11286355645092c4ca13 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Sat, 23 Jul 2022 00:06:47 +0530 Subject: [PATCH 7/8] Change Slash Command, Add Issue Templates --- github/commands/GithubCommand.ts | 8 +- github/enum/Modals.ts | 8 +- github/enum/Subcommands.ts | 2 +- github/handlers/ExecuteBlockActionHandler.ts | 59 +++++++++- github/handlers/ExecuteViewSubmitHandler.ts | 36 +++++- github/helpers/githubSDK.ts | 55 ++++++++++ github/modals/issueTemplateSelectionModal.ts | 109 +++++++++++++++++++ github/modals/newIssueModal.ts | 91 +++++++++++----- github/modals/newIssueStarterModal.ts | 96 ++++++++++++++++ 9 files changed, 427 insertions(+), 37 deletions(-) create mode 100644 github/modals/issueTemplateSelectionModal.ts create mode 100644 github/modals/newIssueStarterModal.ts diff --git a/github/commands/GithubCommand.ts b/github/commands/GithubCommand.ts index f61d5fe..f23ca52 100644 --- a/github/commands/GithubCommand.ts +++ b/github/commands/GithubCommand.ts @@ -8,7 +8,6 @@ import { IPersistence, IRead, } from "@rocket.chat/apps-engine/definition/accessors"; -import { ProcessorsEnum } from "../enum/Processors"; import { GithubApp } from "../GithubApp"; import { initiatorMessage } from "../lib/initiatorMessage"; import { helperMessage } from "../lib/helperMessage"; @@ -17,16 +16,13 @@ import { pullDetailsModal } from "../modals/pullDetailsModal"; import { authorize } from "../oath2/authentication"; import { SubcommandEnum } from "../enum/Subcommands"; import { getAccessTokenForUser,revokeUserAccessToken } from "../persistance/auth"; -import { IUser } from "@rocket.chat/apps-engine/definition/users"; -import { removeToken } from "../persistance/auth"; import { getWebhookUrl } from "../helpers/getWebhookURL"; import { githubWebHooks } from "../endpoints/githubEndpoints"; import { sendDirectMessage, sendNotification } from "../lib/message"; import { createSubscription, deleteSubscription, updateSubscription } from "../helpers/githubSDK"; import { Subscription } from "../persistance/subscriptions"; -import { ISubscription } from "../definitions/subscription"; import { subsciptionsModal } from "../modals/subscriptionsModal"; -import { NewIssueModal } from "../modals/newIssueModal"; +import { NewIssueStarterModal } from "../modals/newIssueStarterModal"; export class GithubCommand implements ISlashCommand { @@ -106,7 +102,7 @@ export class GithubCommand implements ISlashCommand { if(accessToken && accessToken.token){ const triggerId= context.getTriggerId(); if(triggerId){ - const modal = await NewIssueModal({modify,read,persistence,http,slashcommandcontext:context}); + const modal = await NewIssueStarterModal({modify,read,persistence,http,slashcommandcontext:context}); await modify.getUiController().openModalView(modal,{triggerId},context.getSender()); }else{ console.log("Inavlid Trigger ID !"); diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index 885c337..2713de4 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -58,5 +58,11 @@ export enum ModalsEnum { ISSUE_ASSIGNEES_INPUT = "issue-assignees-input", ISSUE_ASSIGNEES_INPUT_LABEL = "Add Assignees", ISSUE_ASSIGNEES_INPUT_ACTION = "issue-assignee-input-action", - ISSUE_ASSIGNEES_INPUT_PLACEHOLDER = "samad-yar-khan RonLek Sing-Li" + ISSUE_ASSIGNEES_INPUT_PLACEHOLDER = "samad-yar-khan RonLek Sing-Li", + NEW_ISSUE_STARTER_VIEW = "new-issue-starter-view", + NEW_ISSUE_STARTER__ACTION= "new-issue-starter-action", + ISSUE_TEMPLATE_SELECTION_VIEW= "issue-template-selection-view", + ISSUE_TEMPLATE_SELECTION_ACTION = "issue-template-selection-action", + ISSUE_TEMPLATE_SELECTION_LABEL = "Select", + BLANK_GITHUB_TEMPLATE = "blank-github-app-template" } \ No newline at end of file diff --git a/github/enum/Subcommands.ts b/github/enum/Subcommands.ts index 5dc0efa..8d6b2ae 100644 --- a/github/enum/Subcommands.ts +++ b/github/enum/Subcommands.ts @@ -5,5 +5,5 @@ export enum SubcommandEnum { SUBSCRIBE = 'subscribe', UNSUBSCRIBE = 'unsubscribe', TEST = 'test', - NEW_ISSUE = 'new-issue' + NEW_ISSUE = 'issue' } \ No newline at end of file diff --git a/github/handlers/ExecuteBlockActionHandler.ts b/github/handlers/ExecuteBlockActionHandler.ts index 9d013e0..fd0d463 100644 --- a/github/handlers/ExecuteBlockActionHandler.ts +++ b/github/handlers/ExecuteBlockActionHandler.ts @@ -16,7 +16,7 @@ import { } from "@rocket.chat/apps-engine/definition/uikit"; import { AddSubscriptionModal } from "../modals/addSubscriptionsModal"; import { deleteSubsciptionsModal } from "../modals/deleteSubscriptions"; -import { deleteSubscription, updateSubscription } from "../helpers/githubSDK"; +import { deleteSubscription, updateSubscription, getIssueTemplateCode } from "../helpers/githubSDK"; import { Subscription } from "../persistance/subscriptions"; import { getAccessTokenForUser } from "../persistance/auth"; import { GithubApp } from "../GithubApp"; @@ -24,6 +24,8 @@ import { IAuthData } from "@rocket.chat/apps-engine/definition/oauth2/IOAuth2"; import { storeInteractionRoomData, getInteractionRoomData } from "../persistance/roomInteraction"; import { sendNotification } from "../lib/message"; import { subsciptionsModal } from "../modals/subscriptionsModal"; +import { NewIssueModal } from "../modals/newIssueModal"; + export class ExecuteBlockActionHandler { constructor( private readonly app: GithubApp, @@ -180,6 +182,61 @@ export class ExecuteBlockActionHandler { await this.modify.getUiController().updateModalView(modal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); break; } + case ModalsEnum.ISSUE_TEMPLATE_SELECTION_ACTION:{ + let { user } = await context.getInteractionData(); + let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + let value: string = context.getInteractionData().value as string; + let actionDetailsArray = value?.trim()?.split(" "); + if(accessToken && actionDetailsArray?.length == 2){ + + if(actionDetailsArray[1] !== ModalsEnum.BLANK_GITHUB_TEMPLATE){ + + let templateResponse = await getIssueTemplateCode(this.http,actionDetailsArray[1],accessToken.token); + // console.log(templateResponse); + let data = {}; + if(templateResponse?.template){ + data = { + template : templateResponse.template, + repository:actionDetailsArray[0] + }; + }else{ + data = { + template : "", + repository:actionDetailsArray[0] + }; + } + const newIssueModal = await NewIssueModal({ + data, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); + return context + .getInteractionResponder() + .openModalViewResponse(newIssueModal); + + }else{ + let data = { + repository:actionDetailsArray[0] + }; + const newIssueModal = await NewIssueModal({ + data, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); + return context + .getInteractionResponder() + .openModalViewResponse(newIssueModal); + } + } + + break; + } } } catch (error) { diff --git a/github/handlers/ExecuteViewSubmitHandler.ts b/github/handlers/ExecuteViewSubmitHandler.ts index 78e883e..96a1f59 100644 --- a/github/handlers/ExecuteViewSubmitHandler.ts +++ b/github/handlers/ExecuteViewSubmitHandler.ts @@ -7,10 +7,11 @@ import { getInteractionRoomData } from '../persistance/roomInteraction'; import { Subscription } from '../persistance/subscriptions'; import { GithubApp } from '../GithubApp'; import { getWebhookUrl } from '../helpers/getWebhookURL'; -import { addSubscribedEvents, createSubscription, updateSubscription, createNewIssue } from '../helpers/githubSDK'; +import { addSubscribedEvents, createSubscription, updateSubscription, createNewIssue, getIssueTemplates } from '../helpers/githubSDK'; import { getAccessTokenForUser } from '../persistance/auth'; import { subsciptionsModal } from '../modals/subscriptionsModal'; - +import { NewIssueModal } from '../modals/newIssueModal'; +import { issueTemplateSelectionModal } from '../modals/issueTemplateSelectionModal'; export class ExecuteViewSubmitHandler { constructor( @@ -134,6 +135,37 @@ export class ExecuteViewSubmitHandler { } break; } + case ModalsEnum.NEW_ISSUE_STARTER_VIEW:{ + const { roomId } = await getInteractionRoomData(this.read.getPersistenceReader(), user.id); + + if (roomId) { + let room = await this.read.getRoomReader().getById(roomId) as IRoom; + let repository = view.state?.[ModalsEnum.REPO_NAME_INPUT]?.[ModalsEnum.REPO_NAME_INPUT_ACTION] as string; + let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config); + if (!accessToken) { + await sendNotification(this.read, this.modify, user, room, `Login To Github ! -> /github login`); + }else{ + + repository=repository?.trim(); + let response = await getIssueTemplates(this.http,repository,accessToken.token); + if((!response.template_not_found) && response?.templates?.length){ + const issueTemplateSelection = await issueTemplateSelectionModal({ data: response, modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, uikitcontext: context }); + return context + .getInteractionResponder() + .openModalViewResponse(issueTemplateSelection); + }else{ + let data = { + repository: repository + } + const createNewIssue = await NewIssueModal({ data: data, modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, uikitcontext: context }); + return context + .getInteractionResponder() + .openModalViewResponse(createNewIssue); + } + } + } + break; + } default: break; } diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index c91ebbc..c1ba996 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -169,4 +169,59 @@ export async function createNewIssue( assignees: issueAssignees, labels: issueLabels }); +} + +export async function getIssueTemplates( + http: IHttp, + repoName: string, + access_token: string, +) { + //this does not use the get , post , patch method defined because we dont want to throw an error for an eror response + const response = await http.get(`https://api.github.com/repos/${repoName}/contents/.github/ISSUE_TEMPLATE/`, { + headers: { + Authorization: `token ${access_token}`, + "Content-Type": "application/json", + } + }); + + // If it isn't a 2xx code, something wrong happened + let repsonseJSON :any = {}; + if (!response.statusCode.toString().startsWith("2")) { + repsonseJSON["template_not_found"] = true; + }else{ + repsonseJSON = { + templates : JSON.parse(response.content || "{}"), + repository: repoName, + template_not_found : false + } + } + return repsonseJSON; +} + +export async function getIssueTemplateCode( + http: IHttp, + templateDownloadUrl: string, + access_token: string, +) { + //this does not use the get , post , patch method defined because we dont want to throw an error for an eror response + const response = await http.get(templateDownloadUrl, { + headers: { + Authorization: `token ${access_token}`, + "Content-Type": "application/json", + } + }); + + // If it isn't a 2xx code, something wrong happened + let repsonseJSON :any = {}; + + if (!response.statusCode.toString().startsWith("2")) { + repsonseJSON = { + template : "" + } + }else{ + repsonseJSON = { + template : response.content || "", + } + } + return repsonseJSON; } \ No newline at end of file diff --git a/github/modals/issueTemplateSelectionModal.ts b/github/modals/issueTemplateSelectionModal.ts new file mode 100644 index 0000000..dfb3e7f --- /dev/null +++ b/github/modals/issueTemplateSelectionModal.ts @@ -0,0 +1,109 @@ +import { + IHttp, + IModify, + IPersistence, + IRead, +} from "@rocket.chat/apps-engine/definition/accessors"; +import { TextObjectType } from "@rocket.chat/apps-engine/definition/uikit/blocks"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { IUser } from "@rocket.chat/apps-engine/definition/users"; +import { ModalsEnum } from "../enum/Modals"; +import { AppEnum } from "../enum/App"; +// import { getRoomTasks, getUIData, persistUIData } from '../lib/persistence'; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { + UIKitBlockInteractionContext, + UIKitInteractionContext, +} from "@rocket.chat/apps-engine/definition/uikit"; + +export async function issueTemplateSelectionModal({ + data, + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext, +}: { + data?; + modify: IModify; + read: IRead; + persistence: IPersistence; + http: IHttp; + slashcommandcontext?: SlashCommandContext; + uikitcontext?: UIKitInteractionContext; +}): Promise { + const viewId = ModalsEnum.ISSUE_TEMPLATE_SELECTION_VIEW; + + const block = modify.getCreator().getBlockBuilder(); + + const room = + slashcommandcontext?.getRoom() || + uikitcontext?.getInteractionData().room; + const user = + slashcommandcontext?.getSender() || + uikitcontext?.getInteractionData().user; + + if (user?.id && data?.repository && data?.templates?.length) { + + let repositoryName = data.repository as string; + let templates = data.templates as Array; + block.addSectionBlock({ + text: { + text: `Choose Issue Template for ${repositoryName}`, + type: TextObjectType.PLAINTEXT, + }, + }); + + block.addDividerBlock(); + + let index = 1; + + for (let template of templates) { + block.addSectionBlock({ + text: { + text: `${template.name}`, + type: TextObjectType.PLAINTEXT, + }, + accessory: block.newButtonElement({ + actionId: ModalsEnum.ISSUE_TEMPLATE_SELECTION_ACTION, + text: { + text: ModalsEnum.ISSUE_TEMPLATE_SELECTION_LABEL, + type: TextObjectType.PLAINTEXT, + }, + value: `${repositoryName} ${template.download_url}`, + }), + }); + index++; + } + block.addSectionBlock({ + text: { + text: `Blank Template`, + type: TextObjectType.PLAINTEXT, + }, + accessory: block.newButtonElement({ + actionId: ModalsEnum.ISSUE_TEMPLATE_SELECTION_ACTION, + text: { + text: ModalsEnum.ISSUE_TEMPLATE_SELECTION_LABEL, + type: TextObjectType.PLAINTEXT, + }, + value: `${repositoryName} ${ModalsEnum.BLANK_GITHUB_TEMPLATE}`, + }), + }); + } + + return { + id: viewId, + title: { + type: TextObjectType.PLAINTEXT, + text: ModalsEnum.NEW_ISSUE_TITLE, + }, + close: block.newButtonElement({ + text: { + type: TextObjectType.PLAINTEXT, + text: "Close", + }, + }), + blocks: block.getBlocks(), + }; +} diff --git a/github/modals/newIssueModal.ts b/github/modals/newIssueModal.ts index a1666d5..18da9ee 100644 --- a/github/modals/newIssueModal.ts +++ b/github/modals/newIssueModal.ts @@ -20,6 +20,7 @@ import { } from "../persistance/roomInteraction"; export async function NewIssueModal({ + data, modify, read, persistence, @@ -27,6 +28,7 @@ export async function NewIssueModal({ slashcommandcontext, uikitcontext, }: { + data: any, modify: IModify; read: IRead; persistence: IPersistence; @@ -54,21 +56,39 @@ export async function NewIssueModal({ ).roomId; } - // shows indentations in input blocks but not inn section block - block.addInputBlock({ - blockId: ModalsEnum.REPO_NAME_INPUT, - label: { - text: ModalsEnum.REPO_NAME_LABEL, - type: TextObjectType.PLAINTEXT, - }, - element: block.newPlainTextInputElement({ - actionId: ModalsEnum.REPO_NAME_INPUT_ACTION, - placeholder: { - text: ModalsEnum.REPO_NAME_PLACEHOLDER, + if(data?.repository != undefined){ + block.addInputBlock({ + blockId: ModalsEnum.REPO_NAME_INPUT, + label: { + text: ModalsEnum.REPO_NAME_LABEL, type: TextObjectType.PLAINTEXT, }, - }), - }); + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.REPO_NAME_INPUT_ACTION, + placeholder: { + text: ModalsEnum.REPO_NAME_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, + }, + initialValue: data?.repository + }), + }); + }else{ + block.addInputBlock({ + blockId: ModalsEnum.REPO_NAME_INPUT, + label: { + text: ModalsEnum.REPO_NAME_LABEL, + type: TextObjectType.PLAINTEXT, + }, + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.REPO_NAME_INPUT_ACTION, + placeholder: { + text: ModalsEnum.REPO_NAME_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, + }, + }), + }); + } + block.addInputBlock({ blockId: ModalsEnum.ISSUE_TITLE_INPUT, @@ -85,21 +105,40 @@ export async function NewIssueModal({ }), }); - block.addInputBlock({ - blockId: ModalsEnum.ISSUE_BODY_INPUT, - label: { - text: ModalsEnum.ISSUE_BODY_INPUT_LABEL, - type: TextObjectType.PLAINTEXT, - }, - element: block.newPlainTextInputElement({ - actionId: ModalsEnum.ISSUE_BODY_INPUT_ACTION, - placeholder: { - text: ModalsEnum.ISSUE_BODY_INPUT_PLACEHOLDER, + if(data?.template != undefined){ + block.addInputBlock({ + blockId: ModalsEnum.ISSUE_BODY_INPUT, + label: { + text: ModalsEnum.ISSUE_BODY_INPUT_LABEL, type: TextObjectType.PLAINTEXT, }, - multiline: true - }), - }); + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.ISSUE_BODY_INPUT_ACTION, + placeholder: { + text: ModalsEnum.ISSUE_BODY_INPUT_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, + }, + multiline: true, + initialValue:data?.template + }), + }); + }else{ + block.addInputBlock({ + blockId: ModalsEnum.ISSUE_BODY_INPUT, + label: { + text: ModalsEnum.ISSUE_BODY_INPUT_LABEL, + type: TextObjectType.PLAINTEXT, + }, + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.ISSUE_BODY_INPUT_ACTION, + placeholder: { + text: ModalsEnum.ISSUE_BODY_INPUT_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, + }, + multiline: true + }), + }); + } block.addInputBlock({ blockId: ModalsEnum.ISSUE_LABELS_INPUT, diff --git a/github/modals/newIssueStarterModal.ts b/github/modals/newIssueStarterModal.ts new file mode 100644 index 0000000..251dff3 --- /dev/null +++ b/github/modals/newIssueStarterModal.ts @@ -0,0 +1,96 @@ +import { + IHttp, + IModify, + IPersistence, + IRead, +} from "@rocket.chat/apps-engine/definition/accessors"; +import { TextObjectType } from "@rocket.chat/apps-engine/definition/uikit/blocks"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { ModalsEnum } from "../enum/Modals"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { + UIKitInteractionContext, +} from "@rocket.chat/apps-engine/definition/uikit"; +import { + storeInteractionRoomData, + getInteractionRoomData, +} from "../persistance/roomInteraction"; + +export async function NewIssueStarterModal({ + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext, +}: { + modify: IModify; + read: IRead; + persistence: IPersistence; + http: IHttp; + slashcommandcontext?: SlashCommandContext; + uikitcontext?: UIKitInteractionContext; +}): Promise { + const viewId = ModalsEnum.NEW_ISSUE_STARTER_VIEW; + const block = modify.getCreator().getBlockBuilder(); + const room = slashcommandcontext?.getRoom() || uikitcontext?.getInteractionData().room; + const user = slashcommandcontext?.getSender() || uikitcontext?.getInteractionData().user; + + if (user?.id) { + let roomId; + + if (room?.id) { + roomId = room.id; + await storeInteractionRoomData(persistence, user.id, roomId); + } else { + roomId = ( + await getInteractionRoomData( + read.getPersistenceReader(), + user.id + ) + ).roomId; + } + + // shows indentations in input blocks but not inn section block + block.addInputBlock({ + blockId: ModalsEnum.REPO_NAME_INPUT, + label: { + text: ModalsEnum.REPO_NAME_LABEL, + type: TextObjectType.PLAINTEXT, + }, + element: block.newPlainTextInputElement({ + actionId: ModalsEnum.REPO_NAME_INPUT_ACTION, + placeholder: { + text: ModalsEnum.REPO_NAME_PLACEHOLDER, + type: TextObjectType.PLAINTEXT, + }, + }), + }); + + } + + block.addDividerBlock(); + + return { + id: viewId, + title: { + type: TextObjectType.PLAINTEXT, + text: ModalsEnum.NEW_ISSUE_TITLE, + }, + close: block.newButtonElement({ + text: { + type: TextObjectType.PLAINTEXT, + text: "Close", + }, + }), + submit: block.newButtonElement({ + actionId: ModalsEnum.NEW_ISSUE_STARTER__ACTION, + text: { + type: TextObjectType.PLAINTEXT, + emoji:true, + text: "Next 🚀", + }, + }), + blocks: block.getBlocks(), + }; +} From a677c84e3237fd4115817bea41629a588301a26d Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Sat, 23 Jul 2022 00:42:28 +0530 Subject: [PATCH 8/8] Update helper message --- github/lib/helperMessage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/lib/helperMessage.ts b/github/lib/helperMessage.ts index 6cb3e26..a3f70a9 100644 --- a/github/lib/helperMessage.ts +++ b/github/lib/helperMessage.ts @@ -33,7 +33,7 @@ export async function helperMessage({ 9) View/Add/Delete/Update Repository Subscriptions -> /github subscribe 10) Subscribe to all repository events -> /github Username/RepositoryName subscribe 11) Unsubscribe to all repository events -> /github Username/RepositoryName unsubscribe - 12) Add New Issues to GitHub Repository -> /github new-issue + 12) Add New Issues to GitHub Repository -> /github issue `;