فهرست منبع

Merge branch 'master' into feat/refactor-HandsontableModal

Ryoji Shimizu 3 سال پیش
والد
کامیت
a2f98a3e83

+ 28 - 3
packages/app/src/components/Admin/Customize/CustomizeLayoutSetting.tsx

@@ -1,4 +1,6 @@
-import React, { useCallback, useState } from 'react';
+import React, {
+  useCallback, useEffect, useState,
+} from 'react';
 
 import { useTranslation } from 'next-i18next';
 
@@ -6,16 +8,31 @@ import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { useSWRxLayoutSetting } from '~/stores/admin/customize';
 import { useNextThemes } from '~/stores/use-next-themes';
 
+const useIsContainerFluid = () => {
+  const { data: layoutSetting, update: updateLayoutSetting } = useSWRxLayoutSetting();
+  const [isContainerFluid, setIsContainerFluid] = useState<boolean>();
+
+  useEffect(() => {
+    setIsContainerFluid(layoutSetting?.isContainerFluid);
+  }, [layoutSetting?.isContainerFluid]);
+
+  return {
+    isContainerFluid,
+    setIsContainerFluid,
+    updateLayoutSetting,
+  };
+};
+
 const CustomizeLayoutSetting = (): JSX.Element => {
   const { t } = useTranslation('admin');
 
   const { resolvedTheme } = useNextThemes();
-  const { data: layoutSetting, update: updateLayoutSetting } = useSWRxLayoutSetting();
 
-  const [isContainerFluid, setIsContainerFluid] = useState<boolean>(layoutSetting?.isContainerFluid ?? false);
+  const { isContainerFluid, setIsContainerFluid, updateLayoutSetting } = useIsContainerFluid();
   const [retrieveError, setRetrieveError] = useState<any>();
 
   const onClickSubmit = useCallback(async() => {
+    if (isContainerFluid == null) { return }
     try {
       await updateLayoutSetting({ isContainerFluid });
       toastSuccess(t('toaster.update_successed', { target: t('customize_settings.layout'), ns: 'commons' }));
@@ -25,6 +42,14 @@ const CustomizeLayoutSetting = (): JSX.Element => {
     }
   }, [isContainerFluid, updateLayoutSetting, t]);
 
+  if (isContainerFluid == null) {
+    return (
+      <div className="text-muted text-center">
+        <i className="fa fa-2x fa-spinner fa-pulse"></i>
+      </div>
+    );
+  }
+
   return (
     <React.Fragment>
       <div className="row">

+ 2 - 2
packages/app/src/components/LoginForm.tsx

@@ -18,7 +18,6 @@ type LoginFormProps = {
   username?: string,
   name?: string,
   email?: string,
-  isRegistrationEnabled: boolean,
   isEmailAuthenticationEnabled: boolean,
   registrationMode: RegistrationMode,
   registrationWhiteList: string[],
@@ -34,7 +33,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
   const router = useRouter();
 
   const {
-    isLocalStrategySetup, isLdapStrategySetup, isLdapSetupFailed, isPasswordResetEnabled, isRegistrationEnabled,
+    isLocalStrategySetup, isLdapStrategySetup, isLdapSetupFailed, isPasswordResetEnabled,
     isEmailAuthenticationEnabled, registrationMode, registrationWhiteList, isMailerSetup, objOfIsExternalAuthEnableds,
   } = props;
   const isLocalOrLdapStrategiesEnabled = isLocalStrategySetup || isLdapStrategySetup;
@@ -57,6 +56,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
 
   const [isSuccessToRagistration, setIsSuccessToRagistration] = useState(false);
 
+  const isRegistrationEnabled = isLocalStrategySetup && registrationMode !== RegistrationMode.CLOSED;
 
   useEffect(() => {
     const { hash } = window.location;

+ 0 - 1
packages/app/src/pages/login.page.tsx

@@ -50,7 +50,6 @@ const LoginPage: NextPage<Props> = (props: Props) => {
         isLdapStrategySetup={props.isLdapStrategySetup}
         isLdapSetupFailed={props.isLdapSetupFailed}
         isEmailAuthenticationEnabled={props.isEmailAuthenticationEnabled}
-        isRegistrationEnabled={true}
         registrationWhiteList={props.registrationWhiteList}
         isPasswordResetEnabled={true}
         isMailerSetup={props.isMailerSetup}

+ 7 - 0
packages/app/src/server/routes/apiv3/user-activation.ts

@@ -5,9 +5,11 @@ import { format, subSeconds } from 'date-fns';
 import { body, validationResult } from 'express-validator';
 
 import { SupportedAction } from '~/interfaces/activity';
+import { RegistrationMode } from '~/interfaces/registration-mode';
 import UserRegistrationOrder from '~/server/models/user-registration-order';
 import loggerFactory from '~/utils/logger';
 
+
 const logger = loggerFactory('growi:routes:apiv3:user-activation');
 
 const PASSOWRD_MINIMUM_NUMBER = 8;
@@ -246,8 +248,13 @@ export const registerAction = (crowi) => {
     const registerForm = req.body.registerForm || {};
     const email = registerForm.email;
     const isRegisterableEmail = await User.isRegisterableEmail(email);
+    const registrationMode = crowi.configManager.getConfig('crowi', 'security:registrationMode') as RegistrationMode;
     const isEmailValid = await User.isEmailValid(email);
 
+    if (registrationMode === RegistrationMode.CLOSED) {
+      return res.apiv3Err(['message.registration_closed'], 400);
+    }
+
     if (!isRegisterableEmail) {
       req.body.registerForm.email = email;
       return res.apiv3Err(['message.email_address_is_already_registered'], 400);

+ 3 - 0
packages/app/test/cypress/support/commands.ts

@@ -34,7 +34,10 @@ Cypress.Commands.add('login', (username, password) => {
     cy.visit('/page-to-return-after-login');
     cy.getByTestid('tiUsernameForLogin').type(username);
     cy.getByTestid('tiPasswordForLogin').type(password);
+
+    cy.intercept('POST', '/_api/v3/login').as('login');
     cy.getByTestid('btnSubmitForLogin').click();
+    cy.wait('@login')
   });
 });