Merged PR 489: API作成(利用規約情報取得API)

## 概要
[Task2808: API作成(利用規約情報取得API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2808)

利用規約情報取得APIを作成しました。

## レビューポイント
なし

## UIの変更
なし

## 動作確認状況
UT、ローカルで動作確認済み

## 補足
なし
This commit is contained in:
oura.a 2023-10-13 06:36:57 +00:00
parent 69ff6f3432
commit 162470838d
9 changed files with 188 additions and 22 deletions

View File

@ -34,6 +34,9 @@ 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,
@ -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) => {

View File

@ -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);
});

View File

@ -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 };
}

View File

@ -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 {}

View File

@ -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,
),
);
});
});

View File

@ -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}`,
);
}
}
}

View File

@ -10,3 +10,8 @@ export class GetTermsInfoResponse {
@ApiProperty({ type: [TermInfo] })
termsInfo: TermInfo[];
}
export type TermsVersion = {
eulaVersion: string;
dpaVersion: string;
};

View File

@ -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 {}

View File

@ -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,
};
});
}
}