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

Feature/354 comment #384

Merged
merged 4 commits into from
Jan 26, 2021
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
1 change: 1 addition & 0 deletions backend/alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from users import models as user_models
from NytLiveCounty import models as nyt_models
from likes import models as like_models
from comments import models as comment_model

# 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,43 @@
"""add table for comment like

Revision ID: 4e16c97d06e7
Revises: 78b6d95e9727
Create Date: 2021-01-16 11:51:46.777209

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "4e16c97d06e7"
down_revision = "78b6d95e9727"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"comment_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("comment_id", sa.Integer(), nullable=True),
sa.Column("story_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(["comment_id"], ["comments.id"],),
sa.ForeignKeyConstraint(["story_id"], ["stories.id"],),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_comment_likes_id"), "comment_likes", ["id"], unique=False
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f("ix_comment_likes_id"), table_name="comment_likes")
op.drop_table("comment_likes")
# ### end Alembic commands ###
43 changes: 43 additions & 0 deletions backend/alembic/versions/78b6d95e9727_add_comment_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""add comment model

Revision ID: 78b6d95e9727
Revises: edace0efb31c
Create Date: 2021-01-16 10:31:42.706758

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "78b6d95e9727"
down_revision = "edace0efb31c"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"comments",
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("text", sa.Text(), nullable=True),
sa.Column("parent", sa.Integer(), nullable=True),
sa.Column("story_id", sa.Integer(), nullable=True),
sa.Column("my_story_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(["my_story_id"], ["my_stories.id"],),
sa.ForeignKeyConstraint(["parent"], ["comments.id"],),
sa.ForeignKeyConstraint(["story_id"], ["stories.id"],),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_comments_id"), "comments", ["id"], unique=False)
# ### end Alembic commands ###


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

from . import models, schemas
from stories.crud import update


def create_comment(db: Session, comment: schemas.CommentCreate):
db_comment = models.Comment(**comment.dict())
db.add(db_comment)
db.commit()
db.refresh(db_comment)

return db_comment


def get_comments_by_my_story(db: Session, my_story_id):
return (
db.query(models.Comment)
.filter(models.Comment.my_story_id == my_story_id)
.all()
)


def update_comment(db: Session, comment_id, comment: schemas.CommentUpdate):
return update(comment_id, comment, models.Comment, db)


def delete_comment(db: Session, comment_id):
db.query(models.Comment).filter(models.Comment.id == comment_id).delete()
db.commit()


def get_comment(db: Session, comment_id):
db_comment = (
db.query(models.Comment)
.filter(models.Comment.id == comment_id)
.first()
)

return db_comment


def get_like_by_comment_and_user(db: Session, comment_id, story_id):
return (
db.query(models.CommentLike)
.filter(
and_(
models.CommentLike.comment_id == comment_id,
models.CommentLike.story_id == story_id,
)
)
.first()
)


def like_comment(db: Session, comment_id, story_id, is_like):
like = schemas.CommentLike(
like=is_like, comment_id=comment_id, story_id=story_id
)

db_like = get_like_by_comment_and_user(db, comment_id, story_id)
if db_like:
update(db_like.id, like, models.CommentLike, db)
else:
db_like = models.CommentLike(**like.dict())
db.add(db_like)
db.commit()

db.refresh(db_like)
return db_like


def count_like(db: Session, comment_id):
like = (
db.query(models.CommentLike)
.filter(
and_(
models.CommentLike.comment_id == comment_id,
models.CommentLike.like == 1,
)
)
.count()
)

dislike = (
db.query(models.CommentLike)
.filter(
and_(
models.CommentLike.comment_id == comment_id,
models.CommentLike.like == 0,
)
)
.count()
)

return {"like": like, "dislike": dislike}
23 changes: 23 additions & 0 deletions backend/comments/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from sqlalchemy import Column, Text, ForeignKey, Integer, Boolean
from database import Base
from sqlalchemy.orm import relationship


class Comment(Base):
__tablename__ = "comments"

text = Column(Text)
parent = Column(Integer, ForeignKey("comments.id"))
story_id = Column(Integer, ForeignKey("stories.id"))
my_story_id = Column(Integer, ForeignKey("my_stories.id"))

story = relationship("Story", back_populates="comments")
my_story = relationship("MyStory", back_populates="comments")


class CommentLike(Base):
__tablename__ = "comment_likes"

like = Column(Boolean)
comment_id = Column(Integer, ForeignKey("comments.id"))
story_id = Column(Integer, ForeignKey("stories.id"))
38 changes: 38 additions & 0 deletions backend/comments/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from datetime import date
from pydantic import BaseModel
from stories.schemas import Story


class CommentUpdate(BaseModel):
text: str


class CommentBase(CommentUpdate):
parent: int = None


class CommentCreate(CommentBase):
story_id: int
my_story_id: int


class Comment(CommentCreate):
id: int
updated_at: date
created_at: date
story: Story = None

class Config:
orm_mode = True


class CommentLikeCreate(BaseModel):
like: bool = None


class CommentLike(CommentLikeCreate):
comment_id: int
story_id: int

class Config:
orm_mode = True
2 changes: 1 addition & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ async-generator
pymysql
alembic
bcrypt
pyjwt
pyjwt==1.7.1
python-multipart
requests
pandas
Expand Down
13 changes: 12 additions & 1 deletion backend/router/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
from fastapi import APIRouter

from router import auth, stories, users, symptoms, data, nyt_live_county, likes
from router import (
auth,
stories,
users,
symptoms,
data,
nyt_live_county,
likes,
comments,
)

router = APIRouter()

Expand All @@ -19,3 +28,5 @@
)

router.include_router(likes.router, prefix="/likes", tags=["likes"])

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

from auth import main
from stories import schemas as stories_schemas
from database import get_db
from comments import crud, schemas
from router.stories import check_permissions

router = APIRouter()


@router.post("/my_stories/{my_story_id}", response_model=schemas.Comment)
def create_comment(
my_story_id: int,
comment: schemas.CommentBase,
current_story: stories_schemas.Story = Depends(main.get_current_story),
db: Session = Depends(get_db),
):
if not current_story:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User must first share their story before commenting",
headers={"WWW-Authenticate": "Bearer"},
)

story_id = current_story.id
comment = schemas.CommentCreate(
story_id=story_id, my_story_id=my_story_id, **comment.dict()
)
comment.story_id = story_id
comment.my_story_id = my_story_id

return crud.create_comment(db, comment)


@router.get("/my_stories/{my_story_id}", response_model=List[schemas.Comment])
def get_comments_by_my_story(my_story_id: int, db: Session = Depends(get_db)):
return crud.get_comments_by_my_story(db, my_story_id)


@router.post("/{comment_id}", response_model=schemas.Comment)
def update_comment(
comment_id: int,
comment: schemas.CommentUpdate,
current_story: stories_schemas.Story = Depends(main.get_current_story),
db: Session = Depends(get_db),
):
db_comment = crud.get_comment(db, comment_id)
check_permissions(current_story, db_comment.story_id)
return crud.update_comment(db, comment_id, comment)


@router.delete("/{comment_id}")
def delete_comment(
comment_id: int,
current_story: stories_schemas.Story = Depends(main.get_current_story),
db: Session = Depends(get_db),
):
db_comment = crud.get_comment(db, comment_id)
check_permissions(current_story, db_comment.story_id)
crud.delete_comment(db, comment_id)


@router.get("/{comment_id}", response_model=schemas.Comment)
def get_comment(
comment_id: int, db: Session = Depends(get_db),
):
return crud.get_comment(db, comment_id)


@router.post("/{comment_id}/like", response_model=schemas.CommentLike)
def like_comment(
comment_id: int,
dto: schemas.CommentLikeCreate,
current_story: stories_schemas.Story = Depends(main.get_current_story),
db: Session = Depends(get_db),
):
if not current_story:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User must first share their story before "
+ "liking or dislike a comment",
headers={"WWW-Authenticate": "Bearer"},
)

return crud.like_comment(db, comment_id, current_story.id, dto.like)


@router.get("/{comment_id}/like")
def count_like(
comment_id: int,
current_story: stories_schemas.Story = Depends(main.get_current_story),
db: Session = Depends(get_db),
):
d = crud.count_like(db, comment_id)
db_like = (
crud.get_like_by_comment_and_user(db, comment_id, current_story.id)
if current_story
else None
)

like_by_me = db_like.like if db_like else None
d["like_by_me"] = like_by_me

return JSONResponse(d, status_code=200,)
Loading