feat: ability to add and view blogs for a user
This commit is contained in:
+60
-11
@@ -1,26 +1,75 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from app import models, schemas
|
||||
from app.utils import hash_password, verify_password
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
def get_item(db: Session, item_id: int):
|
||||
return db.query(models.Item).filter(models.Item.id == item_id).first()
|
||||
def get_blog(db: Session, blog_id: int) -> Optional[models.Blog]:
|
||||
return db.query(models.Blog).filter(models.Blog.id == blog_id).first()
|
||||
|
||||
|
||||
def get_items(db: Session, skip: int = 0, limit: int = 10):
|
||||
return db.query(models.Item).offset(skip).limit(limit).all()
|
||||
def get_blogs(
|
||||
db: Session,
|
||||
skip: int = 0,
|
||||
limit: int = 10,
|
||||
author_id: Optional[int] = None,
|
||||
visibility: Optional[str] = None,
|
||||
) -> List[models.Blog]:
|
||||
q = db.query(models.Blog)
|
||||
if author_id is not None:
|
||||
q = q.filter(models.Blog.author_id == author_id)
|
||||
if visibility is not None:
|
||||
q = q.filter(models.Blog.visibility == visibility)
|
||||
return q.offset(skip).limit(limit).all()
|
||||
|
||||
|
||||
def create_item(db: Session, item: schemas.Item):
|
||||
db_item = models.Item(**item.model_dump())
|
||||
db.add(db_item)
|
||||
def create_blog(db: Session, blog_in: schemas.BlogCreate) -> models.Blog:
|
||||
db_blog = models.Blog(**blog_in.model_dump())
|
||||
db.add(db_blog)
|
||||
db.commit()
|
||||
db.refresh(db_item)
|
||||
return db_item
|
||||
db.refresh(db_blog)
|
||||
return db_blog
|
||||
|
||||
|
||||
def delete_item(db: Session, item_id: int):
|
||||
item = db.query(models.Item).filter(models.Item.id == item_id).first()
|
||||
def update_blog(
|
||||
db: Session, blog_id: int, blog_in: schemas.BlogUpdate
|
||||
) -> Optional[models.Blog]:
|
||||
db_blog = get_blog(db, blog_id)
|
||||
if not db_blog:
|
||||
return None
|
||||
update_data = blog_in.model_dump(exclude_unset=True)
|
||||
for field, value in update_data.items():
|
||||
setattr(db_blog, field, value)
|
||||
db.commit()
|
||||
db.refresh(db_blog)
|
||||
return db_blog
|
||||
|
||||
|
||||
def delete_blog(db: Session, blog_id: int) -> Optional[models.Blog]:
|
||||
db_blog = get_blog(db, blog_id)
|
||||
if not db_blog:
|
||||
return None
|
||||
db.delete(db_blog)
|
||||
db.commit()
|
||||
return db_blog
|
||||
|
||||
|
||||
def increment_view_count(db: Session, blog_id: int) -> None:
|
||||
db.query(models.Blog).filter(models.Blog.id == blog_id).update(
|
||||
{"view_count": models.Blog.view_count + 1}
|
||||
)
|
||||
db.commit()
|
||||
|
||||
|
||||
def add_like(db: Session, blog_id: int) -> None:
|
||||
db.query(models.Blog).filter(models.Blog.id == blog_id).update(
|
||||
{"like_count": models.Blog.like_count + 1}
|
||||
)
|
||||
db.commit()
|
||||
|
||||
|
||||
def delete_blogs(db: Session, item_id: int):
|
||||
item = db.query(models.Blog).filter(models.Blog.id == item_id).first()
|
||||
if item:
|
||||
db.delete(item)
|
||||
db.commit()
|
||||
|
||||
+51
-21
@@ -2,6 +2,7 @@ from fastapi import FastAPI, Depends, HTTPException, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Optional
|
||||
|
||||
from app.utils import create_access_token
|
||||
from . import schemas, crud
|
||||
@@ -34,35 +35,64 @@ def health_check():
|
||||
return {"Health": "Super Healthy!"}
|
||||
|
||||
|
||||
@app.post("/items/", response_model=schemas.Item)
|
||||
def create_item(item: schemas.Item, db: Session = Depends(get_db)):
|
||||
return crud.create_item(db, item)
|
||||
@app.post("/blogs/", response_model=schemas.Blog)
|
||||
def create_blog(
|
||||
blog: schemas.BlogCreate,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
return crud.create_blog(db, blog)
|
||||
|
||||
|
||||
@app.get("/items/", response_model=list[schemas.Item])
|
||||
def read_items(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
|
||||
return crud.get_items(db, skip, limit)
|
||||
@app.get("/blogs/", response_model=list[schemas.Blog])
|
||||
def read_blogs(
|
||||
skip: int = 0,
|
||||
limit: int = 10,
|
||||
author_id: Optional[int] = None,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
return crud.get_blogs(
|
||||
db,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
author_id=author_id,
|
||||
)
|
||||
|
||||
|
||||
@app.get("/items/{item_id}", response_model=schemas.Item)
|
||||
def read_item(item_id: int, db: Session = Depends(get_db)):
|
||||
db_item = crud.get_item(db, item_id)
|
||||
if db_item is None:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
return db_item
|
||||
@app.get("/blogs/{blog_id}", response_model=schemas.Blog)
|
||||
def read_blog(
|
||||
blog_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
db_blog = crud.get_blog(db, blog_id)
|
||||
if not db_blog:
|
||||
raise HTTPException(status_code=404, detail="Blog not found")
|
||||
return db_blog
|
||||
|
||||
|
||||
@app.delete("/items/{item_id}", response_model=schemas.Item)
|
||||
def delete_item(item_id: int, db: Session = Depends(get_db)):
|
||||
item = crud.delete_item(db, item_id)
|
||||
if item is None:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
return item
|
||||
@app.put("/blogs/{blog_id}", response_model=schemas.Blog)
|
||||
def update_blog(
|
||||
blog_id: int,
|
||||
blog_in: schemas.BlogUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
updated = crud.update_blog(db, blog_id, blog_in)
|
||||
if not updated:
|
||||
raise HTTPException(status_code=404, detail="Blog not found")
|
||||
return updated
|
||||
|
||||
|
||||
@app.delete("/blogs/{blog_id}", response_model=schemas.Blog)
|
||||
def delete_blog(
|
||||
blog_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
deleted = crud.delete_blog(db, blog_id)
|
||||
if not deleted:
|
||||
raise HTTPException(status_code=404, detail="Blog not found")
|
||||
return deleted
|
||||
|
||||
|
||||
# Users
|
||||
|
||||
|
||||
@app.post("/login", response_model=schemas.Token)
|
||||
def user_login(
|
||||
form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)
|
||||
@@ -75,7 +105,7 @@ def user_login(
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
access_token = create_access_token(data={"sub": user.username})
|
||||
return {"access_token": access_token, "token_type": "bearer"}
|
||||
return {"access_token": access_token, "token_type": "bearer", "user_id": user.id}
|
||||
|
||||
|
||||
@app.post("/register", response_model=schemas.UserOut)
|
||||
|
||||
+30
-5
@@ -1,14 +1,39 @@
|
||||
from sqlalchemy import JSON, Boolean, Column, Integer, String
|
||||
from sqlalchemy import (
|
||||
JSON,
|
||||
Boolean,
|
||||
Column,
|
||||
DateTime,
|
||||
Integer,
|
||||
String,
|
||||
func,
|
||||
)
|
||||
from .database import Base
|
||||
|
||||
|
||||
class Item(Base):
|
||||
__tablename__ = "items"
|
||||
class Blog(Base):
|
||||
__tablename__ = "blogs"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, index=True)
|
||||
title = Column(String, index=True)
|
||||
author_id = Column(Integer, nullable=False, index=True)
|
||||
description = Column(String, nullable=True)
|
||||
body = Column(JSON, nullable=False)
|
||||
body = Column(String, nullable=False)
|
||||
created_at = Column(
|
||||
DateTime(timezone=True), server_default=func.now(), nullable=False
|
||||
)
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
published_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
# Document Meta Data
|
||||
word_count = Column(Integer, nullable=True)
|
||||
version = Column(Integer, nullable=True)
|
||||
read_time = Column(Integer, nullable=True)
|
||||
language = Column(String, nullable=True)
|
||||
tags = Column(JSON, nullable=True)
|
||||
|
||||
# User Meta Data
|
||||
view_count = Column(Integer, default=0, nullable=False)
|
||||
like_count = Column(Integer, default=0, nullable=False)
|
||||
|
||||
|
||||
class User(Base):
|
||||
|
||||
+48
-8
@@ -1,17 +1,56 @@
|
||||
from pydantic import BaseModel, EmailStr
|
||||
from typing import Optional
|
||||
from pydantic import AwareDatetime, BaseModel, EmailStr
|
||||
|
||||
|
||||
# DB Schemas
|
||||
|
||||
|
||||
class ItemBase(BaseModel):
|
||||
name: str
|
||||
description: str | None = None
|
||||
class BlogBase(BaseModel):
|
||||
title: str
|
||||
author_id: int
|
||||
description: Optional[str] = None
|
||||
body: str
|
||||
created_at: AwareDatetime
|
||||
updated_at: AwareDatetime
|
||||
published_at: AwareDatetime
|
||||
|
||||
# Document meta
|
||||
word_count: Optional[int] = None
|
||||
version: Optional[int] = None
|
||||
read_time: Optional[int] = None
|
||||
language: Optional[str] = None
|
||||
tags: Optional[list[str]] = None
|
||||
|
||||
|
||||
class Item(ItemBase):
|
||||
class BlogCreate(BlogBase):
|
||||
"""All fields required to create a new blog post."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class BlogUpdate(BaseModel):
|
||||
"""All fields are optional for partial updates."""
|
||||
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
body: Optional[str] = None
|
||||
created_at: Optional[str] = None
|
||||
updated_at: Optional[str] = None
|
||||
published_at: Optional[str] = None
|
||||
|
||||
word_count: Optional[int] = None
|
||||
version: Optional[int] = None
|
||||
read_time: Optional[int] = None
|
||||
language: Optional[str] = None
|
||||
tags: Optional[list[str]] = None
|
||||
|
||||
view_count: Optional[int] = None
|
||||
like_count: Optional[int] = None
|
||||
|
||||
|
||||
class Blog(BlogBase):
|
||||
"""What’s returned in responses."""
|
||||
|
||||
id: int
|
||||
view_count: int
|
||||
like_count: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -41,6 +80,7 @@ class UserOut(UserBase):
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
token_type: str
|
||||
user_id: int
|
||||
|
||||
|
||||
class TokenData(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user