kopia lustrzana https://github.com/bugout-dev/moonstream
Add initiate leaderboard config managment.
rodzic
502a7e21d3
commit
edae1f91a1
|
@ -1,10 +1,11 @@
|
|||
from datetime import datetime
|
||||
from collections import Counter
|
||||
from typing import List, Any, Optional, Dict, Union, Tuple
|
||||
import json
|
||||
from typing import List, Any, Optional, Dict, Union, Tuple, cast
|
||||
import uuid
|
||||
import logging
|
||||
|
||||
from bugout.data import BugoutResource
|
||||
from bugout.data import BugoutResource, BugoutSearchResult
|
||||
from eth_typing import Address
|
||||
from hexbytes import HexBytes
|
||||
import requests # type: ignore
|
||||
|
@ -15,7 +16,7 @@ from sqlalchemy.engine import Row
|
|||
from web3 import Web3
|
||||
from web3.types import ChecksumAddress
|
||||
|
||||
from .data import Score, LeaderboardScore
|
||||
from .data import Score, LeaderboardScore, LeaderboardConfigUpdate
|
||||
from .contracts import Dropper_interface, ERC20_interface, Terminus_interface
|
||||
from .models import (
|
||||
DropperClaimant,
|
||||
|
@ -26,11 +27,12 @@ from .models import (
|
|||
)
|
||||
from . import signatures
|
||||
from .settings import (
|
||||
bugout_client as bc,
|
||||
BLOCKCHAIN_WEB3_PROVIDERS,
|
||||
LEADERBOARD_RESOURCE_TYPE,
|
||||
MOONSTREAM_APPLICATION_ID,
|
||||
MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
||||
bugout_client as bc,
|
||||
MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID,
|
||||
)
|
||||
|
||||
|
||||
|
@ -77,6 +79,18 @@ class LeaderboardDeleteError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class LeaderboardConfigNotFound(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LeaderboardConfigAlreadyActive(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LeaderboardConfigAlreadyInactive(Exception):
|
||||
pass
|
||||
|
||||
|
||||
BATCH_SIGNATURE_PAGE_SIZE = 500
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -1491,6 +1505,119 @@ def list_leaderboards_resources(
|
|||
return query.all()
|
||||
|
||||
|
||||
def get_leaderboard_config_entry(
|
||||
leaderboard_id: uuid.UUID,
|
||||
) -> BugoutSearchResult:
|
||||
configs = bc.search(
|
||||
token=MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
||||
journal_id=MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID,
|
||||
query=f"#leaderboard_id:{leaderboard_id}",
|
||||
limit=1,
|
||||
)
|
||||
|
||||
results = cast(List[BugoutSearchResult], configs.results)
|
||||
|
||||
if len(configs.results) == 0 or results[0].content is None:
|
||||
raise LeaderboardConfigNotFound(
|
||||
f"Leaderboard config not found for {leaderboard_id}"
|
||||
)
|
||||
|
||||
return results[0]
|
||||
|
||||
|
||||
def get_leaderboard_config(
|
||||
leaderboard_id: uuid.UUID,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Return leaderboard config from leaderboard generator journal
|
||||
"""
|
||||
|
||||
entry = get_leaderboard_config_entry(leaderboard_id)
|
||||
|
||||
return json.loads(entry.content) # type: ignore
|
||||
|
||||
|
||||
def update_leaderboard_config(
|
||||
leaderboard_id: uuid.UUID, config: LeaderboardConfigUpdate
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Update leaderboard config in leaderboard generator journal
|
||||
|
||||
"""
|
||||
|
||||
entry_config = get_leaderboard_config_entry(leaderboard_id)
|
||||
|
||||
current_config = LeaderboardConfig(**json.loads(entry_config.content)) # type: ignore
|
||||
|
||||
new_params = config.params
|
||||
|
||||
for key, value in new_params.items():
|
||||
if key not in current_config.params:
|
||||
continue
|
||||
|
||||
current_config.params[key] = value
|
||||
|
||||
# we replace values of parameters that are not None
|
||||
|
||||
entry = bc.update_entry_content(
|
||||
token=MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
||||
journal_id=MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID,
|
||||
title=entry_config.title,
|
||||
entry_id=entry_config.entry_url.split("/")[-1],
|
||||
content=json.dumps(current_config.dict()),
|
||||
)
|
||||
|
||||
return json.loads(entry.content)
|
||||
|
||||
|
||||
def activate_leaderboard_config(
|
||||
leaderboard_id: uuid.UUID,
|
||||
):
|
||||
"""
|
||||
Add tag status:active to leaderboard config journal entry
|
||||
"""
|
||||
|
||||
entry_config = get_leaderboard_config_entry(leaderboard_id)
|
||||
|
||||
if "status:active" in entry_config.tags:
|
||||
raise LeaderboardConfigAlreadyActive(
|
||||
f"Leaderboard config {leaderboard_id} already active"
|
||||
)
|
||||
|
||||
bc.create_tags(
|
||||
token=MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
||||
journal_id=MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID,
|
||||
entry_id=entry_config.entry_url.split("/")[-1],
|
||||
tags=["status:active"],
|
||||
)
|
||||
|
||||
|
||||
def deactivate_leaderboard_config(
|
||||
leaderboard_id: uuid.UUID,
|
||||
):
|
||||
"""
|
||||
Remove tag status:active from leaderboard config journal entry
|
||||
"""
|
||||
|
||||
entry_config = get_leaderboard_config_entry(leaderboard_id)
|
||||
|
||||
if "status:active" not in entry_config.tags:
|
||||
raise LeaderboardConfigAlreadyInactive(
|
||||
f"Leaderboard config {leaderboard_id} not active"
|
||||
)
|
||||
|
||||
bc.delete_entries_tags(
|
||||
token=MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
||||
journal_id=MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID,
|
||||
entries_tags=[
|
||||
{
|
||||
"journal_entry_id": entry_config.entry_url.split("/")[-1],
|
||||
"tags": ["status:active"],
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def revoke_resource(
|
||||
db_session: Session, leaderboard_id: uuid.UUID
|
||||
) -> Optional[uuid.UUID]:
|
||||
|
|
|
@ -428,3 +428,16 @@ class LeaderboardDeletedResponse(BaseModel):
|
|||
class LeaderboardScoresChangesResponse(BaseModel):
|
||||
players_count: int
|
||||
date: datetime
|
||||
|
||||
|
||||
class LeaderboardConfig(BaseModel):
|
||||
leaderboard_id: UUID
|
||||
query_name: str
|
||||
params: Dict[str, int]
|
||||
normalize_addresses: bool
|
||||
|
||||
|
||||
class LeaderboardConfigUpdate(BaseModel):
|
||||
query_name: Optional[str] = None
|
||||
params: Dict[str, int]
|
||||
normalize_addresses: Optional[bool] = None
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
"""
|
||||
Leaderboard API.
|
||||
"""
|
||||
from datetime import datetime
|
||||
import logging
|
||||
from uuid import UUID
|
||||
|
||||
from bugout.exceptions import BugoutResponseException
|
||||
from web3 import Web3
|
||||
from fastapi import FastAPI, Request, Depends, Response, Query, Path, Body, Header
|
||||
from sqlalchemy.orm import Session
|
||||
|
@ -668,3 +668,215 @@ async def leaderboard_push_scores(
|
|||
]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@app.get(
|
||||
"/{leaderboard_id}/config",
|
||||
response_model=data.LeaderboardConfig,
|
||||
tags=["Authorized Endpoints"],
|
||||
)
|
||||
async def leaderboard_config(
|
||||
request: Request,
|
||||
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||
db_session: Session = Depends(db.yield_db_session),
|
||||
Authorization: str = AuthHeader,
|
||||
) -> data.LeaderboardConfig:
|
||||
"""
|
||||
Get leaderboard config.
|
||||
"""
|
||||
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_config = actions.get_leaderboard_config(
|
||||
leaderboard_id=leaderboard_id,
|
||||
)
|
||||
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 getting leaderboard config: {e}")
|
||||
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
return data.LeaderboardConfig(**leaderboard_config)
|
||||
|
||||
|
||||
@app.put(
|
||||
"/{leaderboard_id}/config",
|
||||
response_model=data.LeaderboardConfig,
|
||||
tags=["Authorized Endpoints"],
|
||||
)
|
||||
async def leaderboard_config_update(
|
||||
request: Request,
|
||||
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||
config: data.LeaderboardConfigUpdate = Body(..., description="Leaderboard config."),
|
||||
db_session: Session = Depends(db.yield_db_session),
|
||||
Authorization: str = AuthHeader,
|
||||
) -> data.LeaderboardConfig:
|
||||
"""
|
||||
Update leaderboard config.
|
||||
"""
|
||||
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_config = actions.update_leaderboard_config(
|
||||
leaderboard_id=leaderboard_id,
|
||||
config=config,
|
||||
)
|
||||
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 updating leaderboard config: {e}")
|
||||
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
return data.LeaderboardConfig(**leaderboard_config)
|
||||
|
||||
|
||||
@app.post(
|
||||
"/{leaderboard_id}/config/activate",
|
||||
response_model=bool,
|
||||
tags=["Authorized Endpoints"],
|
||||
)
|
||||
async def leaderboard_config_activate(
|
||||
request: Request,
|
||||
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||
db_session: Session = Depends(db.yield_db_session),
|
||||
Authorization: str = AuthHeader,
|
||||
) -> bool:
|
||||
"""
|
||||
Activate leaderboard config.
|
||||
"""
|
||||
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:
|
||||
actions.activate_leaderboard_config(
|
||||
leaderboard_id=leaderboard_id,
|
||||
)
|
||||
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 actions.LeaderboardConfigAlreadyActive as e:
|
||||
raise EngineHTTPException(
|
||||
status_code=409,
|
||||
detail="Leaderboard config is already active.",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error while activating leaderboard config: {e}")
|
||||
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@app.post(
|
||||
"/{leaderboard_id}/config/deactivate",
|
||||
response_model=bool,
|
||||
tags=["Authorized Endpoints"],
|
||||
)
|
||||
async def leaderboard_config_deactivate(
|
||||
request: Request,
|
||||
leaderboard_id: UUID = Path(..., description="Leaderboard ID"),
|
||||
db_session: Session = Depends(db.yield_db_session),
|
||||
Authorization: str = AuthHeader,
|
||||
) -> bool:
|
||||
"""
|
||||
Deactivate leaderboard config.
|
||||
"""
|
||||
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:
|
||||
actions.deactivate_leaderboard_config(
|
||||
leaderboard_id=leaderboard_id,
|
||||
)
|
||||
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 actions.LeaderboardConfigAlreadyInactive as e:
|
||||
raise EngineHTTPException(
|
||||
status_code=409,
|
||||
detail="Leaderboard config is already inactive.",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error while deactivating leaderboard config: {e}")
|
||||
raise EngineHTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
return True
|
||||
|
|
|
@ -198,3 +198,11 @@ if MOONSTREAM_ADMIN_ACCESS_TOKEN == "":
|
|||
MOONSTREAM_ADMIN_ID = os.environ.get("MOONSTREAM_ADMIN_ID", "")
|
||||
if MOONSTREAM_ADMIN_ID == "":
|
||||
raise ValueError("MOONSTREAM_ADMIN_ID environment variable must be set")
|
||||
|
||||
MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID = os.environ.get(
|
||||
"MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID", ""
|
||||
)
|
||||
if MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID == "":
|
||||
raise ValueError(
|
||||
"MOONSTREAM_LEADERBOARD_GENERATOR_JOURNAL_ID environment variable must be set"
|
||||
)
|
||||
|
|
Ładowanie…
Reference in New Issue