From efce5afed2c606042175af65fc250076d31bf048 Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras Date: Sun, 4 Dec 2022 11:26:41 +0530 Subject: [PATCH 1/8] feat: Emoji reaction operation initiated --- github/helpers/githubSDK.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index 8aab870..2b627d1 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -726,3 +726,13 @@ export async function updateGithubIssues( } return repsonseJSON; } + +export async function createIssueReaction(){ + + // https://docs.github.com/en/rest/reactions?apiVersion=2022-11-28#create-reaction-for-an-issue +} + +export async funtion removeIssueReaction(){ + + // https://docs.github.com/en/rest/reactions?apiVersion=2022-11-28#delete-an-issue-reaction +} From 3a219f42bad7549e15da373df4e74f4d5b21491a Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras Date: Sun, 26 Feb 2023 15:50:24 +0530 Subject: [PATCH 2/8] chore: changed textSender(builder) to have customFields --- github/helpers/githubSDK.ts | 2 +- github/lib/issuesListMessage.ts | 40 ++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index 2b627d1..ee99c42 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -732,7 +732,7 @@ export async function createIssueReaction(){ // https://docs.github.com/en/rest/reactions?apiVersion=2022-11-28#create-reaction-for-an-issue } -export async funtion removeIssueReaction(){ +export async function removeIssueReaction(){ // https://docs.github.com/en/rest/reactions?apiVersion=2022-11-28#delete-an-issue-reaction } diff --git a/github/lib/issuesListMessage.ts b/github/lib/issuesListMessage.ts index 79b5e91..683a958 100644 --- a/github/lib/issuesListMessage.ts +++ b/github/lib/issuesListMessage.ts @@ -12,6 +12,7 @@ import { ISlashCommand, SlashCommandContext, } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { IUser } from "@rocket.chat/apps-engine/definition/users"; export async function issueListMessage({ repository, @@ -22,7 +23,7 @@ export async function issueListMessage({ http, accessToken, }: { - repository : String, + repository: String; room: IRoom; read: IRead; persistence: IPersistence; @@ -30,14 +31,17 @@ export async function issueListMessage({ http: IHttp; accessToken?: IAuthData; }) { - let gitResponse:any; - if(accessToken?.token){ - gitResponse = await http.get(`https://api.github.com/repos/${repository}/issues`, { - headers: { - Authorization: `token ${accessToken?.token}`, - "Content-Type": "application/json", - }, - }); + let gitResponse: any; + if (accessToken?.token) { + gitResponse = await http.get( + `https://api.github.com/repos/${repository}/issues`, + { + headers: { + Authorization: `token ${accessToken?.token}`, + "Content-Type": "application/json", + }, + } + ); } else { gitResponse = await http.get( `https://api.github.com/repos/${repository}/issues` @@ -54,17 +58,23 @@ export async function issueListMessage({ } let ind = 0; await modify.getCreator().finish(textSender); + const sender = (await read.getUserReader().getAppUser()) as IUser; resData.forEach(async (issue) => { if (typeof issue.pull_request === "undefined" && ind < 10) { const textSender = await modify .getCreator() .startMessage() - .setText( - `[ #${issue.number} ](${issue.html_url}) *[${issue.title}](${issue.html_url})*` - ); - if (room) { - textSender.setRoom(room); - } + .setData({ + room, + sender, + text: `[ #${issue.number} ](${issue.html_url}) *[${issue.title}](${issue.html_url})*`, + customFields: { + "issue": true, + "issue_url": issue.html_url, + "issue_title": issue.title + } + }); + await modify.getCreator().finish(textSender); ind++; } From b64b5d53b07d799f27b3cfd106ea5bff2b655e90 Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras Date: Sun, 26 Feb 2023 15:53:01 +0530 Subject: [PATCH 3/8] init IPostMessageReacted with precode indentation --- github/GithubApp.ts | 45 ++++++++++++++++++++++++++++++++++++--------- github/app.json | 4 +++- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/github/GithubApp.ts b/github/GithubApp.ts index 8659bde..993c0a1 100644 --- a/github/GithubApp.ts +++ b/github/GithubApp.ts @@ -38,10 +38,17 @@ import { import { githubWebHooks } from "./endpoints/githubEndpoints"; import { IJobContext } from "@rocket.chat/apps-engine/definition/scheduler"; import { IRoom } from "@rocket.chat/apps-engine/definition/rooms"; -import { clearInteractionRoomData, getInteractionRoomData } from "./persistance/roomInteraction"; +import { + clearInteractionRoomData, + getInteractionRoomData, +} from "./persistance/roomInteraction"; import { GHCommand } from "./commands/GhCommand"; +import { + IMessageReactionContext, + IPostMessageReacted, +} from "@rocket.chat/apps-engine/definition/messages"; -export class GithubApp extends App { +export class GithubApp extends App implements IPostMessageReacted { constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { super(info, logger, accessors); } @@ -63,7 +70,10 @@ export class GithubApp extends App { }, }; let text = `GitHub Authentication Succesfull 🚀`; - let interactionData = await getInteractionRoomData(read.getPersistenceReader(),user.id) ; + let interactionData = await getInteractionRoomData( + read.getPersistenceReader(), + user.id + ); if (token) { // await registerAuthorizedUser(read, persistence, user); @@ -71,15 +81,14 @@ export class GithubApp extends App { } else { text = `Authentication Failure 😔`; } - if(interactionData && interactionData.roomId){ + if (interactionData && interactionData.roomId) { let roomId = interactionData.roomId as string; - let room = await read.getRoomReader().getById(roomId) as IRoom; - await clearInteractionRoomData(persistence,user.id); - await sendNotification(read,modify,user,room,text); - }else{ + let room = (await read.getRoomReader().getById(roomId)) as IRoom; + await clearInteractionRoomData(persistence, user.id); + await sendNotification(read, modify, user, room, text); + } else { await sendDirectMessage(read, modify, user, text, persistence); } - } public oauth2ClientInstance: IOAuth2Client; public oauth2Config: IOAuth2ClientOptions = { @@ -152,6 +161,24 @@ export class GithubApp extends App { return await handler.run(context); } + public async executePostMessageReacted( + context: IMessageReactionContext, + read: IRead, + http: IHttp, + persistence: IPersistence, + modify: IModify + ): Promise { + if (context.message.customFields?.["issue"]) { + console.log(context.message.text); + + // when user reacts to those 6 emojis + if (context.isReacted) { + } else { + // when user removes the reaction + } + } + } + public async extendConfiguration( configuration: IConfigurationExtend ): Promise { diff --git a/github/app.json b/github/app.json index 58af157..de34b93 100644 --- a/github/app.json +++ b/github/app.json @@ -12,5 +12,7 @@ "nameSlug": "github", "classFile": "GithubApp.ts", "description": "The ultimate app extending Rocket.Chat for all developers collaborating on Github", - "implements": [] + "implements": [ + "IPostMessageReacted" + ] } \ No newline at end of file From eaa30fb3037f903937418595946aec4bea96fe88 Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras Date: Sun, 26 Feb 2023 20:10:58 +0530 Subject: [PATCH 4/8] feat(alpha): create reaction in issue from RocketChat --- github/GithubApp.ts | 43 ++++++++++++++++++++---- github/enum/OcticonIcons.ts | 24 +++++++++++++- github/helpers/githubIssueReaction.ts | 22 +++++++++++++ github/helpers/githubSDK.ts | 47 ++++++++++++++++++++++++--- github/lib/issuesListMessage.ts | 10 +++--- 5 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 github/helpers/githubIssueReaction.ts diff --git a/github/GithubApp.ts b/github/GithubApp.ts index 993c0a1..cf7b5b8 100644 --- a/github/GithubApp.ts +++ b/github/GithubApp.ts @@ -47,6 +47,10 @@ import { IMessageReactionContext, IPostMessageReacted, } from "@rocket.chat/apps-engine/definition/messages"; +import { createIssueReaction } from "./helpers/githubSDK"; +import { getAccessTokenForUser } from "./persistance/auth"; +import { IssueReactions } from "./enum/OcticonIcons"; +import { isAvailableReaction } from "./helpers/githubIssueReaction"; export class GithubApp extends App implements IPostMessageReacted { constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { @@ -169,12 +173,39 @@ export class GithubApp extends App implements IPostMessageReacted { modify: IModify ): Promise { if (context.message.customFields?.["issue"]) { - console.log(context.message.text); - - // when user reacts to those 6 emojis - if (context.isReacted) { - } else { - // when user removes the reaction + const { includes_emoji, emoji } = isAvailableReaction(context); + // when user reacts to those 8 emojis + if (includes_emoji) { + const user = context.user; + const auth = await getAccessTokenForUser( + read, + user, + this.oauth2Config + ); + + if (auth) { + const { issue_number, owner, repo_name } = + context.message?.customFields; + const token = auth.token; + + // remove true later as issue raised for isReacted field undefined + if (context.isReacted || true) { + const response = await createIssueReaction( + repo_name, + owner, + issue_number, + http, + token, + emoji + ); + + // make an association with the reactionId for deleting the issue reaction + } else { + // when user removes the reaction + } + } else { + // notify in direct message by bot for letting user know that your changes to reaction won't change issue in github + } } } } diff --git a/github/enum/OcticonIcons.ts b/github/enum/OcticonIcons.ts index 0174b80..55063cc 100644 --- a/github/enum/OcticonIcons.ts +++ b/github/enum/OcticonIcons.ts @@ -5,5 +5,27 @@ export enum OcticonIcons { 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" + PENCIL = "https://raw.githubusercontent.com/primer/octicons/main/icons/pencil-24.svg", +} + +export enum IssueReactions { + "LAUGH" = "laughing", + "PLUS_ONE" = "thumbsup", + "MINUS_ONE" = "thumbsdown", + "HEART" = "heart", + "CONFUSED" = "confused", + "ROCKET" = "rocket", + "EYES" = "eyes", + // "HOORAY" = "partying_face", +} + +export enum IssueReactionsAliases { + laughing = "laugh", + thumbsup = "+1", + thumbsdown = "-1", + heart = "heart", + confused = "confused", + rocket = "rocket", + eyes = "eyes", + // partying_face = "hooray", } diff --git a/github/helpers/githubIssueReaction.ts b/github/helpers/githubIssueReaction.ts new file mode 100644 index 0000000..98be5b0 --- /dev/null +++ b/github/helpers/githubIssueReaction.ts @@ -0,0 +1,22 @@ +// this file contains the logic for checking issue reactions which needs to update in github + +import { IMessageReactionContext } from "@rocket.chat/apps-engine/definition/messages"; +import { IssueReactions, IssueReactionsAliases } from "../enum/OcticonIcons"; + +export function isAvailableReaction(context: IMessageReactionContext) { + const content = context.reaction; + const reaction = content.substring(1, content.length - 1); + const includesEmoji = Object.values(IssueReactions).includes( + reaction as IssueReactions + ); + if (includesEmoji) { + return { + includes_emoji: true, + emoji: IssueReactionsAliases[reaction], + }; + } + + return { + includes_emoji: false, + }; +} diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index ee99c42..dcb3d92 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -727,12 +727,51 @@ export async function updateGithubIssues( return repsonseJSON; } -export async function createIssueReaction(){ - +export async function createIssueReaction( + repoName: string, + owner: string, + issueNumber: number, + http: IHttp, + access_token: string, + reaction: string +) { + try { + const request_data = { + content: reaction, + }; + + const response = await http.post( + `${BaseApiHost}repos/${repoName}/issues/${issueNumber}/reactions`, + { + headers: { + Authorization: `Bearer ${access_token}`, + "Content-Type": "application/json", + }, + data: request_data, + } + ); + + const { data } = response; + const responseJSON: any = {}; + if (response.statusCode.toString().startsWith("2")) { + const { id } = data; + responseJSON["reaction_id"] = id; + responseJSON["serverError"] = false; + } else { + responseJSON["serverError"] = true; + responseJSON["message"] = response.content; + } + return responseJSON; + } catch (e) { + return { + error: "Error While Creating Reaction to Issue", + issue_number: issueNumber, + }; + } + // https://docs.github.com/en/rest/reactions?apiVersion=2022-11-28#create-reaction-for-an-issue } -export async function removeIssueReaction(){ - +export async function removeIssueReaction() { // https://docs.github.com/en/rest/reactions?apiVersion=2022-11-28#delete-an-issue-reaction } diff --git a/github/lib/issuesListMessage.ts b/github/lib/issuesListMessage.ts index 683a958..df86498 100644 --- a/github/lib/issuesListMessage.ts +++ b/github/lib/issuesListMessage.ts @@ -69,10 +69,12 @@ export async function issueListMessage({ sender, text: `[ #${issue.number} ](${issue.html_url}) *[${issue.title}](${issue.html_url})*`, customFields: { - "issue": true, - "issue_url": issue.html_url, - "issue_title": issue.title - } + issue: true, + issue_url: issue.html_url, + issue_number: issue.number, + owner: issue.user.login, + repo_name: repository, + }, }); await modify.getCreator().finish(textSender); From 8fc52e234b8fb1ad48aa575652e3d575b4dc2990 Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras Date: Wed, 1 Mar 2023 16:38:36 +0530 Subject: [PATCH 5/8] feat(alpha): remove reaction in issue from RocketChat --- github/GithubApp.ts | 53 ++++++++++++++++++++++++++++++++++--- github/enum/OcticonIcons.ts | 4 --- github/helpers/githubSDK.ts | 34 +++++++++++++++++++++++- 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/github/GithubApp.ts b/github/GithubApp.ts index cf7b5b8..cff9c6b 100644 --- a/github/GithubApp.ts +++ b/github/GithubApp.ts @@ -8,7 +8,11 @@ import { IRead, } from "@rocket.chat/apps-engine/definition/accessors"; import { App } from "@rocket.chat/apps-engine/definition/App"; -import { IAppInfo } from "@rocket.chat/apps-engine/definition/metadata"; +import { + IAppInfo, + RocketChatAssociationModel, + RocketChatAssociationRecord, +} from "@rocket.chat/apps-engine/definition/metadata"; import { GithubCommand } from "./commands/GithubCommand"; import { IUIKitResponse, @@ -47,7 +51,7 @@ import { IMessageReactionContext, IPostMessageReacted, } from "@rocket.chat/apps-engine/definition/messages"; -import { createIssueReaction } from "./helpers/githubSDK"; +import { createIssueReaction, removeIssueReaction } from "./helpers/githubSDK"; import { getAccessTokenForUser } from "./persistance/auth"; import { IssueReactions } from "./enum/OcticonIcons"; import { isAvailableReaction } from "./helpers/githubIssueReaction"; @@ -188,8 +192,26 @@ export class GithubApp extends App implements IPostMessageReacted { context.message?.customFields; const token = auth.token; + const associations: Array = [ + new RocketChatAssociationRecord( + RocketChatAssociationModel.USER, + user.id + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + repo_name as string + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + issue_number as string + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + context.reaction + ) + ]; // remove true later as issue raised for isReacted field undefined - if (context.isReacted || true) { + if (context.isReacted) { const response = await createIssueReaction( repo_name, owner, @@ -199,9 +221,32 @@ export class GithubApp extends App implements IPostMessageReacted { emoji ); - // make an association with the reactionId for deleting the issue reaction + await persistence.updateByAssociations( + associations, + response, + true + ); } else { + const persistanceRead = + await read.getPersistenceReader(); + const issueReactionData = + await persistanceRead.readByAssociations( + associations + ); + console.log(issueReactionData[0]); + const reactionId = + issueReactionData[0]?.["reaction_id"]; + + const response = await removeIssueReaction( + repo_name, + owner, + issue_number, + http, + token, + reactionId + ); // when user removes the reaction + await persistence.removeByAssociations(associations); } } else { // notify in direct message by bot for letting user know that your changes to reaction won't change issue in github diff --git a/github/enum/OcticonIcons.ts b/github/enum/OcticonIcons.ts index 55063cc..18f7f73 100644 --- a/github/enum/OcticonIcons.ts +++ b/github/enum/OcticonIcons.ts @@ -9,23 +9,19 @@ export enum OcticonIcons { } export enum IssueReactions { - "LAUGH" = "laughing", "PLUS_ONE" = "thumbsup", "MINUS_ONE" = "thumbsdown", "HEART" = "heart", "CONFUSED" = "confused", "ROCKET" = "rocket", "EYES" = "eyes", - // "HOORAY" = "partying_face", } export enum IssueReactionsAliases { - laughing = "laugh", thumbsup = "+1", thumbsdown = "-1", heart = "heart", confused = "confused", rocket = "rocket", eyes = "eyes", - // partying_face = "hooray", } diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index dcb3d92..d8fcb68 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -765,6 +765,7 @@ export async function createIssueReaction( } catch (e) { return { error: "Error While Creating Reaction to Issue", + repo_name: repoName, issue_number: issueNumber, }; } @@ -772,6 +773,37 @@ export async function createIssueReaction( // https://docs.github.com/en/rest/reactions?apiVersion=2022-11-28#create-reaction-for-an-issue } -export async function removeIssueReaction() { +export async function removeIssueReaction( + repoName: string, + owner: string, + issueNumber: number, + http: IHttp, + access_token: string, + reactionId: string +) { + try { + const response = await http.del( + `${BaseApiHost}repos/${repoName}/issues/${issueNumber}/reactions/${reactionId}`, + { + headers: { + Authorization: `Bearer ${access_token}`, + "Content-Type": "application/json", + }, + } + ); + + if (response.statusCode.toString().startsWith("2")) { + return true; + } + + return false; + } catch (e) { + return { + error: "Error While Removing Reaction to Issue", + repo_name: repoName, + issue_number: issueNumber, + }; + } + // https://docs.github.com/en/rest/reactions?apiVersion=2022-11-28#delete-an-issue-reaction } From 33c7b8f71b7213fea2b38b483cd1561b5f397b84 Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras Date: Thu, 2 Mar 2023 16:09:17 +0530 Subject: [PATCH 6/8] refactor(feat): created IssueReactionDataStorage --- github/definitions/githubIssueReaction.ts | 8 ++ github/persistance/githubIssueReaction.ts | 134 ++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 github/definitions/githubIssueReaction.ts create mode 100644 github/persistance/githubIssueReaction.ts diff --git a/github/definitions/githubIssueReaction.ts b/github/definitions/githubIssueReaction.ts new file mode 100644 index 0000000..15770ff --- /dev/null +++ b/github/definitions/githubIssueReaction.ts @@ -0,0 +1,8 @@ +// reactions results for issue (without s) +export interface IGithubIssueReaction { + reaction_id?: string; + repo_name: string; + user_id: string; + reaction: string; + issue_number: string; +} diff --git a/github/persistance/githubIssueReaction.ts b/github/persistance/githubIssueReaction.ts new file mode 100644 index 0000000..88eff6d --- /dev/null +++ b/github/persistance/githubIssueReaction.ts @@ -0,0 +1,134 @@ +import { + IPersistence, + IPersistenceRead, +} from "@rocket.chat/apps-engine/definition/accessors"; +import { + RocketChatAssociationModel, + RocketChatAssociationRecord, +} from "@rocket.chat/apps-engine/definition/metadata"; +import { IUser } from "@rocket.chat/apps-engine/definition/users"; +import { IGithubIssueReaction } from "../definitions/githubIssueReaction"; + +export class GithubIssueReactionStorage { + constructor( + private readonly persistence: IPersistence, + private readonly persistenceRead: IPersistenceRead + ) {} + + public async updateIssueReactionData( + user: IUser, + issueReaction: IGithubIssueReaction + ): Promise { + try { + const { issue_number, repo_name, reaction } = issueReaction; + const associations: Array = [ + new RocketChatAssociationRecord( + RocketChatAssociationModel.USER, + user.id + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + repo_name + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + issue_number + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + reaction + ), + ]; + + await this.persistence.updateByAssociations( + associations, + issueReaction, + true + ); + } catch (error) { + console.warn("update Issue Reaction Issue Error :", error); + return false; + } + + return true; + } + + public async getIssueReactionData( + user: IUser, + issueReaction: IGithubIssueReaction + ): Promise { + try { + const { issue_number, repo_name, reaction } = issueReaction; + const associations: Array = [ + new RocketChatAssociationRecord( + RocketChatAssociationModel.USER, + user.id + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + repo_name + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + issue_number + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + reaction + ), + ]; + + const githubIssueReactionData = + (await this.persistenceRead.readByAssociations( + associations + )) as Array; + + if (githubIssueReactionData.length < 1) { + console.warn( + "No Issue Reaction Data Found ", + githubIssueReactionData + ); + return false; + } + + return githubIssueReactionData[0]; + } catch (error) { + console.warn("Error While Fetching Issue ReactionId:", error); + throw new Error("No Related Issue Reaction Found"); + } + } + + public async removeIssueReactionData( + user: IUser, + issueReaction: IGithubIssueReaction + ): Promise { + try { + const { issue_number, repo_name, reaction } = issueReaction; + const associations: Array = [ + new RocketChatAssociationRecord( + RocketChatAssociationModel.USER, + user.id + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + repo_name + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + issue_number + ), + new RocketChatAssociationRecord( + RocketChatAssociationModel.MISC, + reaction + ), + ]; + + await this.persistence.removeByAssociations(associations); + } catch (error) { + console.warn("Error While Remove Issue Reaction Data: ", error); + return false; + } + + return true; + } +} From 8a05217318e8186ab99fc517683a47b7fa2f9da9 Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras Date: Thu, 2 Mar 2023 16:11:08 +0530 Subject: [PATCH 7/8] refactor(feat): created handler for IssueReaction --- github/GithubApp.ts | 79 +----------------- github/handlers/HandleIssueReaction.ts | 108 +++++++++++++++++++++++++ github/helpers/githubSDK.ts | 28 ++++--- 3 files changed, 129 insertions(+), 86 deletions(-) create mode 100644 github/handlers/HandleIssueReaction.ts diff --git a/github/GithubApp.ts b/github/GithubApp.ts index cff9c6b..a8e280c 100644 --- a/github/GithubApp.ts +++ b/github/GithubApp.ts @@ -55,6 +55,7 @@ import { createIssueReaction, removeIssueReaction } from "./helpers/githubSDK"; import { getAccessTokenForUser } from "./persistance/auth"; import { IssueReactions } from "./enum/OcticonIcons"; import { isAvailableReaction } from "./helpers/githubIssueReaction"; +import { HandleIssueReaction } from "./handlers/HandleIssueReaction"; export class GithubApp extends App implements IPostMessageReacted { constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { @@ -176,83 +177,7 @@ export class GithubApp extends App implements IPostMessageReacted { persistence: IPersistence, modify: IModify ): Promise { - if (context.message.customFields?.["issue"]) { - const { includes_emoji, emoji } = isAvailableReaction(context); - // when user reacts to those 8 emojis - if (includes_emoji) { - const user = context.user; - const auth = await getAccessTokenForUser( - read, - user, - this.oauth2Config - ); - - if (auth) { - const { issue_number, owner, repo_name } = - context.message?.customFields; - const token = auth.token; - - const associations: Array = [ - new RocketChatAssociationRecord( - RocketChatAssociationModel.USER, - user.id - ), - new RocketChatAssociationRecord( - RocketChatAssociationModel.MISC, - repo_name as string - ), - new RocketChatAssociationRecord( - RocketChatAssociationModel.MISC, - issue_number as string - ), - new RocketChatAssociationRecord( - RocketChatAssociationModel.MISC, - context.reaction - ) - ]; - // remove true later as issue raised for isReacted field undefined - if (context.isReacted) { - const response = await createIssueReaction( - repo_name, - owner, - issue_number, - http, - token, - emoji - ); - - await persistence.updateByAssociations( - associations, - response, - true - ); - } else { - const persistanceRead = - await read.getPersistenceReader(); - const issueReactionData = - await persistanceRead.readByAssociations( - associations - ); - console.log(issueReactionData[0]); - const reactionId = - issueReactionData[0]?.["reaction_id"]; - - const response = await removeIssueReaction( - repo_name, - owner, - issue_number, - http, - token, - reactionId - ); - // when user removes the reaction - await persistence.removeByAssociations(associations); - } - } else { - // notify in direct message by bot for letting user know that your changes to reaction won't change issue in github - } - } - } + await HandleIssueReaction(this, context, read, http, persistence); } public async extendConfiguration( diff --git a/github/handlers/HandleIssueReaction.ts b/github/handlers/HandleIssueReaction.ts new file mode 100644 index 0000000..7c7b050 --- /dev/null +++ b/github/handlers/HandleIssueReaction.ts @@ -0,0 +1,108 @@ +import { + IHttp, + IPersistence, + IRead, +} from "@rocket.chat/apps-engine/definition/accessors"; +import { IMessageReactionContext } from "@rocket.chat/apps-engine/definition/messages"; +import { IGithubIssueReaction } from "../definitions/githubIssueReaction"; +import { GithubApp } from "../GithubApp"; +import { isAvailableReaction } from "../helpers/githubIssueReaction"; +import { createIssueReaction, removeIssueReaction } from "../helpers/githubSDK"; +import { getAccessTokenForUser } from "../persistance/auth"; +import { GithubIssueReactionStorage } from "../persistance/githubIssueReaction"; + +export async function HandleIssueReaction( + app: GithubApp, + context: IMessageReactionContext, + read: IRead, + http: IHttp, + persistence: IPersistence +) { + if (context.message.customFields?.["issue"]) { + const { includes_emoji, emoji } = isAvailableReaction(context); + // when user reacts to those 6 emojis + if (includes_emoji) { + const user = context.user; + const auth = await getAccessTokenForUser( + read, + user, + app.oauth2Config + ); + + if (auth) { + const { issue_number, owner, repo_name } = + context.message?.customFields; + const token = auth.token; + const persistanceRead = await read.getPersistenceReader(); + const githubIssueReactionStorage = + new GithubIssueReactionStorage( + persistence, + persistanceRead + ); + + // NOTE: isReacted field of context was retrieving undefined until RC-SERVER version 5.4.3 which is fixed in 6.0.0 + if (context.isReacted) { + const response = await createIssueReaction( + repo_name, + owner, + issue_number, + http, + token, + emoji, + user.id + ); + + if (response.error == undefined) { + const issueReactionData = + response as IGithubIssueReaction; + await githubIssueReactionStorage.updateIssueReactionData( + user, + issueReactionData + ); + } + } else { + // when user removes the reaction + + const issueReactionData: IGithubIssueReaction = { + user_id: user.id, + reaction: emoji, + repo_name, + issue_number, + }; + + const issueReactionResponse = + await githubIssueReactionStorage.getIssueReactionData( + user, + issueReactionData + ); + // meaning there are no reactions involved with this associations + if (issueReactionResponse === false) { + return; + } + + const githubIssueReactionData = + issueReactionResponse as IGithubIssueReaction; + + const reaction_id = + githubIssueReactionData.reaction_id as string; + + const response = await removeIssueReaction( + repo_name, + owner, + issue_number, + http, + token, + reaction_id + ); + + if (response === true) { + await githubIssueReactionStorage.removeIssueReactionData( + user, + githubIssueReactionData + ); + } + } + } + } + } +} diff --git a/github/helpers/githubSDK.ts b/github/helpers/githubSDK.ts index d8fcb68..7ab86f6 100644 --- a/github/helpers/githubSDK.ts +++ b/github/helpers/githubSDK.ts @@ -1,5 +1,6 @@ import { IHttp } from "@rocket.chat/apps-engine/definition/accessors"; import { IGitHubIssue } from "../definitions/githubIssue"; +import { IGithubIssueReaction } from "../definitions/githubIssueReaction"; import { ModalsEnum } from "../enum/Modals"; const BaseHost = "https://github.com/"; @@ -733,8 +734,9 @@ export async function createIssueReaction( issueNumber: number, http: IHttp, access_token: string, - reaction: string -) { + reaction: string, + user_id: string +): Promise { try { const request_data = { content: reaction, @@ -752,21 +754,29 @@ export async function createIssueReaction( ); const { data } = response; - const responseJSON: any = {}; if (response.statusCode.toString().startsWith("2")) { const { id } = data; - responseJSON["reaction_id"] = id; - responseJSON["serverError"] = false; - } else { - responseJSON["serverError"] = true; - responseJSON["message"] = response.content; + + return { + reaction_id: id as string, + repo_name: repoName, + user_id, + reaction, + issue_number: issueNumber, + }; } - return responseJSON; + + return { + message: response.content, + error: true, + }; } catch (e) { return { error: "Error While Creating Reaction to Issue", repo_name: repoName, issue_number: issueNumber, + user_id, + reaction, }; } From aaebcb3818d2e824ba33a35104bf7de909ec716a Mon Sep 17 00:00:00 2001 From: Nabhag Motivaras Date: Thu, 2 Mar 2023 16:21:34 +0530 Subject: [PATCH 8/8] refactor(chore): removed unwanted imports --- github/GithubApp.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/github/GithubApp.ts b/github/GithubApp.ts index a8e280c..3789714 100644 --- a/github/GithubApp.ts +++ b/github/GithubApp.ts @@ -8,11 +8,7 @@ import { IRead, } from "@rocket.chat/apps-engine/definition/accessors"; import { App } from "@rocket.chat/apps-engine/definition/App"; -import { - IAppInfo, - RocketChatAssociationModel, - RocketChatAssociationRecord, -} from "@rocket.chat/apps-engine/definition/metadata"; +import { IAppInfo } from "@rocket.chat/apps-engine/definition/metadata"; import { GithubCommand } from "./commands/GithubCommand"; import { IUIKitResponse, @@ -51,10 +47,6 @@ import { IMessageReactionContext, IPostMessageReacted, } from "@rocket.chat/apps-engine/definition/messages"; -import { createIssueReaction, removeIssueReaction } from "./helpers/githubSDK"; -import { getAccessTokenForUser } from "./persistance/auth"; -import { IssueReactions } from "./enum/OcticonIcons"; -import { isAvailableReaction } from "./helpers/githubIssueReaction"; import { HandleIssueReaction } from "./handlers/HandleIssueReaction"; export class GithubApp extends App implements IPostMessageReacted {