Merged PR 228: Revert "Merged PR 218: 画面実装(カードライセンス取り込みPU)
Revert "Merged PR 218: 画面実装(カードライセンス取り込みPU) ## 概要 [Task2161: 画面実装(カードライセンス取り込みPU)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2161) タスク 2161: 画面実装(カードライセンス取り込みPU) カードライセンス取り込みポップアップを実装しました。 以下の項目については別タスクへ切り出しての対応とし、本タスクでは対象外とさせてください。 ・テキストボックスへの4文字区切りの入力 ・テキストボックスの文字数制限 ・改行コード入力時の挙動(バーコードリーダー対応) ## レビューポイント なし ## UIの変更 https://ndstokyo.sharepoint.com/:i:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task2161/%E3%82%AB%E3%83%BC%E3%83%89%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E5%8F%96%E3%82%8A%E8%BE%BC%E3%81%BFPU.PNG?csf=1&web=1&e=cRtMX3 ## 動作確認状況 ローカルで動作確認済み ## 補足 なし" Reverted commit `9a66ca02`.
This commit is contained in:
parent
9a66ca027a
commit
3584a65682
@ -7,7 +7,6 @@ import ui from "features/ui/uiSlice";
|
||||
import user from "features/user/userSlice";
|
||||
import license from "features/license/licenseOrder/licenseSlice";
|
||||
import licenseCardIssue from "features/license/licenseCardIssue/licenseCardIssueSlice";
|
||||
import licenseCardActivate from "features/license/licenseCardActivate/licenseCardActivateSlice";
|
||||
import licenseSummary from "features/license/licenseSummary/licenseSummarySlice";
|
||||
import dictation from "features/dictation/dictationSlice";
|
||||
|
||||
@ -21,7 +20,6 @@ export const store = configureStore({
|
||||
user,
|
||||
license,
|
||||
licenseCardIssue,
|
||||
licenseCardActivate,
|
||||
licenseSummary,
|
||||
dictation,
|
||||
},
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
export * from "./state";
|
||||
export * from "./operations";
|
||||
export * from "./selectors";
|
||||
export * from "./licenseCardActivateSlice";
|
||||
@ -1,31 +0,0 @@
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||
import { LicenseCardActivateState } from "./state";
|
||||
import { activateCardLicenseAsync } from "./operations";
|
||||
|
||||
const initialState: LicenseCardActivateState = {
|
||||
apps: {
|
||||
keyLicense: "",
|
||||
isLoading: false,
|
||||
},
|
||||
};
|
||||
export const licenseCardActivateSlice = createSlice({
|
||||
name: "licenseCardActivate",
|
||||
initialState,
|
||||
reducers: {
|
||||
changeKeyLicense: (
|
||||
state,
|
||||
action: PayloadAction<{ keyLicense: string }>
|
||||
) => {
|
||||
const { keyLicense } = action.payload;
|
||||
state.apps.keyLicense = keyLicense.toUpperCase();
|
||||
},
|
||||
cleanupApps: (state) => {
|
||||
state.apps = initialState.apps;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { changeKeyLicense, cleanupApps } =
|
||||
licenseCardActivateSlice.actions;
|
||||
|
||||
export default licenseCardActivateSlice.reducer;
|
||||
@ -1,64 +0,0 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { openSnackbar } from "../../ui/uiSlice";
|
||||
import type { RootState } from "../../../app/store";
|
||||
import { getTranslationID } from "../../../translation";
|
||||
import { LicensesApi } from "../../../api/api";
|
||||
import { Configuration } from "../../../api/configuration";
|
||||
import { ErrorObject, createErrorObject } from "../../../common/errors";
|
||||
|
||||
export const activateCardLicenseAsync = createAsyncThunk<
|
||||
{
|
||||
/* Empty Object */
|
||||
},
|
||||
{
|
||||
// パラメータ
|
||||
cardLicenseKey: string;
|
||||
},
|
||||
{
|
||||
// rejectした時の返却値の型s
|
||||
rejectValue: {
|
||||
error: ErrorObject;
|
||||
};
|
||||
}
|
||||
>("licenses/activateCardLicenseAsync", async (args, thunkApi) => {
|
||||
const { cardLicenseKey } = args;
|
||||
|
||||
// apiのConfigurationを取得する
|
||||
const { getState } = thunkApi;
|
||||
const state = getState() as RootState;
|
||||
const { configuration, accessToken } = state.auth;
|
||||
const config = new Configuration(configuration);
|
||||
const licensesApi = new LicensesApi(config);
|
||||
|
||||
try {
|
||||
await licensesApi.activateCardLicenses(
|
||||
{
|
||||
cardLicenseKey,
|
||||
},
|
||||
{
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
}
|
||||
);
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "info",
|
||||
message: getTranslationID("common.message.success"),
|
||||
})
|
||||
);
|
||||
return {};
|
||||
} catch (e) {
|
||||
// e ⇒ errorObjectに変換"
|
||||
const error = createErrorObject(e);
|
||||
|
||||
const errorMessage = getTranslationID("common.message.internalServerError");
|
||||
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "error",
|
||||
message: errorMessage,
|
||||
})
|
||||
);
|
||||
|
||||
return thunkApi.rejectWithValue({ error });
|
||||
}
|
||||
});
|
||||
@ -1,18 +0,0 @@
|
||||
import { RootState } from "../../../app/store";
|
||||
|
||||
export const selectInputValidationErrors = (state: RootState) => {
|
||||
const { keyLicense } = state.licenseCardActivate.apps;
|
||||
const hasErrorIncorrectKeyNumber = checkErrorIncorrectKeyNumber(keyLicense);
|
||||
return {
|
||||
hasErrorIncorrectKeyNumber,
|
||||
};
|
||||
};
|
||||
export const checkErrorIncorrectKeyNumber = (keyLicense: string): boolean =>
|
||||
// // 20+4(20文字+space4個)以外の場合はエラー
|
||||
keyLicense.length !== 24;
|
||||
|
||||
export const selectKeyLicense = (state: RootState) =>
|
||||
state.licenseCardActivate.apps.keyLicense;
|
||||
|
||||
export const selectIsLoading = (state: RootState) =>
|
||||
state.licenseCardActivate.apps.isLoading;
|
||||
@ -1,8 +0,0 @@
|
||||
export interface LicenseCardActivateState {
|
||||
apps: Apps;
|
||||
}
|
||||
|
||||
export interface Apps {
|
||||
keyLicense: string;
|
||||
isLoading: boolean;
|
||||
}
|
||||
@ -1,20 +1,6 @@
|
||||
import React, { useState, useCallback, useEffect, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { AppDispatch } from "app/store";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import _ from "lodash";
|
||||
import styles from "../../styles/app.module.scss";
|
||||
import { getTranslationID } from "../../translation";
|
||||
import React, { useCallback } from "react";
|
||||
import styles from "styles/app.module.scss";
|
||||
import close from "../../assets/images/close.svg";
|
||||
import {
|
||||
activateCardLicenseAsync,
|
||||
selectKeyLicense,
|
||||
cleanupApps,
|
||||
selectIsLoading,
|
||||
changeKeyLicense,
|
||||
selectInputValidationErrors,
|
||||
} from "../../features/license/licenseCardActivate/index";
|
||||
import progress_activit from "../../assets/images/progress_activit.svg";
|
||||
|
||||
interface CardLicenseActivatePopupProps {
|
||||
onClose: () => void;
|
||||
@ -24,92 +10,18 @@ export const CardLicenseActivatePopup: React.FC<
|
||||
CardLicenseActivatePopupProps
|
||||
> = (props) => {
|
||||
const { onClose } = props;
|
||||
const { t } = useTranslation();
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
const cardLicenseKey = useSelector(selectKeyLicense);
|
||||
const [keyNumber, setKeyNumber] = useState<string>(cardLicenseKey);
|
||||
const isLoading = useSelector(selectIsLoading);
|
||||
|
||||
// ポップアップを閉じる処理
|
||||
const closePopup = useCallback(() => {
|
||||
if (isLoading) {
|
||||
return;
|
||||
}
|
||||
onClose();
|
||||
}, [isLoading, onClose]);
|
||||
|
||||
// ブラウザのウィンドウが閉じられようとしている場合に発火するイベントハンドラ
|
||||
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
|
||||
// isLoadingがtrueの場合は確認ダイアログを表示する
|
||||
if (isLoading) {
|
||||
e.preventDefault();
|
||||
// ChromeではreturnValueが必要
|
||||
e.returnValue = "";
|
||||
}
|
||||
};
|
||||
// コンポーネントがマウントされた時にイベントハンドラを登録する
|
||||
useEffect(() => {
|
||||
window.addEventListener("beforeunload", handleBeforeUnload);
|
||||
// コンポーネントがアンマウントされるときにイベントハンドラを解除する
|
||||
return () => {
|
||||
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
// useEffectのreturnとしてcleanupAppsを実行することで、ポップアップのアンマウント時に初期化を行う
|
||||
dispatch(cleanupApps());
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const [isPushActivateButton, setIsPushActivateButton] =
|
||||
useState<boolean>(false);
|
||||
|
||||
// エラー宣言
|
||||
const { hasErrorIncorrectKeyNumber } = useSelector(
|
||||
selectInputValidationErrors
|
||||
);
|
||||
|
||||
// activateボタン押下時
|
||||
const onActivateLicense = useCallback(async () => {
|
||||
setIsPushActivateButton(true);
|
||||
|
||||
if (keyNumber.length !== 24) {
|
||||
const inputBox = document.getElementById("inputBox");
|
||||
// カーソルをテキストボックスに戻す
|
||||
if (inputBox) {
|
||||
inputBox.focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// activateAPIの呼び出し
|
||||
const cardLicenseKeyWithoutSpaces = keyNumber.replace(/\s/g, "");
|
||||
const { meta } = await dispatch(
|
||||
activateCardLicenseAsync({ cardLicenseKey: cardLicenseKeyWithoutSpaces })
|
||||
);
|
||||
setIsPushActivateButton(false);
|
||||
|
||||
// カーソルをテキストボックスに戻す
|
||||
const inputBox = document.getElementById("inputBox");
|
||||
if (inputBox) {
|
||||
inputBox.focus();
|
||||
}
|
||||
|
||||
if (meta.requestStatus === "fulfilled") {
|
||||
dispatch(cleanupApps());
|
||||
setKeyNumber("");
|
||||
}
|
||||
}, [keyNumber, dispatch]);
|
||||
}, [onClose]);
|
||||
|
||||
// HTML
|
||||
return (
|
||||
<div className={`${styles.modal} ${styles.isShow}`}>
|
||||
<div className={styles.modalBox}>
|
||||
<p className={styles.modalTitle}>
|
||||
{t(getTranslationID("cardLicenseActivatePopupPage.label.title"))}
|
||||
Activate License Key
|
||||
<button type="button" onClick={closePopup}>
|
||||
<img src={close} className={styles.modalTitleIcon} alt="close" />
|
||||
</button>
|
||||
@ -118,93 +30,24 @@ export const CardLicenseActivatePopup: React.FC<
|
||||
<form className={styles.form}>
|
||||
<dl className={`${styles.formList} ${styles.hasbg}`}>
|
||||
<dt className={styles.formTitle} />
|
||||
<dt>
|
||||
<label htmlFor="inputBox">
|
||||
{t(
|
||||
getTranslationID(
|
||||
"cardLicenseActivatePopupPage.label.keyNumber"
|
||||
)
|
||||
)}
|
||||
</label>
|
||||
</dt>
|
||||
<dt>Key number</dt>
|
||||
<dd className="">
|
||||
<input
|
||||
id="inputBox"
|
||||
type="text"
|
||||
size={48}
|
||||
size={40}
|
||||
name=""
|
||||
value={keyNumber}
|
||||
maxLength={24} // 20+4(20文字+space4個)
|
||||
value=""
|
||||
maxLength={20}
|
||||
className={styles.formInput}
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus
|
||||
onChange={(e) => {
|
||||
let input = e.target.value.toUpperCase();
|
||||
input = input.replace(/[^A-Z0-9]/g, "");
|
||||
// _.chunk関数で、配列の要素を一定の要素数ごとに分ける
|
||||
input = _.chunk(input, 4)
|
||||
.map((a) => a.join(""))
|
||||
.join(" ");
|
||||
setKeyNumber(input);
|
||||
if (input.includes("\n")) {
|
||||
dispatch(
|
||||
changeKeyLicense({
|
||||
keyLicense: e.target.value.toUpperCase(),
|
||||
})
|
||||
);
|
||||
onActivateLicense();
|
||||
}
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
dispatch(
|
||||
changeKeyLicense({
|
||||
keyLicense: e.target.value.toUpperCase(),
|
||||
})
|
||||
);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
const input = e.target.value.toUpperCase();
|
||||
setKeyNumber(input);
|
||||
const button = document.getElementById("button");
|
||||
if (button) {
|
||||
button.focus();
|
||||
button.click();
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{isPushActivateButton && hasErrorIncorrectKeyNumber && (
|
||||
<span className={styles.formError}>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"cardLicenseActivatePopupPage.label.keyNumberIncorrectError"
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</dd>
|
||||
<dd className={`${styles.full} ${styles.alignCenter}`}>
|
||||
<input
|
||||
id="button"
|
||||
type="button"
|
||||
name="submit"
|
||||
value={t(
|
||||
getTranslationID(
|
||||
"cardLicenseActivatePopupPage.label.activateButton"
|
||||
)
|
||||
)}
|
||||
onClick={onActivateLicense}
|
||||
className={`${styles.formSubmit} ${styles.marginBtm1} ${
|
||||
!isLoading ? styles.isActive : ""
|
||||
}`}
|
||||
/>
|
||||
<img
|
||||
style={{ display: isLoading ? "inline" : "none" }}
|
||||
src={progress_activit}
|
||||
className={styles.icLoading}
|
||||
alt="Loading"
|
||||
value="Activate"
|
||||
className={`${styles.formSubmit} ${styles.marginBtm1} ${styles.isActive}`}
|
||||
onClick={closePopup}
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@ -238,17 +238,5 @@
|
||||
"label": {
|
||||
"cardLicenseButton": "(de)License Card"
|
||||
}
|
||||
},
|
||||
"cardLicenseActivatePopupPage": {
|
||||
"label": {
|
||||
"title": "(de)Activate License Key",
|
||||
"keyNumber": "(de)Key number",
|
||||
"activateButton": "(de)activate",
|
||||
"keyNumberIncorrectError": "(de)Key Numberには20桁の半角大文字英数字を入力してください。"
|
||||
},
|
||||
"message": {
|
||||
"LicenseKeyNotExistError": "(de)入力されたライセンスキーは存在しません。ライセンスキーを再度お確かめください。",
|
||||
"LicenseKeyAlreadyActivatedError": "(de)入力されたライセンスキーは、既に有効化されています。ライセンスキーを再度お確かめください。"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,17 +238,5 @@
|
||||
"label": {
|
||||
"cardLicenseButton": "License Card"
|
||||
}
|
||||
},
|
||||
"cardLicenseActivatePopupPage": {
|
||||
"label": {
|
||||
"title": "Activate License Key",
|
||||
"keyNumber": "Key number",
|
||||
"activateButton": "activate",
|
||||
"keyNumberIncorrectError": "Key Numberには20桁の半角大文字英数字を入力してください。"
|
||||
},
|
||||
"message": {
|
||||
"LicenseKeyNotExistError": "入力されたライセンスキーは存在しません。ライセンスキーを再度お確かめください。",
|
||||
"LicenseKeyAlreadyActivatedError": "入力されたライセンスキーは、既に有効化されています。ライセンスキーを再度お確かめください。"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,17 +238,5 @@
|
||||
"label": {
|
||||
"cardLicenseButton": "(es)License Card"
|
||||
}
|
||||
},
|
||||
"cardLicenseActivatePopupPage": {
|
||||
"label": {
|
||||
"title": "(es)Activate License Key",
|
||||
"keyNumber": "(es)Key number",
|
||||
"activateButton": "(es)activate",
|
||||
"keyNumberIncorrectError": "(es)Key Numberには20桁の半角大文字英数字を入力してください。"
|
||||
},
|
||||
"message": {
|
||||
"LicenseKeyNotExistError": "(es)入力されたライセンスキーは存在しません。ライセンスキーを再度お確かめください。",
|
||||
"LicenseKeyAlreadyActivatedError": "(es)入力されたライセンスキーは、既に有効化されています。ライセンスキーを再度お確かめください。"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,17 +238,5 @@
|
||||
"label": {
|
||||
"cardLicenseButton": "(fr)License Card"
|
||||
}
|
||||
},
|
||||
"cardLicenseActivatePopupPage": {
|
||||
"label": {
|
||||
"title": "(fr)Activate License Key",
|
||||
"keyNumber": "(fr)Key number",
|
||||
"activateButton": "(fr)activate",
|
||||
"keyNumberIncorrectError": "(fr)Key Numberには20桁の半角大文字英数字を入力してください。"
|
||||
},
|
||||
"message": {
|
||||
"LicenseKeyNotExistError": "(fr)入力されたライセンスキーは存在しません。ライセンスキーを再度お確かめください。",
|
||||
"LicenseKeyAlreadyActivatedError": "(fr)入力されたライセンスキーは、既に有効化されています。ライセンスキーを再度お確かめください。"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,3 +13,4 @@ TENANT_NAME=adb2codmsdev
|
||||
SIGNIN_FLOW_NAME=b2c_1_signin_dev
|
||||
EMAIL_CONFIRM_LIFETIME=86400000
|
||||
APP_DOMAIN=https://10.1.0.10:4443/
|
||||
STORAGE_TOKEN_EXPIRE_TIME=2
|
||||
@ -16,7 +16,6 @@ MAIL_FROM=xxxxx@xxxxx.xxxx
|
||||
NOTIFICATION_HUB_NAME=ntf-odms-shared
|
||||
NOTIFICATION_HUB_CONNECT_STRING=XXXXXXXXXXXXXXXXXX
|
||||
APP_DOMAIN=http://localhost:8081/
|
||||
STORAGE_TOKEN_EXPIRE_TIME=30
|
||||
STORAGE_ACCOUNT_NAME_US=saodmsusdev
|
||||
STORAGE_ACCOUNT_NAME_AU=saodmsaudev
|
||||
STORAGE_ACCOUNT_NAME_EU=saodmseudev
|
||||
|
||||
@ -36,4 +36,8 @@ export const ErrorCodes = [
|
||||
'E010501', // アカウント不在エラー
|
||||
'E010601', // タスク変更不可エラー(タスクが変更できる状態でない、またはタスクが存在しない)
|
||||
'E010602', // タスク変更権限不足エラー
|
||||
'E010603', // タスク不在エラー
|
||||
'E010701', // Blobファイル不在エラー
|
||||
'E010801', // ライセンス不在エラー
|
||||
'E010802', // ライセンス取り込み済みエラー
|
||||
] as const;
|
||||
|
||||
@ -25,4 +25,8 @@ export const errors: Errors = {
|
||||
E010501: 'Account not Found Error.',
|
||||
E010601: 'Task is not Editable Error',
|
||||
E010602: 'No task edit permissions Error',
|
||||
E010603: 'Task not found Error.',
|
||||
E010701: 'File not found in Blob Storage Error.',
|
||||
E010801: 'License not exist Error',
|
||||
E010802: 'License already activated Error',
|
||||
};
|
||||
|
||||
@ -177,16 +177,24 @@ export class FilesController {
|
||||
'指定した音声ファイルのBlob Storage上のダウンロード先アクセスURLを取得します',
|
||||
})
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AuthGuard)
|
||||
@UseGuards(
|
||||
RoleGuard.requireds({ roles: [USER_ROLES.AUTHOR, USER_ROLES.TYPIST] }),
|
||||
)
|
||||
async downloadLocation(
|
||||
@Headers() headers,
|
||||
@Req() req: Request,
|
||||
@Query() body: AudioDownloadLocationRequest,
|
||||
): Promise<AudioDownloadLocationResponse> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { audioFileId } = body;
|
||||
// コンテナ作成処理の前にアクセストークンの認証を行う
|
||||
//
|
||||
|
||||
return { url: '' };
|
||||
const token = retrieveAuthorizationToken(req);
|
||||
const accessToken = jwt.decode(token, { json: true }) as AccessToken;
|
||||
const url = await this.filesService.publishAudioFileDownloadSas(
|
||||
accessToken.userId,
|
||||
audioFileId,
|
||||
);
|
||||
|
||||
return { url };
|
||||
}
|
||||
|
||||
@Get('template/download-location')
|
||||
|
||||
@ -6,8 +6,16 @@ import {
|
||||
makeDefaultUsersRepositoryMockValue,
|
||||
makeFilesServiceMock,
|
||||
} from './test/files.service.mock';
|
||||
import { DataSource } from 'typeorm';
|
||||
import {
|
||||
createAccount,
|
||||
createTask,
|
||||
createUser,
|
||||
makeTestingModuleWithBlob,
|
||||
} from './test/utility';
|
||||
import { FilesService } from './files.service';
|
||||
|
||||
describe('FilesService', () => {
|
||||
describe('音声ファイルアップロードURL取得', () => {
|
||||
it('アップロードSASトークンが乗っているURLを返却する', async () => {
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const userRepoParam = makeDefaultUsersRepositoryMockValue();
|
||||
@ -95,7 +103,9 @@ describe('FilesService', () => {
|
||||
new HttpException(makeErrorResponse('E009999'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('タスク作成', () => {
|
||||
it('文字起こしタスクを作成できる', async () => {
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const userRepoParam = makeDefaultUsersRepositoryMockValue();
|
||||
|
||||
@ -28,6 +28,7 @@ export class FilesService {
|
||||
private readonly logger = new Logger(FilesService.name);
|
||||
constructor(
|
||||
private readonly usersRepository: UsersRepositoryService,
|
||||
private readonly tasksRepository: TasksRepositoryService,
|
||||
private readonly tasksRepositoryService: TasksRepositoryService,
|
||||
private readonly blobStorageService: BlobstorageService,
|
||||
) {}
|
||||
@ -127,13 +128,19 @@ export class FilesService {
|
||||
}
|
||||
|
||||
try {
|
||||
// URLにSASトークンがついている場合は取り除く
|
||||
const urlObj = new URL(url);
|
||||
urlObj.search = '';
|
||||
const fileUrl = urlObj.toString();
|
||||
this.logger.log(`Request URL: ${url}, Without param URL${fileUrl}`);
|
||||
|
||||
// 文字起こしタスク追加(音声ファイルとオプションアイテムも同時に追加)
|
||||
// 追加時に末尾のJOBナンバーにインクリメントする
|
||||
const task = await this.tasksRepositoryService.create(
|
||||
user.account_id,
|
||||
user.id,
|
||||
priority,
|
||||
url,
|
||||
fileUrl,
|
||||
fileName,
|
||||
authorId,
|
||||
workType,
|
||||
|
||||
@ -9,7 +9,9 @@ import { Task } from '../../../repositories/tasks/entity/task.entity';
|
||||
export type BlobstorageServiceMockValue = {
|
||||
createContainer: void | Error;
|
||||
containerExists: boolean | Error;
|
||||
fileExists: boolean | Error;
|
||||
publishUploadSas: string | Error;
|
||||
publishDownloadSas: string | Error;
|
||||
};
|
||||
|
||||
export type UsersRepositoryMockValue = {
|
||||
@ -47,13 +49,23 @@ export const makeFilesServiceMock = async (
|
||||
export const makeBlobstorageServiceMock = (
|
||||
value: BlobstorageServiceMockValue,
|
||||
) => {
|
||||
const { containerExists, createContainer, publishUploadSas } = value;
|
||||
const {
|
||||
containerExists,
|
||||
fileExists,
|
||||
createContainer,
|
||||
publishUploadSas,
|
||||
publishDownloadSas,
|
||||
} = value;
|
||||
|
||||
return {
|
||||
containerExists:
|
||||
containerExists instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(containerExists)
|
||||
: jest.fn<Promise<boolean>, []>().mockResolvedValue(containerExists),
|
||||
fileExists:
|
||||
fileExists instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(fileExists)
|
||||
: jest.fn<Promise<boolean>, []>().mockResolvedValue(fileExists),
|
||||
createContainer:
|
||||
createContainer instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(createContainer)
|
||||
@ -62,6 +74,10 @@ export const makeBlobstorageServiceMock = (
|
||||
publishUploadSas instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(publishUploadSas)
|
||||
: jest.fn<Promise<string>, []>().mockResolvedValue(publishUploadSas),
|
||||
publishDownloadSas:
|
||||
publishDownloadSas instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(publishDownloadSas)
|
||||
: jest.fn<Promise<string>, []>().mockResolvedValue(publishDownloadSas),
|
||||
};
|
||||
};
|
||||
|
||||
@ -80,7 +96,9 @@ export const makeBlobstorageServiceMockValue =
|
||||
(): BlobstorageServiceMockValue => {
|
||||
return {
|
||||
containerExists: true,
|
||||
fileExists: true,
|
||||
publishUploadSas: 'https://blob-storage?sas-token',
|
||||
publishDownloadSas: 'https://blob-storage?sas-token',
|
||||
createContainer: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
@ -28,7 +28,7 @@ import { retrieveAuthorizationToken } from '../../common/http/helper';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import { AuthGuard } from '../../common/guards/auth/authguards';
|
||||
import { RoleGuard } from '../../common/guards/role/roleguards';
|
||||
import { ADMIN_ROLES } from '../../constants';
|
||||
import { ADMIN_ROLES, TIER_1, TIER_5 } from '../../constants';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
@ -112,7 +112,7 @@ export class LicensesController {
|
||||
const payload = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
|
||||
// 第一階層以外は401を返す(後々UseGuardsで弾く)
|
||||
if (payload.tier != 1) {
|
||||
if (payload.tier != TIER_1) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000108'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
@ -159,6 +159,22 @@ export class LicensesController {
|
||||
console.log(req.header('Authorization'));
|
||||
console.log(body);
|
||||
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
const payload = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
|
||||
// TODO 第五階層以外は401を返す(後々UseGuardsで弾く)
|
||||
if (payload.tier != TIER_5) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000108'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
await this.licensesService.activateCardLicenseKey(
|
||||
payload.userId,
|
||||
body.cardLicenseKey,
|
||||
);
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import {
|
||||
CreateOrdersRequest,
|
||||
IssueCardLicensesRequest,
|
||||
IssueCardLicensesResponse,
|
||||
ActivateCardLicensesRequest,
|
||||
} from './types/types';
|
||||
import {
|
||||
makeDefaultAccountsRepositoryMockValue,
|
||||
@ -12,14 +13,23 @@ import {
|
||||
} from './test/liscense.service.mock';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { PoNumberAlreadyExistError } from '../../repositories/licenses/errors/types';
|
||||
import {
|
||||
PoNumberAlreadyExistError,
|
||||
LicenseKeyAlreadyActivatedError,
|
||||
LicenseNotExistError,
|
||||
} from '../../repositories/licenses/errors/types';
|
||||
import { LicensesService } from './licenses.service';
|
||||
import { makeTestingModule } from '../../common/test/modules';
|
||||
import { DataSource } from 'typeorm';
|
||||
import {
|
||||
createAccount,
|
||||
createUser,
|
||||
createCardLicense,
|
||||
createLicense,
|
||||
createCardLicenseIssue,
|
||||
selectCardLicensesCount,
|
||||
selectCardLicense,
|
||||
selectLicense,
|
||||
} from './test/utility';
|
||||
|
||||
describe('LicensesService', () => {
|
||||
@ -177,6 +187,92 @@ describe('LicensesService', () => {
|
||||
),
|
||||
);
|
||||
});
|
||||
it('カードライセンス取り込みが完了する', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new ActivateCardLicensesRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
body.cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
expect(
|
||||
await service.activateCardLicenseKey(token.userId, body.cardLicenseKey),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
it('カードライセンス取り込みに失敗した場合、エラーになる(DBエラー)', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
lisencesRepositoryMockValue.activateCardLicense = new Error('DB failed');
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new ActivateCardLicensesRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
body.cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
await expect(
|
||||
service.activateCardLicenseKey(token.userId, body.cardLicenseKey),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
it('カードライセンス取り込みに失敗した場合、エラーになる(ライセンスが存在しないエラー)', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
lisencesRepositoryMockValue.activateCardLicense =
|
||||
new LicenseNotExistError();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new ActivateCardLicensesRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
body.cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
await expect(
|
||||
service.activateCardLicenseKey(token.userId, body.cardLicenseKey),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010801'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
it('カードライセンス取り込みに失敗した場合、エラーになる(ライセンスが既に取り込まれているエラー)', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
lisencesRepositoryMockValue.activateCardLicense =
|
||||
new LicenseKeyAlreadyActivatedError();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new ActivateCardLicensesRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
body.cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
await expect(
|
||||
service.activateCardLicenseKey(token.userId, body.cardLicenseKey),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010802'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DBテスト', () => {
|
||||
@ -214,4 +310,38 @@ describe('DBテスト', () => {
|
||||
const dbSelectResult = await selectCardLicensesCount(source);
|
||||
expect(dbSelectResult.count).toEqual(issueCount);
|
||||
});
|
||||
|
||||
it('カードライセンス取り込みが完了する', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
|
||||
const { accountId } = await createAccount(source);
|
||||
const { externalId } = await createUser(
|
||||
source,
|
||||
accountId,
|
||||
'userId',
|
||||
'admin',
|
||||
);
|
||||
|
||||
const cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
const defaultAccountId = 150;
|
||||
const licenseId = 50;
|
||||
const issueId = 100;
|
||||
|
||||
await createLicense(source, licenseId, defaultAccountId);
|
||||
await createCardLicense(source, licenseId, issueId, cardLicenseKey);
|
||||
await createCardLicenseIssue(source, issueId);
|
||||
|
||||
const service = module.get<LicensesService>(LicensesService);
|
||||
|
||||
await service.activateCardLicenseKey(externalId, cardLicenseKey);
|
||||
const dbSelectResultFromCardLicense = await selectCardLicense(
|
||||
source,
|
||||
cardLicenseKey,
|
||||
);
|
||||
const dbSelectResultFromLicense = await selectLicense(source, licenseId);
|
||||
expect(
|
||||
dbSelectResultFromCardLicense.cardLicense.activated_at,
|
||||
).toBeDefined();
|
||||
expect(dbSelectResultFromLicense.license.account_id).toEqual(accountId);
|
||||
});
|
||||
});
|
||||
|
||||
@ -4,7 +4,11 @@ import { AccessToken } from '../../common/token';
|
||||
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
|
||||
import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service';
|
||||
import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
|
||||
import { PoNumberAlreadyExistError } from '../../repositories/licenses/errors/types';
|
||||
import {
|
||||
PoNumberAlreadyExistError,
|
||||
LicenseNotExistError,
|
||||
LicenseKeyAlreadyActivatedError,
|
||||
} from '../../repositories/licenses/errors/types';
|
||||
import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service';
|
||||
import { UserNotFoundError } from '../../repositories/users/errors/types';
|
||||
import { IssueCardLicensesResponse } from './types/types';
|
||||
@ -140,4 +144,71 @@ export class LicensesService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* card license activate
|
||||
* @param externalId
|
||||
* @param cardLicenseKey
|
||||
*/
|
||||
async activateCardLicenseKey(
|
||||
externalId: string,
|
||||
cardLicenseKey: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] ${this.activateCardLicenseKey.name}, argCardLicenseKey: ${cardLicenseKey}`,
|
||||
);
|
||||
let myAccountId: number;
|
||||
|
||||
// ユーザIDからアカウントIDを取得する
|
||||
try {
|
||||
myAccountId = (
|
||||
await this.usersRepository.findUserByExternalId(externalId)
|
||||
).account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010204'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// カードライセンスを取り込む
|
||||
try {
|
||||
await this.licensesRepository.activateCardLicense(
|
||||
myAccountId,
|
||||
cardLicenseKey,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('cardLicenseKey activate failed');
|
||||
|
||||
switch (e.constructor) {
|
||||
case LicenseNotExistError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010801'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
case LicenseKeyAlreadyActivatedError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010802'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
this.logger.log(`[OUT] ${this.activateCardLicenseKey.name}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import { AccountsRepositoryService } from '../../../repositories/accounts/accoun
|
||||
export type LicensesRepositoryMockValue = {
|
||||
order: undefined | Error;
|
||||
createCardLicenses: string[] | Error;
|
||||
activateCardLicense: undefined | Error;
|
||||
};
|
||||
|
||||
export type AccountsRepositoryMockValue = {
|
||||
@ -45,7 +46,7 @@ export const makeLicensesServiceMock = async (
|
||||
export const makeLicensesRepositoryMock = (
|
||||
value: LicensesRepositoryMockValue,
|
||||
) => {
|
||||
const { order, createCardLicenses } = value;
|
||||
const { order, createCardLicenses, activateCardLicense } = value;
|
||||
return {
|
||||
order:
|
||||
order instanceof Error
|
||||
@ -57,6 +58,10 @@ export const makeLicensesRepositoryMock = (
|
||||
: jest
|
||||
.fn<Promise<string[]>, []>()
|
||||
.mockResolvedValue(createCardLicenses),
|
||||
activateCardLicense:
|
||||
activateCardLicense instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(activateCardLicense)
|
||||
: jest.fn<Promise<void>, []>().mockResolvedValue(activateCardLicense),
|
||||
};
|
||||
};
|
||||
|
||||
@ -100,6 +105,7 @@ export const makeDefaultLicensesRepositoryMockValue =
|
||||
'XYLEWNY2LR6Q657CZE41',
|
||||
'AEJWRFFSWRQYQQJ6WVLV',
|
||||
],
|
||||
activateCardLicense: undefined,
|
||||
};
|
||||
};
|
||||
export const makeDefaultUsersRepositoryMockValue =
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import { DataSource } from 'typeorm';
|
||||
import { User } from '../../../repositories/users/entity/user.entity';
|
||||
import { Account } from '../../../repositories/accounts/entity/account.entity';
|
||||
import { CardLicense } from '../../../repositories/licenses/entity/license.entity';
|
||||
import {
|
||||
License,
|
||||
CardLicense,
|
||||
CardLicenseIssue,
|
||||
} from '../../../repositories/licenses/entity/license.entity';
|
||||
|
||||
export const createAccount = async (
|
||||
datasource: DataSource,
|
||||
@ -49,9 +53,92 @@ export const createUser = async (
|
||||
return { userId: user.id, externalId: external_id };
|
||||
};
|
||||
|
||||
export const createLicense = async (
|
||||
datasource: DataSource,
|
||||
licenseId: number,
|
||||
accountId: number,
|
||||
): Promise<void> => {
|
||||
const { identifiers } = await datasource.getRepository(License).insert({
|
||||
id: licenseId,
|
||||
expiry_date: null,
|
||||
account_id: accountId,
|
||||
type: 'card',
|
||||
status: 'Unallocated',
|
||||
allocated_user_id: null,
|
||||
order_id: null,
|
||||
deleted_at: null,
|
||||
delete_order_id: null,
|
||||
created_by: 'test_runner',
|
||||
created_at: new Date(),
|
||||
updated_by: 'updater',
|
||||
updated_at: new Date(),
|
||||
});
|
||||
identifiers.pop() as License;
|
||||
};
|
||||
|
||||
export const createCardLicense = async (
|
||||
datasource: DataSource,
|
||||
licenseId: number,
|
||||
issueId: number,
|
||||
cardLicenseKey: string,
|
||||
): Promise<void> => {
|
||||
const { identifiers } = await datasource.getRepository(CardLicense).insert({
|
||||
license_id: licenseId,
|
||||
issue_id: issueId,
|
||||
card_license_key: cardLicenseKey,
|
||||
activated_at: null,
|
||||
created_by: 'test_runner',
|
||||
created_at: new Date(),
|
||||
updated_by: 'updater',
|
||||
updated_at: new Date(),
|
||||
});
|
||||
identifiers.pop() as CardLicense;
|
||||
};
|
||||
|
||||
export const createCardLicenseIssue = async (
|
||||
datasource: DataSource,
|
||||
issueId: number,
|
||||
): Promise<void> => {
|
||||
const { identifiers } = await datasource
|
||||
.getRepository(CardLicenseIssue)
|
||||
.insert({
|
||||
id: issueId,
|
||||
issued_at: new Date(),
|
||||
created_by: 'test_runner',
|
||||
created_at: new Date(),
|
||||
updated_by: 'updater',
|
||||
updated_at: new Date(),
|
||||
});
|
||||
identifiers.pop() as CardLicenseIssue;
|
||||
};
|
||||
|
||||
export const selectCardLicensesCount = async (
|
||||
datasource: DataSource,
|
||||
): Promise<{ count: number }> => {
|
||||
const count = await datasource.getRepository(CardLicense).count();
|
||||
return { count: count };
|
||||
};
|
||||
|
||||
export const selectCardLicense = async (
|
||||
datasource: DataSource,
|
||||
cardLicenseKey: string,
|
||||
): Promise<{ cardLicense: CardLicense }> => {
|
||||
const cardLicense = await datasource.getRepository(CardLicense).findOne({
|
||||
where: {
|
||||
card_license_key: cardLicenseKey,
|
||||
},
|
||||
});
|
||||
return { cardLicense };
|
||||
};
|
||||
|
||||
export const selectLicense = async (
|
||||
datasource: DataSource,
|
||||
id: number,
|
||||
): Promise<{ license: License }> => {
|
||||
const license = await datasource.getRepository(License).findOne({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
return { license };
|
||||
};
|
||||
|
||||
@ -19,7 +19,6 @@ import {
|
||||
} from './test/utility';
|
||||
import { Adb2cTooManyRequestsError } from '../../gateways/adb2c/adb2c.service';
|
||||
import { makeTestingModule } from '../../common/test/modules';
|
||||
import { TasksNotFoundError } from '../../repositories/tasks/errors/types';
|
||||
|
||||
describe('TasksService', () => {
|
||||
it('タスク一覧を取得できる(admin)', async () => {
|
||||
|
||||
@ -4,7 +4,9 @@ import {
|
||||
StorageSharedKeyCredential,
|
||||
ContainerClient,
|
||||
ContainerSASPermissions,
|
||||
BlobSASPermissions,
|
||||
generateBlobSASQueryParameters,
|
||||
BlobClient,
|
||||
} from '@azure/storage-blob';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import {
|
||||
@ -83,6 +85,27 @@ export class BlobstorageService {
|
||||
return exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Files exists
|
||||
* @param accountId
|
||||
* @param country
|
||||
* @param path
|
||||
* @param fileName
|
||||
* @param containerUrl
|
||||
* @returns exists
|
||||
*/
|
||||
async fileExists(
|
||||
accountId: number,
|
||||
country: string,
|
||||
filePath: string,
|
||||
): Promise<boolean> {
|
||||
const containerClient = this.getContainerClient(accountId, country);
|
||||
const blob = containerClient.getBlobClient(`${filePath}`);
|
||||
const exists = await blob.exists();
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* SASトークン付きのBlobStorageアップロードURLを生成し返却します
|
||||
* @param accountId
|
||||
@ -109,10 +132,9 @@ export class BlobstorageService {
|
||||
}
|
||||
|
||||
//SASの有効期限を設定
|
||||
//TODO 有効期限は仮で30分
|
||||
const expiryDate = new Date();
|
||||
expiryDate.setMinutes(
|
||||
expiryDate.getMinutes() +
|
||||
expiryDate.setHours(
|
||||
expiryDate.getHours() +
|
||||
this.configService.get('STORAGE_TOKEN_EXPIRE_TIME'),
|
||||
);
|
||||
|
||||
@ -137,6 +159,63 @@ export class BlobstorageService {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* SASトークン付きのBlobStorageダウンロードURLを生成し返却します
|
||||
* @param accountId
|
||||
* @param country
|
||||
* @param path
|
||||
* @param fileName
|
||||
* @returns download sas
|
||||
*/
|
||||
async publishDownloadSas(
|
||||
accountId: number,
|
||||
country: string,
|
||||
filePath: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(`[IN] ${this.publishDownloadSas.name}`);
|
||||
let containerClient: ContainerClient;
|
||||
let blobClient: BlobClient;
|
||||
let sharedKeyCredential: StorageSharedKeyCredential;
|
||||
try {
|
||||
// コンテナ名を指定してClientを取得
|
||||
containerClient = this.getContainerClient(accountId, country);
|
||||
// コンテナ内のBlobパス名を指定してClientを取得
|
||||
blobClient = containerClient.getBlobClient(`${filePath}`);
|
||||
// 国に対応したリージョンの接続情報を取得する
|
||||
sharedKeyCredential = this.getSharedKeyCredential(country);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw e;
|
||||
}
|
||||
|
||||
//SASの有効期限を設定
|
||||
const expiryDate = new Date();
|
||||
expiryDate.setHours(
|
||||
expiryDate.getHours() +
|
||||
this.configService.get('STORAGE_TOKEN_EXPIRE_TIME'),
|
||||
);
|
||||
|
||||
//SASの権限を設定(ダウンロードのため読み取り許可)
|
||||
const permissions = new BlobSASPermissions();
|
||||
permissions.read = true;
|
||||
|
||||
//SASを発行
|
||||
const sasToken = generateBlobSASQueryParameters(
|
||||
{
|
||||
containerName: containerClient.containerName,
|
||||
blobName: blobClient.name,
|
||||
permissions: permissions,
|
||||
startsOn: new Date(),
|
||||
expiresOn: expiryDate,
|
||||
},
|
||||
sharedKeyCredential,
|
||||
);
|
||||
|
||||
const url = new URL(blobClient.url);
|
||||
url.search = `${sasToken}`;
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets container client
|
||||
* @param companyName
|
||||
|
||||
@ -3,6 +3,7 @@ import {
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity({ name: 'license_orders' })
|
||||
@ -63,6 +64,18 @@ export class License {
|
||||
|
||||
@Column({ nullable: true })
|
||||
delete_order_id: number;
|
||||
|
||||
@Column({ nullable: true })
|
||||
created_by: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date;
|
||||
|
||||
@Column({ nullable: true })
|
||||
updated_by: string;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updated_at: Date;
|
||||
}
|
||||
@Entity({ name: 'licenses_history' })
|
||||
export class LicenseHistory {
|
||||
@ -92,6 +105,18 @@ export class CardLicenseIssue {
|
||||
|
||||
@Column()
|
||||
issued_at: Date;
|
||||
|
||||
@Column({ nullable: true })
|
||||
created_by: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date;
|
||||
|
||||
@Column({ nullable: true })
|
||||
updated_by: string;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
@Entity({ name: 'card_licenses' })
|
||||
@ -107,4 +132,16 @@ export class CardLicense {
|
||||
|
||||
@Column({ nullable: true })
|
||||
activated_at: Date;
|
||||
|
||||
@Column({ nullable: true })
|
||||
created_by: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date;
|
||||
|
||||
@Column({ nullable: true })
|
||||
updated_by: string;
|
||||
|
||||
@UpdateDateColumn({})
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
@ -1,2 +1,8 @@
|
||||
// POナンバーがすでに存在するエラー
|
||||
export class PoNumberAlreadyExistError extends Error {}
|
||||
|
||||
// 取り込むカードライセンスが存在しないエラー
|
||||
export class LicenseNotExistError extends Error {}
|
||||
|
||||
// 取り込むライセンスが既に取り込み済みのエラー
|
||||
export class LicenseKeyAlreadyActivatedError extends Error {}
|
||||
|
||||
@ -1,10 +1,22 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { CardLicense, CardLicenseIssue, License, LicenseOrder } from './entity/license.entity';
|
||||
import {
|
||||
CardLicense,
|
||||
CardLicenseIssue,
|
||||
License,
|
||||
LicenseOrder,
|
||||
} from './entity/license.entity';
|
||||
import { LicensesRepositoryService } from './licenses.repository.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([LicenseOrder,License,CardLicense,CardLicenseIssue])],
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([
|
||||
LicenseOrder,
|
||||
License,
|
||||
CardLicense,
|
||||
CardLicenseIssue,
|
||||
]),
|
||||
],
|
||||
providers: [LicensesRepositoryService],
|
||||
exports: [LicensesRepositoryService],
|
||||
})
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { DataSource, In } from 'typeorm';
|
||||
import {
|
||||
LicenseOrder,
|
||||
@ -13,11 +13,16 @@ import {
|
||||
LICENSE_STATUS_ISSUED,
|
||||
LICENSE_TYPE,
|
||||
} from '../../constants';
|
||||
import { PoNumberAlreadyExistError } from './errors/types';
|
||||
import {
|
||||
PoNumberAlreadyExistError,
|
||||
LicenseNotExistError,
|
||||
LicenseKeyAlreadyActivatedError,
|
||||
} from './errors/types';
|
||||
|
||||
@Injectable()
|
||||
export class LicensesRepositoryService {
|
||||
constructor(private dataSource: DataSource) {}
|
||||
private readonly logger = new Logger(LicensesRepositoryService.name);
|
||||
|
||||
async order(
|
||||
poNumber: string,
|
||||
@ -185,4 +190,69 @@ export class LicensesRepositoryService {
|
||||
|
||||
return licenseKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* カードライセンスを取り込む
|
||||
* @param accountId
|
||||
* @param licenseKey
|
||||
* @returns void
|
||||
*/
|
||||
async activateCardLicense(
|
||||
accountId: number,
|
||||
licenseKey: string,
|
||||
): Promise<void> {
|
||||
await this.dataSource.transaction(async (entityManager) => {
|
||||
const cardLicenseRepo = entityManager.getRepository(CardLicense);
|
||||
|
||||
// カードライセンステーブルを検索
|
||||
const targetCardLicense = await cardLicenseRepo.findOne({
|
||||
where: {
|
||||
card_license_key: licenseKey,
|
||||
},
|
||||
});
|
||||
// カードライセンスが存在しなければエラー
|
||||
if (!targetCardLicense) {
|
||||
this.logger.error(
|
||||
`card license key not exist. card_licence_key: ${licenseKey}`,
|
||||
);
|
||||
throw new LicenseNotExistError();
|
||||
}
|
||||
// 既に取り込み済みならエラー
|
||||
if (targetCardLicense.activated_at) {
|
||||
this.logger.error(
|
||||
`card license already activated. card_licence_key: ${licenseKey}`,
|
||||
);
|
||||
throw new LicenseKeyAlreadyActivatedError();
|
||||
}
|
||||
|
||||
const licensesRepo = entityManager.getRepository(License);
|
||||
|
||||
// ライセンステーブルを検索
|
||||
const targetLicense = await licensesRepo.findOne({
|
||||
where: {
|
||||
id: targetCardLicense.license_id,
|
||||
},
|
||||
});
|
||||
// ライセンスが存在しなければエラー
|
||||
if (!targetLicense) {
|
||||
this.logger.error(
|
||||
`license not exist. licence_id: ${targetCardLicense.license_id}`,
|
||||
);
|
||||
throw new LicenseNotExistError();
|
||||
}
|
||||
|
||||
// ライセンステーブルを更新する
|
||||
targetLicense.account_id = accountId;
|
||||
await licensesRepo.save(targetLicense);
|
||||
|
||||
// カードライセンステーブルを更新する
|
||||
targetCardLicense.activated_at = new Date();
|
||||
await cardLicenseRepo.save(targetCardLicense);
|
||||
|
||||
this.logger.log(
|
||||
`activate success. licence_id: ${targetCardLicense.license_id}`,
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { TemplateFilesRepositoryService } from './template_files.repository.service';
|
||||
import { TemplateFile } from './entity/template_file.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([TemplateFile])],
|
||||
providers: [TemplateFilesRepositoryService],
|
||||
exports: [TemplateFilesRepositoryService],
|
||||
})
|
||||
export class TemplateFilesRepositoryModule {}
|
||||
@ -0,0 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class TemplateFilesRepositoryService {
|
||||
constructor(private dataSource: DataSource) {}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user