Skip to content

Commit

Permalink
Merge pull request #31 from GetStream/moderation
Browse files Browse the repository at this point in the history
Add moderation endpoints with tests
  • Loading branch information
tbarbugli authored May 9, 2024
2 parents 275ddfe + 7a52554 commit 8254dbd
Show file tree
Hide file tree
Showing 21 changed files with 713 additions and 205 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
STREAM_API_KEY=892s22ypvt6m
STREAM_API_SECRET=5cssrefv55rs3cnkk38kfjam2k7c2ykwn4h79dqh66ym89gm65cxy4h9jx4cypd6
STREAM_BASE_URL=http://127.0.0.1:3030
STREAM_BASE_URL=http://127.0.0.1:3030
14 changes: 14 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.3
hooks:
- id: ruff
args: [ --fix ]
- id: ruff-format
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
- New: query_users
- breaking change: rename Apierror -> ApiError

# 0.1.2: Initial release of the package to PyPI (25-10-2023)
# 0.1.2: Initial release of the package to PyPI (25-10-2023)
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT,
STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO
NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND
CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE
SOFTWARE.
SOFTWARE.

1. SOFTWARE. The Stream.io software accompanying this Agreement, may include
Source Code, Executable Object Code, associated media, printed materials and
Expand Down
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ To install the development dependencies, run the following command:

```sh
poetry install
pre-commit install
```

To activate the virtual environment, run the following command:
Expand All @@ -102,17 +103,30 @@ To activate the virtual environment, run the following command:
poetry shell
```

To run tests, create a `.env` using the `.env.example` and adjust it to have valid API credentials
To run tests, create a `.env` using the `.env.example` and adjust it to have valid API credentials
```sh
poetry run pytest tests/ getstream/
```

Before pushing changes make sure to run the linter:
Before pushing changes make sure to have git hooks installed correctly, so that you get linting done locally `pre-commit install`

You can also run the code formatting yourself if needed:

```sh
poetry run ruff format getstream/ tests/
```

### Writing new tests

pytest is used to run tests and to inject fixtures, simple tests can be written as simple python functions making assert calls. Make sure to have a look at the available test fixtures under `tests/fixtures.py`

### Generate code from spec

To regenerate the Python source from OpenAPI, just run the `./generate.sh` script from this repo.

> [!NOTE]
> Code generation currently relies on tooling that is not publicly available, only Stream devs can regenerate SDK source code from the OpenAPI spec.
## License

This project is licensed under the [MIT License](LICENSE).
Expand Down
23 changes: 23 additions & 0 deletions generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash

SOURCE_PATH=../chat

if [ ! -d $SOURCE_PATH ]
then
echo "cannot find chat path on the parent folder (${SOURCE_PATH}), do you have a copy of the API source?";
exit 1;
fi

if ! poetry -V &> /dev/null
then
echo "cannot find poetry in path, did you setup this repo correctly?";
exit 1;
fi

set -ex

# cd in API repo, generate new spec and then generate code from it
( cd $SOURCE_PATH ; make openapi ; go run ./cmd/chat-manager openapi generate-client --language python --spec ./releases/v2/serverside-api.yaml --output ../stream-py/getstream/ )

# lint generated code with ruff
poetry run ruff format getstream/ tests/
144 changes: 8 additions & 136 deletions getstream/chat/rest_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,6 @@ def __init__(self, api_key: str, base_url: str, timeout: float, token: str):
token=token,
)

def list_block_lists(self) -> StreamResponse[ListBlockListResponse]:
return self.get("/api/v2/chat/blocklists", ListBlockListResponse)

def create_block_list(
self, name: str, words: List[str], type: Optional[str] = None
) -> StreamResponse[Response]:
json = build_body_dict(name=name, words=words, type=type)

return self.post("/api/v2/chat/blocklists", Response, json=json)

def delete_block_list(self, name: str) -> StreamResponse[Response]:
path_params = {
"name": name,
}

return self.delete(
"/api/v2/chat/blocklists/{name}", Response, path_params=path_params
)

def get_block_list(self, name: str) -> StreamResponse[GetBlockListResponse]:
path_params = {
"name": name,
}

return self.get(
"/api/v2/chat/blocklists/{name}",
GetBlockListResponse,
path_params=path_params,
)

def update_block_list(
self, name: str, words: Optional[List[str]] = None
) -> StreamResponse[Response]:
path_params = {
"name": name,
}
json = build_body_dict(words=words)

return self.put(
"/api/v2/chat/blocklists/{name}",
Response,
path_params=path_params,
json=json,
)

def query_channels(
self,
limit: Optional[int] = None,
Expand Down Expand Up @@ -727,13 +682,15 @@ def export_channels(
channels: List[ChannelExport],
clear_deleted_message_text: Optional[bool] = None,
export_users: Optional[bool] = None,
include_soft_deleted_channels: Optional[bool] = None,
include_truncated_messages: Optional[bool] = None,
version: Optional[str] = None,
) -> StreamResponse[ExportChannelsResponse]:
json = build_body_dict(
channels=channels,
clear_deleted_message_text=clear_deleted_message_text,
export_users=export_users,
include_soft_deleted_channels=include_soft_deleted_channels,
include_truncated_messages=include_truncated_messages,
version=version,
)
Expand Down Expand Up @@ -1035,6 +992,7 @@ def get_replies(
created_at_before: Optional[datetime] = None,
id_around: Optional[str] = None,
created_at_around: Optional[datetime] = None,
sort: Optional[List[Optional[SortParam]]] = None,
) -> StreamResponse[GetRepliesResponse]:
query_params = build_query_param(
id_gte=id_gte,
Expand All @@ -1047,6 +1005,7 @@ def get_replies(
created_at_before=created_at_before,
id_around=id_around,
created_at_around=created_at_around,
sort=sort,
)
path_params = {
"parent_id": parent_id,
Expand All @@ -1059,71 +1018,6 @@ def get_replies(
path_params=path_params,
)

def unban(
self,
target_user_id: str,
type: Optional[str] = None,
id: Optional[str] = None,
created_by: Optional[str] = None,
) -> StreamResponse[Response]:
query_params = build_query_param(
target_user_id=target_user_id, type=type, id=id, created_by=created_by
)

return self.delete(
"/api/v2/chat/moderation/ban", Response, query_params=query_params
)

def ban(
self,
target_user_id: str,
banned_by_id: Optional[str] = None,
id: Optional[str] = None,
ip_ban: Optional[bool] = None,
reason: Optional[str] = None,
shadow: Optional[bool] = None,
timeout: Optional[int] = None,
type: Optional[str] = None,
user_id: Optional[str] = None,
banned_by: Optional[UserRequest] = None,
user: Optional[UserRequest] = None,
) -> StreamResponse[Response]:
json = build_body_dict(
target_user_id=target_user_id,
banned_by_id=banned_by_id,
id=id,
ip_ban=ip_ban,
reason=reason,
shadow=shadow,
timeout=timeout,
type=type,
user_id=user_id,
banned_by=banned_by,
user=user,
)

return self.post("/api/v2/chat/moderation/ban", Response, json=json)

def flag(
self,
reason: Optional[str] = None,
target_message_id: Optional[str] = None,
target_user_id: Optional[str] = None,
user_id: Optional[str] = None,
custom: Optional[Dict[str, object]] = None,
user: Optional[UserRequest] = None,
) -> StreamResponse[FlagResponse]:
json = build_body_dict(
reason=reason,
target_message_id=target_message_id,
target_user_id=target_user_id,
user_id=user_id,
custom=custom,
user=user,
)

return self.post("/api/v2/chat/moderation/flag", FlagResponse, json=json)

def query_message_flags(
self, payload: Optional[QueryMessageFlagsRequest] = None
) -> StreamResponse[QueryMessageFlagsResponse]:
Expand All @@ -1135,19 +1029,6 @@ def query_message_flags(
query_params=query_params,
)

def mute_user(
self,
timeout: int,
user_id: Optional[str] = None,
target_ids: Optional[List[str]] = None,
user: Optional[UserRequest] = None,
) -> StreamResponse[MuteUserResponse]:
json = build_body_dict(
timeout=timeout, user_id=user_id, target_ids=target_ids, user=user
)

return self.post("/api/v2/chat/moderation/mute", MuteUserResponse, json=json)

def mute_channel(
self,
expiration: Optional[int] = None,
Expand All @@ -1163,19 +1044,6 @@ def mute_channel(
"/api/v2/chat/moderation/mute/channel", MuteChannelResponse, json=json
)

def unmute_user(
self,
timeout: int,
user_id: Optional[str] = None,
target_ids: Optional[List[str]] = None,
user: Optional[UserRequest] = None,
) -> StreamResponse[UnmuteResponse]:
json = build_body_dict(
timeout=timeout, user_id=user_id, target_ids=target_ids, user=user
)

return self.post("/api/v2/chat/moderation/unmute", UnmuteResponse, json=json)

def unmute_channel(
self,
expiration: Optional[int] = None,
Expand Down Expand Up @@ -1457,6 +1325,7 @@ def search(
def query_threads(
self,
limit: Optional[int] = None,
member_limit: Optional[int] = None,
next: Optional[str] = None,
participant_limit: Optional[int] = None,
prev: Optional[str] = None,
Expand All @@ -1466,6 +1335,7 @@ def query_threads(
) -> StreamResponse[QueryThreadsResponse]:
json = build_body_dict(
limit=limit,
member_limit=member_limit,
next=next,
participant_limit=participant_limit,
prev=prev,
Expand All @@ -1482,11 +1352,13 @@ def get_thread(
connection_id: Optional[str] = None,
reply_limit: Optional[int] = None,
participant_limit: Optional[int] = None,
member_limit: Optional[int] = None,
) -> StreamResponse[GetThreadResponse]:
query_params = build_query_param(
connection_id=connection_id,
reply_limit=reply_limit,
participant_limit=participant_limit,
member_limit=member_limit,
)
path_params = {
"message_id": message_id,
Expand Down
Loading

0 comments on commit 8254dbd

Please sign in to comment.