diff --git a/dictation_client/codegen.sh b/dictation_client/codegen.sh index 5d09ae3..d165c0c 100644 --- a/dictation_client/codegen.sh +++ b/dictation_client/codegen.sh @@ -1,2 +1,2 @@ -npx openapi-generator-cli version-manager set latest +npx openapi-generator-cli version-manager set 7.1.0 npx openapi-generator-cli generate -g typescript-axios -i /app/dictation_server/src/api/odms/openapi.json -o /app/dictation_client/src/api/ diff --git a/dictation_client/src/api/api.ts b/dictation_client/src/api/api.ts index 1c1ac87..645f058 100644 --- a/dictation_client/src/api/api.ts +++ b/dictation_client/src/api/api.ts @@ -1549,12 +1549,6 @@ export interface PostUpdateUserRequest { * @memberof PostUpdateUserRequest */ 'autoRenew': boolean; - /** - * - * @type {boolean} - * @memberof PostUpdateUserRequest - */ - 'licenseAlart': boolean; /** * * @type {boolean} @@ -1660,12 +1654,6 @@ export interface SignupRequest { * @memberof SignupRequest */ 'autoRenew': boolean; - /** - * - * @type {boolean} - * @memberof SignupRequest - */ - 'licenseAlert': boolean; /** * * @type {boolean} @@ -2212,12 +2200,6 @@ export interface User { * @memberof User */ 'autoRenew': boolean; - /** - * - * @type {boolean} - * @memberof User - */ - 'licenseAlert': boolean; /** * * @type {boolean} diff --git a/dictation_client/src/features/user/operations.ts b/dictation_client/src/features/user/operations.ts index f02e38c..b7ca2b0 100644 --- a/dictation_client/src/features/user/operations.ts +++ b/dictation_client/src/features/user/operations.ts @@ -164,7 +164,6 @@ export const updateUserAsync = createAsyncThunk< encryptionPassword, prompt, autoRenew: updateUser.autoRenew, - licenseAlart: updateUser.licenseAlert, notification: updateUser.notification, }, { diff --git a/dictation_client/src/features/user/selectors.ts b/dictation_client/src/features/user/selectors.ts index e1e3cf1..ee1f3fa 100644 --- a/dictation_client/src/features/user/selectors.ts +++ b/dictation_client/src/features/user/selectors.ts @@ -131,8 +131,6 @@ export const selectAuthorId = (state: RootState) => state.user.apps.addUser.authorId; export const selectAutoRenew = (state: RootState) => state.user.apps.addUser.autoRenew; -export const selectLicenseAlert = (state: RootState) => - state.user.apps.addUser.licenseAlert; export const selectNotification = (state: RootState) => state.user.apps.addUser.notification; // AddUserを返却する diff --git a/dictation_client/src/features/user/types.ts b/dictation_client/src/features/user/types.ts index 7f41187..649b63f 100644 --- a/dictation_client/src/features/user/types.ts +++ b/dictation_client/src/features/user/types.ts @@ -16,7 +16,6 @@ export interface UserView encryption: boolean | string; emailVerified: boolean; autoRenew: boolean; - licenseAlert: boolean; notification: boolean; name: string; email: string; @@ -28,7 +27,6 @@ export interface AddUser { role: RoleType; email: string; autoRenew: boolean; - licenseAlert: boolean; notification: boolean; authorId?: string; encryption?: boolean; @@ -46,7 +44,6 @@ export interface UpdateUser { encryptionPassword?: string | undefined; prompt?: boolean | undefined; autoRenew: boolean; - licenseAlert: boolean; notification: boolean; } diff --git a/dictation_client/src/features/user/userSlice.ts b/dictation_client/src/features/user/userSlice.ts index 52ffbc4..ef0589a 100644 --- a/dictation_client/src/features/user/userSlice.ts +++ b/dictation_client/src/features/user/userSlice.ts @@ -23,7 +23,6 @@ const initialState: UsersState = { encryptionPassword: undefined, prompt: undefined, autoRenew: true, - licenseAlert: true, notification: true, }, selectedUser: { @@ -36,7 +35,6 @@ const initialState: UsersState = { encryptionPassword: undefined, prompt: undefined, autoRenew: true, - licenseAlert: true, notification: true, }, addUser: { @@ -44,7 +42,6 @@ const initialState: UsersState = { role: USER_ROLES.NONE, email: "", autoRenew: true, - licenseAlert: true, notification: true, authorId: undefined, encryption: false, @@ -93,13 +90,6 @@ export const userSlice = createSlice({ const { autoRenew } = action.payload; state.apps.addUser.autoRenew = autoRenew; }, - changeLicenseAlert: ( - state, - action: PayloadAction<{ licenseAlert: boolean }> - ) => { - const { licenseAlert } = action.payload; - state.apps.addUser.licenseAlert = licenseAlert; - }, changeEncryption: ( state, action: PayloadAction<{ encryption: boolean }> @@ -149,7 +139,6 @@ export const userSlice = createSlice({ state.apps.updateUser.encryptionPassword = undefined; state.apps.updateUser.prompt = user.prompt; state.apps.updateUser.autoRenew = user.autoRenew; - state.apps.updateUser.licenseAlert = user.licenseAlert; state.apps.updateUser.notification = user.notification; state.apps.selectedUser.id = user.id; @@ -161,7 +150,6 @@ export const userSlice = createSlice({ state.apps.selectedUser.encryptionPassword = undefined; state.apps.selectedUser.prompt = user.prompt; state.apps.selectedUser.autoRenew = user.autoRenew; - state.apps.selectedUser.licenseAlert = user.licenseAlert; state.apps.selectedUser.notification = user.notification; state.apps.hasPasswordMask = user.encryption; @@ -211,13 +199,6 @@ export const userSlice = createSlice({ const { autoRenew } = action.payload; state.apps.updateUser.autoRenew = autoRenew; }, - changeUpdateLicenseAlert: ( - state, - action: PayloadAction<{ licenseAlert: boolean }> - ) => { - const { licenseAlert } = action.payload; - state.apps.updateUser.licenseAlert = licenseAlert; - }, changeUpdateNotification: ( state, action: PayloadAction<{ notification: boolean }> @@ -318,7 +299,6 @@ export const { changeRole, changeAuthorId, changeAutoRenew, - changeLicenseAlert, changeNotification, cleanupAddUser, changeUpdateUser, @@ -328,7 +308,6 @@ export const { changeUpdateEncryptionPassword, changeUpdatePrompt, changeUpdateAutoRenew, - changeUpdateLicenseAlert, changeUpdateNotification, cleanupUpdateUser, changeEncryption, diff --git a/dictation_client/src/pages/AuthPage/index.tsx b/dictation_client/src/pages/AuthPage/index.tsx index a1559bd..a17880d 100644 --- a/dictation_client/src/pages/AuthPage/index.tsx +++ b/dictation_client/src/pages/AuthPage/index.tsx @@ -10,6 +10,14 @@ import { import React, { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useNavigate } from "react-router-dom"; +import { + clearToken, + isAdminUser, + isApproveTier, + isStandardUser, + loadAccessToken, +} from "features/auth"; +import { TIERS } from "components/auth/constants"; const AuthPage: React.FC = (): JSX.Element => { const { instance } = useMsal(); @@ -26,6 +34,39 @@ const AuthPage: React.FC = (): JSX.Element => { (async () => { try { + // ログイン済みの場合、ログイン後の遷移先を決定する + if (loadAccessToken()) { + // 第一~第四階層の管理者はライセンス画面へ遷移 + if ( + isApproveTier([ + TIERS.TIER1, + TIERS.TIER2, + TIERS.TIER3, + TIERS.TIER4, + ]) && + isAdminUser() + ) { + navigate("/license"); + return; + } + // 第五階層の管理者はユーザー画面へ遷移 + if (isApproveTier([TIERS.TIER5]) && isAdminUser()) { + navigate("/user"); + return; + } + // 一般ユーザーはdictationPageへ遷移 + if (isStandardUser()) { + navigate("/dictations"); + return; + } + // それ以外は認証エラー画面へ遷移 + instance.logoutRedirect({ + postLogoutRedirectUri: "/AuthError", + }); + clearToken(); + return; + } + const loginResult = await instance.handleRedirectPromise(); // eslint-disable-next-line diff --git a/dictation_client/src/pages/DictationPage/filePropertyPopup.tsx b/dictation_client/src/pages/DictationPage/filePropertyPopup.tsx index 0bcd5ba..1a4104c 100644 --- a/dictation_client/src/pages/DictationPage/filePropertyPopup.tsx +++ b/dictation_client/src/pages/DictationPage/filePropertyPopup.tsx @@ -122,7 +122,7 @@ export const FilePropertyPopup: React.FC = (props) => {
{t(getTranslationID("dictationPage.label.transcriptionist"))}
{selectedFileTask?.typist?.name ?? ""}
- {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */} + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} close {t(getTranslationID("filePropertyPopup.label.close"))} diff --git a/dictation_client/src/pages/LoginPage/index.tsx b/dictation_client/src/pages/LoginPage/index.tsx index e298c40..c335bd3 100644 --- a/dictation_client/src/pages/LoginPage/index.tsx +++ b/dictation_client/src/pages/LoginPage/index.tsx @@ -28,6 +28,33 @@ const LoginPage: React.FC = (): JSX.Element => { selectLocalStorageKeyforIdToken ); + // ログイン後の遷移先を決定する + const navigateToLoginedPage = useCallback(() => { + // 第一~第四階層の管理者はライセンス画面へ遷移 + if ( + isApproveTier([TIERS.TIER1, TIERS.TIER2, TIERS.TIER3, TIERS.TIER4]) && + isAdminUser() + ) { + navigate("/license"); + return; + } + // 第五階層の管理者はユーザー画面へ遷移 + if (isApproveTier([TIERS.TIER5]) && isAdminUser()) { + navigate("/user"); + return; + } + // 一般ユーザーはdictationPageへ遷移 + if (isStandardUser()) { + navigate("/dictations"); + return; + } + // それ以外は認証エラー画面へ遷移 + instance.logoutRedirect({ + postLogoutRedirectUri: "/AuthError", + }); + clearToken(); + }, [instance, navigate]); + const tokenSet = useCallback( async (idToken: string) => { // ログイン処理呼び出し @@ -59,44 +86,36 @@ const LoginPage: React.FC = (): JSX.Element => { document.body.appendChild(a); a.click(); document.body.removeChild(a); - // 第一~第四階層の管理者はライセンス画面へ遷移 - if ( - isApproveTier([TIERS.TIER1, TIERS.TIER2, TIERS.TIER3, TIERS.TIER4]) && - isAdminUser() - ) { - navigate("/license"); - return; - } - // 第五階層の管理者はユーザー画面へ遷移 - if (isApproveTier([TIERS.TIER5]) && isAdminUser()) { - navigate("/user"); - return; - } - // 一般ユーザーはdictationPageへ遷移 - if (isStandardUser()) { - navigate("/dictations"); - return; - } - // それ以外は認証エラー画面へ遷移 - instance.logoutRedirect({ - postLogoutRedirectUri: "/AuthError", - }); - clearToken(); + + // ログイン成功した場合、適切なページに遷移する + navigateToLoginedPage(); } }, - [dispatch, i18n.language, instance, navigate] + [dispatch, i18n.language, instance, navigate, navigateToLoginedPage] ); useEffect(() => { - // AADB2Cのログイン画面とLoginPageを経由していない場合はトップページに遷移する - if (!localStorageKeyforIdToken) { - navigate("/"); - return; - } - + // idTokenStringがあるか⇒認証中 + // accessTokenがある場合⇒ログイン済み + // どちらもなければ直打ち (async () => { - // IDトークンの取得 + if (loadAccessToken()) { + navigateToLoginedPage(); + return; + } + + // AADB2Cのログイン画面とLoginPageを経由していない場合はトップページに遷移する + if (!localStorageKeyforIdToken) { + navigate("/"); + return; + } const idTokenString = localStorage.getItem(localStorageKeyforIdToken); + + if (idTokenString === null) { + navigate("/"); + return; + } + if (idTokenString) { const idTokenObject = JSON.parse(idTokenString); if (isIdToken(idTokenObject)) { diff --git a/dictation_client/src/pages/TermsPage/index.tsx b/dictation_client/src/pages/TermsPage/index.tsx index 974487e..52f2a0b 100644 --- a/dictation_client/src/pages/TermsPage/index.tsx +++ b/dictation_client/src/pages/TermsPage/index.tsx @@ -18,10 +18,19 @@ import { } from "features//terms"; import { selectLocalStorageKeyforIdToken } from "features/login"; import { useNavigate } from "react-router-dom"; +import { + clearToken, + isAdminUser, + isApproveTier, + isStandardUser, + loadAccessToken, +} from "features/auth"; +import { useMsal } from "@azure/msal-react"; const TermsPage: React.FC = (): JSX.Element => { const [t] = useTranslation(); const dispatch: AppDispatch = useDispatch(); + const { instance } = useMsal(); const navigate = useNavigate(); const updateAccceptVersions = useSelector(selectTermVersions); const localStorageKeyforIdToken = useSelector( @@ -40,6 +49,34 @@ const TermsPage: React.FC = (): JSX.Element => { // 画面起動時 useEffect(() => { + // ログイン済みの場合、ログイン後の遷移先を決定する + if (loadAccessToken()) { + // 第一~第四階層の管理者はライセンス画面へ遷移 + if ( + isApproveTier([TIERS.TIER1, TIERS.TIER2, TIERS.TIER3, TIERS.TIER4]) && + isAdminUser() + ) { + navigate("/license"); + return; + } + // 第五階層の管理者はユーザー画面へ遷移 + if (isApproveTier([TIERS.TIER5]) && isAdminUser()) { + navigate("/user"); + return; + } + // 一般ユーザーはdictationPageへ遷移 + if (isStandardUser()) { + navigate("/dictations"); + return; + } + // それ以外は認証エラー画面へ遷移 + instance.logoutRedirect({ + postLogoutRedirectUri: "/AuthError", + }); + clearToken(); + return; + } + dispatch(getTermsInfoAsync()); if (localStorageKeyforIdToken) { dispatch(getAccountInfoMinimalAccessAsync({ localStorageKeyforIdToken })); diff --git a/dictation_client/src/pages/UserListPage/index.tsx b/dictation_client/src/pages/UserListPage/index.tsx index 46f1223..a1de616 100644 --- a/dictation_client/src/pages/UserListPage/index.tsx +++ b/dictation_client/src/pages/UserListPage/index.tsx @@ -174,9 +174,6 @@ const UserListPage: React.FC = (): JSX.Element => { {t(getTranslationID("userListPage.label.autoRenew"))} - - {t(getTranslationID("userListPage.label.licenseAlert"))} - {t(getTranslationID("userListPage.label.notification"))} @@ -292,7 +289,6 @@ const UserListPage: React.FC = (): JSX.Element => { {boolToElement(user.autoRenew)} - {boolToElement(user.licenseAlert)} {boolToElement(user.notification)} {boolToElement(user.emailVerified)} diff --git a/dictation_client/src/pages/UserListPage/popup.tsx b/dictation_client/src/pages/UserListPage/popup.tsx index 50ed98f..97b3301 100644 --- a/dictation_client/src/pages/UserListPage/popup.tsx +++ b/dictation_client/src/pages/UserListPage/popup.tsx @@ -10,7 +10,6 @@ import { changeRole, changeAuthorId, changeAutoRenew, - changeLicenseAlert, changeNotification, cleanupAddUser, addUserAsync, @@ -324,22 +323,6 @@ export const UserAddPopup: React.FC = (props) => { {t(getTranslationID("userListPage.label.autoRenew"))}

-

- -

-

- -

-

Temporary password:$TEMPORARY_PASSWORD$

+

Temporary password: $TEMPORARY_PASSWORD$

If you need support regarding ODMS Cloud, please contact $PRIMARY_ADMIN_NAME$. @@ -34,7 +34,7 @@ Passwort zu ändern, klicken Sie auf dem ODMS Cloud-Anmeldebildschirm auf den Link [Kennwort vergessen?].

-

Temporäres Passwort:$TEMPORARY_PASSWORD$

+

Temporäres Passwort: $TEMPORARY_PASSWORD$

Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich bitte an $PRIMARY_ADMIN_NAME$. @@ -57,7 +57,7 @@ lien [Vous avez oublié votre mot de passe ?] sur l'écran de connexion ODMS Cloud.

-

Temporary password:$TEMPORARY_PASSWORD$

+

Temporary password: $TEMPORARY_PASSWORD$

Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter $PRIMARY_ADMIN_NAME$. diff --git a/dictation_server/src/templates/template_U_113.txt b/dictation_server/src/templates/template_U_113.txt index 5c444c6..f84bd50 100644 --- a/dictation_server/src/templates/template_U_113.txt +++ b/dictation_server/src/templates/template_U_113.txt @@ -2,7 +2,7 @@ Your user registration has been completed. Please login to ODMS Cloud with the following temporary password. You may continue using your temporary password; however, we strongly recommend that you change your password for security reasons. To change your password, click on [Forgot your password?] link on the ODMS Cloud Sign in screen. -Temporary password:$TEMPORARY_PASSWORD$ +Temporary password: $TEMPORARY_PASSWORD$ If you need support regarding ODMS Cloud, please contact $PRIMARY_ADMIN_NAME$. @@ -13,7 +13,7 @@ This is an automatically generated e-mail and this mailbox is not monitored. P Ihre Benutzerregistrierung ist abgeschlossen. Bitte melden Sie sich mit dem folgenden temporären Passwort bei ODMS Cloud an. Sie können Ihr temporäres Passwort weiterhin verwenden; Aus Sicherheitsgründen empfehlen wir Ihnen jedoch dringend, Ihr Passwort zu ändern. Um Ihr Passwort zu ändern, klicken Sie auf dem ODMS Cloud-Anmeldebildschirm auf den Link [Kennwort vergessen?]. -Temporäres Passwort:$TEMPORARY_PASSWORD$ +Temporäres Passwort: $TEMPORARY_PASSWORD$ Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich bitte an $PRIMARY_ADMIN_NAME$. @@ -24,7 +24,7 @@ Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht über Votre inscription d'utilisateur est terminée. Veuillez vous connecter à ODMS Cloud avec le mot de passe temporaire suivant. Vous pouvez continuer à utiliser votre mot de passe temporaire ; cependant, nous vous recommandons fortement de changer votre mot de passe pour des raisons de sécurité. Pour modifier votre mot de passe, cliquez sur le lien [Vous avez oublié votre mot de passe ?] sur l'écran de connexion ODMS Cloud. -Temporary password:$TEMPORARY_PASSWORD$ +Temporary password: $TEMPORARY_PASSWORD$ Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter $PRIMARY_ADMIN_NAME$.