Skip to content

[CHA-536] support campaign user pagination #188

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions stream_chat/async_chat/campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Any, Optional, Union

from stream_chat.base.campaign import CampaignInterface
from stream_chat.types.campaign import CampaignData
from stream_chat.types.campaign import CampaignData, GetCampaignOptions
from stream_chat.types.stream_response import StreamResponse


Expand All @@ -22,9 +22,9 @@ async def create(
self.campaign_id = state["campaign"]["id"]
return state

async def get(self) -> StreamResponse:
async def get(self, options: Optional[GetCampaignOptions] = None) -> StreamResponse:
return await self.client.get_campaign( # type: ignore
campaign_id=self.campaign_id
campaign_id=self.campaign_id, options=options
)

async def update(self, data: CampaignData) -> StreamResponse:
Expand Down
15 changes: 12 additions & 3 deletions stream_chat/async_chat/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
from stream_chat.async_chat.campaign import Campaign
from stream_chat.async_chat.segment import Segment
from stream_chat.types.base import SortParam
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
from stream_chat.types.campaign import (
CampaignData,
QueryCampaignsOptions,
GetCampaignOptions,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [flake8] <1> reported by reviewdog 🐶
isort found an import in the wrong position

)
from stream_chat.types.segment import (
QuerySegmentsOptions,
QuerySegmentTargetsOptions,
Expand Down Expand Up @@ -664,8 +668,13 @@ async def create_campaign(
payload.update(cast(dict, data))
return await self.post("campaigns", data=payload)

async def get_campaign(self, campaign_id: str) -> StreamResponse:
return await self.get(f"campaigns/{campaign_id}")
async def get_campaign(
self, campaign_id: str, options: Optional[GetCampaignOptions] = None
) -> StreamResponse:
params = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [mypy] reported by reviewdog 🐶
Need type annotation for "params" (hint: "params: dict[, ] = ...") [var-annotated]

if options and "users" in options:
params.update(options["users"])
return await self.get(f"campaigns/{campaign_id}", params)

async def query_campaigns(
self,
Expand Down
6 changes: 4 additions & 2 deletions stream_chat/base/campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Awaitable, Optional, Union

from stream_chat.base.client import StreamChatInterface
from stream_chat.types.campaign import CampaignData
from stream_chat.types.campaign import CampaignData, GetCampaignOptions
from stream_chat.types.stream_response import StreamResponse


Expand All @@ -25,7 +25,9 @@ def create(
pass

@abc.abstractmethod
def get(self) -> Union[StreamResponse, Awaitable[StreamResponse]]:
def get(
self, options: Optional[GetCampaignOptions] = None
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
pass

@abc.abstractmethod
Expand Down
14 changes: 11 additions & 3 deletions stream_chat/base/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
from typing import Any, Awaitable, Dict, Iterable, List, Optional, TypeVar, Union

from stream_chat.types.base import SortParam
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
from stream_chat.types.campaign import (
CampaignData,
QueryCampaignsOptions,
GetCampaignOptions,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [flake8] <1> reported by reviewdog 🐶
isort found an import in the wrong position

)
from stream_chat.types.segment import (
QuerySegmentsOptions,
QuerySegmentTargetsOptions,
Expand Down Expand Up @@ -1084,10 +1088,14 @@ def create_campaign(

@abc.abstractmethod
def get_campaign(
self, campaign_id: str
self, campaign_id: str, options: Optional[GetCampaignOptions] = None
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
"""
Create a campaign
Get a campaign

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[black] reported by reviewdog 🐶

Suggested change

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [flake8] <293> reported by reviewdog 🐶
blank line contains whitespace

:param campaign_id: ID of the campaign to get
:param options: Optional parameters for the request
:return: Campaign data
"""
pass

Expand Down
6 changes: 3 additions & 3 deletions stream_chat/campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Any, Optional, Union

from stream_chat.base.campaign import CampaignInterface
from stream_chat.types.campaign import CampaignData
from stream_chat.types.campaign import CampaignData, GetCampaignOptions
from stream_chat.types.stream_response import StreamResponse


Expand All @@ -22,8 +22,8 @@ def create(
self.campaign_id = state["campaign"]["id"] # type: ignore
return state # type: ignore

def get(self) -> StreamResponse:
return self.client.get_campaign(campaign_id=self.campaign_id) # type: ignore
def get(self, options: Optional[GetCampaignOptions] = None) -> StreamResponse:
return self.client.get_campaign(campaign_id=self.campaign_id, options=options) # type: ignore

def update(self, data: CampaignData) -> StreamResponse:
return self.client.update_campaign( # type: ignore
Expand Down
15 changes: 12 additions & 3 deletions stream_chat/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
from stream_chat.campaign import Campaign
from stream_chat.segment import Segment
from stream_chat.types.base import SortParam
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
from stream_chat.types.campaign import (
CampaignData,
QueryCampaignsOptions,
GetCampaignOptions,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [flake8] <1> reported by reviewdog 🐶
isort found an import in the wrong position

)
from stream_chat.types.segment import (
QuerySegmentsOptions,
QuerySegmentTargetsOptions,
Expand Down Expand Up @@ -636,8 +640,13 @@ def create_campaign(
payload.update(cast(dict, data))
return self.post("campaigns", data=payload)

def get_campaign(self, campaign_id: str) -> StreamResponse:
return self.get(f"campaigns/{campaign_id}")
def get_campaign(
self, campaign_id: str, options: Optional[GetCampaignOptions] = None
) -> StreamResponse:
params = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [mypy] reported by reviewdog 🐶
Need type annotation for "params" (hint: "params: dict[, ] = ...") [var-annotated]

if options and "users" in options:
params.update(options["users"])
return self.get(f"campaigns/{campaign_id}", params)

def query_campaigns(
self,
Expand Down
33 changes: 32 additions & 1 deletion stream_chat/tests/async_chat/test_campaign.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import datetime
from typing import Dict
from typing import Dict, List

import pytest

Expand Down Expand Up @@ -61,6 +61,37 @@ async def test_campaign_crud(self, client: StreamChatAsync, random_user: Dict):

await client.delete_segment(segment_id=segment_id)

async def test_get_campaign_with_user_pagination(
self, client: StreamChatAsync, random_users: List[Dict]
):
# Create a campaign with user_ids
campaign = client.campaign(
data={
"message_template": {
"text": "Test message",
},
"user_ids": [user["id"] for user in random_users],
"sender_id": random_users[0]["id"],
"name": "test campaign with users",
}
)
created = await campaign.create()
assert created.is_ok()
campaign_id = created["campaign"]["id"]

# Test get_campaign with user pagination options
response = await campaign.get(
options={"users": {"limit": 2}} # Limit to 2 users per page
)
assert response.is_ok()
assert "campaign" in response
assert response["campaign"]["id"] == campaign_id
assert "users" in response["campaign"]
assert len(response["campaign"]["users"]) <= 2 # Verify pagination limit worked

# Cleanup
await campaign.delete()

async def test_campaign_start_stop(
self, client: StreamChatAsync, random_user: Dict
):
Expand Down
33 changes: 32 additions & 1 deletion stream_chat/tests/test_campaign.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import datetime
from typing import Dict
from typing import Dict, List

import pytest

Expand Down Expand Up @@ -67,6 +67,37 @@ def test_campaign_crud(self, client: StreamChat, random_user: Dict):
segment_deleted = client.delete_segment(segment_id=segment_id)
assert segment_deleted.is_ok()

def test_get_campaign_with_user_pagination(
self, client: StreamChat, random_users: List[Dict]
):
# Create a campaign with user_ids
campaign = client.campaign(
data={
"message_template": {
"text": "Test message",
},
"user_ids": [user["id"] for user in random_users],
"sender_id": random_users[0]["id"],
"name": "test campaign with users",
}
)
created = campaign.create()
assert created.is_ok()
campaign_id = created["campaign"]["id"]

# Test get_campaign with user pagination options
response = campaign.get(
options={"users": {"limit": 2}} # Limit to 2 users per page
)
assert response.is_ok()
assert "campaign" in response
assert response["campaign"]["id"] == campaign_id
assert "users" in response["campaign"]
assert len(response["campaign"]["users"]) <= 2 # Verify pagination limit worked

# Cleanup
campaign.delete()

def test_campaign_start_stop(self, client: StreamChat, random_user: Dict):
segment = client.create_segment(segment_type=SegmentType.USER)
segment_id = segment["segment"]["id"]
Expand Down
13 changes: 12 additions & 1 deletion stream_chat/types/campaign.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
from typing import Dict, List, Optional
from typing import Dict, List, Optional, Union
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[flake8] <401> reported by reviewdog 🐶
'typing.Union' imported but unused


if sys.version_info >= (3, 8):
from typing import TypedDict
Expand Down Expand Up @@ -76,3 +76,14 @@ class CampaignData(TypedDict, total=False):

class QueryCampaignsOptions(Pager, total=False):
pass


class GetCampaignOptions(TypedDict, total=False):
"""
Options for getting a campaign.

Parameters:
users: Optional Pager containing pagination options for users
"""

users: Optional[Pager]
Loading