diff --git a/backend/app/db/models.py b/backend/app/db/models.py index 9af8bdc..af6df7d 100644 --- a/backend/app/db/models.py +++ b/backend/app/db/models.py @@ -26,6 +26,7 @@ class News(Base): title = Column(String) content = Column(String) created = Column(DateTime, default=datetime.datetime.utcnow) + taps = Column(Integer, default=0) class AnonymousUser(Base): diff --git a/backend/app/views/news/api.py b/backend/app/views/news/api.py index 754ca3d..4dd695a 100644 --- a/backend/app/views/news/api.py +++ b/backend/app/views/news/api.py @@ -1,6 +1,7 @@ from datetime import datetime, timedelta, timezone from typing import Annotated, Union from sqlalchemy.orm import Session +from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm @@ -39,3 +40,12 @@ async def create_news( db: Annotated[Session, Depends(get_db)], ) -> schemas.NewsInDb: return services.create_news(news=news, current_user=current_user, db=db) + + +@router.post("/{news_id}/tap") +async def create_news( + news_id: UUID, + db: Annotated[Session, Depends(get_db)], +) -> schemas.TapResponse: + services.tap_news(news_id=news_id, db=db) + return schemas.TapResponse(tap="ok") diff --git a/backend/app/views/news/schemas.py b/backend/app/views/news/schemas.py index dda29da..fe7074a 100644 --- a/backend/app/views/news/schemas.py +++ b/backend/app/views/news/schemas.py @@ -13,6 +13,7 @@ class News(BaseModel): title: str content: str created: datetime + taps: int class NewsInDb(News): @@ -20,3 +21,7 @@ class NewsInDb(News): class Config: from_attributes = True + + +class TapResponse(BaseModel): + tap: str diff --git a/backend/app/views/news/services.py b/backend/app/views/news/services.py index ef3afdb..dce3625 100644 --- a/backend/app/views/news/services.py +++ b/backend/app/views/news/services.py @@ -1,6 +1,7 @@ -from fastapi import Depends, HTTPException +from fastapi import Depends, HTTPException, status from typing import Annotated from sqlalchemy.orm import Session +from uuid import UUID from ...dependencies import get_db from ...db import models @@ -35,3 +36,15 @@ def create_news( detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) + + +def tap_news(news_id: UUID, db: Session): + n = db.query(models.News).filter(models.News.id == news_id).first() + if n: + setattr(n, "taps", n.taps + 1) + db.commit() + return + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Not found", + ) diff --git a/frontend/app/src/components/news/NewsListCard.tsx b/frontend/app/src/components/news/NewsListCard.tsx index 4629cde..98926db 100644 --- a/frontend/app/src/components/news/NewsListCard.tsx +++ b/frontend/app/src/components/news/NewsListCard.tsx @@ -1,8 +1,8 @@ import React from "react"; import "../styles.css"; -import { Card, Spin } from "antd"; -import { News, useGetNewsQuery } from "../../slice/NewsApi"; -import { ClockCircleOutlined } from "@ant-design/icons"; +import { Button, Card, Spin } from "antd"; +import { News, useGetNewsQuery, useTapNewsMutation } from "../../slice/NewsApi"; +import { ClockCircleOutlined, FireOutlined } from "@ant-design/icons"; const formatTime = (s: string) => { const d = new Date(s + "Z"); @@ -10,7 +10,8 @@ const formatTime = (s: string) => { }; const NewsListCard = (): JSX.Element => { - const { data, isLoading } = useGetNewsQuery({}); + const { data, refetch, isLoading } = useGetNewsQuery({}); + const [tapNews] = useTapNewsMutation(); return (
{news.content}
{formatTime(news.created)}
++ {formatTime(news.created)} +
+