From de88864f4040d1174eca586f7cdf2740e7e7dea1 Mon Sep 17 00:00:00 2001 From: useruseruse Date: Wed, 31 Jul 2024 22:05:58 +0900 Subject: [PATCH 1/7] setup --- src/bootstrap/bootstrap.ts | 7 +++++++ src/bootstrap/nest-cli.json | 5 ++++- src/settings.ts | 11 +++++++++++ tsconfig.json | 7 ++++++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.ts b/src/bootstrap/bootstrap.ts index a178ab3c..8b704a72 100644 --- a/src/bootstrap/bootstrap.ts +++ b/src/bootstrap/bootstrap.ts @@ -6,6 +6,7 @@ import { Server } from 'http'; import { AppModule } from '../app.module'; import { PrismaService } from '../prisma/prisma.service'; import settings from '../settings'; +import { SwaggerModule } from '@nestjs/swagger'; // import { AuthGuard, MockAuthGuard } from '../../common/guards/auth.guard' import morgan = require('morgan'); @@ -60,6 +61,12 @@ async function bootstrap() { }), ); + const document = SwaggerModule.createDocument( + app, + settings().getSwaggerConfig(), + ); + SwaggerModule.setup('docs', app, document); + const prismaService = app.get(PrismaService); await prismaService.enableShutdownHooks(app); return app.listen(8000); diff --git a/src/bootstrap/nest-cli.json b/src/bootstrap/nest-cli.json index 4ffcb8d8..dba574f0 100644 --- a/src/bootstrap/nest-cli.json +++ b/src/bootstrap/nest-cli.json @@ -1,5 +1,8 @@ { "collection": "@nestjs/schematics", "sourceRoot": "src", - "entryFile": "src/bootstrap/bootstrap" + "entryFile": "src/bootstrap/bootstrap", + "compilerOptions": { + "plugins": ["@nestjs/swagger/plugin"] + } } diff --git a/src/settings.ts b/src/settings.ts index 0b77ef65..0c519695 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,6 +1,7 @@ import dotenv from 'dotenv'; import { PrismaClientOptions } from 'prisma/prisma-client/runtime'; import { dotEnvOptions } from './dotenv-options'; +import { DocumentBuilder } from '@nestjs/swagger'; dotenv.config(dotEnvOptions); console.log(`NODE_ENV environment: ${process.env.NODE_ENV}`); @@ -15,6 +16,7 @@ export default () => { getSsoConfig: () => getSsoConfig(), getCorsConfig: () => getCorsConfig(), getVersion: () => getVersion(), + getSwaggerConfig: () => getSwaggerConfig(), }; }; @@ -77,3 +79,12 @@ const getSsoConfig = (): any => { const getVersion = () => { return String(process.env.npm_package_version); }; + +const getSwaggerConfig = () => { + const config = new DocumentBuilder() + .setTitle('OTLPlus-server') + .setDescription('The OTL-server API description') + .setVersion('1.0') + .build(); + return config; +}; diff --git a/tsconfig.json b/tsconfig.json index defa8007..7d18871c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,5 +19,10 @@ "noImplicitAny": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": false - } + }, + "plugins": [ + { + "name": "@nestjs/swagger/plugin" + } + ] } From 96e0309e975d2d2f3b40a70c3efe4dcdd1660e1a Mon Sep 17 00:00:00 2001 From: useruseruse Date: Wed, 31 Jul 2024 22:05:58 +0900 Subject: [PATCH 2/7] setup --- src/bootstrap/bootstrap.ts | 7 +++++++ src/bootstrap/nest-cli.json | 5 ++++- src/settings.ts | 11 +++++++++++ tsconfig.json | 7 ++++++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.ts b/src/bootstrap/bootstrap.ts index a178ab3c..8b704a72 100644 --- a/src/bootstrap/bootstrap.ts +++ b/src/bootstrap/bootstrap.ts @@ -6,6 +6,7 @@ import { Server } from 'http'; import { AppModule } from '../app.module'; import { PrismaService } from '../prisma/prisma.service'; import settings from '../settings'; +import { SwaggerModule } from '@nestjs/swagger'; // import { AuthGuard, MockAuthGuard } from '../../common/guards/auth.guard' import morgan = require('morgan'); @@ -60,6 +61,12 @@ async function bootstrap() { }), ); + const document = SwaggerModule.createDocument( + app, + settings().getSwaggerConfig(), + ); + SwaggerModule.setup('docs', app, document); + const prismaService = app.get(PrismaService); await prismaService.enableShutdownHooks(app); return app.listen(8000); diff --git a/src/bootstrap/nest-cli.json b/src/bootstrap/nest-cli.json index 4ffcb8d8..dba574f0 100644 --- a/src/bootstrap/nest-cli.json +++ b/src/bootstrap/nest-cli.json @@ -1,5 +1,8 @@ { "collection": "@nestjs/schematics", "sourceRoot": "src", - "entryFile": "src/bootstrap/bootstrap" + "entryFile": "src/bootstrap/bootstrap", + "compilerOptions": { + "plugins": ["@nestjs/swagger/plugin"] + } } diff --git a/src/settings.ts b/src/settings.ts index 0b77ef65..0c519695 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,6 +1,7 @@ import dotenv from 'dotenv'; import { PrismaClientOptions } from 'prisma/prisma-client/runtime'; import { dotEnvOptions } from './dotenv-options'; +import { DocumentBuilder } from '@nestjs/swagger'; dotenv.config(dotEnvOptions); console.log(`NODE_ENV environment: ${process.env.NODE_ENV}`); @@ -15,6 +16,7 @@ export default () => { getSsoConfig: () => getSsoConfig(), getCorsConfig: () => getCorsConfig(), getVersion: () => getVersion(), + getSwaggerConfig: () => getSwaggerConfig(), }; }; @@ -77,3 +79,12 @@ const getSsoConfig = (): any => { const getVersion = () => { return String(process.env.npm_package_version); }; + +const getSwaggerConfig = () => { + const config = new DocumentBuilder() + .setTitle('OTLPlus-server') + .setDescription('The OTL-server API description') + .setVersion('1.0') + .build(); + return config; +}; diff --git a/tsconfig.json b/tsconfig.json index defa8007..7d18871c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,5 +19,10 @@ "noImplicitAny": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": false - } + }, + "plugins": [ + { + "name": "@nestjs/swagger/plugin" + } + ] } From be20dc1df054bef41f79acfebc76feaf061088f2 Mon Sep 17 00:00:00 2001 From: LarryKwon <65128957+LarryKwon@users.noreply.github.com> Date: Sat, 3 Aug 2024 21:58:44 +0900 Subject: [PATCH 3/7] Add: add api response type to all controllers/method --- src/common/entities/ECourse.ts | 5 ++ src/common/entities/EReview.ts | 5 ++ src/common/entities/EUser.ts | 6 ++ src/modules/auth/auth.controller.ts | 11 ++-- src/modules/courses/courses.controller.ts | 21 ++++--- src/modules/courses/courses.service.ts | 17 ++++-- src/modules/lectures/lectures.controller.ts | 12 ++-- src/modules/notices/notices.controller.ts | 3 +- src/modules/planners/planners.controller.ts | 10 ++-- src/modules/planners/planners.service.ts | 2 +- src/modules/reviews/reviews.controller.ts | 8 ++- src/modules/reviews/reviews.service.ts | 10 +++- src/modules/semesters/semesters.controller.ts | 4 +- src/modules/session/session.controller.ts | 11 +++- src/modules/session/session.service.ts | 6 +- src/modules/share/share.controller.ts | 4 +- src/modules/status/status.controller.ts | 2 +- .../timetables/timetables.controller.ts | 18 +++--- src/modules/timetables/timetables.service.ts | 56 ++++++++++--------- src/modules/tracks/tracks.controller.ts | 7 ++- src/modules/tracks/tracks.service.ts | 7 ++- src/prisma/repositories/course.repository.ts | 6 +- src/prisma/repositories/review.repository.ts | 9 ++- .../repositories/timetable.repository.ts | 5 +- src/prisma/repositories/user.repository.ts | 6 +- 25 files changed, 164 insertions(+), 87 deletions(-) create mode 100644 src/common/entities/EUser.ts diff --git a/src/common/entities/ECourse.ts b/src/common/entities/ECourse.ts index 811ca754..4fc55103 100644 --- a/src/common/entities/ECourse.ts +++ b/src/common/entities/ECourse.ts @@ -19,4 +19,9 @@ export namespace ECourse { }, }); export type Details = Prisma.subject_courseGetPayload; + + export namespace ECourseUser { + export const Basic = Prisma.validator()({}); + export type Basic = Prisma.subject_courseuserGetPayload; + } } diff --git a/src/common/entities/EReview.ts b/src/common/entities/EReview.ts index cc234ee6..40e1ea17 100644 --- a/src/common/entities/EReview.ts +++ b/src/common/entities/EReview.ts @@ -14,4 +14,9 @@ export namespace EReview { }, }); export type Details = Prisma.review_reviewGetPayload; + + export namespace EReviewVote { + export const Basic = Prisma.validator()({}); + export type Basic = Prisma.review_reviewvoteGetPayload; + } } diff --git a/src/common/entities/EUser.ts b/src/common/entities/EUser.ts new file mode 100644 index 00000000..865bac92 --- /dev/null +++ b/src/common/entities/EUser.ts @@ -0,0 +1,6 @@ +import { Prisma } from '@prisma/client'; + +export namespace EUser { + export const Basic = Prisma.validator()({}); + export type Basic = Prisma.session_userprofileGetPayload; +} diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index 48a8a952..32cc20cd 100644 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -34,7 +34,7 @@ export class AuthController { @Query('social_login') social_login: string, @Req() req: IAuth.Request, @Res() res: IAuth.Response, - ) { + ): void { if (req.user) { return res.redirect(next ?? '/'); } @@ -54,7 +54,7 @@ export class AuthController { @Query('code') code: string, @Session() session: Record, @Res() response: IAuth.Response, - ) { + ): Promise { const stateBefore = session['sso_state']; if (!stateBefore || stateBefore != state) { response.redirect('/error/invalid-login'); @@ -95,7 +95,10 @@ export class AuthController { @Public() @Get('/') - async home(@Req() req: IAuth.Request, @Res() res: IAuth.Response) { + async home( + @Req() req: IAuth.Request, + @Res() res: IAuth.Response, + ): Promise { return res.redirect('/session/login'); } @@ -106,7 +109,7 @@ export class AuthController { @Res() res: IAuth.Response, @Query('next') next: string, @GetUser() user: session_userprofile, - ) { + ): Promise { const webURL = process.env.WEB_URL; if (user) { const sid = user.sid; diff --git a/src/modules/courses/courses.controller.ts b/src/modules/courses/courses.controller.ts index 003b3a5f..f5f00d73 100644 --- a/src/modules/courses/courses.controller.ts +++ b/src/modules/courses/courses.controller.ts @@ -2,8 +2,11 @@ import { Controller, Get, Param, Post, Query } from '@nestjs/common'; import { session_userprofile } from '@prisma/client'; import { GetUser } from 'src/common/decorators/get-user.decorator'; import { Public } from 'src/common/decorators/skip-auth.decorator'; -import { ICourse } from 'src/common/interfaces'; +import { ICourse, ILecture } from 'src/common/interfaces'; import { CoursesService } from './courses.service'; +import { IReview } from '../../common/interfaces/IReview'; +import { ECourse } from '../../common/entities/ECourse'; +import ECourseUser = ECourse.ECourseUser; @Controller('api/courses') export class CourseController { @@ -14,13 +17,15 @@ export class CourseController { async getCourses( @Query() query: ICourse.Query, @GetUser() user: session_userprofile, - ) { + ): Promise { const courses = await this.coursesService.getCourses(query, user); return courses; } @Get('autocomplete') - async getCourseAutocomplete(@Query() query: ICourse.AutocompleteQueryDto) { + async getCourseAutocomplete( + @Query() query: ICourse.AutocompleteQueryDto, + ): Promise { return await this.coursesService.getCourseAutocomplete(query); } @@ -29,7 +34,7 @@ export class CourseController { async getCourseById( @Param('id') id: number, @GetUser() user: session_userprofile, - ) { + ): Promise { return await this.coursesService.getCourseById(id, user); } @@ -37,7 +42,7 @@ export class CourseController { async getLecturesByCourseId( @Query() query: { order: string[] }, @Param('id') id: number, - ) { + ): Promise { return await this.coursesService.getLecturesByCourseId(query, id); } @@ -47,7 +52,7 @@ export class CourseController { @Query() query: ICourse.ReviewQueryDto, @Param('id') id: number, @GetUser() user: session_userprofile, - ) { + ): Promise { return await this.coursesService.getReviewsByCourseId(query, id, user); } @@ -55,7 +60,7 @@ export class CourseController { async readCourse( @Param('id') id: number, @GetUser() user: session_userprofile, - ) { - await this.coursesService.readCourse(user.id, id); + ): Promise { + return await this.coursesService.readCourse(user.id, id); } } diff --git a/src/modules/courses/courses.service.ts b/src/modules/courses/courses.service.ts index 65f55045..80eb4526 100644 --- a/src/modules/courses/courses.service.ts +++ b/src/modules/courses/courses.service.ts @@ -10,6 +10,8 @@ import { } from '../../common/interfaces/serializer/course.serializer'; import { getRepresentativeLecture } from '../../common/utils/lecture.utils'; import { CourseRepository } from './../../prisma/repositories/course.repository'; +import { IReview } from '../../common/interfaces/IReview'; +import ECourseUser = ECourse.ECourseUser; @Injectable() export class CoursesService { @@ -79,7 +81,7 @@ export class CoursesService { query: ICourse.ReviewQueryDto, id: number, user: session_userprofile, - ) { + ): Promise { query.limit = query.limit ?? 100; query.offset = query.offset ?? 0; query.order = query.order ?? [ @@ -96,7 +98,9 @@ export class CoursesService { return reviews.map((review) => toJsonReview(review, user)); } - async getCourseAutocomplete(dto: ICourse.AutocompleteQueryDto) { + async getCourseAutocomplete( + dto: ICourse.AutocompleteQueryDto, + ): Promise { const candidate = await this.courseRepository.getCourseAutocomplete(dto); if (!candidate) return dto.keyword; return this.findAutocompleteFromCandidate(candidate, dto.keyword); @@ -105,7 +109,7 @@ export class CoursesService { private findAutocompleteFromCandidate( candidate: ECourse.Extended, keyword: string, - ) { + ): string | undefined { const keywordLower = keyword.toLowerCase(); if (candidate.subject_department.name.startsWith(keyword)) return candidate.subject_department.name; @@ -130,7 +134,10 @@ export class CoursesService { } } - async readCourse(userId: number, courseId: number) { - await this.courseRepository.readCourse(userId, courseId); + async readCourse( + userId: number, + courseId: number, + ): Promise { + return await this.courseRepository.readCourse(userId, courseId); } } diff --git a/src/modules/lectures/lectures.controller.ts b/src/modules/lectures/lectures.controller.ts index 8cdec84e..71e976b5 100644 --- a/src/modules/lectures/lectures.controller.ts +++ b/src/modules/lectures/lectures.controller.ts @@ -11,18 +11,22 @@ export class LecturesController { constructor(private readonly LectureService: LecturesService) {} @Get() - async getLectures(@Query() query: ILecture.QueryDto) { + async getLectures( + @Query() query: ILecture.QueryDto, + ): Promise { return await this.LectureService.getLectureByFilter(query); } @Public() @Get('autocomplete') - async getLectureAutocomplete(@Query() query: ILecture.AutocompleteQueryDto) { + async getLectureAutocomplete( + @Query() query: ILecture.AutocompleteQueryDto, + ): Promise { return await this.LectureService.getLectureAutocomplete(query); } @Get(':id') - async getLectureById(@Param('id') id: number) { + async getLectureById(@Param('id') id: number): Promise { return await this.LectureService.getLectureById(id); } @@ -32,7 +36,6 @@ export class LecturesController { @Query() query: IReview.LectureReviewsQueryDto, @Param('lectureId') lectureId: number, @GetUser() user: session_userprofile, - // TODO: Consider using IReview.Basic ): Promise<(IReview.Basic & { userspecific_is_liked: boolean })[]> { return await this.LectureService.getLectureReviews(user, lectureId, query); } @@ -43,7 +46,6 @@ export class LecturesController { @Query() query: IReview.LectureReviewsQueryDto, @Param('lectureId') lectureId: number, @GetUser() user: session_userprofile, - // TODO: Consider using IReview.Basic ): Promise<(IReview.Basic & { userspecific_is_liked: boolean })[]> { return await this.LectureService.getLectureRelatedReviews( user, diff --git a/src/modules/notices/notices.controller.ts b/src/modules/notices/notices.controller.ts index 0dc17673..503d16a3 100644 --- a/src/modules/notices/notices.controller.ts +++ b/src/modules/notices/notices.controller.ts @@ -2,6 +2,7 @@ import { Controller, Get } from '@nestjs/common'; import { Public } from 'src/common/decorators/skip-auth.decorator'; import { toJsonNoticeBasic } from 'src/common/interfaces/serializer/notices.serializer'; import { NoticesService } from './notices.service'; +import { INotice } from '../../common/interfaces/INotice'; @Controller('api/notices') export class NoticesController { @@ -9,7 +10,7 @@ export class NoticesController { @Public() @Get() - async getNotices() { + async getNotices(): Promise { const notices = await this.noticesService.getNotices(); return notices.map(toJsonNoticeBasic); diff --git a/src/modules/planners/planners.controller.ts b/src/modules/planners/planners.controller.ts index d9645904..6c0d8a7e 100644 --- a/src/modules/planners/planners.controller.ts +++ b/src/modules/planners/planners.controller.ts @@ -22,7 +22,7 @@ export class PlannersController { @Query() query: IPlanner.QueryDto, @Param('id') id: number, @GetUser() user: session_userprofile, - ) { + ): Promise { if (id !== user.id) { throw new UnauthorizedException(); } @@ -35,7 +35,7 @@ export class PlannersController { @Body() planner: IPlanner.CreateBodyDto, @Param('id') id: number, @GetUser() user: session_userprofile, - ) { + ): Promise { if (id !== user.id) { throw new UnauthorizedException(); } @@ -50,7 +50,7 @@ export class PlannersController { @Param('plannerId') plannerId: number, @Body() item: IPlanner.AddArbitraryItemDto, @GetUser() user: session_userprofile, - ) { + ): Promise { if (id !== user.id) throw new UnauthorizedException(); const newPlanner = await this.plannersService.addArbitraryItem( @@ -80,7 +80,7 @@ export class PlannersController { @Param('id') userId: number, @Param('plannerId') plannerId: number, @GetUser() user: session_userprofile, - ) { + ): Promise { if (userId !== user.id) { throw new UnauthorizedException(); } @@ -112,7 +112,7 @@ export class PlannersController { @Param('plannerId') plannerId: number, @GetUser() user: session_userprofile, @Body() updateItemDto: IPlanner.UpdateItemBodyDto, - ) { + ): Promise { if (userId !== user.id) { throw new UnauthorizedException(); } diff --git a/src/modules/planners/planners.service.ts b/src/modules/planners/planners.service.ts index e9228f67..3bb17c7e 100644 --- a/src/modules/planners/planners.service.ts +++ b/src/modules/planners/planners.service.ts @@ -119,7 +119,7 @@ export class PlannersService { plannerId: number, body: IPlanner.AddArbitraryItemDto, user: session_userprofile, - ) { + ): Promise { const planner = await this.PlannerRepository.getBasicPlannerById(plannerId); if (!planner) throw new NotFoundException(); if (planner.user_id !== user.id) throw new UnauthorizedException(); diff --git a/src/modules/reviews/reviews.controller.ts b/src/modules/reviews/reviews.controller.ts index e160ada1..a05c65a0 100644 --- a/src/modules/reviews/reviews.controller.ts +++ b/src/modules/reviews/reviews.controller.ts @@ -14,6 +14,8 @@ import { GetUser } from 'src/common/decorators/get-user.decorator'; import { Public } from 'src/common/decorators/skip-auth.decorator'; import { IReview } from 'src/common/interfaces/IReview'; import { ReviewsService } from './reviews.service'; +import { EReview } from '../../common/entities/EReview'; +import EReviewVote = EReview.EReviewVote; @Controller('api/reviews') export class ReviewsController { @@ -78,13 +80,13 @@ export class ReviewsController { async likeReviewInstance( @Param('reviewId') reviewId: number, @GetUser() user: session_userprofile, - ) { + ): Promise { const reviewVote = await this.reviewsService.findReviewVote(reviewId, user); if (reviewVote) { throw new HttpException('Already Liked', HttpStatus.BAD_REQUEST); } else { - await this.reviewsService.createReviewVote(reviewId, user); - return null; + const result = await this.reviewsService.createReviewVote(reviewId, user); + return result; } } } diff --git a/src/modules/reviews/reviews.service.ts b/src/modules/reviews/reviews.service.ts index 90f324bf..92a9a6bc 100644 --- a/src/modules/reviews/reviews.service.ts +++ b/src/modules/reviews/reviews.service.ts @@ -4,6 +4,8 @@ import { IReview } from 'src/common/interfaces/IReview'; import { toJsonReview } from 'src/common/interfaces/serializer/review.serializer'; import { LectureRepository } from 'src/prisma/repositories/lecture.repository'; import { ReviewsRepository } from 'src/prisma/repositories/review.repository'; +import { EReview } from '../../common/entities/EReview'; +import EReviewVote = EReview.EReviewVote; @Injectable() export class ReviewsService { @@ -162,8 +164,10 @@ export class ReviewsService { return isLiked; } - async createReviewVote(reviewId: number, user: session_userprofile) { - await this.reviewsRepository.upsertReviewVote(reviewId, user.id); - return null; + async createReviewVote( + reviewId: number, + user: session_userprofile, + ): Promise { + return await this.reviewsRepository.upsertReviewVote(reviewId, user.id); } } diff --git a/src/modules/semesters/semesters.controller.ts b/src/modules/semesters/semesters.controller.ts index 8ddaa0ee..8e1f63d1 100644 --- a/src/modules/semesters/semesters.controller.ts +++ b/src/modules/semesters/semesters.controller.ts @@ -8,7 +8,9 @@ export class SemestersController { constructor(private readonly semestersService: SemestersService) {} @Get() - async getSemesters(@Query() query: ISemester.QueryDto) { + async getSemesters( + @Query() query: ISemester.QueryDto, + ): Promise { const semesters = await this.semestersService.getSemesters(query); return semesters.map((semester) => toJsonSemester(semester)); } diff --git a/src/modules/session/session.controller.ts b/src/modules/session/session.controller.ts index 4f5c8c73..d70e262d 100644 --- a/src/modules/session/session.controller.ts +++ b/src/modules/session/session.controller.ts @@ -5,6 +5,8 @@ import { ISession } from 'src/common/interfaces/ISession'; import { toJsonDepartment } from 'src/common/interfaces/serializer/department.serializer'; import { DepartmentsService } from '../departments/departments.service'; import { SessionService } from './session.service'; +import { IDepartment } from '../../common/interfaces/IDepartment'; +import { EUser } from '../../common/entities/EUser'; @Controller('session') export class SessionController { @@ -14,7 +16,7 @@ export class SessionController { ) {} @Get('department-options') - async departmentOptions() { + async departmentOptions(): Promise { const { undergraduate, recent, other } = await this.departmentsService.getDepartmentOptions(); return [ @@ -28,8 +30,11 @@ export class SessionController { async favoriteDepartments( @Body() body: ISession.FavoriteDepartmentsDto, @GetUser() user: session_userprofile, - ) { + ): Promise { const departmentIds = body.fav_department.map((id) => parseInt(id)); - await this.sessionService.changeFavoriteDepartments(user.id, departmentIds); + return await this.sessionService.changeFavoriteDepartments( + user.id, + departmentIds, + ); } } diff --git a/src/modules/session/session.service.ts b/src/modules/session/session.service.ts index 5e9490e9..0d4f3251 100644 --- a/src/modules/session/session.service.ts +++ b/src/modules/session/session.service.ts @@ -1,11 +1,15 @@ import { Injectable } from '@nestjs/common'; import { UserRepository } from 'src/prisma/repositories/user.repository'; +import { EUser } from '../../common/entities/EUser'; @Injectable() export class SessionService { constructor(private readonly userRepository: UserRepository) {} - async changeFavoriteDepartments(userId: number, departmentIds: number[]) { + async changeFavoriteDepartments( + userId: number, + departmentIds: number[], + ): Promise { return await this.userRepository.changeFavoriteDepartments( userId, departmentIds, diff --git a/src/modules/share/share.controller.ts b/src/modules/share/share.controller.ts index 54af6f38..6d7e9463 100644 --- a/src/modules/share/share.controller.ts +++ b/src/modules/share/share.controller.ts @@ -18,7 +18,7 @@ export class ShareController { @Query() query: IShare.TimetableImageQueryDto, @GetUser() user: session_userprofile, @Res() res: Response, - ) { + ): Promise { const imageBuffer = await this.shareService.createTimetableImage( query, user, @@ -32,7 +32,7 @@ export class ShareController { @Query() query: IShare.TimetableIcalQueryDto, @GetUser() user: session_userprofile, @Res() res: Response, - ) { + ): Promise { const calendar = await this.shareService.createTimetableIcal(query, user); res.setHeader('Content-Type', 'text/calendar'); res.send(calendar.toString()); diff --git a/src/modules/status/status.controller.ts b/src/modules/status/status.controller.ts index 773d8281..742e3553 100644 --- a/src/modules/status/status.controller.ts +++ b/src/modules/status/status.controller.ts @@ -3,7 +3,7 @@ import { Controller, Get } from '@nestjs/common'; @Controller('api/status') export class StatusController { @Get() - getStatus() { + getStatus(): string { return 'I am Healthy!'; } } diff --git a/src/modules/timetables/timetables.controller.ts b/src/modules/timetables/timetables.controller.ts index 013c5192..3b416c81 100644 --- a/src/modules/timetables/timetables.controller.ts +++ b/src/modules/timetables/timetables.controller.ts @@ -13,6 +13,7 @@ import { GetUser } from '../../common/decorators/get-user.decorator'; import { toJsonTimetable } from '../../common/interfaces/serializer/timetable.serializer'; import { LecturesService } from '../lectures/lectures.service'; import { TimetablesService } from './timetables.service'; +import { ETimetable } from '../../common/entities/ETimetable'; @Controller('/api/users/:userId/timetables') export class TimetablesController { @@ -26,7 +27,7 @@ export class TimetablesController { @Param('userId') userId: number, @Query() query: ITimetable.QueryDto, @GetUser() user: session_userprofile, - ) { + ): Promise { const timeTableList = await this.timetablesService.getTimetables( query, user, @@ -39,7 +40,7 @@ export class TimetablesController { @Param('userId') userId: number, @Param('timetableId') timetableId: number, @GetUser() user: session_userprofile, - ) { + ): Promise { const timeTable = await this.timetablesService.getTimetable(timetableId); return toJsonTimetable(timeTable); } @@ -49,16 +50,15 @@ export class TimetablesController { @Param('userId') userId: number, @Param('timetableId') timetableId: number, @GetUser() user: session_userprofile, - ) { - await this.timetablesService.deleteTimetable(user, timetableId); - return null; + ): Promise { + return await this.timetablesService.deleteTimetable(user, timetableId); } @Post() async createTimetable( @Body() timeTableBody: ITimetable.CreateDto, @GetUser() user: session_userprofile, - ) { + ): Promise { const timeTable = await this.timetablesService.createTimetable( timeTableBody, user, @@ -70,7 +70,7 @@ export class TimetablesController { async addLectureToTimetable( @Param('timetableId') timetableId: number, @Body() body: ITimetable.AddLectureDto, - ) { + ): Promise { const timeTable = await this.timetablesService.addLectureToTimetable( timetableId, body, @@ -82,7 +82,7 @@ export class TimetablesController { async removeLectureFromTimetable( @Param('timetableId') timetableId: number, @Body() body: ITimetable.AddLectureDto, - ) { + ): Promise { const timeTable = await this.timetablesService.removeLectureFromTimetable( timetableId, body, @@ -101,7 +101,7 @@ export class TimetablesController { @Param('timetableId') timetableId: number, @Body() body: ITimetable.ReorderTimetableDto, @GetUser() user: session_userprofile, - ) { + ): Promise { const timeTable = await this.timetablesService.reorderTimetable( user, timetableId, diff --git a/src/modules/timetables/timetables.service.ts b/src/modules/timetables/timetables.service.ts index a6bc3f1c..97961404 100644 --- a/src/modules/timetables/timetables.service.ts +++ b/src/modules/timetables/timetables.service.ts @@ -15,6 +15,7 @@ import { PrismaService } from '../../prisma/prisma.service'; import { LectureRepository } from '../../prisma/repositories/lecture.repository'; import { SemesterRepository } from '../../prisma/repositories/semester.repository'; import { TimetableRepository } from '../../prisma/repositories/timetable.repository'; +import { ETimetable } from '../../common/entities/ETimetable'; @Injectable() export class TimetablesService { @@ -156,33 +157,34 @@ export class TimetablesService { return await this.timetableRepository.getTimeTableById(timeTableId); } - async deleteTimetable(user: session_userprofile, timetableId: number) { - return await this.prismaService.$transaction(async (tx) => { - const { semester, year, arrange_order } = - await this.timetableRepository.getTimeTableById(timetableId); - await this.timetableRepository.deleteById(timetableId); - const relatedTimeTables = await this.timetableRepository.getTimetables( - user, - year, - semester, - ); - const timeTablesToBeUpdated = relatedTimeTables - .filter((timeTable) => timeTable.arrange_order > arrange_order) - .map((timeTable) => { - return { - id: timeTable.id, - arrange_order: timeTable.arrange_order - 1, - }; - }); - await Promise.all( - timeTablesToBeUpdated.map(async (updateElem) => { - return this.timetableRepository.updateOrder( - updateElem.id, - updateElem.arrange_order, - ); - }), - ); - }); + async deleteTimetable( + user: session_userprofile, + timetableId: number, + ): Promise { + const { semester, year, arrange_order } = + await this.timetableRepository.getTimeTableById(timetableId); + await this.timetableRepository.deleteById(timetableId); + const relatedTimeTables = await this.timetableRepository.getTimetables( + user, + year, + semester, + ); + const timeTablesToBeUpdated = relatedTimeTables + .filter((timeTable) => timeTable.arrange_order > arrange_order) + .map((timeTable) => { + return { + id: timeTable.id, + arrange_order: timeTable.arrange_order - 1, + }; + }); + return await Promise.all( + timeTablesToBeUpdated.map(async (updateElem) => { + return this.timetableRepository.updateOrder( + updateElem.id, + updateElem.arrange_order, + ); + }), + ); } async reorderTimetable( diff --git a/src/modules/tracks/tracks.controller.ts b/src/modules/tracks/tracks.controller.ts index bcde01c2..44a8c900 100644 --- a/src/modules/tracks/tracks.controller.ts +++ b/src/modules/tracks/tracks.controller.ts @@ -1,12 +1,17 @@ import { Controller, Get } from '@nestjs/common'; import { TracksService } from './tracks.service'; +import { IPlanner } from '../../common/interfaces/IPlanner'; @Controller('/api/tracks') export class TracksController { constructor(private readonly tracksService: TracksService) {} @Get() - async getTracks() { + async getTracks(): Promise<{ + general: IPlanner.ITrack.General[]; + major: IPlanner.ITrack.Major[]; + additional: IPlanner.ITrack.Additional[]; + }> { return await this.tracksService.getAllTrack(); } } diff --git a/src/modules/tracks/tracks.service.ts b/src/modules/tracks/tracks.service.ts index 86e98b12..5aa9b3df 100644 --- a/src/modules/tracks/tracks.service.ts +++ b/src/modules/tracks/tracks.service.ts @@ -5,12 +5,17 @@ import { toJsonMajorTrack, } from 'src/common/interfaces/serializer/track.serializer'; import { TracksRepository } from 'src/prisma/repositories/track.repository'; +import { IPlanner } from '../../common/interfaces/IPlanner'; @Injectable() export class TracksService { constructor(private readonly TracksRepository: TracksRepository) {} - public async getAllTrack() { + public async getAllTrack(): Promise<{ + general: IPlanner.ITrack.General[]; + major: IPlanner.ITrack.Major[]; + additional: IPlanner.ITrack.Additional[]; + }> { const { generalTracks, majorTracks, addtionalTracks } = await this.TracksRepository.getAllTracks(); return { diff --git a/src/prisma/repositories/course.repository.ts b/src/prisma/repositories/course.repository.ts index 632620dc..f871afeb 100644 --- a/src/prisma/repositories/course.repository.ts +++ b/src/prisma/repositories/course.repository.ts @@ -10,6 +10,7 @@ import { orderFilter, } from 'src/common/utils/search.utils'; import { PrismaService } from '../prisma.service'; +import ECourseUser = ECourse.ECourseUser; @Injectable() export class CourseRepository { @@ -432,7 +433,10 @@ export class CourseRepository { return candidate; } - async readCourse(userId: number, courseId: number) { + async readCourse( + userId: number, + courseId: number, + ): Promise { const now = new Date(); return await this.prisma.subject_courseuser.upsert({ create: { diff --git a/src/prisma/repositories/review.repository.ts b/src/prisma/repositories/review.repository.ts index 5f089996..93fdb5a7 100644 --- a/src/prisma/repositories/review.repository.ts +++ b/src/prisma/repositories/review.repository.ts @@ -9,6 +9,7 @@ import { ELecture } from 'src/common/entities/ELecture'; import { EReview } from 'src/common/entities/EReview'; import { orderFilter } from 'src/common/utils/search.utils'; import { PrismaService } from '../prisma.service'; +import EReviewVote = EReview.EReviewVote; @Injectable() export class ReviewsRepository { @@ -397,8 +398,11 @@ export class ReviewsRepository { LIMIT ${n}`; } - async upsertReviewVote(reviewId: number, userId: number) { - await this.prisma.review_reviewvote.upsert({ + async upsertReviewVote( + reviewId: number, + userId: number, + ): Promise { + return await this.prisma.review_reviewvote.upsert({ where: { review_id_userprofile_id: { review_id: reviewId, @@ -411,6 +415,5 @@ export class ReviewsRepository { userprofile: { connect: { id: userId } }, }, }); - return null; } } diff --git a/src/prisma/repositories/timetable.repository.ts b/src/prisma/repositories/timetable.repository.ts index 339a855a..2933ec1b 100644 --- a/src/prisma/repositories/timetable.repository.ts +++ b/src/prisma/repositories/timetable.repository.ts @@ -142,7 +142,10 @@ export class TimetableRepository { }); } - async updateOrder(id: number, arrange_order: number) { + async updateOrder( + id: number, + arrange_order: number, + ): Promise { return await this.prisma.timetable_timetable.update({ where: { id: id, diff --git a/src/prisma/repositories/user.repository.ts b/src/prisma/repositories/user.repository.ts index c0588783..e40ea95d 100644 --- a/src/prisma/repositories/user.repository.ts +++ b/src/prisma/repositories/user.repository.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { Prisma, session_userprofile, subject_semester } from '@prisma/client'; import { PrismaService } from '../prisma.service'; +import { EUser } from '../../common/entities/EUser'; @Injectable() export class UserRepository { @@ -30,7 +31,10 @@ export class UserRepository { }); } - async changeFavoriteDepartments(userId: number, departmentIds: number[]) { + async changeFavoriteDepartments( + userId: number, + departmentIds: number[], + ): Promise { await this.prisma.session_userprofile_favorite_departments.deleteMany({ where: { userprofile_id: userId }, }); From 1a9762a61feac83b7e6cda6e46d582d6068c8237 Mon Sep 17 00:00:00 2001 From: LarryKwon <65128957+LarryKwon@users.noreply.github.com> Date: Sat, 3 Aug 2024 21:59:35 +0900 Subject: [PATCH 4/7] Add: npm publish test & ts-morph install --- src/common/api-docs/docs-generator.ts | 74 ++++ src/common/package-lock.json | 503 ++++++++++++++++++++++++++ src/common/package.json | 20 + src/common/tsconfig.json | 12 + 4 files changed, 609 insertions(+) create mode 100644 src/common/api-docs/docs-generator.ts create mode 100644 src/common/package-lock.json create mode 100644 src/common/package.json create mode 100644 src/common/tsconfig.json diff --git a/src/common/api-docs/docs-generator.ts b/src/common/api-docs/docs-generator.ts new file mode 100644 index 00000000..63bf1c20 --- /dev/null +++ b/src/common/api-docs/docs-generator.ts @@ -0,0 +1,74 @@ +import { Decorator, Project, SyntaxKind } from 'ts-morph'; + +// 프로젝트 초기화 +const project = new Project({ + tsConfigFilePath: '../../../tsconfig.json', +}); + +const sourceFiles = project.getSourceFiles('src/**/*.controller.ts'); + +// 특정 데코레이터를 찾는 헬퍼 함수 +function hasHttpMethodDecorator(decorators: Decorator[]) { + const httpMethods = ['Post', 'Get', 'Put', 'Patch', 'Delete']; + return decorators.some((decorator) => { + const name = decorator.getName(); + return httpMethods.includes(name); + }); +} + +// 파라미터의 데코레이터를 확인하는 헬퍼 함수 +function hasParameterDecorator(parameter: any, decoratorName: string) { + return parameter + .getDecorators() + .some( + (decorator: { getName: () => string }) => + decorator.getName() === decoratorName, + ); +} + +// 소스 파일 필터링 및 처리 +sourceFiles.forEach((sourceFile) => { + // 클래스 선언 찾기 + const classes = sourceFile.getClasses(); + + classes.forEach((classDeclaration) => { + // 클래스의 모든 메서드에 대해 처리 + classDeclaration.getMethods().forEach((method) => { + // 메서드의 데코레이터 확인 + const decorators = method.getDecorators(); + if (!hasHttpMethodDecorator(decorators)) { + return; + } + + // 메서드의 파라미터 처리 + method.getParameters().forEach((parameter) => { + if (hasParameterDecorator(parameter, 'Body')) { + const paramType = parameter.getType().getText(); + method.addDecorator({ + name: 'ApiBody', + arguments: [`{ type: ${paramType} }`], + }); + } + if (hasParameterDecorator(parameter, 'Param')) { + const paramType = parameter.getType().getText(); + method.addDecorator({ + name: 'ApiParam', + arguments: [`{ type: ${paramType} }`], + }); + } + }); + + // 메서드의 반환 타입 가져오기 + const returnType = method.getReturnType().getText(); + method.addDecorator({ + name: 'ApiResponse', + arguments: [ + `{ status: 201, description: 'The response', type: ${returnType} }`, + ], + }); + }); + }); +}); + +// 변경 사항 저장 +project.save().then(() => console.log('Decorators added successfully.')); diff --git a/src/common/package-lock.json b/src/common/package-lock.json new file mode 100644 index 00000000..8ecd7d6c --- /dev/null +++ b/src/common/package-lock.json @@ -0,0 +1,503 @@ +{ + "name": "@koallarry11/interfaces", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@koallarry11/interfaces", + "version": "1.0.0", + "dependencies": { + "ts-morph": "^23.0.0" + }, + "devDependencies": { + "typescript": "^4.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.24.0.tgz", + "integrity": "sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A==", + "dependencies": { + "fast-glob": "^3.3.2", + "minimatch": "^9.0.4", + "mkdirp": "^3.0.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/code-block-writer": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.2.tgz", + "integrity": "sha512-XfXzAGiStXSmCIwrkdfvc7FS5Dtj8yelCtyOf2p2skCAfvLd6zu0rGzuS9NSCO3bq1JKpFZ7tbKdKlcd5occQA==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-morph": { + "version": "23.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-23.0.0.tgz", + "integrity": "sha512-FcvFx7a9E8TUe6T3ShihXJLiJOiqyafzFKUO4aqIHDUCIvADdGNShcbc2W5PMr3LerXRv7mafvFZ9lRENxJmug==", + "dependencies": { + "@ts-morph/common": "~0.24.0", + "code-block-writer": "^13.0.1" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@ts-morph/common": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.24.0.tgz", + "integrity": "sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A==", + "requires": { + "fast-glob": "^3.3.2", + "minimatch": "^9.0.4", + "mkdirp": "^3.0.1", + "path-browserify": "^1.0.1" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "requires": { + "fill-range": "^7.1.1" + } + }, + "code-block-writer": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.2.tgz", + "integrity": "sha512-XfXzAGiStXSmCIwrkdfvc7FS5Dtj8yelCtyOf2p2skCAfvLd6zu0rGzuS9NSCO3bq1JKpFZ7tbKdKlcd5occQA==" + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==" + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-morph": { + "version": "23.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-23.0.0.tgz", + "integrity": "sha512-FcvFx7a9E8TUe6T3ShihXJLiJOiqyafzFKUO4aqIHDUCIvADdGNShcbc2W5PMr3LerXRv7mafvFZ9lRENxJmug==", + "requires": { + "@ts-morph/common": "~0.24.0", + "code-block-writer": "^13.0.1" + } + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + } + } +} diff --git a/src/common/package.json b/src/common/package.json new file mode 100644 index 00000000..398138c3 --- /dev/null +++ b/src/common/package.json @@ -0,0 +1,20 @@ +{ + "name": "@koallarry11/interfaces", + "version": "1.0.0", + "files": [ + "entities", + "interfaces" + ], + "scripts": { + "build": "tsc" + }, + "devDependencies": { + "typescript": "^4.0.0" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "ts-morph": "^23.0.0" + } +} diff --git a/src/common/tsconfig.json b/src/common/tsconfig.json new file mode 100644 index 00000000..a8c50abb --- /dev/null +++ b/src/common/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "declaration": true, + "outDir": "dist", + "module": "commonjs", + "target": "es6", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src"] +} From 400ca31975171fe68868ae1c9c9f5f360f907c62 Mon Sep 17 00:00:00 2001 From: LarryKwon <65128957+LarryKwon@users.noreply.github.com> Date: Sat, 3 Aug 2024 22:02:06 +0900 Subject: [PATCH 5/7] Add: add src/common/node_modules to gitignore --- .gitignore | 1 + package-lock.json | 87 ++++++++++++++++++++++++++++++++++++----------- package.json | 3 +- 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 8172d406..9ad6ecaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # compiled output /dist /node_modules +/src/common/node_modules # /env/* diff --git a/package-lock.json b/package-lock.json index 75ec8ffc..cfa6c302 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,8 @@ "prisma": "4.16.0", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", - "rxjs": "^7.2.0" + "rxjs": "^7.2.0", + "ts-morph": "^23.0.0" }, "devDependencies": { "@nestjs/cli": "^9.0.0", @@ -1673,7 +1674,6 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -1685,7 +1685,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -1693,7 +1692,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -1768,6 +1766,53 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@ts-morph/common": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.24.0.tgz", + "integrity": "sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A==", + "dependencies": { + "fast-glob": "^3.3.2", + "minimatch": "^9.0.4", + "mkdirp": "^3.0.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@ts-morph/common/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@ts-morph/common/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "dev": true, @@ -2869,7 +2914,6 @@ }, "node_modules/braces": { "version": "3.0.2", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.0.1" @@ -3275,6 +3319,11 @@ "node": ">= 0.12.0" } }, + "node_modules/code-block-writer": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.2.tgz", + "integrity": "sha512-XfXzAGiStXSmCIwrkdfvc7FS5Dtj8yelCtyOf2p2skCAfvLd6zu0rGzuS9NSCO3bq1JKpFZ7tbKdKlcd5occQA==" + }, "node_modules/collect-v8-coverage": { "version": "1.0.2", "dev": true, @@ -4236,7 +4285,6 @@ }, "node_modules/fast-glob": { "version": "3.3.2", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -4265,7 +4313,6 @@ }, "node_modules/fastq": { "version": "1.17.1", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -4314,7 +4361,6 @@ }, "node_modules/fill-range": { "version": "7.0.1", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -4623,7 +4669,6 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5010,7 +5055,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5037,7 +5081,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -5056,7 +5099,6 @@ }, "node_modules/is-number": { "version": "7.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -6473,7 +6515,6 @@ }, "node_modules/merge2": { "version": "1.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -6488,7 +6529,6 @@ }, "node_modules/micromatch": { "version": "4.0.5", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.2", @@ -7008,6 +7048,11 @@ "node": ">= 0.4.0" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, "node_modules/path-exists": { "version": "4.0.0", "dev": true, @@ -7080,7 +7125,6 @@ }, "node_modules/picomatch": { "version": "2.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -7300,7 +7344,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "dev": true, "funding": [ { "type": "github", @@ -7480,7 +7523,6 @@ }, "node_modules/reusify": { "version": "1.0.4", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -7515,7 +7557,6 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "dev": true, "funding": [ { "type": "github", @@ -8305,7 +8346,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -8390,6 +8430,15 @@ "webpack": "^5.0.0" } }, + "node_modules/ts-morph": { + "version": "23.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-23.0.0.tgz", + "integrity": "sha512-FcvFx7a9E8TUe6T3ShihXJLiJOiqyafzFKUO4aqIHDUCIvADdGNShcbc2W5PMr3LerXRv7mafvFZ9lRENxJmug==", + "dependencies": { + "@ts-morph/common": "~0.24.0", + "code-block-writer": "^13.0.1" + } + }, "node_modules/ts-node": { "version": "10.9.2", "dev": true, diff --git a/package.json b/package.json index e5704f82..e5435873 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,8 @@ "prisma": "4.16.0", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", - "rxjs": "^7.2.0" + "rxjs": "^7.2.0", + "ts-morph": "^23.0.0" }, "devDependencies": { "@nestjs/cli": "^9.0.0", From 72801240f2eed79708a90d4356b9aa10bd928500 Mon Sep 17 00:00:00 2001 From: useruseruse Date: Fri, 13 Sep 2024 16:39:43 -0400 Subject: [PATCH 6/7] feat: implement type generating --- package-lock.json | 18 +- package.json | 1 + src/common/api-docs/docs-generator.ts | 115 ++++++-- src/common/api-docs/types.ts | 364 ++++++++++++++++++++++++++ src/common/interfaces/index.ts | 13 +- 5 files changed, 486 insertions(+), 25 deletions(-) create mode 100644 src/common/api-docs/types.ts diff --git a/package-lock.json b/package-lock.json index cfa6c302..f161c04c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "UNLICENSED", "dependencies": { "@nestjs/common": "^9.0.0", + "@nestjs/config": "^3.2.3", "@nestjs/core": "^9.0.0", "@nestjs/jwt": "^10.0.3", "@nestjs/passport": "^9.0.3", @@ -1509,6 +1510,20 @@ } } }, + "node_modules/@nestjs/config": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.2.3.tgz", + "integrity": "sha512-p6yv/CvoBewJ72mBq4NXgOAi2rSQNWx3a+IMJLVKS2uiwFCOQQuiIatGwq6MRjXV3Jr+B41iUO8FIf4xBrZ4/w==", + "dependencies": { + "dotenv": "16.4.5", + "dotenv-expand": "10.0.0", + "lodash": "4.17.21" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "rxjs": "^7.1.0" + } + }, "node_modules/@nestjs/core": { "version": "9.4.3", "hasInstallScript": true, @@ -8441,8 +8456,9 @@ }, "node_modules/ts-node": { "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, - "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", diff --git a/package.json b/package.json index e5435873..e19ad424 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ }, "dependencies": { "@nestjs/common": "^9.0.0", + "@nestjs/config": "^3.2.3", "@nestjs/core": "^9.0.0", "@nestjs/jwt": "^10.0.3", "@nestjs/passport": "^9.0.3", diff --git a/src/common/api-docs/docs-generator.ts b/src/common/api-docs/docs-generator.ts index 63bf1c20..00d3e734 100644 --- a/src/common/api-docs/docs-generator.ts +++ b/src/common/api-docs/docs-generator.ts @@ -1,10 +1,18 @@ -import { Decorator, Project, SyntaxKind } from 'ts-morph'; +import { Decorator, Project, SourceFile } from 'ts-morph'; // 프로젝트 초기화 const project = new Project({ - tsConfigFilePath: '../../../tsconfig.json', + tsConfigFilePath: './tsconfig.json', }); +const outputFile = project.createSourceFile( + 'src/common/api-docs/types.ts', + '', + { + overwrite: true, + }, +); + const sourceFiles = project.getSourceFiles('src/**/*.controller.ts'); // 특정 데코레이터를 찾는 헬퍼 함수 @@ -26,49 +34,110 @@ function hasParameterDecorator(parameter: any, decoratorName: string) { ); } +// 인터페이스와 관련된 import 문인지 확인하는 함수 +function isInterfaceImport( + importPath: string, + namedImports: string[], +): boolean { + // import 경로에 'interfaces'가 포함되어 있거나, named import 중 'I'로 시작하는 것이 있는지 확인 + return ( + importPath.includes('interfaces') && + namedImports.some((name) => name.startsWith('I')) + ); +} + +function generateNamespace( + apiName: string, + requestBodyType: any, + requestParamType: any, + responseBodyType: string, +) { + // Add namespace for each method + const namespace = outputFile.addModule({ + name: apiName, + isExported: true, + }); + + // Add types to the namespace + namespace.addTypeAlias({ + name: 'requestParam', + type: requestParamType ?? 'never', + isExported: true, + }); + + namespace.addTypeAlias({ + name: 'requestBody', + type: requestBodyType ?? 'never', + isExported: true, + }); + namespace.addTypeAlias({ + name: 'responseBody', + type: responseBodyType ?? 'never', + isExported: true, + }); +} + +const namedImportsLst: Set = new Set(); + // 소스 파일 필터링 및 처리 -sourceFiles.forEach((sourceFile) => { - // 클래스 선언 찾기 +sourceFiles.forEach((sourceFile: SourceFile) => { + // 인터페이스 관련 import 문 복사 + sourceFile.getImportDeclarations().forEach((importDeclaration) => { + const importPath = importDeclaration.getModuleSpecifierValue(); + const namedImports = importDeclaration + .getNamedImports() + .map((namedImport) => namedImport.getName()); + if (isInterfaceImport(importPath, namedImports)) { + namedImports.forEach((name) => { + namedImportsLst.add(name); + }); + } + }); + const classes = sourceFile.getClasses(); + // 클래스의 메쏘드에 대해서 파라미터와 반환 타입을 추출한 뒤, 네임 스페이스 생성. classes.forEach((classDeclaration) => { - // 클래스의 모든 메서드에 대해 처리 classDeclaration.getMethods().forEach((method) => { - // 메서드의 데코레이터 확인 const decorators = method.getDecorators(); if (!hasHttpMethodDecorator(decorators)) { return; } + let requestBodyType = undefined; + let requestParamType = undefined; + let responseBodyType = undefined; // 메서드의 파라미터 처리 method.getParameters().forEach((parameter) => { if (hasParameterDecorator(parameter, 'Body')) { - const paramType = parameter.getType().getText(); - method.addDecorator({ - name: 'ApiBody', - arguments: [`{ type: ${paramType} }`], - }); + requestBodyType = parameter.getType()?.getText(parameter); //undefined, TypeFormatFlags); } if (hasParameterDecorator(parameter, 'Param')) { - const paramType = parameter.getType().getText(); - method.addDecorator({ - name: 'ApiParam', - arguments: [`{ type: ${paramType} }`], - }); + requestParamType = parameter.getType()?.getText(parameter); } }); // 메서드의 반환 타입 가져오기 - const returnType = method.getReturnType().getText(); - method.addDecorator({ - name: 'ApiResponse', - arguments: [ - `{ status: 201, description: 'The response', type: ${returnType} }`, - ], - }); + responseBodyType = method.getReturnType(); + if (responseBodyType.getTypeArguments()) { + responseBodyType = responseBodyType.getTypeArguments()[0]; + } + responseBodyType = responseBodyType?.getText(method); + + generateNamespace( + method.getName(), + requestBodyType, + requestParamType, + responseBodyType, + ); }); }); }); +outputFile.addImportDeclaration({ + moduleSpecifier: 'src/common/interfaces', + namedImports: [...namedImportsLst].map((name) => ({ name })), +}); + // 변경 사항 저장 project.save().then(() => console.log('Decorators added successfully.')); diff --git a/src/common/api-docs/types.ts b/src/common/api-docs/types.ts new file mode 100644 index 00000000..bbffb7bd --- /dev/null +++ b/src/common/api-docs/types.ts @@ -0,0 +1,364 @@ +/* eslint-disable @typescript-eslint/ban-types */ +import { + IAuth, + IUser, + ICourse, + ILecture, + IReview, + IFeed, + INotice, + IPlanner, + IRate, + ISemester, + ISession, + IDepartment, + IShare, + ITimetable, + IWishlist, +} from 'src/common/interfaces'; +export namespace getHello { + export type requestParam = never; + export type requestBody = never; + export type responseBody = never; +} + +export namespace user_login { + export type requestParam = never; + export type requestBody = never; + export type responseBody = never; +} + +export namespace loginCallback { + export type requestParam = never; + export type requestBody = never; + export type responseBody = void; +} + +export namespace getUserProfile { + export type requestParam = never; + export type requestBody = never; + export type responseBody = IUser.Profile; +} + +export namespace home { + export type requestParam = never; + export type requestBody = never; + export type responseBody = void; +} + +export namespace logout { + export type requestParam = never; + export type requestBody = never; + export type responseBody = void; +} + +export namespace getCourses { + export type requestParam = never; + export type requestBody = never; + export type responseBody = ICourse.DetailWithIsRead[]; +} + +export namespace getCourseAutocomplete { + export type requestParam = never; + export type requestBody = never; + export type responseBody = string | undefined; +} + +export namespace getCourseById { + export type requestParam = number; + export type requestBody = never; + export type responseBody = ICourse.DetailWithIsRead; +} + +export namespace getLecturesByCourseId { + export type requestParam = number; + export type requestBody = never; + export type responseBody = ILecture.Detail[]; +} + +export namespace getReviewByCourseId { + export type requestParam = number; + export type requestBody = never; + export type responseBody = IReview.Basic[]; +} + +export namespace readCourse { + export type requestParam = number; + export type requestBody = never; + export type responseBody = { + id: number; + latest_read_datetime: Date; + course_id: number; + user_profile_id: number; + } & {}; +} + +export namespace getUserFeeds { + export type requestParam = never; + export type requestBody = never; + export type responseBody = IFeed.Details[]; +} + +export namespace getLectures { + export type requestParam = never; + export type requestBody = never; + export type responseBody = ILecture.Detail[]; +} + +export namespace getLectureAutocomplete { + export type requestParam = never; + export type requestBody = never; + export type responseBody = string | undefined; +} + +export namespace getLectureById { + export type requestParam = number; + export type requestBody = never; + export type responseBody = ILecture.Detail; +} + +export namespace getLectureReviews { + export type requestParam = number; + export type requestBody = never; + export type responseBody = (IReview.Basic & { + userspecific_is_liked: boolean; + })[]; +} + +export namespace getLectureRelatedReviews { + export type requestParam = number; + export type requestBody = never; + export type responseBody = (IReview.Basic & { + userspecific_is_liked: boolean; + })[]; +} + +export namespace getNotices { + export type requestParam = never; + export type requestBody = never; + export type responseBody = INotice.Basic[]; +} + +export namespace getPlanners { + export type requestParam = number; + export type requestBody = never; + export type responseBody = IPlanner.Detail[]; +} + +export namespace postPlanner { + export type requestParam = number; + export type requestBody = IPlanner.CreateBodyDto; + export type responseBody = IPlanner.Detail; +} + +export namespace addArbitraryItem { + export type requestParam = number; + export type requestBody = IPlanner.AddArbitraryItemDto; + export type responseBody = IPlanner.IItem.Arbitrary; +} + +export namespace removePlanner { + export type requestParam = number; + export type requestBody = IPlanner.RemoveItemBodyDto; + export type responseBody = IPlanner.Detail; +} + +export namespace addFutureItem { + export type requestParam = number; + export type requestBody = IPlanner.FuturePlannerItemDto; + export type responseBody = IPlanner.IItem.Future; +} + +export namespace reorderPlanner { + export type requestParam = number; + export type requestBody = IPlanner.ReorderBodyDto; + export type responseBody = IPlanner.Detail; +} + +export namespace updatePlanner { + export type requestParam = number; + export type requestBody = IPlanner.UpdateItemBodyDto; + export type responseBody = + | IPlanner.IItem.Taken + | IPlanner.IItem.Future + | IPlanner.IItem.Arbitrary; +} + +export namespace createRates { + export type requestParam = never; + export type requestBody = IRate.CreateDto; + export type responseBody = IRate.Basic; +} + +export namespace getReviews { + export type requestParam = never; + export type requestBody = never; + export type responseBody = + | number + | (IReview.Basic & { userspecific_is_liked: boolean })[]; +} + +export namespace createReviews { + export type requestParam = never; + export type requestBody = IReview.CreateDto; + export type responseBody = IReview.Basic & { userspecific_is_liked: boolean }; +} + +export namespace getReviewInstance { + export type requestParam = number; + export type requestBody = never; + export type responseBody = IReview.Basic & { userspecific_is_liked: boolean }; +} + +export namespace updateReviewInstance { + export type requestParam = number; + export type requestBody = IReview.UpdateDto; + export type responseBody = IReview.Basic & { userspecific_is_liked: boolean }; +} + +export namespace likeReviewInstance { + export type requestParam = number; + export type requestBody = never; + export type responseBody = { + id: number; + review_id: number; + userprofile_id: number | null; + created_datetime: Date | null; + } & {}; +} + +export namespace getSemesters { + export type requestParam = never; + export type requestBody = never; + export type responseBody = ISemester.Response[]; +} + +export namespace departmentOptions { + export type requestParam = never; + export type requestBody = never; + export type responseBody = IDepartment.Basic[][]; +} + +export namespace favoriteDepartments { + export type requestParam = never; + export type requestBody = ISession.FavoriteDepartmentsDto; + export type responseBody = { + id: number; + student_id: string; + sid: string; + department_id: number | null; + email: string | null; + date_joined: Date; + first_name: string; + last_name: string; + refresh_token: string | null; + } & {}; +} + +export namespace getTimetableImage { + export type requestParam = never; + export type requestBody = never; + export type responseBody = void; +} + +export namespace getTimetableIcal { + export type requestParam = never; + export type requestBody = never; + export type responseBody = void; +} + +export namespace getStatus { + export type requestParam = never; + export type requestBody = never; + export type responseBody = never; +} + +export namespace getTimetables { + export type requestParam = number; + export type requestBody = never; + export type responseBody = ITimetable.Response[]; +} + +export namespace getTimeTable { + export type requestParam = number; + export type requestBody = never; + export type responseBody = ITimetable.Response; +} + +export namespace deleteTimetable { + export type requestParam = number; + export type requestBody = never; + export type responseBody = ({ + id: number; + year: number | null; + semester: number | null; + user_id: number; + arrange_order: number; + } & {})[]; +} + +export namespace createTimetable { + export type requestParam = never; + export type requestBody = ITimetable.CreateDto; + export type responseBody = ITimetable.Response; +} + +export namespace addLectureToTimetable { + export type requestParam = number; + export type requestBody = ITimetable.AddLectureDto; + export type responseBody = ITimetable.Response; +} + +export namespace removeLectureFromTimetable { + export type requestParam = number; + export type requestBody = ITimetable.AddLectureDto; + export type responseBody = ITimetable.Response; +} + +export namespace reorderTimetable { + export type requestParam = number; + export type requestBody = ITimetable.ReorderTimetableDto; + export type responseBody = ITimetable.Response; +} + +export namespace getTracks { + export type requestParam = never; + export type requestBody = never; + export type responseBody = { + general: IPlanner.ITrack.General[]; + major: IPlanner.ITrack.Major[]; + additional: IPlanner.ITrack.Additional[]; + }; +} + +export namespace getUserTakenCourses { + export type requestParam = number; + export type requestBody = never; + export type responseBody = ICourse.DetailWithIsRead[]; +} + +export namespace getUserLikedReviews { + export type requestParam = number; + export type requestBody = never; + export type responseBody = (IReview.Basic & { + userspecific_is_liked: boolean; + })[]; +} + +export namespace getLectures { + export type requestParam = number; + export type requestBody = never; + export type responseBody = IWishlist.WithLectures; +} + +export namespace addLecture { + export type requestParam = number; + export type requestBody = IWishlist.AddLectureDto; + export type responseBody = IWishlist.WithLectures; +} + +export namespace removeLecture { + export type requestParam = number; + export type requestBody = IWishlist.RemoveLectureDto; + export type responseBody = IWishlist.WithLectures; +} diff --git a/src/common/interfaces/index.ts b/src/common/interfaces/index.ts index 3e849083..c0e22753 100644 --- a/src/common/interfaces/index.ts +++ b/src/common/interfaces/index.ts @@ -1,6 +1,17 @@ export * from './IAuth'; export * from './ICourse'; export * from './IFeed'; -export * from './ITimetable'; export * from './ILecture'; +export * from './INotice'; +export * from './IPlanner'; +export * from './IProfessor'; +export * from './IRate'; +export * from './IReview'; +export * from './ISemester'; +export * from './ISession'; export * from './IShare'; +export * from './ITimetable'; +export * from './IUser'; +export * from './IPlanner'; +export * from './IWishlist'; +export * from './IDepartment'; From bbe63f61d55a4d847404147551ef1e7bac4e8a9f Mon Sep 17 00:00:00 2001 From: useruseruse Date: Sun, 15 Sep 2024 13:16:10 -0400 Subject: [PATCH 7/7] fix: add query param, refactor, change wishlist method name --- src/common/api-docs/docs-generator.ts | 93 ++++++++++----------- src/common/api-docs/types.ts | 55 +++++++++++- src/modules/wishlist/wishlist.controller.ts | 2 +- 3 files changed, 98 insertions(+), 52 deletions(-) diff --git a/src/common/api-docs/docs-generator.ts b/src/common/api-docs/docs-generator.ts index 00d3e734..fbd5dade 100644 --- a/src/common/api-docs/docs-generator.ts +++ b/src/common/api-docs/docs-generator.ts @@ -1,4 +1,4 @@ -import { Decorator, Project, SourceFile } from 'ts-morph'; +import { Decorator, ImportDeclaration, Project, SourceFile } from 'ts-morph'; // 프로젝트 초기화 const project = new Project({ @@ -46,34 +46,23 @@ function isInterfaceImport( ); } -function generateNamespace( - apiName: string, - requestBodyType: any, - requestParamType: any, - responseBodyType: string, -) { +interface apiEndpoint { + [key: string]: any; +} + +function generateNamespace(apiName: string, apiEndpoint: apiEndpoint) { // Add namespace for each method const namespace = outputFile.addModule({ name: apiName, isExported: true, }); - // Add types to the namespace - namespace.addTypeAlias({ - name: 'requestParam', - type: requestParamType ?? 'never', - isExported: true, - }); - - namespace.addTypeAlias({ - name: 'requestBody', - type: requestBodyType ?? 'never', - isExported: true, - }); - namespace.addTypeAlias({ - name: 'responseBody', - type: responseBodyType ?? 'never', - isExported: true, + Object.keys(apiEndpoint).forEach((key) => { + namespace.addTypeAlias({ + name: key, + type: apiEndpoint[key] ?? 'never', + isExported: true, + }); }); } @@ -82,17 +71,19 @@ const namedImportsLst: Set = new Set(); // 소스 파일 필터링 및 처리 sourceFiles.forEach((sourceFile: SourceFile) => { // 인터페이스 관련 import 문 복사 - sourceFile.getImportDeclarations().forEach((importDeclaration) => { - const importPath = importDeclaration.getModuleSpecifierValue(); - const namedImports = importDeclaration - .getNamedImports() - .map((namedImport) => namedImport.getName()); - if (isInterfaceImport(importPath, namedImports)) { - namedImports.forEach((name) => { - namedImportsLst.add(name); - }); - } - }); + sourceFile + .getImportDeclarations() + .forEach((importDeclaration: ImportDeclaration) => { + const importPath = importDeclaration.getModuleSpecifierValue(); + const namedImports = importDeclaration + .getNamedImports() + .map((namedImport) => namedImport.getName()); + if (isInterfaceImport(importPath, namedImports)) { + namedImports.forEach((name) => { + namedImportsLst.add(name); + }); + } + }); const classes = sourceFile.getClasses(); @@ -103,33 +94,35 @@ sourceFiles.forEach((sourceFile: SourceFile) => { if (!hasHttpMethodDecorator(decorators)) { return; } - let requestBodyType = undefined; - let requestParamType = undefined; - let responseBodyType = undefined; + let requestBody, requestParam, responseBody, requestQuery; // 메서드의 파라미터 처리 method.getParameters().forEach((parameter) => { if (hasParameterDecorator(parameter, 'Body')) { - requestBodyType = parameter.getType()?.getText(parameter); //undefined, TypeFormatFlags); + requestBody = parameter.getType()?.getText(parameter); //undefined, TypeFormatFlags); } if (hasParameterDecorator(parameter, 'Param')) { - requestParamType = parameter.getType()?.getText(parameter); + requestParam = parameter.getType()?.getText(parameter); + } + if (hasParameterDecorator(parameter, 'Query')) { + requestQuery = parameter.getType()?.getText(parameter); } }); // 메서드의 반환 타입 가져오기 - responseBodyType = method.getReturnType(); - if (responseBodyType.getTypeArguments()) { - responseBodyType = responseBodyType.getTypeArguments()[0]; + responseBody = method.getReturnType(); + // Promise 로 감싸져 있는 경우, 타입 argument만 추출 + if (responseBody.getTypeArguments()) { + responseBody = responseBody.getTypeArguments()[0]; } - responseBodyType = responseBodyType?.getText(method); - - generateNamespace( - method.getName(), - requestBodyType, - requestParamType, - responseBodyType, - ); + responseBody = responseBody?.getText(method); + + generateNamespace(method.getName(), { + requestParam, + requestBody, + requestQuery, + responseBody, + }); }); }); }); diff --git a/src/common/api-docs/types.ts b/src/common/api-docs/types.ts index bbffb7bd..49a103d5 100644 --- a/src/common/api-docs/types.ts +++ b/src/common/api-docs/types.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/ban-types */ + import { IAuth, IUser, @@ -16,75 +17,88 @@ import { ITimetable, IWishlist, } from 'src/common/interfaces'; + export namespace getHello { export type requestParam = never; export type requestBody = never; + export type requestQuery = never; export type responseBody = never; } export namespace user_login { export type requestParam = never; export type requestBody = never; + export type requestQuery = string; export type responseBody = never; } export namespace loginCallback { export type requestParam = never; export type requestBody = never; + export type requestQuery = string; export type responseBody = void; } export namespace getUserProfile { export type requestParam = never; export type requestBody = never; + export type requestQuery = never; export type responseBody = IUser.Profile; } export namespace home { export type requestParam = never; export type requestBody = never; + export type requestQuery = never; export type responseBody = void; } export namespace logout { export type requestParam = never; export type requestBody = never; + export type requestQuery = string; export type responseBody = void; } export namespace getCourses { export type requestParam = never; export type requestBody = never; + export type requestQuery = ICourse.Query; export type responseBody = ICourse.DetailWithIsRead[]; } export namespace getCourseAutocomplete { export type requestParam = never; export type requestBody = never; + export type requestQuery = ICourse.AutocompleteQueryDto; export type responseBody = string | undefined; } export namespace getCourseById { export type requestParam = number; export type requestBody = never; + export type requestQuery = never; export type responseBody = ICourse.DetailWithIsRead; } export namespace getLecturesByCourseId { export type requestParam = number; export type requestBody = never; + export type requestQuery = { order: string[] }; export type responseBody = ILecture.Detail[]; } export namespace getReviewByCourseId { export type requestParam = number; export type requestBody = never; + export type requestQuery = ICourse.ReviewQueryDto; export type responseBody = IReview.Basic[]; } export namespace readCourse { export type requestParam = number; export type requestBody = never; + export type requestQuery = never; export type responseBody = { id: number; latest_read_datetime: Date; @@ -96,30 +110,35 @@ export namespace readCourse { export namespace getUserFeeds { export type requestParam = never; export type requestBody = never; + export type requestQuery = IFeed.QueryDto; export type responseBody = IFeed.Details[]; } export namespace getLectures { export type requestParam = never; export type requestBody = never; + export type requestQuery = ILecture.QueryDto; export type responseBody = ILecture.Detail[]; } export namespace getLectureAutocomplete { export type requestParam = never; export type requestBody = never; + export type requestQuery = ILecture.AutocompleteQueryDto; export type responseBody = string | undefined; } export namespace getLectureById { export type requestParam = number; export type requestBody = never; + export type requestQuery = never; export type responseBody = ILecture.Detail; } export namespace getLectureReviews { export type requestParam = number; export type requestBody = never; + export type requestQuery = IReview.LectureReviewsQueryDto; export type responseBody = (IReview.Basic & { userspecific_is_liked: boolean; })[]; @@ -128,6 +147,7 @@ export namespace getLectureReviews { export namespace getLectureRelatedReviews { export type requestParam = number; export type requestBody = never; + export type requestQuery = IReview.LectureReviewsQueryDto; export type responseBody = (IReview.Basic & { userspecific_is_liked: boolean; })[]; @@ -136,48 +156,56 @@ export namespace getLectureRelatedReviews { export namespace getNotices { export type requestParam = never; export type requestBody = never; + export type requestQuery = never; export type responseBody = INotice.Basic[]; } export namespace getPlanners { export type requestParam = number; export type requestBody = never; + export type requestQuery = IPlanner.QueryDto; export type responseBody = IPlanner.Detail[]; } export namespace postPlanner { export type requestParam = number; export type requestBody = IPlanner.CreateBodyDto; + export type requestQuery = never; export type responseBody = IPlanner.Detail; } export namespace addArbitraryItem { export type requestParam = number; export type requestBody = IPlanner.AddArbitraryItemDto; + export type requestQuery = never; export type responseBody = IPlanner.IItem.Arbitrary; } export namespace removePlanner { export type requestParam = number; export type requestBody = IPlanner.RemoveItemBodyDto; + export type requestQuery = never; export type responseBody = IPlanner.Detail; } export namespace addFutureItem { export type requestParam = number; export type requestBody = IPlanner.FuturePlannerItemDto; + export type requestQuery = never; export type responseBody = IPlanner.IItem.Future; } export namespace reorderPlanner { export type requestParam = number; export type requestBody = IPlanner.ReorderBodyDto; + export type requestQuery = never; export type responseBody = IPlanner.Detail; } export namespace updatePlanner { export type requestParam = number; export type requestBody = IPlanner.UpdateItemBodyDto; + export type requestQuery = never; export type responseBody = | IPlanner.IItem.Taken | IPlanner.IItem.Future @@ -187,12 +215,14 @@ export namespace updatePlanner { export namespace createRates { export type requestParam = never; export type requestBody = IRate.CreateDto; + export type requestQuery = never; export type responseBody = IRate.Basic; } export namespace getReviews { export type requestParam = never; export type requestBody = never; + export type requestQuery = IReview.QueryDto; export type responseBody = | number | (IReview.Basic & { userspecific_is_liked: boolean })[]; @@ -201,24 +231,28 @@ export namespace getReviews { export namespace createReviews { export type requestParam = never; export type requestBody = IReview.CreateDto; + export type requestQuery = never; export type responseBody = IReview.Basic & { userspecific_is_liked: boolean }; } export namespace getReviewInstance { export type requestParam = number; export type requestBody = never; + export type requestQuery = never; export type responseBody = IReview.Basic & { userspecific_is_liked: boolean }; } export namespace updateReviewInstance { export type requestParam = number; export type requestBody = IReview.UpdateDto; + export type requestQuery = never; export type responseBody = IReview.Basic & { userspecific_is_liked: boolean }; } export namespace likeReviewInstance { export type requestParam = number; export type requestBody = never; + export type requestQuery = never; export type responseBody = { id: number; review_id: number; @@ -230,18 +264,21 @@ export namespace likeReviewInstance { export namespace getSemesters { export type requestParam = never; export type requestBody = never; + export type requestQuery = ISemester.QueryDto; export type responseBody = ISemester.Response[]; } export namespace departmentOptions { export type requestParam = never; export type requestBody = never; + export type requestQuery = never; export type responseBody = IDepartment.Basic[][]; } export namespace favoriteDepartments { export type requestParam = never; export type requestBody = ISession.FavoriteDepartmentsDto; + export type requestQuery = never; export type responseBody = { id: number; student_id: string; @@ -258,36 +295,42 @@ export namespace favoriteDepartments { export namespace getTimetableImage { export type requestParam = never; export type requestBody = never; + export type requestQuery = IShare.TimetableImageQueryDto; export type responseBody = void; } export namespace getTimetableIcal { export type requestParam = never; export type requestBody = never; + export type requestQuery = IShare.TimetableIcalQueryDto; export type responseBody = void; } export namespace getStatus { export type requestParam = never; export type requestBody = never; + export type requestQuery = never; export type responseBody = never; } export namespace getTimetables { export type requestParam = number; export type requestBody = never; + export type requestQuery = ITimetable.QueryDto; export type responseBody = ITimetable.Response[]; } export namespace getTimeTable { export type requestParam = number; export type requestBody = never; + export type requestQuery = never; export type responseBody = ITimetable.Response; } export namespace deleteTimetable { export type requestParam = number; export type requestBody = never; + export type requestQuery = never; export type responseBody = ({ id: number; year: number | null; @@ -300,30 +343,35 @@ export namespace deleteTimetable { export namespace createTimetable { export type requestParam = never; export type requestBody = ITimetable.CreateDto; + export type requestQuery = never; export type responseBody = ITimetable.Response; } export namespace addLectureToTimetable { export type requestParam = number; export type requestBody = ITimetable.AddLectureDto; + export type requestQuery = never; export type responseBody = ITimetable.Response; } export namespace removeLectureFromTimetable { export type requestParam = number; export type requestBody = ITimetable.AddLectureDto; + export type requestQuery = never; export type responseBody = ITimetable.Response; } export namespace reorderTimetable { export type requestParam = number; export type requestBody = ITimetable.ReorderTimetableDto; + export type requestQuery = never; export type responseBody = ITimetable.Response; } export namespace getTracks { export type requestParam = never; export type requestBody = never; + export type requestQuery = never; export type responseBody = { general: IPlanner.ITrack.General[]; major: IPlanner.ITrack.Major[]; @@ -334,31 +382,36 @@ export namespace getTracks { export namespace getUserTakenCourses { export type requestParam = number; export type requestBody = never; + export type requestQuery = IUser.TakenCoursesQueryDto; export type responseBody = ICourse.DetailWithIsRead[]; } export namespace getUserLikedReviews { export type requestParam = number; export type requestBody = never; + export type requestQuery = IUser.ReviewLikedQueryDto; export type responseBody = (IReview.Basic & { userspecific_is_liked: boolean; })[]; } -export namespace getLectures { +export namespace getWishlist { export type requestParam = number; export type requestBody = never; + export type requestQuery = never; export type responseBody = IWishlist.WithLectures; } export namespace addLecture { export type requestParam = number; export type requestBody = IWishlist.AddLectureDto; + export type requestQuery = never; export type responseBody = IWishlist.WithLectures; } export namespace removeLecture { export type requestParam = number; export type requestBody = IWishlist.RemoveLectureDto; + export type requestQuery = never; export type responseBody = IWishlist.WithLectures; } diff --git a/src/modules/wishlist/wishlist.controller.ts b/src/modules/wishlist/wishlist.controller.ts index 8f3a5b14..74be448b 100644 --- a/src/modules/wishlist/wishlist.controller.ts +++ b/src/modules/wishlist/wishlist.controller.ts @@ -17,7 +17,7 @@ export class WishlistController { constructor(private readonly wishlistService: WishlistService) {} @Get() - async getLectures( + async getWishlist( @Param('userId') userId: number, @GetUser() user: session_userprofile, ) {