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

Merge branch 'master' into support/trash-edit-fix

Yuki Takei 6 лет назад
Родитель
Сommit
22b42782ba

+ 5 - 0
.github/workflows/build-rc.yml

@@ -52,3 +52,8 @@ jobs:
         target: weseek/growi
         semver: ${{ env.SEMVER }}
         publish: true
+
+    - name: Check whether workspace is clean
+      run: |
+        STATUS=`git status --porcelain`
+        if [ -z "$STATUS" ]; then exit 0; else exit 1; fi

+ 5 - 0
.github/workflows/build.yml

@@ -66,6 +66,11 @@ jobs:
         additional-tags: 'latest'
         publish: true
 
+    - name: Check whether workspace is clean
+      run: |
+        STATUS=`git status --porcelain`
+        if [ -z "$STATUS" ]; then exit 0; else exit 1; fi
+
   publish-desc:
 
     runs-on: ubuntu-latest

+ 8 - 4
.github/workflows/ci.yml

@@ -53,12 +53,13 @@ jobs:
         yarn lint
 
     - name: Slack Notification
-      uses: homoluctus/slatify@master
+      uses: weseek/ghaction-slack-notification@master
       if: failure()
       with:
         type: ${{ job.status }}
         job_name: '*test (${{ matrix.node-version }})*'
         channel: '#ci'
+        isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
@@ -113,12 +114,13 @@ jobs:
         MONGO_URI: mongodb://localhost:27017/growi_test
 
     - name: Slack Notification
-      uses: homoluctus/slatify@master
+      uses: weseek/ghaction-slack-notification@master
       if: failure()
       with:
         type: ${{ job.status }}
         job_name: '*test (${{ matrix.node-version }})*'
         channel: '#ci'
+        isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
@@ -183,12 +185,13 @@ jobs:
         yarn build:dev
 
     - name: Slack Notification
-      uses: homoluctus/slatify@master
+      uses: weseek/ghaction-slack-notification@master
       if: failure()
       with:
         type: ${{ job.status }}
         job_name: '*build-dev (${{ matrix.node-version }})*'
         channel: '#ci'
+        isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
@@ -268,10 +271,11 @@ jobs:
         path: report
 
     - name: Slack Notification
-      uses: homoluctus/slatify@master
+      uses: weseek/ghaction-slack-notification@master
       if: failure()
       with:
         type: ${{ job.status }}
         job_name: '*build-prod (${{ matrix.node-version }})*'
         channel: '#ci'
+        isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}

+ 5 - 2
CHANGES.md

@@ -1,8 +1,11 @@
 # CHANGES
 
-## v3.7.5
+## v3.7.5-RC
 
-*
+* Fix: Draw.io diagrams rendered twice
+* Fix: Behavior of password reset modal is strange
+* Fix: Import GROWI Archive doesn't restore some data correctly
+* Fix: Attachments list on root page and users top pages
 
 ## v3.7.4
 

+ 1 - 1
package.json

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

+ 7 - 2
resource/locales/en-US/admin/admin.json

@@ -105,7 +105,7 @@
     },
     "behavior": "Behavior",
     "behavior_desc": {
-      "growi_text1": "Both of <code>/page</code> and <code>/page/</code> shows the same page",
+      "growi_text1": "Both of <code>/page</code> and <code>/page/</code> shows the same page.",
       "growi_text2": "<code>/nonexistent_page</code> shows editing form",
       "growi_text3": "All pages shows the list of sub pages <b>if using GROWI Enhanced Layout</b>",
       "crowi_text1": "<code>/page</code> shows the page",
@@ -151,7 +151,12 @@
     "import_from": "Import from {{from}}",
     "import_growi_archive": "Import GROWI Archive",
     "growi_settings": {
-      "overwrite_documents": "Imported documents will overwrite existing documents",
+      "description_of_import_mode": {
+        "about": "When you import data with the same name as an existing one, choose from the following three modes below.",
+        "insert": "Insert: Skip importing the data.",
+        "upsert": "Upsert: Overwrite and update the existing data with imported data.",
+        "flash_and_insert": "Flash and Insert: After deleting the existing data completely, import the data"
+      },
       "growi_archive_file": "GROWI Archive File",
       "uploaded_data": "Uploaded Data",
       "extracted_file": "Extracted File",

+ 2 - 0
resource/locales/en-US/translation.json

@@ -182,9 +182,11 @@
   "Update API Token": "Update API Token",
   "header_search_box": {
     "label": {
+      "All pages": "All pages",
       "This tree": "This tree"
     },
     "item_label": {
+      "All pages": "All pages",
       "This tree": "Only children of this tree"
     }
   },

+ 6 - 1
resource/locales/ja/admin/admin.json

@@ -169,7 +169,12 @@
     "import_from": "{{from}} からインポート",
     "import_growi_archive": "GROWI アーカイブをインポート",
     "growi_settings": {
-      "overwrite_documents": "インポートされたドキュメントは既存のドキュメントを上書きします",
+      "description_of_import_mode": {
+        "about": "既存のデータと同名であるデータをインポートする際の挙動は以下の3つのモードから選べます。",
+        "insert": "Insert: 当該データのインポートをスキップします。",
+        "upsert": "Upsert: 既存のデータをインポートデータで上書き更新します。",
+        "flash_and_insert": "Flash and Insert: 既存のデータを完全に削除した後、インポートを行います。"
+      },
       "growi_archive_file": "GROWI アーカイブファイル",
       "uploaded_data": "アップロードされたデータ",
       "extracted_file": "展開されたファイル",

+ 2 - 0
resource/locales/ja/translation.json

@@ -181,9 +181,11 @@
   "Update API Token": "API Tokenを更新",
   "header_search_box": {
     "label": {
+      "All pages": "全てのページ",
       "This tree": "この階層"
     },
     "item_label": {
+      "All pages": "全てのページ",
       "This tree": "この階層下の子ページのみ"
     }
   },

+ 13 - 9
src/client/js/components/Admin/ImportData/GrowiArchive/ImportForm.jsx

@@ -333,7 +333,7 @@ class ImportForm extends React.Component {
     );
   }
 
-  renderGroups(groupList, groupName, errors, { wellContent } = {}) {
+  renderGroups(groupList, groupName, errors) {
     const collectionNames = groupList.filter((collectionName) => {
       return this.allCollectionNames.includes(collectionName);
     });
@@ -345,13 +345,6 @@ class ImportForm extends React.Component {
     return (
       <div className="mt-4">
         <legend>{groupName} Collections</legend>
-        {wellContent != null && (
-          <div className="well well-sm small">
-            <ul>
-              <li>{wellContent}</li>
-            </ul>
-          </div>
-        )}
         {this.renderImportItems(collectionNames)}
         {this.renderWarnForGroups(errors, `warnFor${groupName}`)}
       </div>
@@ -464,7 +457,18 @@ class ImportForm extends React.Component {
           </div>
         </form>
 
-        {this.renderGroups(GROUPS_PAGE, 'Page', warnForPageGroups, { wellContent: t('admin:importer_management.growi_settings.overwrite_documents') })}
+        <div className="well well-sm small my-4">
+          <ul>
+            <li>{t('admin:importer_management.growi_settings.description_of_import_mode.about')}</li>
+            <ul>
+              <li>{t('admin:importer_management.growi_settings.description_of_import_mode.insert')}</li>
+              <li>{t('admin:importer_management.growi_settings.description_of_import_mode.upsert')}</li>
+              <li>{t('admin:importer_management.growi_settings.description_of_import_mode.flash_and_insert')}</li>
+            </ul>
+          </ul>
+        </div>
+
+        {this.renderGroups(GROUPS_PAGE, 'Page', warnForPageGroups)}
         {this.renderGroups(GROUPS_USER, 'User', warnForUserGroups)}
         {this.renderGroups(GROUPS_CONFIG, 'Config', warnForConfigGroups)}
         {this.renderOthers()}

+ 2 - 3
src/client/js/components/Admin/Security/LdapAuthTestModal.jsx

@@ -43,8 +43,8 @@ class LdapAuthTestModal extends React.Component {
 
     return (
       <Modal show={this.props.isOpen} onHide={this.props.onClose}>
-        <Modal.Header className="modal-header" closeButton>
-          <Modal.Title>
+        <Modal.Header className="bg-info modal-header" closeButton>
+          <Modal.Title className="text-white">
             Test LDAP Account
           </Modal.Title>
         </Modal.Header>
@@ -56,7 +56,6 @@ class LdapAuthTestModal extends React.Component {
             onChangePassword={this.onChangePassword}
           />
         </Modal.Body>
-        <Modal.Footer />
       </Modal>
     );
   }

+ 2 - 2
src/client/js/components/HeaderSearchBox.jsx

@@ -66,7 +66,7 @@ class HeaderSearchBox extends React.Component {
     const { t, appContainer } = this.props;
     const scopeLabel = this.state.isScopeChildren
       ? t('header_search_box.label.This tree')
-      : 'All pages';
+      : t('header_search_box.label.All pages');
 
     const config = appContainer.getConfig();
     const isReachable = config.isSearchServiceReachable;
@@ -76,7 +76,7 @@ class HeaderSearchBox extends React.Component {
         <InputGroup>
           <InputGroup.Button className="btn-group-dropdown-scope">
             <DropdownButton id="dbScope" title={scopeLabel}>
-              <MenuItem onClick={this.onClickAllPages}>All pages</MenuItem>
+              <MenuItem onClick={this.onClickAllPages}>{ t('header_search_box.item_label.All pages') }</MenuItem>
               <MenuItem onClick={this.onClickChildren}>{ t('header_search_box.item_label.This tree') }</MenuItem>
             </DropdownButton>
           </InputGroup.Button>

+ 6 - 0
src/client/styles/scss/_modal.scss

@@ -0,0 +1,6 @@
+.modal-body {
+  // Adjust the height by subtracting the footer and the footer
+  // show https://stackoverflow.com/questions/24166568/set-bootstrap-modal-body-height-by-percentage/26078942
+  max-height: calc(100% - 120px);
+  overflow-y: auto;
+}

+ 1 - 0
src/client/styles/scss/style-app.scss

@@ -45,6 +45,7 @@
 @import 'tag';
 @import 'staff_credit';
 @import 'draft';
+@import 'modal';
 
 /*
  * for Guest User Mode

+ 3 - 2
src/server/crowi/express-init.js

@@ -97,15 +97,16 @@ module.exports = function(crowi, app) {
   app.use(cookieParser());
 
   // configure express-session
+  const sessionMiddleware = expressSession(crowi.sessionConfig);
   app.use((req, res, next) => {
-    // test whether the route is listed in avoidSessionTroutes
+    // test whether the route is listed in avoidSessionRoutes
     for (const regex of avoidSessionRoutes) {
       if (regex.test(req.path)) {
         return next();
       }
     }
 
-    expressSession(crowi.sessionConfig)(req, res, next);
+    sessionMiddleware(req, res, next);
   });
 
   // passport

+ 13 - 14
src/server/service/import.js

@@ -97,28 +97,27 @@ class ImportService {
    * @param {any} value value from imported document
    * @param {{ document: object, schema: object, propertyName: string }}
    * @return {any} new value for the document
+   *
+   * @see https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-cast
    */
   keepOriginal(value, { document, schema, propertyName }) {
-    let _value = value;
+    // Model
+    if (schema != null && schema.path(propertyName) != null) {
+      const schemaType = schema.path(propertyName);
+      return schemaType.cast(value);
+    }
 
     // _id
     if (propertyName === '_id' && ObjectId.isValid(value)) {
-      _value = ObjectId(value);
-    }
-    // Date
-    else if (isIsoDate(value)) {
-      _value = parseISO(value);
+      return ObjectId(value);
     }
 
-    // Model
-    if (schema != null) {
-      // ObjectID
-      if (schema[propertyName] != null && schema[propertyName].instance === 'ObjectID' && ObjectId.isValid(value)) {
-        _value = ObjectId(value);
-      }
+    // Date
+    if (isIsoDate(value)) {
+      return parseISO(value);
     }
 
-    return _value;
+    return value;
   }
 
   /**
@@ -409,7 +408,7 @@ class ImportService {
    */
   convertDocuments(collectionName, document, overwriteParams) {
     const Model = this.growiBridgeService.getModelFromCollectionName(collectionName);
-    const schema = (Model != null) ? Model.schema.paths : null;
+    const schema = (Model != null) ? Model.schema : null;
     const convertMap = this.convertMap[collectionName];
 
     const _document = {};

+ 1 - 1
src/server/views/layout-growi/page_list.html

@@ -42,7 +42,7 @@
 {% endblock %}
 
 
-{% block content_footer %}
+{% block content_main_after %}
   {% if page %}
     {% include '../widget/page_attachments.html' %}
   {% endif %}

+ 4 - 0
src/server/views/layout-growi/user_page.html

@@ -71,4 +71,8 @@
 
 {% block content_main_after %}
   {% include 'widget/comments.html' %}
+
+  {% if page %}
+    {% include '../widget/page_attachments.html' %}
+  {% endif %}
 {% endblock %}

+ 1 - 1
src/server/views/layout-kibela/page_list.html

@@ -43,7 +43,7 @@
 {% endblock %}
 
 
-{% block content_footer %}
+{% block content_main_after %}
   {% if page %}
     {% include '../widget/page_attachments.html' %}
   {% endif%}

+ 4 - 0
src/server/views/layout-kibela/user_page.html

@@ -64,4 +64,8 @@
 
 {% block content_main_after %}
   {% include 'widget/comments.html' %}
+
+  {% if page %}
+    {% include '../widget/page_attachments.html' %}
+  {% endif %}
 {% endblock %}

+ 2 - 0
src/server/views/modal/rename.html

@@ -27,6 +27,7 @@
 
           <hr>
 
+          {% if page.grant != 2 %}
           <div class="checkbox checkbox-warning">
             <input name="recursively" id="cbRenameRecursively" value="1" type="checkbox" checked>
             <label for="cbRenameRecursively">
@@ -34,6 +35,7 @@
               <p class="help-block mt-0">{{ t('modal_rename.help.recursive', page.path) }}</p>
             </label>
           </div>
+          {% endif %}
 
           <div class="checkbox checkbox-success">
             <input name="create_redirect" id="cbRenameRedirect" value="1" type="checkbox">