Skip to content

Commit

Permalink
Feature/332 like dislike backend (#355)
Browse files Browse the repository at this point in the history
* Add my story to stories

* add table for like and dislike

* add table for like and dislike

* fixed a bug

* change like & dislike for my story

* change like & dislike for my story
  • Loading branch information
vinovo authored Oct 14, 2020
1 parent 72819c2 commit b06e782
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 2 deletions.
2 changes: 1 addition & 1 deletion backend/alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from database import Base
from stories import models as story_models
from users import models as user_models

from NytLiveCounty import models as nyt_models
from likes import models as like_models

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""add table for like and dislike
Revision ID: edace0efb31c
Revises: 527194b9fb18
Create Date: 2020-10-14 02:51:38.265440
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "edace0efb31c"
down_revision = "527194b9fb18"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"likes",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column("updated_at", sa.DateTime(), nullable=True),
sa.Column("like", sa.Boolean(), nullable=True),
sa.Column("my_story_id", sa.Integer(), nullable=True),
sa.Column("liker_story_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(["liker_story_id"], ["stories.id"],),
sa.ForeignKeyConstraint(["my_story_id"], ["my_stories.id"],),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_likes_id"), "likes", ["id"], unique=False)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f("ix_likes_id"), table_name="likes")
op.drop_table("likes")
# ### end Alembic commands ###
Empty file added backend/likes/__init__.py
Empty file.
61 changes: 61 additions & 0 deletions backend/likes/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from sqlalchemy.orm import Session
from . import models, schemas
from sqlalchemy.sql.expression import and_
from stories.crud import update


def get_like_by_story_and_user(
db: Session, my_story_id: int, liker_story_id: int
):
return (
db.query(models.Like)
.filter(
and_(
models.Like.my_story_id == my_story_id,
models.Like.liker_story_id == liker_story_id,
)
)
.first()
)


def update_like(db, like_id, like: schemas.LikeCreate):
return update(like_id, like, models.Like, db)


def create_like(db, like: schemas.LikeCreate, liker_story_id: int):
d = like.dict()
d["liker_story_id"] = liker_story_id
db_like = models.Like(**d)
db.add(db_like)
db.commit()
db.refresh(db_like)
return db_like


def get_like_count(db, my_story_id):
return (
db.query(models.Like)
.filter(
and_(models.Like.my_story_id == my_story_id, models.Like.like == 1)
)
.count()
)


def get_dislike_count(db, my_story_id):
return (
db.query(models.Like)
.filter(
and_(models.Like.my_story_id == my_story_id, models.Like.like == 0)
)
.count()
)


def is_like_by(db, my_story_id, liker_story_id):
db_like = get_like_by_story_and_user(db, my_story_id, liker_story_id)
if db_like:
return db_like.like
else:
return None
13 changes: 13 additions & 0 deletions backend/likes/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from database import Base
from sqlalchemy import Column, ForeignKey, Integer, Boolean
from sqlalchemy.orm import relationship


class Like(Base):
__tablename__ = "likes"

like = Column(Boolean)
my_story_id = Column(Integer, ForeignKey("my_stories.id"))
liker_story_id = Column(Integer, ForeignKey("stories.id"))

my_story = relationship("MyStory", lazy="select")
13 changes: 13 additions & 0 deletions backend/likes/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pydantic import BaseModel


class LikeCreate(BaseModel):
like: bool = None
my_story_id: int


class Like(LikeCreate):
liker_story_id: int

class Config:
orm_mode = True
4 changes: 3 additions & 1 deletion backend/router/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from fastapi import APIRouter

from router import auth, stories, users, symptoms, data, nyt_live_county
from router import auth, stories, users, symptoms, data, nyt_live_county, likes

router = APIRouter()

Expand All @@ -17,3 +17,5 @@
router.include_router(
nyt_live_county.router, prefix="/nyt_live_county", tags=["nyt_live_county"]
)

router.include_router(likes.router, prefix="/likes", tags=["likes"])
71 changes: 71 additions & 0 deletions backend/router/likes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from starlette.responses import JSONResponse

from auth import main
from database import get_db
from likes import crud, schemas
from stories.crud import get_my_story
from stories import schemas as stories_schemas

router = APIRouter()


@router.post("/", response_model=schemas.Like)
def create_like(
like: schemas.LikeCreate,
current_story: stories_schemas.Story = Depends(main.get_current_story),
db: Session = Depends(get_db),
):
my_story = get_my_story(db, like.my_story_id)
if not my_story:
raise HTTPException(
status_code=404,
detail="Target my story cannot be found",
headers={"WWW-Authenticate": "Bearer"},
)

if not current_story:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User haven't shared their story",
headers={"WWW-Authenticate": "Bearer"},
)

like_to_update = crud.get_like_by_story_and_user(
db, my_story_id=like.my_story_id, liker_story_id=current_story.id
)

if like_to_update:
db_like = crud.update_like(db, like_to_update.id, like)
else:
if my_story.story_id == current_story.id:
raise HTTPException(
status_code=422,
detail="User cannot like or dislike their own my stories",
headers={"WWW-Authenticate": "Bearer"},
)

db_like = crud.create_like(db, like, current_story.id)

return db_like


@router.get("/{my_story_id}")
def get_like_count(
my_story_id: int,
current_story: stories_schemas.Story = Depends(main.get_current_story),
db: Session = Depends(get_db),
):
like_count = crud.get_like_count(db, my_story_id)
dislike_count = crud.get_dislike_count(db, my_story_id)
is_like_by_me = crud.is_like_by(db, my_story_id, current_story.id)

return JSONResponse(
{
"like": like_count,
"dislike": dislike_count,
"like_by_me": is_like_by_me,
},
status_code=200,
)
8 changes: 8 additions & 0 deletions backend/stories/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,11 @@ def update_latest_my_story(db: Session, story: schemas.Story, my_story):

def get_my_story_count(db: Session):
return db.query(models.MyStory).count()


def get_my_story(db: Session, my_story_id: int):
return (
db.query(models.MyStory)
.filter(models.MyStory.id == my_story_id)
.first()
)

0 comments on commit b06e782

Please sign in to comment.