|
@@ -1,14 +1,16 @@
|
|
|
import {
|
|
import {
|
|
|
- BodyParams, Controller, Get, Inject, Post, Req, Res, UseBefore,
|
|
|
|
|
|
|
+ BodyParams, Controller, Get, Inject, PlatformResponse, Post, Req, Res, UseBefore,
|
|
|
} from '@tsed/common';
|
|
} from '@tsed/common';
|
|
|
|
|
|
|
|
import axios from 'axios';
|
|
import axios from 'axios';
|
|
|
|
|
|
|
|
import { WebAPICallResult } from '@slack/web-api';
|
|
import { WebAPICallResult } from '@slack/web-api';
|
|
|
|
|
+import { Installation } from '@slack/oauth';
|
|
|
|
|
+
|
|
|
|
|
|
|
|
import {
|
|
import {
|
|
|
markdownSectionBlock, GrowiCommand, parseSlashCommand, postEphemeralErrors, verifySlackRequest, generateWebClient,
|
|
markdownSectionBlock, GrowiCommand, parseSlashCommand, postEphemeralErrors, verifySlackRequest, generateWebClient,
|
|
|
- InvalidGrowiCommandError,
|
|
|
|
|
|
|
+ InvalidGrowiCommandError, requiredScopes, postWelcomeMessage, publishInitialHomeView,
|
|
|
} from '@growi/slack';
|
|
} from '@growi/slack';
|
|
|
|
|
|
|
|
import { Relation } from '~/entities/relation';
|
|
import { Relation } from '~/entities/relation';
|
|
@@ -334,57 +336,68 @@ export class SlackCtrl {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Get('/oauth_redirect')
|
|
@Get('/oauth_redirect')
|
|
|
- async handleOauthRedirect(@Req() req: Req, @Res() res: Res): Promise<void> {
|
|
|
|
|
-
|
|
|
|
|
- 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="/">'
|
|
|
|
|
- + 'Go to install page'
|
|
|
|
|
- + '</a>'
|
|
|
|
|
- + '</body></html>');
|
|
|
|
|
|
|
+ async handleOauthRedirect(@Req() req: Req, @Res() serverRes: Res, @Res() platformRes: PlatformResponse): Promise<void|string> {
|
|
|
|
|
+
|
|
|
|
|
+ // create 'Add to Slack' url
|
|
|
|
|
+ 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 });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- await this.installerService.installer.handleCallback(req, res, {
|
|
|
|
|
- success: (installation, metadata, req, res) => {
|
|
|
|
|
- logger.info('Success to install', { installation, metadata });
|
|
|
|
|
|
|
+ // promisify
|
|
|
|
|
+ const installPromise = new Promise<Installation>((resolve, reject) => {
|
|
|
|
|
+ this.installerService.installer.handleCallback(req, serverRes, {
|
|
|
|
|
+ success: async(installation, metadata) => {
|
|
|
|
|
+ logger.info('Success to install', { installation, metadata });
|
|
|
|
|
+ resolve(installation);
|
|
|
|
|
+ },
|
|
|
|
|
+ failure: async(error) => {
|
|
|
|
|
+ reject(error); // go to catch block
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ let httpStatus = 200;
|
|
|
|
|
+ let httpBody;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const installation = await installPromise;
|
|
|
|
|
|
|
|
|
|
+ // check whether bot is not null
|
|
|
|
|
+ if (installation.bot == 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' });
|
|
|
|
|
+ }
|
|
|
|
|
+ // MAIN PATH: everything is fine
|
|
|
|
|
+ else {
|
|
|
const appPageUrl = `https://slack.com/apps/${installation.appId}`;
|
|
const appPageUrl = `https://slack.com/apps/${installation.appId}`;
|
|
|
|
|
+ httpBody = await platformRes.render('install-succeeded.ejs', { appPageUrl });
|
|
|
|
|
|
|
|
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
|
|
|
- res.end('<html>'
|
|
|
|
|
- + '<head><meta name="viewport" content="width=device-width,initial-scale=1">'
|
|
|
|
|
- + '<link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">'
|
|
|
|
|
- + '</head>'
|
|
|
|
|
- + '<body style="text-align:center; padding-top:20%;">'
|
|
|
|
|
- + '<h1>Congratulations!</h1>'
|
|
|
|
|
- + '<p>GROWI Bot installation has succeeded.</p>'
|
|
|
|
|
- + '<div class="d-inline-flex flex-column">'
|
|
|
|
|
- + `<a class="mb-3" href="${appPageUrl}">`
|
|
|
|
|
- + 'Access to Slack App detail page.'
|
|
|
|
|
- + '</a>'
|
|
|
|
|
- + '<a class="btn btn-outline-success" href="https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/official-bot-settings.html">'
|
|
|
|
|
- + 'Getting started'
|
|
|
|
|
- + '</a>'
|
|
|
|
|
- + '</div>'
|
|
|
|
|
- + '</body></html>');
|
|
|
|
|
- },
|
|
|
|
|
- failure: (error, installOptions, req, res) => {
|
|
|
|
|
- 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>GROWI Bot installation failed</h1>'
|
|
|
|
|
- + '<p>Please contact administrators of your workspace</p>'
|
|
|
|
|
- + 'Reference: <a href="https://slack.com/help/articles/222386767-Manage-app-installation-settings-for-your-workspace">'
|
|
|
|
|
- + 'Manage app installation settings for your workspace'
|
|
|
|
|
- + '</a>'
|
|
|
|
|
- + '</body></html>');
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ // generate client
|
|
|
|
|
+ const client = generateWebClient(installation.bot.token);
|
|
|
|
|
+
|
|
|
|
|
+ const userId = installation.user.id;
|
|
|
|
|
+
|
|
|
|
|
+ await Promise.all([
|
|
|
|
|
+ // post message
|
|
|
|
|
+ postWelcomeMessage(client, userId),
|
|
|
|
|
+ // publish home
|
|
|
|
|
+ publishInitialHomeView(client, userId),
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (error) {
|
|
|
|
|
+ logger.error(error);
|
|
|
|
|
+ httpStatus = 500;
|
|
|
|
|
+ httpBody = await platformRes.status(400).render('install-failed.ejs', { url: addToSlackUrl });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ platformRes.status(httpStatus);
|
|
|
|
|
+ return httpBody;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|