| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- const loggerFactory = require('@alias/logger');
- const logger = loggerFactory('growi:routes:apiv3:notification-setting');
- const express = require('express');
- const { body } = require('express-validator');
- const crypto = require('crypto');
- const { WebClient, LogLevel } = require('@slack/web-api');
- const ErrorV3 = require('../../models/vo/error-apiv3');
- const router = express.Router();
- /**
- * @swagger
- * tags:
- * name: SlackIntegration
- */
- /**
- * @swagger
- *
- * components:
- * schemas:
- * CustomBotWithoutProxy:
- * description: CustomBotWithoutProxy
- * type: object
- * properties:
- * slackSigningSecret:
- * type: string
- * slackBotToken:
- * type: string
- * currentBotType:
- * type: string
- * SlackIntegration:
- * description: SlackIntegration
- * type: object
- * properties:
- * currentBotType:
- * type: string
- */
- module.exports = (crowi) => {
- const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
- const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
- const adminRequired = require('../../middlewares/admin-required')(crowi);
- const csrf = require('../../middlewares/csrf')(crowi);
- const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
- const validator = {
- CustomBotWithoutProxy: [
- body('slackSigningSecret').isString(),
- body('slackBotToken').isString(),
- body('currentBotType').isString(),
- ],
- SlackIntegration: [
- body('currentBotType')
- .isIn(['official-bot', 'custom-bot-without-proxy', 'custom-bot-with-proxy']),
- ],
- };
- async function updateSlackBotSettings(params) {
- const { configManager } = crowi;
- // update config without publishing S2sMessage
- return configManager.updateConfigsInTheSameNamespace('crowi', params, true);
- }
- function generateAccessToken(user) {
- const hasher = crypto.createHash('sha512');
- hasher.update(new Date().getTime() + user._id);
- return hasher.digest('base64');
- }
- /**
- * @swagger
- *
- * /slack-integration/:
- * get:
- * tags: [SlackBotSettingParams]
- * operationId: getSlackBotSettingParams
- * summary: get /slack-integration
- * description: Get slackBot setting params.
- * responses:
- * 200:
- * description: Succeeded to get slackBot setting params.
- */
- router.get('/', accessTokenParser, loginRequiredStrictly, adminRequired, async(req, res) => {
- const slackBotSettingParams = {
- accessToken: crowi.configManager.getConfig('crowi', 'slackbot:access-token'),
- currentBotType: crowi.configManager.getConfig('crowi', 'slackbot:currentBotType'),
- // TODO impl when creating official bot
- officialBotSettings: {
- // TODO impl this after GW-4939
- // AccessToken: "tempaccessdatahogehoge",
- },
- customBotWithoutProxySettings: {
- // TODO impl this after GW-4939
- // AccessToken: "tempaccessdatahogehoge",
- slackSigningSecretEnvVars: crowi.configManager.getConfigFromEnvVars('crowi', 'slackbot:signingSecret'),
- slackBotTokenEnvVars: crowi.configManager.getConfigFromEnvVars('crowi', 'slackbot:token'),
- slackSigningSecret: crowi.configManager.getConfig('crowi', 'slackbot:signingSecret'),
- slackBotToken: crowi.configManager.getConfig('crowi', 'slackbot:token'),
- isSetupSlackBot: crowi.slackBotService.isSetupSlackBot,
- isConnectedToSlack: crowi.slackBotService.isConnectedToSlack,
- },
- // TODO imple when creating with proxy
- customBotWithProxySettings: {
- // TODO impl this after GW-4939
- // AccessToken: "tempaccessdatahogehoge",
- },
- };
- return res.apiv3({ slackBotSettingParams });
- });
- /**
- * @swagger
- *
- * /slack-integration/:
- * put:
- * tags: [SlackIntegration]
- * operationId: putSlackIntegration
- * summary: put /slack-integration
- * description: Put SlackIntegration setting.
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/SlackIntegration'
- * responses:
- * 200:
- * description: Succeeded to put Slack Integration setting.
- */
- router.put('/',
- accessTokenParser, loginRequiredStrictly, adminRequired, csrf, validator.SlackIntegration, apiV3FormValidator, async(req, res) => {
- const { currentBotType } = req.body;
- const requestParams = {
- 'slackbot:currentBotType': currentBotType,
- };
- try {
- await updateSlackBotSettings(requestParams);
- // initialize slack service
- await crowi.slackBotService.initialize();
- crowi.slackBotService.publishUpdatedMessage();
- const slackIntegrationSettingsParams = {
- currentBotType: crowi.configManager.getConfig('crowi', 'slackbot:currentBotType'),
- };
- return res.apiv3({ slackIntegrationSettingsParams });
- }
- catch (error) {
- const msg = 'Error occured in updating Slack bot setting';
- logger.error('Error', error);
- return res.apiv3Err(new ErrorV3(msg, 'update-SlackIntegrationSetting-failed'), 500);
- }
- });
- /**
- * @swagger
- *
- * /slack-integration/custom-bot-without-proxy/:
- * put:
- * tags: [CustomBotWithoutProxy]
- * operationId: putCustomBotWithoutProxy
- * summary: /slack-integration/custom-bot-without-proxy
- * description: Put customBotWithoutProxy setting.
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/CustomBotWithoutProxy'
- * responses:
- * 200:
- * description: Succeeded to put CustomBotWithoutProxy setting.
- */
- router.put('/custom-bot-without-proxy',
- accessTokenParser, loginRequiredStrictly, adminRequired, csrf, validator.CustomBotWithoutProxy, apiV3FormValidator, async(req, res) => {
- const { slackSigningSecret, slackBotToken, currentBotType } = req.body;
- const requestParams = {
- 'slackbot:signingSecret': slackSigningSecret,
- 'slackbot:token': slackBotToken,
- 'slackbot:currentBotType': currentBotType,
- };
- try {
- await updateSlackBotSettings(requestParams);
- // initialize slack service
- await crowi.slackBotService.initialize();
- crowi.slackBotService.publishUpdatedMessage();
- // TODO Impl to delete AccessToken both of Proxy and GROWI when botType changes.
- const customBotWithoutProxySettingParams = {
- slackSigningSecret: crowi.configManager.getConfig('crowi', 'slackbot:signingSecret'),
- slackBotToken: crowi.configManager.getConfig('crowi', 'slackbot:token'),
- slackBotType: crowi.configManager.getConfig('crowi', 'slackbot:currentBotType'),
- };
- return res.apiv3({ customBotWithoutProxySettingParams });
- }
- catch (error) {
- const msg = 'Error occured in updating Custom bot setting';
- logger.error('Error', error);
- return res.apiv3Err(new ErrorV3(msg, 'update-CustomBotSetting-failed'), 500);
- }
- });
- /**
- * @swagger
- *
- * /slack-integration/custom-bot-without-proxy/slack-workspace-name:
- * get:
- * tags: [slackWorkSpaceName]
- * operationId: getSlackWorkSpaceName
- * summary: Get slack work space name for custom bot without proxy
- * description: get slack WS name in custom bot without proxy
- * responses:
- * 200:
- * description: Succeeded to get slack ws name for custom bot without proxy
- */
- router.get('/custom-bot-without-proxy/slack-workspace-name', loginRequiredStrictly, adminRequired, async(req, res) => {
- try {
- const slackWorkSpaceName = await crowi.slackBotService.getSlackChannelName();
- return res.apiv3({ slackWorkSpaceName });
- }
- catch (error) {
- const msg = 'Error occured in slack_bot_token';
- logger.error('Error', error);
- return res.apiv3Err(new ErrorV3(msg, 'get-SlackWorkSpaceName-failed'), 500);
- }
- });
- /**
- * @swagger
- *
- * /slack-integration/access-token:
- * put:
- * tags: [SlackIntegration]
- * operationId: getCustomBotSetting
- * summary: /slack-integration
- * description: Generate accessToken
- * responses:
- * 200:
- * description: Succeeded to update access token for slack
- */
- router.put('/access-token', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
- try {
- const accessToken = generateAccessToken(req.user);
- await updateSlackBotSettings({ 'slackbot:access-token': accessToken });
- // initialize slack service
- await crowi.slackBotService.initialize();
- crowi.slackBotService.publishUpdatedMessage();
- return res.apiv3({ accessToken });
- }
- catch (error) {
- const msg = 'Error occured in updating access token for access token';
- logger.error('Error', error);
- return res.apiv3Err(new ErrorV3(msg, 'update-accessToken-failed'), 500);
- }
- });
- function checkConnectedToSlack(res) {
- const isConnectedToSlack = crowi.slackBotService.isConnectedToSlack;
- if (!isConnectedToSlack) {
- const msg = 'Bot User OAuth Token is not setup.';
- logger.error('Error', msg);
- return res.apiv3Err(new ErrorV3(msg, 'not-setup-slack-bot-token', 400));
- }
- }
- router.post('/test-notification-to-slack-work-space', async(req, res) => {
- checkConnectedToSlack(res);
- const slackBotToken = crowi.configManager.getConfig('crowi', 'slackbot:token');
- this.client = new WebClient(slackBotToken, { logLevel: LogLevel.DEBUG });
- logger.debug('SlackBot: setup is done');
- try {
- this.client.chat.postMessage({
- channel: '#general',
- text: 'Your test was successful!',
- });
- logger.info('SlackTest: send success massage to slack work space at #general.');
- logger.info('If you do not receive a message, you may not have invited the bot to the #general channel.');
- // eslint-disable-next-line max-len
- const message = 'Successfully send message to Slack work space. If you do not receive a message, you may not have invited the bot to the #general channel.';
- return res.apiv3({ message });
- }
- catch (error) {
- const msg = 'Error occured in testing to notify slack work space';
- logger.error('Error', error);
- return res.apiv3Err(new ErrorV3(msg, 'test-notify-slack-work-space-failed'), 500);
- }
- });
- /**
- * @swagger
- *
- * /slack-integration/access-token:
- * delete:
- * tags: [SlackIntegration]
- * operationId: deleteAccessTokenForSlackBot
- * summary: /slack-integration
- * description: Delete accessToken
- * responses:
- * 200:
- * description: Succeeded to delete accessToken
- */
- router.delete('/access-token', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
- try {
- await updateSlackBotSettings({ 'slackbot:access-token': null });
- // initialize slack service
- await crowi.slackBotService.initialize();
- crowi.slackBotService.publishUpdatedMessage();
- return res.apiv3({});
- }
- catch (error) {
- const msg = 'Error occured in discard of slackbotAccessToken';
- logger.error('Error', error);
- return res.apiv3Err(new ErrorV3(msg, 'discard-slackbotAccessToken-failed'), 500);
- }
- });
- return router;
- };
|