Skip to content

Commit b1a6c2f

Browse files
committed
Feat: 게시글에 이미지 업로드, 삭제 기능 추가 #36
- create_post : 게시글 작성 및 s3 이미지 업로드 - update_post : 게시글 이미지 url 수정 및 업데이트 - delete_post : s3에서 이미지 삭제
1 parent d07c000 commit b1a6c2f

2 files changed

Lines changed: 70 additions & 14 deletions

File tree

app/handlers/post_handler.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from fastapi import APIRouter, Depends, HTTPException, Query
1+
from fastapi import APIRouter, Depends, File, Form, Query, UploadFile
22
from sqlmodel import Session, select
33
from typing import List, Optional
44

@@ -12,13 +12,22 @@
1212
router = APIRouter()
1313

1414
@router.post("/posts", response_model=PostRead)
15-
def create_post(
16-
post_data: PostCreate,
15+
async def create_post(
16+
title: str = Form(...),
17+
content: str = Form(...),
18+
region_id: int = Form(...),
19+
files: Optional[List[UploadFile]] = File(None),
1720
current_user: User = Depends(get_current_user),
1821
session: Session = Depends(get_db_session)
1922
):
23+
24+
post_data = PostCreate(
25+
title=title,
26+
content=content,
27+
region_id=region_id,
28+
)
2029
service = PostService(session)
21-
return service.create_post(post_data, current_user.id)
30+
return await service.create_post(post_data, current_user.id, files)
2231

2332
@router.get("/posts", response_model=List[PostRead])
2433
def read_posts(
@@ -47,14 +56,24 @@ def read_post(post_id: int, session: Session = Depends(get_db_session)):
4756
return service.increment_view_count(post_id)
4857

4958
@router.patch("/posts/{post_id}", response_model=PostRead)
50-
def update_post(
59+
async def update_post(
5160
post_id: int,
52-
post_data: PostUpdate,
61+
title: Optional[str] = Form(None),
62+
content: Optional[str] = Form(None),
63+
region_id: Optional[int] = Form(None),
64+
post_imageURLs: Optional[List[str]] = Form(None),
65+
files: Optional[List[UploadFile]] = File(None),
5366
current_user: User = Depends(get_current_user),
5467
session: Session = Depends(get_db_session)
5568
):
69+
post_data = PostUpdate(
70+
title=title or None,
71+
content=content or None,
72+
region_id=region_id,
73+
post_imageURLs = [url for url in post_imageURLs or [] if url] or None
74+
)
5675
service = PostService(session)
57-
return service.update_post(post_id, post_data, current_user.id)
76+
return await service.update_post(post_id, post_data, current_user.id, files)
5877

5978
@router.delete("/posts/{post_id}")
6079
def delete_post(

app/services/post_service.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
from datetime import datetime
2+
from typing import List, Optional
3+
from fastapi.concurrency import run_in_threadpool
24
from sqlmodel import Session, select
3-
from fastapi import HTTPException
5+
from fastapi import HTTPException, UploadFile
46

57
from app.models.post_model import Post
68
from app.schemas.post_schemas import PostCreate, PostUpdate
9+
from app.utils.s3_util import delete_file_from_s3, upload_file_to_s3
710

811
class PostService:
912
def __init__(self, session: Session):
1013
self.session = session
1114

12-
def create_post(self, post_data: PostCreate, user_id: int) -> Post:
15+
async def create_post(
16+
self,
17+
post_data: PostCreate,
18+
user_id: int,
19+
files: Optional[List[UploadFile]] = None
20+
) -> Post:
21+
image_urls = []
22+
if files:
23+
for file in files:
24+
file_bytes = await file.read()
25+
image_url = await run_in_threadpool(upload_file_to_s3, file_bytes, file.filename, "uploads/post")
26+
image_urls.append(image_url)
27+
post_data.post_imageURLs = image_urls
28+
1329
post = Post(
1430
**post_data.dict(),
1531
user_id=user_id
@@ -25,14 +41,32 @@ def get_post(self, post_id: int, raise_exception: bool = True) -> Post:
2541
raise HTTPException(status_code=404, detail="Post not found")
2642
return post
2743

28-
def update_post(self, post_id: int, post_data: PostUpdate, current_user_id: int) -> Post:
44+
async def update_post(
45+
self,
46+
post_id: int,
47+
post_data: PostUpdate,
48+
current_user_id: int,
49+
files: Optional[List[UploadFile]] = None
50+
) -> Post:
2951
post = self.get_post(post_id)
3052
if post.user_id != current_user_id:
3153
raise HTTPException(status_code=403, detail="작성자만 수정할 수 있습니다.")
32-
33-
for key, value in post_data.dict(exclude_unset=True).items():
54+
55+
existing_urls = set(post.post_imageURLs or [])
56+
requested_urls = set(post_data.post_imageURLs or [])
57+
if files:
58+
for file in files:
59+
file_bytes = await file.read()
60+
image_url = await run_in_threadpool(upload_file_to_s3, file_bytes, file.filename, "uploads/post")
61+
requested_urls.add(image_url)
62+
63+
urls_to_delete = existing_urls - requested_urls
64+
for url in urls_to_delete:
65+
delete_file_from_s3(url)
66+
post_data.post_imageURLs = list(requested_urls)
67+
68+
for key, value in post_data.dict(exclude_none=True).items():
3469
setattr(post, key, value)
35-
3670
self.session.add(post)
3771
self.session.commit()
3872
self.session.refresh(post)
@@ -42,7 +76,10 @@ def delete_post(self, post_id: int, current_user_id: int):
4276
post = self.get_post(post_id)
4377
if post.user_id != current_user_id:
4478
raise HTTPException(status_code=403, detail="작성자만 삭제할 수 있습니다.")
45-
79+
80+
if post.post_imageURLs:
81+
for url in post.post_imageURLs:
82+
delete_file_from_s3(url)
4683
self.session.delete(post)
4784
self.session.commit()
4885
return {"ok": True}

0 commit comments

Comments
 (0)