diff --git a/README.md b/README.md index 3f14e19..2e44b60 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ pip install git+https://github.com/sm1ky/remnawave-api.git@development | Contract Version | Remnawave Panel Version | | ---------------- | ----------------------- | +| 1.1.2 | 1.6.3 | | 1.1.1 | 1.6.1, 1.6.2 | | 1.1.0 | 1.6.0 | | 1.0.8 | 1.5.7 | diff --git a/pyproject.toml b/pyproject.toml index 6246937..ebf352e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "remnawave-api" -version = "1.1.1" +version = "1.1.2" description = "A Python SDK for interacting with the Remnawave API." authors = [ {name = "Artem",email = "sm1ky@forestsnet.com"} @@ -32,8 +32,10 @@ classifiers = [ [project.urls] Homepage = "https://github.com/sm1ky/remnawave-api" -Panel Page = "https://remna.st/" +"Panel Page" = "https://remna.st/" Developer = "https://t.me/forests_dev" +"Community Chat" = "https://t.me/+xQs17zMzwCY1NzYy" +"Update Channel" = "https://t.me/remnawave" [tool.poetry.group.test.dependencies] ruff = "^0.4.4" diff --git a/remnawave_api/controllers/auth.py b/remnawave_api/controllers/auth.py index cb9a9a7..3656f7c 100644 --- a/remnawave_api/controllers/auth.py +++ b/remnawave_api/controllers/auth.py @@ -8,6 +8,7 @@ from remnawave_api.models import ( RegisterRequestDto, RegisterResponseDto, StatusResponseDto, + LoginTelegramRequestDto, ) from remnawave_api.rapid import BaseController, get, post @@ -35,3 +36,11 @@ class AuthController(BaseController): ) -> StatusResponseDto: """Get status""" ... + + @post("/auth/oauth2/tg/callback", response_class=LoginResponseDto) + async def oauth2_tg_callback( + self, + body: Annotated[LoginTelegramRequestDto, PydanticBody()], + ) -> LoginResponseDto: + """OAuth2 Telegram callback""" + ... \ No newline at end of file diff --git a/remnawave_api/controllers/users.py b/remnawave_api/controllers/users.py index 9d8957d..3ebce1d 100644 --- a/remnawave_api/controllers/users.py +++ b/remnawave_api/controllers/users.py @@ -1,4 +1,4 @@ -from typing import Annotated +from typing import Annotated, Optional from rapid_api_client import Path, Query from rapid_api_client.annotations import PydanticBody @@ -11,6 +11,8 @@ from remnawave_api.models import ( UpdateUserRequestDto, UserResponseDto, UsersResponseDto, + TagsResponseDto, + RevokeUserRequestDto ) from remnawave_api.rapid import BaseController, delete, get, patch, post @@ -62,6 +64,7 @@ class UsersController(BaseController): async def revoke_user_subscription( self, uuid: Annotated[str, Path(description="UUID of the user")], + body: Optional[Annotated[RevokeUserRequestDto, PydanticBody()]] = None, ) -> UserResponseDto: """Revoke User Subscription""" ... @@ -155,4 +158,11 @@ class UsersController(BaseController): tag: Annotated[str, Path(description="Tag of the user")], ) -> UsersResponseDto: """Get Users By Tag""" + ... + + @get("/users/tags", response_class=TagsResponseDto) + async def get_all_tags( + self, + ) -> TagsResponseDto: + """Get All Tags""" ... \ No newline at end of file diff --git a/remnawave_api/models/__init__.py b/remnawave_api/models/__init__.py index 1c074ea..81e1901 100644 --- a/remnawave_api/models/__init__.py +++ b/remnawave_api/models/__init__.py @@ -10,6 +10,7 @@ from .auth import ( RegisterRequestDto, RegisterResponseDto, StatusResponseDto, + LoginTelegramRequestDto ) from .bandwidthstats import NodesUsageResponseDto, NodeUsageResponseDto, NodesRealtimeUsageResponseDto, NodeRealtimeUsageResponseDto from .hosts import ( @@ -81,6 +82,8 @@ from .users import ( UserLastConnectedNodeDto, UserResponseDto, UsersResponseDto, + TagsResponseDto, + RevokeUserRequestDto ) from .users_bulk_actions import ( BulkAllResetTrafficUsersResponseDto, @@ -181,5 +184,8 @@ __all__ = [ "CreateHWIDUser", "HWIDUserResponseDto", "HWIDUserResponseDtoList", - "HWIDDeleteRequest" + "HWIDDeleteRequest", + "LoginTelegramRequestDto", + "TagsResponseDto", + "RevokeUserRequestDto" ] diff --git a/remnawave_api/models/auth.py b/remnawave_api/models/auth.py index 84d5e62..25da1f4 100644 --- a/remnawave_api/models/auth.py +++ b/remnawave_api/models/auth.py @@ -24,3 +24,12 @@ class RegisterRequestDto(BaseModel): class StatusResponseDto(BaseModel): is_login_allowed: bool = Field(alias="isLoginAllowed") is_register_allowed: bool = Field(alias="isRegisterAllowed") + +class LoginTelegramRequestDto(BaseModel): + id: int + first_name: str + last_name: str + username: str + photo_url: str + auth_date: int + hash: str \ No newline at end of file diff --git a/remnawave_api/models/users.py b/remnawave_api/models/users.py index 183ec32..a871178 100644 --- a/remnawave_api/models/users.py +++ b/remnawave_api/models/users.py @@ -143,3 +143,16 @@ class UsersResponseDto(BaseModel): class DeleteUserResponseDto(BaseModel): is_deleted: bool = Field(alias="isDeleted") + +class TagsResponseDto(BaseModel): + tags: List[str] + +class RevokeUserRequestDto(BaseModel): + short_uuid: Optional[str] = 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.", + min_length=6, + max_length=48, + pattern=r"^[a-zA-Z0-9_-]+$", + ) \ No newline at end of file diff --git a/tests/test_auth.py b/tests/test_auth.py index e477400..f93edbc 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,6 +1,7 @@ import pytest -from remnawave_api.models import LoginRequestDto, LoginResponseDto +from remnawave_api.models import LoginRequestDto, LoginResponseDto, LoginTelegramRequestDto +from remnawave_api.exceptions import ForbiddenError, ApiError from tests.conftest import REMNAWAVE_ADMIN_PASSWORD, REMNAWAVE_ADMIN_USERNAME @@ -13,3 +14,22 @@ async def test_auth(remnawave): ) ) assert isinstance(login, LoginResponseDto) + + try: + telegram_login = await remnawave.auth.oauth2_tg_callback( + LoginTelegramRequestDto( + id=123456789, + first_name="Test", + last_name="User", + username="testuser", + photo_url="https://example.com/photo.jpg", + auth_date=1234567890, + hash="examplehash", + ) + ) + pytest.fail("Expected 403 error, but got successful response") + except ForbiddenError as e: + assert e.status_code == 403, f"Expected 403, got {e.status_code}" + print(f"Получено ожидаемое исключение: {e}") + except ApiError as e: + pytest.fail(f"Неожиданное исключение: {e}") \ No newline at end of file diff --git a/tests/test_users.py b/tests/test_users.py index ad3fe46..57538f5 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -14,6 +14,8 @@ from remnawave_api.models import ( UpdateUserRequestDto, UserResponseDto, UsersResponseDto, + TagsResponseDto, + RevokeUserRequestDto ) from tests.utils import generate_email, generate_random_string @@ -118,7 +120,10 @@ async def test_users(remnawave) -> None: assert update_user.description == update_description revoke_user_subscription = await remnawave.users.revoke_user_subscription( - uuid=string_uuid + uuid=string_uuid, + # body=RevokeUserRequestDto( + # short_uuid="fokfaa" + # ) ) assert isinstance(revoke_user_subscription, UserResponseDto) assert revoke_user_subscription.uuid == create_user.uuid @@ -127,3 +132,6 @@ async def test_users(remnawave) -> None: delete_user = await remnawave.users.delete_user(uuid=string_uuid) assert isinstance(delete_user, DeleteUserResponseDto) assert delete_user.is_deleted is True + + users_tags = await remnawave.users.get_all_tags() + assert isinstance(users_tags, TagsResponseDto) \ No newline at end of file