From c64958bb9d47cb1bd9f20cbe1a43ed8122be5d68 Mon Sep 17 00:00:00 2001 From: Olly Hearn Date: Sun, 14 Apr 2024 01:19:20 +0300 Subject: [PATCH] finally, queue logic --- backend/app/config/jwt_config.py | 2 +- backend/app/db/models.py | 24 +++++++++ backend/app/views/auth/api.py | 2 +- backend/app/views/auth/services.py | 20 +++++++- backend/app/views/queue/api.py | 7 +++ backend/app/views/queue/schemas.py | 5 ++ backend/app/views/queue/services.py | 25 +++++++++- .../src/components/news/CreateNewsCard.tsx | 3 +- .../app/src/components/news/NewsListCard.tsx | 8 ++- .../src/components/queue/CreateQueueCard.tsx | 2 +- .../app/src/components/queue/QueueCard.tsx | 50 +++++++++++++++++++ .../app/src/components/queue/QueuesList.tsx | 29 ++++++++--- frontend/app/src/components/styles.css | 6 ++- frontend/app/src/pages/AppRoutes.tsx | 2 + frontend/app/src/slice/QueueApi.ts | 9 +++- 15 files changed, 177 insertions(+), 17 deletions(-) create mode 100644 frontend/app/src/components/queue/QueueCard.tsx diff --git a/backend/app/config/jwt_config.py b/backend/app/config/jwt_config.py index 0e78c0f..8053a9c 100644 --- a/backend/app/config/jwt_config.py +++ b/backend/app/config/jwt_config.py @@ -1,4 +1,4 @@ from .secret import SECRET_KEY ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 +ACCESS_TOKEN_EXPIRE_WEEKS = 2 diff --git a/backend/app/db/models.py b/backend/app/db/models.py index 1e52c7f..9af8bdc 100644 --- a/backend/app/db/models.py +++ b/backend/app/db/models.py @@ -34,11 +34,35 @@ class AnonymousUser(Base): id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column(String, index=True) + parts_in_queues = relationship("QueueUser", backref="user", lazy="dynamic") + class Queue(Base): __tablename__ = "queues" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + created = Column(DateTime, default=datetime.datetime.utcnow) name = Column(String, index=True) description = Column(String, index=True) owner_id = Column(UUID(as_uuid=True), ForeignKey("users.id")) + start_time = Column(DateTime, nullable=True) + + users = relationship("QueueUser", backref="queue", lazy="dynamic") + + +class QueueUser(Base): + __tablename__ = "queueuser" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + user_id = Column(UUID(as_uuid=True), ForeignKey("anonymoususers.id")) + queue_id = Column(UUID(as_uuid=True), ForeignKey("queues.id")) + position = Column(Integer) + passed = Column(Boolean, default=False) + + +class QueueLog(Base): + __tablename__ = "queuelog" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + action = Column(String) + created = Column(DateTime, default=datetime.datetime.utcnow) diff --git a/backend/app/views/auth/api.py b/backend/app/views/auth/api.py index 4271e2c..d2b4a03 100644 --- a/backend/app/views/auth/api.py +++ b/backend/app/views/auth/api.py @@ -34,7 +34,7 @@ async def login_for_access_token( detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) - access_token_expires = timedelta(minutes=jwt_config.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token_expires = timedelta(weeks=jwt_config.ACCESS_TOKEN_EXPIRE_WEEKS) access_token = services.create_access_token( data={"sub": user.username}, expires_delta=access_token_expires ) diff --git a/backend/app/views/auth/services.py b/backend/app/views/auth/services.py index 35c31c1..c4ebf3e 100644 --- a/backend/app/views/auth/services.py +++ b/backend/app/views/auth/services.py @@ -46,7 +46,7 @@ def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None if expires_delta: expire = datetime.now(timezone.utc) + expires_delta else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) + expire = datetime.now(timezone.utc) + timedelta(weeks=2) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode( to_encode, jwt_config.SECRET_KEY, algorithm=jwt_config.ALGORITHM @@ -90,6 +90,24 @@ async def get_current_user( return user +async def get_current_user_or_none( + token: Annotated[str, Depends(oauth2_scheme)], + db: Annotated[Session, Depends(get_db)], +) -> Union[schemas.UserInDB, None]: + try: + payload = jwt.decode( + token, jwt_config.SECRET_KEY, algorithms=[jwt_config.ALGORITHM] + ) + username: str = payload.get("sub") + if username is None: + raise credentials_exception + token_data = schemas.TokenData(username=username) + except JWTError: + return None + user = get_user_by_username(db, username=token_data.username) + return user + + async def get_current_active_user( current_user: Annotated[schemas.User, Depends(get_current_user)], ): diff --git a/backend/app/views/queue/api.py b/backend/app/views/queue/api.py index ee25683..3ed6d53 100644 --- a/backend/app/views/queue/api.py +++ b/backend/app/views/queue/api.py @@ -32,6 +32,13 @@ async def user_queues_list( return queues +@router.get("/{queue_id}") +async def user_queues_list( + queue: Annotated[schemas.QueueDetail, Depends(services.get_detailed_queue)], +) -> schemas.QueueDetail: + return queue + + @router.post("/") async def create_queue( new_queue: schemas.Queue, diff --git a/backend/app/views/queue/schemas.py b/backend/app/views/queue/schemas.py index 3abca79..918584b 100644 --- a/backend/app/views/queue/schemas.py +++ b/backend/app/views/queue/schemas.py @@ -25,3 +25,8 @@ class QueueInDb(Queue): class Config: from_attributes = True + + +class QueueDetail(Queue): + id: UUID + participants: ParticipantInfo diff --git a/backend/app/views/queue/services.py b/backend/app/views/queue/services.py index f13fdba..0afcbb3 100644 --- a/backend/app/views/queue/services.py +++ b/backend/app/views/queue/services.py @@ -1,6 +1,7 @@ -from fastapi import Depends +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 @@ -28,3 +29,25 @@ def create_queue( db.add(q) db.commit() return schemas.QueueInDb.model_validate(q) + + +def get_detailed_queue( + queue_id: UUID, + db: Annotated[Session, Depends(get_db)], +) -> schemas.QueueDetail: + q = db.query(models.Queue).filter(models.Queue.id == queue_id).first() + print("\n\n", queue_id, "\n\n", flush=True) + if q: + return schemas.QueueDetail( + id=q.id, + name=q.name, + description=q.description, + participants=schemas.ParticipantInfo( + total=q.users.count(), + remaining=q.users.filter(models.QueueUser.passed == False).count(), + ), + ) + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Not Found", + ) diff --git a/frontend/app/src/components/news/CreateNewsCard.tsx b/frontend/app/src/components/news/CreateNewsCard.tsx index baa8ecd..a17f0ae 100644 --- a/frontend/app/src/components/news/CreateNewsCard.tsx +++ b/frontend/app/src/components/news/CreateNewsCard.tsx @@ -7,6 +7,7 @@ import { MessageContext } from "../../App"; import { useNavigate } from "react-router-dom"; import { PlusCircleOutlined } from "@ant-design/icons"; import { CreateNewsRequest, useCreateNewsMutation } from "../../slice/NewsApi"; +import TextArea from "antd/es/input/TextArea"; const CreateNewsCard = (): JSX.Element => { const messageApi = useContext(MessageContext); @@ -55,7 +56,7 @@ const CreateNewsCard = (): JSX.Element => { }, ]} > - +