From 381f6f636422d2a475adfaac148e8296d8cd1a59 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sat, 15 Oct 2022 23:53:39 +0530 Subject: [PATCH 01/33] feat: User Modal Initiated --- github/modals/UserProfileModal.ts | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 github/modals/UserProfileModal.ts diff --git a/github/modals/UserProfileModal.ts b/github/modals/UserProfileModal.ts new file mode 100644 index 0000000..85149a9 --- /dev/null +++ b/github/modals/UserProfileModal.ts @@ -0,0 +1,4 @@ + +export async function userProfileModal() { + +} From d46214faa49b27b65c8f1fafec0ef3764387530f Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Fri, 4 Nov 2022 21:32:46 +0530 Subject: [PATCH 02/33] feat: Command Utility modified for User Profile Subcommand --- github/lib/commandUtility.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/github/lib/commandUtility.ts b/github/lib/commandUtility.ts index a1cdf48..d2fb1c3 100644 --- a/github/lib/commandUtility.ts +++ b/github/lib/commandUtility.ts @@ -22,6 +22,7 @@ import { } from "../handlers/EventHandler"; import { handleSearch } from "../handlers/SearchHandler"; import { handleNewIssue } from "../handlers/HandleNewIssue"; +import { handleUserProfileRequest } from "../handlers/UserProfileHandler"; export class CommandUtility implements ExecutorProps { sender: IUser; @@ -125,6 +126,18 @@ export class CommandUtility implements ExecutorProps { ); break; } + case SubcommandEnum.PROFILE: { + await handleUserProfileRequest( + this.read, + this.context, + this.app, + this.persistence, + this.http, + this.room, + this.modify + ); + break; + } default: { await helperMessage({ room: this.room, From d35cc6981594799aa68922d07b535486a971b62c Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Fri, 4 Nov 2022 21:33:15 +0530 Subject: [PATCH 03/33] feat: Github SDK modified for fetching User Data --- github/helpers/githubSDK.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index eea6ab5..2698864 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -430,6 +430,37 @@ export async function mergePullRequest( return JSONResponse; } +export async function getBasicUserInfo( + http: IHttp, + access_token: String, +){ + try { + const response = await getRequest( + http, + access_token, + BaseApiHost + 'user' + ); + return { + username: response.login, + name : response.name, + email : response.email, + bio: response.bio, + followers : response.followers, + following : response.following, + avatar : response.avatar_url + } + }catch(e){ + return { + name : "", + email : "", + bio: "", + followers : "", + following : "", + avatar : "" + }; + } +} + export async function addNewPullRequestComment( http: IHttp, repoName: string, From 3e0183e4c77ebf0619d28bc04bf1553a3b2e9d21 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Fri, 4 Nov 2022 21:34:52 +0530 Subject: [PATCH 04/33] feat: Handlers and Subcommands Created --- github/enum/Subcommands.ts | 5 +-- github/handlers/UserProfileHandler.ts | 52 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 github/handlers/UserProfileHandler.ts diff --git a/github/enum/Subcommands.ts b/github/enum/Subcommands.ts index 61d4fab..8ba32e2 100644 --- a/github/enum/Subcommands.ts +++ b/github/enum/Subcommands.ts @@ -7,5 +7,6 @@ export enum SubcommandEnum { TEST = 'test', SEARCH = 'search', NEW_ISSUE = 'issue', - ISSUES = 'issues' -} \ No newline at end of file + ISSUES = 'issues', + PROFILE = 'me' +} diff --git a/github/handlers/UserProfileHandler.ts b/github/handlers/UserProfileHandler.ts new file mode 100644 index 0000000..b8eff52 --- /dev/null +++ b/github/handlers/UserProfileHandler.ts @@ -0,0 +1,52 @@ +import { IRead, IPersistence, IHttp, IModify } from "@rocket.chat/apps-engine/definition/accessors"; +import { IRoom } from "@rocket.chat/apps-engine/definition/rooms"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { GithubApp } from "../GithubApp"; +import { sendNotification } from "../lib/message"; +import { userProfileModal } from "../modals/UserProfileModal"; +import { getAccessTokenForUser } from "../persistance/auth"; + +export async function handleUserProfileRequest( + read: IRead, + context: SlashCommandContext, + app: GithubApp, + persistence: IPersistence, + http: IHttp, + room: IRoom, + modify: IModify, + uikitcontext?: UIKitInteractionContext +){ + let access_token = await getAccessTokenForUser( + read, + context.getSender(), + app.oauth2Config + ); + if (access_token && access_token.token){ + const triggerId = context.getTriggerId(); + if (triggerId){ + const modal = await userProfileModal({ + access_token: access_token.token, + modify: modify, + read: read, + persistence: persistence, + http: http, + slashcommandcontext: context + }); + await modify.getUiController().openModalView( + modal, + {triggerId}, + context.getSender() + ); + } + }else { + await sendNotification( + read, + modify, + context.getSender(), + room, + "Login is Mandatory for getting User Info ! `/github login`" + ) + } + +} From 37c772eea727676edb188b9f72a11a2d73c22585 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Fri, 4 Nov 2022 21:35:15 +0530 Subject: [PATCH 05/33] feat: User Profile Modal Created --- github/modals/UserProfileModal.ts | 146 +++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/github/modals/UserProfileModal.ts b/github/modals/UserProfileModal.ts index 85149a9..07dfd90 100644 --- a/github/modals/UserProfileModal.ts +++ b/github/modals/UserProfileModal.ts @@ -1,4 +1,148 @@ +import { IHttp, IModify, IPersistence, IRead } from "@rocket.chat/apps-engine/definition/accessors"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { ButtonStyle, TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { AppEnum } from "../enum/App"; +import { ModalsEnum } from "../enum/Modals"; +import { getBasicUserInfo } from "../helpers/githubSDK"; +import { getInteractionRoomData, storeInteractionRoomData } from "../persistance/roomInteraction"; +import {} from "@rocket.chat/apps-engine/definition/uikit/" -export async function userProfileModal() { +export async function userProfileModal({ + access_token, + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext +} : { + access_token: String, + modify : IModify, + read: IRead, + persistence: IPersistence, + http: IHttp, + slashcommandcontext: SlashCommandContext, + uikitcontext?: UIKitInteractionContext +}) : Promise { + + const viewId = ModalsEnum.USER_PROFILE_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; + } + } + + const userInfo = await getBasicUserInfo(http, access_token); + + + block.addContextBlock({ + elements: [ + block.newPlainTextObject(userInfo.email, true), + ] + }) + + block.addSectionBlock({ + text: block.newPlainTextObject(userInfo.bio), + accessory : block.newImageElement({ + imageUrl: userInfo.avatar, + altText: userInfo.name + }) + }) + + block.addContextBlock({ + elements: [ + block.newPlainTextObject(`followers: ${userInfo.followers}`), + block.newPlainTextObject(`following: ${userInfo.following}`) + ] + }); + + block.addDividerBlock(); + + block.addImageBlock({imageUrl : `https://activity-graph.herokuapp.com/graph?username=${userInfo.username}&bg_color=ffffff&color=708090&line=24292e&point=24292e`, altText: "Github Contribution Graph"}); + + + + block.addDividerBlock(); + + block.addSectionBlock({ + text: block.newPlainTextObject("Where should we teleport ?") + }) + + block.addActionsBlock({ + elements : [ + block.newButtonElement({ + text : { + text : "Share Profile", + type : TextObjectType.PLAINTEXT + }, + actionId: ModalsEnum.SHARE_PROFILE, + style : ButtonStyle.PRIMARY + }), + block.newButtonElement( + { + actionId: "123", + value: "repo", + text: { + type: TextObjectType.PLAINTEXT, + text: "Repositories" + }, + style: ButtonStyle.PRIMARY + }, + ), + block.newButtonElement( + { + actionId: "123", + value: "repo", + text: { + type: TextObjectType.PLAINTEXT, + text: "Issues" + }, + style: ButtonStyle.PRIMARY + }, + ), + block.newButtonElement( + { + actionId: "123", + value: "repo", + text: { + type: TextObjectType.PLAINTEXT, + text: "Notifications" + }, + style: ButtonStyle.PRIMARY + }, + ), + block.newButtonElement( + { + actionId: "123", + value: "repo", + text: { + type: TextObjectType.PLAINTEXT, + text: "Your Feed" + }, + style: ButtonStyle.PRIMARY + }, + ) + ] + }) + + + return { + id: viewId, + title: { + type: TextObjectType.PLAINTEXT, + text: userInfo.name + }, + blocks: block.getBlocks() + } } From bfc2e40dcb8c9831e516fd626d62fccd416ebf94 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Fri, 4 Nov 2022 21:35:49 +0530 Subject: [PATCH 06/33] feat: Share Profile Modal Added --- github/modals/profileShareModal.ts | 114 +++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 github/modals/profileShareModal.ts diff --git a/github/modals/profileShareModal.ts b/github/modals/profileShareModal.ts new file mode 100644 index 0000000..5efc163 --- /dev/null +++ b/github/modals/profileShareModal.ts @@ -0,0 +1,114 @@ +import { IModify, IRead, IPersistence, IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { ModalsEnum } from "../enum/Modals"; +import { getBasicUserInfo } from "../helpers/githubSDK"; +import { storeInteractionRoomData, getInteractionRoomData } from "../persistance/roomInteraction"; + +export async function shareProfileModal({ + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext +} : { + modify : IModify, + read: IRead, + persistence: IPersistence, + http: IHttp, + slashcommandcontext?: SlashCommandContext, + uikitcontext?: UIKitInteractionContext +}) : Promise { + + const viewId = "ProfileShareView"; + const block = modify.getCreator().getBlockBuilder(); + + block.addActionsBlock({ + + elements : [ + block.newMultiStaticElement({ + actionId: ModalsEnum.SHARE_PROFILE_PARAMS, + initialValue: ['username', 'avatar', 'email', 'bio', 'followers', 'following' , 'contributionGraph'], + options: [ + { + value: 'followers', + text: { + type: TextObjectType.PLAINTEXT, + text: 'Followers', + emoji: true, + } + }, + { + value: 'following', + text: { + type: TextObjectType.PLAINTEXT, + text: 'Following', + emoji: true, + } + }, + { + value : 'avatar', + text : { + text: "Avatar", + type: TextObjectType.PLAINTEXT + } + }, + { + value : 'username', + text : { + text : "Github ID", + type : TextObjectType.PLAINTEXT + } + }, + { + value: 'email', + text: { + type: TextObjectType.PLAINTEXT, + text: 'Email', + emoji: true, + } + }, + { + value : 'bio', + text : { + type: TextObjectType.PLAINTEXT, + text: 'bio' + } + }, + { + value : 'contributionGraph', + text : { + text: 'Contribution', + type : TextObjectType.PLAINTEXT + } + } + ], + placeholder: { + type: TextObjectType.PLAINTEXT, + text: 'Select Property to Share', + }, + }), + block.newButtonElement({ + actionId : ModalsEnum.SHARE_PROFILE_EXEC, + text : { + text : "Share to Chat", + type : TextObjectType.PLAINTEXT + }, + value : "shareChat" + + }) + ] + }) + + return { + id: viewId, + title: { + type: TextObjectType.PLAINTEXT, + text: "Share Profile" + }, + blocks: block.getBlocks() + } + +} From 5daa223e559ce7a48b5d04bd2035b93c49de3b1e Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Fri, 4 Nov 2022 21:36:24 +0530 Subject: [PATCH 07/33] feat: Modal Actions Added for Profile Modal and Sharing Modal --- github/enum/Modals.ts | 8 +- github/handlers/ExecuteBlockActionHandler.ts | 101 ++++++++++++++++++- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index ab8ceec..e4ba1b8 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -1,4 +1,7 @@ export enum ModalsEnum { + SHARE_PROFILE_EXEC = 'share-profile-exec', + SHARE_PROFILE_PARAMS = 'share-profile-params', + SHARE_PROFILE = 'share-profile', PULL_VIEW = 'pull-view', CODE_VIEW = 'code-view', CODE_VIEW_LABEL = 'Code Changes', @@ -15,6 +18,7 @@ export enum ModalsEnum { SUBSCRIPTION_VIEW = 'subscriptions-view', ADD_SUBSCRIPTION_VIEW = 'add-subscription-view', DELETE_SUBSCRIPTION_VIEW ='delete-subscription-view', + USER_PROFILE_VIEW = 'user-profile-view', OPEN_ADD_SUBSCRIPTIONS_MODAL='open-add-subscriptions', OPEN_UPDATE_SUBSCRIPTIONS_MODAL='open-update-subscriptions', OPEN_DELETE_SUBSCRIPTIONS_MODAL='open-update-subscriptions', @@ -134,7 +138,7 @@ export enum ModalsEnum { ISSUE_TEMPLATE_SELECTION_LABEL = "Select", BLANK_GITHUB_TEMPLATE = "blank-github-app-template", GITHUB_ISSUES_STARTER_VIEW = "github-issues-starter-view", - GITHUB_ISSUES_TITLE = "GitHub Issues", + GITHUB_ISSUES_TITLE = "GitHub Issues", ISSUE_LIST_VIEW = "github-issue-list-view", ADD_GITHUB_ISSUE_ASSIGNEE = "update-github-issue", ADD_GITHUB_ISSUE_ASSIGNEE_LABEL = "Assign", @@ -157,4 +161,4 @@ export enum ModalsEnum { MULTI_SHARE_GITHUB_ISSUES_INPUT = "multishare-github-issues-input", MULTI_SHARE_GITHUB_ISSUES_INPUT_LABEL = "Issues", MULTI_SHARE_GITHUB_ISSUES_INPUT_ACTION = "multishare-github-issues-input-action", -} \ No newline at end of file +} diff --git a/github/handlers/ExecuteBlockActionHandler.ts b/github/handlers/ExecuteBlockActionHandler.ts index 6cbe820..d8e1e04 100644 --- a/github/handlers/ExecuteBlockActionHandler.ts +++ b/github/handlers/ExecuteBlockActionHandler.ts @@ -12,11 +12,12 @@ import { ModalsEnum } from "../enum/Modals"; import { fileCodeModal } from "../modals/fileCodeModal"; import { IUIKitResponse, + TextObjectType, UIKitBlockInteractionContext, } from "@rocket.chat/apps-engine/definition/uikit"; import { AddSubscriptionModal } from "../modals/addSubscriptionsModal"; import { deleteSubsciptionsModal } from "../modals/deleteSubscriptions"; -import { deleteSubscription, updateSubscription, getIssueTemplateCode, getPullRequestComments, getPullRequestData, getRepositoryIssues } from "../helpers/githubSDK"; +import { deleteSubscription, updateSubscription, getIssueTemplateCode, getPullRequestComments, getPullRequestData, getRepositoryIssues, getBasicUserInfo } from "../helpers/githubSDK"; import { Subscription } from "../persistance/subscriptions"; import { getAccessTokenForUser } from "../persistance/auth"; import { GithubApp } from "../GithubApp"; @@ -39,8 +40,11 @@ import { addIssueAssigneeModal } from "../modals/addIssueAssigneeModal"; import { githubIssuesListModal } from "../modals/githubIssuesListModal"; import { GithubRepoIssuesStorage } from "../persistance/githubIssues"; import { IGitHubIssueData } from "../definitions/githubIssueData"; +import { shareProfileModal } from "../modals/profileShareModal"; +import { RocketChatAssociationModel, RocketChatAssociationRecord } from "@rocket.chat/apps-engine/definition/metadata"; export class ExecuteBlockActionHandler { + constructor( private readonly app: GithubApp, private readonly read: IRead, @@ -102,6 +106,82 @@ export class ExecuteBlockActionHandler { } break; } + case ModalsEnum.SHARE_PROFILE_PARAMS : { + const { user } = context.getInteractionData(); + const profileInteractionData = context.getInteractionData().value; + const datAny = profileInteractionData as any; + const storeData = { + profileParams : datAny as string[] + } + + await this.persistence.updateByAssociation(new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ProfileShareParam"), storeData); + break; + } + case ModalsEnum.SHARE_PROFILE_EXEC : { + let {user, room} = context.getInteractionData(); + const block = this.modify.getCreator().getBlockBuilder(); + let accessToken = await getAccessTokenForUser(this.read, user ,this.app.oauth2Config) as IAuthData; + const userProfile = await getBasicUserInfo(this.http, accessToken.token); + + const idRecord = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ProfileShareParam") + + const profileData = await this.read.getPersistenceReader().readByAssociation(idRecord); + + let profileShareParams: string[] = []; + + if (profileData.length == 0){ + profileShareParams = ['username', 'avatar', 'email', 'bio', 'followers', 'following' , 'contributionGraph']; + } + else { + const dat = profileData[0] as {profileParams : string[]}; + profileShareParams = dat.profileParams; + } + + if (profileShareParams.includes('avatar')){ + block.addImageBlock({ + imageUrl : userProfile.avatar, + altText : "User Info" + }) + } + + profileShareParams.map((value) => { + if (value != 'contributionGraph' && value != 'avatar'){ + block.addSectionBlock({ + text : block.newPlainTextObject(value), + }) + block.addContextBlock({ + elements : [ + block.newPlainTextObject(userProfile[value], true), + ] + }); + block.addDividerBlock(); + } + }) + + if (profileShareParams.includes('contributionGraph')){ + block.addImageBlock({imageUrl : `https://activity-graph.herokuapp.com/graph?username=${userProfile.username}&bg_color=ffffff&color=708090&line=24292e&point=24292e`, altText: "Github Contribution Graph"}) + } + + + if(user?.id){ + if(room?.id){ + await sendMessage(this.modify, room!, user, `${userProfile.name}'s Github Profile`, block) + }else{ + let roomId = ( + await getInteractionRoomData( + this.read.getPersistenceReader(), + user.id + ) + ).roomId; + room = await this.read.getRoomReader().getById(roomId) as IRoom; + await sendMessage(this.modify, room, user, `${userProfile.name}'s Github Profile`, block) + } + } + + this.persistence.removeByAssociation(idRecord); + + break; + } case ModalsEnum.VIEW_FILE_ACTION: { const codeModal = await fileCodeModal({ data, @@ -155,7 +235,7 @@ export class ExecuteBlockActionHandler { } else { roomId = (await getInteractionRoomData(this.read.getPersistenceReader(), user.id)).roomId; } - //delete the susbscriptions for persistance + //delete the susbscriptions for persistance let subscriptionStorage = new Subscription(this.persistence, this.read.getPersistenceReader()); let oldSubscriptions = await subscriptionStorage.getSubscriptionsByRepo(repoName, user.id); await subscriptionStorage.deleteSubscriptionsByRepoUser(repoName, roomId, user.id); @@ -206,7 +286,6 @@ export class ExecuteBlockActionHandler { 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 = { @@ -437,7 +516,7 @@ export class ExecuteBlockActionHandler { .getInteractionResponder() .openModalViewResponse(unauthorizedMessageModal); } - + } break; } @@ -465,6 +544,20 @@ export class ExecuteBlockActionHandler { } break; } + case ModalsEnum.SHARE_PROFILE : { + + const shareProfileMod = await shareProfileModal({ + modify:this.modify, + read:this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context + }) + + return context.getInteractionResponder().openModalViewResponse(shareProfileMod); + } + + case ModalsEnum.PR_COMMENT_LIST_ACTION:{ let value: string = context.getInteractionData().value as string; let splittedValues = value?.split(" "); From 79cdad862dcb56de62ea82c45701ff5cd3a03c99 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sat, 5 Nov 2022 14:29:41 +0530 Subject: [PATCH 08/33] feat: Modal Actiions Registered for issues, repos and feed --- github/enum/Modals.ts | 4 ++++ github/handlers/ExecuteBlockActionHandler.ts | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index e4ba1b8..0f762a2 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -1,4 +1,8 @@ export enum ModalsEnum { + TRIGGER_ISSUES_MODAL = 'trigger-issue-modal', + TRIGGER_REPOS_MODAL = 'trigger-repos-modal', + TRIGGER_ACTIVITY_MODAL = 'trigger-activity-modal', + TRIGGER_NOTIFICATIONS_MODAL = 'trigger-notifications-modal', SHARE_PROFILE_EXEC = 'share-profile-exec', SHARE_PROFILE_PARAMS = 'share-profile-params', SHARE_PROFILE = 'share-profile', diff --git a/github/handlers/ExecuteBlockActionHandler.ts b/github/handlers/ExecuteBlockActionHandler.ts index d8e1e04..a691f79 100644 --- a/github/handlers/ExecuteBlockActionHandler.ts +++ b/github/handlers/ExecuteBlockActionHandler.ts @@ -106,6 +106,15 @@ export class ExecuteBlockActionHandler { } break; } + case ModalsEnum.TRIGGER_ISSUES_MODAL : { + break; + } + case ModalsEnum.TRIGGER_REPOS_MODAL : { + break; + } + case ModalsEnum.TRIGGER_ACTIVITY_MODAL : { + break; + } case ModalsEnum.SHARE_PROFILE_PARAMS : { const { user } = context.getInteractionData(); const profileInteractionData = context.getInteractionData().value; From 5251cabe69bcc8997741e59bf0d2ced601412dfb Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sat, 5 Nov 2022 14:30:10 +0530 Subject: [PATCH 09/33] feat: Issue and Repo actions added for User Profile Modal --- github/modals/UserProfileModal.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/github/modals/UserProfileModal.ts b/github/modals/UserProfileModal.ts index 07dfd90..91e287f 100644 --- a/github/modals/UserProfileModal.ts +++ b/github/modals/UserProfileModal.ts @@ -90,8 +90,8 @@ export async function userProfileModal({ }), block.newButtonElement( { - actionId: "123", - value: "repo", + actionId: ModalsEnum.TRIGGER_REPOS_MODAL, + value: "Trigger Repos Modal", text: { type: TextObjectType.PLAINTEXT, text: "Repositories" @@ -101,8 +101,8 @@ export async function userProfileModal({ ), block.newButtonElement( { - actionId: "123", - value: "repo", + actionId: ModalsEnum.TRIGGER_ISSUES_MODAL, + value: "Trigger Issues Modal", text: { type: TextObjectType.PLAINTEXT, text: "Issues" @@ -112,7 +112,7 @@ export async function userProfileModal({ ), block.newButtonElement( { - actionId: "123", + actionId: ModalsEnum.TRIGGER_NOTIFICATIONS_MODAL, value: "repo", text: { type: TextObjectType.PLAINTEXT, @@ -123,7 +123,7 @@ export async function userProfileModal({ ), block.newButtonElement( { - actionId: "123", + actionId: ModalsEnum.TRIGGER_ACTIVITY_MODAL, value: "repo", text: { type: TextObjectType.PLAINTEXT, From 1f7d233b6ada773e95511ae775771d2fe3a4e765 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sun, 6 Nov 2022 00:45:54 +0530 Subject: [PATCH 10/33] feat: Notification and Repo Modal Templetes Added --- github/modals/UserNotificationsModal.ts | 53 +++++++++++++++++++++++++ github/modals/UserReposModal.ts | 53 +++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 github/modals/UserNotificationsModal.ts create mode 100644 github/modals/UserReposModal.ts diff --git a/github/modals/UserNotificationsModal.ts b/github/modals/UserNotificationsModal.ts new file mode 100644 index 0000000..b646828 --- /dev/null +++ b/github/modals/UserNotificationsModal.ts @@ -0,0 +1,53 @@ +import { IModify, IRead, IPersistence, IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { ModalsEnum } from "../enum/Modals"; +import { getUserAssignedIssues } from "../helpers/githubSDK"; +import { getInteractionRoomData, storeInteractionRoomData } from "../persistance/roomInteraction"; + +export async function userNotificationsModal ({ + access_token, + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext +} : { + access_token: String, + modify : IModify, + read: IRead, + persistence: IPersistence, + http: IHttp, + slashcommandcontext: SlashCommandContext, + uikitcontext?: UIKitInteractionContext +}) : Promise { + const viewId = ModalsEnum.USER_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; + } + } + + // const repoInfo = await getUserAssignedIssues(http, access_token); + + return { + id : viewId, + title : { + text : "Your Issues", + type : TextObjectType.PLAINTEXT + }, + blocks : block.getBlocks() + } + +} diff --git a/github/modals/UserReposModal.ts b/github/modals/UserReposModal.ts new file mode 100644 index 0000000..b95023a --- /dev/null +++ b/github/modals/UserReposModal.ts @@ -0,0 +1,53 @@ +import { IModify, IRead, IPersistence, IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { ModalsEnum } from "../enum/Modals"; +import { getUserAssignedIssues } from "../helpers/githubSDK"; +import { getInteractionRoomData, storeInteractionRoomData } from "../persistance/roomInteraction"; + +export async function userReposModal ({ + access_token, + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext +} : { + access_token: String, + modify : IModify, + read: IRead, + persistence: IPersistence, + http: IHttp, + slashcommandcontext: SlashCommandContext, + uikitcontext?: UIKitInteractionContext +}) : Promise { + const viewId = ModalsEnum.USER_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; + } + } + + // const repoInfo = await getUserAssignedIssues(http, access_token); + + return { + id : viewId, + title : { + text : "Your Repositories", + type : TextObjectType.PLAINTEXT + }, + blocks : block.getBlocks() + } + +} From 6ed04bf0b11de3cb98f194d746b5769cd9bab477 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sun, 6 Nov 2022 00:46:51 +0530 Subject: [PATCH 11/33] feat: Issue Search Filter Blocks Added --- github/modals/UserIssuesModal.ts | 207 +++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 github/modals/UserIssuesModal.ts diff --git a/github/modals/UserIssuesModal.ts b/github/modals/UserIssuesModal.ts new file mode 100644 index 0000000..03d8922 --- /dev/null +++ b/github/modals/UserIssuesModal.ts @@ -0,0 +1,207 @@ +import { IModify, IRead, IPersistence, IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { ModalsEnum } from "../enum/Modals"; +import { getBasicUserInfo, getUserAssignedIssues } from "../helpers/githubSDK"; +import { getInteractionRoomData, storeInteractionRoomData } from "../persistance/roomInteraction"; + +export async function userIssuesModal ({ + filter = { + filter : ModalsEnum.ALL_ISSUE_FILTER, + state : ModalsEnum.ISSUE_STATE_OPEN, + sort : ModalsEnum.ISSUE_SORT_CREATED + }, + access_token, + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext +} : { + filter?: { + filter : String, + state : String, + sort : String + }, + access_token: String, + modify : IModify, + read: IRead, + persistence: IPersistence, + http: IHttp, + slashcommandcontext?: SlashCommandContext, + uikitcontext?: UIKitInteractionContext +}) : Promise { + const viewId = ModalsEnum.USER_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; + } + } + + const userInfo = await getBasicUserInfo(http, access_token); + + const repoInfo = await getUserAssignedIssues(http,userInfo.username, access_token, filter); + + + block.addActionsBlock({ + elements : [ + block.newStaticSelectElement({ + actionId : ModalsEnum.SWITCH_ISSUE_FILTER, + placeholder : { + text : "Select an Issue Filter", + type : TextObjectType.PLAINTEXT + }, + initialValue : ModalsEnum.ASSIGNED_ISSUE_FILTER, + options : [ + { + value : ModalsEnum.ASSIGNED_ISSUE_FILTER, + text : { + text : "Assigned", + type : TextObjectType.PLAINTEXT + } + }, + { + value : ModalsEnum.CREATED_ISSUE_FILTER, + text : { + text : "Created", + type : TextObjectType.PLAINTEXT + } + }, + { + value : ModalsEnum.MENTIONED_ISSUE_FILTER, + text : { + text : "Mentioned", + type : TextObjectType.PLAINTEXT + } + } + ] + }) + ] + }); + + block.addActionsBlock({ + elements : [ + block.newStaticSelectElement({ + actionId : ModalsEnum.SWITCH_ISSUE_STATE, + placeholder : { + text : "Select Issues State", + type : TextObjectType.PLAINTEXT + }, + initialValue : ModalsEnum.ISSUE_STATE_OPEN, + options : [ + { + value : ModalsEnum.ISSUE_STATE_OPEN, + text : { + text : "Open Issues", + type : TextObjectType.PLAINTEXT + }, + }, + { + value : ModalsEnum.ISSUE_STATE_CLOSED, + text : { + text: "Closed Issues", + type : TextObjectType.PLAINTEXT + } + }, + { + value : ModalsEnum.ISSUE_STATE_ALL, + text : { + text : "All Issues", + type : TextObjectType.PLAINTEXT + } + } + ] + }), + block.newStaticSelectElement({ + actionId : ModalsEnum.SWITCH_ISSUE_SORT, + placeholder : { + text : "Sort Issues By...", + type : TextObjectType.PLAINTEXT + }, + initialValue : ModalsEnum.ISSUE_SORT_CREATED, + options : [ + { + value : ModalsEnum.ISSUE_SORT_CREATED, + text : { + text : "Created", + type : TextObjectType.PLAINTEXT + } + }, + { + value : ModalsEnum.ISSUE_SORT_UPDATED, + text : { + text : "Updated", + type : TextObjectType.PLAINTEXT + } + }, + { + value : ModalsEnum.ISSUE_SORT_COMMENTS, + text : { + text : "Comments", + type : TextObjectType.PLAINTEXT + } + } + ] + }), + + ] + }); + + block.addSectionBlock({ + text : { + text : "Issues", + type : TextObjectType.PLAINTEXT + }, + }); + + if (repoInfo.items.length == 0){ + block.addContextBlock({ + elements : [ + block.newPlainTextObject("Sorry, there are no issues to display") + ] + }) + } + else { + repoInfo.items.map((value) => { + if (value.pull_request == undefined){ + block.addSectionBlock({ + text : { + text : value.title ?? "None", + type : TextObjectType.MARKDOWN + } + }) + block.addDividerBlock(); + } + }) + } + + // if (filter == "By Repository"){ + // block.addSectionBlock({ + // text : { + // text : "By Repository Added", + // type : TextObjectType.PLAINTEXT + // } + // }) + // } + + return { + id : viewId, + title : { + text : "Your Issues", + type : TextObjectType.PLAINTEXT + }, + blocks : block.getBlocks() + } + +} From b80f774ba6f8837edfe1359b0ab6ec3e78fb71b2 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sun, 6 Nov 2022 00:47:14 +0530 Subject: [PATCH 12/33] feat: Search Filter Actions Added --- github/handlers/ExecuteBlockActionHandler.ts | 119 ++++++++++++++++++- 1 file changed, 116 insertions(+), 3 deletions(-) diff --git a/github/handlers/ExecuteBlockActionHandler.ts b/github/handlers/ExecuteBlockActionHandler.ts index a691f79..0269c1f 100644 --- a/github/handlers/ExecuteBlockActionHandler.ts +++ b/github/handlers/ExecuteBlockActionHandler.ts @@ -42,6 +42,7 @@ import { GithubRepoIssuesStorage } from "../persistance/githubIssues"; import { IGitHubIssueData } from "../definitions/githubIssueData"; import { shareProfileModal } from "../modals/profileShareModal"; import { RocketChatAssociationModel, RocketChatAssociationRecord } from "@rocket.chat/apps-engine/definition/metadata"; +import { userIssuesModal } from "../modals/UserIssuesModal"; export class ExecuteBlockActionHandler { @@ -53,6 +54,7 @@ export class ExecuteBlockActionHandler { private readonly persistence: IPersistence ) { } + public async run( context: UIKitBlockInteractionContext ): Promise { @@ -104,10 +106,122 @@ export class ExecuteBlockActionHandler { success: false, }; } - break; + } + case ModalsEnum.SWITCH_ISSUE_FILTER : { + const record = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ISSUE_MAIN_FILTER"); + const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record); + const {user, value} = context.getInteractionData(); + let filter : {filter : string, state : string, sort: string, order: string} | undefined; + + if (issueFilterArray.length != 0){ + filter = issueFilterArray[0] as { filter : string, state : string, sort: string, order: string}; + filter.filter = value as string; + }else { + filter = { + filter : value as string, + sort : ModalsEnum.ISSUE_SORT_CREATED, + state : ModalsEnum.ISSUE_STATE_OPEN, + order : ModalsEnum.ISSUES_DESCENDING + } + } + + let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + const issueModal = await userIssuesModal({ + access_token : access_token.token, + filter : filter, + modify : this.modify, + read : this.read, + persistence : this.persistence, + http : this.http + }) + + await this.persistence.updateByAssociation(record, filter); + + + return context.getInteractionResponder().updateModalViewResponse(issueModal); + } + + case ModalsEnum.SWITCH_ISSUE_SORT : { + const record = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ISSUE_MAIN_FILTER"); + const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record); + const {user, value} = context.getInteractionData(); + let filter : {filter : string, state : string, sort: string, order: string} | undefined; + + if (issueFilterArray.length != 0){ + filter = issueFilterArray[0] as { filter : string, state : string, sort: string, order: string}; + filter.filter = value as string; + }else { + filter = { + filter : ModalsEnum.ASSIGNED_ISSUE_FILTER, + sort : value as string, + state : ModalsEnum.ISSUE_STATE_OPEN, + order : ModalsEnum.ISSUES_DESCENDING + } + } + + let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + const issueModal = await userIssuesModal({ + access_token : access_token.token, + filter : filter, + modify : this.modify, + read : this.read, + persistence : this.persistence, + http : this.http + }) + + await this.persistence.updateByAssociation(record, filter); + + return context.getInteractionResponder().updateModalViewResponse(issueModal); + + } + case ModalsEnum.SWITCH_ISSUE_STATE : { + const record = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ISSUE_MAIN_FILTER"); + const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record); + const {user, value} = context.getInteractionData(); + let filter : {filter : string, state : string, sort: string, order: string} | undefined; + + if (issueFilterArray.length != 0){ + filter = issueFilterArray[0] as { filter : string, state : string, sort: string, order: string}; + filter.filter = value as string; + }else { + filter = { + filter : ModalsEnum.ASSIGNED_ISSUE_FILTER, + sort : ModalsEnum.ISSUE_SORT_CREATED, + state : value as string, + order : ModalsEnum.ISSUES_DESCENDING + } + } + + let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + const issueModal = await userIssuesModal({ + access_token : access_token.token, + filter : filter, + modify : this.modify, + read : this.read, + persistence : this.persistence, + http : this.http + }) + + await this.persistence.updateByAssociation(record, filter); + + return context.getInteractionResponder().updateModalViewResponse(issueModal); } case ModalsEnum.TRIGGER_ISSUES_MODAL : { - break; + + const {user} = context.getInteractionData(); + + let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + + const issuesModal = await userIssuesModal({ + access_token : access_token.token, + modify: this.modify, + read : this.read, + persistence : this.persistence, + http : this.http, + uikitcontext : context + }) + + return context.getInteractionResponder().openModalViewResponse(issuesModal); } case ModalsEnum.TRIGGER_REPOS_MODAL : { break; @@ -116,7 +230,6 @@ export class ExecuteBlockActionHandler { break; } case ModalsEnum.SHARE_PROFILE_PARAMS : { - const { user } = context.getInteractionData(); const profileInteractionData = context.getInteractionData().value; const datAny = profileInteractionData as any; const storeData = { From 39ca92709efb9df5a59ade46ef0d483d3020de82 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sun, 6 Nov 2022 00:47:45 +0530 Subject: [PATCH 13/33] feat: Github SDK Configured for issue search methods --- github/enum/Modals.ts | 19 +++++++++++++++++++ github/helpers/githubSDK.ts | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index 0f762a2..0d70d0f 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -1,4 +1,23 @@ export enum ModalsEnum { + SWITCH_ISSUE_ORDER = 'switch-issue-order', + ISSUES_ASCENDING = 'asc', + ISSUES_DESCENDING = 'desc', + SWITCH_ISSUE_STATE = 'switch-issue-state', + SWITCH_ISSUE_SORT = 'switch-issue-sort', + ISSUE_SORT_CREATED = 'created', + ISSUE_SORT_UPDATED = 'updated', + ISSUE_SORT_COMMENTS = 'comments', + ISSUE_STATE_OPEN = 'open', + ISSUE_STATE_CLOSED = 'closed', + ISSUE_STATE_ALL = 'all', + ASSIGNED_ISSUE_FILTER = 'assigned', + CREATED_ISSUE_FILTER = 'created', + MENTIONED_ISSUE_FILTER = 'mentioned', + SUBSCRIBED_ISSUE_FILTER = 'subscribed', + REPOS_ISSUE_FILTER = 'repos', + ALL_ISSUE_FILTER = 'all', + SWITCH_ISSUE_FILTER = 'switch-issue-filter', + USER_ISSUE_VIEW = 'user-issue-view', TRIGGER_ISSUES_MODAL = 'trigger-issue-modal', TRIGGER_REPOS_MODAL = 'trigger-repos-modal', TRIGGER_ACTIVITY_MODAL = 'trigger-activity-modal', diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index 2698864..ceffe33 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -1,4 +1,5 @@ import { IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { ModalsEnum } from "../enum/Modals"; const BaseHost = "https://github.com/"; const BaseApiHost = "https://api.github.com/"; @@ -461,6 +462,39 @@ export async function getBasicUserInfo( } } +// TODO : MAKE THE RESPONSE FORMAT EXPORTABLE +export async function getUserAssignedIssues( + http: IHttp, + username: String, + access_token : String, + filter : { + filter : String, + state : String, + sort : String + }, +){ + + try { + const response = await getRequest( + http, + access_token, + filter.filter == ModalsEnum.CREATED_ISSUE_FILTER ? `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+author:${username}`: (filter.filter == ModalsEnum.ASSIGNED_ISSUE_FILTER ? `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+assignee:${username}`: `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+mentions:${username}` + )); + + return response + } + catch(e){ + + console.log("ERROR GENERATED FROM HTTP REQUEST"); + console.log(e); + + return { + + } + } + +} + export async function addNewPullRequestComment( http: IHttp, repoName: string, From b33a4821f3722a5e236cdd242db88cf8851262ef Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sun, 6 Nov 2022 18:46:09 +0530 Subject: [PATCH 14/33] feat: Octicon Icons Added for Issue Modal --- github/enum/OcticonIcons.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 github/enum/OcticonIcons.ts diff --git a/github/enum/OcticonIcons.ts b/github/enum/OcticonIcons.ts new file mode 100644 index 0000000..0174b80 --- /dev/null +++ b/github/enum/OcticonIcons.ts @@ -0,0 +1,9 @@ +export enum OcticonIcons { + ISSUE_OPEN = "https://raw.githubusercontent.com/primer/octicons/main/icons/issue-opened-24.svg", + ISSUE_CLOSED = "https://raw.githubusercontent.com/primer/octicons/main/icons/issue-closed-24.svg", + COMMENTS = "https://raw.githubusercontent.com/primer/octicons/main/icons/comment-24.svg", + COMMIT = "https://raw.githubusercontent.com/primer/octicons/main/icons/commit-24.svg", + PERSON = "https://raw.githubusercontent.com/primer/octicons/main/icons/person-24.svg", + REPOSITORY = "https://raw.githubusercontent.com/primer/octicons/main/icons/repo-24.svg", + PENCIL = "https://raw.githubusercontent.com/primer/octicons/main/icons/pencil-24.svg" +} From 52daabb3eec855a7aef0b5ab6aab5c4648511f98 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Sun, 6 Nov 2022 18:46:34 +0530 Subject: [PATCH 15/33] feat: Issues Modal UI Modified and Improved --- github/modals/UserIssuesModal.ts | 87 ++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/github/modals/UserIssuesModal.ts b/github/modals/UserIssuesModal.ts index 03d8922..0b17711 100644 --- a/github/modals/UserIssuesModal.ts +++ b/github/modals/UserIssuesModal.ts @@ -1,8 +1,9 @@ import { IModify, IRead, IPersistence, IHttp } from "@rocket.chat/apps-engine/definition/accessors"; import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; -import { TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { ButtonStyle, TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; import { ModalsEnum } from "../enum/Modals"; +import { OcticonIcons } from "../enum/OcticonIcons"; import { getBasicUserInfo, getUserAssignedIssues } from "../helpers/githubSDK"; import { getInteractionRoomData, storeInteractionRoomData } from "../persistance/roomInteraction"; @@ -158,13 +159,6 @@ export async function userIssuesModal ({ ] }); - block.addSectionBlock({ - text : { - text : "Issues", - type : TextObjectType.PLAINTEXT - }, - }); - if (repoInfo.items.length == 0){ block.addContextBlock({ elements : [ @@ -175,26 +169,80 @@ export async function userIssuesModal ({ else { repoInfo.items.map((value) => { if (value.pull_request == undefined){ + const repoURL = value.repository_url as string; + const repoName = repoURL.substring(29, repoURL.length); + block.addContextBlock({ + elements : [ + block.newImageElement({ + imageUrl : OcticonIcons.REPOSITORY, + altText : "REPO_ICON" + }), + block.newPlainTextObject(repoName, false), + block.newImageElement({ + imageUrl : value.user.avatar_url as string, + altText : "User Image" + }), + block.newPlainTextObject(value.user.login) + ] + }) block.addSectionBlock({ text : { - text : value.title ?? "None", + text : `\`#${value.number}\` ${value.title}` ?? "None", type : TextObjectType.MARKDOWN - } + }, }) + const lastUpdated = new Date(value.updated_at); + block.addContextBlock({ + elements : [ + block.newImageElement({ + imageUrl : OcticonIcons.COMMENTS, + altText : "Comments" + }), + block.newPlainTextObject(value.comments as string, false), + block.newImageElement({ + imageUrl : OcticonIcons.ISSUE_OPEN, + altText : "Assignees Icon" + }), + block.newPlainTextObject(value.assignees.length == 0 ? "No Assignees" : `${value.assignees.length} Assignees`), + block.newImageElement({ + imageUrl : value.state == "open" ? OcticonIcons.ISSUE_OPEN : OcticonIcons.ISSUE_CLOSED, + altText : "State" + }), + block.newPlainTextObject(`${value.state}`), + block.newImageElement({ + imageUrl : OcticonIcons.PENCIL, + altText : "Last Update At" + }), + block.newPlainTextObject(`Last Updated at ${lastUpdated.toUTCString()}`) + + ] + }) + + block.addActionsBlock({ + elements : [ + block.newButtonElement({ + text : { + text : "Share Issue", + type : TextObjectType.PLAINTEXT + }, + style : ButtonStyle.PRIMARY + }), + block.newButtonElement({ + text : { + text : "Open Issue", + type : TextObjectType.PLAINTEXT + }, + style : ButtonStyle.PRIMARY + }) + ] + }) + + block.addDividerBlock(); } }) } - // if (filter == "By Repository"){ - // block.addSectionBlock({ - // text : { - // text : "By Repository Added", - // type : TextObjectType.PLAINTEXT - // } - // }) - // } - return { id : viewId, title : { @@ -203,5 +251,4 @@ export async function userIssuesModal ({ }, blocks : block.getBlocks() } - } From 608bbd99d845393c8e9c362c50fc83c9d5ebf753 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Wed, 9 Nov 2022 13:39:29 +0530 Subject: [PATCH 16/33] feat: Github Issue Schema Modified for Issue Display Modal. --- github/definitions/githubIssue.ts | 12 ++++++++++-- github/definitions/githubReactions.ts | 13 +++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 github/definitions/githubReactions.ts diff --git a/github/definitions/githubIssue.ts b/github/definitions/githubIssue.ts index 597517b..b32438c 100644 --- a/github/definitions/githubIssue.ts +++ b/github/definitions/githubIssue.ts @@ -1,13 +1,21 @@ +import { IGithubReactions } from "./githubReactions" + //inidividual issue export interface IGitHubIssue{ issue_id: string|number, title?: string, - html_url?: string, + html_url?: string, number?: string|number labels?: Array, user_login?:string, + user_avatar?:string, + last_updated_at?: string, + comments?:string|number, state?: string, share?: boolean,//true if seacrh result is to be shareed assignees?: Array,//user ids seperated by " " issue_compact: string,//compact string to share issues in rooms -} \ No newline at end of file + repo_url?: string, + body?: string, + reactions? : IGithubReactions +} diff --git a/github/definitions/githubReactions.ts b/github/definitions/githubReactions.ts new file mode 100644 index 0000000..04624d6 --- /dev/null +++ b/github/definitions/githubReactions.ts @@ -0,0 +1,13 @@ +// reactions object for issues, comments and repos + +export interface IGithubReactions { + total_count : number, + plus_one : number, + minus_one : number, + laugh : number, + hooray : number, + confused : number, + heart : number, + rocket : number, + eyes : number +} From 7fb70da3bfa458c887187ec3239047238c05ddf0 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Wed, 9 Nov 2022 13:40:05 +0530 Subject: [PATCH 17/33] feat: Isse Display trigger and Modal added --- github/enum/Modals.ts | 1 + github/handlers/ExecuteBlockActionHandler.ts | 23 +++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index 0d70d0f..f6cddb1 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -1,4 +1,5 @@ export enum ModalsEnum { + TRIGGER_ISSUE_DISPLAY_MODAL = 'display-issue', SWITCH_ISSUE_ORDER = 'switch-issue-order', ISSUES_ASCENDING = 'asc', ISSUES_DESCENDING = 'desc', diff --git a/github/handlers/ExecuteBlockActionHandler.ts b/github/handlers/ExecuteBlockActionHandler.ts index 0269c1f..da96ef7 100644 --- a/github/handlers/ExecuteBlockActionHandler.ts +++ b/github/handlers/ExecuteBlockActionHandler.ts @@ -43,6 +43,7 @@ import { IGitHubIssueData } from "../definitions/githubIssueData"; import { shareProfileModal } from "../modals/profileShareModal"; import { RocketChatAssociationModel, RocketChatAssociationRecord } from "@rocket.chat/apps-engine/definition/metadata"; import { userIssuesModal } from "../modals/UserIssuesModal"; +import { IssueDisplayModal } from "../modals/IssueDisplayModal"; export class ExecuteBlockActionHandler { @@ -107,6 +108,26 @@ export class ExecuteBlockActionHandler { }; } } + case ModalsEnum.TRIGGER_ISSUE_DISPLAY_MODAL : { + const {user, value} = context.getInteractionData(); + const access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + + const repoInfo = value?.split(",")[0] ?? ""; + const issueNumber = value?.split(",")[1] ?? ""; + + const issueDisplayModal = await IssueDisplayModal({ + repoName : repoInfo, + issueNumber : issueNumber, + access_token : access_token.token, + modify : this.modify, + read : this.read, + persistence : this.persistence, + http : this.http, + uikitcontext : context + }) + + return context.getInteractionResponder().updateModalViewResponse(issueDisplayModal); + } case ModalsEnum.SWITCH_ISSUE_FILTER : { const record = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ISSUE_MAIN_FILTER"); const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record); @@ -219,7 +240,7 @@ export class ExecuteBlockActionHandler { persistence : this.persistence, http : this.http, uikitcontext : context - }) + }); return context.getInteractionResponder().openModalViewResponse(issuesModal); } From e6c2a81b0fde83d36d3c0f6ec8c9e83cfdfed857 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Wed, 9 Nov 2022 13:51:35 +0530 Subject: [PATCH 18/33] feat : Github SDK modified for issue data --- github/helpers/githubSDK.ts | 74 +++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index ceffe33..2140e66 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -1,4 +1,5 @@ import { IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { IGitHubIssue } from "../definitions/githubIssue"; import { ModalsEnum } from "../enum/Modals"; const BaseHost = "https://github.com/"; @@ -462,7 +463,6 @@ export async function getBasicUserInfo( } } -// TODO : MAKE THE RESPONSE FORMAT EXPORTABLE export async function getUserAssignedIssues( http: IHttp, username: String, @@ -472,8 +472,7 @@ export async function getUserAssignedIssues( state : String, sort : String }, -){ - +) : Promise{ try { const response = await getRequest( http, @@ -481,18 +480,77 @@ export async function getUserAssignedIssues( filter.filter == ModalsEnum.CREATED_ISSUE_FILTER ? `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+author:${username}`: (filter.filter == ModalsEnum.ASSIGNED_ISSUE_FILTER ? `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+assignee:${username}`: `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+mentions:${username}` )); - return response + const getAssignees = (assignees : any[]) : string[] => assignees.map((val): string => { + return val.login as string; + }) + + const modifiedResponse : Array = response.items.map((value) : IGitHubIssue => { + return { + issue_id : value.id as string, + issue_compact : value.body as string, + repo_url : value.repository_url as string, + user_login : value.user.login as string, + user_avatar : value.user.avatar_url as string, + number : value.number as number, + title : value.title as string, + body : value.body as string, + assignees : getAssignees(value.assignees), + state : value.state as string, + last_updated_at : value.updated_at as string, + comments : value.comments as number, + } + }) + + return modifiedResponse; } catch(e){ + return []; + } +} - console.log("ERROR GENERATED FROM HTTP REQUEST"); - console.log(e); +export async function getIssueData( + repoInfo:String, + issueNumber:String, + access_token:String, + http:IHttp +) : Promise { + try { + const response = await getRequest(http, access_token, BaseRepoApiHost + repoInfo + '/issues/' + issueNumber); + const getAssignees = (assignees : any[]) : string[] => assignees.map((val): string => { + return val.login as string; + }) return { - + issue_id : response.id as string, + issue_compact : response.body as string, + repo_url : response.repository_url as string, + user_login : response.user.login as string, + user_avatar : response.user.avatar_url as string, + number : response.number as number, + title : response.title as string, + body : response.body as string, + assignees : getAssignees(response.assignees), + state : response.state as string, + last_updated_at : response.updated_at as string, + comments : response.comments as number, + reactions : { + total_count : response.reactions["total_count"], + plus_one : response.reactions["+1"], + minus_one : response.reactions["-1"], + laugh : response.reactions["laugh"], + hooray : response.reactions["hooray"], + confused : response.reactions["confused"], + heart : response.reactions["heart"], + rocket : response.reactions["rocket"], + eyes : response.reactions["eyes"] + } + } + }catch(e) { + return { + issue_compact : "Error Fetching Issue", + issue_id : 0 } } - } export async function addNewPullRequestComment( From 34d4ac5a2d10578a032850280fa884bd3d822be7 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Wed, 9 Nov 2022 13:51:54 +0530 Subject: [PATCH 19/33] feat : Issue Display Modal Added to UI --- github/modals/IssueDisplayModal.ts | 154 ++++++++++++ github/modals/UserIssuesModal.ts | 370 ++++++++++++++++------------- 2 files changed, 357 insertions(+), 167 deletions(-) create mode 100644 github/modals/IssueDisplayModal.ts diff --git a/github/modals/IssueDisplayModal.ts b/github/modals/IssueDisplayModal.ts new file mode 100644 index 0000000..1e53ee8 --- /dev/null +++ b/github/modals/IssueDisplayModal.ts @@ -0,0 +1,154 @@ +import { IModify, IRead, IPersistence, IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { IGitHubIssue } from "../definitions/githubIssue"; +import { IGithubReactions } from "../definitions/githubReactions"; +import { ModalsEnum } from "../enum/Modals"; +import { OcticonIcons } from "../enum/OcticonIcons"; +import { getIssueData, getUserAssignedIssues } from "../helpers/githubSDK"; +import { getInteractionRoomData, storeInteractionRoomData } from "../persistance/roomInteraction"; +import { BodyMarkdownRenderer } from "../processors/bodyMarkdowmRenderer"; + +export async function IssueDisplayModal ({ + repoName, + issueNumber, + access_token, + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext +} : { + repoName : String, + issueNumber : String, + access_token: String, + modify : IModify, + read: IRead, + persistence: IPersistence, + http: IHttp, + slashcommandcontext?: SlashCommandContext, + uikitcontext?: UIKitInteractionContext +}) : Promise { + const viewId = ModalsEnum.USER_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; + } + } + + const issueInfo : IGitHubIssue = await getIssueData(repoName, issueNumber, access_token, http); + + if (issueInfo.issue_id == 0){ + block.addSectionBlock({ + text : { + text : "Sorry there is some issue fetching this issue, try again later", + type : TextObjectType.PLAINTEXT + }, + }) + return { + id : viewId, + title : { + text : "Error", + type : TextObjectType.PLAINTEXT + }, + blocks : block.getBlocks() + } + } + + const lastUpdated = new Date(issueInfo.last_updated_at ?? ""); + + block.addContextBlock({ + elements : [ + block.newImageElement({ + imageUrl: OcticonIcons.PENCIL, + altText: "Last Update At", + }), + block.newPlainTextObject( + `Last Updated at ${ lastUpdated.toISOString() }` + ), + ] + }) + + block.addContextBlock({ + elements: [ + block.newImageElement({ + imageUrl: OcticonIcons.COMMENTS, + altText: "Comments", + }), + block.newPlainTextObject( + `${issueInfo.comments}`, + false + ), + block.newImageElement({ + imageUrl: OcticonIcons.ISSUE_OPEN, + altText: "Assignees Icon", + }), + block.newPlainTextObject( + issueInfo.assignees ? (issueInfo.assignees.length == 0 + ? "No Assignees" + : `${issueInfo.assignees.length} Assignees`) : "" + ), + block.newImageElement({ + imageUrl: + issueInfo.state == "open" + ? OcticonIcons.ISSUE_OPEN + : OcticonIcons.ISSUE_CLOSED, + altText: "State", + }), + block.newPlainTextObject(`${issueInfo.state}`), + block.newImageElement({ + imageUrl: issueInfo.user_avatar ?? "", + altText: "User Image", + }), + block.newPlainTextObject(`Created by ${issueInfo.user_login}` ?? ""), + ], + }); + + block.addSectionBlock({ + text : { + text : `*${issueInfo.title}*` ?? "", + type : TextObjectType.MARKDOWN + } + }) + block.addDividerBlock(); + + // reactions + + const reactions = issueInfo.reactions + + block.addContextBlock({ + elements : [ + block.newPlainTextObject(`Total Reactions ${reactions?.total_count}`, true), + block.newPlainTextObject(`➕ ${reactions?.plus_one} `, true), + block.newPlainTextObject(`➖ ${reactions?.minus_one}`, true), + block.newPlainTextObject(`😄 ${reactions?.laugh}`, true), + block.newPlainTextObject(`🎉 ${reactions?.hooray}`, true), + block.newPlainTextObject(`😕 ${reactions?.confused}`, true), + block.newPlainTextObject(`♥️ ${reactions?.heart}`, true), + block.newPlainTextObject(`🚀 ${reactions?.rocket}`, true), + block.newPlainTextObject(`👀 ${reactions?.eyes}`, true), + ] + }) + + issueInfo.body && BodyMarkdownRenderer({body : issueInfo.body, block : block}) + + return { + id : viewId, + title : { + text : `${repoName} \`#${issueNumber}\``, + type : TextObjectType.PLAINTEXT + }, + blocks : block.getBlocks() + } +} diff --git a/github/modals/UserIssuesModal.ts b/github/modals/UserIssuesModal.ts index 0b17711..1a5a58f 100644 --- a/github/modals/UserIssuesModal.ts +++ b/github/modals/UserIssuesModal.ts @@ -1,17 +1,29 @@ -import { IModify, IRead, IPersistence, IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { + IModify, + IRead, + IPersistence, + IHttp, +} from "@rocket.chat/apps-engine/definition/accessors"; import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; -import { ButtonStyle, TextObjectType, UIKitInteractionContext } from "@rocket.chat/apps-engine/definition/uikit"; +import { + ButtonStyle, + TextObjectType, + UIKitInteractionContext, +} from "@rocket.chat/apps-engine/definition/uikit"; import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; import { ModalsEnum } from "../enum/Modals"; import { OcticonIcons } from "../enum/OcticonIcons"; import { getBasicUserInfo, getUserAssignedIssues } from "../helpers/githubSDK"; -import { getInteractionRoomData, storeInteractionRoomData } from "../persistance/roomInteraction"; +import { + getInteractionRoomData, + storeInteractionRoomData, +} from "../persistance/roomInteraction"; -export async function userIssuesModal ({ +export async function userIssuesModal({ filter = { - filter : ModalsEnum.ALL_ISSUE_FILTER, - state : ModalsEnum.ISSUE_STATE_OPEN, - sort : ModalsEnum.ISSUE_SORT_CREATED + filter: ModalsEnum.ALL_ISSUE_FILTER, + state: ModalsEnum.ISSUE_STATE_OPEN, + sort: ModalsEnum.ISSUE_SORT_CREATED, }, access_token, modify, @@ -19,236 +31,260 @@ export async function userIssuesModal ({ persistence, http, slashcommandcontext, - uikitcontext -} : { + uikitcontext, +}: { filter?: { - filter : String, - state : String, - sort : String - }, - access_token: String, - modify : IModify, - read: IRead, - persistence: IPersistence, - http: IHttp, - slashcommandcontext?: SlashCommandContext, - uikitcontext?: UIKitInteractionContext -}) : Promise { + filter: String; + state: String; + sort: String; + }; + access_token: String; + modify: IModify; + read: IRead; + persistence: IPersistence; + http: IHttp; + slashcommandcontext?: SlashCommandContext; + uikitcontext?: UIKitInteractionContext; +}): Promise { const viewId = ModalsEnum.USER_ISSUE_VIEW; const block = modify.getCreator().getBlockBuilder(); - const room = slashcommandcontext?.getRoom() || uikitcontext?.getInteractionData().room; - const user = slashcommandcontext?.getSender() || uikitcontext?.getInteractionData().user; + const room = + slashcommandcontext?.getRoom() || + uikitcontext?.getInteractionData().room; + const user = + slashcommandcontext?.getSender() || + uikitcontext?.getInteractionData().user; - if (user?.id){ + if (user?.id) { let roomId; - if (room?.id){ + if (room?.id) { roomId = room.id; await storeInteractionRoomData(persistence, user.id, roomId); - } - else { - roomId = (await getInteractionRoomData(read.getPersistenceReader(), user.id)).roomId; + } else { + roomId = ( + await getInteractionRoomData( + read.getPersistenceReader(), + user.id + ) + ).roomId; } } const userInfo = await getBasicUserInfo(http, access_token); - const repoInfo = await getUserAssignedIssues(http,userInfo.username, access_token, filter); - + const repoInfo = await getUserAssignedIssues( + http, + userInfo.username, + access_token, + filter + ); block.addActionsBlock({ - elements : [ + elements: [ block.newStaticSelectElement({ - actionId : ModalsEnum.SWITCH_ISSUE_FILTER, - placeholder : { - text : "Select an Issue Filter", - type : TextObjectType.PLAINTEXT + actionId: ModalsEnum.SWITCH_ISSUE_FILTER, + placeholder: { + text: "Select an Issue Filter", + type: TextObjectType.PLAINTEXT, }, - initialValue : ModalsEnum.ASSIGNED_ISSUE_FILTER, - options : [ - { - value : ModalsEnum.ASSIGNED_ISSUE_FILTER, - text : { - text : "Assigned", - type : TextObjectType.PLAINTEXT - } - }, - { - value : ModalsEnum.CREATED_ISSUE_FILTER, - text : { - text : "Created", - type : TextObjectType.PLAINTEXT - } - }, - { - value : ModalsEnum.MENTIONED_ISSUE_FILTER, - text : { - text : "Mentioned", - type : TextObjectType.PLAINTEXT - } - } - ] - }) - ] + initialValue: ModalsEnum.ASSIGNED_ISSUE_FILTER, + options: [ + { + value: ModalsEnum.ASSIGNED_ISSUE_FILTER, + text: { + text: "Assigned", + type: TextObjectType.PLAINTEXT, + }, + }, + { + value: ModalsEnum.CREATED_ISSUE_FILTER, + text: { + text: "Created", + type: TextObjectType.PLAINTEXT, + }, + }, + { + value: ModalsEnum.MENTIONED_ISSUE_FILTER, + text: { + text: "Mentioned", + type: TextObjectType.PLAINTEXT, + }, + }, + ], + }), + ], }); block.addActionsBlock({ - elements : [ + elements: [ block.newStaticSelectElement({ - actionId : ModalsEnum.SWITCH_ISSUE_STATE, - placeholder : { - text : "Select Issues State", - type : TextObjectType.PLAINTEXT + actionId: ModalsEnum.SWITCH_ISSUE_STATE, + placeholder: { + text: "Select Issues State", + type: TextObjectType.PLAINTEXT, }, - initialValue : ModalsEnum.ISSUE_STATE_OPEN, - options : [ + initialValue: ModalsEnum.ISSUE_STATE_OPEN, + options: [ { - value : ModalsEnum.ISSUE_STATE_OPEN, - text : { - text : "Open Issues", - type : TextObjectType.PLAINTEXT + value: ModalsEnum.ISSUE_STATE_OPEN, + text: { + text: "Open Issues", + type: TextObjectType.PLAINTEXT, }, }, { - value : ModalsEnum.ISSUE_STATE_CLOSED, - text : { + value: ModalsEnum.ISSUE_STATE_CLOSED, + text: { text: "Closed Issues", - type : TextObjectType.PLAINTEXT - } + type: TextObjectType.PLAINTEXT, + }, }, { - value : ModalsEnum.ISSUE_STATE_ALL, - text : { - text : "All Issues", - type : TextObjectType.PLAINTEXT - } - } - ] + value: ModalsEnum.ISSUE_STATE_ALL, + text: { + text: "All Issues", + type: TextObjectType.PLAINTEXT, + }, + }, + ], }), block.newStaticSelectElement({ - actionId : ModalsEnum.SWITCH_ISSUE_SORT, - placeholder : { - text : "Sort Issues By...", - type : TextObjectType.PLAINTEXT + actionId: ModalsEnum.SWITCH_ISSUE_SORT, + placeholder: { + text: "Sort Issues By...", + type: TextObjectType.PLAINTEXT, }, - initialValue : ModalsEnum.ISSUE_SORT_CREATED, - options : [ + initialValue: ModalsEnum.ISSUE_SORT_CREATED, + options: [ { - value : ModalsEnum.ISSUE_SORT_CREATED, - text : { - text : "Created", - type : TextObjectType.PLAINTEXT - } + value: ModalsEnum.ISSUE_SORT_CREATED, + text: { + text: "Created", + type: TextObjectType.PLAINTEXT, + }, }, { - value : ModalsEnum.ISSUE_SORT_UPDATED, - text : { - text : "Updated", - type : TextObjectType.PLAINTEXT - } + value: ModalsEnum.ISSUE_SORT_UPDATED, + text: { + text: "Updated", + type: TextObjectType.PLAINTEXT, + }, }, { - value : ModalsEnum.ISSUE_SORT_COMMENTS, - text : { - text : "Comments", - type : TextObjectType.PLAINTEXT - } - } - ] + value: ModalsEnum.ISSUE_SORT_COMMENTS, + text: { + text: "Comments", + type: TextObjectType.PLAINTEXT, + }, + }, + ], }), - - ] + ], }); - if (repoInfo.items.length == 0){ + if (repoInfo.length == 0) { block.addContextBlock({ - elements : [ - block.newPlainTextObject("Sorry, there are no issues to display") - ] - }) - } - else { - repoInfo.items.map((value) => { - if (value.pull_request == undefined){ - const repoURL = value.repository_url as string; + elements: [ + block.newPlainTextObject( + "Sorry, there are no issues to display" + ), + ], + }); + } else { + repoInfo.map( + (value) => { + const repoURL = value.repo_url ?? ""; const repoName = repoURL.substring(29, repoURL.length); block.addContextBlock({ - elements : [ + elements: [ block.newImageElement({ - imageUrl : OcticonIcons.REPOSITORY, - altText : "REPO_ICON" + imageUrl: OcticonIcons.REPOSITORY, + altText: "REPO_ICON", }), block.newPlainTextObject(repoName, false), block.newImageElement({ - imageUrl : value.user.avatar_url as string, - altText : "User Image" + imageUrl: value.user_avatar ?? "", + altText: "User Image", }), - block.newPlainTextObject(value.user.login) - ] - }) + block.newPlainTextObject(value.user_login ?? ""), + ], + }); block.addSectionBlock({ - text : { - text : `\`#${value.number}\` ${value.title}` ?? "None", - type : TextObjectType.MARKDOWN + text: { + text: `\`#${value.number}\` ${value.title}` ?? "None", + type: TextObjectType.MARKDOWN, }, - }) - const lastUpdated = new Date(value.updated_at); + }); + const lastUpdated = new Date(value.last_updated_at ?? ""); block.addContextBlock({ - elements : [ + elements: [ block.newImageElement({ - imageUrl : OcticonIcons.COMMENTS, - altText : "Comments" + imageUrl: OcticonIcons.COMMENTS, + altText: "Comments", }), - block.newPlainTextObject(value.comments as string, false), + block.newPlainTextObject( + `${value.comments}`, + false + ), block.newImageElement({ - imageUrl : OcticonIcons.ISSUE_OPEN, - altText : "Assignees Icon" + imageUrl: OcticonIcons.ISSUE_OPEN, + altText: "Assignees Icon", }), - block.newPlainTextObject(value.assignees.length == 0 ? "No Assignees" : `${value.assignees.length} Assignees`), + block.newPlainTextObject( + value.assignees ? (value.assignees.length == 0 + ? "No Assignees" + : `${value.assignees.length} Assignees`) : "" + ), block.newImageElement({ - imageUrl : value.state == "open" ? OcticonIcons.ISSUE_OPEN : OcticonIcons.ISSUE_CLOSED, - altText : "State" + imageUrl: + value.state == "open" + ? OcticonIcons.ISSUE_OPEN + : OcticonIcons.ISSUE_CLOSED, + altText: "State", }), block.newPlainTextObject(`${value.state}`), block.newImageElement({ - imageUrl : OcticonIcons.PENCIL, - altText : "Last Update At" + imageUrl: OcticonIcons.PENCIL, + altText: "Last Update At", }), - block.newPlainTextObject(`Last Updated at ${lastUpdated.toUTCString()}`) - - ] - }) + block.newPlainTextObject( + `Last Updated at ${lastUpdated.toUTCString()}` + ), + ], + }); block.addActionsBlock({ - elements : [ + elements: [ block.newButtonElement({ - text : { - text : "Share Issue", - type : TextObjectType.PLAINTEXT + value: ``, + text: { + text: "Share Issue", + type: TextObjectType.PLAINTEXT, }, - style : ButtonStyle.PRIMARY + style: ButtonStyle.PRIMARY, }), block.newButtonElement({ - text : { - text : "Open Issue", - type : TextObjectType.PLAINTEXT + actionId: ModalsEnum.TRIGGER_ISSUE_DISPLAY_MODAL, + value: `${repoName}, ${value.number}`, + text: { + text: "Open Issue", + type: TextObjectType.PLAINTEXT, }, - style : ButtonStyle.PRIMARY - }) - ] - }) - - + style: ButtonStyle.PRIMARY, + }), + ], + }); block.addDividerBlock(); } - }) + ); } return { - id : viewId, - title : { - text : "Your Issues", - type : TextObjectType.PLAINTEXT + id: viewId, + title: { + text: "Your Issues", + type: TextObjectType.PLAINTEXT, }, - blocks : block.getBlocks() - } + blocks: block.getBlocks(), + }; } From 098dbd1dec32c7537cd2a9533f0efd25cf3d043a Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Wed, 9 Nov 2022 13:52:11 +0530 Subject: [PATCH 20/33] feat: Body Markdown renderer added --- github/processors/bodyMarkdowmRenderer.ts | 92 +++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 github/processors/bodyMarkdowmRenderer.ts diff --git a/github/processors/bodyMarkdowmRenderer.ts b/github/processors/bodyMarkdowmRenderer.ts new file mode 100644 index 0000000..e7d2b93 --- /dev/null +++ b/github/processors/bodyMarkdowmRenderer.ts @@ -0,0 +1,92 @@ +import { + BlockBuilder, + TextObjectType, +} from "@rocket.chat/apps-engine/definition/uikit"; + +export async function BodyMarkdownRenderer({ + body, + block, +}: { + body: string; + block: BlockBuilder; +}) { + const patterns: { type: string; pattern: RegExp }[] = [ + { + type: "ImageTag", + pattern: RegExp(/()/g, "g"), + }, + { + type: "ImageMarkdownLink", + pattern: RegExp(/[!]\[([^\]]+)\]\(([^)]+(.png|jpg|svg|gif))\)/gim), + }, + ]; + + let matches: { beginningIndex: number; match: string; type: string }[] = []; + var match; + + patterns.forEach((patObj) => { + while ((match = patObj.pattern.exec(body)) != null) { + matches.push({ + beginningIndex: match.index, + match: match[0], + type: patObj.type, + }); + } + }); + + if (matches.length == 0) { + block.addSectionBlock({ + text: { + text: body, + type: TextObjectType.MARKDOWN, + }, + }); + } else { + matches.sort((a, b) => a.beginningIndex - b.beginningIndex); + matches.map((value, index) => { + let start = + index == 0 + ? 0 + : matches[index - 1].beginningIndex + + matches[index - 1].match.length; + + const rawURL = value.match.match( + /(https:\/\/.*\.(png|jpg|gif|svg))/gim + ); + const url = rawURL ? rawURL[0] : ""; + + block.addSectionBlock({ + text: { + text: body.substring(start, value.beginningIndex - 1) ?? "", + type: TextObjectType.MARKDOWN, + }, + }), + block.addImageBlock({ + imageUrl: url, + altText: "ImageURL", + }); + + if ( + index == matches.length - 1 && + value.beginningIndex + value.match.length < body.length + ) { + block.addSectionBlock({ + text: { + text: body.substring( + value.beginningIndex + value.match.length, + body.length + ), + type: TextObjectType.MARKDOWN, + }, + }); + } + }); + } + + // block.addSectionBlock({ + // text : { + // text : body, + // type : TextObjectType.PLAINTEXT + // } + // }) +} From d5d08f34459c5dc29c68c0060d3455969595ce05 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Thu, 10 Nov 2022 00:45:38 +0530 Subject: [PATCH 21/33] refactor: Issue Filter Action Optimized with Single Action --- github/enum/Modals.ts | 11 +- github/handlers/ExecuteBlockActionHandler.ts | 181 +++++++++++-------- github/helpers/githubSDK.ts | 23 ++- 3 files changed, 130 insertions(+), 85 deletions(-) diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index f6cddb1..bc3ee01 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -1,22 +1,19 @@ export enum ModalsEnum { + SHARE_ISSUE_ACTION = 'share-issue-action', TRIGGER_ISSUE_DISPLAY_MODAL = 'display-issue', SWITCH_ISSUE_ORDER = 'switch-issue-order', ISSUES_ASCENDING = 'asc', ISSUES_DESCENDING = 'desc', SWITCH_ISSUE_STATE = 'switch-issue-state', SWITCH_ISSUE_SORT = 'switch-issue-sort', - ISSUE_SORT_CREATED = 'created', - ISSUE_SORT_UPDATED = 'updated', - ISSUE_SORT_COMMENTS = 'comments', + ISSUE_SORT_CREATED = 'sort_created', + ISSUE_SORT_UPDATED = 'sort_updated', + ISSUE_SORT_COMMENTS = 'sort_comments', ISSUE_STATE_OPEN = 'open', ISSUE_STATE_CLOSED = 'closed', - ISSUE_STATE_ALL = 'all', ASSIGNED_ISSUE_FILTER = 'assigned', CREATED_ISSUE_FILTER = 'created', MENTIONED_ISSUE_FILTER = 'mentioned', - SUBSCRIBED_ISSUE_FILTER = 'subscribed', - REPOS_ISSUE_FILTER = 'repos', - ALL_ISSUE_FILTER = 'all', SWITCH_ISSUE_FILTER = 'switch-issue-filter', USER_ISSUE_VIEW = 'user-issue-view', TRIGGER_ISSUES_MODAL = 'trigger-issue-modal', diff --git a/github/handlers/ExecuteBlockActionHandler.ts b/github/handlers/ExecuteBlockActionHandler.ts index da96ef7..1018976 100644 --- a/github/handlers/ExecuteBlockActionHandler.ts +++ b/github/handlers/ExecuteBlockActionHandler.ts @@ -11,13 +11,14 @@ import { basicQueryMessage } from "../helpers/basicQueryMessage"; import { ModalsEnum } from "../enum/Modals"; import { fileCodeModal } from "../modals/fileCodeModal"; import { + ButtonStyle, IUIKitResponse, TextObjectType, UIKitBlockInteractionContext, } from "@rocket.chat/apps-engine/definition/uikit"; import { AddSubscriptionModal } from "../modals/addSubscriptionsModal"; import { deleteSubsciptionsModal } from "../modals/deleteSubscriptions"; -import { deleteSubscription, updateSubscription, getIssueTemplateCode, getPullRequestComments, getPullRequestData, getRepositoryIssues, getBasicUserInfo } from "../helpers/githubSDK"; +import { deleteSubscription, updateSubscription, getIssueTemplateCode, getPullRequestComments, getPullRequestData, getRepositoryIssues, getBasicUserInfo, getIssueData } from "../helpers/githubSDK"; import { Subscription } from "../persistance/subscriptions"; import { getAccessTokenForUser } from "../persistance/auth"; import { GithubApp } from "../GithubApp"; @@ -44,6 +45,9 @@ import { shareProfileModal } from "../modals/profileShareModal"; import { RocketChatAssociationModel, RocketChatAssociationRecord } from "@rocket.chat/apps-engine/definition/metadata"; import { userIssuesModal } from "../modals/UserIssuesModal"; import { IssueDisplayModal } from "../modals/IssueDisplayModal"; +import { IGitHubIssue } from "../definitions/githubIssue"; +import { BodyMarkdownRenderer } from "../processors/bodyMarkdowmRenderer"; +import { CreateIssueStatsBar } from "../lib/CreateIssueStatsBar"; export class ExecuteBlockActionHandler { @@ -108,6 +112,55 @@ export class ExecuteBlockActionHandler { }; } } + case ModalsEnum.SHARE_ISSUE_ACTION : { + let {user, value, room} = context.getInteractionData(); + const access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + + const repoName = value?.split(",")[0] ?? ""; + const issueNumber = value?.split(",")[1] ?? ""; + + const issueInfo : IGitHubIssue = await getIssueData(repoName, issueNumber, access_token.token, this.http); + + const block = this.modify.getCreator().getBlockBuilder(); + + CreateIssueStatsBar(issueInfo, block); + + block.addSectionBlock({ + text : { + text : `*${issueInfo.title}*` ?? "", + type : TextObjectType.MARKDOWN + } + }), + block.addActionsBlock({ + elements : [ + block.newButtonElement({ + text : { + text : "Open Issue in Browser", + type : TextObjectType.PLAINTEXT + }, + url : issueInfo.html_url, + style : ButtonStyle.PRIMARY + }) + ] + }) + issueInfo.body && BodyMarkdownRenderer({body : issueInfo.body, block : block}); + + if(user?.id){ + if(room?.id){ + await sendMessage(this.modify, room!, user, `Issue`, block) + }else{ + let roomId = ( + await getInteractionRoomData( + this.read.getPersistenceReader(), + user.id + ) + ).roomId; + room = await this.read.getRoomReader().getById(roomId) as IRoom; + await sendMessage(this.modify, room, user, `Issue`, block) + } + } + break; + } case ModalsEnum.TRIGGER_ISSUE_DISPLAY_MODAL : { const {user, value} = context.getInteractionData(); const access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; @@ -128,89 +181,58 @@ export class ExecuteBlockActionHandler { return context.getInteractionResponder().updateModalViewResponse(issueDisplayModal); } + case ModalsEnum.SWITCH_ISSUE_SORT : + case ModalsEnum.SWITCH_ISSUE_STATE : case ModalsEnum.SWITCH_ISSUE_FILTER : { const record = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ISSUE_MAIN_FILTER"); - const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record); - const {user, value} = context.getInteractionData(); - let filter : {filter : string, state : string, sort: string, order: string} | undefined; - - if (issueFilterArray.length != 0){ - filter = issueFilterArray[0] as { filter : string, state : string, sort: string, order: string}; - filter.filter = value as string; - }else { - filter = { - filter : value as string, - sort : ModalsEnum.ISSUE_SORT_CREATED, - state : ModalsEnum.ISSUE_STATE_OPEN, - order : ModalsEnum.ISSUES_DESCENDING - } - } - - let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; - const issueModal = await userIssuesModal({ - access_token : access_token.token, - filter : filter, - modify : this.modify, - read : this.read, - persistence : this.persistence, - http : this.http - }) - - await this.persistence.updateByAssociation(record, filter); + const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record) as {filter : string, state : string, sort: string, order: string}[]; - return context.getInteractionResponder().updateModalViewResponse(issueModal); - } - - case ModalsEnum.SWITCH_ISSUE_SORT : { - const record = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ISSUE_MAIN_FILTER"); - const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record); const {user, value} = context.getInteractionData(); - let filter : {filter : string, state : string, sort: string, order: string} | undefined; - - if (issueFilterArray.length != 0){ - filter = issueFilterArray[0] as { filter : string, state : string, sort: string, order: string}; - filter.filter = value as string; - }else { - filter = { - filter : ModalsEnum.ASSIGNED_ISSUE_FILTER, - sort : value as string, - state : ModalsEnum.ISSUE_STATE_OPEN, - order : ModalsEnum.ISSUES_DESCENDING - } - } - - let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; - const issueModal = await userIssuesModal({ - access_token : access_token.token, - filter : filter, - modify : this.modify, - read : this.read, - persistence : this.persistence, - http : this.http - }) - - await this.persistence.updateByAssociation(record, filter); - - return context.getInteractionResponder().updateModalViewResponse(issueModal); - } - case ModalsEnum.SWITCH_ISSUE_STATE : { - const record = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ISSUE_MAIN_FILTER"); - const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record); - const {user, value} = context.getInteractionData(); let filter : {filter : string, state : string, sort: string, order: string} | undefined; - if (issueFilterArray.length != 0){ - filter = issueFilterArray[0] as { filter : string, state : string, sort: string, order: string}; - filter.filter = value as string; - }else { - filter = { - filter : ModalsEnum.ASSIGNED_ISSUE_FILTER, - sort : ModalsEnum.ISSUE_SORT_CREATED, - state : value as string, - order : ModalsEnum.ISSUES_DESCENDING - } + const prev_sort = issueFilterArray.length == 0 ? ModalsEnum.ISSUE_SORT_CREATED : issueFilterArray[0].sort; + const prev_filter = issueFilterArray.length == 0 ? ModalsEnum.ASSIGNED_ISSUE_FILTER : issueFilterArray[0].filter; + const prev_state = issueFilterArray.length == 0 ? ModalsEnum.ISSUE_STATE_OPEN : issueFilterArray[0].state; + + switch (value as string) { + case ModalsEnum.ASSIGNED_ISSUE_FILTER: + case ModalsEnum.MENTIONED_ISSUE_FILTER: + case ModalsEnum.CREATED_ISSUE_FILTER: + filter = { + filter : value as string, + sort : prev_sort, + state : prev_state, + order : ModalsEnum.ISSUES_DESCENDING + } + break; + case ModalsEnum.ISSUE_SORT_CREATED : + case ModalsEnum.ISSUE_SORT_COMMENTS : + case ModalsEnum.ISSUE_SORT_UPDATED : + filter = { + filter : prev_filter, + sort : value as string, + state : prev_state, + order : ModalsEnum.ISSUES_DESCENDING + } + break; + case ModalsEnum.ISSUE_STATE_OPEN : + case ModalsEnum.ISSUE_STATE_CLOSED : + filter = { + filter : prev_filter, + sort : prev_sort, + state : value as string, + order : ModalsEnum.ISSUES_DESCENDING + } + break; + default: + filter = { + filter : ModalsEnum.ASSIGNED_ISSUE_FILTER, + sort : ModalsEnum.ISSUE_SORT_CREATED, + state : ModalsEnum.ISSUE_STATE_OPEN, + order : ModalsEnum.ISSUES_DESCENDING + } } let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; @@ -233,7 +255,14 @@ export class ExecuteBlockActionHandler { let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + const filter = { + filter : ModalsEnum.ASSIGNED_ISSUE_FILTER, + state : ModalsEnum.ISSUE_STATE_OPEN, + sort : ModalsEnum.ISSUE_SORT_CREATED + } + const issuesModal = await userIssuesModal({ + filter : filter, access_token : access_token.token, modify: this.modify, read : this.read, diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index 2140e66..ad1e1e9 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -473,12 +473,30 @@ export async function getUserAssignedIssues( sort : String }, ) : Promise{ + + + let url; + + switch (filter.filter) { + case ModalsEnum.CREATED_ISSUE_FILTER: + url = `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort.substring(5)}-desc+author:${username}` + break; + case ModalsEnum.ASSIGNED_ISSUE_FILTER: + url = `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort.substring(5)}-desc+assignee:${username}` + break; + case ModalsEnum.MENTIONED_ISSUE_FILTER: + url = `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort.substring(5)}-desc+mentions:${username}` + default: + break; + } + + console.log(url); try { const response = await getRequest( http, access_token, - filter.filter == ModalsEnum.CREATED_ISSUE_FILTER ? `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+author:${username}`: (filter.filter == ModalsEnum.ASSIGNED_ISSUE_FILTER ? `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+assignee:${username}`: `https://api.github.com/search/issues?q=is:${filter.state}+is:issue+sort:${filter.sort}-desc+mentions:${username}` - )); + url, + ); const getAssignees = (assignees : any[]) : string[] => assignees.map((val): string => { return val.login as string; @@ -523,6 +541,7 @@ export async function getIssueData( return { issue_id : response.id as string, issue_compact : response.body as string, + html_url : response.html_url as string, repo_url : response.repository_url as string, user_login : response.user.login as string, user_avatar : response.user.avatar_url as string, From 4575f07b89e182c51cff865a301bd69e669d6676 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Thu, 10 Nov 2022 00:46:11 +0530 Subject: [PATCH 22/33] refactor : Stats and Reactions detached from Issue Display --- github/lib/CreateIssueStatsBar.ts | 44 ++++++++++++++++++ github/lib/CreateReactionsBar.ts | 21 +++++++++ github/modals/IssueDisplayModal.ts | 72 ++++++++++-------------------- 3 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 github/lib/CreateIssueStatsBar.ts create mode 100644 github/lib/CreateReactionsBar.ts diff --git a/github/lib/CreateIssueStatsBar.ts b/github/lib/CreateIssueStatsBar.ts new file mode 100644 index 0000000..3682dec --- /dev/null +++ b/github/lib/CreateIssueStatsBar.ts @@ -0,0 +1,44 @@ +import { BlockBuilder } from "@rocket.chat/apps-engine/definition/uikit"; +import { IGitHubIssue } from "../definitions/githubIssue"; +import { OcticonIcons } from "../enum/OcticonIcons"; + +export async function CreateIssueStatsBar( + issueInfo : IGitHubIssue, + block : BlockBuilder +){ + block.addContextBlock({ + elements: [ + block.newImageElement({ + imageUrl: OcticonIcons.COMMENTS, + altText: "Comments", + }), + block.newPlainTextObject( + `${issueInfo.comments}`, + false + ), + block.newImageElement({ + imageUrl: OcticonIcons.ISSUE_OPEN, + altText: "Assignees Icon", + }), + block.newPlainTextObject( + issueInfo.assignees ? (issueInfo.assignees.length == 0 + ? "No Assignees" + : `${issueInfo.assignees.length} Assignees`) : "" + ), + block.newImageElement({ + imageUrl: + issueInfo.state == "open" + ? OcticonIcons.ISSUE_OPEN + : OcticonIcons.ISSUE_CLOSED, + altText: "State", + }), + block.newPlainTextObject(`${issueInfo.state}`), + block.newImageElement({ + imageUrl: issueInfo.user_avatar ?? "", + altText: "User Image", + }), + block.newPlainTextObject(`Created by ${issueInfo.user_login}` ?? ""), + ], + }); + +} diff --git a/github/lib/CreateReactionsBar.ts b/github/lib/CreateReactionsBar.ts new file mode 100644 index 0000000..ab470c5 --- /dev/null +++ b/github/lib/CreateReactionsBar.ts @@ -0,0 +1,21 @@ +import { BlockBuilder } from "@rocket.chat/apps-engine/definition/uikit"; +import { IGithubReactions } from "../definitions/githubReactions"; + +export async function CreateReactionsBar( + reactions : IGithubReactions, + block : BlockBuilder +){ + block.addContextBlock({ + elements : [ + block.newPlainTextObject(`Total Reactions ${reactions?.total_count}`, true), + block.newPlainTextObject(`➕ ${reactions?.plus_one} `, true), + block.newPlainTextObject(`➖ ${reactions?.minus_one}`, true), + block.newPlainTextObject(`😄 ${reactions?.laugh}`, true), + block.newPlainTextObject(`🎉 ${reactions?.hooray}`, true), + block.newPlainTextObject(`😕 ${reactions?.confused}`, true), + block.newPlainTextObject(`♥️ ${reactions?.heart}`, true), + block.newPlainTextObject(`🚀 ${reactions?.rocket}`, true), + block.newPlainTextObject(`👀 ${reactions?.eyes}`, true), + ] + }) +} diff --git a/github/modals/IssueDisplayModal.ts b/github/modals/IssueDisplayModal.ts index 1e53ee8..2cee65b 100644 --- a/github/modals/IssueDisplayModal.ts +++ b/github/modals/IssueDisplayModal.ts @@ -7,6 +7,8 @@ import { IGithubReactions } from "../definitions/githubReactions"; import { ModalsEnum } from "../enum/Modals"; import { OcticonIcons } from "../enum/OcticonIcons"; import { getIssueData, getUserAssignedIssues } from "../helpers/githubSDK"; +import { CreateIssueStatsBar } from "../lib/CreateIssueStatsBar"; +import { CreateReactionsBar } from "../lib/CreateReactionsBar"; import { getInteractionRoomData, storeInteractionRoomData } from "../persistance/roomInteraction"; import { BodyMarkdownRenderer } from "../processors/bodyMarkdowmRenderer"; @@ -80,40 +82,7 @@ export async function IssueDisplayModal ({ ] }) - block.addContextBlock({ - elements: [ - block.newImageElement({ - imageUrl: OcticonIcons.COMMENTS, - altText: "Comments", - }), - block.newPlainTextObject( - `${issueInfo.comments}`, - false - ), - block.newImageElement({ - imageUrl: OcticonIcons.ISSUE_OPEN, - altText: "Assignees Icon", - }), - block.newPlainTextObject( - issueInfo.assignees ? (issueInfo.assignees.length == 0 - ? "No Assignees" - : `${issueInfo.assignees.length} Assignees`) : "" - ), - block.newImageElement({ - imageUrl: - issueInfo.state == "open" - ? OcticonIcons.ISSUE_OPEN - : OcticonIcons.ISSUE_CLOSED, - altText: "State", - }), - block.newPlainTextObject(`${issueInfo.state}`), - block.newImageElement({ - imageUrl: issueInfo.user_avatar ?? "", - altText: "User Image", - }), - block.newPlainTextObject(`Created by ${issueInfo.user_login}` ?? ""), - ], - }); + CreateIssueStatsBar(issueInfo, block); block.addSectionBlock({ text : { @@ -123,31 +92,36 @@ export async function IssueDisplayModal ({ }) block.addDividerBlock(); - // reactions + issueInfo.reactions && CreateReactionsBar(issueInfo.reactions, block); - const reactions = issueInfo.reactions + issueInfo.body && BodyMarkdownRenderer({body : issueInfo.body, block : block}) - block.addContextBlock({ + block.addActionsBlock({ elements : [ - block.newPlainTextObject(`Total Reactions ${reactions?.total_count}`, true), - block.newPlainTextObject(`➕ ${reactions?.plus_one} `, true), - block.newPlainTextObject(`➖ ${reactions?.minus_one}`, true), - block.newPlainTextObject(`😄 ${reactions?.laugh}`, true), - block.newPlainTextObject(`🎉 ${reactions?.hooray}`, true), - block.newPlainTextObject(`😕 ${reactions?.confused}`, true), - block.newPlainTextObject(`♥️ ${reactions?.heart}`, true), - block.newPlainTextObject(`🚀 ${reactions?.rocket}`, true), - block.newPlainTextObject(`👀 ${reactions?.eyes}`, true), + block.newButtonElement({ + actionId : ModalsEnum.SHARE_ISSUE_ACTION, + value : `${repoName}, ${issueNumber}`, + text : { + text : "Share Issue", + type : TextObjectType.PLAINTEXT + }, + }), + block.newButtonElement({ + actionId : ModalsEnum.SHARE_ISSUE_ACTION, + value : `${repoName}, ${issueNumber}`, + text : { + text : "Assign Issue", + type : TextObjectType.PLAINTEXT + }, + }) ] }) - issueInfo.body && BodyMarkdownRenderer({body : issueInfo.body, block : block}) - return { id : viewId, title : { text : `${repoName} \`#${issueNumber}\``, - type : TextObjectType.PLAINTEXT + type : TextObjectType.MARKDOWN }, blocks : block.getBlocks() } From 0a8cec05ac64259f7833132db599d8c88055c992 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Thu, 10 Nov 2022 00:46:51 +0530 Subject: [PATCH 23/33] fix : User Display Model fixed with Distinct Action IDs --- github/modals/UserIssuesModal.ts | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/github/modals/UserIssuesModal.ts b/github/modals/UserIssuesModal.ts index 1a5a58f..e220c2b 100644 --- a/github/modals/UserIssuesModal.ts +++ b/github/modals/UserIssuesModal.ts @@ -4,6 +4,7 @@ import { IPersistence, IHttp, } from "@rocket.chat/apps-engine/definition/accessors"; +import { RocketChatAssociationModel, RocketChatAssociationRecord } from "@rocket.chat/apps-engine/definition/metadata"; import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; import { ButtonStyle, @@ -20,11 +21,7 @@ import { } from "../persistance/roomInteraction"; export async function userIssuesModal({ - filter = { - filter: ModalsEnum.ALL_ISSUE_FILTER, - state: ModalsEnum.ISSUE_STATE_OPEN, - sort: ModalsEnum.ISSUE_SORT_CREATED, - }, + filter, access_token, modify, read, @@ -33,10 +30,10 @@ export async function userIssuesModal({ slashcommandcontext, uikitcontext, }: { - filter?: { - filter: String; - state: String; - sort: String; + filter: { + filter: string; + state: string; + sort: string; }; access_token: String; modify: IModify; @@ -82,12 +79,12 @@ export async function userIssuesModal({ block.addActionsBlock({ elements: [ block.newStaticSelectElement({ - actionId: ModalsEnum.SWITCH_ISSUE_FILTER, placeholder: { text: "Select an Issue Filter", type: TextObjectType.PLAINTEXT, }, - initialValue: ModalsEnum.ASSIGNED_ISSUE_FILTER, + initialValue: filter.filter, + actionId: ModalsEnum.SWITCH_ISSUE_FILTER, options: [ { value: ModalsEnum.ASSIGNED_ISSUE_FILTER, @@ -118,12 +115,12 @@ export async function userIssuesModal({ block.addActionsBlock({ elements: [ block.newStaticSelectElement({ - actionId: ModalsEnum.SWITCH_ISSUE_STATE, placeholder: { text: "Select Issues State", type: TextObjectType.PLAINTEXT, }, - initialValue: ModalsEnum.ISSUE_STATE_OPEN, + initialValue: filter.state, + actionId: ModalsEnum.SWITCH_ISSUE_STATE, options: [ { value: ModalsEnum.ISSUE_STATE_OPEN, @@ -131,6 +128,7 @@ export async function userIssuesModal({ text: "Open Issues", type: TextObjectType.PLAINTEXT, }, + }, { value: ModalsEnum.ISSUE_STATE_CLOSED, @@ -139,13 +137,6 @@ export async function userIssuesModal({ type: TextObjectType.PLAINTEXT, }, }, - { - value: ModalsEnum.ISSUE_STATE_ALL, - text: { - text: "All Issues", - type: TextObjectType.PLAINTEXT, - }, - }, ], }), block.newStaticSelectElement({ @@ -154,7 +145,7 @@ export async function userIssuesModal({ text: "Sort Issues By...", type: TextObjectType.PLAINTEXT, }, - initialValue: ModalsEnum.ISSUE_SORT_CREATED, + initialValue: filter.sort, options: [ { value: ModalsEnum.ISSUE_SORT_CREATED, @@ -272,6 +263,15 @@ export async function userIssuesModal({ }, style: ButtonStyle.PRIMARY, }), + block.newButtonElement({ + actionId: ModalsEnum.ADD_GITHUB_ISSUE_ASSIGNEE, + value: `${repoName} ${value.number} henit-chobisa`, + text: { + text: "Assign Issue", + type: TextObjectType.PLAINTEXT, + }, + style: ButtonStyle.PRIMARY, + }), ], }); block.addDividerBlock(); From 692831a46fd1a3ec0e175786540b6f681129f526 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Thu, 10 Nov 2022 02:18:46 +0530 Subject: [PATCH 24/33] fix : Updated Body Parser for both heading and checkboxes --- github/helpers/githubSDK.ts | 2 - github/processors/bodyMarkdowmRenderer.ts | 58 +++++++++++++++-------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index ad1e1e9..8aab870 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -489,8 +489,6 @@ export async function getUserAssignedIssues( default: break; } - - console.log(url); try { const response = await getRequest( http, diff --git a/github/processors/bodyMarkdowmRenderer.ts b/github/processors/bodyMarkdowmRenderer.ts index e7d2b93..ee31b08 100644 --- a/github/processors/bodyMarkdowmRenderer.ts +++ b/github/processors/bodyMarkdowmRenderer.ts @@ -3,6 +3,23 @@ import { TextObjectType, } from "@rocket.chat/apps-engine/definition/uikit"; + +function cleanHeadingSyntax(text: string) : string{ + try { + text = text.replace(/(#{3}\s)(.*)/g, (val) => `*${val.substring(3, val.length).trim()}*`); + text = text.replace(/(#{2}\s)(.*)/g, (val) => `*${val.substring(3, val.length)}*`); + text = text.replace(/(#{1}\s)(.*)/g, (val) => `*${val.substring(2, val.length)}*`); + text = text.replace(/\[ ] (?!\~|\[\^\d+])/g, (val) => `⭕ ${val.substring(3, val.length)}*`); + text = text.replace(/\[X] (?!\~|\[\^\d+])/g, (val) => `✅ ${val.substring(3, val.length)}*`); + } + catch(e){ + console.log(e); + } + + return text; +} + + export async function BodyMarkdownRenderer({ body, block, @@ -10,7 +27,7 @@ export async function BodyMarkdownRenderer({ body: string; block: BlockBuilder; }) { - const patterns: { type: string; pattern: RegExp }[] = [ + const imagePatterns: { type: string; pattern: RegExp }[] = [ { type: "ImageTag", pattern: RegExp(/()/g, "g"), @@ -24,7 +41,7 @@ export async function BodyMarkdownRenderer({ let matches: { beginningIndex: number; match: string; type: string }[] = []; var match; - patterns.forEach((patObj) => { + imagePatterns.forEach((patObj) => { while ((match = patObj.pattern.exec(body)) != null) { matches.push({ beginningIndex: match.index, @@ -55,29 +72,32 @@ export async function BodyMarkdownRenderer({ ); const url = rawURL ? rawURL[0] : ""; - block.addSectionBlock({ - text: { - text: body.substring(start, value.beginningIndex - 1) ?? "", - type: TextObjectType.MARKDOWN, - }, - }), - block.addImageBlock({ - imageUrl: url, - altText: "ImageURL", - }); + block.addContextBlock({ + elements: [ + block.newMarkdownTextObject( + cleanHeadingSyntax(body.substring(start, value.beginningIndex - 1) ?? "") + ), + ], + }); + + block.addImageBlock({ + imageUrl: url, + altText: "ImageURL", + }); if ( index == matches.length - 1 && value.beginningIndex + value.match.length < body.length ) { - block.addSectionBlock({ - text: { - text: body.substring( - value.beginningIndex + value.match.length, - body.length + block.addContextBlock({ + elements: [ + block.newMarkdownTextObject( + cleanHeadingSyntax(body.substring( + value.beginningIndex + value.match.length, + body.length + )) ), - type: TextObjectType.MARKDOWN, - }, + ], }); } }); From c71ac74830d5e8564e79085b1ff518a58786688a Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Fri, 11 Nov 2022 00:50:06 +0530 Subject: [PATCH 25/33] feat : Body Renderer Added with headings and Check Boxes --- github/processors/bodyMarkdowmRenderer.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/github/processors/bodyMarkdowmRenderer.ts b/github/processors/bodyMarkdowmRenderer.ts index ee31b08..1de7385 100644 --- a/github/processors/bodyMarkdowmRenderer.ts +++ b/github/processors/bodyMarkdowmRenderer.ts @@ -7,15 +7,14 @@ import { function cleanHeadingSyntax(text: string) : string{ try { text = text.replace(/(#{3}\s)(.*)/g, (val) => `*${val.substring(3, val.length).trim()}*`); - text = text.replace(/(#{2}\s)(.*)/g, (val) => `*${val.substring(3, val.length)}*`); - text = text.replace(/(#{1}\s)(.*)/g, (val) => `*${val.substring(2, val.length)}*`); + text = text.replace(/(#{2}\s)(.*)/g, (val) => `*${val.substring(3, val.length).trim()}*`); + text = text.replace(/(#{1}\s)(.*)/g, (val) => `*${val.substring(2, val.length).trim()}*`); text = text.replace(/\[ ] (?!\~|\[\^\d+])/g, (val) => `⭕ ${val.substring(3, val.length)}*`); text = text.replace(/\[X] (?!\~|\[\^\d+])/g, (val) => `✅ ${val.substring(3, val.length)}*`); } catch(e){ console.log(e); } - return text; } @@ -54,7 +53,7 @@ export async function BodyMarkdownRenderer({ if (matches.length == 0) { block.addSectionBlock({ text: { - text: body, + text: cleanHeadingSyntax(body), type: TextObjectType.MARKDOWN, }, }); @@ -102,11 +101,4 @@ export async function BodyMarkdownRenderer({ } }); } - - // block.addSectionBlock({ - // text : { - // text : body, - // type : TextObjectType.PLAINTEXT - // } - // }) } From 5d0d660ebe63f2e02f54927c36b70408845b82c9 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Mon, 14 Nov 2022 01:32:02 +0530 Subject: [PATCH 26/33] feat : Subcommand Added for Gist --- github/enum/Subcommands.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/github/enum/Subcommands.ts b/github/enum/Subcommands.ts index 8ba32e2..b5c689b 100644 --- a/github/enum/Subcommands.ts +++ b/github/enum/Subcommands.ts @@ -8,5 +8,6 @@ export enum SubcommandEnum { SEARCH = 'search', NEW_ISSUE = 'issue', ISSUES = 'issues', - PROFILE = 'me' + PROFILE = 'me', + GIST = 'gist' } From ec178206aa064ba533a2bf6470309c2ec99270e8 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Mon, 14 Nov 2022 01:32:31 +0530 Subject: [PATCH 27/33] feat: Gist Command Handler Added for Command Utility. --- github/handlers/handleGist.ts | 164 ++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 github/handlers/handleGist.ts diff --git a/github/handlers/handleGist.ts b/github/handlers/handleGist.ts new file mode 100644 index 0000000..91b0a04 --- /dev/null +++ b/github/handlers/handleGist.ts @@ -0,0 +1,164 @@ +import { + IRead, + IPersistence, + IHttp, + IModify, + IMessageBuilder +} from "@rocket.chat/apps-engine/definition/accessors"; +import { IRoom } from "@rocket.chat/apps-engine/definition/rooms"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { ButtonStyle, TextObjectType } from "@rocket.chat/apps-engine/definition/uikit"; +import { IGist } from "../definitions/Gist"; +import { IGistFile } from "../definitions/GistFile"; +import { OcticonIcons } from "../enum/OcticonIcons"; +import { GithubApp } from "../GithubApp"; +import { getBasicUserInfo, getUserGist, loadGist } from "../helpers/githubSDK"; +import { + sendMessage, + sendNotification, +} from "../lib/message"; +import { userGistModal } from "../modals/UserGistModal"; +import { getAccessTokenForUser } from "../persistance/auth"; + +export async function handleGist( + read: IRead, + context: SlashCommandContext, + app: GithubApp, + persistence: IPersistence, + http: IHttp, + room: IRoom, + modify: IModify +) { + let access_token = await getAccessTokenForUser( + read, + context.getSender(), + app.oauth2Config + ); + const loggedIn = access_token && access_token.token; + if (!loggedIn) { + await sendNotification( + read, + modify, + context.getSender(), + room, + "Login is Mandatory for getting User Info ! `/github login`" + ); + return; + } + + const triggerId = context.getTriggerId(); + if (triggerId) { + const modal = await userGistModal({ + access_token: access_token!.token, + modify: modify, + read: read, + persistence: persistence, + http: http, + slashcommandcontext: context, + }); + await modify + .getUiController() + .openModalView(modal, { triggerId }, context.getSender()); + } +} + +export async function sendGistWithNumber( + gistNumber: number, + read: IRead, + context: SlashCommandContext, + app: GithubApp, + persistence: IPersistence, + http: IHttp, + room: IRoom, + modify: IModify, + gistFileNumber?: number +) { + let access_token = await getAccessTokenForUser( + read, + context.getSender(), + app.oauth2Config + ); + const loggedIn = access_token && access_token.token; + if (!loggedIn) { + await sendNotification( + read, + modify, + context.getSender(), + room, + "Login is Mandatory for getting User Info ! `/github login`" + ); + return; + } + + const userInfo = await getBasicUserInfo(http, access_token!.token); + const userGist: IGist[] = await getUserGist( + http, + userInfo.username, + access_token!.token + ); + + if (userGist.length < gistNumber || gistNumber <= 0) { + await sendNotification( + read, + modify, + context.getSender(), + room, + "Sorry, not enough gist available, kindly reconfirm the gist number." + ); + + return; + } + + try { + const block = modify.getCreator().getBlockBuilder(); + + const targetGist = userGist[gistNumber - 1]; + + const files = new Map( + Object.entries(targetGist.files) + ); + + block.addContextBlock({ + elements : [ + block.newImageElement({ + imageUrl : targetGist['owner']['avatar_url'], + altText : "Created by" + }), + block.newPlainTextObject(targetGist['owner']['login']), + block.newImageElement({ + imageUrl : OcticonIcons.PENCIL, + altText : "Updated at", + }), + block.newPlainTextObject(new Date(targetGist.updated_at).toISOString()) + ] + }) + + for (const [_, value] of files) { + const gistContent = await loadGist( + http, + value.raw_url, + access_token!.token + ); + + block.addSectionBlock({ + text: { + text: `*${value.filename}*`, + type: TextObjectType.MARKDOWN, + }, + }); + + block.addSectionBlock({ + text: { + text: `\`\`\` ${value.language} \n ${gistContent} \n\`\`\``, + type: TextObjectType.MARKDOWN, + }, + }); + block.addDividerBlock(); + } + + await sendMessage(modify, room, context.getSender(), "Gist", block); + } catch (e) { + console.log(e); + } + return; +} From 89252ac88d639b0a315e76f6ae9f9bc6df366d90 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Mon, 14 Nov 2022 01:33:23 +0530 Subject: [PATCH 28/33] feat : Gist command registered in Command Utility --- github/lib/commandUtility.ts | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/github/lib/commandUtility.ts b/github/lib/commandUtility.ts index d2fb1c3..d669654 100644 --- a/github/lib/commandUtility.ts +++ b/github/lib/commandUtility.ts @@ -23,6 +23,8 @@ import { import { handleSearch } from "../handlers/SearchHandler"; import { handleNewIssue } from "../handlers/HandleNewIssue"; import { handleUserProfileRequest } from "../handlers/UserProfileHandler"; +import { handleGist, sendGistWithNumber } from "../handlers/handleGist"; +import { getUserGist } from "../helpers/githubSDK"; export class CommandUtility implements ExecutorProps { sender: IUser; @@ -63,6 +65,18 @@ export class CommandUtility implements ExecutorProps { }); } else { switch (this.command[0]) { + case SubcommandEnum.GIST : { + await handleGist( + this.read, + this.context, + this.app, + this.persistence, + this.http, + this.room, + this.modify + ) + break; + } case SubcommandEnum.LOGIN: { await handleLogin( this.app, @@ -154,7 +168,23 @@ export class CommandUtility implements ExecutorProps { private async handleDualParamCommands() { const query = this.command[1]; - const repository = this.command[0]; + const command = this.command[0]; + + + if (command == "gist" && command != undefined){ + await sendGistWithNumber( + +query, + this.read, + this.context, + this.app, + this.persistence, + this.http, + this.room, + this.modify + ) + return; + } + switch (query) { case SubcommandEnum.SUBSCRIBE: { SubscribeAllEvents( @@ -185,7 +215,7 @@ export class CommandUtility implements ExecutorProps { default: { await basicQueryMessage({ query, - repository, + repository: command, room: this.room, read: this.read, persistence: this.persistence, From 796770ef4d48ad20b7e536b660174f6d9c3c41db Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Mon, 14 Nov 2022 01:33:40 +0530 Subject: [PATCH 29/33] feat: Gist Modal Created --- github/modals/UserGistModal.ts | 146 +++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 github/modals/UserGistModal.ts diff --git a/github/modals/UserGistModal.ts b/github/modals/UserGistModal.ts new file mode 100644 index 0000000..d0f6bb1 --- /dev/null +++ b/github/modals/UserGistModal.ts @@ -0,0 +1,146 @@ +import { + IModify, + IRead, + IPersistence, + IHttp, +} from "@rocket.chat/apps-engine/definition/accessors"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { + ButtonStyle, + TextObjectType, + UIKitInteractionContext, +} from "@rocket.chat/apps-engine/definition/uikit"; +import { IUIKitModalViewParam } from "@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder"; +import { IGist } from "../definitions/Gist"; +import { IGistFile } from "../definitions/GistFile"; +import { ModalsEnum } from "../enum/Modals"; +import { OcticonIcons } from "../enum/OcticonIcons"; +import { + getBasicUserInfo, + getUserAssignedIssues, + getUserGist, + loadGist, +} from "../helpers/githubSDK"; +import { + getInteractionRoomData, + storeInteractionRoomData, +} from "../persistance/roomInteraction"; + +export async function userGistModal({ + access_token, + modify, + read, + persistence, + http, + slashcommandcontext, + uikitcontext, +}: { + access_token: string; + modify: IModify; + read: IRead; + persistence: IPersistence; + http: IHttp; + slashcommandcontext: SlashCommandContext; + uikitcontext?: UIKitInteractionContext; +}): Promise { + const viewId = ModalsEnum.USER_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; + } + } + + const userInfo = await getBasicUserInfo(http, access_token); + + const usersGist: IGist[] = await getUserGist( + http, + userInfo.username ?? "", + access_token + ); + + block.addContextBlock({ + elements : [ + block.newMarkdownTextObject("*Tip* : You can directly enter `/gh gist 1` to send the most recent gist created by you.") + ] + }) + for(const val of usersGist){ + + block.addContextBlock({ + elements : [ + block.newImageElement({ + imageUrl : val['owner']['avatar_url'], + altText : "Created by" + }), + block.newPlainTextObject(val['owner']['login']), + block.newImageElement({ + imageUrl : OcticonIcons.PENCIL, + altText : "Updated at", + }), + block.newPlainTextObject(new Date(val.updated_at).toISOString()) + ] + }) + + block.addActionsBlock({ + elements : [ + block.newButtonElement({ + value : JSON.stringify(val), + text : { + text : "Share in chat 🚀", + type : TextObjectType.PLAINTEXT + }, + style : ButtonStyle.PRIMARY, + actionId : ModalsEnum.SHARE_GIST_ACTION + }) + ] + }) + + const files = new Map(Object.entries(val.files)); + for(const [_key, value] of files){ + const gistContent = await loadGist( + http, + value.raw_url, + access_token + ); + block.addSectionBlock({ + text: { + text: value.filename, + type: TextObjectType.PLAINTEXT, + }, + }); + block.addSectionBlock({ + text: { + text: `\`\`\`${value.language}\n ${gistContent} \n\`\`\``, + type: TextObjectType.MARKDOWN, + }, + }); + } + + block.addDividerBlock(); + } + + return { + id: viewId, + title: { + text: "Your Gists", + type: TextObjectType.PLAINTEXT, + }, + blocks: block.getBlocks(), + }; +} From 0424fc377ca92fa47ce4c072bca3421eefc5d474 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Mon, 14 Nov 2022 01:34:01 +0530 Subject: [PATCH 30/33] feat: Gist and GistFile Interfaces created --- github/definitions/Gist.ts | 11 +++++++++++ github/definitions/GistFile.ts | 6 ++++++ 2 files changed, 17 insertions(+) create mode 100644 github/definitions/Gist.ts create mode 100644 github/definitions/GistFile.ts diff --git a/github/definitions/Gist.ts b/github/definitions/Gist.ts new file mode 100644 index 0000000..254665a --- /dev/null +++ b/github/definitions/Gist.ts @@ -0,0 +1,11 @@ +import { IGistFile } from "./GistFile"; + +export interface IGist { + id : string, + html_url : string, + updated_at : string, + description : string, + owner_login : string, + owner_avatar : string, + files : any +} diff --git a/github/definitions/GistFile.ts b/github/definitions/GistFile.ts new file mode 100644 index 0000000..7313fe5 --- /dev/null +++ b/github/definitions/GistFile.ts @@ -0,0 +1,6 @@ +export interface IGistFile { + filename : string, + language : string, + raw_url : string, + size : number +} From 6a0d8879633238748d7e57d3efdbd44759a7f2cc Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Mon, 14 Nov 2022 01:34:34 +0530 Subject: [PATCH 31/33] feat: Github SDK Modified for Gist Fetching --- github/helpers/githubSDK.ts | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index 8aab870..079d8ad 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -1,4 +1,5 @@ import { IHttp } from "@rocket.chat/apps-engine/definition/accessors"; +import { IGist } from "../definitions/Gist"; import { IGitHubIssue } from "../definitions/githubIssue"; import { ModalsEnum } from "../enum/Modals"; @@ -366,6 +367,22 @@ export async function githubSearchIssuesPulls( return resultResponse; } + +export async function loadGist(http: IHttp,url : string, access_token : string){ + try { + const response = await http.get(url, { + headers : { + "Authorization" : `Bearer ${access_token}` + } + }); + return response.content; + } catch (error) { + console.error("ERROR WHILE LOADING GIST-------------------------------"); + console.error(error); + return ""; + } +} + export async function getRepoData( http: IHttp, repoName: string, @@ -463,6 +480,21 @@ export async function getBasicUserInfo( } } +export async function getUserGist( + http : IHttp, + username : string, + access_token: string +){ + try { + const response = await getRequest(http, access_token, BaseApiHost + 'users/' + username + '/gists'); + const modRes = response as IGist[]; + return modRes; + } catch (e) { + console.log(e); + return []; + } +} + export async function getUserAssignedIssues( http: IHttp, username: String, @@ -473,8 +505,6 @@ export async function getUserAssignedIssues( sort : String }, ) : Promise{ - - let url; switch (filter.filter) { From 72f6d335dfef4e4f4439b07cbb3cfb3974dd5811 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Mon, 14 Nov 2022 01:35:00 +0530 Subject: [PATCH 32/33] feat: Sharing Added in Gist Modal --- github/enum/Modals.ts | 1 + github/handlers/ExecuteBlockActionHandler.ts | 1416 ++++++++++++------ 2 files changed, 964 insertions(+), 453 deletions(-) diff --git a/github/enum/Modals.ts b/github/enum/Modals.ts index bc3ee01..58052e1 100644 --- a/github/enum/Modals.ts +++ b/github/enum/Modals.ts @@ -1,4 +1,5 @@ export enum ModalsEnum { + SHARE_GIST_ACTION = 'share-gist-action', SHARE_ISSUE_ACTION = 'share-issue-action', TRIGGER_ISSUE_DISPLAY_MODAL = 'display-issue', SWITCH_ISSUE_ORDER = 'switch-issue-order', diff --git a/github/handlers/ExecuteBlockActionHandler.ts b/github/handlers/ExecuteBlockActionHandler.ts index 1018976..2db94de 100644 --- a/github/handlers/ExecuteBlockActionHandler.ts +++ b/github/handlers/ExecuteBlockActionHandler.ts @@ -18,12 +18,25 @@ import { } from "@rocket.chat/apps-engine/definition/uikit"; import { AddSubscriptionModal } from "../modals/addSubscriptionsModal"; import { deleteSubsciptionsModal } from "../modals/deleteSubscriptions"; -import { deleteSubscription, updateSubscription, getIssueTemplateCode, getPullRequestComments, getPullRequestData, getRepositoryIssues, getBasicUserInfo, getIssueData } from "../helpers/githubSDK"; +import { + deleteSubscription, + updateSubscription, + getIssueTemplateCode, + getPullRequestComments, + getPullRequestData, + getRepositoryIssues, + getBasicUserInfo, + getIssueData, + loadGist, +} from "../helpers/githubSDK"; import { Subscription } from "../persistance/subscriptions"; import { getAccessTokenForUser } from "../persistance/auth"; import { GithubApp } from "../GithubApp"; import { IAuthData } from "@rocket.chat/apps-engine/definition/oauth2/IOAuth2"; -import { storeInteractionRoomData, getInteractionRoomData } from "../persistance/roomInteraction"; +import { + storeInteractionRoomData, + getInteractionRoomData, +} from "../persistance/roomInteraction"; import { sendMessage, sendNotification } from "../lib/message"; import { subsciptionsModal } from "../modals/subscriptionsModal"; import { mergePullRequestModal } from "../modals/mergePullReqeustModal"; @@ -42,23 +55,26 @@ import { githubIssuesListModal } from "../modals/githubIssuesListModal"; import { GithubRepoIssuesStorage } from "../persistance/githubIssues"; import { IGitHubIssueData } from "../definitions/githubIssueData"; import { shareProfileModal } from "../modals/profileShareModal"; -import { RocketChatAssociationModel, RocketChatAssociationRecord } from "@rocket.chat/apps-engine/definition/metadata"; +import { + RocketChatAssociationModel, + RocketChatAssociationRecord, +} from "@rocket.chat/apps-engine/definition/metadata"; import { userIssuesModal } from "../modals/UserIssuesModal"; import { IssueDisplayModal } from "../modals/IssueDisplayModal"; import { IGitHubIssue } from "../definitions/githubIssue"; import { BodyMarkdownRenderer } from "../processors/bodyMarkdowmRenderer"; import { CreateIssueStatsBar } from "../lib/CreateIssueStatsBar"; +import { OcticonIcons } from "../enum/OcticonIcons"; +import { IGistFile } from "../definitions/GistFile"; export class ExecuteBlockActionHandler { - constructor( private readonly app: GithubApp, private readonly read: IRead, private readonly http: IHttp, private readonly modify: IModify, private readonly persistence: IPersistence - ) { } - + ) {} public async run( context: UIKitBlockInteractionContext @@ -89,8 +105,12 @@ export class ExecuteBlockActionHandler { lengthOfRepoString ) as String; let { user, room } = await context.getInteractionData(); - let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; - if(room && user){ + let accessToken = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; + if (room && user) { await basicQueryMessage({ query, repository, @@ -112,241 +132,442 @@ export class ExecuteBlockActionHandler { }; } } - case ModalsEnum.SHARE_ISSUE_ACTION : { - let {user, value, room} = context.getInteractionData(); - const access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + case ModalsEnum.SHARE_GIST_ACTION: { + let { user, value, room } = context.getInteractionData(); + const access_token = await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + ); + if (value != undefined && access_token != undefined) { + const val = JSON.parse(value); + const block = this.modify + .getCreator() + .getBlockBuilder(); + + block.addContextBlock({ + elements: [ + block.newImageElement({ + imageUrl: val["owner"]["avatar_url"], + altText: "Created by", + }), + block.newPlainTextObject(val["owner"]["login"]), + block.newImageElement({ + imageUrl: OcticonIcons.PENCIL, + altText: "Updated at", + }), + block.newPlainTextObject( + new Date(val.updated_at).toISOString() + ), + ], + }); + + const files = new Map( + Object.entries(val.files) + ); + for (const [_key, value] of files) { + const gistContent = await loadGist( + this.http, + value.raw_url, + access_token.token + ); + block.addSectionBlock({ + text: { + text: value.filename, + type: TextObjectType.PLAINTEXT, + }, + }); + block.addSectionBlock({ + text: { + text: `\`\`\`${value.language}\n ${gistContent} \n\`\`\``, + type: TextObjectType.MARKDOWN, + }, + }); + } + + if (user?.id) { + if (room?.id) { + await sendMessage( + this.modify, + room!, + user, + `Gist`, + block + ); + } else { + let roomId = ( + await getInteractionRoomData( + this.read.getPersistenceReader(), + user.id + ) + ).roomId; + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; + await sendMessage( + this.modify, + room, + user, + `Gist`, + block + ); + } + } + break; + } + } + case ModalsEnum.SHARE_ISSUE_ACTION: { + let { user, value, room } = context.getInteractionData(); + const access_token = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; const repoName = value?.split(",")[0] ?? ""; const issueNumber = value?.split(",")[1] ?? ""; - const issueInfo : IGitHubIssue = await getIssueData(repoName, issueNumber, access_token.token, this.http); + const issueInfo: IGitHubIssue = await getIssueData( + repoName, + issueNumber, + access_token.token, + this.http + ); const block = this.modify.getCreator().getBlockBuilder(); CreateIssueStatsBar(issueInfo, block); block.addSectionBlock({ - text : { - text : `*${issueInfo.title}*` ?? "", - type : TextObjectType.MARKDOWN - } + text: { + text: `*${issueInfo.title}*` ?? "", + type: TextObjectType.MARKDOWN, + }, }), - block.addActionsBlock({ - elements : [ - block.newButtonElement({ - text : { - text : "Open Issue in Browser", - type : TextObjectType.PLAINTEXT - }, - url : issueInfo.html_url, - style : ButtonStyle.PRIMARY - }) - ] - }) - issueInfo.body && BodyMarkdownRenderer({body : issueInfo.body, block : block}); - - if(user?.id){ - if(room?.id){ - await sendMessage(this.modify, room!, user, `Issue`, block) - }else{ + block.addActionsBlock({ + elements: [ + block.newButtonElement({ + text: { + text: "Open Issue in Browser", + type: TextObjectType.PLAINTEXT, + }, + url: issueInfo.html_url, + style: ButtonStyle.PRIMARY, + }), + ], + }); + issueInfo.body && + BodyMarkdownRenderer({ + body: issueInfo.body, + block: block, + }); + + if (user?.id) { + if (room?.id) { + await sendMessage( + this.modify, + room!, + user, + `Issue`, + block + ); + } else { let roomId = ( await getInteractionRoomData( this.read.getPersistenceReader(), user.id ) ).roomId; - room = await this.read.getRoomReader().getById(roomId) as IRoom; - await sendMessage(this.modify, room, user, `Issue`, block) + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; + await sendMessage( + this.modify, + room, + user, + `Issue`, + block + ); } } break; } - case ModalsEnum.TRIGGER_ISSUE_DISPLAY_MODAL : { - const {user, value} = context.getInteractionData(); - const access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + case ModalsEnum.TRIGGER_ISSUE_DISPLAY_MODAL: { + const { user, value } = context.getInteractionData(); + const access_token = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; const repoInfo = value?.split(",")[0] ?? ""; const issueNumber = value?.split(",")[1] ?? ""; const issueDisplayModal = await IssueDisplayModal({ - repoName : repoInfo, - issueNumber : issueNumber, - access_token : access_token.token, - modify : this.modify, - read : this.read, - persistence : this.persistence, - http : this.http, - uikitcontext : context - }) - - return context.getInteractionResponder().updateModalViewResponse(issueDisplayModal); + repoName: repoInfo, + issueNumber: issueNumber, + access_token: access_token.token, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); + + return context + .getInteractionResponder() + .updateModalViewResponse(issueDisplayModal); } - case ModalsEnum.SWITCH_ISSUE_SORT : - case ModalsEnum.SWITCH_ISSUE_STATE : - case ModalsEnum.SWITCH_ISSUE_FILTER : { - const record = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ISSUE_MAIN_FILTER"); + case ModalsEnum.SWITCH_ISSUE_SORT: + case ModalsEnum.SWITCH_ISSUE_STATE: + case ModalsEnum.SWITCH_ISSUE_FILTER: { + const record = new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + "ISSUE_MAIN_FILTER" + ); - const issueFilterArray = await this.read.getPersistenceReader().readByAssociation(record) as {filter : string, state : string, sort: string, order: string}[]; + const issueFilterArray = (await this.read + .getPersistenceReader() + .readByAssociation(record)) as { + filter: string; + state: string; + sort: string; + order: string; + }[]; - const {user, value} = context.getInteractionData(); + const { user, value } = context.getInteractionData(); - let filter : {filter : string, state : string, sort: string, order: string} | undefined; + let filter: + | { + filter: string; + state: string; + sort: string; + order: string; + } + | undefined; - const prev_sort = issueFilterArray.length == 0 ? ModalsEnum.ISSUE_SORT_CREATED : issueFilterArray[0].sort; - const prev_filter = issueFilterArray.length == 0 ? ModalsEnum.ASSIGNED_ISSUE_FILTER : issueFilterArray[0].filter; - const prev_state = issueFilterArray.length == 0 ? ModalsEnum.ISSUE_STATE_OPEN : issueFilterArray[0].state; + const prev_sort = + issueFilterArray.length == 0 + ? ModalsEnum.ISSUE_SORT_CREATED + : issueFilterArray[0].sort; + const prev_filter = + issueFilterArray.length == 0 + ? ModalsEnum.ASSIGNED_ISSUE_FILTER + : issueFilterArray[0].filter; + const prev_state = + issueFilterArray.length == 0 + ? ModalsEnum.ISSUE_STATE_OPEN + : issueFilterArray[0].state; switch (value as string) { case ModalsEnum.ASSIGNED_ISSUE_FILTER: case ModalsEnum.MENTIONED_ISSUE_FILTER: case ModalsEnum.CREATED_ISSUE_FILTER: filter = { - filter : value as string, - sort : prev_sort, - state : prev_state, - order : ModalsEnum.ISSUES_DESCENDING - } + filter: value as string, + sort: prev_sort, + state: prev_state, + order: ModalsEnum.ISSUES_DESCENDING, + }; break; - case ModalsEnum.ISSUE_SORT_CREATED : - case ModalsEnum.ISSUE_SORT_COMMENTS : - case ModalsEnum.ISSUE_SORT_UPDATED : + case ModalsEnum.ISSUE_SORT_CREATED: + case ModalsEnum.ISSUE_SORT_COMMENTS: + case ModalsEnum.ISSUE_SORT_UPDATED: filter = { - filter : prev_filter, - sort : value as string, - state : prev_state, - order : ModalsEnum.ISSUES_DESCENDING - } + filter: prev_filter, + sort: value as string, + state: prev_state, + order: ModalsEnum.ISSUES_DESCENDING, + }; break; - case ModalsEnum.ISSUE_STATE_OPEN : - case ModalsEnum.ISSUE_STATE_CLOSED : + case ModalsEnum.ISSUE_STATE_OPEN: + case ModalsEnum.ISSUE_STATE_CLOSED: filter = { - filter : prev_filter, - sort : prev_sort, - state : value as string, - order : ModalsEnum.ISSUES_DESCENDING - } + filter: prev_filter, + sort: prev_sort, + state: value as string, + order: ModalsEnum.ISSUES_DESCENDING, + }; break; default: filter = { - filter : ModalsEnum.ASSIGNED_ISSUE_FILTER, - sort : ModalsEnum.ISSUE_SORT_CREATED, - state : ModalsEnum.ISSUE_STATE_OPEN, - order : ModalsEnum.ISSUES_DESCENDING - } + filter: ModalsEnum.ASSIGNED_ISSUE_FILTER, + sort: ModalsEnum.ISSUE_SORT_CREATED, + state: ModalsEnum.ISSUE_STATE_OPEN, + order: ModalsEnum.ISSUES_DESCENDING, + }; } - let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + let access_token = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; const issueModal = await userIssuesModal({ - access_token : access_token.token, - filter : filter, - modify : this.modify, - read : this.read, - persistence : this.persistence, - http : this.http - }) + access_token: access_token.token, + filter: filter, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + }); await this.persistence.updateByAssociation(record, filter); - return context.getInteractionResponder().updateModalViewResponse(issueModal); + return context + .getInteractionResponder() + .updateModalViewResponse(issueModal); } - case ModalsEnum.TRIGGER_ISSUES_MODAL : { - - const {user} = context.getInteractionData(); + case ModalsEnum.TRIGGER_ISSUES_MODAL: { + const { user } = context.getInteractionData(); - let access_token = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; + let access_token = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; const filter = { - filter : ModalsEnum.ASSIGNED_ISSUE_FILTER, - state : ModalsEnum.ISSUE_STATE_OPEN, - sort : ModalsEnum.ISSUE_SORT_CREATED - } + filter: ModalsEnum.ASSIGNED_ISSUE_FILTER, + state: ModalsEnum.ISSUE_STATE_OPEN, + sort: ModalsEnum.ISSUE_SORT_CREATED, + }; const issuesModal = await userIssuesModal({ - filter : filter, - access_token : access_token.token, + filter: filter, + access_token: access_token.token, modify: this.modify, - read : this.read, - persistence : this.persistence, - http : this.http, - uikitcontext : context + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, }); - return context.getInteractionResponder().openModalViewResponse(issuesModal); + return context + .getInteractionResponder() + .openModalViewResponse(issuesModal); } - case ModalsEnum.TRIGGER_REPOS_MODAL : { + case ModalsEnum.TRIGGER_REPOS_MODAL: { break; } - case ModalsEnum.TRIGGER_ACTIVITY_MODAL : { + case ModalsEnum.TRIGGER_ACTIVITY_MODAL: { break; } - case ModalsEnum.SHARE_PROFILE_PARAMS : { - const profileInteractionData = context.getInteractionData().value; + case ModalsEnum.SHARE_PROFILE_PARAMS: { + const profileInteractionData = + context.getInteractionData().value; const datAny = profileInteractionData as any; const storeData = { - profileParams : datAny as string[] - } + profileParams: datAny as string[], + }; - await this.persistence.updateByAssociation(new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ProfileShareParam"), storeData); + await this.persistence.updateByAssociation( + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + "ProfileShareParam" + ), + storeData + ); break; } - case ModalsEnum.SHARE_PROFILE_EXEC : { - let {user, room} = context.getInteractionData(); + case ModalsEnum.SHARE_PROFILE_EXEC: { + let { user, room } = context.getInteractionData(); const block = this.modify.getCreator().getBlockBuilder(); - let accessToken = await getAccessTokenForUser(this.read, user ,this.app.oauth2Config) as IAuthData; - const userProfile = await getBasicUserInfo(this.http, accessToken.token); + let accessToken = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; + const userProfile = await getBasicUserInfo( + this.http, + accessToken.token + ); - const idRecord = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, "ProfileShareParam") + const idRecord = new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + "ProfileShareParam" + ); - const profileData = await this.read.getPersistenceReader().readByAssociation(idRecord); + const profileData = await this.read + .getPersistenceReader() + .readByAssociation(idRecord); let profileShareParams: string[] = []; - if (profileData.length == 0){ - profileShareParams = ['username', 'avatar', 'email', 'bio', 'followers', 'following' , 'contributionGraph']; - } - else { - const dat = profileData[0] as {profileParams : string[]}; + if (profileData.length == 0) { + profileShareParams = [ + "username", + "avatar", + "email", + "bio", + "followers", + "following", + "contributionGraph", + ]; + } else { + const dat = profileData[0] as { + profileParams: string[]; + }; profileShareParams = dat.profileParams; } - if (profileShareParams.includes('avatar')){ + if (profileShareParams.includes("avatar")) { block.addImageBlock({ - imageUrl : userProfile.avatar, - altText : "User Info" - }) + imageUrl: userProfile.avatar, + altText: "User Info", + }); } profileShareParams.map((value) => { - if (value != 'contributionGraph' && value != 'avatar'){ + if (value != "contributionGraph" && value != "avatar") { block.addSectionBlock({ - text : block.newPlainTextObject(value), - }) + text: block.newPlainTextObject(value), + }); block.addContextBlock({ - elements : [ - block.newPlainTextObject(userProfile[value], true), - ] + elements: [ + block.newPlainTextObject( + userProfile[value], + true + ), + ], }); block.addDividerBlock(); } - }) + }); - if (profileShareParams.includes('contributionGraph')){ - block.addImageBlock({imageUrl : `https://activity-graph.herokuapp.com/graph?username=${userProfile.username}&bg_color=ffffff&color=708090&line=24292e&point=24292e`, altText: "Github Contribution Graph"}) + if (profileShareParams.includes("contributionGraph")) { + block.addImageBlock({ + imageUrl: `https://activity-graph.herokuapp.com/graph?username=${userProfile.username}&bg_color=ffffff&color=708090&line=24292e&point=24292e`, + altText: "Github Contribution Graph", + }); } - - if(user?.id){ - if(room?.id){ - await sendMessage(this.modify, room!, user, `${userProfile.name}'s Github Profile`, block) - }else{ + if (user?.id) { + if (room?.id) { + await sendMessage( + this.modify, + room!, + user, + `${userProfile.name}'s Github Profile`, + block + ); + } else { let roomId = ( await getInteractionRoomData( this.read.getPersistenceReader(), user.id ) ).roomId; - room = await this.read.getRoomReader().getById(roomId) as IRoom; - await sendMessage(this.modify, room, user, `${userProfile.name}'s Github Profile`, block) + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; + await sendMessage( + this.modify, + room, + user, + `${userProfile.name}'s Github Profile`, + block + ); } } @@ -373,8 +594,8 @@ export class ExecuteBlockActionHandler { read: this.read, persistence: this.persistence, http: this.http, - uikitcontext: context - }) + uikitcontext: context, + }); return context .getInteractionResponder() .openModalViewResponse(addSubscriptionModal); @@ -385,40 +606,73 @@ export class ExecuteBlockActionHandler { read: this.read, persistence: this.persistence, http: this.http, - uikitcontext: context - }) + uikitcontext: context, + }); return context .getInteractionResponder() .openModalViewResponse(addSubscriptionModal); } case ModalsEnum.DELETE_SUBSCRIPTION_ACTION: { - let { user, room } = await context.getInteractionData(); - let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; - let value: string = context.getInteractionData().value as string; - let splitted = value.split(','); + let accessToken = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; + let value: string = context.getInteractionData() + .value as string; + let splitted = value.split(","); if (splitted.length == 2 && accessToken.token) { let repoName = splitted[0]; let hookId = splitted[1]; let roomId; if (room?.id) { roomId = room.id; - await storeInteractionRoomData(this.persistence, user.id, roomId); + await storeInteractionRoomData( + this.persistence, + user.id, + roomId + ); } else { - roomId = (await getInteractionRoomData(this.read.getPersistenceReader(), user.id)).roomId; + roomId = ( + await getInteractionRoomData( + this.read.getPersistenceReader(), + user.id + ) + ).roomId; } //delete the susbscriptions for persistance - let subscriptionStorage = new Subscription(this.persistence, this.read.getPersistenceReader()); - let oldSubscriptions = await subscriptionStorage.getSubscriptionsByRepo(repoName, user.id); - await subscriptionStorage.deleteSubscriptionsByRepoUser(repoName, roomId, user.id); + let subscriptionStorage = new Subscription( + this.persistence, + this.read.getPersistenceReader() + ); + let oldSubscriptions = + await subscriptionStorage.getSubscriptionsByRepo( + repoName, + user.id + ); + await subscriptionStorage.deleteSubscriptionsByRepoUser( + repoName, + roomId, + user.id + ); //check if any subscription events of the repo is left in any other room - let eventSubscriptions = new Map; + let eventSubscriptions = new Map(); for (let subsciption of oldSubscriptions) { eventSubscriptions.set(subsciption.event, false); } - let updatedsubscriptions = await subscriptionStorage.getSubscriptionsByRepo(repoName, user.id); + let updatedsubscriptions = + await subscriptionStorage.getSubscriptionsByRepo( + repoName, + user.id + ); if (updatedsubscriptions.length == 0) { - await deleteSubscription(this.http, repoName, accessToken.token, hookId); + await deleteSubscription( + this.http, + repoName, + accessToken.token, + hookId + ); } else { for (let subsciption of updatedsubscriptions) { eventSubscriptions.set(subsciption.event, true); @@ -432,42 +686,90 @@ export class ExecuteBlockActionHandler { } } if (updatedEvents.length && !sameEvents) { - let response = await updateSubscription(this.http, repoName, accessToken.token, hookId, updatedEvents); + let response = await updateSubscription( + this.http, + repoName, + accessToken.token, + hookId, + updatedEvents + ); } } - let userRoom = await this.read.getRoomReader().getById(roomId) as IRoom; - await sendNotification(this.read, this.modify, user, userRoom, `Unsubscribed to ${repoName} 🔕`); + let userRoom = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; + await sendNotification( + this.read, + this.modify, + user, + userRoom, + `Unsubscribed to ${repoName} 🔕` + ); } - const modal = await deleteSubsciptionsModal({ modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, uikitcontext: context }); - await this.modify.getUiController().updateModalView(modal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); + const modal = await deleteSubsciptionsModal({ + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); + await this.modify.getUiController().updateModalView( + modal, + { + triggerId: context.getInteractionData().triggerId, + }, + context.getInteractionData().user + ); break; } - case ModalsEnum.SUBSCRIPTION_REFRESH_ACTION:{ - const modal = await subsciptionsModal({ modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, uikitcontext: context }); - await this.modify.getUiController().updateModalView(modal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); + case ModalsEnum.SUBSCRIPTION_REFRESH_ACTION: { + const modal = await subsciptionsModal({ + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); + await this.modify.getUiController().updateModalView( + modal, + { + triggerId: context.getInteractionData().triggerId, + }, + context.getInteractionData().user + ); break; } - case ModalsEnum.ISSUE_TEMPLATE_SELECTION_ACTION:{ + 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 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); + if (accessToken && actionDetailsArray?.length == 2) { + if ( + actionDetailsArray[1] !== + ModalsEnum.BLANK_GITHUB_TEMPLATE + ) { + let templateResponse = await getIssueTemplateCode( + this.http, + actionDetailsArray[1], + accessToken.token + ); let data = {}; - if(templateResponse?.template){ + if (templateResponse?.template) { data = { - template : templateResponse.template, - repository:actionDetailsArray[0] + template: templateResponse.template, + repository: actionDetailsArray[0], }; - }else{ + } else { data = { - template : "", - repository:actionDetailsArray[0] + template: "", + repository: actionDetailsArray[0], }; } const newIssueModal = await NewIssueModal({ @@ -481,10 +783,9 @@ export class ExecuteBlockActionHandler { return context .getInteractionResponder() .openModalViewResponse(newIssueModal); - - }else{ + } else { let data = { - repository:actionDetailsArray[0] + repository: actionDetailsArray[0], }; const newIssueModal = await NewIssueModal({ data, @@ -501,309 +802,429 @@ export class ExecuteBlockActionHandler { } break; } - case ModalsEnum.SHARE_SEARCH_RESULT_ACTION:{ + case ModalsEnum.SHARE_SEARCH_RESULT_ACTION: { let { user, room } = await context.getInteractionData(); - let value: string = context.getInteractionData().value as string; - if(user?.id){ - if(room?.id){ - await sendMessage(this.modify,room,user,`${value}`); - }else{ + let value: string = context.getInteractionData() + .value as string; + if (user?.id) { + if (room?.id) { + await sendMessage( + this.modify, + room, + user, + `${value}` + ); + } else { let roomId = ( await getInteractionRoomData( this.read.getPersistenceReader(), user.id ) ).roomId; - room = await this.read.getRoomReader().getById(roomId) as IRoom; - await sendMessage(this.modify,room,user,`${value}`); + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; + await sendMessage( + this.modify, + room, + user, + `${value}` + ); } } break; } - case ModalsEnum.VIEW_GITHUB_SEARCH_RESULT_PR_CHANGES:{ + case ModalsEnum.VIEW_GITHUB_SEARCH_RESULT_PR_CHANGES: { let { user, room } = await context.getInteractionData(); - let value: string = context.getInteractionData().value as string; + let value: string = context.getInteractionData() + .value as string; let PullRequestDetails = value.split(" "); - if(PullRequestDetails.length==2){ - const triggerId= context.getInteractionData().triggerId; + if (PullRequestDetails.length == 2) { + const triggerId = + context.getInteractionData().triggerId; const data = { - repository:PullRequestDetails[0], - query:"pulls", - number:PullRequestDetails[1] - } - if(triggerId && data){ + repository: PullRequestDetails[0], + query: "pulls", + number: PullRequestDetails[1], + }; + if (triggerId && data) { const resultsModal = await pullDetailsModal({ data, modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, - uikitcontext: context + uikitcontext: context, }); return context - .getInteractionResponder() - .openModalViewResponse(resultsModal); - }else{ + .getInteractionResponder() + .openModalViewResponse(resultsModal); + } else { console.log("Inavlid Trigger ID !"); } } - if(user?.id){ - if(room?.id){ - await sendMessage(this.modify,room,user,`${value}`); - }else{ + if (user?.id) { + if (room?.id) { + await sendMessage( + this.modify, + room, + user, + `${value}` + ); + } else { let roomId = ( await getInteractionRoomData( this.read.getPersistenceReader(), user.id ) ).roomId; - room = await this.read.getRoomReader().getById(roomId) as IRoom; - await sendMessage(this.modify,room,user,`${value}`); + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; + await sendMessage( + this.modify, + room, + user, + `${value}` + ); } } break; } - case ModalsEnum.MULTI_SHARE_ADD_SEARCH_RESULT_ACTION:{ + case ModalsEnum.MULTI_SHARE_ADD_SEARCH_RESULT_ACTION: { let { user, room } = await context.getInteractionData(); - let searchResultId: string = context.getInteractionData().value as string; - let roomId:string=""; - if(user?.id){ - if(room?.id){ + let searchResultId: string = context.getInteractionData() + .value as string; + let roomId: string = ""; + if (user?.id) { + if (room?.id) { roomId = room.id; - }else{ + } else { roomId = ( await getInteractionRoomData( this.read.getPersistenceReader(), user.id ) ).roomId; - room = await this.read.getRoomReader().getById(roomId) as IRoom; + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; } - let githubSearchStorage = new GithubSearchResultStorage(this.persistence,this.read.getPersistenceReader()); - let searchResultData: IGitHubSearchResultData = await githubSearchStorage.getSearchResults(room?.id as string,user); - if(searchResultData?.search_results?.length){ - let index = -1; - let currentIndex = 0; - for(let searchResult of searchResultData.search_results){ - if(searchResult.result_id == searchResultId ){ - index=currentIndex; - break; - } - currentIndex++; - } - if(index !== -1){ - searchResultData.search_results[index].share=true; - await githubSearchStorage.updateSearchResult(room as IRoom,user,searchResultData); + let githubSearchStorage = new GithubSearchResultStorage( + this.persistence, + this.read.getPersistenceReader() + ); + let searchResultData: IGitHubSearchResultData = + await githubSearchStorage.getSearchResults( + room?.id as string, + user + ); + if (searchResultData?.search_results?.length) { + let index = -1; + let currentIndex = 0; + for (let searchResult of searchResultData.search_results) { + if (searchResult.result_id == searchResultId) { + index = currentIndex; + break; } - const resultsModal = await githubSearchResultModal({ - data: searchResultData, - modify: this.modify, - read: this.read, - persistence: this.persistence, - http: this.http, - }) - await this.modify.getUiController().updateModalView(resultsModal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); + currentIndex++; + } + if (index !== -1) { + searchResultData.search_results[index].share = + true; + await githubSearchStorage.updateSearchResult( + room as IRoom, + user, + searchResultData + ); } + const resultsModal = await githubSearchResultModal({ + data: searchResultData, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + }); + await this.modify.getUiController().updateModalView( + resultsModal, + { + triggerId: + context.getInteractionData().triggerId, + }, + context.getInteractionData().user + ); + } } break; } - case ModalsEnum.MULTI_SHARE_REMOVE_SEARCH_RESULT_ACTION:{ + case ModalsEnum.MULTI_SHARE_REMOVE_SEARCH_RESULT_ACTION: { let { user, room } = await context.getInteractionData(); - let searchResultId: string = context.getInteractionData().value as string; - let roomId=""; - if(user?.id && searchResultId){ - if(room?.id){ + let searchResultId: string = context.getInteractionData() + .value as string; + let roomId = ""; + if (user?.id && searchResultId) { + if (room?.id) { roomId = room.id; - }else{ + } else { roomId = ( await getInteractionRoomData( this.read.getPersistenceReader(), user.id ) ).roomId; - room = await this.read.getRoomReader().getById(roomId) as IRoom; + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; } - let githubSearchStorage = new GithubSearchResultStorage(this.persistence,this.read.getPersistenceReader()); - let searchResultData: IGitHubSearchResultData = await githubSearchStorage.getSearchResults(room?.id as string,user); - if(searchResultData?.search_results?.length){ - let index = -1; - let currentIndex = 0; - for(let searchResult of searchResultData.search_results){ - if(searchResult.result_id == searchResultId){ - index=currentIndex; - break; - } - currentIndex++; - } - if(index !== -1){ - searchResultData.search_results[index].share=false; - await githubSearchStorage.updateSearchResult(room as IRoom,user,searchResultData); + let githubSearchStorage = new GithubSearchResultStorage( + this.persistence, + this.read.getPersistenceReader() + ); + let searchResultData: IGitHubSearchResultData = + await githubSearchStorage.getSearchResults( + room?.id as string, + user + ); + if (searchResultData?.search_results?.length) { + let index = -1; + let currentIndex = 0; + for (let searchResult of searchResultData.search_results) { + if (searchResult.result_id == searchResultId) { + index = currentIndex; + break; } - const resultsModal = await githubSearchResultModal({ - data: searchResultData, - modify: this.modify, - read: this.read, - persistence: this.persistence, - http: this.http, - }) - await this.modify.getUiController().updateModalView(resultsModal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); + currentIndex++; + } + if (index !== -1) { + searchResultData.search_results[index].share = + false; + await githubSearchStorage.updateSearchResult( + room as IRoom, + user, + searchResultData + ); } + const resultsModal = await githubSearchResultModal({ + data: searchResultData, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + }); + await this.modify.getUiController().updateModalView( + resultsModal, + { + triggerId: + context.getInteractionData().triggerId, + }, + context.getInteractionData().user + ); + } } break; } - case ModalsEnum.MERGE_PULL_REQUEST_ACTION:{ - let value: string = context.getInteractionData().value as string; + case ModalsEnum.MERGE_PULL_REQUEST_ACTION: { + let value: string = context.getInteractionData() + .value as string; let splittedValues = value?.split(" "); let { user } = await context.getInteractionData(); - let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; - if(splittedValues.length==2 && accessToken?.token){ - let data={ - "repo" : splittedValues[0], - "pullNumber": splittedValues[1] - } - let repoDetails = await getRepoData(this.http,splittedValues[0],accessToken.token); + let accessToken = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; + if (splittedValues.length == 2 && accessToken?.token) { + let data = { + repo: splittedValues[0], + pullNumber: splittedValues[1], + }; + let repoDetails = await getRepoData( + this.http, + splittedValues[0], + accessToken.token + ); - if(repoDetails?.permissions?.admin || repoDetails?.permissions?.push || repoDetails?.permissions?.maintain ){ + if ( + repoDetails?.permissions?.admin || + repoDetails?.permissions?.push || + repoDetails?.permissions?.maintain + ) { const mergePRModal = await mergePullRequestModal({ - data:data, + data: data, modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, - uikitcontext: context - }) + uikitcontext: context, + }); return context .getInteractionResponder() .openModalViewResponse(mergePRModal); - }else{ - const unauthorizedMessageModal = await messageModal({ - message:"Unauthorized Action 🤖 You dont have push rights ⚠️", - modify: this.modify, - read: this.read, - persistence: this.persistence, - http: this.http, - uikitcontext: context - }) + } else { + const unauthorizedMessageModal = await messageModal( + { + message: + "Unauthorized Action 🤖 You dont have push rights ⚠️", + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + } + ); return context .getInteractionResponder() - .openModalViewResponse(unauthorizedMessageModal); + .openModalViewResponse( + unauthorizedMessageModal + ); } - } break; } - case ModalsEnum.COMMENT_PR_ACTION:{ - let value: string = context.getInteractionData().value as string; + case ModalsEnum.COMMENT_PR_ACTION: { + let value: string = context.getInteractionData() + .value as string; let splittedValues = value?.split(" "); let { user } = await context.getInteractionData(); - let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; - if(splittedValues.length==2 && accessToken?.token){ - let data={ - "repo" : splittedValues[0], - "pullNumber": splittedValues[1] - } - const addPRCommentModal = await addPullRequestCommentsModal({ - data:data, - modify:this.modify, - read:this.read, - persistence: this.persistence, - http: this.http, - uikitcontext: context - }) + let accessToken = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; + if (splittedValues.length == 2 && accessToken?.token) { + let data = { + repo: splittedValues[0], + pullNumber: splittedValues[1], + }; + const addPRCommentModal = + await addPullRequestCommentsModal({ + data: data, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); return context - .getInteractionResponder() - .openModalViewResponse(addPRCommentModal); + .getInteractionResponder() + .openModalViewResponse(addPRCommentModal); } break; } - case ModalsEnum.SHARE_PROFILE : { - + case ModalsEnum.SHARE_PROFILE: { const shareProfileMod = await shareProfileModal({ - modify:this.modify, - read:this.read, + modify: this.modify, + read: this.read, persistence: this.persistence, http: this.http, - uikitcontext: context - }) + uikitcontext: context, + }); - return context.getInteractionResponder().openModalViewResponse(shareProfileMod); + return context + .getInteractionResponder() + .openModalViewResponse(shareProfileMod); } - - case ModalsEnum.PR_COMMENT_LIST_ACTION:{ - let value: string = context.getInteractionData().value as string; + case ModalsEnum.PR_COMMENT_LIST_ACTION: { + let value: string = context.getInteractionData() + .value as string; let splittedValues = value?.split(" "); let { user } = await context.getInteractionData(); - let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config) as IAuthData; - if(splittedValues.length==2 && accessToken?.token){ + let accessToken = (await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + )) as IAuthData; + if (splittedValues.length == 2 && accessToken?.token) { let repoName = splittedValues[0]; let pullNumber = splittedValues[1]; - let pullRequestComments = await getPullRequestComments(this.http,repoName,accessToken.token,pullNumber); - let pullRequestData = await getPullRequestData(this.http,repoName,accessToken.token,pullNumber); - if(pullRequestData?.serverError || pullRequestComments?.pullRequestData){ - if(pullRequestData?.serverError){ - const unauthorizedMessageModal = await messageModal({ - message:`🤖 Error Fetching Repository Data: ⚠️ ${pullRequestData?.message}`, - modify: this.modify, - read: this.read, - persistence: this.persistence, - http: this.http, - uikitcontext: context - }) + let pullRequestComments = await getPullRequestComments( + this.http, + repoName, + accessToken.token, + pullNumber + ); + let pullRequestData = await getPullRequestData( + this.http, + repoName, + accessToken.token, + pullNumber + ); + if ( + pullRequestData?.serverError || + pullRequestComments?.pullRequestData + ) { + if (pullRequestData?.serverError) { + const unauthorizedMessageModal = + await messageModal({ + message: `🤖 Error Fetching Repository Data: ⚠️ ${pullRequestData?.message}`, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); return context .getInteractionResponder() - .openModalViewResponse(unauthorizedMessageModal); + .openModalViewResponse( + unauthorizedMessageModal + ); } - if(pullRequestComments?.serverError){ - const unauthorizedMessageModal = await messageModal({ - message:`🤖 Error Fetching Comments: ⚠️ ${pullRequestData?.message}`, - modify: this.modify, - read: this.read, - persistence: this.persistence, - http: this.http, - uikitcontext: context - }) + if (pullRequestComments?.serverError) { + const unauthorizedMessageModal = + await messageModal({ + message: `🤖 Error Fetching Comments: ⚠️ ${pullRequestData?.message}`, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); return context .getInteractionResponder() - .openModalViewResponse(unauthorizedMessageModal); + .openModalViewResponse( + unauthorizedMessageModal + ); } } - let data={ + let data = { repo: repoName, pullNumber: pullNumber, pullData: pullRequestData, - pullRequestComments: pullRequestComments?.data - } - const addPRCommentModal = await pullRequestCommentsModal({ - data:data, - modify:this.modify, - read:this.read, - persistence: this.persistence, - http: this.http, - uikitcontext: context - }) + pullRequestComments: pullRequestComments?.data, + }; + const addPRCommentModal = + await pullRequestCommentsModal({ + data: data, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); return context - .getInteractionResponder() - .openModalViewResponse(addPRCommentModal); + .getInteractionResponder() + .openModalViewResponse(addPRCommentModal); } break; } case ModalsEnum.ADD_GITHUB_ISSUE_ASSIGNEE: { - let value: string = context.getInteractionData().value as string; + let value: string = context.getInteractionData() + .value as string; let splittedValues = value?.split(" "); - if(splittedValues?.length>=3){ + if (splittedValues?.length >= 2) { let repository = splittedValues[0]; let issueNumber = splittedValues[1]; let assignees: string = ""; - for(let i = 2;i0){ + for (let i = 2; i < splittedValues.length; i++) { + if (splittedValues[i].length > 0) { assignees += `${splittedValues[i]} `; } } let data = { repository, issueNumber, - assignees + assignees, }; const addIssueAssignee = await addIssueAssigneeModal({ data, @@ -811,8 +1232,8 @@ export class ExecuteBlockActionHandler { read: this.read, persistence: this.persistence, http: this.http, - uikitcontext: context - }) + uikitcontext: context, + }); return context .getInteractionResponder() .openModalViewResponse(addIssueAssignee); @@ -820,129 +1241,218 @@ export class ExecuteBlockActionHandler { break; } case ModalsEnum.REFRESH_GITHUB_ISSUES_ACTION: { - let repository: string = context.getInteractionData().value as string; - repository=repository?.trim(); + let repository: string = context.getInteractionData() + .value as string; + repository = repository?.trim(); let { user } = await context.getInteractionData(); - let accessToken = await getAccessTokenForUser(this.read, user, this.app.oauth2Config); + let accessToken = await getAccessTokenForUser( + this.read, + user, + this.app.oauth2Config + ); if (!accessToken) { - let response = await getRepositoryIssues(this.http,repository); + let response = await getRepositoryIssues( + this.http, + repository + ); let data = { issues: response.issues, - pushRights : false, //no access token, so user has no pushRights to the repo, - repo: repository - } - const issuesListModal = await githubIssuesListModal( {data: data, modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, uikitcontext: context} ); - await this.modify.getUiController().updateModalView(issuesListModal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); - }else{ - let repoDetails = await getRepoData(this.http,repository,accessToken.token); - let response = await getRepositoryIssues(this.http,repository); + pushRights: false, //no access token, so user has no pushRights to the repo, + repo: repository, + }; + const issuesListModal = await githubIssuesListModal({ + data: data, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); + await this.modify.getUiController().updateModalView( + issuesListModal, + { + triggerId: + context.getInteractionData().triggerId, + }, + context.getInteractionData().user + ); + } else { + let repoDetails = await getRepoData( + this.http, + repository, + accessToken.token + ); + let response = await getRepositoryIssues( + this.http, + repository + ); let data = { issues: response.issues, - pushRights : repoDetails?.permissions?.push || repoDetails?.permissions?.admin, - repo: repository - } - const issuesListModal = await githubIssuesListModal( {data: data, modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, uikitcontext: context} ); - await this.modify.getUiController().updateModalView(issuesListModal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); + pushRights: + repoDetails?.permissions?.push || + repoDetails?.permissions?.admin, + repo: repository, + }; + const issuesListModal = await githubIssuesListModal({ + data: data, + modify: this.modify, + read: this.read, + persistence: this.persistence, + http: this.http, + uikitcontext: context, + }); + await this.modify.getUiController().updateModalView( + issuesListModal, + { + triggerId: + context.getInteractionData().triggerId, + }, + context.getInteractionData().user + ); } break; } - case ModalsEnum.MULTI_SHARE_ADD_GITHUB_ISSUE_ACTION:{ + case ModalsEnum.MULTI_SHARE_ADD_GITHUB_ISSUE_ACTION: { let { user, room } = await context.getInteractionData(); - let issueId: string = context.getInteractionData().value as string; - let roomId:string=""; - if(user?.id){ - if(room?.id){ + let issueId: string = context.getInteractionData() + .value as string; + let roomId: string = ""; + if (user?.id) { + if (room?.id) { roomId = room.id; - }else{ + } else { roomId = ( await getInteractionRoomData( this.read.getPersistenceReader(), user.id ) ).roomId; - room = await this.read.getRoomReader().getById(roomId) as IRoom; + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; } - let githubissueStorage = new GithubRepoIssuesStorage(this.persistence,this.read.getPersistenceReader()); - let repoIssuesData: IGitHubIssueData = await githubissueStorage.getIssueData(room?.id as string,user); - if(repoIssuesData?.issue_list?.length){ - let index = -1; - let currentIndex = 0; - for(let issue of repoIssuesData.issue_list){ - if(issue.issue_id == issueId ){ - index=currentIndex; - break; - } - currentIndex++; - } - if(index !== -1){ - repoIssuesData.issue_list[index].share=true; - await githubissueStorage.updateIssueData(room as IRoom,user,repoIssuesData); + let githubissueStorage = new GithubRepoIssuesStorage( + this.persistence, + this.read.getPersistenceReader() + ); + let repoIssuesData: IGitHubIssueData = + await githubissueStorage.getIssueData( + room?.id as string, + user + ); + if (repoIssuesData?.issue_list?.length) { + let index = -1; + let currentIndex = 0; + for (let issue of repoIssuesData.issue_list) { + if (issue.issue_id == issueId) { + index = currentIndex; + break; } - let data = { - issues: repoIssuesData.issue_list, - pushRights : repoIssuesData.push_rights, //no access token, so user has no pushRights to the repo, - repo: repoIssuesData.repository, - user_id: user.id - } - const githubIssuesModal = await githubIssuesListModal({ + currentIndex++; + } + if (index !== -1) { + repoIssuesData.issue_list[index].share = true; + await githubissueStorage.updateIssueData( + room as IRoom, + user, + repoIssuesData + ); + } + let data = { + issues: repoIssuesData.issue_list, + pushRights: repoIssuesData.push_rights, //no access token, so user has no pushRights to the repo, + repo: repoIssuesData.repository, + user_id: user.id, + }; + const githubIssuesModal = + await githubIssuesListModal({ data: data, modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, - }) - await this.modify.getUiController().updateModalView(githubIssuesModal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); - } + }); + await this.modify.getUiController().updateModalView( + githubIssuesModal, + { + triggerId: + context.getInteractionData().triggerId, + }, + context.getInteractionData().user + ); + } } break; } - case ModalsEnum.MULTI_SHARE_REMOVE_GITHUB_ISSUE_ACTION:{ + case ModalsEnum.MULTI_SHARE_REMOVE_GITHUB_ISSUE_ACTION: { let { user, room } = await context.getInteractionData(); - let issueId: string = context.getInteractionData().value as string; - let roomId:string=""; - if(user?.id){ - if(room?.id){ + let issueId: string = context.getInteractionData() + .value as string; + let roomId: string = ""; + if (user?.id) { + if (room?.id) { roomId = room.id; - }else{ + } else { roomId = ( await getInteractionRoomData( this.read.getPersistenceReader(), user.id ) ).roomId; - room = await this.read.getRoomReader().getById(roomId) as IRoom; + room = (await this.read + .getRoomReader() + .getById(roomId)) as IRoom; } - let githubissueStorage = new GithubRepoIssuesStorage(this.persistence,this.read.getPersistenceReader()); - let repoIssuesData: IGitHubIssueData = await githubissueStorage.getIssueData(room?.id as string,user); - if(repoIssuesData?.issue_list?.length){ - let index = -1; - let currentIndex = 0; - for(let issue of repoIssuesData.issue_list){ - if(issue.issue_id == issueId ){ - index=currentIndex; - break; - } - currentIndex++; - } - if(index !== -1){ - repoIssuesData.issue_list[index].share=false; - await githubissueStorage.updateIssueData(room as IRoom,user,repoIssuesData); - } - let data = { - issues: repoIssuesData.issue_list, - pushRights : repoIssuesData.push_rights, //no access token, so user has no pushRights to the repo, - repo: repoIssuesData.repository, - user_id: user.id + let githubissueStorage = new GithubRepoIssuesStorage( + this.persistence, + this.read.getPersistenceReader() + ); + let repoIssuesData: IGitHubIssueData = + await githubissueStorage.getIssueData( + room?.id as string, + user + ); + if (repoIssuesData?.issue_list?.length) { + let index = -1; + let currentIndex = 0; + for (let issue of repoIssuesData.issue_list) { + if (issue.issue_id == issueId) { + index = currentIndex; + break; } - const githubIssuesModal = await githubIssuesListModal({ + currentIndex++; + } + if (index !== -1) { + repoIssuesData.issue_list[index].share = false; + await githubissueStorage.updateIssueData( + room as IRoom, + user, + repoIssuesData + ); + } + let data = { + issues: repoIssuesData.issue_list, + pushRights: repoIssuesData.push_rights, //no access token, so user has no pushRights to the repo, + repo: repoIssuesData.repository, + user_id: user.id, + }; + const githubIssuesModal = + await githubIssuesListModal({ data: data, modify: this.modify, read: this.read, persistence: this.persistence, http: this.http, - }) - await this.modify.getUiController().updateModalView(githubIssuesModal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); - } + }); + await this.modify.getUiController().updateModalView( + githubIssuesModal, + { + triggerId: + context.getInteractionData().triggerId, + }, + context.getInteractionData().user + ); + } } break; } From 85efc8f8919e4dd6e4df77d01af86bf140cf3aa5 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Mon, 14 Nov 2022 01:35:20 +0530 Subject: [PATCH 33/33] feat: Helper Message Modifed for Gist Feature --- 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 d43858b..0518a54 100644 --- a/github/lib/helperMessage.ts +++ b/github/lib/helperMessage.ts @@ -21,7 +21,7 @@ export async function helperMessage({ }) { let helperMessageString = ` Github App - + - Both /gh and /github commands can be used. 1) See Interactive Button interface to fetch repository data -> /github Username/RepositoryName 2) Get details of a Repository -> /github Username/RepositoryName repo 3) Get Issues of a Repository -> /github Username/RepositoryName issues @@ -30,13 +30,14 @@ export async function helperMessage({ 6) Review a Pull Request -> /github Username/RepositoryName pulls pullNumber 7) Login to GitHub -> /github login 8) Logout from GitHub -> /github logout - 9) View/Add/Delete/Update Repository Subscriptions -> /github subscribe + 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 issue 13) Search Issues and Pull Requests -> /github search 14) Assign and Share Issues -> /github issues - + 15) Review and Share Gist -> /github gist + 16) Get the latest Gist for the Authorized User -> /github gist 1 `; const textSender = await modify