mirror of
https://github.com/remnawave/python-sdk.git
synced 2026-08-04 06:35:09 +00:00
Merge pull request #13 from remnawave:development
Обновить версии SDK до 2.1.18 и 2.1.17; добавить новые DTO для обработки вебхуков и обновить существующие модели
This commit is contained in:
commit
eb7a3014e3
10 changed files with 304 additions and 234 deletions
|
|
@ -63,7 +63,8 @@ pip install git+https://github.com/remnawave/python-sdk.git@development
|
|||
|
||||
| Contract Version | Remnawave Panel Version |
|
||||
| ---------------- | ----------------------- |
|
||||
| 2.1.17 | >=2.1.16 |
|
||||
| 2.1.18 | >=2.1.18 |
|
||||
| 2.1.17 | >=2.1.16, <=2.1.17 |
|
||||
| 2.1.16 | >=2.1.16 |
|
||||
| 2.1.13 | >=2.1.13, <=2.1.15 |
|
||||
| 2.1.9 | >=2.1.9, <=2.1.12 |
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[project]
|
||||
name = "remnawave"
|
||||
version = "2.1.17"
|
||||
description = "A Python SDK for interacting with the Remnawave API v2.1.17."
|
||||
version = "2.1.18"
|
||||
description = "A Python SDK for interacting with the Remnawave API v2.1.18."
|
||||
authors = [
|
||||
{name = "Artem",email = "dev@forestsnet.com"}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ from remnawave.models import (
|
|||
SetInboundToManyHostsRequestDto,
|
||||
SetInboundToManyHostsResponseDto,
|
||||
SetPortToManyHostsResponseDto,
|
||||
SetPortToManyHostsRequestDto
|
||||
)
|
||||
from remnawave.rapid import AttributeBody, BaseController, post
|
||||
|
||||
|
|
@ -53,8 +54,7 @@ class HostsBulkActionsController(BaseController):
|
|||
@post("/hosts/bulk/set-port", response_class=SetPortToManyHostsResponseDto)
|
||||
async def set_port_to_hosts(
|
||||
self,
|
||||
uuids: Annotated[List[UUID], AttributeBody()],
|
||||
port: Annotated[float, AttributeBody()],
|
||||
body: Annotated[SetPortToManyHostsRequestDto, PydanticBody()],
|
||||
) -> SetPortToManyHostsResponseDto:
|
||||
"""Set port to many hosts"""
|
||||
...
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from typing import Union, Optional
|
|||
from remnawave.models.webhook import (
|
||||
WebhookPayloadDto,
|
||||
UserDto,
|
||||
NodesDto,
|
||||
NodeDto,
|
||||
HwidUserDeviceDto,
|
||||
LoginAttemptDto,
|
||||
UserHwidDeviceEventDto,
|
||||
|
|
@ -148,7 +148,7 @@ class WebhookUtility:
|
|||
return event.startswith("errors.")
|
||||
|
||||
@staticmethod
|
||||
def get_typed_data(payload: WebhookPayloadDto) -> Union[UserDto, NodesDto, HwidUserDeviceDto, LoginAttemptDto, UserHwidDeviceEventDto, dict]:
|
||||
def get_typed_data(payload: WebhookPayloadDto) -> Union[UserDto, NodeDto, HwidUserDeviceDto, LoginAttemptDto, UserHwidDeviceEventDto, dict]:
|
||||
"""
|
||||
Get typed data from webhook payload based on event type.
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ from .hosts_bulk_actions import (
|
|||
SetInboundToManyHostsRequestDto,
|
||||
SetInboundToManyHostsResponseDto,
|
||||
SetPortToManyHostsResponseDto,
|
||||
SetPortToManyHostsRequestDto
|
||||
)
|
||||
from .hwid import (
|
||||
CreateHWIDUser, # Legacy alias
|
||||
|
|
@ -252,7 +253,7 @@ from .webhook import (
|
|||
InternalSquadDto,
|
||||
BaseUserDto,
|
||||
UserDto,
|
||||
NodesDto,
|
||||
NodeDto,
|
||||
ConfigProfileInboundDto,
|
||||
InfraProviderDto,
|
||||
LoginAttemptDto,
|
||||
|
|
@ -404,6 +405,7 @@ __all__ = [
|
|||
"SetInboundToManyHostsRequestDto",
|
||||
"SetInboundToManyHostsResponseDto",
|
||||
"SetPortToManyHostsResponseDto",
|
||||
"SetPortToManyHostsRequestDto",
|
||||
# Users models
|
||||
"ActiveInternalSquadDto",
|
||||
"CreateUserRequestDto",
|
||||
|
|
@ -524,7 +526,7 @@ __all__ = [
|
|||
# NODE ENTITIES
|
||||
"ConfigProfileInboundDto",
|
||||
"InfraProviderDto",
|
||||
"NodesDto",
|
||||
"NodeDto",
|
||||
"NodeEventDto",
|
||||
|
||||
# ERROR EVENTS
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ class UpdateHostRequestDto(BaseModel):
|
|||
None, serialization_alias="securityLayer"
|
||||
)
|
||||
server_description: Optional[str] = Field(
|
||||
None, alias="serverDescription", max_length=30
|
||||
None, serialization_alias="serverDescription", max_length=30
|
||||
)
|
||||
muxParams: Optional[str] = Field(
|
||||
mux_params: Optional[str] = Field(
|
||||
None,
|
||||
serialization_alias="muxParams",
|
||||
)
|
||||
|
|
@ -67,19 +67,24 @@ class UpdateHostRequestDto(BaseModel):
|
|||
ge=0,
|
||||
le=65535
|
||||
)
|
||||
shuffle_host: bool = Field(
|
||||
False,
|
||||
shuffle_host: Optional[bool] = Field(
|
||||
None,
|
||||
serialization_alias="shuffleHost",
|
||||
)
|
||||
mihomo_x25519: bool = Field(
|
||||
False,
|
||||
mihomo_x25519: Optional[bool] = Field(
|
||||
None,
|
||||
serialization_alias="mihomoX25519",
|
||||
)
|
||||
x_http_extra_params: Optional[str] = Field(
|
||||
None,
|
||||
serialization_alias="xHttpExtraParams",
|
||||
)
|
||||
nodes: Optional[List[str]] = None
|
||||
|
||||
|
||||
class HostInboundData(BaseModel):
|
||||
config_profile_uuid: UUID = Field(alias="configProfileUuid")
|
||||
config_profile_inbound_uuid: UUID = Field(alias="configProfileInboundUuid")
|
||||
config_profile_uuid: Optional[UUID] = Field(alias="configProfileUuid")
|
||||
config_profile_inbound_uuid: Optional[UUID] = Field(alias="configProfileInboundUuid")
|
||||
|
||||
|
||||
class HostResponseDto(BaseModel):
|
||||
|
|
@ -93,57 +98,54 @@ class HostResponseDto(BaseModel):
|
|||
host: Optional[str] = None
|
||||
alpn: Optional[ALPN] = None
|
||||
fingerprint: Optional[Fingerprint] = None
|
||||
is_disabled: Optional[bool] = Field(
|
||||
None,
|
||||
alias="isDisabled",
|
||||
)
|
||||
security_layer: Optional[SecurityLayer] = Field(
|
||||
None,
|
||||
alias="securityLayer",
|
||||
)
|
||||
x_http_extra_params: Optional[str] = Field(
|
||||
None,
|
||||
alias="xHttpExtraParams",
|
||||
)
|
||||
server_description: Optional[str] = Field(
|
||||
None, alias="serverDescription", max_length=30
|
||||
)
|
||||
inbound: HostInboundData
|
||||
muxParams: Optional[str] = Field(
|
||||
mux_params: Optional[str] = Field(
|
||||
None,
|
||||
serialization_alias="muxParams",
|
||||
alias="muxParams",
|
||||
)
|
||||
sockopt_params: Optional[str] = Field(
|
||||
None,
|
||||
serialization_alias="sockoptParams",
|
||||
alias="sockoptParams",
|
||||
)
|
||||
tag: Optional[Annotated[str, StringConstraints(max_length=32)]] = Field(
|
||||
None, serialization_alias="tag"
|
||||
)
|
||||
is_hidden: Optional[bool] = Field(
|
||||
None,
|
||||
serialization_alias="isHidden",
|
||||
)
|
||||
override_sni_from_address: Optional[bool] = Field(
|
||||
None,
|
||||
serialization_alias="overrideSniFromAddress",
|
||||
inbound: HostInboundData
|
||||
server_description: Optional[str] = Field(
|
||||
None, alias="serverDescription"
|
||||
)
|
||||
tag: Optional[str] = None
|
||||
vless_route_id: Optional[int] = Field(
|
||||
None,
|
||||
serialization_alias="vlessRouteId",
|
||||
alias="vlessRouteId",
|
||||
)
|
||||
shuffle_host: bool = Field(
|
||||
False,
|
||||
serialization_alias="shuffleHost",
|
||||
shuffle_host: bool = Field(alias="shuffleHost")
|
||||
mihomo_x25519: bool = Field(alias="mihomoX25519")
|
||||
nodes: List[str]
|
||||
is_disabled: bool = Field(
|
||||
default=False,
|
||||
alias="isDisabled",
|
||||
)
|
||||
mihomo_x25519: bool = Field(
|
||||
False,
|
||||
serialization_alias="mihomoX25519",
|
||||
security_layer: SecurityLayer = Field(
|
||||
default=SecurityLayer.DEFAULT,
|
||||
alias="securityLayer",
|
||||
)
|
||||
is_hidden: bool = Field(
|
||||
default=False,
|
||||
alias="isHidden",
|
||||
)
|
||||
override_sni_from_address: bool = Field(
|
||||
default=False,
|
||||
alias="overrideSniFromAddress",
|
||||
)
|
||||
allow_insecure: bool = Field(
|
||||
default=False,
|
||||
alias="allowInsecure",
|
||||
)
|
||||
|
||||
# Legacy compatibility property
|
||||
@property
|
||||
def inbound_uuid(self) -> UUID:
|
||||
def inbound_uuid(self) -> Optional[UUID]:
|
||||
return self.inbound.config_profile_inbound_uuid
|
||||
|
||||
|
||||
|
|
@ -186,8 +188,8 @@ class DeleteHostResponseDto(BaseModel):
|
|||
|
||||
|
||||
class CreateHostInboundData(BaseModel):
|
||||
config_profile_uuid: UUID = Field(serialization_alias="configProfileUuid")
|
||||
config_profile_inbound_uuid: UUID = Field(
|
||||
config_profile_uuid: Optional[UUID] = Field(serialization_alias="configProfileUuid")
|
||||
config_profile_inbound_uuid: Optional[UUID] = Field(
|
||||
serialization_alias="configProfileInboundUuid"
|
||||
)
|
||||
|
||||
|
|
@ -202,19 +204,11 @@ class CreateHostRequestDto(BaseModel):
|
|||
host: Optional[str] = None
|
||||
alpn: Optional[ALPN] = None
|
||||
fingerprint: Optional[Fingerprint] = None
|
||||
allow_insecure: bool = Field(
|
||||
False,
|
||||
serialization_alias="allowInsecure",
|
||||
x_http_extra_params: Optional[str] = Field(
|
||||
None,
|
||||
serialization_alias="xHttpExtraParams",
|
||||
)
|
||||
is_disabled: bool = Field(
|
||||
False,
|
||||
serialization_alias="isDisabled",
|
||||
)
|
||||
security_layer: Optional[SecurityLayer] = Field(
|
||||
SecurityLayer.DEFAULT,
|
||||
serialization_alias="securityLayer",
|
||||
)
|
||||
muxParams: Optional[str] = Field(
|
||||
mux_params: Optional[str] = Field(
|
||||
None,
|
||||
serialization_alias="muxParams",
|
||||
)
|
||||
|
|
@ -222,19 +216,11 @@ class CreateHostRequestDto(BaseModel):
|
|||
None,
|
||||
serialization_alias="sockoptParams",
|
||||
)
|
||||
tag: Optional[Annotated[str, StringConstraints(max_length=32, pattern="^[A-Z0-9_:]+$")]] = Field(
|
||||
None, serialization_alias="tag"
|
||||
)
|
||||
is_hidden: bool = Field(
|
||||
False,
|
||||
serialization_alias="isHidden",
|
||||
)
|
||||
override_sni_from_address: bool = Field(
|
||||
False,
|
||||
serialization_alias="overrideSniFromAddress",
|
||||
)
|
||||
server_description: Optional[str] = Field(
|
||||
None, alias="serverDescription", max_length=30
|
||||
None, serialization_alias="serverDescription", max_length=30
|
||||
)
|
||||
tag: Optional[Annotated[str, StringConstraints(max_length=32)]] = Field(
|
||||
None, serialization_alias="tag"
|
||||
)
|
||||
vless_route_id: Optional[int] = Field(
|
||||
None,
|
||||
|
|
@ -250,10 +236,31 @@ class CreateHostRequestDto(BaseModel):
|
|||
False,
|
||||
serialization_alias="mihomoX25519",
|
||||
)
|
||||
nodes: List[str] = Field(default_factory=list)
|
||||
allow_insecure: bool = Field(
|
||||
False,
|
||||
serialization_alias="allowInsecure",
|
||||
)
|
||||
is_disabled: bool = Field(
|
||||
False,
|
||||
serialization_alias="isDisabled",
|
||||
)
|
||||
security_layer: SecurityLayer = Field(
|
||||
SecurityLayer.DEFAULT,
|
||||
serialization_alias="securityLayer",
|
||||
)
|
||||
is_hidden: bool = Field(
|
||||
False,
|
||||
serialization_alias="isHidden",
|
||||
)
|
||||
override_sni_from_address: bool = Field(
|
||||
False,
|
||||
serialization_alias="overrideSniFromAddress",
|
||||
)
|
||||
|
||||
# Legacy compatibility property
|
||||
@property
|
||||
def inbound_uuid(self) -> UUID:
|
||||
def inbound_uuid(self) -> Optional[UUID]:
|
||||
return self.inbound.config_profile_inbound_uuid
|
||||
|
||||
# Constructor compatibility - support old-style inbound_uuid
|
||||
|
|
|
|||
|
|
@ -8,8 +8,14 @@ from remnawave.models import HostResponseDto
|
|||
|
||||
class SetInboundToManyHostsRequestDto(BaseModel):
|
||||
uuids: List[UUID]
|
||||
inbound_uuid: UUID = Field(serialization_alias="inboundUuid")
|
||||
config_profile_uuid: UUID = Field(serialization_alias="configProfileUuid")
|
||||
config_profile_inbound_uuid: UUID = Field(
|
||||
serialization_alias="configProfileInboundUuid"
|
||||
)
|
||||
|
||||
class SetPortToManyHostsRequestDto(BaseModel):
|
||||
uuids: List[UUID]
|
||||
port: int = Field(ge=1, le=65535)
|
||||
|
||||
class BulkDeleteHostsResponseDto(List[HostResponseDto]):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -11,6 +11,136 @@ class HappCrypto(BaseModel):
|
|||
crypto_link: str = Field(alias="cryptoLink")
|
||||
|
||||
|
||||
class UserLastConnectedNodeDto(BaseModel):
|
||||
connected_at: datetime = Field(alias="connectedAt")
|
||||
node_name: str = Field(alias="nodeName")
|
||||
country_code: str = Field(alias="countryCode")
|
||||
|
||||
|
||||
class ActiveInternalSquadDto(BaseModel):
|
||||
uuid: UUID
|
||||
name: str
|
||||
|
||||
|
||||
class UserResponseDto(BaseModel):
|
||||
uuid: UUID
|
||||
short_uuid: str = Field(alias="shortUuid")
|
||||
username: str
|
||||
status: UserStatus = Field(default=UserStatus.ACTIVE)
|
||||
used_traffic_bytes: float = Field(alias="usedTrafficBytes")
|
||||
lifetime_used_traffic_bytes: float = Field(alias="lifetimeUsedTrafficBytes")
|
||||
traffic_limit_bytes: int = Field(default=0, alias="trafficLimitBytes")
|
||||
traffic_limit_strategy: TrafficLimitStrategy = Field(
|
||||
default=TrafficLimitStrategy.NO_RESET,
|
||||
alias="trafficLimitStrategy"
|
||||
)
|
||||
sub_last_user_agent: Optional[str] = Field(None, alias="subLastUserAgent")
|
||||
sub_last_opened_at: Optional[datetime] = Field(None, alias="subLastOpenedAt")
|
||||
expire_at: datetime = Field(alias="expireAt")
|
||||
online_at: Optional[datetime] = Field(None, alias="onlineAt")
|
||||
sub_revoked_at: Optional[datetime] = Field(None, alias="subRevokedAt")
|
||||
last_traffic_reset_at: Optional[datetime] = Field(None, alias="lastTrafficResetAt")
|
||||
trojan_password: str = Field(alias="trojanPassword")
|
||||
vless_uuid: UUID = Field(alias="vlessUuid")
|
||||
ss_password: str = Field(alias="ssPassword")
|
||||
description: Optional[str] = None
|
||||
tag: Optional[str] = None
|
||||
telegram_id: Optional[int] = Field(None, alias="telegramId")
|
||||
email: Optional[str] = None
|
||||
hwid_device_limit: Optional[int] = Field(None, alias="hwidDeviceLimit")
|
||||
first_connected_at: Optional[datetime] = Field(None, alias="firstConnectedAt")
|
||||
last_triggered_threshold: int = Field(default=0, alias="lastTriggeredThreshold")
|
||||
created_at: datetime = Field(alias="createdAt")
|
||||
updated_at: datetime = Field(alias="updatedAt")
|
||||
active_internal_squads: List[ActiveInternalSquadDto] = Field(alias="activeInternalSquads")
|
||||
subscription_url: str = Field(alias="subscriptionUrl")
|
||||
last_connected_node: Optional[UserLastConnectedNodeDto] = Field(None, alias="lastConnectedNode")
|
||||
happ: HappCrypto = Field(alias="happ")
|
||||
|
||||
|
||||
class ConvertedUserInfo(BaseModel):
|
||||
days_left: int = Field(alias="daysLeft")
|
||||
traffic_limit: str = Field(alias="trafficLimit")
|
||||
traffic_used: str = Field(alias="trafficUsed")
|
||||
lifetime_traffic_used: str = Field(alias="lifetimeTrafficUsed")
|
||||
is_hwid_limited: bool = Field(alias="isHwidLimited")
|
||||
|
||||
|
||||
class Passwords(BaseModel):
|
||||
ss_password: str = Field(alias="ssPassword")
|
||||
trojan_password: str = Field(alias="trojanPassword")
|
||||
vless_password: str = Field(alias="vlessPassword")
|
||||
|
||||
|
||||
class RawHostAdditionalParams(BaseModel):
|
||||
mode: Optional[str] = None
|
||||
heartbeat_period: Optional[float] = Field(None, alias="heartbeatPeriod")
|
||||
|
||||
|
||||
class RawHostProtocolOptions(BaseModel):
|
||||
class SSOptions(BaseModel):
|
||||
method: Optional[str] = None
|
||||
|
||||
ss: Optional[SSOptions] = None
|
||||
|
||||
|
||||
class RawHostDbData(BaseModel):
|
||||
raw_inbound: Optional[Dict[str, Any]] = Field(alias="rawInbound")
|
||||
inbound_tag: str = Field(alias="inboundTag")
|
||||
uuid: str
|
||||
config_profile_uuid: Optional[str] = Field(alias="configProfileUuid")
|
||||
config_profile_inbound_uuid: Optional[str] = Field(alias="configProfileInboundUuid")
|
||||
is_disabled: bool = Field(alias="isDisabled")
|
||||
view_position: int = Field(alias="viewPosition")
|
||||
remark: str
|
||||
is_hidden: bool = Field(alias="isHidden")
|
||||
tag: Optional[str] = None
|
||||
vless_route_id: Optional[int] = Field(None, alias="vlessRouteId")
|
||||
|
||||
|
||||
class RawHost(BaseModel):
|
||||
password: Passwords
|
||||
address: Optional[str] = None
|
||||
alpn: Optional[str] = None
|
||||
fingerprint: Optional[str] = None
|
||||
host: Optional[str] = None
|
||||
network: Optional[str] = None
|
||||
path: Optional[str] = None
|
||||
public_key: Optional[str] = Field(None, alias="publicKey")
|
||||
port: Optional[float] = None # изменен тип на float
|
||||
protocol: Optional[str] = None
|
||||
remark: Optional[str] = None
|
||||
short_id: Optional[str] = Field(None, alias="shortId")
|
||||
sni: Optional[str] = None
|
||||
spider_x: Optional[str] = Field(None, alias="spiderX")
|
||||
tls: Optional[str] = None
|
||||
header_type: Optional[str] = Field(None, alias="headerType")
|
||||
additional_params: Optional[RawHostAdditionalParams] = Field(None, alias="additionalParams")
|
||||
x_http_extra_params: Optional[Dict[str, Any]] = Field(None, alias="xHttpExtraParams")
|
||||
mux_params: Optional[Dict[str, Any]] = Field(None, alias="muxParams")
|
||||
sockopt_params: Optional[Dict[str, Any]] = Field(None, alias="sockoptParams")
|
||||
server_description: Optional[str] = Field(None, alias="serverDescription")
|
||||
flow: Optional[str] = None
|
||||
allow_insecure: Optional[bool] = Field(None, alias="allowInsecure")
|
||||
shuffle_host: Optional[bool] = Field(None, alias="shuffleHost")
|
||||
mihomo_x25519: Optional[bool] = Field(None, alias="mihomoX25519")
|
||||
mldsa65_verify: Optional[str] = Field(None, alias="mldsa65Verify")
|
||||
encryption: Optional[str] = None
|
||||
protocol_options: Optional[RawHostProtocolOptions] = Field(None, alias="protocolOptions")
|
||||
db_data: RawHostDbData = Field(alias="dbData")
|
||||
|
||||
|
||||
class RawSubscriptionResponse(BaseModel):
|
||||
user: UserResponseDto
|
||||
converted_user_info: ConvertedUserInfo = Field(alias="convertedUserInfo")
|
||||
headers: Dict[str, str]
|
||||
raw_hosts: List[RawHost] = Field(alias="rawHosts")
|
||||
|
||||
|
||||
class GetRawSubscriptionByShortUuidResponseDto(RawSubscriptionResponse):
|
||||
pass
|
||||
|
||||
# Legacy alias for backward compatibility
|
||||
class UserSubscription(BaseModel):
|
||||
short_uuid: str = Field(alias="shortUuid")
|
||||
username: str
|
||||
|
|
@ -26,6 +156,7 @@ class UserSubscription(BaseModel):
|
|||
user_status: UserStatus = Field(alias="userStatus")
|
||||
is_active: bool = Field(alias="isActive")
|
||||
|
||||
|
||||
class SubscriptionInfoData(BaseModel):
|
||||
is_found: bool = Field(alias="isFound")
|
||||
user: UserSubscription
|
||||
|
|
@ -43,122 +174,6 @@ class GetSubscriptionInfoResponseDto(BaseModel):
|
|||
subscription_url: str = Field(alias="subscriptionUrl")
|
||||
happ: HappCrypto
|
||||
|
||||
class UserLastConnectedNodeDto(BaseModel):
|
||||
connected_at: datetime = Field(alias="connectedAt")
|
||||
node_name: str = Field(alias="nodeName")
|
||||
country_code: Optional[str] = Field(None, alias="countryCode") # новое поле
|
||||
|
||||
class ActiveInternalSquadDto(BaseModel):
|
||||
uuid: UUID
|
||||
name: str
|
||||
|
||||
class HappCrypto(BaseModel):
|
||||
crypto_link: str = Field(alias="cryptoLink")
|
||||
|
||||
class UserResponseDto(BaseModel):
|
||||
uuid: UUID
|
||||
short_uuid: str = Field(alias="shortUuid")
|
||||
username: str
|
||||
status: str
|
||||
used_traffic_bytes: float = Field(alias="usedTrafficBytes")
|
||||
lifetime_used_traffic_bytes: float = Field(alias="lifetimeUsedTrafficBytes")
|
||||
traffic_limit_bytes: int = Field(alias="trafficLimitBytes")
|
||||
traffic_limit_strategy: str = Field(alias="trafficLimitStrategy")
|
||||
sub_last_user_agent: Optional[str] = Field(None, alias="subLastUserAgent")
|
||||
sub_last_opened_at: Optional[datetime] = Field(None, alias="subLastOpenedAt")
|
||||
expire_at: datetime = Field(alias="expireAt")
|
||||
online_at: Optional[datetime] = Field(None, alias="onlineAt")
|
||||
sub_revoked_at: Optional[datetime] = Field(None, alias="subRevokedAt")
|
||||
last_traffic_reset_at: Optional[datetime] = Field(None, alias="lastTrafficResetAt")
|
||||
trojan_password: str = Field(alias="trojanPassword")
|
||||
vless_uuid: UUID = Field(alias="vlessUuid")
|
||||
ss_password: str = Field(alias="ssPassword")
|
||||
description: Optional[str] = None
|
||||
tag: Optional[str] = None
|
||||
telegram_id: Optional[int] = Field(None, alias="telegramId")
|
||||
email: Optional[str] = None
|
||||
hwidDeviceLimit: Optional[int] = Field(None, alias="hwidDeviceLimit")
|
||||
first_connected_at: Optional[datetime] = Field(None, alias="firstConnectedAt")
|
||||
last_triggered_threshold: int = Field(alias="lastTriggeredThreshold")
|
||||
created_at: datetime = Field(alias="createdAt")
|
||||
updated_at: datetime = Field(alias="updatedAt")
|
||||
active_internal_squads: List[ActiveInternalSquadDto] = Field(alias="activeInternalSquads")
|
||||
subscription_url: str = Field(alias="subscriptionUrl")
|
||||
last_connected_node: Optional[UserLastConnectedNodeDto] = Field(None, alias="lastConnectedNode")
|
||||
happ: Optional[HappCrypto] = Field(None, alias="happ")
|
||||
|
||||
class ConvertedUserInfo(BaseModel):
|
||||
days_left: int = Field(alias="daysLeft")
|
||||
traffic_limit: str = Field(alias="trafficLimit")
|
||||
traffic_used: str = Field(alias="trafficUsed")
|
||||
lifetime_traffic_used: str = Field(alias="lifetimeTrafficUsed")
|
||||
is_hwid_limited: bool = Field(alias="isHwidLimited")
|
||||
|
||||
class Passwords(BaseModel):
|
||||
ss_password: Optional[str] = Field(None, alias="ssPassword")
|
||||
trojan_password: Optional[str] = Field(None, alias="trojanPassword")
|
||||
vless_password: Optional[str] = Field(None, alias="vlessPassword")
|
||||
|
||||
|
||||
|
||||
class RawHostAdditionalParams(BaseModel):
|
||||
mode: Optional[str] = None
|
||||
heartbeat_period: Optional[int] = Field(None, alias="heartbeatPeriod")
|
||||
|
||||
|
||||
class RawHostProtocolOptions(BaseModel):
|
||||
class SSOptions(BaseModel):
|
||||
method: Optional[str] = None
|
||||
|
||||
ss: Optional[SSOptions] = None
|
||||
|
||||
|
||||
class RawHostDbData(BaseModel):
|
||||
raw_inbound: Optional[Dict[str, Any]] = Field(alias="rawInbound")
|
||||
inbound_tag: str = Field(alias="inboundTag")
|
||||
uuid: str
|
||||
config_profile_uuid: Optional[str] = Field(alias="configProfileUuid")
|
||||
config_profile_inbound_uuid: Optional[str] = Field(alias="configProfileInboundUuid")
|
||||
is_disabled: bool = Field(alias="isDisabled")
|
||||
view_position: int = Field(alias="viewPosition")
|
||||
remark: str
|
||||
is_hidden: bool = Field(alias="isHidden")
|
||||
tag: Optional[str] = None
|
||||
|
||||
class RawHost(BaseModel):
|
||||
address: Optional[str] = None
|
||||
alpn: Optional[str] = None
|
||||
fingerprint: Optional[str] = None
|
||||
host: Optional[str] = None
|
||||
network: Optional[str] = None
|
||||
password: Optional[Passwords] = None
|
||||
path: Optional[str] = None
|
||||
public_key: Optional[str] = Field(None, alias="publicKey")
|
||||
port: Optional[int] = None
|
||||
protocol: Optional[str] = None
|
||||
remark: Optional[str] = None
|
||||
short_id: Optional[str] = Field(None, alias="shortId")
|
||||
sni: Optional[str] = None
|
||||
spider_x: Optional[str] = Field(None, alias="spiderX")
|
||||
tls: Optional[str] = None
|
||||
header_type: Optional[str] = Field(None, alias="headerType")
|
||||
additional_params: Optional[RawHostAdditionalParams] = Field(None, alias="additionalParams")
|
||||
x_http_extra_params: Optional[Dict[str, Any]] = Field(None, alias="xHttpExtraParams")
|
||||
mux_params: Optional[Dict[str, Any]] = Field(None, alias="muxParams")
|
||||
sockopt_params: Optional[Dict[str, Any]] = Field(None, alias="sockoptParams")
|
||||
server_description: Optional[str] = Field(None, alias="serverDescription")
|
||||
flow: Optional[str] = None
|
||||
protocol_options: Optional[RawHostProtocolOptions] = Field(None, alias="protocolOptions")
|
||||
db_data: RawHostDbData = Field(alias="dbData")
|
||||
|
||||
class RawSubscriptionResponse(BaseModel):
|
||||
user: UserResponseDto
|
||||
converted_user_info: ConvertedUserInfo = Field(alias="convertedUserInfo")
|
||||
headers: Dict[str, str]
|
||||
raw_hosts: List[RawHost] = Field(alias="rawHosts")
|
||||
|
||||
class GetRawSubscriptionByShortUuidResponseDto(RawSubscriptionResponse):
|
||||
pass
|
||||
|
||||
class SubscriptionWithoutHapp(BaseModel):
|
||||
is_found: bool = Field(alias="isFound")
|
||||
|
|
@ -180,11 +195,14 @@ class GetSubscriptionByUsernameResponseDto(BaseModel):
|
|||
ss_conf_links: Dict[str, str] = Field(alias="ssConfLinks")
|
||||
subscription_url: str = Field(alias="subscriptionUrl")
|
||||
|
||||
|
||||
class GetSubscriptionByShortUUIDResponseDto(GetSubscriptionByUsernameResponseDto):
|
||||
pass
|
||||
|
||||
|
||||
class GetSubscriptionByUUIDResponseDto(GetSubscriptionByUsernameResponseDto):
|
||||
pass
|
||||
|
||||
|
||||
# Legacy alias for backward compatibility
|
||||
SubscriptionInfoResponseDto = GetSubscriptionInfoResponseDto
|
||||
SubscriptionInfoResponseDto = GetSubscriptionInfoResponseDto
|
||||
|
|
@ -19,7 +19,6 @@ class LastConnectedNodeDto(BaseModel):
|
|||
class InternalSquadDto(BaseModel):
|
||||
uuid: UUID
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
|
@ -29,11 +28,10 @@ class BaseUserDto(BaseModel):
|
|||
short_uuid: str
|
||||
username: str
|
||||
status: TUsersStatus
|
||||
used_traffic_bytes: int
|
||||
lifetime_used_traffic_bytes: int
|
||||
|
||||
used_traffic_bytes: str
|
||||
lifetime_used_traffic_bytes: str
|
||||
|
||||
traffic_limit_bytes: str
|
||||
traffic_limit_bytes: int
|
||||
traffic_limit_strategy: TResetPeriods
|
||||
sub_last_user_agent: Optional[str] = None
|
||||
sub_last_opened_at: Optional[datetime] = None
|
||||
|
|
@ -48,7 +46,7 @@ class BaseUserDto(BaseModel):
|
|||
|
||||
description: Optional[str] = None
|
||||
tag: Optional[str] = None
|
||||
telegram_id: Optional[str] = None
|
||||
telegram_id: Optional[int] = None
|
||||
email: Optional[str] = None
|
||||
|
||||
hwid_device_limit: Optional[int] = None
|
||||
|
|
@ -57,7 +55,7 @@ class BaseUserDto(BaseModel):
|
|||
last_triggered_threshold: int
|
||||
|
||||
online_at: Optional[datetime] = None
|
||||
last_connected_node_uuid: Optional[str] = None
|
||||
last_connected_node_uuid: Optional[UUID] = None
|
||||
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
|
@ -73,9 +71,8 @@ class UserDto(BaseUserDto):
|
|||
|
||||
|
||||
class UserEventDto(BaseModel):
|
||||
user: UserDto
|
||||
event_name: TUserEvents
|
||||
skip_telegram_notification: bool = False
|
||||
user: UserDto
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
|
@ -106,7 +103,6 @@ class UserHwidDeviceEventDto(BaseModel):
|
|||
def build(cls, user: UserDto, hwid_device: HwidUserDeviceDto, event: TUserHwidDevicesEvents):
|
||||
return cls(data={"user": user, "hwidUserDevice": hwid_device}, event_name=event)
|
||||
|
||||
|
||||
# ---------------- SERVICE EVENTS ---------------- #
|
||||
|
||||
class LoginAttemptDto(BaseModel):
|
||||
|
|
@ -115,7 +111,7 @@ class LoginAttemptDto(BaseModel):
|
|||
user_agent: str
|
||||
description: Optional[str] = None
|
||||
password: Optional[str] = None
|
||||
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
||||
|
|
@ -130,11 +126,30 @@ class ServiceEventDto(BaseModel):
|
|||
|
||||
class ConfigProfileInboundDto(BaseModel):
|
||||
uuid: UUID
|
||||
name: str
|
||||
config: dict
|
||||
profile_uuid: UUID
|
||||
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
tag: str
|
||||
type: str
|
||||
network: Optional[str]
|
||||
security: Optional[str]
|
||||
port: Optional[int]
|
||||
|
||||
raw_inbound: Optional[dict]
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
||||
class InfraBillingHistoryDto(BaseModel):
|
||||
total_amount: int
|
||||
total_bills: int
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
||||
class InfraBillingNodeDto(BaseModel):
|
||||
node_uuid: UUID
|
||||
name: str
|
||||
country_code: str
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
|
@ -148,13 +163,13 @@ class InfraProviderDto(BaseModel):
|
|||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
billing_history: Optional[dict] = None
|
||||
billing_nodes: Optional[List[dict]] = None
|
||||
billing_history: Optional[InfraBillingHistoryDto] = None
|
||||
billing_nodes: Optional[List[InfraBillingNodeDto]] = None
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
||||
class NodesDto(BaseModel):
|
||||
class NodeDto(BaseModel):
|
||||
uuid: UUID
|
||||
name: str
|
||||
address: str
|
||||
|
|
@ -164,7 +179,6 @@ class NodesDto(BaseModel):
|
|||
is_disabled: bool
|
||||
is_node_online: bool
|
||||
is_xray_running: bool
|
||||
|
||||
last_status_change: Optional[datetime] = None
|
||||
last_status_message: Optional[str] = None
|
||||
|
||||
|
|
@ -173,16 +187,16 @@ class NodesDto(BaseModel):
|
|||
xray_uptime: str
|
||||
|
||||
users_online: Optional[int] = None
|
||||
|
||||
|
||||
is_traffic_tracking_active: bool
|
||||
traffic_reset_day: Optional[int] = None
|
||||
traffic_limit_bytes: Optional[str] = None
|
||||
traffic_used_bytes: Optional[str] = None
|
||||
traffic_limit_bytes: Optional[int] = None
|
||||
traffic_used_bytes: Optional[int] = None
|
||||
notify_percent: Optional[int] = None
|
||||
|
||||
view_position: int
|
||||
country_code: str
|
||||
consumption_multiplier: str
|
||||
consumption_multiplier: int
|
||||
|
||||
cpu_count: Optional[int] = None
|
||||
cpu_model: Optional[str] = None
|
||||
|
|
@ -201,27 +215,43 @@ class NodesDto(BaseModel):
|
|||
|
||||
|
||||
class NodeEventDto(BaseModel):
|
||||
node: NodesDto
|
||||
event_name: TNodeEvents
|
||||
data: NodeDto
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
# ---------------- ERROR EVENTS ---------------- #
|
||||
|
||||
# https://github.com/remnawave/backend/blob/main/src/queue/user-jobs/user-jobs.processor.ts#L224
|
||||
# Not implemented yet!
|
||||
|
||||
class ErrorDto(BaseModel):
|
||||
description: str
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
||||
# ---------------- ERROR EVENTS ---------------- #
|
||||
|
||||
class CustomErrorEventDto(BaseModel):
|
||||
event_name: TErrorsEvents
|
||||
data: dict
|
||||
data: ErrorDto
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
||||
# ---------------- CRM EVENTS ---------------- #
|
||||
|
||||
class BillingNodeDto(BaseModel):
|
||||
provider_name: str
|
||||
node_name: str
|
||||
next_billing_at: datetime
|
||||
login_url: str
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
||||
class CrmEventDto(BaseModel):
|
||||
event_name: TCRMEvents
|
||||
data: dict
|
||||
skip_telegram_notification: bool = False
|
||||
data: BillingNodeDto
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
|
@ -230,15 +260,16 @@ class CrmEventDto(BaseModel):
|
|||
|
||||
class WebhookPayloadDto(BaseModel):
|
||||
event: str
|
||||
timestamp: datetime
|
||||
data: Union[
|
||||
UserDto,
|
||||
NodesDto,
|
||||
NodeDto,
|
||||
HwidUserDeviceDto,
|
||||
LoginAttemptDto,
|
||||
UserHwidDeviceEventDto,
|
||||
BillingNodeDto,
|
||||
dict
|
||||
]
|
||||
timestamp: datetime
|
||||
|
||||
model_config = {"alias_generator": to_camel, "populate_by_name": True}
|
||||
|
||||
|
|
@ -250,19 +281,24 @@ class WebhookPayloadDto(BaseModel):
|
|||
if event.startswith("user."):
|
||||
data = UserDto(**data_raw)
|
||||
elif event.startswith("user_hwid_devices."):
|
||||
data = HwidUserDeviceDto(**data_raw)
|
||||
user = UserDto(**data_raw["user"])
|
||||
hwid_device = HwidUserDeviceDto(**data_raw["hwidUserDevice"])
|
||||
data = UserHwidDeviceEventDto.build(
|
||||
user=user,
|
||||
hwid_device=hwid_device,
|
||||
event=event,
|
||||
)
|
||||
elif event.startswith("node."):
|
||||
data = NodesDto(**data_raw)
|
||||
data = NodeDto(**data_raw)
|
||||
elif event.startswith("service."):
|
||||
# может быть loginAttempt или другое
|
||||
if "username" in data_raw and "ip" in data_raw:
|
||||
if event.startswith("service.login_attempt"):
|
||||
data = LoginAttemptDto(**data_raw)
|
||||
else:
|
||||
else: # service.panel_started - содержит пустой json
|
||||
data = data_raw
|
||||
elif event.startswith("errors."):
|
||||
data = data_raw
|
||||
data = ErrorDto(**data_raw)
|
||||
elif event.startswith("crm."):
|
||||
data = data_raw
|
||||
data = BillingNodeDto(**data_raw)
|
||||
else:
|
||||
data = data_raw
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class TestHostsCRUD:
|
|||
# Создаем новый объект для обновления
|
||||
update_data = UpdateHostRequestDto(
|
||||
uuid=test_host.uuid,
|
||||
serverDescription="Updated Host",
|
||||
server_description="Updated Host",
|
||||
is_disabled=False # явно устанавливаем значение
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue