DTO 공용화
This commit is contained in:
geonhee-min
2025-12-16 14:06:28 +09:00
parent ab0a229104
commit 1c8b3685b8
38 changed files with 712 additions and 4 deletions

27
.vscode/snippets.code-snippets vendored Normal file
View File

@@ -0,0 +1,27 @@
{
"RequestDTO": {
"prefix": "ReqDTO",
"body": [
"import { BaseRequestDTO } from '@BaseRequestDTO';",
"",
"export class ${1:DtoName}RequestDTO extends BaseRequestDTO {",
"$0",
"}"
]
},
"RequestField": {
"prefix": "ReqField",
"body": [
"@${1:Decorator}",
"${2:field}!: ${3:type};"
]
},
"ResponseDTO": {
"prefix": "ResDTO",
"body": [
"import type { BaseResponseDTO } from '@BaseResponseDTO';",
"",
"export type ${1:DtoName}ResponseDTO = BaseResponseDTO<${2:data}>;"
]
}
}

255
package-lock.json generated
View File

@@ -9,6 +9,9 @@
"version": "1.0.9",
"license": "ISC",
"dependencies": {
"@swc/core": "^1.15.5",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.3",
"date-fns": "^4.1.0",
"reflect-metadata": "^0.2.2",
"tsup": "^8.5.1"
@@ -755,6 +758,220 @@
"win32"
]
},
"node_modules/@swc/core": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.5.tgz",
"integrity": "sha512-VRy+AEO0zqUkwV9uOgqXtdI5tNj3y3BZI+9u28fHNjNVTtWYVNIq3uYhoGgdBOv7gdzXlqfHKuxH5a9IFAvopQ==",
"hasInstallScript": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@swc/counter": "^0.1.3",
"@swc/types": "^0.1.25"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/swc"
},
"optionalDependencies": {
"@swc/core-darwin-arm64": "1.15.5",
"@swc/core-darwin-x64": "1.15.5",
"@swc/core-linux-arm-gnueabihf": "1.15.5",
"@swc/core-linux-arm64-gnu": "1.15.5",
"@swc/core-linux-arm64-musl": "1.15.5",
"@swc/core-linux-x64-gnu": "1.15.5",
"@swc/core-linux-x64-musl": "1.15.5",
"@swc/core-win32-arm64-msvc": "1.15.5",
"@swc/core-win32-ia32-msvc": "1.15.5",
"@swc/core-win32-x64-msvc": "1.15.5"
},
"peerDependencies": {
"@swc/helpers": ">=0.5.17"
},
"peerDependenciesMeta": {
"@swc/helpers": {
"optional": true
}
}
},
"node_modules/@swc/core-darwin-arm64": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.5.tgz",
"integrity": "sha512-RvdpUcXrIz12yONzOdQrJbEnq23cOc2IHOU1eB8kPxPNNInlm4YTzZEA3zf3PusNpZZLxwArPVLCg0QsFQoTYw==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-darwin-x64": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.5.tgz",
"integrity": "sha512-ufJnz3UAff/8G5OfqZZc5cTQfGtXyXVLTB8TGT0xjkvEbfFg8jZUMDBnZT/Cn0k214JhMjiLCNl0A8aY/OKsYQ==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm-gnueabihf": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.5.tgz",
"integrity": "sha512-Yqu92wIT0FZKLDWes+69kBykX97hc8KmnyFwNZGXJlbKUGIE0hAIhbuBbcY64FGSwey4aDWsZ7Ojk89KUu9Kzw==",
"cpu": [
"arm"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-gnu": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.5.tgz",
"integrity": "sha512-3gR3b5V1abe/K1GpD0vVyZgqgV+ykuB5QNecDYzVroX4QuN+amCzQaNSsVM8Aj6DbShQCBTh3hGHd2f3vZ8gCw==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-musl": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.5.tgz",
"integrity": "sha512-Of+wmVh5h47tTpN9ghHVjfL0CJrgn99XmaJjmzWFW7agPdVY6gTDgkk6zQ6q4hcDQ7hXb0BGw6YFpuanBzNPow==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.5.tgz",
"integrity": "sha512-98kuPS0lZVgjmc/2uTm39r1/OfwKM0PM13ZllOAWi5avJVjRd/j1xA9rKeUzHDWt+ocH9mTCQsAT1jjKSq45bg==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-musl": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.5.tgz",
"integrity": "sha512-Rk+OtNQP3W/dZExL74LlaakXAQn6/vbrgatmjFqJPO4RZkq+nLo5g7eDUVjyojuERh7R2yhqNvZ/ZZQe8JQqqA==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-arm64-msvc": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.5.tgz",
"integrity": "sha512-e3RTdJ769+PrN25iCAlxmsljEVu6iIWS7sE21zmlSiipftBQvSAOWuCDv2A8cH9lm5pSbZtwk8AUpIYCNsj2oQ==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-ia32-msvc": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.5.tgz",
"integrity": "sha512-NmOdl6kyAw6zMz36zCdopTgaK2tcLA53NhUsTRopBc/796Fp87XdsslRHglybQ1HyXIGOQOKv2Y14IUbeci4BA==",
"cpu": [
"ia32"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-x64-msvc": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.5.tgz",
"integrity": "sha512-EPXJRf0A8eOi8woXf/qgVIWRl9yeSl0oN1ykGZNCGI7oElsfxUobJFmpJFJoVqKFfd1l0c+GPmWsN2xavTFkNw==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/counter": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
"license": "Apache-2.0"
},
"node_modules/@swc/types": {
"version": "0.1.25",
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz",
"integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==",
"license": "Apache-2.0",
"dependencies": {
"@swc/counter": "^0.1.3"
}
},
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -771,6 +988,12 @@
"undici-types": "~7.16.0"
}
},
"node_modules/@types/validator": {
"version": "13.15.10",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz",
"integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==",
"license": "MIT"
},
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
@@ -828,6 +1051,23 @@
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"license": "MIT"
},
"node_modules/class-validator": {
"version": "0.14.3",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz",
"integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==",
"license": "MIT",
"dependencies": {
"@types/validator": "^13.15.3",
"libphonenumber-js": "^1.11.1",
"validator": "^13.15.20"
}
},
"node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -972,6 +1212,12 @@
"node": ">=10"
}
},
"node_modules/libphonenumber-js": {
"version": "1.12.31",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.31.tgz",
"integrity": "sha512-Z3IhgVgrqO1S5xPYM3K5XwbkDasU67/Vys4heW+lfSBALcUZjeIIzI8zCLifY+OCzSq+fpDdywMDa7z+4srJPQ==",
"license": "MIT"
},
"node_modules/lilconfig": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
@@ -1370,6 +1616,15 @@
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"node_modules/validator": {
"version": "13.15.23",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz",
"integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
}
}
}

View File

@@ -6,7 +6,8 @@
"types": "dist/index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsup src/index.ts --dts --format cjs,esm"
"build": "tsup src/index.ts --dts --format cjs,esm",
"gen:dto": "node scripts/generate-dto.js"
},
"repository": {
"type": "git",
@@ -27,6 +28,9 @@
"typescript": "^5.9.3"
},
"dependencies": {
"@swc/core": "^1.15.5",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.3",
"date-fns": "^4.1.0",
"reflect-metadata": "^0.2.2",
"tsup": "^8.5.1"

39
scripts/generate-dto.js Normal file
View File

@@ -0,0 +1,39 @@
const fs = require('fs');
const path = require('path');
const targetProject = process.argv[2];
if (!targetProject) {
console.error('targetProject required');
process.exit(1);
}
const targetApi = process.argv[3];
if (!targetApi) {
console.error('targetApi required');
process.exit(1);
}
const name = process.argv[4];
if (!name) {
console.error('name required');
process.exit(1);
}
const nameKebab = name
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
.toLowerCase();
const baseDir = path.resolve('src', targetProject, 'http/dto', targetApi, name);
fs.mkdirSync(baseDir, {recursive: true});
fs.writeFileSync(
path.join(baseDir, `${nameKebab}-request.dto.ts`),
''
);
fs.writeFileSync(
path.join(baseDir, `${nameKebab}-response.dto.ts`),
''
);

View File

@@ -0,0 +1,2 @@
export const PasswordFormat = /^[a-z](?=.*[0-9])(?=.*[!@#$%^])[a-zA-z0-9!@#$%^]{8,12}$/;
export const PasswordFormatString = /^[a-z](?=.*[0-9])(?=.*[!@#$%^])[a-zA-z0-9!@#$%^]{8,12}$/.source;

View File

@@ -0,0 +1,36 @@
import { ValidatorConstraint, type ValidationArguments, type ValidatorConstraintInterface } from "class-validator";
@ValidatorConstraint({ name: 'accountCheckDuplicationValueValidator', async: false })
export class AccountCheckDuplicationValueValidator implements ValidatorConstraintInterface {
validate(value: any, args: ValidationArguments) {
const { type } = args.object as any;
if (type === 'email') {
return typeof value === 'string' && /\S+@\S+\.\S+/.test(value);
}
if (type === 'accountId') {
return typeof value === 'string';
}
return false;
}
}
@ValidatorConstraint({ name: 'loginIdValidator', async: false })
export class LoginIdValidator implements ValidatorConstraintInterface {
validate(value: any, args: ValidationArguments) {
const { type } = args.object as any;
if (type === 'email') {
return typeof value === 'string' && /\S+@\S+\.\S+/.test(value);
}
if (type === 'accountId') {
return typeof value === 'string';
}
return false;
}
}

View File

@@ -9,4 +9,6 @@ export * from './common/format/DateTimeFormat';
export * from './scheduler/http/HttpResponseMessage';
export * from './scheduler/http/HttpApiUrl';
export * from './scheduler/http/HttpApiUrl';
export * as DTO from './scheduler/http/dto';

View File

@@ -39,4 +39,4 @@ export const HttpApiUrl = {
read: '/read',
delete: '/delete'
}
}
} as const;

View File

@@ -0,0 +1,11 @@
import { IsIn, Validate } from 'class-validator';
import { BaseRequestDTO } from '@BaseRequestDTO';
import { AccountCheckDuplicationValueValidator } from 'src/common/validator/CustomValidators';
export class CheckDuplicationRequestDTO extends BaseRequestDTO {
@IsIn(['email', 'accountId'])
type!: 'email' | 'accountId';
@Validate(AccountCheckDuplicationValueValidator)
value!: string;
}

View File

@@ -0,0 +1,3 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type CheckDuplicationResponseDTO = BaseResponseDTO<{ isDuplicated: boolean }>;

View File

@@ -0,0 +1,16 @@
import { IsIn, IsString, Matches, Validate } from "class-validator";
import { BaseRequestDTO } from "../../base/base-request.dto";
import { LoginIdValidator } from "src/common/validator/CustomValidators";
import { PasswordFormat } from "src/common/format/PasswordFormat";
export class LoginRequestDTO extends BaseRequestDTO {
@IsIn(['email', 'accountId'])
type!: 'email' | 'accountId';
@Validate(LoginIdValidator)
id!: string;
@IsString()
@Matches(PasswordFormat)
password!: string;
}

View File

@@ -0,0 +1,8 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type LoginResponseDTO = BaseResponseDTO<
{
accessToken: string;
refreshToken: string;
}
>;

View File

@@ -0,0 +1,8 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type RefreshAccessTokenResponseDTO = BaseResponseDTO<
{
accessToken: string;
refreshToken: string;
}
>;

View File

@@ -0,0 +1,12 @@
import { IsEmail, IsString, Matches } from "class-validator";
import { BaseRequestDTO } from "../../base/base-request.dto";
import { PasswordFormat } from "src/common/format/PasswordFormat";
export class ResetPasswordRequestDTO extends BaseRequestDTO {
@IsEmail()
email!: string;
@IsString()
@Matches(PasswordFormat)
password!: string;
}

View File

@@ -0,0 +1,3 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type ResetPasswordResponseDTO = BaseResponseDTO<{ }>;

View File

@@ -0,0 +1,7 @@
import { IsEmail } from "class-validator";
import { BaseRequestDTO } from "../../base/base-request.dto";
export class SendEmailVerificationCodeRequestDTO extends BaseRequestDTO {
@IsEmail()
email!: string;
}

View File

@@ -0,0 +1,3 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type SendEmailVerificationCodeResponseDTO = BaseResponseDTO<{ }>;

View File

@@ -0,0 +1,7 @@
import { IsEmail } from "class-validator";
import { BaseRequestDTO } from "../../base/base-request.dto";
export class SendPasswordResetCodeRequestDTO extends BaseRequestDTO {
@IsEmail()
email!: string;
}

View File

@@ -0,0 +1,3 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type SendPasswordResetCodeResponseDTO = BaseResponseDTO<{ }>;

View File

@@ -0,0 +1,21 @@
import { BaseRequestDTO } from '@BaseRequestDTO';
import { IsEmail, IsString, Matches } from 'class-validator';
import { PasswordFormat } from 'src/common/format/PasswordFormat';
export class SignupRequestDTO extends BaseRequestDTO {
@IsEmail()
email!: string;
@IsString()
name!: string;
@IsString()
nickname!: string;
@IsString()
accoundId!: string;
@IsString()
@Matches(PasswordFormat)
password!: string;
}

View File

@@ -0,0 +1,3 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type SignupResponseDTO = BaseResponseDTO<{ }>;

View File

@@ -0,0 +1,10 @@
import { BaseRequestDTO } from '@BaseRequestDTO';
import { IsEmail, IsString } from 'class-validator';
export class VerifyEmailVerificationCodeRequestDTO extends BaseRequestDTO {
@IsEmail()
email!: string;
@IsString()
code!: string;
}

View File

@@ -0,0 +1,3 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type VerifyEmailVerificationCodeResponseDTO = BaseResponseDTO<{ verified: boolean }>;

View File

@@ -0,0 +1,10 @@
import { BaseRequestDTO } from '@BaseRequestDTO';
import { IsEmail, IsString } from 'class-validator';
export class VerifyPasswordResetCodeRequestDTO extends BaseRequestDTO {
@IsEmail()
email!: string;
@IsString()
code!: string;
}

View File

@@ -0,0 +1,3 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type VerifyPasswordResetCodeResponseDTO = BaseResponseDTO<{ verified: boolean }>;

View File

@@ -0,0 +1,9 @@
import { validate, type ValidationError } from "class-validator";
export class BaseRequestDTO {
async validateObject(): Promise<ValidationError[]> {
const errors = await validate(this);
return errors;
}
}

View File

@@ -0,0 +1,19 @@
export type SuccessResponse<T> = {
success: true;
message: string;
data: T;
error?: never;
code?: never;
}
export type ErrorResponse = {
success: false;
error: string;
code: string;
message?: never;
data?: never;
}
export type BaseResponseDTO<T> = SuccessResponse<T> | ErrorResponse;

View File

@@ -0,0 +1,33 @@
export { CheckDuplicationRequestDTO as CheckDuplicationRequest } from './account/checkDuplication/check-duplication-request.dto';
export type { CheckDuplicationResponseDTO as CheckDuplicationResponse } from './account/checkDuplication/check-duplication-response.dto';
export { LoginRequestDTO as LoginRequest } from './account/login/login-request.dto';
export type { LoginResponseDTO as LoginResponse } from './account/login/login-response.dto';
export type { RefreshAccessTokenResponseDTO as RefreshAccessTokenResponse } from './account/refreshAccessToken/refresh-access-token-response.dto';
export { ResetPasswordRequestDTO as ResetPasswordRequest } from './account/resetPassword/reset-password-request.dto';
export type { ResetPasswordResponseDTO as ResetPasswordResponse } from './account/resetPassword/reset-password-response.dto';
export { SendEmailVerificationCodeRequestDTO as SendEmailVerificationCodeRequest } from './account/sendEmailVerificationCode/send-email-verification-code-request.dto';
export type { SendEmailVerificationCodeResponseDTO as SendEmailVerificationCodeResponse } from './account/sendEmailVerificationCode/sned-email-verification-code-response.dto';
export { SendPasswordResetCodeRequestDTO as SendPasswordResetCodeRequest } from './account/sendPasswordResetCode/send-password-reset-code-request.dto';
export type { SendPasswordResetCodeResponseDTO as SendPasswordResetCodeResponse } from './account/sendPasswordResetCode/send-password-reset-code-response.dto';
export { SignupRequestDTO as SignupRequest } from './account/signup/signup-request.dto';
export type { SignupResponseDTO as SignupResponse } from './account/signup/signup-response.dto';
export { VerifyEmailVerificationCodeRequestDTO as VerifyEmailVerificationCodeRequest } from './account/verifyEmailVerificationCode/verify-email-verification-code-request.dto';
export type { VerifyEmailVerificationCodeResponseDTO as VerifyEmailVerificationCodeResponse } from './account/verifyEmailVerificationCode/verify-email-verification-code-response.dto';
export { VerifyPasswordResetCodeRequestDTO as VerifyPasswordResetCodeRequest } from './account/verifyPasswordResetCode/verify-password-reset-code-request.dto';
export type { VerifyPasswordResetCodeResponseDTO as VerifyPasswordResetCodeResponse } from './account/verifyPasswordResetCode/verify-password-reset-code.response.dto';
export { ScheduleCreateRequestDTO as ScheduleCreateRequest } from './schedule/create/create-request.dto';
export type { ScheduleCreateResponseDTO as ScheduleCreateResponse } from './schedule/create/create-response.dto';
export { ScheduleListRequestDTO as ScheduleListRequest } from './schedule/list/list-request.dto';
export type { ScheduleListResponseDTO as ScheduleListResponse, ScheduleList } from './schedule/list/list-response.dto';
export type { ScheduleDetailResponseDTO as ScheduleDetailResponse, ScheduleDetail } from './schedule/detail/detail-response.dto';

View File

@@ -0,0 +1,32 @@
import { BaseRequestDTO } from '@BaseRequestDTO';
import { IsArray, IsDateString, IsIn, IsString } from 'class-validator';
import { ScheduleTypeArray } from 'src/scheduler/type/schedule/ScheduleType';
export class ScheduleCreateRequestDTO extends BaseRequestDTO {
@IsString()
name!: string;
@IsDateString()
startDate!: string;
@IsDateString()
endDate!: string;
@IsIn(ScheduleTypeArray)
type!: string;
@IsString()
style!: string;
@IsString()
stratTime!: string;
@IsString()
endTime!: string;
@IsString()
dayList?: string;
@IsArray()
participantList?: string[];
}

View File

@@ -0,0 +1,3 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
export type ScheduleCreateResponseDTO = BaseResponseDTO<{ }>;

View File

@@ -0,0 +1,22 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
import type { ScheduleType } from 'src/scheduler/type/schedule/ScheduleType';
export type ScheduleDetail = {
id: string;
name: string;
startDate: Date;
endDate: Date;
status: string;
content?: string;
isDeleted: boolean;
type: ScheduleType;
createdAt: string;
owner: string;
style: string;
startTime: string;
endTime: string;
dayList?: string;
participantList?: string;
}
export type ScheduleDetailResponseDTO = BaseResponseDTO<ScheduleDetail>;

View File

@@ -0,0 +1,40 @@
import { BaseRequestDTO } from '@BaseRequestDTO';
import { IsArray, IsDateString, IsIn, IsNumberString, IsString, ValidateIf } from 'class-validator';
import { ScheduleStatusArray } from 'src/scheduler/type/schedule/ScheduleStatus';
import { ScheduleTypeArray } from 'src/scheduler/type/schedule/ScheduleType';
export class ScheduleListRequestDTO extends BaseRequestDTO {
@ValidateIf(o => o.date !== undefined)
@IsDateString()
date?: string;
@ValidateIf(o => o.startDate !== undefined)
@IsDateString()
startDate?: string;
@ValidateIf(o => o.endDate !== undefined)
@IsDateString()
endDate?: string;
@ValidateIf(o => o.styleList !== undefined)
@IsArray()
styleList?: string[];
@ValidateIf(o => o.typeList !== undefined)
@IsArray()
@IsIn(ScheduleTypeArray, { each: true})
typeList?: string[];
@ValidateIf(o => o.status !== undefined)
@IsString()
@IsIn(ScheduleStatusArray)
status?: string;
@ValidateIf(o => o.name !== undefined)
@IsString()
name?: string;
@ValidateIf(o => o.dayList !== undefined)
@IsNumberString()
dayList?: string;
}

View File

@@ -0,0 +1,15 @@
import type { BaseResponseDTO } from '@BaseResponseDTO';
import type { ScheduleStatus } from "src/scheduler/type/schedule/ScheduleStatus";
import type { ScheduleType } from "src/scheduler/type/schedule/ScheduleType";
export type ScheduleList = {
name: string;
id: string;
startDate: Date;
endDate: Date;
type: ScheduleType;
style: string;
status: ScheduleStatus;
}
export type ScheduleListResponseDTO = BaseResponseDTO<ScheduleList>;

View File

@@ -0,0 +1,13 @@
export const ScheduleDay: Record<string, string> = {
1: '일',
2: '월',
3: '화',
4: '수',
5: '목',
6: '금',
7: '토'
} as const;
export const ScheduleDayArray = '1234567'.split('');
export const ScheduleDayLabelArray = '일월화수목금토'.split('');

View File

@@ -0,0 +1,8 @@
export type ScheduleStatus = 'yet' | 'completed';
export const ScheduleStatusLabel: Record<ScheduleStatus, string> = {
'yet': '미완료',
'completed': '완료'
} as const;
export const ScheduleStatusArray = ['yet', 'completed'] as const;

View File

@@ -0,0 +1,11 @@
export type ScheduleType = 'once' | 'daily' | 'weekly' | 'monthly' | 'annual';
export const ScheduleTypeLabel: Record<ScheduleType, string> = {
'once': '반복없음',
'daily': '매일',
'weekly': '매주',
'monthly': '매달',
'annual': '매년'
} as const;
export const ScheduleTypeArray = ['once', 'daily', 'weekly', 'monthly', 'annual'] as const;

View File

@@ -44,7 +44,14 @@
"moduleDetection": "force",
"skipLibCheck": true,
"baseUrl": ".",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"paths": {
"@/*": ["src./*"],
"@BaseRequestDTO": ["src/scheduler/http/dto/base/base-request.dto.ts"],
"@BaseResponseDTO": ["src/scheduler/http/dto/base/base-response.dto.ts"]
}
},
"include": ["src/**/*"],
"include": ["src/**/*", "scripts"],
"exclude": ["node-modules", "dist", "**/*.spec.ts"]
}