Skip to content

Commit 54aa798

Browse files
committed
updated
1 parent 17ce6e5 commit 54aa798

File tree

5 files changed

+168
-3
lines changed

5 files changed

+168
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""added post table
2+
3+
Revision ID: 4917da928a79
4+
Revises: 39256113e8e5
5+
Create Date: 2022-07-14 09:05:17.444518
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '4917da928a79'
14+
down_revision = '39256113e8e5'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade() -> None:
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table('posts',
22+
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
23+
sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=False),
24+
sa.Column('title', sa.String(), nullable=False),
25+
sa.Column('content', sa.String(), nullable=False),
26+
sa.Column('category', sa.String(), nullable=False),
27+
sa.Column('image', sa.String(), nullable=False),
28+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
29+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
30+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
31+
sa.PrimaryKeyConstraint('id')
32+
)
33+
# ### end Alembic commands ###
34+
35+
36+
def downgrade() -> None:
37+
# ### commands auto generated by Alembic - please adjust! ###
38+
op.drop_table('posts')
39+
# ### end Alembic commands ###

app/main.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from fastapi import FastAPI
22
from fastapi.middleware.cors import CORSMiddleware
33
from app.config import settings
4-
from app.routers import user, auth
4+
from app.routers import user, auth, post
55

66
app = FastAPI()
77

@@ -20,6 +20,7 @@
2020

2121
app.include_router(auth.router, tags=['Auth'], prefix='/api/auth')
2222
app.include_router(user.router, tags=['Users'], prefix='/api/users')
23+
app.include_router(post.router, tags=['Posts'], prefix='/api/posts')
2324

2425

2526
@app.get('/api/healthchecker')

app/models.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from enum import unique
21
import uuid
32
from .database import Base
4-
from sqlalchemy import TIMESTAMP, Column, String, Boolean, text
3+
from sqlalchemy import TIMESTAMP, Column, ForeignKey, String, Boolean, text
54
from sqlalchemy.dialects.postgresql import UUID
5+
from sqlalchemy.orm import relationship
66

77

88
class User(Base):
@@ -20,3 +20,20 @@ class User(Base):
2020
nullable=False, server_default=text("now()"))
2121
updated_at = Column(TIMESTAMP(timezone=True),
2222
nullable=False, server_default=text("now()"))
23+
24+
25+
class Post(Base):
26+
__tablename__ = 'posts'
27+
id = Column(UUID(as_uuid=True), primary_key=True, nullable=False,
28+
default=uuid.uuid4)
29+
user_id = Column(UUID(as_uuid=True), ForeignKey(
30+
'users.id', ondelete='CASCADE'), nullable=False)
31+
title = Column(String, nullable=False)
32+
content = Column(String, nullable=False)
33+
category = Column(String, nullable=False)
34+
image = Column(String, nullable=False)
35+
created_at = Column(TIMESTAMP(timezone=True),
36+
nullable=False, server_default=text("now()"))
37+
updated_at = Column(TIMESTAMP(timezone=True),
38+
nullable=False, server_default=text("now()"))
39+
user = relationship('User')

app/routers/post.py

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import uuid
2+
from .. import schemas, models
3+
from sqlalchemy.orm import Session
4+
from fastapi import Depends, HTTPException, status, APIRouter, Response
5+
from ..database import get_db
6+
from app.oauth2 import require_user
7+
8+
router = APIRouter()
9+
10+
11+
@router.get('/', response_model=schemas.ListPostResponse)
12+
def get_posts(db: Session = Depends(get_db), limit: int = 10, page: int = 1, search: str = '', user_id: str = Depends(require_user)):
13+
skip = (page - 1) * limit
14+
15+
posts = db.query(models.Post).group_by(models.Post.id).filter(
16+
models.Post.title.contains(search)).limit(limit).offset(skip).all()
17+
return {'status': 'success', 'results': len(posts), 'posts': posts}
18+
19+
20+
@router.post('/', status_code=status.HTTP_201_CREATED, response_model=schemas.PostResponse)
21+
def create_post(post: schemas.CreatePostSchema, db: Session = Depends(get_db), owner_id: str = Depends(require_user)):
22+
post.user_id = uuid.UUID(owner_id)
23+
new_post = models.Post(**post.dict())
24+
db.add(new_post)
25+
db.commit()
26+
db.refresh(new_post)
27+
return new_post
28+
29+
30+
@router.put('/{id}', response_model=schemas.PostResponse)
31+
def update_post(id: str, post: schemas.UpdatePostSchema, db: Session = Depends(get_db), user_id: str = Depends(require_user)):
32+
post_query = db.query(models.Post).filter(models.Post.id == id)
33+
updated_post = post_query.first()
34+
35+
if not updated_post:
36+
raise HTTPException(status_code=status.HTTP_200_OK,
37+
detail=f'No post with this id: {id} found')
38+
if updated_post.user_id != uuid.UUID(user_id):
39+
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
40+
detail='You are not allowed to perform this action')
41+
post_query.update(post.dict(), synchronize_session=False)
42+
db.commit()
43+
return updated_post
44+
45+
46+
@router.get('/{id}', response_model=schemas.PostResponse)
47+
def get_post(id: str, db: Session = Depends(get_db), user_id: str = Depends(require_user)):
48+
post = db.query(models.Post).filter(models.Post.id == id).first()
49+
if not post:
50+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
51+
detail=f"No post with this id: {id} found")
52+
return post
53+
54+
55+
@router.delete('/{id}')
56+
def delete_post(id: str, db: Session = Depends(get_db), user_id: str = Depends(require_user)):
57+
post_query = db.query(models.Post).filter(models.Post.id == id)
58+
post = post_query.first()
59+
if not post:
60+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
61+
detail=f'No post with this id: {id} found')
62+
63+
if post.owner_id != user_id:
64+
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
65+
detail='You are not allowed to perform this action')
66+
post_query.delete(synchronize_session=False)
67+
db.commit()
68+
return Response(status_code=status.HTTP_204_NO_CONTENT)

app/schemas.py

+40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from datetime import datetime
2+
from typing import List
23
import uuid
34
from pydantic import BaseModel, EmailStr, constr
45

@@ -31,4 +32,43 @@ class UserResponse(UserBaseSchema):
3132

3233

3334
class FilteredUserResponse(UserBaseSchema):
35+
id: uuid.UUID
36+
37+
38+
class PostBaseSchema(BaseModel):
39+
title: str
40+
content: str
41+
category: str
42+
image: str
43+
user_id: uuid.UUID | None = None
44+
45+
class Config:
46+
orm_mode = True
47+
48+
49+
class CreatePostSchema(PostBaseSchema):
3450
pass
51+
52+
53+
class PostResponse(PostBaseSchema):
54+
id: uuid.UUID
55+
user: FilteredUserResponse
56+
created_at: datetime
57+
updated_at: datetime
58+
59+
60+
class UpdatePostSchema(BaseModel):
61+
title: str | None = None
62+
content: str | None = None
63+
category: str | None = None
64+
image: str | None = None
65+
user_id: uuid.UUID | None = None
66+
67+
class Config:
68+
orm_mode = True
69+
70+
71+
class ListPostResponse(BaseModel):
72+
status: str
73+
results: int
74+
posts: List[PostResponse]

0 commit comments

Comments
 (0)