Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CHA-15] Added pin, archive and partial member update functions #179

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5500ea4
feat: added pin, archive and partial member update functions
totalimmersion Dec 6, 2024
d000002
fix: update stream_chat/channel.py
totalimmersion Dec 6, 2024
7d6478e
fix: update stream_chat/async_chat/channel.py
totalimmersion Dec 6, 2024
43da753
fix: update stream_chat/async_chat/channel.py
totalimmersion Dec 6, 2024
97cb3ee
fix: update stream_chat/async_chat/channel.py
totalimmersion Dec 6, 2024
2a3094c
fix: update stream_chat/async_chat/channel.py
totalimmersion Dec 6, 2024
e0890c9
fix: update stream_chat/channel.py
totalimmersion Dec 6, 2024
0de1401
remove commitlint
totalimmersion Dec 6, 2024
c54f802
Merge branch 'feature/chat-15-pinning-archiving-member-custom-data' o…
totalimmersion Dec 6, 2024
ad1d805
fix: linting
totalimmersion Dec 6, 2024
3b8b1b2
fix: import
totalimmersion Dec 6, 2024
c15caeb
fix: update stream_chat/channel.py
totalimmersion Dec 6, 2024
0a30e02
fix: update stream_chat/channel.py
totalimmersion Dec 6, 2024
5999443
fix: update stream_chat/base/channel.py
totalimmersion Dec 6, 2024
1875fd7
fix: update stream_chat/base/channel.py
totalimmersion Dec 6, 2024
abe3c74
fix: lint
totalimmersion Dec 6, 2024
d429467
Merge branch 'feature/chat-15-pinning-archiving-member-custom-data' o…
totalimmersion Dec 6, 2024
d13cfd8
fix: linting
totalimmersion Dec 6, 2024
7e4a6c8
fix: stuff
totalimmersion Dec 6, 2024
2b53100
feat: added test for pinning / unpinning
totalimmersion Dec 6, 2024
c1a49f8
fix: update stream_chat/tests/test_channel.py
totalimmersion Dec 6, 2024
328dcfc
fix: update stream_chat/tests/test_channel.py
totalimmersion Dec 6, 2024
9b5c257
fix: update stream_chat/tests/test_channel.py
totalimmersion Dec 6, 2024
a80505a
fix: update stream_chat/tests/test_channel.py
totalimmersion Dec 6, 2024
f161569
fix: linting
totalimmersion Dec 6, 2024
8978ee2
Merge branch 'feature/chat-15-pinning-archiving-member-custom-data' o…
totalimmersion Dec 6, 2024
0b5a594
fix: test
totalimmersion Dec 6, 2024
5713873
feat: adding tests
totalimmersion Dec 6, 2024
50df973
feat: add tests for partial member update
totalimmersion Dec 6, 2024
17389f3
fix: update stream_chat/tests/async_chat/test_channel.py
totalimmersion Dec 6, 2024
42cc3f8
fix: update stream_chat/tests/async_chat/test_channel.py
totalimmersion Dec 6, 2024
e4a2c88
fix: update stream_chat/tests/test_channel.py
totalimmersion Dec 6, 2024
a184fe9
fix: test
totalimmersion Dec 6, 2024
92aebe3
fix: merge branch 'feature/chat-15-pinning-archiving-member-custom-da…
totalimmersion Dec 6, 2024
c551a14
fix: test
totalimmersion Dec 6, 2024
7582489
fix: grammar
totalimmersion Dec 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ jobs:
with:
fetch-depth: 0 # gives the commit message linter access to all previous commits

- name: Commit lint
if: ${{ matrix.python == '3.8' && github.ref == 'refs/heads/master' }}
uses: wagoid/commitlint-github-action@v4

- uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python }}
Expand Down
38 changes: 38 additions & 0 deletions stream_chat/async_chat/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import Any, Dict, Iterable, List, Union

from stream_chat.base.channel import ChannelInterface, add_user_id
from stream_chat.base.exceptions import StreamChannelException
from stream_chat.types.stream_response import StreamResponse


Expand Down Expand Up @@ -209,3 +210,40 @@ async def unmute(self, user_id: str) -> StreamResponse:
"channel_cid": self.cid,
}
return await self.client.post("moderation/unmute/channel", data=params)

async def pin(self, user_id: str) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": {"pinned": True}}
return await self.client.patch(f"{self.url}/member/{user_id}", data=payload)

async def unpin(self, user_id: str) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": {"pinned": False}}
return await self.client.patch(f"{self.url}/member/{user_id}", data=payload)

async def archive(self, user_id: str) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": {"archived": True}}
return await self.client.patch(f"{self.url}/member/{user_id}", data=payload)

async def unarchive(self, user_id: str) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": {"archived": False}}
return await self.client.patch(f"{self.url}/member/{user_id}", data=payload)

async def update_member_partial(
self, user_id: str, to_set: Dict = None, to_unset: Iterable[str] = None
) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": to_set or {}, "unset": to_unset or []}
return await self.client.patch(f"{self.url}/member/{user_id}", data=payload)
46 changes: 46 additions & 0 deletions stream_chat/base/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,52 @@ def unmute(self, user_id: str) -> Union[StreamResponse, Awaitable[StreamResponse
"""
pass

@abc.abstractmethod
def pin(self, user_id: str) -> Union[StreamResponse, Awaitable[StreamResponse]]:
"""
Pins a channel
Allows a user to pin the channel (only for themselves)
"""
pass

@abc.abstractmethod
def unpin(self, user_id: str) -> Union[StreamResponse, Awaitable[StreamResponse]]:
"""
Unpins a channel
Allows a user to unpin the channel (only for themselves)
"""
pass

@abc.abstractmethod
def archive(self, user_id: str) -> Union[StreamResponse, Awaitable[StreamResponse]]:
"""
Pins a channel
Allows a user to archive the channel (only for themselves)
"""
pass

@abc.abstractmethod
def unarchive(
self, user_id: str
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
"""
Unpins a channel
Allows a user to unpin the channel (only for themselves)
"""
pass

@abc.abstractmethod
def update_member_partial(
self, user_id: str, to_set: Dict = None, to_unset: Iterable[str] = None
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
"""
Update channel member partially

:param to_set: a dictionary of key/value pairs to set or to override
:param to_unset: a list of keys to clear
"""
pass


def add_user_id(payload: Dict, user_id: str) -> Dict:
return {**payload, "user": {"id": user_id}}
38 changes: 38 additions & 0 deletions stream_chat/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import Any, Dict, Iterable, List, Union

from stream_chat.base.channel import ChannelInterface, add_user_id
from stream_chat.base.exceptions import StreamChannelException
from stream_chat.types.stream_response import StreamResponse


Expand Down Expand Up @@ -210,3 +211,40 @@ def unmute(self, user_id: str) -> StreamResponse:
"channel_cid": self.cid,
}
return self.client.post("moderation/unmute/channel", data=params)

def pin(self, user_id: str) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": {"pinned": True}}
return self.client.patch(f"{self.url}/member/{user_id}", data=payload)

def unpin(self, user_id: str) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": {"pinned": False}}
return self.client.patch(f"{self.url}/member/{user_id}", data=payload)

def archive(self, user_id: str) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": {"archived": True}}
return self.client.patch(f"{self.url}/member/{user_id}", data=payload)

def unarchive(self, user_id: str) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": {"archived": False}}
return self.client.patch(f"{self.url}/member/{user_id}", data=payload)

def update_member_partial(
self, user_id: str, to_set: Dict = None, to_unset: Iterable[str] = None
) -> StreamResponse:
if not user_id:
raise StreamChannelException("user_id must not be empty")

payload = {"set": to_set or {}, "unset": to_unset or []}
return self.client.patch(f"{self.url}/member/{user_id}", data=payload)
73 changes: 73 additions & 0 deletions stream_chat/tests/async_chat/test_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,76 @@ async def test_export_channel(
assert "error" not in resp
break
time.sleep(0.5)

async def test_pin_channel(
self, client: StreamChatAsync, channel: Channel, random_users: List[Dict]
):
user_id = random_users[0]["id"]
await channel.add_members([user_id])

# Pin the channel
response = await channel.pin(user_id)
assert response is not None

# Query for pinned channels
response = await client.query_channels(
{"pinned": True, "cid": channel.cid}, user_id=user_id
)
assert len(response["channels"]) == 1
assert response["channels"][0]["channel"]["cid"] == channel.cid

# Unpin the channel
response = await channel.unpin(user_id)
assert response is not None

# Query for pinned channels
response = await client.query_channels(
{"pinned": False, "cid": channel.cid}, user_id=user_id
)
assert len(response["channels"]) == 1
assert response["channels"][0]["channel"]["cid"] == channel.cid

async def test_archive_channel(
self, client: StreamChatAsync, channel: Channel, random_users: List[Dict]
):
user_id = random_users[0]["id"]
await channel.add_members([user_id])

# Archive the channel
response = await channel.archive(user_id)
assert response is not None

# Query for archived channels
response = await client.query_channels(
{"archived": True, "cid": channel.cid}, user_id=user_id
)
assert len(response["channels"]) == 1
assert response["channels"][0]["channel"]["cid"] == channel.cid

# Unarchive the channel
response = await channel.unarchive(user_id)
assert response is not None

# Query for archived channels
response = await client.query_channels(
{"archived": False, "cid": channel.cid}, user_id=user_id
)
assert len(response["channels"]) == 1
assert response["channels"][0]["channel"]["cid"] == channel.cid

async def test_update_member_partial(
self, channel: Channel, random_users: List[Dict]
):
user_id = random_users[0]["id"]
await channel.add_members([user_id])

# Test setting a custom field
response = await channel.update_member_partial(user_id, to_set={"hat": "blue"})
assert response["channel_member"]["hat"] == "blue"

# Test setting a new field while unsetting the previous one
response = await channel.update_member_partial(
user_id, to_set={"color": "red"}, to_unset=["hat"]
)
assert response["channel_member"]["color"] == "red"
assert "hat" not in response["channel_member"]
71 changes: 71 additions & 0 deletions stream_chat/tests/test_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,74 @@ def test_export_channel(
assert "error" not in resp
break
time.sleep(0.5)

def test_pin_channel(
self, client: StreamChat, channel: Channel, random_users: List[Dict]
):
user_id = random_users[0]["id"]
channel.add_members([user_id])

# Pin the channel
response = channel.pin(user_id)
assert response is not None

# Query for pinned channels
response = client.query_channels(
{"pinned": True, "cid": channel.cid}, user_id=user_id
)
assert len(response["channels"]) == 1
assert response["channels"][0]["channel"]["cid"] == channel.cid

# Unpin the channel
response = channel.unpin(user_id)
assert response is not None

# Query for pinned channels
response = client.query_channels(
{"pinned": False, "cid": channel.cid}, user_id=user_id
)
assert len(response["channels"]) == 1
assert response["channels"][0]["channel"]["cid"] == channel.cid

def test_archive_channel(
self, client: StreamChat, channel: Channel, random_users: List[Dict]
):
user_id = random_users[0]["id"]
channel.add_members([user_id])

# Archive the channel
response = channel.archive(user_id)
assert response is not None

# Query for archived channels
response = client.query_channels(
{"archived": True, "cid": channel.cid}, user_id=user_id
)
assert len(response["channels"]) == 1
assert response["channels"][0]["channel"]["cid"] == channel.cid

# Unarchive the channel
response = channel.unarchive(user_id)
assert response is not None

# Query for archhived channels
response = client.query_channels(
{"archived": False, "cid": channel.cid}, user_id=user_id
)
assert len(response["channels"]) == 1
assert response["channels"][0]["channel"]["cid"] == channel.cid

def test_update_member_partial(self, channel: Channel, random_users: List[Dict]):
user_id = random_users[0]["id"]
channel.add_members([user_id])

# Test setting a custom field
response = channel.update_member_partial(user_id, to_set={"hat": "blue"})
assert response["channel_member"]["hat"] == "blue"

# Test setting a new field while unsetting the previous one
response = channel.update_member_partial(
user_id, to_set={"color": "red"}, to_unset=["hat"]
)
assert response["channel_member"]["color"] == "red"
assert "hat" not in response["channel_member"]
Loading