Merge branch 'develop' of https://dev.azure.com/ODMSCloud/ODMS%20Cloud/_git/ODMS%20Cloud into develop
This commit is contained in:
commit
cdb6931d57
@ -22,11 +22,11 @@ const App = (): JSX.Element => {
|
||||
useEffect(() => {
|
||||
const id = globalAxios.interceptors.response.use(
|
||||
(response: AxiosResponse) => response,
|
||||
(e: AxiosError) => {
|
||||
(e: AxiosError<{ code?: string }>) => {
|
||||
if (
|
||||
e?.response?.status === 401 &&
|
||||
e.code &&
|
||||
!UNAUTHORIZED_TO_CONTINUE_ERROR_CODES.includes(e.code)
|
||||
e?.response?.data?.code &&
|
||||
!UNAUTHORIZED_TO_CONTINUE_ERROR_CODES.includes(e.response.data.code)
|
||||
) {
|
||||
dispatch(clearToken());
|
||||
instance.logoutRedirect({
|
||||
|
||||
@ -56,4 +56,5 @@ export const errorCodes = [
|
||||
"E011002", // ワークタイプ登録上限超過エラー
|
||||
"E011003", // ワークタイプ不在エラー
|
||||
"E013001", // ワークフローのAuthorIDとWorktypeIDのペア重複エラー
|
||||
"E013002", // ワークフロー不在エラー
|
||||
] as const;
|
||||
|
||||
@ -346,6 +346,17 @@ export const deleteWorkflowAsync = createAsyncThunk<
|
||||
// e ⇒ errorObjectに変換"
|
||||
const error = createErrorObject(e);
|
||||
|
||||
// ワークフローが削除済みの場合は成功扱いとする
|
||||
if (error.code === "E013002") {
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "info",
|
||||
message: getTranslationID("common.message.success"),
|
||||
})
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "error",
|
||||
|
||||
@ -34,10 +34,13 @@ import { TemplatesService } from '../../features/templates/templates.service';
|
||||
import { TemplatesModule } from '../../features/templates/templates.module';
|
||||
import { WorkflowsService } from '../../features/workflows/workflows.service';
|
||||
import { WorkflowsModule } from '../../features/workflows/workflows.module';
|
||||
import { TermsService } from '../../features/terms/terms.service';
|
||||
import { TermsRepositoryModule } from '../../repositories/terms/terms.repository.module';
|
||||
import { TermsModule } from '../../features/terms/terms.module';
|
||||
|
||||
export const makeTestingModule = async (
|
||||
datasource: DataSource,
|
||||
): Promise<TestingModule> => {
|
||||
): Promise<TestingModule | undefined> => {
|
||||
try {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [
|
||||
@ -56,6 +59,7 @@ export const makeTestingModule = async (
|
||||
LicensesModule,
|
||||
TemplatesModule,
|
||||
WorkflowsModule,
|
||||
TermsModule,
|
||||
AccountsRepositoryModule,
|
||||
UsersRepositoryModule,
|
||||
LicensesRepositoryModule,
|
||||
@ -71,6 +75,7 @@ export const makeTestingModule = async (
|
||||
AuthGuardsModule,
|
||||
SortCriteriaRepositoryModule,
|
||||
WorktypesRepositoryModule,
|
||||
TermsRepositoryModule,
|
||||
],
|
||||
providers: [
|
||||
AuthService,
|
||||
@ -82,6 +87,7 @@ export const makeTestingModule = async (
|
||||
LicensesService,
|
||||
TemplatesService,
|
||||
WorkflowsService,
|
||||
TermsService,
|
||||
],
|
||||
})
|
||||
.useMocker(async (token) => {
|
||||
|
||||
@ -2,10 +2,12 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AccountsController } from './accounts.controller';
|
||||
import { AccountsService } from './accounts.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
|
||||
describe('AccountsController', () => {
|
||||
let controller: AccountsController;
|
||||
const mockAccountService = {};
|
||||
const mockAuthService = {};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
@ -16,10 +18,12 @@ describe('AccountsController', () => {
|
||||
}),
|
||||
],
|
||||
controllers: [AccountsController],
|
||||
providers: [AccountsService],
|
||||
providers: [AccountsService, AuthService],
|
||||
})
|
||||
.overrideProvider(AccountsService)
|
||||
.useValue(mockAccountService)
|
||||
.overrideProvider(AuthService)
|
||||
.useValue(mockAuthService)
|
||||
.compile();
|
||||
|
||||
controller = module.get<AccountsController>(AccountsController);
|
||||
|
||||
@ -8,6 +8,7 @@ import {
|
||||
UseGuards,
|
||||
Param,
|
||||
Query,
|
||||
HttpException,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiOperation,
|
||||
@ -74,12 +75,15 @@ import { AccessToken } from '../../common/token';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
@ApiTags('accounts')
|
||||
@Controller('accounts')
|
||||
export class AccountsController {
|
||||
constructor(
|
||||
private readonly accountService: AccountsService, //private readonly cryptoService: CryptoService,
|
||||
private readonly authService: AuthService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
@ -1116,11 +1120,22 @@ export class AccountsController {
|
||||
async getAccountInfoMinimalAccess(
|
||||
@Body() body: GetAccountInfoMinimalAccessRequest,
|
||||
): Promise<GetAccountInfoMinimalAccessResponse> {
|
||||
const context = makeContext(uuidv4());
|
||||
// IDトークンの検証
|
||||
const idToken = await this.authService.getVerifiedIdToken(body.idToken);
|
||||
const isVerified = await this.authService.isVerifiedUser(idToken);
|
||||
if (!isVerified) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010201'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO 仮実装。API実装タスクで本実装する。
|
||||
// const idToken = await this.authService.getVerifiedIdToken(body.idToken);
|
||||
// await this.accountService.getAccountInfoMinimalAccess(context, idToken);
|
||||
return;
|
||||
const context = makeContext(idToken.sub);
|
||||
|
||||
const tier = await this.accountService.getAccountInfoMinimalAccess(
|
||||
context,
|
||||
idToken.sub,
|
||||
);
|
||||
return { tier };
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import { AdB2cModule } from '../../gateways/adb2c/adb2c.module';
|
||||
import { UserGroupsRepositoryModule } from '../../repositories/user_groups/user_groups.repository.module';
|
||||
import { BlobstorageModule } from '../../gateways/blobstorage/blobstorage.module';
|
||||
import { WorktypesRepositoryModule } from '../../repositories/worktypes/worktypes.repository.module';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -22,6 +23,6 @@ import { WorktypesRepositoryModule } from '../../repositories/worktypes/worktype
|
||||
BlobstorageModule,
|
||||
],
|
||||
controllers: [AccountsController],
|
||||
providers: [AccountsService],
|
||||
providers: [AccountsService, AuthService],
|
||||
})
|
||||
export class AccountsModule {}
|
||||
|
||||
@ -5595,3 +5595,127 @@ describe('deleteAccountAndData', () => {
|
||||
expect(userRecord).toBe(null);
|
||||
});
|
||||
});
|
||||
describe('getAccountInfoMinimalAccess', () => {
|
||||
let source: DataSource = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
it('IDトークンのsub情報からアカウントの階層情報を取得できること(第五階層)', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, {
|
||||
tier: 5,
|
||||
});
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const tier5Account = await getAccount(source, account.id);
|
||||
expect(tier5Account.tier).toBe(5);
|
||||
}
|
||||
|
||||
const tier = await service.getAccountInfoMinimalAccess(
|
||||
context,
|
||||
admin.external_id,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
expect(tier).toBe(5);
|
||||
});
|
||||
it('IDトークンのSub情報からアカウントの階層情報を取得できること(第四階層)', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
// 第四階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, {
|
||||
tier: 4,
|
||||
});
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const tier5Account = await getAccount(source, account.id);
|
||||
expect(tier5Account.tier).toBe(4);
|
||||
}
|
||||
|
||||
const tier = await service.getAccountInfoMinimalAccess(
|
||||
context,
|
||||
admin.external_id,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
expect(tier).toBe(4);
|
||||
});
|
||||
it('対象のユーザーが存在しない場合、400エラーとなること', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
// 第四階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, {
|
||||
tier: 4,
|
||||
});
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const tier5Account = await getAccount(source, account.id);
|
||||
expect(tier5Account.tier).toBe(4);
|
||||
}
|
||||
|
||||
try {
|
||||
await service.getAccountInfoMinimalAccess(context, 'fail_external_id');
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
it('DBアクセスに失敗した場合、500エラーとなること', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
// 第四階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, {
|
||||
tier: 4,
|
||||
});
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const tier5Account = await getAccount(source, account.id);
|
||||
expect(tier5Account.tier).toBe(4);
|
||||
}
|
||||
|
||||
//DBアクセスに失敗するようにする
|
||||
const usersRepositoryService = module.get<UsersRepositoryService>(
|
||||
UsersRepositoryService,
|
||||
);
|
||||
usersRepositoryService.findUserByExternalId = jest
|
||||
.fn()
|
||||
.mockRejectedValue('DB failed');
|
||||
|
||||
try {
|
||||
await service.getAccountInfoMinimalAccess(context, admin.external_id);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1843,4 +1843,61 @@ export class AccountsService {
|
||||
`[OUT] [${context.trackingId}] ${this.deleteAccountAndData.name}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* IDトークンのsubからアカウントの階層情報を取得します
|
||||
* @param context
|
||||
* @param externalId
|
||||
* @returns account info minimal access
|
||||
*/
|
||||
async getAccountInfoMinimalAccess(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
): Promise<number> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getAccountInfoMinimalAccess.name} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
const { account } = await this.usersRepository.findUserByExternalId(
|
||||
externalId,
|
||||
);
|
||||
if (!account) {
|
||||
throw new AccountNotFoundError(
|
||||
`Account not found. externalId: ${externalId}`,
|
||||
);
|
||||
}
|
||||
|
||||
return account.tier;
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010204'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
case AccountNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010501'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getAccountInfoMinimalAccess.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ describe('checkIsAcceptedLatestVersion', () => {
|
||||
|
||||
await createTermInfo(source, 'EULA', '1.0');
|
||||
await createTermInfo(source, 'DPA', '1.0');
|
||||
const result = await service.checkIsAcceptedLatestVersion(context, idToken);
|
||||
const result = await service.isAcceptedLatestVersion(context, idToken);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
@ -187,7 +187,7 @@ describe('checkIsAcceptedLatestVersion', () => {
|
||||
|
||||
await createTermInfo(source, 'EULA', '1.0');
|
||||
await createTermInfo(source, 'DPA', '1.0');
|
||||
const result = await service.checkIsAcceptedLatestVersion(context, idToken);
|
||||
const result = await service.isAcceptedLatestVersion(context, idToken);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
@ -208,7 +208,7 @@ describe('checkIsAcceptedLatestVersion', () => {
|
||||
|
||||
await createTermInfo(source, 'EULA', '1.1');
|
||||
await createTermInfo(source, 'DPA', '1.0');
|
||||
const result = await service.checkIsAcceptedLatestVersion(context, idToken);
|
||||
const result = await service.isAcceptedLatestVersion(context, idToken);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
@ -229,7 +229,7 @@ describe('checkIsAcceptedLatestVersion', () => {
|
||||
|
||||
await createTermInfo(source, 'EULA', '1.1');
|
||||
await createTermInfo(source, 'DPA', '1.0');
|
||||
const result = await service.checkIsAcceptedLatestVersion(context, idToken);
|
||||
const result = await service.isAcceptedLatestVersion(context, idToken);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
@ -250,7 +250,7 @@ describe('checkIsAcceptedLatestVersion', () => {
|
||||
|
||||
await createTermInfo(source, 'EULA', '1.0');
|
||||
await createTermInfo(source, 'DPA', '1.1');
|
||||
const result = await service.checkIsAcceptedLatestVersion(context, idToken);
|
||||
const result = await service.isAcceptedLatestVersion(context, idToken);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Post,
|
||||
Req,
|
||||
@ -21,6 +22,7 @@ import { retrieveAuthorizationToken } from '../../common/http/helper';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
@ApiTags('notification')
|
||||
@Controller('notification')
|
||||
@ -57,7 +59,20 @@ export class NotificationController {
|
||||
const { handler, pns } = body;
|
||||
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
import { Controller, Get, HttpStatus, Req, UseGuards } from '@nestjs/common';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Req,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
ApiOperation,
|
||||
@ -16,6 +23,7 @@ import { retrieveAuthorizationToken } from '../../common/http/helper';
|
||||
import { Request } from 'express';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { TemplatesService } from './templates.service';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
@ApiTags('templates')
|
||||
@Controller('templates')
|
||||
@ -46,8 +54,21 @@ export class TemplatesController {
|
||||
@UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] }))
|
||||
@Get()
|
||||
async getTemplates(@Req() req: Request): Promise<GetTemplatesResponse> {
|
||||
const token = retrieveAuthorizationToken(req);
|
||||
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
const templates = await this.templatesService.getTemplates(context, userId);
|
||||
|
||||
@ -9,7 +9,7 @@ import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
describe('getTemplates', () => {
|
||||
let source: DataSource = null;
|
||||
let source: DataSource | undefined = undefined;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
@ -22,12 +22,16 @@ describe('getTemplates', () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (!source) return;
|
||||
await source.destroy();
|
||||
source = null;
|
||||
source = undefined;
|
||||
});
|
||||
|
||||
it('テンプレートファイル一覧を取得できる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
|
||||
const service = module.get<TemplatesService>(TemplatesService);
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
@ -62,10 +66,13 @@ describe('getTemplates', () => {
|
||||
expect(templates[1].id).toBe(template2.id);
|
||||
expect(templates[1].name).toBe(template2.file_name);
|
||||
}
|
||||
});
|
||||
}, 6000000);
|
||||
|
||||
it('テンプレートファイル一覧を取得できる(0件)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
|
||||
const service = module.get<TemplatesService>(TemplatesService);
|
||||
// 第五階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 5 });
|
||||
@ -80,7 +87,10 @@ describe('getTemplates', () => {
|
||||
});
|
||||
|
||||
it('テンプレートファイル一覧の取得に失敗した場合、エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
|
||||
const service = module.get<TemplatesService>(TemplatesService);
|
||||
// 第五階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
@ -6,11 +6,14 @@ describe('TermsController', () => {
|
||||
let controller: TermsController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const mockTermsService = {};
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [TermsController],
|
||||
providers: [TermsService],
|
||||
}).compile();
|
||||
|
||||
})
|
||||
.overrideProvider(TermsService)
|
||||
.useValue(mockTermsService)
|
||||
.compile();
|
||||
controller = module.get<TermsController>(TermsController);
|
||||
});
|
||||
|
||||
|
||||
@ -28,12 +28,7 @@ export class TermsController {
|
||||
async getTermsInfo(): Promise<GetTermsInfoResponse> {
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
// TODO 仮実装。API実装タスクで本実装する。
|
||||
// const termInfo = await this.termsService.getTermsInfo(context);
|
||||
const termsInfo = [
|
||||
{ documentType: 'EULA', version: '1.0' },
|
||||
{ documentType: 'DPA', version: '1.1' },
|
||||
] as TermInfo[];
|
||||
const termsInfo = await this.termsService.getTermsInfo(context);
|
||||
|
||||
return { termsInfo };
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TermsController } from './terms.controller';
|
||||
import { TermsService } from './terms.service';
|
||||
import { TermsRepositoryModule } from '../../repositories/terms/terms.repository.module';
|
||||
|
||||
@Module({
|
||||
imports: [TermsRepositoryModule],
|
||||
controllers: [TermsController],
|
||||
providers: [TermsService]
|
||||
providers: [TermsService],
|
||||
})
|
||||
export class TermsModule {}
|
||||
|
||||
@ -1,18 +1,83 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { TermsService } from './terms.service';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { makeTestingModule } from '../../common/test/modules';
|
||||
import { createTermInfo } from '../auth/test/utility';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
describe('TermsService', () => {
|
||||
let service: TermsService;
|
||||
|
||||
describe('利用規約取得', () => {
|
||||
let source: DataSource = null;
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [TermsService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<TermsService>(TermsService);
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
afterEach(async () => {
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('最新の利用規約情報が取得できる', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const service = module.get<TermsService>(TermsService);
|
||||
|
||||
await createTermInfo(source, 'EULA', 'v1.0');
|
||||
await createTermInfo(source, 'EULA', 'v1.1');
|
||||
await createTermInfo(source, 'DPA', 'v1.0');
|
||||
await createTermInfo(source, 'DPA', 'v1.2');
|
||||
|
||||
const context = makeContext(uuidv4());
|
||||
const result = await service.getTermsInfo(context);
|
||||
|
||||
expect(result[0].documentType).toBe('EULA');
|
||||
expect(result[0].version).toBe('v1.1');
|
||||
expect(result[1].documentType).toBe('DPA');
|
||||
expect(result[1].version).toBe('v1.2');
|
||||
});
|
||||
|
||||
it('利用規約情報(EULA、DPA両方)が存在しない場合エラーとなる', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const service = module.get<TermsService>(TermsService);
|
||||
const context = makeContext(uuidv4());
|
||||
await expect(service.getTermsInfo(context)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('利用規約情報(EULAのみ)が存在しない場合エラーとなる', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const service = module.get<TermsService>(TermsService);
|
||||
await createTermInfo(source, 'DPA', 'v1.0');
|
||||
const context = makeContext(uuidv4());
|
||||
await expect(service.getTermsInfo(context)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('利用規約情報(DPAのみ)が存在しない場合エラーとなる', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const service = module.get<TermsService>(TermsService);
|
||||
await createTermInfo(source, 'EULA', 'v1.0');
|
||||
const context = makeContext(uuidv4());
|
||||
await expect(service.getTermsInfo(context)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,44 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||
import { Context } from '../../common/log';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { TermInfo } from './types/types';
|
||||
import { TermsRepositoryService } from '../../repositories/terms/terms.repository.service';
|
||||
import { TERM_TYPE } from '../../constants';
|
||||
|
||||
@Injectable()
|
||||
export class TermsService {}
|
||||
export class TermsService {
|
||||
constructor(private readonly termsRepository: TermsRepositoryService) {}
|
||||
private readonly logger = new Logger(TermsService.name);
|
||||
|
||||
/**
|
||||
* 利用規約情報を取得する
|
||||
* return termsInfo
|
||||
*/
|
||||
async getTermsInfo(context: Context): Promise<TermInfo[]> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.getTermsInfo.name}`);
|
||||
try {
|
||||
const { eulaVersion, dpaVersion } =
|
||||
await this.termsRepository.getLatestTermsInfo();
|
||||
return [
|
||||
{
|
||||
documentType: TERM_TYPE.EULA,
|
||||
version: eulaVersion,
|
||||
},
|
||||
{
|
||||
documentType: TERM_TYPE.DPA,
|
||||
version: dpaVersion,
|
||||
},
|
||||
];
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getTermsInfo.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,3 +10,8 @@ export class GetTermsInfoResponse {
|
||||
@ApiProperty({ type: [TermInfo] })
|
||||
termsInfo: TermInfo[];
|
||||
}
|
||||
|
||||
export type TermsVersion = {
|
||||
eulaVersion: string;
|
||||
dpaVersion: string;
|
||||
};
|
||||
|
||||
@ -2,10 +2,12 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersController } from './users.controller';
|
||||
import { UsersService } from './users.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
|
||||
describe('UsersController', () => {
|
||||
let controller: UsersController;
|
||||
const mockUserService = {};
|
||||
const mockAuthService = {};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
@ -16,10 +18,12 @@ describe('UsersController', () => {
|
||||
}),
|
||||
],
|
||||
controllers: [UsersController],
|
||||
providers: [UsersService],
|
||||
providers: [UsersService, AuthService],
|
||||
})
|
||||
.overrideProvider(UsersService)
|
||||
.useValue(mockUserService)
|
||||
.overrideProvider(AuthService)
|
||||
.useValue(mockAuthService)
|
||||
.compile();
|
||||
|
||||
controller = module.get<UsersController>(UsersController);
|
||||
|
||||
@ -41,6 +41,7 @@ import {
|
||||
UpdateAcceptedVersionResponse,
|
||||
} from './types/types';
|
||||
import { UsersService } from './users.service';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { AuthGuard } from '../../common/guards/auth/authguards';
|
||||
import {
|
||||
@ -56,7 +57,10 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
@ApiTags('users')
|
||||
@Controller('users')
|
||||
export class UsersController {
|
||||
constructor(private readonly usersService: UsersService) {}
|
||||
constructor(
|
||||
private readonly usersService: UsersService,
|
||||
private readonly authService: AuthService,
|
||||
) {}
|
||||
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
@ -495,11 +499,24 @@ export class UsersController {
|
||||
async updateAcceptedVersion(
|
||||
@Body() body: UpdateAcceptedVersionRequest,
|
||||
): Promise<UpdateAcceptedVersionResponse> {
|
||||
const context = makeContext(uuidv4());
|
||||
const { idToken, acceptedEULAVersion, acceptedDPAVersion } = body;
|
||||
|
||||
// TODO 仮実装。API実装タスクで本実装する。
|
||||
// const idToken = await this.authService.getVerifiedIdToken(body.idToken);
|
||||
// await this.usersService.updateAcceptedVersion(context, idToken);
|
||||
const verifiedIdToken = await this.authService.getVerifiedIdToken(idToken);
|
||||
const context = makeContext(verifiedIdToken.sub);
|
||||
|
||||
const isVerified = await this.authService.isVerifiedUser(verifiedIdToken);
|
||||
if (!isVerified) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010201'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
await this.usersService.updateAcceptedVersion(
|
||||
context,
|
||||
verifiedIdToken.sub,
|
||||
acceptedEULAVersion,
|
||||
acceptedDPAVersion,
|
||||
);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import { UsersRepositoryModule } from '../../repositories/users/users.repository
|
||||
import { LicensesRepositoryModule } from '../../repositories/licenses/licenses.repository.module';
|
||||
import { UsersController } from './users.controller';
|
||||
import { UsersService } from './users.service';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -18,6 +19,6 @@ import { UsersService } from './users.service';
|
||||
ConfigModule,
|
||||
],
|
||||
controllers: [UsersController],
|
||||
providers: [UsersService],
|
||||
providers: [UsersService, AuthService],
|
||||
})
|
||||
export class UsersModule {}
|
||||
|
||||
@ -43,6 +43,7 @@ import {
|
||||
makeTestSimpleAccount,
|
||||
makeTestUser,
|
||||
} from '../../common/test/utility';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
describe('UsersService.confirmUser', () => {
|
||||
let source: DataSource = null;
|
||||
@ -2480,3 +2481,91 @@ describe('UsersService.updateUser', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('UsersService.updateAcceptedVersion', () => {
|
||||
let source: DataSource = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('同意済み利用規約バージョンを更新できる(第五)', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const { admin } = await makeTestAccount(source, {
|
||||
tier: 5,
|
||||
});
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
await service.updateAcceptedVersion(context, admin.external_id, 'v2.0');
|
||||
const user = await getUser(source, admin.id);
|
||||
|
||||
expect(user.accepted_eula_version).toBe('v2.0');
|
||||
});
|
||||
|
||||
it('同意済み利用規約バージョンを更新できる(第一~第四)', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const { admin } = await makeTestAccount(source, {
|
||||
tier: 4,
|
||||
});
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
await service.updateAcceptedVersion(
|
||||
context,
|
||||
admin.external_id,
|
||||
'v2.0',
|
||||
'v3.0',
|
||||
);
|
||||
const user = await getUser(source, admin.id);
|
||||
|
||||
expect(user.accepted_eula_version).toBe('v2.0');
|
||||
expect(user.accepted_dpa_version).toBe('v3.0');
|
||||
});
|
||||
|
||||
it('パラメータが不在のときエラーとなる(第五)', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const { admin } = await makeTestAccount(source, {
|
||||
tier: 5,
|
||||
});
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
await expect(
|
||||
service.updateAcceptedVersion(context, admin.external_id, undefined),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
|
||||
it('パラメータが不在のときエラーとなる(第一~第四)', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const { admin } = await makeTestAccount(source, {
|
||||
tier: 4,
|
||||
});
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
await expect(
|
||||
service.updateAcceptedVersion(
|
||||
context,
|
||||
admin.external_id,
|
||||
'v2.0',
|
||||
undefined,
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -4,7 +4,7 @@ import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { isVerifyError, verify } from '../../common/jwt';
|
||||
import { getPublicKey } from '../../common/jwt/jwt';
|
||||
import { makePassword } from '../../common/password/password';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import { AccessToken, IDToken } from '../../common/token';
|
||||
import {
|
||||
SortDirection,
|
||||
TaskListSortableAttribute,
|
||||
@ -30,6 +30,7 @@ import {
|
||||
EmailAlreadyVerifiedError,
|
||||
EncryptionPasswordNeedError,
|
||||
InvalidRoleChangeError,
|
||||
UpdateTermsVersionNotSetError,
|
||||
UserNotFoundError,
|
||||
} from '../../repositories/users/errors/types';
|
||||
import {
|
||||
@ -967,4 +968,58 @@ export class UsersService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同意済み利用規約バージョンを更新する
|
||||
* @param context
|
||||
* @param idToken
|
||||
* @param eulaVersion
|
||||
* @param dpaVersion
|
||||
*/
|
||||
async updateAcceptedVersion(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
eulaVersion: string,
|
||||
dpaVersion?: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateAcceptedVersion.name} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`eulaVersion: ${eulaVersion}, ` +
|
||||
`dpaVersion: ${dpaVersion}, };`,
|
||||
);
|
||||
|
||||
try {
|
||||
await this.usersRepository.updateAcceptedTermsVersion(
|
||||
externalId,
|
||||
eulaVersion,
|
||||
dpaVersion,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010204'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
case UpdateTermsVersionNotSetError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010001'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateAcceptedVersion.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -34,6 +35,7 @@ import { retrieveAuthorizationToken } from '../../common/http/helper';
|
||||
import { Request } from 'express';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { WorkflowsService } from './workflows.service';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
@ApiTags('workflows')
|
||||
@Controller('workflows')
|
||||
@ -64,8 +66,22 @@ export class WorkflowsController {
|
||||
@UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] }))
|
||||
@Get()
|
||||
async getWorkflows(@Req() req: Request): Promise<GetWorkflowsResponse> {
|
||||
const token = retrieveAuthorizationToken(req);
|
||||
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
|
||||
// TODO strictNullChecks対応
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
|
||||
@ -107,17 +123,31 @@ export class WorkflowsController {
|
||||
@Body() body: CreateWorkflowsRequest,
|
||||
): Promise<CreateWorkflowsResponse> {
|
||||
const { authorId, worktypeId, templateId, typists } = body;
|
||||
const token = retrieveAuthorizationToken(req);
|
||||
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
|
||||
// TODO strictNullChecks対応
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
await this.workflowsService.createWorkflow(
|
||||
context,
|
||||
userId,
|
||||
authorId,
|
||||
typists,
|
||||
worktypeId,
|
||||
templateId,
|
||||
typists,
|
||||
);
|
||||
|
||||
return {};
|
||||
@ -158,8 +188,22 @@ export class WorkflowsController {
|
||||
): Promise<UpdateWorkflowResponse> {
|
||||
const { authorId, worktypeId, templateId, typists } = body;
|
||||
const { workflowId } = param;
|
||||
const token = retrieveAuthorizationToken(req);
|
||||
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
|
||||
// TODO strictNullChecks対応
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
await this.workflowsService.updateWorkflow(
|
||||
@ -167,9 +211,9 @@ export class WorkflowsController {
|
||||
userId,
|
||||
workflowId,
|
||||
authorId,
|
||||
typists,
|
||||
worktypeId,
|
||||
templateId,
|
||||
typists,
|
||||
);
|
||||
|
||||
return {};
|
||||
@ -208,8 +252,22 @@ export class WorkflowsController {
|
||||
@Param() param: DeleteWorkflowRequestParam,
|
||||
): Promise<DeleteWorkflowResponse> {
|
||||
const { workflowId } = param;
|
||||
const token = retrieveAuthorizationToken(req);
|
||||
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
|
||||
// TODO strictNullChecks対応
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
await this.workflowsService.deleteWorkflow(context, userId, workflowId);
|
||||
|
||||
@ -21,7 +21,7 @@ import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
describe('getWorkflows', () => {
|
||||
let source: DataSource = null;
|
||||
let source: DataSource | null = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
@ -34,12 +34,15 @@ describe('getWorkflows', () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (!source) return;
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('アカウント内のWorkflow一覧を取得できる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -149,10 +152,10 @@ describe('getWorkflows', () => {
|
||||
expect(resWorkflows[0].id).toBe(workflow1.id);
|
||||
expect(resWorkflows[0].author.id).toBe(authorId1);
|
||||
expect(resWorkflows[0].author.authorId).toBe('AUTHOR1');
|
||||
expect(resWorkflows[0].worktype.id).toBe(worktypeId1);
|
||||
expect(resWorkflows[0].worktype.worktypeId).toBe('worktype1');
|
||||
expect(resWorkflows[0].template.id).toBe(templateId1);
|
||||
expect(resWorkflows[0].template.fileName).toBe('fileName1');
|
||||
expect(resWorkflows[0].worktype?.id).toBe(worktypeId1);
|
||||
expect(resWorkflows[0].worktype?.worktypeId).toBe('worktype1');
|
||||
expect(resWorkflows[0].template?.id).toBe(templateId1);
|
||||
expect(resWorkflows[0].template?.fileName).toBe('fileName1');
|
||||
expect(resWorkflows[0].typists.length).toBe(1);
|
||||
expect(resWorkflows[0].typists[0].typistUserId).toBe(typistId);
|
||||
expect(resWorkflows[0].typists[0].typistName).toBe('typist1');
|
||||
@ -161,8 +164,8 @@ describe('getWorkflows', () => {
|
||||
expect(resWorkflows[1].author.id).toBe(authorId2);
|
||||
expect(resWorkflows[1].author.authorId).toBe('AUTHOR2');
|
||||
expect(resWorkflows[1].worktype).toBe(undefined);
|
||||
expect(resWorkflows[1].template.id).toBe(templateId1);
|
||||
expect(resWorkflows[1].template.fileName).toBe('fileName1');
|
||||
expect(resWorkflows[1].template?.id).toBe(templateId1);
|
||||
expect(resWorkflows[1].template?.fileName).toBe('fileName1');
|
||||
expect(resWorkflows[1].typists.length).toBe(1);
|
||||
expect(resWorkflows[1].typists[0].typistGroupId).toBe(userGroupId);
|
||||
expect(resWorkflows[1].typists[0].typistName).toBe('group1');
|
||||
@ -170,8 +173,8 @@ describe('getWorkflows', () => {
|
||||
expect(resWorkflows[2].id).toBe(workflow3.id);
|
||||
expect(resWorkflows[2].author.id).toBe(authorId3);
|
||||
expect(resWorkflows[2].author.authorId).toBe('AUTHOR3');
|
||||
expect(resWorkflows[2].worktype.id).toBe(worktypeId1);
|
||||
expect(resWorkflows[2].worktype.worktypeId).toBe('worktype1');
|
||||
expect(resWorkflows[2].worktype?.id).toBe(worktypeId1);
|
||||
expect(resWorkflows[2].worktype?.worktypeId).toBe('worktype1');
|
||||
expect(resWorkflows[2].template).toBe(undefined);
|
||||
expect(resWorkflows[2].typists.length).toBe(1);
|
||||
expect(resWorkflows[2].typists[0].typistGroupId).toBe(userGroupId);
|
||||
@ -180,7 +183,9 @@ describe('getWorkflows', () => {
|
||||
});
|
||||
|
||||
it('アカウント内のWorkflow一覧を取得できる(0件)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
@ -200,7 +205,9 @@ describe('getWorkflows', () => {
|
||||
});
|
||||
|
||||
it('DBアクセスに失敗した場合、500エラーを返却する', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
@ -228,7 +235,7 @@ describe('getWorkflows', () => {
|
||||
});
|
||||
|
||||
describe('createWorkflows', () => {
|
||||
let source: DataSource = null;
|
||||
let source: DataSource | null = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
@ -240,12 +247,15 @@ describe('createWorkflows', () => {
|
||||
return source.initialize();
|
||||
});
|
||||
afterEach(async () => {
|
||||
if (!source) return;
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDあり、テンプレートファイルあり)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -288,13 +298,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -314,7 +324,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDなし、テンプレートファイルあり)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -351,13 +363,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
undefined,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
templateId,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -377,7 +389,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDあり、テンプレートファイルなし)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -413,13 +427,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
worktypeId,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
undefined,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -439,7 +453,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDなし、テンプレートファイルなし)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -469,13 +485,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
undefined,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -495,7 +511,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDなし、テンプレートファイルなし、同一AuthorIDのワークフローあり)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -532,26 +550,26 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
worktypeId,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
undefined,
|
||||
);
|
||||
|
||||
await service.createWorkflow(
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
undefined,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -571,7 +589,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('DBにAuthorが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
@ -611,13 +631,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
0,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -630,7 +650,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('DBにWorktypeIDが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -669,13 +691,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
9999,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
9999,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -688,7 +710,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('DBにテンプレートファイルが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -726,13 +750,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
worktypeId,
|
||||
9999,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
9999,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -745,7 +769,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('DBにルーティング候補ユーザーが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -785,13 +811,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: 9999,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -804,7 +830,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('DBにルーティング候補グループが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -844,13 +872,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistGroupId: 9999,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -863,7 +891,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('DBにAuthorIDとWorktypeIDのペアがすでに存在する場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -912,13 +942,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -931,7 +961,9 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
it('DBアクセスに失敗した場合、500エラーを返却する', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
@ -984,13 +1016,13 @@ describe('createWorkflows', () => {
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -1004,7 +1036,7 @@ describe('createWorkflows', () => {
|
||||
});
|
||||
|
||||
describe('updateWorkflow', () => {
|
||||
let source: DataSource = null;
|
||||
let source: DataSource | null = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
@ -1016,12 +1048,15 @@ describe('updateWorkflow', () => {
|
||||
return source.initialize();
|
||||
});
|
||||
afterEach(async () => {
|
||||
if (!source) return;
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('アカウント内のWorkflowを更新できる(WorktypeIDあり、テンプレートファイルあり)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1090,13 +1125,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId2,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId2,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -1115,7 +1150,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDなし、テンプレートファイルあり)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1178,13 +1215,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId2,
|
||||
undefined,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId2,
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
templateId,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -1203,7 +1240,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDあり、テンプレートファイルなし)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1265,13 +1304,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId2,
|
||||
worktypeId,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId2,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
undefined,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -1290,7 +1329,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDなし、テンプレートファイルなし)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1346,13 +1387,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId2,
|
||||
undefined,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId2,
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -1371,7 +1412,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('アカウント内にWorkflowを作成できる(WorktypeIDなし、テンプレートファイルなし、同一AuthorIDのワークフローあり)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1447,13 +1490,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow1.id,
|
||||
authorId2,
|
||||
undefined,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId2,
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
@ -1472,7 +1515,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('DBにWorkflowが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1497,13 +1542,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
9999,
|
||||
authorId1,
|
||||
undefined,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId1,
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -1515,7 +1560,9 @@ describe('updateWorkflow', () => {
|
||||
}
|
||||
});
|
||||
it('DBにAuthorが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1568,13 +1615,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
9999,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId1,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -1587,7 +1634,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('DBにWorktypeIDが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1634,13 +1683,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId1,
|
||||
9999,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: typistId1,
|
||||
},
|
||||
],
|
||||
9999,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -1653,7 +1702,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('DBにテンプレートファイルが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1699,13 +1750,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId1,
|
||||
worktypeId,
|
||||
9999,
|
||||
[
|
||||
{
|
||||
typistId: typistId1,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
9999,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -1718,7 +1769,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('DBにルーティング候補ユーザーが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1771,13 +1824,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId1,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistId: 9999,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -1790,7 +1843,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('DBにルーティング候補グループが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1843,13 +1898,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId1,
|
||||
worktypeId,
|
||||
templateId,
|
||||
[
|
||||
{
|
||||
typistGroupId: 9999,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -1862,7 +1917,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('DBにAuthorIDとWorktypeIDのペアがすでに存在する場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1909,13 +1966,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId1,
|
||||
worktypeId1,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId1,
|
||||
},
|
||||
],
|
||||
worktypeId1,
|
||||
undefined,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
@ -1928,7 +1985,9 @@ describe('updateWorkflow', () => {
|
||||
});
|
||||
|
||||
it('DBアクセスに失敗した場合、500エラーを返却する', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
@ -1983,13 +2042,13 @@ describe('updateWorkflow', () => {
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId1,
|
||||
undefined,
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
typistId: typistId1,
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
WorkflowNotFoundError,
|
||||
} from '../../repositories/workflows/errors/types';
|
||||
import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
|
||||
import { Assignee } from '../tasks/types/types';
|
||||
|
||||
@Injectable()
|
||||
export class WorkflowsService {
|
||||
@ -47,15 +48,20 @@ export class WorkflowsService {
|
||||
|
||||
// ワークフロー一覧からtypistのexternalIdを取得
|
||||
const externalIds = workflowRecords.flatMap((workflow) => {
|
||||
const workflowTypists = workflow.workflowTypists.flatMap(
|
||||
const workflowTypists = workflow.workflowTypists?.flatMap(
|
||||
(workflowTypist) => {
|
||||
const { typist } = workflowTypist;
|
||||
return typist ? [typist?.external_id] : [];
|
||||
return typist ? [typist.external_id] : [];
|
||||
},
|
||||
);
|
||||
return workflowTypists;
|
||||
});
|
||||
const distinctedExternalIds = [...new Set(externalIds)];
|
||||
// externalIdsからundefinedを除外
|
||||
const filteredExternalIds = externalIds.filter(
|
||||
(externalId): externalId is string => externalId !== undefined,
|
||||
);
|
||||
// externalIdsから重複を除外
|
||||
const distinctedExternalIds = [...new Set(filteredExternalIds)];
|
||||
|
||||
// ADB2Cからユーザー一覧を取得
|
||||
const adb2cUsers = await this.adB2cService.getUsers(
|
||||
@ -64,8 +70,11 @@ export class WorkflowsService {
|
||||
);
|
||||
|
||||
// DBから取得したワークフロー一覧を整形
|
||||
const workflows = workflowRecords.map((workflow) => {
|
||||
const workflows = workflowRecords.map((workflow): Workflow => {
|
||||
const { id, author, worktype, template, workflowTypists } = workflow;
|
||||
if (!author || !author.id || !author.author_id) {
|
||||
throw new Error('author is undefined');
|
||||
}
|
||||
|
||||
const authorId = { id: author.id, authorId: author.author_id };
|
||||
const worktypeId = worktype
|
||||
@ -75,16 +84,24 @@ export class WorkflowsService {
|
||||
? { id: template.id, fileName: template.file_name }
|
||||
: undefined;
|
||||
|
||||
if (!workflowTypists) {
|
||||
throw new Error('workflowTypists is undefined');
|
||||
}
|
||||
|
||||
// ルーティング候補を整形
|
||||
const typists = workflowTypists.map((workflowTypist) => {
|
||||
const typists = workflowTypists.map((workflowTypist): Assignee => {
|
||||
const { typist, typistGroup } = workflowTypist;
|
||||
|
||||
// typistがユーザーの場合はADB2Cからユーザー名を取得
|
||||
const typistName = typist
|
||||
? adb2cUsers.find(
|
||||
(adb2cUser) => adb2cUser.id === typist.external_id,
|
||||
).displayName
|
||||
: typistGroup.name;
|
||||
)?.displayName
|
||||
: typistGroup?.name;
|
||||
|
||||
if (!typistName) {
|
||||
throw new Error('typistName is undefined');
|
||||
}
|
||||
|
||||
return {
|
||||
typistUserId: typist?.id,
|
||||
@ -130,9 +147,9 @@ export class WorkflowsService {
|
||||
context: Context,
|
||||
externalId: string,
|
||||
authorId: number,
|
||||
typists: WorkflowTypist[],
|
||||
worktypeId?: number | undefined,
|
||||
templateId?: number | undefined,
|
||||
typists?: WorkflowTypist[],
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.createWorkflow.name} | | params: { ` +
|
||||
@ -149,9 +166,9 @@ export class WorkflowsService {
|
||||
await this.workflowsRepository.createtWorkflows(
|
||||
accountId,
|
||||
authorId,
|
||||
typists,
|
||||
worktypeId,
|
||||
templateId,
|
||||
typists,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
@ -215,9 +232,9 @@ export class WorkflowsService {
|
||||
externalId: string,
|
||||
workflowId: number,
|
||||
authorId: number,
|
||||
typists: WorkflowTypist[],
|
||||
worktypeId?: number | undefined,
|
||||
templateId?: number | undefined,
|
||||
typists?: WorkflowTypist[],
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateWorkflow.name} | params: { ` +
|
||||
@ -236,9 +253,9 @@ export class WorkflowsService {
|
||||
accountId,
|
||||
workflowId,
|
||||
authorId,
|
||||
typists,
|
||||
worktypeId,
|
||||
templateId,
|
||||
typists,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
|
||||
@ -30,17 +30,18 @@ export const isConflictError = (arg: unknown): arg is ConflictError => {
|
||||
@Injectable()
|
||||
export class AdB2cService {
|
||||
private readonly logger = new Logger(AdB2cService.name);
|
||||
private readonly tenantName = this.configService.get<string>('TENANT_NAME');
|
||||
private readonly tenantName =
|
||||
this.configService.getOrThrow<string>('TENANT_NAME');
|
||||
private readonly flowName =
|
||||
this.configService.get<string>('SIGNIN_FLOW_NAME');
|
||||
this.configService.getOrThrow<string>('SIGNIN_FLOW_NAME');
|
||||
private graphClient: Client;
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
// ADB2Cへの認証情報
|
||||
const credential = new ClientSecretCredential(
|
||||
this.configService.get('ADB2C_TENANT_ID'),
|
||||
this.configService.get('ADB2C_CLIENT_ID'),
|
||||
this.configService.get('ADB2C_CLIENT_SECRET'),
|
||||
this.configService.getOrThrow<string>('ADB2C_TENANT_ID'),
|
||||
this.configService.getOrThrow('ADB2C_CLIENT_ID'),
|
||||
this.configService.getOrThrow('ADB2C_CLIENT_SECRET'),
|
||||
);
|
||||
const authProvider = new TokenCredentialAuthenticationProvider(credential, {
|
||||
scopes: ['https://graph.microsoft.com/.default'],
|
||||
|
||||
@ -28,31 +28,31 @@ export class BlobstorageService {
|
||||
private readonly sasTokenExpireHour: number;
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.sharedKeyCredentialUS = new StorageSharedKeyCredential(
|
||||
this.configService.get('STORAGE_ACCOUNT_NAME_US'),
|
||||
this.configService.get('STORAGE_ACCOUNT_KEY_US'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_NAME_US'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_KEY_US'),
|
||||
);
|
||||
this.sharedKeyCredentialAU = new StorageSharedKeyCredential(
|
||||
this.configService.get('STORAGE_ACCOUNT_NAME_AU'),
|
||||
this.configService.get('STORAGE_ACCOUNT_KEY_AU'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_NAME_AU'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_KEY_AU'),
|
||||
);
|
||||
this.sharedKeyCredentialEU = new StorageSharedKeyCredential(
|
||||
this.configService.get('STORAGE_ACCOUNT_NAME_EU'),
|
||||
this.configService.get('STORAGE_ACCOUNT_KEY_EU'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_NAME_EU'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_KEY_EU'),
|
||||
);
|
||||
this.blobServiceClientUS = new BlobServiceClient(
|
||||
this.configService.get('STORAGE_ACCOUNT_ENDPOINT_US'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_ENDPOINT_US'),
|
||||
this.sharedKeyCredentialUS,
|
||||
);
|
||||
this.blobServiceClientAU = new BlobServiceClient(
|
||||
this.configService.get('STORAGE_ACCOUNT_ENDPOINT_AU'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_ENDPOINT_AU'),
|
||||
this.sharedKeyCredentialAU,
|
||||
);
|
||||
this.blobServiceClientEU = new BlobServiceClient(
|
||||
this.configService.get('STORAGE_ACCOUNT_ENDPOINT_EU'),
|
||||
this.configService.getOrThrow<string>('STORAGE_ACCOUNT_ENDPOINT_EU'),
|
||||
this.sharedKeyCredentialEU,
|
||||
);
|
||||
this.sasTokenExpireHour = Number(
|
||||
this.configService.get('STORAGE_TOKEN_EXPIRE_TIME'),
|
||||
this.sasTokenExpireHour = this.configService.getOrThrow<number>(
|
||||
'STORAGE_TOKEN_EXPIRE_TIME',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -18,8 +18,8 @@ export class NotificationhubService {
|
||||
private readonly client: NotificationHubsClient;
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.client = new NotificationHubsClient(
|
||||
this.configService.get<string>('NOTIFICATION_HUB_CONNECT_STRING'),
|
||||
this.configService.get<string>('NOTIFICATION_HUB_NAME'),
|
||||
this.configService.getOrThrow<string>('NOTIFICATION_HUB_CONNECT_STRING'),
|
||||
this.configService.getOrThrow<string>('NOTIFICATION_HUB_NAME'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import { Context } from '../../common/log';
|
||||
export class SendGridService {
|
||||
private readonly logger = new Logger(SendGridService.name);
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
const key = this.configService.get<string>('SENDGRID_API_KEY');
|
||||
const key = this.configService.getOrThrow<string>('SENDGRID_API_KEY');
|
||||
sendgrid.setApiKey(key);
|
||||
}
|
||||
|
||||
|
||||
@ -5,14 +5,15 @@ import { AppModule } from './app.module';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import helmet from 'helmet';
|
||||
const helmetDirectives = helmet.contentSecurityPolicy.getDefaultDirectives();
|
||||
|
||||
helmetDirectives['connect-src'] =
|
||||
process.env.STAGE === 'local'
|
||||
? [
|
||||
"'self'",
|
||||
process.env.ADB2C_ORIGIN,
|
||||
process.env.STORAGE_ACCOUNT_ENDPOINT_US,
|
||||
process.env.STORAGE_ACCOUNT_ENDPOINT_AU,
|
||||
process.env.STORAGE_ACCOUNT_ENDPOINT_EU,
|
||||
process.env.ADB2C_ORIGIN ?? '',
|
||||
process.env.STORAGE_ACCOUNT_ENDPOINT_US ?? '',
|
||||
process.env.STORAGE_ACCOUNT_ENDPOINT_AU ?? '',
|
||||
process.env.STORAGE_ACCOUNT_ENDPOINT_EU ?? '',
|
||||
]
|
||||
: ["'self'"];
|
||||
|
||||
|
||||
@ -336,7 +336,7 @@ export class TasksRepositoryService {
|
||||
await taskRepo.update(
|
||||
{ audio_file_id: audio_file_id },
|
||||
{
|
||||
typist_user: null,
|
||||
typist_user_id: null,
|
||||
status: TASK_STATUS.UPLOADED,
|
||||
},
|
||||
);
|
||||
|
||||
@ -19,13 +19,13 @@ export class TemplateFile {
|
||||
@Column()
|
||||
file_name: string;
|
||||
@Column({ nullable: true })
|
||||
created_by?: string;
|
||||
created_by: string | null;
|
||||
@CreateDateColumn()
|
||||
created_at: Date;
|
||||
@Column({ nullable: true })
|
||||
updated_by?: string;
|
||||
updated_by: string | null;
|
||||
@UpdateDateColumn()
|
||||
updated_at: Date;
|
||||
@OneToMany(() => Task, (task) => task.template_file)
|
||||
tasks?: Task[];
|
||||
tasks: Task[] | null;
|
||||
}
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Term } from './entity/term.entity';
|
||||
import { TermsRepositoryService } from './terms.repository.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Term])],
|
||||
providers: [TermsRepositoryService],
|
||||
exports: [TermsRepositoryService],
|
||||
})
|
||||
export class TermsRepositoryModule {}
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { TermsVersion } from '../../features/terms/types/types';
|
||||
import { Term } from './entity/term.entity';
|
||||
import { TERM_TYPE } from '../../constants';
|
||||
import { TermInfoNotFoundError } from '../users/errors/types';
|
||||
|
||||
@Injectable()
|
||||
export class TermsRepositoryService {
|
||||
constructor(private dataSource: DataSource) {}
|
||||
|
||||
/*
|
||||
* 利用規約の最新バージョンを取得する
|
||||
* @returns Term[]
|
||||
*/
|
||||
async getLatestTermsInfo(): Promise<TermsVersion> {
|
||||
return await this.dataSource.transaction(async (entityManager) => {
|
||||
const termRepo = entityManager.getRepository(Term);
|
||||
const latestEulaInfo = await termRepo.findOne({
|
||||
where: {
|
||||
document_type: TERM_TYPE.EULA,
|
||||
},
|
||||
order: {
|
||||
id: 'DESC',
|
||||
},
|
||||
});
|
||||
const latestDpaInfo = await termRepo.findOne({
|
||||
where: {
|
||||
document_type: TERM_TYPE.DPA,
|
||||
},
|
||||
order: {
|
||||
id: 'DESC',
|
||||
},
|
||||
});
|
||||
|
||||
if (!latestEulaInfo || !latestDpaInfo) {
|
||||
throw new TermInfoNotFoundError(
|
||||
`Terms info is not found. latestEulaInfo: ${latestEulaInfo}, latestDpaInfo: ${latestDpaInfo}`,
|
||||
);
|
||||
}
|
||||
return {
|
||||
eulaVersion: latestEulaInfo.version,
|
||||
dpaVersion: latestDpaInfo.version,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -10,3 +10,5 @@ export class InvalidRoleChangeError extends Error {}
|
||||
export class EncryptionPasswordNeedError extends Error {}
|
||||
// 利用規約バージョン情報不在エラー
|
||||
export class TermInfoNotFoundError extends Error {}
|
||||
// 利用規約バージョンパラメータ不在エラー
|
||||
export class UpdateTermsVersionNotSetError extends Error {}
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
InvalidRoleChangeError,
|
||||
EncryptionPasswordNeedError,
|
||||
TermInfoNotFoundError,
|
||||
UpdateTermsVersionNotSetError,
|
||||
} from './errors/types';
|
||||
import {
|
||||
LICENSE_ALLOCATED_STATUS,
|
||||
@ -475,4 +476,49 @@ export class UsersRepositoryService {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 同意済み利用規約のバージョンを更新する
|
||||
* @param externalId
|
||||
* @param eulaVersion
|
||||
* @param dpaVersion
|
||||
* @returns update
|
||||
*/
|
||||
async updateAcceptedTermsVersion(
|
||||
externalId: string,
|
||||
eulaVersion: string,
|
||||
dpaVersion: string | undefined,
|
||||
): Promise<void> {
|
||||
await this.dataSource.transaction(async (entityManager) => {
|
||||
const userRepo = entityManager.getRepository(User);
|
||||
const user = await userRepo.findOne({
|
||||
where: {
|
||||
external_id: externalId,
|
||||
},
|
||||
relations: {
|
||||
account: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new UserNotFoundError(
|
||||
`User not found. externalId: ${externalId}`,
|
||||
);
|
||||
}
|
||||
|
||||
// パラメータが不在の場合はエラーを返却
|
||||
if (!eulaVersion) {
|
||||
throw new UpdateTermsVersionNotSetError(`EULA version param not set.`);
|
||||
}
|
||||
if (user.account.tier !== TIERS.TIER5 && !dpaVersion) {
|
||||
throw new UpdateTermsVersionNotSetError(
|
||||
`DPA version param not set. User's tier: ${user.account.tier}`,
|
||||
);
|
||||
}
|
||||
|
||||
user.accepted_eula_version = eulaVersion;
|
||||
user.accepted_dpa_version = dpaVersion ?? user.accepted_dpa_version;
|
||||
await userRepo.update({ id: user.id }, user);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,35 +25,35 @@ export class Workflow {
|
||||
author_id: number;
|
||||
|
||||
@Column({ nullable: true })
|
||||
worktype_id?: number;
|
||||
worktype_id: number | null;
|
||||
|
||||
@Column({ nullable: true })
|
||||
template_id?: number;
|
||||
template_id: number | null;
|
||||
|
||||
@Column({ nullable: true })
|
||||
created_by: string;
|
||||
created_by: string | null;
|
||||
|
||||
@CreateDateColumn({ default: () => "datetime('now', 'localtime')" }) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||
created_at: Date;
|
||||
|
||||
@Column({ nullable: true })
|
||||
updated_by?: string;
|
||||
updated_by: string | null;
|
||||
|
||||
@UpdateDateColumn({ default: () => "datetime('now', 'localtime')" }) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||
updated_at: Date;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.id)
|
||||
@JoinColumn({ name: 'author_id' })
|
||||
author?: User;
|
||||
author: User | null;
|
||||
|
||||
@ManyToOne(() => Worktype, (worktype) => worktype.id)
|
||||
@JoinColumn({ name: 'worktype_id' })
|
||||
worktype?: Worktype;
|
||||
worktype: Worktype | null;
|
||||
|
||||
@ManyToOne(() => TemplateFile, (templateFile) => templateFile.id)
|
||||
@JoinColumn({ name: 'template_id' })
|
||||
template?: TemplateFile;
|
||||
template: TemplateFile | null;
|
||||
|
||||
@OneToMany(() => WorkflowTypist, (workflowTypist) => workflowTypist.workflow)
|
||||
workflowTypists?: WorkflowTypist[];
|
||||
workflowTypists: WorkflowTypist[] | null;
|
||||
}
|
||||
|
||||
@ -61,9 +61,9 @@ export class WorkflowsRepositoryService {
|
||||
async createtWorkflows(
|
||||
accountId: number,
|
||||
authorId: number,
|
||||
typists: WorkflowTypist[],
|
||||
worktypeId?: number | undefined,
|
||||
templateId?: number | undefined,
|
||||
typists?: WorkflowTypist[],
|
||||
): Promise<void> {
|
||||
return await this.dataSource.transaction(async (entityManager) => {
|
||||
// authorの存在確認
|
||||
@ -178,9 +178,9 @@ export class WorkflowsRepositoryService {
|
||||
accountId: number,
|
||||
workflowId: number,
|
||||
authorId: number,
|
||||
typists: WorkflowTypist[],
|
||||
worktypeId?: number | undefined,
|
||||
templateId?: number | undefined,
|
||||
typists?: WorkflowTypist[],
|
||||
): Promise<void> {
|
||||
return await this.dataSource.transaction(async (entityManager) => {
|
||||
const workflowRepo = entityManager.getRepository(Workflow);
|
||||
@ -343,8 +343,8 @@ export class WorkflowsRepositoryService {
|
||||
const workflow = new Workflow();
|
||||
workflow.account_id = accountId;
|
||||
workflow.author_id = authorId;
|
||||
workflow.worktype_id = worktypeId;
|
||||
workflow.template_id = templateId;
|
||||
workflow.worktype_id = worktypeId ?? null;
|
||||
workflow.template_id = templateId ?? null;
|
||||
|
||||
return workflow;
|
||||
}
|
||||
@ -358,8 +358,8 @@ export class WorkflowsRepositoryService {
|
||||
*/
|
||||
private makeWorkflowTypist(
|
||||
workflowId: number,
|
||||
typistId: number,
|
||||
typistGroupId: number,
|
||||
typistId?: number,
|
||||
typistGroupId?: number,
|
||||
): DbWorkflowTypist {
|
||||
const workflowTypist = new DbWorkflowTypist();
|
||||
workflowTypist.workflow_id = workflowId;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user