mirror of
https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
synced 2026-03-05 05:36:54 +08:00
✨ 添加冗余 platform 字段
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
"""Add redundant platform field
|
||||||
|
|
||||||
|
迁移 ID: 6c3206f90cc3
|
||||||
|
父迁移: 9f6582279ce2
|
||||||
|
创建时间: 2023-11-26 20:15:56.033892
|
||||||
|
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
from sqlalchemy.ext.automap import automap_base
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from ujson import dumps, loads
|
||||||
|
|
||||||
|
revision: str = '6c3206f90cc3'
|
||||||
|
down_revision: str | Sequence[str] | None = '9f6582279ce2'
|
||||||
|
branch_labels: str | Sequence[str] | None = None
|
||||||
|
depends_on: str | Sequence[str] | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(name: str = '') -> None:
|
||||||
|
if name:
|
||||||
|
return
|
||||||
|
|
||||||
|
Base = automap_base() # noqa: N806
|
||||||
|
connection = op.get_bind()
|
||||||
|
Base.prepare(autoload_with=connection)
|
||||||
|
|
||||||
|
HistoricalData = Base.classes.nonebot_plugin_tetris_stats_historicaldata # noqa: N806
|
||||||
|
|
||||||
|
with Session(connection) as session:
|
||||||
|
for row in session.query(HistoricalData):
|
||||||
|
platform = row.game_platform
|
||||||
|
game_user = loads(row.game_user)
|
||||||
|
processed_data = loads(row.processed_data)
|
||||||
|
game_user['platform'] = platform
|
||||||
|
processed_data['platform'] = platform
|
||||||
|
row.game_user = dumps(game_user)
|
||||||
|
row.processed_data = dumps(processed_data)
|
||||||
|
session.add(row)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(name: str = '') -> None:
|
||||||
|
if name:
|
||||||
|
return
|
||||||
|
|
||||||
|
Base = automap_base() # noqa: N806
|
||||||
|
connection = op.get_bind()
|
||||||
|
Base.prepare(autoload_with=connection)
|
||||||
|
|
||||||
|
HistoricalData = Base.classes.nonebot_plugin_tetris_stats_historicaldata # noqa: N806
|
||||||
|
|
||||||
|
with Session(connection) as session:
|
||||||
|
for row in session.query(HistoricalData):
|
||||||
|
game_user = loads(row.game_user)
|
||||||
|
processed_data = loads(row.processed_data)
|
||||||
|
game_user.pop('platform', None)
|
||||||
|
processed_data.pop('platform', None)
|
||||||
|
row.game_user = dumps(game_user)
|
||||||
|
row.processed_data = dumps(processed_data)
|
||||||
|
session.add(row)
|
||||||
|
session.commit()
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
from ...utils.typing import GameType
|
from typing import Literal
|
||||||
|
|
||||||
from .typing import Rank
|
from .typing import Rank
|
||||||
|
|
||||||
GAME_TYPE: GameType = 'IO'
|
GAME_TYPE: Literal['IO'] = 'IO'
|
||||||
BASE_URL = 'https://ch.tetr.io/api/'
|
BASE_URL = 'https://ch.tetr.io/api/'
|
||||||
RANK_PERCENTILE: dict[Rank, float] = {
|
RANK_PERCENTILE: dict[Rank, float] = {
|
||||||
'x': 1,
|
'x': 1,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from datetime import UTC, datetime, timedelta
|
|||||||
from math import floor
|
from math import floor
|
||||||
from re import match
|
from re import match
|
||||||
from statistics import mean
|
from statistics import mean
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
from nonebot import get_driver
|
from nonebot import get_driver
|
||||||
from nonebot_plugin_apscheduler import scheduler # type: ignore[import-untyped]
|
from nonebot_plugin_apscheduler import scheduler # type: ignore[import-untyped]
|
||||||
@@ -15,7 +16,6 @@ from ...db import create_or_update_bind
|
|||||||
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
|
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
|
||||||
from ...utils.request import splice_url
|
from ...utils.request import splice_url
|
||||||
from ...utils.retry import retry
|
from ...utils.retry import retry
|
||||||
from ...utils.typing import GameType
|
|
||||||
from .. import Processor as ProcessorMeta
|
from .. import Processor as ProcessorMeta
|
||||||
from .cache import Cache
|
from .cache import Cache
|
||||||
from .constant import BASE_URL, GAME_TYPE, RANK_PERCENTILE
|
from .constant import BASE_URL, GAME_TYPE, RANK_PERCENTILE
|
||||||
@@ -55,7 +55,7 @@ class Processor(ProcessorMeta):
|
|||||||
self.processed_data = ProcessedData()
|
self.processed_data = ProcessedData()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def game_platform(self) -> GameType:
|
def game_platform(self) -> Literal['IO']:
|
||||||
return GAME_TYPE
|
return GAME_TYPE
|
||||||
|
|
||||||
async def handle_bind(self, platform: str, account: str) -> str:
|
async def handle_bind(self, platform: str, account: str) -> str:
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
|
from typing import Literal
|
||||||
|
|
||||||
from ... import ProcessedData as ProcessedDataMeta
|
from ... import ProcessedData as ProcessedDataMeta
|
||||||
from ... import RawResponse as RawResponseMeta
|
from ... import RawResponse as RawResponseMeta
|
||||||
|
from ..constant import GAME_TYPE
|
||||||
from .user_info import SuccessModel as InfoSuccess
|
from .user_info import SuccessModel as InfoSuccess
|
||||||
from .user_records import SuccessModel as RecordsSuccess
|
from .user_records import SuccessModel as RecordsSuccess
|
||||||
|
|
||||||
|
|
||||||
class RawResponse(RawResponseMeta):
|
class RawResponse(RawResponseMeta):
|
||||||
|
platform: Literal['IO'] = GAME_TYPE
|
||||||
|
|
||||||
user_info: bytes | None = None
|
user_info: bytes | None = None
|
||||||
user_records: bytes | None = None
|
user_records: bytes | None = None
|
||||||
|
|
||||||
|
|
||||||
class ProcessedData(ProcessedDataMeta):
|
class ProcessedData(ProcessedDataMeta):
|
||||||
|
platform: Literal['IO'] = GAME_TYPE
|
||||||
|
|
||||||
user_info: InfoSuccess | None = None
|
user_info: InfoSuccess | None = None
|
||||||
user_records: RecordsSuccess | None = None
|
user_records: RecordsSuccess | None = None
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
|
from typing import Literal
|
||||||
|
|
||||||
from ...schemas import BaseUser
|
from ...schemas import BaseUser
|
||||||
|
from ..constant import GAME_TYPE
|
||||||
|
|
||||||
|
|
||||||
class User(BaseUser):
|
class User(BaseUser):
|
||||||
|
platform: Literal['IO'] = GAME_TYPE
|
||||||
|
|
||||||
ID: str | None = None
|
ID: str | None = None
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,14 @@ from abc import ABC, abstractmethod
|
|||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from ..utils.typing import GameType
|
||||||
|
|
||||||
class BaseUser(ABC, BaseModel):
|
|
||||||
|
class Base(BaseModel):
|
||||||
|
platform: GameType
|
||||||
|
|
||||||
|
|
||||||
|
class BaseUser(ABC, Base):
|
||||||
"""游戏用户"""
|
"""游戏用户"""
|
||||||
|
|
||||||
def __eq__(self, __value: object) -> bool:
|
def __eq__(self, __value: object) -> bool:
|
||||||
@@ -17,9 +23,9 @@ class BaseUser(ABC, BaseModel):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class BaseRawResponse(BaseModel):
|
class BaseRawResponse(Base):
|
||||||
"""原始请求数据"""
|
"""原始请求数据"""
|
||||||
|
|
||||||
|
|
||||||
class BaseProcessedData(BaseModel):
|
class BaseProcessedData(Base):
|
||||||
"""处理/验证后的数据"""
|
"""处理/验证后的数据"""
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from ...utils.typing import GameType
|
from typing import Literal
|
||||||
|
|
||||||
GAME_TYPE: GameType = 'TOP'
|
GAME_TYPE: Literal['TOP'] = 'TOP'
|
||||||
BASE_URL = 'http://tetrisonline.pl/top/'
|
BASE_URL = 'http://tetrisonline.pl/top/'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from contextlib import suppress
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from re import match
|
from re import match
|
||||||
from typing import NoReturn
|
from typing import Literal, NoReturn
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
@@ -12,7 +12,6 @@ from pandas import read_html
|
|||||||
from ...db import create_or_update_bind
|
from ...db import create_or_update_bind
|
||||||
from ...utils.exception import MessageFormatError, RequestError
|
from ...utils.exception import MessageFormatError, RequestError
|
||||||
from ...utils.request import Request, splice_url
|
from ...utils.request import Request, splice_url
|
||||||
from ...utils.typing import GameType
|
|
||||||
from .. import Processor as ProcessorMeta
|
from .. import Processor as ProcessorMeta
|
||||||
from ..schemas import BaseUser
|
from ..schemas import BaseUser
|
||||||
from .constant import BASE_URL, GAME_TYPE
|
from .constant import BASE_URL, GAME_TYPE
|
||||||
@@ -20,6 +19,8 @@ from .schemas.response import ProcessedData, RawResponse
|
|||||||
|
|
||||||
|
|
||||||
class User(BaseUser):
|
class User(BaseUser):
|
||||||
|
platform: Literal['TOP'] = GAME_TYPE
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -56,7 +57,7 @@ class Processor(ProcessorMeta):
|
|||||||
self.processed_data = ProcessedData()
|
self.processed_data = ProcessedData()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def game_platform(self) -> GameType:
|
def game_platform(self) -> Literal['TOP']:
|
||||||
return GAME_TYPE
|
return GAME_TYPE
|
||||||
|
|
||||||
async def handle_bind(self, platform: str, account: str) -> str:
|
async def handle_bind(self, platform: str, account: str) -> str:
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
|
from typing import Literal
|
||||||
|
|
||||||
from ...schemas import BaseProcessedData, BaseRawResponse
|
from ...schemas import BaseProcessedData, BaseRawResponse
|
||||||
|
from ..constant import GAME_TYPE
|
||||||
|
|
||||||
|
|
||||||
class RawResponse(BaseRawResponse):
|
class RawResponse(BaseRawResponse):
|
||||||
|
platform: Literal['TOP'] = GAME_TYPE
|
||||||
|
|
||||||
user_profile: bytes | None = None
|
user_profile: bytes | None = None
|
||||||
|
|
||||||
|
|
||||||
class ProcessedData(BaseProcessedData):
|
class ProcessedData(BaseProcessedData):
|
||||||
|
platform: Literal['TOP'] = GAME_TYPE
|
||||||
|
|
||||||
user_profile: str | None = None
|
user_profile: str | None = None
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from ...utils.typing import GameType
|
from typing import Literal
|
||||||
|
|
||||||
GAME_TYPE: GameType = 'TOS'
|
GAME_TYPE: Literal['TOS'] = 'TOS'
|
||||||
BASE_URL = 'https://teatube.cn:8888/'
|
BASE_URL = 'https://teatube.cn:8888/'
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from re import match
|
from re import match
|
||||||
|
from typing import Literal
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from nonebot_plugin_orm import get_session
|
from nonebot_plugin_orm import get_session
|
||||||
@@ -8,7 +9,6 @@ from pydantic import parse_raw_as
|
|||||||
from ...db import create_or_update_bind
|
from ...db import create_or_update_bind
|
||||||
from ...utils.exception import MessageFormatError, RequestError
|
from ...utils.exception import MessageFormatError, RequestError
|
||||||
from ...utils.request import Request, splice_url
|
from ...utils.request import Request, splice_url
|
||||||
from ...utils.typing import GameType
|
|
||||||
from .. import Processor as ProcessorMeta
|
from .. import Processor as ProcessorMeta
|
||||||
from ..schemas import BaseUser
|
from ..schemas import BaseUser
|
||||||
from .constant import BASE_URL, GAME_TYPE
|
from .constant import BASE_URL, GAME_TYPE
|
||||||
@@ -19,6 +19,8 @@ from .schemas.user_profile import UserProfile
|
|||||||
|
|
||||||
|
|
||||||
class User(BaseUser):
|
class User(BaseUser):
|
||||||
|
platform: Literal['TOS'] = GAME_TYPE
|
||||||
|
|
||||||
teaid: str | None = None
|
teaid: str | None = None
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
|
|
||||||
@@ -67,7 +69,7 @@ class Processor(ProcessorMeta):
|
|||||||
self.processed_data = ProcessedData(user_profile={})
|
self.processed_data = ProcessedData(user_profile={})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def game_platform(self) -> GameType:
|
def game_platform(self) -> Literal['TOS']:
|
||||||
return GAME_TYPE
|
return GAME_TYPE
|
||||||
|
|
||||||
async def handle_bind(self, platform: str, account: str) -> str:
|
async def handle_bind(self, platform: str, account: str) -> str:
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
|
from typing import Literal
|
||||||
|
|
||||||
from ...schemas import BaseProcessedData, BaseRawResponse
|
from ...schemas import BaseProcessedData, BaseRawResponse
|
||||||
|
from ..constant import GAME_TYPE
|
||||||
from .user_info import SuccessModel as InfoSuccess
|
from .user_info import SuccessModel as InfoSuccess
|
||||||
from .user_profile import UserProfile
|
from .user_profile import UserProfile
|
||||||
|
|
||||||
|
|
||||||
class RawResponse(BaseRawResponse):
|
class RawResponse(BaseRawResponse):
|
||||||
|
platform: Literal['TOS'] = GAME_TYPE
|
||||||
|
|
||||||
user_profile: dict[str, bytes]
|
user_profile: dict[str, bytes]
|
||||||
user_info: bytes | None = None
|
user_info: bytes | None = None
|
||||||
|
|
||||||
|
|
||||||
class ProcessedData(BaseProcessedData):
|
class ProcessedData(BaseProcessedData):
|
||||||
|
platform: Literal['TOS'] = GAME_TYPE
|
||||||
|
|
||||||
user_profile: dict[str, UserProfile]
|
user_profile: dict[str, UserProfile]
|
||||||
user_info: InfoSuccess | None = None
|
user_info: InfoSuccess | None = None
|
||||||
|
|||||||
Reference in New Issue
Block a user