"""Base data models for API requests and response. These models are used to define the structure of the requests and responses from the API. They use Mashumaro for serialization and deserialization. The `DataClassConfigMixin` class sets default options for `orjson` and `Mashumaro`. Note: Dataclasses should follow the naming convention of Request/Response + API Name. Internal models can have any descriptive name. All models should inherit `ResponseBaseModel` or `RequestBaseModel`. Use [pyvesync.const][pyvesync.const] to set default values and import here. Attributes are inherited from the [const][pyvesync.const] module for default values. """ from __future__ import annotations from dataclasses import dataclass from time import time from typing import ClassVar import orjson from mashumaro.config import BaseConfig from mashumaro.mixins.orjson import DataClassORJSONMixin from pyvesync.const import ( APP_ID, APP_VERSION, BYPASS_HEADER_UA, CLIENT_TYPE, DEFAULT_LANGUAGE, DEFAULT_REGION, DEFAULT_TZ, MOBILE_ID, PHONE_BRAND, PHONE_OS, TERMINAL_ID, USER_TYPE, ) RequestHeaders = { 'User-Agent': BYPASS_HEADER_UA, 'Content-Type': 'application/json; charset=UTF-8', } class BaseModelConfig(BaseConfig): """Base config for dataclasses.""" orjson_options = orjson.OPT_NON_STR_KEYS @dataclass class RequestBaseModel(DataClassORJSONMixin): """Base request model for API requests. Forbids extra keys in the request JSON. """ class Config(BaseModelConfig): """orjson config for dataclasses.""" forbid_extra_keys = True orjson_options = orjson.OPT_NON_STR_KEYS @dataclass class ResponseBaseModel(DataClassORJSONMixin): """Base response model for API responses. Allows extra keys in the response model and non-string keys in the JSON. """ class Config(BaseConfig): """Config for dataclasses.""" orjson_options = orjson.OPT_NON_STR_KEYS forbid_extra_keys = False @dataclass class DefaultValues: """Default request fields. Attributes for the default values of the request fields and static methods for preparing calculated fields. """ _call_number: ClassVar[int] = 0 userType: str = USER_TYPE appVersion: str = APP_VERSION clientType: str = CLIENT_TYPE appId: str = APP_ID phoneBrand: str = PHONE_BRAND phoneOS: str = PHONE_OS mobileId: str = MOBILE_ID deviceRegion: str = DEFAULT_REGION countryCode: str = DEFAULT_REGION userCountryCode: str = DEFAULT_REGION acceptLanguage: str = DEFAULT_LANGUAGE timeZone: str = DEFAULT_TZ terminalId: str = TERMINAL_ID debugMode: bool = False @staticmethod def traceId() -> str: """Trace ID CSRF token.""" return str(int(time())) @staticmethod def newTraceId() -> str: """Generate a new trace ID.""" DefaultValues._call_number += 1 return f'APP{TERMINAL_ID[-5:-1]}{int(time())}-{DefaultValues._call_number:0>5}' @dataclass class ResponseCodeModel(ResponseBaseModel): """Model for the 'result' field in response.""" traceId: str code: int msg: str | None