Skip to content

Commit d2b48e7

Browse files
committed
[CHA-536] support campaign user pagination
1 parent 514a795 commit d2b48e7

File tree

9 files changed

+102
-20
lines changed

9 files changed

+102
-20
lines changed

stream_chat/async_chat/campaign.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Any, Optional, Union
33

44
from stream_chat.base.campaign import CampaignInterface
5-
from stream_chat.types.campaign import CampaignData
5+
from stream_chat.types.campaign import CampaignData, GetCampaignOptions
66
from stream_chat.types.stream_response import StreamResponse
77

88

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

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

3030
async def update(self, data: CampaignData) -> StreamResponse:

stream_chat/async_chat/client.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from stream_chat.async_chat.campaign import Campaign
2121
from stream_chat.async_chat.segment import Segment
2222
from stream_chat.types.base import SortParam
23-
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
23+
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions, GetCampaignOptions
2424
from stream_chat.types.segment import (
2525
QuerySegmentsOptions,
2626
QuerySegmentTargetsOptions,
@@ -664,8 +664,11 @@ async def create_campaign(
664664
payload.update(cast(dict, data))
665665
return await self.post("campaigns", data=payload)
666666

667-
async def get_campaign(self, campaign_id: str) -> StreamResponse:
668-
return await self.get(f"campaigns/{campaign_id}")
667+
async def get_campaign(self, campaign_id: str, options: Optional[GetCampaignOptions] = None) -> StreamResponse:
668+
params = {}
669+
if options and "users" in options:
670+
params.update(options["users"])
671+
return await self.get(f"campaigns/{campaign_id}", params)
669672

670673
async def query_campaigns(
671674
self,

stream_chat/base/campaign.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import Awaitable, Optional, Union
44

55
from stream_chat.base.client import StreamChatInterface
6-
from stream_chat.types.campaign import CampaignData
6+
from stream_chat.types.campaign import CampaignData, GetCampaignOptions
77
from stream_chat.types.stream_response import StreamResponse
88

99

@@ -25,7 +25,9 @@ def create(
2525
pass
2626

2727
@abc.abstractmethod
28-
def get(self) -> Union[StreamResponse, Awaitable[StreamResponse]]:
28+
def get(
29+
self, options: Optional[GetCampaignOptions] = None
30+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
2931
pass
3032

3133
@abc.abstractmethod

stream_chat/base/client.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from typing import Any, Awaitable, Dict, Iterable, List, Optional, TypeVar, Union
99

1010
from stream_chat.types.base import SortParam
11-
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
11+
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions, GetCampaignOptions
1212
from stream_chat.types.segment import (
1313
QuerySegmentsOptions,
1414
QuerySegmentTargetsOptions,
@@ -1084,10 +1084,14 @@ def create_campaign(
10841084

10851085
@abc.abstractmethod
10861086
def get_campaign(
1087-
self, campaign_id: str
1087+
self, campaign_id: str, options: Optional[GetCampaignOptions] = None
10881088
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
10891089
"""
1090-
Create a campaign
1090+
Get a campaign
1091+
1092+
:param campaign_id: ID of the campaign to get
1093+
:param options: Optional parameters for the request
1094+
:return: Campaign data
10911095
"""
10921096
pass
10931097

stream_chat/campaign.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Any, Optional, Union
33

44
from stream_chat.base.campaign import CampaignInterface
5-
from stream_chat.types.campaign import CampaignData
5+
from stream_chat.types.campaign import CampaignData, GetCampaignOptions
66
from stream_chat.types.stream_response import StreamResponse
77

88

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

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

2828
def update(self, data: CampaignData) -> StreamResponse:
2929
return self.client.update_campaign( # type: ignore

stream_chat/client.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from stream_chat.campaign import Campaign
1010
from stream_chat.segment import Segment
1111
from stream_chat.types.base import SortParam
12-
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
12+
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions, GetCampaignOptions
1313
from stream_chat.types.segment import (
1414
QuerySegmentsOptions,
1515
QuerySegmentTargetsOptions,
@@ -636,8 +636,11 @@ def create_campaign(
636636
payload.update(cast(dict, data))
637637
return self.post("campaigns", data=payload)
638638

639-
def get_campaign(self, campaign_id: str) -> StreamResponse:
640-
return self.get(f"campaigns/{campaign_id}")
639+
def get_campaign(self, campaign_id: str, options: Optional[GetCampaignOptions] = None) -> StreamResponse:
640+
params = {}
641+
if options and "users" in options:
642+
params.update(options["users"])
643+
return self.get(f"campaigns/{campaign_id}", params)
641644

642645
def query_campaigns(
643646
self,

stream_chat/tests/async_chat/test_campaign.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import datetime
2-
from typing import Dict
2+
from typing import Dict, List
33

44
import pytest
55

@@ -61,6 +61,36 @@ async def test_campaign_crud(self, client: StreamChatAsync, random_user: Dict):
6161

6262
await client.delete_segment(segment_id=segment_id)
6363

64+
async def test_get_campaign_with_user_pagination(self, client: StreamChatAsync, random_users: List[Dict]):
65+
# Create a campaign with user_ids
66+
campaign = client.campaign(
67+
data={
68+
"message_template": {
69+
"text": "Test message",
70+
},
71+
"user_ids": [user["id"] for user in random_users],
72+
"sender_id": random_users[0]["id"],
73+
"name": "test campaign with users",
74+
}
75+
)
76+
created = await campaign.create()
77+
assert created.is_ok()
78+
campaign_id = created["campaign"]["id"]
79+
80+
# Test get_campaign with user pagination options
81+
response = await client.get_campaign(
82+
campaign_id=campaign_id,
83+
options={"users": {"limit": 2}} # Limit to 2 users per page
84+
)
85+
assert response.is_ok()
86+
assert "campaign" in response
87+
assert response["campaign"]["id"] == campaign_id
88+
assert "users" in response["campaign"]
89+
assert len(response["campaign"]["users"]) <= 2 # Verify pagination limit worked
90+
91+
# Cleanup
92+
await client.delete_campaign(campaign_id=campaign_id)
93+
6494
async def test_campaign_start_stop(
6595
self, client: StreamChatAsync, random_user: Dict
6696
):

stream_chat/tests/test_campaign.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import datetime
2-
from typing import Dict
2+
from typing import Dict, List
33

44
import pytest
55

@@ -67,6 +67,36 @@ def test_campaign_crud(self, client: StreamChat, random_user: Dict):
6767
segment_deleted = client.delete_segment(segment_id=segment_id)
6868
assert segment_deleted.is_ok()
6969

70+
def test_get_campaign_with_user_pagination(self, client: StreamChat, random_users: List[Dict]):
71+
# Create a campaign with user_ids
72+
campaign = client.campaign(
73+
data={
74+
"message_template": {
75+
"text": "Test message",
76+
},
77+
"user_ids": [user["id"] for user in random_users],
78+
"sender_id": random_users[0]["id"],
79+
"name": "test campaign with users",
80+
}
81+
)
82+
created = campaign.create()
83+
assert created.is_ok()
84+
campaign_id = created["campaign"]["id"]
85+
86+
# Test get_campaign with user pagination options
87+
response = client.get_campaign(
88+
campaign_id=campaign_id,
89+
options={"users": {"limit": 2}} # Limit to 2 users per page
90+
)
91+
assert response.is_ok()
92+
assert "campaign" in response
93+
assert response["campaign"]["id"] == campaign_id
94+
assert "users" in response["campaign"]
95+
assert len(response["campaign"]["users"]) <= 2 # Verify pagination limit worked
96+
97+
# Cleanup
98+
client.delete_campaign(campaign_id=campaign_id)
99+
70100
def test_campaign_start_stop(self, client: StreamChat, random_user: Dict):
71101
segment = client.create_segment(segment_type=SegmentType.USER)
72102
segment_id = segment["segment"]["id"]

stream_chat/types/campaign.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import sys
2-
from typing import Dict, List, Optional
2+
from typing import Dict, List, Optional, Union
33

44
if sys.version_info >= (3, 8):
55
from typing import TypedDict
@@ -76,3 +76,13 @@ class CampaignData(TypedDict, total=False):
7676

7777
class QueryCampaignsOptions(Pager, total=False):
7878
pass
79+
80+
81+
class GetCampaignOptions(TypedDict, total=False):
82+
"""
83+
Options for getting a campaign.
84+
85+
Parameters:
86+
users: Optional Pager containing pagination options for users
87+
"""
88+
users: Optional[Pager]

0 commit comments

Comments
 (0)