Skip to content

Commit e9bad16

Browse files
committed
차단 유저 like,comment 제외
1 parent 255ea3d commit e9bad16

File tree

4 files changed

+119
-59
lines changed

4 files changed

+119
-59
lines changed

src/post/dtos/all-posts.response.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ApiProperty } from '@nestjs/swagger';
22
import dayjs from 'dayjs';
33
import { Post } from 'src/common/entities/post.entity';
44
import { PostImage } from 'src/common/entities/post-image.entity';
5+
import { User } from 'src/common/entities/user.entity';
56

67
class PostImageDto {
78
@ApiProperty({
@@ -41,7 +42,7 @@ class UserDto {
4142
})
4243
profilePictureUrl: string;
4344

44-
constructor(user: any) {
45+
constructor(user: User) {
4546
this.userId = user.id;
4647
this.nickname = user.nickname;
4748
this.profilePictureUrl = user.profilePictureUrl;

src/post/dtos/post.response.ts

+104-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { ApiProperty, OmitType } from '@nestjs/swagger';
22
import { Type } from 'class-transformer';
3+
import dayjs from 'dayjs';
4+
import { PostClothing } from 'src/common/entities/post-clothing.entity';
5+
import { PostImage } from 'src/common/entities/post-image.entity';
6+
import { Post } from 'src/common/entities/post.entity';
7+
import { User } from 'src/common/entities/user.entity';
38

49
class PostImageDto {
510
@ApiProperty({
@@ -13,6 +18,11 @@ class PostImageDto {
1318
description: '이미지의 순서 번호',
1419
})
1520
orderNum: number;
21+
22+
constructor(postImage: PostImage) {
23+
this.imageUrl = postImage.url;
24+
this.orderNum = postImage.orderNum;
25+
}
1626
}
1727

1828
class UserDto {
@@ -33,6 +43,12 @@ class UserDto {
3343
description: '사용자의 프로필 사진 URL',
3444
})
3545
profilePictureUrl: string;
46+
47+
constructor(user: User) {
48+
this.userId = user.id;
49+
this.nickname = user.nickname;
50+
this.profilePictureUrl = user.profilePictureUrl;
51+
}
3652
}
3753

3854
class PostClothingDto {
@@ -59,6 +75,14 @@ class PostClothingDto {
5975
description: '옷 상품 링크입니다.',
6076
})
6177
url: string;
78+
79+
constructor(postClothing: PostClothing) {
80+
this.imageUrl = postClothing.clothing.imageUrl;
81+
this.brandName = postClothing.clothing.brandName;
82+
this.modelName = postClothing.clothing.modelName;
83+
this.modelNumber = postClothing.clothing.modelNumber;
84+
this.url = postClothing.clothing.url;
85+
}
6286
}
6387

6488
export class PostResponse {
@@ -106,11 +130,69 @@ export class PostResponse {
106130
description: '대표 게시물 여부입니다.',
107131
})
108132
isRepresentative: boolean;
133+
134+
constructor(post: Post) {
135+
this.userId = post.user.id;
136+
this.postId = post.id;
137+
this.content = post.content;
138+
this.isRepresentative = post.isRepresentative;
139+
this.postImages =
140+
post.postImages?.map((image) => new PostImageDto(image)) || [];
141+
this.postStyletags =
142+
post.postStyletags?.map((postStyleTag) => postStyleTag.styletag.tag) ||
143+
[];
144+
this.postClothings =
145+
post.postClothings?.map((clothing) => new PostClothingDto(clothing)) ||
146+
[];
147+
}
109148
}
149+
export class PostDetailResponse {
150+
@ApiProperty({
151+
example: 1,
152+
description: '게시물 번호입니다.',
153+
})
154+
postId: number;
155+
156+
@ApiProperty({
157+
type: UserDto,
158+
description: '게시물 작성자 정보입니다.',
159+
})
160+
@Type(() => UserDto)
161+
user: UserDto;
162+
163+
@ApiProperty({
164+
example: '게시물 내용',
165+
description: '게시물 내용입니다. 최대 100자까지 입력할 수 있습니다.',
166+
})
167+
content: string;
110168

111-
class PostDetailDto extends OmitType(PostResponse, ['userId']) {}
169+
@ApiProperty({
170+
type: [PostImageDto],
171+
description: '게시물에 포함된 이미지 목록입니다.',
172+
})
173+
postImages?: PostImageDto[];
174+
175+
@ApiProperty({
176+
type: [String],
177+
example: ['classic', 'basic'],
178+
description:
179+
'게시글에 포함된 스타일 태그 목록입니다. 스타일 태그에 저장된 태그만 입력 가능합니다.',
180+
})
181+
postStyletags?: string[];
182+
183+
@ApiProperty({
184+
type: [PostClothingDto],
185+
description: '게시물에 포함된 옷 정보 리스트입니다.',
186+
})
187+
@Type(() => PostClothingDto)
188+
postClothings?: PostClothingDto[];
189+
190+
@ApiProperty({
191+
example: false,
192+
description: '대표 게시물 여부입니다.',
193+
})
194+
isRepresentative: boolean;
112195

113-
export class PostDetailResponse extends PostDetailDto {
114196
@ApiProperty({
115197
example: '2024-10-11T09:00:00.000Z',
116198
description: '생성 시각',
@@ -123,13 +205,6 @@ export class PostDetailResponse extends PostDetailDto {
123205
})
124206
updatedAt: string;
125207

126-
@ApiProperty({
127-
type: UserDto,
128-
description: '게시물 작성자 정보입니다.',
129-
})
130-
@Type(() => UserDto)
131-
user: UserDto;
132-
133208
@ApiProperty({
134209
example: 10,
135210
description: '게시글에 달린 댓글 수입니다.',
@@ -147,4 +222,24 @@ export class PostDetailResponse extends PostDetailDto {
147222
description: '현재 사용자가 게시물에 좋아요를 눌렀는지 여부',
148223
})
149224
isPostLike: boolean;
225+
constructor(post: Post, currentUserId: number) {
226+
this.postId = post.id;
227+
this.content = post.content;
228+
this.isRepresentative = post.isRepresentative;
229+
this.postImages =
230+
post.postImages?.map((image) => new PostImageDto(image)) || [];
231+
this.postStyletags =
232+
post.postStyletags?.map((postStyleTag) => postStyleTag.styletag.tag) ||
233+
[];
234+
this.postClothings =
235+
post.postClothings?.map((clothing) => new PostClothingDto(clothing)) ||
236+
[];
237+
(this.createdAt = dayjs(post.createdAt).format('YYYY-MM-DDTHH:mm:ssZ')),
238+
(this.updatedAt = dayjs(post.updatedAt).format('YYYY-MM-DDTHH:mm:ssZ')),
239+
(this.user = new UserDto(post.user));
240+
this.postCommentsCount = post.postComments?.length || 0;
241+
this.postLikesCount = post.postLikes?.length || 0;
242+
this.isPostLike =
243+
post.postLikes?.some((like) => like.user.id === currentUserId) || false;
244+
}
150245
}

src/post/post.controller.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,12 @@ export class PostController {
105105
@Req() req: Request,
106106
): Promise<BaseResponse<PostDetailResponse>> {
107107
const post = await this.postService.getPost(postId, req.user.id);
108+
if (!post) {
109+
throw DataNotFoundException('해당 게시글을 찾을 수 없습니다.');
110+
}
108111

109-
return new BaseResponse(true, '게시글 조회 성공', post);
112+
const postDetailResponse = new PostDetailResponse(post, req.user.id);
113+
return new BaseResponse(true, '게시글 조회 성공', postDetailResponse);
110114
}
111115

112116
@Post()

src/post/post.service.ts

+8-48
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@ import { PostClothingService } from 'src/post-clothing/post-clothing.service';
1616
import { PostLikeService } from 'src/post-like/post-like.service';
1717
import { PostCommentService } from 'src/post-comment/post-comment.service';
1818
import { PageOptionsDto } from '../common/response/page-options.dto';
19-
import dayjs from 'dayjs';
2019
import { GetAllPostsResponse } from './dtos/all-posts.response';
2120
import {
2221
GetMyPostsResponse,
2322
GetOtherPostsResponse,
2423
PostDto,
2524
} from './dtos/user-posts.response';
26-
import { PostDetailResponse } from './dtos/post.response';
2725

2826
@Injectable()
2927
export class PostService {
@@ -378,11 +376,10 @@ export class PostService {
378376
}
379377

380378
// 게시글 상세 조회
381-
async getPost(
382-
postId: number,
383-
currentUserId: number,
384-
): Promise<PostDetailResponse> {
385-
const post = await this.postRepository
379+
async getPost(postId: number, currentUserId: number): Promise<Post | null> {
380+
const blockedUserIds =
381+
await this.userBlockService.getBlockedUserIdsByRequesterId(currentUserId);
382+
return await this.postRepository
386383
.createQueryBuilder('post')
387384
.leftJoinAndSelect(
388385
'post.postImages',
@@ -394,18 +391,20 @@ export class PostService {
394391
.leftJoinAndSelect(
395392
'post.postLikes',
396393
'postLike',
397-
'postLike.status = :likeStatus',
394+
'postLike.status = :likeStatus AND postLike.user.id NOT IN (:...blockedUserIds)',
398395
{
399396
likeStatus: 'activated',
397+
blockedUserIds: blockedUserIds.length > 0 ? blockedUserIds : [-1], // 차단된 사용자가 없으면 무효화된 조건 (-1)
400398
},
401399
)
402400
.leftJoinAndSelect('postLike.user', 'postLikeUser')
403401
.leftJoinAndSelect(
404402
'post.postComments',
405403
'postComment',
406-
'postComment.status = :commentStatus',
404+
'postComment.status = :commentStatus AND postComment.user.id NOT IN (:...blockedUserIds)',
407405
{
408406
commentStatus: 'activated',
407+
blockedUserIds: blockedUserIds.length > 0 ? blockedUserIds : [-1],
409408
},
410409
)
411410
.leftJoinAndSelect('postComment.user', 'postCommentUser')
@@ -426,45 +425,6 @@ export class PostService {
426425
.where('post.id = :postId', { postId })
427426
.andWhere('post.status = :postStatus', { postStatus: 'activated' })
428427
.getOne();
429-
430-
if (!post) {
431-
throw DataNotFoundException('해당 게시글을 찾을 수 없습니다.');
432-
}
433-
434-
return this.returnPostDetail(post, currentUserId);
435-
}
436-
437-
private returnPostDetail(
438-
post: Post,
439-
currentUserId: number,
440-
): PostDetailResponse {
441-
return {
442-
postId: post.id,
443-
user: {
444-
userId: post.user.id,
445-
nickname: post.user.nickname,
446-
profilePictureUrl: post.user.profilePictureUrl,
447-
},
448-
content: post.content,
449-
isRepresentative: post.isRepresentative,
450-
postStyletags: post.postStyletags?.map((tag) => tag.styletag.tag),
451-
postImages: post.postImages.map((image) => ({
452-
imageUrl: image.url,
453-
orderNum: image.orderNum,
454-
})),
455-
postClothings: post.postClothings.map((postClothing) => ({
456-
imageUrl: postClothing.clothing.imageUrl,
457-
brandName: postClothing.clothing.brandName,
458-
modelName: postClothing.clothing.modelName,
459-
modelNumber: postClothing.clothing.modelNumber,
460-
url: postClothing.clothing.url,
461-
})),
462-
postLikesCount: post.postLikes.length,
463-
postCommentsCount: post.postComments.length,
464-
isPostLike: this.checkIsPostLiked(post, currentUserId),
465-
createdAt: dayjs(post.createdAt).format('YYYY-MM-DDTHH:mm:ssZ'),
466-
updatedAt: dayjs(post.updatedAt).format('YYYY-MM-DDTHH:mm:ssZ'),
467-
};
468428
}
469429

470430
// 대표 게시글 설정

0 commit comments

Comments
 (0)