diff --git a/apps/api/package.json b/apps/api/package.json index d5bdcc62f..8b2630e8c 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -49,7 +49,6 @@ "bcrypt": "^5.1.1", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "dayjs": "^1.11.10", "exceljs": "^4.4.0", "fast-csv": "^4.3.6", "joi": "^17.11.0", diff --git a/apps/api/src/common/entities/common.entity.ts b/apps/api/src/common/entities/common.entity.ts index 3d5595a47..77bf07aff 100644 --- a/apps/api/src/common/entities/common.entity.ts +++ b/apps/api/src/common/entities/common.entity.ts @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import { BeforeInsert, BeforeUpdate, @@ -38,12 +38,12 @@ export abstract class CommonEntity { @BeforeInsert() beforeInsertHook() { - this.createdAt = dayjs().toDate(); - this.updatedAt = dayjs().toDate(); + this.createdAt = DateTime.utc().toJSDate(); + this.updatedAt = DateTime.utc().toJSDate(); } @BeforeUpdate() beforeUpdateHook() { - this.updatedAt = dayjs().toDate(); + this.updatedAt = DateTime.utc().toJSDate(); } } diff --git a/apps/api/src/domains/auth/auth.controller.spec.ts b/apps/api/src/domains/auth/auth.controller.spec.ts index 22f3ecdbf..91521ded3 100644 --- a/apps/api/src/domains/auth/auth.controller.spec.ts +++ b/apps/api/src/domains/auth/auth.controller.spec.ts @@ -15,7 +15,7 @@ */ import { faker } from '@faker-js/faker'; import { Test } from '@nestjs/testing'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import { getMockProvider } from '@/test-utils/util-functions'; import { TenantService } from '../tenant/tenant.service'; @@ -59,7 +59,7 @@ describe('AuthController', () => { it('sendCode', async () => { jest .spyOn(MockAuthService, 'sendEmailCode') - .mockResolvedValue(dayjs().format()); + .mockResolvedValue(DateTime.utc().toISO()); const dto = new EmailVerificationMailingRequestDto(); dto.email = faker.internet.email(); diff --git a/apps/api/src/domains/auth/auth.service.ts b/apps/api/src/domains/auth/auth.service.ts index 4ecd21f8a..d08932ec0 100644 --- a/apps/api/src/domains/auth/auth.service.ts +++ b/apps/api/src/domains/auth/auth.service.ts @@ -24,7 +24,7 @@ import { ConfigService } from '@nestjs/config'; import { JwtService } from '@nestjs/jwt'; import { AxiosError } from 'axios'; import * as bcrypt from 'bcrypt'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import { catchError, lastValueFrom, map } from 'rxjs'; import { Transactional } from 'typeorm-transactional'; @@ -90,9 +90,9 @@ export class AuthService { }); await this.emailVerificationMailingService.send({ code, email }); - return dayjs() - .add(5 * 60, 'seconds') - .format(); + return DateTime.utc() + .plus({ seconds: 5 * 60 }) + .toISO(); } async verifyEmailCode({ code, email }: VerifyEmailCodeDto) { diff --git a/apps/api/src/domains/channel/channel/dtos/requests/create-channel-request.dto.ts b/apps/api/src/domains/channel/channel/dtos/requests/create-channel-request.dto.ts index 3d44a1bea..aae5ef33d 100644 --- a/apps/api/src/domains/channel/channel/dtos/requests/create-channel-request.dto.ts +++ b/apps/api/src/domains/channel/channel/dtos/requests/create-channel-request.dto.ts @@ -21,6 +21,7 @@ import { IsObject, IsOptional, IsString, + MaxLength, MinLength, ValidateNested, } from 'class-validator'; @@ -90,11 +91,13 @@ export class CreateChannelRequestDto { @ApiProperty() @IsString() @MinLength(1) + @MaxLength(20) name: string; @ApiProperty({ nullable: true }) @IsNullable() @IsString() + @MaxLength(50) description: string | null; @ApiProperty({ required: false, nullable: true, type: ImageConfigRequestDto }) diff --git a/apps/api/src/domains/channel/channel/dtos/requests/update-channel-request.dto.ts b/apps/api/src/domains/channel/channel/dtos/requests/update-channel-request.dto.ts index 0f3b2858e..dea35bf1a 100644 --- a/apps/api/src/domains/channel/channel/dtos/requests/update-channel-request.dto.ts +++ b/apps/api/src/domains/channel/channel/dtos/requests/update-channel-request.dto.ts @@ -14,7 +14,7 @@ * under the License. */ import { ApiProperty } from '@nestjs/swagger'; -import { IsObject, IsString, MinLength } from 'class-validator'; +import { IsObject, IsString, MaxLength, MinLength } from 'class-validator'; import { IsNullable } from '@/domains/user/decorators'; import { ImageConfigRequestDto } from './image-config-request.dto'; @@ -23,11 +23,13 @@ export class UpdateChannelRequestDto { @ApiProperty() @IsString() @MinLength(1) + @MaxLength(20) name: string; @ApiProperty({ nullable: true }) @IsNullable() @IsString() + @MaxLength(50) description: string | null; @ApiProperty({ nullable: true, type: ImageConfigRequestDto }) diff --git a/apps/api/src/domains/channel/option/dtos/requests/create-option-request.dto.ts b/apps/api/src/domains/channel/option/dtos/requests/create-option-request.dto.ts index 2d5ab5401..3f8372336 100644 --- a/apps/api/src/domains/channel/option/dtos/requests/create-option-request.dto.ts +++ b/apps/api/src/domains/channel/option/dtos/requests/create-option-request.dto.ts @@ -14,14 +14,18 @@ * under the License. */ import { ApiProperty } from '@nestjs/swagger'; -import { IsString } from 'class-validator'; +import { IsString, MaxLength, MinLength } from 'class-validator'; export class CreateOptionRequestDto { @ApiProperty() @IsString() + @MinLength(1) + @MaxLength(20) name: string; @ApiProperty() @IsString() + @MinLength(1) + @MaxLength(20) key: string; } diff --git a/apps/api/src/domains/feedback/feedback.controller.ts b/apps/api/src/domains/feedback/feedback.controller.ts index d58da7526..98410aaf6 100644 --- a/apps/api/src/domains/feedback/feedback.controller.ts +++ b/apps/api/src/domains/feedback/feedback.controller.ts @@ -27,8 +27,8 @@ import { UseGuards, } from '@nestjs/common'; import { ApiOkResponse, ApiParam } from '@nestjs/swagger'; -import dayjs from 'dayjs'; import { FastifyReply } from 'fastify'; +import { DateTime } from 'luxon'; import { ApiKeyAuthGuard } from '@/domains/auth/guards'; import { ChannelService } from '../channel/channel/channel.service'; @@ -144,8 +144,8 @@ export class FeedbackController { }); const stream = streamableFile.getStream(); - const filename = `UFB_${projectName}_${channelName}_Feedback_${dayjs().format( - 'YYYY-MM-DD', + const filename = `UFB_${projectName}_${channelName}_Feedback_${DateTime.utc().toFormat( + 'yyyy-MM-dd', )}.${type}`; res.header('Content-Disposition', `attachment; filename="${filename}"`); diff --git a/apps/api/src/domains/feedback/feedback.mysql.service.ts b/apps/api/src/domains/feedback/feedback.mysql.service.ts index 31561402f..a77e84de0 100644 --- a/apps/api/src/domains/feedback/feedback.mysql.service.ts +++ b/apps/api/src/domains/feedback/feedback.mysql.service.ts @@ -15,7 +15,7 @@ */ import { BadRequestException, Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import { ClsService } from 'nestjs-cls'; import type { IPaginationMeta, Pagination } from 'nestjs-typeorm-paginate'; import { Brackets, QueryFailedError, Repository } from 'typeorm'; @@ -291,7 +291,7 @@ export class FeedbackMySQLService { return query; }, - updatedAt: () => `'${dayjs().format('YYYY-MM-DD HH:mm:ss')}'`, + updatedAt: () => `'${DateTime.utc().toFormat('yyyy-MM-dd HH:mm:ss')}'`, }) .where('id = :feedbackId', { feedbackId }) .execute(); @@ -316,12 +316,12 @@ export class FeedbackMySQLService { await this.feedbackRepository.save({ ...feedback, - updatedAt: dayjs().format('YYYY-MM-DD HH:mm:ss'), + updatedAt: DateTime.utc().toFormat('yyyy-MM-dd HH:mm:ss'), }); await this.issueRepository.update(dto.issueId, { feedbackCount: () => 'feedback_count + 1', - updatedAt: () => `'${dayjs().format('YYYY-MM-DD HH:mm:ss')}'`, + updatedAt: () => `'${DateTime.utc().toFormat('yyyy-MM-dd HH:mm:ss')}'`, }); } catch (e) { if (e instanceof QueryFailedError) { @@ -353,12 +353,12 @@ export class FeedbackMySQLService { await this.feedbackRepository.save({ ...feedback, - updatedAt: dayjs().format('YYYY-MM-DD HH:mm:ss'), + updatedAt: DateTime.utc().toFormat('yyyy-MM-dd HH:mm:ss'), }); await this.issueRepository.update(dto.issueId, { feedbackCount: () => 'feedback_count - 1', - updatedAt: () => `'${dayjs().format('YYYY-MM-DD HH:mm:ss')}'`, + updatedAt: () => `'${DateTime.utc().toFormat('yyyy-MM-dd HH:mm:ss')}'`, }); } catch (e) { if (e instanceof QueryFailedError) { diff --git a/apps/api/src/domains/feedback/feedback.os.service.ts b/apps/api/src/domains/feedback/feedback.os.service.ts index 64bfdb6d5..4ffea2116 100644 --- a/apps/api/src/domains/feedback/feedback.os.service.ts +++ b/apps/api/src/domains/feedback/feedback.os.service.ts @@ -15,7 +15,7 @@ */ import { BadRequestException, Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import type { IPaginationMeta, Pagination } from 'nestjs-typeorm-paginate'; import { In, Repository } from 'typeorm'; @@ -216,8 +216,8 @@ export class FeedbackOSService { const osFeedbackData = { ...feedback.rawData, id: feedback.id, - createdAt: dayjs().toISOString(), - updatedAt: dayjs().toISOString(), + createdAt: DateTime.utc().toISO(), + updatedAt: DateTime.utc().toISO(), }; return await this.osRepository.createData({ @@ -304,7 +304,7 @@ export class FeedbackOSService { async upsertFeedbackItem(dto: UpdateFeedbackESDto) { const { feedbackId, data, channelId } = dto; - data.updatedAt = dayjs().toISOString(); + data.updatedAt = DateTime.utc().toISO(); await this.osRepository.updateData({ id: feedbackId.toString(), index: channelId.toString(), diff --git a/apps/api/src/domains/feedback/feedback.service.ts b/apps/api/src/domains/feedback/feedback.service.ts index e6b7face4..266b5fc91 100644 --- a/apps/api/src/domains/feedback/feedback.service.ts +++ b/apps/api/src/domains/feedback/feedback.service.ts @@ -25,7 +25,6 @@ import { StreamableFile, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import dayjs from 'dayjs'; import * as ExcelJS from 'exceljs'; import * as fastcsv from 'fast-csv'; import { DateTime } from 'luxon'; @@ -521,7 +520,7 @@ export class FeedbackService { await this.feedbackOSService.upsertFeedbackItem({ channelId: dto.channelId, feedbackId: dto.feedbackId, - data: { updatedAt: dayjs().toISOString() }, + data: { updatedAt: DateTime.utc().toISO() }, }); } } @@ -534,7 +533,7 @@ export class FeedbackService { await this.feedbackOSService.upsertFeedbackItem({ channelId: dto.channelId, feedbackId: dto.feedbackId, - data: { updatedAt: dayjs().toISOString() }, + data: { updatedAt: DateTime.utc().toISO() }, }); } } diff --git a/apps/api/src/domains/migration/migration.service.ts b/apps/api/src/domains/migration/migration.service.ts index 3b8f69087..3b2c0bb5c 100644 --- a/apps/api/src/domains/migration/migration.service.ts +++ b/apps/api/src/domains/migration/migration.service.ts @@ -16,7 +16,7 @@ import { Inject, Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Client } from '@opensearch-project/opensearch'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import { Repository } from 'typeorm'; import { OpensearchRepository } from '@/common/repositories'; @@ -62,8 +62,12 @@ export class MigrationService { id: feedback.id, ...feedback.rawData, ...feedback.additionalData, - createdAt: dayjs(feedback.createdAt).format('YYYY-MM-DD HH:mm:ssZ'), - updatedAt: dayjs(feedback.updatedAt).format('YYYY-MM-DD HH:mm:ssZ'), + createdAt: DateTime.fromJSDate(feedback.createdAt).toFormat( + 'yyyy-MM-dd HH:mm:ssZZ', + ), + updatedAt: DateTime.fromJSDate(feedback.updatedAt).toFormat( + 'yyyy-MM-dd HH:mm:ssZZ', + ), }; }); this.logger.log('documents.length: ' + documents.length); diff --git a/apps/api/src/domains/project/api-key/api-key.service.ts b/apps/api/src/domains/project/api-key/api-key.service.ts index 12cdd27bf..e40f8ca97 100644 --- a/apps/api/src/domains/project/api-key/api-key.service.ts +++ b/apps/api/src/domains/project/api-key/api-key.service.ts @@ -16,7 +16,7 @@ import { randomBytes } from 'crypto'; import { BadRequestException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import { Repository } from 'typeorm'; import { Transactional } from 'typeorm-transactional'; @@ -105,7 +105,7 @@ export class ApiKeyService { }); await this.repository.save( - Object.assign(apiKey, { deletedAt: dayjs().toDate() }), + Object.assign(apiKey, { deletedAt: DateTime.utc().toJSDate() }), ); } diff --git a/apps/api/src/domains/project/issue/dtos/requests/create-issue-request.dto.ts b/apps/api/src/domains/project/issue/dtos/requests/create-issue-request.dto.ts index b2f7bdda7..ca679fbed 100644 --- a/apps/api/src/domains/project/issue/dtos/requests/create-issue-request.dto.ts +++ b/apps/api/src/domains/project/issue/dtos/requests/create-issue-request.dto.ts @@ -14,11 +14,12 @@ * under the License. */ import { ApiProperty } from '@nestjs/swagger'; -import { IsString, MinLength } from 'class-validator'; +import { IsString, MaxLength, MinLength } from 'class-validator'; export class CreateIssueRequestDto { @ApiProperty() @IsString() @MinLength(1) + @MaxLength(20) name: string; } diff --git a/apps/api/src/domains/project/issue/dtos/requests/update-issue-request.dto.ts b/apps/api/src/domains/project/issue/dtos/requests/update-issue-request.dto.ts index 6576113c9..affb7a8c0 100644 --- a/apps/api/src/domains/project/issue/dtos/requests/update-issue-request.dto.ts +++ b/apps/api/src/domains/project/issue/dtos/requests/update-issue-request.dto.ts @@ -14,7 +14,7 @@ * under the License. */ import { ApiProperty } from '@nestjs/swagger'; -import { IsEnum, IsOptional, IsString } from 'class-validator'; +import { IsEnum, IsOptional, IsString, MaxLength } from 'class-validator'; import { IssueStatusEnum } from '@/common/enums'; import { IsNullable } from '@/domains/user/decorators'; @@ -24,6 +24,7 @@ export class UpdateIssueRequestDto extends CreateIssueRequestDto { @ApiProperty({ nullable: true }) @IsString() @IsNullable() + @MaxLength(50) description: string | null; @ApiProperty({ required: false }) diff --git a/apps/api/src/domains/project/issue/issue.service.ts b/apps/api/src/domains/project/issue/issue.service.ts index a14c9cdd4..633906155 100644 --- a/apps/api/src/domains/project/issue/issue.service.ts +++ b/apps/api/src/domains/project/issue/issue.service.ts @@ -92,8 +92,16 @@ export class IssueService { andWhere.id = query.id as number; } + if (query.statuses) { + andWhere.status = In(query.statuses as string[]); + } + for (const column of Object.keys(query)) { - if (['id', 'createdAt', 'updatedAt', 'searchText'].includes(column)) { + if ( + ['id', 'createdAt', 'updatedAt', 'searchText', 'statuses'].includes( + column, + ) + ) { continue; } diff --git a/apps/api/src/domains/project/project/dtos/requests/create-project-request.dto.ts b/apps/api/src/domains/project/project/dtos/requests/create-project-request.dto.ts index 9830514f6..c6bbe4f3e 100644 --- a/apps/api/src/domains/project/project/dtos/requests/create-project-request.dto.ts +++ b/apps/api/src/domains/project/project/dtos/requests/create-project-request.dto.ts @@ -20,6 +20,8 @@ import { IsOptional, IsString, Length, + MaxLength, + MinLength, } from 'class-validator'; import { TimezoneOffset } from '@ufb/shared'; @@ -48,11 +50,14 @@ class CreateApiKeyByValueDto { export class CreateProjectRequestDto { @ApiProperty() @IsString() + @MinLength(1) + @MaxLength(20) name: string; @ApiProperty({ nullable: true }) @IsString() @IsNullable() + @MaxLength(50) description: string | null; @ApiProperty() diff --git a/apps/api/src/domains/statistics/feedback-issue/feedback-issue-statistics.service.ts b/apps/api/src/domains/statistics/feedback-issue/feedback-issue-statistics.service.ts index 9104e572c..d7f2a217f 100644 --- a/apps/api/src/domains/statistics/feedback-issue/feedback-issue-statistics.service.ts +++ b/apps/api/src/domains/statistics/feedback-issue/feedback-issue-statistics.service.ts @@ -17,7 +17,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { SchedulerRegistry } from '@nestjs/schedule'; import { InjectRepository } from '@nestjs/typeorm'; import { CronJob } from 'cron'; -import dayjs from 'dayjs'; import dotenv from 'dotenv'; import { DateTime } from 'luxon'; import { Between, In, Repository } from 'typeorm'; @@ -145,16 +144,16 @@ export class FeedbackIssueStatisticsService { where: { issues: { id: issue.id }, createdAt: Between( - dayjs() - .subtract(day, 'day') + DateTime.utc() + .minus({ days: day }) .startOf('day') - .subtract(offset, 'hour') - .toDate(), - dayjs() - .subtract(day, 'day') + .minus({ hours: offset }) + .toJSDate(), + DateTime.utc() + .minus({ days: day }) .endOf('day') - .subtract(offset, 'hour') - .toDate(), + .minus({ hours: offset }) + .toJSDate(), ), }, }); @@ -165,7 +164,18 @@ export class FeedbackIssueStatisticsService { .createQueryBuilder() .insert() .values({ - date: dayjs().subtract(day, 'day').toDate(), + date: + offset >= 0 + ? DateTime.utc() + .minus({ days: day }) + .endOf('day') + .minus({ hours: offset }) + .toFormat('yyyy-MM-dd') + : DateTime.utc() + .minus({ days: day }) + .startOf('day') + .minus({ hours: offset }) + .toFormat('yyyy-MM-dd'), issue: { id: issue.id }, feedbackCount, }) diff --git a/apps/api/src/domains/statistics/feedback/feedback-statistics.service.ts b/apps/api/src/domains/statistics/feedback/feedback-statistics.service.ts index 9d60ebf0b..30b227fc7 100644 --- a/apps/api/src/domains/statistics/feedback/feedback-statistics.service.ts +++ b/apps/api/src/domains/statistics/feedback/feedback-statistics.service.ts @@ -17,7 +17,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { SchedulerRegistry } from '@nestjs/schedule'; import { InjectRepository } from '@nestjs/typeorm'; import { CronJob } from 'cron'; -import dayjs from 'dayjs'; import dotenv from 'dotenv'; import { DateTime } from 'luxon'; import { Between, In, Repository } from 'typeorm'; @@ -186,16 +185,16 @@ export class FeedbackStatisticsService { where: { channel: { id: channel.id }, createdAt: Between( - dayjs() - .subtract(day, 'day') + DateTime.utc() + .minus({ days: day }) .startOf('day') - .subtract(offset, 'hour') - .toDate(), - dayjs() - .subtract(day, 'day') + .minus({ hours: offset }) + .toJSDate(), + DateTime.utc() + .minus({ days: day }) .endOf('day') - .subtract(offset, 'hour') - .toDate(), + .minus({ hours: offset }) + .toJSDate(), ), }, }); @@ -206,7 +205,18 @@ export class FeedbackStatisticsService { .createQueryBuilder() .insert() .values({ - date: dayjs().subtract(day, 'day').toDate(), + date: + offset >= 0 + ? DateTime.utc() + .minus({ days: day }) + .endOf('day') + .minus({ hours: offset }) + .toFormat('yyyy-MM-dd') + : DateTime.utc() + .minus({ days: day }) + .startOf('day') + .minus({ hours: offset }) + .toFormat('yyyy-MM-dd'), count: feedbackCount, channel: { id: channel.id }, }) diff --git a/apps/api/src/domains/statistics/issue/issue-statistics.service.ts b/apps/api/src/domains/statistics/issue/issue-statistics.service.ts index 5ad608645..ef0d5bb60 100644 --- a/apps/api/src/domains/statistics/issue/issue-statistics.service.ts +++ b/apps/api/src/domains/statistics/issue/issue-statistics.service.ts @@ -17,7 +17,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { SchedulerRegistry } from '@nestjs/schedule'; import { InjectRepository } from '@nestjs/typeorm'; import { CronJob } from 'cron'; -import dayjs from 'dayjs'; import dotenv from 'dotenv'; import { DateTime } from 'luxon'; import { Between, Repository } from 'typeorm'; @@ -146,16 +145,16 @@ export class IssueStatisticsService { where: { project: { id }, createdAt: Between( - dayjs() - .subtract(day, 'day') + DateTime.utc() + .minus({ days: day }) .startOf('day') - .subtract(offset, 'hour') - .toDate(), - dayjs() - .subtract(day, 'day') + .minus({ hours: offset }) + .toJSDate(), + DateTime.utc() + .minus({ days: day }) .endOf('day') - .subtract(offset, 'hour') - .toDate(), + .minus({ hours: offset }) + .toJSDate(), ), }, }); @@ -166,7 +165,18 @@ export class IssueStatisticsService { .createQueryBuilder() .insert() .values({ - date: dayjs().subtract(day, 'day').toDate(), + date: + offset >= 0 + ? DateTime.utc() + .minus({ days: day }) + .endOf('day') + .minus({ hours: offset }) + .toFormat('yyyy-MM-dd') + : DateTime.utc() + .minus({ days: day }) + .startOf('day') + .minus({ hours: offset }) + .toFormat('yyyy-MM-dd'), count: issueCount, project: { id }, }) diff --git a/apps/api/src/domains/tenant/dtos/requests/setup-tenant-request.dto.ts b/apps/api/src/domains/tenant/dtos/requests/setup-tenant-request.dto.ts index 1991dac6d..17ba9cc14 100644 --- a/apps/api/src/domains/tenant/dtos/requests/setup-tenant-request.dto.ts +++ b/apps/api/src/domains/tenant/dtos/requests/setup-tenant-request.dto.ts @@ -14,10 +14,12 @@ * under the License. */ import { ApiProperty } from '@nestjs/swagger'; -import { IsString } from 'class-validator'; +import { IsString, MaxLength, MinLength } from 'class-validator'; export class SetupTenantRequestDto { @ApiProperty() @IsString() + @MinLength(1) + @MaxLength(20) siteName: string; } diff --git a/apps/api/src/shared/code/code.service.spec.ts b/apps/api/src/shared/code/code.service.spec.ts index 960163980..97ee9f07b 100644 --- a/apps/api/src/shared/code/code.service.spec.ts +++ b/apps/api/src/shared/code/code.service.spec.ts @@ -17,7 +17,7 @@ import { faker } from '@faker-js/faker'; import { BadRequestException, NotFoundException } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import MockDate from 'mockdate'; import type { Repository } from 'typeorm'; @@ -140,7 +140,7 @@ describe('CodeService', () => { codeEntity.type = CodeTypeEnum.EMAIL_VEIRIFICATION; codeEntity.isVerified = false; codeEntity.id = faker.number.int(); - codeEntity.expiredAt = dayjs().add(5, 'minutes').toDate(); + codeEntity.expiredAt = DateTime.utc().plus({ minutes: 5 }).toJSDate(); }); it('verify code with valid code, key, type', async () => { const { code, type } = codeEntity; diff --git a/apps/api/src/shared/code/code.service.ts b/apps/api/src/shared/code/code.service.ts index 65eb33fcd..a0b3da464 100644 --- a/apps/api/src/shared/code/code.service.ts +++ b/apps/api/src/shared/code/code.service.ts @@ -19,7 +19,7 @@ import { NotFoundException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import { Repository } from 'typeorm'; import { Transactional } from 'typeorm-transactional'; @@ -52,9 +52,9 @@ export class CodeService { key, code, isVerified: false, - expiredAt: dayjs() - .add(durationSec ?? SECONDS, 'seconds') - .toDate(), + expiredAt: DateTime.utc() + .plus({ seconds: durationSec ?? SECONDS }) + .toJSDate(), data: type === CodeTypeEnum.USER_INVITATION ? dto.data : undefined, }), ); @@ -74,7 +74,7 @@ export class CodeService { throw new BadRequestException('invalid code'); } - if (dayjs().isAfter(codeEntity.expiredAt)) { + if (DateTime.utc() > DateTime.fromJSDate(codeEntity.expiredAt)) { throw new BadRequestException('code expired'); } diff --git a/apps/api/test/user.e2e-spec.ts b/apps/api/test/user.e2e-spec.ts index 683f38c5a..6d70a61d6 100644 --- a/apps/api/test/user.e2e-spec.ts +++ b/apps/api/test/user.e2e-spec.ts @@ -19,7 +19,7 @@ import { ValidationPipe } from '@nestjs/common'; import type { TestingModule } from '@nestjs/testing'; import { Test } from '@nestjs/testing'; import { getDataSourceToken } from '@nestjs/typeorm'; -import dayjs from 'dayjs'; +import { DateTime } from 'luxon'; import request from 'supertest'; import type { DataSource, Repository } from 'typeorm'; @@ -83,7 +83,11 @@ describe('AppController (e2e)', () => { hashPassword: faker.internet.password(), })), ) - ).sort((a, b) => dayjs(b.createdAt).diff(a.createdAt)); + ).sort((a, b) => + DateTime.fromJSDate(b.createdAt) + .diff(DateTime.fromJSDate(a.createdAt)) + .as('milliseconds'), + ); const { jwt, user } = await signInTestUser(dataSource, authService); accessToken = jwt.accessToken; @@ -96,7 +100,11 @@ describe('AppController (e2e)', () => { it('no query', async () => { const expectUsers = userEntities .concat(ownerUser) - .sort((a, b) => dayjs(b.createdAt).diff(a.createdAt)) + .sort((a, b) => + DateTime.fromJSDate(b.createdAt) + .diff(DateTime.fromJSDate(a.createdAt)) + .as('milliseconds'), + ) .map(({ id, email }) => ({ id, email, @@ -133,7 +141,11 @@ describe('AppController (e2e)', () => { const expectUsers = userEntities .concat(ownerUser) - .sort((a, b) => dayjs(b.createdAt).diff(a.createdAt)) + .sort((a, b) => + DateTime.fromJSDate(b.createdAt) + .diff(DateTime.fromJSDate(a.createdAt)) + .as('milliseconds'), + ) .map(({ id, email }) => ({ id, email,