diff --git a/.gitignore b/.gitignore index dfb63b8..a8453d3 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,4 @@ test.py .DS_Store docs/ openapi/ +.DS_Store diff --git a/pyproject.toml b/pyproject.toml index dbb9578..1f0b5bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,8 @@ addopts = [ "-n", "logical", "-ra", "--strict-config", "--strict-markers" ] testpaths = ["tests"] log_cli_level = "INFO" xfail_strict = true +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "function" [build-system] requires = ["poetry-core>=2.0.0,<3.0.0"] diff --git a/pytest.ini b/pytest.ini index d280de0..2d371ae 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,3 @@ [pytest] -asyncio_mode = auto \ No newline at end of file +asyncio_mode = auto +asyncio_default_fixture_loop_scope = function \ No newline at end of file diff --git a/remnawave_api/controllers/api_tokens_management.py b/remnawave_api/controllers/api_tokens_management.py index ebba5a9..49f514e 100644 --- a/remnawave_api/controllers/api_tokens_management.py +++ b/remnawave_api/controllers/api_tokens_management.py @@ -14,7 +14,7 @@ from remnawave_api.rapid import BaseController, delete, get, post class APITokensManagementController(BaseController): - @post("/tokens/create", response_class=CreateApiTokenResponseDto) + @post("/tokens", response_class=CreateApiTokenResponseDto) async def create( self, body: Annotated[CreateApiTokenRequestDto, PydanticBody()], @@ -22,7 +22,7 @@ class APITokensManagementController(BaseController): """Create new API token""" ... - @delete("/tokens/delete/{uuid}", response_class=DeleteApiTokenResponseDto) + @delete("/tokens/{uuid}", response_class=DeleteApiTokenResponseDto) async def delete( self, uuid: Annotated[str, Path(description="UUID of the API token")], diff --git a/remnawave_api/controllers/bandwidthstats.py b/remnawave_api/controllers/bandwidthstats.py index e18ea2b..e83558d 100644 --- a/remnawave_api/controllers/bandwidthstats.py +++ b/remnawave_api/controllers/bandwidthstats.py @@ -2,7 +2,7 @@ from typing import Annotated from rapid_api_client import Query -from remnawave_api.models import NodesUsageResponseDto +from remnawave_api.models import NodesUsageResponseDto, NodesRealtimeUsageResponseDto from remnawave_api.rapid import BaseController, get @@ -15,3 +15,11 @@ class BandWidthStatsController(BaseController): ) -> NodesUsageResponseDto: """Get Nodes Usage By Range""" ... + + @get("/nodes/usage/realtime", response_class=NodesRealtimeUsageResponseDto) + async def get_nodes_usage_realtime( + self, + ) -> NodesRealtimeUsageResponseDto: + """Get Nodes Usage Realtime""" + ... + \ No newline at end of file diff --git a/remnawave_api/controllers/hosts.py b/remnawave_api/controllers/hosts.py index b1d60bf..490851b 100644 --- a/remnawave_api/controllers/hosts.py +++ b/remnawave_api/controllers/hosts.py @@ -12,11 +12,11 @@ from remnawave_api.models import ( ReorderHostResponseDto, UpdateHostRequestDto, ) -from remnawave_api.rapid import AttributeBody, BaseController, delete, get, post +from remnawave_api.rapid import AttributeBody, BaseController, delete, get, post, patch class HostsController(BaseController): - @post("/hosts/create", response_class=HostResponseDto) + @post("/hosts", response_class=HostResponseDto) async def create_host( self, body: Annotated[CreateHostRequestDto, PydanticBody()], @@ -24,7 +24,7 @@ class HostsController(BaseController): """Create Host""" ... - @post("/hosts/update", response_class=HostResponseDto) + @patch("/hosts", response_class=HostResponseDto) async def update_host( self, body: Annotated[UpdateHostRequestDto, PydanticBody()], @@ -32,14 +32,22 @@ class HostsController(BaseController): """Update Host""" ... - @get("/hosts/all", response_class=HostsResponseDto) + @get("/hosts", response_class=HostsResponseDto) async def get_all_hosts( self, ) -> HostsResponseDto: """Get All Hosts""" ... + + @delete("/hosts/{uuid}", response_class=DeleteHostResponseDto) + async def delete_host( + self, + uuid: Annotated[str, Path(description="UUID of the host")], + ) -> DeleteHostResponseDto: + """Delete Host""" + ... - @get("/hosts/get-one/{uuid}", response_class=HostResponseDto) + @get("/hosts/{uuid}", response_class=HostResponseDto) async def get_one_host( self, uuid: Annotated[str, Path(description="UUID of the host")], @@ -47,18 +55,10 @@ class HostsController(BaseController): """Get One Host""" ... - @post("/hosts/reorder", response_class=ReorderHostResponseDto) + @post("/hosts/actions/reorder", response_class=ReorderHostResponseDto) async def reorder_hosts( self, hosts: Annotated[List[ReorderHostRequestDto], AttributeBody()], ) -> ReorderHostResponseDto: """Reorder Hosts""" ... - - @delete("/hosts/delete/{uuid}", response_class=DeleteHostResponseDto) - async def delete_host( - self, - uuid: Annotated[str, Path(description="UUID of the host")], - ) -> DeleteHostResponseDto: - """Delete Host""" - ... diff --git a/remnawave_api/controllers/hwid.py b/remnawave_api/controllers/hwid.py new file mode 100644 index 0000000..2e07acd --- /dev/null +++ b/remnawave_api/controllers/hwid.py @@ -0,0 +1,38 @@ +from typing import Annotated +from uuid import UUID + +from rapid_api_client import PydanticBody + +from remnawave_api.models import ( + HWIDUserResponseDto, + HWIDUserResponseDtoList, + CreateHWIDUser, + HWIDDeleteRequest +) +from remnawave_api.rapid import AttributeBody, BaseController, post + + +class HWIDUserController(BaseController): + @post("/hwid/devices", response_class=HWIDUserResponseDtoList) + async def add_hwid_to_users( + self, + body: Annotated[CreateHWIDUser, PydanticBody()], + ) -> HWIDUserResponseDtoList: + """Create a user HWID device""" + ... + + @post("/hwid/devices/delete", response_class=HWIDUserResponseDtoList) + async def delete_hwid_to_user( + self, + body: Annotated[HWIDDeleteRequest, PydanticBody()], + ) -> HWIDUserResponseDtoList: + """Delete a user HWID device""" + ... + + @post("/hwid/devices/{uuid}", response_class=HWIDUserResponseDto) + async def get_hwid_user( + self, + uuid: Annotated[UUID, AttributeBody()], + ) -> HWIDUserResponseDto: + """Get a user HWID device""" + ... \ No newline at end of file diff --git a/remnawave_api/controllers/keygen.py b/remnawave_api/controllers/keygen.py index 2f65345..b3d39c4 100644 --- a/remnawave_api/controllers/keygen.py +++ b/remnawave_api/controllers/keygen.py @@ -3,7 +3,7 @@ from remnawave_api.rapid import BaseController, get class KeygenController(BaseController): - @get("/keygen/get", response_class=PubKeyResponseDto) + @get("/keygen", response_class=PubKeyResponseDto) async def generate_key( self, ) -> PubKeyResponseDto: diff --git a/remnawave_api/controllers/nodes.py b/remnawave_api/controllers/nodes.py index c2afbaf..ce5dcb3 100644 --- a/remnawave_api/controllers/nodes.py +++ b/remnawave_api/controllers/nodes.py @@ -16,7 +16,7 @@ from remnawave_api.rapid import AttributeBody, BaseController, delete, get, patc class NodesController(BaseController): - @post("/nodes/create", response_class=NodeResponseDto) + @post("/nodes", response_class=NodeResponseDto) async def create_node( self, body: Annotated[CreateNodeRequestDto, PydanticBody()], @@ -24,46 +24,30 @@ class NodesController(BaseController): """Create Node""" ... - @get("/nodes/get-all", response_class=NodesResponseDto) + @get("/nodes", response_class=NodesResponseDto) async def get_all_nodes( self, ) -> NodesResponseDto: """Get All Nodes""" ... - @get("/nodes/get-one/{uuid}", response_class=NodeResponseDto) + @get("/nodes/{uuid}", response_class=NodeResponseDto) async def get_one_node( self, uuid: Annotated[str, Path(description="Node UUID")], ) -> NodeResponseDto: """Get One Node""" ... - - @patch("/nodes/enable/{uuid}", response_class=NodeResponseDto) - async def enable_node( - self, - uuid: Annotated[str, Path(description="Node UUID")], - ) -> NodeResponseDto: - """Enable Node""" - ... - - @patch("/nodes/disable/{uuid}", response_class=NodeResponseDto) - async def disable_node( - self, - uuid: Annotated[str, Path(description="Node UUID")], - ) -> NodeResponseDto: - """Disable Node""" - ... - - @delete("/nodes/delete/{uuid}", response_class=DeleteNodeResponseDto) + + @delete("/nodes/{uuid}", response_class=DeleteNodeResponseDto) async def delete_node( self, uuid: Annotated[str, Path(description="Node UUID")], ) -> DeleteNodeResponseDto: """Delete Node""" ... - - @post("/nodes/update", response_class=NodeResponseDto) + + @patch("/nodes", response_class=NodeResponseDto) async def update_node( self, body: Annotated[UpdateNodeRequestDto, PydanticBody()], @@ -71,7 +55,23 @@ class NodesController(BaseController): """Update Node""" ... - @get("/nodes/restart/{uuid}", response_class=RestartNodeResponseDto) + @post("/nodes/{uuid}/actions/enable", response_class=NodeResponseDto) + async def enable_node( + self, + uuid: Annotated[str, Path(description="Node UUID")], + ) -> NodeResponseDto: + """Enable Node""" + ... + + @post("/nodes/{uuid}/actions/disable", response_class=NodeResponseDto) + async def disable_node( + self, + uuid: Annotated[str, Path(description="Node UUID")], + ) -> NodeResponseDto: + """Disable Node""" + ... + + @post("/nodes/{uuid}/actions/restart", response_class=RestartNodeResponseDto) async def restart_node( self, uuid: Annotated[str, Path(description="Node UUID")], @@ -79,14 +79,14 @@ class NodesController(BaseController): """Restart Node""" ... - @patch("/nodes/restart-all", response_class=RestartNodeResponseDto) + @post("/nodes/actions/restart-all", response_class=RestartNodeResponseDto) async def restart_all_nodes( self, ) -> RestartNodeResponseDto: """Restart All Nodes""" ... - @post("/nodes/reorder", response_class=NodesResponseDto) + @post("/nodes/actions/reorder", response_class=NodesResponseDto) async def reorder_nodes( self, nodes: Annotated[List[ReorderNodeRequestDto], AttributeBody()], diff --git a/remnawave_api/controllers/subscriptions_settings.py b/remnawave_api/controllers/subscriptions_settings.py index 986790c..fa33516 100644 --- a/remnawave_api/controllers/subscriptions_settings.py +++ b/remnawave_api/controllers/subscriptions_settings.py @@ -6,19 +6,19 @@ from remnawave_api.models import ( SubscriptionSettingsResponseDto, UpdateSubscriptionSettingsRequestDto, ) -from remnawave_api.rapid import BaseController, get, post +from remnawave_api.rapid import BaseController, get, patch class SubscriptionsSettingsController(BaseController): - @get("/subscription-settings/get", response_class=SubscriptionSettingsResponseDto) + @get("/subscription-settings", response_class=SubscriptionSettingsResponseDto) async def get_settings( self, ) -> SubscriptionSettingsResponseDto: """Get Subscription Settings""" ... - @post( - "/subscription-settings/update", + @patch( + "/subscription-settings", response_class=SubscriptionSettingsResponseDto, ) async def update_settings( diff --git a/remnawave_api/controllers/subscriptions_template.py b/remnawave_api/controllers/subscriptions_template.py index 2de1afa..5a9202b 100644 --- a/remnawave_api/controllers/subscriptions_template.py +++ b/remnawave_api/controllers/subscriptions_template.py @@ -4,12 +4,12 @@ from rapid_api_client.annotations import Path, PydanticBody from remnawave_api.enums import TemplateType from remnawave_api.models import TemplateResponseDto, UpdateTemplateRequestDto -from remnawave_api.rapid import BaseController, get, post +from remnawave_api.rapid import BaseController, get, put class SubscriptionsTemplateController(BaseController): @get( - "/subscription-templates/get-template/{template_type}", + "/subscription-templates/{template_type}", response_class=TemplateResponseDto, ) async def get_template( @@ -19,8 +19,8 @@ class SubscriptionsTemplateController(BaseController): """Get Template""" ... - @post( - "/subscription-templates/update-template", + @put( + "/subscription-templates", response_class=TemplateResponseDto, ) async def update_template( diff --git a/remnawave_api/controllers/system.py b/remnawave_api/controllers/system.py index f41fc26..a206e20 100644 --- a/remnawave_api/controllers/system.py +++ b/remnawave_api/controllers/system.py @@ -14,14 +14,14 @@ class SystemController(BaseController): """Get System Stats""" ... - @get("/system/bandwidth", response_class=BandwidthStatisticResponseDto) + @get("/system/stats/bandwidth", response_class=BandwidthStatisticResponseDto) async def get_bandwidth_stats( self, ) -> BandwidthStatisticResponseDto: """Get System Bandwidth Statistics""" ... - @get("/system/statistics/nodes", response_class=NodesStatisticResponseDto) + @get("/system/stats/nodes", response_class=NodesStatisticResponseDto) async def get_nodes_statistics( self, ) -> NodesStatisticResponseDto: diff --git a/remnawave_api/controllers/users.py b/remnawave_api/controllers/users.py index 597756c..c35d134 100644 --- a/remnawave_api/controllers/users.py +++ b/remnawave_api/controllers/users.py @@ -24,7 +24,7 @@ class UsersController(BaseController): """Create User""" ... - @post("/users/update", response_class=UserResponseDto) + @patch("/users", response_class=UserResponseDto) async def update_user( self, body: Annotated[UpdateUserRequestDto, PydanticBody()], @@ -32,11 +32,11 @@ class UsersController(BaseController): """Update User""" ... - @get("/users/v2", response_class=UsersResponseDto) + @get("/users", response_class=UsersResponseDto) async def get_all_users_v2( self, - start: Annotated[int, Query(description="Index to start pagination from")], - size: Annotated[int, Query(description="Number of users per page")], + start: Annotated[int, Query(default=0, ge=0, description="Index to start pagination from")], + size: Annotated[int, Query(default=25, ge=1, description="Number of users per page")], ) -> UsersResponseDto: """ Get users page from the end. @@ -49,24 +49,8 @@ class UsersController(BaseController): UsersResponseDto """ ... - - @patch("/users/revoke/{uuid}", response_class=UserResponseDto) - async def revoke_user_subscription( - self, - uuid: Annotated[str, Path(description="UUID of the user")], - ) -> UserResponseDto: - """Revoke User Subscription""" - ... - - @patch("/users/disable/{uuid}", response_class=UserResponseDto) - async def disable_user( - self, - uuid: Annotated[str, Path(description="UUID of the user")], - ) -> UserResponseDto: - """Disable User""" - ... - - @delete("/users/delete/{uuid}", response_class=DeleteUserResponseDto) + + @delete("/users/{uuid}", response_class=DeleteUserResponseDto) async def delete_user( self, uuid: Annotated[str, Path(description="UUID of the user")], @@ -74,7 +58,23 @@ class UsersController(BaseController): """Delete User""" ... - @patch("/users/enable/{uuid}", response_class=UserResponseDto) + @post("users/{uuid}/actions/revoke", response_class=UserResponseDto) + async def revoke_user_subscription( + self, + uuid: Annotated[str, Path(description="UUID of the user")], + ) -> UserResponseDto: + """Revoke User Subscription""" + ... + + @post("/users/{uuid}/actions/disable", response_class=UserResponseDto) + async def disable_user( + self, + uuid: Annotated[str, Path(description="UUID of the user")], + ) -> UserResponseDto: + """Disable User""" + ... + + @post("/users/{uuid}/actions/enable", response_class=UserResponseDto) async def enable_user( self, uuid: Annotated[str, Path(description="UUID of the user")], @@ -82,15 +82,23 @@ class UsersController(BaseController): """Enable User""" ... - @patch("/users/reset-traffic/{uuid}", response_class=UserResponseDto) + @post("/users/{uuid}/actions/reset-traffic", response_class=UserResponseDto) async def reset_user_traffic( self, uuid: Annotated[str, Path(description="UUID of the user")], ) -> 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/short-uuid/{short_uuid}", response_class=UserResponseDto) + @get("/users/by-short-uuid/{short_uuid}", response_class=UserResponseDto) async def get_user_by_short_uuid( self, short_uuid: Annotated[str, Path(description="Short UUID of the user")], @@ -98,7 +106,7 @@ class UsersController(BaseController): """Get User By Short UUID""" ... - @get("/users/sub-uuid/{subscription_uuid}", response_class=UserResponseDto) + @get("/users/by-subscription-uuid/{subscription_uuid}", response_class=UserResponseDto) async def get_user_by_subscription_uuid( self, subscription_uuid: Annotated[str, Path(description="UUID of the subscription")], @@ -106,7 +114,7 @@ class UsersController(BaseController): """Get User By Subscription UUID""" ... - @get("/users/uuid/{uuid}", response_class=UserResponseDto) + @get("/users/{uuid}", response_class=UserResponseDto) async def get_user_by_uuid( self, uuid: Annotated[str, Path(description="UUID of the user")], @@ -114,7 +122,7 @@ class UsersController(BaseController): """Get User By UUID""" ... - @get("/users/username/{username}", response_class=UserResponseDto) + @get("/users/by-username/{username}", response_class=UserResponseDto) async def get_user_by_username( self, username: Annotated[str, Path(description="Username of the user")], @@ -123,7 +131,7 @@ class UsersController(BaseController): ... @get( - "/users/tg/{telegram_id}", + "/users/by-telegram-id/{telegram_id}", response_class=TelegramUserResponseDto, ) async def get_users_by_telegram_id( @@ -133,7 +141,7 @@ class UsersController(BaseController): """Get Users By Telegram ID""" ... - @get("/users/email/{email}", response_class=EmailUserResponseDto) + @get("/users/by-email/{email}", response_class=EmailUserResponseDto) async def get_users_by_email( self, email: Annotated[str, Path(description="Email of the user")], diff --git a/remnawave_api/controllers/users_bulk_actions.py b/remnawave_api/controllers/users_bulk_actions.py index 801ce4f..7ca373a 100644 --- a/remnawave_api/controllers/users_bulk_actions.py +++ b/remnawave_api/controllers/users_bulk_actions.py @@ -78,7 +78,7 @@ class UsersBulkActionsController(BaseController): """Bulk Update All Users""" ... - @patch( + @post( "/users/bulk/all/reset-traffic", response_class=BulkAllResetTrafficUsersResponseDto, ) diff --git a/remnawave_api/controllers/users_stats.py b/remnawave_api/controllers/users_stats.py index 1ee17e3..fbaad34 100644 --- a/remnawave_api/controllers/users_stats.py +++ b/remnawave_api/controllers/users_stats.py @@ -8,7 +8,7 @@ from remnawave_api.rapid import BaseController, get class UsersStatsController(BaseController): @get( - "/users/stats/usage/range/{uuid}", + "/users/stats/usage/{uuid}/range", response_class=UserUsageByRangeResponseDto, ) async def get_user_usage_by_range( diff --git a/remnawave_api/controllers/xray_config.py b/remnawave_api/controllers/xray_config.py index 93309a4..83b7d8f 100644 --- a/remnawave_api/controllers/xray_config.py +++ b/remnawave_api/controllers/xray_config.py @@ -3,18 +3,18 @@ from typing import Annotated from rapid_api_client.annotations import JsonBody from remnawave_api.models import ConfigResponseDto -from remnawave_api.rapid import BaseController, get, post +from remnawave_api.rapid import BaseController, get, put class XrayConfigController(BaseController): - @get("/xray/get-config", response_class=ConfigResponseDto) + @get("/xray", response_class=ConfigResponseDto) async def get_config( self, ) -> ConfigResponseDto: """Get Xray Config""" ... - @post("/xray/update-config", response_class=ConfigResponseDto) + @put("/xray", response_class=ConfigResponseDto) async def update_config( self, body: Annotated[dict, JsonBody()], diff --git a/remnawave_api/models/__init__.py b/remnawave_api/models/__init__.py index 9147eea..f6c94b1 100644 --- a/remnawave_api/models/__init__.py +++ b/remnawave_api/models/__init__.py @@ -11,7 +11,7 @@ from .auth import ( RegisterResponseDto, StatusResponseDto, ) -from .bandwidthstats import NodesUsageResponseDto, NodeUsageResponseDto +from .bandwidthstats import NodesUsageResponseDto, NodeUsageResponseDto, NodesRealtimeUsageResponseDto, NodeRealtimeUsageResponseDto from .hosts import ( CreateHostRequestDto, DeleteHostResponseDto, @@ -92,6 +92,12 @@ from .users_bulk_actions import ( ) from .users_stats import UserUsageByRange, UserUsageByRangeResponseDto from .xray_config import ConfigResponseDto +from .hwid import ( + CreateHWIDUser, + HWIDUserResponseDto, + HWIDUserResponseDtoList, + HWIDDeleteRequest +) __all__ = [ "CPUStatistic", @@ -172,4 +178,10 @@ __all__ = [ "CreateApiTokenResponseDto", "CreateApiTokenRequestDto", "DeleteApiTokenResponseDto", + "NodesRealtimeUsageResponseDto", + "NodeRealtimeUsageResponseDto", + "CreateHWIDUser", + "HWIDUserResponseDto", + "HWIDUserResponseDtoList", + "HWIDDeleteRequest" ] diff --git a/remnawave_api/models/api_tokens_management.py b/remnawave_api/models/api_tokens_management.py index 74f2097..e3265ee 100644 --- a/remnawave_api/models/api_tokens_management.py +++ b/remnawave_api/models/api_tokens_management.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import List, Optional -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field class CreateApiTokenRequestDto(BaseModel): @@ -39,5 +39,4 @@ class FindAllApiTokensResponseDto(BaseModel): api_keys: List[ApiTokenDto] = Field(..., alias="apiKeys") docs: DocsInfoDto - class Config: - populate_by_name = True \ No newline at end of file + model_config = ConfigDict(populate_by_name=True) \ No newline at end of file diff --git a/remnawave_api/models/bandwidthstats.py b/remnawave_api/models/bandwidthstats.py index a2aaad8..83797a5 100644 --- a/remnawave_api/models/bandwidthstats.py +++ b/remnawave_api/models/bandwidthstats.py @@ -19,3 +19,18 @@ class NodeUsageResponseDto(BaseModel): class NodesUsageResponseDto(BaseModel): response: List[NodeUsageResponseDto] + + +class NodeRealtimeUsageResponseDto(BaseModel): + node_uuid: UUID = Field(alias="nodeUuid") + node_name: str = Field(alias="nodeName") + country_code: str = Field(alias="countryCode") + download_bytes: float = Field(alias="downloadBytes") + upload_bytes: float = Field(alias="uploadBytes") + total_bytes: float = Field(alias="totalBytes") + download_speed_bps: float = Field(alias="downloadSpeedBps") + upload_speed_bps: float = Field(alias="uploadSpeedBps") + total_speed_bps: float = Field(alias="totalSpeedBps") + +class NodesRealtimeUsageResponseDto(BaseModel): + response: List[NodeRealtimeUsageResponseDto] diff --git a/remnawave_api/models/hwid.py b/remnawave_api/models/hwid.py new file mode 100644 index 0000000..1c49004 --- /dev/null +++ b/remnawave_api/models/hwid.py @@ -0,0 +1,30 @@ +from typing import Any, List, Optional +from uuid import UUID + +from pydantic import BaseModel, Field + +class CreateHWIDUser(BaseModel): + hwid: str + userUuid: UUID + platform: str + osVersion: str + deviceModel: str + userAgent: str + +class HWIDUserResponseDto(BaseModel): + hwid: str + user_uuid: UUID = Field(alias="userUuid") + platform: str + os_version: str = Field(alias="osVersion") + device_model: str = Field(alias="deviceModel") + user_agent: str = Field(alias="userAgent") + created_at: str = Field(alias="createdAt") + updated_at: str = Field(alias="updatedAt") + +class HWIDUserResponseDtoList(BaseModel): + response: List[HWIDUserResponseDto] + +class HWIDDeleteRequest(BaseModel): + hwid: str + userUuid: UUID + diff --git a/remnawave_api/models/subscriptions_settings.py b/remnawave_api/models/subscriptions_settings.py index c95d996..e8991f8 100644 --- a/remnawave_api/models/subscriptions_settings.py +++ b/remnawave_api/models/subscriptions_settings.py @@ -25,7 +25,6 @@ class SubscriptionSettingsResponseDto(BaseModel): created_at: datetime = Field(alias="createdAt") updated_at: datetime = Field(alias="updatedAt") - class UpdateSubscriptionSettingsRequestDto(BaseModel): uuid: UUID profile_title: Optional[str] = Field(None, serialization_alias="profileTitle") @@ -42,6 +41,9 @@ class UpdateSubscriptionSettingsRequestDto(BaseModel): add_username_to_base_subscription: Optional[bool] = Field( None, serialization_alias="addUsernameToBaseSubscription" ) + is_show_custom_remarks: Optional[bool] = Field( + None, serialization_alias="isShowCustomRemarks" + ) happ_announce: Annotated[Optional[str], StringConstraints(max_length=200)] = Field( None, serialization_alias="happAnnounce" ) @@ -55,3 +57,6 @@ class UpdateSubscriptionSettingsRequestDto(BaseModel): disabled_users_remarks: Optional[List[str]] = Field( None, serialization_alias="disabledUsersRemarks" ) + custom_response_headers: Optional[dict] = Field( + None, serialization_alias="customResponseHeaders" + ) \ No newline at end of file