From e0119ad5487dbb46b28e3424a3209a7a21d96dbf Mon Sep 17 00:00:00 2001 From: haemza30 Date: Wed, 29 Mar 2023 04:14:45 +0530 Subject: [PATCH 1/8] Bump changes to support latest version --- ClickUpApp.ts | 195 +++++------- app.json | 2 +- package-lock.json | 47 ++- package.json | 3 +- src/enums/App.ts | 3 +- src/enums/Misc.ts | 1 - src/handlers/ExecuteBlockActionHandler.ts | 6 +- src/helpers/blockBuilder.ts | 130 ++++++++ src/helpers/getWebhookURL.ts | 20 +- src/lib/blocks.ts | 30 -- src/lib/delete/deleteFolder.ts | 72 ++--- src/lib/delete/deleteList.ts | 72 ++--- src/lib/delete/deleteSpace.ts | 72 ++--- src/lib/delete/deleteTask.ts | 72 ++--- src/lib/deleteSubscription.ts | 97 ++---- src/lib/get/editTask.ts | 85 ++--- src/lib/get/getFolders.ts | 2 +- src/lib/get/getLists.ts | 69 ++--- src/lib/get/getSpaces.ts | 63 ++-- src/lib/get/getTasks.ts | 192 ++++-------- src/lib/get/saveWorkspace.ts | 85 ++--- src/lib/get/shareTask.ts | 77 ++--- src/lib/message.ts | 129 ++++---- src/lib/notifications.ts | 77 ++--- src/lib/persistSubscription.ts | 132 +++----- src/lib/persistWorkspace.ts | 89 ++---- src/lib/persistence.ts | 33 +- src/lib/post/postTask.ts | 179 +++++------ src/modals/addSubscriptionModal.ts | 198 +++--------- src/modals/createTaskModal.ts | 161 +++------- src/modals/deleteSubscriptionModal.ts | 157 +++++----- src/modals/editTaskModal.ts | 112 ++----- src/modals/getFoldersModal.ts | 85 +++-- src/modals/getListsModal.ts | 88 ++---- src/modals/getSpacesModal.ts | 89 +++--- src/modals/getTasksModal.ts | 114 +++---- src/modals/getWorkspacesModal.ts | 73 ++--- src/modals/saveWorkspaceModal.ts | 68 ++-- src/modals/subscriptionsModal.ts | 174 +++++------ src/slashcommands/clickUp.ts | 98 +++--- src/slashcommands/subcommands/authorize.ts | 21 +- src/slashcommands/subcommands/createTask.ts | 30 +- src/slashcommands/subcommands/getTasks.ts | 30 +- .../subcommands/getWorkspaces.ts | 44 ++- src/slashcommands/subcommands/subscribe.ts | 28 +- src/storage/roomInteraction.ts | 57 +--- src/storage/subscription.ts | 290 +++++------------- src/storage/users.ts | 100 +++--- 48 files changed, 1549 insertions(+), 2502 deletions(-) create mode 100644 src/helpers/blockBuilder.ts delete mode 100644 src/lib/blocks.ts diff --git a/ClickUpApp.ts b/ClickUpApp.ts index 43117cc..1c03c5d 100644 --- a/ClickUpApp.ts +++ b/ClickUpApp.ts @@ -1,13 +1,4 @@ -import { - IAppAccessors, - IAppInstallationContext, - IConfigurationExtend, - IHttp, - ILogger, - IModify, - IPersistence, - IRead, -} from '@rocket.chat/apps-engine/definition/accessors'; +import { IAppAccessors, IAppInstallationContext, IConfigurationExtend, IHttp, ILogger, IModify, IPersistence, 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 { IUser } from '@rocket.chat/apps-engine/definition/users'; @@ -15,131 +6,97 @@ import { isUserHighHierarchy, sendDirectMessage } from './src/lib/message'; import { IAuthData, IOAuth2Client, IOAuth2ClientOptions } from '@rocket.chat/apps-engine/definition/oauth2/IOAuth2'; import { createOAuth2Client } from '@rocket.chat/apps-engine/definition/oauth2/OAuth2'; import { connect_user_to_clickup_uid } from './src/storage/users'; -import { createSectionBlock } from './src/lib/blocks'; import { ClickUp as ClickUpCommand } from './src/slashcommands/clickUp'; import { IUIKitResponse, UIKitBlockInteractionContext, UIKitViewSubmitInteractionContext } from '@rocket.chat/apps-engine/definition/uikit'; import { ExecuteBlockActionHandler } from './src/handlers/ExecuteBlockActionHandler'; import { ExecuteViewSubmitHandler } from './src/handlers/ExecuteViewSubmitHandler'; import { HttpStatusCode } from '@rocket.chat/apps-engine/definition/accessors'; import { ApiSecurity, ApiVisibility } from '@rocket.chat/apps-engine/definition/api'; -import {clickupWebhooks} from './src/endpoints/incoming' +import { clickupWebhooks } from './src/endpoints/incoming'; +import { getSectionBlock } from './src/helpers/blockBuilder'; +import { Block } from '@rocket.chat/ui-kit'; export class ClickUpApp extends App { - - public botUsername: string; - public botUser: IUser; - - constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { - super(info, logger, accessors); + public botUsername: string; + public botUser: IUser; + + constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { + super(info, logger, accessors); + } + + private oauth2ClientInstance: IOAuth2Client; + private oauth2Config: IOAuth2ClientOptions = { + alias: 'clickup-app', + accessTokenUri: 'https://api.clickup.com/api/v2/oauth/token', + authUri: 'https://app.clickup.com/api', + refreshTokenUri: 'https://api.clickup.com/api/v2/oauth/token', + revokeTokenUri: 'https://api.clickup.com/api/v2/oauth/token', + authorizationCallback: this.autorizationCallback.bind(this), + }; + + private async autorizationCallback(token: IAuthData, user: IUser, read: IRead, modify: IModify, http: IHttp, persistence: IPersistence) { + if (token) { + const headers = { + Authorization: `${token?.token}`, + }; + + const userData = await http.get(`https://api.clickup.com/api/v2/user`, { headers }); + if (userData.statusCode == HttpStatusCode.OK) { + await connect_user_to_clickup_uid(read, persistence, userData.data.user.id, user.id); + } } - private oauth2ClientInstance: IOAuth2Client; - private oauth2Config: IOAuth2ClientOptions = { - alias: 'clickup-app', - accessTokenUri: 'https://api.clickup.com/api/v2/oauth/token', - authUri: 'https://app.clickup.com/api', - refreshTokenUri: 'https://api.clickup.com/api/v2/oauth/token', - revokeTokenUri: 'https://api.clickup.com/api/v2/oauth/token', - authorizationCallback: this.autorizationCallback.bind(this), - }; - - private async autorizationCallback( - token: IAuthData, - user: IUser, - read: IRead, - modify: IModify, - http: IHttp, - persistence: IPersistence, - ) { - - if (token) { - const headers = { - Authorization: `${token?.token}`, - }; - - const userData = await http.get(`https://api.clickup.com/api/v2/user`,{ headers }); - if(userData.statusCode==HttpStatusCode.OK) { - await connect_user_to_clickup_uid(read, persistence, userData.data.user.id, user.id); - } - - } - - const text = - `The authentication process has succeeded! :tada:\n` + - `If you are a workspace admin, retrieve it using ` + - `\`/clickup-app get-workspaces\` slash command and ` + - `save it for managing its members and tasks.\n` + - `If you are just a member of a workspace, you will be notified` + - `once your admin assigns you a task.`; - - - const blocks = await createSectionBlock(modify, text); - - await sendDirectMessage(read, modify, user, text, persistence, blocks); - } + const text = `The authentication process has succeeded! :tada:\n` + `If you are a workspace admin, retrieve it using ` + `\`/clickup-app get-workspaces\` slash command and ` + `save it for managing its members and tasks.\n` + `If you are just a member of a workspace, you will be notified` + `once your admin assigns you a task.`; + const block: Block[] = []; + let sectionBlock = await getSectionBlock(text); - public async onEnable(): Promise { - this.botUsername = 'clickup-app.bot'; - this.botUser = (await this.getAccessors() - .reader.getUserReader() - .getByUsername(this.botUsername)) as IUser; - return true; - } + block.push(sectionBlock); - public async onInstall( - context: IAppInstallationContext, - read: IRead, - http: IHttp, - persistence: IPersistence, - modify: IModify, - ): Promise { - const user = context.user; + await sendDirectMessage(read, modify, user, text, persistence, block); + } - const quickReminder = 'Quick reminder: Let your workspace users know about the ClickUp App,\ - so everyone will be able to manage their tasks/workspaces as well.\n'; + public async onEnable(): Promise { + this.botUsername = 'clickup-app.bot'; + this.botUser = (await this.getAccessors().reader.getUserReader().getByUsername(this.botUsername)) as IUser; + return true; + } - const text = - `Welcome to the ClickUp Rocket.Chat App!\n` + - `To start managing your workspaces, tasks, etc. ` + - `You first need to complete the app's setup and then authorize your ClickUp account.\n` + - `To do so, type \`/clickup-app auth\`\n` + - `${isUserHighHierarchy(user) ? quickReminder : ''}`; + public async onInstall(context: IAppInstallationContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise { + const user = context.user; - await sendDirectMessage(read, modify, user, text, persistence); - } - public getOauth2ClientInstance(): IOAuth2Client { - if (!this.oauth2ClientInstance) { - this.oauth2ClientInstance = createOAuth2Client(this, this.oauth2Config); - } - return this.oauth2ClientInstance; - } + const quickReminder = + 'Quick reminder: Let your workspace users know about the ClickUp App,\ + so everyone will be able to manage their tasks/workspaces as well.\n'; - public async executeBlockActionHandler(context: UIKitBlockInteractionContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise { - const handler = new ExecuteBlockActionHandler(this, read, http, modify, persistence); - return await handler.run(context, read, http, persistence, modify); - } + const text = `Welcome to the ClickUp Rocket.Chat App!\n` + `To start managing your workspaces, tasks, etc. ` + `You first need to complete the app's setup and then authorize your ClickUp account.\n` + `To do so, type \`/clickup-app auth\`\n` + `${isUserHighHierarchy(user) ? quickReminder : ''}`; - public async executeViewSubmitHandler(context: UIKitViewSubmitInteractionContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify) { - const handler = new ExecuteViewSubmitHandler(this, read, http, modify, persistence); - return await handler.run(this, context, read, http, persistence, modify); - } - - protected async extendConfiguration( - configuration: IConfigurationExtend, - ): Promise { - const user = (await this.getAccessors() - .reader.getUserReader() - .getAppUser()) as IUser; - - await Promise.all([ - this.getOauth2ClientInstance().setup(configuration), - configuration.slashCommands.provideSlashCommand(new ClickUpCommand(this)), - ]); - configuration.api.provideApi({ - visibility: ApiVisibility.PUBLIC, - security: ApiSecurity.UNSECURE, - endpoints: [new clickupWebhooks(this)] - }); + await sendDirectMessage(read, modify, user, text, persistence); + } + public getOauth2ClientInstance(): IOAuth2Client { + if (!this.oauth2ClientInstance) { + this.oauth2ClientInstance = createOAuth2Client(this, this.oauth2Config); } - + return this.oauth2ClientInstance; + } + + public async executeBlockActionHandler(context: UIKitBlockInteractionContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise { + const handler = new ExecuteBlockActionHandler(this, read, http, modify, persistence); + return await handler.run(context, read, http, persistence, modify); + } + + public async executeViewSubmitHandler(context: UIKitViewSubmitInteractionContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify) { + const handler = new ExecuteViewSubmitHandler(this, read, http, modify, persistence); + return await handler.run(this, context, read, http, persistence, modify); + } + + protected async extendConfiguration(configuration: IConfigurationExtend): Promise { + const user = (await this.getAccessors().reader.getUserReader().getAppUser()) as IUser; + + await Promise.all([this.getOauth2ClientInstance().setup(configuration), configuration.slashCommands.provideSlashCommand(new ClickUpCommand(this))]); + configuration.api.provideApi({ + visibility: ApiVisibility.PUBLIC, + security: ApiSecurity.UNSECURE, + endpoints: [new clickupWebhooks(this)], + }); + } } diff --git a/app.json b/app.json index 8d50b8c..14c4efb 100644 --- a/app.json +++ b/app.json @@ -1,7 +1,7 @@ { "id": "b3252284-88b0-4ef4-b81c-3a644ed0e401", "version": "0.0.1", - "requiredApiVersion": "1.36.0", + "requiredApiVersion": "^1.19.0", "iconFile": "icon.png", "author": { "name": "Mustafa Hasan Khan", diff --git a/package-lock.json b/package-lock.json index b641d9c..bfe4ecd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,8 @@ "packages": { "": { "devDependencies": { - "@rocket.chat/apps-engine": "1.36.0", + "@rocket.chat/apps-engine": "^1.37.1", + "@rocket.chat/ui-kit": "^0.31.22", "@types/node": "14.14.6", "tslint": "^5.10.0", "typescript": "^4.1.3" @@ -47,20 +48,30 @@ } }, "node_modules/@rocket.chat/apps-engine": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.36.0.tgz", - "integrity": "sha512-PnG7fuO4Rq8FYf9JVU5mybhACRP8Ftj+XSHBKZ1vOuoEa1U32Rdmb9F012iawnI7wgP/K0vYp/bY3HH2N2Bv0w==", + "version": "1.37.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.37.1.tgz", + "integrity": "sha512-hN/KopX+8zRWu78/p2qVPpdRFXNRsvZV4HwjuqEi4Z4HKsI7Qgh0D0wmVStqQDNRHJxheRbobI8ys22RoZPSjA==", "dev": true, "dependencies": { "adm-zip": "^0.5.9", "cryptiles": "^4.1.3", + "jose": "^4.11.1", "lodash.clonedeep": "^4.5.0", "semver": "^5.7.1", "stack-trace": "0.0.10", "uuid": "^3.4.0", "vm2": "^3.9.11" + }, + "peerDependencies": { + "@rocket.chat/ui-kit": "next" } }, + "node_modules/@rocket.chat/ui-kit": { + "version": "0.31.22", + "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.31.22.tgz", + "integrity": "sha512-CH7kBVBsAql57DwDMOpMvj8lp+23muEqiaQ4x0cr0CV/HjmOBBiclzJ2wvh7ab7KEkABIhDK8dwSreNgk0LiJQ==", + "dev": true + }, "node_modules/@types/node": { "version": "14.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", @@ -323,6 +334,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/jose": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", + "integrity": "sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -589,13 +609,14 @@ } }, "@rocket.chat/apps-engine": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.36.0.tgz", - "integrity": "sha512-PnG7fuO4Rq8FYf9JVU5mybhACRP8Ftj+XSHBKZ1vOuoEa1U32Rdmb9F012iawnI7wgP/K0vYp/bY3HH2N2Bv0w==", + "version": "1.37.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.37.1.tgz", + "integrity": "sha512-hN/KopX+8zRWu78/p2qVPpdRFXNRsvZV4HwjuqEi4Z4HKsI7Qgh0D0wmVStqQDNRHJxheRbobI8ys22RoZPSjA==", "dev": true, "requires": { "adm-zip": "^0.5.9", "cryptiles": "^4.1.3", + "jose": "^4.11.1", "lodash.clonedeep": "^4.5.0", "semver": "^5.7.1", "stack-trace": "0.0.10", @@ -603,6 +624,12 @@ "vm2": "^3.9.11" } }, + "@rocket.chat/ui-kit": { + "version": "0.31.22", + "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.31.22.tgz", + "integrity": "sha512-CH7kBVBsAql57DwDMOpMvj8lp+23muEqiaQ4x0cr0CV/HjmOBBiclzJ2wvh7ab7KEkABIhDK8dwSreNgk0LiJQ==", + "dev": true + }, "@types/node": { "version": "14.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", @@ -813,6 +840,12 @@ "has": "^1.0.3" } }, + "jose": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", + "integrity": "sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index 3b79c6e..f168f10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "devDependencies": { - "@rocket.chat/apps-engine": "1.36.0", + "@rocket.chat/apps-engine": "^1.19.0", + "@rocket.chat/ui-kit": "^0.31.22", "@types/node": "14.14.6", "tslint": "^5.10.0", "typescript": "^4.1.3" diff --git a/src/enums/App.ts b/src/enums/App.ts index 1ab34f1..a46ab2f 100644 --- a/src/enums/App.ts +++ b/src/enums/App.ts @@ -3,4 +3,5 @@ export enum AppEnum { USERNAME_ALIAS = 'ClickUp', EMOJI_AVATAR = '', USER_MESSAGED_BOT = 'You have messaged the bot user. This has no effect.', -} + APP_ID ='b3252284-88b0-4ef4-b81c-3a644ed0e401' +} \ No newline at end of file diff --git a/src/enums/Misc.ts b/src/enums/Misc.ts index ae01c3a..f23e882 100644 --- a/src/enums/Misc.ts +++ b/src/enums/Misc.ts @@ -32,5 +32,4 @@ export enum MiscEnum { DELETE_FOLDER_ACTION_ID = 'delete-folder', DELETE_LIST_BUTTON = 'Delete', DELETE_LIST_ACTION_ID = 'delete-list', - } diff --git a/src/handlers/ExecuteBlockActionHandler.ts b/src/handlers/ExecuteBlockActionHandler.ts index ccae1c2..1ac744b 100644 --- a/src/handlers/ExecuteBlockActionHandler.ts +++ b/src/handlers/ExecuteBlockActionHandler.ts @@ -95,11 +95,11 @@ export class ExecuteBlockActionHandler { return context.getInteractionResponder().successResponse(); case MiscEnum.CREATE_TASK_BUTTON_ACTION_ID: const createTaskmodal = await createTaskModal({modify,read,persistence,http,data:context.getInteractionData().value}); - await modify.getUiController().openModalView(createTaskmodal,{triggerId},context.getInteractionData().user); + await modify.getUiController().openSurfaceView(createTaskmodal,{triggerId},context.getInteractionData().user); return context.getInteractionResponder().successResponse(); case MiscEnum.GET_TASKS_ACTION_ID: const getTasksmodal = await getTasksModal({modify,read,persistence,http,data:context.getInteractionData().value}); - await modify.getUiController().openModalView(getTasksmodal,{triggerId},context.getInteractionData().user); + await modify.getUiController().openSurfaceView(getTasksmodal,{triggerId},context.getInteractionData().user); return context.getInteractionResponder().successResponse(); case ModalsEnum.OPEN_ADD_SUBSCRIPTIONS_MODAL: const addSubscriptionmodal = await AddSubscriptionModal({modify,read,persistence,http,uikitcontext:context}) @@ -112,7 +112,7 @@ export class ExecuteBlockActionHandler { break; case ModalsEnum.SUBSCRIPTION_REFRESH_ACTION: const subscriptionsmodal = await subscriptionsModal({ modify, read, persistence, http, uikitcontext: context }); - await modify.getUiController().updateModalView(subscriptionsmodal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); + await modify.getUiController().updateSurfaceView(subscriptionsmodal, { triggerId: context.getInteractionData().triggerId }, context.getInteractionData().user); break; default: break; diff --git a/src/helpers/blockBuilder.ts b/src/helpers/blockBuilder.ts new file mode 100644 index 0000000..617acf7 --- /dev/null +++ b/src/helpers/blockBuilder.ts @@ -0,0 +1,130 @@ +import { ButtonStyle } from "@rocket.chat/apps-engine/definition/uikit"; +import { ActionsBlock, ButtonElement, ContextBlock, DividerBlock, InputBlock, Option, SectionBlock, StaticSelectElement } from "@rocket.chat/ui-kit"; +import { AppEnum } from "../enums/App"; + +export async function getInputBox(labelText: string, placeholderText: string, blockId: string, actionId: string, initialValue?: string, multiline?: boolean): Promise { + const block: InputBlock = { + type: "input", + label: { + type: "plain_text", + text: labelText, + }, + element: { + type: "plain_text_input", + placeholder: { + type: "plain_text", + text: placeholderText, + }, + appId: AppEnum.APP_ID, + blockId: blockId, + actionId: actionId, + initialValue: initialValue, + multiline: multiline, + }, + }; + return block; +} + +export async function getInputBoxDate(labelText: string, placeholderText: string, blockId: string, actionId: string, initialDate?: string): Promise { + const block: InputBlock = { + type: "input", + label: { + type: "plain_text", + text: labelText, + }, + element: { + type: "datepicker", + placeholder: { + type: "plain_text", + text: placeholderText, + }, + appId: AppEnum.APP_ID, + blockId: blockId, + actionId: actionId, + initialDate: initialDate, + }, + }; + return block; +} + +export async function getButton(labelText: string, blockId: string, actionId: string, value?: string, style?: ButtonStyle.PRIMARY | ButtonStyle.DANGER, url?: string): Promise { + const button: ButtonElement = { + type: "button", + text: { + type: "plain_text", + text: labelText, + }, + appId: AppEnum.APP_ID, + blockId: blockId, + actionId: actionId, + url: url, + value: value, + style: style, + }; + return button; +} + +export async function getSectionBlock(labelText: string, accessory?: any): Promise { + const block: SectionBlock = { + type: "section", + text: { + type: "plain_text", + text: labelText, + }, + accessory: accessory, + }; + return block; +} + +export async function getDividerBlock(): Promise { + const block: DividerBlock = { + type: "divider", + }; + return block; +} + +export async function getContextBlock(elementText: string): Promise { + const block: ContextBlock = { + type: "context", + elements: [ + { + type: "plain_text", + text: elementText, + }, + ], + }; + return block; +} + +export async function getStaticSelectElement(placeholderText: string, options: Array