From f1aabace38ec434d5768bfa7f2baaa92365e1dd4 Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:33:25 +0900 Subject: [PATCH 01/10] =?UTF-8?q?chore:=20.env=20=ED=85=9C=ED=94=8C?= =?UTF-8?q?=EB=A6=BF=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.templete | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .env.templete diff --git a/.env.templete b/.env.templete new file mode 100644 index 0000000..9e54184 --- /dev/null +++ b/.env.templete @@ -0,0 +1,4 @@ +MYSQL_USER= +MYSQL_PASSWORD= +MYSQL_DATABASE= +MYSQL_ROOT_PASSWORD= \ No newline at end of file From c811943485fae0de8a07723728870a84991a89c9 Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:35:10 +0900 Subject: [PATCH 02/10] =?UTF-8?q?chore:=20.gitignore=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ecb57ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +./.env +*__pycache__* +.DS_Store +.env From 75f2d01c4df066f11c6184ceba5c87411cf4b069 Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:37:23 +0900 Subject: [PATCH 03/10] =?UTF-8?q?chore:=20docker-copose=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B0=B1=EC=97=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Docker-compose.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Docker-compose.yml b/Docker-compose.yml index 45571c8..fdd1b14 100644 --- a/Docker-compose.yml +++ b/Docker-compose.yml @@ -9,3 +9,38 @@ services: ports: - "3000:3000" tty: true + + mysql: + container_name: taegong_mysql + image: mysql:8.0-oracle + volumes: + - mysql_data_dev:/mysql + env_file: + - ./.env + networks: + - mynet + ports: + - 3306:3306 + + backend: + container_name: taegong_backend + build: ./backend + environment: + MYSQL_HOST: "1234" + entrypoint: /bin/bash + command: -c "sleep 10 && uvicorn main:app --host 0.0.0.0 --reload" + ports: + - 8000:8000 + networks: + - mynet + # 작업이 끝나도 종료되지 않게 하는 명령 + tty: true + depends_on: + - mysql + +volumes: + mysql_data_dev: null + +networks: + mynet: + driver: bridge \ No newline at end of file From 056e72ff51722e80f15b7ac628dd62af6fa34fa3 Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:39:05 +0900 Subject: [PATCH 04/10] =?UTF-8?q?chore:=20Dockerfile=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/Dockerfile | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 backend/Dockerfile diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..8759e6d --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.10-slim + +ENV PYTHONUNBUFFERED 1 +ENV PYTHONDONTWRITEBYTECODE 1 + +WORKDIR /taegong +COPY requirements.txt /taegong +RUN apt-get update \ + # dependencies for building Python packages + && apt-get install -y build-essential \ + # psycopg2 dependencies + && apt-get install -y libpq-dev +RUN pip install --upgrade pip +RUN pip install cryptography +RUN pip install -r requirements.txt + +COPY . /taegong/ +EXPOSE 8000 From c249acf450d3c95af5c6596414c6c48f5883456b Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:39:44 +0900 Subject: [PATCH 05/10] =?UTF-8?q?chore:=20requirements.txt=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/requirements.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 backend/requirements.txt diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000..1c610b1 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,12 @@ +anyio==3.6.2 +click==8.1.3 +fastapi==0.88.0 +h11==0.14.0 +idna==3.4 +pydantic==1.10.4 +PyMySQL==1.0.2 +sniffio==1.3.0 +SQLAlchemy==1.4.46 +starlette==0.22.0 +typing_extensions==4.4.0 +uvicorn==0.20.0 From 5f0433ae0eab8997afddc33d8dff44c435cef7d5 Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:42:58 +0900 Subject: [PATCH 06/10] =?UTF-8?q?chore:=20sqlalchemy=EB=A5=BC=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20db=20connection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/database.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 backend/database.py diff --git a/backend/database.py b/backend/database.py new file mode 100644 index 0000000..eb101cc --- /dev/null +++ b/backend/database.py @@ -0,0 +1,21 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +import os +# SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db" #host.doc +# +# ker.internal 외부에서 도커에 접속하기 위한 주소 +if os.getenv('MYSQL_HOST'): + SQLALCHEMY_DATABASE_URL = "mysql+pymysql://taegong:taegong@host.docker.internal:3306/taegong" +else: + SQLALCHEMY_DATABASE_URL = "mysql+pymysql://taegong:taegong@localhost:3306/taegong" + +engine = create_engine( + SQLALCHEMY_DATABASE_URL, + # connect_args={"check_same_thread": False} +) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + + +Base = declarative_base() From 8ef1d3ee0344c717310f56b780afda619a4293ee Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:43:55 +0900 Subject: [PATCH 07/10] =?UTF-8?q?chore:=20db=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=97=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/api/dep.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 backend/api/dep.py diff --git a/backend/api/dep.py b/backend/api/dep.py new file mode 100644 index 0000000..ff0dae7 --- /dev/null +++ b/backend/api/dep.py @@ -0,0 +1,9 @@ +from database import SessionLocal + +# Dependency +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() From 5c1f8eb6c9b9a1b9c3df444880968478f505bcde Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:44:27 +0900 Subject: [PATCH 08/10] =?UTF-8?q?chore:=20main.py=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/main.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 backend/main.py diff --git a/backend/main.py b/backend/main.py new file mode 100644 index 0000000..8b70db1 --- /dev/null +++ b/backend/main.py @@ -0,0 +1,27 @@ +import uuid +from fastapi import FastAPI +from fastapi import UploadFile, File +from fastapi.middleware.cors import CORSMiddleware + +from database import Base +from database import engine + +from api.api import api_router + +Base.metadata.create_all(bind=engine) + +# cors +origins = [ + "http://localhost", + "http://localhost:3000", + "http://localhost:8080", +] +app = FastAPI(title="TaeGong’s life",docs_url="/swagger") +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) +app.include_router(api_router, prefix="/api") From 8d14eb5adac78074d1484a58c7fb09dce7d83697 Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:45:23 +0900 Subject: [PATCH 09/10] =?UTF-8?q?chore:=20=EB=8B=A4=EB=A5=B8=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=EC=97=90=EC=84=9C=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=9D=84=20=ED=8E=B8=ED=95=98=EA=B2=8C=20=ED=95=98=EA=B8=B0=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20=5F=5Finit=5F=5F.py=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/api/__init__.py | 0 backend/crud/__init__.py | 0 backend/models/__init__.py | 1 + 3 files changed, 1 insertion(+) create mode 100644 backend/api/__init__.py create mode 100644 backend/crud/__init__.py create mode 100644 backend/models/__init__.py diff --git a/backend/api/__init__.py b/backend/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/crud/__init__.py b/backend/crud/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/models/__init__.py b/backend/models/__init__.py new file mode 100644 index 0000000..b7bb9be --- /dev/null +++ b/backend/models/__init__.py @@ -0,0 +1 @@ +from .user import User \ No newline at end of file From 21de7e7bf13f7c3d8a479bbd9b329a56cceaf922 Mon Sep 17 00:00:00 2001 From: jung Date: Wed, 11 Jan 2023 02:48:31 +0900 Subject: [PATCH 10/10] =?UTF-8?q?feat:=20user=20=EC=98=88=EC=8B=9C=20api?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/api/api.py | 5 +++ backend/api/endpoints/users.py | 31 +++++++++++++++++++ backend/crud/user_crud.py | 56 ++++++++++++++++++++++++++++++++++ backend/models/user.py | 23 ++++++++++++++ backend/schemas/user_schema.py | 35 +++++++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 backend/api/api.py create mode 100644 backend/api/endpoints/users.py create mode 100644 backend/crud/user_crud.py create mode 100644 backend/models/user.py create mode 100644 backend/schemas/user_schema.py diff --git a/backend/api/api.py b/backend/api/api.py new file mode 100644 index 0000000..a5f4437 --- /dev/null +++ b/backend/api/api.py @@ -0,0 +1,5 @@ +from fastapi import APIRouter +from api.endpoints import users + +api_router = APIRouter() +api_router.include_router(users.router, prefix="/users", tags=["users"]) \ No newline at end of file diff --git a/backend/api/endpoints/users.py b/backend/api/endpoints/users.py new file mode 100644 index 0000000..eb48c5a --- /dev/null +++ b/backend/api/endpoints/users.py @@ -0,0 +1,31 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.orm import Session + +from starlette.status import HTTP_201_CREATED, HTTP_204_NO_CONTENT +from crud import user_crud +from schemas import user_schema +from api.dep import get_db + +router = APIRouter() + + +# TODO: 에러 처리 + +# 유저 생성 +@router.post("", status_code=HTTP_201_CREATED, response_model=user_schema.User) +def create_user_info(user: user_schema.UserCreate, db: Session = Depends(get_db)): + user_ = user_crud.create_user(db, user=user) + return user_ + + +# 유저 상세 조회 +@router.get("/{token}") +def get_user_by_id(token: str, db: Session = Depends(get_db)): + users = user_crud.get_user_by_token(db, token=token) + return users + + +# 유저 삭제 +@router.delete("/{user_id}", status_code=HTTP_204_NO_CONTENT) +def delete_user_by_id(user_id: int, db: Session = Depends(get_db)): + user_crud.delete_user_by_id(db, user_id=user_id) \ No newline at end of file diff --git a/backend/crud/user_crud.py b/backend/crud/user_crud.py new file mode 100644 index 0000000..51e0532 --- /dev/null +++ b/backend/crud/user_crud.py @@ -0,0 +1,56 @@ +from models import User +from schemas import user_schema +from fastapi import Response, HTTPException +from sqlalchemy.orm import Session +from starlette.responses import Response +from starlette.status import HTTP_204_NO_CONTENT, HTTP_404_NOT_FOUND + + +# user +# id로 user 검색 +def get_user_by_token(db: Session, token: str): + user = ( + db.query(User) + .filter(User.is_active == True) + .filter(User.token == token) + .first() + ) + if not user: + return Response(status_code=HTTP_404_NOT_FOUND) + return user + + +# user 생성 +def create_user(db: Session, user: user_schema.UserCreate): + existing_user = ( + db.query(User) + .filter(User.phone_num == user.phone_num) + .filter(User.user_type == user.user_type) + .first() + ) + if existing_user: + db_user = ( + db.query(User) + .filter(User.id == existing_user.id) + .update({"token": user.token}) + ) + db.commit() + return db.query(User).filter(User.id == existing_user.id).first() + db_user = User( + name=user.name, + user_type=user.user_type, + gender=user.gender, + age_range=user.age_range, + phone_num=user.phone_num, + token=user.token, + ) + db.add(db_user) + db.commit() + return db_user + + +# user 삭제 +def delete_user_by_id(db: Session, user_id: int): + user = db.query(User).filter(User.id == user_id).update({"is_active": False}) + db.commit() + return Response(status_code=HTTP_204_NO_CONTENT) \ No newline at end of file diff --git a/backend/models/user.py b/backend/models/user.py new file mode 100644 index 0000000..575287a --- /dev/null +++ b/backend/models/user.py @@ -0,0 +1,23 @@ +from sqlalchemy import Boolean, Column, Integer, String +from sqlalchemy.types import TIMESTAMP +from sqlalchemy.sql import text, func + +from database import Base +from sqlalchemy import func + + +class User(Base): + __tablename__ = "users" + + id = Column(Integer, primary_key=True, index=True) + user_type = Column(Boolean, nullable=False, default=True) + name = Column(String(100), index=True) + gender = Column(String(6), index=True) + age_range = Column(String(20), index=True) + phone_num = Column(String(16), index=True) + token = Column(String(255), nullable=False, index=True) + is_active = Column(Boolean, nullable=False, default=True) + created_at = Column(TIMESTAMP, server_default=func.now()) + updated_at = Column( + TIMESTAMP, server_default=text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + ) \ No newline at end of file diff --git a/backend/schemas/user_schema.py b/backend/schemas/user_schema.py new file mode 100644 index 0000000..40e9d97 --- /dev/null +++ b/backend/schemas/user_schema.py @@ -0,0 +1,35 @@ +from pydantic import BaseModel + + +class UserBase(BaseModel): + class Config: + orm_mode = True + + +class User(UserBase): + id: int + user_type: int + name: str + gender: str + age_range: str + phone_num: str + token: str + is_active: bool + + + +class UserCreate(UserBase): + name: str + gender: str + age_range: str + phone_num: str + user_type: bool + token: str + + +class UserRead(UserCreate): + id: int + + +class UserDelete(UserBase): + is_active: bool \ No newline at end of file