diff --git a/dictation_client/src/App.tsx b/dictation_client/src/App.tsx index f08dfd1..f730016 100644 --- a/dictation_client/src/App.tsx +++ b/dictation_client/src/App.tsx @@ -17,7 +17,16 @@ const App = (): JSX.Element => { const { instance } = useMsal(); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [t, i18n] = useTranslation(); + useEffect(() => { + // すべてのリクエストのヘッダーにX-Requested-Withを追加 + globalAxios.interceptors.request.use((config) => { + // headersがあれば追加、なければ新規作成 + config.headers = config.headers || {}; + // X-Requested-Withを追加 + config.headers["X-Requested-With"] = "XMLHttpRequest"; + return config; + }); const id = globalAxios.interceptors.response.use( (response: AxiosResponse) => response, (e: AxiosError<{ code?: string }>) => { diff --git a/dictation_client/src/common/errors/code.ts b/dictation_client/src/common/errors/code.ts index 25366a9..ce0c7b6 100644 --- a/dictation_client/src/common/errors/code.ts +++ b/dictation_client/src/common/errors/code.ts @@ -54,6 +54,7 @@ export const errorCodes = [ "E010809", // ライセンス発行キャンセル不可エラー(ステータスが変えられている場合) "E010810", // ライセンス発行キャンセル不可エラー(発行から一定期間経過した場合) "E010811", // ライセンス発行キャンセル不可エラー(発行したライセンスが割り当てされている場合) + "E010812", // ライセンス未割当エラー "E010908", // タイピストグループ不在エラー "E010909", // タイピストグループ名重複エラー "E011001", // ワークタイプ重複エラー diff --git a/dictation_client/src/features/dictation/operations.ts b/dictation_client/src/features/dictation/operations.ts index 4a80927..2cad273 100644 --- a/dictation_client/src/features/dictation/operations.ts +++ b/dictation_client/src/features/dictation/operations.ts @@ -343,6 +343,30 @@ export const playbackAsync = createAsyncThunk< ); return thunkApi.rejectWithValue({ error }); } + // ライセンスの有効期限が切れている場合 + if (error.code === "E010805") { + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: getTranslationID( + "dictationPage.message.licenseExpiredError" + ), + }) + ); + return thunkApi.rejectWithValue({ error }); + } + // ライセンスが未割当の場合 + if (error.code === "E010812") { + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: getTranslationID( + "dictationPage.message.licenseNotAssignedError" + ), + }) + ); + return thunkApi.rejectWithValue({ error }); + } thunkApi.dispatch( openSnackbar({ diff --git a/dictation_client/src/pages/DictationPage/index.tsx b/dictation_client/src/pages/DictationPage/index.tsx index 9f6d995..ec0ee93 100644 --- a/dictation_client/src/pages/DictationPage/index.tsx +++ b/dictation_client/src/pages/DictationPage/index.tsx @@ -1481,9 +1481,10 @@ const DictationPage: React.FC = (): JSX.Element => {
  • {t(getTranslationID("dictationPage.label.applications"))} {
    { setIsOpenPolicy(true); }} + rel="noreferrer" > {t(getTranslationID("signupPage.label.linkOfEula"))} @@ -398,12 +399,13 @@ const SignupInput: React.FC = (): JSX.Element => {
    { setIsOpenPrivacyNoyice(true); }} + rel="noreferrer" > {t( getTranslationID("signupPage.label.linkOfPrivacyNotice") diff --git a/dictation_client/src/pages/SupportPage/index.tsx b/dictation_client/src/pages/SupportPage/index.tsx index b5d2cc8..8f1ad90 100644 --- a/dictation_client/src/pages/SupportPage/index.tsx +++ b/dictation_client/src/pages/SupportPage/index.tsx @@ -28,54 +28,15 @@ const SupportPage: React.FC = () => { -

    {t(getTranslationID("supportPage.text.notResolved"))}

    diff --git a/dictation_client/src/pages/TermsPage/index.tsx b/dictation_client/src/pages/TermsPage/index.tsx index 4e5e910..74041e3 100644 --- a/dictation_client/src/pages/TermsPage/index.tsx +++ b/dictation_client/src/pages/TermsPage/index.tsx @@ -155,11 +155,12 @@ const TermsPage: React.FC = (): JSX.Element => {

    {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} setIsClickedEulaLink(true)} data-tag="open-eula" + rel="noreferrer" > {t(getTranslationID("termsPage.label.linkOfEula"))} @@ -187,11 +188,12 @@ const TermsPage: React.FC = (): JSX.Element => {

    {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} setIsClickedPrivacyNoticeLink(true)} data-tag="open-pricacy-notice" + rel="noreferrer" > {t( getTranslationID("termsPage.label.linkOfPrivacyNotice") @@ -225,11 +227,12 @@ const TermsPage: React.FC = (): JSX.Element => {

    {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} setIsClickedDpaLink(true)} data-tag="open-dpa" + rel="noreferrer" > {t(getTranslationID("termsPage.label.linkOfDpa"))} diff --git a/dictation_client/src/translation/de.json b/dictation_client/src/translation/de.json index 7ed2025..9a7af9d 100644 --- a/dictation_client/src/translation/de.json +++ b/dictation_client/src/translation/de.json @@ -252,7 +252,7 @@ "backupFailedError": "Der Prozess „Dateisicherung“ ist fehlgeschlagen. Bitte versuchen Sie es später noch einmal. Wenn der Fehler weiterhin besteht, wenden Sie sich an Ihren Systemadministrator.", "cancelFailedError": "Die Diktate konnten nicht gelöscht werden. Bitte aktualisieren Sie Ihren Bildschirm und versuchen Sie es erneut.", "deleteFailedError": "(de)タスクの削除に失敗しました。画面を更新し、再度ご確認ください。", - "licenseNotAssignedError": "Das Diktat kann nicht hochgeladen werden, da keine gültige Lizenz zugewiesen ist. Bitte fragen Sie Ihren Administrator.", + "licenseNotAssignedError": "Die Transkription ist nicht möglich, da keine gültige Lizenz zugewiesen ist.Bitten Sie Ihren Administrator, eine gültige Lizenz zuzuweisen.", "licenseExpiredError": "Die Transkription ist nicht möglich, da Ihre Lizenz abgelaufen ist. Bitte bitten Sie Ihren Administrator, Ihnen eine gültige Lizenz zuzuweisen." }, "label": { @@ -597,10 +597,7 @@ "label": { "title": "Support", "howToUse": "So verwenden Sie das System", - "supportPageEnglish": "OMDS Cloud User Guide", - "supportPageGerman": "OMDS Cloud-Benutzerhandbuch", - "supportPageFrench": "Guía del usuario de la nube OMDS", - "supportPageSpanish": "Guide de l'utilisateur du cloud OMDS" + "supportPageLink": "OMDS Cloud-Benutzerhandbuch" }, "text": { "notResolved": "Informationen zu den Funktionen der ODMS Cloud finden Sie im Benutzerhandbuch. Wenn Sie zusätzlichen Support benötigen, wenden Sie sich bitte an Ihren Administrator oder zertifizierten ODMS Cloud-Händler." diff --git a/dictation_client/src/translation/en.json b/dictation_client/src/translation/en.json index e3186d5..7b91390 100644 --- a/dictation_client/src/translation/en.json +++ b/dictation_client/src/translation/en.json @@ -252,7 +252,7 @@ "backupFailedError": "The \"File Backup\" process has failed. Please try again later. If the error continues, contact your system administrator.", "cancelFailedError": "Failed to delete the dictations. Please refresh your screen and try again.", "deleteFailedError": "タスクの削除に失敗しました。画面を更新し、再度ご確認ください。", - "licenseNotAssignedError": "Dictation cannot be uploaded because a vaild license is not assigned. Please ask your administrator.", + "licenseNotAssignedError": "Transcription is not possible because a valid license is not assigned.Please ask your administrator to assign a valid license.", "licenseExpiredError": "Transcription is not possible because your license is expired. Please ask your administrator to assign a valid license." }, "label": { @@ -597,10 +597,7 @@ "label": { "title": "Support", "howToUse": "How to use the system", - "supportPageEnglish": "OMDS Cloud User Guide", - "supportPageGerman": "OMDS Cloud-Benutzerhandbuch", - "supportPageFrench": "Guía del usuario de la nube OMDS", - "supportPageSpanish": "Guide de l'utilisateur du cloud OMDS" + "supportPageLink": "OMDS Cloud User Guide" }, "text": { "notResolved": "Please refer to the User Guide for information about the features of the ODMS Cloud. If you require additional support, please contact your administrator or certified ODMS Cloud reseller." diff --git a/dictation_client/src/translation/es.json b/dictation_client/src/translation/es.json index ea17dd8..4dd9b29 100644 --- a/dictation_client/src/translation/es.json +++ b/dictation_client/src/translation/es.json @@ -252,7 +252,7 @@ "backupFailedError": "El proceso de \"Copia de seguridad de archivos\" ha fallado. Por favor, inténtelo de nuevo más tarde. Si el error continúa, comuníquese con el administrador del sistema.", "cancelFailedError": "No se pudieron eliminar los dictados. Actualice su pantalla e inténtelo nuevamente.", "deleteFailedError": "(es)タスクの削除に失敗しました。画面を更新し、再度ご確認ください。", - "licenseNotAssignedError": "No se puede cargar el dictado porque no se ha asignado una licencia válida. Consulte a su administrador.", + "licenseNotAssignedError": "La transcripción no es posible porque no se ha asignado una licencia válida.Solicite a su administrador que le asigne una licencia válida.", "licenseExpiredError": "La transcripción no es posible porque su licencia ha caducado. Solicite a su administrador que le asigne una licencia válida." }, "label": { @@ -597,10 +597,7 @@ "label": { "title": "Soporte", "howToUse": "Cómo utilizar el sistema", - "supportPageEnglish": "OMDS Cloud User Guide", - "supportPageGerman": "OMDS Cloud-Benutzerhandbuch", - "supportPageFrench": "Guía del usuario de la nube OMDS", - "supportPageSpanish": "Guide de l'utilisateur du cloud OMDS" + "supportPageLink": "Guía del usuario de la nube OMDS" }, "text": { "notResolved": "Consulte la Guía del usuario para obtener información sobre las funciones de ODMS Cloud. Si necesita soporte adicional, comuníquese con su administrador o revendedor certificado de ODMS Cloud." diff --git a/dictation_client/src/translation/fr.json b/dictation_client/src/translation/fr.json index 1b473e6..af62dc2 100644 --- a/dictation_client/src/translation/fr.json +++ b/dictation_client/src/translation/fr.json @@ -252,7 +252,7 @@ "backupFailedError": "Le processus de « Sauvegarde de fichier » a échoué. Veuillez réessayer plus tard. Si l'erreur persiste, contactez votre administrateur système.", "cancelFailedError": "Échec de la suppression des dictées. Veuillez actualiser votre écran et réessayer.", "deleteFailedError": "(fr)タスクの削除に失敗しました。画面を更新し、再度ご確認ください。", - "licenseNotAssignedError": "La dictée ne peut pas être téléchargée parce qu'une licence valable n'est pas attribuée. Veuillez vous adresser à votre administrateur.", + "licenseNotAssignedError": "La transcription n'est pas possible car aucune licence valide n'a été attribuée.Veuillez demander à votre administrateur d'attribuer une licence valide.", "licenseExpiredError": "La transcription n'est pas possible car votre licence est expirée. Veuillez demander à votre administrateur de vous attribuer une licence valide." }, "label": { @@ -597,10 +597,7 @@ "label": { "title": "Support", "howToUse": "Comment utiliser le système", - "supportPageEnglish": "OMDS Cloud User Guide", - "supportPageGerman": "OMDS Cloud-Benutzerhandbuch", - "supportPageFrench": "Guía del usuario de la nube OMDS", - "supportPageSpanish": "Guide de l'utilisateur du cloud OMDS" + "supportPageLink": "Guide de l'utilisateur du cloud OMDS" }, "text": { "notResolved": "Veuillez vous référer au Guide de l'utilisateur pour plus d'informations sur les fonctionnalités d'ODMS Cloud. Si vous avez besoin d'une assistance supplémentaire, veuillez contacter votre administrateur ou votre revendeur certifié ODMS Cloud." diff --git a/dictation_server/src/app.module.ts b/dictation_server/src/app.module.ts index 5d76aac..7525fb7 100644 --- a/dictation_server/src/app.module.ts +++ b/dictation_server/src/app.module.ts @@ -53,6 +53,7 @@ import { TermsModule } from './features/terms/terms.module'; import { RedisModule } from './gateways/redis/redis.module'; import * as redisStore from 'cache-manager-redis-store'; import { SystemAccessGuardsModule } from './common/guards/system/accessguards.module'; +import { CheckHeaderMiddleware } from './common/check-header.middleware'; @Module({ imports: [ ServeStaticModule.forRootAsync({ @@ -166,6 +167,13 @@ import { SystemAccessGuardsModule } from './common/guards/system/accessguards.mo }) export class AppModule { configure(consumer: MiddlewareConsumer) { - consumer.apply(LoggerMiddleware).forRoutes(''); + consumer + .apply(LoggerMiddleware) + .forRoutes(''); + // stage=localの場合はmiddlewareを適用しない + // ローカル環境ではサーバーから静的ファイルも返すため、APIリクエスト以外のリクエストにもmiddlewareが適用されてしまう + if (process.env.STAGE !== 'local') { + consumer.apply(CheckHeaderMiddleware).forRoutes(''); + } } } diff --git a/dictation_server/src/common/check-header.middleware.ts b/dictation_server/src/common/check-header.middleware.ts new file mode 100644 index 0000000..359b2e0 --- /dev/null +++ b/dictation_server/src/common/check-header.middleware.ts @@ -0,0 +1,32 @@ +import { + HttpException, + Injectable, + Logger, + NestMiddleware, +} from '@nestjs/common'; +import { Request, Response, NextFunction } from 'express'; + +/** + * CheckHeaderMiddleware + * リクエストヘッダのチェックを行うミドルウェア + * + * ローカル環境ではヘッダチェックを行わない + */ +@Injectable() +export class CheckHeaderMiddleware implements NestMiddleware { + private readonly logger = new Logger(CheckHeaderMiddleware.name); + use(req: Request, res: Response, next: NextFunction): void { + // /healthcheckはheaderチェックを行わない + if (req.url === '/health') { + next(); + return; + } + + if (req.headers['x-requested-with'] === 'XMLHttpRequest') { + next(); + } else { + this.logger.error('header check failed'); + throw new HttpException('header check failed', 400); + } + } +}