mirror of https://github.com/zulip/zulip.git
remote_server_post_analytics: Return remote realms data in response.
This is a prep commit to return, for each remote realm, the 'uuid', 'can_push', and 'expected_end_timestamp'. This data will be used in 'initialize_push_notifications'.
This commit is contained in:
parent
895d76f6f0
commit
6aa911a9b2
|
@ -15,6 +15,7 @@ from zerver.lib.exceptions import JsonableError, MissingRemoteRealmError
|
||||||
from zerver.lib.export import floatify_datetime_fields
|
from zerver.lib.export import floatify_datetime_fields
|
||||||
from zerver.lib.outgoing_http import OutgoingSession
|
from zerver.lib.outgoing_http import OutgoingSession
|
||||||
from zerver.lib.queue import queue_json_publish
|
from zerver.lib.queue import queue_json_publish
|
||||||
|
from zerver.lib.types import RemoteRealmDictValue
|
||||||
from zerver.models import OrgTypeEnum, Realm, RealmAuditLog
|
from zerver.models import OrgTypeEnum, Realm, RealmAuditLog
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,7 +288,7 @@ def send_analytics_to_push_bouncer() -> None:
|
||||||
logger.info("Reported %d records", record_count)
|
logger.info("Reported %d records", record_count)
|
||||||
|
|
||||||
|
|
||||||
def send_realms_only_to_push_bouncer() -> None:
|
def send_realms_only_to_push_bouncer() -> Dict[str, RemoteRealmDictValue]:
|
||||||
request = {
|
request = {
|
||||||
"realm_counts": "[]",
|
"realm_counts": "[]",
|
||||||
"installation_counts": "[]",
|
"installation_counts": "[]",
|
||||||
|
@ -299,7 +300,10 @@ def send_realms_only_to_push_bouncer() -> None:
|
||||||
|
|
||||||
# We don't catch JsonableError here, because we want it to propagate further
|
# We don't catch JsonableError here, because we want it to propagate further
|
||||||
# to either explicitly, loudly fail or be error-handled by the caller.
|
# to either explicitly, loudly fail or be error-handled by the caller.
|
||||||
send_to_push_bouncer("POST", "server/analytics", request)
|
response = send_to_push_bouncer("POST", "server/analytics", request)
|
||||||
|
assert isinstance(response["realms"], dict) # for mypy
|
||||||
|
|
||||||
|
return response["realms"]
|
||||||
|
|
||||||
|
|
||||||
def enqueue_register_realm_with_push_bouncer_if_needed(realm: Realm) -> None:
|
def enqueue_register_realm_with_push_bouncer_if_needed(realm: Realm) -> None:
|
||||||
|
|
|
@ -315,3 +315,8 @@ class RawUserDict(TypedDict):
|
||||||
bot_type: Optional[int]
|
bot_type: Optional[int]
|
||||||
long_term_idle: bool
|
long_term_idle: bool
|
||||||
email_address_visibility: int
|
email_address_visibility: int
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteRealmDictValue(TypedDict):
|
||||||
|
can_push: bool
|
||||||
|
expected_end_timestamp: Optional[int]
|
||||||
|
|
|
@ -23,6 +23,7 @@ from typing_extensions import override
|
||||||
|
|
||||||
from analytics.lib.counts import CountStat, LoggingCountStat
|
from analytics.lib.counts import CountStat, LoggingCountStat
|
||||||
from analytics.models import InstallationCount, RealmCount
|
from analytics.models import InstallationCount, RealmCount
|
||||||
|
from corporate.models import CustomerPlan
|
||||||
from version import ZULIP_VERSION
|
from version import ZULIP_VERSION
|
||||||
from zerver.actions.message_delete import do_delete_messages
|
from zerver.actions.message_delete import do_delete_messages
|
||||||
from zerver.actions.message_flags import do_mark_stream_messages_as_read, do_update_message_flags
|
from zerver.actions.message_flags import do_mark_stream_messages_as_read, do_update_message_flags
|
||||||
|
@ -1577,6 +1578,47 @@ class AnalyticsBouncerTest(BouncerTestCase):
|
||||||
def test_send_realms_only_to_push_bouncer(self) -> None:
|
def test_send_realms_only_to_push_bouncer(self) -> None:
|
||||||
self.add_mock_response()
|
self.add_mock_response()
|
||||||
|
|
||||||
|
with mock.patch(
|
||||||
|
"zilencer.views.RemoteRealmBillingSession.get_customer", return_value=None
|
||||||
|
) as m:
|
||||||
|
realms = send_realms_only_to_push_bouncer()
|
||||||
|
m.assert_called()
|
||||||
|
for data in realms.values():
|
||||||
|
self.assertEqual(data["can_push"], True)
|
||||||
|
self.assertEqual(data["expected_end_timestamp"], None)
|
||||||
|
|
||||||
|
dummy_customer = mock.MagicMock()
|
||||||
|
with mock.patch(
|
||||||
|
"zilencer.views.RemoteRealmBillingSession.get_customer", return_value=dummy_customer
|
||||||
|
):
|
||||||
|
with mock.patch("zilencer.views.get_current_plan_by_customer", return_value=None) as m:
|
||||||
|
realms = send_realms_only_to_push_bouncer()
|
||||||
|
m.assert_called()
|
||||||
|
for data in realms.values():
|
||||||
|
self.assertEqual(data["can_push"], True)
|
||||||
|
self.assertEqual(data["expected_end_timestamp"], None)
|
||||||
|
|
||||||
|
dummy_customer_plan = mock.MagicMock()
|
||||||
|
dummy_customer_plan.status = CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE
|
||||||
|
dummy_date = datetime.datetime(year=2023, month=12, day=3, tzinfo=datetime.timezone.utc)
|
||||||
|
with mock.patch(
|
||||||
|
"zilencer.views.RemoteRealmBillingSession.get_customer", return_value=dummy_customer
|
||||||
|
):
|
||||||
|
with mock.patch(
|
||||||
|
"zilencer.views.get_current_plan_by_customer", return_value=dummy_customer_plan
|
||||||
|
):
|
||||||
|
with mock.patch(
|
||||||
|
"zilencer.views.RemoteRealmBillingSession.get_next_billing_cycle",
|
||||||
|
return_value=dummy_date,
|
||||||
|
) as m:
|
||||||
|
realms = send_realms_only_to_push_bouncer()
|
||||||
|
m.assert_called()
|
||||||
|
for data in realms.values():
|
||||||
|
self.assertEqual(data["can_push"], True)
|
||||||
|
self.assertEqual(
|
||||||
|
data["expected_end_timestamp"], datetime_to_timestamp(dummy_date)
|
||||||
|
)
|
||||||
|
|
||||||
send_realms_only_to_push_bouncer()
|
send_realms_only_to_push_bouncer()
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -1608,8 +1650,19 @@ class AnalyticsBouncerTest(BouncerTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Use a mock to assert exactly the data that gets sent.
|
# Use a mock to assert exactly the data that gets sent.
|
||||||
|
dummy_send_realms_only_response = {
|
||||||
|
"result": "success",
|
||||||
|
"msg": "",
|
||||||
|
"realms": {
|
||||||
|
"f9535515-84d0-489e-80d5-9ae97c3c7ec1": {
|
||||||
|
"can_push": True,
|
||||||
|
"expected_end_timestamp": None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
with mock.patch(
|
with mock.patch(
|
||||||
"zerver.lib.remote_server.send_to_push_bouncer"
|
"zerver.lib.remote_server.send_to_push_bouncer",
|
||||||
|
return_value=dummy_send_realms_only_response,
|
||||||
) as mock_send_to_push_bouncer:
|
) as mock_send_to_push_bouncer:
|
||||||
send_realms_only_to_push_bouncer()
|
send_realms_only_to_push_bouncer()
|
||||||
|
|
||||||
|
|
|
@ -1065,7 +1065,20 @@ class RealmTest(ZulipTestCase):
|
||||||
|
|
||||||
@override_settings(PUSH_NOTIFICATION_BOUNCER_URL="https://push.zulip.org.example.com")
|
@override_settings(PUSH_NOTIFICATION_BOUNCER_URL="https://push.zulip.org.example.com")
|
||||||
def test_do_create_realm_notify_bouncer(self) -> None:
|
def test_do_create_realm_notify_bouncer(self) -> None:
|
||||||
with mock.patch("zerver.lib.remote_server.send_to_push_bouncer") as m:
|
dummy_send_realms_only_response = {
|
||||||
|
"result": "success",
|
||||||
|
"msg": "",
|
||||||
|
"realms": {
|
||||||
|
"dummy-uuid": {
|
||||||
|
"can_push": True,
|
||||||
|
"expected_end_timestamp": None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
with mock.patch(
|
||||||
|
"zerver.lib.remote_server.send_to_push_bouncer",
|
||||||
|
return_value=dummy_send_realms_only_response,
|
||||||
|
) as m:
|
||||||
realm = do_create_realm("realm_string_id", "realm name")
|
realm = do_create_realm("realm_string_id", "realm name")
|
||||||
|
|
||||||
self.assertEqual(realm.string_id, "realm_string_id")
|
self.assertEqual(realm.string_id, "realm_string_id")
|
||||||
|
|
|
@ -23,7 +23,8 @@ from analytics.lib.counts import (
|
||||||
REMOTE_INSTALLATION_COUNT_STATS,
|
REMOTE_INSTALLATION_COUNT_STATS,
|
||||||
do_increment_logging_stat,
|
do_increment_logging_stat,
|
||||||
)
|
)
|
||||||
from corporate.lib.stripe import do_deactivate_remote_server
|
from corporate.lib.stripe import RemoteRealmBillingSession, do_deactivate_remote_server
|
||||||
|
from corporate.models import CustomerPlan, get_current_plan_by_customer
|
||||||
from zerver.decorator import require_post
|
from zerver.decorator import require_post
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
from zerver.lib.push_notifications import (
|
from zerver.lib.push_notifications import (
|
||||||
|
@ -36,8 +37,9 @@ from zerver.lib.push_notifications import (
|
||||||
from zerver.lib.remote_server import RealmDataForAnalytics
|
from zerver.lib.remote_server import RealmDataForAnalytics
|
||||||
from zerver.lib.request import REQ, has_request_variables
|
from zerver.lib.request import REQ, has_request_variables
|
||||||
from zerver.lib.response import json_success
|
from zerver.lib.response import json_success
|
||||||
from zerver.lib.timestamp import timestamp_to_datetime
|
from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime
|
||||||
from zerver.lib.typed_endpoint import JsonBodyPayload, typed_endpoint
|
from zerver.lib.typed_endpoint import JsonBodyPayload, typed_endpoint
|
||||||
|
from zerver.lib.types import RemoteRealmDictValue
|
||||||
from zerver.lib.validator import check_capped_string, check_int, check_string_fixed_length
|
from zerver.lib.validator import check_capped_string, check_int, check_string_fixed_length
|
||||||
from zerver.views.push_notifications import check_app_id, validate_token
|
from zerver.views.push_notifications import check_app_id, validate_token
|
||||||
from zilencer.auth import InvalidZulipServerKeyError
|
from zilencer.auth import InvalidZulipServerKeyError
|
||||||
|
@ -766,7 +768,36 @@ def remote_server_post_analytics(
|
||||||
)
|
)
|
||||||
batch_create_table_data(server, RemoteRealmAuditLog, remote_realm_audit_logs)
|
batch_create_table_data(server, RemoteRealmAuditLog, remote_realm_audit_logs)
|
||||||
|
|
||||||
return json_success(request)
|
remote_realm_dict: Dict[str, RemoteRealmDictValue] = {}
|
||||||
|
remote_realms = RemoteRealm.objects.filter(server=server)
|
||||||
|
for remote_realm in remote_realms:
|
||||||
|
uuid = str(remote_realm.uuid)
|
||||||
|
billing_session = RemoteRealmBillingSession(remote_realm)
|
||||||
|
|
||||||
|
customer = billing_session.get_customer()
|
||||||
|
if customer is None:
|
||||||
|
remote_realm_dict[uuid] = {"can_push": True, "expected_end_timestamp": None}
|
||||||
|
continue
|
||||||
|
|
||||||
|
current_plan = get_current_plan_by_customer(customer)
|
||||||
|
if current_plan is None:
|
||||||
|
remote_realm_dict[uuid] = {"can_push": True, "expected_end_timestamp": None}
|
||||||
|
continue
|
||||||
|
|
||||||
|
expected_end_timestamp = None
|
||||||
|
if current_plan.status in [
|
||||||
|
CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE,
|
||||||
|
CustomerPlan.DOWNGRADE_AT_END_OF_FREE_TRIAL,
|
||||||
|
]:
|
||||||
|
expected_end_timestamp = datetime_to_timestamp(
|
||||||
|
billing_session.get_next_billing_cycle(current_plan)
|
||||||
|
)
|
||||||
|
remote_realm_dict[uuid] = {
|
||||||
|
"can_push": True,
|
||||||
|
"expected_end_timestamp": expected_end_timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_success(request, data={"realms": remote_realm_dict})
|
||||||
|
|
||||||
|
|
||||||
def get_last_id_from_server(server: RemoteZulipServer, model: Any) -> int:
|
def get_last_id_from_server(server: RemoteZulipServer, model: Any) -> int:
|
||||||
|
|
Loading…
Reference in New Issue