Sfoglia il codice sorgente

Merge pull request #1380 from weseek/create-passport-local-component

Create passport local component
Yuki Takei 6 anni fa
parent
commit
441a8b0bb2

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

@@ -494,7 +494,8 @@
     "Use default if both are empty": "If both ​​are empty, the default value <code>%s</code> is used.",
     "missing mandatory configs": "The following mandatory items are not set in either database nor environment variables.",
     "Local": {
-      "name": "ID/Password"
+      "name": "ID/Password",
+      "enable_local": "enable ID/Password"
     },
     "ldap": {
       "server_url_detail": "The LDAP URL of the directory service in the format <code>ldap://host:port/DN</code> or <code>ldaps://host:port/DN</code>.",

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

@@ -489,7 +489,8 @@
     "Use default if both are empty": "どちらの値も空の場合、デフォルト値 <code>%s</code> を利用します",
     "missing mandatory configs": "以下の必須項目の値がデータベースと環境変数のどちらにも設定されていません",
     "Local": {
-      "name": "ID/Password"
+      "name": "ID/Password",
+      "enable_local": "ID/Password を有効にする"
     },
     "ldap": {
       "server_url_detail": "LDAP URLを <code>ldap://host:port/DN</code> または <code>ldaps://host:port/DN</code> の形式で入力してください。",

+ 119 - 0
src/client/js/components/Admin/Security/SecurityLocalSetting.jsx

@@ -0,0 +1,119 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+import { createSubscribedElement } from '../../UnstatedUtils';
+
+import AppContainer from '../../../services/AppContainer';
+import AdminSecurityContainer from '../../../services/AdminSecurityContainer';
+
+class SecurityLocalSetting extends React.Component {
+
+  render() {
+    const { t, adminSecurityContainer } = this.props;
+
+    return (
+      <React.Fragment>
+
+        <h2 className="alert-anchor border-bottom">
+          { t('security_setting.Local.name') } { t('security_setting.configuration') }
+        </h2>
+
+        {adminSecurityContainer.state.useOnlyEnvVarsForSomeOptions && (
+        <p className="alert alert-info">
+          { t('security_setting.Local.note for the only env option', 'LOCAL_STRATEGY_USES_ONLY_ENV_VARS_FOR_SOME_OPTIONS') }
+        </p>
+        )}
+
+        <div className="row mb-5">
+          <strong className="col-xs-3 text-right">{ t('security_setting.Local.name') }</strong>
+          <div className="col-xs-6 text-left">
+            <div className="checkbox checkbox-success">
+              <input
+                id="isLocalEnabled"
+                type="checkbox"
+                checked={adminSecurityContainer.state.isLocalEnabled}
+                onChange={() => { adminSecurityContainer.switchIsLocalEnabled() }}
+              />
+              <label htmlFor="isLocalEnabled">
+                { t('security_setting.Local.enable_local') }
+              </label>
+            </div>
+          </div>
+        </div>
+
+        {adminSecurityContainer.state.isLocalEnabled && (
+          <div>
+            <div className="row mb-5">
+              <strong className="col-xs-3 text-right">{ t('Register limitation') }</strong>
+              <div className="col-xs-9 text-left">
+                <div className="my-0 btn-group">
+                  <div className="dropdown">
+                    <button className="btn btn-default dropdown-toggle w-100" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                      <span className="pull-left">{t(`security_setting.registration_mode.${adminSecurityContainer.state.registrationMode}`)}</span>
+                      <span className="bs-caret pull-right">
+                        <span className="caret" />
+                      </span>
+                    </button>
+                    {/* TODO adjust dropdown after BS4 */}
+                    <ul className="dropdown-menu" role="menu">
+                      <li key="open" role="presentation" type="button" onClick={() => { adminSecurityContainer.changeRegistrationMode('open') }}>
+                        <a role="menuitem">{ t('security_setting.registration_mode.open') }</a>
+                      </li>
+                      <li key="restricted" role="presentation" type="button" onClick={() => { adminSecurityContainer.changeRegistrationMode('restricted') }}>
+                        <a role="menuitem">{ t('security_setting.registration_mode.restricted') }</a>
+                      </li>
+                      <li key="closed" role="presentation" type="button" onClick={() => { adminSecurityContainer.changeRegistrationMode('closed') }}>
+                        <a role="menuitem">{ t('security_setting.registration_mode.closed') }</a>
+                      </li>
+                    </ul>
+                  </div>
+                  <p className="help-block">
+                    { t('security_setting.Register limitation desc') }
+                  </p>
+                </div>
+              </div>
+            </div>
+            <div className="row mb-5">
+              {/* eslint-disable-next-line react/no-danger */}
+              <strong className="col-xs-3 text-right" dangerouslySetInnerHTML={{ __html: t('The whitelist of registration permission E-mail address') }} />
+              <div className="col-xs-6">
+                <div>
+                  <textarea
+                    className="form-control"
+                    type="textarea"
+                    name="registrationWhiteList"
+                    placeholder={adminSecurityContainer.state.registrationWhiteList}
+                  />
+                  <p className="help-block small">{ t('security_setting.restrict_emails') }<br />{ t('security_setting.for_instance') }
+                    <code>@growi.org</code>{ t('security_setting.only_those') }<br />
+                    { t('security_setting.insert_single') }
+                  </p>
+                </div>
+              </div>
+            </div>
+          </div>
+        )}
+
+        {/*  TODO replace component */}
+        <div className="col-xs-offset-3 col-xs-6 mb-5">
+          <button type="submit" className="btn btn-primary">{ t('Update') }</button>
+        </div>
+
+      </React.Fragment>
+    );
+  }
+
+}
+
+SecurityLocalSetting.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  adminSecurityContainer: PropTypes.instanceOf(AdminSecurityContainer).isRequired,
+};
+
+const SecurityLocalSettingWrapper = (props) => {
+  return createSubscribedElement(SecurityLocalSetting, props, [AppContainer, AdminSecurityContainer]);
+};
+
+export default withTranslation()(SecurityLocalSettingWrapper);

+ 2 - 1
src/client/js/components/Admin/Security/SecurityManagement.jsx

@@ -5,6 +5,7 @@ import { withTranslation } from 'react-i18next';
 import { createSubscribedElement } from '../../UnstatedUtils';
 
 import AppContainer from '../../../services/AppContainer';
+import SecurityLocalSetting from './SecurityLocalSetting';
 
 class SecurityManagement extends React.Component {
 
@@ -139,7 +140,7 @@ class SecurityManagement extends React.Component {
             </ul>
             <div className="tab-content p-t-10">
               <div id="passport-local" className="tab-pane active" role="tabpanel">
-                {/* TODO GW-542 reactify local.html */}
+                <SecurityLocalSetting />
               </div>
               <div id="passport-ldap" className="tab-pane" role="tabpanel">
                 {/* TODO GW-543 reactify ldap.html */}

+ 36 - 1
src/client/js/services/AdminSecurityContainer.js

@@ -9,7 +9,7 @@ const logger = loggerFactory('growi:services:AdminSecurityContainer');
  * Service container for admin security page (SecurityManagement.jsx)
  * @extends {Container} unstated Container
  */
-export default class AdminUsersContainer extends Container {
+export default class AdminSecurityContainer extends Container {
 
   constructor(appContainer) {
     super();
@@ -17,8 +17,43 @@ export default class AdminUsersContainer extends Container {
     this.appContainer = appContainer;
 
     this.state = {
+      // TODO GW-583 set value
+      useOnlyEnvVarsForSomeOptions: true,
+      isLocalEnabled: true,
+      registrationMode: 'open',
+      registrationWhiteList: '',
     };
 
+    this.init();
+
+    this.switchIsLocalEnabled = this.switchIsLocalEnabled.bind(this);
+    this.changeRegistrationMode = this.changeRegistrationMode.bind(this);
+  }
+
+  init() {
+    // TODO GW-583 fetch config value with api
+  }
+
+
+  /**
+   * Workaround for the mangling in production build to break constructor.name
+   */
+  static getClassName() {
+    return 'AdminSecurityContainer';
+  }
+
+  /**
+   * Switch local enabled
+   */
+  switchIsLocalEnabled() {
+    this.setState({ isLocalEnabled: !this.state.isLocalEnabled });
+  }
+
+  /**
+   * Change registration mode
+   */
+  changeRegistrationMode(value) {
+    this.setState({ registrationMode: value });
   }
 
 }

+ 1 - 0
src/server/views/admin/widget/passport/local.html

@@ -6,6 +6,7 @@
   {% set isLocalEnabled = getConfig('crowi', 'security:passport-local:isEnabled') %}
   {% set useOnlyEnvVars = getConfig('crowi', 'security:passport-local:useOnlyEnvVarsForSomeOptions') %}
 
+  <!-- TODO delete file after reactify-admin -->
   {% if useOnlyEnvVars %}
     <p class="alert alert-info">
       {{ t("security_setting.Local.note for the only env option", "LOCAL_STRATEGY_USES_ONLY_ENV_VARS_FOR_SOME_OPTIONS") }}