diff --git a/server/src/entity/meeting/meeting.entity.ts b/server/src/entity/meeting/meeting.entity.ts index 380a2c95..5a6fd968 100644 --- a/server/src/entity/meeting/meeting.entity.ts +++ b/server/src/entity/meeting/meeting.entity.ts @@ -103,6 +103,13 @@ export class Meeting extends BaseEntity { @Column() canJoinOnlyActiveGeneration: boolean; + /** + * 모임 기수 + * @description 생성 시점의 기수 + */ + @Column() + createdGeneration: number; + /** * 대상 활동 기수 * null인 경우 모든 기수 허용 diff --git a/server/src/entity/meeting/meeting.repository.ts b/server/src/entity/meeting/meeting.repository.ts index a6560a1d..eed0b954 100644 --- a/server/src/entity/meeting/meeting.repository.ts +++ b/server/src/entity/meeting/meeting.repository.ts @@ -38,13 +38,21 @@ export class MeetingRepository extends Repository { } // id와 카테고리, 상태로 모임 정보 및 개수 조회 - async getMeetingsAndCount( - getMeetingDto: MeetingV0GetAllMeetingsQueryDto, - categoryArr: MeetingCategory[], - statusArr: MeetingV0MeetingStatus[], - canJoinOnlyActiveGeneration: boolean, - joinableParts?: MeetingJoinablePart | MeetingJoinablePart[], - ): Promise<[Meeting[], number]> { + async getMeetingsAndCount({ + getMeetingDto, + categoryArr, + statusArr, + canJoinOnlyActiveGeneration, + joinableParts, + createdGenerations, + }: { + getMeetingDto: MeetingV0GetAllMeetingsQueryDto; + categoryArr: MeetingCategory[]; + statusArr: MeetingV0MeetingStatus[]; + canJoinOnlyActiveGeneration: boolean; + joinableParts?: MeetingJoinablePart | MeetingJoinablePart[]; + createdGenerations?: number[]; + }): Promise<[Meeting[], number]> { const { query, skip, take } = getMeetingDto; const nowDate = dayjs().toDate(); @@ -55,8 +63,7 @@ export class MeetingRepository extends Repository { 'apply.status = :status', { status: 1 }, ) - .leftJoinAndSelect('meeting.user', 'user') - .where('1 = 1'); + .leftJoinAndSelect('meeting.user', 'user'); if (query) { meetingQuery.andWhere('meeting.title like :title', { @@ -70,6 +77,15 @@ export class MeetingRepository extends Repository { }); } + if (createdGenerations !== undefined) { + meetingQuery.andWhere( + 'meeting.createdGeneration IN (:...createdGenerations)', + { + createdGenerations, + }, + ); + } + if (canJoinOnlyActiveGeneration === true) { meetingQuery.andWhere( 'meeting.canJoinOnlyActiveGeneration = :canJoinOnlyActiveGeneration', diff --git a/server/src/meeting/v0/dto/get-all-meetings/meeting-v0-get-all-meetings-query.dto.ts b/server/src/meeting/v0/dto/get-all-meetings/meeting-v0-get-all-meetings-query.dto.ts index b4e3914c..6967cc61 100644 --- a/server/src/meeting/v0/dto/get-all-meetings/meeting-v0-get-all-meetings-query.dto.ts +++ b/server/src/meeting/v0/dto/get-all-meetings/meeting-v0-get-all-meetings-query.dto.ts @@ -1,9 +1,16 @@ -import { IsString, IsOptional, IsNotEmpty, IsEnum } from 'class-validator'; +import { + IsString, + IsOptional, + IsNotEmpty, + IsEnum, + IsNumber, +} from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; import { PageOptionsDto } from 'src/common/pagination/dto/page-options.dto'; import { MeetingJoinablePart } from '../../../../entity/meeting/enum/meeting-joinable-part.enum'; import { IsBoolean } from 'src/common/decorator/is-boolean.decorator'; +import { Transform } from 'class-transformer'; export class MeetingV0GetAllMeetingsQueryDto extends PageOptionsDto { @ApiProperty({ @@ -51,4 +58,16 @@ export class MeetingV0GetAllMeetingsQueryDto extends PageOptionsDto { @IsOptional() @IsString() readonly query?: string; + + @ApiProperty({ + example: '32,33', + description: '모임 기수', + type: 'string', + required: false, + }) + @IsOptional() + @Transform(({ value }) => value.split(',').map(Number)) + @IsNotEmpty({ each: true }) + @IsNumber({}, { each: true }) + readonly createdGenerations?: number[]; } diff --git a/server/src/meeting/v0/dto/meeting-v0-get-meeting-by-id-response.dto.ts b/server/src/meeting/v0/dto/meeting-v0-get-meeting-by-id-response.dto.ts index 6f8a94c8..5f083451 100644 --- a/server/src/meeting/v0/dto/meeting-v0-get-meeting-by-id-response.dto.ts +++ b/server/src/meeting/v0/dto/meeting-v0-get-meeting-by-id-response.dto.ts @@ -72,6 +72,8 @@ export class MeetingV0GetMeetingByIdResponseDto { approvedApplyCount: number; + createdGeneration: number; + joinableParts: MeetingJoinablePart[]; // 칼럼이 아닌 response할 때 meeting 객체에 넣어줄 값 status?: MeetingV0MeetingStatus; // 모임 상태 diff --git a/server/src/meeting/v0/meeting-v0.service.ts b/server/src/meeting/v0/meeting-v0.service.ts index 6dcb8201..d9ce39a0 100644 --- a/server/src/meeting/v0/meeting-v0.service.ts +++ b/server/src/meeting/v0/meeting-v0.service.ts @@ -214,6 +214,7 @@ export class MeetingV0Service { page, isOnlyActiveGeneration, joinableParts, + createdGenerations, } = getMeetingDto; const categoryArr: MeetingCategory[] = category @@ -225,13 +226,14 @@ export class MeetingV0Service { : []; const [meetingResponse, itemCount] = - await this.meetingRepository.getMeetingsAndCount( + await this.meetingRepository.getMeetingsAndCount({ getMeetingDto, categoryArr, statusArr, - isOnlyActiveGeneration, + canJoinOnlyActiveGeneration: isOnlyActiveGeneration, joinableParts, - ); + createdGenerations, + }); const meetingPromises = meetingResponse.map(async (meeting) => { const { status } = await getMeetingStatus(meeting); diff --git a/server/src/meeting/v1/meeting-v1.service.ts b/server/src/meeting/v1/meeting-v1.service.ts index e1d24b88..87bfad73 100644 --- a/server/src/meeting/v1/meeting-v1.service.ts +++ b/server/src/meeting/v1/meeting-v1.service.ts @@ -159,6 +159,7 @@ export class MeetingV1Service { { ...meeting, targetActiveGeneration, + createdGeneration: ACTIVE_GENERATION, canJoinOnlyActiveGeneration, endDate, },