Skip to content

Commit

Permalink
[CHA-15] Added pin, archive and partial member update functions (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
totalimmersion authored Dec 7, 2024
1 parent fa23514 commit 0e11543
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 4 deletions.
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"]

0 comments on commit 0e11543

Please sign in to comment.