getstream 3.3.4__tar.gz → 3.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- getstream-3.4.0/.github/workflows/release.yml +219 -0
- {getstream-3.3.4 → getstream-3.4.0}/.github/workflows/run_tests.yml +3 -3
- {getstream-3.3.4 → getstream-3.4.0}/CHANGELOG.md +35 -0
- {getstream-3.3.4 → getstream-3.4.0}/Makefile +4 -2
- {getstream-3.3.4 → getstream-3.4.0}/PKG-INFO +24 -5
- {getstream-3.3.4 → getstream-3.4.0}/README.md +18 -1
- {getstream-3.3.4 → getstream-3.4.0}/generate.sh +4 -1
- {getstream-3.3.4 → getstream-3.4.0}/getstream/chat/async_rest_client.py +108 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/chat/rest_client.py +106 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/common/async_rest_client.py +24 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/common/rest_client.py +24 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/config.py +1 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/feeds/feeds.py +23 -2
- {getstream-3.3.4 → getstream-3.4.0}/getstream/feeds/rest_client.py +223 -16
- {getstream-3.3.4 → getstream-3.4.0}/getstream/models/__init__.py +1707 -143
- {getstream-3.3.4 → getstream-3.4.0}/getstream/moderation/async_rest_client.py +203 -4
- {getstream-3.3.4 → getstream-3.4.0}/getstream/moderation/rest_client.py +205 -4
- {getstream-3.3.4 → getstream-3.4.0}/getstream/stream.py +184 -10
- {getstream-3.3.4 → getstream-3.4.0}/getstream/tests/test_webhook.py +156 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/async_rest_client.py +20 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rest_client.py +20 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/connection_manager.py +2 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/connection_utils.py +26 -31
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/coordinator/ws.py +3 -9
- {getstream-3.3.4 → getstream-3.4.0}/getstream/webhook.py +236 -3
- {getstream-3.3.4 → getstream-3.4.0}/pyproject.toml +7 -9
- {getstream-3.3.4 → getstream-3.4.0}/pytest.ini +2 -0
- {getstream-3.3.4 → getstream-3.4.0}/uv.lock +187 -7
- getstream-3.3.4/.github/workflows/release.yml +0 -60
- getstream-3.3.4/getstream/video/rtc/coordinator_api.py +0 -81
- {getstream-3.3.4 → getstream-3.4.0}/.cursor/worktrees.json +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/.env.example +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/.github/actions/python-uv-setup/action.yml +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/.github/workflows/ci.yml +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/.github/workflows/stream-py.code-workspace +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/.gitignore +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/.gitmodules +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/.pre-commit-config.yaml +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/AGENTS.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/DEVELOPMENT.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/LICENSE.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/MIGRATION_v2_to_v3.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/dev.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/docs/migration-from-stream-chat-python/01-setup-and-auth.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/docs/migration-from-stream-chat-python/02-users.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/docs/migration-from-stream-chat-python/03-channels.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/docs/migration-from-stream-chat-python/04-messages-and-reactions.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/docs/migration-from-stream-chat-python/05-moderation.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/docs/migration-from-stream-chat-python/06-devices.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/docs/migration-from-stream-chat-python/README.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/generate_webrtc.sh +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/base.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/chat/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/chat/async_channel.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/chat/async_client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/chat/channel.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/chat/client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/common/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/common/async_client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/common/client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/common/telemetry.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/feeds/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/feeds/client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/generic.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/meta.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/moderation/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/moderation/async_client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/moderation/client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/rate_limit.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/stream_response.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/utils/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/utils/event_emitter.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/utils/retry.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/version.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/async_call.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/async_client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/call.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/client.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/openai.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/README.md +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/audio_track.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/coordinator/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/coordinator/backoff.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/coordinator/errors.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/encoders_patches.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/g711.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/location_discovery.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/models.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/network_monitor.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/participants.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/event/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/event/events_pb2.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/event/events_pb2.pyi +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/models/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/models/models_pb2.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/models/models_pb2.pyi +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/signal_rpc/__init__.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/signal_rpc/signal_pb2.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/signal_rpc/signal_pb2.pyi +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pb/stream/video/sfu/signal_rpc/signal_twirp.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/pc.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/peer_connection.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/reconnection.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/recording.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/signaling.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/stats_reporter.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/stats_tracer.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/tracer.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/track_util.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/tracks.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/twirp_client_wrapper.py +0 -0
- {getstream-3.3.4 → getstream-3.4.0}/getstream/video/rtc/utils.py +0 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version_bump:
|
|
7
|
+
description: 'Version bump type for manual release'
|
|
8
|
+
required: true
|
|
9
|
+
default: 'patch'
|
|
10
|
+
type: choice
|
|
11
|
+
options:
|
|
12
|
+
- patch
|
|
13
|
+
- minor
|
|
14
|
+
- major
|
|
15
|
+
use_current_version:
|
|
16
|
+
description: 'Skip version bump and publish the version already set in pyproject.toml'
|
|
17
|
+
required: false
|
|
18
|
+
default: false
|
|
19
|
+
type: boolean
|
|
20
|
+
pull_request:
|
|
21
|
+
types: [closed]
|
|
22
|
+
branches:
|
|
23
|
+
- main
|
|
24
|
+
|
|
25
|
+
concurrency:
|
|
26
|
+
group: release-${{ github.event.pull_request.base.ref || github.ref_name }}
|
|
27
|
+
cancel-in-progress: false
|
|
28
|
+
|
|
29
|
+
permissions:
|
|
30
|
+
contents: read
|
|
31
|
+
|
|
32
|
+
jobs:
|
|
33
|
+
prepare:
|
|
34
|
+
name: Prepare release
|
|
35
|
+
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
outputs:
|
|
38
|
+
should_release: ${{ steps.release_meta_final.outputs.should_release }}
|
|
39
|
+
bump: ${{ steps.release_meta_final.outputs.bump }}
|
|
40
|
+
previous_version: ${{ steps.release_meta_final.outputs.previous_version }}
|
|
41
|
+
version: ${{ steps.release_meta_final.outputs.version }}
|
|
42
|
+
tag: ${{ steps.release_meta_final.outputs.tag }}
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v5
|
|
45
|
+
with:
|
|
46
|
+
fetch-depth: 0
|
|
47
|
+
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || github.ref_name }}
|
|
48
|
+
|
|
49
|
+
- name: Skip when PR is already released
|
|
50
|
+
id: already_released
|
|
51
|
+
run: |
|
|
52
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
53
|
+
echo "value=false" >> "$GITHUB_OUTPUT"
|
|
54
|
+
else
|
|
55
|
+
if git log --oneline --grep="(pr #${{ github.event.pull_request.number }})" -n 1 | grep -q "chore(release):"; then
|
|
56
|
+
echo "value=true" >> "$GITHUB_OUTPUT"
|
|
57
|
+
else
|
|
58
|
+
echo "value=false" >> "$GITHUB_OUTPUT"
|
|
59
|
+
fi
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
- name: Determine version bump (from PR metadata)
|
|
63
|
+
id: release_meta
|
|
64
|
+
if: github.event_name == 'pull_request' && steps.already_released.outputs.value != 'true'
|
|
65
|
+
env:
|
|
66
|
+
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
67
|
+
PR_BODY: ${{ github.event.pull_request.body }}
|
|
68
|
+
run: |
|
|
69
|
+
PR_BODY_FILE=$(mktemp)
|
|
70
|
+
printf '%s' "$PR_BODY" > "$PR_BODY_FILE"
|
|
71
|
+
python3 scripts/release/bump_version.py \
|
|
72
|
+
--title "$PR_TITLE" \
|
|
73
|
+
--body-file "$PR_BODY_FILE" \
|
|
74
|
+
--output "$GITHUB_OUTPUT"
|
|
75
|
+
|
|
76
|
+
- name: Determine version bump (manual)
|
|
77
|
+
id: release_meta_manual
|
|
78
|
+
if: github.event_name == 'workflow_dispatch'
|
|
79
|
+
run: |
|
|
80
|
+
python3 scripts/release/bump_version.py \
|
|
81
|
+
--manual-bump "${{ github.event.inputs.version_bump }}" \
|
|
82
|
+
--use-current-version "${{ github.event.inputs.use_current_version }}" \
|
|
83
|
+
--output "$GITHUB_OUTPUT"
|
|
84
|
+
|
|
85
|
+
- name: Consolidate release metadata
|
|
86
|
+
id: release_meta_final
|
|
87
|
+
run: |
|
|
88
|
+
if [ "${{ steps.already_released.outputs.value }}" = "true" ]; then
|
|
89
|
+
echo "should_release=false" >> "$GITHUB_OUTPUT"
|
|
90
|
+
echo "bump=none" >> "$GITHUB_OUTPUT"
|
|
91
|
+
exit 0
|
|
92
|
+
fi
|
|
93
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
94
|
+
echo "should_release=${{ steps.release_meta_manual.outputs.should_release }}" >> "$GITHUB_OUTPUT"
|
|
95
|
+
echo "bump=${{ steps.release_meta_manual.outputs.bump }}" >> "$GITHUB_OUTPUT"
|
|
96
|
+
echo "previous_version=${{ steps.release_meta_manual.outputs.previous_version }}" >> "$GITHUB_OUTPUT"
|
|
97
|
+
echo "version=${{ steps.release_meta_manual.outputs.version }}" >> "$GITHUB_OUTPUT"
|
|
98
|
+
echo "tag=${{ steps.release_meta_manual.outputs.tag }}" >> "$GITHUB_OUTPUT"
|
|
99
|
+
else
|
|
100
|
+
echo "should_release=${{ steps.release_meta.outputs.should_release }}" >> "$GITHUB_OUTPUT"
|
|
101
|
+
echo "bump=${{ steps.release_meta.outputs.bump }}" >> "$GITHUB_OUTPUT"
|
|
102
|
+
echo "previous_version=${{ steps.release_meta.outputs.previous_version }}" >> "$GITHUB_OUTPUT"
|
|
103
|
+
echo "version=${{ steps.release_meta.outputs.version }}" >> "$GITHUB_OUTPUT"
|
|
104
|
+
echo "tag=${{ steps.release_meta.outputs.tag }}" >> "$GITHUB_OUTPUT"
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
test-unit:
|
|
108
|
+
name: Test (unit)
|
|
109
|
+
needs: prepare
|
|
110
|
+
if: needs.prepare.outputs.should_release == 'true'
|
|
111
|
+
uses: ./.github/workflows/run_tests.yml
|
|
112
|
+
with:
|
|
113
|
+
marker: 'not integration'
|
|
114
|
+
secrets: inherit
|
|
115
|
+
|
|
116
|
+
test-integration:
|
|
117
|
+
name: Test (integration)
|
|
118
|
+
needs: prepare
|
|
119
|
+
if: needs.prepare.outputs.should_release == 'true'
|
|
120
|
+
uses: ./.github/workflows/run_tests.yml
|
|
121
|
+
with:
|
|
122
|
+
marker: 'integration'
|
|
123
|
+
secrets: inherit
|
|
124
|
+
|
|
125
|
+
release:
|
|
126
|
+
name: 🚀 Release
|
|
127
|
+
needs: [prepare, test-unit, test-integration]
|
|
128
|
+
if: needs.prepare.outputs.should_release == 'true'
|
|
129
|
+
runs-on: ubuntu-latest
|
|
130
|
+
environment: pypi
|
|
131
|
+
permissions:
|
|
132
|
+
contents: write
|
|
133
|
+
id-token: write
|
|
134
|
+
steps:
|
|
135
|
+
- uses: actions/checkout@v5
|
|
136
|
+
with:
|
|
137
|
+
fetch-depth: 0
|
|
138
|
+
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || github.ref_name }}
|
|
139
|
+
|
|
140
|
+
- uses: ./.github/actions/python-uv-setup
|
|
141
|
+
|
|
142
|
+
- name: Apply version bump
|
|
143
|
+
env:
|
|
144
|
+
VERSION: ${{ needs.prepare.outputs.version }}
|
|
145
|
+
run: |
|
|
146
|
+
python3 - <<'PY'
|
|
147
|
+
import os, re
|
|
148
|
+
from pathlib import Path
|
|
149
|
+
version = os.environ['VERSION']
|
|
150
|
+
path = Path('pyproject.toml')
|
|
151
|
+
text = path.read_text(encoding='utf-8')
|
|
152
|
+
pattern = re.compile(r'^version\s*=\s*"\d+\.\d+\.\d+"\s*$', re.MULTILINE)
|
|
153
|
+
new_text, count = pattern.subn(f'version = "{version}"', text, count=1)
|
|
154
|
+
if count == 0:
|
|
155
|
+
raise SystemExit('Could not update version line in pyproject.toml')
|
|
156
|
+
path.write_text(new_text, encoding='utf-8')
|
|
157
|
+
PY
|
|
158
|
+
|
|
159
|
+
- name: Commit version bump
|
|
160
|
+
env:
|
|
161
|
+
VERSION: ${{ needs.prepare.outputs.version }}
|
|
162
|
+
run: |
|
|
163
|
+
git config user.name "github-actions[bot]"
|
|
164
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
165
|
+
git add pyproject.toml
|
|
166
|
+
if git diff --cached --quiet; then
|
|
167
|
+
echo "No version changes to commit."
|
|
168
|
+
exit 0
|
|
169
|
+
fi
|
|
170
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
171
|
+
git commit -m "chore(release): v${VERSION} (manual)"
|
|
172
|
+
git push origin "HEAD:${{ github.ref_name }}"
|
|
173
|
+
else
|
|
174
|
+
git commit -m "chore(release): v${VERSION} (pr #${{ github.event.pull_request.number }})"
|
|
175
|
+
git push origin "HEAD:${{ github.event.pull_request.base.ref }}"
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
- name: Create release tag
|
|
179
|
+
env:
|
|
180
|
+
TAG: ${{ needs.prepare.outputs.tag }}
|
|
181
|
+
run: |
|
|
182
|
+
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
|
|
183
|
+
echo "Tag ${TAG} already exists; skipping tag creation."
|
|
184
|
+
exit 0
|
|
185
|
+
fi
|
|
186
|
+
git tag "${TAG}"
|
|
187
|
+
git push origin "${TAG}"
|
|
188
|
+
|
|
189
|
+
- name: Clean dist directory
|
|
190
|
+
run: rm -rf dist
|
|
191
|
+
|
|
192
|
+
- name: Build distributions
|
|
193
|
+
run: uv build
|
|
194
|
+
|
|
195
|
+
- name: Publish to PyPI (Trusted Publishing)
|
|
196
|
+
run: uv publish
|
|
197
|
+
|
|
198
|
+
- name: Create release on GitHub
|
|
199
|
+
uses: ncipollo/release-action@v1
|
|
200
|
+
with:
|
|
201
|
+
tag: ${{ needs.prepare.outputs.tag }}
|
|
202
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
203
|
+
skipIfReleaseExists: true
|
|
204
|
+
body: |
|
|
205
|
+
Release v${{ needs.prepare.outputs.version }}
|
|
206
|
+
|
|
207
|
+
- Bump type: `${{ needs.prepare.outputs.bump }}`
|
|
208
|
+
- Previous: `${{ needs.prepare.outputs.previous_version }}`
|
|
209
|
+
- Next: `${{ needs.prepare.outputs.version }}`
|
|
210
|
+
- Trigger: `${{ github.event_name }}`
|
|
211
|
+
|
|
212
|
+
Install with: `pip install getstream==${{ needs.prepare.outputs.version }}`
|
|
213
|
+
|
|
214
|
+
- name: Verify pip install
|
|
215
|
+
env:
|
|
216
|
+
UV_NO_SOURCES: "1"
|
|
217
|
+
run: |
|
|
218
|
+
uv pip install "getstream==${{ needs.prepare.outputs.version }}" || \
|
|
219
|
+
echo "WARNING: pip install verification failed (PyPI index may need a moment to propagate)"
|
|
@@ -8,7 +8,7 @@ on:
|
|
|
8
8
|
type: string
|
|
9
9
|
secrets: { }
|
|
10
10
|
concurrency:
|
|
11
|
-
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.marker }}
|
|
12
12
|
cancel-in-progress: true
|
|
13
13
|
|
|
14
14
|
env:
|
|
@@ -49,7 +49,7 @@ jobs:
|
|
|
49
49
|
strategy:
|
|
50
50
|
fail-fast: false
|
|
51
51
|
matrix:
|
|
52
|
-
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
52
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
53
53
|
timeout-minutes: 30
|
|
54
54
|
steps:
|
|
55
55
|
- name: Checkout
|
|
@@ -75,7 +75,7 @@ jobs:
|
|
|
75
75
|
strategy:
|
|
76
76
|
fail-fast: false
|
|
77
77
|
matrix:
|
|
78
|
-
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
78
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
79
79
|
timeout-minutes: 30
|
|
80
80
|
steps:
|
|
81
81
|
- name: Checkout
|
|
@@ -5,6 +5,41 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Webhook handling spec helpers (CHA-2961): `UnknownEvent` dataclass for
|
|
13
|
+
forward-compat; `gunzip_payload`, `decode_sqs_payload`, `decode_sns_payload`
|
|
14
|
+
primitives; `parse_event` (returns typed event or `UnknownEvent` for
|
|
15
|
+
unrecognized discriminators); `verify_signature` canonical alias of
|
|
16
|
+
`verify_webhook_signature`; `verify_and_parse_webhook` HTTP composite
|
|
17
|
+
(gunzip + verify + parse); `parse_sqs` and `parse_sns` queue composites
|
|
18
|
+
(no signature parameter — queue transports are authenticated by AWS IAM,
|
|
19
|
+
so the backend emits no HMAC for queue messages today). Transparent gzip
|
|
20
|
+
via magic-byte detection.
|
|
21
|
+
- New instance methods on `Stream` and `AsyncStream`:
|
|
22
|
+
`verify_signature(body, signature)` and
|
|
23
|
+
`verify_and_parse_webhook(body, signature)` — drop the api_secret parameter
|
|
24
|
+
in favor of the client's stored secret. Dual API: the module-level functions
|
|
25
|
+
in `getstream.webhook` remain available for callers who want explicit
|
|
26
|
+
secret control.
|
|
27
|
+
- New instance methods on `Stream` / `AsyncStream`: `parse_sqs(message_body)`,
|
|
28
|
+
`parse_sns(notification_body)` (no signature; AWS IAM).
|
|
29
|
+
- `InvalidWebhookError` exception type covering both signature mismatches and
|
|
30
|
+
malformed payloads. Distinguish failure modes via the exception message or
|
|
31
|
+
`__cause__` chain.
|
|
32
|
+
- Conformance fixture suite under `tests/fixtures/webhooks/` (13 happy-path
|
|
33
|
+
event directories + 8 negative cases) for SDK conformance testing across
|
|
34
|
+
language ports.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- No breaking changes. All existing webhook helpers (`verify_webhook_signature`,
|
|
39
|
+
`parse_webhook_event`, `get_event_type`, event type constants) are preserved.
|
|
40
|
+
|
|
41
|
+
[Spec](https://www.notion.so/stream-wiki/Server-Side-SDK-Webhook-Handling-Spec-34b6a5d7f9f681e78003c443f227493c)
|
|
42
|
+
|
|
8
43
|
## [3.0.0b1] - 2026-02-27
|
|
9
44
|
|
|
10
45
|
### Breaking Changes
|
|
@@ -56,11 +56,13 @@ TY_EXCLUDES := \
|
|
|
56
56
|
|
|
57
57
|
## Run non-video tests (chat, feeds, moderation, etc.)
|
|
58
58
|
test:
|
|
59
|
-
uv run pytest -m "$(MARKER)" tests/ getstream/ $(VIDEO_IGNORE) $(MANUAL_IGNORE)
|
|
59
|
+
@uv run pytest -m "$(MARKER)" tests/ getstream/ $(VIDEO_IGNORE) $(MANUAL_IGNORE); \
|
|
60
|
+
ec=$$?; if [ $$ec -eq 5 ]; then echo "No tests matched marker '$(MARKER)' — treating as success."; exit 0; else exit $$ec; fi
|
|
60
61
|
|
|
61
62
|
## Run video/WebRTC tests only
|
|
62
63
|
test-video:
|
|
63
|
-
uv run pytest -m "$(MARKER)" $(VIDEO_PATHS)
|
|
64
|
+
@uv run pytest -m "$(MARKER)" $(VIDEO_PATHS); \
|
|
65
|
+
ec=$$?; if [ $$ec -eq 5 ]; then echo "No tests matched marker '$(MARKER)' — treating as success."; exit 0; else exit $$ec; fi
|
|
64
66
|
|
|
65
67
|
## Run all tests (non-video + video), excluding manual tests
|
|
66
68
|
test-all:
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: getstream
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
4
4
|
Summary: GetStream Python SDK - Build scalable activity feeds, chat, and video calling applications
|
|
5
5
|
Author-email: sachaarbonel <sacha.arbonel@hotmail.fr>, tbarbugli <tbarbugli@gmail.com>
|
|
6
6
|
License-File: LICENSE.md
|
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
9
8
|
Classifier: Programming Language :: Python :: 3.10
|
|
10
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
11
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
13
|
Requires-Python: <4.0.0,>=3.10
|
|
14
14
|
Requires-Dist: dataclasses-json<0.7,>=0.6.0
|
|
15
15
|
Requires-Dist: httpx>=0.28.1
|
|
@@ -31,13 +31,15 @@ Provides-Extra: webrtc
|
|
|
31
31
|
Requires-Dist: aiohttp<4,>=3.13.2; extra == 'webrtc'
|
|
32
32
|
Requires-Dist: aiortc<1.15.0,>=1.14.0; extra == 'webrtc'
|
|
33
33
|
Requires-Dist: av<17,>=14.2.0; extra == 'webrtc'
|
|
34
|
-
Requires-Dist: numpy<2.3,>=2.2.6; extra == 'webrtc'
|
|
34
|
+
Requires-Dist: numpy<2.3,>=2.2.6; (python_version < '3.14') and extra == 'webrtc'
|
|
35
|
+
Requires-Dist: numpy<2.4,>=2.3.2; (python_version >= '3.14') and extra == 'webrtc'
|
|
35
36
|
Requires-Dist: numpy>=2.2.6; extra == 'webrtc'
|
|
36
37
|
Requires-Dist: ping3>=4.0.8; extra == 'webrtc'
|
|
37
38
|
Requires-Dist: protobuf>=4.25.1; extra == 'webrtc'
|
|
38
39
|
Requires-Dist: protobuf>=6.31.1; extra == 'webrtc'
|
|
39
40
|
Requires-Dist: python-dateutil>=2.8.2; extra == 'webrtc'
|
|
40
|
-
Requires-Dist: scipy<1.16,>=1.15.3; extra == 'webrtc'
|
|
41
|
+
Requires-Dist: scipy<1.16,>=1.15.3; (python_version < '3.14') and extra == 'webrtc'
|
|
42
|
+
Requires-Dist: scipy<1.17,>=1.16.1; (python_version >= '3.14') and extra == 'webrtc'
|
|
41
43
|
Requires-Dist: scipy>=1.15.3; extra == 'webrtc'
|
|
42
44
|
Requires-Dist: soundfile>=0.13.1; extra == 'webrtc'
|
|
43
45
|
Requires-Dist: structlog<24; extra == 'webrtc'
|
|
@@ -175,7 +177,7 @@ We use [uv](https://github.com/astral-sh/uv) to manage dependencies and run test
|
|
|
175
177
|
### 🚀 Quick Start
|
|
176
178
|
|
|
177
179
|
**Prerequisites:**
|
|
178
|
-
- Python 3.
|
|
180
|
+
- Python 3.10+ (recommended: 3.12.2)
|
|
179
181
|
- [uv](https://github.com/astral-sh/uv) package manager
|
|
180
182
|
|
|
181
183
|
**Setup:**
|
|
@@ -280,6 +282,23 @@ uv run pytest -v -s
|
|
|
280
282
|
uv run pytest tests/test_video.py::test_specific_function -v
|
|
281
283
|
```
|
|
282
284
|
|
|
285
|
+
## Releases
|
|
286
|
+
|
|
287
|
+
Releases use two paths:
|
|
288
|
+
|
|
289
|
+
- **Default**: automatic release when a PR is merged to `main`. The PR title (and body) drives the semver bump.
|
|
290
|
+
- **Fallback**: manual release via the `Release` workflow's `workflow_dispatch` (admin use). Select a `version_bump` (`patch`/`minor`/`major`). `use_current_version=true` skips the bump and publishes whatever is already in `pyproject.toml`.
|
|
291
|
+
|
|
292
|
+
Automatic semver bump rules:
|
|
293
|
+
|
|
294
|
+
- `feat:` -> minor
|
|
295
|
+
- `fix:` (or `bug:`) -> patch
|
|
296
|
+
- `feat!:`, `<type>(scope)!:`, or `BREAKING CHANGE` in the PR body/title -> major
|
|
297
|
+
|
|
298
|
+
PRs with any other prefix do not trigger a release.
|
|
299
|
+
|
|
300
|
+
The release pipeline runs lint, type-check, and the full test matrix (unit + integration, across all supported Python versions) on the merged commit before publishing to PyPI via Trusted Publishing (OIDC). Each step in the publish job is idempotent: a failed run can be re-dispatched from the Actions UI.
|
|
301
|
+
|
|
283
302
|
## License
|
|
284
303
|
|
|
285
304
|
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -125,7 +125,7 @@ We use [uv](https://github.com/astral-sh/uv) to manage dependencies and run test
|
|
|
125
125
|
### 🚀 Quick Start
|
|
126
126
|
|
|
127
127
|
**Prerequisites:**
|
|
128
|
-
- Python 3.
|
|
128
|
+
- Python 3.10+ (recommended: 3.12.2)
|
|
129
129
|
- [uv](https://github.com/astral-sh/uv) package manager
|
|
130
130
|
|
|
131
131
|
**Setup:**
|
|
@@ -230,6 +230,23 @@ uv run pytest -v -s
|
|
|
230
230
|
uv run pytest tests/test_video.py::test_specific_function -v
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
+
## Releases
|
|
234
|
+
|
|
235
|
+
Releases use two paths:
|
|
236
|
+
|
|
237
|
+
- **Default**: automatic release when a PR is merged to `main`. The PR title (and body) drives the semver bump.
|
|
238
|
+
- **Fallback**: manual release via the `Release` workflow's `workflow_dispatch` (admin use). Select a `version_bump` (`patch`/`minor`/`major`). `use_current_version=true` skips the bump and publishes whatever is already in `pyproject.toml`.
|
|
239
|
+
|
|
240
|
+
Automatic semver bump rules:
|
|
241
|
+
|
|
242
|
+
- `feat:` -> minor
|
|
243
|
+
- `fix:` (or `bug:`) -> patch
|
|
244
|
+
- `feat!:`, `<type>(scope)!:`, or `BREAKING CHANGE` in the PR body/title -> major
|
|
245
|
+
|
|
246
|
+
PRs with any other prefix do not trigger a release.
|
|
247
|
+
|
|
248
|
+
The release pipeline runs lint, type-check, and the full test matrix (unit + integration, across all supported Python versions) on the merged commit before publishing to PyPI via Trusted Publishing (OIDC). Each step in the publish job is idempotent: a failed run can be re-dispatched from the Actions UI.
|
|
249
|
+
|
|
233
250
|
## License
|
|
234
251
|
|
|
235
252
|
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -17,7 +17,10 @@ fi
|
|
|
17
17
|
set -ex
|
|
18
18
|
|
|
19
19
|
# cd in API repo, generate new spec and then generate code from it
|
|
20
|
-
( cd $SOURCE_PATH ; make openapi ;
|
|
20
|
+
( cd $SOURCE_PATH ; make openapi ; ./build/chat-manager openapi generate-client --language python --spec ./releases/v2/serverside-api.yaml --output ../stream-py/getstream/ )
|
|
21
|
+
|
|
22
|
+
# Regenerate webhook conformance fixtures (CHA-2961)
|
|
23
|
+
( cd $SOURCE_PATH ; ./build/chat-manager openapi generate-webhook-fixtures --output ../stream-py/tests/assets/webhooks --time-format=unix-ns )
|
|
21
24
|
|
|
22
25
|
# lint + auto-fix, then format generated code with ruff (align with pre-commit)
|
|
23
26
|
uv run ruff check --fix getstream/ tests/
|
|
@@ -31,6 +31,44 @@ class ChatRestClient(AsyncBaseClient):
|
|
|
31
31
|
user_agent=user_agent,
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
+
@telemetry.operation_name("getstream.api.chat.create_campaign")
|
|
35
|
+
async def create_campaign(
|
|
36
|
+
self,
|
|
37
|
+
sender_id: str,
|
|
38
|
+
message_template: CampaignMessageTemplate,
|
|
39
|
+
create_channels: Optional[bool] = None,
|
|
40
|
+
description: Optional[str] = None,
|
|
41
|
+
id: Optional[str] = None,
|
|
42
|
+
name: Optional[str] = None,
|
|
43
|
+
sender_mode: Optional[str] = None,
|
|
44
|
+
sender_visibility: Optional[str] = None,
|
|
45
|
+
show_channels: Optional[bool] = None,
|
|
46
|
+
skip_push: Optional[bool] = None,
|
|
47
|
+
skip_webhook: Optional[bool] = None,
|
|
48
|
+
segment_ids: Optional[List[str]] = None,
|
|
49
|
+
user_ids: Optional[List[str]] = None,
|
|
50
|
+
channel_template: Optional[CampaignChannelTemplate] = None,
|
|
51
|
+
) -> StreamResponse[CreateCampaignResponse]:
|
|
52
|
+
json = CreateCampaignRequest(
|
|
53
|
+
sender_id=sender_id,
|
|
54
|
+
message_template=message_template,
|
|
55
|
+
create_channels=create_channels,
|
|
56
|
+
description=description,
|
|
57
|
+
id=id,
|
|
58
|
+
name=name,
|
|
59
|
+
sender_mode=sender_mode,
|
|
60
|
+
sender_visibility=sender_visibility,
|
|
61
|
+
show_channels=show_channels,
|
|
62
|
+
skip_push=skip_push,
|
|
63
|
+
skip_webhook=skip_webhook,
|
|
64
|
+
segment_ids=segment_ids,
|
|
65
|
+
user_ids=user_ids,
|
|
66
|
+
channel_template=channel_template,
|
|
67
|
+
).to_dict()
|
|
68
|
+
return await self.post(
|
|
69
|
+
"/api/v2/chat/campaigns", CreateCampaignResponse, json=json
|
|
70
|
+
)
|
|
71
|
+
|
|
34
72
|
@telemetry.operation_name("getstream.api.chat.query_campaigns")
|
|
35
73
|
async def query_campaigns(
|
|
36
74
|
self,
|
|
@@ -53,6 +91,17 @@ class ChatRestClient(AsyncBaseClient):
|
|
|
53
91
|
"/api/v2/chat/campaigns/query", QueryCampaignsResponse, json=json
|
|
54
92
|
)
|
|
55
93
|
|
|
94
|
+
@telemetry.operation_name("getstream.api.chat.delete_campaign")
|
|
95
|
+
async def delete_campaign(self, id: str) -> StreamResponse[DeleteCampaignResponse]:
|
|
96
|
+
path_params = {
|
|
97
|
+
"id": id,
|
|
98
|
+
}
|
|
99
|
+
return await self.delete(
|
|
100
|
+
"/api/v2/chat/campaigns/{id}",
|
|
101
|
+
DeleteCampaignResponse,
|
|
102
|
+
path_params=path_params,
|
|
103
|
+
)
|
|
104
|
+
|
|
56
105
|
@telemetry.operation_name("getstream.api.chat.get_campaign")
|
|
57
106
|
async def get_campaign(
|
|
58
107
|
self,
|
|
@@ -72,6 +121,51 @@ class ChatRestClient(AsyncBaseClient):
|
|
|
72
121
|
path_params=path_params,
|
|
73
122
|
)
|
|
74
123
|
|
|
124
|
+
@telemetry.operation_name("getstream.api.chat.update_campaign")
|
|
125
|
+
async def update_campaign(
|
|
126
|
+
self,
|
|
127
|
+
id: str,
|
|
128
|
+
sender_id: str,
|
|
129
|
+
message_template: CampaignMessageTemplate,
|
|
130
|
+
create_channels: Optional[bool] = None,
|
|
131
|
+
description: Optional[str] = None,
|
|
132
|
+
id_: Optional[str] = None,
|
|
133
|
+
name: Optional[str] = None,
|
|
134
|
+
sender_mode: Optional[str] = None,
|
|
135
|
+
sender_visibility: Optional[str] = None,
|
|
136
|
+
show_channels: Optional[bool] = None,
|
|
137
|
+
skip_push: Optional[bool] = None,
|
|
138
|
+
skip_webhook: Optional[bool] = None,
|
|
139
|
+
segment_ids: Optional[List[str]] = None,
|
|
140
|
+
user_ids: Optional[List[str]] = None,
|
|
141
|
+
channel_template: Optional[CampaignChannelTemplate] = None,
|
|
142
|
+
) -> StreamResponse[CampaignResponse]:
|
|
143
|
+
path_params = {
|
|
144
|
+
"id": id,
|
|
145
|
+
}
|
|
146
|
+
json = UpdateCampaignRequest(
|
|
147
|
+
sender_id=sender_id,
|
|
148
|
+
message_template=message_template,
|
|
149
|
+
create_channels=create_channels,
|
|
150
|
+
description=description,
|
|
151
|
+
id=id_,
|
|
152
|
+
name=name,
|
|
153
|
+
sender_mode=sender_mode,
|
|
154
|
+
sender_visibility=sender_visibility,
|
|
155
|
+
show_channels=show_channels,
|
|
156
|
+
skip_push=skip_push,
|
|
157
|
+
skip_webhook=skip_webhook,
|
|
158
|
+
segment_ids=segment_ids,
|
|
159
|
+
user_ids=user_ids,
|
|
160
|
+
channel_template=channel_template,
|
|
161
|
+
).to_dict()
|
|
162
|
+
return await self.put(
|
|
163
|
+
"/api/v2/chat/campaigns/{id}",
|
|
164
|
+
CampaignResponse,
|
|
165
|
+
path_params=path_params,
|
|
166
|
+
json=json,
|
|
167
|
+
)
|
|
168
|
+
|
|
75
169
|
@telemetry.operation_name("getstream.api.chat.start_campaign")
|
|
76
170
|
async def start_campaign(
|
|
77
171
|
self,
|
|
@@ -183,6 +277,20 @@ class ChatRestClient(AsyncBaseClient):
|
|
|
183
277
|
json=json,
|
|
184
278
|
)
|
|
185
279
|
|
|
280
|
+
@telemetry.operation_name("getstream.api.chat.grouped_query_channels")
|
|
281
|
+
async def grouped_query_channels(
|
|
282
|
+
self,
|
|
283
|
+
limit: Optional[int] = None,
|
|
284
|
+
user_id: Optional[str] = None,
|
|
285
|
+
user: Optional[UserRequest] = None,
|
|
286
|
+
) -> StreamResponse[GroupedQueryChannelsResponse]:
|
|
287
|
+
json = GroupedQueryChannelsRequest(
|
|
288
|
+
limit=limit, user_id=user_id, user=user
|
|
289
|
+
).to_dict()
|
|
290
|
+
return await self.post(
|
|
291
|
+
"/api/v2/chat/channels/grouped", GroupedQueryChannelsResponse, json=json
|
|
292
|
+
)
|
|
293
|
+
|
|
186
294
|
@telemetry.operation_name("getstream.api.chat.mark_channels_read")
|
|
187
295
|
async def mark_channels_read(
|
|
188
296
|
self,
|
|
@@ -31,6 +31,42 @@ class ChatRestClient(BaseClient):
|
|
|
31
31
|
user_agent=user_agent,
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
+
@telemetry.operation_name("getstream.api.chat.create_campaign")
|
|
35
|
+
def create_campaign(
|
|
36
|
+
self,
|
|
37
|
+
sender_id: str,
|
|
38
|
+
message_template: CampaignMessageTemplate,
|
|
39
|
+
create_channels: Optional[bool] = None,
|
|
40
|
+
description: Optional[str] = None,
|
|
41
|
+
id: Optional[str] = None,
|
|
42
|
+
name: Optional[str] = None,
|
|
43
|
+
sender_mode: Optional[str] = None,
|
|
44
|
+
sender_visibility: Optional[str] = None,
|
|
45
|
+
show_channels: Optional[bool] = None,
|
|
46
|
+
skip_push: Optional[bool] = None,
|
|
47
|
+
skip_webhook: Optional[bool] = None,
|
|
48
|
+
segment_ids: Optional[List[str]] = None,
|
|
49
|
+
user_ids: Optional[List[str]] = None,
|
|
50
|
+
channel_template: Optional[CampaignChannelTemplate] = None,
|
|
51
|
+
) -> StreamResponse[CreateCampaignResponse]:
|
|
52
|
+
json = CreateCampaignRequest(
|
|
53
|
+
sender_id=sender_id,
|
|
54
|
+
message_template=message_template,
|
|
55
|
+
create_channels=create_channels,
|
|
56
|
+
description=description,
|
|
57
|
+
id=id,
|
|
58
|
+
name=name,
|
|
59
|
+
sender_mode=sender_mode,
|
|
60
|
+
sender_visibility=sender_visibility,
|
|
61
|
+
show_channels=show_channels,
|
|
62
|
+
skip_push=skip_push,
|
|
63
|
+
skip_webhook=skip_webhook,
|
|
64
|
+
segment_ids=segment_ids,
|
|
65
|
+
user_ids=user_ids,
|
|
66
|
+
channel_template=channel_template,
|
|
67
|
+
).to_dict()
|
|
68
|
+
return self.post("/api/v2/chat/campaigns", CreateCampaignResponse, json=json)
|
|
69
|
+
|
|
34
70
|
@telemetry.operation_name("getstream.api.chat.query_campaigns")
|
|
35
71
|
def query_campaigns(
|
|
36
72
|
self,
|
|
@@ -53,6 +89,17 @@ class ChatRestClient(BaseClient):
|
|
|
53
89
|
"/api/v2/chat/campaigns/query", QueryCampaignsResponse, json=json
|
|
54
90
|
)
|
|
55
91
|
|
|
92
|
+
@telemetry.operation_name("getstream.api.chat.delete_campaign")
|
|
93
|
+
def delete_campaign(self, id: str) -> StreamResponse[DeleteCampaignResponse]:
|
|
94
|
+
path_params = {
|
|
95
|
+
"id": id,
|
|
96
|
+
}
|
|
97
|
+
return self.delete(
|
|
98
|
+
"/api/v2/chat/campaigns/{id}",
|
|
99
|
+
DeleteCampaignResponse,
|
|
100
|
+
path_params=path_params,
|
|
101
|
+
)
|
|
102
|
+
|
|
56
103
|
@telemetry.operation_name("getstream.api.chat.get_campaign")
|
|
57
104
|
def get_campaign(
|
|
58
105
|
self,
|
|
@@ -72,6 +119,51 @@ class ChatRestClient(BaseClient):
|
|
|
72
119
|
path_params=path_params,
|
|
73
120
|
)
|
|
74
121
|
|
|
122
|
+
@telemetry.operation_name("getstream.api.chat.update_campaign")
|
|
123
|
+
def update_campaign(
|
|
124
|
+
self,
|
|
125
|
+
id: str,
|
|
126
|
+
sender_id: str,
|
|
127
|
+
message_template: CampaignMessageTemplate,
|
|
128
|
+
create_channels: Optional[bool] = None,
|
|
129
|
+
description: Optional[str] = None,
|
|
130
|
+
id_: Optional[str] = None,
|
|
131
|
+
name: Optional[str] = None,
|
|
132
|
+
sender_mode: Optional[str] = None,
|
|
133
|
+
sender_visibility: Optional[str] = None,
|
|
134
|
+
show_channels: Optional[bool] = None,
|
|
135
|
+
skip_push: Optional[bool] = None,
|
|
136
|
+
skip_webhook: Optional[bool] = None,
|
|
137
|
+
segment_ids: Optional[List[str]] = None,
|
|
138
|
+
user_ids: Optional[List[str]] = None,
|
|
139
|
+
channel_template: Optional[CampaignChannelTemplate] = None,
|
|
140
|
+
) -> StreamResponse[CampaignResponse]:
|
|
141
|
+
path_params = {
|
|
142
|
+
"id": id,
|
|
143
|
+
}
|
|
144
|
+
json = UpdateCampaignRequest(
|
|
145
|
+
sender_id=sender_id,
|
|
146
|
+
message_template=message_template,
|
|
147
|
+
create_channels=create_channels,
|
|
148
|
+
description=description,
|
|
149
|
+
id=id_,
|
|
150
|
+
name=name,
|
|
151
|
+
sender_mode=sender_mode,
|
|
152
|
+
sender_visibility=sender_visibility,
|
|
153
|
+
show_channels=show_channels,
|
|
154
|
+
skip_push=skip_push,
|
|
155
|
+
skip_webhook=skip_webhook,
|
|
156
|
+
segment_ids=segment_ids,
|
|
157
|
+
user_ids=user_ids,
|
|
158
|
+
channel_template=channel_template,
|
|
159
|
+
).to_dict()
|
|
160
|
+
return self.put(
|
|
161
|
+
"/api/v2/chat/campaigns/{id}",
|
|
162
|
+
CampaignResponse,
|
|
163
|
+
path_params=path_params,
|
|
164
|
+
json=json,
|
|
165
|
+
)
|
|
166
|
+
|
|
75
167
|
@telemetry.operation_name("getstream.api.chat.start_campaign")
|
|
76
168
|
def start_campaign(
|
|
77
169
|
self,
|
|
@@ -181,6 +273,20 @@ class ChatRestClient(BaseClient):
|
|
|
181
273
|
json=json,
|
|
182
274
|
)
|
|
183
275
|
|
|
276
|
+
@telemetry.operation_name("getstream.api.chat.grouped_query_channels")
|
|
277
|
+
def grouped_query_channels(
|
|
278
|
+
self,
|
|
279
|
+
limit: Optional[int] = None,
|
|
280
|
+
user_id: Optional[str] = None,
|
|
281
|
+
user: Optional[UserRequest] = None,
|
|
282
|
+
) -> StreamResponse[GroupedQueryChannelsResponse]:
|
|
283
|
+
json = GroupedQueryChannelsRequest(
|
|
284
|
+
limit=limit, user_id=user_id, user=user
|
|
285
|
+
).to_dict()
|
|
286
|
+
return self.post(
|
|
287
|
+
"/api/v2/chat/channels/grouped", GroupedQueryChannelsResponse, json=json
|
|
288
|
+
)
|
|
289
|
+
|
|
184
290
|
@telemetry.operation_name("getstream.api.chat.mark_channels_read")
|
|
185
291
|
def mark_channels_read(
|
|
186
292
|
self,
|