Ver Fonte

Update for Chatto API changes, bump to 0.0.149a0

- Remove createSpace and createUser mutations (removed from API)
- Fix roomEvents before/after params: ID → Time scalar
- Update CLAUDE.md, tests, and version
TheCodemancer há 5 meses atrás
pai
commit
578eb6a919
6 ficheiros alterados com 5 adições e 93 exclusões
  1. 3 3
      CLAUDE.md
  2. 1 1
      pyproject.toml
  3. 0 14
      src/chattolib/client.py
  4. 1 24
      src/chattolib/queries.py
  5. 0 34
      tests/test_client.py
  6. 0 17
      tests/test_integration.py

+ 3 - 3
CLAUDE.md

@@ -42,12 +42,12 @@ The library uses **httpx** for async HTTP and **websockets** for GraphQL subscri
 
 | Domain | Queries | Mutations | Subscriptions |
 |---|---|---|---|
-| **Spaces** | `spaces`, `space(id)` | `createSpace`, `updateSpace`, `joinSpace`, `leaveSpace`, logo/banner uploads | `mySpaceEvents` |
+| **Spaces** | `spaces`, `space(id)` | `updateSpace`, `joinSpace`, `leaveSpace`, logo/banner uploads | `mySpaceEvents` |
 | **Rooms** | `room`, `roomEvents`, `roomEventByEventId`, `threadEvents`, `roomEventsAround` | `createRoom`, `updateRoom`, `archiveRoom`, `joinRoom`, `leaveRoom`, `markRoomAsRead` | via space events |
 | **Messages** | (via roomEvents) | `postMessage`, `editMessage`, `deleteMessage` | `MessagePostedEvent`, `MessageUpdatedEvent`, `MessageDeletedEvent` |
 | **Reactions** | (on message events) | `addReaction`, `removeReaction` | `ReactionAddedEvent`, `ReactionRemovedEvent` |
 | **Threads** | `threadEvents`, `myFollowedThreads` | `followThread`, `unfollowThread`, `markThreadAsOpened` | `ThreadFollowChangedEvent` |
-| **Users** | `me`, `user(id)`, `userByLogin`, `users` | `updateMyProfile`, `uploadMyAvatar`, `deleteMyAvatar`, `createUser` | `UserProfileUpdatedEvent`, `PresenceChangedEvent` |
+| **Users** | `me`, `user(id)`, `userByLogin`, `users` | `updateMyProfile`, `uploadMyAvatar`, `deleteMyAvatar` | `UserProfileUpdatedEvent`, `PresenceChangedEvent` |
 | **DMs** | (via rooms) | `startDM` | `NewDirectMessageNotificationEvent` |
 | **Notifications** | `notifications`, `hasNotifications` | `dismissNotification`, `dismissAllNotifications` | `NotificationCreatedEvent`, `NotificationDismissedEvent` |
 | **Permissions/Roles** | via `admin` query, `space.roles` | `grantInstancePermission`, `createRole`, `assignInstanceRole`, space-level equivalents | — |
@@ -59,7 +59,7 @@ The library uses **httpx** for async HTTP and **websockets** for GraphQL subscri
 - IDs are opaque strings (`ID` scalar).
 - Large integers use `Int64` scalar (e.g., byte counts) — map to Python `int`.
 - File uploads use a custom `Upload` scalar (multipart form).
-- Pagination uses `limit`/`before`/`after` cursor style on room events; `limit`/`offset` on space members.
+- Pagination uses `limit`/`before`/`after` on room events (`before`/`after` are `Time` scalars, ISO timestamps); `limit`/`offset` on space members.
 - All mutations take a single `input` argument with a corresponding `*Input` type.
 - Subscriptions use `spaceId` scoping (`mySpaceEvents`) or are instance-wide (`myInstanceEvents`).
 - Image URLs accept optional `width`, `height`, `fit` (enum: `CONTAIN`, `COVER`, `EXACT`) for server-side resizing.

+ 1 - 1
pyproject.toml

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
 
 [project]
 name = "chattolib"
-version = "0.1.0"
+version = "0.0.149a0"
 description = "Async Python client library for the Chatto webchat GraphQL API"
 requires-python = ">=3.11"
 license = "MIT"

+ 0 - 14
src/chattolib/client.py

@@ -349,13 +349,6 @@ class ChattoClient:
 
     # --- Mutations ---
 
-    async def create_user(self, login: str, display_name: str, password: str) -> User:
-        data = await self._execute(
-            Q.MUTATION_CREATE_USER,
-            {"input": {"login": login, "displayName": display_name, "password": password}},
-        )
-        return _parse_user(data["createUser"])
-
     async def post_message(
         self,
         space_id: str,
@@ -418,13 +411,6 @@ class ChattoClient:
         )
         return data["removeReaction"]
 
-    async def create_space(self, name: str, description: str | None = None) -> Space:
-        input_data: dict[str, Any] = {"name": name}
-        if description is not None:
-            input_data["description"] = description
-        data = await self._execute(Q.MUTATION_CREATE_SPACE, {"input": input_data})
-        return _parse_space(data["createSpace"])
-
     async def join_space(self, space_id: str) -> dict[str, Any]:
         data = await self._execute(Q.MUTATION_JOIN_SPACE, {"input": {"spaceId": space_id}})
         return data["joinSpace"]

+ 1 - 24
src/chattolib/queries.py

@@ -59,7 +59,7 @@ query Room($spaceId: ID!, $roomId: ID!) {
 """
 
 QUERY_ROOM_EVENTS = """
-query RoomEvents($spaceId: ID!, $roomId: ID!, $limit: Int, $before: ID, $after: ID) {
+query RoomEvents($spaceId: ID!, $roomId: ID!, $limit: Int, $before: Time, $after: Time) {
     roomEvents(spaceId: $spaceId, roomId: $roomId, limit: $limit, before: $before, after: $after) {
         events {
             id
@@ -199,19 +199,6 @@ query FollowedThreads($spaceId: ID!) {
 
 # --- Mutations ---
 
-MUTATION_CREATE_USER = """
-mutation CreateUser($input: CreateUserInput!) {
-    createUser(input: $input) {
-        id
-        login
-        displayName
-        createdAt
-        avatarUrl
-        presenceStatus
-    }
-}
-"""
-
 MUTATION_POST_MESSAGE = """
 mutation PostMessage($input: PostMessageInput!) {
     postMessage(input: $input) {
@@ -247,16 +234,6 @@ mutation RemoveReaction($input: RemoveReactionInput!) {
 }
 """
 
-MUTATION_CREATE_SPACE = """
-mutation CreateSpace($input: CreateSpaceInput!) {
-    createSpace(input: $input) {
-        id
-        name
-        description
-    }
-}
-"""
-
 MUTATION_JOIN_SPACE = """
 mutation JoinSpace($input: JoinSpaceInput!) {
     joinSpace(input: $input) {

+ 0 - 34
tests/test_client.py

@@ -165,28 +165,6 @@ async def test_login_invalid():
             await ChattoClient.login("bad", "creds")
 
 
-async def test_create_user(mock_api, client):
-    mock_api.post("/api/graphql").mock(
-        return_value=_gql_response(
-            {
-                "createUser": {
-                    "id": "u2",
-                    "login": "newbot",
-                    "displayName": "New Bot",
-                    "createdAt": "2025-01-01T00:00:00Z",
-                    "avatarUrl": None,
-                    "presenceStatus": None,
-                }
-            }
-        )
-    )
-    async with client:
-        user = await client.create_user("newbot", "New Bot", "pass123")
-    assert user.id == "u2"
-    assert user.login == "newbot"
-    assert user.display_name == "New Bot"
-
-
 async def test_edit_message(mock_api, client):
     mock_api.post("/api/graphql").mock(
         return_value=_gql_response({"editMessage": {"id": "e1"}})
@@ -223,18 +201,6 @@ async def test_remove_reaction(mock_api, client):
     assert result is True
 
 
-async def test_create_space(mock_api, client):
-    mock_api.post("/api/graphql").mock(
-        return_value=_gql_response(
-            {"createSpace": {"id": "s1", "name": "Test Space", "description": "A test"}}
-        )
-    )
-    async with client:
-        space = await client.create_space("Test Space", description="A test")
-    assert space.id == "s1"
-    assert space.name == "Test Space"
-
-
 async def test_create_room(mock_api, client):
     mock_api.post("/api/graphql").mock(
         return_value=_gql_response(

+ 0 - 17
tests/test_integration.py

@@ -46,20 +46,3 @@ async def test_list_spaces(client):
     print(f"Found {len(spaces)} spaces")
     for s in spaces:
         print(f"  - {s.name} (id={s.id}, members={s.member_count})")
-
-
-async def test_create_user(client):
-    """Test creating a new user via the createUser mutation (requires admin)."""
-    import random
-    import string
-
-    suffix = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
-    login = f"testbot_{suffix}"
-    display_name = f"Test Bot {suffix}"
-    password = "TestPass123!"
-
-    user = await client.create_user(login, display_name, password)
-    assert user.id
-    assert user.login == login
-    assert user.display_name == display_name
-    print(f"Created user: {user.login} (id={user.id})")