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

Merge branch 'imprv/duplicate-Page-with-child' into apiv3-for-duplicate

zahmis 5 лет назад
Родитель
Сommit
fb0107c019

+ 8 - 1
CHANGES.md

@@ -11,14 +11,21 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/41x.html>
 
 ### Updates
 
-* Feature: Config synchronization for multiple GROWI Apps
+* Feature: Server settings synchronization for multiple GROWI Apps
+* Feature: Page status alert synchronization for multiple GROWI Apps
 * Feature: Smooth scroll for anchor links
 * Feature: Mirror Mode with [Konami Code](https://en.wikipedia.org/wiki/Konami_Code)
 * Improvement: Determine whether the "In Use" badge is displayed or not by attachment ID
+* Improvement: draw.io under NO_CDN environment
+* Fix: Deleting/renaming with recursive option affects pages that are inaccessible to active users
+* Fix: DrawioModal cuts without beginning/ending line
 * Fix: New settings of SMTP and AWS SES are not reflected when server is running
+* Fix: Sidebar layout broken when using Kibela layout
 * Fix: PageAlert broken
     * Introduced by v4.0.9
 * Support: Support Node.js v14
+* Support: Update libs
+    * mathjax
 
 
 

+ 1 - 1
resource/cdn-manifests.js

@@ -39,7 +39,7 @@ module.exports = {
     },
     {
       name: 'mathjax',
-      url: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js',
+      url: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js',
       args: {
         async: true,
         integrity: '',

+ 4 - 5
src/client/js/services/PageContainer.js

@@ -323,11 +323,10 @@ export default class PageContainer extends Container {
       body: markdown,
     });
 
-    const res = await this.appContainer.apiPost('/pages.create', params);
-    if (!res.ok) {
-      throw new Error(res.error);
-    }
-    return { page: res.page, tags: res.tags };
+    const res = await this.appContainer.apiv3Post('/pages/', params);
+    const { page, tags } = res.data;
+
+    return { page, tags };
   }
 
   async updatePage(pageId, revisionId, markdown, tmpParams) {

+ 91 - 1
src/server/routes/apiv3/pages.js

@@ -3,6 +3,7 @@ const loggerFactory = require('@alias/logger');
 const logger = loggerFactory('growi:routes:apiv3:pages'); // eslint-disable-line no-unused-vars
 
 const express = require('express');
+const pathUtils = require('growi-commons').pathUtils;
 
 
 const router = express.Router();
@@ -18,11 +19,100 @@ module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
-
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const csrf = require('../../middlewares/csrf')(crowi);
 
   const Page = crowi.model('Page');
+  const PageTagRelation = crowi.model('PageTagRelation');
+  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);
+        });
+    }
+  }
+
+  // TODO write swagger(GW-3384) and validation(GW-3385)
+  router.post('/', accessTokenParser, loginRequiredStrictly, csrf, async(req, res) => {
+    const {
+      body, grant, grantUserGroupId, overwriteScopesOfDescendants, isSlackEnabled, slackChannels, socketClientId, pageTags,
+    } = req.body;
+    let { path } = req.body;
+
+    // check whether path starts slash
+    path = pathUtils.addHeadingSlash(path);
+
+    // check page existence
+    const isExist = await Page.count({ path }) > 0;
+    if (isExist) {
+      res.code = 'page_exists';
+      return res.apiv3Err('Page exists', 409);
+    }
+
+    const options = { socketClientId };
+    if (grant != null) {
+      options.grant = grant;
+      options.grantUserGroupId = grantUserGroupId;
+    }
+
+    const createdPage = await Page.create(path, body, req.user, options);
+
+    let savedTags;
+    if (pageTags != null) {
+      await PageTagRelation.updatePageTags(createdPage.id, pageTags);
+      savedTags = await PageTagRelation.listTagNamesByPage(createdPage.id);
+    }
+
+    const result = { page: pageService.serializeToObj(createdPage), tags: savedTags };
+
+    // update scopes for descendants
+    if (overwriteScopesOfDescendants) {
+      Page.applyScopesToDescendantsAsyncronously(createdPage, req.user);
+    }
+
+    // global notification
+    try {
+      await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_CREATE, createdPage, req.user);
+    }
+    catch (err) {
+      logger.error('Create notification failed', err);
+    }
+
+    // user notification
+    if (isSlackEnabled) {
+      await notifyToSlackByUser(createdPage, req.user, slackChannels, 'create', false);
+    }
+
+    return res.apiv3(result);
+  });
 
   /**
    * @swagger

+ 1 - 0
src/server/routes/page.js

@@ -672,6 +672,7 @@ module.exports = function(crowi, app) {
    * @apiParam {String} grant
    * @apiParam {Array} pageTags
    */
+  // TODO If everything that depends on this route, delete it too
   api.create = async function(req, res) {
     const body = req.body.body || null;
     let pagePath = req.body.path || null;

+ 3 - 2
src/server/service/app.js

@@ -64,10 +64,11 @@ class AppService extends S2sMessageHandlable {
       catch (e) {
         logger.error('Failed to publish post installation message with S2sMessagingService: ', e.message);
       }
+
+      // remove message handler
+      s2sMessagingService.removeMessageHandler(this);
     }
 
-    // remove message handler
-    s2sMessagingService.removeMessageHandler(this);
   }
 
   getAppTitle() {

+ 17 - 12
src/server/views/widget/headers/mathjax.html

@@ -1,16 +1,21 @@
 <!-- Mathjax -->
-<script type="text/x-mathjax-config" async>
-  MathJax.Hub.Config({
-    skipStartupTypeset: true,
-    extensions: ["tex2jax.js"],
-    jax: ["input/TeX", "output/SVG"],
-    tex2jax: {
-      processEscapes: true
+<script type="text/javascript">
+  window.MathJax = {
+    startup: {
+      typeset: false
     },
-    showMathMenu: false,
-    showMathMenuMSIE: false,
-    showProcessingMessages: false,
-    messageStyle: "none"
-  });
+    tex: {
+      processEscapes: true,
+      inlineMath: [['$', '$'], ['\\(', '\\)']]
+    },
+    options: {
+      renderActions: {
+        addMenu: [],
+        checkLoading: []
+      },
+      ignoreHtmlClass: 'tex2jax_ignore',
+      processHtmlClass: 'tex2jax_process'
+    }
+  };
 </script>
 {{ cdnScriptTag('mathjax') }}