Yuki Takei 8 лет назад
Родитель
Сommit
5d3e26e48a
4 измененных файлов с 243 добавлено и 57 удалено
  1. 3 3
      lib/models/config.js
  2. 181 36
      lib/routes/admin.js
  3. 57 16
      lib/util/slack.js
  4. 2 2
      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;
     }
 

+ 181 - 36
lib/routes/admin.js

@@ -6,6 +6,8 @@ module.exports = function(crowi, app) {
     , Page = models.Page
     , User = models.User
     , Config = models.Config
+    , PluginUtils = require('../plugins/plugin-utils')
+    , pluginUtils = new PluginUtils()
     , ApiResponse = require('../util/apiResponse')
 
     , MAX_PAGE_LIST = 5
@@ -66,9 +68,12 @@ module.exports = function(crowi, app) {
   }
 
   actions.index = function(req, res) {
-    return res.render('admin/index');
+    return res.render('admin/index', {
+      plugins: pluginUtils.listPlugins(crowi.rootDir),
+    });
   };
 
+  // app.get('/admin/app'                  , admin.app.index);
   actions.app = {};
   actions.app.index = function(req, res) {
     var settingForm;
@@ -82,23 +87,75 @@ module.exports = function(crowi, app) {
   actions.app.settingUpdate = function(req, res) {
   };
 
+  // app.get('/admin/security'                  , admin.security.index);
+  actions.security = {};
+  actions.security.index = function(req, res) {
+    var settingForm;
+    settingForm = Config.setupCofigFormData('crowi', req.config);
+    return res.render('admin/security', { settingForm });
+  };
+
+  // app.get('/admin/markdown'                  , admin.markdown.index);
+  actions.markdown = {};
+  actions.markdown.index = function(req, res) {
+    var config = crowi.getConfig();
+    var markdownSetting = Config.setupCofigFormData('markdown', config);
+    return res.render('admin/markdown', {
+      markdownSetting: markdownSetting,
+    });
+  };
+
+  // app.post('/admin/markdown/lineBreaksSetting' , admin.markdown.lineBreaksSetting);
+  actions.markdown.lineBreaksSetting = function(req, res) {
+    var markdownSetting = req.form.markdownSetting;
+
+    req.session.markdownSetting = markdownSetting;
+    if (req.form.isValid) {
+      Config.updateNamespaceByArray('markdown', markdownSetting, function(err, config) {
+        Config.updateConfigCache('markdown', config);
+        req.session.markdownSetting = null;
+        req.flash('successMessage', ['Successfully updated!']);
+        return res.redirect('/admin/markdown');
+      });
+    } else {
+      req.flash('errorMessage', req.form.errors);
+      return res.redirect('/admin/markdown');
+    }
+  };
+
+  // app.get('/admin/customize' , admin.customize.index);
+  actions.customize = {};
+  actions.customize.index = function(req, res) {
+    var settingForm;
+    settingForm = Config.setupCofigFormData('crowi', req.config);
+
+    return res.render('admin/customize', {
+      settingForm: settingForm,
+    });
+  };
+
   // app.get('/admin/notification'               , admin.notification.index);
   actions.notification = {};
   actions.notification.index = function(req, res) {
     var config = crowi.getConfig();
     var UpdatePost = crowi.model('UpdatePost');
     var slackSetting = Config.setupCofigFormData('notification', config);
-    var hasSlackConfig = Config.hasSlackConfig(config);
+    var hasSlackWebClientConfig = Config.hasSlackWebClientConfig(config);
+    var hasSlackIwhUrl = Config.hasSlackIwhUrl(config);
     var hasSlackToken = Config.hasSlackToken(config);
     var slack = crowi.slack;
     var slackAuthUrl = '';
 
-    if (!Config.hasSlackConfig(req.config)) {
+    if (!Config.hasSlackWebClientConfig(req.config)) {
       slackSetting['slack:clientId'] = '';
       slackSetting['slack:clientSecret'] = '';
-    } else {
+    }
+    else {
       slackAuthUrl = slack.getAuthorizeURL();
     }
+    if (!Config.hasSlackIwhUrl(req.config)) {
+      slackSetting['slack:incomingWebhookUrl'] = '';
+    }
 
     if (req.session.slackSetting) {
       slackSetting = req.session.slackSetting;
@@ -110,7 +167,8 @@ module.exports = function(crowi, app) {
       return res.render('admin/notification', {
         settings,
         slackSetting,
-        hasSlackConfig,
+        hasSlackWebClientConfig,
+        hasSlackIwhUrl,
         hasSlackToken,
         slackAuthUrl
       });
@@ -125,8 +183,10 @@ module.exports = function(crowi, app) {
     if (req.form.isValid) {
       Config.updateNamespaceByArray('notification', slackSetting, function(err, config) {
         Config.updateConfigCache('notification', config);
+        req.flash('successMessage', ['Successfully Updated!']);
         req.session.slackSetting = null;
 
+        // Re-setup
         crowi.setupSlack().then(function() {
           return res.redirect('/admin/notification');
         });
@@ -178,43 +238,77 @@ module.exports = function(crowi, app) {
     });
   };
 
+  // app.post('/admin/notification/slackIwhSetting' , admin.notification.slackIwhSetting);
+  actions.notification.slackIwhSetting = function(req, res) {
+    var slackIwhSetting = req.form.slackIwhSetting;
+
+    if (req.form.isValid) {
+      Config.updateNamespaceByArray('notification', slackIwhSetting, function(err, config) {
+        Config.updateConfigCache('notification', config);
+        req.flash('successMessage', ['Successfully Updated!']);
+
+        // Re-setup
+        crowi.setupSlack().then(function() {
+          return res.redirect('/admin/notification#slack-incoming-webhooks');
+        });
+      });
+    } else {
+      req.flash('errorMessage', req.form.errors);
+      return res.redirect('/admin/notification#slack-incoming-webhooks');
+    }
+  };
+
+  // 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) {
       return res.redirect('/admin');
     }
 
-    Promise.resolve().then(function() {
-      return new Promise(function(resolve, reject) {
-        search.deleteIndex()
-          .then(function(data) {
-            debug('Index deleted.');
-            resolve();
-          }).catch(function(err) {
-            debug('Delete index Error, but if it is initialize, its ok.', err);
-            resolve();
-          });
-      });
-    }).then(function() {
-      search.buildIndex()
-        .then(function(data) {
-          if (!data.errors) {
-            debug('Index created.');
-          }
-          return search.addAllPages();
-        })
+    return new Promise(function(resolve, reject) {
+      search.deleteIndex()
         .then(function(data) {
-          if (!data.errors) {
-            debug('Data is successfully indexed.');
-          } else {
-            debug('Data index error.', data.errors);
-          }
-        })
-        .catch(function(err) {
-          debug('Error', err);
+          debug('Index deleted.');
+          resolve();
+        }).catch(function(err) {
+          debug('Delete index Error, but if it is initialize, its ok.', err);
+          resolve();
         });
-
-      req.flash('successMessage', 'Now re-building index ... this takes a while.');
+    })
+    .then(function() {
+      return search.buildIndex()
+    })
+    .then(function(data) {
+      if (!data.errors) {
+        debug('Index created.');
+      }
+      return search.addAllPages();
+    })
+    .then(function(data) {
+      if (!data.errors) {
+        debug('Data is successfully indexed.');
+        req.flash('successMessage', 'Data is successfully indexed.');
+      } else {
+        debug('Data index error.', data.errors);
+        req.flash('errorMessage', `Data index error: ${data.errors}`);
+      }
+      return res.redirect('/admin/search');
+    })
+    .catch(function(err) {
+      debug('Error', err);
+      req.flash('errorMessage', `Error: ${err}`);
       return res.redirect('/admin/search');
     });
   };
@@ -313,8 +407,37 @@ module.exports = function(crowi, app) {
   };
 
   actions.user.remove = function(req, res) {
-    // 未実装
-    return res.redirect('/admin/users');
+    var id = req.params.id;
+    let username = '';
+
+    return new Promise((resolve, reject) => {
+      User.findById(id, (err, userData) => {
+        username = userData.username;
+        return resolve(userData);
+      });
+    })
+    .then((userData) => {
+      return new Promise((resolve, reject) => {
+        userData.statusDelete((err, userData) => {
+          if (err) {
+            reject(err);
+          }
+          resolve(userData);
+        });
+      });
+    })
+    .then((userData) => {
+      return Page.removePageByPath(`/user/${username}`)
+        .then(() => userData);
+    })
+    .then((userData) => {
+      req.flash('successMessage', `${username} さんのアカウントを削除しました`);
+      return res.redirect('/admin/users');
+    })
+    .catch((err) => {
+      req.flash('errorMessage', '削除に失敗しました。');
+      return res.redirect('/admin/users');
+    });
   };
 
   // これやったときの relation の挙動未確認
@@ -374,6 +497,28 @@ module.exports = function(crowi, app) {
     }
   };
 
+  actions.api.securitySetting = function(req, res) {
+    var form = req.form.settingForm;
+
+    if (req.form.isValid) {
+      debug('form content', form);
+      return saveSetting(req, res, form);
+    } else {
+      return res.json({status: false, message: req.form.errors.join('\n')});
+    }
+  };
+
+  actions.api.customizeSetting = function(req, res) {
+    var form = req.form.settingForm;
+
+    if (req.form.isValid) {
+      debug('form content', form);
+      return saveSetting(req, res, form);
+    } else {
+      return res.json({status: false, message: req.form.errors.join('\n')});
+    }
+  }
+
   // app.post('/_api/admin/notifications.add'    , admin.api.notificationAdd);
   actions.api.notificationAdd = function(req, res) {
     var UpdatePost = crowi.model('UpdatePost');

+ 57 - 16
lib/util/slack.js

@@ -10,14 +10,12 @@ module.exports = function(crowi) {
   const debug = require('debug')('crowi:util:slack'),
     Config = crowi.model('Config'),
     SlackWebClient = require('@slack/client').WebClient,
-    sprintf = require('sprintf'),
-    pageEvent = crowi.event('page'),
+    SlackIncomingWebhook = require('@slack/client').IncomingWebhook,
     slack = {};
 
   slack.client = undefined;
+  slack.incomingWebhook = undefined;
 
-  // get client with access token,
-  // if access token is not fetched, return undefiend
   slack.getClient = function() {
     // alreay created
     if (slack.client) {
@@ -47,7 +45,7 @@ module.exports = function(crowi) {
   // this is called to get the url for oauth screen
   slack.getAuthorizeURL = function () {
     const config = crowi.getConfig();
-    if (Config.hasSlackConfig(config)) {
+    if (Config.hasSlackWebClientConfig(config)) {
       const slackClientId = config.notification['slack:clientId'];
       const redirectUri = slack.getSlackAuthCallbackUrl();
 
@@ -71,19 +69,62 @@ module.exports = function(crowi) {
     return client.oauth.access(clientId, clientSecret, code, {redirect_uri: redirectUri});
   }
 
+  slack.getIncomingWebhook = function() {
+    // alreay created
+    if (slack.incomingWebhook) {
+      return slack.incomingWebhook;
+    }
+
+    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 client = slack.getClient();
+    const config = crowi.getConfig();
 
     return new Promise(function(resolve, reject) {
-      client.chat.postMessage(channel, message, opts, 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();
     });
   };
 
@@ -121,12 +162,12 @@ module.exports = function(crowi) {
       debug('diff line', line)
       var value = line.value.replace(/\r\n|\r/g, '\n');
       if (line.added) {
-        diffText += sprintf(':pencil2: ...\n%s', line.value);
+        diffText += `:pencil2: ...\n${line.value}`;
       } else if (line.removed) {
         // diffText += '-' + line.value.replace(/(.+)?\n/g, '- $1\n');
         // 1以下は無視
         if (line.count > 1) {
-          diffText += sprintf(':wastebasket: ... %s lines\n', line.count);
+          diffText += `:wastebasket: ... ${line.count} lines\n`;
         }
       } else {
         //diffText += '...\n';
@@ -166,23 +207,23 @@ module.exports = function(crowi) {
     var message = {
       channel: '#' + channel,
       username: 'Crowi',
-      text: this.getSlackMessageText(page, user, updateType),
+      text: this.getSlackMessageText(page.path, user, updateType),
       attachments: [attachment],
     };
 
     return message;
   };
 
-  slack.getSlackMessageText = function(page, user, updateType) {
+  slack.getSlackMessageText = function(path, user, updateType) {
     let text;
     const config = crowi.getConfig();
     const url = config.crowi['app:url'] || '';
 
-    const pageLink = `<${url}/${page._id}|${page.path}>`;
+    const pageUrl = `<${url}${path}|${path}>`;
     if (updateType == 'create') {
-      text = sprintf(':white_check_mark: %s created a new page! %s', user.username, pageLink);
+      text = `:white_check_mark: ${user.username} created a new page! ${pageUrl}`;
     } else {
-      text = sprintf(':up: %s updated %s', user.username, pageLink);
+      text = `:up: ${user.username} updated ${pageUrl}`;
     }
 
     return text;

+ 2 - 2
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>