kopia lustrzana https://github.com/bugout-dev/moonstream
Add type annotations.
rodzic
cb7950d922
commit
3319d4a8a4
|
@ -1,6 +1,6 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from typing import List, Any, Optional, Dict, Union
|
from typing import List, Any, Optional, Dict, Union, Tuple
|
||||||
import uuid
|
import uuid
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import requests # type: ignore
|
||||||
from sqlalchemy.dialects.postgresql import insert
|
from sqlalchemy.dialects.postgresql import insert
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from sqlalchemy import func, text, or_
|
from sqlalchemy import func, text, or_
|
||||||
|
from sqlalchemy.engine import Row
|
||||||
from web3 import Web3
|
from web3 import Web3
|
||||||
from web3.types import ChecksumAddress
|
from web3.types import ChecksumAddress
|
||||||
|
|
||||||
|
@ -944,7 +945,7 @@ def refetch_drop_signatures(
|
||||||
return claimant_objects
|
return claimant_objects
|
||||||
|
|
||||||
|
|
||||||
def get_leaderboard_total_count(db_session: Session, leaderboard_id):
|
def get_leaderboard_total_count(db_session: Session, leaderboard_id) -> int:
|
||||||
"""
|
"""
|
||||||
Get the total number of claimants in the leaderboard
|
Get the total number of claimants in the leaderboard
|
||||||
"""
|
"""
|
||||||
|
@ -955,7 +956,9 @@ def get_leaderboard_total_count(db_session: Session, leaderboard_id):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_leaderboard_info(db_session: Session, leaderboard_id: uuid.UUID) -> Any:
|
def get_leaderboard_info(
|
||||||
|
db_session: Session, leaderboard_id: uuid.UUID
|
||||||
|
) -> Row[Tuple[uuid.UUID, str, str, int, Optional[datetime]]]:
|
||||||
"""
|
"""
|
||||||
Get the leaderboard from the database with users count
|
Get the leaderboard from the database with users count
|
||||||
"""
|
"""
|
||||||
|
@ -968,7 +971,11 @@ def get_leaderboard_info(db_session: Session, leaderboard_id: uuid.UUID) -> Any:
|
||||||
func.count(LeaderboardScores.id).label("users_count"),
|
func.count(LeaderboardScores.id).label("users_count"),
|
||||||
func.max(LeaderboardScores.updated_at).label("last_update"),
|
func.max(LeaderboardScores.updated_at).label("last_update"),
|
||||||
)
|
)
|
||||||
.join(LeaderboardScores, LeaderboardScores.leaderboard_id == Leaderboard.id, isouter=True)
|
.join(
|
||||||
|
LeaderboardScores,
|
||||||
|
LeaderboardScores.leaderboard_id == Leaderboard.id,
|
||||||
|
isouter=True,
|
||||||
|
)
|
||||||
.filter(Leaderboard.id == leaderboard_id)
|
.filter(Leaderboard.id == leaderboard_id)
|
||||||
.group_by(Leaderboard.id, Leaderboard.title, Leaderboard.description)
|
.group_by(Leaderboard.id, Leaderboard.title, Leaderboard.description)
|
||||||
.one()
|
.one()
|
||||||
|
@ -979,8 +986,7 @@ def get_leaderboard_info(db_session: Session, leaderboard_id: uuid.UUID) -> Any:
|
||||||
|
|
||||||
def get_leaderboard_scores_changes(
|
def get_leaderboard_scores_changes(
|
||||||
db_session: Session, leaderboard_id: uuid.UUID
|
db_session: Session, leaderboard_id: uuid.UUID
|
||||||
) -> Any:
|
) -> List[Row[Tuple[int, datetime]]]:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Return the leaderboard scores changes timeline changes of leaderboard scores
|
Return the leaderboard scores changes timeline changes of leaderboard scores
|
||||||
"""
|
"""
|
||||||
|
@ -994,7 +1000,7 @@ def get_leaderboard_scores_changes(
|
||||||
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
||||||
.group_by(LeaderboardScores.updated_at)
|
.group_by(LeaderboardScores.updated_at)
|
||||||
.order_by(LeaderboardScores.updated_at.desc())
|
.order_by(LeaderboardScores.updated_at.desc())
|
||||||
)
|
).all()
|
||||||
|
|
||||||
return leaderboard_scores_changes
|
return leaderboard_scores_changes
|
||||||
|
|
||||||
|
@ -1005,8 +1011,7 @@ def get_leaderboard_scores_by_timestamp(
|
||||||
date: datetime,
|
date: datetime,
|
||||||
limit: int,
|
limit: int,
|
||||||
offset: int,
|
offset: int,
|
||||||
) -> Any:
|
) -> List[LeaderboardScores]:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Return the leaderboard scores by timestamp
|
Return the leaderboard scores by timestamp
|
||||||
"""
|
"""
|
||||||
|
@ -1060,7 +1065,7 @@ def get_leaderboards(
|
||||||
|
|
||||||
def get_position(
|
def get_position(
|
||||||
db_session: Session, leaderboard_id, address, window_size, limit: int, offset: int
|
db_session: Session, leaderboard_id, address, window_size, limit: int, offset: int
|
||||||
):
|
) -> List[Row[Tuple[str, int, int, int, Any]]]:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Return position by address with window size
|
Return position by address with window size
|
||||||
|
@ -1112,7 +1117,7 @@ def get_position(
|
||||||
|
|
||||||
def get_leaderboard_positions(
|
def get_leaderboard_positions(
|
||||||
db_session: Session, leaderboard_id, limit: int, offset: int
|
db_session: Session, leaderboard_id, limit: int, offset: int
|
||||||
):
|
) -> List[Row[Tuple[uuid.UUID, str, int, str, int]]]:
|
||||||
"""
|
"""
|
||||||
Get the leaderboard positions
|
Get the leaderboard positions
|
||||||
"""
|
"""
|
||||||
|
@ -1137,7 +1142,9 @@ def get_leaderboard_positions(
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
def get_qurtiles(db_session: Session, leaderboard_id):
|
def get_qurtiles(
|
||||||
|
db_session: Session, leaderboard_id
|
||||||
|
) -> Tuple[Row[Tuple[str, float, int]], ...]:
|
||||||
"""
|
"""
|
||||||
Get the leaderboard qurtiles
|
Get the leaderboard qurtiles
|
||||||
https://docs.sqlalchemy.org/en/14/core/functions.html#sqlalchemy.sql.functions.percentile_disc
|
https://docs.sqlalchemy.org/en/14/core/functions.html#sqlalchemy.sql.functions.percentile_disc
|
||||||
|
@ -1171,7 +1178,7 @@ def get_qurtiles(db_session: Session, leaderboard_id):
|
||||||
return q1, q2, q3
|
return q1, q2, q3
|
||||||
|
|
||||||
|
|
||||||
def get_ranks(db_session: Session, leaderboard_id):
|
def get_ranks(db_session: Session, leaderboard_id) -> List[Row[Tuple[int, int, int]]]:
|
||||||
"""
|
"""
|
||||||
Get the leaderboard rank buckets(rank, size, score)
|
Get the leaderboard rank buckets(rank, size, score)
|
||||||
"""
|
"""
|
||||||
|
@ -1199,7 +1206,7 @@ def get_rank(
|
||||||
rank: int,
|
rank: int,
|
||||||
limit: Optional[int] = None,
|
limit: Optional[int] = None,
|
||||||
offset: Optional[int] = None,
|
offset: Optional[int] = None,
|
||||||
):
|
) -> List[Row[Tuple[uuid.UUID, str, int, str, int]]]:
|
||||||
"""
|
"""
|
||||||
Get bucket in leaderboard by rank
|
Get bucket in leaderboard by rank
|
||||||
"""
|
"""
|
||||||
|
@ -1234,11 +1241,14 @@ def create_leaderboard(
|
||||||
db_session: Session,
|
db_session: Session,
|
||||||
title: str,
|
title: str,
|
||||||
description: Optional[str],
|
description: Optional[str],
|
||||||
token: uuid.UUID,
|
token: Optional[uuid.UUID],
|
||||||
):
|
) -> Leaderboard:
|
||||||
"""
|
"""
|
||||||
Create a leaderboard
|
Create a leaderboard
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if not token:
|
||||||
|
token = uuid.UUID(MOONSTREAM_ADMIN_ACCESS_TOKEN)
|
||||||
try:
|
try:
|
||||||
leaderboard = Leaderboard(title=title, description=description)
|
leaderboard = Leaderboard(title=title, description=description)
|
||||||
db_session.add(leaderboard)
|
db_session.add(leaderboard)
|
||||||
|
@ -1262,8 +1272,7 @@ def create_leaderboard(
|
||||||
|
|
||||||
def delete_leaderboard(
|
def delete_leaderboard(
|
||||||
db_session: Session, leaderboard_id: uuid.UUID, token: uuid.UUID
|
db_session: Session, leaderboard_id: uuid.UUID, token: uuid.UUID
|
||||||
):
|
) -> Leaderboard:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Delete a leaderboard
|
Delete a leaderboard
|
||||||
"""
|
"""
|
||||||
|
@ -1280,6 +1289,10 @@ def delete_leaderboard(
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error deleting leaderboard resource: {e}")
|
logger.error(f"Error deleting leaderboard resource: {e}")
|
||||||
|
else:
|
||||||
|
logger.error(
|
||||||
|
f"Leaderboard {leaderboard_id} has no resource id. Skipping. Better delete it manually."
|
||||||
|
)
|
||||||
|
|
||||||
db_session.delete(leaderboard)
|
db_session.delete(leaderboard)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
@ -1296,9 +1309,7 @@ def update_leaderboard(
|
||||||
leaderboard_id: uuid.UUID,
|
leaderboard_id: uuid.UUID,
|
||||||
title: Optional[str],
|
title: Optional[str],
|
||||||
description: Optional[str],
|
description: Optional[str],
|
||||||
token: uuid.UUID,
|
) -> Leaderboard:
|
||||||
):
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Update a leaderboard
|
Update a leaderboard
|
||||||
"""
|
"""
|
||||||
|
@ -1317,21 +1328,23 @@ def update_leaderboard(
|
||||||
return leaderboard
|
return leaderboard
|
||||||
|
|
||||||
|
|
||||||
def get_leaderboard_by_id(db_session: Session, leaderboard_id):
|
def get_leaderboard_by_id(db_session: Session, leaderboard_id) -> Leaderboard:
|
||||||
"""
|
"""
|
||||||
Get the leaderboard by id
|
Get the leaderboard by id
|
||||||
"""
|
"""
|
||||||
return db_session.query(Leaderboard).filter(Leaderboard.id == leaderboard_id).one() # type: ignore
|
return db_session.query(Leaderboard).filter(Leaderboard.id == leaderboard_id).one() # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def get_leaderboard_by_title(db_session: Session, title):
|
def get_leaderboard_by_title(db_session: Session, title) -> Leaderboard:
|
||||||
"""
|
"""
|
||||||
Get the leaderboard by title
|
Get the leaderboard by title
|
||||||
"""
|
"""
|
||||||
return db_session.query(Leaderboard).filter(Leaderboard.title == title).one() # type: ignore
|
return db_session.query(Leaderboard).filter(Leaderboard.title == title).one() # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def list_leaderboards(db_session: Session, limit: int, offset: int):
|
def list_leaderboards(
|
||||||
|
db_session: Session, limit: int, offset: int
|
||||||
|
) -> List[Row[Tuple[uuid.UUID, str, str]]]:
|
||||||
"""
|
"""
|
||||||
List all leaderboards
|
List all leaderboards
|
||||||
"""
|
"""
|
||||||
|
@ -1413,10 +1426,7 @@ def add_scores(
|
||||||
|
|
||||||
|
|
||||||
def create_leaderboard_resource(
|
def create_leaderboard_resource(
|
||||||
leaderboard_id: str,
|
leaderboard_id: str, token: Union[Optional[uuid.UUID], str] = None
|
||||||
token: Union[Optional[uuid.UUID], str] = None,
|
|
||||||
title: Optional[str] = None,
|
|
||||||
user_id: Optional[uuid.UUID] = None,
|
|
||||||
) -> BugoutResource:
|
) -> BugoutResource:
|
||||||
resource_data: Dict[str, Any] = {
|
resource_data: Dict[str, Any] = {
|
||||||
"type": LEADERBOARD_RESOURCE_TYPE,
|
"type": LEADERBOARD_RESOURCE_TYPE,
|
||||||
|
@ -1481,7 +1491,9 @@ def list_leaderboards_resources(
|
||||||
return query.all()
|
return query.all()
|
||||||
|
|
||||||
|
|
||||||
def revoke_resource(db_session: Session, leaderboard_id: uuid.UUID):
|
def revoke_resource(
|
||||||
|
db_session: Session, leaderboard_id: uuid.UUID
|
||||||
|
) -> Optional[uuid.UUID]:
|
||||||
"""
|
"""
|
||||||
Revoke a resource handler to a leaderboard
|
Revoke a resource handler to a leaderboard
|
||||||
"""
|
"""
|
||||||
|
@ -1505,7 +1517,7 @@ def revoke_resource(db_session: Session, leaderboard_id: uuid.UUID):
|
||||||
|
|
||||||
def check_leaderboard_resource_permissions(
|
def check_leaderboard_resource_permissions(
|
||||||
db_session: Session, leaderboard_id: uuid.UUID, token: uuid.UUID
|
db_session: Session, leaderboard_id: uuid.UUID, token: uuid.UUID
|
||||||
):
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if the user has permissions to access the leaderboard
|
Check if the user has permissions to access the leaderboard
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -372,6 +372,9 @@ class LeaderboardCreatedResponse(BaseModel):
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
updated_at: datetime
|
updated_at: datetime
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class LeaderboardUpdatedResponse(BaseModel):
|
class LeaderboardUpdatedResponse(BaseModel):
|
||||||
id: UUID
|
id: UUID
|
||||||
|
@ -381,6 +384,9 @@ class LeaderboardUpdatedResponse(BaseModel):
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
updated_at: datetime
|
updated_at: datetime
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class LeaderboardUpdateRequest(BaseModel):
|
class LeaderboardUpdateRequest(BaseModel):
|
||||||
title: Optional[str] = None
|
title: Optional[str] = None
|
||||||
|
|
|
@ -66,7 +66,6 @@ app.add_middleware(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("", response_model=List[data.LeaderboardPosition])
|
@app.get("", response_model=List[data.LeaderboardPosition])
|
||||||
@app.get("/", response_model=List[data.LeaderboardPosition])
|
@app.get("/", response_model=List[data.LeaderboardPosition])
|
||||||
async def leaderboard(
|
async def leaderboard(
|
||||||
|
@ -114,7 +113,6 @@ async def create_leaderboard(
|
||||||
leaderboard: data.LeaderboardCreateRequest,
|
leaderboard: data.LeaderboardCreateRequest,
|
||||||
db_session: Session = Depends(db.yield_db_session),
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
) -> data.LeaderboardCreatedResponse:
|
) -> data.LeaderboardCreatedResponse:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Create leaderboard.
|
Create leaderboard.
|
||||||
|
@ -143,12 +141,12 @@ async def create_leaderboard(
|
||||||
# Add resource to the leaderboard
|
# Add resource to the leaderboard
|
||||||
|
|
||||||
return data.LeaderboardCreatedResponse(
|
return data.LeaderboardCreatedResponse(
|
||||||
id=created_leaderboard.id,
|
id=created_leaderboard.id, # type: ignore
|
||||||
title=created_leaderboard.title,
|
title=created_leaderboard.title, # type: ignore
|
||||||
description=created_leaderboard.description,
|
description=created_leaderboard.description, # type: ignore
|
||||||
resource_id=created_leaderboard.resource_id,
|
resource_id=created_leaderboard.resource_id, # type: ignore
|
||||||
created_at=created_leaderboard.created_at,
|
created_at=created_leaderboard.created_at, # type: ignore
|
||||||
updated_at=created_leaderboard.updated_at,
|
updated_at=created_leaderboard.updated_at, # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,7 +157,6 @@ async def update_leaderboard(
|
||||||
leaderboard: data.LeaderboardUpdateRequest,
|
leaderboard: data.LeaderboardUpdateRequest,
|
||||||
db_session: Session = Depends(db.yield_db_session),
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
) -> data.LeaderboardUpdatedResponse:
|
) -> data.LeaderboardUpdatedResponse:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Update leaderboard.
|
Update leaderboard.
|
||||||
"""
|
"""
|
||||||
|
@ -188,7 +185,6 @@ async def update_leaderboard(
|
||||||
leaderboard_id=leaderboard_id,
|
leaderboard_id=leaderboard_id,
|
||||||
title=leaderboard.title,
|
title=leaderboard.title,
|
||||||
description=leaderboard.description,
|
description=leaderboard.description,
|
||||||
token=token,
|
|
||||||
)
|
)
|
||||||
except actions.LeaderboardUpdateError as e:
|
except actions.LeaderboardUpdateError as e:
|
||||||
logger.error(f"Error while updating leaderboard: {e}")
|
logger.error(f"Error while updating leaderboard: {e}")
|
||||||
|
@ -202,12 +198,12 @@ async def update_leaderboard(
|
||||||
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
return data.LeaderboardUpdatedResponse(
|
return data.LeaderboardUpdatedResponse(
|
||||||
id=updated_leaderboard.id,
|
id=updated_leaderboard.id, # type: ignore
|
||||||
title=updated_leaderboard.title,
|
title=updated_leaderboard.title, # type: ignore
|
||||||
description=updated_leaderboard.description,
|
description=updated_leaderboard.description, # type: ignore
|
||||||
resource_id=updated_leaderboard.resource_id,
|
resource_id=updated_leaderboard.resource_id, # type: ignore
|
||||||
created_at=updated_leaderboard.created_at,
|
created_at=updated_leaderboard.created_at, # type: ignore
|
||||||
updated_at=updated_leaderboard.updated_at,
|
updated_at=updated_leaderboard.updated_at, # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,7 +213,6 @@ async def delete_leaderboard(
|
||||||
leaderboard_id: UUID,
|
leaderboard_id: UUID,
|
||||||
db_session: Session = Depends(db.yield_db_session),
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
) -> data.LeaderboardDeletedResponse:
|
) -> data.LeaderboardDeletedResponse:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Delete leaderboard.
|
Delete leaderboard.
|
||||||
"""
|
"""
|
||||||
|
@ -228,7 +223,7 @@ async def delete_leaderboard(
|
||||||
db_session=db_session,
|
db_session=db_session,
|
||||||
leaderboard_id=leaderboard_id,
|
leaderboard_id=leaderboard_id,
|
||||||
token=token,
|
token=token,
|
||||||
)
|
)
|
||||||
except NoResultFound as e:
|
except NoResultFound as e:
|
||||||
raise EngineHTTPException(
|
raise EngineHTTPException(
|
||||||
status_code=404,
|
status_code=404,
|
||||||
|
@ -258,12 +253,11 @@ async def delete_leaderboard(
|
||||||
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
return data.LeaderboardDeletedResponse(
|
return data.LeaderboardDeletedResponse(
|
||||||
id=deleted_leaderboard.id,
|
id=deleted_leaderboard.id, # type: ignore
|
||||||
title=deleted_leaderboard.title,
|
title=deleted_leaderboard.title, # type: ignore
|
||||||
description=deleted_leaderboard.description,
|
description=deleted_leaderboard.description, # type: ignore
|
||||||
resource_id=deleted_leaderboard.resource_id,
|
created_at=deleted_leaderboard.created_at, # type: ignore
|
||||||
created_at=deleted_leaderboard.created_at,
|
updated_at=deleted_leaderboard.updated_at, # type: ignore
|
||||||
updated_at=deleted_leaderboard.updated_at,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,18 +284,19 @@ async def get_leaderboards(
|
||||||
|
|
||||||
results = [
|
results = [
|
||||||
data.Leaderboard(
|
data.Leaderboard(
|
||||||
id=leaderboard.id,
|
id=leaderboard.id, # type: ignore
|
||||||
title=leaderboard.title,
|
title=leaderboard.title, # type: ignore
|
||||||
description=leaderboard.description,
|
description=leaderboard.description, # type: ignore
|
||||||
resource_id=leaderboard.resource_id,
|
resource_id=leaderboard.resource_id, # type: ignore
|
||||||
created_at=leaderboard.created_at,
|
created_at=leaderboard.created_at, # type: ignore
|
||||||
updated_at=leaderboard.updated_at,
|
updated_at=leaderboard.updated_at, # type: ignore
|
||||||
)
|
)
|
||||||
for leaderboard in leaderboards
|
for leaderboard in leaderboards
|
||||||
]
|
]
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
@app.get("/count/addresses", response_model=data.CountAddressesResponse)
|
@app.get("/count/addresses", response_model=data.CountAddressesResponse)
|
||||||
async def count_addresses(
|
async def count_addresses(
|
||||||
leaderboard_id: UUID,
|
leaderboard_id: UUID,
|
||||||
|
@ -361,13 +356,11 @@ async def get_scores_changes(
|
||||||
leaderboard_id: UUID,
|
leaderboard_id: UUID,
|
||||||
db_session: Session = Depends(db.yield_db_session),
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
) -> Any:
|
) -> Any:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Returns the score history for the given address.
|
Returns the score history for the given address.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
scores = actions.get_leaderboard_scores_changes(db_session, leaderboard_id)
|
scores = actions.get_leaderboard_scores_changes(db_session, leaderboard_id)
|
||||||
except actions.LeaderboardIsEmpty:
|
except actions.LeaderboardIsEmpty:
|
||||||
raise EngineHTTPException(status_code=204, detail="Leaderboard is empty.")
|
raise EngineHTTPException(status_code=204, detail="Leaderboard is empty.")
|
||||||
|
|
Ładowanie…
Reference in New Issue