Просмотр исходного кода

Merge pull request #189 from weseek/imprv/use-slack-client

Imprv/use slack client
Yuki Takei 8 лет назад
Родитель
Сommit
674084f764
5 измененных файлов с 127 добавлено и 170 удалено
  1. 3 3
      lib/models/config.js
  2. 25 33
      lib/routes/admin.js
  3. 1 1
      lib/routes/page.js
  4. 90 125
      lib/util/slack.js
  5. 8 8
      lib/views/admin/notification.html

+ 3 - 3
lib/models/config.js

@@ -366,10 +366,10 @@ module.exports = function(crowi) {
 
   configSchema.statics.hasSlackConfig = function(config)
   {
-    return Config.hasSlackAppConfig(config) || Config.hasSlackIwhUrl(config);
+    return Config.hasSlackWebClientConfig(config) || Config.hasSlackIwhUrl(config);
   };
 
-  configSchema.statics.hasSlackAppConfig = function(config)
+  configSchema.statics.hasSlackWebClientConfig = function(config)
   {
     if (!config.notification) {
       return false;
@@ -403,7 +403,7 @@ module.exports = function(crowi) {
 
   configSchema.statics.hasSlackToken = function(config)
   {
-    if (!this.hasSlackAppConfig(config)) {
+    if (!this.hasSlackWebClientConfig(config)) {
       return false;
     }
 

+ 25 - 33
lib/routes/admin.js

@@ -140,13 +140,13 @@ module.exports = function(crowi, app) {
     var config = crowi.getConfig();
     var UpdatePost = crowi.model('UpdatePost');
     var slackSetting = Config.setupCofigFormData('notification', config);
-    var hasSlackAppConfig = Config.hasSlackAppConfig(config);
+    var hasSlackWebClientConfig = Config.hasSlackWebClientConfig(config);
     var hasSlackIwhUrl = Config.hasSlackIwhUrl(config);
     var hasSlackToken = Config.hasSlackToken(config);
     var slack = crowi.slack;
     var slackAuthUrl = '';
 
-    if (!Config.hasSlackAppConfig(req.config)) {
+    if (!Config.hasSlackWebClientConfig(req.config)) {
       slackSetting['slack:clientId'] = '';
       slackSetting['slack:clientSecret'] = '';
     }
@@ -167,7 +167,7 @@ module.exports = function(crowi, app) {
       return res.render('admin/notification', {
         settings,
         slackSetting,
-        hasSlackAppConfig,
+        hasSlackWebClientConfig,
         hasSlackIwhUrl,
         hasSlackToken,
         slackAuthUrl
@@ -175,7 +175,7 @@ module.exports = function(crowi, app) {
     });
   };
 
-  // app.post('/admin/notification/slackSetting' , admin.notification.slackSetting);
+  // app.post('/admin/notification/slackSetting' , admin.notification.slackauth);
   actions.notification.slackSetting = function(req, res) {
     var slackSetting = req.form.slackSetting;
 
@@ -202,23 +202,14 @@ module.exports = function(crowi, app) {
     const code = req.query.code;
     const config = crowi.getConfig();
 
-    if (!code || !Config.hasSlackAppConfig(req.config)) {
+    if (!code || !Config.hasSlackConfig(req.config)) {
       return res.redirect('/admin/notification');
     }
 
-    var slack = crowi.slack;
-    var bot = slack.initAppBot(true);
-    var args = {
-      code,
-      client_id: config.notification['slack:clientId'],
-      client_secret: config.notification['slack:clientSecret'],
-    }
-    bot.api.oauth.access(args, function(err, data) {
-      debug('oauth response', err, data);
-      if (!data.ok || !data.access_token) {
-        req.flash('errorMessage', ['Failed to fetch access_token. Please do connect again.']);
-        return res.redirect('/admin/notification');
-      } else {
+    const slack = crowi.slack;
+    slack.getOauthAccessToken(code)
+    .then(data => {
+      debug('oauth response', data);
         Config.updateNamespaceByArray('notification', {'slack:token': data.access_token}, function(err, config) {
           if (err) {
             req.flash('errorMessage', ['Failed to save access_token. Please try again.']);
@@ -227,23 +218,11 @@ module.exports = function(crowi, app) {
             req.flash('successMessage', ['Successfully Connected!']);
           }
 
-          slack.initAppBot();
           return res.redirect('/admin/notification');
         });
-      }
-    });
-  };
-
-  // app.post('/admin/notification/slackSetting/disconnect' , admin.notification.disconnectFromSlack);
-  actions.notification.disconnectFromSlack = function(req, res) {
-    const config = crowi.getConfig();
-    const slack = crowi.slack;
-
-    Config.updateNamespaceByArray('notification', {'slack:token': ''}, function(err, config) {
-      Config.updateConfigCache('notification', config);
-      req.flash('successMessage', ['Successfully Disconnected!']);
-
-      slack.initAppBot();
+    }).catch(err => {
+      debug('oauth response ERROR', err);
+      req.flash('errorMessage', ['Failed to fetch access_token. Please do connect again.']);
       return res.redirect('/admin/notification');
     });
   };
@@ -279,6 +258,19 @@ module.exports = function(crowi, app) {
     }
   };
 
+  // app.post('/admin/notification/slackSetting/disconnect' , admin.notification.disconnectFromSlack);
+  actions.notification.disconnectFromSlack = function(req, res) {
+    const config = crowi.getConfig();
+    const slack = crowi.slack;
+
+    Config.updateNamespaceByArray('notification', {'slack:token': ''}, function(err, config) {
+      Config.updateConfigCache('notification', config);
+      req.flash('successMessage', ['Successfully Disconnected!']);
+
+      return res.redirect('/admin/notification');
+    });
+  };
+
   actions.search.buildIndex = function(req, res) {
     var search = crowi.getSearcher();
     if (!search) {

+ 1 - 1
lib/routes/page.js

@@ -605,7 +605,7 @@ module.exports = function(crowi, app) {
           if (crowi.slack) {
             notify.slack.channel.split(',').map(function(chan) {
               var message = crowi.slack.prepareSlackMessage(pageData, req.user, chan, updateOrCreate, previousRevision);
-              crowi.slack.post(message).then(function(){}).catch(function(){});
+              crowi.slack.post(message.channel, message.text, message).then(function(){}).catch(function(){});
             });
           }
         }

+ 90 - 125
lib/util/slack.js

@@ -5,114 +5,35 @@
 module.exports = function(crowi) {
   'use strict';
 
-  var debug = require('debug')('crowi:util:slack'),
+  const SLACK_URL = 'https://slack.com';
+
+  const debug = require('debug')('crowi:util:slack'),
     Config = crowi.model('Config'),
-    Botkit = require('botkit'),
-    isDebugSlackbot = false,
-    appBot = null,                  // for Slack App
-    iwhBot = null,                  // for Slack Incoming Webhooks
+    SlackWebClient = require('@slack/client').WebClient,
+    SlackIncomingWebhook = require('@slack/client').IncomingWebhook,
     slack = {};
-  slack.appController = undefined;  // for Slack App
-  slack.iwhController = undefined;  // for Slack Incoming Webhooks
-
-  // isDebugSlackbot = true;           // for debug
 
-  slack.getBot = function() {
-    var config = crowi.getConfig();
+  slack.client = undefined;
+  slack.incomingWebhook = undefined;
 
-    // when incoming Webhooks is prioritized
-    if (Config.isIncomingWebhookPrioritized(config)) {
-      if (Config.hasSlackIwhUrl(config)) {
-        return iwhBot || slack.initIwhBot();
-      }
-      else if (Config.hasSlackToken(config)) {
-        return appBot || slack.initAppBot();
-      }
-    }
-    // else
-    else {
-      if (Config.hasSlackToken(config)) {
-        return appBot || slack.initAppBot();
-      }
-      else if (Config.hasSlackIwhUrl(config)) {
-        return iwhBot || slack.initIwhBot();
-      }
+  slack.getClient = function() {
+    // alreay created
+    if (slack.client) {
+      return slack.client;
     }
 
-    return false;
-  };
+    const config = crowi.getConfig();
 
-  slack.initAppBot = function(isClearToken) {
-    var config = crowi.getConfig();
-
-    if (!slack.appController) {
-      slack.configureSlackApp();
-    }
-
-    if (!slack.appController) {
-      return false;
+    let client;
+    if (Config.hasSlackToken(config)) {
+      client = new SlackWebClient(config.notification['slack:token']);
+      slack.client = client;
     }
 
-    if (!isClearToken && Config.hasSlackToken(config)) {
-      appBot = slack.appController.spawn({token: config.notification['slack:token']});
-    } else {
-      appBot = slack.appController.spawn();
-    }
-    return appBot;
+    return slack.client;
   };
 
-  slack.initIwhBot = function() {
-    var config = crowi.getConfig();
-
-    if (!slack.iwhController) {
-      slack.configureSlackIwh();
-    }
-
-    if (!slack.iwhController) {
-      return false;
-    }
-
-    iwhBot = slack.iwhController.spawn({
-      incoming_webhook: {
-        url: config.notification['slack:incomingWebhookUrl']
-      }
-    });
-
-    return iwhBot;
-  }
-
-  slack.configureSlackApp = function ()
-  {
-    var config = crowi.getConfig();
-
-    if (Config.hasSlackAppConfig(config)) {
-      slack.appController = Botkit.slackbot({debug: isDebugSlackbot});
-      slack.appController.configureSlackApp({
-        clientId: config.notification['slack:clientId'],
-        clientSecret: config.notification['slack:clientSecret'],
-        redirectUri: slack.getSlackAuthCallbackUrl(),
-        scopes: ['chat:write:bot']
-      });
-
-      return true;
-    }
-
-    return false;
-  }
-
-  slack.configureSlackIwh = function ()
-  {
-    var config = crowi.getConfig();
-
-    if (Config.hasSlackIwhUrl(config)) {
-      slack.iwhController = Botkit.slackbot({debug: isDebugSlackbot});
-      return true;
-    }
-
-    return false;
-  }
-
-  // hmmm
+  // this is called to generate redirect_uri
   slack.getSlackAuthCallbackUrl = function()
   {
     var config = crowi.getConfig();
@@ -121,48 +42,89 @@ module.exports = function(crowi) {
     return (config.crowi['app:url'] || '') + '/admin/notification/slackAuth';
   }
 
+  // this is called to get the url for oauth screen
   slack.getAuthorizeURL = function () {
-    if (!slack.appController) {
-      slack.configureSlackApp();
-    }
+    const config = crowi.getConfig();
+    if (Config.hasSlackWebClientConfig(config)) {
+      const slackClientId = config.notification['slack:clientId'];
+      const redirectUri = slack.getSlackAuthCallbackUrl();
+
+      return `${SLACK_URL}/oauth/authorize?client_id=${slackClientId}&redirect_uri=${redirectUri}&scope=chat:write:bot`;
+    } else {
 
-    if (!slack.appController) {
       return '';
     }
-
-    return slack.appController.getAuthorizeURL();
   }
 
-  slack.post = function (message) {
-    var bot = slack.getBot();
-    let sendMethod = undefined;
+  // this is called to get access token with code (oauth process)
+  slack.getOauthAccessToken = function(code) {
 
-    // use Slack App
-    if (bot === appBot) {
-      debug(`sendMethod: bot.api.chat.postMessage`);
-      sendMethod = bot.api.chat.postMessage;
-    }
-    // use Slack Incoming Webhooks
-    else if (bot === iwhBot) {
-      debug(`sendMethod: bot.sendWebhook`);
-      sendMethod = bot.sendWebhook;
+    const client = new SlackWebClient();
+
+    const config = crowi.getConfig();
+    const clientId = config.notification['slack:clientId'];
+    const clientSecret = config.notification['slack:clientSecret'];
+    const redirectUri = slack.getSlackAuthCallbackUrl();
+
+    return client.oauth.access(clientId, clientSecret, code, {redirect_uri: redirectUri});
+  }
+
+  slack.getIncomingWebhook = function() {
+    // alreay created
+    if (slack.incomingWebhook) {
+      return slack.incomingWebhook;
     }
 
-    if (sendMethod === undefined) {
-      debug(`sendMethod is undefined`);
-      return Promise.resolve();
+    const config = crowi.getConfig();
+
+    let incomingWebhook;
+    if (Config.hasSlackIwhUrl(config)) {
+      incomingWebhook = new SlackIncomingWebhook(config.notification['slack:incomingWebhookUrl']);
+      slack.incomingWebhook = incomingWebhook;
     }
 
+    return slack.incomingWebhook;
+  };
+
+  slack.post = function (channel, message, opts) {
+    const config = crowi.getConfig();
+
     return new Promise(function(resolve, reject) {
-      sendMethod(message, function(err, res) {
+
+      // define callback function
+      const callback = function(err, res) {
         if (err) {
           debug('Post error', err, res);
           debug('Sent data to slack is:', message);
           return reject(err);
         }
-
         resolve(res);
-      });
+      };
+
+      // when incoming Webhooks is prioritized
+      if (Config.isIncomingWebhookPrioritized(config)) {
+        if (Config.hasSlackIwhUrl(config)) {
+          debug(`posting message with IncomingWebhook`);
+          slack.getIncomingWebhook().send(opts, callback);
+        }
+        else if (Config.hasSlackToken(config)) {
+          debug(`posting message with WebClient`);
+          slack.getClient().chat.postMessage(channel, message, opts, callback);
+        }
+      }
+      // else
+      else {
+        if (Config.hasSlackToken(config)) {
+          debug(`posting message with WebClient`);
+          slack.getClient().chat.postMessage(channel, message, opts, callback);
+        }
+        else if (Config.hasSlackIwhUrl(config)) {
+          debug(`posting message with IncomingWebhook`);
+          slack.getIncomingWebhook().send(opts, callback);
+        }
+      }
+
+      resolve();
     });
   };
 
@@ -244,7 +206,7 @@ module.exports = function(crowi) {
 
     var message = {
       channel: '#' + channel,
-      username: 'Crowi',
+      username: config.crowi['app:title'],
       text: this.getSlackMessageText(page.path, user, updateType),
       attachments: [attachment],
     };
@@ -253,12 +215,15 @@ module.exports = function(crowi) {
   };
 
   slack.getSlackMessageText = function(path, user, updateType) {
-    var text;
+    let text;
+    const config = crowi.getConfig();
+    const url = config.crowi['app:url'] || '';
 
+    const pageUrl = `<${url}${path}|${path}>`;
     if (updateType == 'create') {
-      text = `:white_check_mark: ${user.username} created a new page! ${path}`;
+      text = `:white_check_mark: ${user.username} created a new page! ${pageUrl}`;
     } else {
-      text = `:up: ${user.username} updated ${path}`;
+      text = `:up: ${user.username} updated ${pageUrl}`;
     }
 
     return text;

+ 8 - 8
lib/views/admin/notification.html

@@ -84,7 +84,7 @@
             <input type="hidden" name="_csrf" value="{{ csrf() }}">
           </form>
 
-          {% if hasSlackAppConfig %}
+          {% if hasSlackWebClientConfig %}
           <div class="text-center">
             {% if hasSlackToken %}
             <p>Crowi and Slack is already <strong>connected</strong>. You can re-connect to refresh and overwirte the token with your Slack account.</p>
@@ -104,7 +104,7 @@
 
           {% endif %}
 
-          {# {% if not hasSlackAppConfig %} #}
+          {# {% if not hasSlackWebClientConfig %} #}
           <hr>
           <h3>
             <i class="fa fa-question-circle" aria-hidden="true"></i>
@@ -119,7 +119,7 @@
                   Create App from <a href="https://api.slack.com/applications/new">this link</a>, and fill the form out as below:
                   <dl class="dl-horizontal">
                     <dt>App Name</dt> <dd><code>crowi-plus</code> </dd>
-                    <dt>Development Slack Team</dt> <dd>Select the team you want to notify to.</dd>
+                    <dt>Development Slack Workspace</dt> <dd>Select the workspace you want to notify to.</dd>
                   </dl>
                 </li>
                 <li><strong>Save</strong> it.</li>
@@ -156,17 +156,17 @@
             <li>
               Install the app
               <ol>
-                <li>Go to "Install App to Your Team" page and install.</li>
+                <li>Go to "Install App to Your Workspace" page and install.</li>
               </ol>
             </li>
             <li>
-              (At Team) Approve the app
+              (At Workspace) Approve the app
               <ol>
-                <li>Go to the management Apps page for the team you installed the app and approve crowi-plus.</li>
+                <li>Go to the management Apps page for the workspace you installed the app and approve crowi-plus.</li>
               </ol>
             </li>
             <li>
-              (At Team) Invite the bot to your team
+              (At Workspace) Invite the bot to your workspace
               <ol>
                 <li>Invite the user you created in <code>4. Add a bot user</code> to the channel you notify to.</li>
               </ol>
@@ -223,7 +223,7 @@
 
           <ol id="collapseHelpForIwh" class="collapse">
             <li>
-              (At Team) Add a hook
+              (At Workspace) Add a hook
               <ol>
                 <li>Go to <a href="https://slack.com/services/new/incoming-webhook">Incoming Webhooks Configuration page</a>.</li>
                 <li>Choose the default channel to post.</li>