diff --git a/remnawave/controllers/hwid.py b/remnawave/controllers/hwid.py index acde1c2..2dbf37d 100644 --- a/remnawave/controllers/hwid.py +++ b/remnawave/controllers/hwid.py @@ -20,7 +20,7 @@ class HWIDUserController(BaseController): ) -> CreateUserHwidDeviceResponseDto: """Create a user HWID device""" ... - + @post("/hwid/devices/delete", response_class=DeleteUserHwidDeviceResponseDto) async def delete_hwid_to_user( self, @@ -28,11 +28,19 @@ class HWIDUserController(BaseController): ) -> DeleteUserHwidDeviceResponseDto: """Delete a user HWID device""" ... - + + @post("/hwid/devices/delete-all", response_class=CreateUserHwidDeviceResponseDto) + async def delete_all_hwid_user( + self, + uuid: Annotated[str, Path(description="UUID of the User")], + ) -> CreateUserHwidDeviceResponseDto: + """Delete all user HWID devices""" + ... + @get("/hwid/devices/{uuid}", response_class=GetUserHwidDevicesResponseDto) async def get_hwid_user( self, uuid: Annotated[str, Path(description="UUID of the User")], ) -> GetUserHwidDevicesResponseDto: """Get a user HWID device""" - ... \ No newline at end of file + ... diff --git a/remnawave/models/hwid.py b/remnawave/models/hwid.py index 1904287..5e4e58b 100644 --- a/remnawave/models/hwid.py +++ b/remnawave/models/hwid.py @@ -31,22 +31,22 @@ class HwidDeviceDto(BaseModel): class HwidDevicesData(BaseModel): - total: float + total: int devices: List[HwidDeviceDto] class CreateUserHwidDeviceResponseDto(BaseModel): - total: float + total: int devices: List[HwidDeviceDto] class DeleteUserHwidDeviceResponseDto(BaseModel): - total: float + total: int devices: List[HwidDeviceDto] class GetUserHwidDevicesResponseDto(BaseModel): - total: float + total: int devices: List[HwidDeviceDto] @@ -55,4 +55,3 @@ CreateHWIDUser = CreateUserHwidDeviceRequestDto HWIDUserResponseDto = HwidDeviceDto HWIDUserResponseDtoList = HwidDevicesData HWIDDeleteRequest = DeleteUserHwidDeviceRequestDto - diff --git a/remnawave/models/users.py b/remnawave/models/users.py index cc47ff4..13dba13 100644 --- a/remnawave/models/users.py +++ b/remnawave/models/users.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Annotated, List, Optional +from typing import Annotated from uuid import UUID from pydantic import ( @@ -16,8 +16,8 @@ class UserActiveInboundsDto(BaseModel): uuid: UUID tag: str type: str - network: Optional[str] = None - security: Optional[str] = None + network: str | None = None + security: str | None = None class UserLastConnectedNodeDto(BaseModel): @@ -39,103 +39,99 @@ class CreateUserRequestDto(BaseModel): username: Annotated[ str, StringConstraints(pattern=r"^[a-zA-Z0-9_-]+$", min_length=3, max_length=36) ] - created_at: Optional[datetime] = Field(None, serialization_alias="createdAt") - status: Optional[UserStatus] = None - subscription_uuid: Optional[str] = Field( - None, serialization_alias="subscriptionUuid" - ) - short_uuid: Optional[str] = Field(None, serialization_alias="shortUuid") + created_at: datetime | None = Field(None, serialization_alias="createdAt") + status: UserStatus | None = None + short_uuid: str | None = Field(None, serialization_alias="shortUuid") trojan_password: Annotated[ - Optional[str], StringConstraints(min_length=8, max_length=32) + str | None, StringConstraints(min_length=8, max_length=32) ] = Field(None, serialization_alias="trojanPassword") - vless_uuid: Optional[str] = Field(None, serialization_alias="vlessUuid") + vless_uuid: str | None = Field(None, serialization_alias="vlessUuid") ss_password: Annotated[ - Optional[str], StringConstraints(min_length=8, max_length=32) + str | None, StringConstraints(min_length=8, max_length=32) ] = Field(None, serialization_alias="ssPassword") - traffic_limit_bytes: Optional[int] = Field( + traffic_limit_bytes: int | None = Field( None, serialization_alias="trafficLimitBytes", strict=True, ge=0 ) - traffic_limit_strategy: Optional[TrafficLimitStrategy] = Field( + traffic_limit_strategy: TrafficLimitStrategy | None = Field( None, serialization_alias="trafficLimitStrategy" ) - last_traffic_reset_at: Optional[datetime] = Field( + last_traffic_reset_at: datetime | None = Field( None, serialization_alias="lastTrafficResetAt" ) - description: Optional[str] = None - tag: Optional[str] = None - telegram_id: Optional[int] = Field(None, serialization_alias="telegramId") - email: Optional[str] = None - hwidDeviceLimit: Optional[int] = Field( + description: str | None = None + tag: str | None = None + telegram_id: int | None = Field(None, serialization_alias="telegramId") + email: str | None = None + hwidDeviceLimit: int | None = Field( None, serialization_alias="hwidDeviceLimit", strict=True, ge=0 ) - active_internal_squads: Optional[List[str]] = Field( + active_internal_squads: list[str] | None = Field( None, serialization_alias="activeInternalSquads" ) class UpdateUserRequestDto(BaseModel): uuid: UUID - active_internal_squads: Optional[List[str]] = Field( + active_internal_squads: list[str] | None = Field( None, serialization_alias="activeInternalSquads" ) - description: Optional[str] = None - email: Optional[str] = None - expire_at: Optional[datetime] = Field(None, serialization_alias="expireAt") - hwidDeviceLimit: Optional[int] = Field( + description: str | None = None + email: str | None = None + expire_at: datetime | None = Field(None, serialization_alias="expireAt") + hwidDeviceLimit: int | None = Field( None, serialization_alias="hwidDeviceLimit", strict=True, ge=0 ) - status: Optional[UserStatus] = None - tag: Optional[str] = None - telegram_id: Optional[int] = Field(None, serialization_alias="telegramId") - traffic_limit_bytes: Optional[int] = Field( + status: UserStatus | None = None + tag: str | None = None + telegram_id: int | None = Field(None, serialization_alias="telegramId") + traffic_limit_bytes: int | None = Field( None, serialization_alias="trafficLimitBytes", strict=True, ge=0 ) - traffic_limit_strategy: Optional[TrafficLimitStrategy] = Field( + traffic_limit_strategy: TrafficLimitStrategy | None = Field( None, serialization_alias="trafficLimitStrategy" ) class UserResponseDto(BaseModel): uuid: UUID - subscription_uuid: Optional[UUID] = Field(None, alias="subscriptionUuid") short_uuid: str = Field(alias="shortUuid") username: str - status: Optional[UserStatus] = None + status: UserStatus | None = None used_traffic_bytes: float = Field(alias="usedTrafficBytes") lifetime_used_traffic_bytes: float = Field(alias="lifetimeUsedTrafficBytes") - traffic_limit_bytes: Optional[int] = Field(None, alias="trafficLimitBytes") - traffic_limit_strategy: Optional[str] = Field(None, alias="trafficLimitStrategy") - sub_last_user_agent: Optional[str] = Field(None, alias="subLastUserAgent") - sub_last_opened_at: Optional[datetime] = Field(None, alias="subLastOpenedAt") - expire_at: Optional[datetime] = Field(None, 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") + traffic_limit_bytes: int | None = Field(None, alias="trafficLimitBytes") + traffic_limit_strategy: str | None = Field(None, alias="trafficLimitStrategy") + sub_last_user_agent: str | None = Field(None, alias="subLastUserAgent") + sub_last_opened_at: datetime | None = Field(None, alias="subLastOpenedAt") + expire_at: datetime | None = Field(None, alias="expireAt") + online_at: datetime | None = Field(None, alias="onlineAt") + sub_revoked_at: datetime | None = Field(None, alias="subRevokedAt") + last_traffic_reset_at: datetime | None = 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 - telegram_id: Optional[int] = Field(None, alias="telegramId") - email: Optional[str] = None - hwidDeviceLimit: Optional[int] = Field( + description: str | None = None + telegram_id: int | None = Field(None, alias="telegramId") + email: str | None = None + hwidDeviceLimit: int | None = Field( None, serialization_alias="hwidDeviceLimit", strict=True, ge=0 ) - active_internal_squads: Optional[List[ActiveInternalSquadDto]] = Field( + active_internal_squads: list[ActiveInternalSquadDto] | None = Field( None, alias="activeInternalSquads" ) - subscription_url: str = Field(alias="subscriptionUrl") - first_connected: Optional[datetime] = Field(None, alias="firstConnectedAt") - last_trigger_threshold: Optional[int] = Field(None, alias="lastTriggeredThreshold") - last_connected_node: Optional[UserLastConnectedNodeDto] = Field( + subscription_url: str | None = Field(None, alias="subscriptionUrl") + first_connected: datetime | None = Field(None, alias="firstConnectedAt") + last_trigger_threshold: int | None = Field(None, alias="lastTriggeredThreshold") + last_connected_node: UserLastConnectedNodeDto | None = Field( None, alias="lastConnectedNode" ) - happ: Optional[HappCrypto] = Field(None, alias="happ") - tag: Optional[str] = Field(None, alias="tag") + happ: HappCrypto | None = Field(None, alias="happ") + tag: str | None = Field(None, alias="tag") created_at: datetime = Field(alias="createdAt") updated_at: datetime = Field(alias="updatedAt") -class EmailUserResponseDto(RootModel[List[UserResponseDto]]): +class EmailUserResponseDto(RootModel[list[UserResponseDto]]): def __iter__(self): return iter(self.root) @@ -143,7 +139,7 @@ class EmailUserResponseDto(RootModel[List[UserResponseDto]]): return self.root[item] -class TagUserResponseDto(RootModel[List[UserResponseDto]]): +class TagUserResponseDto(RootModel[list[UserResponseDto]]): def __iter__(self): return iter(self.root) @@ -151,7 +147,7 @@ class TagUserResponseDto(RootModel[List[UserResponseDto]]): return self.root[item] -class TelegramUserResponseDto(RootModel[List[UserResponseDto]]): +class TelegramUserResponseDto(RootModel[list[UserResponseDto]]): def __iter__(self): return iter(self.root) @@ -160,7 +156,7 @@ class TelegramUserResponseDto(RootModel[List[UserResponseDto]]): class UsersResponseDto(BaseModel): - users: List[UserResponseDto] + users: list[UserResponseDto] total: float @@ -169,7 +165,7 @@ class DeleteUserResponseDto(BaseModel): class TagsResponseDto(BaseModel): - tags: List[str] + tags: list[str] class CreateUserResponseDto(UserResponseDto): @@ -213,7 +209,7 @@ class GetUserByUsernameResponseDto(UserResponseDto): class RevokeUserRequestDto(BaseModel): - short_uuid: Optional[str] = Field( + short_uuid: str | None = Field( None, serialization_alias="shortUuid", description="Optional. If not provided, a new short UUID will be generated by Remnawave. Please note that it is strongly recommended to allow Remnawave to generate the short UUID.",