Browse Source

Merge branch 'master' into feat/growi-bot

Yuki Takei 5 years ago
parent
commit
912813c936

+ 12 - 1
CHANGES.md

@@ -1,10 +1,21 @@
 # CHANGES
 
-## v4.2.15-EC
+## v4.2.16-RC
 
 * Support: Update libs
     * eslint-config-weseek
 
+## v4.2.15
+
+* Improvement: toastr location for editing
+* Improvement: Handsontable with static backdrop to prevent from closing when backdrop is clicked
+* Fix: Accept invalid page path like `..%2f`
+* Fix: Pages updated date is corrupted after recursive operation
+    * Introduced by v4.2.8
+* Support: Upgrade libs
+    * reactstrap
+
+
 ## v4.2.14
 
 * Feature: Add an option to restrict publishing email property for new users

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "4.2.15-RC",
+  "version": "4.2.16-RC",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",

+ 2 - 1
packages/app-for-hoisting/package.json

@@ -144,6 +144,7 @@
     "i18next-browser-languagedetector": "^4.0.1",
     "imports-loader": "^0.8.0",
     "jest": "^25.1.0",
+    "jest-date-mock": "^1.0.8",
     "jquery-slimscroll": "^1.3.8",
     "jquery-ui": "^1.12.1",
     "jquery.cookie": "~1.4.1",
@@ -182,7 +183,7 @@
     "react-hotkeys": "^2.0.0",
     "react-i18next": "^11.1.0",
     "react-waypoint": "^9.0.0",
-    "reactstrap": "^8.0.1",
+    "reactstrap": "^8.9.0",
     "replacestream": "^4.0.3",
     "reveal.js": "^3.5.0",
     "rs-i18n": "^0.0.9",

+ 2 - 1
packages/app/package.json

@@ -144,6 +144,7 @@
     "i18next-browser-languagedetector": "^4.0.1",
     "imports-loader": "^0.8.0",
     "jest": "^25.1.0",
+    "jest-date-mock": "^1.0.8",
     "jquery-slimscroll": "^1.3.8",
     "jquery-ui": "^1.12.1",
     "jquery.cookie": "~1.4.1",
@@ -182,7 +183,7 @@
     "react-hotkeys": "^2.0.0",
     "react-i18next": "^11.1.0",
     "react-waypoint": "^9.0.0",
-    "reactstrap": "^8.0.1",
+    "reactstrap": "^8.9.0",
     "replacestream": "^4.0.3",
     "reveal.js": "^3.5.0",
     "rs-i18n": "^0.0.9",

+ 8 - 1
src/client/js/components/PageEditor/HandsontableModal.jsx

@@ -428,7 +428,14 @@ export default class HandsontableModal extends React.PureComponent {
     );
 
     return (
-      <Modal isOpen={this.state.show} toggle={this.cancel} size="lg" className={`handsontable-modal ${this.state.isWindowExpanded && 'grw-modal-expanded'}`}>
+      <Modal
+        isOpen={this.state.show}
+        toggle={this.cancel}
+        backdrop="static"
+        keyboard={false}
+        size="lg"
+        className={`handsontable-modal ${this.state.isWindowExpanded && 'grw-modal-expanded'}`}
+      >
         <ModalHeader tag="h4" toggle={this.cancel} close={buttons} className="bg-primary text-light">
           Edit Table
         </ModalHeader>

+ 4 - 0
src/client/styles/scss/_on-edit.scss

@@ -76,6 +76,10 @@ body.on-edit {
     display: none;
   }
 
+  .toast-top-right {
+    top: 64px;
+  }
+
   /*****************
    * Expand Editor
    *****************/

+ 13 - 0
src/client/styles/scss/_override-bootstrap.scss

@@ -133,6 +133,19 @@
     border-top: 1px solid #e5e5e5;
   }
 
+  // When fading in the modal, animate it to slide down
+  .modal.fade .modal-dialog {
+    @include transition($modal-transition);
+    transform: $modal-fade-transform;
+  }
+  .modal.show .modal-dialog {
+    transform: $modal-show-transform;
+  }
+  // When trying to close, animate focus to scale
+  .modal.modal-static .modal-dialog {
+    transform: $modal-scale-transform;
+  }
+
   // col-form-label (substitute for control-label of bootstrap3)
   .col-form-label {
     text-align: right;

+ 3 - 1
src/server/models/page.js

@@ -533,7 +533,9 @@ module.exports = function(crowi) {
       /\s+\/\s+/, // avoid miss in renaming
       /.+\/edit$/,
       /.+\.md$/,
-      /^\/(installer|register|login|logout|admin|me|files|trash|paste|comments|tags)(\/.*|$)/,
+      /^(\.\.)$/, // see: https://github.com/weseek/growi/issues/3582
+      /(\/\.\.)\/?/, // see: https://github.com/weseek/growi/issues/3582
+      /^\/(installer|register|login|logout|admin|me|files|trash|paste|comments|tags|share)(\/.*|$)/,
     ];
 
     let isCreatable = true;

+ 1 - 1
src/server/service/page.js

@@ -104,7 +104,7 @@ class PageService {
       if (updateMetadata) {
         unorderedBulkOp
           .find({ _id: page._id })
-          .update({ $set: { path: newPagePath, lastUpdateUser: user._id, updatedAt: Date.now().toISOString() } });
+          .update({ $set: { path: newPagePath, lastUpdateUser: user._id, updatedAt: new Date() } });
       }
       else {
         unorderedBulkOp.find({ _id: page._id }).update({ $set: { path: newPagePath } });

+ 6 - 0
src/test/models/page.test.js

@@ -193,6 +193,12 @@ describe('Page', () => {
 
       expect(Page.isCreatableName('/hoge/xx.md')).toBeFalsy();
 
+      // relative path
+      expect(Page.isCreatableName('/..')).toBeFalsy();
+      expect(Page.isCreatableName('/../page')).toBeFalsy();
+      expect(Page.isCreatableName('/page/..')).toBeFalsy();
+      expect(Page.isCreatableName('/page/../page')).toBeFalsy();
+
       // start with https?
       expect(Page.isCreatableName('/http://demo.growi.org/hoge')).toBeFalsy();
       expect(Page.isCreatableName('/https://demo.growi.org/hoge')).toBeFalsy();

+ 5 - 2
src/test/service/page.test.js

@@ -1,4 +1,6 @@
 /* eslint-disable no-unused-vars */
+import { advanceTo } from 'jest-date-mock';
+
 const mongoose = require('mongoose');
 
 const { getInstance } = require('../setup-crowi');
@@ -236,11 +238,12 @@ describe('PageService', () => {
   describe('rename page', () => {
     let pageEventSpy;
     let renameDescendantsWithStreamSpy;
-    const dateToUse = new Date('2000-01-01');
+    // mock new Date() and Date.now()
+    advanceTo(new Date(2000, 1, 1, 0, 0, 0));
+    const dateToUse = new Date();
     const socketClientId = null;
 
     beforeEach(async(done) => {
-      jest.spyOn(global.Date, 'now').mockImplementation(() => dateToUse);
       pageEventSpy = jest.spyOn(crowi.pageService.pageEvent, 'emit').mockImplementation();
       renameDescendantsWithStreamSpy = jest.spyOn(crowi.pageService, 'renameDescendantsWithStream').mockImplementation();
       done();