Merge branch 'develop' into ccb
This commit is contained in:
commit
e44cb3b955
2
data_migration_tools/client/codegen.sh
Normal file
2
data_migration_tools/client/codegen.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
npx openapi-generator-cli version-manager set 7.1.0
|
||||||
|
npx openapi-generator-cli generate -g typescript-axios -i /app/data_migration_tools/server/src/api/odms/openapi.json -o /app/data_migration_tools/client/src/api/
|
||||||
7
data_migration_tools/client/openapitools.json
Normal file
7
data_migration_tools/client/openapitools.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||||
|
"spaces": 2,
|
||||||
|
"generator-cli": {
|
||||||
|
"version": "7.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,11 @@
|
|||||||
import { Route, Routes } from "react-router-dom";
|
import { Route, Routes } from "react-router-dom";
|
||||||
|
import TopPage from "./pages/topPage";
|
||||||
|
import DeletePage from "./pages/deletePage";
|
||||||
|
|
||||||
const AppRouter: React.FC = () => (
|
const AppRouter: React.FC = () => (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<div />} />
|
<Route path="/" element={<TopPage />} />
|
||||||
|
<Route path="/delete" element={<DeletePage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
4
data_migration_tools/client/src/api/.gitignore
vendored
Normal file
4
data_migration_tools/client/src/api/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
wwwroot/*.js
|
||||||
|
node_modules
|
||||||
|
typings
|
||||||
|
dist
|
||||||
1
data_migration_tools/client/src/api/.npmignore
Normal file
1
data_migration_tools/client/src/api/.npmignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
# OpenAPI Generator Ignore
|
||||||
|
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||||
|
|
||||||
|
# Use this file to prevent files from being overwritten by the generator.
|
||||||
|
# The patterns follow closely to .gitignore or .dockerignore.
|
||||||
|
|
||||||
|
# As an example, the C# client generator defines ApiClient.cs.
|
||||||
|
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||||
|
#ApiClient.cs
|
||||||
|
|
||||||
|
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||||
|
#foo/*/qux
|
||||||
|
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||||
|
|
||||||
|
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||||
|
#foo/**/qux
|
||||||
|
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||||
|
|
||||||
|
# You can also negate patterns with an exclamation (!).
|
||||||
|
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||||
|
#docs/*.md
|
||||||
|
# Then explicitly reverse the ignore rule for a single file:
|
||||||
|
#!docs/README.md
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
.gitignore
|
||||||
|
.npmignore
|
||||||
|
.openapi-generator-ignore
|
||||||
|
api.ts
|
||||||
|
base.ts
|
||||||
|
common.ts
|
||||||
|
configuration.ts
|
||||||
|
git_push.sh
|
||||||
|
index.ts
|
||||||
@ -0,0 +1 @@
|
|||||||
|
7.1.0
|
||||||
146
data_migration_tools/client/src/api/api.ts
Normal file
146
data_migration_tools/client/src/api/api.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* ODMSOpenAPI
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 1.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import type { Configuration } from './configuration';
|
||||||
|
import type { AxiosPromise, AxiosInstance, AxiosRequestConfig } from 'axios';
|
||||||
|
import globalAxios from 'axios';
|
||||||
|
// Some imports not used depending on template conditions
|
||||||
|
// @ts-ignore
|
||||||
|
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common';
|
||||||
|
import type { RequestArgs } from './base';
|
||||||
|
// @ts-ignore
|
||||||
|
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ErrorResponse
|
||||||
|
*/
|
||||||
|
export interface ErrorResponse {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ErrorResponse
|
||||||
|
*/
|
||||||
|
'message': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ErrorResponse
|
||||||
|
*/
|
||||||
|
'code': string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeleteApi - axios parameter creator
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const DeleteApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* すべてのデータを削除します
|
||||||
|
* @summary
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
deleteData: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
const localVarPath = `/delete`;
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeleteApi - functional programming interface
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const DeleteApiFp = function(configuration?: Configuration) {
|
||||||
|
const localVarAxiosParamCreator = DeleteApiAxiosParamCreator(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* すべてのデータを削除します
|
||||||
|
* @summary
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async deleteData(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.deleteData(options);
|
||||||
|
const index = configuration?.serverIndex ?? 0;
|
||||||
|
const operationBasePath = operationServerMap['DeleteApi.deleteData']?.[index]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeleteApi - factory interface
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const DeleteApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||||
|
const localVarFp = DeleteApiFp(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* すべてのデータを削除します
|
||||||
|
* @summary
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
deleteData(options?: any): AxiosPromise<object> {
|
||||||
|
return localVarFp.deleteData(options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeleteApi - object-oriented interface
|
||||||
|
* @export
|
||||||
|
* @class DeleteApi
|
||||||
|
* @extends {BaseAPI}
|
||||||
|
*/
|
||||||
|
export class DeleteApi extends BaseAPI {
|
||||||
|
/**
|
||||||
|
* すべてのデータを削除します
|
||||||
|
* @summary
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof DeleteApi
|
||||||
|
*/
|
||||||
|
public deleteData(options?: AxiosRequestConfig) {
|
||||||
|
return DeleteApiFp(this.configuration).deleteData(options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
86
data_migration_tools/client/src/api/base.ts
Normal file
86
data_migration_tools/client/src/api/base.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* ODMSOpenAPI
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 1.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import type { Configuration } from './configuration';
|
||||||
|
// Some imports not used depending on template conditions
|
||||||
|
// @ts-ignore
|
||||||
|
import type { AxiosPromise, AxiosInstance, AxiosRequestConfig } from 'axios';
|
||||||
|
import globalAxios from 'axios';
|
||||||
|
|
||||||
|
export const BASE_PATH = "http://localhost".replace(/\/+$/, "");
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const COLLECTION_FORMATS = {
|
||||||
|
csv: ",",
|
||||||
|
ssv: " ",
|
||||||
|
tsv: "\t",
|
||||||
|
pipes: "|",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface RequestArgs
|
||||||
|
*/
|
||||||
|
export interface RequestArgs {
|
||||||
|
url: string;
|
||||||
|
options: AxiosRequestConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class BaseAPI
|
||||||
|
*/
|
||||||
|
export class BaseAPI {
|
||||||
|
protected configuration: Configuration | undefined;
|
||||||
|
|
||||||
|
constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) {
|
||||||
|
if (configuration) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.basePath = configuration.basePath ?? basePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class RequiredError
|
||||||
|
* @extends {Error}
|
||||||
|
*/
|
||||||
|
export class RequiredError extends Error {
|
||||||
|
constructor(public field: string, msg?: string) {
|
||||||
|
super(msg);
|
||||||
|
this.name = "RequiredError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServerMap {
|
||||||
|
[key: string]: {
|
||||||
|
url: string,
|
||||||
|
description: string,
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const operationServerMap: ServerMap = {
|
||||||
|
}
|
||||||
150
data_migration_tools/client/src/api/common.ts
Normal file
150
data_migration_tools/client/src/api/common.ts
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* ODMSOpenAPI
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 1.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import type { Configuration } from "./configuration";
|
||||||
|
import type { RequestArgs } from "./base";
|
||||||
|
import type { AxiosInstance, AxiosResponse } from 'axios';
|
||||||
|
import { RequiredError } from "./base";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const DUMMY_BASE_URL = 'https://example.com'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) {
|
||||||
|
if (paramValue === null || paramValue === undefined) {
|
||||||
|
throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) {
|
||||||
|
if (configuration && configuration.apiKey) {
|
||||||
|
const localVarApiKeyValue = typeof configuration.apiKey === 'function'
|
||||||
|
? await configuration.apiKey(keyParamName)
|
||||||
|
: await configuration.apiKey;
|
||||||
|
object[keyParamName] = localVarApiKeyValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const setBasicAuthToObject = function (object: any, configuration?: Configuration) {
|
||||||
|
if (configuration && (configuration.username || configuration.password)) {
|
||||||
|
object["auth"] = { username: configuration.username, password: configuration.password };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) {
|
||||||
|
if (configuration && configuration.accessToken) {
|
||||||
|
const accessToken = typeof configuration.accessToken === 'function'
|
||||||
|
? await configuration.accessToken()
|
||||||
|
: await configuration.accessToken;
|
||||||
|
object["Authorization"] = "Bearer " + accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) {
|
||||||
|
if (configuration && configuration.accessToken) {
|
||||||
|
const localVarAccessTokenValue = typeof configuration.accessToken === 'function'
|
||||||
|
? await configuration.accessToken(name, scopes)
|
||||||
|
: await configuration.accessToken;
|
||||||
|
object["Authorization"] = "Bearer " + localVarAccessTokenValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
|
||||||
|
if (parameter == null) return;
|
||||||
|
if (typeof parameter === "object") {
|
||||||
|
if (Array.isArray(parameter)) {
|
||||||
|
(parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Object.keys(parameter).forEach(currentKey =>
|
||||||
|
setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (urlSearchParams.has(key)) {
|
||||||
|
urlSearchParams.append(key, parameter);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
urlSearchParams.set(key, parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const setSearchParams = function (url: URL, ...objects: any[]) {
|
||||||
|
const searchParams = new URLSearchParams(url.search);
|
||||||
|
setFlattenedQueryParams(searchParams, objects);
|
||||||
|
url.search = searchParams.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
|
||||||
|
const nonString = typeof value !== 'string';
|
||||||
|
const needsSerialization = nonString && configuration && configuration.isJsonMime
|
||||||
|
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
|
||||||
|
: nonString;
|
||||||
|
return needsSerialization
|
||||||
|
? JSON.stringify(value !== undefined ? value : {})
|
||||||
|
: (value || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const toPathString = function (url: URL) {
|
||||||
|
return url.pathname + url.search + url.hash
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) {
|
||||||
|
return <T = unknown, R = AxiosResponse<T>>(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||||
|
const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || axios.defaults.baseURL || basePath) + axiosArgs.url};
|
||||||
|
return axios.request<T, R>(axiosRequestArgs);
|
||||||
|
};
|
||||||
|
}
|
||||||
110
data_migration_tools/client/src/api/configuration.ts
Normal file
110
data_migration_tools/client/src/api/configuration.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* ODMSOpenAPI
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 1.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
export interface ConfigurationParameters {
|
||||||
|
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
|
||||||
|
basePath?: string;
|
||||||
|
serverIndex?: number;
|
||||||
|
baseOptions?: any;
|
||||||
|
formDataCtor?: new () => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Configuration {
|
||||||
|
/**
|
||||||
|
* parameter for apiKey security
|
||||||
|
* @param name security name
|
||||||
|
* @memberof Configuration
|
||||||
|
*/
|
||||||
|
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
|
||||||
|
/**
|
||||||
|
* parameter for basic security
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof Configuration
|
||||||
|
*/
|
||||||
|
username?: string;
|
||||||
|
/**
|
||||||
|
* parameter for basic security
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof Configuration
|
||||||
|
*/
|
||||||
|
password?: string;
|
||||||
|
/**
|
||||||
|
* parameter for oauth2 security
|
||||||
|
* @param name security name
|
||||||
|
* @param scopes oauth2 scope
|
||||||
|
* @memberof Configuration
|
||||||
|
*/
|
||||||
|
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
|
||||||
|
/**
|
||||||
|
* override base path
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof Configuration
|
||||||
|
*/
|
||||||
|
basePath?: string;
|
||||||
|
/**
|
||||||
|
* override server index
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof Configuration
|
||||||
|
*/
|
||||||
|
serverIndex?: number;
|
||||||
|
/**
|
||||||
|
* base options for axios calls
|
||||||
|
*
|
||||||
|
* @type {any}
|
||||||
|
* @memberof Configuration
|
||||||
|
*/
|
||||||
|
baseOptions?: any;
|
||||||
|
/**
|
||||||
|
* The FormData constructor that will be used to create multipart form data
|
||||||
|
* requests. You can inject this here so that execution environments that
|
||||||
|
* do not support the FormData class can still run the generated client.
|
||||||
|
*
|
||||||
|
* @type {new () => FormData}
|
||||||
|
*/
|
||||||
|
formDataCtor?: new () => any;
|
||||||
|
|
||||||
|
constructor(param: ConfigurationParameters = {}) {
|
||||||
|
this.apiKey = param.apiKey;
|
||||||
|
this.username = param.username;
|
||||||
|
this.password = param.password;
|
||||||
|
this.accessToken = param.accessToken;
|
||||||
|
this.basePath = param.basePath;
|
||||||
|
this.serverIndex = param.serverIndex;
|
||||||
|
this.baseOptions = param.baseOptions;
|
||||||
|
this.formDataCtor = param.formDataCtor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given MIME is a JSON MIME.
|
||||||
|
* JSON MIME examples:
|
||||||
|
* application/json
|
||||||
|
* application/json; charset=UTF8
|
||||||
|
* APPLICATION/JSON
|
||||||
|
* application/vnd.company+json
|
||||||
|
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
||||||
|
* @return True if the given MIME is JSON, false otherwise.
|
||||||
|
*/
|
||||||
|
public isJsonMime(mime: string): boolean {
|
||||||
|
const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
|
||||||
|
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
|
||||||
|
}
|
||||||
|
}
|
||||||
57
data_migration_tools/client/src/api/git_push.sh
Normal file
57
data_migration_tools/client/src/api/git_push.sh
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
|
||||||
|
#
|
||||||
|
# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com"
|
||||||
|
|
||||||
|
git_user_id=$1
|
||||||
|
git_repo_id=$2
|
||||||
|
release_note=$3
|
||||||
|
git_host=$4
|
||||||
|
|
||||||
|
if [ "$git_host" = "" ]; then
|
||||||
|
git_host="github.com"
|
||||||
|
echo "[INFO] No command line input provided. Set \$git_host to $git_host"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$git_user_id" = "" ]; then
|
||||||
|
git_user_id="GIT_USER_ID"
|
||||||
|
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$git_repo_id" = "" ]; then
|
||||||
|
git_repo_id="GIT_REPO_ID"
|
||||||
|
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$release_note" = "" ]; then
|
||||||
|
release_note="Minor update"
|
||||||
|
echo "[INFO] No command line input provided. Set \$release_note to $release_note"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initialize the local directory as a Git repository
|
||||||
|
git init
|
||||||
|
|
||||||
|
# Adds the files in the local repository and stages them for commit.
|
||||||
|
git add .
|
||||||
|
|
||||||
|
# Commits the tracked changes and prepares them to be pushed to a remote repository.
|
||||||
|
git commit -m "$release_note"
|
||||||
|
|
||||||
|
# Sets the new remote
|
||||||
|
git_remote=$(git remote)
|
||||||
|
if [ "$git_remote" = "" ]; then # git remote not defined
|
||||||
|
|
||||||
|
if [ "$GIT_TOKEN" = "" ]; then
|
||||||
|
echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment."
|
||||||
|
git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git
|
||||||
|
else
|
||||||
|
git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
git pull origin master
|
||||||
|
|
||||||
|
# Pushes (Forces) the changes in the local repository up to the remote repository
|
||||||
|
echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git"
|
||||||
|
git push origin master 2>&1 | grep -v 'To https'
|
||||||
18
data_migration_tools/client/src/api/index.ts
Normal file
18
data_migration_tools/client/src/api/index.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* ODMSOpenAPI
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 1.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
export * from "./api";
|
||||||
|
export * from "./configuration";
|
||||||
|
|
||||||
@ -1,7 +1,11 @@
|
|||||||
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
|
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
|
||||||
|
import auth from "features/auth/authSlice";
|
||||||
|
import ui from "features/ui/uiSlice";
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
|
auth,
|
||||||
|
ui,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
17
data_migration_tools/client/src/common/errors/code.ts
Normal file
17
data_migration_tools/client/src/common/errors/code.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
エラーコード作成方針
|
||||||
|
E+6桁(数字)で構成する。
|
||||||
|
- 1~2桁目の値は種類(業務エラー、システムエラー...)
|
||||||
|
- 3~4桁目の値は原因箇所(トークン、DB、...)
|
||||||
|
- 5~6桁目の値は任意の重複しない値
|
||||||
|
ex)
|
||||||
|
E00XXXX : システムエラー(通信エラーやDB接続失敗など)
|
||||||
|
E01XXXX : 業務エラー
|
||||||
|
EXX00XX : 内部エラー(内部プログラムのエラー)
|
||||||
|
EXX01XX : トークンエラー(トークン認証関連)
|
||||||
|
EXX02XX : DBエラー(DB関連)
|
||||||
|
EXX03XX : ADB2Cエラー(DB関連)
|
||||||
|
*/
|
||||||
|
export const errorCodes = [
|
||||||
|
"E009999", // 汎用エラー
|
||||||
|
] as const;
|
||||||
3
data_migration_tools/client/src/common/errors/index.ts
Normal file
3
data_migration_tools/client/src/common/errors/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./code";
|
||||||
|
export * from "./types";
|
||||||
|
export * from "./utils";
|
||||||
9
data_migration_tools/client/src/common/errors/types.ts
Normal file
9
data_migration_tools/client/src/common/errors/types.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { errorCodes } from "./code";
|
||||||
|
|
||||||
|
export type ErrorObject = {
|
||||||
|
message: string;
|
||||||
|
code: ErrorCodeType;
|
||||||
|
statusCode?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ErrorCodeType = (typeof errorCodes)[number];
|
||||||
101
data_migration_tools/client/src/common/errors/utils.ts
Normal file
101
data_migration_tools/client/src/common/errors/utils.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { AxiosError } from "axios";
|
||||||
|
import { isError } from "lodash";
|
||||||
|
import { ErrorResponse } from "../../api";
|
||||||
|
import { errorCodes } from "./code";
|
||||||
|
import { ErrorCodeType, ErrorObject } from "./types";
|
||||||
|
|
||||||
|
export const createErrorObject = (error: unknown): ErrorObject => {
|
||||||
|
// 最低限通常のエラーかを判定
|
||||||
|
// Error以外のものがthrowされた場合
|
||||||
|
// 基本的にないはずだがプログラム上あるので拾う
|
||||||
|
if (!isError(error)) {
|
||||||
|
return {
|
||||||
|
message: "not error type.",
|
||||||
|
code: "E009999",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Axiosエラー 通信してのエラーであるかを判定
|
||||||
|
if (!isAxiosError(error)) {
|
||||||
|
return {
|
||||||
|
message: "not axios error.",
|
||||||
|
code: "E009999",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorResponse = error.response;
|
||||||
|
if (!errorResponse) {
|
||||||
|
return {
|
||||||
|
message: error.message,
|
||||||
|
code: "E009999",
|
||||||
|
statusCode: errorResponse,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = errorResponse;
|
||||||
|
|
||||||
|
// 想定しているエラーレスポンスの型か判定
|
||||||
|
if (!isErrorResponse(data)) {
|
||||||
|
return {
|
||||||
|
message: error.message,
|
||||||
|
code: "E009999",
|
||||||
|
statusCode: errorResponse.status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { message, code } = data;
|
||||||
|
|
||||||
|
// 想定しているエラーコードかを判定
|
||||||
|
if (!isErrorCode(code)) {
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
code: "E009999",
|
||||||
|
statusCode: errorResponse.status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
code,
|
||||||
|
statusCode: errorResponse.status,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const isAxiosError = (e: unknown): e is AxiosError => {
|
||||||
|
const error = e as AxiosError;
|
||||||
|
return error?.isAxiosError ?? false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isErrorResponse = (error: unknown): error is ErrorResponse => {
|
||||||
|
const errorResponse = error as ErrorResponse;
|
||||||
|
if (
|
||||||
|
errorResponse === undefined ||
|
||||||
|
errorResponse.message === undefined ||
|
||||||
|
errorResponse.code === undefined
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isErrorCode = (errorCode: string): errorCode is ErrorCodeType =>
|
||||||
|
errorCodes.includes(errorCode as ErrorCodeType);
|
||||||
|
|
||||||
|
export const isErrorObject = (
|
||||||
|
data: unknown
|
||||||
|
): data is { error: ErrorObject } => {
|
||||||
|
if (
|
||||||
|
data &&
|
||||||
|
typeof data === "object" &&
|
||||||
|
"error" in data &&
|
||||||
|
typeof (data as { error: ErrorObject }).error === "object" &&
|
||||||
|
typeof (data as { error: ErrorObject }).error.message === "string" &&
|
||||||
|
typeof (data as { error: ErrorObject }).error.code === "string" &&
|
||||||
|
(typeof (data as { error: ErrorObject }).error.statusCode === "number" ||
|
||||||
|
(data as { error: ErrorObject }).error.statusCode === undefined)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
export const getBasePath = () => {
|
export const getBasePath = () => {
|
||||||
if (import.meta.env.VITE_STAGE === "local") {
|
if (import.meta.env.VITE_STAGE === "local") {
|
||||||
return "http://localhost:8180";
|
return "http://localhost:8280";
|
||||||
}
|
}
|
||||||
return window.location.origin;
|
return window.location.origin;
|
||||||
};
|
};
|
||||||
|
|||||||
15
data_migration_tools/client/src/features/auth/authSlice.ts
Normal file
15
data_migration_tools/client/src/features/auth/authSlice.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
|
import type { AuthState } from "./state";
|
||||||
|
import { initialConfig } from "./utils";
|
||||||
|
|
||||||
|
const initialState: AuthState = {
|
||||||
|
configuration: initialConfig(),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const authSlice = createSlice({
|
||||||
|
name: "auth",
|
||||||
|
initialState,
|
||||||
|
reducers: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default authSlice.reducer;
|
||||||
3
data_migration_tools/client/src/features/auth/index.ts
Normal file
3
data_migration_tools/client/src/features/auth/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./authSlice";
|
||||||
|
export * from "./state";
|
||||||
|
export * from "./utils";
|
||||||
5
data_migration_tools/client/src/features/auth/state.ts
Normal file
5
data_migration_tools/client/src/features/auth/state.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { ConfigurationParameters } from "../../api";
|
||||||
|
|
||||||
|
export interface AuthState {
|
||||||
|
configuration: ConfigurationParameters;
|
||||||
|
}
|
||||||
13
data_migration_tools/client/src/features/auth/utils.ts
Normal file
13
data_migration_tools/client/src/features/auth/utils.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { ConfigurationParameters } from "../../api";
|
||||||
|
|
||||||
|
// 初期状態のAPI Config
|
||||||
|
export const initialConfig = (): ConfigurationParameters => {
|
||||||
|
const config: ConfigurationParameters = {};
|
||||||
|
if (import.meta.env.VITE_STAGE === "local") {
|
||||||
|
config.basePath = "http://localhost:8280";
|
||||||
|
} else {
|
||||||
|
config.basePath = `${window.location.origin}/dictation/api`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
|
import { DeleteState } from "./state";
|
||||||
|
import { deleteDataAsync } from "./operations";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
|
||||||
|
const initialState: DeleteState = {};
|
||||||
|
|
||||||
|
export const deleteSlice = createSlice({
|
||||||
|
name: "detete",
|
||||||
|
initialState,
|
||||||
|
reducers: {},
|
||||||
|
extraReducers: (builder) => {
|
||||||
|
builder.addCase(deleteDataAsync.pending, () => {
|
||||||
|
/* Empty Object */
|
||||||
|
});
|
||||||
|
builder.addCase(deleteDataAsync.fulfilled, () => {
|
||||||
|
/* Empty Object */
|
||||||
|
});
|
||||||
|
builder.addCase(deleteDataAsync.rejected, () => {
|
||||||
|
/* Empty Object */
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default deleteSlice.reducer;
|
||||||
3
data_migration_tools/client/src/features/delete/index.ts
Normal file
3
data_migration_tools/client/src/features/delete/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./state";
|
||||||
|
export * from "./deleteSlice";
|
||||||
|
export * from "./operations";
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||||
|
import { openSnackbar } from "../ui/uiSlice";
|
||||||
|
import type { RootState } from "../../app/store";
|
||||||
|
import { ErrorObject, createErrorObject } from "../../common/errors";
|
||||||
|
import { DeleteApi } from "../../api/api";
|
||||||
|
import { Configuration } from "../../api/configuration";
|
||||||
|
|
||||||
|
export const deleteDataAsync = createAsyncThunk<
|
||||||
|
{
|
||||||
|
/* Empty Object */
|
||||||
|
},
|
||||||
|
void,
|
||||||
|
{
|
||||||
|
// rejectした時の返却値の型
|
||||||
|
rejectValue: {
|
||||||
|
error: ErrorObject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
>("delete/deleteDataAsync", async (args, thunkApi) => {
|
||||||
|
// apiのConfigurationを取得する
|
||||||
|
const { getState } = thunkApi;
|
||||||
|
const state = getState() as RootState;
|
||||||
|
const { configuration } = state.auth;
|
||||||
|
const config = new Configuration(configuration);
|
||||||
|
const deleteApi = new DeleteApi(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await deleteApi.deleteData();
|
||||||
|
thunkApi.dispatch(
|
||||||
|
openSnackbar({
|
||||||
|
level: "info",
|
||||||
|
message: "削除しました。",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return {};
|
||||||
|
} catch (e) {
|
||||||
|
const error = createErrorObject(e);
|
||||||
|
thunkApi.dispatch(
|
||||||
|
openSnackbar({
|
||||||
|
level: "error",
|
||||||
|
message: "削除に失敗しました。",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return thunkApi.rejectWithValue({ error });
|
||||||
|
}
|
||||||
|
});
|
||||||
2
data_migration_tools/client/src/features/delete/state.ts
Normal file
2
data_migration_tools/client/src/features/delete/state.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||||
|
export interface DeleteState {}
|
||||||
2
data_migration_tools/client/src/features/ui/constants.ts
Normal file
2
data_migration_tools/client/src/features/ui/constants.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// 標準のスナックバー表示時間(ミリ秒)
|
||||||
|
export const DEFAULT_SNACKBAR_DURATION = 3000;
|
||||||
5
data_migration_tools/client/src/features/ui/index.ts
Normal file
5
data_migration_tools/client/src/features/ui/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export * from "./constants";
|
||||||
|
export * from "./selectors";
|
||||||
|
export * from "./state";
|
||||||
|
export * from "./uiSlice";
|
||||||
|
export * from "./types";
|
||||||
15
data_migration_tools/client/src/features/ui/selectors.ts
Normal file
15
data_migration_tools/client/src/features/ui/selectors.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import type { RootState } from "app/store";
|
||||||
|
import { SnackbarLevel } from "./types";
|
||||||
|
|
||||||
|
export const selectSnackber = (
|
||||||
|
state: RootState
|
||||||
|
): {
|
||||||
|
isOpen: boolean;
|
||||||
|
level: SnackbarLevel;
|
||||||
|
message: string;
|
||||||
|
duration?: number;
|
||||||
|
} => {
|
||||||
|
const { isOpen, level, message, duration } = state.ui;
|
||||||
|
|
||||||
|
return { isOpen, level, message, duration };
|
||||||
|
};
|
||||||
8
data_migration_tools/client/src/features/ui/state.ts
Normal file
8
data_migration_tools/client/src/features/ui/state.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { SnackbarLevel } from "./types";
|
||||||
|
|
||||||
|
export interface UIState {
|
||||||
|
isOpen: boolean;
|
||||||
|
level: SnackbarLevel;
|
||||||
|
message: string;
|
||||||
|
duration?: number;
|
||||||
|
}
|
||||||
1
data_migration_tools/client/src/features/ui/types.ts
Normal file
1
data_migration_tools/client/src/features/ui/types.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export type SnackbarLevel = "info" | "error";
|
||||||
38
data_migration_tools/client/src/features/ui/uiSlice.ts
Normal file
38
data_migration_tools/client/src/features/ui/uiSlice.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
|
import { SnackbarLevel } from "./types";
|
||||||
|
import { UIState } from "./state";
|
||||||
|
import { DEFAULT_SNACKBAR_DURATION } from "./constants";
|
||||||
|
|
||||||
|
const initialState: UIState = {
|
||||||
|
isOpen: false,
|
||||||
|
level: "error",
|
||||||
|
message: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const uiSlice = createSlice({
|
||||||
|
name: "ui",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
openSnackbar: (
|
||||||
|
state,
|
||||||
|
action: PayloadAction<{
|
||||||
|
level: SnackbarLevel;
|
||||||
|
message: string;
|
||||||
|
duration?: number;
|
||||||
|
}>
|
||||||
|
) => {
|
||||||
|
const { level, message, duration } = action.payload;
|
||||||
|
state.isOpen = true;
|
||||||
|
state.level = level;
|
||||||
|
state.message = message;
|
||||||
|
state.duration =
|
||||||
|
level === "error" ? undefined : duration ?? DEFAULT_SNACKBAR_DURATION;
|
||||||
|
},
|
||||||
|
closeSnackbar: (state) => {
|
||||||
|
state.isOpen = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export const { openSnackbar, closeSnackbar } = uiSlice.actions;
|
||||||
|
|
||||||
|
export default uiSlice.reducer;
|
||||||
32
data_migration_tools/client/src/pages/deletePage/index.tsx
Normal file
32
data_migration_tools/client/src/pages/deletePage/index.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { AppDispatch } from "app/store";
|
||||||
|
import { deleteDataAsync } from "features/delete";
|
||||||
|
import React, { useCallback } from "react";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
const DeletePage = (): JSX.Element => {
|
||||||
|
const dispatch: AppDispatch = useDispatch();
|
||||||
|
|
||||||
|
const onDelete = useCallback(() => {
|
||||||
|
if (
|
||||||
|
/* eslint-disable-next-line no-alert */
|
||||||
|
!window.confirm("本当に削除しますか?")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch(deleteDataAsync());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>データ削除ツール</p>
|
||||||
|
<button type="button" onClick={onDelete}>
|
||||||
|
削除
|
||||||
|
</button>
|
||||||
|
<br />
|
||||||
|
<Link to="/">return to TopPage</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DeletePage;
|
||||||
15
data_migration_tools/client/src/pages/topPage/index.tsx
Normal file
15
data_migration_tools/client/src/pages/topPage/index.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
const TopPage = (): JSX.Element => {
|
||||||
|
console.log("DeletePage");
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Link to="/delete">データ削除ツール</Link>
|
||||||
|
<br />
|
||||||
|
<Link to="/">return to TopPage</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TopPage;
|
||||||
@ -14,5 +14,11 @@ services:
|
|||||||
- "8280"
|
- "8280"
|
||||||
environment:
|
environment:
|
||||||
- CHOKIDAR_USEPOLLING=true
|
- CHOKIDAR_USEPOLLING=true
|
||||||
|
networks:
|
||||||
|
- external
|
||||||
|
networks:
|
||||||
|
external:
|
||||||
|
name: omds_network
|
||||||
|
external: true
|
||||||
volumes:
|
volumes:
|
||||||
data_migration_tools_server_node_modules:
|
data_migration_tools_server_node_modules:
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
DB_HOST=omds-mysql
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_NAME=omds
|
||||||
|
DB_USERNAME=omdsdbuser
|
||||||
|
DB_PASSWORD=omdsdbpass
|
||||||
2366
data_migration_tools/server/package-lock.json
generated
2366
data_migration_tools/server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,10 +19,13 @@
|
|||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"test:cov": "jest --coverage",
|
"test:cov": "jest --coverage",
|
||||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand"
|
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||||
|
"apigen": "ts-node src/api/generate.ts && prettier --write \"src/api/odms/*.json\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@azure/identity": "^4.0.1",
|
||||||
"@azure/storage-blob": "^12.14.0",
|
"@azure/storage-blob": "^12.14.0",
|
||||||
|
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||||
"@nestjs/common": "^9.3.9",
|
"@nestjs/common": "^9.3.9",
|
||||||
"@nestjs/config": "^2.3.1",
|
"@nestjs/config": "^2.3.1",
|
||||||
"@nestjs/core": "^9.3.9",
|
"@nestjs/core": "^9.3.9",
|
||||||
@ -30,6 +33,7 @@
|
|||||||
"@nestjs/serve-static": "^3.0.1",
|
"@nestjs/serve-static": "^3.0.1",
|
||||||
"@nestjs/swagger": "^6.2.1",
|
"@nestjs/swagger": "^6.2.1",
|
||||||
"@nestjs/testing": "^9.3.9",
|
"@nestjs/testing": "^9.3.9",
|
||||||
|
"@nestjs/typeorm": "^10.0.2",
|
||||||
"@openapitools/openapi-generator-cli": "^2.5.2",
|
"@openapitools/openapi-generator-cli": "^2.5.2",
|
||||||
"@vercel/ncc": "^0.36.1",
|
"@vercel/ncc": "^0.36.1",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
@ -37,6 +41,7 @@
|
|||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
|
"mysql2": "^3.9.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.8.0",
|
"rxjs": "^7.8.0",
|
||||||
"swagger-cli": "^4.0.4"
|
"swagger-cli": "^4.0.4"
|
||||||
|
|||||||
25
data_migration_tools/server/src/api/generate.ts
Normal file
25
data_migration_tools/server/src/api/generate.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
|
||||||
|
import { AppModule } from "../app.module";
|
||||||
|
import { promises as fs } from "fs";
|
||||||
|
import { NestFactory } from "@nestjs/core";
|
||||||
|
async function bootstrap(): Promise<void> {
|
||||||
|
const app = await NestFactory.create(AppModule, {
|
||||||
|
preview: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = new DocumentBuilder()
|
||||||
|
.setTitle("ODMSOpenAPI")
|
||||||
|
.setVersion("1.0.0")
|
||||||
|
.addBearerAuth({
|
||||||
|
type: "http",
|
||||||
|
scheme: "bearer",
|
||||||
|
bearerFormat: "JWT",
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
const document = SwaggerModule.createDocument(app, options);
|
||||||
|
await fs.writeFile(
|
||||||
|
"src/api/odms/openapi.json",
|
||||||
|
JSON.stringify(document, null, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bootstrap();
|
||||||
56
data_migration_tools/server/src/api/odms/openapi.json
Normal file
56
data_migration_tools/server/src/api/odms/openapi.json
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.0.0",
|
||||||
|
"paths": {
|
||||||
|
"/delete": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "deleteData",
|
||||||
|
"summary": "",
|
||||||
|
"description": "すべてのデータを削除します",
|
||||||
|
"parameters": [],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "成功時のレスポンス",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": { "$ref": "#/components/schemas/DeleteResponse" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "想定外のサーバーエラー",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": ["delete"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"title": "ODMSOpenAPI",
|
||||||
|
"description": "",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"contact": {}
|
||||||
|
},
|
||||||
|
"tags": [],
|
||||||
|
"servers": [],
|
||||||
|
"components": {
|
||||||
|
"securitySchemes": {
|
||||||
|
"bearer": { "scheme": "bearer", "bearerFormat": "JWT", "type": "http" }
|
||||||
|
},
|
||||||
|
"schemas": {
|
||||||
|
"DeleteResponse": { "type": "object", "properties": {} },
|
||||||
|
"ErrorResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"message": { "type": "string" },
|
||||||
|
"code": { "type": "string" }
|
||||||
|
},
|
||||||
|
"required": ["message", "code"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,15 @@
|
|||||||
import { MiddlewareConsumer, Module } from "@nestjs/common";
|
import { MiddlewareConsumer, Module } from "@nestjs/common";
|
||||||
import { ServeStaticModule } from "@nestjs/serve-static";
|
import { ServeStaticModule } from "@nestjs/serve-static";
|
||||||
import { ConfigModule } from "@nestjs/config";
|
import { ConfigModule, ConfigService } from "@nestjs/config";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { LoggerMiddleware } from "./common/loggerMiddleware";
|
import { LoggerMiddleware } from "./common/loggerMiddleware";
|
||||||
|
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||||
|
import { DeleteModule } from "./features/delete/delete.module";
|
||||||
|
import { AdB2cModule } from "./gateways/adb2c/adb2c.module";
|
||||||
|
import { DeleteRepositoryModule } from "./repositories/delete/delete.repository.module";
|
||||||
|
import { DeleteController } from "./features/delete/delete.controller";
|
||||||
|
import { DeleteService } from "./features/delete/delete.service";
|
||||||
|
import { BlobstorageModule } from "./gateways/blobstorage/blobstorage.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@ -13,9 +20,27 @@ import { LoggerMiddleware } from "./common/loggerMiddleware";
|
|||||||
envFilePath: [".env.local", ".env"],
|
envFilePath: [".env.local", ".env"],
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
}),
|
}),
|
||||||
|
TypeOrmModule.forRootAsync({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
useFactory: async (configService: ConfigService) => ({
|
||||||
|
type: "mysql",
|
||||||
|
host: configService.get("DB_HOST"),
|
||||||
|
port: configService.get("DB_PORT"),
|
||||||
|
username: configService.get("DB_USERNAME"),
|
||||||
|
password: configService.get("DB_PASSWORD"),
|
||||||
|
database: configService.get("DB_NAME"),
|
||||||
|
autoLoadEntities: true, // forFeature()で登録されたEntityを自動的にロード
|
||||||
|
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
|
||||||
|
}),
|
||||||
|
inject: [ConfigService],
|
||||||
|
}),
|
||||||
|
DeleteModule,
|
||||||
|
AdB2cModule,
|
||||||
|
BlobstorageModule,
|
||||||
|
DeleteRepositoryModule,
|
||||||
],
|
],
|
||||||
controllers: [],
|
controllers: [DeleteController],
|
||||||
providers: [],
|
providers: [DeleteService],
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
import { bigintTransformer } from '.';
|
||||||
|
|
||||||
|
describe('bigintTransformer', () => {
|
||||||
|
describe('to', () => {
|
||||||
|
it('number型を整数を表す文字列に変換できる', () => {
|
||||||
|
expect(bigintTransformer.to(0)).toBe('0');
|
||||||
|
expect(bigintTransformer.to(1)).toBe('1');
|
||||||
|
expect(bigintTransformer.to(1234567890)).toBe('1234567890');
|
||||||
|
expect(bigintTransformer.to(9007199254740991)).toBe('9007199254740991');
|
||||||
|
expect(bigintTransformer.to(-1)).toBe('-1');
|
||||||
|
});
|
||||||
|
it('少数点以下がある場合はエラーとなる', () => {
|
||||||
|
expect(() => bigintTransformer.to(1.1)).toThrowError(
|
||||||
|
'1.1 is not integer.',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('Number.MAX_SAFE_INTEGERを超える値を変換しようとするとエラーになる', () => {
|
||||||
|
expect(() => bigintTransformer.to(9007199254740992)).toThrowError(
|
||||||
|
'value is greater than 9007199254740991.',
|
||||||
|
);
|
||||||
|
expect(() => bigintTransformer.to(9223372036854775807)).toThrowError(
|
||||||
|
'value is greater than 9007199254740991.',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('from', () => {
|
||||||
|
it('bigint型の文字列をnumber型に変換できる', () => {
|
||||||
|
expect(bigintTransformer.from('0')).toBe(0);
|
||||||
|
expect(bigintTransformer.from('1')).toBe(1);
|
||||||
|
expect(bigintTransformer.from('1234567890')).toBe(1234567890);
|
||||||
|
expect(bigintTransformer.from('-1')).toBe(-1);
|
||||||
|
});
|
||||||
|
it('Number.MAX_SAFE_INTEGERを超える値を変換しようとするとエラーになる', () => {
|
||||||
|
expect(() => bigintTransformer.from('9007199254740992')).toThrowError(
|
||||||
|
'9007199254740992 is greater than 9007199254740991.',
|
||||||
|
);
|
||||||
|
expect(() => bigintTransformer.from('9223372036854775807')).toThrowError(
|
||||||
|
'9223372036854775807 is greater than 9007199254740991.',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('number型の場合はそのまま返す', () => {
|
||||||
|
expect(bigintTransformer.from(0)).toBe(0);
|
||||||
|
expect(bigintTransformer.from(1)).toBe(1);
|
||||||
|
expect(bigintTransformer.from(1234567890)).toBe(1234567890);
|
||||||
|
expect(bigintTransformer.from(-1)).toBe(-1);
|
||||||
|
});
|
||||||
|
it('nullの場合はそのまま返す', () => {
|
||||||
|
expect(bigintTransformer.from(null)).toBe(null);
|
||||||
|
});
|
||||||
|
it('number型に変換できない場合はエラーとなる', () => {
|
||||||
|
expect(() => bigintTransformer.from('a')).toThrowError('a is not int.');
|
||||||
|
expect(() => bigintTransformer.from('')).toThrowError(' is not int.');
|
||||||
|
expect(() => bigintTransformer.from(undefined)).toThrowError(
|
||||||
|
'undefined is not string.',
|
||||||
|
);
|
||||||
|
expect(() => bigintTransformer.from({})).toThrowError(
|
||||||
|
'[object Object] is not string.',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
57
data_migration_tools/server/src/common/entity/index.ts
Normal file
57
data_migration_tools/server/src/common/entity/index.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { ValueTransformer } from 'typeorm';
|
||||||
|
|
||||||
|
// DBのbigint型をnumber型に変換するためのtransformer
|
||||||
|
// DBのBigInt型をそのまま扱うと、JSのNumber型の最大値を超えると誤差が発生するため、本来はNumber型に変換すべきではないが、
|
||||||
|
// 影響範囲を最小限に抑えるため、Number型に変換する。使用するのはAutoIncrementされるIDのみの想定のため、
|
||||||
|
// Number.MAX_SAFE_INTEGERより大きい値は現実的には発生しない想定で変換する。
|
||||||
|
export const bigintTransformer: ValueTransformer = {
|
||||||
|
from: (value: any): number | null => {
|
||||||
|
// valueがnullであればそのまま返す
|
||||||
|
if (value === null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
// valueがnumber型かどうかを判定
|
||||||
|
// 利用DBによってはbigint型であってもnumber型で返ってくる場合があるため、number型の場合はそのまま返す(sqliteの場合)
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
// valueが文字列かどうかを判定
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
throw new Error(`${value} is not string.`);
|
||||||
|
}
|
||||||
|
// 数値に変換可能な文字列かどうかを判定
|
||||||
|
if (Number.isNaN(parseInt(value))) {
|
||||||
|
throw new Error(`${value} is not int.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文字列ならbigintに変換
|
||||||
|
// valueが整数でない場合は値が丸められてしまうが、TypeORMのEntityの定義上、整数を表す文字列以外はありえないため、少数点は考慮しない
|
||||||
|
const bigIntValue = BigInt(value);
|
||||||
|
// bigIntValueがNumber.MAX_SAFE_INTEGERより大きいかどうかを判定
|
||||||
|
if (bigIntValue > Number.MAX_SAFE_INTEGER) {
|
||||||
|
throw new Error(`${value} is greater than ${Number.MAX_SAFE_INTEGER}.`);
|
||||||
|
}
|
||||||
|
// number型で表現できる整数であればnumber型に変換して返す
|
||||||
|
return Number(bigIntValue);
|
||||||
|
},
|
||||||
|
to: (value: any): string | null | undefined => {
|
||||||
|
// valueがnullまたはundefinedであればそのまま返す
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
// valueがnumber型かどうかを判定
|
||||||
|
if (typeof value !== 'number') {
|
||||||
|
throw new Error(`${value} is not number.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// valueがNumber.MAX_SAFE_INTEGERより大きいかどうかを判定
|
||||||
|
if (value > Number.MAX_SAFE_INTEGER) {
|
||||||
|
throw new Error(`value is greater than ${Number.MAX_SAFE_INTEGER}.`);
|
||||||
|
}
|
||||||
|
// valueが整数かどうかを判定
|
||||||
|
if (!Number.isInteger(value)) {
|
||||||
|
throw new Error(`${value} is not integer.`);
|
||||||
|
}
|
||||||
|
return value.toString();
|
||||||
|
},
|
||||||
|
};
|
||||||
17
data_migration_tools/server/src/common/errors/code.ts
Normal file
17
data_migration_tools/server/src/common/errors/code.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
エラーコード作成方針
|
||||||
|
E+6桁(数字)で構成する。
|
||||||
|
- 1~2桁目の値は種類(業務エラー、システムエラー...)
|
||||||
|
- 3~4桁目の値は原因箇所(トークン、DB、...)
|
||||||
|
- 5~6桁目の値は任意の重複しない値
|
||||||
|
ex)
|
||||||
|
E00XXXX : システムエラー(通信エラーやDB接続失敗など)
|
||||||
|
E01XXXX : 業務エラー
|
||||||
|
EXX00XX : 内部エラー(内部プログラムのエラー)
|
||||||
|
EXX01XX : トークンエラー(トークン認証関連)
|
||||||
|
EXX02XX : DBエラー(DB関連)
|
||||||
|
EXX03XX : ADB2Cエラー(DB関連)
|
||||||
|
*/
|
||||||
|
export const ErrorCodes = [
|
||||||
|
"E009999", // 汎用エラー
|
||||||
|
] as const;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { errors } from "./message";
|
||||||
|
import { ErrorCodeType, ErrorResponse } from "./types/types";
|
||||||
|
|
||||||
|
export const makeErrorResponse = (errorcode: ErrorCodeType): ErrorResponse => {
|
||||||
|
const msg = errors[errorcode];
|
||||||
|
return {
|
||||||
|
code: errorcode,
|
||||||
|
message: msg,
|
||||||
|
};
|
||||||
|
};
|
||||||
6
data_migration_tools/server/src/common/errors/message.ts
Normal file
6
data_migration_tools/server/src/common/errors/message.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { Errors } from "./types/types";
|
||||||
|
|
||||||
|
// エラーコードとメッセージ対応表
|
||||||
|
export const errors: Errors = {
|
||||||
|
E009999: "Internal Server Error.",
|
||||||
|
};
|
||||||
15
data_migration_tools/server/src/common/errors/types/types.ts
Normal file
15
data_migration_tools/server/src/common/errors/types/types.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { ErrorCodes } from '../code';
|
||||||
|
|
||||||
|
export class ErrorResponse {
|
||||||
|
@ApiProperty()
|
||||||
|
message: string;
|
||||||
|
@ApiProperty()
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ErrorCodeType = (typeof ErrorCodes)[number];
|
||||||
|
|
||||||
|
export type Errors = {
|
||||||
|
[P in ErrorCodeType]: string;
|
||||||
|
};
|
||||||
67
data_migration_tools/server/src/constants/index.ts
Normal file
67
data_migration_tools/server/src/constants/index.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* 音声ファイルをEast USに保存する国リスト
|
||||||
|
* @const {number}
|
||||||
|
*/
|
||||||
|
export const BLOB_STORAGE_REGION_US = ["CA", "KY", "US"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音声ファイルをAustralia Eastに保存する国リスト
|
||||||
|
* @const {number}
|
||||||
|
*/
|
||||||
|
export const BLOB_STORAGE_REGION_AU = ["AU", "NZ"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音声ファイルをNorth Europeに保存する国リスト
|
||||||
|
* @const {number}
|
||||||
|
*/
|
||||||
|
export const BLOB_STORAGE_REGION_EU = [
|
||||||
|
"AT",
|
||||||
|
"BE",
|
||||||
|
"BG",
|
||||||
|
"HR",
|
||||||
|
"CY",
|
||||||
|
"CZ",
|
||||||
|
"DK",
|
||||||
|
"EE",
|
||||||
|
"FI",
|
||||||
|
"FR",
|
||||||
|
"DE",
|
||||||
|
"GR",
|
||||||
|
"HU",
|
||||||
|
"IS",
|
||||||
|
"IE",
|
||||||
|
"IT",
|
||||||
|
"LV",
|
||||||
|
"LI",
|
||||||
|
"LT",
|
||||||
|
"LU",
|
||||||
|
"MT",
|
||||||
|
"NL",
|
||||||
|
"NO",
|
||||||
|
"PL",
|
||||||
|
"PT",
|
||||||
|
"RO",
|
||||||
|
"RS",
|
||||||
|
"SK",
|
||||||
|
"SI",
|
||||||
|
"ZA",
|
||||||
|
"ES",
|
||||||
|
"SE",
|
||||||
|
"CH",
|
||||||
|
"TR",
|
||||||
|
"GB",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ADB2Cユーザのidentity.signInType
|
||||||
|
* @const {string[]}
|
||||||
|
*/
|
||||||
|
export const ADB2C_SIGN_IN_TYPE = {
|
||||||
|
EMAILADDRESS: "emailAddress",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AutoIncrementの初期値
|
||||||
|
* @const {number}
|
||||||
|
*/
|
||||||
|
export const AUTO_INCREMENT_START = 853211;
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
import { Test, TestingModule } from "@nestjs/testing";
|
||||||
|
import { ConfigModule } from "@nestjs/config";
|
||||||
|
import { DeleteService } from "./delete.service";
|
||||||
|
import { DeleteController } from "./delete.controller";
|
||||||
|
|
||||||
|
describe("DeleteController", () => {
|
||||||
|
let controller: DeleteController;
|
||||||
|
const mockTemplatesService = {};
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [
|
||||||
|
ConfigModule.forRoot({
|
||||||
|
envFilePath: [".env.test", ".env"],
|
||||||
|
isGlobal: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
controllers: [DeleteController],
|
||||||
|
providers: [DeleteService],
|
||||||
|
})
|
||||||
|
.overrideProvider(DeleteService)
|
||||||
|
.useValue(mockTemplatesService)
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
controller = module.get<DeleteController>(DeleteController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be defined", () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
|
Logger,
|
||||||
|
Post,
|
||||||
|
Req,
|
||||||
|
} from "@nestjs/common";
|
||||||
|
import { ErrorResponse } from "../../common/errors/types/types";
|
||||||
|
import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
||||||
|
import { Request } from "express";
|
||||||
|
import { DeleteService } from "./delete.service";
|
||||||
|
import { DeleteResponse } from "./types/types";
|
||||||
|
|
||||||
|
@ApiTags("delete")
|
||||||
|
@Controller("delete")
|
||||||
|
export class DeleteController {
|
||||||
|
constructor(private readonly deleteService: DeleteService) {}
|
||||||
|
|
||||||
|
@ApiResponse({
|
||||||
|
status: HttpStatus.OK,
|
||||||
|
type: DeleteResponse,
|
||||||
|
description: "成功時のレスポンス",
|
||||||
|
})
|
||||||
|
@ApiResponse({
|
||||||
|
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
description: "想定外のサーバーエラー",
|
||||||
|
type: ErrorResponse,
|
||||||
|
})
|
||||||
|
@ApiOperation({
|
||||||
|
operationId: "deleteData",
|
||||||
|
description: "すべてのデータを削除します",
|
||||||
|
})
|
||||||
|
@Post()
|
||||||
|
async deleteData(): Promise<{}> {
|
||||||
|
await this.deleteService.deleteData();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { DeleteRepositoryModule } from "../../repositories/delete/delete.repository.module";
|
||||||
|
import { DeleteController } from "./delete.controller";
|
||||||
|
import { DeleteService } from "./delete.service";
|
||||||
|
import { AdB2cModule } from "../../gateways/adb2c/adb2c.module";
|
||||||
|
import { BlobstorageModule } from "../../gateways/blobstorage/blobstorage.module";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [DeleteRepositoryModule, AdB2cModule, BlobstorageModule],
|
||||||
|
providers: [DeleteService],
|
||||||
|
controllers: [DeleteController],
|
||||||
|
})
|
||||||
|
export class DeleteModule {}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { DataSource } from "typeorm";
|
||||||
|
import { ConfigModule } from "@nestjs/config";
|
||||||
|
import { DeleteService } from "./delete.service";
|
||||||
|
import { Test, TestingModule } from "@nestjs/testing";
|
||||||
|
|
||||||
|
describe("DeleteController", () => {
|
||||||
|
let service: DeleteService;
|
||||||
|
const mockTemplatesService = {};
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [
|
||||||
|
ConfigModule.forRoot({
|
||||||
|
envFilePath: [".env.test", ".env"],
|
||||||
|
isGlobal: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
providers: [DeleteService],
|
||||||
|
})
|
||||||
|
.overrideProvider(DeleteService)
|
||||||
|
.useValue(mockTemplatesService)
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
service = module.get<DeleteService>(DeleteService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be defined", () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common";
|
||||||
|
import { DeleteRepositoryService } from "../../repositories/delete/delete.repository.service";
|
||||||
|
import { makeErrorResponse } from "../../common/errors/makeErrorResponse";
|
||||||
|
import { AdB2cService } from "../../gateways/adb2c/adb2c.service";
|
||||||
|
import { BlobstorageService } from "../../gateways/blobstorage/blobstorage.service";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DeleteService {
|
||||||
|
private readonly logger = new Logger(DeleteService.name);
|
||||||
|
constructor(
|
||||||
|
private readonly deleteRepositoryService: DeleteRepositoryService,
|
||||||
|
private readonly blobstorageService: BlobstorageService,
|
||||||
|
private readonly adB2cService: AdB2cService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* データを削除する
|
||||||
|
* @returns data
|
||||||
|
*/
|
||||||
|
async deleteData(): Promise<void> {
|
||||||
|
this.logger.log(`[IN] ${this.deleteData.name}`);
|
||||||
|
try {
|
||||||
|
// BlobStorageからデータを削除する
|
||||||
|
await this.blobstorageService.deleteContainers();
|
||||||
|
|
||||||
|
// ADB2Cからユーザ情報を取得する
|
||||||
|
const users = await this.adB2cService.getUsers();
|
||||||
|
const externalIds = users.map((user) => user.id);
|
||||||
|
await this.adB2cService.deleteUsers(externalIds);
|
||||||
|
|
||||||
|
// データベースからデータを削除する
|
||||||
|
await this.deleteRepositoryService.deleteData();
|
||||||
|
// AutoIncrementの値をリセットする
|
||||||
|
await this.deleteRepositoryService.resetAutoIncrement();
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`error=${e}`);
|
||||||
|
if (e instanceof Error) {
|
||||||
|
switch (e.constructor) {
|
||||||
|
default:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse("E009999"),
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse("E009999"),
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
this.logger.log(`[OUT] ${this.deleteData.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
import { DataSource } from "typeorm";
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export class DeleteResponse {}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { ConfigModule } from "@nestjs/config";
|
||||||
|
import { AdB2cService } from "./adb2c.service";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
exports: [AdB2cService],
|
||||||
|
providers: [AdB2cService],
|
||||||
|
})
|
||||||
|
export class AdB2cModule {}
|
||||||
116
data_migration_tools/server/src/gateways/adb2c/adb2c.service.ts
Normal file
116
data_migration_tools/server/src/gateways/adb2c/adb2c.service.ts
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import { ClientSecretCredential } from "@azure/identity";
|
||||||
|
import { Client } from "@microsoft/microsoft-graph-client";
|
||||||
|
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
|
||||||
|
import { Injectable, Logger } from "@nestjs/common";
|
||||||
|
import { ConfigService } from "@nestjs/config";
|
||||||
|
import { AdB2cResponse, AdB2cUser } from "./types/types";
|
||||||
|
import { isPromiseRejectedResult } from "./utils/utils";
|
||||||
|
|
||||||
|
export type ConflictError = {
|
||||||
|
reason: "email";
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Adb2cTooManyRequestsError extends Error {}
|
||||||
|
|
||||||
|
export const isConflictError = (arg: unknown): arg is ConflictError => {
|
||||||
|
const value = arg as ConflictError;
|
||||||
|
if (value.message === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (value.reason === "email") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AdB2cService {
|
||||||
|
private readonly logger = new Logger(AdB2cService.name);
|
||||||
|
private graphClient: Client;
|
||||||
|
|
||||||
|
constructor(private readonly configService: ConfigService) {
|
||||||
|
// ADB2Cへの認証情報
|
||||||
|
const credential = new ClientSecretCredential(
|
||||||
|
this.configService.getOrThrow<string>("ADB2C_TENANT_ID"),
|
||||||
|
this.configService.getOrThrow<string>("ADB2C_CLIENT_ID"),
|
||||||
|
this.configService.getOrThrow<string>("ADB2C_CLIENT_SECRET")
|
||||||
|
);
|
||||||
|
const authProvider = new TokenCredentialAuthenticationProvider(credential, {
|
||||||
|
scopes: ["https://graph.microsoft.com/.default"],
|
||||||
|
});
|
||||||
|
|
||||||
|
this.graphClient = Client.initWithMiddleware({ authProvider });
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Gets users
|
||||||
|
* @param externalIds
|
||||||
|
* @returns users
|
||||||
|
*/
|
||||||
|
async getUsers(): Promise<AdB2cUser[]> {
|
||||||
|
this.logger.log(`[IN] ${this.getUsers.name}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res: AdB2cResponse = await this.graphClient
|
||||||
|
.api(`users/`)
|
||||||
|
.select(["id", "displayName", "identities"])
|
||||||
|
.filter(`creationType eq 'LocalAccount'`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return res.value;
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`error=${e}`);
|
||||||
|
const { statusCode } = e;
|
||||||
|
if (statusCode === 429) {
|
||||||
|
throw new Adb2cTooManyRequestsError();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
this.logger.log(`[OUT] ${this.getUsers.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Azure AD B2Cからユーザ情報を削除する(複数)
|
||||||
|
* @param externalIds 外部ユーザーID
|
||||||
|
*/
|
||||||
|
async deleteUsers(externalIds: string[]): Promise<void> {
|
||||||
|
this.logger.log(
|
||||||
|
`[IN]${this.deleteUsers.name} | params: { externalIds: ${externalIds} };`
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 複数ユーザーを一括削除する方法がないため、1人ずつで削除を行う
|
||||||
|
const results = await Promise.allSettled(
|
||||||
|
externalIds.map(async (externalId) => {
|
||||||
|
await this.graphClient.api(`users/${externalId}`).delete();
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 15)); // 15ms待つ
|
||||||
|
this.logger.log(`[[ADB2C DELETE] externalId: ${externalId}`);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// 失敗したプロミスのエラーをログに記録
|
||||||
|
results.forEach((result, index) => {
|
||||||
|
// statusがrejectedでない場合は、エラーが発生していないためログに記録しない
|
||||||
|
if (result.status !== "rejected") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const failedId = externalIds[index];
|
||||||
|
if (isPromiseRejectedResult(result)) {
|
||||||
|
const error = result.reason.toString();
|
||||||
|
|
||||||
|
this.logger.error(`Failed to delete user ${failedId}: ${error}`);
|
||||||
|
} else {
|
||||||
|
this.logger.error(`Failed to delete user ${failedId}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`error=${e}`);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
this.logger.log(`[OUT] ${this.deleteUsers.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
export type AdB2cResponse = {
|
||||||
|
'@odata.context': string;
|
||||||
|
value: AdB2cUser[];
|
||||||
|
};
|
||||||
|
export type AdB2cUser = {
|
||||||
|
id: string;
|
||||||
|
displayName: string;
|
||||||
|
identities?: UserIdentity[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UserIdentity = {
|
||||||
|
signInType: string;
|
||||||
|
issuer: string;
|
||||||
|
issuerAssignedId: string;
|
||||||
|
};
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { ADB2C_SIGN_IN_TYPE } from '../../../constants';
|
||||||
|
import { AdB2cUser } from '../types/types';
|
||||||
|
|
||||||
|
export const isPromiseRejectedResult = (
|
||||||
|
data: unknown,
|
||||||
|
): data is PromiseRejectedResult => {
|
||||||
|
return (
|
||||||
|
data !== null &&
|
||||||
|
typeof data === 'object' &&
|
||||||
|
'status' in data &&
|
||||||
|
'reason' in data
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生のAdB2cUserのレスポンスから表示名とメールアドレスを取得する
|
||||||
|
export const getUserNameAndMailAddress = (user: AdB2cUser) => {
|
||||||
|
const { displayName, identities } = user;
|
||||||
|
const emailAddress = identities?.find(
|
||||||
|
(identity) => identity.signInType === ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
|
||||||
|
)?.issuerAssignedId;
|
||||||
|
return { displayName, emailAddress };
|
||||||
|
};
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { BlobstorageService } from './blobstorage.service';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
exports: [BlobstorageService],
|
||||||
|
imports: [ConfigModule],
|
||||||
|
providers: [BlobstorageService],
|
||||||
|
})
|
||||||
|
export class BlobstorageModule {}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
import { Injectable, Logger } from "@nestjs/common";
|
||||||
|
import {
|
||||||
|
BlobServiceClient,
|
||||||
|
StorageSharedKeyCredential,
|
||||||
|
} from "@azure/storage-blob";
|
||||||
|
import { ConfigService } from "@nestjs/config";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class BlobstorageService {
|
||||||
|
private readonly logger = new Logger(BlobstorageService.name);
|
||||||
|
private readonly blobServiceClientUS: BlobServiceClient;
|
||||||
|
private readonly blobServiceClientEU: BlobServiceClient;
|
||||||
|
private readonly blobServiceClientAU: BlobServiceClient;
|
||||||
|
private readonly sharedKeyCredentialUS: StorageSharedKeyCredential;
|
||||||
|
private readonly sharedKeyCredentialAU: StorageSharedKeyCredential;
|
||||||
|
private readonly sharedKeyCredentialEU: StorageSharedKeyCredential;
|
||||||
|
constructor(private readonly configService: ConfigService) {
|
||||||
|
this.sharedKeyCredentialUS = new StorageSharedKeyCredential(
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_NAME_US"),
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_KEY_US")
|
||||||
|
);
|
||||||
|
this.sharedKeyCredentialAU = new StorageSharedKeyCredential(
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_NAME_AU"),
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_KEY_AU")
|
||||||
|
);
|
||||||
|
this.sharedKeyCredentialEU = new StorageSharedKeyCredential(
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_NAME_EU"),
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_KEY_EU")
|
||||||
|
);
|
||||||
|
this.blobServiceClientUS = new BlobServiceClient(
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_ENDPOINT_US"),
|
||||||
|
this.sharedKeyCredentialUS
|
||||||
|
);
|
||||||
|
this.blobServiceClientAU = new BlobServiceClient(
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_ENDPOINT_AU"),
|
||||||
|
this.sharedKeyCredentialAU
|
||||||
|
);
|
||||||
|
this.blobServiceClientEU = new BlobServiceClient(
|
||||||
|
this.configService.getOrThrow<string>("STORAGE_ACCOUNT_ENDPOINT_EU"),
|
||||||
|
this.sharedKeyCredentialEU
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* すべてのコンテナを削除します。
|
||||||
|
* @returns containers
|
||||||
|
*/
|
||||||
|
async deleteContainers(): Promise<void> {
|
||||||
|
this.logger.log(`[IN] ${this.deleteContainers.name}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
for await (const container of this.blobServiceClientAU.listContainers({
|
||||||
|
prefix: "account-",
|
||||||
|
})) {
|
||||||
|
const client = this.blobServiceClientAU.getContainerClient(
|
||||||
|
container.name
|
||||||
|
);
|
||||||
|
await client.deleteIfExists();
|
||||||
|
}
|
||||||
|
for await (const container of this.blobServiceClientEU.listContainers({
|
||||||
|
prefix: "account-",
|
||||||
|
})) {
|
||||||
|
const client = this.blobServiceClientEU.getContainerClient(
|
||||||
|
container.name
|
||||||
|
);
|
||||||
|
await client.deleteIfExists();
|
||||||
|
}
|
||||||
|
for await (const container of this.blobServiceClientUS.listContainers({
|
||||||
|
prefix: "account-",
|
||||||
|
})) {
|
||||||
|
const client = this.blobServiceClientUS.getContainerClient(
|
||||||
|
container.name
|
||||||
|
);
|
||||||
|
await client.deleteIfExists();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`error=${e}`);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
this.logger.log(`[OUT] ${this.deleteContainers.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,35 +1,35 @@
|
|||||||
import { NestFactory } from "@nestjs/core";
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||||
import { AppModule } from "./app.module";
|
import { AppModule } from './app.module';
|
||||||
import { ValidationPipe } from "@nestjs/common";
|
import { ValidationPipe } from '@nestjs/common';
|
||||||
import { LoggerMiddleware } from "./common/loggerMiddleware";
|
import { LoggerMiddleware } from './common/loggerMiddleware';
|
||||||
import cookieParser from "cookie-parser";
|
import cookieParser from 'cookie-parser';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule, {
|
const app = await NestFactory.create(AppModule, {
|
||||||
cors: process.env.CORS === "TRUE",
|
cors: process.env.CORS === 'TRUE',
|
||||||
});
|
});
|
||||||
app.use(new LoggerMiddleware(), cookieParser());
|
app.use(new LoggerMiddleware(), cookieParser());
|
||||||
|
|
||||||
// バリデーター(+型の自動変換機能)を適用
|
// バリデーター(+型の自動変換機能)を適用
|
||||||
app.useGlobalPipes(
|
app.useGlobalPipes(
|
||||||
new ValidationPipe({ transform: true, forbidUnknownValues: false })
|
new ValidationPipe({ transform: true, forbidUnknownValues: false }),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (process.env.STAGE === "local") {
|
if (process.env.STAGE === 'local') {
|
||||||
const options = new DocumentBuilder()
|
const options = new DocumentBuilder()
|
||||||
.setTitle("data_migration_toolsOpenAPI")
|
.setTitle('data_migration_toolsOpenAPI')
|
||||||
.setVersion("1.0.0")
|
.setVersion('1.0.0')
|
||||||
.addBearerAuth({
|
.addBearerAuth({
|
||||||
type: "http",
|
type: 'http',
|
||||||
scheme: "bearer",
|
scheme: 'bearer',
|
||||||
bearerFormat: "JWT",
|
bearerFormat: 'JWT',
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
const document = SwaggerModule.createDocument(app, options);
|
const document = SwaggerModule.createDocument(app, options);
|
||||||
SwaggerModule.setup("api", app, document);
|
SwaggerModule.setup('api', app, document);
|
||||||
}
|
}
|
||||||
|
|
||||||
await app.listen(process.env.PORT || 8180);
|
await app.listen(process.env.PORT || 8280);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||||
|
import { DeleteRepositoryService } from "./delete.repository.service";
|
||||||
|
import { Account } from "./entity/account.entity";
|
||||||
|
import { AudioFile } from "./entity/audio_file.entity";
|
||||||
|
import { AudioOptionItem } from "./entity/audio_option_item.entity";
|
||||||
|
import { CheckoutPermission } from "./entity/checkout_permission.entity";
|
||||||
|
import {
|
||||||
|
CardLicense,
|
||||||
|
CardLicenseIssue,
|
||||||
|
License,
|
||||||
|
LicenseAllocationHistory,
|
||||||
|
LicenseAllocationHistoryArchive,
|
||||||
|
LicenseArchive,
|
||||||
|
LicenseOrder,
|
||||||
|
} from "./entity/license.entity";
|
||||||
|
import { OptionItem } from "./entity/option_item.entity";
|
||||||
|
import { SortCriteria } from "./entity/sort_criteria.entity";
|
||||||
|
import { Task } from "./entity/task.entity";
|
||||||
|
import { TemplateFile } from "./entity/template_file.entity";
|
||||||
|
import { Term } from "./entity/term.entity";
|
||||||
|
import { UserGroupMember } from "./entity/user_group_member.entity";
|
||||||
|
import { UserGroup } from "./entity/user_group.entity";
|
||||||
|
import { User, UserArchive } from "./entity/user.entity";
|
||||||
|
import { WorkflowTypist } from "./entity/workflow_typists.entity";
|
||||||
|
import { Workflow } from "./entity/workflow.entity";
|
||||||
|
import { Worktype } from "./entity/worktype.entity";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([
|
||||||
|
Account,
|
||||||
|
AudioFile,
|
||||||
|
AudioOptionItem,
|
||||||
|
CheckoutPermission,
|
||||||
|
License,
|
||||||
|
LicenseOrder,
|
||||||
|
CardLicense,
|
||||||
|
CardLicenseIssue,
|
||||||
|
LicenseArchive,
|
||||||
|
LicenseAllocationHistory,
|
||||||
|
LicenseAllocationHistoryArchive,
|
||||||
|
OptionItem,
|
||||||
|
SortCriteria,
|
||||||
|
Task,
|
||||||
|
TemplateFile,
|
||||||
|
Term,
|
||||||
|
UserGroupMember,
|
||||||
|
UserGroup,
|
||||||
|
User,
|
||||||
|
UserArchive,
|
||||||
|
WorkflowTypist,
|
||||||
|
Workflow,
|
||||||
|
Worktype,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
providers: [DeleteRepositoryService],
|
||||||
|
exports: [DeleteRepositoryService],
|
||||||
|
})
|
||||||
|
export class DeleteRepositoryModule {}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
import { Injectable } from "@nestjs/common";
|
||||||
|
import { DataSource } from "typeorm";
|
||||||
|
import { logger } from "@azure/identity";
|
||||||
|
import { Account } from "./entity/account.entity";
|
||||||
|
import { AUTO_INCREMENT_START } from "../../constants";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DeleteRepositoryService {
|
||||||
|
constructor(private dataSource: DataSource) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全テーブルをTrancateする
|
||||||
|
* @returns data
|
||||||
|
*/
|
||||||
|
async deleteData(): Promise<void> {
|
||||||
|
const entities = this.dataSource.entityMetadatas;
|
||||||
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await queryRunner.startTransaction();
|
||||||
|
await queryRunner.query("SET FOREIGN_KEY_CHECKS=0");
|
||||||
|
for (const entity of entities) {
|
||||||
|
await queryRunner.query(`TRUNCATE TABLE \`${entity.tableName}\``);
|
||||||
|
}
|
||||||
|
await queryRunner.query("SET FOREIGN_KEY_CHECKS=1");
|
||||||
|
await queryRunner.commitTransaction();
|
||||||
|
} catch (err) {
|
||||||
|
await queryRunner.rollbackTransaction();
|
||||||
|
logger.error(err);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AutoIncrementの値をリセットする
|
||||||
|
* @returns data
|
||||||
|
*/
|
||||||
|
async resetAutoIncrement(): Promise<void> {
|
||||||
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await queryRunner.startTransaction();
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE accounts AUTO_INCREMENT = ${AUTO_INCREMENT_START}`
|
||||||
|
);
|
||||||
|
await queryRunner.commitTransaction();
|
||||||
|
} catch (err) {
|
||||||
|
await queryRunner.rollbackTransaction();
|
||||||
|
logger.error(err);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
import { bigintTransformer } from "../../../common/entity";
|
||||||
|
import { User } from "./user.entity";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
OneToMany,
|
||||||
|
} from "typeorm";
|
||||||
|
|
||||||
|
@Entity({ name: "accounts" })
|
||||||
|
export class Account {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
parent_account_id: number | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
tier: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
country: string;
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
delegation_permission: boolean;
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
locked: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
company_name: string;
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
verified: boolean;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
primary_admin_user_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
secondary_admin_user_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
active_worktype_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@OneToMany(() => User, (user) => user.id)
|
||||||
|
user: User[] | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { Task } from "./task.entity";
|
||||||
|
import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from "typeorm";
|
||||||
|
|
||||||
|
@Entity({ name: "audio_files" })
|
||||||
|
export class AudioFile {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
@Column()
|
||||||
|
owner_user_id: number;
|
||||||
|
@Column()
|
||||||
|
url: string;
|
||||||
|
@Column()
|
||||||
|
file_name: string;
|
||||||
|
@Column()
|
||||||
|
author_id: string;
|
||||||
|
@Column()
|
||||||
|
work_type_id: string;
|
||||||
|
@Column()
|
||||||
|
started_at: Date;
|
||||||
|
@Column({ type: "time" })
|
||||||
|
duration: string;
|
||||||
|
@Column()
|
||||||
|
finished_at: Date;
|
||||||
|
@Column()
|
||||||
|
uploaded_at: Date;
|
||||||
|
@Column()
|
||||||
|
file_size: number;
|
||||||
|
@Column()
|
||||||
|
priority: string;
|
||||||
|
@Column()
|
||||||
|
audio_format: string;
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
comment: string | null;
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
@Column()
|
||||||
|
is_encrypted: boolean;
|
||||||
|
@OneToOne(() => Task, (task) => task.file)
|
||||||
|
task: Task | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { Task } from "./task.entity";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
ManyToOne,
|
||||||
|
JoinColumn,
|
||||||
|
} from "typeorm";
|
||||||
|
|
||||||
|
@Entity({ name: "audio_option_items" })
|
||||||
|
export class AudioOptionItem {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
@Column()
|
||||||
|
audio_file_id: number;
|
||||||
|
@Column()
|
||||||
|
label: string;
|
||||||
|
@Column()
|
||||||
|
value: string;
|
||||||
|
@ManyToOne(() => Task, (task) => task.audio_file_id)
|
||||||
|
@JoinColumn({ name: "audio_file_id", referencedColumnName: "audio_file_id" })
|
||||||
|
task: Task | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { bigintTransformer } from "../../../common/entity";
|
||||||
|
import { Task } from "./task.entity";
|
||||||
|
import { UserGroup } from "./user_group.entity";
|
||||||
|
import { User } from "./user.entity";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
JoinColumn,
|
||||||
|
ManyToOne,
|
||||||
|
} from "typeorm";
|
||||||
|
|
||||||
|
@Entity({ name: "checkout_permission" })
|
||||||
|
export class CheckoutPermission {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({})
|
||||||
|
task_id: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
user_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
user_group_id: number | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => User, (user) => user.id)
|
||||||
|
@JoinColumn({ name: "user_id" })
|
||||||
|
user: User | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => UserGroup, (group) => group.id)
|
||||||
|
@JoinColumn({ name: "user_group_id" })
|
||||||
|
user_group: UserGroup | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => Task, (task) => task.id)
|
||||||
|
@JoinColumn({ name: "task_id" })
|
||||||
|
task: Task | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,322 @@
|
|||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
OneToOne,
|
||||||
|
JoinColumn,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryColumn,
|
||||||
|
} from "typeorm";
|
||||||
|
import { User } from "./user.entity";
|
||||||
|
import { bigintTransformer } from "../../../common/entity";
|
||||||
|
|
||||||
|
@Entity({ name: "license_orders" })
|
||||||
|
export class LicenseOrder {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
po_number: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
from_account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
to_account_id: number;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
ordered_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
issued_at: Date | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
status: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
canceled_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
updated_at: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity({ name: "licenses" })
|
||||||
|
export class License {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
expiry_date: Date | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
status: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
allocated_user_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
order_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
delete_order_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@OneToOne(() => User, (user) => user.license, {
|
||||||
|
createForeignKeyConstraints: false,
|
||||||
|
}) // createForeignKeyConstraintsはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
@JoinColumn({ name: "allocated_user_id" })
|
||||||
|
user: User | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity({ name: "card_license_issue" })
|
||||||
|
export class CardLicenseIssue {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
issued_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
updated_at: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity({ name: "card_licenses" })
|
||||||
|
export class CardLicense {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
license_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
issue_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
card_license_key: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
activated_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
updated_at: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity({ name: "license_allocation_history" })
|
||||||
|
export class LicenseAllocationHistory {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
user_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
license_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
is_allocated: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
executed_at: Date;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
switch_from_type: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@ManyToOne(() => License, (licenses) => licenses.id, {
|
||||||
|
createForeignKeyConstraints: false,
|
||||||
|
}) // createForeignKeyConstraintsはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
@JoinColumn({ name: "license_id" })
|
||||||
|
license: License | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity({ name: "licenses_archive" })
|
||||||
|
export class LicenseArchive {
|
||||||
|
@PrimaryColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
expiry_date: Date | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
status: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
allocated_user_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
order_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
delete_order_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
archived_at: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity({ name: "license_allocation_history_archive" })
|
||||||
|
export class LicenseAllocationHistoryArchive {
|
||||||
|
@PrimaryColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
user_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
license_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
is_allocated: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
executed_at: Date;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
switch_from_type: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
})
|
||||||
|
archived_at: Date;
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
ManyToOne,
|
||||||
|
JoinColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { Worktype } from './worktype.entity';
|
||||||
|
|
||||||
|
@Entity({ name: 'option_items' })
|
||||||
|
export class OptionItem {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
@Column()
|
||||||
|
worktype_id: number;
|
||||||
|
@Column()
|
||||||
|
item_label: string;
|
||||||
|
@Column()
|
||||||
|
default_value_type: string;
|
||||||
|
@Column()
|
||||||
|
initial_value: string;
|
||||||
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
|
created_by: string | null;
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: 'datetime',
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date | null;
|
||||||
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
|
updated_by: string | null;
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: 'datetime',
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => Worktype, (worktype) => worktype.id)
|
||||||
|
@JoinColumn({ name: 'worktype_id' })
|
||||||
|
worktype: Worktype;
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity({ name: 'sort_criteria' })
|
||||||
|
export class SortCriteria {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
user_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
parameter: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
direction: string;
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
import { AudioOptionItem } from "./audio_option_item.entity";
|
||||||
|
import { AudioFile } from "./audio_file.entity";
|
||||||
|
import { User } from "./user.entity";
|
||||||
|
import { TemplateFile } from "./template_file.entity";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
OneToOne,
|
||||||
|
JoinColumn,
|
||||||
|
OneToMany,
|
||||||
|
ManyToOne,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from "typeorm";
|
||||||
|
import { bigintTransformer } from "../../../common/entity";
|
||||||
|
|
||||||
|
@Entity({ name: "tasks" })
|
||||||
|
export class Task {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
@Column()
|
||||||
|
job_number: string;
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
@Column({ nullable: true, type: "boolean" })
|
||||||
|
is_job_number_enabled: boolean | null;
|
||||||
|
@Column()
|
||||||
|
audio_file_id: number;
|
||||||
|
@Column()
|
||||||
|
status: string;
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
typist_user_id: number | null;
|
||||||
|
@Column()
|
||||||
|
priority: string;
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
template_file_id: number | null;
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
started_at: Date | null;
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
finished_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date;
|
||||||
|
@OneToOne(() => AudioFile, (audiofile) => audiofile.task)
|
||||||
|
@JoinColumn({ name: "audio_file_id" })
|
||||||
|
file: AudioFile | null;
|
||||||
|
@OneToMany(() => AudioOptionItem, (option) => option.task)
|
||||||
|
option_items: AudioOptionItem[] | null;
|
||||||
|
@OneToOne(() => User, (user) => user.id)
|
||||||
|
@JoinColumn({ name: "typist_user_id" })
|
||||||
|
typist_user: User | null;
|
||||||
|
@ManyToOne(() => TemplateFile, (templateFile) => templateFile.id)
|
||||||
|
@JoinColumn({ name: "template_file_id" })
|
||||||
|
template_file: TemplateFile | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
OneToMany,
|
||||||
|
} from "typeorm";
|
||||||
|
import { Task } from "./task.entity";
|
||||||
|
|
||||||
|
@Entity({ name: "template_files" })
|
||||||
|
export class TemplateFile {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
@Column()
|
||||||
|
url: string;
|
||||||
|
@Column()
|
||||||
|
file_name: string;
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
@CreateDateColumn()
|
||||||
|
created_at: Date;
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updated_at: Date;
|
||||||
|
@OneToMany(() => Task, (task) => task.template_file)
|
||||||
|
tasks: Task[] | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity({ name: 'terms' })
|
||||||
|
export class Term {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
document_type: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
version: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: 'datetime',
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'varchar' })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: 'datetime',
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date;
|
||||||
|
}
|
||||||
@ -0,0 +1,170 @@
|
|||||||
|
import { Account } from "./account.entity";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
ManyToOne,
|
||||||
|
JoinColumn,
|
||||||
|
OneToOne,
|
||||||
|
OneToMany,
|
||||||
|
PrimaryColumn,
|
||||||
|
} from "typeorm";
|
||||||
|
import { License } from "./license.entity";
|
||||||
|
import { UserGroupMember } from "./user_group_member.entity";
|
||||||
|
|
||||||
|
@Entity({ name: "users" })
|
||||||
|
export class User {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
external_id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
role: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
author_id: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
accepted_eula_version: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
accepted_privacy_notice_version: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
accepted_dpa_version: string | null;
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
email_verified: boolean;
|
||||||
|
|
||||||
|
@Column({ default: true })
|
||||||
|
auto_renew: boolean;
|
||||||
|
|
||||||
|
@Column({ default: true })
|
||||||
|
notification: boolean;
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
encryption: boolean;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
encryption_password: string | null;
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
prompt: boolean;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@ManyToOne(() => Account, (account) => account.user, {
|
||||||
|
createForeignKeyConstraints: false,
|
||||||
|
}) // createForeignKeyConstraintsはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
@JoinColumn({ name: "account_id" })
|
||||||
|
account: Account | null;
|
||||||
|
|
||||||
|
@OneToOne(() => License, (license) => license.user)
|
||||||
|
license: License | null;
|
||||||
|
|
||||||
|
@OneToMany(() => UserGroupMember, (userGroupMember) => userGroupMember.user)
|
||||||
|
userGroupMembers: UserGroupMember[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity({ name: "users_archive" })
|
||||||
|
export class UserArchive {
|
||||||
|
@PrimaryColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
external_id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
role: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
author_id: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
accepted_eula_version: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
accepted_privacy_notice_version: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
accepted_dpa_version: string | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
email_verified: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
auto_renew: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
notification: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
encryption: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
prompt: boolean;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
archived_at: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type newUser = Omit<
|
||||||
|
User,
|
||||||
|
| "id"
|
||||||
|
| "deleted_at"
|
||||||
|
| "created_at"
|
||||||
|
| "updated_at"
|
||||||
|
| "updated_by"
|
||||||
|
| "created_by"
|
||||||
|
| "account"
|
||||||
|
| "license"
|
||||||
|
| "userGroupMembers"
|
||||||
|
| "email_verified"
|
||||||
|
>;
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
OneToMany,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { UserGroupMember } from './user_group_member.entity';
|
||||||
|
|
||||||
|
@Entity({ name: 'user_group' })
|
||||||
|
export class UserGroup {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: 'datetime',
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: 'datetime',
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date | null;
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
() => UserGroupMember,
|
||||||
|
(userGroupMember) => userGroupMember.userGroup,
|
||||||
|
)
|
||||||
|
userGroupMembers: UserGroupMember[] | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
import { User } from "./user.entity";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
JoinColumn,
|
||||||
|
ManyToOne,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from "typeorm";
|
||||||
|
import { UserGroup } from "./user_group.entity";
|
||||||
|
|
||||||
|
@Entity({ name: "user_group_member" })
|
||||||
|
export class UserGroupMember {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
user_group_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
user_id: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => User, (user) => user.id)
|
||||||
|
@JoinColumn({ name: "user_id" })
|
||||||
|
user: User | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => UserGroup, (userGroup) => userGroup.id)
|
||||||
|
@JoinColumn({ name: "user_group_id" })
|
||||||
|
userGroup: UserGroup | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
OneToMany,
|
||||||
|
JoinColumn,
|
||||||
|
ManyToOne,
|
||||||
|
} from "typeorm";
|
||||||
|
import { WorkflowTypist } from "./workflow_typists.entity";
|
||||||
|
import { Worktype } from "./worktype.entity";
|
||||||
|
import { TemplateFile } from "./template_file.entity";
|
||||||
|
import { User } from "./user.entity";
|
||||||
|
import { bigintTransformer } from "../../../common/entity";
|
||||||
|
|
||||||
|
@Entity({ name: "workflows" })
|
||||||
|
export class Workflow {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
author_id: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
worktype_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
template_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@ManyToOne(() => User, (user) => user.id)
|
||||||
|
@JoinColumn({ name: "author_id" })
|
||||||
|
author: User | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => Worktype, (worktype) => worktype.id)
|
||||||
|
@JoinColumn({ name: "worktype_id" })
|
||||||
|
worktype: Worktype | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => TemplateFile, (templateFile) => templateFile.id)
|
||||||
|
@JoinColumn({ name: "template_id" })
|
||||||
|
template: TemplateFile | null;
|
||||||
|
|
||||||
|
@OneToMany(() => WorkflowTypist, (workflowTypist) => workflowTypist.workflow)
|
||||||
|
workflowTypists: WorkflowTypist[] | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
ManyToOne,
|
||||||
|
JoinColumn,
|
||||||
|
} from "typeorm";
|
||||||
|
import { Workflow } from "./workflow.entity";
|
||||||
|
import { User } from "./user.entity";
|
||||||
|
import { UserGroup } from "./user_group.entity";
|
||||||
|
import { bigintTransformer } from "../../../common/entity";
|
||||||
|
|
||||||
|
@Entity({ name: "workflow_typists" })
|
||||||
|
export class WorkflowTypist {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
workflow_id: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
typist_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "bigint", transformer: bigintTransformer })
|
||||||
|
typist_group_id: number | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@ManyToOne(() => Workflow, (workflow) => workflow.id)
|
||||||
|
@JoinColumn({ name: "workflow_id" })
|
||||||
|
workflow: Workflow | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => User, (user) => user.id)
|
||||||
|
@JoinColumn({ name: "typist_id" })
|
||||||
|
typist: User | null;
|
||||||
|
|
||||||
|
@ManyToOne(() => UserGroup, (userGroup) => userGroup.id)
|
||||||
|
@JoinColumn({ name: "typist_group_id" })
|
||||||
|
typistGroup: UserGroup | null;
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
import { Account } from "./account.entity";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
OneToMany,
|
||||||
|
} from "typeorm";
|
||||||
|
import { OptionItem } from "./option_item.entity";
|
||||||
|
|
||||||
|
@Entity({ name: "worktypes" })
|
||||||
|
export class Worktype {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
account_id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
custom_worktype_id: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "varchar" })
|
||||||
|
description: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
deleted_at: Date | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
created_by: string | null;
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
created_at: Date;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: "datetime" })
|
||||||
|
updated_by: string | null;
|
||||||
|
|
||||||
|
@UpdateDateColumn({
|
||||||
|
default: () => "datetime('now', 'localtime')",
|
||||||
|
type: "datetime",
|
||||||
|
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||||
|
updated_at: Date;
|
||||||
|
|
||||||
|
@OneToMany(() => OptionItem, (optionItem) => optionItem.worktype)
|
||||||
|
option_items: OptionItem[];
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user