Skip to content
Merged
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
12 changes: 8 additions & 4 deletions fcm_django/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,20 +566,24 @@ def handle_topic_subscription(
app = SETTINGS["DEFAULT_FIREBASE_APP"] if app is None else app
if not registration_ids:
return self.get_default_topic_response()
responses: list[messaging.SendResponse] = []
topic_results: list[dict[str, str]] = [{} for _ in registration_ids]
for i in range(0, len(registration_ids), MAX_DEVICES_PER_SUBSCRIBE_REQUEST):
batch_ids = registration_ids[i : i + MAX_DEVICES_PER_SUBSCRIBE_REQUEST]
responses.extend(
batch_response = (
messaging.subscribe_to_topic
if should_subscribe
else messaging.unsubscribe_from_topic
)(batch_ids, topic, app=app, **more_subscribe_kwargs)
for error in batch_response.errors:
topic_results[i + error.index] = {"error": error.reason}

response = messaging.TopicManagementResponse({"results": topic_results})

return FirebaseResponseDict(
response=messaging.BatchResponse(responses),
response=response,
registration_ids_sent=registration_ids,
deactivated_registration_ids=self.deactivate_devices_with_error_results(
registration_ids, responses
registration_ids, response.errors
),
)

Expand Down
46 changes: 46 additions & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,52 @@ def test_firebase_response_dict_summary_for_topic_response(mocker):
assert result.failed_exceptions == ["messaging/mismatched-credential"]


@pytest.mark.django_db
def test_queryset_handle_topic_subscription_aggregates_topic_errors(mocker):
registration_ids = ["token-1", "token-2", "token-3"]

mock_subscribe = mocker.patch("fcm_django.models.messaging.subscribe_to_topic")
mock_subscribe.side_effect = [
mocker.Mock(
spec=["errors"],
errors=[mocker.Mock(index=1, reason="messaging/mismatched-credential")],
),
mocker.Mock(
spec=["errors"],
errors=[
mocker.Mock(
index=0,
reason="messaging/registration-token-not-registered",
)
],
),
]
mocker.patch("fcm_django.models.MAX_DEVICES_PER_SUBSCRIBE_REQUEST", 2)

response = FCMDevice.objects.none().handle_topic_subscription(
True,
topic="topic-name",
skip_registration_id_lookup=True,
additional_registration_ids=registration_ids,
)

assert mock_subscribe.call_args_list == [
mocker.call(
["token-1", "token-2"],
"topic-name",
app=None,
),
mocker.call(
["token-3"],
"topic-name",
app=None,
),
]
assert response.failure_count == 2
assert response.failed_registration_ids == ["token-2", "token-3"]
assert [error.index for error in response.response.errors] == [1, 2]


@pytest.mark.django_db
class TestFCMDeviceSendMessage:
def assert_sent_successfully(
Expand Down
Loading