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

Merge pull request #1616 from weseek/reactify-admin/null-values-​​are-not-saved

Reactify admin/null values ​​are not saved
itizawa 6 лет назад
Родитель
Сommit
3b2d458a5b

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

@@ -98,7 +98,7 @@ class BasicSecurityManagement extends React.Component {
                 <input
                   id="bindByEmail-basic"
                   type="checkbox"
-                  checked={adminBasicSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
+                  checked={adminBasicSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                   onChange={() => { adminBasicSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                 />
                 <label

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

@@ -117,7 +117,7 @@ class GitHubSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="githubClientId"
-                  value={adminGitHubSecurityContainer.state.githubClientId}
+                  value={adminGitHubSecurityContainer.state.githubClientId || ''}
                   onChange={e => adminGitHubSecurityContainer.changeGitHubClientId(e.target.value)}
                 />
                 <p className="help-block">
@@ -133,7 +133,7 @@ class GitHubSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="githubClientSecret"
-                  defaultValue={adminGitHubSecurityContainer.state.githubClientSecret}
+                  defaultValue={adminGitHubSecurityContainer.state.githubClientSecret || ''}
                   onChange={e => adminGitHubSecurityContainer.changeGitHubClientSecret(e.target.value)}
                 />
                 <p className="help-block">
@@ -148,7 +148,7 @@ class GitHubSecurityManagement extends React.Component {
                   <input
                     id="bindByUserNameGitHub"
                     type="checkbox"
-                    checked={adminGitHubSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
+                    checked={adminGitHubSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                     onChange={() => { adminGitHubSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label

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

@@ -117,7 +117,7 @@ class GoogleSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="googleClientId"
-                  defaultValue={adminGoogleSecurityContainer.state.googleClientId}
+                  defaultValue={adminGoogleSecurityContainer.state.googleClientId || ''}
                   onChange={e => adminGoogleSecurityContainer.changeGoogleClientId(e.target.value)}
                 />
                 <p className="help-block">
@@ -133,7 +133,7 @@ class GoogleSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="googleClientSecret"
-                  defaultValue={adminGoogleSecurityContainer.state.googleClientSecret}
+                  defaultValue={adminGoogleSecurityContainer.state.googleClientSecret || ''}
                   onChange={e => adminGoogleSecurityContainer.changeGoogleClientSecret(e.target.value)}
                 />
                 <p className="help-block">
@@ -148,7 +148,7 @@ class GoogleSecurityManagement extends React.Component {
                   <input
                     id="bindByUserNameGoogle"
                     type="checkbox"
-                    checked={adminGoogleSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
+                    checked={adminGoogleSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                     onChange={() => { adminGoogleSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label

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

@@ -287,7 +287,7 @@ class OidcSecurityManagement extends React.Component {
                   <input
                     id="bindByEmail-oidc"
                     type="checkbox"
-                    checked={adminOidcSecurityContainer.state.isSameEmailTreatedAsIdenticalUser}
+                    checked={adminOidcSecurityContainer.state.isSameEmailTreatedAsIdenticalUser || false}
                     onChange={() => { adminOidcSecurityContainer.switchIsSameEmailTreatedAsIdenticalUser() }}
                   />
                   <label

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

@@ -427,7 +427,7 @@ pWVdnzS1VCO8fKsJ7YYIr+JmHvseph3kFUOI5RqkCcMZlKUv83aUThsTHw==
                   <input
                     id="bindByUserName-SAML"
                     type="checkbox"
-                    checked={adminSamlSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
+                    checked={adminSamlSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                     onChange={() => { adminSamlSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label
@@ -447,7 +447,7 @@ pWVdnzS1VCO8fKsJ7YYIr+JmHvseph3kFUOI5RqkCcMZlKUv83aUThsTHw==
                   <input
                     id="bindByEmail-SAML"
                     type="checkbox"
-                    checked={adminSamlSecurityContainer.state.isSameEmailTreatedAsIdenticalUser}
+                    checked={adminSamlSecurityContainer.state.isSameEmailTreatedAsIdenticalUser || false}
                     onChange={() => { adminSamlSecurityContainer.switchIsSameEmailTreatedAsIdenticalUser() }}
                   />
                   <label

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

@@ -117,7 +117,7 @@ class TwitterSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="TwitterConsumerId"
-                  defaultValue={adminTwitterSecurityContainer.state.twitterConsumerKey}
+                  defaultValue={adminTwitterSecurityContainer.state.twitterConsumerKey || ''}
                   onChange={e => adminTwitterSecurityContainer.changeTwitterConsumerKey(e.target.value)}
                 />
                 <p className="help-block">
@@ -133,7 +133,7 @@ class TwitterSecurityManagement extends React.Component {
                   className="form-control"
                   type="text"
                   name="TwitterConsumerSecret"
-                  defaultValue={adminTwitterSecurityContainer.state.twitterConsumerSecret}
+                  defaultValue={adminTwitterSecurityContainer.state.twitterConsumerSecret || ''}
                   onChange={e => adminTwitterSecurityContainer.changeTwitterConsumerSecret(e.target.value)}
                 />
                 <p className="help-block">
@@ -148,7 +148,7 @@ class TwitterSecurityManagement extends React.Component {
                   <input
                     id="bindByUserNameTwitter"
                     type="checkbox"
-                    checked={adminTwitterSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
+                    checked={adminTwitterSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser || false}
                     onChange={() => { adminTwitterSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   <label

+ 4 - 8
src/client/js/services/AdminBasicSecurityContainer.js

@@ -1,9 +1,6 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminBasicSecurityContainer');
+import removeNullPropertyFromObject from '../../../lib/util/removeNullPropertyFromObject';
 
 /**
  * Service container for admin security page (BasicSecuritySetting.jsx)
@@ -51,11 +48,10 @@ export default class AdminBasicSecurityContainer extends Container {
    * Update basicSetting
    */
   async updateBasicSetting() {
+    let requestParams = { isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser };
 
-    const response = await this.appContainer.apiv3.put('/security-setting/basic', {
-      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
-    });
-
+    requestParams = await removeNullPropertyFromObject(requestParams);
+    const response = await this.appContainer.apiv3.put('/security-setting/basic', requestParams);
     const { securitySettingParams } = response.data;
 
     this.setState({

+ 7 - 6
src/client/js/services/AdminGeneralSecurityContainer.js

@@ -1,10 +1,7 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
 import { toastError } from '../util/apiNotification';
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminGeneralSecurityContainer');
+import removeNullPropertyFromObject from '../../../lib/util/removeNullPropertyFromObject';
 
 /**
  * Service container for admin security page (SecuritySetting.jsx)
@@ -111,12 +108,16 @@ export default class AdminGeneralSecurityContainer extends Container {
    * @return {string} Appearance
    */
   async updateGeneralSecuritySetting() {
-    const response = await this.appContainer.apiv3.put('/security-setting/general-setting', {
+
+    let requestParams = {
       restrictGuestMode: this.state.currentRestrictGuestMode,
       pageCompleteDeletionAuthority: this.state.currentPageCompleteDeletionAuthority,
       hideRestrictedByGroup: !this.state.isShowRestrictedByGroup,
       hideRestrictedByOwner: !this.state.isShowRestrictedByOwner,
-    });
+    };
+
+    requestParams = await removeNullPropertyFromObject(requestParams);
+    const response = await this.appContainer.apiv3.put('/security-setting/general-setting', requestParams);
     const { securitySettingParams } = response.data;
     return securitySettingParams;
   }

+ 6 - 10
src/client/js/services/AdminGitHubSecurityContainer.js

@@ -1,12 +1,9 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
 import { pathUtils } from 'growi-commons';
-
 import urljoin from 'url-join';
+import removeNullPropertyFromObject from '../../../lib/util/removeNullPropertyFromObject';
 
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminGitHubSecurityContainer');
 
 /**
  * Service container for admin security page (GitHubSecurityManagement.jsx)
@@ -23,7 +20,7 @@ export default class AdminGitHubSecurityContainer extends Container {
       appSiteUrl: urljoin(pathUtils.removeTrailingSlash(appContainer.config.crowi.url), '/passport/github/callback'),
       githubClientId: '',
       githubClientSecret: '',
-      isSameUsernameTreatedAsIdenticalUser: true,
+      isSameUsernameTreatedAsIdenticalUser: false,
     };
 
   }
@@ -73,13 +70,12 @@ export default class AdminGitHubSecurityContainer extends Container {
    * Update githubSetting
    */
   async updateGitHubSetting() {
+    const { githubClientId, githubClientSecret, isSameUsernameTreatedAsIdenticalUser } = this.state;
 
-    const response = await this.appContainer.apiv3.put('/security-setting/github-oauth', {
-      githubClientId: this.state.githubClientId,
-      githubClientSecret: this.state.githubClientSecret,
-      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
-    });
+    let requestParams = { githubClientId, githubClientSecret, isSameUsernameTreatedAsIdenticalUser };
 
+    requestParams = await removeNullPropertyFromObject(requestParams);
+    const response = await this.appContainer.apiv3.put('/security-setting/github-oauth', requestParams);
     const { securitySettingParams } = response.data;
 
     this.setState({

+ 7 - 10
src/client/js/services/AdminGoogleSecurityContainer.js

@@ -1,12 +1,8 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
 import { pathUtils } from 'growi-commons';
-
 import urljoin from 'url-join';
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminGoogleSecurityContainer');
+import removeNullPropertyFromObject from '../../../lib/util/removeNullPropertyFromObject';
 
 /**
  * Service container for admin security page (GoogleSecurityManagement.jsx)
@@ -74,13 +70,14 @@ export default class AdminGoogleSecurityContainer extends Container {
    * Update googleSetting
    */
   async updateGoogleSetting() {
+    const { googleClientId, googleClientSecret, isSameUsernameTreatedAsIdenticalUser } = this.state;
 
-    const response = await this.appContainer.apiv3.put('/security-setting/google-oauth', {
-      googleClientId: this.state.googleClientId,
-      googleClientSecret: this.state.googleClientSecret,
-      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
-    });
+    let requestParams = {
+      googleClientId, googleClientSecret, isSameUsernameTreatedAsIdenticalUser,
+    };
 
+    requestParams = await removeNullPropertyFromObject(requestParams);
+    const response = await this.appContainer.apiv3.put('/security-setting/google-oauth', requestParams);
     const { securitySettingParams } = response.data;
 
     this.setState({

+ 34 - 31
src/client/js/services/AdminLdapSecurityContainer.js

@@ -1,9 +1,6 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminLdapSecurityContainer');
+import removeNullPropertyFromObject from '../../../lib/util/removeNullPropertyFromObject';
 
 /**
  * Service container for admin security page (SecurityLdapSetting.jsx)
@@ -151,37 +148,43 @@ export default class AdminLdapSecurityContainer extends Container {
    * Update ldap option
    */
   async updateLdapSetting() {
+    const {
+      serverUrl, isUserBind, ldapBindDN, ldapBindDNPassword, ldapSearchFilter, ldapAttrMapUsername, isSameUsernameTreatedAsIdenticalUser,
+      ldapAttrMapMail, ldapAttrMapName, ldapGroupSearchBase, ldapGroupSearchFilter, ldapGroupDnProperty,
+    } = this.state;
+
+    let requestParams = {
+      serverUrl,
+      isUserBind,
+      ldapBindDN,
+      ldapBindDNPassword,
+      ldapSearchFilter,
+      ldapAttrMapUsername,
+      isSameUsernameTreatedAsIdenticalUser,
+      ldapAttrMapMail,
+      ldapAttrMapName,
+      ldapGroupSearchBase,
+      ldapGroupSearchFilter,
+      ldapGroupDnProperty,
+    };
 
-    const response = await this.appContainer.apiv3.put('/security-setting/ldap', {
-      serverUrl: this.state.serverUrl,
-      isUserBind: this.state.isUserBind,
-      ldapBindDN: this.state.ldapBindDN,
-      ldapBindDNPassword: this.state.ldapBindDNPassword,
-      ldapSearchFilter: this.state.ldapSearchFilter,
-      ldapAttrMapUsername: this.state.ldapAttrMapUsername,
-      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
-      ldapAttrMapMail: this.state.ldapAttrMapMail,
-      ldapAttrMapName: this.state.ldapAttrMapName,
-      ldapGroupSearchBase: this.state.ldapGroupSearchBase,
-      ldapGroupSearchFilter: this.state.ldapGroupSearchFilter,
-      ldapGroupDnProperty: this.state.ldapGroupDnProperty,
-    });
-
+    requestParams = await removeNullPropertyFromObject(requestParams);
+    const response = await this.appContainer.apiv3.put('/security-setting/ldap', requestParams);
     const { securitySettingParams } = response.data;
 
     this.setState({
-      serverUrl: securitySettingParams.serverUrl || '',
-      isUserBind: securitySettingParams.isUserBind || false,
-      ldapBindDN: securitySettingParams.ldapBindDN || '',
-      ldapBindDNPassword: securitySettingParams.ldapBindDNPassword || '',
-      ldapSearchFilter: securitySettingParams.ldapSearchFilter || '',
-      ldapAttrMapUsername: securitySettingParams.ldapAttrMapUsername || '',
-      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser || false,
-      ldapAttrMapMail: securitySettingParams.ldapAttrMapMail || '',
-      ldapAttrMapName: securitySettingParams.ldapAttrMapName || '',
-      ldapGroupSearchBase: securitySettingParams.ldapGroupSearchBase || '',
-      ldapGroupSearchFilter: securitySettingParams.ldapGroupSearchFilter || '',
-      ldapGroupDnProperty: securitySettingParams.ldapGroupDnProperty || '',
+      serverUrl: securitySettingParams.serverUrl,
+      isUserBind: securitySettingParams.isUserBind,
+      ldapBindDN: securitySettingParams.ldapBindDN,
+      ldapBindDNPassword: securitySettingParams.ldapBindDNPassword,
+      ldapSearchFilter: securitySettingParams.ldapSearchFilter,
+      ldapAttrMapUsername: securitySettingParams.ldapAttrMapUsername,
+      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser,
+      ldapAttrMapMail: securitySettingParams.ldapAttrMapMail,
+      ldapAttrMapName: securitySettingParams.ldapAttrMapName,
+      ldapGroupSearchBase: securitySettingParams.ldapGroupSearchBase,
+      ldapGroupSearchFilter: securitySettingParams.ldapGroupSearchFilter,
+      ldapGroupDnProperty: securitySettingParams.ldapGroupDnProperty,
     });
     return response;
   }

+ 0 - 5
src/client/js/services/AdminLocalSecurityContainer.js

@@ -1,10 +1,5 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminLocalSecurityContainer');
-
 /**
  * Service container for admin security page (LocalSecuritySetting.jsx)
  * @extends {Container} unstated Container

+ 30 - 28
src/client/js/services/AdminOidcSecurityContainer.js

@@ -1,12 +1,8 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
 import { pathUtils } from 'growi-commons';
-
 import urljoin from 'url-join';
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminOidcSecurityContainer');
+import removeNullPropertyFromObject from '../../../lib/util/removeNullPropertyFromObject';
 
 /**
  * Service container for admin security page (OidcSecurityManagement.jsx)
@@ -136,33 +132,39 @@ export default class AdminOidcSecurityContainer extends Container {
    * Update OpenID Connect
    */
   async updateOidcSetting() {
+    const {
+      oidcProviderName, oidcIssuerHost, oidcClientId, oidcClientSecret, oidcAttrMapId, oidcAttrMapUserName,
+      oidcAttrMapName, oidcAttrMapEmail, isSameUsernameTreatedAsIdenticalUser, isSameEmailTreatedAsIdenticalUser,
+    } = this.state;
+
+    let requestParams = {
+      oidcProviderName,
+      oidcIssuerHost,
+      oidcClientId,
+      oidcClientSecret,
+      oidcAttrMapId,
+      oidcAttrMapUserName,
+      oidcAttrMapName,
+      oidcAttrMapEmail,
+      isSameUsernameTreatedAsIdenticalUser,
+      isSameEmailTreatedAsIdenticalUser,
+    };
 
-    const response = await this.appContainer.apiv3.put('/security-setting/oidc', {
-      oidcProviderName: this.state.oidcProviderName,
-      oidcIssuerHost: this.state.oidcIssuerHost,
-      oidcClientId: this.state.oidcClientId,
-      oidcClientSecret: this.state.oidcClientSecret,
-      oidcAttrMapId: this.state.oidcAttrMapId,
-      oidcAttrMapUserName: this.state.oidcAttrMapUserName,
-      oidcAttrMapName: this.state.oidcAttrMapName,
-      oidcAttrMapEmail: this.state.oidcAttrMapEmail,
-      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
-      isSameEmailTreatedAsIdenticalUser: this.state.isSameEmailTreatedAsIdenticalUser,
-    });
-
+    requestParams = await removeNullPropertyFromObject(requestParams);
+    const response = await this.appContainer.apiv3.put('/security-setting/oidc', requestParams);
     const { securitySettingParams } = response.data;
 
     this.setState({
-      oidcProviderName: securitySettingParams.oidcProviderName || '',
-      oidcIssuerHost: securitySettingParams.oidcIssuerHost || '',
-      oidcClientId: securitySettingParams.oidcClientId || '',
-      oidcClientSecret: securitySettingParams.oidcClientSecret || '',
-      oidcAttrMapId: securitySettingParams.oidcAttrMapId || '',
-      oidcAttrMapUserName: securitySettingParams.oidcAttrMapUserName || '',
-      oidcAttrMapName: securitySettingParams.oidcAttrMapName || '',
-      oidcAttrMapEmail: securitySettingParams.oidcAttrMapEmail || '',
-      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser || false,
-      isSameEmailTreatedAsIdenticalUser: securitySettingParams.isSameEmailTreatedAsIdenticalUser || false,
+      oidcProviderName: securitySettingParams.oidcProviderName,
+      oidcIssuerHost: securitySettingParams.oidcIssuerHost,
+      oidcClientId: securitySettingParams.oidcClientId,
+      oidcClientSecret: securitySettingParams.oidcClientSecret,
+      oidcAttrMapId: securitySettingParams.oidcAttrMapId,
+      oidcAttrMapUserName: securitySettingParams.oidcAttrMapUserName,
+      oidcAttrMapName: securitySettingParams.oidcAttrMapName,
+      oidcAttrMapEmail: securitySettingParams.oidcAttrMapEmail,
+      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser,
+      isSameEmailTreatedAsIdenticalUser: securitySettingParams.isSameEmailTreatedAsIdenticalUser,
     });
     return response;
   }

+ 30 - 28
src/client/js/services/AdminSamlSecurityContainer.js

@@ -1,12 +1,8 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
 import { pathUtils } from 'growi-commons';
-
 import urljoin from 'url-join';
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminSamlSecurityContainer');
+import removeNullPropertyFromObject from '../../../lib/util/removeNullPropertyFromObject';
 
 /**
  * Service container for admin security page (SecuritySamlSetting.jsx)
@@ -140,34 +136,40 @@ export default class AdminSamlSecurityContainer extends Container {
    * Update saml option
    */
   async updateSamlSetting() {
+    const {
+      samlEntryPoint, samlIssuer, samlCert, samlAttrMapId, samlAttrMapUserName, samlAttrMapMail,
+      samlAttrMapFirstName, samlAttrMapLastName, isSameUsernameTreatedAsIdenticalUser, isSameEmailTreatedAsIdenticalUser,
+    } = this.state;
+
+    let requestParams = {
+      samlEntryPoint,
+      samlIssuer,
+      samlCert,
+      samlAttrMapId,
+      samlAttrMapUserName,
+      samlAttrMapMail,
+      samlAttrMapFirstName,
+      samlAttrMapLastName,
+      isSameUsernameTreatedAsIdenticalUser,
+      isSameEmailTreatedAsIdenticalUser,
+    };
 
-    const response = await this.appContainer.apiv3.put('/security-setting/saml', {
-      samlEntryPoint: this.state.samlEntryPoint,
-      samlIssuer: this.state.samlIssuer,
-      samlCert: this.state.samlCert,
-      samlAttrMapId: this.state.samlAttrMapId,
-      samlAttrMapUserName: this.state.samlAttrMapUserName,
-      samlAttrMapMail: this.state.samlAttrMapMail,
-      samlAttrMapFirstName: this.state.samlAttrMapFirstName,
-      samlAttrMapLastName: this.state.samlAttrMapLastName,
-      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
-      isSameEmailTreatedAsIdenticalUser: this.state.isSameEmailTreatedAsIdenticalUser,
-    });
-
+    requestParams = await removeNullPropertyFromObject(requestParams);
+    const response = await this.appContainer.apiv3.put('/security-setting/saml', requestParams);
     const { securitySettingParams } = response.data;
 
     this.setState({
       missingMandatoryConfigKeys: securitySettingParams.missingMandatoryConfigKeys,
-      samlEntryPoint: securitySettingParams.samlEntryPoint || '',
-      samlIssuer: securitySettingParams.samlIssuer || '',
-      samlCert: securitySettingParams.samlCert || '',
-      samlAttrMapId: securitySettingParams.samlAttrMapId || '',
-      samlAttrMapUserName: securitySettingParams.samlAttrMapUserName || '',
-      samlAttrMapMail: securitySettingParams.samlAttrMapMail || '',
-      samlAttrMapFirstName: securitySettingParams.samlAttrMapFirstName || '',
-      samlAttrMapLastName: securitySettingParams.samlAttrMapLastName || '',
-      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser || false,
-      isSameEmailTreatedAsIdenticalUser: securitySettingParams.isSameEmailTreatedAsIdenticalUser || false,
+      samlEntryPoint: securitySettingParams.samlEntryPoint,
+      samlIssuer: securitySettingParams.samlIssuer,
+      samlCert: securitySettingParams.samlCert,
+      samlAttrMapId: securitySettingParams.samlAttrMapId,
+      samlAttrMapUserName: securitySettingParams.samlAttrMapUserName,
+      samlAttrMapMail: securitySettingParams.samlAttrMapMail,
+      samlAttrMapFirstName: securitySettingParams.samlAttrMapFirstName,
+      samlAttrMapLastName: securitySettingParams.samlAttrMapLastName,
+      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser,
+      isSameEmailTreatedAsIdenticalUser: securitySettingParams.isSameEmailTreatedAsIdenticalUser,
     });
     return response;
   }

+ 2 - 12
src/client/js/services/AdminTwitterSecurityContainer.js

@@ -1,13 +1,9 @@
 import { Container } from 'unstated';
 
-import loggerFactory from '@alias/logger';
 import { pathUtils } from 'growi-commons';
-
 import urljoin from 'url-join';
 import removeNullPropertyFromObject from '../../../lib/util/removeNullPropertyFromObject';
 
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:security:AdminTwitterSecurityContainer');
 
 /**
  * Service container for admin security page (TwitterSecurityManagement.jsx)
@@ -77,16 +73,10 @@ export default class AdminTwitterSecurityContainer extends Container {
   async updateTwitterSetting() {
     const { twitterConsumerKey, twitterConsumerSecret, isSameUsernameTreatedAsIdenticalUser } = this.state;
 
-    let requestParams = {
-      twitterConsumerKey,
-      twitterConsumerSecret,
-      isSameUsernameTreatedAsIdenticalUser,
-    };
-
-    requestParams = removeNullPropertyFromObject(requestParams);
+    let requestParams = { twitterConsumerKey, twitterConsumerSecret, isSameUsernameTreatedAsIdenticalUser };
 
+    requestParams = await removeNullPropertyFromObject(requestParams);
     const response = await this.appContainer.apiv3.put('/security-setting/twitter-oauth', requestParams);
-
     const { securitySettingParams } = response.data;
 
     this.setState({

+ 42 - 42
src/server/routes/apiv3/security-setting.js

@@ -21,11 +21,11 @@ const validator = {
     body('pageCompleteDeletionAuthority').isString().isIn([
       'anyOne', 'adminOnly', 'adminAndAuthor',
     ]),
-    body('hideRestrictedByOwner').isBoolean(),
-    body('hideRestrictedByGroup').isBoolean(),
+    body('hideRestrictedByOwner').if((value, { req }) => req.body.hideRestrictedByOwner).isBoolean(),
+    body('hideRestrictedByGroup').if((value, { req }) => req.body.hideRestrictedByGroup).isBoolean(),
   ],
   authenticationSetting: [
-    body('isEnabled').isBoolean(),
+    body('isEnabled').if((value, { req }) => req.body.isEnabled).isBoolean(),
     body('authId').isString().isIn([
       'local', 'ldap', 'saml', 'oidc', 'basic', 'google', 'github', 'twitter',
     ]),
@@ -34,57 +34,57 @@ const validator = {
     body('registrationMode').isString().isIn([
       'Open', 'Restricted', 'Closed',
     ]),
-    body('registrationWhiteList').isArray(),
+    body('registrationWhiteList').if((value, { req }) => req.body.registrationWhiteList).isArray(),
   ],
   ldapAuth: [
-    body('serverUrl').isString(),
-    body('isUserBind').isBoolean(),
-    body('ldapBindDN').isString(),
-    body('ldapBindDNPassword').isString(),
-    body('ldapSearchFilter').isString(),
-    body('ldapAttrMapUsername').isString(),
-    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
-    body('ldapAttrMapMail').isString(),
-    body('ldapAttrMapName').isString(),
-    body('ldapGroupSearchBase').isString(),
-    body('ldapGroupSearchFilter').isString(),
-    body('ldapGroupDnProperty').isString(),
+    body('serverUrl').if((value, { req }) => req.body.serverUrl).isString(),
+    body('isUserBind').if((value, { req }) => req.body.isUserBind).isBoolean(),
+    body('ldapBindDN').if((value, { req }) => req.body.ldapBindDN).isString(),
+    body('ldapBindDNPassword').if((value, { req }) => req.body.ldapBindDNPassword).isString(),
+    body('ldapSearchFilter').if((value, { req }) => req.body.ldapSearchFilter).isString(),
+    body('ldapAttrMapUsername').if((value, { req }) => req.body.ldapAttrMapUsername).isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').if((value, { req }) => req.body.isSameUsernameTreatedAsIdenticalUser).isBoolean(),
+    body('ldapAttrMapMail').if((value, { req }) => req.body.ldapAttrMapMail).isString(),
+    body('ldapAttrMapName').if((value, { req }) => req.body.ldapAttrMapName).isString(),
+    body('ldapGroupSearchBase').if((value, { req }) => req.body.ldapGroupSearchBase).isString(),
+    body('ldapGroupSearchFilter').if((value, { req }) => req.body.ldapGroupSearchFilter).isString(),
+    body('ldapGroupDnProperty').if((value, { req }) => req.body.ldapGroupDnProperty).isString(),
   ],
   samlAuth: [
-    body('samlEntryPoint').isString(),
-    body('samlIssuer').isString(),
-    body('samlCert').isString(),
-    body('samlAttrMapId').isString(),
-    body('samlAttrMapUserName').isString(),
-    body('samlAttrMapMail').isString(),
-    body('samlAttrMapFirstName').isString(),
-    body('samlAttrMapLastName').isString(),
-    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
-    body('isSameEmailTreatedAsIdenticalUser').isBoolean(),
+    body('samlEntryPoint').if((value, { req }) => req.body.samlEntryPoint).isString(),
+    body('samlIssuer').if((value, { req }) => req.body.samlIssuer).isString(),
+    body('samlCert').if((value, { req }) => req.body.samlCert).isString(),
+    body('samlAttrMapId').if((value, { req }) => req.body.samlAttrMapId).isString(),
+    body('samlAttrMapUserName').if((value, { req }) => req.body.samlAttrMapUserName).isString(),
+    body('samlAttrMapMail').if((value, { req }) => req.body.samlAttrMapMail).isString(),
+    body('samlAttrMapFirstName').if((value, { req }) => req.body.samlAttrMapFirstName).isString(),
+    body('samlAttrMapLastName').if((value, { req }) => req.body.samlAttrMapLastName).isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').if((value, { req }) => req.body.isSameUsernameTreatedAsIdenticalUser).isBoolean(),
+    body('isSameEmailTreatedAsIdenticalUser').if((value, { req }) => req.body.isSameEmailTreatedAsIdenticalUser).isBoolean(),
   ],
   oidcAuth: [
-    body('oidcProviderName').isString(),
-    body('oidcIssuerHost').isString(),
-    body('oidcClientId').isString(),
-    body('oidcClientSecret').isString(),
-    body('oidcAttrMapId').isString(),
-    body('oidcAttrMapUserName').isString(),
-    body('oidcAttrMapEmail').isString(),
-    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
-    body('isSameEmailTreatedAsIdenticalUser').isBoolean(),
+    body('oidcProviderName').if((value, { req }) => req.body.oidcProviderName).isString(),
+    body('oidcIssuerHost').if((value, { req }) => req.body.oidcIssuerHost).isString(),
+    body('oidcClientId').if((value, { req }) => req.body.oidcClientId).isString(),
+    body('oidcClientSecret').if((value, { req }) => req.body.oidcClientSecret).isString(),
+    body('oidcAttrMapId').if((value, { req }) => req.body.oidcAttrMapId).isString(),
+    body('oidcAttrMapUserName').if((value, { req }) => req.body.oidcAttrMapUserName).isString(),
+    body('oidcAttrMapEmail').if((value, { req }) => req.body.oidcAttrMapEmail).isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').if((value, { req }) => req.body.isSameUsernameTreatedAsIdenticalUser).isBoolean(),
+    body('isSameEmailTreatedAsIdenticalUser').if((value, { req }) => req.body.isSameEmailTreatedAsIdenticalUser).isBoolean(),
   ],
   basicAuth: [
-    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
+    body('isSameUsernameTreatedAsIdenticalUser').if((value, { req }) => req.body.isSameUsernameTreatedAsIdenticalUser).isBoolean(),
   ],
   googleOAuth: [
-    body('googleClientId').isString(),
-    body('googleClientSecret').isString(),
-    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
+    body('googleClientId').if((value, { req }) => req.body.googleClientId).isString(),
+    body('googleClientSecret').if((value, { req }) => req.body.googleClientSecret).isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').if((value, { req }) => req.body.isSameUsernameTreatedAsIdenticalUser).isBoolean(),
   ],
   githubOAuth: [
-    body('githubClientId').isString(),
-    body('githubClientSecret').isString(),
-    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
+    body('githubClientId').if((value, { req }) => req.body.githubClientId).isString(),
+    body('githubClientSecret').if((value, { req }) => req.body.githubClientSecret).isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').if((value, { req }) => req.body.isSameUsernameTreatedAsIdenticalUser).isBoolean(),
   ],
   twitterOAuth: [
     body('twitterConsumerKey').if((value, { req }) => req.body.twitterConsumerKey).isString(),

+ 0 - 6
src/server/views/admin/widget/passport/facebook.html

@@ -1,6 +0,0 @@
-<form action="" method="post" class="form-horizontal passportStrategy" id="facebookOauthSetting" role="form">
-  <fieldset>
-    <legend>Facebook OAuth {{ t("security_setting.configuration") }}</legend>
-    <p class="well">(TBD)</p>
-  </fieldset>
-</form>

+ 0 - 120
src/server/views/admin/widget/passport/github.html

@@ -1,120 +0,0 @@
-<form action="/_api/admin/security/passport-github" method="post" class="form-horizontal passportStrategy" id="githubSetting" role="form">
-  <legend class="alert-anchor">{{ t("security_setting.OAuth.GitHub.name") }} {{ t("security_setting.configuration") }}</legend>
-
-  {% set nameForIsGitHubEnabled = "settingForm[security:passport-github:isEnabled]" %}
-  {% set isGitHubEnabled = getConfig('crowi', 'security:passport-github:isEnabled') %}
-  {% set siteUrl = getConfig('crowi', 'app:siteUrl') || '[INVALID]' %}
-  {% set callbackUrl = pathUtils.removeTrailingSlash(siteUrl) + '/passport/github/callback' %}
-
-  <div class="form-group">
-    <label for="{{nameForIsGitHubEnabled}}" class="col-xs-3 control-label">{{ t("security_setting.OAuth.GitHub.name") }}</label>
-    <div class="col-xs-6">
-      <div class="btn-group btn-toggle" data-toggle="buttons">
-        <label class="btn btn-default btn-rounded btn-outline {% if isGitHubEnabled %}active{% endif %}" data-active-class="primary">
-          <input name="{{nameForIsGitHubEnabled}}" value="true" type="radio"
-              {% if true === isGitHubEnabled %}checked{% endif %}> ON
-        </label>
-        <label class="btn btn-default btn-rounded btn-outline {% if !isGitHubEnabled %}active{% endif %}" data-active-class="default">
-          <input name="{{nameForIsGitHubEnabled}}" value="false" type="radio"
-              {% if !isGitHubEnabled %}checked{% endif %}> OFF
-        </label>
-      </div>
-    </div>
-  </div>
-
-
-  <div class="form-group">
-    <label class="col-xs-3 control-label">{{ t("security_setting.callback_URL") }}</label>
-    <div class="col-xs-6">
-        <input class="form-control" type="text" value="{{ callbackUrl }}" readonly>
-      <p class="help-block small">{{ t("security_setting.desc_of_callback_URL", 'OAuth') }}</p>
-      {% if !getConfig('crowi', 'app:siteUrl') %}
-      <div class="alert alert-danger">
-        <i class="icon-exclamation"></i> {{ t("security_setting.alert_siteUrl_is_not_set", '<a href="/admin/app">' + t('App settings') + '<i class="icon-login"></i></a>') }}
-      </div>
-      {% endif %}
-    </div>
-  </div>
-
-  <fieldset id="passport-github-hide-when-disabled" {%if !isGitHubEnabled %}style="display: none;"{% endif %}>
-
-    <div class="form-group">
-      <label for="settingForm[security:passport-github:clientId]" class="col-xs-3 control-label">{{ t("security_setting.clientID") }}</label>
-      <div class="col-xs-6">
-        <input class="form-control" type="text" name="settingForm[security:passport-github:clientId]" value="{{ getConfig('crowi', 'security:passport-github:clientId') | default('') }}">
-        <p class="help-block">
-          <small>
-            {{ t("security_setting.Use env var if empty", "OAUTH_GITHUB_CLIENT_SECRET") }}
-          </small>
-        </p>
-      </div>
-    </div>
-
-    <div class="form-group">
-      <label for="settingForm[security:passport-github:clientSecret]" class="col-xs-3 control-label">{{ t("security_setting.client_secret") }}</label>
-      <div class="col-xs-6">
-        <input class="form-control" type="text" name="settingForm[security:passport-github:clientSecret]" value="{{ getConfig('crowi', 'security:passport-github:clientSecret') | default('') }}">
-        <p class="help-block">
-          <small>
-            {{ t("security_setting.Use env var if empty", "OAUTH_GITHUB_CLIENT_SECRET") }}
-          </small>
-        </p>
-      </div>
-    </div>
-
-    <div class="form-group">
-      <div class="col-xs-6 col-xs-offset-3">
-        <div class="checkbox checkbox-info">
-          <input type="checkbox" id="bindByUserName-GitHub" name="settingForm[security:passport-github:isSameUsernameTreatedAsIdenticalUser]" value="1"
-              {% if getConfig('crowi', 'security:passport-github:isSameUsernameTreatedAsIdenticalUser') %}checked{% endif %} />
-          <label for="bindByUserName-GitHub">
-            {{ t("security_setting.Treat username matching as identical", "username") }}
-          </label>
-          <p class="help-block">
-            <small>
-              {{ t("security_setting.Treat username matching as identical_warn", "username") }}
-            </small>
-          </p>
-        </div>
-      </div>
-    </div>
-
-  </fieldset>
-
-  <div class="form-group" id="btn-update">
-    <div class="col-xs-offset-3 col-xs-6">
-      <input type="hidden" name="_csrf" value="{{ csrf() }}">
-      <button type="submit" class="btn btn-primary">{{ t('Update') }}</button>
-    </div>
-  </div>
-
-</form>
-
-{# Help Section #}
-<hr>
-
-<div style="min-height: 300px;">
-  <h4>
-    <i class="icon-question" aria-hidden="true"></i>
-    <a href="#collapseHelpForGithubOauth" data-toggle="collapse">{{ t("security_setting.OAuth.how_to.github") }}</a>
-  </h4>
-  <ol id="collapseHelpForGithubOauth" class="collapse">
-    <li>{{ t("security_setting.OAuth.GitHub.register_1", "https://github.com/settings/developers", "GitHub Developer Settings") }}</li>
-    <li>{{ t("security_setting.OAuth.GitHub.register_2", callbackUrl) }}</li>
-    <li>{{ t("security_setting.OAuth.GitHub.register_3") }}</li>
-  </ol>
-</div>
-
-<script>
-  $('input[name="settingForm[security:passport-github:isEnabled]"]').change(function() {
-    const isEnabled = ($(this).val() === "true");
-
-    if (isEnabled) {
-      $('#passport-github-hide-when-disabled').show(400);
-    }
-    else {
-      $('#passport-github-hide-when-disabled').hide(400);
-    }
-  });
-</script>
-

+ 0 - 120
src/server/views/admin/widget/passport/google-oauth.html

@@ -1,120 +0,0 @@
-<form action="/_api/admin/security/passport-google" method="post" class="form-horizontal passportStrategy" id="googleSetting" role="form">
-  <legend class="alert-anchor">{{ t("security_setting.OAuth.Google.name") }} {{ t("security_setting.configuration") }}</legend>
-
-  {% set nameForIsGoogleEnabled = "settingForm[security:passport-google:isEnabled]" %}
-  {% set isGoogleEnabled = getConfig('crowi', 'security:passport-google:isEnabled') | default('') %}
-  {% set siteUrl = getConfig('crowi', 'app:siteUrl') || '[INVALID]' %}
-  {% set callbackUrl = pathUtils.removeTrailingSlash(siteUrl) + '/passport/google/callback' %}
-
-  <div class="form-group">
-    <label for="{{nameForIsGoogleEnabled}}" class="col-xs-3 control-label">{{ t("security_setting.OAuth.Google.name") }}</label>
-    <div class="col-xs-6">
-      <div class="btn-group btn-toggle" data-toggle="buttons">
-        <label class="btn btn-default btn-rounded btn-outline {% if isGoogleEnabled %}active{% endif %}" data-active-class="primary">
-          <input name="{{nameForIsGoogleEnabled}}" value="true" type="radio"
-              {% if true === isGoogleEnabled %}checked{% endif %}> ON
-        </label>
-        <label class="btn btn-default btn-rounded btn-outline {% if !isGoogleEnabled %}active{% endif %}" data-active-class="default">
-          <input name="{{nameForIsGoogleEnabled}}" value="false" type="radio"
-              {% if !isGoogleEnabled %}checked{% endif %}> OFF
-        </label>
-      </div>
-    </div>
-  </div>
-
-  <div class="form-group">
-    <label class="col-xs-3 control-label">{{ t("security_setting.callback_URL") }}</label>
-    <div class="col-xs-6">
-        <input class="form-control" type="text" value="{{ callbackUrl }}" readonly>
-      <p class="help-block small">{{ t("security_setting.desc_of_callback_URL", 'OAuth') }}</p>
-      {% if !getConfig('crowi', 'app:siteUrl') %}
-      <div class="alert alert-danger">
-        <i class="icon-exclamation"></i> {{ t("security_setting.alert_siteUrl_is_not_set", '<a href="/admin/app">' + t('App settings') + '<i class="icon-login"></i></a>') }}
-      </div>
-      {% endif %}
-    </div>
-  </div>
-
-  <fieldset id="passport-google-hide-when-disabled" {%if !isGoogleEnabled %}style="display: none;"{% endif %}>
-
-    <div class="form-group">
-      <label for="settingForm[security:passport-google:clientId]" class="col-xs-3 control-label">{{ t("security_setting.clientID") }}</label>
-      <div class="col-xs-6">
-        <input class="form-control" type="text" name="settingForm[security:passport-google:clientId]" value="{{ getConfig('crowi', 'security:passport-google:clientId') | default('') }}">
-        <p class="help-block">
-          <small>
-            {{ t("security_setting.Use env var if empty", "OAUTH_GOOGLE_CLIENT_ID") }}
-          </small>
-        </p>
-      </div>
-    </div>
-
-    <div class="form-group">
-      <label for="settingForm[security:passport-google:clientSecret]" class="col-xs-3 control-label">{{ t("security_setting.client_secret") }}</label>
-      <div class="col-xs-6">
-        <input class="form-control" type="text" name="settingForm[security:passport-google:clientSecret]" value="{{ getConfig('crowi', 'security:passport-google:clientSecret') | default('') }}">
-        <p class="help-block">
-          <small>
-            {{ t("security_setting.Use env var if empty", "OAUTH_GOOGLE_CLIENT_SECRET") }}
-          </small>
-        </p>
-      </div>
-    </div>
-
-    <div class="form-group">
-      <div class="col-xs-6 col-xs-offset-3">
-        <div class="checkbox checkbox-info">
-          <input type="checkbox" id="bindByUserName-Google" name="settingForm[security:passport-google:isSameUsernameTreatedAsIdenticalUser]" value="1"
-              {% if getConfig('crowi', 'security:passport-google:isSameUsernameTreatedAsIdenticalUser') %}checked{% endif %} />
-          <label for="bindByUserName-Google">
-            {{ t("security_setting.Treat username matching as identical", "username") }}
-          </label>
-          <p class="help-block">
-            <small>
-              {{ t("security_setting.Treat username matching as identical_warn", "username") }}
-            </small>
-          </p>
-        </div>
-      </div>
-    </div>
-
-  </fieldset>
-
-  <div class="form-group" id="btn-update">
-    <div class="col-xs-offset-3 col-xs-6">
-      <input type="hidden" name="_csrf" value="{{ csrf() }}">
-      <button type="submit" class="btn btn-primary">{{ t('Update') }}</button>
-    </div>
-  </div>
-
-</form>
-
-{# Help Section #}
-<hr>
-
-<div style="min-height: 300px;">
-  <h4>
-    <i class="icon-question" aria-hidden="true"></i>
-    <a href="#collapseHelpForGoogleOauth" data-toggle="collapse">{{ t("security_setting.OAuth.how_to.google") }}</a>
-  </h4>
-  <ol id="collapseHelpForGoogleOauth" class="collapse">
-    <li>{{ t("security_setting.OAuth.Google.register_1", "https://console.cloud.google.com/apis/credentials", "Google Cloud Platform API Manager") }}</li>
-    <li>{{ t("security_setting.OAuth.Google.register_2") }}</li>
-    <li>{{ t("security_setting.OAuth.Google.register_3") }}</li>
-    <li>{{ t("security_setting.OAuth.Google.register_4", callbackUrl) }}</li>
-    <li>{{ t("security_setting.OAuth.Google.register_5") }}</li>
-  </ol>
-</div>
-
-<script>
-  $('input[name="settingForm[security:passport-google:isEnabled]"]').change(function() {
-    const isEnabled = ($(this).val() === "true");
-
-    if (isEnabled) {
-      $('#passport-google-hide-when-disabled').show(400);
-    }
-    else {
-      $('#passport-google-hide-when-disabled').hide(400);
-    }
-  });
-</script>

+ 0 - 120
src/server/views/admin/widget/passport/twitter.html

@@ -1,120 +0,0 @@
-<form action="/_api/admin/security/passport-twitter" method="post" class="form-horizontal passportStrategy" id="twitterSetting" role="form">
-  <legend class="alert-anchor">{{ t("security_setting.OAuth.Twitter.name") }} {{ t("security_setting.configuration") }}</legend>
-
-  {% set nameForIsTwitterEnabled = "settingForm[security:passport-twitter:isEnabled]" %}
-  {% set isTwitterEnabled = getConfig('crowi', 'security:passport-twitter:isEnabled') %}
-  {% set siteUrl = getConfig('crowi', 'app:siteUrl') || '[INVALID]' %}
-  {% set callbackUrl = pathUtils.removeTrailingSlash(siteUrl) + '/passport/twitter/callback' %}
-
-  <div class="form-group">
-    <label for="{{nameForIsTwitterEnabled}}" class="col-xs-3 control-label">{{ t("security_setting.OAuth.Twitter.name") }}</label>
-    <div class="col-xs-6">
-      <div class="btn-group btn-toggle" data-toggle="buttons">
-        <label class="btn btn-default btn-rounded btn-outline {% if isTwitterEnabled %}active{% endif %}" data-active-class="primary">
-          <input name="{{nameForIsTwitterEnabled}}" value="true" type="radio"
-              {% if true === isTwitterEnabled %}checked{% endif %}> ON
-        </label>
-        <label class="btn btn-default btn-rounded btn-outline {% if !isTwitterEnabled %}active{% endif %}" data-active-class="default">
-          <input name="{{nameForIsTwitterEnabled}}" value="false" type="radio"
-              {% if !isTwitterEnabled %}checked{% endif %}> OFF
-        </label>
-      </div>
-    </div>
-  </div>
-
-  <div class="form-group">
-    <label class="col-xs-3 control-label">{{ t("security_setting.callback_URL") }}</label>
-    <div class="col-xs-6">
-      <input class="form-control" type="text" value="{{ callbackUrl }}" readonly>
-      <p class="help-block small">{{ t("security_setting.desc_of_callback_URL", 'OAuth') }}</p>
-      {% if !getConfig('crowi', 'app:siteUrl') %}
-      <div class="alert alert-danger">
-        <i class="icon-exclamation"></i> {{ t("security_setting.alert_siteUrl_is_not_set", '<a href="/admin/app">' + t('App settings') + '<i class="icon-login"></i></a>') }}
-      </div>
-      {% endif %}
-    </div>
-  </div>
-
-  <fieldset id="passport-twitter-hide-when-disabled" {%if !isTwitterEnabled %}style="display: none;"{% endif %}>
-
-    <div class="form-group">
-      <label for="settingForm[security:passport-twitter:consumerKey]" class="col-xs-3 control-label">{{ t("security_setting.clientID") }}</label>
-      <div class="col-xs-6">
-        <input class="form-control" type="text" name="settingForm[security:passport-twitter:consumerKey]" value="{{ getConfig('crowi', 'security:passport-twitter:consumerKey') | default('') }}">
-        <p class="help-block">
-          <small>
-                {{ t("security_setting.Use env var if empty", "OAUTH_TWITTER_CONSUMER_KEY") }}
-          </small>
-        </p>
-      </div>
-    </div>
-
-    <div class="form-group">
-      <label for="settingForm[security:passport-twitter:consumerSecret]" class="col-xs-3 control-label">{{ t("security_setting.client_secret") }}</label>
-      <div class="col-xs-6">
-        <input class="form-control" type="text" name="settingForm[security:passport-twitter:consumerSecret]" value="{{ getConfig('crowi', 'security:passport-twitter:consumerSecret') | default('') }}">
-        <p class="help-block">
-          <small>
-             {{ t("security_setting.Use env var if empty", "OAUTH_TWITTER_CONSUMER_SECRET") }}
-          </small>
-        </p>
-      </div>
-    </div>
-
-    <div class="form-group">
-      <div class="col-xs-6 col-xs-offset-3">
-        <div class="checkbox checkbox-info">
-          <input type="checkbox" id="bindByUserName-Twitter" name="settingForm[security:passport-twitter:isSameUsernameTreatedAsIdenticalUser]" value="1"
-              {% if getConfig('crowi', 'security:passport-twitter:isSameUsernameTreatedAsIdenticalUser') %}checked{% endif %} />
-          <label for="bindByUserName-Twitter">
-            {{ t("security_setting.Treat username matching as identical", "username") }}
-          </label>
-          <p class="help-block">
-            <small>
-              {{ t("security_setting.Treat username matching as identical_warn", "username") }}
-            </small>
-          </p>
-        </div>
-      </div>
-    </div>
-
-  </fieldset>
-
-  <div class="form-group" id="btn-update">
-    <div class="col-xs-offset-3 col-xs-6">
-      <input type="hidden" name="_csrf" value="{{ csrf() }}">
-      <button type="submit" class="btn btn-primary">{{ t('Update') }}</button>
-    </div>
-  </div>
-
-</form>
-
-{# Help Section #}
-<hr>
-
-<div style="min-height: 300px;">
-  <h4>
-    <i class="icon-question" aria-hidden="true"></i>
-    <a href="#collapseHelpForTwitterOauth" data-toggle="collapse">{{ t("security_setting.OAuth.how_to.twitter") }}</a>
-  </h4>
-  <ol id="collapseHelpForTwitterOauth" class="collapse">
-    <li>{{ t("security_setting.OAuth.Twitter.register_1", "https://apps.twitter.com/", "Twitter Application Management") }}</li>
-    <li>{{ t("security_setting.OAuth.Twitter.register_2") }}</li>
-    <li>{{ t("security_setting.OAuth.Twitter.register_3") }}</li>
-    <li>{{ t("security_setting.OAuth.Twitter.register_4", callbackUrl) }}</li>
-  </ol>
-</div>
-
-<script>
-  $('input[name="settingForm[security:passport-twitter:isEnabled]"]').change(function() {
-      const isEnabled = ($(this).val() === "true");
-
-      if (isEnabled) {
-        $('#passport-twitter-hide-when-disabled').show(400);
-      }
-      else {
-        $('#passport-twitter-hide-when-disabled').hide(400);
-      }
-    });
-</script>
-