mirror of
https://github.com/remnawave/python-sdk.git
synced 2026-05-13 12:16:42 +00:00
Merge pull request #28 from remnawave:development
Update API versions and add new models for HWID and users
This commit is contained in:
commit
95a93d72d5
13 changed files with 220 additions and 19 deletions
|
|
@ -63,7 +63,8 @@ pip install git+https://github.com/remnawave/python-sdk.git@development
|
||||||
|
|
||||||
| Contract Version | Remnawave Panel Version |
|
| Contract Version | Remnawave Panel Version |
|
||||||
| ---------------- | ----------------------- |
|
| ---------------- | ----------------------- |
|
||||||
| 2.3.0 | >=2.3.0 |
|
| 2.3.2 | >=2.3.0 |
|
||||||
|
| 2.3.0 | >=2.3.0, <2.3.2 |
|
||||||
| 2.2.6 | ==2.2.6 |
|
| 2.2.6 | ==2.2.6 |
|
||||||
| 2.2.3 | >=2.2.13 |
|
| 2.2.3 | >=2.2.13 |
|
||||||
| 2.1.19 | >=2.1.19, <2.2.0 |
|
| 2.1.19 | >=2.1.19, <2.2.0 |
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
[project]
|
[project]
|
||||||
name = "remnawave"
|
name = "remnawave"
|
||||||
version = "2.3.0"
|
version = "2.3.2"
|
||||||
description = "A Python SDK for interacting with the Remnawave API v2.3.0."
|
description = "A Python SDK for interacting with the Remnawave API v2.3.2."
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Artem",email = "dev@forestsnet.com"}
|
{name = "Artem",email = "dev@forestsnet.com"}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Annotated
|
from typing import Annotated, Optional
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from remnawave.models import (
|
from remnawave.models import (
|
||||||
|
|
@ -8,9 +8,10 @@ from remnawave.models import (
|
||||||
GetHwidStatisticsResponseDto,
|
GetHwidStatisticsResponseDto,
|
||||||
CreateHWIDUser,
|
CreateHWIDUser,
|
||||||
HWIDDeleteRequest,
|
HWIDDeleteRequest,
|
||||||
DeleteUserAllHwidDeviceRequestDto
|
DeleteUserAllHwidDeviceRequestDto,
|
||||||
|
GetTopUsersByHwidDevicesResponseDto
|
||||||
)
|
)
|
||||||
from rapid_api_client import Path, PydanticBody
|
from rapid_api_client import Path, PydanticBody, Query
|
||||||
from remnawave.rapid import AttributeBody, BaseController, post, get
|
from remnawave.rapid import AttributeBody, BaseController, post, get
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -62,3 +63,12 @@ class HWIDUserController(BaseController):
|
||||||
) -> GetUserHwidDevicesResponseDto:
|
) -> GetUserHwidDevicesResponseDto:
|
||||||
"""Get a user HWID device"""
|
"""Get a user HWID device"""
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@get("/hwid/devices/top-users", response_class=GetTopUsersByHwidDevicesResponseDto)
|
||||||
|
async def get_top_users_by_hwid_devices(
|
||||||
|
self,
|
||||||
|
size: Annotated[Optional[int], Query(default=None, description="Page size for pagination")] = None,
|
||||||
|
start: Annotated[Optional[int], Query(default=None, description="Offset for pagination")] = None,
|
||||||
|
) -> GetTopUsersByHwidDevicesResponseDto:
|
||||||
|
"""Get top users by HWID devices"""
|
||||||
|
...
|
||||||
|
|
@ -84,7 +84,10 @@ from .hwid import (
|
||||||
HWIDUserResponseDto, # Legacy alias
|
HWIDUserResponseDto, # Legacy alias
|
||||||
HWIDUserResponseDtoList, # Legacy alias
|
HWIDUserResponseDtoList, # Legacy alias
|
||||||
GetHwidStatisticsResponseDto,
|
GetHwidStatisticsResponseDto,
|
||||||
DeleteUserAllHwidDeviceRequestDto
|
DeleteUserAllHwidDeviceRequestDto,
|
||||||
|
GetTopUsersByHwidDevicesResponseDto,
|
||||||
|
TopUserByHwidDevicesDto,
|
||||||
|
TopUsersByHwidDevicesData,
|
||||||
)
|
)
|
||||||
from .inbounds import (
|
from .inbounds import (
|
||||||
AllInboundsData,
|
AllInboundsData,
|
||||||
|
|
@ -351,6 +354,7 @@ from .webhook import (
|
||||||
CustomErrorEventDto,
|
CustomErrorEventDto,
|
||||||
CrmEventDto,
|
CrmEventDto,
|
||||||
WebhookPayloadDto,
|
WebhookPayloadDto,
|
||||||
|
UserTrafficDto
|
||||||
)
|
)
|
||||||
from .passkeys import (
|
from .passkeys import (
|
||||||
DeletePasskeyRequestDto,
|
DeletePasskeyRequestDto,
|
||||||
|
|
@ -545,6 +549,9 @@ __all__ = [
|
||||||
"HWIDUserResponseDtoList", # Legacy alias
|
"HWIDUserResponseDtoList", # Legacy alias
|
||||||
"GetHwidStatisticsResponseDto",
|
"GetHwidStatisticsResponseDto",
|
||||||
"DeleteUserAllHwidDeviceRequestDto",
|
"DeleteUserAllHwidDeviceRequestDto",
|
||||||
|
"GetTopUsersByHwidDevicesResponseDto",
|
||||||
|
"TopUserByHwidDevicesDto",
|
||||||
|
"TopUsersByHwidDevicesData",
|
||||||
# Bandwidth stats models
|
# Bandwidth stats models
|
||||||
"GetNodeUserUsageByRangeResponseDto",
|
"GetNodeUserUsageByRangeResponseDto",
|
||||||
"GetNodesRealtimeUsageResponseDto",
|
"GetNodesRealtimeUsageResponseDto",
|
||||||
|
|
@ -712,6 +719,7 @@ __all__ = [
|
||||||
"BaseUserDto",
|
"BaseUserDto",
|
||||||
"UserDto",
|
"UserDto",
|
||||||
"UserEventDto",
|
"UserEventDto",
|
||||||
|
"UserTrafficDto",
|
||||||
|
|
||||||
# HWID DEVICES
|
# HWID DEVICES
|
||||||
"HwidUserDeviceDto",
|
"HwidUserDeviceDto",
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,14 @@ class NodesUsageResponseDto(RootModel[List[NodeUsageResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class GetNodesUsageByRangeResponseDto(RootModel[List[NodeUsageResponseDto]]):
|
class GetNodesUsageByRangeResponseDto(RootModel[List[NodeUsageResponseDto]]):
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
|
|
@ -32,6 +40,14 @@ class GetNodesUsageByRangeResponseDto(RootModel[List[NodeUsageResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class NodeRealtimeUsageResponseDto(BaseModel):
|
class NodeRealtimeUsageResponseDto(BaseModel):
|
||||||
node_uuid: UUID = Field(alias="nodeUuid")
|
node_uuid: UUID = Field(alias="nodeUuid")
|
||||||
|
|
@ -52,6 +68,14 @@ class NodesRealtimeUsageResponseDto(RootModel[List[NodeRealtimeUsageResponseDto]
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class GetNodesRealtimeUsageResponseDto(RootModel[List[NodeRealtimeUsageResponseDto]]):
|
class GetNodesRealtimeUsageResponseDto(RootModel[List[NodeRealtimeUsageResponseDto]]):
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
|
|
@ -60,6 +84,14 @@ class GetNodesRealtimeUsageResponseDto(RootModel[List[NodeRealtimeUsageResponseD
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class UserUsageByRangeItem(BaseModel):
|
class UserUsageByRangeItem(BaseModel):
|
||||||
user_uuid: UUID = Field(alias="userUuid")
|
user_uuid: UUID = Field(alias="userUuid")
|
||||||
|
|
@ -76,6 +108,14 @@ class GetUserUsageByRangeResponseDto(RootModel[List[UserUsageByRangeItem]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class NodeUserUsageItem(BaseModel):
|
class NodeUserUsageItem(BaseModel):
|
||||||
user_uuid: UUID = Field(alias="userUuid")
|
user_uuid: UUID = Field(alias="userUuid")
|
||||||
|
|
@ -91,3 +131,11 @@ class GetNodeUserUsageByRangeResponseDto(RootModel[List[NodeUserUsageItem]]):
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,6 @@ class ExternalSquadSubscriptionSettingsDto(BaseModel):
|
||||||
happ_routing: Optional[str] = Field(None, alias="happRouting")
|
happ_routing: Optional[str] = Field(None, alias="happRouting")
|
||||||
randomize_hosts: bool = Field(alias="randomizeHosts")
|
randomize_hosts: bool = Field(alias="randomizeHosts")
|
||||||
|
|
||||||
|
|
||||||
# НОВЫЕ МОДЕЛИ
|
|
||||||
class ExternalSquadHostOverridesDto(BaseModel):
|
class ExternalSquadHostOverridesDto(BaseModel):
|
||||||
"""External squad host overrides"""
|
"""External squad host overrides"""
|
||||||
server_description: Optional[str] = Field(None, alias="serverDescription", max_length=30)
|
server_description: Optional[str] = Field(None, alias="serverDescription", max_length=30)
|
||||||
|
|
@ -61,7 +59,7 @@ class ExternalSquadDto(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
# Request/Response models
|
# Request/Response models
|
||||||
class GetExternalSquadsResponseDto(ExternalSquadDto):
|
class GetExternalSquadsResponseDto(BaseModel):
|
||||||
"""Response with all external squads"""
|
"""Response with all external squads"""
|
||||||
total: int = Field(alias="total")
|
total: int = Field(alias="total")
|
||||||
external_squads: List[ExternalSquadDto] = Field(alias="externalSquads")
|
external_squads: List[ExternalSquadDto] = Field(alias="externalSquads")
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ class UpdateHostRequestDto(BaseModel):
|
||||||
tag: Optional[Annotated[str, StringConstraints(max_length=32, pattern=r"^[A-Z0-9_:]+$")]] = None
|
tag: Optional[Annotated[str, StringConstraints(max_length=32, pattern=r"^[A-Z0-9_:]+$")]] = None
|
||||||
is_hidden: Optional[bool] = Field(None, serialization_alias="isHidden")
|
is_hidden: Optional[bool] = Field(None, serialization_alias="isHidden")
|
||||||
override_sni_from_address: Optional[bool] = Field(None, serialization_alias="overrideSniFromAddress")
|
override_sni_from_address: Optional[bool] = Field(None, serialization_alias="overrideSniFromAddress")
|
||||||
|
keep_blank_sni: Optional[bool] = Field(None, serialization_alias="keepBlankSni")
|
||||||
vless_route_id: Optional[int] = Field(None, serialization_alias="vlessRouteId", ge=0, le=65535)
|
vless_route_id: Optional[int] = Field(None, serialization_alias="vlessRouteId", ge=0, le=65535)
|
||||||
shuffle_host: Optional[bool] = Field(None, serialization_alias="shuffleHost")
|
shuffle_host: Optional[bool] = Field(None, serialization_alias="shuffleHost")
|
||||||
mihomo_x25519: Optional[bool] = Field(None, serialization_alias="mihomoX25519")
|
mihomo_x25519: Optional[bool] = Field(None, serialization_alias="mihomoX25519")
|
||||||
|
|
@ -83,6 +84,7 @@ class HostResponseDto(BaseModel):
|
||||||
security_layer: SecurityLayer = Field(SecurityLayer.DEFAULT, alias="securityLayer")
|
security_layer: SecurityLayer = Field(SecurityLayer.DEFAULT, alias="securityLayer")
|
||||||
is_hidden: bool = Field(False, alias="isHidden")
|
is_hidden: bool = Field(False, alias="isHidden")
|
||||||
override_sni_from_address: bool = Field(False, alias="overrideSniFromAddress")
|
override_sni_from_address: bool = Field(False, alias="overrideSniFromAddress")
|
||||||
|
keep_blank_sni: bool = Field(False, alias="keepBlankSni")
|
||||||
allow_insecure: bool = Field(False, alias="allowInsecure")
|
allow_insecure: bool = Field(False, alias="allowInsecure")
|
||||||
xray_json_template_uuid: Optional[UUID] = Field(None, alias="xrayJsonTemplateUuid")
|
xray_json_template_uuid: Optional[UUID] = Field(None, alias="xrayJsonTemplateUuid")
|
||||||
excluded_internal_squads: List[UUID] = Field(default_factory=list, alias="excludedInternalSquads")
|
excluded_internal_squads: List[UUID] = Field(default_factory=list, alias="excludedInternalSquads")
|
||||||
|
|
@ -116,6 +118,7 @@ class CreateHostRequestDto(BaseModel):
|
||||||
security_layer: SecurityLayer = Field(SecurityLayer.DEFAULT, serialization_alias="securityLayer")
|
security_layer: SecurityLayer = Field(SecurityLayer.DEFAULT, serialization_alias="securityLayer")
|
||||||
is_hidden: bool = Field(False, serialization_alias="isHidden")
|
is_hidden: bool = Field(False, serialization_alias="isHidden")
|
||||||
override_sni_from_address: bool = Field(False, serialization_alias="overrideSniFromAddress")
|
override_sni_from_address: bool = Field(False, serialization_alias="overrideSniFromAddress")
|
||||||
|
keep_blank_sni: bool = Field(False, serialization_alias="keepBlankSni")
|
||||||
xray_json_template_uuid: Optional[UUID] = Field(None, serialization_alias="xrayJsonTemplateUuid")
|
xray_json_template_uuid: Optional[UUID] = Field(None, serialization_alias="xrayJsonTemplateUuid")
|
||||||
excluded_internal_squads: List[UUID] = Field(default_factory=list, serialization_alias="excludedInternalSquads")
|
excluded_internal_squads: List[UUID] = Field(default_factory=list, serialization_alias="excludedInternalSquads")
|
||||||
|
|
||||||
|
|
@ -162,6 +165,14 @@ class GetAllHostsResponseDto(RootModel[List[HostResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class GetOneHostResponseDto(HostResponseDto):
|
class GetOneHostResponseDto(HostResponseDto):
|
||||||
"""Get one host response"""
|
"""Get one host response"""
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,24 @@ class GetHwidStatisticsResponseDto(HwidStatisticsData):
|
||||||
class DeleteUserAllHwidDeviceRequestDto(BaseModel):
|
class DeleteUserAllHwidDeviceRequestDto(BaseModel):
|
||||||
user_uuid: UUID = Field(serialization_alias="userUuid")
|
user_uuid: UUID = Field(serialization_alias="userUuid")
|
||||||
|
|
||||||
|
class TopUserByHwidDevicesDto(BaseModel):
|
||||||
|
"""Top user by HWID devices"""
|
||||||
|
user_uuid: UUID = Field(alias="userUuid")
|
||||||
|
id: int
|
||||||
|
username: str
|
||||||
|
devices_count: int = Field(alias="devicesCount")
|
||||||
|
|
||||||
|
|
||||||
|
class TopUsersByHwidDevicesData(BaseModel):
|
||||||
|
"""Top users by HWID devices data"""
|
||||||
|
users: list[TopUserByHwidDevicesDto]
|
||||||
|
total: int
|
||||||
|
|
||||||
|
|
||||||
|
class GetTopUsersByHwidDevicesResponseDto(TopUsersByHwidDevicesData):
|
||||||
|
"""Response for get top users by HWID devices"""
|
||||||
|
pass
|
||||||
|
|
||||||
# Legacy aliases for backward compatibility
|
# Legacy aliases for backward compatibility
|
||||||
CreateHWIDUser = CreateUserHwidDeviceRequestDto
|
CreateHWIDUser = CreateUserHwidDeviceRequestDto
|
||||||
HWIDUserResponseDto = HwidDeviceDto
|
HWIDUserResponseDto = HwidDeviceDto
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,14 @@ class GetInboundsResponseDto(RootModel[List[InboundResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class FullInboundStatistic(BaseModel):
|
class FullInboundStatistic(BaseModel):
|
||||||
enabled: float
|
enabled: float
|
||||||
|
|
@ -67,6 +75,14 @@ class GetFullInboundsResponseDto(RootModel[List[FullInboundResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
# Legacy aliases for backward compatibility
|
# Legacy aliases for backward compatibility
|
||||||
InboundsResponseDto = GetInboundsResponseDto
|
InboundsResponseDto = GetInboundsResponseDto
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,15 @@ class GetAllNodesResponseDto(RootModel[List[NodeResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EnableNodeResponseDto(NodeResponseDto):
|
class EnableNodeResponseDto(NodeResponseDto):
|
||||||
pass
|
pass
|
||||||
|
|
@ -196,6 +205,14 @@ class ReorderNodeResponseDto(RootModel[List[NodeResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class DeleteNodeResponseDto(BaseModel):
|
class DeleteNodeResponseDto(BaseModel):
|
||||||
is_deleted: bool = Field(alias="isDeleted")
|
is_deleted: bool = Field(alias="isDeleted")
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,14 @@ class GetNodesUsageByRangeResponseDto(RootModel[List[NodeUsageDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class UserUsageDto(BaseModel):
|
class UserUsageDto(BaseModel):
|
||||||
user_uuid: UUID = Field(alias="userUuid")
|
user_uuid: UUID = Field(alias="userUuid")
|
||||||
|
|
@ -53,3 +61,11 @@ class GetNodeUserUsageByRangeResponseDto(RootModel[List[UserUsageDto]]):
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
|
||||||
|
|
@ -305,6 +305,14 @@ class EmailUserResponseDto(RootModel[list[UserResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class TagUserResponseDto(RootModel[list[UserResponseDto]]):
|
class TagUserResponseDto(RootModel[list[UserResponseDto]]):
|
||||||
"""Response for get users by tag"""
|
"""Response for get users by tag"""
|
||||||
|
|
@ -314,6 +322,14 @@ class TagUserResponseDto(RootModel[list[UserResponseDto]]):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
||||||
|
|
||||||
class TelegramUserResponseDto(RootModel[list[UserResponseDto]]):
|
class TelegramUserResponseDto(RootModel[list[UserResponseDto]]):
|
||||||
"""Response for get users by telegram ID"""
|
"""Response for get users by telegram ID"""
|
||||||
|
|
@ -322,3 +338,11 @@ class TelegramUserResponseDto(RootModel[list[UserResponseDto]]):
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return self.root[item]
|
return self.root[item]
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Return True if list is not empty"""
|
||||||
|
return bool(self.root)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
"""Return length of list"""
|
||||||
|
return len(self.root)
|
||||||
|
|
@ -23,13 +23,24 @@ class InternalSquadDto(BaseModel):
|
||||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class UserTrafficDto(BaseModel):
|
||||||
|
"""User traffic information for webhooks"""
|
||||||
|
used_traffic_bytes: int
|
||||||
|
lifetime_used_traffic_bytes: int
|
||||||
|
online_at: Optional[datetime] = None
|
||||||
|
first_connected_at: Optional[datetime] = None
|
||||||
|
last_connected_node_uuid: Optional[UUID] = None
|
||||||
|
|
||||||
|
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||||
|
|
||||||
|
|
||||||
class BaseUserDto(BaseModel):
|
class BaseUserDto(BaseModel):
|
||||||
uuid: UUID
|
uuid: UUID
|
||||||
short_uuid: str
|
short_uuid: str
|
||||||
username: str
|
username: str
|
||||||
status: TUsersStatus
|
status: TUsersStatus
|
||||||
used_traffic_bytes: int
|
user_traffic: UserTrafficDto
|
||||||
lifetime_used_traffic_bytes: int
|
|
||||||
|
|
||||||
traffic_limit_bytes: int
|
traffic_limit_bytes: int
|
||||||
traffic_limit_strategy: TResetPeriods
|
traffic_limit_strategy: TResetPeriods
|
||||||
|
|
@ -50,18 +61,41 @@ class BaseUserDto(BaseModel):
|
||||||
email: Optional[str] = None
|
email: Optional[str] = None
|
||||||
|
|
||||||
hwid_device_limit: Optional[int] = None
|
hwid_device_limit: Optional[int] = None
|
||||||
|
|
||||||
first_connected_at: Optional[datetime] = None
|
|
||||||
last_triggered_threshold: int
|
last_triggered_threshold: int
|
||||||
|
|
||||||
online_at: Optional[datetime] = None
|
|
||||||
last_connected_node_uuid: Optional[UUID] = None
|
|
||||||
|
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
updated_at: datetime
|
updated_at: datetime
|
||||||
|
|
||||||
|
|
||||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||||
|
|
||||||
|
# Backward compatibility properties
|
||||||
|
@property
|
||||||
|
def used_traffic_bytes(self) -> int:
|
||||||
|
"""Backward compatibility property"""
|
||||||
|
return self.user_traffic.used_traffic_bytes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lifetime_used_traffic_bytes(self) -> int:
|
||||||
|
"""Backward compatibility property"""
|
||||||
|
return self.user_traffic.lifetime_used_traffic_bytes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def online_at(self) -> Optional[datetime]:
|
||||||
|
"""Backward compatibility property"""
|
||||||
|
return self.user_traffic.online_at
|
||||||
|
|
||||||
|
@property
|
||||||
|
def first_connected_at(self) -> Optional[datetime]:
|
||||||
|
"""Backward compatibility property"""
|
||||||
|
return self.user_traffic.first_connected_at
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_connected_node_uuid(self) -> Optional[UUID]:
|
||||||
|
"""Backward compatibility property"""
|
||||||
|
return self.user_traffic.last_connected_node_uuid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserDto(BaseUserDto):
|
class UserDto(BaseUserDto):
|
||||||
active_internal_squads: List[InternalSquadDto] = Field(default_factory=list)
|
active_internal_squads: List[InternalSquadDto] = Field(default_factory=list)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue