Skip to content

Commit

Permalink
[Add] User 생성 API 추가
Browse files Browse the repository at this point in the history
 - 새로운 도메인 User와 관련된 기능 추가
  - schema, crud, router 코드 생성
  - main.py에 user router 연결
  - 사용자 정보 중복 상황을 다루기 위한 유효성 검사 반영
  - 비밀번호 암호화를 위한 passlib 사용
   - passlib와 bcrypt 간의 버전 문제가 있는 듯 하다.
    - pyca/bcrypt#684
  - 이메일 정보 포맷 확인을 위한 Pydantic 확장
   - pip install pydantic[email]
  • Loading branch information
Minwook11 committed Mar 29, 2024
1 parent 654d6d5 commit 095a115
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 2 deletions.
24 changes: 24 additions & 0 deletions domain/user/user_crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from sqlalchemy.orm import Session
from passlib.context import CryptContext

from domain.user.user_schema import UserCreate
from models import User


pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def create_user(db: Session, user_create: UserCreate):
db_user = User(
username=user_create.username,
password=pwd_context.hash(user_create.password1),
email=user_create.email
)

db.add(db_user)

db.commit()

def get_existing_user(db: Session, user_create: UserCreate):
return db.query(User).filter(
(User.username == user_create.username) | (User.email == user_create.email)
).first()
18 changes: 18 additions & 0 deletions domain/user/user_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from starlette import status

from database import get_db
from domain.user import user_crud, user_schema


router = APIRouter(
prefix="/api/user",
)

@router.post("/create", status_code=status.HTTP_204_NO_CONTENT)
def user_create(_user_create: user_schema.UserCreate, db: Session = Depends(get_db)):
user = user_crud.get_existing_user(db, user_create=_user_create)
if user:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="ALREADY_EXIST_USER")
user_crud.create_user(db=db, user_create=_user_create)
21 changes: 21 additions & 0 deletions domain/user/user_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from pydantic import BaseModel, field_validator, EmailStr
from pydantic_core.core_schema import FieldValidationInfo


class UserCreate(BaseModel):
username: str
password1: str
password2: str
email: EmailStr

@field_validator("username","password1", "password2", "email")
def not_empty(cls, v):
if not v or not v.strip():
raise ValueError("NOT_ALLOW_EMPTY_VALUE")
return v

@field_validator("password2")
def passwords_match(cls, v, info: FieldValidationInfo):
if "password1" in info.data and v != info.data["password1"]:
raise ValueError("PASSWORD_NOT_MATCH")
return v
4 changes: 3 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from domain.question import question_router
from domain.answer import answer_router
from domain.user import user_router


app = FastAPI()
Expand All @@ -12,4 +13,5 @@ def health_check():
return {"STATUS" : "WORKING_WELL..."}

app.include_router(question_router.router)
app.include_router(answer_router.router)
app.include_router(answer_router.router)
app.include_router(user_router.router)
11 changes: 10 additions & 1 deletion models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,13 @@ class Answer(Base):
content= Column(Text, nullable=False)
create_date = Column(DateTime, nullable=False)
question_id = Column(Integer, ForeignKey("question.id"))
question = relationship("Question", backref="answers")
question = relationship("Question", backref="answers")


class User(Base):
__tablename__= "user"

id = Column(Integer, primary_key=True)
username = Column(String, nullable=False, unique=True)
password = Column(String, nullable=False)
email = Column(String, nullable=False, unique=True)

0 comments on commit 095a115

Please sign in to comment.