Skip to content

Commit 357cc79

Browse files
authored
Merge pull request #81 from oodd-team/OD-196
2 parents 69a406a + 07782ab commit 357cc79

5 files changed

+199
-108
lines changed

src/matching/dto/matching.response.ts

+20-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ApiProperty, OmitType } from '@nestjs/swagger';
22
import { Type } from 'class-transformer';
3+
import { MatchingRequestStatusEnum } from 'src/common/enum/matchingRequestStatus';
34

45
export class PatchMatchingResponse {
56
@ApiProperty({ example: 1, description: '매칭 ID' })
@@ -67,7 +68,7 @@ class RequesterResponse {
6768
representativePost?: RepresentativePost;
6869
}
6970

70-
class MatchingResponse {
71+
export class MatchingResponse {
7172
@ApiProperty({ example: 1, description: '매칭 ID' })
7273
id: number;
7374

@@ -110,18 +111,6 @@ export class CreateMatchingResponse {
110111
}
111112

112113
export class GetMatchingsResponse {
113-
@ApiProperty({
114-
description: '매칭 존재 여부',
115-
example: true,
116-
})
117-
hasMatching: boolean;
118-
119-
@ApiProperty({
120-
description: '받은 매칭 수',
121-
example: 10,
122-
})
123-
matchingsCount: number;
124-
125114
@ApiProperty({
126115
description: '매칭 정보',
127116
type: [MatchingResponse],
@@ -139,3 +128,21 @@ export class GetOneMatchingResponse extends OmitType(PatchMatchingResponse, [
139128
})
140129
createdAt: string;
141130
}
131+
132+
export interface MatchingRequest {
133+
id: number;
134+
message: string;
135+
createdAt: string;
136+
requestStatus: MatchingRequestStatusEnum;
137+
chatRoomId: number;
138+
targetId: number;
139+
requester: {
140+
id: number;
141+
nickname: string;
142+
profilePictureUrl: string;
143+
representativePost?: {
144+
postImages: { url: string; orderNum: number }[];
145+
styleTags: string[];
146+
};
147+
};
148+
}

src/matching/matching.controller.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434
PatchMatchingResponse,
3535
CreateMatchingResponse,
3636
GetMatchingsResponse,
37-
GetOneMatchingResponse,
3837
} from './dto/matching.response';
3938
import { AuthGuard } from 'src/auth/guards/jwt.auth.guard';
4039
import { PostService } from 'src/post/post.service';
@@ -83,8 +82,8 @@ export class MatchingController {
8382
)
8483
throw InvalidInputValueException('이미 매칭 요청을 보냈습니다.');
8584

86-
const matching = await this.matchingService.createMatching(body);
87-
return new BaseResponse<CreateMatchingResponse>(true, 'SUCCESS', matching);
85+
await this.matchingService.createMatching(body);
86+
return new BaseResponse<CreateMatchingResponse>(true, 'SUCCESS');
8887
}
8988

9089
@Patch(':matchingId')

src/matching/matching.service.ts

+128-75
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import { InternalServerException } from 'src/common/exception/service.exception'
1010
import { ChatMessageService } from 'src/chat-message/chat-message.service';
1111
import { InjectRepository } from '@nestjs/typeorm';
1212
import {
13-
CreateMatchingResponse,
1413
GetMatchingsResponse,
1514
GetOneMatchingResponse,
15+
MatchingRequest,
1616
} from './dto/matching.response';
1717
import { MatchingRequestStatusEnum } from 'src/common/enum/matchingRequestStatus';
1818
import { StatusEnum } from 'src/common/enum/entityStatus';
@@ -38,9 +38,7 @@ export class MatchingService {
3838
});
3939
}
4040

41-
async createMatching(
42-
body: CreateMatchingRequest,
43-
): Promise<CreateMatchingResponse> {
41+
async createMatching(body: CreateMatchingRequest): Promise<void> {
4442
const queryRunner = this.dataSource.createQueryRunner();
4543
await queryRunner.connect();
4644
await queryRunner.startTransaction();
@@ -63,46 +61,8 @@ export class MatchingService {
6361
body,
6462
);
6563

66-
const matchingInfo = await queryRunner.manager
67-
.createQueryBuilder(Matching, 'matching')
68-
.leftJoinAndSelect('matching.target', 'target')
69-
.leftJoinAndSelect('matching.requester', 'requester')
70-
.leftJoinAndSelect('requester.posts', 'post')
71-
.leftJoinAndSelect('post.postImages', 'image')
72-
.leftJoinAndSelect('post.postStyletags', 'styleTag')
73-
.leftJoinAndSelect('styleTag.styletag', 'styletag')
74-
.where('matching.id = :id', { id: matching.id })
75-
.getOne();
76-
77-
const requesterPost = matchingInfo.requester.posts[0];
78-
7964
await queryRunner.commitTransaction();
80-
81-
return {
82-
id: matchingInfo.id,
83-
message: body.message,
84-
createdAt: dayjs(matching.createdAt).format('YYYY-MM-DDTHH:mm:ssZ'),
85-
chatRoomId: chatRoom.id,
86-
targetId: body.targetId,
87-
requester: {
88-
id: body.requesterId,
89-
nickname: matchingInfo.requester.nickname,
90-
profilePictureUrl: matchingInfo.requester.profilePictureUrl,
91-
representativePost: requesterPost
92-
? {
93-
postImages: requesterPost.postImages.map((image) => ({
94-
url: image.url,
95-
orderNum: image.orderNum,
96-
})),
97-
styleTags: requesterPost.postStyletags
98-
? requesterPost.postStyletags.map(
99-
(styleTag) => styleTag.styletag.tag,
100-
)
101-
: [],
102-
}
103-
: {},
104-
},
105-
};
65+
await this.addMatchingQueues(body.targetId);
10666
} catch (error) {
10767
await queryRunner.rollbackTransaction();
10868
throw InternalServerException(error.message);
@@ -122,7 +82,6 @@ export class MatchingService {
12282
matching.id,
12383
);
12484
try {
125-
console.log(body.requestStatus);
12685
if (body.requestStatus === 'accept') {
12786
matching.requestStatus = MatchingRequestStatusEnum.ACCEPTED;
12887
matching.acceptedAt = new Date();
@@ -157,7 +116,7 @@ export class MatchingService {
157116
});
158117

159118
if (!matching) {
160-
return {};
119+
return null;
161120
}
162121

163122
return {
@@ -169,16 +128,96 @@ export class MatchingService {
169128
};
170129
}
171130

172-
async getMatchings(currentUserId: number): Promise<GetMatchingsResponse> {
131+
private matchingQueues: { [key: number]: MatchingRequest[] } = [];
132+
// 매칭 추가
133+
async addMatchingQueues(userId: number) {
134+
try {
135+
const matchingInfo = await this.matchingRepository
136+
.createQueryBuilder('matching')
137+
.leftJoinAndSelect('matching.requester', 'requester')
138+
.leftJoinAndSelect('requester.posts', 'post')
139+
.leftJoinAndSelect('post.postImages', 'image')
140+
.leftJoinAndSelect('post.postStyletags', 'styleTag')
141+
.leftJoinAndSelect('styleTag.styletag', 'styletag')
142+
.where('matching.targetId = :userId', { userId })
143+
.andWhere('matching.requestStatus = :status', {
144+
status: MatchingRequestStatusEnum.PENDING,
145+
})
146+
.andWhere('matching.status = :activated', {
147+
activated: StatusEnum.ACTIVATED,
148+
})
149+
.andWhere('requester.status = :activated', {
150+
activated: StatusEnum.ACTIVATED,
151+
})
152+
.orderBy('matching.createdAt', 'DESC')
153+
.addOrderBy('post.isRepresentative', 'DESC')
154+
.addOrderBy('post.createdAt', 'DESC')
155+
.orderBy('matching.createdAt', 'DESC')
156+
.getOne();
157+
158+
const requesterPost = matchingInfo.requester.posts[0];
159+
const chatRoom = await this.chatRoomService.getChatRoomByMatchingId(
160+
matchingInfo.id,
161+
);
162+
163+
const formattedMatching: MatchingRequest = {
164+
id: matchingInfo.id,
165+
message: matchingInfo.message,
166+
createdAt: dayjs(matchingInfo.createdAt).format('YYYY-MM-DDTHH:mm:ssZ'),
167+
requestStatus: matchingInfo.requestStatus,
168+
chatRoomId: chatRoom.id,
169+
targetId: userId,
170+
requester: {
171+
id: matchingInfo.requester.id,
172+
nickname: matchingInfo.requester.nickname,
173+
profilePictureUrl: matchingInfo.requester.profilePictureUrl,
174+
representativePost: requesterPost
175+
? {
176+
postImages: requesterPost.postImages.map((image) => ({
177+
url: image.url,
178+
orderNum: image.orderNum,
179+
})),
180+
styleTags: requesterPost.postStyletags
181+
? requesterPost.postStyletags.map(
182+
(styleTag) => styleTag.styletag.tag,
183+
)
184+
: [],
185+
}
186+
: undefined,
187+
},
188+
};
189+
190+
if (!this.matchingQueues[userId]) {
191+
this.matchingQueues[userId] = [];
192+
}
193+
this.matchingQueues[userId].push(formattedMatching);
194+
} catch (error) {
195+
throw InternalServerException(error);
196+
}
197+
}
198+
199+
// 다음 매칭 가져오기 (큐에서 제거)
200+
getNextMatching(userId: number): MatchingRequest | {} {
201+
if (
202+
!this.matchingQueues[userId] ||
203+
this.matchingQueues[userId].length === 0
204+
) {
205+
return {};
206+
}
207+
return this.matchingQueues[userId].shift() || {};
208+
}
209+
210+
async getMatchings(userId: number): Promise<GetMatchingsResponse> {
173211
const matchings = await this.matchingRepository
174212
.createQueryBuilder('matching')
175213
.leftJoinAndSelect('matching.requester', 'requester')
176214
.leftJoinAndSelect('requester.posts', 'post')
177215
.leftJoinAndSelect('post.postImages', 'image')
178216
.leftJoinAndSelect('post.postStyletags', 'styleTag')
179217
.leftJoinAndSelect('styleTag.styletag', 'styletag')
180-
.where('matching.targetId = :currentUserId', { currentUserId })
181-
.andWhere('matching.requestStatus = :status', {
218+
.where('matching.targetId = :userId', { userId })
219+
// Pending이 아닌 매칭 조회
220+
.andWhere('matching.requestStatus <> :status', {
182221
status: MatchingRequestStatusEnum.PENDING,
183222
})
184223
.andWhere('matching.status = :activated', {
@@ -193,35 +232,49 @@ export class MatchingService {
193232
.getMany();
194233

195234
const response: GetMatchingsResponse = {
196-
hasMatching: matchings.length > 0,
197-
matchingsCount: matchings.length,
198-
matching: matchings.map((matching) => {
199-
const requesterPost = matching.requester.posts[0];
235+
matching: await Promise.all(
236+
matchings.map(async (matching) => {
237+
try {
238+
const requesterPost = matching.requester.posts[0];
239+
const chatRoom = await this.chatRoomService.getChatRoomByMatchingId(
240+
matching.id,
241+
);
200242

201-
return {
202-
id: matching.id,
203-
requester: {
204-
id: matching.requester.id,
205-
nickname: matching.requester.nickname,
206-
profilePictureUrl: matching.requester.profilePictureUrl,
207-
representativePost: requesterPost
208-
? {
209-
postImages: requesterPost.postImages.map((image) => ({
210-
url: image.url,
211-
orderNum: image.orderNum,
212-
})),
213-
styleTags: requesterPost.postStyletags
214-
? requesterPost.postStyletags.map(
215-
(styleTag) => styleTag.styletag.tag,
216-
)
217-
: [],
218-
}
219-
: {},
220-
},
221-
};
222-
}),
243+
return {
244+
id: matching.id,
245+
message: matching.message,
246+
createdAt: dayjs(matching.createdAt).format(
247+
'YYYY-MM-DDTHH:mm:ssZ',
248+
),
249+
requestStatus: matching.requestStatus,
250+
chatRoomId: chatRoom.id,
251+
targetId: userId,
252+
requester: {
253+
id: matching.requester.id,
254+
nickname: matching.requester.nickname,
255+
profilePictureUrl: matching.requester.profilePictureUrl,
256+
representativePost: requesterPost
257+
? {
258+
postImages: requesterPost.postImages.map((image) => ({
259+
url: image.url,
260+
orderNum: image.orderNum,
261+
})),
262+
styleTags: requesterPost.postStyletags
263+
? requesterPost.postStyletags.map(
264+
(styleTag) => styleTag.styletag.tag,
265+
)
266+
: [],
267+
}
268+
: {},
269+
},
270+
};
271+
} catch (error) {
272+
throw InternalServerException(error);
273+
}
274+
}),
275+
),
223276
};
224-
return response;
277+
return response.matching.length ? response : { matching: [] };
225278
}
226279

227280
async getMatchingById(matchingId: number): Promise<Matching> {

0 commit comments

Comments
 (0)