|
|
@@ -1,5 +1,5 @@
|
|
|
import {
|
|
|
- BodyParams, Controller, Get, Inject, Post, Req, Res,
|
|
|
+ BodyParams, Controller, Get, Inject, Post, Req, Res, UseBefore,
|
|
|
} from '@tsed/common';
|
|
|
import { parseSlashCommand } from '@growi/slack';
|
|
|
import { Installation } from '~/entities/installation';
|
|
|
@@ -10,6 +10,11 @@ import { OrderRepository } from '~/repositories/order';
|
|
|
import { InstallerService } from '~/services/InstallerService';
|
|
|
import { RegisterService } from '~/services/RegisterService';
|
|
|
|
|
|
+import loggerFactory from '~/utils/logger';
|
|
|
+import { AuthorizeMiddleware } from '~/middlewares/authorizer';
|
|
|
+import { AuthedReq } from '~/interfaces/authorized-req';
|
|
|
+
|
|
|
+const logger = loggerFactory('slackbot-proxy:controllers:slack');
|
|
|
|
|
|
@Controller('/slack')
|
|
|
export class SlackCtrl {
|
|
|
@@ -29,10 +34,6 @@ export class SlackCtrl {
|
|
|
@Inject()
|
|
|
registerService: RegisterService;
|
|
|
|
|
|
- growiCommandsMappings = {
|
|
|
- register: async(body:{[key:string]:string}):Promise<void> => this.registerService.execSlashCommand(body),
|
|
|
- };
|
|
|
-
|
|
|
@Get('/testsave')
|
|
|
testsave(): void {
|
|
|
const installation = new Installation();
|
|
|
@@ -72,10 +73,10 @@ export class SlackCtrl {
|
|
|
+ '</a>';
|
|
|
}
|
|
|
|
|
|
- @Post('/events')
|
|
|
- async handleEvent(@BodyParams() body:{[key:string]:string}, @Res() res: Res): Promise<string> {
|
|
|
- // Send response immediately to avoid opelation_timeout error
|
|
|
- // See https://api.slack.com/apis/connections/events-api#the-events-api__responding-to-events
|
|
|
+ @Post('/commands')
|
|
|
+ @UseBefore(AuthorizeMiddleware)
|
|
|
+ async handleCommand(@Req() req: AuthedReq, @Res() res: Res): Promise<void|string> {
|
|
|
+ const { body, authorizeResult } = req;
|
|
|
|
|
|
const handleViewSubmission = async(inputValues) => {
|
|
|
|
|
|
@@ -124,14 +125,17 @@ export class SlackCtrl {
|
|
|
return 'No text.';
|
|
|
}
|
|
|
|
|
|
- const parsedBody = parseSlashCommand(body);
|
|
|
- const executeGrowiCommand = this.growiCommandsMappings[parsedBody.growiCommandType];
|
|
|
+ // Send response immediately to avoid opelation_timeout error
|
|
|
+ // See https://api.slack.com/apis/connections/events-api#the-events-api__responding-to-events
|
|
|
+ res.send();
|
|
|
+
|
|
|
+ const growiCommand = parseSlashCommand(body);
|
|
|
|
|
|
- if (executeGrowiCommand == null) {
|
|
|
- return 'No executeGrowiCommand';
|
|
|
+ // register
|
|
|
+ if (growiCommand.growiCommandType === 'register') {
|
|
|
+ await this.registerService.process(growiCommand, authorizeResult, body as {[key:string]:string});
|
|
|
+ return;
|
|
|
}
|
|
|
- await executeGrowiCommand(body);
|
|
|
- res.send();
|
|
|
|
|
|
const installation = await this.installationRepository.findByID('1');
|
|
|
if (installation == null) {
|
|
|
@@ -151,28 +155,60 @@ export class SlackCtrl {
|
|
|
order = await this.orderRepository.save({ installation: installation.id });
|
|
|
}
|
|
|
|
|
|
- return 'This action will be handled by bolt service.';
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Post('/interactions')
|
|
|
+ async handleInteraction(@BodyParams() body:{[key:string]:string}, @Res() res: Res): Promise<void|string> {
|
|
|
+ logger.info('receive interaction', body);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Post('/events')
|
|
|
+ async handleEvent(@BodyParams() body:{[key:string]:string}, @Res() res: Res): Promise<void|string> {
|
|
|
+ // eslint-disable-next-line max-len
|
|
|
+ // see: https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls__request-url-configuration--verification
|
|
|
+ if (body.type === 'url_verification') {
|
|
|
+ return body.challenge;
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.info('receive event', body);
|
|
|
+
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
@Get('/oauth_redirect')
|
|
|
async handleOauthRedirect(@Req() req: Req, @Res() res: Res): Promise<void> {
|
|
|
|
|
|
- // illegal state
|
|
|
- // TODO: https://youtrack.weseek.co.jp/issue/GW-5543
|
|
|
- if (req.query.state !== 'init') {
|
|
|
+ if (req.query.state === '') {
|
|
|
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
|
res.end('<html>'
|
|
|
+ '<head><meta name="viewport" content="width=device-width,initial-scale=1"></head>'
|
|
|
+ '<body style="text-align:center; padding-top:20%;">'
|
|
|
+ '<h1>Illegal state, try it again.</h1>'
|
|
|
+ '<a href="/slack/install">'
|
|
|
- + 'go to install page'
|
|
|
+ + 'Go to install page'
|
|
|
+ '</a>'
|
|
|
+ '</body></html>');
|
|
|
}
|
|
|
|
|
|
- this.installerService.installer.handleCallback(req, res, {
|
|
|
- // success: (installation, metadata, req, res) => {},
|
|
|
+ await this.installerService.installer.handleCallback(req, res, {
|
|
|
+ success: (installation, metadata, req, res) => {
|
|
|
+ logger.info('Success to install', { installation, metadata });
|
|
|
+
|
|
|
+ const appPageUrl = `https://slack.com/apps/${installation.appId}`;
|
|
|
+
|
|
|
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
|
+ res.end('<html>'
|
|
|
+ + '<head><meta name="viewport" content="width=device-width,initial-scale=1"></head>'
|
|
|
+ + '<body style="text-align:center; padding-top:20%;">'
|
|
|
+ + '<h1>Congratulations!</h1>'
|
|
|
+ + '<p>GROWI Bot installation has succeeded.</p>'
|
|
|
+ + `<a href="${appPageUrl}">`
|
|
|
+ + 'Access to Slack App detail page.'
|
|
|
+ + '</a>'
|
|
|
+ + '</body></html>');
|
|
|
+ },
|
|
|
failure: (error, installOptions, req, res) => {
|
|
|
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
|
res.end('<html>'
|