|
|
@@ -1,13 +1,16 @@
|
|
|
-
|
|
|
-
|
|
|
import { ServerResponse } from 'http';
|
|
|
|
|
|
import {
|
|
|
- type GrowiCommand, type IChannelOptionalId,
|
|
|
- requiredScopes, REQUEST_TIMEOUT_FOR_PTOG,
|
|
|
+ type GrowiCommand,
|
|
|
+ type IChannelOptionalId,
|
|
|
+ REQUEST_TIMEOUT_FOR_PTOG,
|
|
|
+ requiredScopes,
|
|
|
supportedGrowiCommands,
|
|
|
} from '@growi/slack';
|
|
|
-import { parseSlackInteractionRequest, verifySlackRequest } from '@growi/slack/dist/middlewares';
|
|
|
+import {
|
|
|
+ parseSlackInteractionRequest,
|
|
|
+ verifySlackRequest,
|
|
|
+} from '@growi/slack/dist/middlewares';
|
|
|
import { InvalidGrowiCommandError } from '@growi/slack/dist/models';
|
|
|
import { markdownSectionBlock } from '@growi/slack/dist/utils/block-kit-builder';
|
|
|
import { respondRejectedErrors } from '@growi/slack/dist/utils/post-ephemeral-errors';
|
|
|
@@ -17,7 +20,14 @@ import { generateWebClient } from '@growi/slack/dist/utils/webclient-factory';
|
|
|
import { Installation } from '@slack/oauth';
|
|
|
import { WebAPICallResult } from '@slack/web-api';
|
|
|
import {
|
|
|
- Controller, Get, Inject, PlatformResponse, Post, Req, Res, UseBefore,
|
|
|
+ Controller,
|
|
|
+ Get,
|
|
|
+ Inject,
|
|
|
+ PlatformResponse,
|
|
|
+ Post,
|
|
|
+ Req,
|
|
|
+ Res,
|
|
|
+ UseBefore,
|
|
|
} from '@tsed/common';
|
|
|
import axios from 'axios';
|
|
|
|
|
|
@@ -25,7 +35,9 @@ import { Relation } from '~/entities/relation';
|
|
|
import { SlackOauthReq } from '~/interfaces/slack-to-growi/slack-oauth-req';
|
|
|
import { AddSigningSecretToReq } from '~/middlewares/slack-to-growi/add-signing-secret-to-req';
|
|
|
import {
|
|
|
- AuthorizeCommandMiddleware, AuthorizeInteractionMiddleware, AuthorizeEventsMiddleware,
|
|
|
+ AuthorizeCommandMiddleware,
|
|
|
+ AuthorizeEventsMiddleware,
|
|
|
+ AuthorizeInteractionMiddleware,
|
|
|
} from '~/middlewares/slack-to-growi/authorizer';
|
|
|
import { ExtractGrowiUriFromReq } from '~/middlewares/slack-to-growi/extract-growi-uri-from-req';
|
|
|
import { UrlVerificationMiddleware } from '~/middlewares/slack-to-growi/url-verification';
|
|
|
@@ -39,20 +51,26 @@ import { RelationsService } from '~/services/RelationsService';
|
|
|
import { SelectGrowiService } from '~/services/SelectGrowiService';
|
|
|
import { UnregisterService } from '~/services/UnregisterService';
|
|
|
import loggerFactory from '~/utils/logger';
|
|
|
-import { postInstallSuccessMessage, postWelcomeMessageOnce } from '~/utils/welcome-message';
|
|
|
-
|
|
|
+import {
|
|
|
+ postInstallSuccessMessage,
|
|
|
+ postWelcomeMessageOnce,
|
|
|
+} from '~/utils/welcome-message';
|
|
|
|
|
|
const logger = loggerFactory('slackbot-proxy:controllers:slack');
|
|
|
|
|
|
-const postNotAllowedMessage = async(responseUrl, disallowedGrowiUrls:Set<string>, commandName:string):Promise<void> => {
|
|
|
-
|
|
|
+const postNotAllowedMessage = async (
|
|
|
+ responseUrl,
|
|
|
+ disallowedGrowiUrls: Set<string>,
|
|
|
+ commandName: string,
|
|
|
+): Promise<void> => {
|
|
|
const linkUrlList = Array.from(disallowedGrowiUrls).map((growiUrl) => {
|
|
|
- return '\n'
|
|
|
- + `• ${new URL('/admin/slack-integration', growiUrl).toString()}`;
|
|
|
+ return (
|
|
|
+ '\n' + `• ${new URL('/admin/slack-integration', growiUrl).toString()}`
|
|
|
+ );
|
|
|
});
|
|
|
|
|
|
- const growiDocsLink = 'https://docs.growi.org/en/admin-guide/upgrading/43x.html';
|
|
|
-
|
|
|
+ const growiDocsLink =
|
|
|
+ 'https://docs.growi.org/en/admin-guide/upgrading/43x.html';
|
|
|
|
|
|
await respond(responseUrl, {
|
|
|
text: 'Error occured.',
|
|
|
@@ -72,7 +90,6 @@ const postNotAllowedMessage = async(responseUrl, disallowedGrowiUrls:Set<string>
|
|
|
};
|
|
|
@Controller('/slack')
|
|
|
export class SlackCtrl {
|
|
|
-
|
|
|
@Inject()
|
|
|
installerService: InstallerService;
|
|
|
|
|
|
@@ -107,41 +124,59 @@ export class SlackCtrl {
|
|
|
* @param body
|
|
|
* @returns
|
|
|
*/
|
|
|
- private async sendCommand(growiCommand: GrowiCommand, relations: Relation[], body: any) {
|
|
|
+ private async sendCommand(
|
|
|
+ growiCommand: GrowiCommand,
|
|
|
+ relations: Relation[],
|
|
|
+ body: any,
|
|
|
+ ) {
|
|
|
if (relations.length === 0) {
|
|
|
throw new Error('relations must be set');
|
|
|
}
|
|
|
|
|
|
const promises = relations.map((relation: Relation) => {
|
|
|
// generate API URL
|
|
|
- const url = new URL('/_api/v3/slack-integration/proxied/commands', relation.growiUri);
|
|
|
- return axios.post(url.toString(), {
|
|
|
- ...body,
|
|
|
- growiCommand,
|
|
|
- }, {
|
|
|
- headers: {
|
|
|
- 'x-growi-ptog-tokens': relation.tokenPtoG,
|
|
|
+ const url = new URL(
|
|
|
+ '/_api/v3/slack-integration/proxied/commands',
|
|
|
+ relation.growiUri,
|
|
|
+ );
|
|
|
+ return axios.post(
|
|
|
+ url.toString(),
|
|
|
+ {
|
|
|
+ ...body,
|
|
|
+ growiCommand,
|
|
|
},
|
|
|
- timeout: REQUEST_TIMEOUT_FOR_PTOG,
|
|
|
- });
|
|
|
+ {
|
|
|
+ headers: {
|
|
|
+ 'x-growi-ptog-tokens': relation.tokenPtoG,
|
|
|
+ },
|
|
|
+ timeout: REQUEST_TIMEOUT_FOR_PTOG,
|
|
|
+ },
|
|
|
+ );
|
|
|
});
|
|
|
|
|
|
// pickup PromiseRejectedResult only
|
|
|
const results = await Promise.allSettled(promises);
|
|
|
- const rejectedResults: PromiseRejectedResult[] = results.filter((result): result is PromiseRejectedResult => result.status === 'rejected');
|
|
|
+ const rejectedResults: PromiseRejectedResult[] = results.filter(
|
|
|
+ (result): result is PromiseRejectedResult => result.status === 'rejected',
|
|
|
+ );
|
|
|
|
|
|
try {
|
|
|
return respondRejectedErrors(rejectedResults, growiCommand.responseUrl);
|
|
|
- }
|
|
|
- catch (err) {
|
|
|
+ } catch (err) {
|
|
|
logger.error(err);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
@Post('/commands')
|
|
|
- @UseBefore(AddSigningSecretToReq, verifySlackRequest, AuthorizeCommandMiddleware)
|
|
|
- async handleCommand(@Req() req: SlackOauthReq, @Res() res: Res): Promise<void|string|Res|WebAPICallResult> {
|
|
|
+ @UseBefore(
|
|
|
+ AddSigningSecretToReq,
|
|
|
+ verifySlackRequest,
|
|
|
+ AuthorizeCommandMiddleware,
|
|
|
+ )
|
|
|
+ async handleCommand(
|
|
|
+ @Req() req: SlackOauthReq,
|
|
|
+ @Res() res: Res,
|
|
|
+ ): Promise<void | string | Res | WebAPICallResult> {
|
|
|
const { body, authorizeResult } = req;
|
|
|
|
|
|
// retrieve bot token
|
|
|
@@ -151,7 +186,9 @@ export class SlackCtrl {
|
|
|
res.json({
|
|
|
blocks: [
|
|
|
markdownSectionBlock('*Installation might be failed.*'),
|
|
|
- markdownSectionBlock(`Access to ${serverUri} and re-install GROWI App`),
|
|
|
+ markdownSectionBlock(
|
|
|
+ `Access to ${serverUri} and re-install GROWI App`,
|
|
|
+ ),
|
|
|
],
|
|
|
});
|
|
|
}
|
|
|
@@ -160,13 +197,14 @@ export class SlackCtrl {
|
|
|
let growiCommand: GrowiCommand;
|
|
|
try {
|
|
|
growiCommand = parseSlashCommand(body);
|
|
|
- }
|
|
|
- catch (err) {
|
|
|
+ } catch (err) {
|
|
|
if (err instanceof InvalidGrowiCommandError) {
|
|
|
res.json({
|
|
|
blocks: [
|
|
|
markdownSectionBlock('*Command type is not specified.*'),
|
|
|
- markdownSectionBlock('Run `/growi help` to check the commands you can use.'),
|
|
|
+ markdownSectionBlock(
|
|
|
+ 'Run `/growi help` to check the commands you can use.',
|
|
|
+ ),
|
|
|
],
|
|
|
});
|
|
|
}
|
|
|
@@ -180,19 +218,31 @@ export class SlackCtrl {
|
|
|
|
|
|
// register
|
|
|
if (this.registerService.shouldHandleCommand(growiCommand)) {
|
|
|
- return this.registerService.processCommand(growiCommand, authorizeResult, body);
|
|
|
+ return this.registerService.processCommand(
|
|
|
+ growiCommand,
|
|
|
+ authorizeResult,
|
|
|
+ body,
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
// unregister
|
|
|
if (this.unregisterService.shouldHandleCommand(growiCommand)) {
|
|
|
- return this.unregisterService.processCommand(growiCommand, authorizeResult);
|
|
|
+ return this.unregisterService.processCommand(
|
|
|
+ growiCommand,
|
|
|
+ authorizeResult,
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
// get relations
|
|
|
- const installationId = authorizeResult.enterpriseId || authorizeResult.teamId;
|
|
|
+ const installationId =
|
|
|
+ authorizeResult.enterpriseId || authorizeResult.teamId;
|
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
- const installation = await this.installationRepository.findByTeamIdOrEnterpriseId(installationId!);
|
|
|
- const relations = await this.relationRepository.createQueryBuilder('relation')
|
|
|
+ const installation =
|
|
|
+ await this.installationRepository.findByTeamIdOrEnterpriseId(
|
|
|
+ installationId!,
|
|
|
+ );
|
|
|
+ const relations = await this.relationRepository
|
|
|
+ .createQueryBuilder('relation')
|
|
|
.where('relation.installationId = :id', { id: installation?.id })
|
|
|
.leftJoinAndSelect('relation.installation', 'installation')
|
|
|
.getMany();
|
|
|
@@ -211,7 +261,9 @@ export class SlackCtrl {
|
|
|
return respond(growiCommand.responseUrl, {
|
|
|
blocks: [
|
|
|
markdownSectionBlock('*Found Relations to GROWI.*'),
|
|
|
- ...relations.map(relation => markdownSectionBlock(`GROWI url: ${relation.growiUri}`)),
|
|
|
+ ...relations.map((relation) =>
|
|
|
+ markdownSectionBlock(`GROWI url: ${relation.growiUri}`),
|
|
|
+ ),
|
|
|
],
|
|
|
});
|
|
|
}
|
|
|
@@ -223,7 +275,9 @@ export class SlackCtrl {
|
|
|
blocks: [
|
|
|
markdownSectionBlock('*Command is not supported*'),
|
|
|
// eslint-disable-next-line max-len
|
|
|
- markdownSectionBlock(`\`/growi ${growiCommand.growiCommandType}\` command is not supported in this version of GROWI bot. Run \`/growi help\` to see all supported commands.`),
|
|
|
+ markdownSectionBlock(
|
|
|
+ `\`/growi ${growiCommand.growiCommandType}\` command is not supported in this version of GROWI bot. Run \`/growi help\` to see all supported commands.`,
|
|
|
+ ),
|
|
|
],
|
|
|
});
|
|
|
}
|
|
|
@@ -233,8 +287,8 @@ export class SlackCtrl {
|
|
|
return this.sendCommand(growiCommand, relations, body);
|
|
|
}
|
|
|
|
|
|
- const allowedRelationsForSingleUse:Relation[] = [];
|
|
|
- const allowedRelationsForBroadcastUse:Relation[] = [];
|
|
|
+ const allowedRelationsForSingleUse: Relation[] = [];
|
|
|
+ const allowedRelationsForBroadcastUse: Relation[] = [];
|
|
|
const disallowedGrowiUrls: Set<string> = new Set();
|
|
|
|
|
|
const channel: IChannelOptionalId = {
|
|
|
@@ -243,43 +297,53 @@ export class SlackCtrl {
|
|
|
};
|
|
|
|
|
|
// check permission
|
|
|
- await Promise.all(relations.map(async(relation) => {
|
|
|
- const isSupportedForSingleUse = await this.relationsService.isPermissionsForSingleUseCommands(
|
|
|
- relation, growiCommand.growiCommandType, channel,
|
|
|
- );
|
|
|
-
|
|
|
- let isSupportedForBroadcastUse = false;
|
|
|
- if (!isSupportedForSingleUse) {
|
|
|
- isSupportedForBroadcastUse = await this.relationsService.isPermissionsUseBroadcastCommands(
|
|
|
- relation, growiCommand.growiCommandType, channel,
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- if (isSupportedForSingleUse) {
|
|
|
- allowedRelationsForSingleUse.push(relation);
|
|
|
- }
|
|
|
- else if (isSupportedForBroadcastUse) {
|
|
|
- allowedRelationsForBroadcastUse.push(relation);
|
|
|
- }
|
|
|
- else {
|
|
|
- disallowedGrowiUrls.add(relation.growiUri);
|
|
|
- }
|
|
|
- }));
|
|
|
+ await Promise.all(
|
|
|
+ relations.map(async (relation) => {
|
|
|
+ const isSupportedForSingleUse =
|
|
|
+ await this.relationsService.isPermissionsForSingleUseCommands(
|
|
|
+ relation,
|
|
|
+ growiCommand.growiCommandType,
|
|
|
+ channel,
|
|
|
+ );
|
|
|
+
|
|
|
+ let isSupportedForBroadcastUse = false;
|
|
|
+ if (!isSupportedForSingleUse) {
|
|
|
+ isSupportedForBroadcastUse =
|
|
|
+ await this.relationsService.isPermissionsUseBroadcastCommands(
|
|
|
+ relation,
|
|
|
+ growiCommand.growiCommandType,
|
|
|
+ channel,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isSupportedForSingleUse) {
|
|
|
+ allowedRelationsForSingleUse.push(relation);
|
|
|
+ } else if (isSupportedForBroadcastUse) {
|
|
|
+ allowedRelationsForBroadcastUse.push(relation);
|
|
|
+ } else {
|
|
|
+ disallowedGrowiUrls.add(relation.growiUri);
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ );
|
|
|
|
|
|
// when all of GROWI disallowed
|
|
|
if (relations.length === disallowedGrowiUrls.size) {
|
|
|
const linkUrlList = Array.from(disallowedGrowiUrls).map((growiUrl) => {
|
|
|
- return '\n'
|
|
|
- + `• ${new URL('/admin/slack-integration', growiUrl).toString()}`;
|
|
|
+ return (
|
|
|
+ '\n' + `• ${new URL('/admin/slack-integration', growiUrl).toString()}`
|
|
|
+ );
|
|
|
});
|
|
|
|
|
|
- const growiDocsLink = 'https://docs.growi.org/en/admin-guide/upgrading/43x.html';
|
|
|
+ const growiDocsLink =
|
|
|
+ 'https://docs.growi.org/en/admin-guide/upgrading/43x.html';
|
|
|
|
|
|
return respond(growiCommand.responseUrl, {
|
|
|
text: 'Command not permitted.',
|
|
|
blocks: [
|
|
|
markdownSectionBlock('*None of GROWI permitted the command.*'),
|
|
|
- markdownSectionBlock(`*'${growiCommand.growiCommandType}'* command was not allowed.`),
|
|
|
+ markdownSectionBlock(
|
|
|
+ `*'${growiCommand.growiCommandType}'* command was not allowed.`,
|
|
|
+ ),
|
|
|
markdownSectionBlock(
|
|
|
`To use this command, modify settings from following pages: ${linkUrlList}`,
|
|
|
),
|
|
|
@@ -292,25 +356,47 @@ export class SlackCtrl {
|
|
|
|
|
|
// select GROWI
|
|
|
if (allowedRelationsForSingleUse.length > 0) {
|
|
|
- body.growiUrisForSingleUse = allowedRelationsForSingleUse.map(v => v.growiUri);
|
|
|
- return this.selectGrowiService.processCommand(growiCommand, authorizeResult, body);
|
|
|
+ body.growiUrisForSingleUse = allowedRelationsForSingleUse.map(
|
|
|
+ (v) => v.growiUri,
|
|
|
+ );
|
|
|
+ return this.selectGrowiService.processCommand(
|
|
|
+ growiCommand,
|
|
|
+ authorizeResult,
|
|
|
+ body,
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
// forward to GROWI server
|
|
|
if (allowedRelationsForBroadcastUse.length > 0) {
|
|
|
- return this.sendCommand(growiCommand, allowedRelationsForBroadcastUse, body);
|
|
|
+ return this.sendCommand(
|
|
|
+ growiCommand,
|
|
|
+ allowedRelationsForBroadcastUse,
|
|
|
+ body,
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
@Post('/interactions')
|
|
|
- @UseBefore(AddSigningSecretToReq, verifySlackRequest, parseSlackInteractionRequest, AuthorizeInteractionMiddleware, ExtractGrowiUriFromReq)
|
|
|
- async handleInteraction(@Req() req: SlackOauthReq, @Res() res: Res): Promise<void|string|Res|WebAPICallResult> {
|
|
|
+ @UseBefore(
|
|
|
+ AddSigningSecretToReq,
|
|
|
+ verifySlackRequest,
|
|
|
+ parseSlackInteractionRequest,
|
|
|
+ AuthorizeInteractionMiddleware,
|
|
|
+ ExtractGrowiUriFromReq,
|
|
|
+ )
|
|
|
+ async handleInteraction(
|
|
|
+ @Req() req: SlackOauthReq,
|
|
|
+ @Res() res: Res,
|
|
|
+ ): Promise<void | string | Res | WebAPICallResult> {
|
|
|
logger.info('receive interaction', req.authorizeResult);
|
|
|
logger.debug('receive interaction', req.body);
|
|
|
|
|
|
const {
|
|
|
- body, authorizeResult, interactionPayload, interactionPayloadAccessor, growiUri,
|
|
|
+ body,
|
|
|
+ authorizeResult,
|
|
|
+ interactionPayload,
|
|
|
+ interactionPayloadAccessor,
|
|
|
+ growiUri,
|
|
|
} = req;
|
|
|
|
|
|
// pass
|
|
|
@@ -322,27 +408,48 @@ export class SlackCtrl {
|
|
|
}
|
|
|
|
|
|
// register
|
|
|
- const registerResult = await this.registerService.processInteraction(authorizeResult, interactionPayload, interactionPayloadAccessor);
|
|
|
+ const registerResult = await this.registerService.processInteraction(
|
|
|
+ authorizeResult,
|
|
|
+ interactionPayload,
|
|
|
+ interactionPayloadAccessor,
|
|
|
+ );
|
|
|
if (registerResult.isTerminated) return;
|
|
|
// unregister
|
|
|
- const unregisterResult = await this.unregisterService.processInteraction(authorizeResult, interactionPayload, interactionPayloadAccessor);
|
|
|
+ const unregisterResult = await this.unregisterService.processInteraction(
|
|
|
+ authorizeResult,
|
|
|
+ interactionPayload,
|
|
|
+ interactionPayloadAccessor,
|
|
|
+ );
|
|
|
if (unregisterResult.isTerminated) return;
|
|
|
|
|
|
// immediate response to slack
|
|
|
res.send();
|
|
|
|
|
|
// select growi
|
|
|
- const selectGrowiResult = await this.selectGrowiService.processInteraction(authorizeResult, interactionPayload, interactionPayloadAccessor);
|
|
|
+ const selectGrowiResult = await this.selectGrowiService.processInteraction(
|
|
|
+ authorizeResult,
|
|
|
+ interactionPayload,
|
|
|
+ interactionPayloadAccessor,
|
|
|
+ );
|
|
|
const selectedGrowiInformation = selectGrowiResult.result;
|
|
|
if (!selectGrowiResult.isTerminated && selectedGrowiInformation != null) {
|
|
|
- return this.sendCommand(selectedGrowiInformation.growiCommand, [selectedGrowiInformation.relation], selectedGrowiInformation.sendCommandBody);
|
|
|
+ return this.sendCommand(
|
|
|
+ selectedGrowiInformation.growiCommand,
|
|
|
+ [selectedGrowiInformation.relation],
|
|
|
+ selectedGrowiInformation.sendCommandBody,
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
// check permission
|
|
|
- const installationId = authorizeResult.enterpriseId || authorizeResult.teamId;
|
|
|
+ const installationId =
|
|
|
+ authorizeResult.enterpriseId || authorizeResult.teamId;
|
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
- const installation = await this.installationRepository.findByTeamIdOrEnterpriseId(installationId!);
|
|
|
- const relations = await this.relationRepository.createQueryBuilder('relation')
|
|
|
+ const installation =
|
|
|
+ await this.installationRepository.findByTeamIdOrEnterpriseId(
|
|
|
+ installationId!,
|
|
|
+ );
|
|
|
+ const relations = await this.relationRepository
|
|
|
+ .createQueryBuilder('relation')
|
|
|
.where('relation.installationId = :id', { id: installation?.id })
|
|
|
.andWhere('relation.growiUri = :uri', { uri: growiUri })
|
|
|
.leftJoinAndSelect('relation.installation', 'installation')
|
|
|
@@ -357,7 +464,8 @@ export class SlackCtrl {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- const { actionId, callbackId } = interactionPayloadAccessor.getActionIdAndCallbackIdFromPayLoad();
|
|
|
+ const { actionId, callbackId } =
|
|
|
+ interactionPayloadAccessor.getActionIdAndCallbackIdFromPayLoad();
|
|
|
|
|
|
const privateMeta = interactionPayloadAccessor.getViewPrivateMetaData();
|
|
|
|
|
|
@@ -365,48 +473,74 @@ export class SlackCtrl {
|
|
|
name: privateMeta?.body?.channel_name || privateMeta?.channelName,
|
|
|
};
|
|
|
|
|
|
- const channel: IChannelOptionalId = interactionPayload.channel || channelFromMeta;
|
|
|
- const permission = await this.relationsService.checkPermissionForInteractions(relations, actionId, callbackId, channel);
|
|
|
+ const channel: IChannelOptionalId =
|
|
|
+ interactionPayload.channel || channelFromMeta;
|
|
|
+ const permission =
|
|
|
+ await this.relationsService.checkPermissionForInteractions(
|
|
|
+ relations,
|
|
|
+ actionId,
|
|
|
+ callbackId,
|
|
|
+ channel,
|
|
|
+ );
|
|
|
|
|
|
const {
|
|
|
- allowedRelations, disallowedGrowiUrls, commandName, rejectedResults,
|
|
|
+ allowedRelations,
|
|
|
+ disallowedGrowiUrls,
|
|
|
+ commandName,
|
|
|
+ rejectedResults,
|
|
|
} = permission;
|
|
|
|
|
|
try {
|
|
|
- await respondRejectedErrors(rejectedResults, interactionPayloadAccessor.getResponseUrl());
|
|
|
- }
|
|
|
- catch (err) {
|
|
|
+ await respondRejectedErrors(
|
|
|
+ rejectedResults,
|
|
|
+ interactionPayloadAccessor.getResponseUrl(),
|
|
|
+ );
|
|
|
+ } catch (err) {
|
|
|
logger.error(err);
|
|
|
}
|
|
|
|
|
|
if (relations.length === disallowedGrowiUrls.size) {
|
|
|
- return postNotAllowedMessage(interactionPayloadAccessor.getResponseUrl(), disallowedGrowiUrls, commandName);
|
|
|
+ return postNotAllowedMessage(
|
|
|
+ interactionPayloadAccessor.getResponseUrl(),
|
|
|
+ disallowedGrowiUrls,
|
|
|
+ commandName,
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* forward to GROWI server
|
|
|
*/
|
|
|
- allowedRelations.map(async(relation) => {
|
|
|
+ allowedRelations.map(async (relation) => {
|
|
|
try {
|
|
|
// generate API URL
|
|
|
- const url = new URL('/_api/v3/slack-integration/proxied/interactions', relation.growiUri);
|
|
|
- await axios.post(url.toString(), {
|
|
|
- ...body,
|
|
|
- }, {
|
|
|
- headers: {
|
|
|
- 'x-growi-ptog-tokens': relation.tokenPtoG,
|
|
|
+ const url = new URL(
|
|
|
+ '/_api/v3/slack-integration/proxied/interactions',
|
|
|
+ relation.growiUri,
|
|
|
+ );
|
|
|
+ await axios.post(
|
|
|
+ url.toString(),
|
|
|
+ {
|
|
|
+ ...body,
|
|
|
},
|
|
|
- });
|
|
|
- }
|
|
|
- catch (err) {
|
|
|
+ {
|
|
|
+ headers: {
|
|
|
+ 'x-growi-ptog-tokens': relation.tokenPtoG,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ );
|
|
|
+ } catch (err) {
|
|
|
logger.error(err);
|
|
|
}
|
|
|
-
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@Post('/events')
|
|
|
- @UseBefore(UrlVerificationMiddleware, AddSigningSecretToReq, verifySlackRequest, AuthorizeEventsMiddleware)
|
|
|
+ @UseBefore(
|
|
|
+ UrlVerificationMiddleware,
|
|
|
+ AddSigningSecretToReq,
|
|
|
+ verifySlackRequest,
|
|
|
+ AuthorizeEventsMiddleware,
|
|
|
+ )
|
|
|
async handleEvent(@Req() req: SlackOauthReq): Promise<void> {
|
|
|
const { authorizeResult } = req;
|
|
|
const client = generateWebClient(authorizeResult.botToken);
|
|
|
@@ -416,8 +550,7 @@ export class SlackCtrl {
|
|
|
if (event.type === 'app_home_opened') {
|
|
|
try {
|
|
|
await postWelcomeMessageOnce(client, event.channel);
|
|
|
- }
|
|
|
- catch (err) {
|
|
|
+ } catch (err) {
|
|
|
logger.error('Failed to post welcome message', err);
|
|
|
}
|
|
|
}
|
|
|
@@ -431,26 +564,32 @@ export class SlackCtrl {
|
|
|
}
|
|
|
|
|
|
@Get('/oauth_redirect')
|
|
|
- async handleOauthRedirect(@Req() req: Req, @Res() serverRes: ServerResponse, @Res() platformRes: PlatformResponse): Promise<void|string> {
|
|
|
-
|
|
|
+ async handleOauthRedirect(
|
|
|
+ @Req() req: Req,
|
|
|
+ @Res() serverRes: ServerResponse,
|
|
|
+ @Res() platformRes: PlatformResponse,
|
|
|
+ ): Promise<void | string> {
|
|
|
// create 'Add to Slack' url
|
|
|
- const addToSlackUrl = await this.installerService.installer.generateInstallUrl({
|
|
|
- scopes: requiredScopes,
|
|
|
- });
|
|
|
+ const addToSlackUrl =
|
|
|
+ await this.installerService.installer.generateInstallUrl({
|
|
|
+ scopes: requiredScopes,
|
|
|
+ });
|
|
|
|
|
|
const state = req.query.state;
|
|
|
if (state == null || state === '') {
|
|
|
- return platformRes.status(400).render('install-failed.ejs', { url: addToSlackUrl });
|
|
|
+ return platformRes
|
|
|
+ .status(400)
|
|
|
+ .render('install-failed.ejs', { url: addToSlackUrl });
|
|
|
}
|
|
|
|
|
|
// promisify
|
|
|
const installPromise = new Promise<Installation>((resolve, reject) => {
|
|
|
this.installerService.installer.handleCallback(req, serverRes, {
|
|
|
- success: async(installation, metadata) => {
|
|
|
+ success: async (installation, metadata) => {
|
|
|
logger.info('Success to install', { installation, metadata });
|
|
|
resolve(installation);
|
|
|
},
|
|
|
- failure: async(error) => {
|
|
|
+ failure: async (error) => {
|
|
|
reject(error); // go to catch block
|
|
|
},
|
|
|
});
|
|
|
@@ -463,14 +602,21 @@ export class SlackCtrl {
|
|
|
|
|
|
// check whether bot is not null
|
|
|
if (installation.bot == null) {
|
|
|
- logger.warn('Success to install but something wrong. `installation.bot` is null.');
|
|
|
+ logger.warn(
|
|
|
+ 'Success to install but something wrong. `installation.bot` is null.',
|
|
|
+ );
|
|
|
httpStatus = 500;
|
|
|
- httpBody = await platformRes.render('install-succeeded-but-has-problem.ejs', { reason: '`installation.bot` is null' });
|
|
|
+ httpBody = await platformRes.render(
|
|
|
+ 'install-succeeded-but-has-problem.ejs',
|
|
|
+ { reason: '`installation.bot` is null' },
|
|
|
+ );
|
|
|
}
|
|
|
// MAIN PATH: everything is fine
|
|
|
else {
|
|
|
const appPageUrl = `https://slack.com/apps/${installation.appId}`;
|
|
|
- httpBody = await platformRes.render('install-succeeded.ejs', { appPageUrl });
|
|
|
+ httpBody = await platformRes.render('install-succeeded.ejs', {
|
|
|
+ appPageUrl,
|
|
|
+ });
|
|
|
|
|
|
// generate client
|
|
|
const client = generateWebClient(installation.bot.token);
|
|
|
@@ -485,15 +631,15 @@ export class SlackCtrl {
|
|
|
// publishInitialHomeView(client, userId),
|
|
|
]);
|
|
|
}
|
|
|
- }
|
|
|
- catch (error) {
|
|
|
+ } catch (error) {
|
|
|
logger.error(error);
|
|
|
httpStatus = 500;
|
|
|
- httpBody = await platformRes.status(400).render('install-failed.ejs', { url: addToSlackUrl });
|
|
|
+ httpBody = await platformRes
|
|
|
+ .status(400)
|
|
|
+ .render('install-failed.ejs', { url: addToSlackUrl });
|
|
|
}
|
|
|
|
|
|
platformRes.status(httpStatus);
|
|
|
return httpBody;
|
|
|
}
|
|
|
-
|
|
|
}
|