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

Merge pull request #2599 from weseek/imprv/create-notifyToSlackByUser-module

Imprv/create notify to slack by user module
itizawa 5 лет назад
Родитель
Сommit
b22d529b5a

+ 5 - 0
package.json

@@ -266,6 +266,11 @@
     "@alias/logger": "src/lib/service/logger",
     "debug": "src/lib/service/logger/alias-for-debug"
   },
+  "jest": {
+    "moduleNameMapper": {
+      "@commons/(.*)": "<rootDir>/src/lib/$1"
+    }
+  },
   "engines": {
     "node": "^12 || ^14",
     "npm": ">=6.11.3 <7",

+ 15 - 0
src/lib/util/to-array-from-csv.js

@@ -0,0 +1,15 @@
+// converts csv item to array
+const toArrayFromCsv = (text) => {
+  let array = [];
+
+  if (text == null) {
+    return array;
+  }
+
+  array = text.split(',').map(el => el.trim());
+  array = array.filter(el => el !== '');
+
+  return array;
+};
+
+module.exports = toArrayFromCsv;

+ 15 - 0
src/server/crowi/index.js

@@ -41,6 +41,7 @@ function Crowi(rootdir) {
   this.mailService = null;
   this.passportService = null;
   this.globalNotificationService = null;
+  this.userNotificationService = null;
   this.slackNotificationService = null;
   this.xssService = null;
   this.aclService = null;
@@ -313,6 +314,10 @@ Crowi.prototype.getGlobalNotificationService = function() {
   return this.globalNotificationService;
 };
 
+Crowi.prototype.getUserNotificationService = function() {
+  return this.userNotificationService;
+};
+
 Crowi.prototype.getRestQiitaAPIService = function() {
   return this.restQiitaAPIService;
 };
@@ -478,6 +483,16 @@ Crowi.prototype.setUpGlobalNotification = async function() {
   }
 };
 
+/**
+ * setup UserNotificationService
+ */
+Crowi.prototype.setUpGlobalNotification = async function() {
+  const UserNotificationService = require('../service/user-notification');
+  if (this.userNotificationService == null) {
+    this.userNotificationService = new UserNotificationService(this);
+  }
+};
+
 /**
  * setup SlackNotificationService
  */

+ 21 - 39
src/server/routes/apiv3/pages.js

@@ -25,38 +25,8 @@ module.exports = (crowi) => {
   const GlobalNotificationSetting = crowi.model('GlobalNotificationSetting');
 
   const globalNotificationService = crowi.getGlobalNotificationService();
-  const { pageService, slackNotificationService } = crowi;
-
-  // user notification
-  // TODO GW-3387 create '/service/user-notification' module
-  /**
-   *
-   * @param {Page} page
-   * @param {User} user
-   * @param {string} slackChannelsStr comma separated string. e.g. 'general,channel1,channel2'
-   * @param {boolean} updateOrCreate
-   * @param {string} previousRevision
-   */
-  async function notifyToSlackByUser(page, user, slackChannelsStr, updateOrCreate, previousRevision) {
-    await page.updateSlackChannel(slackChannelsStr)
-      .catch((err) => {
-        logger.error('Error occured in updating slack channels: ', err);
-      });
-
-
-    if (slackNotificationService.hasSlackConfig()) {
-      const slackChannels = slackChannelsStr != null ? slackChannelsStr.split(',') : [null];
-
-      const promises = slackChannels.map((chan) => {
-        return crowi.slack.postPage(page, user, chan, updateOrCreate, previousRevision);
-      });
-
-      Promise.all(promises)
-        .catch((err) => {
-          logger.error('Error occured in sending slack notification: ', err);
-        });
-    }
-  }
+  const userNotificationService = crowi.getUserNotificationService();
+  const { pageService } = crowi;
 
   // TODO write swagger(GW-3384) and validation(GW-3385)
   router.post('/', accessTokenParser, loginRequiredStrictly, csrf, async(req, res) => {
@@ -97,16 +67,28 @@ module.exports = (crowi) => {
     }
 
     // global notification
-    try {
-      await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_CREATE, createdPage, req.user);
-    }
-    catch (err) {
-      logger.error('Create notification failed', err);
+    if (globalNotificationService != null) {
+      try {
+        await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_CREATE, createdPage, req.user);
+      }
+      catch (err) {
+        logger.error('Create grobal notification failed', err);
+      }
     }
 
     // user notification
-    if (isSlackEnabled) {
-      await notifyToSlackByUser(createdPage, req.user, slackChannels, 'create', false);
+    if (isSlackEnabled && userNotificationService != null) {
+      try {
+        const results = await userNotificationService.fire(createdPage, req.user, slackChannels, 'create', false);
+        results.forEach((result) => {
+          if (result.status === 'rejected') {
+            logger.error('Create user notification failed', result.reason);
+          }
+        });
+      }
+      catch (err) {
+        logger.error('Create user notification failed', err);
+      }
     }
 
     return res.apiv3(result);

+ 50 - 0
src/server/service/user-notification/index.js

@@ -0,0 +1,50 @@
+const toArrayFromCsv = require('@commons/util/to-array-from-csv');
+
+/**
+ * service class of UserNotification
+ */
+class UserNotificationService {
+
+  constructor(crowi) {
+    this.crowi = crowi;
+
+    this.Page = this.crowi.model('Page');
+  }
+
+  /**
+   * fire user notification
+   *
+   * @memberof UserNotificationService
+   *
+   * @param {Page} page
+   * @param {User} user
+   * @param {string} slackChannelsStr comma separated string. e.g. 'general,channel1,channel2'
+   * @param {boolean} updateOrCreate
+   * @param {string} previousRevision
+   */
+  async fire(page, user, slackChannelsStr, updateOrCreate, previousRevision) {
+    const { slackNotificationService, slack } = this.crowi;
+
+    await page.updateSlackChannel(slackChannelsStr);
+
+    if (!slackNotificationService.hasSlackConfig()) {
+      throw new Error('slackNotificationService has not been set up');
+    }
+
+    // "dev,slacktest" => [dev,slacktest]
+    const slackChannels = toArrayFromCsv(slackChannelsStr);
+
+    const promises = slackChannels.map(async(chan) => {
+      const res = await slack.postPage(page, user, chan, updateOrCreate, previousRevision);
+      if (res.status !== 'ok') {
+        throw new Error(`fail to send slack notification to #${chan} channel`);
+      }
+      return res;
+    });
+
+    return Promise.allSettled(promises);
+  }
+
+}
+
+module.exports = UserNotificationService;

+ 30 - 0
src/test/libs/to-array-from-csv.test.js

@@ -0,0 +1,30 @@
+const toArrayFromCsv = require('@commons/util/to-array-from-csv');
+
+describe('To array from csv', () => {
+
+  test('case 1', () => {
+    const result = toArrayFromCsv('dev,general');
+    expect(result).toStrictEqual(['dev', 'general']);
+  });
+
+  test('case 2', () => {
+    const result = toArrayFromCsv('dev');
+    expect(result).toStrictEqual(['dev']);
+  });
+
+  test('case 3', () => {
+    const result = toArrayFromCsv('');
+    expect(result).toStrictEqual([]);
+  });
+
+  test('case 4', () => {
+    const result = toArrayFromCsv('dev, general');
+    expect(result).toStrictEqual(['dev', 'general']);
+  });
+
+  test('case 5', () => {
+    const result = toArrayFromCsv(',dev,general');
+    expect(result).toStrictEqual(['dev', 'general']);
+  });
+
+});