Skip to content

Commit eab1064

Browse files
authored
Merge pull request #9 from wang-bam-bbang/post
Post
2 parents 5e921f6 + cabb1a4 commit eab1064

File tree

9 files changed

+113
-68
lines changed

9 files changed

+113
-68
lines changed

database_setup/database.dbml

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,69 @@ Project find_it {
66
Enum item_category {
77
ELECTRONICS [note: '전자기기']
88
WALLET [note: '지갑']
9-
BAG [note: '가방']
10-
CLOTHING [note: '의류']
11-
ACCESSORIES [note: '액세서리']
12-
DOCUMENT [note: '서류']
13-
CARD [note: '카드']
14-
OTHER [note: '기타']
9+
BAG [note: '가방']
10+
CLOTHING [note: '의류']
11+
ACCESSORIES [note: '액세서리']
12+
DOCUMENT [note: '서류']
13+
CARD [note: '카드']
14+
ETC [note: '기타']
1515
}
1616

1717
Enum post_status {
18-
PENDING [note: '미해결']
18+
IN_PROGRESS [note: '진행 중']
1919
RESOLVED [note: '해결됨']
20+
CANCELLED [note: '취소됨']
21+
}
22+
23+
Enum post_type {
24+
FOUND [note: '발견']
25+
LOST [note: '분실']
26+
}
27+
28+
Enum comment_type {
29+
COMMENT [note: '일반 댓글']
30+
REPLY [note: '대댓글']
2031
}
2132

2233
Table users {
2334
uuid uuid [pk, not null]
2435
name varchar [not null]
25-
email varchar [not null, unique]
2636
created_at timestamp [not null, default: `now()`]
2737
updated_at timestamp [not null]
2838

2939
Note: '사용자 정보'
3040
}
3141

32-
Table found_posts {
33-
id uuid [pk, not null, default: `gen_random_uuid()`]
34-
title varchar [not null]
35-
description text [not null]
42+
Table posts {
43+
id serial [pk, not null]
44+
type post_type [not null, note: '게시글 타입 (발견/분실)']
45+
title varchar(255) [not null, note: '게시글 제목']
46+
description text [not null, note: '게시글 설명']
3647
images varchar[] [note: '이미지 URL 배열']
37-
location varchar [not null, note: '발견 장소']
38-
category item_category [not null]
39-
status post_status [not null, default: 'PENDING']
40-
author_id uuid [ref: > users.uuid, not null]
48+
location varchar [not null, note: '발견/분실 장소']
49+
category item_category [not null, default: 'ETC', note: '아이템 카테고리']
50+
status post_status [not null, note: '게시글 상태']
4151
created_at timestamp [not null, default: `now()`]
4252
updated_at timestamp [not null]
53+
deleted_at timestamp [note: '게시글 삭제 일자']
54+
author_id uuid [ref: > users.uuid, not null, note: '작성자 UUID']
4355

4456
indexes {
4557
author_id
4658
}
4759

48-
Note: '발견 게시글'
60+
Note: '게시글 정보'
4961
}
5062

51-
Table lost_posts {
52-
id uuid [pk, not null, default: `gen_random_uuid()`]
53-
title varchar [not null]
54-
description text [not null]
55-
images varchar[] [note: '이미지 URL 배열']
56-
location varchar [not null, note: '분실 추정 장소']
57-
category item_category [not null]
58-
status post_status [not null, default: 'PENDING']
59-
author_id uuid [ref: > users.uuid, not null]
63+
Table comments {
64+
id serial [pk, not null]
65+
content text [not null, note: '댓글 내용']
66+
type comment_type [not null, note: '댓글 타입 (댓글/대댓글)']
6067
created_at timestamp [not null, default: `now()`]
61-
updated_at timestamp [not null]
68+
is_deleted boolean [not null, default: false, note: '댓글 삭제 여부']
69+
post_id int [ref: > posts.id, not null, note: '게시글 ID']
70+
author_id uuid [ref: > users.uuid, not null, note: '작성자 UUID']
71+
parent_id int [ref: > comments.id, note: '상위 댓글 ID']
6272

63-
indexes {
64-
author_id
65-
}
66-
67-
Note: '분실 게시글'
68-
}
73+
Note: '댓글 정보'
74+
}

src/idp/idp.service.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
BadRequestException,
23
Injectable,
34
InternalServerErrorException,
45
UnauthorizedException,
@@ -52,7 +53,10 @@ export class IdpService {
5253
if (error instanceof AxiosError && error.response?.status === 401) {
5354
throw new UnauthorizedException();
5455
}
55-
throw new InternalServerErrorException();
56+
if (error instanceof AxiosError && error.response?.status === 400) {
57+
throw new BadRequestException(error.response.data);
58+
}
59+
throw new InternalServerErrorException(error.response.data);
5660
}),
5761
),
5862
);

src/image/image.service.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
BadRequestException,
1111
Injectable,
1212
InternalServerErrorException,
13+
NotFoundException,
1314
} from '@nestjs/common';
1415
import { ConfigService } from '@nestjs/config';
1516

@@ -139,7 +140,11 @@ export class ImageService {
139140
},
140141
});
141142
await this.s3Client.send(command).catch((error) => {
142-
throw new InternalServerErrorException(error);
143+
if (error.Code === 'AccessDenied') {
144+
throw new NotFoundException('Image key is invalid');
145+
}
146+
147+
throw new InternalServerErrorException();
143148
});
144149
}
145150

src/post/dto/req/createPost.dto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class CreatePostDto {
3434
@ApiProperty({
3535
type: [String],
3636
description: 'Array of image keys/filenames for the post',
37-
example: '[thisisanimagekey.jpg]',
37+
example: ['thisisanimagekey.jpg'],
3838
})
3939
@IsString({ each: true })
4040
@IsOptional()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { PostType } from '@prisma/client';
3+
import { IsEnum, IsOptional } from 'class-validator';
4+
5+
export class MyPostFilterDto {
6+
@ApiProperty({
7+
enum: PostType,
8+
enumName: 'PostType',
9+
description: 'Type of post (FOUND or LOST)',
10+
example: PostType.FOUND,
11+
required: false,
12+
})
13+
@IsEnum(PostType)
14+
@IsOptional()
15+
type?: PostType;
16+
}

src/post/dto/req/postFilter.dto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class PostFilterDto {
3737
@ApiProperty({
3838
type: Number,
3939
description: 'Pagination cursor for next set of results',
40-
example: 17,
40+
example: 0,
4141
})
4242
@Transform(({ value }) => parseInt(value, 10), { toClassOnly: true })
4343
@IsInt()

src/post/post.controller.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
ApiTags,
2828
ApiUnauthorizedResponse,
2929
} from '@nestjs/swagger';
30+
import { MyPostFilterDto } from './dto/req/myPostFilter.dto';
3031

3132
@ApiTags('Post')
3233
@Controller('post')
@@ -66,8 +67,11 @@ export class PostController {
6667
@ApiBearerAuth('access-token')
6768
@Get('my-posts')
6869
@UseGuards(IdPGuard)
69-
async getMyPosts(@GetUser() user: User): Promise<PostListDto> {
70-
return this.postService.getMyPostList(user.uuid);
70+
async getMyPosts(
71+
@GetUser() user: User,
72+
@Query() myPostFilterDto: MyPostFilterDto,
73+
): Promise<PostListDto> {
74+
return this.postService.getMyPostList(user.uuid, myPostFilterDto);
7175
}
7276

7377
@ApiOperation({

src/post/post.repository.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { PostResponseDto } from './dto/res/postRes.dto';
55
import { Injectable } from '@nestjs/common';
66
import { UpdatePostDto } from './dto/req/updatePost.dto';
77
import { PostFilterDto } from './dto/req/postFilter.dto';
8+
import { PostType } from '@prisma/client';
89

910
@Injectable()
1011
export class PostRepository {
@@ -96,9 +97,12 @@ export class PostRepository {
9697
};
9798
}
9899

99-
async findPostsByUser(userUuid: string): Promise<PostResponseDto[]> {
100+
async findPostsByUser(
101+
userUuid: string,
102+
type?: PostType,
103+
): Promise<PostResponseDto[]> {
100104
const posts = await this.prismaService.post.findMany({
101-
where: { authorId: userUuid },
105+
where: { authorId: userUuid, type },
102106
include: {
103107
author: {
104108
select: {

src/post/post.service.ts

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { PostListDto, PostResponseDto } from './dto/res/postRes.dto';
1111
import { UpdatePostDto } from './dto/req/updatePost.dto';
1212
import { PostFilterDto } from './dto/req/postFilter.dto';
1313
import { ImageService } from 'src/image/image.service';
14+
import { MyPostFilterDto } from './dto/req/myPostFilter.dto';
1415

1516
@Injectable()
1617
export class PostService {
@@ -52,8 +53,13 @@ export class PostService {
5253
};
5354
}
5455

55-
async getMyPostList(userUuid: string): Promise<PostListDto> {
56-
const postList = await this.postRepository.findPostsByUser(userUuid);
56+
async getMyPostList(
57+
userUuid: string,
58+
myPostFilterDto: MyPostFilterDto,
59+
): Promise<PostListDto> {
60+
const { type } = myPostFilterDto;
61+
62+
const postList = await this.postRepository.findPostsByUser(userUuid, type);
5763

5864
const formattedPosts = await Promise.all(
5965
postList.map(async (post) => {
@@ -87,6 +93,31 @@ export class PostService {
8793
};
8894
}
8995

96+
async createPost(
97+
createPostDto: CreatePostDto,
98+
userUuid: string,
99+
): Promise<PostResponseDto> {
100+
if (createPostDto.images.length) {
101+
await this.imageService.validateImages(createPostDto.images);
102+
}
103+
104+
const newPost = await this.postRepository.createPost(
105+
createPostDto,
106+
userUuid,
107+
);
108+
109+
const signedUrls = await this.imageService.generateSignedUrls(
110+
newPost.images,
111+
);
112+
113+
// TODO: FCM process need to be added.
114+
115+
return {
116+
...newPost,
117+
images: signedUrls,
118+
};
119+
}
120+
90121
async updatePost(
91122
id: number,
92123
updatePostDto: UpdatePostDto,
@@ -123,29 +154,4 @@ export class PostService {
123154

124155
return this.postRepository.deletePost(id);
125156
}
126-
127-
async createPost(
128-
createPostDto: CreatePostDto,
129-
userUuid: string,
130-
): Promise<PostResponseDto> {
131-
if (createPostDto.images.length) {
132-
await this.imageService.validateImages(createPostDto.images);
133-
}
134-
135-
const newPost = await this.postRepository.createPost(
136-
createPostDto,
137-
userUuid,
138-
);
139-
140-
const signedUrls = await this.imageService.generateSignedUrls(
141-
newPost.images,
142-
);
143-
144-
// TODO: FCM process need to be added.
145-
146-
return {
147-
...newPost,
148-
images: signedUrls,
149-
};
150-
}
151157
}

0 commit comments

Comments
 (0)