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

Merge branch 'master' into feat/3176-grid-edit-modal-for-master-merge

yusuketk 5 лет назад
Родитель
Сommit
6dd75e8239

+ 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
 
 

+ 2 - 1
src/client/js/components/PageEditor/LinkEditModal.jsx

@@ -299,6 +299,7 @@ class LinkEditModal extends React.PureComponent {
                 placeholder="Input page path or URL"
                 placeholder="Input page path or URL"
                 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">
@@ -421,7 +422,7 @@ class LinkEditModal extends React.PureComponent {
 
 
   render() {
   render() {
     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
           Edit Links
         </ModalHeader>
         </ModalHeader>

+ 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,

+ 25 - 0
src/client/js/components/SearchForm.jsx

@@ -13,10 +13,13 @@ class SearchForm extends React.Component {
 
 
     this.state = {
     this.state = {
       searchError: null,
       searchError: null,
+      isShownHelp: false,
     };
     };
 
 
     this.onSearchError = this.onSearchError.bind(this);
     this.onSearchError = this.onSearchError.bind(this);
     this.onChange = this.onChange.bind(this);
     this.onChange = this.onChange.bind(this);
+    this.onBlur = this.onBlur.bind(this);
+    this.onFocus = this.onFocus.bind(this);
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {
@@ -40,12 +43,28 @@ class SearchForm extends React.Component {
     }
     }
   }
   }
 
 
+  onBlur() {
+    this.setState({
+      isShownHelp: false,
+    });
+
+    this.getHelpElement();
+  }
+
+  onFocus() {
+    this.setState({
+      isShownHelp: true,
+    });
+  }
+
   getHelpElement() {
   getHelpElement() {
     const { t, appContainer } = this.props;
     const { t, appContainer } = this.props;
+    const { isShownHelp } = this.state;
 
 
     const config = appContainer.getConfig();
     const config = appContainer.getConfig();
     const isReachable = config.isSearchServiceReachable;
     const isReachable = config.isSearchServiceReachable;
 
 
+
     if (!isReachable) {
     if (!isReachable) {
       return (
       return (
         <>
         <>
@@ -55,6 +74,10 @@ class SearchForm extends React.Component {
       );
       );
     }
     }
 
 
+    if (!isShownHelp) {
+      return null;
+    }
+
     return (
     return (
       <table className="table grw-search-table search-help m-0">
       <table className="table grw-search-table search-help m-0">
         <caption className="text-left text-primary p-2">
         <caption className="text-left text-primary p-2">
@@ -124,6 +147,8 @@ class SearchForm extends React.Component {
         placeholder={placeholder}
         placeholder={placeholder}
         helpElement={this.getHelpElement()}
         helpElement={this.getHelpElement()}
         keywordOnInit={this.props.keyword}
         keywordOnInit={this.props.keyword}
+        onBlur={this.onBlur}
+        onFocus={this.onFocus}
       />
       />
     );
     );
   }
   }

+ 7 - 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,9 @@ 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}
+          onFocus={this.props.onFocus}
         />
         />
         {resetFormButton}
         {resetFormButton}
       </div>
       </div>
@@ -244,6 +244,8 @@ SearchTypeahead.propTypes = {
   onSearchSuccess: PropTypes.func,
   onSearchSuccess: PropTypes.func,
   onSearchError:   PropTypes.func,
   onSearchError:   PropTypes.func,
   onChange:        PropTypes.func,
   onChange:        PropTypes.func,
+  onBlur:          PropTypes.func,
+  onFocus:         PropTypes.func,
   onSubmit:        PropTypes.func,
   onSubmit:        PropTypes.func,
   onInputChange:   PropTypes.func,
   onInputChange:   PropTypes.func,
   inputName:       PropTypes.string,
   inputName:       PropTypes.string,
@@ -252,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']),
 };
 };
 
 
@@ -265,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) {