Browse Source

Merge pull request #1093 from weseek/master

release v3.5.1
Yuki Takei 6 years ago
parent
commit
4ecf1e9db6

+ 0 - 16
.babelrc

@@ -1,16 +0,0 @@
-{
-  "plugins": [
-    "lodash",
-    ["transform-runtime", {
-      "regenerator": true
-    }]
-  ],
-  "presets": [
-    ["env", {
-      "targets": {
-        "browsers": ["last 2 versions"]
-      }
-    }],
-    "react"
-  ]
-}

+ 20 - 1
CHANGES.md

@@ -1,6 +1,6 @@
 # CHANGES
 
-## 3.5.0-RC
+## 3.5.1-RC
 
 ### BREAKING CHANGES
 
@@ -8,6 +8,13 @@
     * Protection system with Basic Authentication
     * Crowi Classic Authentication Mechanism
     * [Crowi Template syntax](https://medium.com/crowi-book/crowi-v1-5-0-5a62e7c6be90)
+    * GROWI Plugins with schema version 2
+        * Upgrade [weseek/growi-plugin-lsx](https://github.com/weseek/growi-plugin-lsx) to v3.0.0 or above
+        * Upgrade [weseek/growi-plugin-pukiwiki-like-linker
+](https://github.com/weseek/growi-plugin-pukiwiki-like-linker
+) to v3.0.0 or above
+* The restriction mode of the root page (`/`) will be set 'Public'
+* The restriction mode of the root page (`/`) can not be changed after v 3.5.1
 
 Upgrading Guide: https://docs.growi.org/guide/upgrading/35x.html
 
@@ -17,18 +24,28 @@ Upgrading Guide: https://docs.growi.org/guide/upgrading/35x.html
 * Feature: OpenID Connect authentication
 * Feature: HTTP Basic authentication
 * Feature: Staff Credits with [Konami Code](https://en.wikipedia.org/wiki/Konami_Code)
+* Feature: Restricte Complete Deletion of Pages
 * Improvement Draft list
 * Fix: Deleting page completely
 * Fix: Search with `prefix:` param with CJK pathname
+* Fix: Could not edit UserGroup even if `PUBLIC_WIKI_ONLY` is not set
 * I18n: User Management Details
 * I18n: Group Management Details
 * Support: Apply unstated
+* Support: Use Babel 7
+* Support: Support plugins with schema version 3
 * Support: Abolish Old Config API
 * Support: Apply Jest for Tests
 * Support: Upgrade libs
     * async
     * axios
     * connect-mongo
+    * css-loader
+    * eslint
+    * eslint-config-weseek
+    * eslint-plugin-import
+    * eslint-plugin-jest
+    * eslint-plugin-react
     * file-loader
     * googleapis
     * i18next
@@ -39,6 +56,8 @@ Upgrading Guide: https://docs.growi.org/guide/upgrading/35x.html
     * mongoose-unique-validator
     * null-loader
 
+## 3.5.0 (Missing number)
+
 ## 3.4.7
 
 * Improvement: Handle private pages on group deletion

+ 23 - 0
babel.config.js

@@ -0,0 +1,23 @@
+module.exports = function(api) {
+  api.cache(true);
+
+  const presets = [
+    [
+      '@babel/preset-env',
+      {
+        targets: {
+          node: 'current',
+        },
+      },
+    ],
+    '@babel/preset-react',
+  ];
+  const plugins = [
+    'lodash',
+  ];
+
+  return {
+    presets,
+    plugins,
+  };
+};

+ 6 - 1
bin/generate-plugin-definitions-source.js

@@ -4,13 +4,14 @@
  * @author Yuki Takei <yuki@weseek.co.jp>
  */
 require('module-alias/register');
+const logger = require('@alias/logger')('growi:bin:generate-plugin-definitions-source');
 
 const fs = require('graceful-fs');
 const normalize = require('normalize-path');
 const swig = require('swig-templates');
 
 const helpers = require('@commons/util/helpers');
-const PluginUtils = require('../src/server/plugins/plugin-utils');
+const PluginUtils = require('@server/plugins/plugin-utils');
 
 const pluginUtils = new PluginUtils();
 
@@ -20,12 +21,16 @@ const OUT = helpers.root('tmp/plugins/plugin-definitions.js');
 
 // list plugin names
 let pluginNames = pluginUtils.listPluginNames(helpers.root());
+logger.info('Detected plugins: ', pluginNames);
+
 // add from PLUGIN_NAMES_TOBE_LOADED when development
 if (process.env.NODE_ENV === 'development'
     && process.env.PLUGIN_NAMES_TOBE_LOADED !== undefined
     && process.env.PLUGIN_NAMES_TOBE_LOADED.length > 0) {
   const pluginNamesDev = process.env.PLUGIN_NAMES_TOBE_LOADED.split(',');
 
+  logger.info('Detected plugins from PLUGIN_NAMES_TOBE_LOADED: ', pluginNamesDev);
+
   // merge and remove duplicates
   if (pluginNamesDev.length > 0) {
     pluginNames = pluginNames.concat(pluginNamesDev);

+ 1 - 1
bin/templates/plugin-definitions.js.swig

@@ -8,7 +8,7 @@ module.exports = [
     meta: require('{{ definition.name }}'),
     entries: [
       {% for entryPath in definition.entries %}
-      require('{{ entryPath }}'),
+      require('{{ entryPath }}').default,
       {% endfor %}
     ]
   },

+ 3 - 2
config/webpack.common.js

@@ -125,6 +125,7 @@ module.exports = (options) => {
 
       // ignore
       new webpack.IgnorePlugin(/^\.\/lib\/deflate\.js/, /markdown-it-plantuml/),
+      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
 
       new LodashModuleReplacementPlugin({
         flattening: true,
@@ -155,7 +156,7 @@ module.exports = (options) => {
             enforce: true,
           },
           commons: {
-            test: /src[\\/].*\.jsx?$/,
+            test: /(src|resource)[\\/].*\.(js|jsx|json)$/,
             chunks: 'initial',
             name: 'js/commons',
             minChunks: 2,
@@ -163,7 +164,7 @@ module.exports = (options) => {
             priority: 20,
           },
           vendors: {
-            test: /node_modules[\\/].*\.jsx?$/,
+            test: /node_modules[\\/].*\.(js|jsx|json)$/,
             chunks: (chunk) => {
               // ignore patterns
               return chunk.name != null && !chunk.name.match(/legacy-presentation|ie11-polyfill|hackmd-/);

+ 4 - 2
config/webpack.dev.dll.js

@@ -11,21 +11,23 @@ module.exports = {
     dlls: [
       // Libraries
       'axios',
-      'babel-polyfill',
       'browser-bunyan', 'bunyan-format',
       'codemirror', 'react-codemirror2',
       'date-fns',
       'diff2html',
       'debug',
       'entities',
+      'growi-commons',
       'i18next', 'i18next-browser-languagedetector',
       'jquery-slimscroll',
       'lodash', 'pako',
       'markdown-it', 'csv-to-markdown-table',
       'react', 'react-dom',
-      'react-bootstrap', 'react-bootstrap-typeahead', 'react-i18next', 'react-dropzone', 'react-copy-to-clipboard',
+      'react-bootstrap', 'react-bootstrap-typeahead',
+      'react-i18next', 'react-dropzone', 'react-hotkeys', 'react-copy-to-clipboard', 'react-waypoint',
       'socket.io-client',
       'toastr',
+      'unstated',
       'xss',
     ],
   },

+ 18 - 23
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "3.5.0-RC",
+  "version": "3.5.1-RC",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",
@@ -32,8 +32,8 @@
     "clean:report": "rimraf -- report",
     "clean": "npm-run-all -p clean:*",
     "heroku-postbuild": "sh bin/heroku/install-plugins.sh && npm run build:prod",
-    "lint:js:fix": "eslint **/*.{js,jsx} --fix",
-    "lint:js": "eslint **/*.{js,jsx}",
+    "lint:js:fix": "eslint \"**/*.{js,jsx}\" --fix",
+    "lint:js": "eslint \"**/*.{js,jsx}\"",
     "lint:styles:fix": "prettier-stylelint --quiet --write src/client/styles/scss/**/*.scss",
     "lint:styles": "stylelint src/client/styles/scss/**/*.scss",
     "lint": "npm-run-all -p lint:js lint:styles",
@@ -121,8 +121,6 @@
     "passport-local": "^1.0.0",
     "passport-saml": "^1.0.0",
     "passport-twitter": "^1.0.4",
-    "react-dropzone": "^10.1.3",
-    "react-hotkeys": "^1.1.4",
     "rimraf": "^2.6.1",
     "slack-node": "^0.1.8",
     "socket.io": "^2.0.3",
@@ -135,16 +133,15 @@
   },
   "devDependencies": {
     "@alienfast/i18next-loader": "^1.0.16",
+    "@babel/core": "^7.4.5",
+    "@babel/polyfill": "^7.4.4",
+    "@babel/preset-env": "^7.4.5",
+    "@babel/preset-react": "^7.0.0",
     "@handsontable/react": "^2.0.0",
     "autoprefixer": "^9.0.0",
-    "babel-core": "^6.25.0",
     "babel-eslint": "^10.0.1",
-    "babel-loader": "^7.1.1",
-    "babel-plugin-lodash": "^3.3.2",
-    "babel-plugin-transform-runtime": "^6.23.0",
-    "babel-polyfill": "^6.26.0",
-    "babel-preset-env": "^1.6.0",
-    "babel-preset-react": "^6.24.1",
+    "babel-loader": "^8.0.6",
+    "babel-plugin-lodash": "^3.3.4",
     "bootstrap-sass": "^3.4.1",
     "bootstrap-select": "^1.12.4",
     "browser-bunyan": "^1.3.0",
@@ -155,16 +152,17 @@
     "colors": "^1.2.5",
     "commander": "^2.11.0",
     "connect-browser-sync": "^2.1.0",
-    "css-loader": "^1.0.0",
+    "core-js": "^2.6.9",
+    "css-loader": "^3.0.0",
     "csv-to-markdown-table": "^0.5.0",
     "date-fns": "^1.29.0",
     "diff2html": "^2.3.3",
     "eazy-logger": "^3.0.2",
-    "eslint": "^5.15.1",
-    "eslint-config-weseek": "^1.0.1",
-    "eslint-plugin-import": "^2.16.0",
-    "eslint-plugin-jest": "^22.6.4",
-    "eslint-plugin-react": "^7.12.4",
+    "eslint": "^6.0.1",
+    "eslint-config-weseek": "^1.0.2",
+    "eslint-plugin-import": "^2.18.0",
+    "eslint-plugin-jest": "^22.7.1",
+    "eslint-plugin-react": "^7.14.2",
     "file-loader": "^4.0.0",
     "handsontable": "^6.0.1",
     "i18next-browser-languagedetector": "^3.0.1",
@@ -190,7 +188,6 @@
     "morgan": "^1.9.0",
     "node-dev": "^4.0.0",
     "node-sass": "^4.11.0",
-    "nodelist-foreach-polyfill": "^1.2.0",
     "normalize-path": "^3.0.0",
     "null-loader": "^3.0.0",
     "on-headers": "^1.0.1",
@@ -205,7 +202,9 @@
     "react-codemirror2": "^6.0.0",
     "react-copy-to-clipboard": "^5.0.1",
     "react-dom": "^16.8.3",
+    "react-dropzone": "^10.1.3",
     "react-frame-component": "^4.0.0",
+    "react-hotkeys": "^1.1.4",
     "react-i18next": "^10.6.1",
     "react-waypoint": "^9.0.0",
     "replacestream": "^4.0.3",
@@ -226,10 +225,6 @@
     "webpack-cli": "^3.2.3",
     "webpack-merge": "^4.2.1"
   },
-  "resolutions": {
-    "//": "see https://github.com/facebook/jest/issues/8155",
-    "babel-jest": "23.6.0"
-  },
   "_moduleAliases": {
     "@root": ".",
     "@commons": "src/lib",

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

@@ -510,8 +510,9 @@
       "group_search_base_DN_detail": "The base DN from which to search for groups. If defined, also <code>Group Search Filter</code> must be defined for the search to work.",
       "group_search_filter": "Group Search Filter",
       "group_search_filter_detail1": "The query used to filter for groups.",
-      "group_search_filter_detail2": "Use <code>&#123;&#123;dn&#125;&#125;</code> to have it replaced of the found user object.",
-      "group_search_filter_detail3": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> hits the groups which has <code>cn=group1</code> and <code>memberUid</code> includes the user's <code>uid</code>(when <code>Group DN Property</code> is not changed from the default value.)",
+      "group_search_filter_detail2": "Login via LDAP is accepted only when this query hits one or more groups.",
+      "group_search_filter_detail3": "Use <code>&#123;&#123;dn&#125;&#125;</code> to have it replaced of the found user object.",
+      "group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> hits the groups which has <code>cn=group1</code> and <code>memberUid</code> includes the user's <code>uid</code>(when <code>Group DN Property</code> is not changed from the default value.)",
       "group_search_user_DN_property": "User DN Property",
       "group_search_user_DN_property_detail": "The property of user object to use in <code>&#123;&#123;dn&#125;&#125;</code> interpolation of <code>Group Search Filter</code>.",
       "test_config": "Test Saved Configuration"

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

@@ -506,8 +506,9 @@
       "group_search_base_DN_detail": "グループ検索を実行するベース DN。利用する場合は <code>グループ検索フィルター</code> も入力する必要があります。",
       "group_search_filter": "グループ検索フィルター",
       "group_search_filter_detail1": "グループフィルターに用いるクエリ",
-      "group_search_filter_detail2": "ログイン対象ユーザーオブジェクトのプロパティーで置換する場合は <code>&#123;&#123;dn&#125;&#125;</code> を用いてください。",
-      "group_search_filter_detail3": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> は <code>cn=group1</code> と、ユーザーの <code>uid</code> を含む <code>memberUid</code> を持つグループにヒットします(<code>ユーザーの DN プロパティー</code> がデフォルトから変更されていない場合)",
+      "group_search_filter_detail2": "このクエリにヒットするグループがあったときのみ、LDAPでのログインが成功します。",
+      "group_search_filter_detail3": "ログイン対象ユーザーオブジェクトのプロパティーで置換する場合は <code>&#123;&#123;dn&#125;&#125;</code> を用いてください。",
+      "group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> は <code>cn=group1</code> と、ユーザーの <code>uid</code> を含む <code>memberUid</code> を持つグループにヒットします(<code>ユーザーの DN プロパティー</code> がデフォルトから変更されていない場合)",
       "group_search_user_DN_property": "ユーザーの DN プロパティー",
       "group_search_user_DN_property_detail": "<code>グループ検索フィルター</code> 内の <code>&#123;&#123;dn&#125;&#125;</code> で置換される、ユーザーオブジェクトのプロパティー",
       "test_config": "ログインテスト"

+ 29 - 25
src/client/js/components/InstallerForm.jsx

@@ -1,8 +1,12 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+
 import i18next from 'i18next';
 import { withTranslation } from 'react-i18next';
 
+import FormGroup from 'react-bootstrap/es/FormGroup';
+import Radio from 'react-bootstrap/es/Radio';
+
 class InstallerForm extends React.Component {
 
   constructor(props) {
@@ -10,6 +14,7 @@ class InstallerForm extends React.Component {
 
     this.state = {
       isValidUserName: true,
+      checkedBtn: 'en-US',
     };
     this.checkUserName = this.checkUserName.bind(this);
   }
@@ -32,6 +37,7 @@ class InstallerForm extends React.Component {
 
   changeLanguage(locale) {
     i18next.changeLanguage(locale);
+    this.setState({ checkedBtn: locale });
   }
 
   render() {
@@ -40,6 +46,8 @@ class InstallerForm extends React.Component {
       ? ''
       : <span><i className="icon-fw icon-ban" />{ this.props.t('installer.unavaliable_user_id') }</span>;
 
+    const checkedBtn = this.state.checkedBtn;
+
     return (
       <div className={`login-dialog p-t-10 p-b-10 col-sm-offset-4 col-sm-4${hasErrorClass}`}>
         <p className="alert alert-success">
@@ -48,30 +56,26 @@ class InstallerForm extends React.Component {
         </p>
 
         <form role="form" action="/installer" method="post" id="register-form">
-          <div className="input-group m-t-20 m-b-20 mx-auto">
-            <div className="radio radio-primary radio-inline">
-              <input
-                type="radio"
-                id="radioLangEn"
-                name="registerForm[app:globalLang]"
-                value="en-US"
-                defaultChecked
-                onClick={() => { return this.changeLanguage('en-US') }}
-              />
-              <label htmlFor="radioLangEn">English</label>
-            </div>
-            <div className="radio radio-primary radio-inline">
-              <input
-                type="radio"
-                id="radioLangJa"
-                name="registerForm[app:globalLang]"
-                value="ja"
-                defaultChecked={false}
-                onClick={() => { return this.changeLanguage('ja') }}
-              />
-              <label htmlFor="radioLangJa">日本語</label>
-            </div>
-          </div>
+          <FormGroup className="text-center">
+            <Radio
+              name="registerForm[app:globalLang]"
+              value="en-US"
+              checked={checkedBtn === 'en-US'}
+              inline
+              onClick={() => { return this.changeLanguage('en-US') }}
+            >
+              English
+            </Radio>
+            <Radio
+              name="registerForm[app:globalLang]"
+              value="ja"
+              checked={checkedBtn === 'ja'}
+              inline
+              onClick={() => { return this.changeLanguage('ja') }}
+            >
+              日本語
+            </Radio>
+          </FormGroup>
 
           <div className={`input-group${hasErrorClass}`}>
             <span className="input-group-addon"><i className="icon-user" /></span>
@@ -127,7 +131,7 @@ class InstallerForm extends React.Component {
           <div className="input-group m-t-30 m-b-20 d-flex justify-content-center">
             <button type="submit" className="fcbtn btn btn-success btn-1b btn-register">
               <span className="btn-label"><i className="icon-user-follow" /></span>
-              { this.props.t('Create') }
+              <span className="btn-label-text">{ this.props.t('Create') }</span>
             </button>
           </div>
 

+ 4 - 2
src/client/js/components/SavePageControls.jsx

@@ -65,8 +65,9 @@ class SavePageControls extends React.Component {
   }
 
   render() {
-    const { t, editorContainer } = this.props;
-    const labelSubmitButton = this.props.pageContainer.state.pageId == null ? t('Create') : t('Update');
+    const { t, pageContainer, editorContainer } = this.props;
+    const isRootPage = pageContainer.state.path === '/';
+    const labelSubmitButton = pageContainer.state.pageId == null ? t('Create') : t('Update');
     const labelOverwriteScopes = t('page_edit.overwrite_scopes', { operation: labelSubmitButton });
 
     return (
@@ -88,6 +89,7 @@ class SavePageControls extends React.Component {
           && (
           <div className="mr-2">
             <GrantSelector
+              disabled={isRootPage}
               grant={editorContainer.state.grant}
               grantGroupId={editorContainer.state.grantGroupId}
               grantGroupName={editorContainer.state.grantGroupName}

+ 4 - 2
src/client/js/components/SavePageControls/GrantSelector.jsx

@@ -205,6 +205,7 @@ class GrantSelector extends React.Component {
     return (
       <FormGroup className="grant-selector m-b-0">
         <FormControl
+          disabled={this.props.disabled}
           componentClass="select"
           placeholder="select"
           defaultValue={selectedValue}
@@ -275,8 +276,8 @@ class GrantSelector extends React.Component {
   render() {
     return (
       <React.Fragment>
-        {this.renderGrantSelector()}
-        {this.renderSelectGroupModal()}
+        { this.renderGrantSelector() }
+        { this.props.disabled && this.renderSelectGroupModal() }
       </React.Fragment>
     );
   }
@@ -294,6 +295,7 @@ GrantSelector.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
 
+  disabled: PropTypes.bool,
   grant: PropTypes.number.isRequired,
   grantGroupId: PropTypes.string,
   grantGroupName: PropTypes.string,

+ 0 - 2
src/client/js/components/SearchPage/SearchResult.js

@@ -1,5 +1,3 @@
-/* eslint-disable jsx-a11y/label-has-associated-control */
-/* eslint-disable jsx-a11y/label-has-for */
 import React from 'react';
 import PropTypes from 'prop-types';
 import * as toastr from 'toastr';

+ 1 - 0
src/client/js/components/StaffCredit/Contributor.js

@@ -69,6 +69,7 @@ const contributors = [
           { name: 'nekoruri' },
           { name: 'kmyk' },
           { name: 'aximov' },
+          { name: 'tats-u' },
         ],
       },
     ],

+ 1 - 2
src/client/js/ie11-polyfill.js

@@ -1,2 +1 @@
-import 'nodelist-foreach-polyfill';
-import 'babel-polyfill';
+import '@babel/polyfill';

+ 25 - 1
src/client/js/legacy/crowi.js

@@ -1,4 +1,3 @@
-/* global location */
 /* eslint no-restricted-globals: ['error', 'locaion'] */
 
 import React from 'react';
@@ -212,6 +211,30 @@ Crowi.initSlimScrollForRevisionToc = () => {
   });
 };
 
+Crowi.initClassesByOS = function() {
+  // add classes to cmd-key by OS
+  const platform = navigator.platform.toLowerCase();
+  const isMac = (platform.indexOf('mac') > -1);
+
+  document.querySelectorAll('.system-version .cmd-key').forEach((element) => {
+    if (isMac) {
+      element.classList.add('mac');
+    }
+    else {
+      element.classList.add('win');
+    }
+  });
+
+  document.querySelectorAll('#shortcuts-modal .cmd-key').forEach((element) => {
+    if (isMac) {
+      element.classList.add('mac');
+    }
+    else {
+      element.classList.add('win', 'key-longer');
+    }
+  });
+};
+
 Crowi.findHashFromUrl = function(url) {
   let match;
   /* eslint-disable no-cond-assign */
@@ -748,6 +771,7 @@ window.addEventListener('load', (e) => {
   Crowi.modifyScrollTop();
   Crowi.initSlimScrollForRevisionToc();
   Crowi.initAffix();
+  Crowi.initClassesByOS();
 });
 
 window.addEventListener('hashchange', (e) => {

+ 10 - 3
src/client/js/plugin.js

@@ -30,12 +30,19 @@ export default class GrowiPlugin {
       switch (meta.pluginSchemaVersion) {
         // v1 is deprecated
         case 1:
+          logger.warn('pluginSchemaVersion 1 is deprecated', definition);
           break;
-        // v2 or above
-        default:
+        // v2 is deprecated
+        case 2:
+          logger.warn('pluginSchemaVersion 2 is deprecated', definition);
+          break;
+        case 3:
           definition.entries.forEach((entry) => {
-            entry(appContainer, originRenderer);
+            entry(appContainer);
           });
+          break;
+        default:
+          logger.warn('Unsupported schema version', meta.pluginSchemaVersion);
       }
     });
 

+ 4 - 0
src/client/styles/scss/_login.scss

@@ -187,6 +187,10 @@
     .btn-label {
       background-color: rgba($brand-success, 0.4);
     }
+    .btn-label-text {
+      display: inline-block;
+      min-width: 45px;
+    }
     &:after {
       background-color: #3f7263;
     }

+ 3 - 1
src/client/styles/scss/_vendor.scss

@@ -1,5 +1,7 @@
 // import bootstrap
-$bootstrap-sass-asset-helper: true;
+// see https://github.com/webpack-contrib/css-loader/issues/909#issuecomment-472828905
+$bootstrap-sass-asset-helper: false;
+$icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/';
 @import '~bootstrap-sass/assets/stylesheets/bootstrap';
 
 // import bootstrap4 utility classes

+ 32 - 0
src/migrations/20190619055421-adjust-page-grant.js

@@ -0,0 +1,32 @@
+require('module-alias/register');
+const logger = require('@alias/logger')('growi:migrate:adjust-page-grant');
+
+const mongoose = require('mongoose');
+const config = require('@root/config/migrate');
+
+module.exports = {
+
+  async up(db) {
+    logger.info('Apply migration');
+    mongoose.connect(config.mongoUri, config.mongodb.options);
+
+    const Page = require('@server/models/page')();
+
+    await Page.bulkWrite([
+      {
+        updateMany:
+         {
+           filter: { grant: null },
+           update: { $set: { grant: Page.GRANT_PUBLIC } },
+         },
+      },
+    ]);
+
+    logger.info('Migration has successfully applied');
+
+  },
+
+  down(db) {
+    // do not rollback
+  },
+};

+ 29 - 0
src/migrations/20190629193445-make-root-page-public.js

@@ -0,0 +1,29 @@
+require('module-alias/register');
+const logger = require('@alias/logger')('growi:migrate:make-root-page-public');
+
+const mongoose = require('mongoose');
+const config = require('@root/config/migrate');
+
+module.exports = {
+  async up(db) {
+    logger.info('Apply migration');
+    mongoose.connect(config.mongoUri, config.mongodb.options);
+
+    const Page = require('@server/models/page')();
+
+    await Page.findOneAndUpdate(
+      { path: '/' },
+      {
+        grant: Page.GRANT_PUBLIC,
+        grantedUsers: [],
+        grantedGroup: null,
+      },
+    );
+
+    logger.info('Migration has successfully applied');
+  },
+
+  down(db) {
+    // do not rollback
+  },
+};

+ 9 - 3
src/server/plugins/plugin.service.js

@@ -34,15 +34,21 @@ class PluginService {
     switch (meta.pluginSchemaVersion) {
       // v1 is deprecated
       case 1:
-        logger.warn('pluginSchemaVersion 1 is deprecated');
+        logger.warn('pluginSchemaVersion 1 is deprecated', definition);
         break;
-      // v2 or above
-      default:
+      // v2 is deprecated
+      case 2:
+        logger.warn('pluginSchemaVersion 2 is deprecated', definition);
+        break;
+      case 3:
         logger.info(`load plugin '${definition.name}'`);
         definition.entries.forEach((entryPath) => {
           const entry = require(entryPath);
           entry(this.crowi, this.app);
         });
+        break;
+      default:
+        logger.warn('Unsupported schema version', meta.pluginSchemaVersion);
     }
   }
 

+ 1 - 1
src/server/routes/admin.js

@@ -624,7 +624,7 @@ module.exports = function(crowi, app) {
   actions.userGroup = {};
   actions.userGroup.index = function(req, res) {
     const page = parseInt(req.query.page) || 1;
-    const isAclEnabled = aclService.getIsPublicWikiOnly();
+    const isAclEnabled = !aclService.getIsPublicWikiOnly();
     const renderVar = {
       userGroups: [],
       userGroupRelations: new Map(),

+ 1 - 1
src/server/routes/login-passport.js

@@ -177,7 +177,7 @@ module.exports = function(crowi, app) {
         if (!isValidLdapUserByGroupFilter(user)) {
           return res.json({
             status: 'warning',
-            message: 'The user is found, but that has no groups.',
+            message: 'This user does not belong to any groups designated by the group search filter.',
             ldapConfiguration: req.ldapConfiguration,
             ldapAccountInfo: req.ldapAccountInfo,
           });

+ 4 - 6
src/server/service/acl.js

@@ -27,13 +27,11 @@ class AclService {
       return true;
     }
 
-    // return false if undefined
-    const isRestrictGuestMode = this.configManager.getConfig('crowi', 'security:restrictGuestMode');
-    if (isRestrictGuestMode) {
-      return false;
-    }
+    const guestMode = this.configManager.getConfig('crowi', 'security:restrictGuestMode');
 
-    return this.labels.SECURITY_RESTRICT_GUEST_MODE_READONLY === isRestrictGuestMode;
+    // 'Readonly' => returns true (allow access to guests)
+    // 'Deny', null, undefined, '', ... everything else => returns false (requires login)
+    return guestMode === this.labels.SECURITY_RESTRICT_GUEST_MODE_READONLY;
   }
 
   getRestrictGuestModeLabels() {

+ 3 - 2
src/server/views/admin/widget/passport/ldap.html

@@ -199,12 +199,13 @@
           <p class="help-block">
             <small>
               {{ t("security_setting.ldap.group_search_filter_detail1") }}<br>
-              {{ t("security_setting.ldap.group_search_filter_detail2") }}
+              {{ t("security_setting.ldap.group_search_filter_detail2") }}<br>
+              {{ t("security_setting.ldap.group_search_filter_detail3") }}
             </small>
           </p>
           <p class="help-block">
             <small>
-              {{ t("security_setting.example") }}: {{ t("security_setting.ldap.group_search_filter_detail3") }}
+              {{ t("security_setting.example") }}: {{ t("security_setting.ldap.group_search_filter_detail4") }}
             </small>
           </p>
         </div>

+ 1 - 1
src/server/views/installer.html

@@ -25,7 +25,7 @@
   <!-- styles -->
   {% include './widget/headers/styles-for-app.html' %}
   {% block theme_css_block %}
-    {% include './widget/headers/styles-theme.html' with {theme: 'default'} %}
+    {% include './widget/headers/styles-theme.html' with {themeName: 'default'} %}
   {% endblock %}
 
   {{ cdnStyleTagsByGroup('basis') }}

+ 1 - 1
src/server/views/login.html

@@ -299,7 +299,7 @@
           <div class="input-group m-t-30 m-b-20 d-flex justify-content-center">
             <button type="submit" class="fcbtn btn btn-success btn-1b btn-register">
               <span class="btn-label"><i class="icon-user-follow"></i></span>
-              {{ t('Sign up') }}
+              <span class="btn-label-text">{{ t('Sign up') }}</span>
             </button>
           </div>
         </form>

+ 0 - 16
src/server/views/modal/shortcuts.html

@@ -93,20 +93,4 @@
     </div><!-- /.modal-content -->
   </div><!-- /.modal-dialog -->
 
-  <script>
-    /*
-     * add classes to cmd-key by OS
-     */
-    var platform = navigator.platform.toLowerCase();
-    var isMac = (platform.indexOf('mac') > -1);
-
-    document.querySelectorAll('#shortcuts-modal .cmd-key').forEach(function(element) {
-      if (isMac) {
-        element.classList.add('mac');
-      }
-      else {
-        element.classList.add('win', 'key-longer');
-      }
-    });
-  </script>
 </div><!-- /.modal -->

+ 0 - 16
src/server/views/widget/system-version.html

@@ -6,19 +6,3 @@
     <a href="" data-target="#shortcuts-modal" data-toggle="modal"><i class="fa fa-keyboard-o"></i>&nbsp;<span class="cmd-key"></span>-/</a>
   </span>
 </div>
-<script>
-  /*
-  * add classes to cmd-key by OS
-  */
-  var platform = navigator.platform.toLowerCase();
-  var isMac = (platform.indexOf('mac') > -1);
-
-  document.querySelectorAll('.system-version .cmd-key').forEach(function(element) {
-    if (isMac) {
-      element.classList.add('mac');
-    }
-    else {
-      element.classList.add('win');
-    }
-  });
-</script>

File diff suppressed because it is too large
+ 694 - 665
yarn.lock


Some files were not shown because too many files changed in this diff