kopia lustrzana https://github.com/bugout-dev/moonstream
Add endpoints for LeaderboardVersions.
Change add_scores. Change get leaderboards positions.pull/966/head
rodzic
7295b9c023
commit
e6b75d59d9
|
@ -11,7 +11,7 @@ from hexbytes import HexBytes
|
||||||
import requests # type: ignore
|
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_, Subquery
|
||||||
from sqlalchemy.engine import Row
|
from sqlalchemy.engine import Row
|
||||||
from web3 import Web3
|
from web3 import Web3
|
||||||
from web3.types import ChecksumAddress
|
from web3.types import ChecksumAddress
|
||||||
|
@ -24,6 +24,7 @@ from .models import (
|
||||||
DropperClaim,
|
DropperClaim,
|
||||||
Leaderboard,
|
Leaderboard,
|
||||||
LeaderboardScores,
|
LeaderboardScores,
|
||||||
|
LeaderboardVersion,
|
||||||
)
|
)
|
||||||
from . import signatures
|
from . import signatures
|
||||||
from .settings import (
|
from .settings import (
|
||||||
|
@ -91,6 +92,10 @@ class LeaderboardConfigAlreadyInactive(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LeaderboardVersionNotFound(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
BATCH_SIGNATURE_PAGE_SIZE = 500
|
BATCH_SIGNATURE_PAGE_SIZE = 500
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -959,6 +964,25 @@ def refetch_drop_signatures(
|
||||||
return claimant_objects
|
return claimant_objects
|
||||||
|
|
||||||
|
|
||||||
|
def leaderboard_version_filter(
|
||||||
|
db_session: Session,
|
||||||
|
leaderboard_id: uuid.UUID,
|
||||||
|
version_number: Optional[int] = None,
|
||||||
|
) -> Union[Subquery, int]:
|
||||||
|
# Subquery to get the latest version number for the given leaderboard
|
||||||
|
if not version_number:
|
||||||
|
latest_version = (
|
||||||
|
db_session.query(func.max(LeaderboardVersion.version_number)).filter(
|
||||||
|
LeaderboardVersion.leaderboard_id == leaderboard_id,
|
||||||
|
LeaderboardVersion.published == True,
|
||||||
|
)
|
||||||
|
).scalar_subquery()
|
||||||
|
else:
|
||||||
|
latest_version = version_number
|
||||||
|
|
||||||
|
return latest_version
|
||||||
|
|
||||||
|
|
||||||
def get_leaderboard_total_count(db_session: Session, leaderboard_id) -> int:
|
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
|
||||||
|
@ -971,12 +995,17 @@ def get_leaderboard_total_count(db_session: Session, leaderboard_id) -> int:
|
||||||
|
|
||||||
|
|
||||||
def get_leaderboard_info(
|
def get_leaderboard_info(
|
||||||
db_session: Session, leaderboard_id: uuid.UUID
|
db_session: Session, leaderboard_id: uuid.UUID, version_number: Optional[int] = None
|
||||||
) -> Row[Tuple[uuid.UUID, str, str, int, Optional[datetime]]]:
|
) -> 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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
latest_version = leaderboard_version_filter(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version_number,
|
||||||
|
)
|
||||||
leaderboard = (
|
leaderboard = (
|
||||||
db_session.query(
|
db_session.query(
|
||||||
Leaderboard.id,
|
Leaderboard.id,
|
||||||
|
@ -990,6 +1019,15 @@ def get_leaderboard_info(
|
||||||
LeaderboardScores.leaderboard_id == Leaderboard.id,
|
LeaderboardScores.leaderboard_id == Leaderboard.id,
|
||||||
isouter=True,
|
isouter=True,
|
||||||
)
|
)
|
||||||
|
.join(
|
||||||
|
LeaderboardVersion,
|
||||||
|
LeaderboardVersion.leaderboard_id == Leaderboard.id,
|
||||||
|
isouter=True,
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
LeaderboardVersion.published == True,
|
||||||
|
LeaderboardVersion.version_number == latest_version,
|
||||||
|
)
|
||||||
.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()
|
||||||
|
@ -1078,19 +1116,44 @@ 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,
|
||||||
|
version_number: Optional[int] = None,
|
||||||
) -> List[Row[Tuple[str, int, int, int, Any]]]:
|
) -> List[Row[Tuple[str, int, int, int, Any]]]:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Return position by address with window size
|
Return position by address with window size
|
||||||
"""
|
"""
|
||||||
query = db_session.query(
|
|
||||||
LeaderboardScores.address,
|
latest_version = leaderboard_version_filter(
|
||||||
LeaderboardScores.score,
|
db_session=db_session,
|
||||||
LeaderboardScores.points_data.label("points_data"),
|
leaderboard_id=leaderboard_id,
|
||||||
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
version_number=version_number,
|
||||||
func.row_number().over(order_by=LeaderboardScores.score.desc()).label("number"),
|
)
|
||||||
).filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
|
||||||
|
query = (
|
||||||
|
db_session.query(
|
||||||
|
LeaderboardScores.address,
|
||||||
|
LeaderboardScores.score,
|
||||||
|
LeaderboardScores.points_data.label("points_data"),
|
||||||
|
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
||||||
|
func.row_number()
|
||||||
|
.over(order_by=LeaderboardScores.score.desc())
|
||||||
|
.label("number"),
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
LeaderboardVersion,
|
||||||
|
LeaderboardVersion.leaderboard_id == LeaderboardScores.leaderboard_id,
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
LeaderboardVersion.published == True,
|
||||||
|
LeaderboardVersion.version_number == latest_version,
|
||||||
|
)
|
||||||
|
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
||||||
|
)
|
||||||
|
|
||||||
ranked_leaderboard = query.cte(name="ranked_leaderboard")
|
ranked_leaderboard = query.cte(name="ranked_leaderboard")
|
||||||
|
|
||||||
|
@ -1130,11 +1193,25 @@ 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,
|
||||||
|
version_number: Optional[int] = None,
|
||||||
) -> List[Row[Tuple[uuid.UUID, str, int, str, int]]]:
|
) -> List[Row[Tuple[uuid.UUID, str, int, str, int]]]:
|
||||||
"""
|
"""
|
||||||
Get the leaderboard positions
|
Get the leaderboard positions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# get public leaderboard scores with max version
|
||||||
|
|
||||||
|
latest_version = leaderboard_version_filter(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version_number,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Main query
|
||||||
query = (
|
query = (
|
||||||
db_session.query(
|
db_session.query(
|
||||||
LeaderboardScores.id,
|
LeaderboardScores.id,
|
||||||
|
@ -1143,8 +1220,13 @@ def get_leaderboard_positions(
|
||||||
LeaderboardScores.points_data,
|
LeaderboardScores.points_data,
|
||||||
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
||||||
)
|
)
|
||||||
|
.join(
|
||||||
|
LeaderboardVersion,
|
||||||
|
LeaderboardVersion.leaderboard_id == LeaderboardScores.leaderboard_id,
|
||||||
|
)
|
||||||
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
||||||
.order_by(text("rank asc, id asc"))
|
.filter(LeaderboardVersion.published == True)
|
||||||
|
.filter(LeaderboardVersion.version_number == latest_version)
|
||||||
)
|
)
|
||||||
|
|
||||||
if limit:
|
if limit:
|
||||||
|
@ -1157,18 +1239,35 @@ def get_leaderboard_positions(
|
||||||
|
|
||||||
|
|
||||||
def get_qurtiles(
|
def get_qurtiles(
|
||||||
db_session: Session, leaderboard_id
|
db_session: Session, leaderboard_id, version_number: Optional[int] = None
|
||||||
) -> Tuple[Row[Tuple[str, float, int]], ...]:
|
) -> 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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
query = db_session.query(
|
latest_version = leaderboard_version_filter(
|
||||||
LeaderboardScores.address,
|
db_session=db_session,
|
||||||
LeaderboardScores.score,
|
leaderboard_id=leaderboard_id,
|
||||||
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
version_number=version_number,
|
||||||
).filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
)
|
||||||
|
|
||||||
|
query = (
|
||||||
|
db_session.query(
|
||||||
|
LeaderboardScores.address,
|
||||||
|
LeaderboardScores.score,
|
||||||
|
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
LeaderboardVersion,
|
||||||
|
LeaderboardVersion.leaderboard_id == LeaderboardScores.leaderboard_id,
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
LeaderboardVersion.published == True,
|
||||||
|
LeaderboardVersion.version_number == latest_version,
|
||||||
|
)
|
||||||
|
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
||||||
|
)
|
||||||
|
|
||||||
ranked_leaderboard = query.cte(name="ranked_leaderboard")
|
ranked_leaderboard = query.cte(name="ranked_leaderboard")
|
||||||
|
|
||||||
|
@ -1192,17 +1291,37 @@ def get_qurtiles(
|
||||||
return q1, q2, q3
|
return q1, q2, q3
|
||||||
|
|
||||||
|
|
||||||
def get_ranks(db_session: Session, leaderboard_id) -> List[Row[Tuple[int, int, int]]]:
|
def get_ranks(
|
||||||
|
db_session: Session, leaderboard_id, version_number: Optional[int] = None
|
||||||
|
) -> List[Row[Tuple[int, int, int]]]:
|
||||||
"""
|
"""
|
||||||
Get the leaderboard rank buckets(rank, size, score)
|
Get the leaderboard rank buckets(rank, size, score)
|
||||||
"""
|
"""
|
||||||
query = db_session.query(
|
|
||||||
LeaderboardScores.id,
|
latest_version = leaderboard_version_filter(
|
||||||
LeaderboardScores.address,
|
db_session=db_session,
|
||||||
LeaderboardScores.score,
|
leaderboard_id=leaderboard_id,
|
||||||
LeaderboardScores.points_data,
|
version_number=version_number,
|
||||||
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
)
|
||||||
).filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
|
||||||
|
query = (
|
||||||
|
db_session.query(
|
||||||
|
LeaderboardScores.id,
|
||||||
|
LeaderboardScores.address,
|
||||||
|
LeaderboardScores.score,
|
||||||
|
LeaderboardScores.points_data,
|
||||||
|
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
LeaderboardVersion,
|
||||||
|
LeaderboardVersion.leaderboard_id == LeaderboardScores.leaderboard_id,
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
LeaderboardVersion.published == True,
|
||||||
|
LeaderboardVersion.version_number == latest_version,
|
||||||
|
)
|
||||||
|
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
||||||
|
)
|
||||||
|
|
||||||
ranked_leaderboard = query.cte(name="ranked_leaderboard")
|
ranked_leaderboard = query.cte(name="ranked_leaderboard")
|
||||||
|
|
||||||
|
@ -1220,10 +1339,18 @@ def get_rank(
|
||||||
rank: int,
|
rank: int,
|
||||||
limit: Optional[int] = None,
|
limit: Optional[int] = None,
|
||||||
offset: Optional[int] = None,
|
offset: Optional[int] = None,
|
||||||
|
version_number: Optional[int] = None,
|
||||||
) -> List[Row[Tuple[uuid.UUID, str, int, str, int]]]:
|
) -> List[Row[Tuple[uuid.UUID, str, int, str, int]]]:
|
||||||
"""
|
"""
|
||||||
Get bucket in leaderboard by rank
|
Get bucket in leaderboard by rank
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
latest_version = leaderboard_version_filter(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version_number,
|
||||||
|
)
|
||||||
|
|
||||||
query = (
|
query = (
|
||||||
db_session.query(
|
db_session.query(
|
||||||
LeaderboardScores.id,
|
LeaderboardScores.id,
|
||||||
|
@ -1232,6 +1359,14 @@ def get_rank(
|
||||||
LeaderboardScores.points_data,
|
LeaderboardScores.points_data,
|
||||||
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
||||||
)
|
)
|
||||||
|
.join(
|
||||||
|
LeaderboardVersion,
|
||||||
|
LeaderboardVersion.leaderboard_id == LeaderboardScores.leaderboard_id,
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
LeaderboardVersion.published == True,
|
||||||
|
LeaderboardVersion.version_number == latest_version,
|
||||||
|
)
|
||||||
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
||||||
.order_by(text("rank asc, id asc"))
|
.order_by(text("rank asc, id asc"))
|
||||||
)
|
)
|
||||||
|
@ -1377,7 +1512,7 @@ def add_scores(
|
||||||
db_session: Session,
|
db_session: Session,
|
||||||
leaderboard_id: uuid.UUID,
|
leaderboard_id: uuid.UUID,
|
||||||
scores: List[Score],
|
scores: List[Score],
|
||||||
overwrite: bool = False,
|
version_number: int,
|
||||||
normalize_addresses: bool = True,
|
normalize_addresses: bool = True,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -1397,16 +1532,6 @@ def add_scores(
|
||||||
|
|
||||||
raise DuplicateLeaderboardAddressError("Dublicated addresses", duplicates)
|
raise DuplicateLeaderboardAddressError("Dublicated addresses", duplicates)
|
||||||
|
|
||||||
if overwrite:
|
|
||||||
db_session.query(LeaderboardScores).filter(
|
|
||||||
LeaderboardScores.leaderboard_id == leaderboard_id
|
|
||||||
).delete()
|
|
||||||
try:
|
|
||||||
db_session.commit()
|
|
||||||
except:
|
|
||||||
db_session.rollback()
|
|
||||||
raise LeaderboardDeleteScoresError("Error deleting leaderboard scores")
|
|
||||||
|
|
||||||
for score in scores:
|
for score in scores:
|
||||||
leaderboard_scores.append(
|
leaderboard_scores.append(
|
||||||
{
|
{
|
||||||
|
@ -1414,6 +1539,7 @@ def add_scores(
|
||||||
"address": normalizer_fn(score.address),
|
"address": normalizer_fn(score.address),
|
||||||
"score": score.score,
|
"score": score.score,
|
||||||
"points_data": score.points_data,
|
"points_data": score.points_data,
|
||||||
|
"leaderboard_version_number": version_number,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1675,3 +1801,137 @@ def check_leaderboard_resource_permissions(
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_leaderboard_version(
|
||||||
|
db_session: Session, leaderboard_id: uuid.UUID, version_number: int
|
||||||
|
) -> LeaderboardVersion:
|
||||||
|
"""
|
||||||
|
Get the leaderboard version by id
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
db_session.query(LeaderboardVersion)
|
||||||
|
.filter(LeaderboardVersion.leaderboard_id == leaderboard_id)
|
||||||
|
.filter(LeaderboardVersion.version_number == version_number)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_leaderboard_version(
|
||||||
|
db_session: Session,
|
||||||
|
leaderboard_id: uuid.UUID,
|
||||||
|
version_number: Optional[int] = None,
|
||||||
|
publish: bool = False,
|
||||||
|
) -> LeaderboardVersion:
|
||||||
|
"""
|
||||||
|
Create a leaderboard version
|
||||||
|
"""
|
||||||
|
|
||||||
|
if version_number is None:
|
||||||
|
latest_version_result = (
|
||||||
|
db_session.query(func.max(LeaderboardVersion.version_number))
|
||||||
|
.filter(LeaderboardVersion.leaderboard_id == leaderboard_id)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
|
latest_version = latest_version_result[0]
|
||||||
|
|
||||||
|
if latest_version is None:
|
||||||
|
version_number = 0
|
||||||
|
else:
|
||||||
|
version_number = latest_version + 1
|
||||||
|
|
||||||
|
leaderboard_version = LeaderboardVersion(
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version_number,
|
||||||
|
published=publish,
|
||||||
|
)
|
||||||
|
|
||||||
|
db_session.add(leaderboard_version)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
return leaderboard_version
|
||||||
|
|
||||||
|
|
||||||
|
def change_publish_leaderboard_version_status(
|
||||||
|
db_session: Session, leaderboard_id: uuid.UUID, version_number: int, published: bool
|
||||||
|
) -> LeaderboardVersion:
|
||||||
|
"""
|
||||||
|
Publish a leaderboard version
|
||||||
|
"""
|
||||||
|
leaderboard_version = (
|
||||||
|
db_session.query(LeaderboardVersion)
|
||||||
|
.filter(LeaderboardVersion.leaderboard_id == leaderboard_id)
|
||||||
|
.filter(LeaderboardVersion.version_number == version_number)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
|
leaderboard_version.published = published
|
||||||
|
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
return leaderboard_version
|
||||||
|
|
||||||
|
|
||||||
|
def get_leaderboard_versions(
|
||||||
|
db_session: Session, leaderboard_id: uuid.UUID
|
||||||
|
) -> List[LeaderboardVersion]:
|
||||||
|
"""
|
||||||
|
Get all leaderboard versions
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
db_session.query(LeaderboardVersion)
|
||||||
|
.filter(LeaderboardVersion.leaderboard_id == leaderboard_id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_leaderboard_version(
|
||||||
|
db_session: Session, leaderboard_id: uuid.UUID, version_number: int
|
||||||
|
) -> LeaderboardVersion:
|
||||||
|
"""
|
||||||
|
Delete a leaderboard version
|
||||||
|
"""
|
||||||
|
leaderboard_version = (
|
||||||
|
db_session.query(LeaderboardVersion)
|
||||||
|
.filter(LeaderboardVersion.leaderboard_id == leaderboard_id)
|
||||||
|
.filter(LeaderboardVersion.version_number == version_number)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
|
db_session.delete(leaderboard_version)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
return leaderboard_version
|
||||||
|
|
||||||
|
|
||||||
|
def get_leaderboard_version_scores(
|
||||||
|
db_session: Session,
|
||||||
|
leaderboard_id: uuid.UUID,
|
||||||
|
version_number: int,
|
||||||
|
limit: int,
|
||||||
|
offset: int,
|
||||||
|
) -> List[LeaderboardScores]:
|
||||||
|
"""
|
||||||
|
Get the leaderboard scores by version number
|
||||||
|
"""
|
||||||
|
|
||||||
|
query = (
|
||||||
|
db_session.query(
|
||||||
|
LeaderboardScores.id,
|
||||||
|
LeaderboardScores.address.label("address"),
|
||||||
|
LeaderboardScores.score.label("score"),
|
||||||
|
LeaderboardScores.points_data.label("points_data"),
|
||||||
|
func.rank().over(order_by=LeaderboardScores.score.desc()).label("rank"),
|
||||||
|
)
|
||||||
|
.filter(LeaderboardScores.leaderboard_id == leaderboard_id)
|
||||||
|
.filter(LeaderboardScores.leaderboard_version_number == version_number)
|
||||||
|
)
|
||||||
|
|
||||||
|
if limit:
|
||||||
|
query = query.limit(limit)
|
||||||
|
|
||||||
|
if offset:
|
||||||
|
query = query.offset(offset)
|
||||||
|
|
||||||
|
return query
|
||||||
|
|
|
@ -442,3 +442,11 @@ class LeaderboardConfigUpdate(BaseModel):
|
||||||
query_name: Optional[str] = None
|
query_name: Optional[str] = None
|
||||||
params: Dict[str, int]
|
params: Dict[str, int]
|
||||||
normalize_addresses: Optional[bool] = None
|
normalize_addresses: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
|
class LeaderboardVersion(BaseModel):
|
||||||
|
leaderboard_id: UUID
|
||||||
|
version: int
|
||||||
|
published: bool
|
||||||
|
created_at: datetime
|
||||||
|
updated_at: datetime
|
||||||
|
|
|
@ -94,6 +94,7 @@ async def leaderboard(
|
||||||
limit: int = Query(10),
|
limit: int = Query(10),
|
||||||
offset: int = Query(0),
|
offset: int = Query(0),
|
||||||
db_session: Session = Depends(db.yield_db_session),
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
|
version: Optional[str] = Query(None, description="Version of the leaderboard."),
|
||||||
) -> List[data.LeaderboardPosition]:
|
) -> List[data.LeaderboardPosition]:
|
||||||
"""
|
"""
|
||||||
Returns the leaderboard positions.
|
Returns the leaderboard positions.
|
||||||
|
@ -112,7 +113,7 @@ async def leaderboard(
|
||||||
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
leaderboard_positions = actions.get_leaderboard_positions(
|
leaderboard_positions = actions.get_leaderboard_positions(
|
||||||
db_session, leaderboard_id, limit, offset
|
db_session, leaderboard_id, limit, offset, version
|
||||||
)
|
)
|
||||||
result = [
|
result = [
|
||||||
data.LeaderboardPosition(
|
data.LeaderboardPosition(
|
||||||
|
@ -604,10 +605,6 @@ async def leaderboard_push_scores(
|
||||||
scores: List[data.Score] = Body(
|
scores: List[data.Score] = Body(
|
||||||
..., description="Scores to put to the leaderboard."
|
..., description="Scores to put to the leaderboard."
|
||||||
),
|
),
|
||||||
overwrite: bool = Query(
|
|
||||||
False,
|
|
||||||
description="If enabled, this will delete all current scores and replace them with the new scores provided.",
|
|
||||||
),
|
|
||||||
normalize_addresses: bool = Query(
|
normalize_addresses: bool = Query(
|
||||||
True, description="Normalize addresses to checksum."
|
True, description="Normalize addresses to checksum."
|
||||||
),
|
),
|
||||||
|
@ -635,13 +632,22 @@ async def leaderboard_push_scores(
|
||||||
status_code=403, detail="You don't have access to this leaderboard."
|
status_code=403, detail="You don't have access to this leaderboard."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_version = actions.create_leaderboard_version(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while creating leaderboard version: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
leaderboard_points = actions.add_scores(
|
leaderboard_points = actions.add_scores(
|
||||||
db_session=db_session,
|
db_session=db_session,
|
||||||
leaderboard_id=leaderboard_id,
|
leaderboard_id=leaderboard_id,
|
||||||
scores=scores,
|
scores=scores,
|
||||||
overwrite=overwrite,
|
|
||||||
normalize_addresses=normalize_addresses,
|
normalize_addresses=normalize_addresses,
|
||||||
|
version_number=new_version.version_number,
|
||||||
)
|
)
|
||||||
except actions.DuplicateLeaderboardAddressError as e:
|
except actions.DuplicateLeaderboardAddressError as e:
|
||||||
raise EngineHTTPException(
|
raise EngineHTTPException(
|
||||||
|
@ -658,6 +664,17 @@ async def leaderboard_push_scores(
|
||||||
logger.error(f"Score update failed with error: {e}")
|
logger.error(f"Score update failed with error: {e}")
|
||||||
raise EngineHTTPException(status_code=500, detail="Score update failed.")
|
raise EngineHTTPException(status_code=500, detail="Score update failed.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
actions.change_publish_leaderboard_version_status(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=new_version.version_number,
|
||||||
|
published=True,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while updating leaderboard version: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
result = [
|
result = [
|
||||||
data.LeaderboardScore(
|
data.LeaderboardScore(
|
||||||
leaderboard_id=score["leaderboard_id"],
|
leaderboard_id=score["leaderboard_id"],
|
||||||
|
@ -881,3 +898,420 @@ async def leaderboard_config_deactivate(
|
||||||
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(
|
||||||
|
"/{leaderboard_id}/versions",
|
||||||
|
response_model=List[data.LeaderboardVersion],
|
||||||
|
tags=["Authorized Endpoints"],
|
||||||
|
)
|
||||||
|
async def leaderboard_versions_list(
|
||||||
|
request: Request,
|
||||||
|
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||||
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
|
Authorization: str = AuthHeader,
|
||||||
|
) -> List[data.LeaderboardVersion]:
|
||||||
|
"""
|
||||||
|
Get leaderboard versions list.
|
||||||
|
"""
|
||||||
|
token = request.state.token
|
||||||
|
try:
|
||||||
|
access = actions.check_leaderboard_resource_permissions(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard version not found.",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not access:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=403, detail="You don't have access to this leaderboard version."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
leaderboard_versions = actions.get_leaderboard_versions(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while getting leaderboard versions list: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
|
result = [
|
||||||
|
data.LeaderboardVersion(
|
||||||
|
leaderboard_id=version.leaderboard_id,
|
||||||
|
version=version.version_number,
|
||||||
|
published=version.published,
|
||||||
|
created_at=version.created_at,
|
||||||
|
updated_at=version.updated_at,
|
||||||
|
)
|
||||||
|
for version in leaderboard_versions
|
||||||
|
]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(
|
||||||
|
"/{leaderboard_id}/versions/{version}",
|
||||||
|
response_model=data.LeaderboardVersion,
|
||||||
|
tags=["Authorized Endpoints"],
|
||||||
|
)
|
||||||
|
async def leaderboard_version_handler(
|
||||||
|
request: Request,
|
||||||
|
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||||
|
version: int = Path(..., description="Version of the leaderboard."),
|
||||||
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
|
Authorization: str = AuthHeader,
|
||||||
|
) -> data.LeaderboardVersion:
|
||||||
|
"""
|
||||||
|
Get leaderboard version.
|
||||||
|
"""
|
||||||
|
token = request.state.token
|
||||||
|
try:
|
||||||
|
access = actions.check_leaderboard_resource_permissions(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard not found.",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not access:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=403, detail="You don't have access to this leaderboard."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
leaderboard_version = actions.get_leaderboard_version(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version,
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard version not found.",
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while getting leaderboard version: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
|
return data.LeaderboardVersion(
|
||||||
|
leaderboard_id=leaderboard_version.leaderboard_id,
|
||||||
|
version=leaderboard_version.version_number,
|
||||||
|
published=leaderboard_version.published,
|
||||||
|
created_at=leaderboard_version.created_at,
|
||||||
|
updated_at=leaderboard_version.updated_at,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.post(
|
||||||
|
"/{leaderboard_id}/versions",
|
||||||
|
response_model=data.LeaderboardVersion,
|
||||||
|
tags=["Authorized Endpoints"],
|
||||||
|
)
|
||||||
|
async def create_leaderboard_version(
|
||||||
|
request: Request,
|
||||||
|
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||||
|
version: int = Query(..., description="Version of the leaderboard."),
|
||||||
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
|
Authorization: str = AuthHeader,
|
||||||
|
) -> data.LeaderboardVersion:
|
||||||
|
"""
|
||||||
|
Create leaderboard version.
|
||||||
|
"""
|
||||||
|
token = request.state.token
|
||||||
|
try:
|
||||||
|
access = actions.check_leaderboard_resource_permissions(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard not found.",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not access:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=403, detail="You don't have access to this leaderboard."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
leaderboard_version = actions.create_leaderboard_version(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version=version,
|
||||||
|
)
|
||||||
|
except BugoutResponseException as e:
|
||||||
|
raise EngineHTTPException(status_code=e.status_code, detail=e.detail)
|
||||||
|
except actions.LeaderboardConfigNotFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard config not found.",
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while creating leaderboard version: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
|
return leaderboard_version
|
||||||
|
|
||||||
|
|
||||||
|
@app.put(
|
||||||
|
"/{leaderboard_id}/versions/{version}",
|
||||||
|
response_model=data.LeaderboardVersion,
|
||||||
|
tags=["Authorized Endpoints"],
|
||||||
|
)
|
||||||
|
async def update_leaderboard_version_handler(
|
||||||
|
request: Request,
|
||||||
|
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||||
|
version: int = Path(..., description="Version of the leaderboard."),
|
||||||
|
publish: bool = Query(
|
||||||
|
False,
|
||||||
|
description="If enabled, this will publish the leaderboard version.",
|
||||||
|
),
|
||||||
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
|
Authorization: str = AuthHeader,
|
||||||
|
) -> data.LeaderboardVersion:
|
||||||
|
"""
|
||||||
|
Update leaderboard version.
|
||||||
|
"""
|
||||||
|
token = request.state.token
|
||||||
|
try:
|
||||||
|
access = actions.check_leaderboard_resource_permissions(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard version not found.",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not access:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=403, detail="You don't have access to this leaderboard version."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
leaderboard_version = actions.change_publish_leaderboard_version_status(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version,
|
||||||
|
published=publish,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while updating leaderboard version: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
|
return data.LeaderboardVersion(
|
||||||
|
leaderboard_id=leaderboard_version.leaderboard_id,
|
||||||
|
version=leaderboard_version.version_number,
|
||||||
|
published=leaderboard_version.published,
|
||||||
|
created_at=leaderboard_version.created_at,
|
||||||
|
updated_at=leaderboard_version.updated_at,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.delete(
|
||||||
|
"/{leaderboard_id}/versions/{version}",
|
||||||
|
response_model=data.LeaderboardVersion,
|
||||||
|
tags=["Authorized Endpoints"],
|
||||||
|
)
|
||||||
|
async def delete_leaderboard_version_handler(
|
||||||
|
request: Request,
|
||||||
|
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||||
|
version: int = Path(..., description="Version of the leaderboard."),
|
||||||
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
|
Authorization: str = AuthHeader,
|
||||||
|
) -> data.LeaderboardVersion:
|
||||||
|
"""
|
||||||
|
Delete leaderboard version.
|
||||||
|
"""
|
||||||
|
token = request.state.token
|
||||||
|
try:
|
||||||
|
access = actions.check_leaderboard_resource_permissions(
|
||||||
|
db_session=db_session, leaderboard_id=leaderboard_id, token=token
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard version not found.",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not access:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=403, detail="You don't have access to this leaderboard version."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
leaderboard_version = actions.delete_leaderboard_version(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version,
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard version not found.",
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while deleting leaderboard version: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
|
return data.LeaderboardVersion(
|
||||||
|
leaderboard_id=leaderboard_version.leaderboard_id,
|
||||||
|
version=leaderboard_version.version_number,
|
||||||
|
published=leaderboard_version.published,
|
||||||
|
created_at=leaderboard_version.created_at,
|
||||||
|
updated_at=leaderboard_version.updated_at,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(
|
||||||
|
"/{leaderboard_id}/versions/{version}/scores",
|
||||||
|
response_model=List[data.LeaderboardPosition],
|
||||||
|
tags=["Authorized Endpoints"],
|
||||||
|
)
|
||||||
|
async def leaderboard_version_scores_handler(
|
||||||
|
request: Request,
|
||||||
|
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||||
|
version: int = Path(..., description="Version of the leaderboard."),
|
||||||
|
limit: int = Query(10),
|
||||||
|
offset: int = Query(0),
|
||||||
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
|
Authorization: str = AuthHeader,
|
||||||
|
) -> List[data.LeaderboardPosition]:
|
||||||
|
"""
|
||||||
|
Get leaderboard version scores.
|
||||||
|
"""
|
||||||
|
token = request.state.token
|
||||||
|
try:
|
||||||
|
access = actions.check_leaderboard_resource_permissions(
|
||||||
|
db_session=db_session, leaderboard_id=leaderboard_id, token=token
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard version not found.",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not access:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=403, detail="You don't have access to this leaderboard version."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
leaderboard_version_scores = actions.get_leaderboard_version_scores(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version,
|
||||||
|
limit=limit,
|
||||||
|
offset=offset,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while getting leaderboard version scores: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
|
result = [
|
||||||
|
data.LeaderboardPosition(
|
||||||
|
address=score.address,
|
||||||
|
score=score.score,
|
||||||
|
rank=score.rank,
|
||||||
|
points_data=score.points_data,
|
||||||
|
)
|
||||||
|
for score in leaderboard_version_scores
|
||||||
|
]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@app.put(
|
||||||
|
"/{leaderboard_id}/versions/{version}/scores",
|
||||||
|
response_model=List[data.LeaderboardScore],
|
||||||
|
tags=["Authorized Endpoints"],
|
||||||
|
)
|
||||||
|
async def leaderboard_version_push_scores_handler(
|
||||||
|
request: Request,
|
||||||
|
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||||
|
version: int = Path(..., description="Version of the leaderboard."),
|
||||||
|
scores: List[data.Score] = Body(
|
||||||
|
..., description="Scores to put to the leaderboard version."
|
||||||
|
),
|
||||||
|
normalize_addresses: bool = Query(
|
||||||
|
True, description="Normalize addresses to checksum."
|
||||||
|
),
|
||||||
|
db_session: Session = Depends(db.yield_db_session),
|
||||||
|
Authorization: str = AuthHeader,
|
||||||
|
) -> List[data.LeaderboardScore]:
|
||||||
|
"""
|
||||||
|
Put the leaderboard version to the database.
|
||||||
|
"""
|
||||||
|
token = request.state.token
|
||||||
|
try:
|
||||||
|
access = actions.check_leaderboard_resource_permissions(
|
||||||
|
db_session=db_session, leaderboard_id=leaderboard_id, token=token
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard version not found.",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not access:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=403, detail="You don't have access to this leaderboard version."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
leaderboard_version = actions.get_leaderboard_version(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
version_number=version,
|
||||||
|
)
|
||||||
|
except NoResultFound as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Leaderboard version not found.",
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error while getting leaderboard version: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||||
|
|
||||||
|
try:
|
||||||
|
leaderboard_points = actions.add_scores(
|
||||||
|
db_session=db_session,
|
||||||
|
leaderboard_id=leaderboard_id,
|
||||||
|
scores=scores,
|
||||||
|
normalize_addresses=normalize_addresses,
|
||||||
|
version_number=leaderboard_version.version_number,
|
||||||
|
)
|
||||||
|
except actions.DuplicateLeaderboardAddressError as e:
|
||||||
|
raise EngineHTTPException(
|
||||||
|
status_code=409,
|
||||||
|
detail=f"Duplicates in push to database is disallowed.\n List of duplicates:{e.duplicates}.\n Please handle duplicates manualy.",
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Score update failed with error: {e}")
|
||||||
|
raise EngineHTTPException(status_code=500, detail="Score update failed.")
|
||||||
|
|
||||||
|
result = [
|
||||||
|
data.LeaderboardScore(
|
||||||
|
leaderboard_id=score["leaderboard_id"],
|
||||||
|
address=score["address"],
|
||||||
|
score=score["score"],
|
||||||
|
points_data=score["points_data"],
|
||||||
|
)
|
||||||
|
for score in leaderboard_points
|
||||||
|
]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
Ładowanie…
Reference in New Issue