diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index c4a9239..fd35ef9 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -44,7 +44,7 @@ jobs: continue-on-error: true - name: Upload analysis results to GitHub - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: eslint-results.sarif wait-for-processing: true diff --git a/.prettierrc b/.prettierrc index 743afce..75beb3f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,8 +1,22 @@ { "printWidth": 80, + "tabWidth": 2, "trailingComma": "all", "singleQuote": true, "semi": true, + "plugins": [ + "@trivago/prettier-plugin-sort-imports" + ], + "importOrderParserPlugins": [ + "typescript", + "decorators-legacy" + ], + "importOrder": [ + "^@core/(.*)$", + "^@server/(.*)$", + "^@ui/(.*)$", + "^[./]" + ], "importOrderSeparation": true, "importOrderSortSpecifiers": true -} \ No newline at end of file +} diff --git a/src/app.module.ts b/src/app.module.ts index c670f4c..e5c7b8c 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,10 +1,11 @@ import { Module } from '@nestjs/common'; -import { UserModule } from './user/user.module'; -import { GroupModule } from './group/group.module'; -import { AuthModule } from './auth/auth.module'; -import { MemberModule } from './member/member.module'; import { ConfigModule } from '@nestjs/config'; + +import { AuthModule } from './auth/auth.module'; import { EventModule } from './event/event.module'; +import { GroupModule } from './group/group.module'; +import { MemberModule } from './member/member.module'; +import { UserModule } from './user/user.module'; @Module({ imports: [ diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 46e183a..0b99e8e 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; -import { AuthService } from './auth.service'; + import { AuthController } from './auth.controller'; +import { AuthService } from './auth.service'; @Module({ controllers: [AuthController], diff --git a/src/config.swagger.ts b/src/common/configs/swagger.config.ts similarity index 89% rename from src/config.swagger.ts rename to src/common/configs/swagger.config.ts index 23b9ac6..3262b13 100644 --- a/src/config.swagger.ts +++ b/src/common/configs/swagger.config.ts @@ -1,7 +1,7 @@ import { INestApplication } from '@nestjs/common'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; -export const configSwagger = (app: INestApplication) => { +export const swaggerConfig = (app: INestApplication) => { const config = new DocumentBuilder() .setTitle('sometime API') .addTag('Group', '모임 관련 API') diff --git a/src/api-file.decorator.ts b/src/common/decorators/api-file.decorator.ts similarity index 88% rename from src/api-file.decorator.ts rename to src/common/decorators/api-file.decorator.ts index 5ef8c87..dd4ac66 100644 --- a/src/api-file.decorator.ts +++ b/src/common/decorators/api-file.decorator.ts @@ -1,6 +1,6 @@ -import { ApiBody, ApiConsumes } from '@nestjs/swagger'; +import { UseInterceptors, applyDecorators } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; -import { applyDecorators, UseInterceptors } from '@nestjs/common'; +import { ApiBody, ApiConsumes } from '@nestjs/swagger'; export function ApiFile(fieldName: string = 'file') { return applyDecorators( diff --git a/src/http-exception.filter.ts b/src/common/filters/http-exception.filter.ts similarity index 100% rename from src/http-exception.filter.ts rename to src/common/filters/http-exception.filter.ts diff --git a/src/database/database.module.ts b/src/database/database.module.ts index 857bc80..8211a38 100644 --- a/src/database/database.module.ts +++ b/src/database/database.module.ts @@ -1,4 +1,5 @@ import { Module } from '@nestjs/common'; + import { databaseProviders } from './database.providers'; @Module({ diff --git a/src/database/database.providers.ts b/src/database/database.providers.ts index 2111b88..a2d82cd 100644 --- a/src/database/database.providers.ts +++ b/src/database/database.providers.ts @@ -1,5 +1,5 @@ -import * as mongoose from 'mongoose'; import { ConfigService } from '@nestjs/config'; +import * as mongoose from 'mongoose'; export const databaseProviders = [ { diff --git a/src/event/dto/create-event.dto.ts b/src/event/dto/create-event.dto.ts index f23a408..fbb7d5e 100644 --- a/src/event/dto/create-event.dto.ts +++ b/src/event/dto/create-event.dto.ts @@ -1 +1,33 @@ -export class CreateEventDto {} +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateEventDto { + @ApiProperty({ + description: '이벤트 이름', + example: '2024년 1학기 모임', + }) + name: string; + + @ApiProperty({ + description: '이벤트 설명', + example: '2024년 1학기 모임입니다.', + }) + description: string; + + @ApiProperty({ + description: '이벤트 시작일', + example: new Date().toISOString(), + }) + startDate: Date; + + @ApiProperty({ + description: '이벤트 종료일', + example: new Date(), + }) + endDate: Date; + + @ApiProperty({ + description: '이벤트 참가비', + example: 10000, + }) + fee: number; +} diff --git a/src/event/dto/update-event.dto.ts b/src/event/dto/update-event.dto.ts index f161e01..c26d0b1 100644 --- a/src/event/dto/update-event.dto.ts +++ b/src/event/dto/update-event.dto.ts @@ -1,4 +1,5 @@ import { PartialType } from '@nestjs/swagger'; + import { CreateEventDto } from './create-event.dto'; export class UpdateEventDto extends PartialType(CreateEventDto) {} diff --git a/src/event/entities/event.entity.ts b/src/event/entities/event.entity.ts index 8c34a9a..0e15c7c 100644 --- a/src/event/entities/event.entity.ts +++ b/src/event/entities/event.entity.ts @@ -1 +1,8 @@ -export class Event {} +export class Event { + name: string; + description: string; + startDate: Date; + endDate: Date; + fee: number; + attendees: string[]; +} diff --git a/src/event/event.controller.ts b/src/event/event.controller.ts index 309eca1..59294b8 100644 --- a/src/event/event.controller.ts +++ b/src/event/event.controller.ts @@ -7,10 +7,11 @@ import { Patch, Post, } from '@nestjs/common'; -import { EventService } from './event.service'; +import { ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; + import { CreateEventDto } from './dto/create-event.dto'; import { UpdateEventDto } from './dto/update-event.dto'; -import { ApiParam, ApiTags } from '@nestjs/swagger'; +import { EventService } from './event.service'; @ApiTags('Event') @Controller('group/:groupId/event') @@ -23,20 +24,35 @@ export class EventController { constructor(private readonly eventService: EventService) {} @Post() - create(@Body() createEventDto: CreateEventDto) { - return this.eventService.create(createEventDto); + @ApiOperation({ + summary: '이벤트 생성', + description: '모임의 이벤트를 생성합니다.', + }) + create( + @Param('groupId') groupId: string, + @Body() createEventDto: CreateEventDto, + ) { + return this.eventService.create(groupId, createEventDto); } @Get() - findAll() { - return this.eventService.findAll(); + @ApiOperation({ + summary: '모임 모든 이벤트 조회', + description: '모임의 모든 이벤트를 조회합니다.', + }) + findAll(@Param('groupId') groupId: string) { + return this.eventService.findAll(groupId); } @Get(':eventId') + @ApiOperation({ + summary: '이벤트 상세 조회', + description: '특정 이벤트를 조회합니다.', + }) @ApiParam({ - name: 'memberId', + name: 'eventId', required: true, - description: '모임 회원 ID', + description: '이벤트 ID', }) findOne( @Param('groupId') groupId: string, @@ -46,25 +62,34 @@ export class EventController { } @Patch(':eventId') + @ApiOperation({ + summary: '이벤트 수정', + description: '특정 이벤트를 수정합니다.', + }) @ApiParam({ - name: 'memberId', + name: 'eventId', required: true, - description: '모임 회원 ID', + description: '이벤트 ID', }) update( + @Param('groupId') groupId: string, @Param('eventId') eventId: string, @Body() updateEventDto: UpdateEventDto, ) { - return this.eventService.update(+eventId, updateEventDto); + return this.eventService.update(groupId, eventId, updateEventDto); } @Delete(':eventId') + @ApiOperation({ + summary: '이벤트 삭제', + description: '특정 이벤트를 삭제합니다.', + }) @ApiParam({ - name: 'memberId', + name: 'eventId', required: true, - description: '모임 회원 ID', + description: '이벤트 ID', }) - remove(@Param('eventId') eventId: string) { - return this.eventService.remove(+eventId); + remove(@Param('groupId') groupId: string, @Param('eventId') eventId: string) { + return this.eventService.remove(groupId, eventId); } } diff --git a/src/event/event.module.ts b/src/event/event.module.ts index 0ae4e92..e15569d 100644 --- a/src/event/event.module.ts +++ b/src/event/event.module.ts @@ -1,9 +1,15 @@ import { Module } from '@nestjs/common'; -import { EventService } from './event.service'; + +import { DatabaseModule } from '../database/database.module'; +import { GroupModule } from '../group/group.module'; import { EventController } from './event.controller'; +import { eventProviders } from './event.providers'; +import { EventRepository } from './event.repository'; +import { EventService } from './event.service'; @Module({ + imports: [DatabaseModule, GroupModule], controllers: [EventController], - providers: [EventService], + providers: [EventService, ...eventProviders, EventRepository], }) export class EventModule {} diff --git a/src/event/event.providers.ts b/src/event/event.providers.ts new file mode 100644 index 0000000..201b57a --- /dev/null +++ b/src/event/event.providers.ts @@ -0,0 +1,12 @@ +import { Connection } from 'mongoose'; + +import { EventSchema } from './schemas/event.schema'; + +export const eventProviders = [ + { + provide: 'EVENT_MODEL', + useFactory: (connection: Connection) => + connection.model('Event', EventSchema), + inject: ['MONGODB_CONNECTION'], + }, +]; diff --git a/src/event/event.repository.ts b/src/event/event.repository.ts new file mode 100644 index 0000000..298a672 --- /dev/null +++ b/src/event/event.repository.ts @@ -0,0 +1,35 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Model } from 'mongoose'; + +import { CreateEventDto } from './dto/create-event.dto'; +import { Event } from './interfaces/event.interface'; + +@Injectable() +export class EventRepository { + constructor( + @Inject('EVENT_MODEL') + private readonly eventModel: Model, + ) {} + + async create(createEventDto: CreateEventDto): Promise { + return await this.eventModel.create(createEventDto); + } + + findAll(): Promise { + return this.eventModel.find().exec(); + } + + async findOne(eventId: string): Promise { + return await this.eventModel.findById(eventId).exec(); + } + + update(eventId: string, event: Event): Promise { + return this.eventModel + .findByIdAndUpdate(eventId, event, { new: true }) + .exec(); + } + + delete(eventId: string) { + this.eventModel.findByIdAndDelete(eventId); + } +} diff --git a/src/event/event.service.ts b/src/event/event.service.ts index 75652ca..4c8fc07 100644 --- a/src/event/event.service.ts +++ b/src/event/event.service.ts @@ -1,29 +1,65 @@ import { Injectable } from '@nestjs/common'; + +import { GroupService } from '../group/group.service'; import { CreateEventDto } from './dto/create-event.dto'; import { UpdateEventDto } from './dto/update-event.dto'; +import { EventRepository } from './event.repository'; @Injectable() export class EventService { - create(createEventDto: CreateEventDto) { - return createEventDto; + constructor( + private readonly eventRepository: EventRepository, + private readonly groupService: GroupService, + ) {} + + async create(groupId: string, createEventDto: CreateEventDto) { + const createdEvent = await this.eventRepository.create(createEventDto); + await this.groupService.addEvent(groupId, createdEvent.id); + + return createdEvent; } - findAll() { - return `This action returns all event`; + async findAll(groupId: string) { + const group = await this.groupService.findOne(groupId); + + const events = []; + for (const eventId of group.events) { + events.push(await this.eventRepository.findOne(eventId)); + } + + return events; } - findOne(groupId: string, eventId: string) { + async findOne(groupId: string, eventId: string) { + const group = await this.groupService.findOne(groupId); + const event = await this.eventRepository.findOne(eventId); + return { - groupId, - eventId, + group, + event, }; } - update(eventId: number, updateEventDto: UpdateEventDto) { - return `This action updates a #${eventId} event` + updateEventDto; + async update( + groupId: string, + eventId: string, + updateEventDto: UpdateEventDto, + ) { + const group = await this.groupService.findOne(groupId); + const event = await this.eventRepository.findOne(eventId); + + for (const key in updateEventDto) { + event[key] = updateEventDto[key]; + } + await this.eventRepository.update(eventId, event); + + return { + group, + event, + }; } - remove(eventId: number) { - return `This action removes a #${eventId} event`; + async remove(groupId: string, eventId: string) { + return await this.groupService.deleteEvent(groupId, eventId); } } diff --git a/src/event/interfaces/event.interface.ts b/src/event/interfaces/event.interface.ts new file mode 100644 index 0000000..f1095cc --- /dev/null +++ b/src/event/interfaces/event.interface.ts @@ -0,0 +1,10 @@ +import { Document } from 'mongoose'; + +export interface Event extends Document { + name: string; + description: string; + startDate: Date; + endDate: Date; + fee: number; + attendees: string[]; +} diff --git a/src/event/schemas/event.schema.ts b/src/event/schemas/event.schema.ts new file mode 100644 index 0000000..ad9608e --- /dev/null +++ b/src/event/schemas/event.schema.ts @@ -0,0 +1,10 @@ +import { Schema } from 'mongoose'; + +export const EventSchema = new Schema({ + name: String, + description: String, + startDate: Date, + endDate: Date, + fee: Number, + attendees: { type: [String], default: [] }, +}); diff --git a/src/excel/excel.service.ts b/src/excel/excel.service.ts new file mode 100644 index 0000000..dfa55a5 --- /dev/null +++ b/src/excel/excel.service.ts @@ -0,0 +1,64 @@ +import * as XLSX from 'exceljs'; + +export class ExcelService { + async convertExcelToJSON(groupId: string, excel: Express.Multer.File) { + const workbook = new XLSX.Workbook(); + await workbook.xlsx.load(excel.buffer); + + const worksheet = workbook.getWorksheet(1); + + const columns = []; + worksheet.getRow(1).eachCell((cell) => { + columns.push(cell.value); + }); + + const data = []; + worksheet.eachRow((row, rowNumber) => { + if (rowNumber !== 1) { + const rowObject = {}; + row.eachCell((cell, colNumber) => { + const col = columns[colNumber - 1]; + rowObject[col] = cell.value; + }); + data.push(rowObject); + } + }); + + return { + groupId, + data, + }; + } + + async convertMemberExcelToJSON(excel: Express.Multer.File) { + const workbook = new XLSX.Workbook(); + await workbook.xlsx.load(excel.buffer); + + const worksheet = workbook.getWorksheet(1); + + const columns = []; + worksheet.getRow(1).eachCell((cell) => { + columns.push(cell.value); + }); + + const data = []; + worksheet.eachRow((row, rowNumber) => { + if (rowNumber !== 1) { + const rowObject = {}; + const memberInfo = {}; + row.eachCell((cell, colNumber) => { + const col = columns[colNumber - 1]; + if (col == 'name' || col == '이름') { + rowObject['name'] = String(cell.value).trim(); + } else { + memberInfo[col] = String(cell.value).trim(); + } + }); + rowObject['memberInfo'] = memberInfo; + data.push(rowObject); + } + }); + + return data; + } +} diff --git a/src/group/entities/group.entity.ts b/src/group/entities/group.entity.ts index d19745f..dfdf42f 100644 --- a/src/group/entities/group.entity.ts +++ b/src/group/entities/group.entity.ts @@ -9,5 +9,6 @@ export class Group { authorities: string[]; }, ]; - members: string[]; + members: any[]; + events: string[]; } diff --git a/src/group/group.controller.spec.ts b/src/group/group.controller.spec.ts index 6a46ba4..e75ebed 100644 --- a/src/group/group.controller.spec.ts +++ b/src/group/group.controller.spec.ts @@ -1,14 +1,15 @@ -import { GroupController } from './group.controller'; -import { GroupService } from './group.service'; import { Test, TestingModule } from '@nestjs/testing'; -import { DatabaseModule } from '../database/database.module'; -import { groupProvider } from './group.provider'; import { MongoMemoryServer } from 'mongodb-memory-server'; -import * as process from 'process'; -import { Group } from './entities/group.entity'; import mongoose from 'mongoose'; +import * as process from 'process'; + +import { DatabaseModule } from '../database/database.module'; import { CreateGroupDto } from './dto/create-group.dto'; +import { Group } from './entities/group.entity'; +import { GroupController } from './group.controller'; +import { groupProvider } from './group.provider'; import { GroupRepository } from './group.repository'; +import { GroupService } from './group.service'; describe('GroupController', () => { let groupController: GroupController; diff --git a/src/group/group.controller.ts b/src/group/group.controller.ts index 535b8f0..c52e5b2 100644 --- a/src/group/group.controller.ts +++ b/src/group/group.controller.ts @@ -6,15 +6,14 @@ import { Param, Patch, Post, - UploadedFile, UseFilters, } from '@nestjs/common'; -import { GroupService } from './group.service'; +import { ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; + +import { HttpExceptionFilter } from '../common/filters/http-exception.filter'; import { CreateGroupDto } from './dto/create-group.dto'; import { UpdateGroupDto } from './dto/update-group.dto'; -import { ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; -import { HttpExceptionFilter } from '../http-exception.filter'; -import { ApiFile } from '../api-file.decorator'; +import { GroupService } from './group.service'; @ApiTags('Group') @Controller('group') @@ -93,22 +92,4 @@ export class GroupController { delete(@Param('groupId') groupId: string) { return this.groupService.delete(groupId); } - - @Post(':groupId/member/excel') - @ApiParam({ - name: 'groupId', - required: true, - description: '모임 ID', - }) - @ApiOperation({ - summary: '모임 회원 엑셀 파일 업로드', - description: '모임 회원 엑셀 파일을 업로드합니다.', - }) - @ApiFile('excel') - async uploadMemberFile( - @Param('groupId') groupId: string, - @UploadedFile() excel: Express.Multer.File, - ) { - return await this.groupService.convertExcelToJSON(groupId, excel); - } } diff --git a/src/group/group.module.ts b/src/group/group.module.ts index 1363d92..6589077 100644 --- a/src/group/group.module.ts +++ b/src/group/group.module.ts @@ -1,9 +1,10 @@ import { Module } from '@nestjs/common'; -import { GroupService } from './group.service'; + +import { DatabaseModule } from '../database/database.module'; import { GroupController } from './group.controller'; import { groupProvider } from './group.provider'; -import { DatabaseModule } from '../database/database.module'; import { GroupRepository } from './group.repository'; +import { GroupService } from './group.service'; @Module({ imports: [DatabaseModule], diff --git a/src/group/group.provider.ts b/src/group/group.provider.ts index c6093d0..33a4e2f 100644 --- a/src/group/group.provider.ts +++ b/src/group/group.provider.ts @@ -1,4 +1,5 @@ import { Connection } from 'mongoose'; + import { GroupSchema } from './schemas/group.schema'; export const groupProvider = [ diff --git a/src/group/group.repository.ts b/src/group/group.repository.ts index 2229422..c731e96 100644 --- a/src/group/group.repository.ts +++ b/src/group/group.repository.ts @@ -1,8 +1,9 @@ import { Inject, Injectable } from '@nestjs/common'; import { Model } from 'mongoose'; -import { Group } from './interfaces/group.interface'; + import { CreateGroupDto } from './dto/create-group.dto'; import { UpdateGroupDto } from './dto/update-group.dto'; +import { Group } from './interfaces/group.interface'; @Injectable() export class GroupRepository { diff --git a/src/group/group.service.ts b/src/group/group.service.ts index 8ce3051..9583730 100644 --- a/src/group/group.service.ts +++ b/src/group/group.service.ts @@ -1,9 +1,9 @@ import { Injectable } from '@nestjs/common'; -import { GroupRepository } from './group.repository'; + import { CreateGroupDto } from './dto/create-group.dto'; -import { Group } from './entities/group.entity'; import { UpdateGroupDto } from './dto/update-group.dto'; -import * as XLSX from 'exceljs'; +import { Group } from './entities/group.entity'; +import { GroupRepository } from './group.repository'; @Injectable() export class GroupService { @@ -22,6 +22,13 @@ export class GroupService { return group; } + async addEvent(groupId: string, eventId: string): Promise { + const group = (await this.groupRepository.findOne(groupId)) as Group; + group.events.push(eventId); + await this.groupRepository.update(groupId, group); + return group; + } + async findAll(): Promise { return (await this.groupRepository.findAll()) as Group[]; } @@ -55,68 +62,16 @@ export class GroupService { await this.groupRepository.update(groupId, group); } - async deleteAll(): Promise { - return this.groupRepository.deleteAll(); - } + async deleteEvent(groupId: string, eventId: string): Promise { + const group = (await this.groupRepository.findOne(groupId)) as Group; + const groupEvents = group.events; - async convertExcelToJSON(groupId: string, excel: Express.Multer.File) { - const workbook = new XLSX.Workbook(); - await workbook.xlsx.load(excel.buffer); - - const worksheet = workbook.getWorksheet(1); - - const columns = []; - worksheet.getRow(1).eachCell((cell) => { - columns.push(cell.value); - }); - - const data = []; - worksheet.eachRow((row, rowNumber) => { - if (rowNumber !== 1) { - const rowObject = {}; - row.eachCell((cell, colNumber) => { - const col = columns[colNumber - 1]; - rowObject[col] = cell.value; - }); - data.push(rowObject); - } - }); - - return { - groupId, - data, - }; + group.events = groupEvents.filter((event) => event !== eventId); + + await this.groupRepository.update(groupId, group); } - async convertMemberExcelToJSON(excel: Express.Multer.File) { - const workbook = new XLSX.Workbook(); - await workbook.xlsx.load(excel.buffer); - - const worksheet = workbook.getWorksheet(1); - - const columns = []; - worksheet.getRow(1).eachCell((cell) => { - columns.push(cell.value); - }); - - const data = []; - worksheet.eachRow((row, rowNumber) => { - if (rowNumber !== 1) { - const rowObject = {}; - const memberInfo = {}; - row.eachCell((cell, colNumber) => { - const col = columns[colNumber - 1]; - if (col == 'name' || col == '이름') { - rowObject['name'] = String(cell.value).trim(); - } else { - memberInfo[col] = String(cell.value).trim(); - } - }); - rowObject['memberInfo'] = memberInfo; - data.push(rowObject); - } - }); - - return data; + async deleteAll(): Promise { + return this.groupRepository.deleteAll(); } } diff --git a/src/group/interfaces/group.interface.ts b/src/group/interfaces/group.interface.ts index aeb4422..cadcb74 100644 --- a/src/group/interfaces/group.interface.ts +++ b/src/group/interfaces/group.interface.ts @@ -10,5 +10,6 @@ export interface Group extends Document { authorities: string[]; }, ]; - members: string[]; + members: any[]; + events: string[]; } diff --git a/src/group/schemas/group.schema.ts b/src/group/schemas/group.schema.ts index 12de0ba..30ad9b0 100644 --- a/src/group/schemas/group.schema.ts +++ b/src/group/schemas/group.schema.ts @@ -14,4 +14,5 @@ export const GroupSchema = new Schema({ default: [], }, members: { type: [String], default: [] }, + events: { type: [String], default: [] }, }); diff --git a/src/main.ts b/src/main.ts index 2a46ca4..5f4bc5b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,13 @@ +import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; -import { AppModule } from './app.module'; -import { configSwagger } from './config.swagger'; import * as process from 'process'; -import { ValidationPipe } from '@nestjs/common'; + +import { AppModule } from './app.module'; +import { swaggerConfig } from './common/configs/swagger.config'; async function bootstrap() { const app = await NestFactory.create(AppModule); - configSwagger(app); + swaggerConfig(app); app.useGlobalPipes(new ValidationPipe()); app.enableCors(); await app.listen(process.env.SERVER_PORT); diff --git a/src/member/dto/update-member.dto.ts b/src/member/dto/update-member.dto.ts index 7a0a493..75b6f9d 100644 --- a/src/member/dto/update-member.dto.ts +++ b/src/member/dto/update-member.dto.ts @@ -1,4 +1,5 @@ import { ApiProperty, PartialType } from '@nestjs/swagger'; + import { CreateMemberDto } from './create-member.dto'; export class UpdateMemberDto extends PartialType(CreateMemberDto) { diff --git a/src/member/member.controller.spec.ts b/src/member/member.controller.spec.ts index 6defd3b..f44ded1 100644 --- a/src/member/member.controller.spec.ts +++ b/src/member/member.controller.spec.ts @@ -1,13 +1,15 @@ -import { MemberController } from './member.controller'; -import { MemberService } from './member.service'; -import mongoose from 'mongoose'; import { Test } from '@nestjs/testing'; -import { DatabaseModule } from '../database/database.module'; import { MongoMemoryServer } from 'mongodb-memory-server'; +import mongoose from 'mongoose'; import * as process from 'process'; + +import { DatabaseModule } from '../database/database.module'; +import { ExcelService } from '../excel/excel.service'; +import { GroupModule } from '../group/group.module'; +import { MemberController } from './member.controller'; import { memberProvider } from './member.provider'; import { MemberRepository } from './member.repository'; -import { GroupModule } from '../group/group.module'; +import { MemberService } from './member.service'; describe('MemberController', () => { // let memberController: MemberController; @@ -21,7 +23,12 @@ describe('MemberController', () => { await Test.createTestingModule({ imports: [DatabaseModule, GroupModule], controllers: [MemberController], - providers: [MemberService, ...memberProvider, MemberRepository], + providers: [ + MemberService, + ...memberProvider, + MemberRepository, + ExcelService, + ], }).compile(); // memberService = module.get(MemberService); diff --git a/src/member/member.controller.ts b/src/member/member.controller.ts index f366ac6..410beba 100644 --- a/src/member/member.controller.ts +++ b/src/member/member.controller.ts @@ -9,12 +9,13 @@ import { UploadedFile, UseFilters, } from '@nestjs/common'; -import { MemberService } from './member.service'; +import { ApiBody, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; + +import { ApiFile } from '../common/decorators/api-file.decorator'; +import { HttpExceptionFilter } from '../common/filters/http-exception.filter'; import { CreateMemberDto } from './dto/create-member.dto'; import { UpdateMemberDto } from './dto/update-member.dto'; -import { ApiBody, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; -import { HttpExceptionFilter } from '../http-exception.filter'; -import { ApiFile } from '../api-file.decorator'; +import { MemberService } from './member.service'; @UseFilters(HttpExceptionFilter) @ApiTags('Member') @@ -52,6 +53,19 @@ export class MemberController { return this.memberService.createGroupMembers(groupId, createMemberDto); } + @Post('/excel') + @ApiOperation({ + summary: '모임 회원 명단 업로드', + description: '모임 회원 명단을 재구성합니다.', + }) + @ApiFile('excel') + uploadMemberFIle( + @Param('groupId') groupId: string, + @UploadedFile() excel: Express.Multer.File, + ) { + return this.memberService.uploadMemberFile(groupId, excel); + } + @Get() @ApiOperation({ summary: '모임 모든 회원 조회', @@ -141,17 +155,4 @@ export class MemberController { deleteAllGroupMembers(@Param('groupId') groupId: string) { return this.memberService.deleteAllGroupMembers(groupId); } - - @Post('/upload/excel') - @ApiOperation({ - summary: '회원 명단 업로드', - description: '회원 명단을 재구성합니다.', - }) - @ApiFile('excel') - async uploadMemberFIle( - @Param('groupId') groupId: string, - @UploadedFile() excel: Express.Multer.File, - ) { - return await this.memberService.uploadMemberFile(groupId, excel); - } } diff --git a/src/member/member.module.ts b/src/member/member.module.ts index bed589c..1abc293 100644 --- a/src/member/member.module.ts +++ b/src/member/member.module.ts @@ -1,14 +1,16 @@ import { Module } from '@nestjs/common'; -import { MemberService } from './member.service'; -import { MemberController } from './member.controller'; + import { DatabaseModule } from '../database/database.module'; +import { ExcelService } from '../excel/excel.service'; +import { GroupModule } from '../group/group.module'; +import { MemberController } from './member.controller'; import { memberProvider } from './member.provider'; import { MemberRepository } from './member.repository'; -import { GroupModule } from '../group/group.module'; +import { MemberService } from './member.service'; @Module({ imports: [DatabaseModule, GroupModule], controllers: [MemberController], - providers: [MemberService, ...memberProvider, MemberRepository], + providers: [MemberService, ...memberProvider, MemberRepository, ExcelService], }) export class MemberModule {} diff --git a/src/member/member.provider.ts b/src/member/member.provider.ts index 6c18893..3a266b7 100644 --- a/src/member/member.provider.ts +++ b/src/member/member.provider.ts @@ -1,4 +1,5 @@ import { Connection } from 'mongoose'; + import { MemberSchema } from './schemas/member.schema'; export const memberProvider = [ diff --git a/src/member/member.repository.ts b/src/member/member.repository.ts index 46fc391..0807985 100644 --- a/src/member/member.repository.ts +++ b/src/member/member.repository.ts @@ -1,8 +1,9 @@ import { Inject, Injectable } from '@nestjs/common'; -import { Member } from './interfaces/member.interface'; import { Model } from 'mongoose'; + import { CreateMemberDto } from './dto/create-member.dto'; import { UpdateMemberDto } from './dto/update-member.dto'; +import { Member } from './interfaces/member.interface'; @Injectable() export class MemberRepository { @@ -15,10 +16,6 @@ export class MemberRepository { return this.memberModel.create(createMemberDto); } - findAll(members: string[]): Promise { - return this.memberModel.find({ _id: { $in: members } }).exec(); - } - findOne(memberId: string): Promise { return this.memberModel.findById(memberId).exec(); } diff --git a/src/member/member.service.ts b/src/member/member.service.ts index 74ec67b..93da30e 100644 --- a/src/member/member.service.ts +++ b/src/member/member.service.ts @@ -1,16 +1,19 @@ import { Injectable, NotFoundException } from '@nestjs/common'; -import { MemberRepository } from './member.repository'; -import { Member } from './entities/member.entity'; +import mongoose from 'mongoose'; + +import { ExcelService } from '../excel/excel.service'; +import { GroupService } from '../group/group.service'; import { CreateMemberDto } from './dto/create-member.dto'; import { UpdateMemberDto } from './dto/update-member.dto'; -import { GroupService } from '../group/group.service'; -import mongoose from 'mongoose'; +import { Member } from './entities/member.entity'; +import { MemberRepository } from './member.repository'; @Injectable() export class MemberService { constructor( private readonly memberRepository: MemberRepository, private readonly groupService: GroupService, + private readonly excelService: ExcelService, ) {} async create( @@ -42,9 +45,15 @@ export class MemberService { } async findAll(groupId: string): Promise { - //lookup 써서 join하려고 했는데 model처리가 어려워서 임시로..디비 두번 접근 const group = await this.groupService.findOne(groupId); - return (await this.memberRepository.findAll(group.members)) as Member[]; + + const members = []; + for (const memberId of group.members) { + const member = await this.memberRepository.findOne(memberId); + if (member) members.push(member); + } + + return members; } async findOne(groupId: string, memberId: string): Promise { @@ -101,7 +110,7 @@ export class MemberService { excel: Express.Multer.File, ): Promise { const members: Member[] = - await this.groupService.convertMemberExcelToJSON(excel); + await this.excelService.convertMemberExcelToJSON(excel); //멤버 삭제 await this.deleteAllGroupMembers(groupId); //group에 멤버 추가 diff --git a/src/user/dto/update-user.dto.ts b/src/user/dto/update-user.dto.ts index 78ab602..e1cec90 100644 --- a/src/user/dto/update-user.dto.ts +++ b/src/user/dto/update-user.dto.ts @@ -1,4 +1,5 @@ import { PartialType } from '@nestjs/swagger'; + import { CreateUserDto } from './create-user.dto'; export class UpdateUserDto extends PartialType(CreateUserDto) {} diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts index ffad450..f975628 100644 --- a/src/user/user.controller.ts +++ b/src/user/user.controller.ts @@ -7,10 +7,11 @@ import { Patch, Post, } from '@nestjs/common'; -import { UserService } from './user.service'; +import { ApiTags } from '@nestjs/swagger'; + import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; -import { ApiTags } from '@nestjs/swagger'; +import { UserService } from './user.service'; @ApiTags('User') @Controller('user') diff --git a/src/user/user.module.ts b/src/user/user.module.ts index e21d51f..c59c53a 100644 --- a/src/user/user.module.ts +++ b/src/user/user.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; -import { UserService } from './user.service'; + import { UserController } from './user.controller'; +import { UserService } from './user.service'; @Module({ controllers: [UserController], diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 23b2ef6..af873a0 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@nestjs/common'; + import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; diff --git a/test/app.e2e-spec.ts b/test/app.e2e-spec.ts index 50cda62..22e885e 100644 --- a/test/app.e2e-spec.ts +++ b/test/app.e2e-spec.ts @@ -1,7 +1,8 @@ -import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; import * as request from 'supertest'; -import { AppModule } from './../src/app.module'; + +import { AppModule } from '../src/app.module'; describe('AppController (e2e)', () => { let app: INestApplication;