2
0
Эх сурвалжийг харах

apply read only validator

ryoji-s 2 жил өмнө
parent
commit
4febb234ef

+ 4 - 4
apps/app/src/server/routes/apiv3/page.js

@@ -4,12 +4,12 @@ import {
 
 
 import { SupportedAction, SupportedTargetModel } from '~/interfaces/activity';
 import { SupportedAction, SupportedTargetModel } from '~/interfaces/activity';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
+import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
+import { readOnlyValidator } from '~/server/middlewares/read-only-validator';
 import Subscription from '~/server/models/subscription';
 import Subscription from '~/server/models/subscription';
 import UserGroup from '~/server/models/user-group';
 import UserGroup from '~/server/models/user-group';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
-import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
-
 const logger = loggerFactory('growi:routes:apiv3:page'); // eslint-disable-line no-unused-vars
 const logger = loggerFactory('growi:routes:apiv3:page'); // eslint-disable-line no-unused-vars
 
 
 const express = require('express');
 const express = require('express');
@@ -542,7 +542,7 @@ module.exports = (crowi) => {
     return res.apiv3(data);
     return res.apiv3(data);
   });
   });
 
 
-  router.put('/:pageId/grant', loginRequiredStrictly, validator.updateGrant, apiV3FormValidator, async(req, res) => {
+  router.put('/:pageId/grant', loginRequiredStrictly, readOnlyValidator, validator.updateGrant, apiV3FormValidator, async(req, res) => {
     const { pageId } = req.params;
     const { pageId } = req.params;
     const { grant, grantedGroup } = req.body;
     const { grant, grantedGroup } = req.body;
 
 
@@ -837,7 +837,7 @@ module.exports = (crowi) => {
   });
   });
 
 
 
 
-  router.put('/:pageId/content-width', accessTokenParser, loginRequiredStrictly,
+  router.put('/:pageId/content-width', accessTokenParser, loginRequiredStrictly, readOnlyValidator,
     validator.contentWidth, apiV3FormValidator, async(req, res) => {
     validator.contentWidth, apiV3FormValidator, async(req, res) => {
       const { pageId } = req.params;
       const { pageId } = req.params;
       const { expandContentWidth } = req.body;
       const { expandContentWidth } = req.body;

+ 79 - 76
apps/app/src/server/routes/apiv3/pages.js

@@ -6,6 +6,7 @@ import loggerFactory from '~/utils/logger';
 
 
 import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
 import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
 import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
 import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
+import { readOnlyValidator } from '../../middlewares/read-only-validator';
 import { isV5ConversionError } from '../../models/vo/v5-conversion-error';
 import { isV5ConversionError } from '../../models/vo/v5-conversion-error';
 
 
 import { ErrorV3 } from '@growi/core';
 import { ErrorV3 } from '@growi/core';
@@ -292,7 +293,7 @@ module.exports = (crowi) => {
    *          409:
    *          409:
    *            description: page path is already existed
    *            description: page path is already existed
    */
    */
-  router.post('/', accessTokenParser, loginRequiredStrictly, addActivity, validator.createPage, apiV3FormValidator, async(req, res) => {
+  router.post('/', accessTokenParser, loginRequiredStrictly, readOnlyValidator, addActivity, validator.createPage, apiV3FormValidator, async(req, res) => {
     const {
     const {
       body, grant, grantUserGroupId, overwriteScopesOfDescendants, isSlackEnabled, slackChannels, pageTags,
       body, grant, grantUserGroupId, overwriteScopesOfDescendants, isSlackEnabled, slackChannels, pageTags,
     } = req.body;
     } = req.body;
@@ -504,7 +505,7 @@ module.exports = (crowi) => {
    *          409:
    *          409:
    *            description: page path is already existed
    *            description: page path is already existed
    */
    */
-  router.put('/rename', accessTokenParser, loginRequiredStrictly, validator.renamePage, apiV3FormValidator, async(req, res) => {
+  router.put('/rename', accessTokenParser, loginRequiredStrictly, readOnlyValidator, validator.renamePage, apiV3FormValidator, async(req, res) => {
     const { pageId, revisionId } = req.body;
     const { pageId, revisionId } = req.body;
 
 
     let newPagePath = pathUtils.normalizePath(req.body.newPagePath);
     let newPagePath = pathUtils.normalizePath(req.body.newPagePath);
@@ -575,35 +576,36 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
-  router.post('/resume-rename', accessTokenParser, loginRequiredStrictly, validator.resumeRenamePage, apiV3FormValidator, async(req, res) => {
+  router.post('/resume-rename', accessTokenParser, loginRequiredStrictly, readOnlyValidator, validator.resumeRenamePage, apiV3FormValidator,
+    async(req, res) => {
 
 
-    const { pageId } = req.body;
-    const { user } = req;
+      const { pageId } = req.body;
+      const { user } = req;
 
 
-    // The user has permission to resume rename operation if page is returned.
-    const page = await Page.findByIdAndViewer(pageId, user, null, true);
-    if (page == null) {
-      const msg = 'The operation is forbidden for this user';
-      const code = 'forbidden-user';
-      return res.apiv3Err(new ErrorV3(msg, code), 403);
-    }
+      // The user has permission to resume rename operation if page is returned.
+      const page = await Page.findByIdAndViewer(pageId, user, null, true);
+      if (page == null) {
+        const msg = 'The operation is forbidden for this user';
+        const code = 'forbidden-user';
+        return res.apiv3Err(new ErrorV3(msg, code), 403);
+      }
 
 
-    const pageOp = await crowi.pageOperationService.getRenameSubOperationByPageId(page._id);
-    if (pageOp == null) {
-      const msg = 'PageOperation document for Rename Sub operation not found.';
-      const code = 'document_not_found';
-      return res.apiv3Err(new ErrorV3(msg, code), 404);
-    }
+      const pageOp = await crowi.pageOperationService.getRenameSubOperationByPageId(page._id);
+      if (pageOp == null) {
+        const msg = 'PageOperation document for Rename Sub operation not found.';
+        const code = 'document_not_found';
+        return res.apiv3Err(new ErrorV3(msg, code), 404);
+      }
 
 
-    try {
-      await crowi.pageService.resumeRenameSubOperation(page, pageOp);
-    }
-    catch (err) {
-      logger.error(err);
-      return res.apiv3Err(err, 500);
-    }
-    return res.apiv3();
-  });
+      try {
+        await crowi.pageService.resumeRenameSubOperation(page, pageOp);
+      }
+      catch (err) {
+        logger.error(err);
+        return res.apiv3Err(err, 500);
+      }
+      return res.apiv3();
+    });
 
 
   /**
   /**
    * @swagger
    * @swagger
@@ -616,7 +618,7 @@ module.exports = (crowi) => {
    *          200:
    *          200:
    *            description: Succeeded to remove all trash pages
    *            description: Succeeded to remove all trash pages
    */
    */
-  router.delete('/empty-trash', accessTokenParser, loginRequired, addActivity, apiV3FormValidator, async(req, res) => {
+  router.delete('/empty-trash', accessTokenParser, loginRequired, readOnlyValidator, addActivity, apiV3FormValidator, async(req, res) => {
     const options = {};
     const options = {};
 
 
     const pagesInTrash = await crowi.pageService.findAllTrashPages(req.user);
     const pagesInTrash = await crowi.pageService.findAllTrashPages(req.user);
@@ -746,61 +748,62 @@ module.exports = (crowi) => {
    *          500:
    *          500:
    *            description: Internal server error.
    *            description: Internal server error.
    */
    */
-  router.post('/duplicate', accessTokenParser, loginRequiredStrictly, addActivity, validator.duplicatePage, apiV3FormValidator, async(req, res) => {
-    const { pageId, isRecursively } = req.body;
+  router.post('/duplicate', accessTokenParser, loginRequiredStrictly, readOnlyValidator, addActivity, validator.duplicatePage, apiV3FormValidator,
+    async(req, res) => {
+      const { pageId, isRecursively } = req.body;
 
 
-    const newPagePath = pathUtils.normalizePath(req.body.pageNameInput);
+      const newPagePath = pathUtils.normalizePath(req.body.pageNameInput);
 
 
-    const isCreatable = isCreatablePage(newPagePath);
-    if (!isCreatable) {
-      return res.apiv3Err(new ErrorV3('This page path is invalid', 'invalid_path'), 400);
-    }
+      const isCreatable = isCreatablePage(newPagePath);
+      if (!isCreatable) {
+        return res.apiv3Err(new ErrorV3('This page path is invalid', 'invalid_path'), 400);
+      }
 
 
-    // check page existence
-    const isExist = (await Page.count({ path: newPagePath })) > 0;
-    if (isExist) {
-      return res.apiv3Err(new ErrorV3(`Page exists '${newPagePath})'`, 'already_exists'), 409);
-    }
+      // check page existence
+      const isExist = (await Page.count({ path: newPagePath })) > 0;
+      if (isExist) {
+        return res.apiv3Err(new ErrorV3(`Page exists '${newPagePath})'`, 'already_exists'), 409);
+      }
 
 
-    const page = await Page.findByIdAndViewer(pageId, req.user, null, true);
+      const page = await Page.findByIdAndViewer(pageId, req.user, null, true);
 
 
-    const isEmptyAndNotRecursively = page?.isEmpty && !isRecursively;
-    if (page == null || isEmptyAndNotRecursively) {
-      res.code = 'Page is not found';
-      logger.error('Failed to find the pages');
-      return res.apiv3Err(new ErrorV3(`Page '${pageId}' is not found or forbidden`, 'notfound_or_forbidden'), 401);
-    }
+      const isEmptyAndNotRecursively = page?.isEmpty && !isRecursively;
+      if (page == null || isEmptyAndNotRecursively) {
+        res.code = 'Page is not found';
+        logger.error('Failed to find the pages');
+        return res.apiv3Err(new ErrorV3(`Page '${pageId}' is not found or forbidden`, 'notfound_or_forbidden'), 401);
+      }
 
 
-    const newParentPage = await crowi.pageService.duplicate(page, newPagePath, req.user, isRecursively);
-    const result = { page: serializePageSecurely(newParentPage) };
+      const newParentPage = await crowi.pageService.duplicate(page, newPagePath, req.user, isRecursively);
+      const result = { page: serializePageSecurely(newParentPage) };
 
 
-    // copy the page since it's used and updated in crowi.pageService.duplicate
-    const copyPage = { ...page };
-    copyPage.path = newPagePath;
-    try {
-      await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_CREATE, copyPage, req.user);
-    }
-    catch (err) {
-      logger.error('Create grobal notification failed', err);
-    }
+      // copy the page since it's used and updated in crowi.pageService.duplicate
+      const copyPage = { ...page };
+      copyPage.path = newPagePath;
+      try {
+        await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_CREATE, copyPage, req.user);
+      }
+      catch (err) {
+        logger.error('Create grobal notification failed', err);
+      }
 
 
-    // create subscription (parent page only)
-    try {
-      await crowi.inAppNotificationService.createSubscription(req.user.id, newParentPage._id, subscribeRuleNames.PAGE_CREATE);
-    }
-    catch (err) {
-      logger.error('Failed to create subscription document', err);
-    }
+      // create subscription (parent page only)
+      try {
+        await crowi.inAppNotificationService.createSubscription(req.user.id, newParentPage._id, subscribeRuleNames.PAGE_CREATE);
+      }
+      catch (err) {
+        logger.error('Failed to create subscription document', err);
+      }
 
 
-    const parameters = {
-      targetModel: SupportedTargetModel.MODEL_PAGE,
-      target: page,
-      action: SupportedAction.ACTION_PAGE_DUPLICATE,
-    };
-    activityEvent.emit('update', res.locals.activity._id, parameters, page);
+      const parameters = {
+        targetModel: SupportedTargetModel.MODEL_PAGE,
+        target: page,
+        action: SupportedAction.ACTION_PAGE_DUPLICATE,
+      };
+      activityEvent.emit('update', res.locals.activity._id, parameters, page);
 
 
-    return res.apiv3(result);
-  });
+      return res.apiv3(result);
+    });
 
 
   /**
   /**
    * @swagger
    * @swagger
@@ -851,7 +854,7 @@ module.exports = (crowi) => {
 
 
   });
   });
 
 
-  router.post('/delete', accessTokenParser, loginRequiredStrictly, validator.deletePages, apiV3FormValidator, async(req, res) => {
+  router.post('/delete', accessTokenParser, loginRequiredStrictly, readOnlyValidator, validator.deletePages, apiV3FormValidator, async(req, res) => {
     const {
     const {
       pageIdToRevisionIdMap, isCompletely, isRecursively, isAnyoneWithTheLink,
       pageIdToRevisionIdMap, isCompletely, isRecursively, isAnyoneWithTheLink,
     } = req.body;
     } = req.body;
@@ -913,7 +916,7 @@ module.exports = (crowi) => {
 
 
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.post('/convert-pages-by-path', accessTokenParser, loginRequiredStrictly, adminRequired, validator.convertPagesByPath, apiV3FormValidator, async(req, res) => {
+  router.post('/convert-pages-by-path', accessTokenParser, loginRequiredStrictly, readOnlyValidator, adminRequired, validator.convertPagesByPath, apiV3FormValidator, async(req, res) => {
     const { convertPath } = req.body;
     const { convertPath } = req.body;
 
 
     // Convert by path
     // Convert by path
@@ -935,7 +938,7 @@ module.exports = (crowi) => {
   });
   });
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.post('/legacy-pages-migration', accessTokenParser, loginRequired, validator.legacyPagesMigration, apiV3FormValidator, async(req, res) => {
+  router.post('/legacy-pages-migration', accessTokenParser, loginRequired, readOnlyValidator, validator.legacyPagesMigration, apiV3FormValidator, async(req, res) => {
     const { pageIds: _pageIds, isRecursively } = req.body;
     const { pageIds: _pageIds, isRecursively } = req.body;
 
 
     // Convert by pageIds
     // Convert by pageIds

+ 5 - 6
apps/app/src/server/routes/apiv3/share-links.js

@@ -4,11 +4,10 @@ import { ErrorV3 } from '@growi/core';
 
 
 import { SupportedAction } from '~/interfaces/activity';
 import { SupportedAction } from '~/interfaces/activity';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
+import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
+import { readOnlyValidator } from '~/server/middlewares/read-only-validator';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
-import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
-
-
 const logger = loggerFactory('growi:routes:apiv3:share-links');
 const logger = loggerFactory('growi:routes:apiv3:share-links');
 
 
 const express = require('express');
 const express = require('express');
@@ -135,7 +134,7 @@ module.exports = (crowi) => {
    *            description: Succeeded to create one share link
    *            description: Succeeded to create one share link
    */
    */
 
 
-  router.post('/', loginRequired, linkSharingRequired, addActivity, validator.shareLinkStatus, apiV3FormValidator, async(req, res) => {
+  router.post('/', loginRequired, readOnlyValidator, linkSharingRequired, addActivity, validator.shareLinkStatus, apiV3FormValidator, async(req, res) => {
     const { relatedPage, expiredAt, description } = req.body;
     const { relatedPage, expiredAt, description } = req.body;
 
 
     const page = await Page.findByIdAndViewer(relatedPage, req.user);
     const page = await Page.findByIdAndViewer(relatedPage, req.user);
@@ -187,7 +186,7 @@ module.exports = (crowi) => {
   *          200:
   *          200:
   *            description: Succeeded to delete o all share links related one page
   *            description: Succeeded to delete o all share links related one page
   */
   */
-  router.delete('/', loginRequired, addActivity, validator.deleteShareLinks, apiV3FormValidator, async(req, res) => {
+  router.delete('/', loginRequired, readOnlyValidator, addActivity, validator.deleteShareLinks, apiV3FormValidator, async(req, res) => {
     const { relatedPage } = req.query;
     const { relatedPage } = req.query;
     const page = await Page.findByIdAndViewer(relatedPage, req.user);
     const page = await Page.findByIdAndViewer(relatedPage, req.user);
 
 
@@ -261,7 +260,7 @@ module.exports = (crowi) => {
   *          200:
   *          200:
   *            description: Succeeded to delete one share link
   *            description: Succeeded to delete one share link
   */
   */
-  router.delete('/:id', loginRequired, addActivity, validator.deleteShareLink, apiV3FormValidator, async(req, res) => {
+  router.delete('/:id', loginRequired, readOnlyValidator, addActivity, validator.deleteShareLink, apiV3FormValidator, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
     const { user } = req;
     const { user } = req;
 
 

+ 19 - 18
apps/app/src/server/routes/apiv3/slack-integration-settings.js

@@ -507,28 +507,29 @@ module.exports = (crowi) => {
    *          200:
    *          200:
    *            description: Succeeded to delete access tokens for slack
    *            description: Succeeded to delete access tokens for slack
    */
    */
-  router.delete('/slack-app-integrations/:id', validator.deleteIntegration, apiV3FormValidator, addActivity, async(req, res) => {
-    const { id } = req.params;
+  router.delete('/slack-app-integrations/:id', loginRequiredStrictly, adminRequired, validator.deleteIntegration, apiV3FormValidator, addActivity,
+    async(req, res) => {
+      const { id } = req.params;
 
 
-    try {
-      const response = await SlackAppIntegration.findOneAndDelete({ _id: id });
+      try {
+        const response = await SlackAppIntegration.findOneAndDelete({ _id: id });
 
 
-      // update primary
-      const countOfPrimary = await SlackAppIntegration.countDocuments({ isPrimary: true });
-      if (countOfPrimary === 0) {
-        await SlackAppIntegration.updateOne({}, { isPrimary: true });
-      }
+        // update primary
+        const countOfPrimary = await SlackAppIntegration.countDocuments({ isPrimary: true });
+        if (countOfPrimary === 0) {
+          await SlackAppIntegration.updateOne({}, { isPrimary: true });
+        }
 
 
-      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_SLACK_WORKSPACE_DELETE });
+        activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_SLACK_WORKSPACE_DELETE });
 
 
-      return res.apiv3({ response });
-    }
-    catch (error) {
-      const msg = 'Error occured in deleting access token for slack app tokens';
-      logger.error('Error', error);
-      return res.apiv3Err(new ErrorV3(msg, 'update-slackAppTokens-failed'), 500);
-    }
-  });
+        return res.apiv3({ response });
+      }
+      catch (error) {
+        const msg = 'Error occured in deleting access token for slack app tokens';
+        logger.error('Error', error);
+        return res.apiv3Err(new ErrorV3(msg, 'update-slackAppTokens-failed'), 500);
+      }
+    });
 
 
   router.put('/proxy-uri', loginRequiredStrictly, adminRequired, addActivity, validator.proxyUri, apiV3FormValidator, async(req, res) => {
   router.put('/proxy-uri', loginRequiredStrictly, adminRequired, addActivity, validator.proxyUri, apiV3FormValidator, async(req, res) => {
     const { proxyUri } = req.body;
     const { proxyUri } = req.body;