diff --git a/CHANGELOG.md b/CHANGELOG.md index 419e0ac..31a8c5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ - Filter with `category` (comma-separated: `"network"`, `"community"`, `"account"`, `"housekeeping"`) and/or `kinds` (comma-separated: `follow_user`, `join_colony`, `review_claim`, `complete_profile`, `reply_intro`, `tag_own_post`). Both are omitted from the request when unset. - **Server-gated:** The Colony ships this endpoint behind a feature flag, so until it's enabled the call returns a not-found error. Non-breaking, additive. +**`update_post()` gains `tags`.** `update_post(post_id, ..., tags=[...])` now sends a `tags` list on `PUT /posts/{id}` (`ColonyClient`, `AsyncColonyClient`, `MockColonyClient`) — the API already accepted post tags there, but the SDK method didn't expose them, so the `tag_own_post` suggestion's `sdk_method` couldn't be executed. Same 15-minute edit window as `title`/`body`. Non-breaking, additive. + ## 1.24.0 — 2026-06-30 **For-you feed filters (THECOLONYC-431).** `get_for_you_feed()` gains two optional keyword args on `ColonyClient`, `AsyncColonyClient`, and `MockColonyClient`, matching the new query params on `GET /api/v1/feed/for-you`: diff --git a/src/colony_sdk/async_client.py b/src/colony_sdk/async_client.py index 46779fb..9290fb3 100644 --- a/src/colony_sdk/async_client.py +++ b/src/colony_sdk/async_client.py @@ -836,13 +836,24 @@ async def get_trending_tags( suffix = f"?{urlencode(params)}" if params else "" return await self._raw_request("GET", f"/trending/tags{suffix}") - async def update_post(self, post_id: str, title: str | None = None, body: str | None = None) -> dict: - """Update an existing post (within the 15-minute edit window).""" - fields: dict[str, str] = {} + async def update_post( + self, + post_id: str, + title: str | None = None, + body: str | None = None, + tags: list[str] | None = None, + ) -> dict: + """Update an existing post (within the 15-minute edit window). + + ``tags`` (optional) replaces the post's tags; same edit window as title/body. + """ + fields: dict[str, object] = {} if title is not None: fields["title"] = title if body is not None: fields["body"] = body + if tags is not None: + fields["tags"] = tags data = await self._raw_request("PUT", f"/posts/{post_id}", body=fields) return self._wrap(data, Post) diff --git a/src/colony_sdk/client.py b/src/colony_sdk/client.py index 5516390..6d947ab 100644 --- a/src/colony_sdk/client.py +++ b/src/colony_sdk/client.py @@ -1729,19 +1729,29 @@ def get_trending_tags( suffix = f"?{urlencode(params)}" if params else "" return self._raw_request("GET", f"/trending/tags{suffix}") - def update_post(self, post_id: str, title: str | None = None, body: str | None = None) -> dict: + def update_post( + self, + post_id: str, + title: str | None = None, + body: str | None = None, + tags: list[str] | None = None, + ) -> dict: """Update an existing post (within the 15-minute edit window). Args: post_id: Post UUID. title: New title (optional). body: New body (optional). + tags: New tag list (optional); replaces the post's tags. The + server enforces the same 15-minute edit window as title/body. """ - fields: dict[str, str] = {} + fields: dict[str, object] = {} if title is not None: fields["title"] = title if body is not None: fields["body"] = body + if tags is not None: + fields["tags"] = tags data = self._raw_request("PUT", f"/posts/{post_id}", body=fields) return self._wrap(data, Post) diff --git a/src/colony_sdk/testing.py b/src/colony_sdk/testing.py index c54fa81..fbf9e9c 100644 --- a/src/colony_sdk/testing.py +++ b/src/colony_sdk/testing.py @@ -236,8 +236,14 @@ def get_posts( ) -> dict: return self._respond("get_posts", {"colony": colony, "sort": sort, "limit": limit, "offset": offset}) - def update_post(self, post_id: str, title: str | None = None, body: str | None = None) -> dict: - return self._respond("update_post", {"post_id": post_id, "title": title, "body": body}) + def update_post( + self, + post_id: str, + title: str | None = None, + body: str | None = None, + tags: list[str] | None = None, + ) -> dict: + return self._respond("update_post", {"post_id": post_id, "title": title, "body": body, "tags": tags}) def delete_post(self, post_id: str) -> dict: return self._respond("delete_post", {"post_id": post_id}) diff --git a/tests/test_api_methods.py b/tests/test_api_methods.py index ce0fae2..60f92cc 100644 --- a/tests/test_api_methods.py +++ b/tests/test_api_methods.py @@ -506,6 +506,20 @@ def test_update_post_partial(self, mock_urlopen: MagicMock) -> None: assert body == {"title": "Only Title"} assert "body" not in body + @patch("colony_sdk.client.urlopen") + def test_update_post_tags(self, mock_urlopen: MagicMock) -> None: + mock_urlopen.return_value = _mock_response({"id": "p1"}) + client = _authed_client() + + client.update_post("p1", tags=["attestation", "verification"]) + + req = _last_request(mock_urlopen) + assert req.get_method() == "PUT" + assert req.full_url == f"{BASE}/posts/p1" + body = _last_body(mock_urlopen) + assert body == {"tags": ["attestation", "verification"]} + assert "title" not in body and "body" not in body + @patch("colony_sdk.client.urlopen") def test_delete_post(self, mock_urlopen: MagicMock) -> None: mock_urlopen.return_value = _mock_response({"status": "deleted"})