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

Merge branch 'feat/pt-dev-3' into imprv/define-item-area-css

Taichi Masuyama 4 лет назад
Родитель
Сommit
b1dd040020

+ 19 - 13
packages/app/src/client/app.jsx

@@ -177,19 +177,25 @@ const renderMainComponents = () => {
 
 // extract context before rendering main components
 const elem = document.getElementById('page-context');
-ReactDOM.render(
-  <I18nextProvider i18n={i18n}>
-    <ErrorBoundary>
-      <SWRConfig value={swrGlobalConfiguration}>
-        <Provider inject={injectableContainers}>
-          {componentMappings['page-context']}
-        </Provider>
-      </SWRConfig>
-    </ErrorBoundary>
-  </I18nextProvider>,
-  elem,
-  renderMainComponents,
-);
+
+if (elem != null) {
+  ReactDOM.render(
+    <I18nextProvider i18n={i18n}>
+      <ErrorBoundary>
+        <SWRConfig value={swrGlobalConfiguration}>
+          <Provider inject={injectableContainers}>
+            {componentMappings['page-context']}
+          </Provider>
+        </SWRConfig>
+      </ErrorBoundary>
+    </I18nextProvider>,
+    elem,
+    renderMainComponents,
+  );
+}
+else {
+  renderMainComponents();
+}
 
 
 // initialize scrollpos-styler

+ 17 - 8
packages/app/src/server/models/obsolete-page.js

@@ -929,22 +929,31 @@ export const getPageSchema = (crowi) => {
       grant = GRANT_PUBLIC;
     }
 
-    const isV5Compatible = crowi.configManager.getConfig('crowi', 'app:isV5Compatible');
-    // for v4 compatibility
-    if (!isV5Compatible) {
-      const isExist = await this.count({ path });
+    const isExist = await this.count({ path });
+    if (isExist) {
+      throw new Error('Cannot create new page to existed path');
+    }
 
-      if (isExist) {
-        throw new Error('Cannot create new page to existed path');
-      }
+    /*
+     * update empty page if exists, if not, create a new page
+     */
+    let page;
+    const emptyPage = await Page.findOne({ path, isEmpty: true });
+    if (emptyPage != null) {
+      page = emptyPage;
+      page.isEmpty = false;
     }
+    else {
+      page = new Page();
+    }
+
+    const isV5Compatible = crowi.configManager.getConfig('crowi', 'app:isV5Compatible');
 
     let parent = parentId;
     if (isV5Compatible && parent == null && !isTopPage(path)) {
       parent = await Page.getParentIdAndFillAncestors(path);
     }
 
-    const page = new Page();
     page.path = path;
     page.creator = user;
     page.lastUpdateUser = user;

+ 10 - 10
packages/app/src/server/routes/apiv3/pages.js

@@ -192,7 +192,7 @@ module.exports = (crowi) => {
   async function createPageAction({
     path, body, user, options,
   }) {
-    const createdPage = Page.create(path, body, user, options);
+    const createdPage = await Page.create(path, body, user, options);
     return createdPage;
   }
 
@@ -267,21 +267,21 @@ module.exports = (crowi) => {
     // check whether path starts slash
     path = pathUtils.addHeadingSlash(path);
 
-    // check page existence
-    const isExist = await Page.count({ path }) > 0;
-    if (isExist) {
-      return res.apiv3Err(new ErrorV3('Failed to post page', 'page_exists'), 500);
-    }
-
     const options = {};
     if (grant != null) {
       options.grant = grant;
       options.grantUserGroupId = grantUserGroupId;
     }
 
-    const createdPage = await createPageAction({
-      path, body, user: req.user, options,
-    });
+    let createdPage;
+    try {
+      createdPage = await createPageAction({
+        path, body, user: req.user, options,
+      });
+    }
+    catch (err) {
+      return res.apiv3Error(err);
+    }
 
     const savedTags = await saveTagsAction({ createdPage, pageTags });
 

+ 4 - 4
packages/app/src/server/routes/index.js

@@ -139,8 +139,6 @@ module.exports = function(crowi, app) {
   // my drafts
   app.get('/me/drafts'                , loginRequiredStrictly, me.drafts.list);
 
-  app.get('/:id([0-9a-z]{24})'       , loginRequired , page.showPage);
-  app.get('/_r/:id([0-9a-z]{24})'    , loginRequired , page.redirector); // alias
   app.get('/attachment/:id([0-9a-z]{24})' , certifySharedFile , loginRequired, attachment.api.get);
   app.get('/attachment/profile/:id([0-9a-z]{24})' , loginRequired, attachment.api.get);
   app.get('/attachment/:pageId/:fileName', loginRequired, attachment.api.obsoletedGetForMongoDB); // DEPRECATED: remains for backward compatibility for v3.3.x or below
@@ -195,7 +193,9 @@ module.exports = function(crowi, app) {
 
   app.get('/share/:linkId', page.showSharedPage);
 
-  app.get('/*/$'                   , loginRequired , page.redirectorWithEndOfSlash, page.notFound);
-  app.get('/*'                     , loginRequired , autoReconnectToSearch, page.redirector, page.notFound);
+  app.get('/:id([0-9a-z]{24})'       , loginRequired , page.showPage);
+
+  app.get('/*/$'                   , loginRequired , page.redirectorWithEndOfSlash);
+  app.get('/*'                     , loginRequired , autoReconnectToSearch, page.redirector);
 
 };

+ 60 - 41
packages/app/src/server/routes/page.js

@@ -168,7 +168,7 @@ module.exports = function(crowi, app) {
   const actions = {};
 
   function getPathFromRequest(req) {
-    return pathUtils.normalizePath(req.params[0] || '');
+    return pathUtils.normalizePath(req.pagePath || req.params[0] || '');
   }
 
   function isUserPage(path) {
@@ -289,6 +289,47 @@ module.exports = function(crowi, app) {
     return compiledTemplate(definitions);
   }
 
+  async function _notFound(req, res) {
+    const path = getPathFromRequest(req);
+
+    let view;
+    const renderVars = { path };
+
+    if (!isCreatablePage(path)) {
+      view = 'layout-growi/not_creatable';
+    }
+    else if (req.isForbidden) {
+      view = 'layout-growi/forbidden';
+    }
+    else {
+      view = 'layout-growi/not_found';
+
+      // retrieve templates
+      if (req.user != null) {
+        const template = await Page.findTemplate(path);
+        if (template.templateBody) {
+          const body = replacePlaceholdersOfTemplate(template.templateBody, req);
+          const tags = template.templateTags;
+          renderVars.template = body;
+          renderVars.templateTags = tags;
+        }
+      }
+
+      // add scope variables by ancestor page
+      const ancestor = await Page.findAncestorByPathAndViewer(path, req.user);
+      if (ancestor != null) {
+        await ancestor.populate('grantedGroup').execPopulate();
+        addRenderVarsForScope(renderVars, ancestor);
+      }
+    }
+
+    const limit = 50;
+    const offset = parseInt(req.query.offset) || 0;
+    await addRenderVarsForDescendants(renderVars, path, req.user, offset, limit, true);
+
+    return res.render(view, renderVars);
+  }
+
   async function showPageForPresentation(req, res, next) {
     const id = req.params.id;
     const { revisionId } = req.query;
@@ -299,6 +340,11 @@ module.exports = function(crowi, app) {
       next();
     }
 
+    if (page.isEmpty) {
+      req.pagePath = page.path;
+      return next();
+    }
+
     const renderVars = {};
 
     // populate
@@ -354,7 +400,13 @@ module.exports = function(crowi, app) {
     if (page == null) {
       // check the page is forbidden or just does not exist.
       req.isForbidden = await Page.count({ _id: id }) > 0;
-      return next();
+      return _notFound(req, res);
+    }
+
+    // empty page
+    if (page.isEmpty) {
+      req.pagePath = page.path;
+      return _notFound(req, res);
     }
 
     const { path } = page; // this must exist
@@ -503,44 +555,7 @@ module.exports = function(crowi, app) {
   /* eslint-enable no-else-return */
 
   actions.notFound = async function(req, res) {
-    const path = getPathFromRequest(req);
-
-    let view;
-    const renderVars = { path };
-
-    if (!isCreatablePage(path)) {
-      view = 'layout-growi/not_creatable';
-    }
-    else if (req.isForbidden) {
-      view = 'layout-growi/forbidden';
-    }
-    else {
-      view = 'layout-growi/not_found';
-
-      // retrieve templates
-      if (req.user != null) {
-        const template = await Page.findTemplate(path);
-        if (template.templateBody) {
-          const body = replacePlaceholdersOfTemplate(template.templateBody, req);
-          const tags = template.templateTags;
-          renderVars.template = body;
-          renderVars.templateTags = tags;
-        }
-      }
-
-      // add scope variables by ancestor page
-      const ancestor = await Page.findAncestorByPathAndViewer(path, req.user);
-      if (ancestor != null) {
-        await ancestor.populate('grantedGroup').execPopulate();
-        addRenderVarsForScope(renderVars, ancestor);
-      }
-    }
-
-    const limit = 50;
-    const offset = parseInt(req.query.offset) || 0;
-    await addRenderVarsForDescendants(renderVars, path, req.user, offset, limit, true);
-
-    return res.render(view, renderVars);
+    return _notFound(req, res);
   };
 
   actions.deletedPageListShow = async function(req, res) {
@@ -586,6 +601,10 @@ module.exports = function(crowi, app) {
     }
 
     if (pages.length === 1) {
+      if (pages[0].isEmpty) {
+        return _notFound(req, res);
+      }
+
       const url = new URL('https://dummy.origin');
       url.pathname = `/${pages[0]._id}`;
       Object.entries(req.query).forEach(([key, value], i) => {
@@ -594,7 +613,7 @@ module.exports = function(crowi, app) {
       return res.safeRedirect(urljoin(url.pathname, url.search));
     }
 
-    return next(); // to page.notFound
+    return _notFound(req, res);
   }
 
   actions.redirector = async function(req, res, next) {