From 8a8450319162965e013e78c90b2a71b8850e1721 Mon Sep 17 00:00:00 2001 From: Artem Date: Thu, 21 Aug 2025 23:58:28 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=8D=D0=BD=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD=D1=82?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=81=D1=8B=D1=80=D0=BE=D0=B9=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=BF=D0=B8=D1=81=D0=BA=D0=B8=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D0=BA=D0=BE=D1=80=D0=BE=D1=82=D0=BA=D0=BE=D0=BC=D1=83=20UUID?= =?UTF-8?q?=20=D0=B8=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82=D1=8C=20?= =?UTF-8?q?=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20=D0=BF=D0=BE=D0=B4=D0=BF?= =?UTF-8?q?=D0=B8=D1=81=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remnawave/controllers/subscription.py | 12 ++++- remnawave/controllers/users.py | 8 ---- remnawave/models/subscription.py | 67 +++++++++++++++++++++++++++ remnawave/models/users.py | 3 -- tests/test_users.py | 1 - 5 files changed, 78 insertions(+), 13 deletions(-) diff --git a/remnawave/controllers/subscription.py b/remnawave/controllers/subscription.py index 860cad8..32ac88f 100644 --- a/remnawave/controllers/subscription.py +++ b/remnawave/controllers/subscription.py @@ -3,7 +3,7 @@ from typing import Annotated from rapid_api_client import Path from remnawave.enums import ClientType -from remnawave.models import GetSubscriptionInfoResponseDto +from remnawave.models import GetSubscriptionInfoResponseDto, GetRawSubscriptionByShortUuidResponseDto from remnawave.rapid import BaseController, get @@ -52,3 +52,13 @@ class SubscriptionController(BaseController): ) -> str: """None""" ... + + # get raw sub by short uuid + @get("/sub/{short_uuid}/raw", response_class=GetRawSubscriptionByShortUuidResponseDto) + async def get_raw_subscription( + self, + short_uuid: Annotated[str, Path(description="Short UUID of the user")], + withDisabledHosts: Annotated[Annotated[bool, Path(description="Include disabled hosts")], bool] = False, + ) -> GetRawSubscriptionByShortUuidResponseDto: + """None""" + ... \ No newline at end of file diff --git a/remnawave/controllers/users.py b/remnawave/controllers/users.py index b8b92ce..d0bd942 100644 --- a/remnawave/controllers/users.py +++ b/remnawave/controllers/users.py @@ -93,14 +93,6 @@ class UsersController(BaseController): ) -> UserResponseDto: """Reset User Traffic""" ... - - @post("/users/{uuid}/actions/activate-all-inbounds", response_class=UserResponseDto) - async def activate_all_inbounds( - self, - uuid: Annotated[str, Path(description="UUID of the user")], - ) -> UserResponseDto: - """Activate All Inbounds""" - ... @get("/users/by-short-uuid/{short_uuid}", response_class=UserResponseDto) async def get_user_by_short_uuid( diff --git a/remnawave/models/subscription.py b/remnawave/models/subscription.py index 3d587ce..18969cd 100644 --- a/remnawave/models/subscription.py +++ b/remnawave/models/subscription.py @@ -16,6 +16,10 @@ class UserSubscription(BaseModel): days_left: int = Field(alias="daysLeft") traffic_used: str = Field(alias="trafficUsed") traffic_limit: str = Field(alias="trafficLimit") + lifetime_traffic_used: str = Field(alias="lifetimeTrafficUsed") + traffic_used_bytes: str = Field(alias="trafficUsedBytes") + traffic_limit_bytes: str = Field(alias="trafficLimitBytes") + lifetime_traffic_used_bytes: int = Field(alias="lifetimeTrafficUsedBytes") traffic_limit_strategy: TrafficLimitStrategy = Field(alias="trafficLimitStrategy") expires_at: datetime = Field(alias="expiresAt") user_status: UserStatus = Field(alias="userStatus") @@ -40,6 +44,69 @@ class GetSubscriptionInfoResponseDto(BaseModel): happ: HappCrypto +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[str] = 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: UserSubscription + subscription_url: str = Field(alias="subscriptionUrl") + raw_hosts: List[RawHost] = Field(alias="rawHosts") + headers: Dict[str, str] + is_hwid_limited: bool = Field(alias="isHwidLimited") + + +class GetRawSubscriptionByShortUuidResponseDto(RawSubscriptionResponse): + pass + class SubscriptionWithoutHapp(BaseModel): is_found: bool = Field(alias="isFound") user: UserSubscription diff --git a/remnawave/models/users.py b/remnawave/models/users.py index 18120d2..b56ee30 100644 --- a/remnawave/models/users.py +++ b/remnawave/models/users.py @@ -71,9 +71,6 @@ class CreateUserRequestDto(BaseModel): hwidDeviceLimit: Optional[int] = Field( None, serialization_alias="hwidDeviceLimit", strict=True, ge=0 ) - activate_all_inbounds: Optional[bool] = Field( - None, serialization_alias="activateAllInbounds" - ) active_internal_squads: Optional[List[str]] = Field( None, serialization_alias="activeInternalSquads" ) diff --git a/tests/test_users.py b/tests/test_users.py index 500093b..8972b68 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -34,7 +34,6 @@ async def test_users(remnawave) -> None: email=email, telegram_id=telegram_id, expire_at=expire_at, - activate_all_inbounds=True, ) )