Skip to content

Commit

Permalink
Merge pull request #90 from line/dev
Browse files Browse the repository at this point in the history
beta release: 3.2349.20-beta
  • Loading branch information
h4l-yup authored Dec 4, 2023
2 parents aed7551 + 4bd157b commit 672f985
Show file tree
Hide file tree
Showing 99 changed files with 4,313 additions and 542 deletions.
1 change: 1 addition & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@nestjs/passport": "^10.0.2",
"@nestjs/platform-express": "^10.2.7",
"@nestjs/platform-fastify": "^10.2.7",
"@nestjs/schedule": "^4.0.0",
"@nestjs/swagger": "^7.1.14",
"@nestjs/terminus": "^10.1.1",
"@nestjs/typeorm": "^10.0.0",
Expand Down
8 changes: 8 additions & 0 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ScheduleModule } from '@nestjs/schedule';
import { PrometheusModule } from '@willsoto/nestjs-prometheus';
import { ClsModule } from 'nestjs-cls';
import { LoggerModule } from 'nestjs-pino';
Expand Down Expand Up @@ -46,6 +47,9 @@ import { IssueModule } from './domains/project/issue/issue.module';
import { MemberModule } from './domains/project/member/member.module';
import { ProjectModule } from './domains/project/project/project.module';
import { RoleModule } from './domains/project/role/role.module';
import { FeedbackIssueStatisticsModule } from './domains/statistics/feedback-issue/feedback-issue-statistics.module';
import { FeedbackStatisticsModule } from './domains/statistics/feedback/feedback-statistics.module';
import { IssueStatisticsModule } from './domains/statistics/issue/issue-statistics.module';
import { TenantModule } from './domains/tenant/tenant.module';
import { UserModule } from './domains/user/user.module';

Expand All @@ -66,6 +70,9 @@ const domainModules = [
UserModule,
MemberModule,
HistoryModule,
FeedbackStatisticsModule,
IssueStatisticsModule,
FeedbackIssueStatisticsModule,
];

@Module({
Expand Down Expand Up @@ -107,6 +114,7 @@ const domainModules = [
global: true,
middleware: { mount: true },
}),
ScheduleModule.forRoot(),
...domainModules,
],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/**
* Copyright 2023 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import { MigrationInterface, QueryRunner } from 'typeorm';

export class Init1692159572819 implements MigrationInterface {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/**
* Copyright 2023 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import { MigrationInterface, QueryRunner } from 'typeorm';

export class IssueNameUnique1692690482919 implements MigrationInterface {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright 2023 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import { MigrationInterface, QueryRunner } from 'typeorm';

export class FeedbackStatistics1700795163534 implements MigrationInterface {
name = 'FeedbackStatistics1700795163534';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE \`feedback_statistics\` (\`id\` int NOT NULL AUTO_INCREMENT, \`date\` date NOT NULL, \`count\` int NOT NULL DEFAULT '0', \`channel_id\` int NULL, UNIQUE INDEX \`channel-date-unique\` (\`channel_id\`, \`date\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`,
);
await queryRunner.query(
`ALTER TABLE \`feedback_statistics\` ADD CONSTRAINT \`FK_7250a09c7ee486d1d24938a7054\` FOREIGN KEY (\`channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`feedback_statistics\` DROP FOREIGN KEY \`FK_7250a09c7ee486d1d24938a7054\``,
);
await queryRunner.query(
`DROP INDEX \`channel-date-unique\` ON \`feedback_statistics\``,
);
await queryRunner.query(`DROP TABLE \`feedback_statistics\``);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright 2023 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import { MigrationInterface, QueryRunner } from 'typeorm';

export class ProjectTimezoneOffset1700795948817 implements MigrationInterface {
name = 'ProjectTimezoneOffset1700795948817';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`projects\` ADD \`timezone_offset\` varchar(255) NOT NULL`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`projects\` DROP COLUMN \`timezone_offset\``,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright 2023 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import { MigrationInterface, QueryRunner } from 'typeorm';

export class IssueStatistics1701090850194 implements MigrationInterface {
name = 'IssueStatistics1701090850194';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE \`issue_statistics\` (\`id\` int NOT NULL AUTO_INCREMENT, \`date\` date NOT NULL, \`count\` int NOT NULL DEFAULT '0', \`project_id\` int NULL, UNIQUE INDEX \`project-date-unique\` (\`project_id\`, \`date\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`,
);
await queryRunner.query(
`ALTER TABLE \`issue_statistics\` ADD CONSTRAINT \`FK_86e6ee861d8895004659b4fe076\` FOREIGN KEY (\`project_id\`) REFERENCES \`projects\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`issue_statistics\` DROP FOREIGN KEY \`FK_86e6ee861d8895004659b4fe076\``,
);
await queryRunner.query(
`DROP INDEX \`project-date-unique\` ON \`issue_statistics\``,
);
await queryRunner.query(`DROP TABLE \`issue_statistics\``);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright 2023 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import { MigrationInterface, QueryRunner } from 'typeorm';

export class FeedbackIssueStatistics1701234953280
implements MigrationInterface
{
name = 'FeedbackIssueStatistics1701234953280';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE \`feedback_issue_statistics\` (\`id\` int NOT NULL AUTO_INCREMENT, \`date\` date NOT NULL, \`feedback_count\` int NOT NULL DEFAULT '0', \`issue_id\` int NULL, UNIQUE INDEX \`issue-date-unique\` (\`issue_id\`, \`date\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`,
);
await queryRunner.query(
`ALTER TABLE \`feedback_issue_statistics\` ADD CONSTRAINT \`FK_f90e8299de4ac2a05d3b6cbb2a6\` FOREIGN KEY (\`issue_id\`) REFERENCES \`issues\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`feedback_issue_statistics\` DROP FOREIGN KEY \`FK_f90e8299de4ac2a05d3b6cbb2a6\``,
);
await queryRunner.query(
`DROP INDEX \`issue-date-unique\` ON \`feedback_issue_statistics\``,
);
await queryRunner.query(`DROP TABLE \`feedback_issue_statistics\``);
}
}
3 changes: 3 additions & 0 deletions apps/api/src/configs/mysql.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
* under the License.
*/
import { registerAs } from '@nestjs/config';
import dotenv from 'dotenv';
import Joi from 'joi';

dotenv.config();

export const mysqlConfigSchema = Joi.object({
MYSQL_PRIMARY_URL: Joi.string().required(),
MYSQL_SECONDARY_URLS: Joi.string()
Expand Down
10 changes: 10 additions & 0 deletions apps/api/src/domains/channel/channel/channel.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from 'typeorm';

import { CommonEntity } from '@/common/entities';
import { FeedbackStatisticsEntity } from '@/domains/statistics/feedback/feedback-statistics.entity';
import { FeedbackEntity } from '../../feedback/feedback.entity';
import { ProjectEntity } from '../../project/project/project.entity';
import { FieldEntity } from '../field/field.entity';
Expand Down Expand Up @@ -53,6 +54,15 @@ export class ChannelEntity extends CommonEntity {
})
feedbacks: Relation<FeedbackEntity>[];

@OneToMany(
() => FeedbackStatisticsEntity,
(feedbackStats) => feedbackStats.channel,
{
cascade: true,
},
)
feedbackStats: Relation<FeedbackStatisticsEntity>[];

static from(name: string, description: string, projectId: number) {
const channel = new ChannelEntity();
channel.name = name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class ChannelMySQLService {
return await paginate(
this.repository.createQueryBuilder().setFindOptions({
where: { project: { id: projectId }, name: Like(`%${searchText}%`) },
order: { createdAt: 'DESC' },
order: { createdAt: 'ASC' },
}),
options,
);
Expand Down
6 changes: 5 additions & 1 deletion apps/api/src/domains/channel/field/field.mysql.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { In, Repository } from 'typeorm';
import { Transactional } from 'typeorm-transactional';

import {
Expand Down Expand Up @@ -213,4 +213,8 @@ export class FieldMySQLService {

return createdFields;
}

async findByIds(ids: number[]) {
return await this.repository.findBy({ id: In(ids) });
}
}
4 changes: 4 additions & 0 deletions apps/api/src/domains/channel/field/field.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,8 @@ export class FieldService {
});
}
}

async findByIds(ids: number[]) {
return this.fieldMySQLService.findByIds(ids);
}
}
1 change: 1 addition & 0 deletions apps/api/src/domains/feedback/dtos/generate-excel.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export class GenerateExcelDto {
[key: string]: SortMethodEnum;
};
type: 'xlsx' | 'csv';
fieldIds?: number[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@
* under the License.
*/
import { ApiProperty } from '@nestjs/swagger';
import { IsArray, IsOptional, IsString } from 'class-validator';

import { FindFeedbacksByChannelIdRequestDto } from './find-feedbacks-by-channel-id-request.dto';

export class ExportFeedbacksRequestDto extends FindFeedbacksByChannelIdRequestDto {
@ApiProperty({ required: false })
type: string;
@ApiProperty()
@IsString()
type: 'xlsx' | 'csv';

@ApiProperty({ required: false, type: [Number] })
@IsOptional()
@IsArray()
fieldIds?: number[];
}
8 changes: 1 addition & 7 deletions apps/api/src/domains/feedback/feedback.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,7 @@ describe('FeedbackController', () => {
project: { name: faker.string.sample() },
} as ChannelEntity);

await feedbackController.exportFeedbacks(
channelId,
dto,
'csv',
response,
userDto,
);
await feedbackController.exportFeedbacks(channelId, dto, response, userDto);

expect(MockFeedbackService.generateFile).toBeCalledTimes(1);
});
Expand Down
23 changes: 12 additions & 11 deletions apps/api/src/domains/feedback/feedback.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,24 @@ export class FeedbackController {
async exportFeedbacks(
@Param('channelId', ParseIntPipe) channelId: number,
@Body() body: ExportFeedbacksRequestDto,
@Body('type') type: 'xlsx' | 'csv',
@Res() res: FastifyReply,
@CurrentUser() user: UserDto,
) {
const { query, sort } = body;
const { query, sort, type, fieldIds } = body;
const channel = await this.channelService.findById({ channelId });
const projectName = channel.project.name;
const channelName = channel.name;

const { streamableFile, feedbackIds } =
await this.feedbackService.generateFile({
channelId,
query,
sort,
type,
fieldIds,
});
const stream = streamableFile.getStream();

const filename = `UFB_${projectName}_${channelName}_Feedback_${dayjs().format(
'YYYY-MM-DD',
)}.${type}`;
Expand All @@ -146,15 +156,6 @@ export class FeedbackController {
res.type('text/csv');
}

const { streamableFile, feedbackIds } =
await this.feedbackService.generateFile({
channelId,
query,
sort,
type,
});
const stream = streamableFile.getStream();

res.send(stream);

this.historyService.createHistory({
Expand Down
Loading

0 comments on commit 672f985

Please sign in to comment.