LocalSecuritySettingContents.jsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. import React from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import PropTypes from 'prop-types';
  4. import AdminGeneralSecurityContainer from '~/client/services/AdminGeneralSecurityContainer';
  5. import AdminLocalSecurityContainer from '~/client/services/AdminLocalSecurityContainer';
  6. import { toastSuccess, toastError } from '~/client/util/toastr';
  7. import { useIsMailerSetup } from '~/stores/context';
  8. import { withUnstatedContainers } from '../../UnstatedUtils';
  9. class LocalSecuritySettingContents extends React.Component {
  10. constructor(props) {
  11. super(props);
  12. this.onClickSubmit = this.onClickSubmit.bind(this);
  13. }
  14. async onClickSubmit() {
  15. const { t, adminGeneralSecurityContainer, adminLocalSecurityContainer } = this.props;
  16. try {
  17. await adminLocalSecurityContainer.updateLocalSecuritySetting();
  18. await adminGeneralSecurityContainer.retrieveSetupStratedies();
  19. toastSuccess(t('security_settings.updated_general_security_setting'));
  20. }
  21. catch (err) {
  22. toastError(err);
  23. }
  24. }
  25. render() {
  26. const {
  27. t,
  28. adminGeneralSecurityContainer,
  29. adminLocalSecurityContainer,
  30. isMailerSetup,
  31. } = this.props;
  32. const { registrationMode, isPasswordResetEnabled, isEmailAuthenticationEnabled } = adminLocalSecurityContainer.state;
  33. const { isLocalEnabled } = adminGeneralSecurityContainer.state;
  34. return (
  35. <>
  36. {adminLocalSecurityContainer.state.retrieveError != null && (
  37. <div className="alert alert-danger">
  38. <p>
  39. {t('Error occurred')} : {adminLocalSecurityContainer.state.retrieveError}
  40. </p>
  41. </div>
  42. )}
  43. <h2 className="alert-anchor border-bottom">{t('security_settings.Local.name')}</h2>
  44. {adminLocalSecurityContainer.state.useOnlyEnvVars && (
  45. <p
  46. className="alert alert-info"
  47. // eslint-disable-next-line max-len
  48. dangerouslySetInnerHTML={{
  49. __html: t('security_settings.Local.note for the only env option', { env: 'LOCAL_STRATEGY_USES_ONLY_ENV_VARS_FOR_SOME_OPTIONS' }),
  50. }}
  51. />
  52. )}
  53. <div className="row mb-5">
  54. <div className="col-6 offset-3">
  55. <div className="custom-control custom-switch custom-checkbox-success">
  56. <input
  57. type="checkbox"
  58. className="custom-control-input"
  59. id="isLocalEnabled"
  60. checked={isLocalEnabled}
  61. onChange={() => adminGeneralSecurityContainer.switchIsLocalEnabled()}
  62. disabled={adminLocalSecurityContainer.state.useOnlyEnvVars}
  63. />
  64. <label className="custom-control-label" htmlFor="isLocalEnabled">
  65. {t('security_settings.Local.enable_local')}
  66. </label>
  67. </div>
  68. {!adminGeneralSecurityContainer.state.setupStrategies.includes('local') && isLocalEnabled && (
  69. <div className="badge badge-warning">{t('security_settings.setup_is_not_yet_complete')}</div>
  70. )}
  71. </div>
  72. </div>
  73. {isLocalEnabled && (
  74. <>
  75. <h3 className="border-bottom">{t('security_settings.configuration')}</h3>
  76. <div className="row">
  77. <div className="col-12 col-md-3 text-left text-md-right py-2">
  78. <strong>{t('security_settings.register_limitation')}</strong>
  79. </div>
  80. <div className="col-12 col-md-6">
  81. <div className="dropdown">
  82. <button
  83. className="btn btn-outline-secondary dropdown-toggle"
  84. type="button"
  85. id="dropdownMenuButton"
  86. data-toggle="dropdown"
  87. aria-haspopup="true"
  88. aria-expanded="true"
  89. >
  90. {registrationMode === 'Open' && t('security_settings.registration_mode.open')}
  91. {registrationMode === 'Restricted' && t('security_settings.registration_mode.restricted')}
  92. {registrationMode === 'Closed' && t('security_settings.registration_mode.closed')}
  93. </button>
  94. <div className="dropdown-menu" aria-labelledby="dropdownMenuButton">
  95. <button
  96. className="dropdown-item"
  97. type="button"
  98. onClick={() => {
  99. adminLocalSecurityContainer.changeRegistrationMode('Open');
  100. }}
  101. >
  102. {t('security_settings.registration_mode.open')}
  103. </button>
  104. <button
  105. className="dropdown-item"
  106. type="button"
  107. onClick={() => {
  108. adminLocalSecurityContainer.changeRegistrationMode('Restricted');
  109. }}
  110. >
  111. {t('security_settings.registration_mode.restricted')}
  112. </button>
  113. <button
  114. className="dropdown-item"
  115. type="button"
  116. onClick={() => {
  117. adminLocalSecurityContainer.changeRegistrationMode('Closed');
  118. }}
  119. >
  120. {t('security_settings.registration_mode.closed')}
  121. </button>
  122. </div>
  123. {!isMailerSetup && (
  124. <div className="alert alert-warning p-1 my-1 small d-inline-block">
  125. <span>{t('commons:alert.register_limitation_please_enable_mailer')}</span>
  126. <a href="/admin/app#mail-settings"> <i className="fa fa-link"></i> {t('app_setting.mail_settings')}</a>
  127. </div>
  128. )}
  129. </div>
  130. <p className="form-text text-muted small">{t('security_settings.register_limitation_desc')}</p>
  131. </div>
  132. </div>
  133. <div className="row">
  134. <div className="col-12 col-md-3 text-left text-md-right">
  135. <strong dangerouslySetInnerHTML={{ __html: t('security_settings.The whitelist of registration permission E-mail address') }} />
  136. </div>
  137. <div className="col-12 col-md-6">
  138. <textarea
  139. className="form-control"
  140. type="textarea"
  141. name="registrationWhiteList"
  142. defaultValue={adminLocalSecurityContainer.state.registrationWhiteList.join('\n')}
  143. onChange={e => adminLocalSecurityContainer.changeRegistrationWhiteList(e.target.value)}
  144. />
  145. <p className="form-text text-muted small">
  146. {t('security_settings.restrict_emails')}
  147. <br />
  148. {t('security_settings.for_example')}
  149. <code>@growi.org</code>
  150. {t('security_settings.in_this_case')}
  151. <br />
  152. {t('security_settings.insert_single')}
  153. </p>
  154. </div>
  155. </div>
  156. <div className="row">
  157. <label className="col-12 col-md-3 text-left text-md-right col-form-label">{t('security_settings.Local.password_reset_by_users')}</label>
  158. <div className="col-12 col-md-6">
  159. <div className="custom-control custom-switch custom-checkbox-success">
  160. <input
  161. type="checkbox"
  162. className="custom-control-input"
  163. id="isPasswordResetEnabled"
  164. checked={isPasswordResetEnabled}
  165. onChange={() => adminLocalSecurityContainer.switchIsPasswordResetEnabled()}
  166. />
  167. <label className="custom-control-label" htmlFor="isPasswordResetEnabled">
  168. {t('security_settings.Local.enable_password_reset_by_users')}
  169. </label>
  170. </div>
  171. <p className="form-text text-muted small">
  172. {t('security_settings.Local.password_reset_desc')}
  173. </p>
  174. </div>
  175. </div>
  176. <div className="row">
  177. <label className="col-12 col-md-3 text-left text-md-right col-form-label">{t('security_settings.Local.email_authentication')}</label>
  178. <div className="col-12 col-md-6">
  179. <div className="custom-control custom-switch custom-checkbox-success">
  180. <input
  181. type="checkbox"
  182. className="custom-control-input"
  183. id="isEmailAuthenticationEnabled"
  184. checked={isEmailAuthenticationEnabled}
  185. onChange={() => adminLocalSecurityContainer.switchIsEmailAuthenticationEnabled()}
  186. />
  187. <label className="custom-control-label" htmlFor="isEmailAuthenticationEnabled">
  188. {t('security_settings.Local.enable_email_authentication')}
  189. </label>
  190. </div>
  191. {!isMailerSetup && (
  192. <div className="alert alert-warning p-1 my-1 small d-inline-block">
  193. <span>{t('commons:alert.please_enable_mailer')}</span>
  194. <a href="/admin/app#mail-settings"> <i className="fa fa-link"></i> {t('app_setting.mail_settings')}</a>
  195. </div>
  196. )}
  197. <p className="form-text text-muted small">
  198. {t('security_settings.Local.enable_email_authentication_desc')}
  199. </p>
  200. </div>
  201. </div>
  202. <div className="row my-3">
  203. <div className="offset-3 col-6">
  204. <button
  205. type="button"
  206. className="btn btn-primary"
  207. disabled={adminLocalSecurityContainer.state.retrieveError != null}
  208. onClick={this.onClickSubmit}
  209. >
  210. {t('Update')}
  211. </button>
  212. </div>
  213. </div>
  214. </>
  215. )}
  216. </>
  217. );
  218. }
  219. }
  220. LocalSecuritySettingContents.propTypes = {
  221. t: PropTypes.func.isRequired, // i18next
  222. adminGeneralSecurityContainer: PropTypes.instanceOf(AdminGeneralSecurityContainer).isRequired,
  223. adminLocalSecurityContainer: PropTypes.instanceOf(AdminLocalSecurityContainer).isRequired,
  224. };
  225. const LocalSecuritySettingContentsWrapperFC = (props) => {
  226. const { t } = useTranslation('admin');
  227. const { data: isMailerSetup } = useIsMailerSetup();
  228. return <LocalSecuritySettingContents t={t} {...props} isMailerSetup={isMailerSetup ?? false} />;
  229. };
  230. const LocalSecuritySettingContentsWrapper = withUnstatedContainers(LocalSecuritySettingContentsWrapperFC, [
  231. AdminGeneralSecurityContainer,
  232. AdminLocalSecurityContainer,
  233. ]);
  234. export default LocalSecuritySettingContentsWrapper;