Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] create market category posts #2

Merged
merged 7 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/api/routes/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from fastapi import APIRouter

from app.api.routes import users
from app.api.routes import markets


router = APIRouter()
router.include_router(users.router, tags=["users"], prefix="/user")
router.include_router(markets.router, tags=["markets"], prefix="/market")
32 changes: 32 additions & 0 deletions app/api/routes/markets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import logging
from typing import Any, List
from fastapi import APIRouter, Depends, HTTPException, UploadFile
from sqlalchemy.orm import Session
from app.api.dependencies import database
from app.models.domain import markets
from app.crud import crud_markets, crud_posts

router = APIRouter()


@router.post("/create")
def create_market_posts(
*,
db: Session = Depends(database.get_db),
files: List[UploadFile],
market_in: markets.MarketCreate = Depends()
) -> Any:
"""
Create new user.
"""
# post data create
post_data = crud_posts.create(db=db, obj_in=market_in, files=files)
# room data create
market_data = crud_markets.create(db=db, obj_in=market_in, post_id=post_data.id)
if market_data and post_data:
return {"message": "create success"}
else:
raise HTTPException(
status_code=500,
detail="create failed",
)
7 changes: 6 additions & 1 deletion app/core/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import logging
import sys
from typing import List, Any

import boto3
from pydantic_settings import BaseSettings
from loguru import logger
from starlette.config import Config
Expand All @@ -11,7 +13,7 @@

class Settings(BaseSettings):
config: Config = Config(".env")
API_PREFIX: str = "/api"
API_PREFIX: str = "/api/v1"
JWT_TOKEN_PREFIX: str = "Token"
VERSION: str = "1.0.0"

Expand All @@ -29,6 +31,9 @@ class Settings(BaseSettings):
ALLOWED_HOSTS: List[str] = config(
"ALLOWED_HOSTS", cast=CommaSeparatedStrings, default=""
)
BUCKET_NAME: str = config("BUCKET_NAME", cast=str)
AWS_ACCESS_KEY: str = config("AWS_ACCESS_KEY", cast=str)
AWS_SECRET_KEY: str = config("AWS_SECRET_KEY", cast=str)


# logging configuration
Expand Down
Empty file added app/crud/__init__.py
Empty file.
26 changes: 26 additions & 0 deletions app/crud/crud_markets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from sqlalchemy.orm import Session
from app.models.domain import markets
from app.models.schemas.markets import Market


def create(db: Session, *, obj_in: markets.MarketCreate, post_id: int) -> Market:
db_obj = None
if obj_in.starting_price:
db_obj = Market(
starting_price=obj_in.starting_price,
price=obj_in.price,
auction=obj_in.auction,
deadline=obj_in.deadline,
post_id=post_id,
)
else:
db_obj = Market(
price=obj_in.price,
auction=obj_in.auction,
deadline=obj_in.deadline,
post_id=post_id,
)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
34 changes: 34 additions & 0 deletions app/crud/crud_posts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from sqlalchemy.orm import Session
from app.models.domain import posts
from app.models.schemas.posts import Post
from app.services.aws import s3_upload
from fastapi import HTTPException
from fastapi import UploadFile
from typing import List
import datetime


def create(db: Session, *, obj_in: posts.PostCreate, files: List[UploadFile]) -> Post:
db_obj = Post(
title=obj_in.title,
content=obj_in.content,
status=obj_in.status,
category=obj_in.category,
created_at=datetime.datetime.today(),
)
# image bool value insert
db_obj.image = True if files else False
db.add(db_obj)
db.commit()
db.refresh(db_obj)
# if image exits, do uploading in s3
if files:
s3_result = s3_upload(
files=files, post_id=db_obj.id, user_email="[email protected]"
)
if not s3_result:
raise HTTPException(
status_code=500,
detail="s3 upload failed",
)
return db_obj
2 changes: 2 additions & 0 deletions app/db/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
# imported by Alembic
from app.db.base_class import Base # noqa
from app.models.schemas.users import User # noqa
from app.models.schemas.posts import Post # noqa
from app.models.schemas.markets import Market # noqa
16 changes: 16 additions & 0 deletions app/models/domain/markets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from typing import Optional
from pydantic import BaseModel
import datetime
from app.resources.status import Status


class MarketCreate(BaseModel):
post_id: Optional[int] = None
starting_price: Optional[int] = None
price: int
auction: bool
deadline: datetime.datetime
title: str
content: str
status: Status
category: str
11 changes: 11 additions & 0 deletions app/models/domain/posts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pydantic import BaseModel
from typing import Optional
from app.resources.status import Status


class PostCreate(BaseModel):
title: str
content: str
status: Status
category: str
user_id: Optional[int] = None
17 changes: 17 additions & 0 deletions app/models/schemas/markets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from sqlalchemy import Boolean, Column, Integer, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from typing import TYPE_CHECKING
from app.db.base_class import Base

if TYPE_CHECKING:
from .posts import Post # noqa: F401


class Market(Base):
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
starting_price = Column(Integer)
price = Column(Integer, nullable=False)
auction = Column(Boolean(), default=False)
deadline = Column(DateTime, nullable=False)
post_id = Column(Integer, ForeignKey("post.id"))
post = relationship("Post", back_populates="market")
23 changes: 23 additions & 0 deletions app/models/schemas/posts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from sqlalchemy import Boolean, Column, Integer, String, DateTime, ForeignKey, Enum
from sqlalchemy.orm import relationship
from app.db.base_class import Base
from typing import TYPE_CHECKING
from app.resources.status import Status

if TYPE_CHECKING:
from .users import User # noqa: F401
from .markets import Market # noqa: F401


class Post(Base):
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
title = Column(String(255), index=True)
content = Column(String(255), index=True)
user_id = Column(Integer)
user_id = Column(Integer, ForeignKey("user.id"))
user = relationship("User", back_populates="posts")
status = Column(Enum(Status), nullable=False, default=Status.PROCESSING)
created_at = Column(DateTime, nullable=False)
category = Column(String(255), index=True)
image = Column(Boolean(), default=False)
market = relationship("Market", back_populates="post")
9 changes: 7 additions & 2 deletions app/models/schemas/users.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from sqlalchemy import Boolean, Column, Integer, String

from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import relationship
from app.db.base_class import Base
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from .posts import Post # noqa: F401


class User(Base):
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
username = Column(String(255), index=True)
email = Column(String(255), unique=True, index=True, nullable=False)
posts = relationship("Post", back_populates="user")
6 changes: 6 additions & 0 deletions app/resources/status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import enum


class Status(enum.Enum):
COMPLETED = "COMPLETED"
PROCESSING = "PROCESSING"
26 changes: 26 additions & 0 deletions app/services/aws.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import boto3
from botocore.exceptions import ClientError
from fastapi import UploadFile
from app.core.config import settings
from typing import List


def s3_upload(files: List[UploadFile], post_id: int, user_email: str) -> bool:
client = boto3.client(
"s3",
region_name="us-east-1",
aws_access_key_id=settings.AWS_ACCESS_KEY,
aws_secret_access_key=settings.AWS_SECRET_KEY,
)
try:
for file in files:
new_filename = f"/{user_email}/{post_id}/{file.filename}"
client.upload_fileobj(
file.file,
settings.BUCKET_NAME,
new_filename,
ExtraArgs={"ContentType": file.content_type},
)
except ClientError as e:
return False
return True
4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
services:
app:
build: .
build:
no_cache: true
context: .
ports:
- "8000:8000"
env_file:
Expand Down
8 changes: 8 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ anyio==3.7.1
astroid==3.0.1
bcrypt==4.0.1
black==23.9.1
boto3==1.28.64
botocore==1.31.64
cffi==1.16.0
click==8.1.7
cryptography==41.0.4
Expand All @@ -15,6 +17,7 @@ fastapi==0.103.2
h11==0.14.0
idna==3.4
isort==5.12.0
jmespath==1.0.1
jwt==1.3.1
lists==1.3.0
loguru==0.7.2
Expand All @@ -30,10 +33,15 @@ pydantic-settings==2.0.3
pydantic_core==2.10.1
pylint==3.0.1
PyMySQL==1.1.0
python-dateutil==2.8.2
python-dotenv==1.0.0
python-multipart==0.0.6
s3transfer==0.7.0
six==1.16.0
sniffio==1.3.0
SQLAlchemy==1.4.49
starlette==0.27.0
tomlkit==0.12.1
typing_extensions==4.8.0
urllib3==2.0.6
uvicorn==0.23.2