groups functional & bugfixes

This commit is contained in:
2024-06-15 22:36:45 +03:00
parent 480d2fe141
commit e51140583b
12 changed files with 399 additions and 77 deletions

View File

@ -76,6 +76,7 @@ class Queue(Base):
users = relationship("QueueUser", backref="queue", lazy="dynamic")
logs = relationship("QueueLog", backref="queue", lazy="dynamic")
groups = relationship("QueueGroup", backref="queue", lazy="dynamic")
class QueueUser(Base):
@ -86,6 +87,7 @@ class QueueUser(Base):
queue_id = Column(UUID(as_uuid=True), ForeignKey("queues.id"))
position = Column(Integer)
passed = Column(Boolean, default=False)
group_id = Column(UUID(as_uuid=True), ForeignKey("queuegroup.id"), nullable=True)
class QueueLog(Base):
@ -97,6 +99,17 @@ class QueueLog(Base):
created = Column(DateTime, default=datetime.datetime.utcnow)
class QueueGroup(Base):
__tablename__ = "queuegroup"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
name = Column(String)
priority = Column(Integer)
queue_id = Column(UUID(as_uuid=True), ForeignKey("queues.id"))
users = relationship("QueueUser", backref="group", lazy="dynamic")
class Captcha(Base):
__tablename__ = "captcha"

View File

@ -96,17 +96,21 @@ def get_current_user(
def get_current_user_or_none(
token: Annotated[str, Depends(oauth2_scheme)],
db: Annotated[Session, Depends(get_db)],
authorization: Annotated[Union[str, None], Header()] = None,
) -> 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)
if authorization:
token = authorization.split()[1]
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)
else:
return None
except JWTError:
return None
user = get_user_by_username(db, username=token_data.username)

View File

@ -4,10 +4,23 @@ from uuid import UUID
from ..auth import schemas as auth_schemas
class QueueGroup(BaseModel):
name: str
priority: int
class QueueGroupDetail(QueueGroup):
id: UUID
class Config:
from_attributes = True
class QueueUser(BaseModel):
id: UUID
position: int
passed: bool
group_id: UUID | None = None
user: auth_schemas.AnonUser
class Config:
@ -23,6 +36,7 @@ class ParticipantInfo(BaseModel):
class Queue(BaseModel):
name: str
description: Union[str, None] = None
groups: List[QueueGroup] | None = None
class QueueInList(Queue):
@ -32,8 +46,10 @@ class QueueInList(Queue):
from_attributes = True
class QueueInDb(Queue):
class QueueInDb(BaseModel):
id: UUID
name: str
description: Union[str, None] = None
class Config:
from_attributes = True
@ -44,6 +60,7 @@ class QueueDetail(Queue):
status: str
owner_id: UUID
participants: ParticipantInfo
groups: List[QueueGroupDetail] | None
class ActionResult(BaseModel):
@ -52,3 +69,7 @@ class ActionResult(BaseModel):
class Config:
from_attributes = True
class JoinRequest(BaseModel):
group_id: UUID | None = None

View File

@ -1,6 +1,7 @@
from fastapi import Depends, HTTPException, status
from typing import Annotated
from sqlalchemy.orm import Session
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import func
from uuid import UUID
import redis
import asyncio
@ -49,6 +50,14 @@ def create_queue(
)
db.add(q)
db.commit()
if new_queue.groups:
db.add_all(
instances=[
models.QueueGroup(name=qg.name, priority=qg.priority, queue_id=q.id)
for qg in new_queue.groups
]
)
db.commit()
return schemas.QueueInDb.model_validate(q)
@ -64,6 +73,7 @@ def get_detailed_queue(
description=q.description,
status=q.status,
owner_id=q.owner_id,
groups=q.groups.order_by(models.QueueGroup.priority.asc()),
participants=schemas.ParticipantInfo(
total=q.users.count(),
remaining=q.users.filter(models.QueueUser.passed == False).count(),
@ -80,6 +90,7 @@ def get_detailed_queue(
async def join_queue(
queue_id: UUID,
join_request: schemas.JoinRequest | None,
client: Annotated[auth_schemas.AnonUser, Depends(auth_services.get_anon_user)],
db: Annotated[Session, Depends(get_db)],
r: Annotated[redis.client.Redis, Depends(get_redis)],
@ -90,10 +101,18 @@ async def join_queue(
last_qu = q.users.order_by(models.QueueUser.position.desc()).first()
position = last_qu.position + 1 if last_qu else 0
new_qu = models.QueueUser(
user_id=client.id, queue_id=q.id, position=position
user_id=client.id,
queue_id=q.id,
position=position,
group_id=(
join_request.group_id
if join_request and join_request.group_id
else None
),
)
db.add(new_qu)
db.commit()
await rebuild_queue(queue=q, db=db)
await r.publish(str(queue_id), "updated")
return new_qu
raise HTTPException(
@ -129,7 +148,7 @@ async def get_queue_owner(
async def verify_queue_owner(
queue_owner: Annotated[auth_schemas.UserInDB, Depends(get_queue_owner)],
current_user: Annotated[
auth_schemas.UserInDB, Depends(auth_services.get_current_user)
auth_schemas.UserInDB, Depends(auth_services.get_current_user_or_none)
],
) -> bool:
return queue_owner.id == current_user.id if queue_owner and current_user else False
@ -139,11 +158,32 @@ async def rebuild_queue(
queue: Annotated[models.Queue, Depends(get_queue_by_id)],
db: Annotated[Session, Depends(get_db)],
):
for i, qu in enumerate(
queue.users.filter(models.QueueUser.passed == False).order_by(
models.QueueUser.position.asc()
query = (
db.query(models.QueueUser)
.join(
models.QueueGroup,
models.QueueUser.group_id == models.QueueGroup.id,
isouter=True,
)
):
.filter(models.QueueUser.passed == False, models.QueueUser.queue_id == queue.id)
.order_by(
func.coalesce(models.QueueGroup.priority, 0).asc(),
models.QueueUser.position.asc(),
)
.options(joinedload(models.QueueUser.group))
)
queueusers = query.all()
first_qu_found_and_queue_in_process = False
if queue.status == "active":
for i, qu in enumerate(queueusers):
if qu.position == 0:
first_qu_found_and_queue_in_process = True
del queueusers[i]
break
for i, qu in enumerate(queueusers):
if first_qu_found_and_queue_in_process:
setattr(qu, "position", i + 1)
continue
setattr(qu, "position", i)
db.commit()