Skip to content

Commit

Permalink
release: 4.2404.33
Browse files Browse the repository at this point in the history
  • Loading branch information
h4l-yup authored Jan 24, 2024
2 parents c884946 + aef00ce commit 9619e95
Show file tree
Hide file tree
Showing 262 changed files with 7,431 additions and 1,499 deletions.
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
target-branch: 'dev'
52 changes: 52 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: E2E Tests

on:
pull_request:
branches: [dev, main]

jobs:
e2e-test:
runs-on: ubuntu-latest

services:
mysql:
image: mysql:8.0.19
env:
MYSQL_ROOT_PASSWORD: userfeedback
MYSQL_DATABASE: e2e
MYSQL_USER: userfeedback
MYSQL_PASSWORD: userfeedback
TZ: UTC
ports:
- 13307:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

smtp:
image: rnwood/smtp4dev:v3
ports:
- 5080:80
- 25:25
- 143:143

# opensearch:
# image: opensearchproject/opensearch:2.4.1
# ports:
# - 9200:9200

steps:
- name: Check out repository code
uses: actions/checkout@main

- name: Build and run
run: |
docker-compose -f "./docker/docker-compose.e2e.yml" up -d
- name: Setup e2e test
run: |
cd apps/e2e
yarn
yarn playwright install
- name: Run e2e tests
run: |
npm run test:e2e
2 changes: 1 addition & 1 deletion .github/workflows/test-on-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Run Tests On Pull Request

on:
pull_request:
branches: [dev, beta, main]
branches: [dev, main]

jobs:
test:
Expand Down
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,9 @@ volumes

dist

tsconfig.tsbuildinfo
tsconfig.tsbuildinfo

# playwright
playwright-report
test-results
user.json
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn install
yarn typecheck
yarn format
yarn lint
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# ABC User Feedback

![cover image](./assets/cover.png)

ABC User Feedback is a standalone web application that manages Voice of Customer (VoC) data. It allows you to gather and sort feedback from your customers. The product is being applied and used in services worth 10 million MAU.
ABC User Feedback is a standalone web application that manages Voice of Customer (VoC) data. It allows you to gather and sort feedback from your customers. The product is being applied and used in services worth 10 million MAU.

![sample image](./assets/sample.png)

Expand Down
4 changes: 2 additions & 2 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
JWT_SECRET= # required

MYSQL_PRIMARY_URL= # default: mysql://userfeedback:userfeedback@localhost:13306/userfeedback
MYSQL_SECONDARY_URLS= # default: ["mysql://userfeedback:userfeedback@localhost:13306/userfeedback"]
MYSQL_PRIMARY_URL= # required, default: mysql://userfeedback:userfeedback@localhost:13306/userfeedback
MYSQL_SECONDARY_URLS= # required, default: ["mysql://userfeedback:userfeedback@localhost:13306/userfeedback"]

SMTP_USE= # default: false
SMTP_HOST= # required if SMTP_USE=true
Expand Down
10 changes: 10 additions & 0 deletions apps/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ npm run migration:run

The swagger documentation can be found on the `/docs` endpoint.

## Dashboard statistics data migration

Dashboard data is generated by mysql data every AM 00:00 with the timezone set by its project with schedulers.
The schedulers generate data for 365 days.
If you want to generate dashboard data by yourself, you can use `/migration/statistics` APIs (ref: [migration API](./src/domains/migration/migration.controller.ts))
With the APIs you can generate data which are inserted more than 365 days.

If you are willing to change the project's timezone, you can manually change it in mysql database. (it is not available in admin web as it is not a usual case.)
Then you should delete all statistics data and re-genearte by migration APIs.

## Learn More

To learn NestJS, check out the [NestJS documentation](https://nestjs.com/).
2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"@ufb/shared": "^0.1.0",
"@willsoto/nestjs-prometheus": "^6.0.0",
"aws-sdk": "^2.1509.0",
"axios": "^1.5.1",
"axios": "^1.6.0",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { AuthModule } from './domains/auth/auth.module';
import { ChannelModule } from './domains/channel/channel/channel.module';
import { FieldModule } from './domains/channel/field/field.module';
import { OptionModule } from './domains/channel/option/option.module';
import { ExternalModule } from './domains/external/external.module';
import { FeedbackModule } from './domains/feedback/feedback.module';
import { HealthModule } from './domains/health/health.module';
import { HistoryModule } from './domains/history/history.module';
Expand Down Expand Up @@ -73,6 +74,7 @@ const domainModules = [
FeedbackStatisticsModule,
IssueStatisticsModule,
FeedbackIssueStatisticsModule,
ExternalModule,
];

@Module({
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/common/dtos/pagination-request.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ import { toNumber } from '@/common/helper/cast.helper';

export class PaginationRequestDto {
@Transform(({ value }) => toNumber(value, { default: 10, min: 1 }))
@ApiProperty({ required: false, minimum: 1, default: 10 })
@ApiProperty({ required: false, minimum: 1, default: 10, example: 10 })
@IsOptional()
@IsNumber()
@Min(1)
limit: number;

@Transform(({ value }) => toNumber(value, { default: 1, min: 1 }))
@ApiProperty({ required: false, minimum: 1, default: 1 })
@ApiProperty({ required: false, minimum: 1, default: 1, example: 1 })
@IsOptional()
@IsNumber()
@Min(1)
Expand Down
10 changes: 5 additions & 5 deletions apps/api/src/common/dtos/pagination-response.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ import { Expose, Type } from 'class-transformer';
import type { IPaginationMeta, Pagination } from 'nestjs-typeorm-paginate';

class PaginationMetaDto implements IPaginationMeta {
@ApiProperty()
@ApiProperty({ example: 10 })
@Expose()
itemCount: number;

@ApiProperty()
@ApiProperty({ example: 100 })
@Expose()
totalItems?: number;

@ApiProperty()
@ApiProperty({ example: 10 })
@Expose()
itemsPerPage: number;

@ApiProperty()
@ApiProperty({ example: 10 })
@Expose()
totalPages?: number;

@ApiProperty()
@ApiProperty({ example: 1 })
@Expose()
currentPage: number;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import type { ConfigServiceType } from '@/types/config-service.type';
auth: username && password && { user: username, pass: password },
secure: port === 465,
},
defaults: { from: `"User feedback" <${sender}>` },
defaults: { from: `"User feedback" <${sender}>`, sdd: '' },
template: {
dir: __dirname + '/templates/',
adapter: new HandlebarsAdapter(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* 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 type { MigrationInterface, QueryRunner } from 'typeorm';

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

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`projects\` CHANGE \`timezone_offset\` \`timezone\` varchar(255) NULL DEFAULT '+00:00'`,
);
await queryRunner.query(
`ALTER TABLE \`projects\` DROP COLUMN \`timezone\``,
);
await queryRunner.query(
`ALTER TABLE \`projects\` ADD \`timezone\` varchar(255) NOT NULL DEFAULT '{"countryCode":"KR","name":"Asia/Seoul","offset":"+09:00"}'`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`projects\` DROP COLUMN \`timezone\``,
);
await queryRunner.query(
`ALTER TABLE \`projects\` ADD \`timezone\` varchar(255) NULL DEFAULT '+00:00'`,
);
await queryRunner.query(
`ALTER TABLE \`projects\` CHANGE \`timezone\` \`timezone_offset\` varchar(255) NULL DEFAULT '+00:00'`,
);
}
}
59 changes: 59 additions & 0 deletions apps/api/src/domains/external/external.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* 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 { Controller, Get, Logger, Req, Res } from '@nestjs/common';
import { ApiExcludeController } from '@nestjs/swagger';
import { FastifyReply, FastifyRequest } from 'fastify';

@Controller('/external')
@ApiExcludeController()
export class ExternalController {
constructor() {}
private logger = new Logger(ExternalController.name);

@Get('docs')
getExternalDocs(
@Req() request: FastifyRequest,
@Res() reply: FastifyReply,
): void {
const { protocol, hostname } = request;
this.logger.log(`protocol: ${protocol}, hostname: ${hostname}`);
const html = `<!DOCTYPE html>
<html>
<head>
<title>Redoc</title>
<!-- needed for adaptive design -->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<!--
Redoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<redoc spec-url='${protocol}://${hostname}/external-docs-json'></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
</body>
</html>`;
reply.type('text/html').send(html);
}
}
58 changes: 58 additions & 0 deletions apps/api/src/domains/external/external.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* 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 { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { OpensearchRepository } from '@/common/repositories';
import { AuthModule } from '../auth/auth.module';
import { ChannelModule } from '../channel/channel/channel.module';
import { FieldModule } from '../channel/field/field.module';
import { OptionEntity } from '../channel/option/option.entity';
import { OptionModule } from '../channel/option/option.module';
import { FeedbackEntity } from '../feedback/feedback.entity';
import { FeedbackModule } from '../feedback/feedback.module';
import { FeedbackMySQLService } from '../feedback/feedback.mysql.service';
import { FeedbackOSService } from '../feedback/feedback.os.service';
import { FeedbackService } from '../feedback/feedback.service';
import { IssueEntity } from '../project/issue/issue.entity';
import { IssueModule } from '../project/issue/issue.module';
import { FeedbackIssueStatisticsModule } from '../statistics/feedback-issue/feedback-issue-statistics.module';
import { FeedbackStatisticsModule } from '../statistics/feedback/feedback-statistics.module';
import { ExternalController } from './external.controller';
import { FeedbackController } from './feedback.controller';
import { IssueController } from './issue.controller';

@Module({
imports: [
TypeOrmModule.forFeature([FeedbackEntity, IssueEntity, OptionEntity]),
FeedbackModule,
IssueModule,
FieldModule,
OptionModule,
ChannelModule,
FeedbackStatisticsModule,
FeedbackIssueStatisticsModule,
AuthModule,
],
providers: [
FeedbackService,
FeedbackMySQLService,
FeedbackOSService,
OpensearchRepository,
],
controllers: [FeedbackController, IssueController, ExternalController],
})
export class ExternalModule {}
Loading

0 comments on commit 9619e95

Please sign in to comment.