Răsfoiți Sursa

Merge branch 'master' into upgrade-nodejs-to-v14

utsushiiro 5 ani în urmă
părinte
comite
4eb7d69f20
100 a modificat fișierele cu 364 adăugiri și 301 ștergeri
  1. 1 1
      CHANGES.md
  2. 2 0
      config/migrate.js
  3. 0 1
      config/webpack.common.js
  4. 2 2
      package.json
  5. 0 3
      resource/locales/en-US/_conf.json
  6. 0 0
      resource/locales/en_US/admin/admin.json
  7. 0 0
      resource/locales/en_US/admin/userInvitation.txt
  8. 0 0
      resource/locales/en_US/admin/userWaitingActivation.txt
  9. 4 0
      resource/locales/en_US/meta.json
  10. 0 0
      resource/locales/en_US/notifications/comment.txt
  11. 0 0
      resource/locales/en_US/notifications/pageCreate.txt
  12. 0 0
      resource/locales/en_US/notifications/pageDelete.txt
  13. 0 0
      resource/locales/en_US/notifications/pageEdit.txt
  14. 0 0
      resource/locales/en_US/notifications/pageLike.txt
  15. 0 0
      resource/locales/en_US/notifications/pageMove.txt
  16. 0 0
      resource/locales/en_US/sandbox-bootstrap4.md
  17. 0 0
      resource/locales/en_US/sandbox-diagrams.md
  18. 0 0
      resource/locales/en_US/sandbox-math.md
  19. 0 0
      resource/locales/en_US/sandbox.md
  20. 10 10
      resource/locales/en_US/translation.json
  21. 0 0
      resource/locales/en_US/welcome.md
  22. 1 1
      resource/locales/index.js
  23. 0 3
      resource/locales/ja/_conf.json
  24. 0 0
      resource/locales/ja_JP/admin/admin.json
  25. 0 0
      resource/locales/ja_JP/admin/userInvitation.txt
  26. 0 0
      resource/locales/ja_JP/admin/userWaitingActivation.txt
  27. 4 0
      resource/locales/ja_JP/meta.json
  28. 0 0
      resource/locales/ja_JP/notifications/comment.txt
  29. 0 0
      resource/locales/ja_JP/notifications/pageCreate.txt
  30. 0 0
      resource/locales/ja_JP/notifications/pageDelete.txt
  31. 0 0
      resource/locales/ja_JP/notifications/pageEdit.txt
  32. 0 0
      resource/locales/ja_JP/notifications/pageLike.txt
  33. 0 0
      resource/locales/ja_JP/notifications/pageMove.txt
  34. 0 0
      resource/locales/ja_JP/sandbox-bootstrap4.md
  35. 0 0
      resource/locales/ja_JP/sandbox-diagrams.md
  36. 0 0
      resource/locales/ja_JP/sandbox-math.md
  37. 0 0
      resource/locales/ja_JP/sandbox.md
  38. 0 0
      resource/locales/ja_JP/translation.json
  39. 0 0
      resource/locales/ja_JP/welcome.md
  40. 0 3
      resource/locales/zh-CN/_conf.json
  41. 0 0
      resource/locales/zh_CN/admin/admin.json
  42. 0 0
      resource/locales/zh_CN/admin/userInvitation.txt
  43. 0 0
      resource/locales/zh_CN/admin/userWaitingActivation.txt
  44. 4 0
      resource/locales/zh_CN/meta.json
  45. 0 0
      resource/locales/zh_CN/notifications/comment.txt
  46. 0 0
      resource/locales/zh_CN/notifications/pageCreate.txt
  47. 0 0
      resource/locales/zh_CN/notifications/pageDelete.txt
  48. 0 0
      resource/locales/zh_CN/notifications/pageEdit.txt
  49. 0 0
      resource/locales/zh_CN/notifications/pageLike.txt
  50. 0 0
      resource/locales/zh_CN/notifications/pageMove.txt
  51. 0 0
      resource/locales/zh_CN/sandbox-bootstrap4.md
  52. 0 0
      resource/locales/zh_CN/sandbox-diagrams.md
  53. 0 0
      resource/locales/zh_CN/sandbox-math.md
  54. 0 0
      resource/locales/zh_CN/sandbox.md
  55. 0 0
      resource/locales/zh_CN/translation.json
  56. 0 0
      resource/locales/zh_CN/welcome.md
  57. 2 2
      rs-i18n.env
  58. 11 12
      src/client/js/components/Admin/App/AppSetting.jsx
  59. 12 13
      src/client/js/components/InstallerForm.jsx
  60. 11 13
      src/client/js/components/Me/BasicInfoSettings.jsx
  61. 4 1
      src/client/js/components/Me/PasswordSettings.jsx
  62. 10 5
      src/client/js/components/Me/PersonalSettings.jsx
  63. 1 1
      src/client/js/nologin.jsx
  64. 9 9
      src/client/js/services/AppContainer.js
  65. 1 1
      src/client/js/services/PersonalContainer.js
  66. 8 5
      src/client/js/util/i18n.js
  67. 34 0
      src/lib/util/locale-utils.js
  68. 7 0
      src/lib/util/mongoose-utils.js
  69. 47 0
      src/migrations/20200620203632-normalize-locale-id.js
  70. 2 2
      src/server/console.js
  71. 6 7
      src/server/crowi/dev.js
  72. 7 9
      src/server/crowi/express-init.js
  73. 2 15
      src/server/crowi/index.js
  74. 0 30
      src/server/middlewares/ApiV3FormValidator.js
  75. 0 0
      src/server/middlewares/access-token-parser.js
  76. 0 0
      src/server/middlewares/admin-required.js
  77. 22 0
      src/server/middlewares/apiv3-form-validator.js
  78. 13 0
      src/server/middlewares/application-installed.js
  79. 14 0
      src/server/middlewares/application-not-installed.js
  80. 0 0
      src/server/middlewares/csrf.js
  81. 0 21
      src/server/middlewares/index.js
  82. 6 0
      src/server/middlewares/inject-currentuser-to-localvars.js
  83. 0 0
      src/server/middlewares/login-required.js
  84. 1 1
      src/server/middlewares/safe-redirect.js
  85. 1 1
      src/server/models/config.js
  86. 5 24
      src/server/models/user.js
  87. 2 2
      src/server/routes/apiv3/admin-home.js
  88. 14 13
      src/server/routes/apiv3/app-settings.js
  89. 5 5
      src/server/routes/apiv3/bookmarks.js
  90. 13 14
      src/server/routes/apiv3/customize-setting.js
  91. 4 4
      src/server/routes/apiv3/export.js
  92. 4 4
      src/server/routes/apiv3/import.js
  93. 7 8
      src/server/routes/apiv3/markdown-setting.js
  94. 9 10
      src/server/routes/apiv3/notification-setting.js
  95. 5 6
      src/server/routes/apiv3/page.js
  96. 3 3
      src/server/routes/apiv3/pages.js
  97. 12 12
      src/server/routes/apiv3/personal-setting.js
  98. 6 7
      src/server/routes/apiv3/search.js
  99. 14 15
      src/server/routes/apiv3/security-setting.js
  100. 2 2
      src/server/routes/apiv3/user-group-relation.js

+ 1 - 1
CHANGES.md

@@ -1357,7 +1357,7 @@ Upgrading Guide: <https://docs.growi.org/en/admin-guide/upgrading/34x.html>
 
 
 * Fix: The problem that path including round bracket makes something bad
 * Fix: The problem that path including round bracket makes something bad
 * Fix: Recursively option processes also unexpedted pages
 * Fix: Recursively option processes also unexpedted pages
-* Fix: en-US translation
+* Fix: en_US translation
 
 
 ## v2.0.7
 ## v2.0.7
 
 

+ 2 - 0
config/migrate.js

@@ -21,6 +21,8 @@ const mongodb = {
   databaseName: url.pathname.substring(1), // omit heading slash
   databaseName: url.pathname.substring(1), // omit heading slash
   options: {
   options: {
     useNewUrlParser: true, // removes a deprecation warning when connecting
     useNewUrlParser: true, // removes a deprecation warning when connecting
+    useUnifiedTopology: true,
+    useFindAndModify: false,
   },
   },
 };
 };
 
 

+ 0 - 1
config/webpack.common.js

@@ -69,7 +69,6 @@ module.exports = (options) => {
         '@client': helpers.root('src/client'),
         '@client': helpers.root('src/client'),
         '@tmp': helpers.root('tmp'),
         '@tmp': helpers.root('tmp'),
         '@alias/logger': helpers.root('src/lib/service/logger'),
         '@alias/logger': helpers.root('src/lib/service/logger'),
-        '@alias/locales': helpers.root('resource/locales'),
         // replace bunyan
         // replace bunyan
         bunyan: 'browser-bunyan',
         bunyan: 'browser-bunyan',
       },
       },

+ 2 - 2
package.json

@@ -54,8 +54,8 @@
     "preserver:prod": "npm run migrate",
     "preserver:prod": "npm run migrate",
     "prestart": "npm run build:prod",
     "prestart": "npm run build:prod",
     "resource": "node bin/download-cdn-resources.js",
     "resource": "node bin/download-cdn-resources.js",
-    "translations": "rs-i18n -lan zh-CN -t",
-    "i18n-json-merge:noTran": "rs-i18n -lan zh-CN",
+    "translations": "rs-i18n -lan zh_CN -t",
+    "i18n-json-merge:noTran": "rs-i18n -lan zh_CN",
     "server:nolazy": "env-cmd -f config/env.dev.js node-dev --nolazy --inspect src/server/app.js",
     "server:nolazy": "env-cmd -f config/env.dev.js node-dev --nolazy --inspect src/server/app.js",
     "server:dev": "env-cmd -f config/env.dev.js node-dev --inspect src/server/app.js",
     "server:dev": "env-cmd -f config/env.dev.js node-dev --inspect src/server/app.js",
     "server:prod:ci": "npm run server:prod -- --ci",
     "server:prod:ci": "npm run server:prod -- --ci",

+ 0 - 3
resource/locales/en-US/_conf.json

@@ -1,3 +0,0 @@
-{
-  "name": "English"
-}

+ 0 - 0
resource/locales/en-US/admin/admin.json → resource/locales/en_US/admin/admin.json


+ 0 - 0
resource/locales/en-US/admin/userInvitation.txt → resource/locales/en_US/admin/userInvitation.txt


+ 0 - 0
resource/locales/en-US/admin/userWaitingActivation.txt → resource/locales/en_US/admin/userWaitingActivation.txt


+ 4 - 0
resource/locales/en_US/meta.json

@@ -0,0 +1,4 @@
+{
+  "id": "en_US",
+  "displayName": "English"
+}

+ 0 - 0
resource/locales/en-US/notifications/comment.txt → resource/locales/en_US/notifications/comment.txt


+ 0 - 0
resource/locales/en-US/notifications/pageCreate.txt → resource/locales/en_US/notifications/pageCreate.txt


+ 0 - 0
resource/locales/en-US/notifications/pageDelete.txt → resource/locales/en_US/notifications/pageDelete.txt


+ 0 - 0
resource/locales/en-US/notifications/pageEdit.txt → resource/locales/en_US/notifications/pageEdit.txt


+ 0 - 0
resource/locales/en-US/notifications/pageLike.txt → resource/locales/en_US/notifications/pageLike.txt


+ 0 - 0
resource/locales/en-US/notifications/pageMove.txt → resource/locales/en_US/notifications/pageMove.txt


+ 0 - 0
resource/locales/en-US/sandbox-bootstrap4.md → resource/locales/en_US/sandbox-bootstrap4.md


+ 0 - 0
resource/locales/en-US/sandbox-diagrams.md → resource/locales/en_US/sandbox-diagrams.md


+ 0 - 0
resource/locales/en-US/sandbox-math.md → resource/locales/en_US/sandbox-math.md


+ 0 - 0
resource/locales/en-US/sandbox.md → resource/locales/en_US/sandbox.md


+ 10 - 10
resource/locales/en-US/translation.json → resource/locales/en_US/translation.json

@@ -179,16 +179,16 @@
   },
   },
   "Password": "Password",
   "Password": "Password",
   "Password Settings": "Password settings",
   "Password Settings": "Password settings",
-    "personal_settings": {
-    "disassociate_external_account": "Disassociate External Account",
-    "disassociate_external_account_desc": "Are you sure to disassociate the <strong>{{providerType}}</strong> account <strong>{{accountId}}</strong>?",
-    "set_new_password": "Set new Password",
-    "update_password": "Update password",
-      "current_password": "Current password",
-      "new_password": "New password",
-      "new_password_confirm": "Re-enter new password",
-      "password_is_not_set": "Password is not set"
-    },
+  "personal_settings": {
+  "disassociate_external_account": "Disassociate External Account",
+  "disassociate_external_account_desc": "Are you sure to disassociate the <strong>{{providerType}}</strong> account <strong>{{accountId}}</strong>?",
+  "set_new_password": "Set new Password",
+  "update_password": "Update password",
+    "current_password": "Current password",
+    "new_password": "New password",
+    "new_password_confirm": "Re-enter new password",
+    "password_is_not_set": "Password is not set"
+  },
   "security_settings": "Security settings",
   "security_settings": "Security settings",
   "API Settings": "API settings",
   "API Settings": "API settings",
   "API Token Settings": "API token settings",
   "API Token Settings": "API token settings",

+ 0 - 0
resource/locales/en-US/welcome.md → resource/locales/en_US/welcome.md


+ 1 - 1
resource/locales/index.js

@@ -1,2 +1,2 @@
-// !!DO NOT REMOVE THIS FILE!!
+// !!DO NOT EDIT/REMOVE THIS FILE!!
 // entry point for @alienfast/i18next-loader
 // entry point for @alienfast/i18next-loader

+ 0 - 3
resource/locales/ja/_conf.json

@@ -1,3 +0,0 @@
-{
-  "name": "日本語"
-}

+ 0 - 0
resource/locales/ja/admin/admin.json → resource/locales/ja_JP/admin/admin.json


+ 0 - 0
resource/locales/ja/admin/userInvitation.txt → resource/locales/ja_JP/admin/userInvitation.txt


+ 0 - 0
resource/locales/ja/admin/userWaitingActivation.txt → resource/locales/ja_JP/admin/userWaitingActivation.txt


+ 4 - 0
resource/locales/ja_JP/meta.json

@@ -0,0 +1,4 @@
+{
+  "id": "ja_JP",
+  "displayName": "日本語"
+}

+ 0 - 0
resource/locales/ja/notifications/comment.txt → resource/locales/ja_JP/notifications/comment.txt


+ 0 - 0
resource/locales/ja/notifications/pageCreate.txt → resource/locales/ja_JP/notifications/pageCreate.txt


+ 0 - 0
resource/locales/ja/notifications/pageDelete.txt → resource/locales/ja_JP/notifications/pageDelete.txt


+ 0 - 0
resource/locales/ja/notifications/pageEdit.txt → resource/locales/ja_JP/notifications/pageEdit.txt


+ 0 - 0
resource/locales/ja/notifications/pageLike.txt → resource/locales/ja_JP/notifications/pageLike.txt


+ 0 - 0
resource/locales/ja/notifications/pageMove.txt → resource/locales/ja_JP/notifications/pageMove.txt


+ 0 - 0
resource/locales/ja/sandbox-bootstrap4.md → resource/locales/ja_JP/sandbox-bootstrap4.md


+ 0 - 0
resource/locales/ja/sandbox-diagrams.md → resource/locales/ja_JP/sandbox-diagrams.md


+ 0 - 0
resource/locales/ja/sandbox-math.md → resource/locales/ja_JP/sandbox-math.md


+ 0 - 0
resource/locales/ja/sandbox.md → resource/locales/ja_JP/sandbox.md


+ 0 - 0
resource/locales/ja/translation.json → resource/locales/ja_JP/translation.json


+ 0 - 0
resource/locales/ja/welcome.md → resource/locales/ja_JP/welcome.md


+ 0 - 3
resource/locales/zh-CN/_conf.json

@@ -1,3 +0,0 @@
-{
-  "name": "简体中文"
-}

+ 0 - 0
resource/locales/zh-CN/admin/admin.json → resource/locales/zh_CN/admin/admin.json


+ 0 - 0
resource/locales/zh-CN/admin/userInvitation.txt → resource/locales/zh_CN/admin/userInvitation.txt


+ 0 - 0
resource/locales/zh-CN/admin/userWaitingActivation.txt → resource/locales/zh_CN/admin/userWaitingActivation.txt


+ 4 - 0
resource/locales/zh_CN/meta.json

@@ -0,0 +1,4 @@
+{
+  "id": "zh_CN",
+  "displayName": "简体中文"
+}

+ 0 - 0
resource/locales/zh-CN/notifications/comment.txt → resource/locales/zh_CN/notifications/comment.txt


+ 0 - 0
resource/locales/zh-CN/notifications/pageCreate.txt → resource/locales/zh_CN/notifications/pageCreate.txt


+ 0 - 0
resource/locales/zh-CN/notifications/pageDelete.txt → resource/locales/zh_CN/notifications/pageDelete.txt


+ 0 - 0
resource/locales/zh-CN/notifications/pageEdit.txt → resource/locales/zh_CN/notifications/pageEdit.txt


+ 0 - 0
resource/locales/zh-CN/notifications/pageLike.txt → resource/locales/zh_CN/notifications/pageLike.txt


+ 0 - 0
resource/locales/zh-CN/notifications/pageMove.txt → resource/locales/zh_CN/notifications/pageMove.txt


+ 0 - 0
resource/locales/zh-CN/sandbox-bootstrap4.md → resource/locales/zh_CN/sandbox-bootstrap4.md


+ 0 - 0
resource/locales/zh-CN/sandbox-diagrams.md → resource/locales/zh_CN/sandbox-diagrams.md


+ 0 - 0
resource/locales/zh-CN/sandbox-math.md → resource/locales/zh_CN/sandbox-math.md


+ 0 - 0
resource/locales/zh-CN/sandbox.md → resource/locales/zh_CN/sandbox.md


+ 0 - 0
resource/locales/zh-CN/translation.json → resource/locales/zh_CN/translation.json


+ 0 - 0
resource/locales/zh-CN/welcome.md → resource/locales/zh_CN/welcome.md


+ 2 - 2
rs-i18n.env

@@ -1,9 +1,9 @@
 RS_I18N_BAIDU_APP_ID=
 RS_I18N_BAIDU_APP_ID=
 RS_I18N_BAIDU_APP_SECRET=
 RS_I18N_BAIDU_APP_SECRET=
 RS_I18N_LOCALES_DIR=./resource/locales
 RS_I18N_LOCALES_DIR=./resource/locales
-RS_I18N_BASE_LANGUAGE=en-US
+RS_I18N_BASE_LANGUAGE=en_US
 RS_I18N_TARGET_FILE_SUFFIX= '.json'
 RS_I18N_TARGET_FILE_SUFFIX= '.json'
 RS_I18N_DEBUG_FORMAT=__{%s}__
 RS_I18N_DEBUG_FORMAT=__{%s}__
 
 
-RS_I18N_LAN_zh-CN=zh
+RS_I18N_LAN_zh_CN=zh
 RS_I18N_LAN_ja=jp
 RS_I18N_LAN_ja=jp

+ 11 - 12
src/client/js/components/Admin/App/AppSetting.jsx

@@ -3,10 +3,11 @@ import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
 import loggerFactory from '@alias/logger';
 import loggerFactory from '@alias/logger';
 
 
+import { localeMetadatas } from '../../../util/i18n';
+
 import { withUnstatedContainers } from '../../UnstatedUtils';
 import { withUnstatedContainers } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 
-import AppContainer from '../../../services/AppContainer';
 import AdminAppContainer from '../../../services/AdminAppContainer';
 import AdminAppContainer from '../../../services/AdminAppContainer';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 
 
@@ -34,9 +35,8 @@ class AppSetting extends React.Component {
   }
   }
 
 
   render() {
   render() {
-    const { t, adminAppContainer, appContainer } = this.props;
-    const locales = appContainer.locales;
-    const languages = Object.keys(locales);
+    const { t, adminAppContainer } = this.props;
+
     return (
     return (
       <React.Fragment>
       <React.Fragment>
         <div className="form-group row">
         <div className="form-group row">
@@ -83,20 +83,20 @@ class AppSetting extends React.Component {
           </label>
           </label>
           <div className="col-md-6">
           <div className="col-md-6">
             {
             {
-              languages.map(lan => (
-                <div key={lan} className="custom-control custom-radio custom-control-inline">
+              localeMetadatas.map(meta => (
+                <div key={meta.id} className="custom-control custom-radio custom-control-inline">
                   <input
                   <input
                     type="radio"
                     type="radio"
-                    id={`radioLang${lan}`}
+                    id={`radioLang${meta.id}`}
                     className="custom-control-input"
                     className="custom-control-input"
                     name="globalLang"
                     name="globalLang"
-                    value={lan}
-                    checked={adminAppContainer.state.globalLang === lan}
+                    value={meta.id}
+                    checked={adminAppContainer.state.globalLang === meta.id}
                     onChange={(e) => {
                     onChange={(e) => {
                       adminAppContainer.changeGlobalLang(e.target.value);
                       adminAppContainer.changeGlobalLang(e.target.value);
                     }}
                     }}
                   />
                   />
-                  <label className="custom-control-label" htmlFor={`radioLang${lan}`}>{locales[lan]._conf.name}</label>
+                  <label className="custom-control-label" htmlFor={`radioLang${meta.id}`}>{meta.displayName}</label>
                 </div>
                 </div>
               ))
               ))
             }
             }
@@ -145,11 +145,10 @@ class AppSetting extends React.Component {
 /**
 /**
  * Wrapper component for using unstated
  * Wrapper component for using unstated
  */
  */
-const AppSettingWrapper = withUnstatedContainers(AppSetting, [AppContainer, AdminAppContainer]);
+const AppSettingWrapper = withUnstatedContainers(AppSetting, [AdminAppContainer]);
 
 
 AppSetting.propTypes = {
 AppSetting.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   adminAppContainer: PropTypes.instanceOf(AdminAppContainer).isRequired,
   adminAppContainer: PropTypes.instanceOf(AdminAppContainer).isRequired,
 };
 };
 
 

+ 12 - 13
src/client/js/components/InstallerForm.jsx

@@ -4,6 +4,8 @@ import PropTypes from 'prop-types';
 import i18next from 'i18next';
 import i18next from 'i18next';
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
 
 
+import { localeMetadatas } from '../util/i18n';
+
 class InstallerForm extends React.Component {
 class InstallerForm extends React.Component {
 
 
   constructor(props) {
   constructor(props) {
@@ -11,13 +13,13 @@ class InstallerForm extends React.Component {
 
 
     this.state = {
     this.state = {
       isValidUserName: true,
       isValidUserName: true,
-      checkedBtn: 'en-US',
+      checkedBtn: 'en_US',
     };
     };
     this.checkUserName = this.checkUserName.bind(this);
     this.checkUserName = this.checkUserName.bind(this);
   }
   }
 
 
   componentWillMount() {
   componentWillMount() {
-    this.changeLanguage('en-US');
+    this.changeLanguage('en_US');
   }
   }
 
 
   checkUserName(event) {
   checkUserName(event) {
@@ -44,9 +46,6 @@ class InstallerForm extends React.Component {
       : <span><i className="icon-fw icon-ban" />{ this.props.t('installer.unavaliable_user_id') }</span>;
       : <span><i className="icon-fw icon-ban" />{ this.props.t('installer.unavaliable_user_id') }</span>;
 
 
     const checkedBtn = this.state.checkedBtn;
     const checkedBtn = this.state.checkedBtn;
-    const { i18n } = this.props;
-    const locales = i18n.options.resources;
-    const languages = Object.keys(locales);
 
 
     return (
     return (
       <div className={`login-dialog p-3 mx-auto${hasErrorClass}`}>
       <div className={`login-dialog p-3 mx-auto${hasErrorClass}`}>
@@ -62,19 +61,19 @@ class InstallerForm extends React.Component {
           <form role="form" action="/installer" method="post" id="register-form" className="col-md-12">
           <form role="form" action="/installer" method="post" id="register-form" className="col-md-12">
             <div className="form-group text-center">
             <div className="form-group text-center">
               {
               {
-                languages.map(lan => (
-                  <div key={lan} className="custom-control custom-radio custom-control-inline">
+                localeMetadatas.map(meta => (
+                  <div key={meta.id} className="custom-control custom-radio custom-control-inline">
                     <input
                     <input
                       type="radio"
                       type="radio"
                       className="custom-control-input"
                       className="custom-control-input"
-                      id={`register-form-check-${lan}`}
+                      id={`register-form-check-${meta.id}`}
                       name="registerForm[app:globalLang]"
                       name="registerForm[app:globalLang]"
-                      value={lan}
-                      checked={checkedBtn === lan}
-                      onChange={(e) => { if (e.target.checked) { this.changeLanguage(lan) } }}
+                      value={meta.id}
+                      checked={checkedBtn === meta.id}
+                      onChange={(e) => { if (e.target.checked) { this.changeLanguage(meta.id) } }}
                     />
                     />
-                    <label className="custom-control-label" htmlFor={`register-form-check-${lan}`}>
-                      {locales[lan]._conf.name}
+                    <label className="custom-control-label" htmlFor={`register-form-check-${meta.id}`}>
+                      {meta.displayName}
                     </label>
                     </label>
                   </div>
                   </div>
                 ))
                 ))

+ 11 - 13
src/client/js/components/Me/BasicInfoSettings.jsx

@@ -3,15 +3,16 @@ import React, { Fragment } from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
 
 
+import { localeMetadatas } from '../../util/i18n';
+
 import { toastSuccess, toastError } from '../../util/apiNotification';
 import { toastSuccess, toastError } from '../../util/apiNotification';
 import { withUnstatedContainers } from '../UnstatedUtils';
 import { withUnstatedContainers } from '../UnstatedUtils';
 
 
-import AppContainer from '../../services/AppContainer';
 import PersonalContainer from '../../services/PersonalContainer';
 import PersonalContainer from '../../services/PersonalContainer';
 
 
 class BasicInfoSettings extends React.Component {
 class BasicInfoSettings extends React.Component {
 
 
-  constructor(appContainer) {
+  constructor() {
     super();
     super();
 
 
     this.onClickSubmit = this.onClickSubmit.bind(this);
     this.onClickSubmit = this.onClickSubmit.bind(this);
@@ -39,10 +40,8 @@ class BasicInfoSettings extends React.Component {
   }
   }
 
 
   render() {
   render() {
-    const { t, personalContainer, appContainer } = this.props;
+    const { t, personalContainer } = this.props;
     const { registrationWhiteList } = personalContainer.state;
     const { registrationWhiteList } = personalContainer.state;
-    const locales = appContainer.locales;
-    const languages = Object.keys(locales);
 
 
     return (
     return (
       <Fragment>
       <Fragment>
@@ -113,17 +112,17 @@ class BasicInfoSettings extends React.Component {
           <label className="text-left text-md-right col-md-3 col-form-label">{t('Language')}</label>
           <label className="text-left text-md-right col-md-3 col-form-label">{t('Language')}</label>
           <div className="col-md-6">
           <div className="col-md-6">
             {
             {
-              languages.map(lan => (
-                <div key={lan} className="custom-control custom-radio custom-control-inline">
+              localeMetadatas.map(meta => (
+                <div key={meta.id} className="custom-control custom-radio custom-control-inline">
                   <input
                   <input
                     type="radio"
                     type="radio"
-                    id={`radioLang${lan}`}
+                    id={`radioLang${meta.id}`}
                     className="custom-control-input"
                     className="custom-control-input"
                     name="userForm[lang]"
                     name="userForm[lang]"
-                    checked={personalContainer.state.lang === lan}
-                    onChange={() => { personalContainer.changeLang(lan) }}
+                    checked={personalContainer.state.lang === meta.id}
+                    onChange={() => { personalContainer.changeLang(meta.id) }}
                   />
                   />
-                  <label className="custom-control-label" htmlFor={`radioLang${lan}`}>{locales[lan]._conf.name}</label>
+                  <label className="custom-control-label" htmlFor={`radioLang${meta.id}`}>{meta.displayName}</label>
                 </div>
                 </div>
               ))
               ))
             }
             }
@@ -144,11 +143,10 @@ class BasicInfoSettings extends React.Component {
 
 
 }
 }
 
 
-const BasicInfoSettingsWrapper = withUnstatedContainers(BasicInfoSettings, [AppContainer, PersonalContainer]);
+const BasicInfoSettingsWrapper = withUnstatedContainers(BasicInfoSettings, [PersonalContainer]);
 
 
 BasicInfoSettings.propTypes = {
 BasicInfoSettings.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   personalContainer: PropTypes.instanceOf(PersonalContainer).isRequired,
   personalContainer: PropTypes.instanceOf(PersonalContainer).isRequired,
 };
 };
 
 

+ 4 - 1
src/client/js/components/Me/PasswordSettings.jsx

@@ -67,7 +67,10 @@ class PasswordSettings extends React.Component {
 
 
     return (
     return (
       <React.Fragment>
       <React.Fragment>
-        {(!personalContainer.state.isPasswordSet) && <div className="alert alert-warning">{ t('Password is not set') }</div>}
+        { (!personalContainer.state.isPasswordSet) && (
+          <div className="alert alert-warning">{ t('personal_settings.password_is_not_set') }</div>
+        ) }
+
         <div className="container-fluid my-4">
         <div className="container-fluid my-4">
           {(personalContainer.state.isPasswordSet)
           {(personalContainer.state.isPasswordSet)
             ? <h2 className="border-bottom">{t('personal_settings.update_password')}</h2>
             ? <h2 className="border-bottom">{t('personal_settings.update_password')}</h2>

+ 10 - 5
src/client/js/components/Me/PersonalSettings.jsx

@@ -18,19 +18,24 @@ class PersonalSettings extends React.Component {
         <div className="personal-settings">
         <div className="personal-settings">
           <ul className="nav nav-tabs" role="tablist">
           <ul className="nav nav-tabs" role="tablist">
             <li className="nav-item">
             <li className="nav-item">
-              <a className="nav-link active" href="#user-settings" data-toggle="tab" role="tab"><i className="icon-user"></i> { t('User Information') }</a>
+              <a className="nav-link active" href="#user-settings" data-toggle="tab" role="tab">
+                <i className="icon-fw icon-user"></i>{ t('User Information') }
+              </a>
             </li>
             </li>
             <li className="nav-item">
             <li className="nav-item">
               <a className="nav-link" href="#external-accounts" data-toggle="tab" role="tab">
               <a className="nav-link" href="#external-accounts" data-toggle="tab" role="tab">
-                <i className="icon-share-alt mr-1"></i>
-                { t('admin:user_management.external_accounts') }
+                <i className="icon-fw icon-share-alt"></i>{ t('admin:user_management.external_accounts') }
               </a>
               </a>
             </li>
             </li>
             <li className="nav-item">
             <li className="nav-item">
-              <a className="nav-link" href="#password-settings" data-toggle="tab" role="tab"><i className="icon-lock"></i> { t('Password Settings') }</a>
+              <a className="nav-link" href="#password-settings" data-toggle="tab" role="tab">
+                <i className="icon-fw icon-lock"></i>{ t('Password Settings') }
+              </a>
             </li>
             </li>
             <li className="nav-item">
             <li className="nav-item">
-              <a className="nav-link" href="#apiToken" data-toggle="tab" role="tab"><i className="icon-paper-plane"></i> { t('API Settings') }</a>
+              <a className="nav-link" href="#apiToken" data-toggle="tab" role="tab">
+                <i className="icon-fw icon-paper-plane"></i>{ t('API Settings') }
+              </a>
             </li>
             </li>
           </ul>
           </ul>
           <div className="tab-content p-t-10">
           <div className="tab-content p-t-10">

+ 1 - 1
src/client/js/nologin.jsx

@@ -3,7 +3,7 @@ import ReactDOM from 'react-dom';
 import { Provider } from 'unstated';
 import { Provider } from 'unstated';
 import { I18nextProvider } from 'react-i18next';
 import { I18nextProvider } from 'react-i18next';
 
 
-import i18nFactory from './util/i18n';
+import { i18nFactory } from './util/i18n';
 
 
 import AppContainer from './services/AppContainer';
 import AppContainer from './services/AppContainer';
 
 

+ 9 - 9
src/client/js/services/AppContainer.js

@@ -14,7 +14,7 @@ import {
 } from '../util/color-scheme';
 } from '../util/color-scheme';
 import Apiv1ErrorHandler from '../util/apiv1ErrorHandler';
 import Apiv1ErrorHandler from '../util/apiv1ErrorHandler';
 
 
-import i18nFactory from '../util/i18n';
+import { i18nFactory } from '../util/i18n';
 import apiv3ErrorHandler from '../util/apiv3ErrorHandler';
 import apiv3ErrorHandler from '../util/apiv3ErrorHandler';
 
 
 /**
 /**
@@ -42,9 +42,14 @@ export default class AppContainer extends Container {
     const userAgent = window.navigator.userAgent.toLowerCase();
     const userAgent = window.navigator.userAgent.toLowerCase();
     this.isMobile = /iphone|ipad|android/.test(userAgent);
     this.isMobile = /iphone|ipad|android/.test(userAgent);
 
 
-    const userlang = body.dataset.userlang;
-    this.i18n = i18nFactory(userlang);
-    this.locales = this.i18n.options.resources;
+    const currentUserElem = document.getElementById('growi-current-user');
+    if (currentUserElem != null) {
+      this.currentUser = JSON.parse(currentUserElem.textContent);
+    }
+
+    const userLocaleId = this.currentUser.lang;
+    this.i18n = i18nFactory(userLocaleId);
+
     this.containerInstances = {};
     this.containerInstances = {};
     this.componentInstances = {};
     this.componentInstances = {};
     this.rendererInstances = {};
     this.rendererInstances = {};
@@ -79,11 +84,6 @@ export default class AppContainer extends Container {
   initContents() {
   initContents() {
     const body = document.querySelector('body');
     const body = document.querySelector('body');
 
 
-    const currentUserElem = document.getElementById('growi-current-user');
-    if (currentUserElem != null) {
-      this.currentUser = JSON.parse(currentUserElem.textContent);
-    }
-
     this.isAdmin = body.dataset.isAdmin === 'true';
     this.isAdmin = body.dataset.isAdmin === 'true';
 
 
     this.isDocSaved = true;
     this.isDocSaved = true;

+ 1 - 1
src/client/js/services/PersonalContainer.js

@@ -24,7 +24,7 @@ export default class PersonalContainer extends Container {
       email: '',
       email: '',
       registrationWhiteList: this.appContainer.getConfig().registrationWhiteList,
       registrationWhiteList: this.appContainer.getConfig().registrationWhiteList,
       isEmailPublished: false,
       isEmailPublished: false,
-      lang: 'en-US',
+      lang: 'en_US',
       isGravatarEnabled: false,
       isGravatarEnabled: false,
       isUploadedPicture: false,
       isUploadedPicture: false,
       uploadedPictureSrc: this.getUploadedPictureSrc(this.appContainer.currentUser),
       uploadedPictureSrc: this.getUploadedPictureSrc(this.appContainer.currentUser),

+ 8 - 5
src/client/js/util/i18n.js

@@ -2,15 +2,18 @@ import i18n from 'i18next';
 import LanguageDetector from 'i18next-browser-languagedetector';
 import LanguageDetector from 'i18next-browser-languagedetector';
 import { initReactI18next } from 'react-i18next';
 import { initReactI18next } from 'react-i18next';
 
 
-import resources from '@alias/locales';
+import locales from '@root/resource/locales';
 
 
-export default (userlang) => {
+// extract metadata list from 'resource/locales/${locale}/meta.json'
+export const localeMetadatas = Object.values(locales).map(locale => locale.meta);
+
+export const i18nFactory = (userLocaleId) => {
   // setup LanguageDetector
   // setup LanguageDetector
   const langDetector = new LanguageDetector();
   const langDetector = new LanguageDetector();
   langDetector.addDetector({
   langDetector.addDetector({
     name: 'userSettingDetector',
     name: 'userSettingDetector',
     lookup(options) {
     lookup(options) {
-      return userlang;
+      return userLocaleId;
     },
     },
     cacheUserlanguage(lng, options) {
     cacheUserlanguage(lng, options) {
     },
     },
@@ -21,10 +24,10 @@ export default (userlang) => {
     .use(initReactI18next) // if not using I18nextProvider
     .use(initReactI18next) // if not using I18nextProvider
     .init({
     .init({
       debug: (process.env.NODE_ENV !== 'production'),
       debug: (process.env.NODE_ENV !== 'production'),
-      resources,
+      resources: locales,
       load: 'currentOnly',
       load: 'currentOnly',
 
 
-      fallbackLng: 'en-US',
+      fallbackLng: 'en_US',
       detection: {
       detection: {
         order: ['userSettingDetector', 'querystring', 'localStorage'],
         order: ['userSettingDetector', 'querystring', 'localStorage'],
       },
       },

+ 34 - 0
src/lib/util/locale-utils.js

@@ -0,0 +1,34 @@
+const fs = require('fs');
+
+const helpers = require('./helpers');
+
+/**
+ * List locales dirents
+ */
+function listLocaleDirents() {
+  const allDirents = fs.readdirSync(helpers.root('resource/locales'), { withFileTypes: true });
+  return allDirents
+    .filter(dirent => dirent.isDirectory());
+}
+
+/**
+ * List locales aliases
+ */
+function listLocaleMetadatas() {
+  return listLocaleDirents()
+    .map(dir => dir.name)
+    .map(localeDirName => require(`../../../resource/locales/${localeDirName}/meta.json`));
+}
+
+/**
+ * List locales IDs (=subdir names)
+ */
+function listLocaleIds() {
+  return listLocaleMetadatas()
+    .map(meta => meta.id);
+}
+
+module.exports = {
+  listLocaleMetadatas,
+  listLocaleIds,
+};

+ 7 - 0
src/lib/util/mongoose-utils.js

@@ -17,7 +17,14 @@ const getModelSafely = (modelName) => {
   return null;
   return null;
 };
 };
 
 
+const mongoOptions = {
+  useNewUrlParser: true, // removes a deprecation warning when connecting
+  useUnifiedTopology: true,
+  useFindAndModify: false,
+};
+
 module.exports = {
 module.exports = {
   getMongoUri,
   getMongoUri,
   getModelSafely,
   getModelSafely,
+  mongoOptions,
 };
 };

+ 47 - 0
src/migrations/20200620203632-normalize-locale-id.js

@@ -0,0 +1,47 @@
+require('module-alias/register');
+const logger = require('@alias/logger')('growi:migrate:normalize-locale-id');
+
+const mongoose = require('mongoose');
+const config = require('@root/config/migrate');
+
+const { getModelSafely } = require('@commons/util/mongoose-utils');
+
+module.exports = {
+  async up(db, client) {
+    logger.info('Apply migration');
+    mongoose.connect(config.mongoUri, config.mongodb.options);
+
+    const Config = getModelSafely('Config') || require('@server/models/config')();
+    const User = getModelSafely('User') || require('@server/models/user')();
+
+    await Promise.all([
+      // update en-US -> en_US
+      Config.update(
+        { key: 'app:globalLang', value: JSON.stringify('en-US') },
+        { value: JSON.stringify('en_US') },
+      ),
+      // update ja -> ja_JP
+      Config.update(
+        { key: 'app:globalLang', value: JSON.stringify('ja') },
+        { value: JSON.stringify('ja_JP') },
+      ),
+
+      // update en-US -> en_US
+      User.updateMany(
+        { lang: 'en-US' },
+        { lang: 'en_US' },
+      ),
+      // update ja -> ja_JP
+      User.updateMany(
+        { lang: 'ja' },
+        { lang: 'ja_JP' },
+      ),
+    ]);
+
+    logger.info('Migration has successfully applied');
+  },
+
+  async down(db, client) {
+    // do not rollback
+  },
+};

+ 2 - 2
src/server/console.js

@@ -4,7 +4,7 @@ const repl = require('repl');
 const fs = require('fs');
 const fs = require('fs');
 const path = require('path');
 const path = require('path');
 const mongoose = require('mongoose');
 const mongoose = require('mongoose');
-const { getMongoUri } = require('@commons/util/mongoose-utils');
+const { getMongoUri, mongoOptions } = require('@commons/util/mongoose-utils');
 
 
 const models = require('./models');
 const models = require('./models');
 
 
@@ -34,7 +34,7 @@ fs.readFile(replHistoryPath, 'utf8', (err, data) => {
 replServer.context.mongoose = mongoose;
 replServer.context.mongoose = mongoose;
 replServer.context.models = models;
 replServer.context.models = models;
 
 
-mongoose.connect(getMongoUri(), { useNewUrlParser: true })
+mongoose.connect(getMongoUri(), mongoOptions)
   .then(() => {
   .then(() => {
     replServer.context.db = mongoose.connection.db;
     replServer.context.db = mongoose.connection.db;
   });
   });

+ 6 - 7
src/server/crowi/dev.js

@@ -1,10 +1,12 @@
 const logger = require('@alias/logger')('growi:crowi:dev');
 const logger = require('@alias/logger')('growi:crowi:dev');
-const fs = require('fs');
 const path = require('path');
 const path = require('path');
 
 
+const { listLocaleIds } = require('@commons/util/locale-utils');
+
 const swig = require('swig-templates');
 const swig = require('swig-templates');
 const onHeaders = require('on-headers');
 const onHeaders = require('on-headers');
 
 
+
 class CrowiDev {
 class CrowiDev {
 
 
   /**
   /**
@@ -38,12 +40,9 @@ class CrowiDev {
    */
    */
   requireForAutoReloadServer() {
   requireForAutoReloadServer() {
     // load all json files for live reloading
     // load all json files for live reloading
-    fs.readdirSync(this.crowi.localeDir)
-      .filter((filename) => {
-        return fs.statSync(path.join(this.crowi.localeDir, filename)).isDirectory();
-      })
-      .forEach((dirname) => {
-        require(path.join(this.crowi.localeDir, dirname, 'translation.json'));
+    listLocaleIds()
+      .forEach((localeId) => {
+        require(path.join(this.crowi.localeDir, localeId, 'translation.json'));
       });
       });
   }
   }
 
 

+ 7 - 9
src/server/crowi/express-init.js

@@ -18,14 +18,15 @@ module.exports = function(crowi, app) {
   const i18nSprintf = require('i18next-sprintf-postprocessor');
   const i18nSprintf = require('i18next-sprintf-postprocessor');
   const i18nMiddleware = require('i18next-express-middleware');
   const i18nMiddleware = require('i18next-express-middleware');
 
 
-  const registerSafeRedirect = require('../middleware/safe-redirect')();
+  const registerSafeRedirect = require('../middlewares/safe-redirect')();
+  const injectCurrentuserToLocalvars = require('../middlewares/inject-currentuser-to-localvars')();
+  const { listLocaleIds } = require('@commons/util/locale-utils');
 
 
   const avoidSessionRoutes = require('../routes/avoid-session-routes');
   const avoidSessionRoutes = require('../routes/avoid-session-routes');
   const i18nUserSettingDetector = require('../util/i18nUserSettingDetector');
   const i18nUserSettingDetector = require('../util/i18nUserSettingDetector');
 
 
   const env = crowi.node_env;
   const env = crowi.node_env;
 
 
-  const User = crowi.model('User');
   const lngDetector = new i18nMiddleware.LanguageDetector();
   const lngDetector = new i18nMiddleware.LanguageDetector();
   lngDetector.addDetector(i18nUserSettingDetector);
   lngDetector.addDetector(i18nUserSettingDetector);
 
 
@@ -35,8 +36,8 @@ module.exports = function(crowi, app) {
     .use(i18nSprintf)
     .use(i18nSprintf)
     .init({
     .init({
       // debug: true,
       // debug: true,
-      fallbackLng: [User.LANG_EN_US],
-      whitelist: Object.keys(User.getLanguageLabels()).map((k) => { return User[k] }),
+      fallbackLng: ['en_US'],
+      whitelist: listLocaleIds(),
       backend: {
       backend: {
         loadPath: `${crowi.localeDir}{{lng}}/translation.json`,
         loadPath: `${crowi.localeDir}{{lng}}/translation.json`,
       },
       },
@@ -69,7 +70,7 @@ module.exports = function(crowi, app) {
     res.locals.consts = {
     res.locals.consts = {
       pageGrants: Page.getGrantLabels(),
       pageGrants: Page.getGrantLabels(),
       userStatus: User.getUserStatusLabels(),
       userStatus: User.getUserStatusLabels(),
-      language:   User.getLanguageLabels(),
+      language:   listLocaleIds(),
       restrictGuestMode: crowi.aclService.getRestrictGuestModeLabels(),
       restrictGuestMode: crowi.aclService.getRestrictGuestModeLabels(),
       registrationMode: crowi.aclService.getRegistrationModeLabels(),
       registrationMode: crowi.aclService.getRegistrationModeLabels(),
     };
     };
@@ -115,15 +116,12 @@ module.exports = function(crowi, app) {
   app.use(flash());
   app.use(flash());
 
 
   app.use(registerSafeRedirect);
   app.use(registerSafeRedirect);
+  app.use(injectCurrentuserToLocalvars);
 
 
   const middlewares = require('../util/middlewares')(crowi, app);
   const middlewares = require('../util/middlewares')(crowi, app);
-
   app.use(middlewares.swigFilters(swig));
   app.use(middlewares.swigFilters(swig));
   app.use(middlewares.swigFunctions());
   app.use(middlewares.swigFunctions());
-
   app.use(middlewares.csrfKeyGenerator());
   app.use(middlewares.csrfKeyGenerator());
 
 
-  app.use(middlewares.loginCheckerForPassport);
-
   app.use(i18nMiddleware.handle(i18next));
   app.use(i18nMiddleware.handle(i18next));
 };
 };

+ 2 - 15
src/server/crowi/index.js

@@ -6,9 +6,8 @@ const pkg = require('@root/package.json');
 const InterceptorManager = require('@commons/service/interceptor-manager');
 const InterceptorManager = require('@commons/service/interceptor-manager');
 const CdnResourcesService = require('@commons/service/cdn-resources-service');
 const CdnResourcesService = require('@commons/service/cdn-resources-service');
 const Xss = require('@commons/service/xss');
 const Xss = require('@commons/service/xss');
-const { getMongoUri } = require('@commons/util/mongoose-utils');
+const { getMongoUri, mongoOptions } = require('@commons/util/mongoose-utils');
 
 
-const fs = require('fs');
 const path = require('path');
 const path = require('path');
 
 
 const sep = path.sep;
 const sep = path.sep;
@@ -16,7 +15,6 @@ const sep = path.sep;
 const mongoose = require('mongoose');
 const mongoose = require('mongoose');
 
 
 const models = require('../models');
 const models = require('../models');
-const initMiddlewares = require('../middlewares');
 
 
 const PluginService = require('../plugins/plugin.service');
 const PluginService = require('../plugins/plugin.service');
 
 
@@ -34,10 +32,6 @@ function Crowi(rootdir) {
   this.viewsDir = path.join(this.libDir, 'views') + sep;
   this.viewsDir = path.join(this.libDir, 'views') + sep;
   this.resourceDir = path.join(this.rootDir, 'resource') + sep;
   this.resourceDir = path.join(this.rootDir, 'resource') + sep;
   this.localeDir = path.join(this.resourceDir, 'locales') + sep;
   this.localeDir = path.join(this.resourceDir, 'locales') + sep;
-  this.locales = fs.readdirSync(this.localeDir)
-    .filter((filename) => {
-      return fs.statSync(path.join(this.localeDir, filename)).isDirectory();
-    });
   this.tmpDir = path.join(this.rootDir, 'tmp') + sep;
   this.tmpDir = path.join(this.rootDir, 'tmp') + sep;
   this.cacheDir = path.join(this.tmpDir, 'cache');
   this.cacheDir = path.join(this.tmpDir, 'cache');
 
 
@@ -63,7 +57,6 @@ function Crowi(rootdir) {
   this.tokens = null;
   this.tokens = null;
 
 
   this.models = {};
   this.models = {};
-  this.middlewares = {};
 
 
   this.env = process.env;
   this.env = process.env;
   this.node_env = this.env.NODE_ENV || 'development';
   this.node_env = this.env.NODE_ENV || 'development';
@@ -83,7 +76,6 @@ function Crowi(rootdir) {
 Crowi.prototype.init = async function() {
 Crowi.prototype.init = async function() {
   await this.setupDatabase();
   await this.setupDatabase();
   await this.setupModels();
   await this.setupModels();
-  await this.setupMiddlewares();
   await this.setupSessionConfig();
   await this.setupSessionConfig();
   await this.setupConfigManager();
   await this.setupConfigManager();
 
 
@@ -205,7 +197,7 @@ Crowi.prototype.setupDatabase = function() {
   // mongoUri = mongodb://user:password@host/dbname
   // mongoUri = mongodb://user:password@host/dbname
   const mongoUri = getMongoUri();
   const mongoUri = getMongoUri();
 
 
-  return mongoose.connect(mongoUri, { useNewUrlParser: true });
+  return mongoose.connect(mongoUri, mongoOptions);
 };
 };
 
 
 Crowi.prototype.setupSessionConfig = async function() {
 Crowi.prototype.setupSessionConfig = async function() {
@@ -266,11 +258,6 @@ Crowi.prototype.setupModels = async function() {
   });
   });
 };
 };
 
 
-Crowi.prototype.setupMiddlewares = async function() {
-  // const self = this;
-  this.middlewares = await initMiddlewares(this);
-};
-
 Crowi.prototype.getIo = function() {
 Crowi.prototype.getIo = function() {
   return this.io;
   return this.io;
 };
 };

+ 0 - 30
src/server/middlewares/ApiV3FormValidator.js

@@ -1,30 +0,0 @@
-const logger = require('@alias/logger')('growi:middlewares:ApiV3FormValidator');
-const { validationResult } = require('express-validator/check');
-
-const ErrorV3 = require('../models/vo/error-apiv3');
-
-class ApiV3FormValidator {
-
-  constructor(crowi) {
-    return (req, res, next) => {
-      logger.debug('req.query', req.query);
-      logger.debug('req.params', req.params);
-      logger.debug('req.body', req.body);
-
-      const errObjArray = validationResult(req);
-      if (errObjArray.isEmpty()) {
-        return next();
-      }
-
-      const errs = errObjArray.array().map((err) => {
-        logger.error(`${err.location}.${err.param}: ${err.value} - ${err.msg}`);
-        return new ErrorV3(`${err.param}: ${err.msg}`, 'validation_failed');
-      });
-
-      return res.apiv3Err(errs);
-    };
-  }
-
-}
-
-module.exports = ApiV3FormValidator;

+ 0 - 0
src/server/middleware/access-token-parser.js → src/server/middlewares/access-token-parser.js


+ 0 - 0
src/server/middleware/admin-required.js → src/server/middlewares/admin-required.js


+ 22 - 0
src/server/middlewares/apiv3-form-validator.js

@@ -0,0 +1,22 @@
+const logger = require('@alias/logger')('growi:middlewares:ApiV3FormValidator');
+const { validationResult } = require('express-validator/check');
+
+const ErrorV3 = require('../models/vo/error-apiv3');
+
+module.exports = () => (req, res, next) => {
+  logger.debug('req.query', req.query);
+  logger.debug('req.params', req.params);
+  logger.debug('req.body', req.body);
+
+  const errObjArray = validationResult(req);
+  if (errObjArray.isEmpty()) {
+    return next();
+  }
+
+  const errs = errObjArray.array().map((err) => {
+    logger.error(`${err.location}.${err.param}: ${err.value} - ${err.msg}`);
+    return new ErrorV3(`${err.param}: ${err.msg}`, 'validation_failed');
+  });
+
+  return res.apiv3Err(errs);
+};

+ 13 - 0
src/server/middlewares/application-installed.js

@@ -0,0 +1,13 @@
+module.exports = (crowi) => {
+  const { appService } = crowi;
+
+  return async(req, res, next) => {
+    const isInstalled = await appService.isDBInitialized();
+
+    if (!isInstalled) {
+      return res.redirect('/installer');
+    }
+
+    return next();
+  };
+};

+ 14 - 0
src/server/middlewares/application-not-installed.js

@@ -0,0 +1,14 @@
+module.exports = (crowi) => {
+  const { appService } = crowi;
+
+  return async(req, res, next) => {
+    const isInstalled = await appService.isDBInitialized();
+
+    if (isInstalled) {
+      req.flash('errorMessage', req.t('message.application_already_installed'));
+      return res.redirect('admin');
+    }
+
+    return next();
+  };
+};

+ 0 - 0
src/server/middleware/csrf.js → src/server/middlewares/csrf.js


+ 0 - 21
src/server/middlewares/index.js

@@ -1,21 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-
-const initMiddlewares = (crowi) => {
-  const basename = path.basename(__filename);
-  const middlewares = {};
-
-  fs
-    .readdirSync(__dirname)
-    .filter((file) => {
-      return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
-    })
-    .forEach((file) => {
-      const Middleware = require(path.join(__dirname, file));
-      middlewares[file.slice(0, -3)] = new Middleware(crowi);
-    });
-
-  return middlewares;
-};
-
-module.exports = initMiddlewares;

+ 6 - 0
src/server/middlewares/inject-currentuser-to-localvars.js

@@ -0,0 +1,6 @@
+module.exports = () => {
+  return (req, res, next) => {
+    res.locals.user = req.user;
+    next();
+  };
+};

+ 0 - 0
src/server/middleware/login-required.js → src/server/middlewares/login-required.js


+ 1 - 1
src/server/middleware/safe-redirect.js → src/server/middlewares/safe-redirect.js

@@ -1,7 +1,7 @@
 /**
 /**
  * Redirect with prevention from Open Redirect
  * Redirect with prevention from Open Redirect
  *
  *
- * Usage: app.use(require('middleware/safe-redirect')(['example.com', 'some.example.com:8080']))
+ * Usage: app.use(require('middlewares/safe-redirect')(['example.com', 'some.example.com:8080']))
  */
  */
 
 
 const loggerFactory = require('@alias/logger');
 const loggerFactory = require('@alias/logger');

+ 1 - 1
src/server/models/config.js

@@ -38,7 +38,7 @@ module.exports = function(crowi) {
       'app:confidential'  : undefined,
       'app:confidential'  : undefined,
 
 
       'app:fileUpload'    : false,
       'app:fileUpload'    : false,
-      'app:globalLang'    : 'en-US',
+      'app:globalLang'    : 'en_US',
 
 
       'security:restrictGuestMode'      : 'Deny',
       'security:restrictGuestMode'      : 'Deny',
 
 

+ 5 - 24
src/server/models/user.js

@@ -11,6 +11,8 @@ const md5 = require('md5');
 const ObjectId = mongoose.Schema.Types.ObjectId;
 const ObjectId = mongoose.Schema.Types.ObjectId;
 const crypto = require('crypto');
 const crypto = require('crypto');
 
 
+const { listLocaleIds } = require('@commons/util/locale-utils');
+
 module.exports = function(crowi) {
 module.exports = function(crowi) {
   const STATUS_REGISTERED = 1;
   const STATUS_REGISTERED = 1;
   const STATUS_ACTIVE = 2;
   const STATUS_ACTIVE = 2;
@@ -22,11 +24,6 @@ module.exports = function(crowi) {
   /* eslint-disable no-unused-vars */
   /* eslint-disable no-unused-vars */
   const IMAGE_POPULATION = { path: 'imageAttachment', select: 'filePathProxied' };
   const IMAGE_POPULATION = { path: 'imageAttachment', select: 'filePathProxied' };
 
 
-  const LANG_EN = 'en';
-  const LANG_EN_US = 'en-US';
-  const LANG_EN_GB = 'en-GB';
-  const LANG_JA = 'ja';
-
   const PAGE_ITEMS = 50;
   const PAGE_ITEMS = 50;
 
 
   let userEvent;
   let userEvent;
@@ -58,8 +55,8 @@ module.exports = function(crowi) {
     apiToken: { type: String, index: true },
     apiToken: { type: String, index: true },
     lang: {
     lang: {
       type: String,
       type: String,
-      enum: crowi.locales,
-      default: LANG_EN_US,
+      enum: listLocaleIds(),
+      default: 'en_US',
     },
     },
     status: {
     status: {
       type: Number, required: true, default: STATUS_ACTIVE, index: true,
       type: Number, required: true, default: STATUS_ACTIVE, index: true,
@@ -146,16 +143,6 @@ module.exports = function(crowi) {
     return hasher.digest('base64');
     return hasher.digest('base64');
   }
   }
 
 
-  function getLanguageLabels() {
-    const lang = {};
-    lang.LANG_EN = LANG_EN;
-    lang.LANG_EN_US = LANG_EN_US;
-    lang.LANG_EN_GB = LANG_EN_GB;
-    lang.LANG_JA = LANG_JA;
-
-    return lang;
-  }
-
   userSchema.methods.isPasswordSet = function() {
   userSchema.methods.isPasswordSet = function() {
     if (this.password) {
     if (this.password) {
       return true;
       return true;
@@ -354,7 +341,6 @@ module.exports = function(crowi) {
     });
     });
   };
   };
 
 
-  userSchema.statics.getLanguageLabels = getLanguageLabels;
   userSchema.statics.getUserStatusLabels = function() {
   userSchema.statics.getUserStatusLabels = function() {
     const userStatus = {};
     const userStatus = {};
     userStatus[STATUS_REGISTERED] = 'Approval Pending';
     userStatus[STATUS_REGISTERED] = 'Approval Pending';
@@ -632,7 +618,7 @@ module.exports = function(crowi) {
         return mailer.send({
         return mailer.send({
           to: user.email,
           to: user.email,
           subject: `Invitation to ${appTitle}`,
           subject: `Invitation to ${appTitle}`,
-          template: path.join(crowi.localeDir, 'en-US/admin/userInvitation.txt'),
+          template: path.join(crowi.localeDir, 'en_US/admin/userInvitation.txt'),
           vars: {
           vars: {
             email: user.email,
             email: user.email,
             password: user.password,
             password: user.password,
@@ -767,10 +753,5 @@ module.exports = function(crowi) {
   userSchema.statics.IMAGE_POPULATION = IMAGE_POPULATION;
   userSchema.statics.IMAGE_POPULATION = IMAGE_POPULATION;
   userSchema.statics.PAGE_ITEMS = PAGE_ITEMS;
   userSchema.statics.PAGE_ITEMS = PAGE_ITEMS;
 
 
-  userSchema.statics.LANG_EN = LANG_EN;
-  userSchema.statics.LANG_EN_US = LANG_EN_US;
-  userSchema.statics.LANG_EN_GB = LANG_EN_US;
-  userSchema.statics.LANG_JA = LANG_JA;
-
   return mongoose.model('User', userSchema);
   return mongoose.model('User', userSchema);
 };
 };

+ 2 - 2
src/server/routes/apiv3/admin-home.js

@@ -41,8 +41,8 @@ const router = express.Router();
  */
  */
 
 
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
+  const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
 
 
   /**
   /**
    * @swagger
    * @swagger

+ 14 - 13
src/server/routes/apiv3/app-settings.js

@@ -6,6 +6,8 @@ const debug = require('debug')('growi:routes:admin');
 
 
 const express = require('express');
 const express = require('express');
 
 
+const { listLocaleIds } = require('@commons/util/locale-utils');
+
 const router = express.Router();
 const router = express.Router();
 
 
 const { body } = require('express-validator/check');
 const { body } = require('express-validator/check');
@@ -96,19 +98,18 @@ const ErrorV3 = require('../../models/vo/error-apiv3');
  */
  */
 
 
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const accessTokenParser = require('../../middleware/access-token-parser')(crowi);
-  const loginRequired = require('../../middleware/login-required')(crowi);
-  const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
-
-  const { ApiV3FormValidator } = crowi.middlewares;
+  const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
+  const loginRequired = require('../../middlewares/login-required')(crowi);
+  const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
   const validator = {
   const validator = {
     appSetting: [
     appSetting: [
       body('title').trim(),
       body('title').trim(),
       body('confidential'),
       body('confidential'),
-      body('globalLang').isIn(crowi.locales),
+      body('globalLang').isIn(listLocaleIds()),
       body('fileUpload').isBoolean(),
       body('fileUpload').isBoolean(),
     ],
     ],
     siteUrlSetting: [
     siteUrlSetting: [
@@ -201,7 +202,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/AppSettingParams'
    *                  $ref: '#/components/schemas/AppSettingParams'
    */
    */
-  router.put('/app-setting', loginRequiredStrictly, adminRequired, csrf, validator.appSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/app-setting', loginRequiredStrictly, adminRequired, csrf, validator.appSetting, apiV3FormValidator, async(req, res) => {
     const requestAppSettingParams = {
     const requestAppSettingParams = {
       'app:title': req.body.title,
       'app:title': req.body.title,
       'app:confidential': req.body.confidential,
       'app:confidential': req.body.confidential,
@@ -250,7 +251,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/SiteUrlSettingParams'
    *                  $ref: '#/components/schemas/SiteUrlSettingParams'
    */
    */
-  router.put('/site-url-setting', loginRequiredStrictly, adminRequired, csrf, validator.siteUrlSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/site-url-setting', loginRequiredStrictly, adminRequired, csrf, validator.siteUrlSetting, apiV3FormValidator, async(req, res) => {
 
 
     const requestSiteUrlSettingParams = {
     const requestSiteUrlSettingParams = {
       'app:siteUrl': req.body.siteUrl,
       'app:siteUrl': req.body.siteUrl,
@@ -342,7 +343,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/MailSettingParams'
    *                  $ref: '#/components/schemas/MailSettingParams'
    */
    */
-  router.put('/mail-setting', loginRequiredStrictly, adminRequired, csrf, validator.mailSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/mail-setting', loginRequiredStrictly, adminRequired, csrf, validator.mailSetting, apiV3FormValidator, async(req, res) => {
     // テストメール送信によるバリデート
     // テストメール送信によるバリデート
     try {
     try {
       await validateMailSetting(req);
       await validateMailSetting(req);
@@ -404,7 +405,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/AwsSettingParams'
    *                  $ref: '#/components/schemas/AwsSettingParams'
    */
    */
-  router.put('/aws-setting', loginRequiredStrictly, adminRequired, csrf, validator.awsSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/aws-setting', loginRequiredStrictly, adminRequired, csrf, validator.awsSetting, apiV3FormValidator, async(req, res) => {
     const requestAwsSettingParams = {
     const requestAwsSettingParams = {
       'aws:region': req.body.region,
       'aws:region': req.body.region,
       'aws:customEndpoint': req.body.customEndpoint,
       'aws:customEndpoint': req.body.customEndpoint,
@@ -455,7 +456,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/PluginSettingParams'
    *                  $ref: '#/components/schemas/PluginSettingParams'
    */
    */
-  router.put('/plugin-setting', loginRequiredStrictly, adminRequired, csrf, validator.pluginSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/plugin-setting', loginRequiredStrictly, adminRequired, csrf, validator.pluginSetting, apiV3FormValidator, async(req, res) => {
     const requestPluginSettingParams = {
     const requestPluginSettingParams = {
       'plugin:isEnabledPlugins': req.body.isEnabledPlugins,
       'plugin:isEnabledPlugins': req.body.isEnabledPlugins,
     };
     };

+ 5 - 5
src/server/routes/apiv3/bookmarks.js

@@ -53,12 +53,12 @@ const router = express.Router();
  */
  */
 
 
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const accessTokenParser = require('../../middleware/access-token-parser')(crowi);
-  const loginRequired = require('../../middleware/login-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
+  const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
+  const loginRequired = require('../../middlewares/login-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
   const { Page, Bookmark } = crowi.models;
   const { Page, Bookmark } = crowi.models;
-  const { ApiV3FormValidator } = crowi.middlewares;
 
 
   const validator = {
   const validator = {
     bookmarks: [
     bookmarks: [
@@ -126,7 +126,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/Bookmark'
    *                  $ref: '#/components/schemas/Bookmark'
    */
    */
-  router.put('/', accessTokenParser, loginRequired, csrf, validator.bookmarks, ApiV3FormValidator, async(req, res) => {
+  router.put('/', accessTokenParser, loginRequired, csrf, validator.bookmarks, apiV3FormValidator, async(req, res) => {
     const { pageId, bool } = req.body;
     const { pageId, bool } = req.body;
 
 
     let bookmark;
     let bookmark;

+ 13 - 14
src/server/routes/apiv3/customize-setting.js

@@ -79,13 +79,12 @@ const ErrorV3 = require('../../models/vo/error-apiv3');
  *            type: string
  *            type: string
  */
  */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
-  const { customizeService } = crowi;
-
+  const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
-  const { ApiV3FormValidator } = crowi.middlewares;
+  const { customizeService } = crowi;
 
 
   const validator = {
   const validator = {
     themeAssetPath: [
     themeAssetPath: [
@@ -194,7 +193,7 @@ module.exports = (crowi) => {
    *                    assetPath:
    *                    assetPath:
    *                      type: string
    *                      type: string
    */
    */
-  router.get('/layout-theme/asset-path', loginRequiredStrictly, adminRequired, validator.themeAssetPath, ApiV3FormValidator, async(req, res) => {
+  router.get('/layout-theme/asset-path', loginRequiredStrictly, adminRequired, validator.themeAssetPath, apiV3FormValidator, async(req, res) => {
     const themeName = req.query.themeName;
     const themeName = req.query.themeName;
 
 
     const webpackAssetKey = `styles/theme-${themeName}.css`;
     const webpackAssetKey = `styles/theme-${themeName}.css`;
@@ -230,7 +229,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeLayoutTheme'
    *                  $ref: '#/components/schemas/CustomizeLayoutTheme'
    */
    */
-  router.put('/layout-theme', loginRequiredStrictly, adminRequired, csrf, validator.layoutTheme, ApiV3FormValidator, async(req, res) => {
+  router.put('/layout-theme', loginRequiredStrictly, adminRequired, csrf, validator.layoutTheme, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:layout': req.body.layoutType,
       'customize:layout': req.body.layoutType,
       'customize:theme': req.body.themeType,
       'customize:theme': req.body.themeType,
@@ -274,7 +273,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeFunction'
    *                  $ref: '#/components/schemas/CustomizeFunction'
    */
    */
-  router.put('/function', loginRequiredStrictly, adminRequired, csrf, validator.function, ApiV3FormValidator, async(req, res) => {
+  router.put('/function', loginRequiredStrictly, adminRequired, csrf, validator.function, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:isEnabledTimeline': req.body.isEnabledTimeline,
       'customize:isEnabledTimeline': req.body.isEnabledTimeline,
       'customize:isSavedStatesOfTabChanges': req.body.isSavedStatesOfTabChanges,
       'customize:isSavedStatesOfTabChanges': req.body.isSavedStatesOfTabChanges,
@@ -326,7 +325,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeHighlight'
    *                  $ref: '#/components/schemas/CustomizeHighlight'
    */
    */
-  router.put('/highlight', loginRequiredStrictly, adminRequired, csrf, validator.highlight, ApiV3FormValidator, async(req, res) => {
+  router.put('/highlight', loginRequiredStrictly, adminRequired, csrf, validator.highlight, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:highlightJsStyle': req.body.highlightJsStyle,
       'customize:highlightJsStyle': req.body.highlightJsStyle,
       'customize:highlightJsStyleBorder': req.body.highlightJsStyleBorder,
       'customize:highlightJsStyleBorder': req.body.highlightJsStyleBorder,
@@ -370,7 +369,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeTitle'
    *                  $ref: '#/components/schemas/CustomizeTitle'
    */
    */
-  router.put('/customize-title', loginRequiredStrictly, adminRequired, csrf, validator.customizeTitle, ApiV3FormValidator, async(req, res) => {
+  router.put('/customize-title', loginRequiredStrictly, adminRequired, csrf, validator.customizeTitle, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:title': req.body.customizeTitle,
       'customize:title': req.body.customizeTitle,
     };
     };
@@ -413,7 +412,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeHeader'
    *                  $ref: '#/components/schemas/CustomizeHeader'
    */
    */
-  router.put('/customize-header', loginRequiredStrictly, adminRequired, csrf, validator.customizeHeader, ApiV3FormValidator, async(req, res) => {
+  router.put('/customize-header', loginRequiredStrictly, adminRequired, csrf, validator.customizeHeader, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:header': req.body.customizeHeader,
       'customize:header': req.body.customizeHeader,
     };
     };
@@ -454,7 +453,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeCss'
    *                  $ref: '#/components/schemas/CustomizeCss'
    */
    */
-  router.put('/customize-css', loginRequiredStrictly, adminRequired, csrf, validator.customizeCss, ApiV3FormValidator, async(req, res) => {
+  router.put('/customize-css', loginRequiredStrictly, adminRequired, csrf, validator.customizeCss, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:css': req.body.customizeCss,
       'customize:css': req.body.customizeCss,
     };
     };
@@ -496,7 +495,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeScript'
    *                  $ref: '#/components/schemas/CustomizeScript'
    */
    */
-  router.put('/customize-script', loginRequiredStrictly, adminRequired, csrf, validator.customizeScript, ApiV3FormValidator, async(req, res) => {
+  router.put('/customize-script', loginRequiredStrictly, adminRequired, csrf, validator.customizeScript, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:script': req.body.customizeScript,
       'customize:script': req.body.customizeScript,
     };
     };

+ 4 - 4
src/server/routes/apiv3/export.js

@@ -38,10 +38,10 @@ const router = express.Router();
  */
  */
 
 
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const accessTokenParser = require('../../middleware/access-token-parser')(crowi);
-  const loginRequired = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
+  const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
+  const loginRequired = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const { exportService } = crowi;
   const { exportService } = crowi;
 
 

+ 4 - 4
src/server/routes/apiv3/import.js

@@ -61,10 +61,10 @@ const generateOverwriteParams = (collectionName, req, options) => {
 
 
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const { growiBridgeService, importService } = crowi;
   const { growiBridgeService, importService } = crowi;
-  const accessTokenParser = require('../../middleware/access-token-parser')(crowi);
-  const loginRequired = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
+  const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
+  const loginRequired = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   this.adminEvent = crowi.event('admin');
   this.adminEvent = crowi.event('admin');
 
 

+ 7 - 8
src/server/routes/apiv3/markdown-setting.js

@@ -82,11 +82,10 @@ const validator = {
  */
  */
 
 
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
-
-  const { ApiV3FormValidator } = crowi.middlewares;
+  const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
   /**
   /**
    * @swagger
    * @swagger
@@ -146,7 +145,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
   *                   $ref: '#/components/schemas/LineBreakParams'
   *                   $ref: '#/components/schemas/LineBreakParams'
    */
    */
-  router.put('/lineBreak', loginRequiredStrictly, adminRequired, csrf, validator.lineBreak, ApiV3FormValidator, async(req, res) => {
+  router.put('/lineBreak', loginRequiredStrictly, adminRequired, csrf, validator.lineBreak, apiV3FormValidator, async(req, res) => {
 
 
     const requestLineBreakParams = {
     const requestLineBreakParams = {
       'markdown:isEnabledLinebreaks': req.body.isEnabledLinebreaks,
       'markdown:isEnabledLinebreaks': req.body.isEnabledLinebreaks,
@@ -192,7 +191,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/PresentationParams'
    *                  $ref: '#/components/schemas/PresentationParams'
    */
    */
-  router.put('/presentation', loginRequiredStrictly, adminRequired, csrf, validator.presentationSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/presentation', loginRequiredStrictly, adminRequired, csrf, validator.presentationSetting, apiV3FormValidator, async(req, res) => {
     if (req.body.pageBreakSeparator === 3 && req.body.pageBreakCustomSeparator === '') {
     if (req.body.pageBreakSeparator === 3 && req.body.pageBreakCustomSeparator === '') {
       return res.apiv3Err(new ErrorV3('customRegularExpression is required'));
       return res.apiv3Err(new ErrorV3('customRegularExpression is required'));
     }
     }
@@ -241,7 +240,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/XssParams'
    *                  $ref: '#/components/schemas/XssParams'
    */
    */
-  router.put('/xss', loginRequiredStrictly, adminRequired, csrf, validator.xssSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/xss', loginRequiredStrictly, adminRequired, csrf, validator.xssSetting, apiV3FormValidator, async(req, res) => {
     if (req.body.isEnabledXss && req.body.xssOption == null) {
     if (req.body.isEnabledXss && req.body.xssOption == null) {
       return res.apiv3Err(new ErrorV3('xss option is required'));
       return res.apiv3Err(new ErrorV3('xss option is required'));
     }
     }

+ 9 - 10
src/server/routes/apiv3/notification-setting.js

@@ -102,15 +102,14 @@ const validator = {
  *              description: trigger events for notify
  *              description: trigger events for notify
  */
  */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
+  const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
   const UpdatePost = crowi.model('UpdatePost');
   const UpdatePost = crowi.model('UpdatePost');
   const GlobalNotificationSetting = crowi.model('GlobalNotificationSetting');
   const GlobalNotificationSetting = crowi.model('GlobalNotificationSetting');
 
 
-  const { ApiV3FormValidator } = crowi.middlewares;
-
   const GlobalNotificationMailSetting = crowi.models.GlobalNotificationMailSetting;
   const GlobalNotificationMailSetting = crowi.models.GlobalNotificationMailSetting;
   const GlobalNotificationSlackSetting = crowi.models.GlobalNotificationSlackSetting;
   const GlobalNotificationSlackSetting = crowi.models.GlobalNotificationSlackSetting;
 
 
@@ -167,7 +166,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/SlackConfigurationParams'
    *                  $ref: '#/components/schemas/SlackConfigurationParams'
    */
    */
-  router.put('/slack-configuration', loginRequiredStrictly, adminRequired, csrf, validator.slackConfiguration, ApiV3FormValidator, async(req, res) => {
+  router.put('/slack-configuration', loginRequiredStrictly, adminRequired, csrf, validator.slackConfiguration, apiV3FormValidator, async(req, res) => {
 
 
     const requestParams = {
     const requestParams = {
       'slack:incomingWebhookUrl': req.body.webhookUrl,
       'slack:incomingWebhookUrl': req.body.webhookUrl,
@@ -220,7 +219,7 @@ module.exports = (crowi) => {
   *                      type: object
   *                      type: object
   *                      description: user trigger notifications for updated
   *                      description: user trigger notifications for updated
   */
   */
-  router.post('/user-notification', loginRequiredStrictly, adminRequired, csrf, validator.userNotification, ApiV3FormValidator, async(req, res) => {
+  router.post('/user-notification', loginRequiredStrictly, adminRequired, csrf, validator.userNotification, apiV3FormValidator, async(req, res) => {
     const { pathPattern, channel } = req.body;
     const { pathPattern, channel } = req.body;
     const UpdatePost = crowi.model('UpdatePost');
     const UpdatePost = crowi.model('UpdatePost');
 
 
@@ -305,7 +304,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: notification param created
    *                      description: notification param created
    */
    */
-  router.post('/global-notification', loginRequiredStrictly, adminRequired, csrf, validator.globalNotification, ApiV3FormValidator, async(req, res) => {
+  router.post('/global-notification', loginRequiredStrictly, adminRequired, csrf, validator.globalNotification, apiV3FormValidator, async(req, res) => {
 
 
     const {
     const {
       notifyToType, toEmail, slackChannels, triggerPath, triggerEvents,
       notifyToType, toEmail, slackChannels, triggerPath, triggerEvents,
@@ -368,7 +367,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: notification param updated
    *                      description: notification param updated
    */
    */
-  router.put('/global-notification/:id', loginRequiredStrictly, adminRequired, csrf, validator.globalNotification, ApiV3FormValidator, async(req, res) => {
+  router.put('/global-notification/:id', loginRequiredStrictly, adminRequired, csrf, validator.globalNotification, apiV3FormValidator, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
     const {
     const {
       notifyToType, toEmail, slackChannels, triggerPath, triggerEvents,
       notifyToType, toEmail, slackChannels, triggerPath, triggerEvents,
@@ -439,7 +438,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/NotifyForPageGrant'
    *                  $ref: '#/components/schemas/NotifyForPageGrant'
    */
    */
-  router.put('/notify-for-page-grant', loginRequiredStrictly, adminRequired, csrf, validator.notifyForPageGrant, ApiV3FormValidator, async(req, res) => {
+  router.put('/notify-for-page-grant', loginRequiredStrictly, adminRequired, csrf, validator.notifyForPageGrant, apiV3FormValidator, async(req, res) => {
 
 
     let requestParams = {
     let requestParams = {
       'notification:owner-page:isEnabled': req.body.isNotificationForOwnerPageEnabled,
       'notification:owner-page:isEnabled': req.body.isNotificationForOwnerPageEnabled,

+ 5 - 6
src/server/routes/apiv3/page.js

@@ -111,14 +111,13 @@ const router = express.Router();
  *            description: boolean for like status
  *            description: boolean for like status
  */
  */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const accessTokenParser = require('../../middleware/access-token-parser')(crowi);
-  const loginRequired = require('../../middleware/login-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
+  const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
+  const loginRequired = require('../../middlewares/login-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
   const globalNotificationService = crowi.getGlobalNotificationService();
   const globalNotificationService = crowi.getGlobalNotificationService();
   const { Page, GlobalNotificationSetting } = crowi.models;
   const { Page, GlobalNotificationSetting } = crowi.models;
-  const { ApiV3FormValidator } = crowi.middlewares;
-
 
 
   const validator = {
   const validator = {
     likes: [
     likes: [
@@ -149,7 +148,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/Page'
    *                  $ref: '#/components/schemas/Page'
    */
    */
-  router.put('/likes', accessTokenParser, loginRequired, csrf, validator.likes, ApiV3FormValidator, async(req, res) => {
+  router.put('/likes', accessTokenParser, loginRequired, csrf, validator.likes, apiV3FormValidator, async(req, res) => {
     const { pageId, bool } = req.body;
     const { pageId, bool } = req.body;
 
 
     let page;
     let page;

+ 3 - 3
src/server/routes/apiv3/pages.js

@@ -13,9 +13,9 @@ const router = express.Router();
  *    name: Pages
  *    name: Pages
  */
  */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const loginRequired = require('../../middleware/login-required')(crowi, true);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
+  const loginRequired = require('../../middlewares/login-required')(crowi, true);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const Page = crowi.model('Page');
   const Page = crowi.model('Page');
 
 

+ 12 - 12
src/server/routes/apiv3/personal-setting.js

@@ -7,6 +7,8 @@ const express = require('express');
 
 
 const passport = require('passport');
 const passport = require('passport');
 
 
+const { listLocaleIds } = require('@commons/util/locale-utils');
+
 const router = express.Router();
 const router = express.Router();
 
 
 const { body } = require('express-validator/check');
 const { body } = require('express-validator/check');
@@ -63,20 +65,18 @@ const ErrorV3 = require('../../models/vo/error-apiv3');
  *            type: string
  *            type: string
  */
  */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const accessTokenParser = require('../../middleware/access-token-parser')(crowi);
-  const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
+  const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
+  const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
   const { User, ExternalAccount } = crowi.models;
   const { User, ExternalAccount } = crowi.models;
 
 
-
-  const { ApiV3FormValidator } = crowi.middlewares;
-
   const validator = {
   const validator = {
     personal: [
     personal: [
       body('name').isString().not().isEmpty(),
       body('name').isString().not().isEmpty(),
       body('email').isEmail(),
       body('email').isEmail(),
-      body('lang').isString().isIn(crowi.locales),
+      body('lang').isString().isIn(listLocaleIds()),
       body('isEmailPublished').isBoolean(),
       body('isEmailPublished').isBoolean(),
     ],
     ],
     imageType: [
     imageType: [
@@ -153,7 +153,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: personal params
    *                      description: personal params
    */
    */
-  router.put('/', accessTokenParser, loginRequiredStrictly, csrf, validator.personal, ApiV3FormValidator, async(req, res) => {
+  router.put('/', accessTokenParser, loginRequiredStrictly, csrf, validator.personal, apiV3FormValidator, async(req, res) => {
 
 
     try {
     try {
       const user = await User.findOne({ _id: req.user.id });
       const user = await User.findOne({ _id: req.user.id });
@@ -193,7 +193,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: user data
    *                      description: user data
    */
    */
-  router.put('/image-type', accessTokenParser, loginRequiredStrictly, csrf, validator.imageType, ApiV3FormValidator, async(req, res) => {
+  router.put('/image-type', accessTokenParser, loginRequiredStrictly, csrf, validator.imageType, apiV3FormValidator, async(req, res) => {
     const { isGravatarEnabled } = req.body;
     const { isGravatarEnabled } = req.body;
 
 
     try {
     try {
@@ -266,7 +266,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: user data updated
    *                      description: user data updated
    */
    */
-  router.put('/password', accessTokenParser, loginRequiredStrictly, csrf, validator.password, ApiV3FormValidator, async(req, res) => {
+  router.put('/password', accessTokenParser, loginRequiredStrictly, csrf, validator.password, apiV3FormValidator, async(req, res) => {
     const { body, user } = req;
     const { body, user } = req;
     const { oldPassword, newPassword } = body;
     const { oldPassword, newPassword } = body;
 
 
@@ -344,7 +344,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: Ldap account associate to me
    *                      description: Ldap account associate to me
    */
    */
-  router.put('/associate-ldap', accessTokenParser, loginRequiredStrictly, csrf, validator.associateLdap, ApiV3FormValidator, async(req, res) => {
+  router.put('/associate-ldap', accessTokenParser, loginRequiredStrictly, csrf, validator.associateLdap, apiV3FormValidator, async(req, res) => {
     const { passportService } = crowi;
     const { passportService } = crowi;
     const { user, body } = req;
     const { user, body } = req;
     const { username } = body;
     const { username } = body;
@@ -392,7 +392,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: Ldap account disassociate to me
    *                      description: Ldap account disassociate to me
    */
    */
-  router.put('/disassociate-ldap', accessTokenParser, loginRequiredStrictly, csrf, validator.disassociateLdap, ApiV3FormValidator, async(req, res) => {
+  router.put('/disassociate-ldap', accessTokenParser, loginRequiredStrictly, csrf, validator.disassociateLdap, apiV3FormValidator, async(req, res) => {
     const { user, body } = req;
     const { user, body } = req;
     const { providerType, accountId } = body;
     const { providerType, accountId } = body;
 
 

+ 6 - 7
src/server/routes/apiv3/search.js

@@ -17,12 +17,11 @@ const ErrorV3 = require('../../models/vo/error-apiv3');
  *    name: Search
  *    name: Search
  */
  */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const accessTokenParser = require('../../middleware/access-token-parser')(crowi);
-  const loginRequired = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
-
-  const { ApiV3FormValidator } = crowi.middlewares;
+  const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
+  const loginRequired = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
   /**
   /**
    * @swagger
    * @swagger
@@ -114,7 +113,7 @@ module.exports = (crowi) => {
    *        200:
    *        200:
    *          description: Return 200
    *          description: Return 200
    */
    */
-  router.put('/indices', accessTokenParser, loginRequired, adminRequired, csrf, validatorForPutIndices, ApiV3FormValidator, async(req, res) => {
+  router.put('/indices', accessTokenParser, loginRequired, adminRequired, csrf, validatorForPutIndices, apiV3FormValidator, async(req, res) => {
     const operation = req.body.operation;
     const operation = req.body.operation;
 
 
     const { searchService } = crowi;
     const { searchService } = crowi;

+ 14 - 15
src/server/routes/apiv3/security-setting.js

@@ -287,11 +287,10 @@ const validator = {
  *            description: local account automatically linked the email matched
  *            description: local account automatically linked the email matched
  */
  */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
-  const csrf = require('../../middleware/csrf')(crowi);
-
-  const { ApiV3FormValidator } = crowi.middlewares;
+  const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
+  const csrf = require('../../middlewares/csrf')(crowi);
+  const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
   /**
   /**
    * @swagger
    * @swagger
@@ -435,7 +434,7 @@ module.exports = (crowi) => {
    *                  type: object
    *                  type: object
    *                  description: updated param
    *                  description: updated param
    */
    */
-  router.put('/authentication/enabled', loginRequiredStrictly, adminRequired, csrf, validator.authenticationSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/authentication/enabled', loginRequiredStrictly, adminRequired, csrf, validator.authenticationSetting, apiV3FormValidator, async(req, res) => {
     const { isEnabled, authId } = req.body;
     const { isEnabled, authId } = req.body;
 
 
     let setupStrategies = await crowi.passportService.getSetupStrategies();
     let setupStrategies = await crowi.passportService.getSetupStrategies();
@@ -518,7 +517,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/GeneralSetting'
    *                  $ref: '#/components/schemas/GeneralSetting'
    */
    */
-  router.put('/general-setting', loginRequiredStrictly, adminRequired, csrf, validator.generalSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/general-setting', loginRequiredStrictly, adminRequired, csrf, validator.generalSetting, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:restrictGuestMode': req.body.restrictGuestMode,
       'security:restrictGuestMode': req.body.restrictGuestMode,
       'security:pageCompleteDeletionAuthority': req.body.pageCompleteDeletionAuthority,
       'security:pageCompleteDeletionAuthority': req.body.pageCompleteDeletionAuthority,
@@ -568,7 +567,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/LocalSetting'
    *                  $ref: '#/components/schemas/LocalSetting'
    */
    */
-  router.put('/local-setting', loginRequiredStrictly, adminRequired, csrf, validator.localSetting, ApiV3FormValidator, async(req, res) => {
+  router.put('/local-setting', loginRequiredStrictly, adminRequired, csrf, validator.localSetting, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:registrationMode': req.body.registrationMode,
       'security:registrationMode': req.body.registrationMode,
       'security:registrationWhiteList': req.body.registrationWhiteList,
       'security:registrationWhiteList': req.body.registrationWhiteList,
@@ -610,7 +609,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/LdapAuthSetting'
    *                  $ref: '#/components/schemas/LdapAuthSetting'
    */
    */
-  router.put('/ldap', loginRequiredStrictly, adminRequired, csrf, validator.ldapAuth, ApiV3FormValidator, async(req, res) => {
+  router.put('/ldap', loginRequiredStrictly, adminRequired, csrf, validator.ldapAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-ldap:serverUrl': req.body.serverUrl,
       'security:passport-ldap:serverUrl': req.body.serverUrl,
       'security:passport-ldap:isUserBind': req.body.isUserBind,
       'security:passport-ldap:isUserBind': req.body.isUserBind,
@@ -673,7 +672,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/SamlAuthSetting'
    *                  $ref: '#/components/schemas/SamlAuthSetting'
    */
    */
-  router.put('/saml', loginRequiredStrictly, adminRequired, csrf, validator.samlAuth, ApiV3FormValidator, async(req, res) => {
+  router.put('/saml', loginRequiredStrictly, adminRequired, csrf, validator.samlAuth, apiV3FormValidator, async(req, res) => {
 
 
     //  For the value of each mandatory items,
     //  For the value of each mandatory items,
     //  check whether it from the environment variables is empty and form value to update it is empty
     //  check whether it from the environment variables is empty and form value to update it is empty
@@ -764,7 +763,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/OidcAuthSetting'
    *                  $ref: '#/components/schemas/OidcAuthSetting'
    */
    */
-  router.put('/oidc', loginRequiredStrictly, adminRequired, csrf, validator.oidcAuth, ApiV3FormValidator, async(req, res) => {
+  router.put('/oidc', loginRequiredStrictly, adminRequired, csrf, validator.oidcAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-oidc:providerName': req.body.oidcProviderName,
       'security:passport-oidc:providerName': req.body.oidcProviderName,
       'security:passport-oidc:issuerHost': req.body.oidcIssuerHost,
       'security:passport-oidc:issuerHost': req.body.oidcIssuerHost,
@@ -823,7 +822,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/BasicAuthSetting'
    *                  $ref: '#/components/schemas/BasicAuthSetting'
    */
    */
-  router.put('/basic', loginRequiredStrictly, adminRequired, csrf, validator.basicAuth, ApiV3FormValidator, async(req, res) => {
+  router.put('/basic', loginRequiredStrictly, adminRequired, csrf, validator.basicAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-basic:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
       'security:passport-basic:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
     };
     };
@@ -864,7 +863,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/GoogleOAuthSetting'
    *                  $ref: '#/components/schemas/GoogleOAuthSetting'
    */
    */
-  router.put('/google-oauth', loginRequiredStrictly, adminRequired, csrf, validator.googleOAuth, ApiV3FormValidator, async(req, res) => {
+  router.put('/google-oauth', loginRequiredStrictly, adminRequired, csrf, validator.googleOAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-google:clientId': req.body.googleClientId,
       'security:passport-google:clientId': req.body.googleClientId,
       'security:passport-google:clientSecret': req.body.googleClientSecret,
       'security:passport-google:clientSecret': req.body.googleClientSecret,
@@ -909,7 +908,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/GitHubOAuthSetting'
    *                  $ref: '#/components/schemas/GitHubOAuthSetting'
    */
    */
-  router.put('/github-oauth', loginRequiredStrictly, adminRequired, csrf, validator.githubOAuth, ApiV3FormValidator, async(req, res) => {
+  router.put('/github-oauth', loginRequiredStrictly, adminRequired, csrf, validator.githubOAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-github:clientId': req.body.githubClientId,
       'security:passport-github:clientId': req.body.githubClientId,
       'security:passport-github:clientSecret': req.body.githubClientSecret,
       'security:passport-github:clientSecret': req.body.githubClientSecret,
@@ -956,7 +955,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/TwitterOAuthSetting'
    *                  $ref: '#/components/schemas/TwitterOAuthSetting'
    */
    */
-  router.put('/twitter-oauth', loginRequiredStrictly, adminRequired, csrf, validator.twitterOAuth, ApiV3FormValidator, async(req, res) => {
+  router.put('/twitter-oauth', loginRequiredStrictly, adminRequired, csrf, validator.twitterOAuth, apiV3FormValidator, async(req, res) => {
 
 
     let requestParams = {
     let requestParams = {
       'security:passport-twitter:consumerKey': req.body.twitterConsumerKey,
       'security:passport-twitter:consumerKey': req.body.twitterConsumerKey,

+ 2 - 2
src/server/routes/apiv3/user-group-relation.js

@@ -15,8 +15,8 @@ const router = express.Router();
  */
  */
 
 
 module.exports = (crowi) => {
 module.exports = (crowi) => {
-  const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
-  const adminRequired = require('../../middleware/admin-required')(crowi);
+  const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
 
 
   const { UserGroup, UserGroupRelation } = crowi.models;
   const { UserGroup, UserGroupRelation } = crowi.models;
 
 

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff