Merge branch 'develop' into main

This commit is contained in:
iwata 2023-09-22 14:25:14 +09:00
commit 409a021cdb
14 changed files with 242 additions and 33 deletions

View File

@ -7,9 +7,9 @@
}, },
"scripts": { "scripts": {
"start": "vite", "start": "vite",
"build": "tsc && vite build && cp -r static_contents/. build/", "build": "tsc && vite build",
"build:prod": "tsc && vite build && cp -r static_contents/. build/", "build:prod": "tsc && vite build",
"build:local": "tsc && vite build && cp -r static_contents/. build/ && sh localdeploy.sh", "build:local": "tsc && vite build && sh localdeploy.sh",
"preview": "vite preview", "preview": "vite preview",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"codegen": "sh codegen.sh", "codegen": "sh codegen.sh",
@ -96,4 +96,4 @@
} }
] ]
} }
} }

View File

@ -1 +0,0 @@
YOweYATRY5PBN1G9dHDpfWLbSeVvGNpe61DtYdLSC82pqmPNyIw8EHXwTa6o4iNQB5rNSa

View File

@ -3792,7 +3792,7 @@
"properties": { "url": { "type": "string" } }, "properties": { "url": { "type": "string" } },
"required": ["url"] "required": ["url"]
}, },
"TemplateFile": { "TemplateUploadFinishedRequest": {
"type": "object", "type": "object",
"properties": { "properties": {
"name": { "name": {
@ -3801,21 +3801,11 @@
}, },
"url": { "url": {
"type": "string", "type": "string",
"description": "テンプレートファイルのURL" "description": "テンプレートファイルのアップロード先URL"
} }
}, },
"required": ["name", "url"] "required": ["name", "url"]
}, },
"TemplateUploadFinishedRequest": {
"type": "object",
"properties": {
"templateFile": {
"description": "テンプレートファイルのファイル情報",
"allOf": [{ "$ref": "#/components/schemas/TemplateFile" }]
}
},
"required": ["templateFile"]
},
"TemplateUploadFinishedReqponse": { "type": "object", "properties": {} }, "TemplateUploadFinishedReqponse": { "type": "object", "properties": {} },
"Assignee": { "Assignee": {
"type": "object", "type": "object",
@ -4023,6 +4013,17 @@
"required": ["poNumber"] "required": ["poNumber"]
}, },
"CancelOrderResponse": { "type": "object", "properties": {} }, "CancelOrderResponse": { "type": "object", "properties": {} },
"TemplateFile": {
"type": "object",
"properties": {
"id": { "type": "number", "description": "テンプレートファイルのID" },
"name": {
"type": "string",
"description": "テンプレートファイルのファイル名"
}
},
"required": ["id", "name"]
},
"GetTemplatesResponse": { "GetTemplatesResponse": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -30,6 +30,8 @@ import { NotificationhubService } from '../../gateways/notificationhub/notificat
import { FilesService } from '../../features/files/files.service'; import { FilesService } from '../../features/files/files.service';
import { LicensesService } from '../../features/licenses/licenses.service'; import { LicensesService } from '../../features/licenses/licenses.service';
import { TasksService } from '../../features/tasks/tasks.service'; import { TasksService } from '../../features/tasks/tasks.service';
import { TemplatesService } from '../../features/templates/templates.service';
import { TemplatesModule } from '../../features/templates/templates.module';
export const makeTestingModule = async ( export const makeTestingModule = async (
datasource: DataSource, datasource: DataSource,
@ -50,6 +52,7 @@ export const makeTestingModule = async (
UsersModule, UsersModule,
SendGridModule, SendGridModule,
LicensesModule, LicensesModule,
TemplatesModule,
AccountsRepositoryModule, AccountsRepositoryModule,
UsersRepositoryModule, UsersRepositoryModule,
LicensesRepositoryModule, LicensesRepositoryModule,
@ -74,6 +77,7 @@ export const makeTestingModule = async (
FilesService, FilesService,
TasksService, TasksService,
LicensesService, LicensesService,
TemplatesService,
], ],
}) })
.useMocker(async (token) => { .useMocker(async (token) => {

View File

@ -331,13 +331,14 @@ export class FilesController {
@Req() req: Request, @Req() req: Request,
@Body() body: TemplateUploadFinishedRequest, @Body() body: TemplateUploadFinishedRequest,
): Promise<TemplateUploadFinishedReqponse> { ): Promise<TemplateUploadFinishedReqponse> {
const { templateFile } = body; const { name, url } = body;
const token = retrieveAuthorizationToken(req); const token = retrieveAuthorizationToken(req);
const accessToken = jwt.decode(token, { json: true }) as AccessToken; const accessToken = jwt.decode(token, { json: true }) as AccessToken;
const context = makeContext(accessToken.userId); const context = makeContext(accessToken.userId);
console.log(context.trackingId); console.log(context.trackingId);
console.log(templateFile); console.log(name);
console.log(url);
return {}; return {};
} }

View File

@ -1,5 +1,4 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { TemplateFile } from '../../templates/types/types';
export class AudioUploadLocationRequest {} export class AudioUploadLocationRequest {}
@ -95,8 +94,10 @@ export class AudioUploadFinishedResponse {
} }
export class TemplateUploadFinishedRequest { export class TemplateUploadFinishedRequest {
@ApiProperty({ description: 'テンプレートファイルのファイル情報' }) @ApiProperty({ description: 'テンプレートファイルのファイル名' })
templateFile: TemplateFile; name: string;
@ApiProperty({ description: 'テンプレートファイルのアップロード先URL' })
url: string;
} }
export class TemplateUploadFinishedReqponse {} export class TemplateUploadFinishedReqponse {}

View File

@ -47,11 +47,11 @@ export class TemplatesController {
@Get() @Get()
async getTemplates(@Req() req: Request): Promise<GetTemplatesResponse> { async getTemplates(@Req() req: Request): Promise<GetTemplatesResponse> {
const token = retrieveAuthorizationToken(req); const token = retrieveAuthorizationToken(req);
const accessToken = jwt.decode(token, { json: true }) as AccessToken; const { userId } = jwt.decode(token, { json: true }) as AccessToken;
const context = makeContext(accessToken.userId); const context = makeContext(userId);
console.log(context.trackingId); const templates = await this.templatesService.getTemplates(context, userId);
return { templates: [] }; return { templates };
} }
} }

View File

@ -1,9 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TemplatesController } from './templates.controller'; import { TemplatesController } from './templates.controller';
import { TemplatesService } from './templates.service'; import { TemplatesService } from './templates.service';
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
import { TemplateFilesRepositoryModule } from '../../repositories/template_files/template_files.repository.module';
@Module({ @Module({
imports: [], imports: [UsersRepositoryModule, TemplateFilesRepositoryModule],
providers: [TemplatesService], providers: [TemplatesService],
controllers: [TemplatesController], controllers: [TemplatesController],
}) })

View File

@ -0,0 +1,108 @@
import { DataSource } from 'typeorm';
import { makeTestingModule } from '../../common/test/modules';
import { TemplatesService } from './templates.service';
import { createTemplateFile } from './test/utility';
import { makeTestAccount } from '../../common/test/utility';
import { makeContext } from '../../common/log';
import { TemplateFilesRepositoryService } from '../../repositories/template_files/template_files.repository.service';
import { HttpException, HttpStatus } from '@nestjs/common';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
describe('getTemplates', () => {
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 service = module.get<TemplatesService>(TemplatesService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id);
const template1 = await createTemplateFile(
source,
account.id,
'test1',
'https://url1/test1',
);
const template2 = await createTemplateFile(
source,
account.id,
'test2',
'https://url2/test2',
);
// 作成したデータを確認
{
expect(template1.file_name).toBe('test1');
expect(template2.file_name).toBe('test2');
}
const templates = await service.getTemplates(context, admin.external_id);
//実行結果を確認
{
expect(templates.length).toBe(2);
expect(templates[0].id).toBe(template1.id);
expect(templates[0].name).toBe(template1.file_name);
expect(templates[1].id).toBe(template2.id);
expect(templates[1].name).toBe(template2.file_name);
}
});
it('テンプレートファイル一覧を取得できる0件', async () => {
const module = await makeTestingModule(source);
const service = module.get<TemplatesService>(TemplatesService);
// 第五階層のアカウント作成
const { admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id);
const templates = await service.getTemplates(context, admin.external_id);
//実行結果を確認
{
expect(templates.length).toBe(0);
}
});
it('テンプレートファイル一覧の取得に失敗した場合、エラーとなること', async () => {
const module = await makeTestingModule(source);
const service = module.get<TemplatesService>(TemplatesService);
// 第五階層のアカウント作成
const { admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id);
//DBアクセスに失敗するようにする
const typistGroupService = module.get<TemplateFilesRepositoryService>(
TemplateFilesRepositoryService,
);
typistGroupService.getTemplateFiles = jest
.fn()
.mockRejectedValue('DB failed');
try {
await service.getTemplates(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();
}
}
});
});

View File

@ -1,7 +1,56 @@
import { Injectable, Logger } from '@nestjs/common'; import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
import { TemplateFile } from './types/types';
import { Context } from '../../common/log';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { TemplateFilesRepositoryService } from '../../repositories/template_files/template_files.repository.service';
@Injectable() @Injectable()
export class TemplatesService { export class TemplatesService {
private readonly logger = new Logger(TemplatesService.name); private readonly logger = new Logger(TemplatesService.name);
constructor() {} constructor(
private readonly usersRepository: UsersRepositoryService,
private readonly templateFilesRepository: TemplateFilesRepositoryService,
) {}
/**
*
* @param context
* @param externalId
* @returns templates
*/
async getTemplates(
context: Context,
externalId: string,
): Promise<TemplateFile[]> {
this.logger.log(
`[IN] [${context.trackingId}] ${this.getTemplates.name} | params: { externalId: ${externalId} };`,
);
try {
const { account_id: accountId } =
await this.usersRepository.findUserByExternalId(externalId);
const templateFileRecords =
await this.templateFilesRepository.getTemplateFiles(accountId);
// DBから取得したテンプレートファイルのレコードをレスポンス用に整形する
const resTemplates = templateFileRecords.map((templateFile) => ({
id: templateFile.id,
name: templateFile.file_name,
}));
return resTemplates;
} catch (e) {
this.logger.error(`error=${e}`);
throw new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
);
} finally {
this.logger.log(
`[OUT] [${context.trackingId}] ${this.getTemplates.name}`,
);
}
}
} }

View File

@ -0,0 +1,28 @@
import { DataSource } from 'typeorm';
import { TemplateFile } from '../../../repositories/template_files/entity/template_file.entity';
export const createTemplateFile = async (
datasource: DataSource,
accountId: number,
name: string,
url: string,
): Promise<TemplateFile> => {
const { identifiers } = await datasource.getRepository(TemplateFile).insert({
account_id: accountId,
file_name: name,
url: url,
created_by: 'test_runner',
created_at: new Date(),
updated_by: 'updater',
updated_at: new Date(),
});
const template = identifiers.pop() as TemplateFile;
const templateFile = await datasource.getRepository(TemplateFile).findOne({
where: {
id: template.id,
},
});
return templateFile;
};

View File

@ -1,10 +1,10 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
export class TemplateFile { export class TemplateFile {
@ApiProperty({ description: 'テンプレートファイルのID' })
id: number;
@ApiProperty({ description: 'テンプレートファイルのファイル名' }) @ApiProperty({ description: 'テンプレートファイルのファイル名' })
name: string; name: string;
@ApiProperty({ description: 'テンプレートファイルのURL' })
url: string;
} }
export class GetTemplatesResponse { export class GetTemplatesResponse {

View File

@ -18,8 +18,6 @@ export class TemplateFile {
url: string; url: string;
@Column() @Column()
file_name: string; file_name: string;
@Column({ nullable: true })
deleted_at?: Date;
@Column() @Column()
created_by: string; created_by: string;
@CreateDateColumn() @CreateDateColumn()

View File

@ -1,7 +1,25 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import { TemplateFile } from './entity/template_file.entity';
@Injectable() @Injectable()
export class TemplateFilesRepositoryService { export class TemplateFilesRepositoryService {
constructor(private dataSource: DataSource) {} constructor(private dataSource: DataSource) {}
/**
*
* @param accountId
* @returns template files
*/
async getTemplateFiles(accountId: number): Promise<TemplateFile[]> {
return await this.dataSource.transaction(async (entityManager) => {
const templateFilesRepo = entityManager.getRepository(TemplateFile);
const templates = await templateFilesRepo.find({
where: { account_id: accountId },
});
return templates;
});
}
} }