Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 54aa798

Browse filesBrowse files
committed
updated
1 parent 17ce6e5 commit 54aa798
Copy full SHA for 54aa798

File tree

5 files changed

+168
-3
lines changed
Filter options

5 files changed

+168
-3
lines changed
+39Lines changed: 39 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: app/main.py
+2-1Lines changed: 2 additions & 1 deletion
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

Copy file name to clipboardExpand all lines: app/models.py
+19-2Lines changed: 19 additions & 2 deletions
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

Copy file name to clipboard
+68Lines changed: 68 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: app/schemas.py
+40Lines changed: 40 additions & 0 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.