Przeglądaj źródła

Merge branch 'master' into fix/4202-4203-add-gabage-collection

itizawa 5 lat temu
rodzic
commit
752ba6bf5c

+ 4 - 1
CHANGES.md

@@ -2,7 +2,10 @@
 
 
 ## v4.2.4
 ## v4.2.4
 
 
-* 
+* Fix: Fixed an error when creating a new page with `Ctrl-S`
+    * Introduced by v4.2.2
+* Fix: Fixed a strange diff in PageHistory due to Pagination
+* Fix: Fixed that the user group page could not be found when using api from the outside
 
 
 ## v4.2.3
 ## v4.2.3
 
 

+ 17 - 0
resource/locales/en_US/translation.json

@@ -13,6 +13,7 @@
   "Unlinked": "Unlinked",
   "Unlinked": "Unlinked",
   "Like!": "Like!",
   "Like!": "Like!",
   "Seen by": "Seen by",
   "Seen by": "Seen by",
+  "Done": "Done",
   "Cancel": "Cancel",
   "Cancel": "Cancel",
   "Create": "Create",
   "Create": "Create",
   "Admin": "Admin",
   "Admin": "Admin",
@@ -396,6 +397,22 @@
       "Post": "Post"
       "Post": "Post"
     }
     }
   },
   },
+  "link_edit": {
+    "edit_link": "Edit Link",
+    "set_link_and_label": "Set link and label",
+    "link": "Link",
+    "placeholder_of_link_input": "Input page path or URL",
+    "label": "Label",
+    "path_format": "Path format",
+    "use_relative_path": "Use relative path",
+    "use_permanent_link": "Use permanent link",
+    "notation": "Notation",
+    "markdown": "Markdown",
+    "GROWI_original": "GROWI original",
+    "pukiwiki": "Pukiwiki",
+    "preview": "Preview",
+    "page_not_found_in_preview": "\"{{path}}\" is not a GROWI page."
+  },
   "toaster": {
   "toaster": {
     "update_successed": "Succeeded to update {{target}}",
     "update_successed": "Succeeded to update {{target}}",
     "initialize_successed": "Succeeded to initialize {{target}}",
     "initialize_successed": "Succeeded to initialize {{target}}",

+ 17 - 0
resource/locales/ja_JP/translation.json

@@ -13,6 +13,7 @@
   "Unlinked": "リダイレクト削除",
   "Unlinked": "リダイレクト削除",
   "Like!": "いいね!",
   "Like!": "いいね!",
   "Seen by": "見た人",
   "Seen by": "見た人",
+  "Done": "完了",
   "Cancel": "キャンセル",
   "Cancel": "キャンセル",
   "Create": "作成",
   "Create": "作成",
   "Admin": "管理",
   "Admin": "管理",
@@ -398,6 +399,22 @@
       "Post": "投稿"
       "Post": "投稿"
     }
     }
   },
   },
+  "link_edit": {
+    "edit_link": "リンク編集",
+    "set_link_and_label": "リンク情報",
+    "link": "リンク",
+    "placeholder_of_link_input": "ページパスまたはURLを入力してください",
+    "label": "ラベル",
+    "path_format": "ページパス設定",
+    "use_relative_path": "相対パスを使う",
+    "use_permanent_link": "パーマリンクを使う",
+    "notation": "リンクの形式",
+    "markdown": "マークダウン 記法",
+    "GROWI_original": "GROWI 独自記法",
+    "pukiwiki": "Pukiwiki 記法",
+    "preview": "プレビュー",
+    "page_not_found_in_preview": "\"{{path}}\" というページはありません。"
+  },
   "toaster": {
   "toaster": {
     "update_successed": "{{target}}を更新しました",
     "update_successed": "{{target}}を更新しました",
     "initialize_successed": "{{target}}を初期化しました",
     "initialize_successed": "{{target}}を初期化しました",

+ 18 - 1
resource/locales/zh_CN/translation.json

@@ -14,7 +14,8 @@
 	"Unlinked": "Unlinked",
 	"Unlinked": "Unlinked",
 	"Like!": "Like!",
 	"Like!": "Like!",
 	"Seen by": "Seen by",
 	"Seen by": "Seen by",
-	"Cancel": "取消",
+  "Done": "Done",
+  "Cancel": "取消",
 	"Create": "创建",
 	"Create": "创建",
 	"Admin": "管理",
 	"Admin": "管理",
 	"administrator": "管理员",
 	"administrator": "管理员",
@@ -376,6 +377,22 @@
 			"Post": "提交"
 			"Post": "提交"
 		}
 		}
 	},
 	},
+  "link_edit": {
+    "edit_link": "Edit Link",
+    "set_link_and_label": "Set link and label",
+    "link": "Link",
+    "placeholder_of_link_input": "Input page path or URL",
+    "label": "Label",
+    "path_format": "Path format",
+    "use_relative_path": "Use relative path",
+    "use_permanent_link": "Use permanent link",
+    "notation": "Notation",
+    "markdown": "Markdown",
+    "GROWI_original": "GROWI original",
+    "pukiwiki": "Pukiwiki",
+    "preview": "Preview",
+    "page_not_found_in_preview": "\"{{path}}\" is not a GROWI page."
+  },
 	"toaster": {
 	"toaster": {
 		"update_successed": "Succeeded to update {{target}}",
 		"update_successed": "Succeeded to update {{target}}",
     "initialize_successed": "Succeeded to initialize {{target}}",
     "initialize_successed": "Succeeded to initialize {{target}}",

+ 25 - 18
src/client/js/components/PageEditor/LinkEditModal.jsx

@@ -11,6 +11,7 @@ import {
 
 
 import path from 'path';
 import path from 'path';
 import validator from 'validator';
 import validator from 'validator';
+import { withTranslation } from 'react-i18next';
 import PreviewWithSuspense from './PreviewWithSuspense';
 import PreviewWithSuspense from './PreviewWithSuspense';
 import PagePreviewIcon from '../Icons/PagePreviewIcon';
 import PagePreviewIcon from '../Icons/PagePreviewIcon';
 
 
@@ -147,6 +148,7 @@ class LinkEditModal extends React.PureComponent {
   }
   }
 
 
   async setMarkdown() {
   async setMarkdown() {
+    const { t } = this.props;
     const path = this.state.linkInputValue;
     const path = this.state.linkInputValue;
     let markdown = '';
     let markdown = '';
     let previewError = '';
     let previewError = '';
@@ -168,7 +170,7 @@ class LinkEditModal extends React.PureComponent {
       }
       }
     }
     }
     else {
     else {
-      previewError = `'${path}' is not a GROWI page.`;
+      previewError = t('link_edit.page_not_found_in_preview', { path });
     }
     }
     this.setState({ markdown, previewError, permalink });
     this.setState({ markdown, previewError, permalink });
   }
   }
@@ -283,22 +285,24 @@ class LinkEditModal extends React.PureComponent {
   }
   }
 
 
   renderLinkAndLabelForm() {
   renderLinkAndLabelForm() {
+    const { t } = this.props;
     return (
     return (
       <>
       <>
-        <h3 className="grw-modal-head">Set link and label</h3>
+        <h3 className="grw-modal-head">{t('link_edit.set_link_and_label')}</h3>
         <form className="form-group">
         <form className="form-group">
           <div className="form-gorup my-3">
           <div className="form-gorup my-3">
             <div className="input-group flex-nowrap">
             <div className="input-group flex-nowrap">
               <div className="input-group-prepend">
               <div className="input-group-prepend">
-                <span className="input-group-text">link</span>
+                <span className="input-group-text">{t('link_edit.link')}</span>
               </div>
               </div>
               <SearchTypeahead
               <SearchTypeahead
                 onChange={this.handleChangeTypeahead}
                 onChange={this.handleChangeTypeahead}
                 onInputChange={this.handleChangeLinkInput}
                 onInputChange={this.handleChangeLinkInput}
                 inputName="link"
                 inputName="link"
-                placeholder="Input page path or URL"
+                placeholder={t('link_edit.placeholder_of_link_input')}
                 keywordOnInit={this.state.linkInputValue}
                 keywordOnInit={this.state.linkInputValue}
                 behaviorOfResetBtn="clear"
                 behaviorOfResetBtn="clear"
+                autoFocus
               />
               />
               <div className="d-none d-sm-block input-group-append">
               <div className="d-none d-sm-block input-group-append">
                 <button type="button" id="preview-btn" className="btn btn-info btn-page-preview">
                 <button type="button" id="preview-btn" className="btn btn-info btn-page-preview">
@@ -315,7 +319,7 @@ class LinkEditModal extends React.PureComponent {
           <div className="form-gorup my-3">
           <div className="form-gorup my-3">
             <div className="input-group flex-nowrap">
             <div className="input-group flex-nowrap">
               <div className="input-group-prepend">
               <div className="input-group-prepend">
-                <span className="input-group-text">label</span>
+                <span className="input-group-text">{t('link_edit.label')}</span>
               </div>
               </div>
               <input
               <input
                 type="text"
                 type="text"
@@ -334,11 +338,12 @@ class LinkEditModal extends React.PureComponent {
   }
   }
 
 
   renderPathFormatForm() {
   renderPathFormatForm() {
+    const { t } = this.props;
     return (
     return (
       <div className="card well pt-3">
       <div className="card well pt-3">
         <form className="form-group mb-0">
         <form className="form-group mb-0">
           <div className="form-group row">
           <div className="form-group row">
-            <label className="col-sm-3">Path format</label>
+            <label className="col-sm-3">{t('link_edit.path_format')}</label>
             <div className="col-sm-9">
             <div className="col-sm-9">
               <div className="custom-control custom-checkbox custom-checkbox-info custom-control-inline">
               <div className="custom-control custom-checkbox custom-checkbox-info custom-control-inline">
                 <input
                 <input
@@ -350,7 +355,7 @@ class LinkEditModal extends React.PureComponent {
                   disabled={!this.state.linkInputValue.startsWith('/') || this.state.linkerType === Linker.types.growiLink}
                   disabled={!this.state.linkInputValue.startsWith('/') || this.state.linkerType === Linker.types.growiLink}
                 />
                 />
                 <label className="custom-control-label" htmlFor="relativePath">
                 <label className="custom-control-label" htmlFor="relativePath">
-                  Use relative path
+                  {t('link_edit.use_relative_path')}
                 </label>
                 </label>
               </div>
               </div>
               <div className="custom-control custom-checkbox custom-checkbox-info custom-control-inline">
               <div className="custom-control custom-checkbox custom-checkbox-info custom-control-inline">
@@ -363,13 +368,13 @@ class LinkEditModal extends React.PureComponent {
                   disabled={this.state.permalink === '' || this.state.linkerType === Linker.types.growiLink}
                   disabled={this.state.permalink === '' || this.state.linkerType === Linker.types.growiLink}
                 />
                 />
                 <label className="custom-control-label" htmlFor="permanentLink">
                 <label className="custom-control-label" htmlFor="permanentLink">
-                  Use permanent link
+                  {t('link_edit.use_permanent_link')}
                 </label>
                 </label>
               </div>
               </div>
             </div>
             </div>
           </div>
           </div>
           <div className="form-group row mb-0">
           <div className="form-group row mb-0">
-            <label className="col-sm-3">Notation</label>
+            <label className="col-sm-3">{t('link_edit.notation')}</label>
             <div className="col-sm-9">
             <div className="col-sm-9">
               <div className="custom-control custom-radio custom-control-inline">
               <div className="custom-control custom-radio custom-control-inline">
                 <input
                 <input
@@ -381,7 +386,7 @@ class LinkEditModal extends React.PureComponent {
                   onChange={e => this.handleSelecteLinkerType(e.target.value)}
                   onChange={e => this.handleSelecteLinkerType(e.target.value)}
                 />
                 />
                 <label className="custom-control-label" htmlFor="markdownType">
                 <label className="custom-control-label" htmlFor="markdownType">
-                  Markdown
+                  {t('link_edit.markdown')}
                 </label>
                 </label>
               </div>
               </div>
               <div className="custom-control custom-radio custom-control-inline">
               <div className="custom-control custom-radio custom-control-inline">
@@ -394,7 +399,7 @@ class LinkEditModal extends React.PureComponent {
                   onChange={e => this.handleSelecteLinkerType(e.target.value)}
                   onChange={e => this.handleSelecteLinkerType(e.target.value)}
                 />
                 />
                 <label className="custom-control-label" htmlFor="growiType">
                 <label className="custom-control-label" htmlFor="growiType">
-                  Growi original
+                  {t('link_edit.GROWI_original')}
                 </label>
                 </label>
               </div>
               </div>
               {this.isApplyPukiwikiLikeLinkerPlugin && (
               {this.isApplyPukiwikiLikeLinkerPlugin && (
@@ -408,7 +413,7 @@ class LinkEditModal extends React.PureComponent {
                     onChange={e => this.handleSelecteLinkerType(e.target.value)}
                     onChange={e => this.handleSelecteLinkerType(e.target.value)}
                   />
                   />
                   <label className="custom-control-label" htmlFor="pukiwikiType">
                   <label className="custom-control-label" htmlFor="pukiwikiType">
-                    Pukiwiki
+                    {t('link_edit.pukiwiki')}
                   </label>
                   </label>
                 </div>
                 </div>
               )}
               )}
@@ -420,10 +425,11 @@ class LinkEditModal extends React.PureComponent {
   }
   }
 
 
   render() {
   render() {
+    const { t } = this.props;
     return (
     return (
-      <Modal className="link-edit-modal" isOpen={this.state.show} toggle={this.cancel} size="lg">
+      <Modal className="link-edit-modal" isOpen={this.state.show} toggle={this.cancel} size="lg" autoFocus={false}>
         <ModalHeader tag="h4" toggle={this.cancel} className="bg-primary text-light">
         <ModalHeader tag="h4" toggle={this.cancel} className="bg-primary text-light">
-          Edit Links
+          {t('link_edit.edit_link')}
         </ModalHeader>
         </ModalHeader>
 
 
         <ModalBody className="container">
         <ModalBody className="container">
@@ -435,17 +441,17 @@ class LinkEditModal extends React.PureComponent {
           </div>
           </div>
           <div className="row">
           <div className="row">
             <div className="col-12">
             <div className="col-12">
-              <h3 className="grw-modal-head">Preview</h3>
+              <h3 className="grw-modal-head">{t('link_edit.preview')}</h3>
               {this.renderLinkPreview()}
               {this.renderLinkPreview()}
             </div>
             </div>
           </div>
           </div>
           <div className="row">
           <div className="row">
             <div className="col-12 text-center">
             <div className="col-12 text-center">
               <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={this.hide}>
               <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={this.hide}>
-                Cancel
+                {t('Cancel')}
               </button>
               </button>
               <button type="submit" className="btn btn-sm btn-primary mx-1" onClick={this.save}>
               <button type="submit" className="btn btn-sm btn-primary mx-1" onClick={this.save}>
-                Done
+                {t('Done')}
               </button>
               </button>
             </div>
             </div>
           </div>
           </div>
@@ -457,6 +463,7 @@ class LinkEditModal extends React.PureComponent {
 }
 }
 
 
 LinkEditModal.propTypes = {
 LinkEditModal.propTypes = {
+  t: PropTypes.func.isRequired,
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
   onSave: PropTypes.func,
   onSave: PropTypes.func,
@@ -467,4 +474,4 @@ LinkEditModal.propTypes = {
  */
  */
 const LinkEditModalWrapper = withUnstatedContainers(LinkEditModal, [AppContainer, PageContainer]);
 const LinkEditModalWrapper = withUnstatedContainers(LinkEditModal, [AppContainer, PageContainer]);
 
 
-export default LinkEditModalWrapper;
+export default withTranslation('translation', { withRef: true })(LinkEditModalWrapper);

+ 1 - 0
src/client/js/components/PageHistory.jsx

@@ -68,6 +68,7 @@ function PageHistory(props) {
   return (
   return (
     <div>
     <div>
       <PageRevisionList
       <PageRevisionList
+        pageHistoryContainer={pageHistoryContainer}
         revisions={revisions}
         revisions={revisions}
         diffOpened={diffOpened}
         diffOpened={diffOpened}
         getPreviousRevision={getPreviousRevision}
         getPreviousRevision={getPreviousRevision}

+ 8 - 1
src/client/js/components/PageHistory/PageRevisionList.jsx

@@ -2,6 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 
 
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
+import PageHistroyContainer from '../../services/PageHistoryContainer';
 
 
 import Revision from './Revision';
 import Revision from './Revision';
 import RevisionDiff from './RevisionDiff';
 import RevisionDiff from './RevisionDiff';
@@ -64,7 +65,7 @@ class PageRevisionList extends React.Component {
   }
   }
 
 
   render() {
   render() {
-    const { t } = this.props;
+    const { t, pageHistoryContainer } = this.props;
 
 
     const revisions = this.props.revisions;
     const revisions = this.props.revisions;
     const revisionCount = this.props.revisions.length;
     const revisionCount = this.props.revisions.length;
@@ -72,6 +73,11 @@ class PageRevisionList extends React.Component {
     let hasDiffPrev;
     let hasDiffPrev;
 
 
     const revisionList = this.props.revisions.map((revision, idx) => {
     const revisionList = this.props.revisions.map((revision, idx) => {
+      // Returns null because the last revision is for the bottom diff display
+      if (idx === pageHistoryContainer.state.pagingLimit) {
+        return null;
+      }
+
       let previousRevision;
       let previousRevision;
       if (idx + 1 < revisionCount) {
       if (idx + 1 < revisionCount) {
         previousRevision = revisions[idx + 1];
         previousRevision = revisions[idx + 1];
@@ -117,6 +123,7 @@ class PageRevisionList extends React.Component {
 
 
 PageRevisionList.propTypes = {
 PageRevisionList.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   t: PropTypes.func.isRequired, // i18next
+  pageHistoryContainer: PropTypes.instanceOf(PageHistroyContainer).isRequired,
 
 
   revisions: PropTypes.array,
   revisions: PropTypes.array,
   diffOpened: PropTypes.object,
   diffOpened: PropTypes.object,

+ 3 - 3
src/client/js/components/SearchTypeahead.jsx

@@ -44,9 +44,6 @@ class SearchTypeahead extends React.Component {
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {
-    // **MEMO** This doesn't work at this time -- 2019.05.13 Yuki Takei
-    // It is needed to use Modal component of react-bootstrap when showing Move/Duplicate/CreateNewPage modals
-    // this.typeahead.getInstance().focus();
   }
   }
 
 
   componentWillUnmount() {
   componentWillUnmount() {
@@ -222,6 +219,7 @@ class SearchTypeahead extends React.Component {
           renderMenuItemChildren={this.renderMenuItemChildren}
           renderMenuItemChildren={this.renderMenuItemChildren}
           caseSensitive={false}
           caseSensitive={false}
           defaultSelected={defaultSelected}
           defaultSelected={defaultSelected}
+          autoFocus={this.props.autoFocus}
           onBlur={this.props.onBlur}
           onBlur={this.props.onBlur}
           onFocus={this.props.onFocus}
           onFocus={this.props.onFocus}
         />
         />
@@ -256,6 +254,7 @@ SearchTypeahead.propTypes = {
   placeholder:     PropTypes.string,
   placeholder:     PropTypes.string,
   keywordOnInit:   PropTypes.string,
   keywordOnInit:   PropTypes.string,
   helpElement:     PropTypes.object,
   helpElement:     PropTypes.object,
+  autoFocus:       PropTypes.bool,
   behaviorOfResetBtn: PropTypes.oneOf(['restore', 'clear']),
   behaviorOfResetBtn: PropTypes.oneOf(['restore', 'clear']),
 };
 };
 
 
@@ -269,6 +268,7 @@ SearchTypeahead.defaultProps = {
   placeholder:     '',
   placeholder:     '',
   keywordOnInit:   '',
   keywordOnInit:   '',
   behaviorOfResetBtn: 'restore',
   behaviorOfResetBtn: 'restore',
+  autoFocus:       false,
   onInputChange: () => {},
   onInputChange: () => {},
 };
 };
 
 

+ 2 - 2
src/client/js/services/PageContainer.js

@@ -469,9 +469,9 @@ export default class PageContainer extends Container {
     });
     });
 
 
     const res = await this.appContainer.apiv3Post('/pages/', params);
     const res = await this.appContainer.apiv3Post('/pages/', params);
-    const { page, tags } = res.data;
+    const { page, tags, revision } = res.data;
 
 
-    return { page, tags };
+    return { page, tags, revision };
   }
   }
 
 
   async updatePage(pageId, revisionId, markdown, tmpParams) {
   async updatePage(pageId, revisionId, markdown, tmpParams) {

+ 13 - 4
src/client/js/services/PageHistoryContainer.js

@@ -28,7 +28,7 @@ export default class PageHistoryContainer extends Container {
 
 
       totalPages: 0,
       totalPages: 0,
       activePage: 1,
       activePage: 1,
-      pagingLimit: Infinity,
+      pagingLimit: 10,
     };
     };
 
 
     this.retrieveRevisions = this.retrieveRevisions.bind(this);
     this.retrieveRevisions = this.retrieveRevisions.bind(this);
@@ -50,25 +50,34 @@ export default class PageHistoryContainer extends Container {
    */
    */
   async retrieveRevisions(selectedPage) {
   async retrieveRevisions(selectedPage) {
     const { pageId, shareLinkId } = this.pageContainer.state;
     const { pageId, shareLinkId } = this.pageContainer.state;
+    const { pagingLimit } = this.state;
     const page = selectedPage;
     const page = selectedPage;
+    const pagingLimitForApiParam = pagingLimit + 1;
 
 
     if (!pageId) {
     if (!pageId) {
       return;
       return;
     }
     }
 
 
+    // Get one more for the bottom display
     const res = await this.appContainer.apiv3Get('/revisions/list', {
     const res = await this.appContainer.apiv3Get('/revisions/list', {
-      pageId, shareLinkId, page,
+      pageId, shareLinkId, page, limit: pagingLimitForApiParam,
     });
     });
     const rev = res.data.docs;
     const rev = res.data.docs;
     // set Pagination state
     // set Pagination state
     this.setState({
     this.setState({
       activePage: selectedPage,
       activePage: selectedPage,
       totalPages: res.data.totalDocs,
       totalPages: res.data.totalDocs,
-      pagingLimit: res.data.limit,
+      pagingLimit,
     });
     });
 
 
     const diffOpened = {};
     const diffOpened = {};
-    const lastId = rev.length - 1;
+
+    let lastId = rev.length - 1;
+
+    // If the number of rev count is the same, the last rev is for diff display, so exclude it.
+    if (rev.length > pagingLimit) {
+      lastId = rev.length - 2;
+    }
 
 
     res.data.docs.forEach((revision, i) => {
     res.data.docs.forEach((revision, i) => {
       const user = revision.author;
       const user = revision.author;

+ 2 - 2
src/server/middlewares/access-token-parser.js

@@ -1,4 +1,5 @@
 const loggerFactory = require('@alias/logger');
 const loggerFactory = require('@alias/logger');
+const { serializeUserSecurely } = require('../models/serializers/user-serializer');
 
 
 const logger = loggerFactory('growi:middleware:access-token-parser');
 const logger = loggerFactory('growi:middleware:access-token-parser');
 
 
@@ -23,8 +24,7 @@ module.exports = (crowi) => {
     }
     }
 
 
     // transforming attributes
     // transforming attributes
-    // see User model
-    req.user = user.toObject();
+    req.user = serializeUserSecurely(user);
     req.skipCsrfVerify = true;
     req.skipCsrfVerify = true;
 
 
     logger.debug('Access token parsed: skipCsrfVerify');
     logger.debug('Access token parsed: skipCsrfVerify');

+ 1 - 1
src/server/models/user-group-relation.js

@@ -139,7 +139,7 @@ class UserGroupRelation {
    * @returns {Promise<ObjectId[]>}
    * @returns {Promise<ObjectId[]>}
    */
    */
   static async findAllUserGroupIdsRelatedToUser(user) {
   static async findAllUserGroupIdsRelatedToUser(user) {
-    const relations = await this.find({ relatedUser: user.id })
+    const relations = await this.find({ relatedUser: user._id })
       .select('relatedGroup')
       .select('relatedGroup')
       .exec();
       .exec();
 
 

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

@@ -119,6 +119,7 @@ module.exports = (crowi) => {
   const userNotificationService = crowi.getUserNotificationService();
   const userNotificationService = crowi.getUserNotificationService();
 
 
   const { serializePageSecurely } = require('../../models/serializers/page-serializer');
   const { serializePageSecurely } = require('../../models/serializers/page-serializer');
+  const { serializeRevisionSecurely } = require('../../models/serializers/revision-serializer');
 
 
   const validator = {
   const validator = {
     createPage: [
     createPage: [
@@ -229,7 +230,11 @@ module.exports = (crowi) => {
 
 
     const savedTags = await saveTagsAction({ createdPage, pageTags });
     const savedTags = await saveTagsAction({ createdPage, pageTags });
 
 
-    const result = { page: serializePageSecurely(createdPage), tags: savedTags };
+    const result = {
+      page: serializePageSecurely(createdPage),
+      tags: savedTags,
+      revision: serializeRevisionSecurely(createdPage.revision),
+    };
 
 
     // update scopes for descendants
     // update scopes for descendants
     if (overwriteScopesOfDescendants) {
     if (overwriteScopesOfDescendants) {